diff options
Diffstat (limited to 'erts/emulator/drivers/common')
| -rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 153 | 
1 files changed, 118 insertions, 35 deletions
| diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 09bada457d..3c6922eb8e 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -268,14 +268,13 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD);  #define sock_htonl(x)              htonl((x))  #define sock_send(s,buf,len,flag)  send((s),(buf),(len),(flag))  #define sock_sendv(s, vec, size, np, flag) \ -                WSASend((s),(WSABUF*)(vec),\ -				   (size),(np),(flag),NULL,NULL) +            WSASend((s),(WSABUF*)(vec),(size),(np),(flag),NULL,NULL)  #define sock_recv(s,buf,len,flag)  recv((s),(buf),(len),(flag))  #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ -                recvfrom((s),(buf),(blen),(flag),(addr),(alen)) +	    recvfrom((s),(buf),(blen),(flag),(addr),(alen))  #define sock_sendto(s,buf,blen,flag,addr,alen) \ -                sendto((s),(buf),(blen),(flag),(addr),(alen)) +	    sendto((s),(buf),(blen),(flag),(addr),(alen))  #define sock_hostname(buf, len)    gethostname((buf), (len))  #define sock_getservbyname(name,proto) getservbyname((name),(proto)) @@ -360,9 +359,9 @@ static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int  #define sock_accept(s, addr, len)   accept((s), (addr), (len))  #define sock_send(s,buf,len,flag)   inet_send((s),(buf),(len),(flag))  #define sock_sendto(s,buf,blen,flag,addr,alen) \ -                sendto((s),(buf),(blen),(flag),(addr),(alen)) +	    sendto((s),(buf),(blen),(flag),(addr),(alen))  #define sock_sendv(s, vec, size, np, flag) \ -		(*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) +	    (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np))))  #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag))  #define sock_open(af, type, proto)  socket((af), (type), (proto)) @@ -1178,6 +1177,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int,  static void tcp_inet_timeout(ErlDrvData);  static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *);   static void inet_stop_select(ErlDrvEvent, void*);  +static void inet_emergency_close(ErlDrvData);  #ifdef __WIN32__  static void tcp_inet_event(ErlDrvData, ErlDrvEvent);  static void find_dynamic_functions(void); @@ -1288,7 +1288,8 @@ static struct erl_drv_entry tcp_inet_driver_entry =      ERL_DRV_FLAG_USE_PORT_LOCKING|ERL_DRV_FLAG_SOFT_BUSY,      NULL,      tcp_inet_process_exit, -    inet_stop_select +    inet_stop_select, +    inet_emergency_close  }; @@ -1341,7 +1342,8 @@ static struct erl_drv_entry udp_inet_driver_entry =      ERL_DRV_FLAG_USE_PORT_LOCKING,      NULL,      NULL, -    inet_stop_select +    inet_stop_select, +    inet_emergency_close  };  #endif @@ -1375,7 +1377,8 @@ static struct erl_drv_entry sctp_inet_driver_entry =      ERL_DRV_FLAG_USE_PORT_LOCKING,      NULL,      NULL, /* process_exit */ -    inet_stop_select +    inet_stop_select, +    inet_emergency_close  };  #endif @@ -1421,7 +1424,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event);  static int packet_inet_output(udp_descriptor* udesc, HANDLE event);  #endif -/* convert descriptor poiner to inet_descriptor pointer */ +/* convert descriptor pointer to inet_descriptor pointer */  #define INETP(d) (&(d)->inet)  #ifdef __OSE__ @@ -2890,6 +2893,9 @@ static ErlDrvTermData   am_sctp_rtoinfo, /* Option names */      /* For #sctp_paddrinfo{}: */      am_active,                         am_inactive, +#    if HAVE_DECL_SCTP_UNCONFIRMED +    am_unconfirmed, +#    endif      /* For #sctp_status{}: */  #    if HAVE_DECL_SCTP_EMPTY @@ -3919,7 +3925,10 @@ static void inet_init_sctp(void) {      /* For #sctp_paddrinfo{}: */      INIT_ATOM(active);      INIT_ATOM(inactive); -     +#    if HAVE_DECL_SCTP_UNCONFIRMED +    INIT_ATOM(unconfirmed); +#    endif +      /* For #sctp_status{}: */  #    if HAVE_DECL_SCTP_EMPTY      INIT_ATOM(empty); @@ -4372,7 +4381,7 @@ static int erl_inet_close(inet_descriptor* desc)  	desc_close(desc);  	desc->state = INET_STATE_CLOSED;      } else if (desc->prebound && (desc->s != INVALID_SOCKET)) { -	sock_select(desc, FD_READ | FD_WRITE | FD_CLOSE, 0); +	sock_select(desc, FD_READ | FD_WRITE | FD_CLOSE | ERL_DRV_USE_NO_CALLBACK, 0);  	desc->event_mask = 0;  #ifdef __WIN32__  	desc->forced_events = 0; @@ -4536,16 +4545,19 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,  /* as inet_open but pass in an open socket (MUST BE OF RIGHT TYPE) */  static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, -				    SOCKET s, char** rbuf, ErlDrvSizeT rsize) +				    SOCKET s, Uint32 bound, +                                    char** rbuf, ErlDrvSizeT rsize)  {      inet_address name;      unsigned int sz = sizeof(name); -    /* check that it is a socket and that the socket is bound */ -    if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz))) -	return ctl_error(sock_errno(), rbuf, rsize); -    if (name.sa.sa_family != domain) -	return ctl_error(EINVAL, rbuf, rsize); +    if (bound) { +        /* check that it is a socket and that the socket is bound */ +        if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz))) +            return ctl_error(sock_errno(), rbuf, rsize); +        if (name.sa.sa_family != domain) +            return ctl_error(EINVAL, rbuf, rsize); +    }  #ifdef __OSE__              /* for fdopen duplicating the sd will allow to uniquely identify         the signal from OSE with erlang port */ @@ -4560,7 +4572,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,  #ifdef __WIN32__      driver_select(desc->port, desc->event, ERL_DRV_READ, 1);  #endif -    desc->state = INET_STATE_BOUND; /* assume bound */ + +    if (bound) +        desc->state = INET_STATE_BOUND; +    else +        desc->state = INET_STATE_OPEN; +      if (type == SOCK_STREAM) { /* check if connected */  	sz = sizeof(name);  	if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) { @@ -4713,6 +4730,36 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end)      return NULL;  } +/* sockaddr_bufsz_need + * Returns the number of bytes needed to store the information + * through sockaddr_to_buf + */ + +static size_t sockaddr_bufsz_need(struct sockaddr* addr) +{ +    if (addr->sa_family == AF_INET || addr->sa_family == 0) { +	return 1 + sizeof(struct in_addr); +    } +#if defined(HAVE_IN6) && defined(AF_INET6) +    else if (addr->sa_family == AF_INET6) { +	return 1 + sizeof(struct in6_addr); +    } +#endif +#if defined(AF_LINK) +    if (addr->sa_family == AF_LINK) { +	struct sockaddr_dl *sdl_p = (struct sockaddr_dl*) addr; +	return 2 + sdl_p->sdl_alen; +    } +#endif +#if defined(AF_PACKET) && defined(HAVE_NETPACKET_PACKET_H) +    else if(addr->sa_family == AF_PACKET) { +	struct sockaddr_ll *sll_p = (struct sockaddr_ll*) addr; +	return 2 + sll_p->sll_halen; +    } +#endif +    return 0; +} +  static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)  {      buf_check(ptr,end,1); @@ -5772,7 +5819,7 @@ done:  	    ia_p->Ipv6IfIndex &&  	    ia_p->Ipv6IfIndex != index)  	{ -	    /* Oops, there was an other interface for IPv6. Possible? XXX */ +	    /* Oops, there was another interface for IPv6. Possible? XXX */  	    index = ia_p->Ipv6IfIndex;  	    goto index;  	} @@ -5791,6 +5838,11 @@ done:  }  #elif defined(HAVE_GETIFADDRS) +#ifdef  DEBUG +#define GETIFADDRS_BUFSZ (1) +#else +#define GETIFADDRS_BUFSZ (512) +#endif  static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,  					char **rbuf_pp, ErlDrvSizeT rsize) @@ -5801,15 +5853,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,      char *buf_p;      char *buf_alloc_p; -    buf_size = 512; -    buf_alloc_p = ALLOC(buf_size); +    buf_size = GETIFADDRS_BUFSZ; +    buf_alloc_p = ALLOC(GETIFADDRS_BUFSZ);      buf_p = buf_alloc_p;  #   define BUF_ENSURE(Size)						\      do {								\  	int NEED_, GOT_ = buf_p - buf_alloc_p;				\  	NEED_ = GOT_ + (Size);						\  	if (NEED_ > buf_size) {						\ -	    buf_size = NEED_ + 512;					\ +	    buf_size = NEED_ + GETIFADDRS_BUFSZ;			\  	    buf_alloc_p = REALLOC(buf_alloc_p, buf_size);		\  	    buf_p = buf_alloc_p + GOT_;					\  	}								\ @@ -5822,7 +5874,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,  	    while (! (P_ = sockaddr_to_buf((sa), buf_p,			\  					   buf_alloc_p+buf_size))) {	\  		int GOT_ = buf_p - buf_alloc_p;				\ -		buf_size += 512;					\ +		buf_size += GETIFADDRS_BUFSZ;				\  		buf_alloc_p = REALLOC(buf_alloc_p, buf_size);		\  		buf_p = buf_alloc_p + GOT_;				\  	    }								\ @@ -5879,10 +5931,11 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,  		     || ifa_p->ifa_addr->sa_family == AF_PACKET  #endif  		     ) { -		char *bp = buf_p; -		BUF_ENSURE(1); -		SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); -		if (buf_p - bp < 4) buf_p = bp; /* Empty hwaddr */ +		size_t need = sockaddr_bufsz_need(ifa_p->ifa_addr); +		if (need > 3) { +		    BUF_ENSURE(1 + need); +		    SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); +		}  	    }  #endif  	} @@ -5897,6 +5950,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,      return buf_size;  #   undef BUF_ENSURE  } +#undef GETIFADDRS_BUFSZ  #else @@ -7330,8 +7384,13 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i,      case SCTP_INACTIVE:  	i = LOAD_ATOM	(spec, i, am_inactive);  	break; +#   if HAVE_DECL_SCTP_UNCONFIRMED +    case SCTP_UNCONFIRMED: +      i = LOAD_ATOM	(spec, i, am_unconfirmed); +      break; +#   endif      default: -	ASSERT(0);	/* NB: SCTP_UNCONFIRMED modifier not yet supported */ +      i = LOAD_ATOM	(spec, i, am_undefined);      }      i = LOAD_INT	(spec, i, pai->spinfo_cwnd);      i = LOAD_INT	(spec, i, pai->spinfo_srtt); @@ -8196,6 +8255,19 @@ static void inet_stop(inet_descriptor* desc)      FREE(desc);  } +static void inet_emergency_close(ErlDrvData data) +{ +    /* valid for any (UDP, TCP or SCTP) descriptor */ +    tcp_descriptor* tcp_desc = (tcp_descriptor*)data; +    inet_descriptor* desc = INETP(tcp_desc); +    DEBUGF(("inet_emergency_close(%ld) {s=%d\r\n", +	    (long)desc->port, desc->s)); +    if (desc->s != INVALID_SOCKET) { +	sock_close(desc->s); +    } +} + +  static void set_default_msgq_limits(ErlDrvPort port)  {      ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK; @@ -9121,10 +9193,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,  	break;      } -    case INET_REQ_FDOPEN: {  /* pass in an open socket */ +    case INET_REQ_FDOPEN: {  /* pass in an open (and optionally bound) socket */  	int domain; +        int bound;  	DEBUGF(("tcp_inet_ctl(%ld): FDOPEN\r\n", (long)desc->inet.port)); -	if (len != 6) return ctl_error(EINVAL, rbuf, rsize); +	if (len != 6 && len != 10) return ctl_error(EINVAL, rbuf, rsize);  	switch(buf[0]) {  	case INET_AF_INET:  	    domain = AF_INET; @@ -9142,8 +9215,13 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,  	    return ctl_error(EINVAL, rbuf, rsize);  	}  	if (buf[1] != INET_TYPE_STREAM) return ctl_error(EINVAL, rbuf, rsize); + +        if (len == 6) bound = 1; +        else bound = get_int32(buf+2+4); +  	return inet_ctl_fdopen(INETP(desc), domain, SOCK_STREAM, -			       (SOCKET) get_int32(buf+2), rbuf, rsize); +                               (SOCKET) get_int32(buf+2), +                               bound, rbuf, rsize);  	break;      } @@ -11116,10 +11194,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,  	return replen; -    case INET_REQ_FDOPEN: {  /* pass in an open (and bound) socket */ +    case INET_REQ_FDOPEN: {  /* pass in an open (and optionally bound) socket */  	SOCKET s; +        int bound;  	DEBUGF(("packet inet_ctl(%ld): FDOPEN\r\n", (long)desc->port)); -	if (len != 6) { +	if (len != 6 && len != 10) {  	    return ctl_error(EINVAL, rbuf, rsize);  	}  	switch (buf[0]) { @@ -11144,7 +11223,11 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,  	    return ctl_error(EINVAL, rbuf, rsize);  	}  	s = (SOCKET)get_int32(buf+2); -	replen = inet_ctl_fdopen(desc, af, type, s, rbuf, rsize); + +        if (len == 6) bound = 1; +        else bound = get_int32(buf+2+4); + +	replen = inet_ctl_fdopen(desc, af, type, s, bound, rbuf, rsize);  	if ((*rbuf)[0] != INET_REP_ERROR) {  	    if (desc->active) | 
