From 39e137878aa5d1f745cf3c343429fe9de47ed1be Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Mon, 13 May 2019 12:55:03 +0200
Subject: [esock|test] Add plain (stream) send and recv test case for local

Add a plain send and recv test case for a unix domain (stream) socket.

OTP-15822
---
 erts/emulator/test/socket_SUITE.erl | 224 +++++++++++++++++++++++-------------
 1 file changed, 146 insertions(+), 78 deletions(-)

(limited to 'erts')

diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 74a6e2ecde..639dfcd14d 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -75,6 +75,7 @@
          api_b_sendto_and_recvfrom_udp4/1,
          api_b_sendmsg_and_recvmsg_udp4/1,
          api_b_send_and_recv_tcp4/1,
+         api_b_send_and_recv_tcpL/1,
          api_b_sendmsg_and_recvmsg_tcp4/1,
 
          %% *** API Options ***
@@ -595,6 +596,7 @@ api_basic_cases() ->
      api_b_sendto_and_recvfrom_udp4,
      api_b_sendmsg_and_recvmsg_udp4,
      api_b_send_and_recv_tcp4,
+     api_b_send_and_recv_tcpL,
      api_b_sendmsg_and_recvmsg_tcp4
     ].
 
@@ -1523,6 +1525,7 @@ api_b_open_and_close_udpL(doc) ->
 api_b_open_and_close_udpL(_Config) when is_list(_Config) ->
     ?TT(?SECS(5)),
     tc_try(api_b_open_and_close_udpL,
+           fun() -> supports_unix_domain_socket() end,
            fun() ->
                    InitState = #{domain   => local,
                                  type     => dgram,
@@ -1542,6 +1545,7 @@ api_b_open_and_close_tcpL(doc) ->
 api_b_open_and_close_tcpL(_Config) when is_list(_Config) ->
     ?TT(?SECS(5)),
     tc_try(api_b_open_and_close_tcpL,
+           fun() -> supports_unix_domain_socket() end,
            fun() ->
                    InitState = #{domain   => local,
                                  type     => stream,
@@ -1731,8 +1735,7 @@ api_b_send_and_recv_udp(InitState) ->
         [
          #{desc => "local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "open src socket",
@@ -1838,6 +1841,36 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) ->
                                   socket:recv(Sock)
                           end,
                    InitState = #{domain => inet,
+                                 type   => stream,
+                                 proto  => tcp,
+                                 send   => Send,
+                                 recv   => Recv},
+                   ok = api_b_send_and_recv_tcp(InitState)
+           end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Basically send and receive using the "common" functions (send and recv)
+%% on an IPv4 TCP (stream) socket.
+api_b_send_and_recv_tcpL(suite) ->
+    [];
+api_b_send_and_recv_tcpL(doc) ->
+    [];
+api_b_send_and_recv_tcpL(_Config) when is_list(_Config) ->
+    ?TT(?SECS(10)),
+    tc_try(api_b_send_and_recv_tcpL,
+           fun() -> supports_unix_domain_socket() end,
+           fun() ->
+                   Send = fun(Sock, Data) ->
+                                  socket:send(Sock, Data)
+                          end,
+                   Recv = fun(Sock) ->
+                                  socket:recv(Sock)
+                          end,
+                   InitState = #{domain => local,
+                                 type   => stream,
+                                 proto  => default,
                                  send   => Send,
                                  recv   => Recv},
                    ok = api_b_send_and_recv_tcp(InitState)
@@ -1870,6 +1903,8 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
                                   end
                           end,
                    InitState = #{domain => inet,
+                                 type   => stream,
+                                 proto  => tcp,
                                  send   => Send,
                                  recv   => Recv},
                    ok = api_b_send_and_recv_tcp(InitState)
@@ -1897,13 +1932,14 @@ api_b_send_and_recv_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "create listen socket",
-           cmd  => fun(#{domain := Domain} = State) ->
-                           case socket:open(Domain, stream, tcp) of
+           cmd  => fun(#{domain := Domain,
+                         type   := Type,
+                         proto  := Proto} = State) ->
+                           case socket:open(Domain, Type, Proto) of
                                {ok, Sock} ->
                                    {ok, State#{lsock => Sock}};
                                {error, _} = ERROR ->
@@ -1911,9 +1947,19 @@ api_b_send_and_recv_tcp(InitState) ->
                            end
                    end},
          #{desc => "bind to local address",
-           cmd  => fun(#{lsock := LSock, lsa := LSA} = State) ->
+           cmd  => fun(#{domain := local,
+                         lsock  := LSock,
+                         lsa    := LSA} = _State) ->
+                           case socket:bind(LSock, LSA) of
+                               {ok, _Port} ->
+                                   ok; % We do not care about the port for local
+                               {error, _} = ERROR ->
+                                   ERROR
+                           end;
+                      (#{lsock := LSock, lsa := LSA} = State) ->
                            case socket:bind(LSock, LSA) of
                                {ok, Port} ->
+                                   ?SEV_IPRINT("bound to port: ~w", [Port]),
                                    {ok, State#{lport => Port}};
                                {error, _} = ERROR ->
                                    ERROR
@@ -1924,7 +1970,12 @@ api_b_send_and_recv_tcp(InitState) ->
                            socket:listen(LSock)
                    end},
          #{desc => "announce ready (init)",
-           cmd  => fun(#{tester := Tester, lport := Port}) ->
+           cmd  => fun(#{domain := local,
+                         tester := Tester, lsa := #{path := Path}}) ->
+                           ?SEV_ANNOUNCE_READY(Tester, init, Path),
+                           ok;
+                      (#{tester := Tester, lport := Port}) ->
+                           %% This is actually not used for unix domain socket
                            ?SEV_ANNOUNCE_READY(Tester, init, Port),
                            ok
                    end},
@@ -1988,7 +2039,20 @@ api_b_send_and_recv_tcp(InitState) ->
                            end
                    end},
          #{desc => "close connection socket",
-           cmd  => fun(#{csock := Sock}) ->
+           cmd  => fun(#{domain := local,
+                         csock  := Sock,
+                         lsa    := #{path := Path}}) ->
+                           ok = socket:close(Sock),
+                           case os:cmd("unlink " ++ Path) of
+                               "" ->
+                                   ok;
+                               Result ->
+                                   ?SEV_IPRINT("unlink result: "
+                                               "~n   ~s", [Result]),
+                                   ok
+                           end,
+                           ok;
+                      (#{csock := Sock}) ->
                            socket:close(Sock)
                    end},
          #{desc => "close listen socket",
@@ -2004,7 +2068,10 @@ api_b_send_and_recv_tcp(InitState) ->
         [
          %% *** Wait for start order ***
          #{desc => "await start (from tester)",
-           cmd  => fun(State) ->
+           cmd  => fun(#{domain := local} = State) ->
+                           {Tester, Path} = ?SEV_AWAIT_START(),
+                           {ok, State#{tester => Tester, server_path => Path}};
+                      (State) ->
                            {Tester, Port} = ?SEV_AWAIT_START(),
                            {ok, State#{tester => Tester, server_port => Port}}
                    end},
@@ -2016,16 +2083,21 @@ api_b_send_and_recv_tcp(InitState) ->
 
          %% *** The init part ***
          #{desc => "which server (local) address",
-           cmd  => fun(#{domain := Domain, server_port := Port} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, 
-                                     addr   => LAddr},
-                           SSA   = LSA#{port => Port},
+           cmd  => fun(#{domain      := local = Domain,
+                         server_path := Path} = State) ->
+                           LSA = which_local_socket_addr(Domain),
+                           SSA = #{family => Domain, path => Path},
+                           {ok, State#{local_sa => LSA, server_sa => SSA}};
+                      (#{domain := Domain, server_port := Port} = State) ->
+                           LSA = which_local_socket_addr(Domain),
+                           SSA = LSA#{port => Port},
                            {ok, State#{local_sa => LSA, server_sa => SSA}}
                    end},
          #{desc => "create socket",
-           cmd  => fun(#{domain := Domain} = State) ->
-                           case socket:open(Domain, stream, tcp) of
+           cmd  => fun(#{domain := Domain,
+                         type   := Type,
+                         proto  := Proto} = State) ->
+                           case socket:open(Domain, Type, Proto) of
                                {ok, Sock} ->
                                    {ok, State#{sock => Sock}};
                                {error, _} = ERROR ->
@@ -2096,7 +2168,20 @@ api_b_send_and_recv_tcp(InitState) ->
                            end
                    end},
          #{desc => "close socket",
-           cmd  => fun(#{sock := Sock}) ->
+           cmd  => fun(#{domain   := local,
+                         sock     := Sock,
+                         local_sa := #{path := Path}}) ->
+                           ok = socket:close(Sock),
+                           case os:cmd("unlink " ++ Path) of
+                               "" ->
+                                   ok;
+                               Result ->
+                                   ?SEV_IPRINT("unlink result:"
+                                               "~n   ~s", [Result]),
+                                   ok
+                           end,
+                           ok;
+                      (#{sock := Sock} = S) ->
                            socket:close(Sock)
                    end},
 
@@ -2572,8 +2657,7 @@ api_opt_simple_otp_rcvbuf_option() ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -2818,8 +2902,7 @@ api_opt_simple_otp_rcvbuf_option() ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create socket",
@@ -3573,8 +3656,7 @@ api_to_connect_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -3645,8 +3727,7 @@ api_to_connect_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create node",
@@ -3796,8 +3877,7 @@ api_to_connect_tcp(InitState) ->
                    end},
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "order server start",
@@ -3948,9 +4028,7 @@ api_toc_tcp_client_await_terminate(Parent) ->
     end.
 
 api_to_connect_tcp_await_timeout(To, ServerSA, Domain, ConLimit) ->
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain,
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     NewSock = fun() ->
                       S = case socket:open(Domain, stream, tcp) of
                               {ok, Sock} ->
@@ -4062,8 +4140,7 @@ api_to_accept_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "create (listen) socket",
@@ -4187,8 +4264,7 @@ api_to_maccept_tcp(InitState) ->
                    end},
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "create (listen) socket",
@@ -4705,8 +4781,7 @@ api_to_receive_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -4824,10 +4899,8 @@ api_to_receive_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain, server_port := Port} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain,
-                                     addr   => LAddr},
-                           SSA   = LSA#{port => Port},
+                           LSA = which_local_socket_addr(Domain),
+                           SSA = LSA#{port => Port},
                            {ok, State#{local_sa => LSA, server_sa => SSA}}
                    end},
          #{desc => "create socket",
@@ -5043,8 +5116,7 @@ api_to_receive_udp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "create socket",
@@ -5486,8 +5558,7 @@ sc_lc_receive_response_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create (listen) socket",
@@ -5709,8 +5780,7 @@ sc_lc_receive_response_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create socket",
@@ -6097,8 +6167,7 @@ sc_lc_receive_response_udp(InitState) ->
          %% *** Init part ***
          #{desc => "local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "open socket",
@@ -6606,8 +6675,7 @@ sc_lc_acceptor_response_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{lsa => LSA}}
                    end},
          #{desc => "create (listen) socket",
@@ -7046,8 +7114,7 @@ sc_rc_receive_response_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -7756,9 +7823,7 @@ sc_rc_tcp_client_create(Domain) ->
 
 sc_rc_tcp_client_bind(Sock, Domain) ->
     i("sc_rc_tcp_client_bind -> entry"),
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain, 
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     case socket:bind(Sock, LSA) of
         {ok, _} ->
             ok;
@@ -7994,8 +8059,7 @@ sc_rs_send_shutdown_receive_tcp(InitState) ->
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
                            i("get local address for ~p", [Domain]),
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -8590,9 +8654,7 @@ sc_rs_tcp_client_create(Domain) ->
 
 sc_rs_tcp_client_bind(Sock, Domain) ->
     i("sc_rs_tcp_client_bind -> entry"),
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain,
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     case socket:bind(Sock, LSA) of
         {ok, _} ->
             ok;
@@ -8865,8 +8927,7 @@ traffic_send_and_recv_chunks_tcp(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -9750,9 +9811,7 @@ traffic_snr_tcp_client_create(Domain) ->
 
 traffic_snr_tcp_client_bind(Sock, Domain) ->
     i("traffic_snr_tcp_client_bind -> entry"),
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain, 
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     case socket:bind(Sock, LSA) of
         {ok, _} ->
             ok;
@@ -10423,8 +10482,7 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -11151,9 +11209,7 @@ tpp_tcp_client_sock_open(Domain, BufInit) ->
     end.
 
 tpp_tcp_client_sock_bind(Sock, Domain) ->
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain, 
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     case socket:bind(Sock, LSA) of
         {ok, _} ->
             ok;
@@ -11342,8 +11398,7 @@ traffic_ping_pong_send_and_receive_udp2(InitState) ->
          %% *** Init part ***
          #{desc => "which local address",
            cmd  => fun(#{domain := Domain} = State) ->
-                           LAddr = which_local_addr(Domain),
-                           LSA   = #{family => Domain, addr => LAddr},
+                           LSA = which_local_socket_addr(Domain),
                            {ok, State#{local_sa => LSA}}
                    end},
          #{desc => "create listen socket",
@@ -12049,9 +12104,7 @@ tpp_udp_sock_open(Domain, BufInit) ->
     end.
 
 tpp_udp_sock_bind(Sock, Domain) ->
-    LAddr = which_local_addr(Domain),
-    LSA   = #{family => Domain, 
-              addr   => LAddr},
+    LSA = which_local_socket_addr(Domain),
     case socket:bind(Sock, LSA) of
         {ok, _} ->
             ok;
@@ -17941,13 +17994,19 @@ local_host() ->
     end.
 
 
+which_local_socket_addr(local = Domain) ->
+    #{family => Domain,
+      path   => ?LIB:f("/tmp/socket_~w", [erlang:unique_integer()])};
+
 %% This gets the local address (not 127.0...)
 %% We should really implement this using the (new) net module,
 %% but until that gets the necessary functionality...
-which_local_addr(Domain) ->
+which_local_socket_addr(Domain) ->
     case inet:getifaddrs() of
         {ok, IFL} ->
-            which_addr(Domain, IFL);
+            Addr = which_addr(Domain, IFL),
+            #{family => Domain,
+              addr   => Addr};
         {error, Reason} ->
             ?FAIL({inet, getifaddrs, Reason})
     end.
@@ -17983,6 +18042,15 @@ which_addr2(Domain, [_|IFO]) ->
 
 %% Here are all the *general* test vase condition functions.
 
+supports_unix_domain_socket() ->
+    case os:type() of
+        {win32, _} ->
+            {skip, "Not supported"};
+        _ ->
+            ok
+    end.
+
+
 %% The idea is that this function shall test if the test host has 
 %% support for IPv6. If not, there is no point in running IPv6 tests.
 %% Currently we just skip.
-- 
cgit v1.2.3