From 8118227d80fc41efac23d30a5601fdfadb75931f Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Tue, 10 Jul 2018 17:41:40 +0200
Subject: [socket-nif] Add support for socket (level ip) option multicast_if

Added support for the IP option MULTICAST_IF.

OTP-14831
---
 lib/kernel/test/socket_client.erl | 77 +++++++++++++++++++++++++++++++--------
 lib/kernel/test/socket_server.erl | 22 ++++++++---
 2 files changed, 77 insertions(+), 22 deletions(-)

(limited to 'lib/kernel')

diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl
index 0b570e1f71..23d3c9956e 100644
--- a/lib/kernel/test/socket_client.erl
+++ b/lib/kernel/test/socket_client.erl
@@ -22,8 +22,8 @@
 
 -export([
          start/1,
-         start_tcp/1, start_tcp/2,
-         start_udp/1, start_udp/2
+         start_tcp/1, start_tcp/2, start_tcp6/1,
+         start_udp/1, start_udp/2, start_udp6/1
         ]).
 
 -define(LIB, socket_lib).
@@ -36,6 +36,9 @@ start(Port) ->
 start_tcp(Port) ->
     start(inet, stream, tcp, Port).
 
+start_tcp6(Port) ->
+    start(inet6, stream, tcp, Port).
+
 start_tcp(Addr, Port) when (size(Addr) =:= 4) ->
     start(inet, stream, tcp, Addr, Port);
 start_tcp(Addr, Port) when (size(Addr) =:= 8) ->
@@ -45,6 +48,9 @@ start_tcp(Addr, Port) when (size(Addr) =:= 8) ->
 start_udp(Port) ->
     start(inet, dgram, udp, Port).
 
+start_udp6(Port) ->
+    start(inet6, dgram, udp, Port).
+
 start_udp(Addr, Port) when (size(Addr) =:= 4) ->
     start(inet, dgram, udp, Addr, Port);
 start_udp(Addr, Port) when (size(Addr) =:= 8) ->
@@ -65,21 +71,37 @@ do_start(Domain, stream = Type, Proto, SA) ->
     try do_init(Domain, Type, Proto) of
         Sock ->
             connect(Sock, SA),
+            {ok, Name} = socket:sockname(Sock), 
+            {ok, Peer} = socket:peername(Sock),
+            {ok, Domain} = socket:getopt(Sock, socket, domain),
+            {ok, Type}   = socket:getopt(Sock, socket, type),
+            {ok, Proto}  = socket:getopt(Sock, socket, protocol),
+            {ok, OOBI}   = socket:getopt(Sock, socket, oobinline),
+            {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
+            {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
+            {ok, Linger} = socket:getopt(Sock, socket, linger),
+            {ok, MIF}    = socket:getopt(Sock, ip,     multicast_if),
+            {ok, MLoop}  = socket:getopt(Sock, ip,     multicast_loop),
+            {ok, MTTL}   = socket:getopt(Sock, ip,     multicast_ttl),
             i("connected: "
               "~n   From: ~p"
-              "~n   To:   ~p", 
-              [
-               case socket:sockname(Sock) of
-                   {ok, Name} -> Name;
-                   {error, _} = NE -> NE
-               end,
-               case socket:peername(Sock) of
-                   {ok, Name} -> Name;
-                   {error, _} = PE -> PE
-               end
-              ]),
+              "~n   To:   ~p"
+              "~nwhen"
+              "~n   (socket) Domain:         ~p"
+              "~n   (socket) Type:           ~p"
+              "~n   (socket) Protocol:       ~p"
+              "~n   (socket) OOBInline:      ~p"
+              "~n   (socket) SndBuf:         ~p"
+              "~n   (socket) RcvBuf:         ~p"
+              "~n   (socket) Linger:         ~p"
+              "~n   (ip)     Multicast IF:   ~p"
+              "~n   (ip)     Multicast Loop: ~p"
+              "~n   (ip)     Multicast TTL:  ~p"
+              "~n   => wait some", 
+              [Name, Peer,
+               Domain, Type, Proto, 
+               OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
             %% Give the server some time...
-            i("wait some", []),
             ?LIB:sleep(5000),
             %% ok = socket:close(Sock),
             send_loop(#client{socket = Sock, 
@@ -93,7 +115,30 @@ do_start(Domain, dgram = Type, Proto, SA) ->
     try do_init(Domain, Type, Proto) of
         Sock ->
             %% Give the server some time...
-            i("wait some", []),
+            {ok, Domain} = socket:getopt(Sock, socket, domain),
+            {ok, Type}   = socket:getopt(Sock, socket, type),
+            {ok, Proto}  = socket:getopt(Sock, socket, protocol),
+            {ok, OOBI}   = socket:getopt(Sock, socket, oobinline),
+            {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf),
+            {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf),
+            {ok, Linger} = socket:getopt(Sock, socket, linger),
+            {ok, MIF}    = socket:getopt(Sock, ip,     multicast_if),
+            {ok, MLoop}  = socket:getopt(Sock, ip,     multicast_loop),
+            {ok, MTTL}   = socket:getopt(Sock, ip,     multicast_ttl),
+            i("initiated when: "
+              "~n   (socket) Domain:         ~p"
+              "~n   (socket) Type:           ~p"
+              "~n   (socket) Protocol:       ~p"
+              "~n   (socket) OOBInline:      ~p"
+              "~n   (socket) SndBuf:         ~p"
+              "~n   (socket) RcvBuf:         ~p"
+              "~n   (socket) Linger:         ~p"
+              "~n   (ip)     Multicast IF:   ~p"
+              "~n   (ip)     Multicast Loop: ~p"
+              "~n   (ip)     Multicast TTL:  ~p"
+              "~n   => wait some", 
+              [Domain, Type, Proto, 
+               OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
             ?LIB:sleep(5000),
             %% ok = socket:close(Sock),
             send_loop(#client{socket = Sock, 
@@ -185,7 +230,7 @@ send_loop(#client{msg_id = N} = C) when (N =< 10) ->
             end;
         {error, SReason} ->
             e("Failed send request ~w: "
-              "~n   ~p", [SReason]),
+              "~n   ~p", [N, SReason]),
             exit({failed_send, SReason})
     end;
 send_loop(#client{socket = Sock}) ->
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 9e4e355179..5fd32e040c 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -21,7 +21,7 @@
 -module(socket_server).
 
 -export([
-         start/0,
+         start/0, start/4,
          start_tcp/0, start_tcp/1,
          start_udp/0, start_udp/1
         ]).
@@ -104,7 +104,7 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
                               {error, _} -> "-"
                           end
                 end,
-            i("(socket) open (~s,~s,~s): "
+            i("socket opened (~s,~s,~s): "
               "~n   broadcast: ~s"
               "~n   dontroute: ~s"
               "~n   keepalive: ~s"
@@ -114,13 +114,15 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
               "~n   prio:      ~s"
               "~n   rcvbuf:    ~s"
               "~n   sndbuf:    ~s"
-              "~n   try find (local) address", 
+              "~n   => try find (local) address", 
               [F(domain), F(type), F(protocol), 
                F(broadcast), F(dontroute), F(keepalive), F(reuseaddr), F(linger),
                F(debug), F(priority), F(rcvbuf), F(sndbuf)]),
             Addr = which_addr(Domain),
             SA = #{family => Domain,
                    addr   => Addr},
+            i("try bind to: "
+              "~n   ~p", [Addr]),
             case socket:bind(Sock, SA) of
                 {ok, _P} ->
                    ok;
@@ -290,7 +292,9 @@ acceptor_do_init(Domain, Type, Proto) ->
     Addr = which_addr(Domain),
     SA = #{family => Domain,
            addr   => Addr},
-    i("found (~p) - try (socket) bind", [Addr]),
+    i("found: "
+      "~n   ~p"
+      "~n   => try (socket) bind", [Addr]),
     %% ok = socket:setopt(Sock, otp, debug, true),
     %% ok = socket:setopt(Sock, socket, debug, 1), %% must have rights!!
     Port = case socket:bind(Sock, SA) of
@@ -301,7 +305,9 @@ acceptor_do_init(Domain, Type, Proto) ->
                {error, BReason} ->
                    throw({bind, BReason})
            end,
-    i("bound (~w) - try (socket) listen (acceptconn: ~s)", 
+    i("bound to: "
+      "~n   ~p"
+      "~n   => try (socket) listen (acceptconn: ~s)", 
       [Port, F(acceptconn)]),
     case socket:listen(Sock) of
         ok ->
@@ -328,6 +334,8 @@ which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") ->
 which_addr(Domain, [_|IFL]) ->
     which_addr(Domain, IFL).
 
+which_addr2(_, []) ->
+    throw(no_address);
 which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) ->
     Addr;
 which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) ->
@@ -434,6 +442,7 @@ 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),
+            {ok, MIF}    = socket:getopt(Sock, ip,     multicast_if),
             {ok, MLoop}  = socket:getopt(Sock, ip,     multicast_loop),
             {ok, MTTL}   = socket:getopt(Sock, ip,     multicast_ttl),
             i("got continue when: "
@@ -444,10 +453,11 @@ handler_init(Manager, ID, Peek, Sock) ->
               "~n   (socket) SndBuf:         ~p"
               "~n   (socket) RcvBuf:         ~p"
               "~n   (socket) Linger:         ~p"
+              "~n   (ip)     Multicast IF:   ~p"
               "~n   (ip)     Multicast Loop: ~p"
               "~n   (ip)     Multicast TTL:  ~p", 
               [Domain, Type, Proto, 
-               OOBI, SndBuf, RcvBuf, Linger, MLoop, MTTL]),
+               OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]),
             %% socket:setopt(Sock, otp, debug, true),
             handler_loop(#handler{peek    = Peek,
                                   manager = Manager,
-- 
cgit v1.2.3