Esempio n. 1
0
boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz)
{
	int			temp_1 = 1;
	char			*errptr;
	int4			errlen, msec_timeout, real_errno;
	short			len;
	in_port_t		actual_port;
	boolean_t		no_time_left = FALSE;
	d_socket_struct		*dsocketptr;
	struct addrinfo		*ai_ptr;
	char			port_buffer[NI_MAXSERV];
	int			errcode;
	ABS_TIME        	cur_time, end_time;
	GTM_SOCKLEN_TYPE	addrlen;
	GTM_SOCKLEN_TYPE	sockbuflen;

	dsocketptr = socketptr->dev;
	ai_ptr = (struct addrinfo*)(&socketptr->local.ai);
	assert(NULL != dsocketptr);
	dsocketptr->iod->dollar.key[0] = '\0';
	if (FD_INVALID != socketptr->temp_sd)
	{
		socketptr->sd = socketptr->temp_sd;
		socketptr->temp_sd = FD_INVALID;
	}
	if (timepar != NO_M_TIMEOUT)
	{
		msec_timeout = timeout2msec(timepar);
		sys_get_curr_time(&cur_time);
		add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
	}

	do
	{
		temp_1 = 1;
		if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1)))
		{
		        real_errno = errno;
			errptr = (char *)STRERROR(real_errno);
			errlen = STRLEN(errptr);
			SOCKET_FREE(socketptr);
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("SO_REUSEADDR"), real_errno, errlen, errptr);
			return FALSE;
		}
#ifdef TCP_NODELAY
		temp_1 = socketptr->nodelay ? 1 : 0;
		if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1)))
		{
		        real_errno = errno;
			errptr = (char *)STRERROR(real_errno);
			errlen = STRLEN(errptr);
			SOCKET_FREE(socketptr);
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("TCP_NODELAY"), real_errno, errlen, errptr);
			return FALSE;
		}
#endif
		if (update_bufsiz)
		{
			if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
				SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, SIZEOF(socketptr->bufsiz)))
			{
			        real_errno = errno;
				errptr = (char *)STRERROR(real_errno);
				errlen = STRLEN(errptr);
				SOCKET_FREE(socketptr);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
						RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr);
				return FALSE;
			}
		} else
		{
			sockbuflen = SIZEOF(socketptr->bufsiz);
			if (-1 == tcp_routines.aa_getsockopt(socketptr->sd,
				SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &sockbuflen))
			{
			        real_errno = errno;
				errptr = (char *)STRERROR(real_errno);
				errlen = STRLEN(errptr);
				SOCKET_FREE(socketptr);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
					RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr);
				return FALSE;
			}
		}
		temp_1 = tcp_routines.aa_bind(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen);
		if (temp_1 < 0)
		{
			real_errno = errno;
			no_time_left = TRUE;
			switch (real_errno)
			{
				case EADDRINUSE:
					if (NO_M_TIMEOUT != timepar)
					{
						sys_get_curr_time(&cur_time);
						cur_time = sub_abs_time(&end_time, &cur_time);
						if (cur_time.at_sec > 0)
							no_time_left = FALSE;
					}
					break;
				case EINTR:
					break;
				default:
					SOCKET_FREE(socketptr);
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBIND, 0, real_errno, 0);
					break;
			}
			if (no_time_left)
				return FALSE;
			hiber_start(100);
			tcp_routines.aa_close(socketptr->sd);
			if (-1 == (socketptr->sd = tcp_routines.aa_socket(ai_ptr->ai_family,ai_ptr->ai_socktype,
									  ai_ptr->ai_protocol)))
			{
				real_errno = errno;
				errptr = (char *)STRERROR(real_errno);
				errlen = STRLEN(errptr);
				SOCKET_FREE(socketptr);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr);
				return FALSE;
			}
		}
	} while (temp_1 < 0);

	/* obtain actual port from the bound address if port 0 was specified */
	addrlen = SOCKET_ADDRLEN(socketptr, ai_ptr, local);
	if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &addrlen))
	{
		real_errno = errno;
		errptr = (char *)STRERROR(real_errno);
		errlen = STRLEN(errptr);
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr);
	        return FALSE;
	}
	assert(ai_ptr->ai_addrlen == addrlen);
	GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
	if (0 != errcode)
	{
		SOCKET_FREE(socketptr);
		RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
		return FALSE;
	}
	actual_port = ATOI(port_buffer);
	if (0 == socketptr->local.port)
		socketptr->local.port = actual_port;
	assert(socketptr->local.port == actual_port);
	socketptr->state = socket_bound;
	len = SIZEOF(BOUND) - 1;
        memcpy(&dsocketptr->iod->dollar.key[0], BOUND, len);
        dsocketptr->iod->dollar.key[len++] = '|';
        memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len);
        len += socketptr->handle_len;
        dsocketptr->iod->dollar.key[len++] = '|';
        SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port);
	return TRUE;
}
socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des, boolean_t listen_specified)
{
	socket_struct		*socketptr;
	socket_struct		*prev_socketptr;
	socket_struct		*socklist_head;
	boolean_t		passive = FALSE;
	unsigned short		port;
	int			ii, save_errno, tmplen, errlen, sockaddrlen;
	char 			temp_addr[SA_MAXLITLEN], protocolstr[6], *adptr;
	const char		*errptr;
	struct addrinfo		*ai_ptr;
	struct addrinfo		hints, *addr_info_ptr = NULL;
#ifndef VMS
	struct sockaddr_un	*sa_un_ptr, sa_un_trans;
	mval			localpath;
	mstr			transpath;
	int			trans_status;
#endif
	enum socket_protocol	protocol;
	int			af;
	int			sd;
	int			errcode;
	char			host_buffer[NI_MAXHOST];
	char			port_buffer[NI_MAXSERV];
	int			port_buffer_len;
	int			colon_cnt, protooffset;
	char			*last_2colon = NULL;
	int			addrlen;
	GTM_SOCKLEN_TYPE	tmp_addrlen;

	if (0 > file_des)
	{	/* no socket descriptor yet */
		memset(&hints, 0, SIZEOF(hints));

		protooffset = colon_cnt = 0;
		sockaddrlen = STRLEN(sockaddr);
		for (ii = sockaddrlen - 1; 0 <= ii; ii--)
		{
			if (SEPARATOR == sockaddr[ii])
			{
				colon_cnt++;
				if (1 == colon_cnt)
					protooffset = ii + 1;
				else
				{
					last_2colon = &sockaddr[ii];
					break;
				}
			}
		}
		if (0 == colon_cnt)
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
			return NULL;
		}
		tmplen = sockaddrlen - protooffset;
		if (SIZEOF(protocolstr) <= tmplen)
		{	/* last piece just too big to be valid */
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, tmplen , &sockaddr[protooffset]);
			return NULL;
		}
		lower_to_upper((uchar_ptr_t)protocolstr, (uchar_ptr_t)&sockaddr[protooffset], tmplen);
		if (((SIZEOF("TCP") - 1) == tmplen) && (0 == MEMCMP_LIT(protocolstr, "TCP")))
			protocol = socket_tcpip;
#		ifndef VMS
		else if (((SIZEOF("LOCAL") - 1) == tmplen) && (0 == MEMCMP_LIT(protocolstr, "LOCAL")))
			protocol = socket_local;
#		endif
		else
		{
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, tmplen , &sockaddr[protooffset]);
			return NULL;
		}
		if (socket_tcpip == protocol)
		{
			if (1 == colon_cnt)
			{	/* for listening socket or broadcasting socket */
				if (!listen_specified || (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, protocolstr) < 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 = socket(af, SOCK_STREAM, IPPROTO_TCP)))
				{
					/* Try creating IPv4 socket */
					af = AF_INET;
					if (-1 == (sd = 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)))
				{
					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 (listen_specified || (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, protocolstr) < 2))
				{
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
					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_INVADDRSPEC);
						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 */
			}
#		ifndef VMS
		} else if (socket_local == protocol)
		{	/* should we get_full_path first */
			/* check protooffset < sizeof sun_path */
			/* protooffset is after colon */
			SOCKET_ALLOC(socketptr);
			socketptr->protocol = socket_local;
			sa_un_ptr = malloc(SIZEOF(struct sockaddr_un));
			sa_un_ptr->sun_family = AF_UNIX;
			MV_INIT_STRING(&localpath, protooffset - 1, sockaddr);
			trans_status = TRANS_LOG_NAME(&localpath.str, &transpath, sa_un_trans.sun_path,
				(int)SIZEOF(sa_un_trans.sun_path), dont_sendmsg_on_log2long);
			if (SS_LOG2LONG == trans_status)
			{	/* if LOG2LONG, returned len not valid so report untranslated length */
				SOCKET_FREE(socketptr);
				rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, localpath.str.len, localpath.str.addr,
					localpath.str.len, SIZEOF(sa_un_trans.sun_path));
				return NULL;
			}
			memcpy(sa_un_ptr->sun_path, transpath.addr, transpath.len);
			sa_un_ptr->sun_path[transpath.len] = '\0';
			if (listen_specified)
			{
				passive = TRUE;
				socketptr->local.sa = (struct sockaddr *)sa_un_ptr;
				socketptr->local.ai.ai_family = AF_UNIX;
				socketptr->local.ai.ai_socktype = SOCK_STREAM;
				socketptr->local.ai.ai_addrlen = (size_t)((struct sockaddr_un *)0)->sun_path + protooffset;
				if (-1 == (sd = socket(AF_UNIX, SOCK_STREAM, 0)))
				{
					save_errno = errno;
					SOCKET_FREE(socketptr);
					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;
				}
				socketptr->temp_sd = sd;
				socketptr->sd = FD_INVALID;
			} else
			{
				socketptr->remote.sa = (struct sockaddr *)sa_un_ptr;
				/* setup remote fields */
				socketptr->remote.ai.ai_family = AF_UNIX;
				socketptr->remote.ai.ai_socktype = SOCK_STREAM;
				socketptr->remote.ai.ai_addrlen = (size_t)((struct sockaddr_un *)0)->sun_path + protooffset;
				socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */
			}
#		endif
		} else