diff options
author | Micael Karlberg <[email protected]> | 2018-07-12 21:17:14 +0200 |
---|---|---|
committer | Micael Karlberg <[email protected]> | 2018-09-18 14:50:18 +0200 |
commit | 3a2c48b2740f08d3582028fd2f8d626009aa911e (patch) | |
tree | 67ce169ff4e07488b36ce2e16f7e694d2ea62376 | |
parent | 2151895b4eb4cb3172ba7597477fd83eb85b444a (diff) | |
download | otp-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.c | 108 | ||||
-rw-r--r-- | erts/preloaded/ebin/socket.beam | bin | 45756 -> 46248 bytes | |||
-rw-r--r-- | erts/preloaded/src/socket.erl | 28 |
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 Binary files differindex fd19efd516..03a7012131 100644 --- a/erts/preloaded/ebin/socket.beam +++ b/erts/preloaded/ebin/socket.beam 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; |