From 0122d2cafdb6f44c221796f1a6b2a5188dfb153d Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Thu, 12 Jul 2018 11:04:38 +0200
Subject: [socket-nif] Add support for socket (level ip) option nodefrag

Added support for the IP option NODEFRAG.

OTP-14831
---
 erts/emulator/nifs/common/socket_nif.c |  65 +++++++++++++++++++++++++++++++++
 erts/preloaded/ebin/socket.beam        | Bin 44744 -> 44804 bytes
 erts/preloaded/src/socket.erl          |   9 +++--
 lib/kernel/test/socket_server.erl      |  23 ++++++++----
 4 files changed, 86 insertions(+), 11 deletions(-)

diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index a2bebcd621..0972834cb2 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -370,6 +370,7 @@ typedef union {
 #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
 #define SOCKET_OPT_IP_RECVTOS         25
 #define SOCKET_OPT_IP_ROUTER_ALERT    28
 #define SOCKET_OPT_IP_TOS             30
@@ -893,6 +894,11 @@ static ERL_NIF_TERM nsetopt_lvl_ip_multicast_ttl(ErlNifEnv*        env,
                                                  SocketDescriptor* descP,
                                                  ERL_NIF_TERM      eVal);
 #endif
+#if defined(IP_NODEFRAG)
+static ERL_NIF_TERM nsetopt_lvl_ip_nodefrag(ErlNifEnv*        env,
+                                            SocketDescriptor* descP,
+                                            ERL_NIF_TERM      eVal);
+#endif
 #if defined(IP_RECVTOS)
 static ERL_NIF_TERM nsetopt_lvl_ip_recvtos(ErlNifEnv*        env,
                                            SocketDescriptor* descP,
@@ -1085,6 +1091,10 @@ static ERL_NIF_TERM ngetopt_lvl_ip_multicast_loop(ErlNifEnv*        env,
 static ERL_NIF_TERM ngetopt_lvl_ip_multicast_ttl(ErlNifEnv*        env,
                                                  SocketDescriptor* descP);
 #endif
+#if defined(IP_NODEFRAG)
+static ERL_NIF_TERM ngetopt_lvl_ip_nodefrag(ErlNifEnv*        env,
+                                            SocketDescriptor* descP);
+#endif
 #if defined(IP_RECVTOS)
 static ERL_NIF_TERM ngetopt_lvl_ip_recvtos(ErlNifEnv*        env,
                                            SocketDescriptor* descP);
@@ -4055,6 +4065,12 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv*        env,
         break;
 #endif
 
+#if defined(IP_MULTICAST_ALL)
+    case SOCKET_OPT_IP_MULTICAST_ALL:
+        result = nsetopt_lvl_ip_multicast_all(env, descP, eVal);
+        break;
+#endif
+
 #if defined(IP_MULTICAST_IF)
     case SOCKET_OPT_IP_MULTICAST_IF:
         result = nsetopt_lvl_ip_multicast_if(env, descP, eVal);
@@ -4073,6 +4089,12 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv*        env,
         break;
 #endif
 
+#if defined(IP_NODEFRAG)
+    case SOCKET_OPT_IP_NODEFRAG:
+        result = nsetopt_lvl_ip_nodefrag(env, descP, eVal);
+        break;
+#endif
+
 #if defined(IP_RECVTOS)
     case SOCKET_OPT_IP_RECVTOS:
         result = nsetopt_lvl_ip_recvtos(env, descP, eVal);
@@ -4338,6 +4360,25 @@ ERL_NIF_TERM nsetopt_lvl_ip_multicast_ttl(ErlNifEnv*        env,
 #endif
 
 
+/* nsetopt_lvl_ip_nodefrag - Level IP NODEFRAG option
+ */
+#if defined(IP_NODEFRAG)
+static
+ERL_NIF_TERM nsetopt_lvl_ip_nodefrag(ErlNifEnv*        env,
+                                     SocketDescriptor* descP,
+                                     ERL_NIF_TERM      eVal)
+{
+#if defined(SOL_IP)
+    int level = SOL_IP;
+#else
+    int level = IPPROTO_IP;
+#endif
+
+    return nsetopt_bool_opt(env, descP, level, IP_NODEFRAG, eVal);
+}
+#endif
+
+
 /* nsetopt_lvl_ip_recvtos - Level IP RECVTOS option
  */
 #if defined(IP_RECVTOS)
@@ -5603,6 +5644,12 @@ ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv*        env,
         break;
 #endif
 
+#if defined(IP_NODEFRAG)
+    case SOCKET_OPT_IP_NODEFRAG:
+        result = ngetopt_lvl_ip_nodefrag(env, descP);
+        break;
+#endif
+
 #if defined(IP_RECVTOS)
     case SOCKET_OPT_IP_RECVTOS:
         result = ngetopt_lvl_ip_recvtos(env, descP);
@@ -5779,6 +5826,24 @@ ERL_NIF_TERM ngetopt_lvl_ip_multicast_ttl(ErlNifEnv*        env,
 #endif
 
 
+/* ngetopt_lvl_ip_nodefrag - Level IP NODEFRAG option
+ */
+#if defined(IP_NODEFRAG)
+static
+ERL_NIF_TERM ngetopt_lvl_ip_nodefrag(ErlNifEnv*        env,
+                                     SocketDescriptor* descP)
+{
+#if defined(SOL_IP)
+    int level = SOL_IP;
+#else
+    int level = IPPROTO_IP;
+#endif
+
+    return ngetopt_bool_opt(env, descP, level, IP_NODEFRAG);
+}
+#endif
+
+
 /* ngetopt_lvl_ip_recvtos - Level IP RECVTOS option
  */
 #if defined(IP_RECVTOS)
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index ca05529931..359a329287 100644
Binary files a/erts/preloaded/ebin/socket.beam and b/erts/preloaded/ebin/socket.beam differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 643f59467b..3077a794a5 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -531,7 +531,7 @@
 -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).
+-define(SOCKET_OPT_IP_NODEFRAG,              17).
 %% -define(SOCKET_OPT_IP_OPTIONS,               18).
 %% -define(SOCKET_OPT_IP_PKTINFO,               19).
 %% -define(SOCKET_OPT_IP_RECVERR,               20).
@@ -2004,6 +2004,9 @@ enc_setopt_value(ip, multicast_loop, V, _D, _T, _P)
 enc_setopt_value(ip, multicast_ttl, V, _D, _T, _P)
   when is_integer(V) andalso (0 =< V) andalso (V =< 255) ->
     V;
+enc_setopt_value(ip, nodefrag, V, _D, _T, _P)
+  when is_boolean(V) ->
+    V;
 enc_setopt_value(ip, recvtos, V, _D, _T, _P)
   when is_boolean(V) ->
     V;
@@ -2300,8 +2303,8 @@ 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) ->
     ?SOCKET_OPT_IP_MULTICAST_TTL;
-enc_sockopt_key(ip = L, nodefrag = Opt, _Dir, _D, raw = _T, _P) ->
-    not_supported({L, Opt});
+enc_sockopt_key(ip = _L, nodefrag = _Opt, _Dir, _D, raw = _T, _P) ->
+    ?SOCKET_OPT_IP_NODEFRAG;
 enc_sockopt_key(ip = L, options = Opt, _Dir, _D, _T, _P) ->
     not_supported({Opt, L});
 enc_sockopt_key(ip = L, pktinfo = Opt, _Dir, _D, _T, _P) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index f2d63c4dc1..6a207a7b1b 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -436,10 +436,14 @@ handler_init(Manager, ID, Peek, Sock) ->
             i("got continue"),
             handler_reply(Pid, Ref, ok),
             G = fun(K) -> case socket:getopt(Sock, ip, K) of
-                      {ok, Val} ->
-                          f("~w", [Val]);
-                      {error, _} ->
-                          "-"
+                              {ok, Val} ->
+                                  f("~p", [Val]);
+                              {error, R} when is_atom(R) ->
+                                  f("error: ~w", [R]);
+                              {error, {T, R}} when is_atom(T) ->
+                                  f("error: ~w, ~p", [T, R]);
+                              {error, R} ->
+                                  f("error: ~p", [R])
                           end
                 end,
             {ok, Domain} = socket:getopt(Sock, socket, domain),
@@ -449,12 +453,13 @@ 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),
-            MTU     = G(mtu),
-            MTUDisc = G(mtu_discover),
+            MTU          = G(mtu),
+            MTUDisc      = G(mtu_discover),
             {ok, MALL}   = socket:getopt(Sock, ip,     multicast_all),
             {ok, MIF}    = socket:getopt(Sock, ip,     multicast_if),
             {ok, MLoop}  = socket:getopt(Sock, ip,     multicast_loop),
             {ok, MTTL}   = socket:getopt(Sock, ip,     multicast_ttl),
+            NF           = G(nodefrag), % raw only
             i("got continue when: "
               "~n   (socket) Domain:         ~p"
               "~n   (socket) Type:           ~p"
@@ -468,10 +473,12 @@ handler_init(Manager, ID, Peek, Sock) ->
               "~n   (ip)     Multicast ALL:  ~p"
               "~n   (ip)     Multicast IF:   ~p"
               "~n   (ip)     Multicast Loop: ~p"
-              "~n   (ip)     Multicast TTL:  ~p", 
+              "~n   (ip)     Multicast TTL:  ~p"
+              "~n   (ip)     NodeFrag:       ~s",
               [Domain, Type, Proto,
                OOBI, SndBuf, RcvBuf, Linger,
-               MTU, MTUDisc, MALL, MIF, MLoop, MTTL]),
+               MTU, MTUDisc, MALL, MIF, MLoop, MTTL,
+               NF]),
             %% socket:setopt(Sock, otp, debug, true),
             handler_loop(#handler{peek    = Peek,
                                   manager = Manager,
-- 
cgit v1.2.3