aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/nifs/common/socket_nif.c518
-rw-r--r--erts/emulator/nifs/common/socket_util.c83
-rw-r--r--erts/emulator/nifs/common/socket_util.h18
-rw-r--r--erts/preloaded/ebin/socket.beambin43884 -> 44012 bytes
-rw-r--r--erts/preloaded/src/socket.erl9
-rw-r--r--lib/kernel/test/socket_client.erl77
-rw-r--r--lib/kernel/test/socket_server.erl22
7 files changed, 255 insertions, 472 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index f73364f28f..05ba9e55f1 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -362,6 +362,7 @@ typedef union {
#define SOCKET_OPT_SOCK_SNDBUF 27
#define SOCKET_OPT_SOCK_TYPE 32
+#define SOCKET_OPT_IP_MULTICAST_IF 14
#define SOCKET_OPT_IP_MULTICAST_LOOP 15
#define SOCKET_OPT_IP_MULTICAST_TTL 16
#define SOCKET_OPT_IP_RECVTOS 25
@@ -845,6 +846,11 @@ static ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt,
ERL_NIF_TERM eVal);
+#if defined(IP_MULTICAST_IF)
+static ERL_NIF_TERM nsetopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IP_MULTICAST_LOOP)
static ERL_NIF_TERM nsetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1023,6 +1029,10 @@ static ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt);
+#if defined(IP_MULTICAST_IF)
+static ERL_NIF_TERM ngetopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(IP_MULTICAST_LOOP)
static ERL_NIF_TERM ngetopt_lvl_ip_multicast_loop(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1974,6 +1984,8 @@ ERL_NIF_TERM nbind(ErlNifEnv* env,
return esock_make_error_errno(env, sock_errno());
}
+ SSDBG( descP, ("SOCKET", "nbind -> bound - get port\r\n") );
+
port = which_address_port(sockAddrP);
SSDBG( descP, ("SOCKET", "nbind -> port: %d\r\n", port) );
if (port == 0) {
@@ -3646,7 +3658,7 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
int res = socket_setopt(descP->sock, level, opt,
val.data, val.size);
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
} else {
@@ -3866,7 +3878,7 @@ ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env,
int res = socket_setopt(descP->sock, SOL_SOCKET, SO_LINGER,
(void*) &val, optLen);
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
} else {
@@ -3956,6 +3968,12 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
ERL_NIF_TERM result;
switch (eOpt) {
+#if defined(IP_MULTICAST_IF)
+ case SOCKET_OPT_IP_MULTICAST_IF:
+ result = nsetopt_lvl_ip_multicast_if(env, descP, eVal);
+ break;
+#endif
+
#if defined(IP_MULTICAST_LOOP)
case SOCKET_OPT_IP_MULTICAST_LOOP:
result = nsetopt_lvl_ip_multicast_loop(env, descP, eVal);
@@ -4001,6 +4019,45 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env,
}
+/* nsetopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
+ *
+ * The value is either the atom 'any' or a 4-tuple.
+ */
+#if defined(IP_MULTICAST_IF)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ struct in_addr ifAddr;
+ char* xres;
+ int res;
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+
+ if ((xres = esock_decode_ip4_address(env, eVal, &ifAddr)) != NULL) {
+ result = esock_make_error_str(env, xres);
+ } else {
+
+ res = socket_setopt(descP->sock, level, IP_MULTICAST_LOOP,
+ &ifAddr, sizeof(ifAddr));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ }
+
+ return result;
+}
+#endif
+
+
/* nsetopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
*/
#if defined(IP_MULTICAST_LOOP)
@@ -4097,7 +4154,7 @@ ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env,
int res = socket_setopt(descP->sock, level, IP_TOS, &val, sizeof(val));
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
@@ -4376,7 +4433,7 @@ ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env,
int res = socket_setopt(descP->sock, level, opt, &val, optLen);
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
@@ -4409,7 +4466,7 @@ ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env,
res = socket_setopt(descP->sock, level, opt, &ival, sizeof(ival));
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
@@ -4789,7 +4846,7 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
if (valueSz == 0) {
res = sock_getopt(descP->sock, level, opt, NULL, NULL);
if (res != 0)
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
else
result = esock_atom_ok;
} else {
@@ -4798,7 +4855,7 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env,
if (ALLOC_BIN(valueSz, &val)) {
res = sock_getopt(descP->sock, level, opt, val.data, &valueSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
if (valueSz < val.size) {
if (REALLOC_BIN(&val, valueSz)) {
@@ -5023,7 +5080,7 @@ ERL_NIF_TERM ngetopt_lvl_sock_domain(ErlNifEnv* env,
&val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
switch (val) {
case AF_INET:
@@ -5090,7 +5147,7 @@ ERL_NIF_TERM ngetopt_lvl_sock_linger(ErlNifEnv* env,
&val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
ERL_NIF_TERM lOnOff = ((val.l_onoff) ? atom_true : atom_false);
ERL_NIF_TERM lSecs = MKI(env, val.l_linger);
@@ -5148,7 +5205,7 @@ ERL_NIF_TERM ngetopt_lvl_sock_protocol(ErlNifEnv* env,
&val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
switch (val) {
case IPPROTO_IP:
@@ -5224,7 +5281,7 @@ ERL_NIF_TERM ngetopt_lvl_sock_type(ErlNifEnv* env,
res = sock_getopt(descP->sock, SOL_SOCKET, SO_TYPE, &val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
switch (val) {
case SOCK_STREAM:
@@ -5266,6 +5323,12 @@ ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
ERL_NIF_TERM result;
switch (eOpt) {
+#if defined(IP_MULTICAST_IF)
+ case SOCKET_OPT_IP_MULTICAST_IF:
+ result = ngetopt_lvl_ip_multicast_if(env, descP);
+ break;
+#endif
+
#if defined(IP_MULTICAST_LOOP)
case SOCKET_OPT_IP_MULTICAST_LOOP:
result = ngetopt_lvl_ip_multicast_loop(env, descP);
@@ -5311,6 +5374,43 @@ ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env,
}
+/* ngetopt_lvl_ip_multicast_if - Level IP MULTICAST_IF option
+ */
+#if defined(IP_MULTICAST_IF)
+static
+ERL_NIF_TERM ngetopt_lvl_ip_multicast_if(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eAddr;
+ struct in_addr ifAddr;
+ SOCKOPTLEN_T ifAddrSz = sizeof(ifAddr);
+ char* xres;
+ int res;
+#if defined(SOL_IP)
+ int level = SOL_IP;
+#else
+ int level = IPPROTO_IP;
+#endif
+
+ res = sock_getopt(descP->sock, level, IP_MULTICAST_IF, &ifAddr, &ifAddrSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ if ((xres = esock_encode_ip4_address(env, &ifAddr, &eAddr)) != NULL) {
+ result = esock_make_error_str(env, xres);
+ } else {
+ result = esock_make_ok2(env, eAddr);
+ }
+ }
+
+ return result;
+
+}
+#endif
+
+
/* ngetopt_lvl_ip_multicast_loop - Level IP MULTICAST_LOOP option
*/
#if defined(IP_MULTICAST_LOOP)
@@ -5403,7 +5503,7 @@ ERL_NIF_TERM ngetopt_lvl_ip_tos(ErlNifEnv* env,
res = sock_getopt(descP->sock, level, IP_TOS, &val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
result = encode_ip_tos(env, val);
}
@@ -5663,7 +5763,7 @@ ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env,
res = sock_getopt(descP->sock, level, opt, &val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
ERL_NIF_TERM sval = MKSL(env, val, valSz);
@@ -5692,7 +5792,7 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env,
res = sock_getopt(descP->sock, level, opt, &val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
ERL_NIF_TERM bval = ((val) ? atom_true : atom_false);
@@ -5719,7 +5819,7 @@ ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env,
res = sock_getopt(descP->sock, level, opt, &val, &valSz);
if (res != 0) {
- result = esock_make_error_errno(env, res);
+ result = esock_make_error_errno(env, sock_errno());
} else {
result = esock_make_ok2(env, MKI(env, val));
}
@@ -6936,394 +7036,6 @@ BOOLEAN_T ehow2how(unsigned int ehow, int* how)
-/* +++ decode_sockaddr +++
- *
- * Decode a socket address - sockaddr. In erlang its represented by
- * a map, which has a specific set of attributes, depending on one
- * mandatory attribute; family. So depending on the value of the family
- * attribute:
- *
- * local - sockaddr_un: path
- * inet - sockaddr_in4: port, addr
- * inet6 - sockaddr_in6: port, addr, flowinfo, scope_id
- */
-/*
-static
-char* decode_sockaddr(ErlNifEnv* env,
- ERL_NIF_TERM eSockAddr,
- SocketAddress* sockAddrP,
- unsigned int* addrLen)
-{
- ERL_NIF_TERM efam;
- int fam;
- char* res;
-
- if (!IS_MAP(env, eSockAddr))
- return ESOCK_STR_EINVAL;
-
- if (!GET_MAP_VAL(env, eSockAddr, esock_atom_family, &efam))
- return ESOCK_STR_EINVAL;
-
- if (!decode_domain(env, efam, &fam))
- return ESOCK_STR_EINVAL;
-
- switch (fam) {
- case AF_INET:
- res = decode_sockaddr_in4(env, eSockAddr, &sockAddrP->in6, addrLen);
- break;
-
-#if defined(HAVE_IN6) && defined(AF_INET6)
- case AF_INET6:
- res = decode_sockaddr_in6(env, eSockAddr, &sockAddrP->in6, addrLen);
- break;
-#endif
-
-#ifdef HAVE_SYS_UN_H
- case AF_UNIX:
- res = decode_sockaddr_un(env, eSockAddr, &sockAddrP->un, addrLen);
- break;
-#endif
-
- default:
- result = ESOCK_STR_EAFNOSUPPORT;
- break;
-
- }
-
- return res;
-}
-*/
-
-
-
-/* +++ decode_sockaddr_in4 +++
- *
- * Decode a IPv4 socket address - sockaddr_in4. In erlang its represented by
- * a map, which has a specific set of attributes:
- *
- * port :: port_numbber()
- * addr :: ip4_address()
- *
- * The erlang module ensures that both of these has values exist, so there
- * is no need for any elaborate error handling.
- */
-/*
-static
-char* decode_sockaddr_in4(ErlNifEnv* env,
- ERL_NIF_TERM eSockAddr,
- struct sockaddr_in* sockAddrP,
- unsigned int* addrLen)
-{
- ERL_NIF_TERM eport, eaddr;
- short port;
-
- / * Basic init * /
- sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in));
-
-#ifndef NO_SA_LEN
- sockAddrP->sin_len = sizeof(struct sockaddr_in);
-#endif
-
- sockAddrP->sin_family = AF_INET;
-
- / * Extract (e) port number from map * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_port, &eport))
- return ESOCK_STR_EINVAL;
-
- / * Decode port number * /
- if (!GET_INT(env, eport, &port))
- return ESOCK_STR_EINVAL;
- sockAddrP->sin_port = sock_htons(port);
-
- / * Extract (e) address from map * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_addr, &eaddr))
- return ESOCK_STR_EINVAL;
-
- / * Decode address * /
- if (!decode_ip4_address(env, eaddr, sockAddrP, addrLen))
- return ESOCK_STR_EINVAL;
-
- return NULL;
-}
-*/
-
-
-
-/* +++ decode_sockaddr_in6 +++
- *
- * Decode a IPv6 socket address - sockaddr_in6. In erlang its represented by
- * a map, which has a specific set of attributes:
- *
- * port :: port_numbber() (integer)
- * addr :: ip6_address() (tuple)
- * flowinfo :: in6_flow_info() (integer)
- * scope_id :: in6_scope_id() (integer)
- *
- * The erlang module ensures that all of these has values exist, so there
- * is no need for any elaborate error handling.
- */
-/*
-#if defined(HAVE_IN6) && defined(AF_INET6)
-static
-char* decode_sockaddr_in6(ErlNifEnv* env,
- ERL_NIF_TERM eSockAddr,
- struct sockaddr_in6* sockAddrP,
- unsigned int* addrLen)
-{
- ERL_NIF_TERM eport, eaddr;
- short port;
-
- / * Basic init * /
- sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in6));
-#ifndef NO_SA_LEN
- sockAddrP->sin6_len = sizeof(struct sockaddr_in);
-#endif
-
- sockAddrP->sin6_family = AF_INET6;
-
- / * *** Extract (e) port number from map *** * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_port, &eport))
- return ESOCK_STR_EINVAL;
-
- / * Decode port number * /
- if (!GET_INT(env, eport, &port))
- return ESOCK_STR_EINVAL;
-
- sockAddrP->sin6_port = sock_htons(port);
-
- / * *** Extract (e) flowinfo from map *** * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_flowinfo, &eflowInfo))
- return ESOCK_STR_EINVAL;
-
- / * 4: Get the flowinfo * /
- if (!GET_UINT(env, eflowInfo, &flowInfo))
- return ESOCK_STR_EINVAL;
-
- sockAddrP->sin6_flowinfo = flowInfo;
-
- / * *** Extract (e) scope_id from map *** * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_scope_id, &escopeId))
- return ESOCK_STR_EINVAL;
-
- / * *** Get the scope_id *** * /
- if (!GET_UINT(env, escopeId, &scopeId))
- return ESOCK_STR_EINVAL;
-
- sockAddrP->sin6_scope_id = scopeId;
-
- / * *** Extract (e) address from map *** * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_addr, &eaddr))
- return ESOCK_STR_EINVAL;
-
- / * Decode address * /
- if (!decode_ip6_address(env, eaddr, sockAddrP, addrLen))
- return ESOCK_STR_EINVAL;
-
- return NULL;
-}
-#endif
-*/
-
-
-
-
-/* +++ decode_sockaddr_un +++
- *
- * Decode a Unix Domain socket address - sockaddr_un. In erlang its represented by
- * a map, which has a specific set of attributes:
- *
- * path :: binary()
- *
- * The erlang module ensures that this value exist, so there
- * is no need for any elaborate error handling.
- */
-/*
-#ifdef HAVE_SYS_UN_H
-static
-char* decode_sockaddr_un(ErlNifEnv* env,
- ERL_NIF_TERM eSockAddr,
- struct sockaddr_un* sockAddrP,
- unsigned int* addrLen)
-{
- ErlNifBinary bin;
- ERL_NIF_TERM epath;
- unsigned int len;
-
- / * *** Extract (e) path (a binary) from map *** * /
- if (!GET_MAP_VAL(env, eSockAddr, atom_port, &epath))
- return ESOCK_STR_EINVAL;
-
- / * Get the path * /
- if (!GET_BIN(env, epath, &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(sockaAddrP->sun_path))
- return ESOCK_STR_EINVAL;
-
-
- sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_un));
- sockAddrP->sun_family = AF_UNIX;
-
- sys_memcpy(sockAddrP->sun_path, bin.data, bin.size);
- len = offsetof(struct sockaddr_un, sun_path) + bin.size;
-
-#ifndef NO_SA_LEN
- sockAddrP->sun_len = len;
-#endif
- *addrLen = len:
-
- return NULL;
-}
-#endif
-*/
-
-
-
-/* +++ decode_ip4_address +++
- *
- * Decode a IPv4 address. This can be three things:
- *
- * + Then atom 'any'
- * + Then atom 'loopback'
- * + An ip4_address() (4 tuple)
- *
- * Note that this *only* decodes the "address" part of a
- * (IPv4) socket address. There are several other things (port).
- */
-/*
-static
-char* decode_ip4_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in* sockAddrP,
- unsigned int* addrLen)
-{
- if (IS_ATOM(env, eAddr)) {
- / * This is either 'any' or 'loopback' * /
- struct in_addr addr;
-
- if (COMPARE(esock_atom_loopback, eAddr) == 0) {
- addr.s_addr = sock_htonl(INADDR_LOOPBACK);
- } else if (COMPARE(esock_atom_any, eAddr) == 0) {
- addr.s_addr = sock_htonl(INADDR_ANY);
- } else {
- return ESOCK_STR_EINVAL;
- }
-
- sockAddrP->sin_addr.s_addr = addr.s_addr;
- *addrLen = sizeof(struct sockaddr_in);
-
- } else {
- / * This is a 4-tuple * /
-
- const ERL_NIF_TERM* addrt;
- int addrtSz;
- int a, v;
- char addr[4];
-
- if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt))
- return ESOCK_STR_EINVAL;
-
- if (addrtSz != 4)
- return ESOCK_STR_EINVAL;
-
- for (a = 0; a < 4; a++) {
- if (!GET_INT(env, addrt[a], &v))
- return ESOCK_STR_EINVAL;
- addr[a] = v;
- }
-
- sys_memcpy(&sockAddrP->sin_addr, &addr, sizeof(addr));
- *addrLenP = sizeof(struct sockaddr_in);
-
- }
-
- return NULL;
-}
-*/
-
-
-
-/* +++ decode_ip6_address +++
- *
- * Decode a IPv6 address. This can be three things:
- *
- * + Then atom 'any'
- * + Then atom 'loopback'
- * + An ip6_address() (8 tuple)
- *
- * Note that this *only* decodes the "address" part of a
- * (IPv6) socket address. There are several other things
- * (port, flowinfo and scope_id) that are handled elsewhere).
- */
-/*
-#if defined(HAVE_IN6) && defined(AF_INET6)
-static
-char* decode_ip6_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in6* sockAddrP,
- unsigned int* addrLen)
-{
- if (IS_ATOM(env, eAddr)) {
- / * This is either 'any' or 'loopback' * /
- const struct in6_addr* addr;
-
- if (COMPARE(esock_atom_loopback, eAddr) == 0) {
- addr = &in6addr_loopback;
- } else if (COMPARE(esock_atom_any, eAddr) == 0) {
- addr = &in6addr_any;
- } else {
- return ESOCK_STR_EINVAL;
- }
-
- sockAddrP->sin6_addr = *addr;
- *addrLen = sizeof(struct sockaddr_in6);
-
- } else {
- / * This is a 8-tuple * /
-
- const ERL_NIF_TERM* addrt;
- int addrtSz;
- int a, v;
- char addr[16];
-
- if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt))
- return ESOCK_STR_EINVAL;
-
- if (addrtSz != 8)
- return ESOCK_STR_EINVAL;
-
- for (a = 0; a < 8; a++) {
- if (!GET_INT(env, addrt[a], &v))
- return ESOCK_STR_EINVAL;
- addr[a*2 ] = ((v >> 8) & 0xFF);
- addr[a*2+1] = (v & 0xFF);
- }
-
- sys_memcpy(&sockAddrP->sin6_addr, &addr, sizeof(addr));
- *addrLen = sizeof(struct sockaddr_in6);
-
- }
-
- return NULL;
-}
-#endif
-*/
-
-
-
#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE)
/* strnlen doesn't exist everywhere */
/*
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c
index 5014688852..512c1d38e0 100644
--- a/erts/emulator/nifs/common/socket_util.c
+++ b/erts/emulator/nifs/common/socket_util.c
@@ -237,9 +237,13 @@ char* esock_decode_sockaddr_in4(ErlNifEnv* env,
/* Decode address */
UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> try decode (ip) address\r\n") );
- if ((xres = esock_decode_ip4_address(env, eaddr, sockAddrP, addrLen)) != NULL)
+ if ((xres = esock_decode_ip4_address(env,
+ eaddr,
+ &sockAddrP->sin_addr)) != NULL)
return xres;
+ *addrLen = sizeof(struct sockaddr_in);
+
UDBG( ("SUTIL", "esock_decode_sockaddr_in4 -> done\r\n") );
return NULL;
@@ -330,6 +334,8 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env,
unsigned int flowInfo, scopeId;
char* xres;
+ UDBG( ("SUTIL", "esock_decode_sockaddr_in6 -> entry\r\n") );
+
/* Basic init */
sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in6));
#ifndef NO_SA_LEN
@@ -346,6 +352,8 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env,
if (!GET_INT(env, eport, &port))
return ESOCK_STR_EINVAL;
+ UDBG( ("SUTIL", "esock_decode_sockaddr_in6 -> port: %d\r\n", port) );
+
sockAddrP->sin6_port = htons(port);
/* *** Extract (e) flowinfo from map *** */
@@ -356,6 +364,8 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env,
if (!GET_UINT(env, eflowInfo, &flowInfo))
return ESOCK_STR_EINVAL;
+ UDBG( ("SUTIL", "esock_decode_sockaddr_in6 -> flowinfo: %d\r\n", flowInfo) );
+
sockAddrP->sin6_flowinfo = flowInfo;
/* *** Extract (e) scope_id from map *** */
@@ -366,6 +376,8 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env,
if (!GET_UINT(env, escopeId, &scopeId))
return ESOCK_STR_EINVAL;
+ UDBG( ("SUTIL", "esock_decode_sockaddr_in6 -> scopeId: %d\r\n", scopeId) );
+
sockAddrP->sin6_scope_id = scopeId;
/* *** Extract (e) address from map *** */
@@ -373,9 +385,15 @@ char* esock_decode_sockaddr_in6(ErlNifEnv* env,
return ESOCK_STR_EINVAL;
/* Decode address */
- if ((xres = esock_decode_ip6_address(env, eaddr, sockAddrP, addrLen)) != NULL)
+ if ((xres = esock_decode_ip6_address(env,
+ eaddr,
+ &sockAddrP->sin6_addr)) != NULL)
return xres;
+ *addrLen = sizeof(struct sockaddr_in6);
+
+ UDBG( ("SUTIL", "esock_decode_sockaddr_in6 -> done\r\n") );
+
return NULL;
}
#endif
@@ -570,22 +588,22 @@ char* esock_encode_sockaddr_un(ErlNifEnv* env,
* + An ip4_address() (4 tuple)
*
* Note that this *only* decodes the "address" part of a
- * (IPv4) socket address. There are several other things (port).
+ * (IPv4) socket address.
*/
extern
-char* esock_decode_ip4_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in* sockAddrP,
- unsigned int* addrLen)
+char* esock_decode_ip4_address(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ struct in_addr* inAddrP)
{
+ struct in_addr addr;
+
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") );
@@ -598,8 +616,7 @@ char* esock_decode_ip4_address(ErlNifEnv* env,
return ESOCK_STR_EINVAL;
}
- sockAddrP->sin_addr.s_addr = addr.s_addr;
- *addrLen = sizeof(struct sockaddr_in);
+ inAddrP->s_addr = addr.s_addr;
} else {
/* This is a 4-tuple */
@@ -621,8 +638,7 @@ char* esock_decode_ip4_address(ErlNifEnv* env,
addr[a] = v;
}
- sys_memcpy(&sockAddrP->sin_addr, &addr, sizeof(addr));
- *addrLen = sizeof(struct sockaddr_in);
+ sys_memcpy(inAddrP, &addr, sizeof(addr));
}
@@ -682,11 +698,14 @@ char* esock_encode_ip4_address(ErlNifEnv* env,
#if defined(HAVE_IN6) && defined(AF_INET6)
extern
-char* esock_decode_ip6_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in6* sockAddrP,
- unsigned int* addrLen)
+char* esock_decode_ip6_address(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ struct in6_addr* inAddrP)
{
+ UDBG( ("SUTIL", "esock_decode_ip6_address -> entry with"
+ "\r\n eAddr: %T"
+ "\r\n", eAddr) );
+
if (IS_ATOM(env, eAddr)) {
/* This is either 'any' or 'loopback' */
const struct in6_addr* addr;
@@ -698,34 +717,34 @@ char* esock_decode_ip6_address(ErlNifEnv* env,
} else {
return ESOCK_STR_EINVAL;
}
-
- sockAddrP->sin6_addr = *addr;
- *addrLen = sizeof(struct sockaddr_in6);
-
+
+ *inAddrP = *addr;
+
} else {
/* This is a 8-tuple */
-
+
const ERL_NIF_TERM* addrt;
int addrtSz;
- int a, v;
- char addr[16];
+ int ai, v;
+ unsigned char addr[16];
+ unsigned char* a = addr;
+ unsigned int addrLen = sizeof(addr) / sizeof(unsigned char);
if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt))
return ESOCK_STR_EINVAL;
if (addrtSz != 8)
return ESOCK_STR_EINVAL;
-
- for (a = 0; a < 8; a++) {
- if (!GET_INT(env, addrt[a], &v))
+
+ for (ai = 0; ai < 8; ai++) {
+ if (!GET_INT(env, addrt[ai], &v))
return ESOCK_STR_EINVAL;
- addr[a*2 ] = ((v >> 8) & 0xFF);
- addr[a*2+1] = (v & 0xFF);
+ put_int16(v, a);
+ a += 2;
}
-
- sys_memcpy(&sockAddrP->sin6_addr, &addr, sizeof(addr));
- *addrLen = sizeof(struct sockaddr_in6);
+ sys_memcpy(inAddrP, &addr, addrLen);
+
}
return NULL;
@@ -754,7 +773,7 @@ char* esock_encode_ip6_address(ErlNifEnv* env,
unsigned int i;
ERL_NIF_TERM at[8];
unsigned int atLen = sizeof(at) / sizeof(ERL_NIF_TERM);
- unsigned char* a = (unsigned char*) &addrP;
+ unsigned char* a = (unsigned char*) addrP;
/* The address */
for (i = 0; i < atLen; i++) {
diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h
index cd8cc7e1fb..f1c122e281 100644
--- a/erts/emulator/nifs/common/socket_util.h
+++ b/erts/emulator/nifs/common/socket_util.h
@@ -32,10 +32,6 @@
#define ESOCK_ABORT(E) esock_abort(E, __func__, __FILE__, __LINE__)
#define ESOCK_ASSERT(e) ((void) ((e) ? 1 : (ESOCK_ABORT(#e), 0)))
-/* Two byte integer decoding */
-#define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \
- (((unsigned char*) (s))[1]))
-
extern
char* esock_decode_sockaddr(ErlNifEnv* env,
ERL_NIF_TERM eSockAddr,
@@ -85,10 +81,9 @@ char* esock_encode_sockaddr_un(ErlNifEnv* env,
#endif
extern
-char* esock_decode_ip4_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in* sockAddrP,
- unsigned int* addrLen);
+char* esock_decode_ip4_address(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ struct in_addr* inAddrP);
extern
char* esock_encode_ip4_address(ErlNifEnv* env,
struct in_addr* addrP,
@@ -96,10 +91,9 @@ char* esock_encode_ip4_address(ErlNifEnv* env,
#if defined(HAVE_IN6) && defined(AF_INET6)
extern
-char* esock_decode_ip6_address(ErlNifEnv* env,
- ERL_NIF_TERM eAddr,
- struct sockaddr_in6* sockAddrP,
- unsigned int* addrLen);
+char* esock_decode_ip6_address(ErlNifEnv* env,
+ ERL_NIF_TERM eAddr,
+ struct in6_addr* inAddrP);
extern
char* esock_encode_ip6_address(ErlNifEnv* env,
struct in6_addr* addrP,
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 4ffa22f70d..01db75c170 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index f243559ceb..997a4ac225 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -510,7 +510,7 @@
%% -define(SOCKET_OPT_IP_MTU, 11).
%% -define(SOCKET_OPT_IP_MTU_DISCOVER, 12).
%% -define(SOCKET_OPT_IP_MULTICAST_ALL, 13).
-%% -define(SOCKET_OPT_IP_MULTICAST_IF, 14).
+-define(SOCKET_OPT_IP_MULTICAST_IF, 14).
-define(SOCKET_OPT_IP_MULTICAST_LOOP, 15).
-define(SOCKET_OPT_IP_MULTICAST_TTL, 16).
%% -define(SOCKET_OPT_IP_NODEFRAG, 17).
@@ -1955,6 +1955,9 @@ enc_setopt_value(socket, sndbuf, V, _D, _T, _P) when is_integer(V) ->
enc_setopt_value(socket = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
+enc_setopt_value(ip, multicast_if, V, _D, _T, _P)
+ when (V =:= any) orelse (is_tuple(V) andalso (size(V) =:= 4)) ->
+ V;
enc_setopt_value(ip, multicast_loop, V, _D, _T, _P)
when is_boolean(V) ->
V;
@@ -2251,8 +2254,8 @@ enc_sockopt_key(ip = L, mtu_discover = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ip = L, multicast_all = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(ip = L, multicast_if = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(ip = _L, multicast_if = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_IP_MULTICAST_IF;
enc_sockopt_key(ip = _L, multicast_loop = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_IP_MULTICAST_LOOP;
enc_sockopt_key(ip = _L, multicast_ttl = _Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl
index 0b570e1f71..23d3c9956e 100644
--- a/lib/kernel/test/socket_client.erl
+++ b/lib/kernel/test/socket_client.erl
@@ -22,8 +22,8 @@
-export([
start/1,
- start_tcp/1, start_tcp/2,
- start_udp/1, start_udp/2
+ start_tcp/1, start_tcp/2, start_tcp6/1,
+ start_udp/1, start_udp/2, start_udp6/1
]).
-define(LIB, socket_lib).
@@ -36,6 +36,9 @@ start(Port) ->
start_tcp(Port) ->
start(inet, stream, tcp, Port).
+start_tcp6(Port) ->
+ start(inet6, stream, tcp, Port).
+
start_tcp(Addr, Port) when (size(Addr) =:= 4) ->
start(inet, stream, tcp, Addr, Port);
start_tcp(Addr, Port) when (size(Addr) =:= 8) ->
@@ -45,6 +48,9 @@ start_tcp(Addr, Port) when (size(Addr) =:= 8) ->
start_udp(Port) ->
start(inet, dgram, udp, Port).
+start_udp6(Port) ->
+ start(inet6, dgram, udp, Port).
+
start_udp(Addr, Port) when (size(Addr) =:= 4) ->
start(inet, dgram, udp, Addr, Port);
start_udp(Addr, Port) when (size(Addr) =:= 8) ->
@@ -65,21 +71,37 @@ do_start(Domain, stream = Type, Proto, SA) ->
try do_init(Domain, Type, Proto) of
Sock ->
connect(Sock, SA),
+ {ok, Name} = socket:sockname(Sock),
+ {ok, Peer} = socket:peername(Sock),
+ {ok, Domain} = socket:getopt(Sock, socket, domain),
+ {ok, Type} = socket:getopt(Sock, socket, type),
+ {ok, Proto} = socket:getopt(Sock, socket, protocol),
+ {ok, OOBI} = socket:getopt(Sock, socket, oobinline),
+ {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
+ {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
+ {ok, Linger} = socket:getopt(Sock, socket, linger),
+ {ok, MIF} = socket:getopt(Sock, ip, multicast_if),
+ {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
+ {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
i("connected: "
"~n From: ~p"
- "~n To: ~p",
- [
- case socket:sockname(Sock) of
- {ok, Name} -> Name;
- {error, _} = NE -> NE
- end,
- case socket:peername(Sock) of
- {ok, Name} -> Name;
- {error, _} = PE -> PE
- end
- ]),
+ "~n To: ~p"
+ "~nwhen"
+ "~n (socket) Domain: ~p"
+ "~n (socket) Type: ~p"
+ "~n (socket) Protocol: ~p"
+ "~n (socket) OOBInline: ~p"
+ "~n (socket) SndBuf: ~p"
+ "~n (socket) RcvBuf: ~p"
+ "~n (socket) Linger: ~p"
+ "~n (ip) Multicast IF: ~p"
+ "~n (ip) Multicast Loop: ~p"
+ "~n (ip) Multicast TTL: ~p"
+ "~n => wait some",
+ [Name, Peer,
+ Domain, Type, Proto,
+ OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
%% Give the server some time...
- i("wait some", []),
?LIB:sleep(5000),
%% ok = socket:close(Sock),
send_loop(#client{socket = Sock,
@@ -93,7 +115,30 @@ do_start(Domain, dgram = Type, Proto, SA) ->
try do_init(Domain, Type, Proto) of
Sock ->
%% Give the server some time...
- i("wait some", []),
+ {ok, Domain} = socket:getopt(Sock, socket, domain),
+ {ok, Type} = socket:getopt(Sock, socket, type),
+ {ok, Proto} = socket:getopt(Sock, socket, protocol),
+ {ok, OOBI} = socket:getopt(Sock, socket, oobinline),
+ {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
+ {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
+ {ok, Linger} = socket:getopt(Sock, socket, linger),
+ {ok, MIF} = socket:getopt(Sock, ip, multicast_if),
+ {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
+ {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
+ i("initiated when: "
+ "~n (socket) Domain: ~p"
+ "~n (socket) Type: ~p"
+ "~n (socket) Protocol: ~p"
+ "~n (socket) OOBInline: ~p"
+ "~n (socket) SndBuf: ~p"
+ "~n (socket) RcvBuf: ~p"
+ "~n (socket) Linger: ~p"
+ "~n (ip) Multicast IF: ~p"
+ "~n (ip) Multicast Loop: ~p"
+ "~n (ip) Multicast TTL: ~p"
+ "~n => wait some",
+ [Domain, Type, Proto,
+ OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
?LIB:sleep(5000),
%% ok = socket:close(Sock),
send_loop(#client{socket = Sock,
@@ -185,7 +230,7 @@ send_loop(#client{msg_id = N} = C) when (N =< 10) ->
end;
{error, SReason} ->
e("Failed send request ~w: "
- "~n ~p", [SReason]),
+ "~n ~p", [N, SReason]),
exit({failed_send, SReason})
end;
send_loop(#client{socket = Sock}) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 9e4e355179..5fd32e040c 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -21,7 +21,7 @@
-module(socket_server).
-export([
- start/0,
+ start/0, start/4,
start_tcp/0, start_tcp/1,
start_udp/0, start_udp/1
]).
@@ -104,7 +104,7 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
{error, _} -> "-"
end
end,
- i("(socket) open (~s,~s,~s): "
+ i("socket opened (~s,~s,~s): "
"~n broadcast: ~s"
"~n dontroute: ~s"
"~n keepalive: ~s"
@@ -114,13 +114,15 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
"~n prio: ~s"
"~n rcvbuf: ~s"
"~n sndbuf: ~s"
- "~n try find (local) address",
+ "~n => try find (local) address",
[F(domain), F(type), F(protocol),
F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger),
F(debug), F(priority), F(rcvbuf), F(sndbuf)]),
Addr = which_addr(Domain),
SA = #{family => Domain,
addr => Addr},
+ i("try bind to: "
+ "~n ~p", [Addr]),
case socket:bind(Sock, SA) of
{ok, _P} ->
ok;
@@ -290,7 +292,9 @@ acceptor_do_init(Domain, Type, Proto) ->
Addr = which_addr(Domain),
SA = #{family => Domain,
addr => Addr},
- i("found (~p) - try (socket) bind", [Addr]),
+ i("found: "
+ "~n ~p"
+ "~n => try (socket) bind", [Addr]),
%% ok = socket:setopt(Sock, otp, debug, true),
%% ok = socket:setopt(Sock, socket, debug, 1), %% must have rights!!
Port = case socket:bind(Sock, SA) of
@@ -301,7 +305,9 @@ acceptor_do_init(Domain, Type, Proto) ->
{error, BReason} ->
throw({bind, BReason})
end,
- i("bound (~w) - try (socket) listen (acceptconn: ~s)",
+ i("bound to: "
+ "~n ~p"
+ "~n => try (socket) listen (acceptconn: ~s)",
[Port, F(acceptconn)]),
case socket:listen(Sock) of
ok ->
@@ -328,6 +334,8 @@ which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") ->
which_addr(Domain, [_|IFL]) ->
which_addr(Domain, IFL).
+which_addr2(_, []) ->
+ throw(no_address);
which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
Addr;
which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
@@ -434,6 +442,7 @@ handler_init(Manager, ID, Peek, Sock) ->
{ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
{ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
{ok, Linger} = socket:getopt(Sock, socket, linger),
+ {ok, MIF} = socket:getopt(Sock, ip, multicast_if),
{ok, MLoop} = socket:getopt(Sock, ip, multicast_loop),
{ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl),
i("got continue when: "
@@ -444,10 +453,11 @@ handler_init(Manager, ID, Peek, Sock) ->
"~n (socket) SndBuf: ~p"
"~n (socket) RcvBuf: ~p"
"~n (socket) Linger: ~p"
+ "~n (ip) Multicast IF: ~p"
"~n (ip) Multicast Loop: ~p"
"~n (ip) Multicast TTL: ~p",
[Domain, Type, Proto,
- OOBI, SndBuf, RcvBuf, Linger, MLoop, MTTL]),
+ OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
%% socket:setopt(Sock, otp, debug, true),
handler_loop(#handler{peek = Peek,
manager = Manager,