From b63a16d0958bd748644d22f13f35f8956a903d6c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 18 Jun 2018 18:19:39 +0200 Subject: [socket+net-nif] Moved common functions into util files The common stuff, like decode and encode of common types (soch as socket address), has been moved into a util file (socket_util). The debug stuff has also been moved into its own file. Also introduced a common include file for common macros and types. OTP-14831 --- erts/emulator/nifs/common/net_nif.c | 87 +---------- erts/emulator/nifs/common/socket_nif.c | 266 ++++++++++++-------------------- erts/emulator/nifs/common/socket_util.c | 168 +++++++++++++++++++- erts/emulator/nifs/common/socket_util.h | 11 +- erts/preloaded/ebin/socket.beam | Bin 39704 -> 39680 bytes erts/preloaded/src/socket.erl | 56 ++----- 6 files changed, 284 insertions(+), 304 deletions(-) diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c index 9a96eff654..572813ac62 100644 --- a/erts/emulator/nifs/common/net_nif.c +++ b/erts/emulator/nifs/common/net_nif.c @@ -1390,7 +1390,7 @@ ERL_NIF_TERM encode_address_info(ErlNifEnv* env, } -/* Convert an "native" family to an erlang family +/* Convert an "native" family to an erlang family (=domain). * Note that this is not currently exhaustive, but only supports * inet and inet6. Other values will be returned as is, that is * in the form of an integer. @@ -1401,34 +1401,15 @@ ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, { ERL_NIF_TERM efam; - switch (family) { - case AF_INET: - efam = esock_atom_inet; - break; - -#if defined(HAVE_IN6) && defined(AF_INET6) - case AF_INET6: - efam = esock_atom_inet6; - break; -#endif - - #ifdef HAVE_SYS_UN_H - case AF_UNIX: - efam = esock_atom_local; - break; -#endif - - default: + if (NULL != esock_encode_type(env, family, &efam)) efam = MKI(env, family); - break; - } return efam; } -/* Convert an "native" socket type to an erlang socket type +/* Convert an "native" socket type to an erlang socket type. * Note that this is not currently exhaustive, but only supports * stream and dgram. Other values will be returned as is, that is * in the form of an integer. @@ -1439,38 +1420,15 @@ ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, { ERL_NIF_TERM etype; - switch (socktype) { - case SOCK_STREAM: - etype = esock_atom_stream; - break; - - case SOCK_DGRAM: - etype = esock_atom_dgram; - break; - - case SOCK_RAW: - etype = esock_atom_raw; - break; - - case SOCK_RDM: - etype = esock_atom_rdm; - break; - - case SOCK_SEQPACKET: - etype = esock_atom_seqpacket; - break; - - default: + if (NULL != esock_encode_type(env, socktype, &etype)) etype = MKI(env, socktype); - break; - } return etype; } -/* Convert an "native" protocol to an erlang protocol +/* Convert an "native" protocol to an erlang protocol. * Note that this is not currently exhaustive, but only supports * tcp and udp. Other values will be returned as is, that is * in the form of an integer. @@ -1481,39 +1439,8 @@ ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, { ERL_NIF_TERM eproto; - switch (proto) { -#if defined(SOL_IP) - case SOL_IP: -#else - case IPPROTO_IP: -#endif - eproto = esock_atom_ip; - break; - -#if defined(SOL_IPV6) - case SOL_IPV6: - eproto = esock_atom_ipv6; - break; -#endif - - case IPPROTO_TCP: - eproto = esock_atom_tcp; - break; - - case IPPROTO_UDP: - eproto = esock_atom_udp; - break; - -#if defined(HAVE_SCTP) - case IPPROTO_SCTP: - eproto = esock_atom_sctp; - break; -#endif - - default: + if (NULL != esock_encode_protocol(env, proto, &eproto)) eproto = MKI(env, proto); - break; - } return eproto; } @@ -1615,7 +1542,7 @@ static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { // We should make it possible to use load_info to get default values - data.debug = FALSE; + data.debug = TRUE; NDBG( ("NET", "on_load -> entry\r\n") ); diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index d2455a7b3a..848e502ec5 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -757,7 +757,8 @@ static ERL_NIF_TERM nopen(ErlNifEnv* env, char* netns); static ERL_NIF_TERM nbind(ErlNifEnv* env, SocketDescriptor* descP, - ERL_NIF_TERM addr); + SocketAddress* sockAddrP, + unsigned int addrLen); static ERL_NIF_TERM nconnect(ErlNifEnv* env, SocketDescriptor* descP); static ERL_NIF_TERM nlisten(ErlNifEnv* env, @@ -1131,7 +1132,7 @@ static ERL_NIF_TERM nfinalize_connection(ErlNifEnv* env, static ERL_NIF_TERM nfinalize_close(ErlNifEnv* env, SocketDescriptor* descP); - +/* static char* decode_in_sockaddr(ErlNifEnv* env, ERL_NIF_TERM eSockAddr, SocketAddress* sockAddrP, @@ -1162,7 +1163,7 @@ static char* decode_in6_sockaddr_atomaddr(ErlNifEnv* env, unsigned int scopeId, SocketAddress* sockAddrP, unsigned int* addrLenP); -/* Decode an in6_sockaddr where the address field is a tuple */ +/ * Decode an in6_sockaddr where the address field is a tuple * / static char* decode_in6_sockaddr_addr(ErlNifEnv* env, ERL_NIF_TERM eAddr, int port, @@ -1171,6 +1172,8 @@ static char* decode_in6_sockaddr_addr(ErlNifEnv* env, SocketAddress* sockAddrP, unsigned int* addrLenP); #endif +*/ +/* static char* decode_laddress(ErlNifEnv* env, int domain, ERL_NIF_TERM localAddr, @@ -1181,6 +1184,7 @@ static char* decode_laddress_binary(ErlNifEnv* env, ERL_NIF_TERM localAddr, SocketAddress* localP, unsigned int* addrLenP); +*/ /* static char* decode_address_tuple(ErlNifEnv* env, int domain, @@ -1212,11 +1216,13 @@ static char* decode_send_addr_tuple(ErlNifEnv* env, SocketAddress* toAddrP, unsigned int* addrLenP); */ +/* static void encode_address(ErlNifEnv* env, SocketAddress* fromAddrP, unsigned int fromAddrLen, ERL_NIF_TERM* fromDomainT, ERL_NIF_TERM* fromSourceT); +*/ static BOOLEAN_T decode_sock_linger(ErlNifEnv* env, ERL_NIF_TERM eVal, struct linger* valP); @@ -1276,9 +1282,11 @@ static BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err); static BOOLEAN_T cnt_inc(uint32_t* cnt, uint32_t inc); +/* #if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) static size_t my_strnlen(const char *s, size_t maxlen); #endif +*/ static void socket_dtor(ErlNifEnv* env, void* obj); static void socket_stop(ErlNifEnv* env, @@ -1875,16 +1883,8 @@ BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err) * Bind a name to a socket. * * Arguments: - * Socket (ref) - Points to the socket descriptor. - * LocalAddr - Local address is either: - * - a binary - when the socket domain = local - * - a tuple of size 2 with - * - first element is the address - * - second element is the port number - * The address can be in the form of either: - * - A tuple of size 4 or 8 (depending on domain) - * - The atom 'any' - * - The atom 'loopback' + * [0] Socket (ref) - Points to the socket descriptor. + * [1] LocalAddr - Local address is a sockaddr map ( socket:sockaddr() ). */ static ERL_NIF_TERM nif_bind(ErlNifEnv* env, @@ -1892,6 +1892,12 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, const ERL_NIF_TERM argv[]) { SocketDescriptor* descP; + ERL_NIF_TERM eSockAddr; + SocketAddress sockAddr; + unsigned int addrLen; + char* xres; + + SGDBG( ("SOCKET", "nif_bind -> entry with argc: %d\r\n", argc) ); /* Extract arguments and perform preliminary validation */ @@ -1899,25 +1905,13 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, !enif_get_resource(env, argv[0], sockets, (void**) &descP)) { return enif_make_badarg(env); } + eSockAddr = argv[1]; SSDBG( descP, - ("SOCKET", "nif_bind -> " - "\r\n Socket: %T" - "\r\n Addr: %T" - "\r\n", argv[0], argv[1]) ); - - /* Basic arg validation: - * - if binary domain must be local (unix) - * - if tuple domain must be either inet or inet6 - */ - if (IS_BIN(env, argv[1]) && (descP->domain != AF_UNIX)) { - return enif_make_badarg(env); - } else if (IS_TUPLE(env, argv[1]) && - (descP->domain != AF_INET) && - (descP->domain != AF_INET6)) { - return enif_make_badarg(env); - } - + ("SOCKET", "nif_bind -> args:" + "\r\n Socket: %T" + "\r\n SockAddr: %T" + "\r\n", argv[0], eSockAddr) ); /* Make sure we are ready * Not sure how this would even happen, but... @@ -1926,42 +1920,35 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, if (descP->state != SOCKET_STATE_OPEN) return esock_make_error(env, atom_exbadstate); - return nbind(env, descP, argv[1]); + if ((xres = esock_decode_sockaddr(env, eSockAddr, &sockAddr, &addrLen)) != NULL) + return esock_make_error_str(env, xres); + + return nbind(env, descP, &sockAddr, addrLen); } static ERL_NIF_TERM nbind(ErlNifEnv* env, SocketDescriptor* descP, - ERL_NIF_TERM addr) + SocketAddress* sockAddrP, + unsigned int addrLen) { - SocketAddress local; - unsigned int addrLen = 0; - char* xerr; - int port; - - SSDBG( descP, - ("SOCKET", "nbind -> entry with" - "\r\n addr: %T" - "\r\n", addr) ); - - if ((xerr = decode_laddress(env, - descP->domain, addr, &local, &addrLen)) != NULL) - return esock_make_error_str(env, xerr); + int port; SSDBG( descP, ("SOCKET", "nbind -> try bind\r\n") ); if (IS_SOCKET_ERROR(sock_bind(descP->sock, - (struct sockaddr*) &local, addrLen))) { + (struct sockaddr*) sockAddrP, addrLen))) { return esock_make_error_errno(env, sock_errno()); } - port = which_address_port(&local); + port = which_address_port(sockAddrP); + SSDBG( descP, ("SOCKET", "nbind -> port: %d\r\n", port) ); if (port == 0) { - SOCKLEN_T len = sizeof(local); - sys_memzero((char *) &local, len); - sock_name(descP->sock, &local.sa, &len); - port = which_address_port(&local); + SOCKLEN_T len = sizeof(SocketAddress); + sys_memzero((char *) sockAddrP, len); + sock_name(descP->sock, &sockAddrP->sa, &len); + port = which_address_port(sockAddrP); } else if (port == -1) { port = 0; } @@ -1973,83 +1960,6 @@ ERL_NIF_TERM nbind(ErlNifEnv* env, } -/* Decode the (local) address. The format of the address should - * either be an binary (domain = local) or an in_sockaddr(), which - * is either a in4_sockaddr record or a int6_sockaddr record - * (if domain is either inet or inet6). - */ -static -char* decode_laddress(ErlNifEnv* env, - int domain, - ERL_NIF_TERM localAddr, - SocketAddress* localP, - unsigned int* addrLenP) -{ - if (IS_BIN(env, localAddr)) { - return decode_laddress_binary(env, domain, localAddr, localP, addrLenP); - } else if (IS_TUPLE(env, localAddr)) { - return decode_in_sockaddr(env, localAddr, localP, addrLenP); - } else { - return ESOCK_STR_EINVAL; - } - -} - - -/* Only for domain = local (unix) - * The erlang interface module (socket) ensures that the size of the - * binary is > 0, so we need not do that here. - */ -static -char* decode_laddress_binary(ErlNifEnv* env, - int domain, - ERL_NIF_TERM localAddr, - SocketAddress* localP, - unsigned int* addrLenP) -{ - unsigned int addrLen; - -#ifdef HAVE_SYS_UN_H - ErlNifBinary bin; - - if (domain != AF_UNIX) - return ESOCK_STR_EINVAL; - - if (!GET_BIN(env, localAddr, &bin)) - return ESOCK_STR_EINVAL; - - if ((bin.size + -#ifdef __linux__ - /* Make sure the address gets zero terminated - * except when the first byte is \0 because then it is - * sort of zero terminated although the zero termination - * comes before the address... - * This fix handles Linux's nonportable - * abstract socket address extension. - */ - (bin.data[0] == '\0' ? 0 : 1) -#else - 1 -#endif - ) > sizeof(localP->un.sun_path)) - return ESOCK_STR_EINVAL; - - sys_memzero((char*)localP, sizeof(struct sockaddr_un)); - localP->un.sun_family = domain; - sys_memcpy(localP->un.sun_path, bin.data, bin.size); - addrLen = offsetof(struct sockaddr_un, sun_path) + bin.size; -#ifndef NO_SA_LEN - localP->un.sun_len = addrLen; -#endif - *addrLenP = addrLen; - return NULL; - -#else // HAVE_SYS_UN_H - return str_eafnosupport; -#endif - -} - /* ---------------------------------------------------------------------- @@ -2061,9 +1971,8 @@ char* decode_laddress_binary(ErlNifEnv* env, * Arguments: * Socket (ref) - Points to the socket descriptor. * SockAddr - Socket Address of "remote" host. - * This is in_sockaddr(), which is either - * in4_sockaddr (#in4_sockaddr{}) or - * in6_sockaddr (#in6_sockaddr{}). + * This is sockaddr(), which is either + * sockaddr_in4 or sockaddr_in6. */ static ERL_NIF_TERM nif_connect(ErlNifEnv* env, @@ -2082,8 +1991,8 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, } eSockAddr = argv[1]; - if ((xres = decode_in_sockaddr(env, eSockAddr, - &descP->remote, &descP->addrLen)) != NULL) { + if ((xres = esock_decode_sockaddr(env, eSockAddr, + &descP->remote, &descP->addrLen)) != NULL) { return esock_make_error_str(env, xres); } @@ -2203,6 +2112,7 @@ BOOLEAN_T verify_is_connected(SocketDescriptor* descP, int* err) */ #ifndef SO_ERROR + int sz, code; sz = sizeof(descP->remote); @@ -2689,7 +2599,7 @@ ERL_NIF_TERM nsend(ErlNifEnv* env, * SendRef - A unique id for this (send) request. * Data - The data to send in the form of a IOVec. * Flags - Send flags. - * DestSockAddr - Destination (socket) address. + * Dest - Destination (socket) address. */ static @@ -2725,9 +2635,9 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, if (!esendflags2sendflags(eflags, &flags)) return esock_make_error(env, esock_atom_einval); - if ((xres = decode_in_sockaddr(env, eSockAddr, - &remoteAddr, - &remoteAddrLen)) != NULL) + if ((xres = esock_decode_sockaddr(env, eSockAddr, + &remoteAddr, + &remoteAddrLen)) != NULL) return esock_make_error_str(env, xres); return nsendto(env, descP, sendRef, &data, flags, &remoteAddr, remoteAddrLen); @@ -5404,11 +5314,11 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, /* +++ We sucessfully got a message - time to encode the address +++ */ - ERL_NIF_TERM fromDomainT, fromSourceT; + ERL_NIF_TERM eSockAddr; - encode_address(env, - fromAddrP, fromAddrLen, - &fromDomainT, &fromSourceT); + esock_encode_sockaddr(env, + fromAddrP, fromAddrLen, + &eSockAddr); if (read == bufP->size) { data = MKBIN(env, bufP); @@ -5424,7 +5334,7 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, data = MKSBIN(env, data, 0, read); } - return esock_make_ok2(env, MKT3(env, fromDomainT, fromSourceT, data)); + return esock_make_ok2(env, MKT2(env, eSockAddr, data)); } } @@ -5539,6 +5449,7 @@ char* decode_send_addr_tuple(ErlNifEnv* env, * 5: Scope Id: integer() * */ +/* static char* decode_in_sockaddr(ErlNifEnv* env, ERL_NIF_TERM eSockAddr, @@ -5552,10 +5463,10 @@ char* decode_in_sockaddr(ErlNifEnv* env, if (!GET_TUPLE(env, eSockAddr, &addrtSz, &addrt)) return ESOCK_STR_EINVAL; - /* + / * * We use the tuple size to figure out which * of the records this is. - */ + * / switch (addrtSz) { case 3: result = decode_in4_sockaddr(env, addrt, sockAddrP, addrLenP); @@ -5574,7 +5485,7 @@ char* decode_in_sockaddr(ErlNifEnv* env, return result; } - +*/ /* Decode an in4_sockaddr(). @@ -5582,6 +5493,7 @@ char* decode_in_sockaddr(ErlNifEnv* env, * The second, the port number integer . * The third and final, the ip4_address tuple. */ +/* static char* decode_in4_sockaddr(ErlNifEnv* env, const ERL_NIF_TERM* eIn4SockAddr, @@ -5590,18 +5502,18 @@ char* decode_in4_sockaddr(ErlNifEnv* env, { int port; - /* 1: Ensure that the tuple has the correct tag: in4_sockaddr */ + / * 1: Ensure that the tuple has the correct tag: in4_sockaddr * / if (COMPARE(atom_in4_sockaddr, eIn4SockAddr[0]) != 0) return ESOCK_STR_EINVAL; - /* 2: Get the port number */ + / * 2: Get the port number * / if (!GET_INT(env, eIn4SockAddr[1], &port)) return ESOCK_STR_EINVAL; - /* 3: Get the address. + / * 3: Get the address. * It can either be the atoms: any | loopback, * or the IPv4 address tuple (size 4). - */ + * / if (IS_ATOM(env, eIn4SockAddr[2])) { return decode_in4_sockaddr_atomaddr(env, eIn4SockAddr[2], port, sockAddrP, addrLenP); @@ -5612,9 +5524,10 @@ char* decode_in4_sockaddr(ErlNifEnv* env, return ESOCK_STR_EINVAL; } } +*/ - +/* static char* decode_in4_sockaddr_atomaddr(ErlNifEnv* env, ERL_NIF_TERM eAddr, @@ -5643,11 +5556,13 @@ char* decode_in4_sockaddr_atomaddr(ErlNifEnv* env, return NULL; } +*/ /* Decode an in4_sockaddr where the address field is a tuple. * Its *supposed* to be an ip4_address (tuple). */ +/* static char* decode_in4_sockaddr_addr(ErlNifEnv* env, ERL_NIF_TERM eAddr, @@ -5660,7 +5575,7 @@ char* decode_in4_sockaddr_addr(ErlNifEnv* env, int a, v; char addr[4]; - /* This shall be a 4 tuple */ + / * This shall be a 4 tuple * / if (!GET_TUPLE(env, eAddr, &ip4AddrTSz, &ip4AddrT)) return ESOCK_STR_EINVAL; @@ -5683,6 +5598,7 @@ char* decode_in4_sockaddr_addr(ErlNifEnv* env, return NULL; } +*/ @@ -5693,6 +5609,7 @@ char* decode_in4_sockaddr_addr(ErlNifEnv* env, * The forth, the flowinfo integer. * The fifth and final, the scope_id integer. */ +/* #if defined(HAVE_IN6) && defined(AF_INET6) static char* decode_in6_sockaddr(ErlNifEnv* env, @@ -5703,26 +5620,26 @@ char* decode_in6_sockaddr(ErlNifEnv* env, int port; unsigned int flowInfo, scopeId; - /* 1: Ensure that the tuple has the correct tag: in6_sockaddr */ + / * 1: Ensure that the tuple has the correct tag: in6_sockaddr * / if (COMPARE(atom_in6_sockaddr, eIn6SockAddr[0]) != 0) return ESOCK_STR_EINVAL; - /* 2: Get the port number */ + / * 2: Get the port number * / if (!GET_INT(env, eIn6SockAddr[1], &port)) return ESOCK_STR_EINVAL; - /* 4: Get the flowinfo */ + / * 4: Get the flowinfo * / if (!GET_UINT(env, eIn6SockAddr[3], &flowInfo)) return ESOCK_STR_EINVAL; - /* 5: Get the scope_id */ + / * 5: Get the scope_id * / if (!GET_UINT(env, eIn6SockAddr[4], &scopeId)) return ESOCK_STR_EINVAL; - /* 3: Get the address. + / * 3: Get the address. * It can either be the atoms: any | loopback, * or the IPv6 address tuple (size 8). - */ + * / if (IS_ATOM(env, eIn6SockAddr[2])) { return decode_in6_sockaddr_atomaddr(env, eIn6SockAddr[2], port, flowInfo, scopeId, @@ -5736,8 +5653,10 @@ char* decode_in6_sockaddr(ErlNifEnv* env, } } #endif +*/ +/* #if defined(HAVE_IN6) && defined(AF_INET6) static char* decode_in6_sockaddr_atomaddr(ErlNifEnv* env, @@ -5772,11 +5691,13 @@ char* decode_in6_sockaddr_atomaddr(ErlNifEnv* env, return NULL; } #endif +*/ #if defined(HAVE_IN6) && defined(AF_INET6) /* Decode an in6_sockaddr where the address field is a tuple */ +/* static char* decode_in6_sockaddr_addr(ErlNifEnv* env, ERL_NIF_TERM eAddr, @@ -5791,7 +5712,7 @@ char* decode_in6_sockaddr_addr(ErlNifEnv* env, int a, v; char addr[16]; - /* This shall be a 8 tuple */ + / * This shall be a 8 tuple * / if (!GET_TUPLE(env, eAddr, &ip6AddrTSz, &ip6AddrT)) return ESOCK_STR_EINVAL; @@ -5806,9 +5727,9 @@ char* decode_in6_sockaddr_addr(ErlNifEnv* env, sockAddrP->in6.sin6_port = sock_htons(port); sockAddrP->in6.sin6_flowinfo = flowInfo; sockAddrP->in6.sin6_scope_id = scopeId; - /* The address tuple is of size 8 + / * The address tuple is of size 8 * and each element is a two byte integer - */ + * / for (a = 0; a < 8; a++) { if (!GET_INT(env, ip6AddrT[a], &v)) return ESOCK_STR_EINVAL; @@ -5820,6 +5741,7 @@ char* decode_in6_sockaddr_addr(ErlNifEnv* env, return NULL; } +*/ #endif @@ -5912,6 +5834,7 @@ char* decode_address_tuple(ErlNifEnv* env, * Source: {Address, Port} | string() * */ +/* static void encode_address(ErlNifEnv* env, SocketAddress* sockAddrP, @@ -5923,7 +5846,7 @@ void encode_address(ErlNifEnv* env, switch (sockAddrP->sa.sa_family) { - /* +++ inet (IPv4) +++ */ + / * +++ inet (IPv4) +++ * / case AF_INET: if (addrLen >= sizeof(struct sockaddr_in)) { @@ -5948,7 +5871,7 @@ void encode_address(ErlNifEnv* env, break; - /* +++ inet6 (IPv6) +++ */ + / * +++ inet6 (IPv6) +++ * / #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: @@ -5959,9 +5882,9 @@ void encode_address(ErlNifEnv* env, char* a16 = (char*) &sockAddrP->in6.sin6_addr; port = sock_ntohs(sockAddrP->in6.sin6_port); - /* The address tuple is of size 8 + / * The address tuple is of size 8 * and each element is a two byte integer - */ + * / for (i = 0; i < 8; i++) { // at6[i] = MKI(env, get_int16(a16[i*2])); at6[i] = MKI(env, get_int16(a16 + i*2)); @@ -5980,7 +5903,7 @@ void encode_address(ErlNifEnv* env, break; #endif - /* +++ local (Unix Domain Sockets) +++ */ + / * +++ local (Unix Domain Sockets) +++ * / #ifdef HAVE_SYS_UN_H case AF_UNIX: @@ -5997,12 +5920,12 @@ void encode_address(ErlNifEnv* env, } else { m = my_strnlen(sockAddrP->un.sun_path, n); #ifdef __linux__ - /* Assume that the address is a zero terminated string, + / * Assume that the address is a zero terminated string, * except when the first byte is \0 i.e the string length is 0, * then use the reported length instead. * This fix handles Linux's nonportable * abstract socket address extension. - */ + * / if (m == 0) { m = n; } @@ -6020,9 +5943,10 @@ void encode_address(ErlNifEnv* env, *sourceT = esock_atom_undefined; break; - } /* switch (addrP->sa.sa_family) */ + } / * switch (addrP->sa.sa_family) * / } +*/ /* Decode the address when its an atom. @@ -7100,6 +7024,7 @@ char* decode_ip6_address(ErlNifEnv* env, #if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) /* strnlen doesn't exist everywhere */ +/* static size_t my_strnlen(const char *s, size_t maxlen) { @@ -7108,6 +7033,7 @@ size_t my_strnlen(const char *s, size_t maxlen) i++; return i; } +*/ #endif @@ -7439,7 +7365,7 @@ ErlNifFunc socket_funcs[] = // {"nif_debug", 1, nif_debug_, 0}, // The proper "socket" interface - // This is used when we already have a file descriptor + // nif_open/1 is used when we already have a file descriptor // {"nif_open", 1, nif_open, 0}, {"nif_open", 4, nif_open, 0}, {"nif_bind", 2, nif_bind, 0}, @@ -7608,7 +7534,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) esock_atom_any = MKA(env, "any"); esock_atom_dgram = MKA(env, "dgram"); esock_atom_error = MKA(env, "error"); - esock_atom_false = MKA(env, "famlse"); + esock_atom_false = MKA(env, "false"); esock_atom_family = MKA(env, "family"); esock_atom_flowinfo = MKA(env, "flowinfo"); esock_atom_inet = MKA(env, "inet"); diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index 37adee682b..05fb40e286 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -26,9 +26,23 @@ #include #include "socket_int.h" #include "socket_util.h" +#include "socket_dbg.h" #include "sys.h" +/* We don't have a "debug flag" to check here, so we + * should use the compile debug flag, whatever that is... + */ + +// #define COMPILE_DEBUG_FLAG_WE_NEED_TO_CHECK 1 +#if defined(COMPILE_DEBUG_FLAG_WE_NEED_TO_CHECK) +#define UTIL_DEBUG TRUE +#else +#define UTIL_DEBUG FALSE +#endif + +#define UDBG( proto ) ESOCK_DBG_PRINTF( UTIL_DEBUG , proto ) + extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ @@ -69,15 +83,19 @@ char* esock_decode_sockaddr(ErlNifEnv* env, int fam; char* xres; + UDBG( ("SUTIL", "esock_decode_sockaddr -> entry\r\n") ); + if (!IS_MAP(env, eSockAddr)) return ESOCK_STR_EINVAL; if (!GET_MAP_VAL(env, eSockAddr, esock_atom_family, &efam)) return ESOCK_STR_EINVAL; + UDBG( ("SUTIL", "esock_decode_sockaddr -> try decode domain (%T)\r\n", efam) ); if ((xres = esock_decode_domain(env, efam, &fam)) != NULL) return xres; + UDBG( ("SUTIL", "esock_decode_sockaddr -> fam: %d\r\n", fam) ); switch (fam) { case AF_INET: xres = esock_decode_sockaddr_in4(env, eSockAddr, @@ -147,7 +165,8 @@ char* esock_encode_sockaddr(ErlNifEnv* env, #endif default: - xres = ESOCK_STR_EAFNOSUPPORT; + *eSockAddr = esock_atom_undefined; + xres = ESOCK_STR_EAFNOSUPPORT; break; } @@ -178,6 +197,9 @@ char* esock_decode_sockaddr_in4(ErlNifEnv* env, { ERL_NIF_TERM eport, eaddr; int port; + char* xres; + + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> entry\r\n") ); /* Basic init */ sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in)); @@ -189,22 +211,28 @@ char* esock_decode_sockaddr_in4(ErlNifEnv* env, sockAddrP->sin_family = AF_INET; /* Extract (e) port number from map */ + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> try get port number\r\n") ); if (!GET_MAP_VAL(env, eSockAddr, esock_atom_port, &eport)) return ESOCK_STR_EINVAL; /* Decode port number */ + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> try decode port number\r\n") ); if (!GET_INT(env, eport, &port)) return ESOCK_STR_EINVAL; sockAddrP->sin_port = htons(port); /* Extract (e) address from map */ + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> try get (ip) address\r\n") ); if (!GET_MAP_VAL(env, eSockAddr, esock_atom_addr, &eaddr)) return ESOCK_STR_EINVAL; /* Decode address */ - if (!esock_decode_ip4_address(env, eaddr, sockAddrP, addrLen)) - return ESOCK_STR_EINVAL; + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> try decode (ip) address\r\n") ); + if ((xres = esock_decode_ip4_address(env, eaddr, sockAddrP, addrLen)) != NULL) + return xres; + + UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> done\r\n") ); return NULL; } @@ -232,6 +260,8 @@ char* esock_encode_sockaddr_in4(ErlNifEnv* env, int port; char* xres = NULL; + UDBG( ("SUTIL", "esock_encode_sockaddr_in4 -> entry\r\n") ); + if (addrLen >= sizeof(struct sockaddr_in)) { /* The port */ port = ntohs(sockAddrP->sin_port); @@ -239,15 +269,23 @@ char* esock_encode_sockaddr_in4(ErlNifEnv* env, /* The address */ if ((xres = esock_encode_ip4_address(env, &sockAddrP->sin_addr, - &eAddr)) != NULL) { + &eAddr)) == NULL) { /* And finally construct the in4_sockaddr record */ xres = make_sockaddr_in4(env, ePort, eAddr, eSockAddr); } else { + UDBG( ("SUTIL", "esock_encode_sockaddr_in4 -> " + "failed encoding (ip) address: " + "\r\n xres: %s" + "\r\n", xres) ); *eSockAddr = esock_atom_undefined; xres = ESOCK_STR_EINVAL; } } else { + UDBG( ("SUTIL", "esock_encode_sockaddr_in4 -> wrong size: " + "\r\n addrLen: %d" + "\r\n addr size: %d" + "\r\n", addrLen, sizeof(struct sockaddr_in)) ); *eSockAddr = esock_atom_undefined; xres = ESOCK_STR_EINVAL; } @@ -282,6 +320,7 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env, ERL_NIF_TERM eport, eaddr, eflowInfo, escopeId; int port; unsigned int flowInfo, scopeId; + char* xres; /* Basic init */ sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in6)); @@ -326,8 +365,8 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env, return ESOCK_STR_EINVAL; /* Decode address */ - if (!esock_decode_ip6_address(env, eaddr, sockAddrP, addrLen)) - return ESOCK_STR_EINVAL; + if ((xres = esock_decode_ip6_address(env, eaddr, sockAddrP, addrLen)) != NULL) + return xres; return NULL; } @@ -370,7 +409,7 @@ char* esock_encode_sockaddr_in6(ErlNifEnv* env, /* The address */ if ((xres = esock_encode_ip6_address(env, &sockAddrP->sin6_addr, - &eAddr)) != NULL) { + &eAddr)) == NULL) { /* And finally construct the in6_sockaddr record */ xres = make_sockaddr_in6(env, ePort, eAddr, eFlowInfo, eScopeId, eSockAddr); @@ -532,15 +571,22 @@ char* esock_decode_ip4_address(ErlNifEnv* env, struct sockaddr_in* sockAddrP, unsigned int* addrLen) { + UDBG( ("SUTIL", "esock_decode_ip4_address -> entry with" + "\r\n eAddr: %T" + "\r\n", eAddr) ); + if (IS_ATOM(env, eAddr)) { /* This is either 'any' or 'loopback' */ struct in_addr addr; if (COMPARE(esock_atom_loopback, eAddr) == 0) { + UDBG( ("SUTIL", "esock_decode_ip4_address -> address: lookback\r\n") ); addr.s_addr = htonl(INADDR_LOOPBACK); } else if (COMPARE(esock_atom_any, eAddr) == 0) { + UDBG( ("SUTIL", "esock_decode_ip4_address -> address: any\r\n") ); addr.s_addr = htonl(INADDR_ANY); } else { + UDBG( ("SUTIL", "esock_decode_ip4_address -> address: unknown\r\n") ); return ESOCK_STR_EINVAL; } @@ -596,13 +642,17 @@ char* esock_encode_ip4_address(ErlNifEnv* env, ERL_NIF_TERM at[4]; unsigned int atLen = sizeof(at) / sizeof(ERL_NIF_TERM); unsigned char* a = (unsigned char*) addrP; + ERL_NIF_TERM addr; /* The address */ for (i = 0; i < atLen; i++) { at[i] = MKI(env, a[i]); } - *eAddr = MKTA(env, at, atLen); + addr = MKTA(env, at, atLen); + UDBG( ("SUTIL", "esock_encode_ip4_address -> addr: %T\r\n", addr) ); + // *eAddr = MKTA(env, at, atLen); + *eAddr = addr; return NULL; } @@ -878,6 +928,108 @@ char* esock_encode_type(ErlNifEnv* env, +/* +++ esock_decode_protocol +++ + * + * Encode the native protocol to the Erlang form, that is: + * + * SOL_IP | IPPROTO_IP => ip + * SOL_IPV6 => ipv6 + * SOL_TCP => tcp + * SOL_UDP => udp + * SOL_SCTP => sctp + * + */ +extern +char* esock_encode_protocol(ErlNifEnv* env, + int proto, + ERL_NIF_TERM* eProto) +{ + char* xres = NULL; + + switch (proto) { +#if defined(SOL_IP) + case SOL_IP: +#else + case IPPROTO_IP: +#endif + *eProto = esock_atom_ip; + break; + +#if defined(SOL_IPV6) + case SOL_IPV6: + *eProto = esock_atom_ipv6; + break; +#endif + + case IPPROTO_TCP: + *eProto = esock_atom_tcp; + break; + + case IPPROTO_UDP: + *eProto = esock_atom_udp; + break; + +#if defined(HAVE_SCTP) + case IPPROTO_SCTP: + *eProto = esock_atom_sctp; + break; +#endif + + default: + *eProto = esock_atom_undefined; + xres = ESOCK_STR_EAFNOSUPPORT; + break; + } + + return xres; +} + + + +/* +++ esock_decode_protocol +++ + * + * Decode the Erlang form of the 'protocol' type, that is: + * + * ip => SOL_IP | IPPROTO_IP + * ipv6 => SOL_IPV6 + * tcp => SOL_TCP + * udp => SOL_UDP + * sctp => SOL_SCTP + * + */ +extern +char* esock_decode_protocol(ErlNifEnv* env, + ERL_NIF_TERM eProto, + int* proto) +{ + char* xres = NULL; + + if (COMPARE(esock_atom_ip, eProto) == 0) { +#if defined(SOL_IP) + *proto = SOL_IP; +#else + *proto = IPPROTO_IP; +#endif + } else if (COMPARE(esock_atom_ipv6, eProto) == 0) { + *proto = SOL_IPV6; + } else if (COMPARE(esock_atom_tcp, eProto) == 0) { + *proto = IPPROTO_TCP; + } else if (COMPARE(esock_atom_udp, eProto) == 0) { + *proto = IPPROTO_UDP; +#if defined(HAVE_SCTP) + } else if (COMPARE(esock_atom_sctp, eProto) == 0) { + *proto = IPPROTO_SCTP; +#endif + } else { + *proto = -1; + xres = ESOCK_STR_EAFNOSUPPORT; + } + + return xres; +} + + + /* *** esock_decode_bool *** * * Decode a boolean value. diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h index f5594c408e..dedeb8dd7d 100644 --- a/erts/emulator/nifs/common/socket_util.h +++ b/erts/emulator/nifs/common/socket_util.h @@ -110,7 +110,6 @@ extern char* esock_decode_domain(ErlNifEnv* env, ERL_NIF_TERM eDomain, int* domain); - extern char* esock_encode_domain(ErlNifEnv* env, int domain, @@ -120,12 +119,20 @@ extern char* esock_decode_type(ErlNifEnv* env, ERL_NIF_TERM eType, int* type); - extern char* esock_encode_type(ErlNifEnv* env, int type, ERL_NIF_TERM* eType); +extern +char* esock_decode_protocol(ErlNifEnv* env, + ERL_NIF_TERM eProtocol, + int* protocol); +extern +char* esock_encode_protocol(ErlNifEnv* env, + int type, + ERL_NIF_TERM* eProtocol); + extern BOOLEAN_T esock_decode_bool(ERL_NIF_TERM val); extern diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam index cafd5af945..f82db6e44e 100644 Binary files a/erts/preloaded/ebin/socket.beam and b/erts/preloaded/ebin/socket.beam differ diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl index b89fa06da8..ba3ff6bab9 100644 --- a/erts/preloaded/src/socket.erl +++ b/erts/preloaded/src/socket.erl @@ -657,7 +657,7 @@ open(Domain, Type, Protocol0, Extra) when is_map(Extra) -> end. %% Note that this is just a convenience function for when the protocol was -%% not specified. If its actually specied, then that will be selected. +%% not specified. If its actually specified, then that will be selected. %% Also, this only works for the some of the type's (stream, dgram and %% seqpacket). default_protocol(null, stream) -> tcp; @@ -677,57 +677,22 @@ default_protocol(Protocol, _) -> Protocol. Addr :: any | loopback | sockaddr(), Reason :: term(). -bind(#socket{info = #{domain := inet}} = Socket, Addr) +bind(#socket{ref = SockRef, info = #{domain := inet}} = _Socket, Addr) when ((Addr =:= any) orelse (Addr =:= loopback)) -> - bind(Socket, ?SOCKADDR_IN4_DEFAULT(Addr)); -bind(#socket{info = #{domain := inet6}} = Socket, Addr) + nif_bind(SockRef, ?SOCKADDR_IN4_DEFAULT(Addr)); +bind(#socket{ref = SockRef, info = #{domain := inet6}} = _Socket, Addr) when ((Addr =:= any) orelse (Addr =:= loopback)) -> - bind(Socket, ?SOCKADDR_IN6_DEFAULT(Addr)); -bind(Socket, Addr) -> + nif_bind(SockRef, ?SOCKADDR_IN6_DEFAULT(Addr)); +bind(#socket{ref = SockRef} = _Socket, Addr) when is_map(Addr) -> try begin - nif_bind(Socket, ensure_sockaddr(Addr)) + nif_bind(SockRef, ensure_sockaddr(Addr)) end catch throw:ERROR -> ERROR end. -%% -spec bind(Socket, FileOrAddr) -> ok | {error, Reason} when -%% Socket :: socket(), -%% FileOrAddr :: binary() | string() | in_sockaddr() | any | loopback, -%% Reason :: term(). - -%% bind(Socket, File) when is_binary(File) -> -%% if -%% byte_size(File) =:= 0 -> -%% {error, einval}; -%% byte_size(File) =< 255 -> -%% nif_bind(Socket, File); -%% true -> -%% {error, einval} -%% end; -%% bind(Socket, File) when is_list(File) andalso (File =/= []) -> -%% Bin = unicode:characters_to_binary(File, file:native_name_encoding()), -%% if -%% byte_size(Bin) =< 255 -> -%% nif_bind(Socket, Bin); -%% true -> -%% {error, einval} -%% end; -%% bind(#socket{info = #{domain := inet}} = Socket, Addr) -%% when ((Addr =:= any) orelse (Addr =:= loopback)) -> -%% bind(Socket, #in4_sockaddr{addr = Addr}); -%% bind(#socket{info = #{domain := inet6}} = Socket, Addr) -%% when ((Addr =:= any) orelse (Addr =:= loopback)) -> -%% bind(Socket, #in6_sockaddr{addr = Addr}); -%% bind(#socket{info = #{domain := inet}, ref = SockRef} = _Socket, SockAddr) -%% when is_record(SockAddr, in4_sockaddr) -> -%% nif_bind(SockRef, SockAddr); -%% bind(#socket{info = #{domain := inet6}, ref = SockRef} = _Socket, SockAddr) -%% when is_record(SockAddr, in6_sockaddr) -> -%% nif_bind(SockRef, SockAddr). - %% =========================================================================== @@ -749,6 +714,9 @@ connect(Socket, SockAddr) -> Timeout :: timeout(), Reason :: term(). +%% +%% Is it possible to connect with family = local for the (dest) sockaddr? +%% connect(_Socket, _SockAddr, Timeout) when (is_integer(Timeout) andalso (Timeout =< 0)) -> {error, timeout}; @@ -970,9 +938,9 @@ sendto(Socket, Data, Flags, Dest) -> Timeout :: timeout(), Reason :: term(). -sendto(Socket, Data, Flags, DestSockAddr, Timeout) when is_list(Data) -> +sendto(Socket, Data, Flags, Dest, Timeout) when is_list(Data) -> Bin = erlang:list_to_binary(Data), - sendto(Socket, Bin, Flags, DestSockAddr, Timeout); + sendto(Socket, Bin, Flags, Dest, Timeout); sendto(#socket{ref = SockRef}, Data, Flags, Dest, Timeout) when is_binary(Data) andalso is_list(Flags) andalso -- cgit v1.2.3