fis-gtm/sr_port/iosocket_create.c

253 lines
7.6 KiB
C

/****************************************************************
* *
* Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
/* iosocket_create.c */
/* this module takes care of
* 1. allocate the space
* 2. for passive: local.sa & local.ai
* for active : remote.sa & remote.ai
* for $principal: via getsockname and getsockpeer
* 3. socketptr->protocol
* 4. socketptr->sd (initialized to -1) unless already open via inetd
* 5. socketptr->passive
* 6. socketptr->state (initialized to created) unless already open
*/
#include "mdef.h"
#include <errno.h>
#include "gtm_ctype.h"
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "gtm_netdb.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
#include "gtm_ipv6.h"
#include "gtm_stdlib.h"
#include "io.h"
#include "iotcproutine.h"
#include "iotcpdef.h"
#include "gt_timer.h"
#include "iosocketdef.h"
#include "min_max.h"
#include "gtm_caseconv.h"
#include "util.h"
GBLREF tcp_library_struct tcp_routines;
error_def(ERR_GETSOCKNAMERR);
error_def(ERR_GETADDRINFO);
error_def(ERR_GETNAMEINFO);
error_def(ERR_INVPORTSPEC);
error_def(ERR_INVADDRSPEC);
error_def(ERR_PROTNOTSUP);
error_def(ERR_TEXT);
error_def(ERR_SOCKINIT);
/* PORT_PROTO_FORMAT defines the format for <port>:<protocol> */
#define PORT_PROTO_FORMAT "%hu:%3[^:]"
#define SEPARATOR ':'
socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des)
{
socket_struct *socketptr;
socket_struct *prev_socketptr;
socket_struct *socklist_head;
bool passive = FALSE;
unsigned short port;
int ii, save_errno, tmplen, errlen;
char temp_addr[SA_MAXLITLEN], tcp[4], *adptr;
const char *errptr;
struct addrinfo *ai_ptr;
struct addrinfo hints, *addr_info_ptr = NULL;
int af;
int sd;
int errcode;
char port_buffer[NI_MAXSERV];
int port_buffer_len;
int colon_cnt;
char *last_2colon;
int addrlen;
GTM_SOCKLEN_TYPE tmp_addrlen;
if (0 > file_des)
{ /* no socket descriptor yet */
memset(&hints, 0, SIZEOF(hints));
colon_cnt = 0;
for (ii = strlen(sockaddr) - 1; 0 <= ii; ii--)
{
if (SEPARATOR == sockaddr[ii])
{
colon_cnt++;
if (2 == colon_cnt)
{
last_2colon = &sockaddr[ii];
break;
}
}
}
if (0 == colon_cnt)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return NULL;
}
if (1 == colon_cnt)
{ /* for listening socket or broadcasting socket */
if (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, tcp) < 2)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return NULL;
}
passive = TRUE;
/* We always first try using IPv6 address, if supported */
af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP)))
{
/* Try creating IPv4 socket */
af = AF_INET;
if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP)))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
return NULL;
}
}
SERVER_HINTS(hints, af);
port_buffer_len = 0;
I2A(port_buffer, port_buffer_len, port);
port_buffer[port_buffer_len]='\0';
if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &addr_info_ptr)))
{
tcp_routines.aa_close(sd);
RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return NULL;
}
SOCKET_ALLOC(socketptr);
socketptr->local.port = port;
socketptr->temp_sd = sd;
socketptr->sd = FD_INVALID;
ai_ptr = &(socketptr->local.ai);
memcpy(ai_ptr, addr_info_ptr, SIZEOF(struct addrinfo));
SOCKET_AI_TO_LOCAL_ADDR(socketptr, addr_info_ptr);
ai_ptr->ai_addr = SOCKET_LOCAL_ADDR(socketptr);
ai_ptr->ai_addrlen = addr_info_ptr->ai_addrlen;
ai_ptr->ai_next = NULL;
freeaddrinfo(addr_info_ptr);
} else
{ /* connection socket */
assert(2 == colon_cnt);
if (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, tcp) < 2)
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return NULL;
}
/* for connection socket */
SPRINTF(port_buffer, "%hu", port);
addrlen = last_2colon - sockaddr;
if ('[' == sockaddr[0])
{
if (NULL == memchr(sockaddr, ']', addrlen))
{
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return NULL;
}
addrlen -= 2;
memcpy(temp_addr, &sockaddr[1], addrlen);
} else
memcpy(temp_addr, sockaddr, addrlen);
temp_addr[addrlen] = 0;
CLIENT_HINTS(hints);
if (0 != (errcode = getaddrinfo(temp_addr, port_buffer, &hints, &addr_info_ptr)))
{
RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return NULL;
}
/* we will test all address families in iosocket_connect() */
SOCKET_ALLOC(socketptr);
socketptr->remote.ai_head = addr_info_ptr;
socketptr->remote.port = port;
socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */
}
lower_to_upper((uchar_ptr_t)tcp, (uchar_ptr_t)tcp, SIZEOF("TCP") - 1);
if (0 == MEMCMP_LIT(tcp, "TCP"))
{
socketptr->protocol = socket_tcpip;
} else
{
SOCKET_FREE(socketptr);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp);
return NULL;
}
socketptr->state = socket_created;
SOCKET_BUFFER_INIT(socketptr, bfsize);
socketptr->passive = passive;
socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
return socketptr;
} else
{ /* socket already setup by inetd */
SOCKET_ALLOC(socketptr);
socketptr->sd = file_des;
socketptr->temp_sd = FD_INVALID;
ai_ptr = &(socketptr->local.ai);
tmp_addrlen = SIZEOF(struct sockaddr_storage);
if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &tmp_addrlen))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
tmplen = STRLEN(errptr);
SOCKET_FREE(socketptr);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr);
return NULL;
}
ai_ptr->ai_addrlen = tmp_addrlen;
/* extract port information */
GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), tmp_addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
if (0 != errcode)
{
SOCKET_FREE(socketptr);
RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
return NULL;
}
socketptr->local.port = ATOI(port_buffer);
tmp_addrlen = SIZEOF(struct sockaddr_storage);
if (-1 == getpeername(socketptr->sd, SOCKET_REMOTE_ADDR(socketptr), &tmp_addrlen))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
tmplen = STRLEN(errptr);
SOCKET_FREE(socketptr);
rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr);
return NULL;
}
socketptr->remote.ai.ai_addrlen = tmp_addrlen;
assert(0 != SOCKET_REMOTE_ADDR(socketptr)->sa_family);
GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), socketptr->remote.ai.ai_addrlen, NULL, 0, port_buffer, NI_MAXSERV,
NI_NUMERICSERV, errcode);
if (0 != errcode)
{
SOCKET_FREE(socketptr);
RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
return NULL;
}
socketptr->remote.port = ATOI(port_buffer);
socketptr->state = socket_connected;
socketptr->protocol = socket_tcpip;
SOCKET_BUFFER_INIT(socketptr, bfsize);
socketptr->passive = passive;
socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
return socketptr;
}
}