From 9b9cd6e6ac8919e90f5a265c6081e7f04223bb7e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 5 Aug 2021 17:50:14 +0200 Subject: Implement setting native socket addresses --- erts/emulator/nifs/common/prim_socket_nif.c | 6 +- erts/emulator/nifs/common/socket_util.c | 134 +++++++++++++++++++++------- erts/emulator/nifs/common/socket_util.h | 8 +- erts/preloaded/ebin/prim_socket.beam | Bin 31544 -> 31676 bytes erts/preloaded/src/prim_socket.erl | 4 + lib/kernel/doc/src/socket.xml | 6 +- lib/kernel/src/socket.erl | 18 ++-- 7 files changed, 129 insertions(+), 47 deletions(-) diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index 2c0359f528..51c601d340 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -5013,7 +5013,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, "\r\n eopts: %T" "\r\n", argv[0], argv[1], argv[2], eopts) ); - if (! esock_decode_domain(env, edomain, &domain)) { + if (esock_decode_domain(env, edomain, &domain) == 0) { SGDBG( ("SOCKET", "nif_open -> invalid domain: %d\r\n", edomain) ); return esock_make_invalid(env, esock_atom_domain); @@ -5229,7 +5229,7 @@ BOOLEAN_T esock_open2_get_domain(ErlNifEnv* env, esock_atom_domain, &edomain)) return FALSE; - if (! esock_decode_domain(env, edomain, domain)) + if (esock_decode_domain(env, edomain, domain) == 0) return FALSE; return TRUE; @@ -10032,7 +10032,7 @@ ERL_NIF_TERM esock_setopt_addrform(ErlNifEnv* env, "\r\n eVal: %T" "\r\n", eVal) ); - if (! esock_decode_domain(env, eVal, &domain)) + if (esock_decode_domain(env, eVal, &domain) == 0) return esock_make_invalid(env, atom_value); SSDBG( descP, ("SOCKET", 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; diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h index 8d35d3c06d..61b237383c 100644 --- a/erts/emulator/nifs/common/socket_util.h +++ b/erts/emulator/nifs/common/socket_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2018-2020. All Rights Reserved. + * Copyright Ericsson AB 2018-2021. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,9 +152,9 @@ void esock_encode_domain(ErlNifEnv* env, int domain, ERL_NIF_TERM* eDomain); 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); extern BOOLEAN_T esock_decode_type(ErlNifEnv* env, diff --git a/erts/preloaded/ebin/prim_socket.beam b/erts/preloaded/ebin/prim_socket.beam index e73b8f067d..6436d32114 100644 Binary files a/erts/preloaded/ebin/prim_socket.beam and b/erts/preloaded/ebin/prim_socket.beam differ diff --git a/erts/preloaded/src/prim_socket.erl b/erts/preloaded/src/prim_socket.erl index 5b72841a32..5ad8cdffd3 100644 --- a/erts/preloaded/src/prim_socket.erl +++ b/erts/preloaded/src/prim_socket.erl @@ -63,6 +63,8 @@ -define(ESOCK_SOCKADDR_IN6_DEFAULTS, (#{port => 0, addr => any, flowinfo => 0, scope_id => 0})). +-define(ESOCK_SOCKADDR_NATIVE_DEFAULTS, + (#{addr => <<>>})). %% =========================================================================== %% @@ -835,6 +837,8 @@ enc_sockaddr(#{family := local, path := Path} = SockAddr) -> enc_sockaddr(#{family := local} = SockAddr) -> %% Neater than a function clause erlang:error({invalid, {sockaddr, path, SockAddr}}); +enc_sockaddr(#{family := Native} = SockAddr) when is_integer(Native) -> + maps:merge(?ESOCK_SOCKADDR_NATIVE_DEFAULTS, SockAddr); enc_sockaddr(#{family := _} = SockAddr) -> SockAddr; enc_sockaddr(SockAddr) -> diff --git a/lib/kernel/doc/src/socket.xml b/lib/kernel/doc/src/socket.xml index 548580381c..c9a6866f3e 100644 --- a/lib/kernel/doc/src/socket.xml +++ b/lib/kernel/doc/src/socket.xml @@ -249,6 +249,10 @@ + + + + @@ -288,7 +292,7 @@ - + diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl index a5c27339b8..295fd37782 100644 --- a/lib/kernel/src/socket.erl +++ b/lib/kernel/src/socket.erl @@ -102,6 +102,7 @@ sockaddr_in6/0, sockaddr_un/0, sockaddr_ll/0, + sockaddr_native/0, msg_flag/0, @@ -307,6 +308,10 @@ max := 0..16#ffffffff, min := 0..16#ffffffff}. +-type packet_type() :: host | broadcast | multicast | otherhost | + outgoing | loopback | user | kernel | fastroute | + non_neg_integer(). + -type sockaddr_un() :: #{family := local, path := binary() | string()}. -type sockaddr_in() :: #{family := inet, @@ -324,18 +329,15 @@ pkttype := packet_type(), hatype := non_neg_integer(), addr := binary()}. --type packet_type() :: host | broadcast | multicast | otherhost | - outgoing | loopback | user | kernel | fastroute | - non_neg_integer(). --type sockaddr() :: sockaddr_in() | +-type sockaddr_native() :: #{family := integer(), addr := binary()}. +-type sockaddr() :: sockaddr_in() | sockaddr_in6() | sockaddr_un() | - sockaddr_ll(). + sockaddr_ll() | + sockaddr_native(). -type sockaddr_recv() :: - sockaddr() | - #{family := integer(), addr := binary()} | - binary(). + sockaddr() | binary(). %% (otp) - This option is internal to our (OTP) implementation. %% socket - The socket layer (SOL_SOCKET). -- cgit v1.2.1