summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaimo Niskanen <raimo@erlang.org>2021-08-05 17:50:14 +0200
committerRaimo Niskanen <raimo@erlang.org>2021-08-30 14:27:36 +0200
commit9b9cd6e6ac8919e90f5a265c6081e7f04223bb7e (patch)
tree22effd1a1c774c22568f5d110a95560f169acd59
parent22dfa830724a3f3c84f5a2dd003ef8cf0d85e3d0 (diff)
downloaderlang-9b9cd6e6ac8919e90f5a265c6081e7f04223bb7e.tar.gz
Implement setting native socket addresses
-rw-r--r--erts/emulator/nifs/common/prim_socket_nif.c6
-rw-r--r--erts/emulator/nifs/common/socket_util.c134
-rw-r--r--erts/emulator/nifs/common/socket_util.h8
-rw-r--r--erts/preloaded/ebin/prim_socket.beambin31544 -> 31676 bytes
-rw-r--r--erts/preloaded/src/prim_socket.erl4
-rw-r--r--lib/kernel/doc/src/socket.xml6
-rw-r--r--lib/kernel/src/socket.erl18
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
--- a/erts/preloaded/ebin/prim_socket.beam
+++ b/erts/preloaded/ebin/prim_socket.beam
Binary files 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
@@ -250,6 +250,10 @@
<desc></desc>
</datatype>
<datatype>
+ <name name="sockaddr_recv"/>
+ <desc></desc>
+ </datatype>
+ <datatype>
<name name="sockaddr_in"/>
<desc></desc>
</datatype>
@@ -288,7 +292,7 @@
<desc></desc>
</datatype>
<datatype>
- <name name="sockaddr_recv"/>
+ <name name="sockaddr_native"/>
<desc></desc>
</datatype>
<datatype>
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).