diff options
Diffstat (limited to 'erts/emulator/nifs/common/socket_util.c')
-rw-r--r-- | erts/emulator/nifs/common/socket_util.c | 134 |
1 files changed, 103 insertions, 31 deletions
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index d03a593238..d01eb7da26 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -65,17 +65,24 @@ extern char* erl_errno_id(int error); /* THIS IS JUST TEMPORARY??? */ #if (defined(HAVE_LOCALTIME_R) && defined(HAVE_STRFTIME)) #define ESOCK_USE_PRETTY_TIMESTAMP 1 #endif - + + +static +BOOLEAN_T esock_decode_sockaddr_native(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + ESockAddress* sockAddrP, + int family, + SOCKLEN_T* addrLen); static void esock_encode_packet_addr_tuple(ErlNifEnv* env, unsigned char len, unsigned char* addr, ERL_NIF_TERM* eAddr); -static void esock_encode_sockaddr_unknown(ErlNifEnv* env, - struct sockaddr* sa, - SOCKLEN_T len, - ERL_NIF_TERM* eSockAddr); +static void esock_encode_sockaddr_native(ErlNifEnv* env, + struct sockaddr* sa, + SOCKLEN_T len, + ERL_NIF_TERM* eSockAddr); static void esock_encode_sockaddr_broken(ErlNifEnv* env, struct sockaddr* sa, @@ -284,9 +291,10 @@ extern BOOLEAN_T esock_decode_sockaddr(ErlNifEnv* env, ERL_NIF_TERM eSockAddr, ESockAddress* sockAddrP, - SOCKLEN_T* addrLen) + SOCKLEN_T* addrLenP) { ERL_NIF_TERM efam; + int decode; int fam; UDBG( ("SUTIL", "esock_decode_sockaddr -> entry\r\n") ); @@ -300,25 +308,30 @@ BOOLEAN_T esock_decode_sockaddr(ErlNifEnv* env, UDBG( ("SUTIL", "esock_decode_sockaddr -> try decode domain (%T)\r\n", efam) ); - if (! esock_decode_domain(env, efam, &fam)) + decode = esock_decode_domain(env, efam, &fam); + if (0 >= decode) { + if (0 > decode) + return esock_decode_sockaddr_native(env, eSockAddr, sockAddrP, + fam, addrLenP); return FALSE; + } UDBG( ("SUTIL", "esock_decode_sockaddr -> fam: %d\r\n", fam) ); switch (fam) { case AF_INET: return esock_decode_sockaddr_in(env, eSockAddr, - &sockAddrP->in4, addrLen); + &sockAddrP->in4, addrLenP); #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: return esock_decode_sockaddr_in6(env, eSockAddr, - &sockAddrP->in6, addrLen); + &sockAddrP->in6, addrLenP); #endif #ifdef HAS_AF_LOCAL case AF_LOCAL: return esock_decode_sockaddr_un(env, eSockAddr, - &sockAddrP->un, addrLen); + &sockAddrP->un, addrLenP); #endif default: @@ -386,7 +399,7 @@ void esock_encode_sockaddr(ErlNifEnv* env, #endif default: - esock_encode_sockaddr_unknown(env, &sockAddrP->sa, addrLen, eSockAddr); + esock_encode_sockaddr_native(env, &sockAddrP->sa, addrLen, eSockAddr); break; } } @@ -498,8 +511,8 @@ void esock_encode_sockaddr_in(ErlNifEnv* env, "\r\n addrLen: %d" "\r\n addr size: %d" "\r\n", addrLen, sizeof(struct sockaddr_in)) ); - esock_encode_sockaddr_unknown(env, (struct sockaddr *)sockAddrP, - addrLen, eSockAddr); + esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, + addrLen, eSockAddr); } } @@ -638,8 +651,8 @@ void esock_encode_sockaddr_in6(ErlNifEnv* env, eFlowInfo, eScopeId, eSockAddr); } else { - esock_encode_sockaddr_unknown(env, (struct sockaddr *)sockAddrP, - addrLen, eSockAddr); + esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, + addrLen, eSockAddr); } } #endif @@ -766,8 +779,8 @@ void esock_encode_sockaddr_un(ErlNifEnv* env, make_sockaddr_un(env, ePath, eSockAddr); } } else { - esock_encode_sockaddr_unknown(env, (struct sockaddr *)sockAddrP, - addrLen, eSockAddr); + esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, + addrLen, eSockAddr); } } #endif @@ -823,8 +836,8 @@ void esock_encode_sockaddr_ll(ErlNifEnv* env, eSockAddr); } else { - esock_encode_sockaddr_unknown(env, (struct sockaddr *)sockAddrP, - addrLen, eSockAddr); + esock_encode_sockaddr_native(env, (struct sockaddr *)sockAddrP, + addrLen, eSockAddr); } } #endif @@ -1131,15 +1144,21 @@ BOOLEAN_T esock_decode_timeval(ErlNifEnv* env, * * Decode the Erlang form of the 'domain' type, that is: * + * Return 1: * inet => AF_INET * inet6 => AF_INET6 * local => AF_LOCAL * + * Return -1: + * Int => Int + * + * Otherwise return 0. + * */ extern -BOOLEAN_T esock_decode_domain(ErlNifEnv* env, - ERL_NIF_TERM eDomain, - int* domain) +int esock_decode_domain(ErlNifEnv* env, + ERL_NIF_TERM eDomain, + int* domain) { if (COMPARE(esock_atom_inet, eDomain) == 0) { *domain = AF_INET; @@ -1155,15 +1174,17 @@ BOOLEAN_T esock_decode_domain(ErlNifEnv* env, #endif } else { - int d = 0; + int d; - if (GET_INT(env, eDomain, &d)) + d = 0; + if (GET_INT(env, eDomain, &d)) { *domain = d; - else - return FALSE; + return -1; + } + return 0; } - return TRUE; + return 1; } @@ -1470,15 +1491,66 @@ void esock_encode_packet_addr_tuple(ErlNifEnv* env, +/* +++ esock_decode_sockaddr_native +++ + * + * Decode a general sockaddr of unknown domain, within Erlang + * represented as a map, which has a specific set of attributes + * (beside the mandatory family attribute, which is "inherited" from + * the "sockaddr" type): + * + * addr :: binary() + * + * The erlang module ensures that this value exist, so there + * is no need for any elaborate error handling here. + */ + +static +BOOLEAN_T esock_decode_sockaddr_native(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + ESockAddress* sockAddrP, + int family, + SOCKLEN_T* addrLen) +{ + ErlNifBinary bin; + ERL_NIF_TERM eAddr; + SOCKLEN_T len; + + /* *** Extract (e) Addr (a binary) from map *** */ + if (! GET_MAP_VAL(env, eSockAddr, esock_atom_addr, &eAddr)) + return FALSE; + + /* Get the address */ + if (! GET_BIN(env, eAddr, &bin)) + return FALSE; + + len = sizeof(*sockAddrP) - + (CHARP(sockAddrP->sa.sa_data) - CHARP(sockAddrP)); // Max addr size + if ((size_t)len < bin.size) + return FALSE; + + sys_memzero((char*) sockAddrP, sizeof(*sockAddrP)); + sockAddrP->sa.sa_family = (sa_family_t) family; + sys_memcpy(sockAddrP->sa.sa_data, bin.data, bin.size); + len = (sockAddrP->sa.sa_data - CHARP(sockAddrP)) + bin.size; +#ifndef NO_SA_LEN + sockAddrP->sa.sa_len = len; +#endif + *addrLen = len; + + return TRUE; +} + + + /* Encode as #{family := integer(), addr := binary()} * assuming at least the ->family field can be accessed * and hence at least 0 bytes of address */ static -void esock_encode_sockaddr_unknown(ErlNifEnv* env, - struct sockaddr* addr, - SOCKLEN_T len, - ERL_NIF_TERM* eSockAddr) +void esock_encode_sockaddr_native(ErlNifEnv* env, + struct sockaddr* addr, + SOCKLEN_T len, + ERL_NIF_TERM* eSockAddr) { size_t size; ERL_NIF_TERM eFamily, eData; |