aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-24 10:25:25 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commitd7ca5ba9d8a7f094037878acfecb52b0bfbacc2e (patch)
tree4c2d864c0d276329c6402c91eaa8eb12f780ec4a
parentde82310c32063b8556add3fe7cf62b26eef27841 (diff)
downloadotp-d7ca5ba9d8a7f094037878acfecb52b0bfbacc2e.tar.gz
otp-d7ca5ba9d8a7f094037878acfecb52b0bfbacc2e.tar.bz2
otp-d7ca5ba9d8a7f094037878acfecb52b0bfbacc2e.zip
[socket-nif] Add support for socket (level ipv6) option rthdr
Added support for the IPv6 socket option RTHDR. On FreeBSD this option requires superuser privileges to update. There is no mention of this on linux, but its still not possible to update (einval), so I assume that its the same there. OTP-14831.
-rw-r--r--erts/doc/src/socket_usage.xml7
-rw-r--r--erts/emulator/nifs/common/socket_nif.c71
-rw-r--r--erts/preloaded/ebin/socket.beambin57144 -> 57224 bytes
-rw-r--r--erts/preloaded/src/socket.erl11
-rw-r--r--lib/kernel/test/socket_server.erl27
5 files changed, 102 insertions, 14 deletions
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 78662e7d0d..b3ee38dbcb 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -475,6 +475,13 @@
<cell>type = dgram | raw</cell>
</row>
<row>
+ <cell>rthdr</cell>
+ <cell>boolean()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>type = dgram | raw, requires superuser privileges to update</cell>
+ </row>
+ <row>
<cell>v6only</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 35997c359d..f4ac43a9cd 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -544,6 +544,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_RTHDR 28
#define SOCKET_OPT_IPV6_V6ONLY 32
#define SOCKET_OPT_TCP_CONGESTION 1
@@ -1240,6 +1241,11 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(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,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IPV6_V6ONLY)
static ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1545,6 +1551,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_RTHDR)
+static ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(IPV6_V6ONLY)
static ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -4323,9 +4333,10 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "nsetopt_native -> entry with"
- "\r\n opt: %d"
- "\r\n eVal: %T"
- "\r\n", opt, eVal) );
+ "\r\n level: %d"
+ "\r\n opt: %d"
+ "\r\n eVal: %T"
+ "\r\n", level, opt, eVal) );
if (GET_BIN(env, eVal, &val)) {
int res = socket_setopt(descP->sock, level, opt,
@@ -4338,6 +4349,11 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env,
result = esock_make_error(env, esock_atom_einval);
}
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_native -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
@@ -4393,10 +4409,17 @@ ERL_NIF_TERM nsetopt_level(ErlNifEnv* env,
#endif
default:
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_level -> unknown level (%d)\r\n", level) );
result = esock_make_error(env, esock_atom_einval);
break;
}
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_level -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
@@ -4527,6 +4550,8 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env,
#endif
default:
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_socket -> unknown opt (%d)\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
@@ -5572,6 +5597,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_RTHDR)
+ case SOCKET_OPT_IPV6_RTHDR:
+ result = nsetopt_lvl_ipv6_rthdr(env, descP, eVal);
+ break;
+#endif
+
#if defined(IPV6_V6ONLY)
case SOCKET_OPT_IPV6_V6ONLY:
result = nsetopt_lvl_ipv6_v6only(env, descP, eVal);
@@ -5579,10 +5610,17 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
#endif
default:
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_ipv6 -> unknown opt (%d)\r\n", eOpt) );
result = esock_make_error(env, esock_atom_einval);
break;
}
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_ipv6 -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
return result;
}
@@ -5721,6 +5759,17 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
#endif
+#if defined(IPV6_RTHDR)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ return nsetopt_bool_opt(env, descP, SOL_IPV6, IPV6_RTHDR, eVal);
+}
+#endif
+
+
#if defined(IPV6_V6ONLY)
static
ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
@@ -8090,6 +8139,12 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_RTHDR)
+ case SOCKET_OPT_IPV6_RTHDR:
+ result = ngetopt_lvl_ipv6_rthdr(env, descP);
+ break;
+#endif
+
#if defined(IPV6_V6ONLY)
case SOCKET_OPT_IPV6_V6ONLY:
result = ngetopt_lvl_ipv6_v6only(env, descP);
@@ -8205,6 +8260,16 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_recvpktinfo(ErlNifEnv* env,
#endif
+#if defined(IPV6_RTHDR)
+static
+ERL_NIF_TERM ngetopt_lvl_ipv6_rthdr(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ return ngetopt_bool_opt(env, descP, SOL_IPV6, IPV6_RTHDR);
+}
+#endif
+
+
#if defined(IPV6_V6ONLY)
static
ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 15bc762ae9..1873289486 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 7e9b61ba8f..d2267192e5 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -657,7 +657,7 @@
-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_RTHDR, 28).
+-define(SOCKET_OPT_IPV6_RTHDR, 28).
%% -define(SOCKET_OPT_IPV6_TCLASS, 29).
%% -define(SOCKET_OPT_IPV6_UNICAST_HOPS, 30).
%% -define(SOCKET_OPT_IPV6_USE_MIN_MTU, 31).
@@ -2282,6 +2282,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, rthdr, V, _D, _T, _P)
+ when is_boolean(V) ->
+ V;
enc_setopt_value(ipv6, v6only, V, _D, _T, _P) when is_boolean(V) ->
V;
enc_setopt_value(ipv6 = L, Opt, V, _D, _T, _P) ->
@@ -2727,9 +2730,9 @@ 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, rthdr = Opt, set = _Dir, _D, T, _P)
+enc_sockopt_key(ipv6 = _L, rthdr = _Opt, _Dir, _D, T, _P)
when ((T =:= dgram) orelse (T =:= raw)) ->
- not_supported({L, Opt});
+ ?SOCKET_OPT_IPV6_RTHDR;
enc_sockopt_key(ipv6 = L, tclass = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, unicast_hops = Opt, _Dir, _D, _T, _P) ->
@@ -2739,7 +2742,7 @@ enc_sockopt_key(ipv6 = L, use_min_mtu = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(ipv6 = _L, v6only = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_IPV6_V6ONLY;
enc_sockopt_key(ipv6 = L, UnknownOpt, _Dir, _D, _T, _P) ->
- unknown({L, UnknownOpt});
+ unknown({L, UnknownOpt, _Dir, _D, _T, _P});
%% TCP socket options
%% There are other options that would be useful; info,
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index ba74964ed1..75cede75e5 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -23,9 +23,9 @@
-export([
start/0, start/4,
start_tcp/0, start_tcp/1, start_tcp/2,
- start_tcp4/1, start_tcp6/1,
+ start_tcp4/0, start_tcp4/1, start_tcp6/0, start_tcp6/1,
start_udp/0, start_udp/1, start_udp/2,
- start_udp4/1, start_udp6/1,
+ start_udp4/0, start_udp4/1, start_udp6/0, start_udp6/1,
start_sctp/0, start_sctp/1
]).
@@ -41,14 +41,20 @@ start() ->
start_tcp().
start_tcp() ->
- start_tcp(false).
+ start_tcp4().
start_tcp(Peek) ->
start_tcp4(Peek).
+start_tcp4() ->
+ start_tcp4(false).
+
start_tcp4(Peek) ->
start_tcp(inet, Peek).
+start_tcp6() ->
+ start_tcp6(false).
+
start_tcp6(Peek) ->
start_tcp(inet6, Peek).
@@ -56,14 +62,20 @@ start_tcp(Domain, Peek) when is_boolean(Peek) ->
start(Domain, stream, tcp, Peek).
start_udp() ->
- start_udp(false).
+ start_udp4().
start_udp(Peek) ->
start_udp4(Peek).
+start_udp4() ->
+ start_udp4(false).
+
start_udp4(Peek) ->
start_udp(inet, Peek).
+start_udp6() ->
+ start_udp6(false).
+
start_udp6(Peek) ->
start_udp(inet6, Peek).
@@ -621,6 +633,7 @@ handler_init(Manager, ID, Peek, Sock) ->
MIF6 = GIP6(multicast_if), % Only dgram and raw
MLoop6 = GIP6(multicast_loop),
RecvPktInfo = GIP6(recvpktinfo),
+ RtHdr = GIP6(rthdr),
i("got continue when: "
"~n (socket) Domain: ~p"
"~n (socket) Type: ~p"
@@ -652,15 +665,15 @@ handler_init(Manager, ID, Peek, Sock) ->
"~n (ipv6) Multicast Hops: ~s"
"~n (ipv6) Multicast IF: ~s"
"~n (ipv6) Multicast Loop: ~s"
- "~n (ipv6) Recv Pkt Info: ~s",
+ "~n (ipv6) Recv Pkt Info: ~s"
+ "~n (ipv6) RT Hdr: ~s",
[Domain, Type, Proto,
RA, RP, B2D, OOBI,
RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO,
Linger, Timestamp,
FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL,
NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL,
- MHops, MIF6, MLoop6,
- RecvPktInfo]),
+ MHops, MIF6, MLoop6, RecvPktInfo, RtHdr]),
handler_loop(#handler{peek = Peek,
manager = Manager,