aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-24 15:03:36 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d (patch)
tree3f28de3cea2604a7bfacdb53b00107e1ddccfede
parentb598160c2f1162658ea948284aee5b53951a3b9e (diff)
downloadotp-7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d.tar.gz
otp-7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d.tar.bz2
otp-7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d.zip
[socket-nif] Add support for socket (level ipv6) option router_alert
Added support for the IPv6 socket option ROUTER_ALERT. Only supported for raw sockets. OTP-14831.
-rw-r--r--erts/doc/src/socket_usage.xml7
-rw-r--r--erts/emulator/nifs/common/socket_nif.c138
-rw-r--r--erts/preloaded/ebin/socket.beambin57664 -> 57952 bytes
-rw-r--r--erts/preloaded/src/socket.erl25
-rw-r--r--lib/kernel/test/socket_server.erl11
5 files changed, 151 insertions, 30 deletions
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 383aebdab1..1423571f5c 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -503,6 +503,13 @@
<cell>type = dgram | raw</cell>
</row>
<row>
+ <cell>router_alert</cell>
+ <cell>integer()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>type = raw</cell>
+ </row>
+ <row>
<cell>rthdr</cell>
<cell>boolean()</cell>
<cell>yes</cell>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 5aba0bca03..4d78e89a4f 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -470,6 +470,8 @@ typedef union {
#define SOCKET_PROTOCOL_TCP 2
#define SOCKET_PROTOCOL_UDP 3
#define SOCKET_PROTOCOL_SCTP 4
+#define SOCKET_PROTOCOL_ICMP 5
+#define SOCKET_PROTOCOL_IGMP 6
/* shutdown how */
#define SOCKET_SHUTDOWN_HOW_RD 0
@@ -548,6 +550,7 @@ typedef union {
#define SOCKET_OPT_IPV6_MULTICAST_IF 20
#define SOCKET_OPT_IPV6_MULTICAST_LOOP 21
#define SOCKET_OPT_IPV6_RECVPKTINFO 25 // PKTINFO on FreeBSD
+#define SOCKET_OPT_IPV6_ROUTER_ALERT 27
#define SOCKET_OPT_IPV6_RTHDR 28
#define SOCKET_OPT_IPV6_UNICAST_HOPS 30
#define SOCKET_OPT_IPV6_V6ONLY 32
@@ -1266,6 +1269,11 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(IPV6_ROUTER_ALERT)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IPV6_RTHDR)
static ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1597,6 +1605,10 @@ static ERL_NIF_TERM ngetopt_lvl_ipv6_multicast_loop(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(IPV6_ROUTER_ALERT)
+static ERL_NIF_TERM ngetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(IPV6_RTHDR)
static ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1896,7 +1908,9 @@ static int compare_pids(ErlNifEnv* env,
static BOOLEAN_T edomain2domain(int edomain, int* domain);
static BOOLEAN_T etype2type(int etype, int* type);
-static BOOLEAN_T eproto2proto(int eproto, int* proto);
+static BOOLEAN_T eproto2proto(ErlNifEnv* env,
+ const ERL_NIF_TERM eproto,
+ int* proto);
static BOOLEAN_T ehow2how(unsigned int ehow, int* how);
static BOOLEAN_T esendflags2sendflags(unsigned int esendflags, int* sendflags);
static BOOLEAN_T erecvflags2recvflags(unsigned int erecvflags, int* recvflags);
@@ -2344,18 +2358,18 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
if ((argc != 4) ||
!GET_INT(env, argv[0], &edomain) ||
!GET_INT(env, argv[1], &etype) ||
- !GET_INT(env, argv[2], &eproto) ||
!IS_MAP(env, argv[3])) {
return enif_make_badarg(env);
}
- emap = argv[3];
+ eproto = argv[2];
+ emap = argv[3];
SGDBG( ("SOCKET", "nif_open -> "
"\r\n edomain: %T"
"\r\n etype: %T"
"\r\n eproto: %T"
"\r\n extra: %T"
- "\r\n", argv[0], argv[1], argv[2], argv[3]) );
+ "\r\n", argv[0], argv[1], eproto, emap) );
if (!edomain2domain(edomain, &domain)) {
SGDBG( ("SOCKET", "nif_open -> domain: %d\r\n", domain) );
@@ -2367,7 +2381,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
return esock_make_error(env, esock_atom_einval);
}
- if (!eproto2proto(eproto, &proto)) {
+ if (!eproto2proto(env, eproto, &proto)) {
SGDBG( ("SOCKET", "nif_open -> protocol: %d\r\n", proto) );
return esock_make_error(env, esock_atom_einval);
}
@@ -5671,6 +5685,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_ROUTER_ALERT)
+ case SOCKET_OPT_IPV6_ROUTER_ALERT:
+ result = nsetopt_lvl_ipv6_router_alert(env, descP, eVal);
+ break;
+#endif
+
#if defined(IPV6_RTHDR)
case SOCKET_OPT_IPV6_RTHDR:
result = nsetopt_lvl_ipv6_rthdr(env, descP, eVal);
@@ -5883,6 +5903,18 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
#endif
+#if defined(IPV6_ROUTER_ALERT)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_int_opt(env, descP, SOL_IPV6, IPV6_ROUTER_ALERT, eVal);
+}
+#endif
+
+
+
#if defined(IPV6_RTHDR)
static
ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
@@ -8299,6 +8331,12 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_ROUTER_ALERT)
+ case SOCKET_OPT_IPV6_ROUTER_ALERT:
+ result = ngetopt_lvl_ipv6_router_alert(env, descP);
+ break;
+#endif
+
#if defined(IPV6_RTHDR)
case SOCKET_OPT_IPV6_RTHDR:
result = ngetopt_lvl_ipv6_rthdr(env, descP);
@@ -8466,6 +8504,16 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
#endif
+#if defined(IPV6_ROUTER_ALERT)
+static
+ERL_NIF_TERM ngetopt_lvl_ipv6_router_alert(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ return ngetopt_int_opt(env, descP, SOL_IPV6, IPV6_ROUTER_ALERT);
+}
+#endif
+
+
#if defined(IPV6_RTHDR)
static
ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
@@ -8479,7 +8527,7 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
#if defined(IPV6_UNICAST_HOPS)
static
ERL_NIF_TERM ngetopt_lvl_ipv6_unicast_hops(ErlNifEnv* env,
- SocketDescriptor* descP)
+ SocketDescriptor* descP)
{
return ngetopt_int_opt(env, descP, SOL_IPV6, IPV6_UNICAST_HOPS);
}
@@ -10235,30 +10283,72 @@ BOOLEAN_T etype2type(int etype, int* type)
* Note that only a subset is supported.
*/
static
-BOOLEAN_T eproto2proto(int eproto, int* proto)
+BOOLEAN_T eproto2proto(ErlNifEnv* env,
+ ERL_NIF_TERM eproto,
+ int* proto)
{
- switch (eproto) {
- case SOCKET_PROTOCOL_IP:
- *proto = IPPROTO_IP;
- break;
-
- case SOCKET_PROTOCOL_TCP:
- *proto = IPPROTO_TCP;
- break;
+ if (IS_NUM(env, eproto)) {
+ int ep;
- case SOCKET_PROTOCOL_UDP:
- *proto = IPPROTO_UDP;
- break;
+ if (!GET_INT(env, eproto, &ep)) {
+ *proto = -1;
+ return FALSE;
+ }
+ switch (ep) {
+ case SOCKET_PROTOCOL_IP:
+ *proto = IPPROTO_IP;
+ break;
+
+ case SOCKET_PROTOCOL_TCP:
+ *proto = IPPROTO_TCP;
+ break;
+
+ case SOCKET_PROTOCOL_UDP:
+ *proto = IPPROTO_UDP;
+ break;
+
#if defined(HAVE_SCTP)
- case SOCKET_PROTOCOL_SCTP:
- *proto = IPPROTO_SCTP;
- break;
+ case SOCKET_PROTOCOL_SCTP:
+ *proto = IPPROTO_SCTP;
+ break;
#endif
+
+ case SOCKET_PROTOCOL_ICMP:
+ *proto = IPPROTO_ICMP;
+ break;
+
+ case SOCKET_PROTOCOL_IGMP:
+ *proto = IPPROTO_IGMP;
+ break;
+
+ default:
+ *proto = -2;
+ return FALSE;
+ }
+ } else {
+ const ERL_NIF_TERM* a;
+ int sz;
- default:
- *proto = -1;
- return FALSE;
+ if (!GET_TUPLE(env, eproto, &sz, &a)) {
+ *proto = -3;
+ return FALSE;
+ }
+
+ if (sz != 2) {
+ *proto = -4;
+ return FALSE;
+ }
+
+ if (COMPARE(a[0], esock_atom_raw) != 0) {
+ *proto = -5;
+ return FALSE;
+ }
+
+ if (!GET_INT(env, a[1], proto)) {
+ *proto = -6;
+ return FALSE;
+ }
}
return TRUE;
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 5ab64f442f..cdc403055b 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 3bc3c7dc28..82a51ee245 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -128,7 +128,10 @@
-type type() :: stream | dgram | raw | rdm | seqpacket.
%% We support only a subset of all protocols:
--type protocol() :: ip | tcp | udp | sctp.
+%% Note that the '{raw, integer()}' construct is intended
+%% to be used with type = raw.
+%% Note also that only the "superuser" can create a raw socket.
+-type protocol() :: ip | tcp | udp | sctp | icmp | igmp | {raw, integer()}.
-type port_number() :: 0..65535.
@@ -525,6 +528,8 @@
-define(SOCKET_PROTOCOL_TCP, 2).
-define(SOCKET_PROTOCOL_UDP, 3).
-define(SOCKET_PROTOCOL_SCTP, 4).
+-define(SOCKET_PROTOCOL_ICMP, 5).
+-define(SOCKET_PROTOCOL_IGMP, 6).
-define(SOCKET_LISTEN_BACKLOG_DEFAULT, 5).
@@ -656,7 +661,7 @@
%% -define(SOCKET_OPT_IPV6_RECVERR, 24).
-define(SOCKET_OPT_IPV6_RECVPKTINFO, 25). % On FreeBSD: PKTINFO
%% -define(SOCKET_OPT_IPV6_RECVTCLASS, 26).
-%% -define(SOCKET_OPT_IPV6_ROUTER_ALERT, 27).
+-define(SOCKET_OPT_IPV6_ROUTER_ALERT, 27).
-define(SOCKET_OPT_IPV6_RTHDR, 28).
%% -define(SOCKET_OPT_IPV6_TCLASS, 29).
-define(SOCKET_OPT_IPV6_UNICAST_HOPS, 30).
@@ -2004,7 +2009,8 @@ enc_type(_, raw) -> ?SOCKET_TYPE_RAW;
enc_type(_, seqpacket) -> ?SOCKET_TYPE_SEQPACKET;
enc_type(_, Type) -> throw({error, {invalid_type, Type}}).
--spec enc_protocol(Type, Protocol) -> non_neg_integer() when
+-spec enc_protocol(Type, Protocol) -> non_neg_integer() |
+ {raw, non_neg_integer()} when
Type :: type(),
Protocol :: protocol().
@@ -2012,7 +2018,11 @@ enc_protocol(dgram, ip) -> ?SOCKET_PROTOCOL_IP;
enc_protocol(stream, tcp) -> ?SOCKET_PROTOCOL_TCP;
enc_protocol(dgram, udp) -> ?SOCKET_PROTOCOL_UDP;
enc_protocol(seqpacket, sctp) -> ?SOCKET_PROTOCOL_SCTP;
-enc_protocol(Type, Proto) -> throw({error, {invalid_protocol, {Type, Proto}}}).
+enc_protocol(raw, icmp) -> ?SOCKET_PROTOCOL_ICMP;
+enc_protocol(raw, igmp) -> ?SOCKET_PROTOCOL_IGMP;
+enc_protocol(raw, {raw, P} = RAW) when is_integer(P) -> RAW;
+enc_protocol(Type, Proto) ->
+ throw({error, {invalid_protocol, {Type, Proto}}}).
-spec enc_send_flags(Flags) -> non_neg_integer() when
@@ -2297,6 +2307,9 @@ enc_setopt_value(ipv6, Opt, V, _D, _T, _P)
when ((Opt =:= recvpktinfo) orelse (Opt =:= pktinfo)) andalso
is_boolean(V) ->
V;
+enc_setopt_value(ipv6, router_alert, V, _D, T, _P)
+ when is_integer(V) andalso (T =:= raw) ->
+ V;
enc_setopt_value(ipv6, rthdr, V, _D, T, _P)
when is_boolean(V) andalso ((T =:= dgram) orelse (T =:= raw)) ->
V;
@@ -2749,8 +2762,8 @@ enc_sockopt_key(ipv6 = _L, Opt, _Dir, _D, T, _P)
?SOCKET_OPT_IPV6_RECVPKTINFO;
enc_sockopt_key(ipv6 = L, recvtclass = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(ipv6 = L, router_alert = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(ipv6 = _L, router_alert = _Opt, _Dir, _D, T, _P) when (T =:= raw) ->
+ ?SOCKET_OPT_IPV6_ROUTER_ALERT;
enc_sockopt_key(ipv6 = _L, rthdr = _Opt, _Dir, _D, T, _P)
when ((T =:= dgram) orelse (T =:= raw)) ->
?SOCKET_OPT_IPV6_RTHDR;
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 2cb505cabc..54e9244d19 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -247,6 +247,17 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) ->
EXP(close_socket, ok, socket:close(Sock));
{error, Reason} ->
exit({failed_open, Reason})
+ end;
+do_manager_init(Domain, raw = Type, Proto, Peek) when is_integer(Proto) ->
+ do_manager_init(Domain, Type, {raw, Proto}, Peek);
+do_manager_init(Domain, raw = Type, Proto, _Peek) ->
+ case socket:open(Domain, Type, Proto) of
+ {ok, Sock} ->
+ i("(sctp) socket opened: "
+ "~n ~p", [Sock]),
+ socket:close(Sock);
+ {error, Reason} ->
+ exit({failed_open, Reason})
end.