aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-12 21:17:14 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit3a2c48b2740f08d3582028fd2f8d626009aa911e (patch)
tree67ce169ff4e07488b36ce2e16f7e694d2ea62376
parent2151895b4eb4cb3172ba7597477fd83eb85b444a (diff)
downloadotp-3a2c48b2740f08d3582028fd2f8d626009aa911e.tar.gz
otp-3a2c48b2740f08d3582028fd2f8d626009aa911e.tar.bz2
otp-3a2c48b2740f08d3582028fd2f8d626009aa911e.zip
[socket-nif] Add support for socket (level ipv6) option(s) [add|drop]_membership
Added support for the IPv6 options ADD_MEMBERSHIP, DROP_MEMBERSHIP OTP-14831
-rw-r--r--erts/emulator/nifs/common/socket_nif.c108
-rw-r--r--erts/preloaded/ebin/socket.beambin45756 -> 46248 bytes
-rw-r--r--erts/preloaded/src/socket.erl28
3 files changed, 130 insertions, 6 deletions
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 37bb307e2b..1f9234016c 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -383,7 +383,9 @@ typedef union {
#define SOCKET_OPT_IP_TTL 32
#define SOCKET_OPT_IP_UNBLOCK_SOURCE 33
-#define SOCKET_OPT_IPV6_HOPLIMIT 12
+#define SOCKET_OPT_IPV6_ADD_MEMBERSHIP 2
+#define SOCKET_OPT_IPV6_DROP_MEMBERSHIP 6
+#define SOCKET_OPT_IPV6_HOPLIMIT 12
#define SOCKET_OPT_TCP_CONGESTION 1
#define SOCKET_OPT_TCP_CORK 2
@@ -976,11 +978,29 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
SocketDescriptor* descP,
int eOpt,
ERL_NIF_TERM eVal);
+#if defined(IPV6_ADD_MEMBERSHIP)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
+#if defined(IPV6_DROP_MEMBERSHIP)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IPV6_HOPLIMIT)
static ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+
+#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt);
+#endif
+
#endif // defined(SOL_IPV6)
static ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -4779,6 +4799,7 @@ ERL_NIF_TERM nsetopt_lvl_ip_update_source(ErlNifEnv* env,
#endif
+
/* *** Handling set of socket options for level = ipv6 *** */
/* nsetopt_lvl_ipv6 - Level *IPv6* option(s)
@@ -4793,6 +4814,18 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
ERL_NIF_TERM result;
switch (eOpt) {
+#if defined(IPV6_ADD_MEMBERSHIP)
+ case SOCKET_OPT_IPV6_ADD_MEMBERSHIP:
+ result = nsetopt_lvl_ipv6_add_membership(env, descP, eVal);
+ break;
+#endif
+
+#if defined(IPV6_DROP_MEMBERSHIP)
+ case SOCKET_OPT_IPV6_DROP_MEMBERSHIP:
+ result = nsetopt_lvl_ipv6_drop_membership(env, descP, eVal);
+ break;
+#endif
+
#if defined(IPV6_HOPLIMIT)
case SOCKET_OPT_IPV6_HOPLIMIT:
result = nsetopt_lvl_ipv6_hoplimit(env, descP, eVal);
@@ -4808,6 +4841,30 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
}
+#if defined(IPV6_ADD_MEMBERSHIP)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_add_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_lvl_ipv6_update_membership(env, descP, eVal,
+ IPV6_ADD_MEMBERSHIP);
+}
+#endif
+
+
+#if defined(IPV6_DROP_MEMBERSHIP)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_drop_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_lvl_ipv6_update_membership(env, descP, eVal,
+ IPV6_DROP_MEMBERSHIP);
+}
+#endif
+
+
#if defined(IPV6_HOPLIMIT)
static
ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
@@ -4819,6 +4876,55 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
#endif
+#if defined(IPV6_ADD_MEMBERSHIP) || defined(IPV6_DROP_MEMBERSHIP)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_update_membership(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal,
+ int opt)
+{
+ ERL_NIF_TERM result, eMultiAddr, eInterface;
+ struct ipv6_mreq mreq;
+ char* xres;
+ int res;
+ size_t sz;
+ int level = IPPROTO_IPV6;
+
+ // It must be a map
+ if (!IS_MAP(env, eVal))
+ return enif_make_badarg(env);
+
+ // It must have atleast two attributes
+ if (!enif_get_map_size(env, eVal, &sz) || (sz >= 2))
+ return enif_make_badarg(env);
+
+ if (!GET_MAP_VAL(env, eVal, atom_multiaddr, &eMultiAddr))
+ return enif_make_badarg(env);
+
+ if (!GET_MAP_VAL(env, eVal, atom_interface, &eInterface))
+ return enif_make_badarg(env);
+
+ if ((xres = esock_decode_ip6_address(env,
+ eMultiAddr,
+ &mreq.ipv6mr_multiaddr)) != NULL)
+ return esock_make_error_str(env, xres);
+
+ if (!GET_UINT(env, eInterface, &mreq.ipv6mr_interface))
+ return esock_make_error(env, esock_atom_einval);
+
+ res = socket_setopt(descP->sock, level, opt, &mreq, sizeof(mreq));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ return result;
+}
+#endif
+
+
+
#endif // defined(SOL_IPV6)
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index fd19efd516..03a7012131 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 c8238e9a1a..8d377d808e 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -92,6 +92,7 @@
ip_mreq/0,
ip_mreq_source/0,
ip_pmtudisc/0,
+ ipv6_mreq/0,
msg_hdr/0
@@ -160,6 +161,9 @@
-type ip_pmtudisc() :: want | dont | do | probe.
+-type ipv6_mreq() :: #{multiaddr := ip6_address(),
+ interface := non_neg_integer()}.
+
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
@@ -526,7 +530,7 @@
-define(SOCKET_OPT_IP_ADD_MEMBERSHIP, 1).
-define(SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP, 2).
-define(SOCKET_OPT_IP_BLOCK_SOURCE, 3).
-%% -define(SOCKET_OPT_IP_DONTFRAG, 4). % Windows? MTU_DISCOVER...
+%% -define(SOCKET_OPT_IP_DONTFRAG, 4).
-define(SOCKET_OPT_IP_DROP_MEMBERSHIP, 5).
-define(SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP, 6).
%% -define(SOCKET_OPT_IP_FREEBIND, 7).
@@ -558,11 +562,11 @@
-define(SOCKET_OPT_IP_UNBLOCK_SOURCE, 33).
%% -define(SOCKET_OPT_IPV6_ADDFORM, 1).
-%% -define(SOCKET_OPT_IPV6_ADD_MEMBERSHIP, 2).
+-define(SOCKET_OPT_IPV6_ADD_MEMBERSHIP, 2).
%% -define(SOCKET_OPT_IPV6_AUTHHDR, 3).
%% -define(SOCKET_OPT_IPV6_AUTH_LEVEL, 4).
%% -define(SOCKET_OPT_IPV6_CHECKSUM, 5).
-%% -define(SOCKET_OPT_IPV6_DROP_MEMBERSHIP, 6).
+-define(SOCKET_OPT_IPV6_DROP_MEMBERSHIP, 6).
%% -define(SOCKET_OPT_IPV6_DSTOPTS, 7).
%% -define(SOCKET_OPT_IPV6_ESP_TRANS_LEVEL, 8).
%% -define(SOCKET_OPT_IPV6_ESP_NETWORK_LEVEL, 9).
@@ -1983,9 +1987,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, add_membership, #{multiaddr := M,
+enc_setopt_value(ip, add_membership, #{multiaddr := MA,
interface := IF} = V, _D, _T, _P)
- when (is_tuple(M) andalso (size(M) =:= 4)) andalso
+ when (is_tuple(MA) andalso (size(MA) =:= 4)) andalso
((IF =:= any) orelse (is_tuple(IF) andalso (size(IF) =:= 4))) ->
V;
enc_setopt_value(ip, add_source_membership, #{multiaddr := MA,
@@ -2070,6 +2074,16 @@ enc_setopt_value(ip, unblock_source, #{multiaddr := MA,
enc_setopt_value(ip = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
+enc_setopt_value(ipv6, add_membership, #{multiaddr := MA,
+ interface := IF} = V, _D, _T, _P)
+ when ((is_tuple(MA) andalso (size(MA) =:= 8)) andalso
+ (is_integer(IF) andalso (IF >= 0))) ->
+ V;
+enc_setopt_value(ipv6, drop_membership, #{multiaddr := MA,
+ interface := IF} = V, _D, _T, _P)
+ when ((is_tuple(MA) andalso (size(MA) =:= 8)) andalso
+ (is_integer(IF) andalso (IF >= 0))) ->
+ V;
enc_setopt_value(ipv6, hoplimit, V, _D, T, _P)
when is_boolean(V) andalso ((T =:= dgram) orelse (T =:= raw)) ->
V;
@@ -2389,6 +2403,10 @@ enc_sockopt_key(ip = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
%% IPv6 socket options
+enc_sockopt_key(ipv6, add_membership = _Opt, set = _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_IPV6_ADD_MEMBERSHIP;
+enc_sockopt_key(ipv6, drop_membership = _Opt, set = _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_IPV6_DROP_MEMBERSHIP;
enc_sockopt_key(ipv6, hoplimit = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
?SOCKET_OPT_IPV6_HOPLIMIT;