From 9b45f4dd2cc8862a183941bb4925223bcec35987 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 27 Jun 2018 18:37:29 +0200 Subject: [test-socket-nif] Add *very primitive* test progs --- lib/kernel/test/socket_client.erl | 99 +++++++++++++++++++++++++++++++++++ lib/kernel/test/socket_server.erl | 107 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 lib/kernel/test/socket_client.erl create mode 100644 lib/kernel/test/socket_server.erl (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl new file mode 100644 index 0000000000..6d74d19442 --- /dev/null +++ b/lib/kernel/test/socket_client.erl @@ -0,0 +1,99 @@ +%%%------------------------------------------------------------------- +%%% @author Micael Karlberg +%%% @copyright (C) 2018, Micael Karlberg +%%% @doc +%%% +%%% @end +%%% Created : 27 Jun 2018 by Micael Karlberg +%%%------------------------------------------------------------------- +-module(client). + +-export([start/1]). + +start(Port) -> + start_tcp(Port). + +start_tcp(Port) -> + start(inet, stream, tcp, Port). + +start(Domain, Type, Proto, Port) -> + try do_init(Domain, Type, Proto) of + Sock -> + connect(Sock, Domain, Port) + catch + throw:E:P -> + e("Failed initiate: " + "~n Error: ~p" + "~n Path: ~p", [E, P]) + end. + +do_init(Domain, Type, Proto) -> + i("try (socket) open"), + Sock = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, OReason} -> + throw({open, OReason}) + end, + i("try (socket) bind"), + case socket:bind(Sock, any) of + {ok, _P} -> + Sock; + {error, BReason} -> + throw({bind, BReason}) + end. + +which_addr(Domain) -> + Iflist = case inet:getifaddrs() of + {ok, IFL} -> + IFL; + {error, Reason} -> + throw({inet,getifaddrs,Reason}) + end, + which_addr(Domain, Iflist). + + +connect(Sock, Domain, Port) -> + Addr = which_addr(Domain), + SA = #{family => Domain, + addr => Addr, + port => Port}, + i("try (socket) connect to ~p", [SA]), + case socket:connect(Sock, SA) of + ok -> + i("connected"), + ok; + {error, Reason} -> + e("connect failure: " + "~n ~p", [Reason]), + exit({connect, Reason}) + end. + + +which_addr(_Domain, []) -> + throw(no_address); +which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> + which_addr2(Domain, IFO); +which_addr(Domain, [_|IFL]) -> + which_addr(Domain, IFL). + +which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> + Addr; +which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> + Addr; +which_addr2(Domain, [_|IFO]) -> + which_addr2(Domain, IFO). + + + +e(F, A) -> + p(" " ++ F, A). + +i(F) -> + i(F, []). +i(F, A) -> + p("*** " ++ F, A). + +p(F, A) -> + io:format("[client] " ++ F ++ "~n", A). + diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl new file mode 100644 index 0000000000..039998ba92 --- /dev/null +++ b/lib/kernel/test/socket_server.erl @@ -0,0 +1,107 @@ +%%%------------------------------------------------------------------- +%%% @author Micael Karlberg +%%% @copyright (C) 2018, Micael Karlberg +%%% @doc +%%% +%%% @end +%%% Created : 27 Jun 2018 by Micael Karlberg +%%%------------------------------------------------------------------- +-module(server). + +-export([start/0]). + +start() -> + start_tcp(). + +start_tcp() -> + start(inet, stream, tcp). + +start(Domain, Type, Proto) -> + try do_init(Domain, Type, Proto) of + Sock -> + accept_loop(Sock) + catch + throw:E:P -> + e("Failed initiate: " + "~n Error: ~p" + "~n Path: ~p", [E, P]) + end. + +do_init(Domain, Type, Proto) -> + i("try (socket) open"), + Sock = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, OReason} -> + throw({open, OReason}) + end, + i("opened - now try find (local) address"), + Addr = which_addr(Domain), + SA = #{family => Domain, + addr => Addr}, + i("addr ~p - now try (socket) bind", [Addr]), + Port = case socket:bind(Sock, SA) of + {ok, P} -> + P; + {error, BReason} -> + throw({bind, BReason}) + end, + i("bound to ~w - now try (socket) listen", [Port]), + case socket:listen(Sock) of + ok -> + Sock; + {error, LReason} -> + throw({listen, LReason}) + end. + +which_addr(Domain) -> + Iflist = case inet:getifaddrs() of + {ok, IFL} -> + IFL; + {error, Reason} -> + throw({inet,getifaddrs,Reason}) + end, + which_addr(Domain, Iflist). + +which_addr(_Domain, []) -> + throw(no_address); +which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> + which_addr2(Domain, IFO); +which_addr(Domain, [_|IFL]) -> + which_addr(Domain, IFL). + +which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> + Addr; +which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> + Addr; +which_addr2(Domain, [_|IFO]) -> + which_addr2(Domain, IFO). + + +accept_loop(LSock) -> + accept_loop(LSock, []). + +accept_loop(LSock, Socks) -> + i("try accept"), + case socket:accept(LSock, infinity) of + {ok, Sock} -> + i("accepted: ~p", [Sock]), + accept_loop(LSock, [Sock|Socks]); + {error, Reason} -> + e("accept failure: " + "~n ~p", [Reason]), + exit({accept, Reason}) + end. + + +e(F, A) -> + p(" " ++ F, A). + +i(F) -> + i(F, []). +i(F, A) -> + p("*** " ++ F, A). + +p(F, A) -> + io:format("[server] " ++ F ++ "~n", A). + -- cgit v1.2.3 From b09136301525b0717e897ec0864c3d2ea7708758 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 28 Jun 2018 21:57:03 +0200 Subject: [socket-nit-test] Added some more test code Added some more features o the simple socket test server and client. OTP-14831 --- lib/kernel/test/Makefile | 13 ++++++- lib/kernel/test/socket_client.erl | 23 +++++++++++- lib/kernel/test/socket_server.erl | 73 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 103 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 4a86265a4a..07e7922d3d 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -24,6 +24,10 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Target Specs # ---------------------------------------------------- +SOCKET_MODULES = \ + socket_server \ + socket_client + MODULES= \ rpc_SUITE \ pdict_SUITE \ @@ -90,7 +94,8 @@ MODULES= \ sendfile_SUITE \ standard_error_SUITE \ multi_load_SUITE \ - zzz_SUITE + zzz_SUITE \ + $(SOCKET_MODULES) APP_FILES = \ appinc.app \ @@ -127,6 +132,9 @@ ERL_COMPILE_FLAGS += EBIN = . +SOCKET_TARGETS = $(SOCKET_MODULES:%=$(EBIN)/%.$(EMULATOR)) + + # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -147,6 +155,9 @@ clean: docs: +socket: $(SOCKET_TARGETS) + + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 6d74d19442..13e87f4109 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -6,7 +6,7 @@ %%% @end %%% Created : 27 Jun 2018 by Micael Karlberg %%%------------------------------------------------------------------- --module(client). +-module(socket_client). -export([start/1]). @@ -62,6 +62,7 @@ connect(Sock, Domain, Port) -> case socket:connect(Sock, SA) of ok -> i("connected"), + send_loop(Sock), ok; {error, Reason} -> e("connect failure: " @@ -70,6 +71,26 @@ connect(Sock, Domain, Port) -> end. +send_loop(Sock) -> + send_loop(Sock, 1). + +send_loop(Sock, N) -> + case socket:send(Sock, <<0:32, N:32, "hejsan">>) of + ok -> + case send:recv(Sock, 0) of + {ok, <<1:32, N:32, "hejsan">>} -> + send_loop(Sock, N+1); + {error, RReason} -> + e("Failed recv response for request ~w: " + "~n ~p", [RReason]), + exit({failed_recv, RReason}) + end; + {error, SReason} -> + e("Failed send request ~w: " + "~n ~p", [SReason]), + exit({failed_send, SReason}) + end. + which_addr(_Domain, []) -> throw(no_address); which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 039998ba92..0effc7c0ff 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -6,10 +6,12 @@ %%% @end %%% Created : 27 Jun 2018 by Micael Karlberg %%%------------------------------------------------------------------- --module(server). +-module(socket_server). -export([start/0]). +-record(handler, {socket, parent}). + start() -> start_tcp(). @@ -17,6 +19,7 @@ start_tcp() -> start(inet, stream, tcp). start(Domain, Type, Proto) -> + put(sname, "starter"), try do_init(Domain, Type, Proto) of Sock -> accept_loop(Sock) @@ -79,14 +82,23 @@ which_addr2(Domain, [_|IFO]) -> accept_loop(LSock) -> + put(sname, "accept-loop"), accept_loop(LSock, []). -accept_loop(LSock, Socks) -> +accept_loop(LSock, Handlers) -> i("try accept"), case socket:accept(LSock, infinity) of {ok, Sock} -> i("accepted: ~p", [Sock]), - accept_loop(LSock, [Sock|Socks]); + case handle_accept_success(Sock) of + {ok, Handler} -> + accept_loop(LSock, [Handler|Handlers]); + {error, HReason} -> + e("Failed starting handler: " + "~n ~p", [HReason]), + socket:close(Sock), + exit({failed_starting_handler, HReason}) + end; {error, Reason} -> e("accept failure: " "~n ~p", [Reason]), @@ -94,6 +106,56 @@ accept_loop(LSock, Socks) -> end. +handle_accept_success(Sock) -> + Self = self(), + Handler = spawn_link(fun() -> handler_init(Self, Sock) end), + case socket:setopt(Sock, otp, controlling_process, Handler) of + ok -> + %% Normally we should have a msgs collection here + %% (of messages we receive before the control was + %% handled over to Handler), but since we don't + %% have active implemented yet... + handler_continue(Handler), + {ok, {Handler, Sock}}; + {error, _} = ERROR -> + exit(Handler, kill), + ERROR + end. + + +handler_init(Parent, Socket) -> + put(sname, "handler"), + receive + {handler, Parent, continue} -> + handler_loop(#handler{parent = Parent, + socket = Socket}) + end. + +handler_continue(Handler) -> + Handler ! {handler, self(), continue}. + +handler_loop(#handler{socket = Socket} = H) -> + case socket:read(Socket, 0) of + {ok, <<0:32, N:32, ReqData/binary>>} -> + i("received request ~w: " + "~n ~p", [N, ReqData]), + Reply = <<1:32, N:32, ReqData/binary>>, + case socket:send(Socket, Reply) of + ok -> + i("successfully sent reply ~w", [N]), + handler_loop(H); + {error, SReason} -> + e("failed sending reply ~w:" + "~n ~p", [N, SReason]), + exit({failed_sending_reply, SReason}) + end; + {error, RReason} -> + e("failed reading request: " + "~n ~p", [RReason]), + exit({failed_sending_reply, RReason}) + end. + + e(F, A) -> p(" " ++ F, A). @@ -103,5 +165,8 @@ i(F, A) -> p("*** " ++ F, A). p(F, A) -> - io:format("[server] " ++ F ++ "~n", A). + p(get(sname), F, A). + +p(SName, F, A) -> + io:format("[server,~s] " ++ F ++ "~n", [SName|A]). -- cgit v1.2.3 From 24be0729fe3a1ccfd5f0713b565463d6557d8aa7 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 29 Jun 2018 18:23:55 +0200 Subject: [socket-nif] Fixed (stream) recv Fixed handling of closed in the recv function. We still need to properly handle when we get 0 bytes of data for other types ock sockets then stream (its valid for dgram for instance). OTP-14831 --- lib/kernel/test/socket_client.erl | 105 +++++++++++++++++++++++++++++++++----- lib/kernel/test/socket_server.erl | 105 ++++++++++++++++++++++++++++++++------ 2 files changed, 179 insertions(+), 31 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 13e87f4109..a284777046 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -10,6 +10,9 @@ -export([start/1]). +-define(REQ, 0). +-define(REP, 1). + start(Port) -> start_tcp(Port). @@ -19,12 +22,16 @@ start_tcp(Port) -> start(Domain, Type, Proto, Port) -> try do_init(Domain, Type, Proto) of Sock -> - connect(Sock, Domain, Port) + connect(Sock, Domain, Port), + %% Give the server some time... + p("wait some", []), + %% sleep(5000), + %% ok = socket:close(Sock), + send_loop(Sock) catch - throw:E:P -> + throw:E -> e("Failed initiate: " - "~n Error: ~p" - "~n Path: ~p", [E, P]) + "~n Error: ~p", [E]) end. do_init(Domain, Type, Proto) -> @@ -58,11 +65,11 @@ connect(Sock, Domain, Port) -> SA = #{family => Domain, addr => Addr, port => Port}, - i("try (socket) connect to ~p", [SA]), + i("try (socket) connect to:" + "~n ~p", [SA]), case socket:connect(Sock, SA) of ok -> i("connected"), - send_loop(Sock), ok; {error, Reason} -> e("connect failure: " @@ -74,22 +81,37 @@ connect(Sock, Domain, Port) -> send_loop(Sock) -> send_loop(Sock, 1). -send_loop(Sock, N) -> - case socket:send(Sock, <<0:32, N:32, "hejsan">>) of +send_loop(Sock, N) when (N =< 10) -> + i("try send request ~w", [N]), + Req = enc_req_msg(N, "hejsan"), + case socket:send(Sock, Req) of ok -> - case send:recv(Sock, 0) of - {ok, <<1:32, N:32, "hejsan">>} -> - send_loop(Sock, N+1); + i("request ~w sent - now try read answer", [N]), + case socket:recv(Sock, 0) of + {ok, Msg} -> + i("received ~w bytes of data", [size(Msg)]), + case dec_msg(Msg) of + {reply, N, Reply} -> + i("received reply ~w: ~p", [N, Reply]), + send_loop(Sock, N+1) + end; {error, RReason} -> e("Failed recv response for request ~w: " - "~n ~p", [RReason]), + "~n ~p", [N, RReason]), exit({failed_recv, RReason}) end; {error, SReason} -> e("Failed send request ~w: " "~n ~p", [SReason]), exit({failed_send, SReason}) - end. + end; +send_loop(Sock, _N) -> + i("we are done - close the socket when: " + "~n ~p", [socket:info()]), + ok = socket:close(Sock), + i("we are done - socket closed when: " + "~n ~p", [socket:info()]). + which_addr(_Domain, []) -> throw(no_address); @@ -106,6 +128,61 @@ which_addr2(Domain, [_|IFO]) -> which_addr2(Domain, IFO). +%% --- + +enc_req_msg(N, Data) -> + enc_msg(?REQ, N, Data). + +enc_rep_msg(N, Data) -> + enc_msg(?REP, N, Data). + +enc_msg(Type, N, Data) when is_list(Data) -> + enc_msg(Type, N, list_to_binary(Data)); +enc_msg(Type, N, Data) + when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> + <>. + +dec_msg(<>) -> + {request, N, Data}; +dec_msg(<>) -> + {reply, N, Data}. + + +%% --- + +sleep(T) -> + receive after T -> ok end. + + +%% --- + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp(Now) -> + N2T = fun(N) -> calendar:now_to_local_time(N) end, + format_timestamp(Now, N2T, true). + +format_timestamp({_N1, _N2, N3} = N, N2T, true) -> + FormatExtra = ".~.2.0w", + ArgsExtra = [N3 div 10000], + format_timestamp(N, N2T, FormatExtra, ArgsExtra); +format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> + FormatExtra = "", + ArgsExtra = [], + format_timestamp(N, N2T, FormatExtra, ArgsExtra). + +format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> + {Date, Time} = N2T(N), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, + [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), + lists:flatten(FormatDate). + + +%% --- e(F, A) -> p(" " ++ F, A). @@ -116,5 +193,5 @@ i(F, A) -> p("*** " ++ F, A). p(F, A) -> - io:format("[client] " ++ F ++ "~n", A). + io:format("[client,~p][~s] " ++ F ++ "~n", [self(),formated_timestamp()|A]). diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 0effc7c0ff..64bd6396e4 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -10,6 +10,9 @@ -export([start/0]). +-define(REQ, 0). +-define(REP, 1). + -record(handler, {socket, parent}). start() -> @@ -82,14 +85,17 @@ which_addr2(Domain, [_|IFO]) -> accept_loop(LSock) -> - put(sname, "accept-loop"), + put(sname, "acceptor"), accept_loop(LSock, []). accept_loop(LSock, Handlers) -> i("try accept"), case socket:accept(LSock, infinity) of {ok, Sock} -> - i("accepted: ~p", [Sock]), + i("accepted: " + "~n ~p" + "~nwhen" + "~n ~p", [Sock, socket:info()]), case handle_accept_success(Sock) of {ok, Handler} -> accept_loop(LSock, [Handler|Handlers]); @@ -127,6 +133,7 @@ handler_init(Parent, Socket) -> put(sname, "handler"), receive {handler, Parent, continue} -> + socket:setopt(Socket, otp, debug, true), handler_loop(#handler{parent = Parent, socket = Socket}) end. @@ -135,27 +142,90 @@ handler_continue(Handler) -> Handler ! {handler, self(), continue}. handler_loop(#handler{socket = Socket} = H) -> - case socket:read(Socket, 0) of - {ok, <<0:32, N:32, ReqData/binary>>} -> - i("received request ~w: " - "~n ~p", [N, ReqData]), - Reply = <<1:32, N:32, ReqData/binary>>, - case socket:send(Socket, Reply) of - ok -> - i("successfully sent reply ~w", [N]), - handler_loop(H); - {error, SReason} -> - e("failed sending reply ~w:" - "~n ~p", [N, SReason]), - exit({failed_sending_reply, SReason}) + case socket:recv(Socket, 0) of + {ok, Msg} when (size(Msg) =:= 0) -> + i("received empty msg - hickup? - try again", []), + handler_loop(H); + {ok, Msg} -> + i("received ~w bytes of data", [size(Msg)]), + case dec_msg(Msg) of + {request, N, Req} -> + i("received request ~w: " + "~n ~p", [N, Req]), + Reply = enc_rep_msg(N, "hoppsan"), + case socket:send(Socket, Reply) of + ok -> + i("successfully sent reply ~w", [N]), + handler_loop(H); + {error, SReason} -> + e("failed sending reply ~w:" + "~n ~p", [N, SReason]), + exit({failed_sending_reply, SReason}) + end end; + + {error, closed} -> + i("closed when" + "~n ~p", [socket:info()]), + exit(normal); + {error, RReason} -> e("failed reading request: " "~n ~p", [RReason]), - exit({failed_sending_reply, RReason}) + exit({failed_reading_request, RReason}) end. +%% --- + +enc_req_msg(N, Data) -> + enc_msg(?REQ, N, Data). + +enc_rep_msg(N, Data) -> + enc_msg(?REP, N, Data). + +enc_msg(Type, N, Data) when is_list(Data) -> + enc_msg(Type, N, list_to_binary(Data)); +enc_msg(Type, N, Data) + when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> + <>. + +dec_msg(<>) -> + {request, N, Data}; +dec_msg(<>) -> + {reply, N, Data}. + + +%% --- + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp(Now) -> + N2T = fun(N) -> calendar:now_to_local_time(N) end, + format_timestamp(Now, N2T, true). + +format_timestamp({_N1, _N2, N3} = N, N2T, true) -> + FormatExtra = ".~.2.0w", + ArgsExtra = [N3 div 10000], + format_timestamp(N, N2T, FormatExtra, ArgsExtra); +format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> + FormatExtra = "", + ArgsExtra = [], + format_timestamp(N, N2T, FormatExtra, ArgsExtra). + +format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> + {Date, Time} = N2T(N), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, + [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), + lists:flatten(FormatDate). + + +%% --- + e(F, A) -> p(" " ++ F, A). @@ -168,5 +238,6 @@ p(F, A) -> p(get(sname), F, A). p(SName, F, A) -> - io:format("[server,~s] " ++ F ++ "~n", [SName|A]). + io:format("[server:~s,~p][~s] " ++ F ++ "~n", + [SName,self(),formated_timestamp()|A]). -- cgit v1.2.3 From dce68cf27f2dd1721bd316594a29ff99a0de7bb9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 3 Jul 2018 15:46:30 +0200 Subject: [socket-nif] Restructure of the socket (test) server --- lib/kernel/test/socket_server.erl | 301 +++++++++++++++++++++++++++++++------- 1 file changed, 252 insertions(+), 49 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 64bd6396e4..dde605b624 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -13,7 +13,9 @@ -define(REQ, 0). -define(REP, 1). --record(handler, {socket, parent}). +-record(manager, {acceptor, handler_id, handlers}). +-record(acceptor, {socket, manager}). +-record(handler, {socket, manager}). start() -> start_tcp(). @@ -23,17 +25,169 @@ start_tcp() -> start(Domain, Type, Proto) -> put(sname, "starter"), - try do_init(Domain, Type, Proto) of + i("try start manager"), + {Pid, MRef} = manager_start(Domain, Type, Proto), + i("manager (~p) started", [Pid]), + loop(Pid, MRef). + +loop(Pid, MRef) -> + receive + {'DOWN', MRef, process, Pid, Reason} -> + i("manager process exited: " + "~n ~p", [Reason]), + ok + end. + + +%% ========================================================================= + +manager_start(Domain, Type, Proto) -> + spawn_monitor(fun() -> manager_init(Domain, Type, Proto) end). + +manager_start_handler(Pid, Sock) -> + manager_request(Pid, {start_handler, Sock}). + +manager_stop(Pid, Reason) -> + manager_request(Pid, {stop, Reason}). + +manager_request(Pid, Request) -> + request(manager, Pid, Request). + +manager_reply(Pid, Ref, Reply) -> + reply(manager, Pid, Ref, Reply). + + +manager_init(Domain, Type, Proto) -> + put(sname, "manager"), + i("try start acceptor"), + case acceptor_start(Domain, Type, Proto) of + {ok, {Pid, MRef}} -> + i("acceptor started"), + manager_loop(#manager{acceptor = {Pid, MRef}, + handler_id = 1, + handlers = []}); + {error, Reason} -> + exit({failed_starting_acceptor, Reason}) + end. + +manager_loop(M) -> + receive + {'DOWN', MRef, process, Pid, Reason} -> + M2 = manager_handle_down(M, MRef, Pid, Reason), + manager_loop(M2); + + {manager, Pid, Ref, Request} -> + M2 = manager_handle_request(M, Pid, Ref, Request), + manager_loop(M2) + end. + + +manager_handle_down(#manager{acceptor = {Pid, MRef}}, MRef, Pid, Reason) + when (Reason =/= normal) -> + e("acceptor died: " + "~n ~p", [Reason]), + exit({acceptor_died, Reason}); +manager_handle_down(#manager{acceptor = {Pid, MRef}}, MRef, Pid, Reason) -> + exit(Reason); +manager_handle_down(#manager{handlers = Handlers} = M, _MRef, Pid, Reason) -> + if + (Reason =/= normal) -> + e("handler ~p died: " + "~n ~p", [Pid, Reason]); + true -> + i("handler ~p terminated", [Pid]) + end, + Handlers2 = lists:keydelete(Pid, 1, Handlers), + M#manager{handlers = Handlers2}. + + +manager_handle_request(#manager{handler_id = HID, + handlers = Handlers} = M, Pid, Ref, + {start_handler, Sock}) -> + i("try start handler (~w)", [HID]), + case handler_start(HID, Sock) of + {ok, {HPid, HMRef}} -> + i("handler ~w started", [HID]), + manager_reply(Pid, Ref, {ok, HPid}), + M#manager{handler_id = HID+1, + handlers = [{HPid, HMRef, HID}|Handlers]}; + {error, Reason} = ERROR -> + e("Failed starting new handler: " + "~n Sock: ~p" + "~n Reason: ~p", [Sock, Reason]), + manager_reply(Pid, Ref, ERROR), + M + end; +manager_handle_request(#manager{acceptor = {Pid, MRef}, + handlers = Handlers}, Pid, Ref, + {stop, Reason}) -> + i("stop"), + manager_reply(Pid, Ref, ok), + manager_stop_handlers(Handlers, Reason), + i("try stop acceptor ~p: ~p", [Pid, Reason]), + erlang:demonitor(MRef, [flush]), + acceptor_stop(Pid, Reason), + i("stop", []), + exit(Reason). + + +manager_stop_handlers(Handlers, Reason) -> + lists:foreach(fun({P,M,ID}) -> + manager_stop_handler(P, M, ID, Reason) + end, Handlers). + +manager_stop_handler(Pid, MRef, ID, Reason) -> + i("try stop handler ~w (~p): ~p", [ID, Pid, Reason]), + erlang:demonitor(MRef, [flush]), + handler_stop(Pid, Reason), + ok. + + + +%% ========================================================================= + +acceptor_start(Domain, Type, Proto) -> + Self = self(), + A = {Pid, _} = spawn_monitor(fun() -> + acceptor_init(Self, Domain, Type, Proto) + end), + receive + {acceptor, Pid, ok} -> + {ok, A}; + {acceptor, Pid, {error, _} = Error} -> + exit(Pid, kill), % Just in case + Error; + {'DOWN', _MRef, process, Pid, Reason} -> + {error, {crashed, Reason}} + end. + +acceptor_stop(Pid, _Reason) -> + %% acceptor_request(Pid, {stop, Reason}). + exit(Pid, kill). + +%% acceptor_request(Pid, Request) -> +%% request(acceptor, Pid, Request). + +%% acceptor_reply(Pid, Ref, Reply) -> +%% reply(acceptor, Pid, Ref, Reply). + + +acceptor_init(Manager, Domain, Type, Proto) -> + put(sname, "acceptor"), + try acceptor_do_init(Domain, Type, Proto) of Sock -> - accept_loop(Sock) + Manager ! {acceptor, self(), ok}, + acceptor_loop(#acceptor{manager = Manager, + socket = Sock}) catch throw:E:P -> e("Failed initiate: " "~n Error: ~p" - "~n Path: ~p", [E, P]) + "~n Path: ~p", [E, P]), + Manager ! {acceptor, self(), {error, {catched, E, P}}} end. -do_init(Domain, Type, Proto) -> +acceptor_do_init(Domain, Type, Proto) -> i("try (socket) open"), Sock = case socket:open(Domain, Type, Proto) of {ok, S} -> @@ -41,18 +195,18 @@ do_init(Domain, Type, Proto) -> {error, OReason} -> throw({open, OReason}) end, - i("opened - now try find (local) address"), + i("(socket) open - try find (local) address"), Addr = which_addr(Domain), SA = #{family => Domain, addr => Addr}, - i("addr ~p - now try (socket) bind", [Addr]), + i("found (~p) - try (socket) bind", [Addr]), Port = case socket:bind(Sock, SA) of {ok, P} -> P; {error, BReason} -> throw({bind, BReason}) end, - i("bound to ~w - now try (socket) listen", [Port]), + i("bound (~w) - try (socket) listen", [Port]), case socket:listen(Sock) of ok -> Sock; @@ -84,11 +238,7 @@ which_addr2(Domain, [_|IFO]) -> which_addr2(Domain, IFO). -accept_loop(LSock) -> - put(sname, "acceptor"), - accept_loop(LSock, []). - -accept_loop(LSock, Handlers) -> +acceptor_loop(#acceptor{socket = LSock} = A) -> i("try accept"), case socket:accept(LSock, infinity) of {ok, Sock} -> @@ -96,14 +246,14 @@ accept_loop(LSock, Handlers) -> "~n ~p" "~nwhen" "~n ~p", [Sock, socket:info()]), - case handle_accept_success(Sock) of - {ok, Handler} -> - accept_loop(LSock, [Handler|Handlers]); - {error, HReason} -> + case acceptor_handle_accept_success(A, Sock) of + ok -> + acceptor_loop(A); + {error, Reason} -> e("Failed starting handler: " - "~n ~p", [HReason]), + "~n ~p", [Reason]), socket:close(Sock), - exit({failed_starting_handler, HReason}) + exit({failed_starting_handler, Reason}) end; {error, Reason} -> e("accept failure: " @@ -111,41 +261,75 @@ accept_loop(LSock, Handlers) -> exit({accept, Reason}) end. +acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> + i("try start handler"), + case manager_start_handler(Manager, Sock) of + {ok, Pid} -> + i("handler (~p) started - now change 'ownership'", [Pid]), + case socket:setopt(Sock, otp, controlling_process, Pid) of + ok -> + %% Normally we should have a msgs collection here + %% (of messages we receive before the control was + %% handled over to Handler), but since we don't + %% have active implemented yet... + i("new handler (~p) now controlling process", [Pid]), + handler_continue(Pid), + ok; + {error, _} = ERROR -> + exit(Pid, kill), + ERROR + end; + {error, Reason2} -> + e("failed starting handler: " + "~n (new) Socket: ~p" + "~n Reason: ~p", [Sock, Reason2]), + exit({failed_starting_handler, Reason2}) + end. -handle_accept_success(Sock) -> - Self = self(), - Handler = spawn_link(fun() -> handler_init(Self, Sock) end), - case socket:setopt(Sock, otp, controlling_process, Handler) of - ok -> - %% Normally we should have a msgs collection here - %% (of messages we receive before the control was - %% handled over to Handler), but since we don't - %% have active implemented yet... - handler_continue(Handler), - {ok, {Handler, Sock}}; - {error, _} = ERROR -> - exit(Handler, kill), + + +%% ========================================================================= + +handler_start(ID, Sock) -> + Self = self(), + H = {Pid, _} = spawn_monitor(fun() -> handler_init(Self, ID, Sock) end), + receive + {handler, Pid, ok} -> + {ok, H}; + {handler, Pid, {error, _} = ERROR} -> + exit(Pid, kill), % Just in case ERROR end. +handler_stop(Pid, _Reason) -> + %% handler_request(Pid, {stop, Reason}). + exit(Pid, kill). + +handler_continue(Pid) -> + handler_request(Pid, continue). + +handler_request(Pid, Request) -> + request(handler, Pid, Request). + +handler_reply(Pid, Ref, Reply) -> + reply(handler, Pid, Ref, Reply). + -handler_init(Parent, Socket) -> - put(sname, "handler"), +handler_init(Manager, ID, Sock) -> + put(sname, f("handler:~w", [ID])), + i("starting"), + Manager ! {handler, self(), ok}, receive - {handler, Parent, continue} -> - socket:setopt(Socket, otp, debug, true), - handler_loop(#handler{parent = Parent, - socket = Socket}) + {handler, Pid, Ref, continue} -> + i("continue"), + handler_reply(Pid, Ref, ok), + %% socket:setopt(Socket, otp, debug, true), + handler_loop(#handler{manager = Manager, + socket = Sock}) end. -handler_continue(Handler) -> - Handler ! {handler, self(), continue}. - handler_loop(#handler{socket = Socket} = H) -> - case socket:recv(Socket, 0) of - {ok, Msg} when (size(Msg) =:= 0) -> - i("received empty msg - hickup? - try again", []), - handler_loop(H); + case socket:recv(Socket) of {ok, Msg} -> i("received ~w bytes of data", [size(Msg)]), case dec_msg(Msg) of @@ -174,9 +358,10 @@ handler_loop(#handler{socket = Socket} = H) -> "~n ~p", [RReason]), exit({failed_reading_request, RReason}) end. - - -%% --- + + + +%% ========================================================================= enc_req_msg(N, Data) -> enc_msg(?REQ, N, Data). @@ -196,6 +381,21 @@ dec_msg(<>) -> {reply, N, Data}. + +%% --- + +request(Tag, Pid, Request) -> + Ref = make_ref(), + Pid ! {Tag, self(), Ref, Request}, + receive + {Tag, Pid, Ref, Reply} -> + Reply + end. + +reply(Tag, Pid, Ref, Reply) -> + Pid ! {Tag, self(), Ref, Reply}. + + %% --- formated_timestamp() -> @@ -226,6 +426,9 @@ format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> %% --- +f(F, A) -> + lists:flatten(io_lib:format(F, A)). + e(F, A) -> p(" " ++ F, A). @@ -238,6 +441,6 @@ p(F, A) -> p(get(sname), F, A). p(SName, F, A) -> - io:format("[server:~s,~p][~s] " ++ F ++ "~n", + io:format("[~s,~p][~s] " ++ F ++ "~n", [SName,self(),formated_timestamp()|A]). -- cgit v1.2.3 From e39e25d84405e13ca0ce476e3ba473510e5548de Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 4 Jul 2018 15:18:18 +0200 Subject: [socket-nif] Fixed (dgram) recv Fixed handling of recvfrom (used by dgram sockets). Had forgot to do select(read) when we got block from the call to recvfrom. Argh! Also updated the (simple) test server and client to to be able to use udp (dgram+udp). OTP-14831 --- lib/kernel/test/Makefile | 1 + lib/kernel/test/socket_client.erl | 252 ++++++++++++++++++++++++++------------ lib/kernel/test/socket_lib.erl | 129 +++++++++++++++++++ lib/kernel/test/socket_server.erl | 237 +++++++++++++++++++++++------------ 4 files changed, 462 insertions(+), 157 deletions(-) create mode 100644 lib/kernel/test/socket_lib.erl (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 07e7922d3d..051fac25af 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -25,6 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # ---------------------------------------------------- SOCKET_MODULES = \ + socket_lib \ socket_server \ socket_client diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index a284777046..0b570e1f71 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -1,17 +1,34 @@ -%%%------------------------------------------------------------------- -%%% @author Micael Karlberg -%%% @copyright (C) 2018, Micael Karlberg -%%% @doc -%%% -%%% @end -%%% Created : 27 Jun 2018 by Micael Karlberg -%%%------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + -module(socket_client). --export([start/1]). +-export([ + start/1, + start_tcp/1, start_tcp/2, + start_udp/1, start_udp/2 + ]). + +-define(LIB, socket_lib). --define(REQ, 0). --define(REP, 1). +-record(client, {socket, type, dest, msg_id = 1}). start(Port) -> start_tcp(Port). @@ -19,22 +36,77 @@ start(Port) -> start_tcp(Port) -> start(inet, 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) -> + start(inet6, stream, tcp, Addr, Port). + + +start_udp(Port) -> + start(inet, 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) -> + start(inet6, dgram, udp, Addr, Port). + + start(Domain, Type, Proto, Port) -> + start(Domain, Type, Proto, which_addr(Domain), Port). + +start(Domain, Type, Proto, Addr, Port) -> + put(sname, "starter"), + SA = #{family => Domain, + addr => Addr, + port => Port}, + do_start(Domain, Type, Proto, SA). + +do_start(Domain, stream = Type, Proto, SA) -> try do_init(Domain, Type, Proto) of Sock -> - connect(Sock, Domain, Port), + connect(Sock, SA), + 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 + ]), %% Give the server some time... - p("wait some", []), - %% sleep(5000), + i("wait some", []), + ?LIB:sleep(5000), %% ok = socket:close(Sock), - send_loop(Sock) + send_loop(#client{socket = Sock, + type = Type}) + catch + throw:E -> + e("Failed initiate: " + "~n Error: ~p", [E]) + end; +do_start(Domain, dgram = Type, Proto, SA) -> + try do_init(Domain, Type, Proto) of + Sock -> + %% Give the server some time... + i("wait some", []), + ?LIB:sleep(5000), + %% ok = socket:close(Sock), + send_loop(#client{socket = Sock, + type = Type, + dest = SA}) catch throw:E -> e("Failed initiate: " "~n Error: ~p", [E]) end. -do_init(Domain, Type, Proto) -> + +do_init(Domain, stream = Type, Proto) -> i("try (socket) open"), Sock = case socket:open(Domain, Type, Proto) of {ok, S} -> @@ -48,8 +120,23 @@ do_init(Domain, Type, Proto) -> Sock; {error, BReason} -> throw({bind, BReason}) + end; +do_init(Domain, dgram = Type, Proto) -> + i("try (socket) open"), + Sock = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, OReason} -> + throw({open, OReason}) + end, + case socket:bind(Sock, any) of + {ok, _} -> + Sock; + {error, BReason} -> + throw({bind, BReason}) end. + which_addr(Domain) -> Iflist = case inet:getifaddrs() of {ok, IFL} -> @@ -60,16 +147,11 @@ which_addr(Domain) -> which_addr(Domain, Iflist). -connect(Sock, Domain, Port) -> - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => Addr, - port => Port}, +connect(Sock, SA) -> i("try (socket) connect to:" "~n ~p", [SA]), case socket:connect(Sock, SA) of ok -> - i("connected"), ok; {error, Reason} -> e("connect failure: " @@ -78,22 +160,23 @@ connect(Sock, Domain, Port) -> end. -send_loop(Sock) -> - send_loop(Sock, 1). - -send_loop(Sock, N) when (N =< 10) -> +send_loop(#client{msg_id = N} = C) when (N =< 10) -> i("try send request ~w", [N]), - Req = enc_req_msg(N, "hejsan"), - case socket:send(Sock, Req) of + Req = ?LIB:enc_req_msg(N, "hejsan"), + case send(C, Req) of ok -> i("request ~w sent - now try read answer", [N]), - case socket:recv(Sock, 0) of - {ok, Msg} -> - i("received ~w bytes of data", [size(Msg)]), - case dec_msg(Msg) of + case recv(C) of + {ok, {Source, Msg}} -> + i("received ~w bytes of data~s", + [size(Msg), case Source of + undefined -> ""; + _ -> ?LIB:f(" from:~n ~p", [Source]) + end]), + case ?LIB:dec_msg(Msg) of {reply, N, Reply} -> i("received reply ~w: ~p", [N, Reply]), - send_loop(Sock, N+1) + send_loop(C#client{msg_id = N+1}) end; {error, RReason} -> e("Failed recv response for request ~w: " @@ -105,7 +188,7 @@ send_loop(Sock, N) when (N =< 10) -> "~n ~p", [SReason]), exit({failed_send, SReason}) end; -send_loop(Sock, _N) -> +send_loop(#client{socket = Sock}) -> i("we are done - close the socket when: " "~n ~p", [socket:info()]), ok = socket:close(Sock), @@ -113,6 +196,25 @@ send_loop(Sock, _N) -> "~n ~p", [socket:info()]). +send(#client{socket = Sock, type = stream}, Msg) -> + socket:send(Sock, Msg); +send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> + %% i("try send to: " + %% "~n ~p", [Dest]), + %% ok = socket:setopt(Sock, otp, debug, true), + socket:sendto(Sock, Msg, Dest). + +recv(#client{socket = Sock, type = stream}) -> + case socket:recv(Sock) of + {ok, Msg} -> + {ok, {undefined, Msg}}; + {error, _} = ERROR -> + ERROR + end; +recv(#client{socket = Sock, type = dgram}) -> + socket:recvfrom(Sock). + + which_addr(_Domain, []) -> throw(no_address); which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> @@ -130,68 +232,66 @@ which_addr2(Domain, [_|IFO]) -> %% --- -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). +%% enc_req_msg(N, Data) -> +%% enc_msg(?REQ, N, Data). -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). +%% enc_rep_msg(N, Data) -> +%% enc_msg(?REP, N, Data). -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <>. +%% enc_msg(Type, N, Data) when is_list(Data) -> +%% enc_msg(Type, N, list_to_binary(Data)); +%% enc_msg(Type, N, Data) +%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> +%% <>. -dec_msg(<>) -> - {request, N, Data}; -dec_msg(<>) -> - {reply, N, Data}. +%% dec_msg(<>) -> +%% {request, N, Data}; +%% dec_msg(<>) -> +%% {reply, N, Data}. %% --- -sleep(T) -> - receive after T -> ok end. +%% sleep(T) -> +%% receive after T -> ok end. %% --- -formated_timestamp() -> - format_timestamp(os:timestamp()). +%% formated_timestamp() -> +%% format_timestamp(os:timestamp()). -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). +%% format_timestamp(Now) -> +%% N2T = fun(N) -> calendar:now_to_local_time(N) end, +%% format_timestamp(Now, N2T, true). -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). +%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> +%% FormatExtra = ".~.2.0w", +%% ArgsExtra = [N3 div 10000], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); +%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> +%% FormatExtra = "", +%% ArgsExtra = [], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> +%% {Date, Time} = N2T(N), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, +%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), +%% lists:flatten(FormatDate). %% --- e(F, A) -> - p(" " ++ F, A). + ?LIB:e(F, A). i(F) -> - i(F, []). + ?LIB:i(F). + i(F, A) -> - p("*** " ++ F, A). - -p(F, A) -> - io:format("[client,~p][~s] " ++ F ++ "~n", [self(),formated_timestamp()|A]). + ?LIB:i(F, A). diff --git a/lib/kernel/test/socket_lib.erl b/lib/kernel/test/socket_lib.erl new file mode 100644 index 0000000000..0eed81d61a --- /dev/null +++ b/lib/kernel/test/socket_lib.erl @@ -0,0 +1,129 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(socket_lib). + +-export([ + sleep/1, + enc_req_msg/2, enc_rep_msg/2, + enc_msg/3, dec_msg/1, + request/3, reply/4, + f/2, + i/1, i/2, + e/2 + ]). + + +-define(REQ, 0). +-define(REP, 1). + + +%% --- + +sleep(T) -> + receive after T -> ok end. + + +%% --- + +enc_req_msg(N, Data) -> + enc_msg(?REQ, N, Data). + +enc_rep_msg(N, Data) -> + enc_msg(?REP, N, Data). + +enc_msg(Type, N, Data) when is_list(Data) -> + enc_msg(Type, N, list_to_binary(Data)); +enc_msg(Type, N, Data) + when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> + <>. + +dec_msg(<>) -> + {request, N, Data}; +dec_msg(<>) -> + {reply, N, Data}. + + +%% --- + +request(Tag, Pid, Request) -> + Ref = make_ref(), + Pid ! {Tag, self(), Ref, Request}, + receive + {Tag, Pid, Ref, Reply} -> + Reply + end. + +reply(Tag, Pid, Ref, Reply) -> + Pid ! {Tag, self(), Ref, Reply}. + + +%% --- + +f(F, A) -> + lists:flatten(io_lib:format(F, A)). + + +%% --- + +e(F, A) -> + p(" " ++ F, A). + +i(F) -> + i(F, []). +i(F, A) -> + p("*** " ++ F, A). + +p(F, A) -> + p(get(sname), F, A). + +p(SName, F, A) -> + io:format("[~s,~p][~s] " ++ F ++ "~n", + [SName,self(),formated_timestamp()|A]). + + +%% --- + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp(Now) -> + N2T = fun(N) -> calendar:now_to_local_time(N) end, + format_timestamp(Now, N2T, true). + +format_timestamp({_N1, _N2, N3} = N, N2T, true) -> + FormatExtra = ".~.2.0w", + ArgsExtra = [N3 div 10000], + format_timestamp(N, N2T, FormatExtra, ArgsExtra); +format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> + FormatExtra = "", + ArgsExtra = [], + format_timestamp(N, N2T, FormatExtra, ArgsExtra). + +format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> + {Date, Time} = N2T(N), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, + [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), + lists:flatten(FormatDate). + + diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index dde605b624..702f040434 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -1,21 +1,34 @@ -%%%------------------------------------------------------------------- -%%% @author Micael Karlberg -%%% @copyright (C) 2018, Micael Karlberg -%%% @doc -%%% -%%% @end -%%% Created : 27 Jun 2018 by Micael Karlberg -%%%------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + -module(socket_server). --export([start/0]). +-export([start/0, + start_tcp/0, + start_udp/0]). --define(REQ, 0). --define(REP, 1). +-define(LIB, socket_lib). --record(manager, {acceptor, handler_id, handlers}). +-record(manager, {acceptor, handler_id, handlers}). -record(acceptor, {socket, manager}). --record(handler, {socket, manager}). +-record(handler, {socket, type, manager}). start() -> start_tcp(). @@ -23,6 +36,9 @@ start() -> start_tcp() -> start(inet, stream, tcp). +start_udp() -> + start(inet, dgram, udp). + start(Domain, Type, Proto) -> put(sname, "starter"), i("try start manager"), @@ -51,13 +67,13 @@ manager_stop(Pid, Reason) -> manager_request(Pid, {stop, Reason}). manager_request(Pid, Request) -> - request(manager, Pid, Request). + ?LIB:request(manager, Pid, Request). manager_reply(Pid, Ref, Reply) -> - reply(manager, Pid, Ref, Reply). + ?LIB:reply(manager, Pid, Ref, Reply). -manager_init(Domain, Type, Proto) -> +manager_init(Domain, stream = Type, Proto) -> put(sname, "manager"), i("try start acceptor"), case acceptor_start(Domain, Type, Proto) of @@ -68,8 +84,44 @@ manager_init(Domain, Type, Proto) -> handlers = []}); {error, Reason} -> exit({failed_starting_acceptor, Reason}) + end; +manager_init(Domain, dgram = Type, Proto) -> + put(sname, "manager"), + i("try open socket"), + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + Addr = which_addr(Domain), + SA = #{family => Domain, + addr => Addr}, + case socket:bind(Sock, SA) of + {ok, _P} -> + ok; + {error, BReason} -> + throw({bind, BReason}) + end, + i("try start handler for" + "~n ~p", [case socket:sockname(Sock) of + {ok, Name} -> Name; + {error, _} = E -> E + end]), + case handler_start(1, Sock) of + {ok, {Pid, MRef}} -> + i("handler (~p) started", [Pid]), + handler_continue(Pid), + manager_loop(#manager{handler_id = 2, % Just in case + handlers = [{Pid, MRef, 1}]}); + {error, SReason} -> + e("Failed starting handler: " + "~n ~p", [SReason]), + exit({failed_start_handler, SReason}) + end; + {error, OReason} -> + e("Failed open socket: " + "~n ~p", [OReason]), + exit({failed_open_socket, OReason}) end. + manager_loop(M) -> receive {'DOWN', MRef, process, Pid, Reason} -> @@ -262,7 +314,11 @@ acceptor_loop(#acceptor{socket = LSock} = A) -> end. acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> - i("try start handler"), + i("try start handler for peer" + "~n ~p", [case socket:peername(Sock) of + {ok, Peer} -> Peer; + {error, _} = E -> E + end]), case manager_start_handler(Manager, Sock) of {ok, Pid} -> i("handler (~p) started - now change 'ownership'", [Pid]), @@ -309,10 +365,10 @@ handler_continue(Pid) -> handler_request(Pid, continue). handler_request(Pid, Request) -> - request(handler, Pid, Request). + ?LIB:request(handler, Pid, Request). handler_reply(Pid, Ref, Reply) -> - reply(handler, Pid, Ref, Reply). + ?LIB:reply(handler, Pid, Ref, Reply). handler_init(Manager, ID, Sock) -> @@ -321,23 +377,30 @@ handler_init(Manager, ID, Sock) -> Manager ! {handler, self(), ok}, receive {handler, Pid, Ref, continue} -> - i("continue"), + i("got continue"), handler_reply(Pid, Ref, ok), + {ok, Type} = socket:getopt(Sock, socket, type), %% socket:setopt(Socket, otp, debug, true), handler_loop(#handler{manager = Manager, + type = Type, socket = Sock}) end. -handler_loop(#handler{socket = Socket} = H) -> - case socket:recv(Socket) of - {ok, Msg} -> - i("received ~w bytes of data", [size(Msg)]), - case dec_msg(Msg) of +handler_loop(H) -> + i("try read message"), + case recv(H) of + {ok, {Source, Msg}} -> + i("received ~w bytes of data~s", + [size(Msg), case Source of + undefined -> ""; + _ -> f(" from:~n ~p", [Source]) + end]), + case ?LIB:dec_msg(Msg) of {request, N, Req} -> i("received request ~w: " "~n ~p", [N, Req]), - Reply = enc_rep_msg(N, "hoppsan"), - case socket:send(Socket, Reply) of + Reply = ?LIB:enc_rep_msg(N, "hoppsan"), + case send(H, Reply, Source) of ok -> i("successfully sent reply ~w", [N]), handler_loop(H); @@ -360,87 +423,99 @@ handler_loop(#handler{socket = Socket} = H) -> end. +recv(#handler{socket = Sock, type = stream}) -> + case socket:recv(Sock) of + {ok, Msg} -> + {ok, {undefined, Msg}}; + {error, _} = ERROR -> + ERROR + end; +recv(#handler{socket = Sock, type = dgram}) -> + %% ok = socket:setopt(Sock, otp, debug, true), + socket:recvfrom(Sock). + + +send(#handler{socket = Sock, type = stream}, Msg, _) -> + socket:send(Sock, Msg); +send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> + socket:sendto(Sock, Msg, Dest). + + %% ========================================================================= -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). +%% enc_req_msg(N, Data) -> +%% enc_msg(?REQ, N, Data). -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). +%% enc_rep_msg(N, Data) -> +%% enc_msg(?REP, N, Data). -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <>. +%% enc_msg(Type, N, Data) when is_list(Data) -> +%% enc_msg(Type, N, list_to_binary(Data)); +%% enc_msg(Type, N, Data) +%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> +%% <>. -dec_msg(<>) -> - {request, N, Data}; -dec_msg(<>) -> - {reply, N, Data}. +%% dec_msg(<>) -> +%% {request, N, Data}; +%% dec_msg(<>) -> +%% {reply, N, Data}. %% --- -request(Tag, Pid, Request) -> - Ref = make_ref(), - Pid ! {Tag, self(), Ref, Request}, - receive - {Tag, Pid, Ref, Reply} -> - Reply - end. +%% request(Tag, Pid, Request) -> +%% Ref = make_ref(), +%% Pid ! {Tag, self(), Ref, Request}, +%% receive +%% {Tag, Pid, Ref, Reply} -> +%% Reply +%% end. -reply(Tag, Pid, Ref, Reply) -> - Pid ! {Tag, self(), Ref, Reply}. +%% reply(Tag, Pid, Ref, Reply) -> +%% Pid ! {Tag, self(), Ref, Reply}. %% --- -formated_timestamp() -> - format_timestamp(os:timestamp()). +%% formated_timestamp() -> +%% format_timestamp(os:timestamp()). -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). +%% format_timestamp(Now) -> +%% N2T = fun(N) -> calendar:now_to_local_time(N) end, +%% format_timestamp(Now, N2T, true). -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). +%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> +%% FormatExtra = ".~.2.0w", +%% ArgsExtra = [N3 div 10000], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); +%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> +%% FormatExtra = "", +%% ArgsExtra = [], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> +%% {Date, Time} = N2T(N), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, +%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), +%% lists:flatten(FormatDate). %% --- f(F, A) -> - lists:flatten(io_lib:format(F, A)). + ?LIB:f(F, A). e(F, A) -> - p(" " ++ F, A). + ?LIB:e(F, A). i(F) -> - i(F, []). -i(F, A) -> - p("*** " ++ F, A). + ?LIB:i(F). -p(F, A) -> - p(get(sname), F, A). +i(F, A) -> + ?LIB:i(F, A). -p(SName, F, A) -> - io:format("[~s,~p][~s] " ++ F ++ "~n", - [SName,self(),formated_timestamp()|A]). - -- cgit v1.2.3 From 1952754950f371f43ed4dd675a42c60b3d166bd7 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 5 Jul 2018 11:27:26 +0200 Subject: [socket-test-nif] Testing with the (recv/recvfrom) peek flag --- lib/kernel/test/socket_lib.erl | 4 + lib/kernel/test/socket_server.erl | 170 ++++++++++++++++++-------------------- 2 files changed, 84 insertions(+), 90 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_lib.erl b/lib/kernel/test/socket_lib.erl index 0eed81d61a..9d6524d467 100644 --- a/lib/kernel/test/socket_lib.erl +++ b/lib/kernel/test/socket_lib.erl @@ -22,6 +22,7 @@ -export([ sleep/1, + req/0, rep/0, enc_req_msg/2, enc_rep_msg/2, enc_msg/3, dec_msg/1, request/3, reply/4, @@ -43,6 +44,9 @@ sleep(T) -> %% --- +req() -> ?REQ. +rep() -> ?REP. + enc_req_msg(N, Data) -> enc_msg(?REQ, N, Data). diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 702f040434..02fc6fc26d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -20,29 +20,37 @@ -module(socket_server). --export([start/0, - start_tcp/0, - start_udp/0]). +-export([ + start/0, + start_tcp/0, start_tcp/1, + start_udp/0, start_udp/1 + ]). -define(LIB, socket_lib). --record(manager, {acceptor, handler_id, handlers}). +-record(manager, {peek, acceptor, handler_id, handlers}). -record(acceptor, {socket, manager}). --record(handler, {socket, type, manager}). +-record(handler, {socket, peek, type, manager}). start() -> start_tcp(). start_tcp() -> - start(inet, stream, tcp). + start_tcp(false). + +start_tcp(Peek) -> + start(inet, stream, tcp, Peek). start_udp() -> - start(inet, dgram, udp). + start_udp(false). + +start_udp(Peek) when is_boolean(Peek) -> + start(inet, dgram, udp, Peek). -start(Domain, Type, Proto) -> +start(Domain, Type, Proto, Peek) -> put(sname, "starter"), i("try start manager"), - {Pid, MRef} = manager_start(Domain, Type, Proto), + {Pid, MRef} = manager_start(Domain, Type, Proto, Peek), i("manager (~p) started", [Pid]), loop(Pid, MRef). @@ -57,8 +65,8 @@ loop(Pid, MRef) -> %% ========================================================================= -manager_start(Domain, Type, Proto) -> - spawn_monitor(fun() -> manager_init(Domain, Type, Proto) end). +manager_start(Domain, Type, Proto, Peek) -> + spawn_monitor(fun() -> manager_init(Domain, Type, Proto, Peek) end). manager_start_handler(Pid, Sock) -> manager_request(Pid, {start_handler, Sock}). @@ -73,19 +81,20 @@ manager_reply(Pid, Ref, Reply) -> ?LIB:reply(manager, Pid, Ref, Reply). -manager_init(Domain, stream = Type, Proto) -> +manager_init(Domain, stream = Type, Proto, Peek) -> put(sname, "manager"), i("try start acceptor"), case acceptor_start(Domain, Type, Proto) of {ok, {Pid, MRef}} -> i("acceptor started"), - manager_loop(#manager{acceptor = {Pid, MRef}, + manager_loop(#manager{peek = Peek, + acceptor = {Pid, MRef}, handler_id = 1, handlers = []}); {error, Reason} -> exit({failed_starting_acceptor, Reason}) end; -manager_init(Domain, dgram = Type, Proto) -> +manager_init(Domain, dgram = Type, Proto, Peek) -> put(sname, "manager"), i("try open socket"), case socket:open(Domain, Type, Proto) of @@ -104,11 +113,12 @@ manager_init(Domain, dgram = Type, Proto) -> {ok, Name} -> Name; {error, _} = E -> E end]), - case handler_start(1, Sock) of + case handler_start(1, Sock, Peek) of {ok, {Pid, MRef}} -> i("handler (~p) started", [Pid]), handler_continue(Pid), - manager_loop(#manager{handler_id = 2, % Just in case + manager_loop(#manager{peek = Peek, + handler_id = 2, % Just in case handlers = [{Pid, MRef, 1}]}); {error, SReason} -> e("Failed starting handler: " @@ -153,11 +163,12 @@ manager_handle_down(#manager{handlers = Handlers} = M, _MRef, Pid, Reason) -> M#manager{handlers = Handlers2}. -manager_handle_request(#manager{handler_id = HID, +manager_handle_request(#manager{peek = Peek, + handler_id = HID, handlers = Handlers} = M, Pid, Ref, {start_handler, Sock}) -> i("try start handler (~w)", [HID]), - case handler_start(HID, Sock) of + case handler_start(HID, Sock, Peek) of {ok, {HPid, HMRef}} -> i("handler ~w started", [HID]), manager_reply(Pid, Ref, {ok, HPid}), @@ -346,9 +357,11 @@ acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> %% ========================================================================= -handler_start(ID, Sock) -> +handler_start(ID, Sock, Peek) -> Self = self(), - H = {Pid, _} = spawn_monitor(fun() -> handler_init(Self, ID, Sock) end), + H = {Pid, _} = spawn_monitor(fun() -> + handler_init(Self, ID, Peek, Sock) + end), receive {handler, Pid, ok} -> {ok, H}; @@ -371,7 +384,7 @@ handler_reply(Pid, Ref, Reply) -> ?LIB:reply(handler, Pid, Ref, Reply). -handler_init(Manager, ID, Sock) -> +handler_init(Manager, ID, Peek, Sock) -> put(sname, f("handler:~w", [ID])), i("starting"), Manager ! {handler, self(), ok}, @@ -381,7 +394,8 @@ handler_init(Manager, ID, Sock) -> handler_reply(Pid, Ref, ok), {ok, Type} = socket:getopt(Sock, socket, type), %% socket:setopt(Socket, otp, debug, true), - handler_loop(#handler{manager = Manager, + handler_loop(#handler{peek = Peek, + manager = Manager, type = Type, socket = Sock}) end. @@ -423,16 +437,55 @@ handler_loop(H) -> end. -recv(#handler{socket = Sock, type = stream}) -> +recv(#handler{peek = true, socket = Sock, type = stream}) -> + peek_recv(Sock); +recv(#handler{peek = false, socket = Sock, type = stream}) -> + do_recv(Sock); +recv(#handler{peek = Peek, socket = Sock, type = dgram}) + when (Peek =:= true) -> + %% ok = socket:setopt(Sock, otp, debug, true), + RES = peek_recvfrom(Sock, 5), + %% ok = socket:setopt(Sock, otp, debug, false), + RES; +recv(#handler{peek = Peek, socket = Sock, type = dgram}) + when (Peek =:= false) -> + %% ok = socket:setopt(Sock, otp, debug, true), + socket:recvfrom(Sock). + +do_recv(Sock) -> case socket:recv(Sock) of {ok, Msg} -> {ok, {undefined, Msg}}; {error, _} = ERROR -> ERROR - end; -recv(#handler{socket = Sock, type = dgram}) -> - %% ok = socket:setopt(Sock, otp, debug, true), - socket:recvfrom(Sock). + end. + +peek_recv(Sock) -> + i("try peek on the message type (expect request)"), + Type = ?LIB:req(), + case socket:recv(Sock, 4, [peek]) of + {ok, <>} -> + i("was request - do proper recv"), + do_recv(Sock); + {error, _} = ERROR -> + ERROR + end. + +peek_recvfrom(Sock, BufSz) -> + i("try peek recvfrom with buffer size ~w", [BufSz]), + case socket:recvfrom(Sock, BufSz, [peek]) of + {ok, {_Source, Msg}} when (BufSz =:= size(Msg)) -> + %% i("we filled the buffer: " + %% "~n ~p", [Msg]), + %% It *may not* fit => try again with double size + peek_recvfrom(Sock, BufSz*2); + {ok, _} -> + %% It fits => read for real + i("we did *not* fill the buffer - do the 'real' read"), + socket:recvfrom(Sock); + {error, _} = ERROR -> + ERROR + end. send(#handler{socket = Sock, type = stream}, Msg, _) -> @@ -444,69 +497,6 @@ send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> %% ========================================================================= -%% enc_req_msg(N, Data) -> -%% enc_msg(?REQ, N, Data). - -%% enc_rep_msg(N, Data) -> -%% enc_msg(?REP, N, Data). - -%% enc_msg(Type, N, Data) when is_list(Data) -> -%% enc_msg(Type, N, list_to_binary(Data)); -%% enc_msg(Type, N, Data) -%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> -%% <>. - -%% dec_msg(<>) -> -%% {request, N, Data}; -%% dec_msg(<>) -> -%% {reply, N, Data}. - - - -%% --- - -%% request(Tag, Pid, Request) -> -%% Ref = make_ref(), -%% Pid ! {Tag, self(), Ref, Request}, -%% receive -%% {Tag, Pid, Ref, Reply} -> -%% Reply -%% end. - -%% reply(Tag, Pid, Ref, Reply) -> -%% Pid ! {Tag, self(), Ref, Reply}. - - -%% --- - -%% formated_timestamp() -> -%% format_timestamp(os:timestamp()). - -%% format_timestamp(Now) -> -%% N2T = fun(N) -> calendar:now_to_local_time(N) end, -%% format_timestamp(Now, N2T, true). - -%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> -%% FormatExtra = ".~.2.0w", -%% ArgsExtra = [N3 div 10000], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); -%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> -%% FormatExtra = "", -%% ArgsExtra = [], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> -%% {Date, Time} = N2T(N), -%% {YYYY,MM,DD} = Date, -%% {Hour,Min,Sec} = Time, -%% FormatDate = -%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, -%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), -%% lists:flatten(FormatDate). - - -%% --- - f(F, A) -> ?LIB:f(F, A). -- cgit v1.2.3 From d45e3bf3dfeda0e849b07a9a7a19e50a52b04c35 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 9 Jul 2018 14:10:35 +0200 Subject: [socket-nif] Add support for socket (level socket) options domain and protocol Make it possible to *get* the socket options domain and protocol (in addition to type). OTP-14831 --- lib/kernel/test/socket_server.erl | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 02fc6fc26d..cf7e349a3d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -258,7 +258,13 @@ acceptor_do_init(Domain, Type, Proto) -> {error, OReason} -> throw({open, OReason}) end, - i("(socket) open - try find (local) address"), + F = fun(X) -> case socket:getopt(Sock, socket, X) of + {ok, V} -> f("~p", [V]); + {error, _} -> f("~w", [X]) + end + end, + i("(socket) open (~s,~s,~s) - try find (local) address", + [F(domain), F(type), F(protocol)]), Addr = which_addr(Domain), SA = #{family => Domain, addr => Addr}, @@ -392,7 +398,13 @@ handler_init(Manager, ID, Peek, Sock) -> {handler, Pid, Ref, continue} -> i("got continue"), handler_reply(Pid, Ref, ok), - {ok, Type} = socket:getopt(Sock, socket, type), + {ok, Domain} = socket:getopt(Sock, socket, domain), + {ok, Type} = socket:getopt(Sock, socket, type), + {ok, Proto} = socket:getopt(Sock, socket, protocol), + i("got continue when: " + "~n Domain: ~p" + "~n Type: ~p" + "~n Protocol: ~p", [Domain, Type, Proto]), %% socket:setopt(Socket, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 7ed2af8dcfd62a051686ac1e1326fbeca0b18334 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 9 Jul 2018 14:54:57 +0200 Subject: [socket-nif] Add support for socket (level socket) option acceptconn The socket (level socket) option acceptconn is now supported (for getopt). OTP-14831 --- lib/kernel/test/socket_server.erl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index cf7e349a3d..52b0d5b558 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -275,9 +275,12 @@ acceptor_do_init(Domain, Type, Proto) -> {error, BReason} -> throw({bind, BReason}) end, - i("bound (~w) - try (socket) listen", [Port]), + i("bound (~w) - try (socket) listen (acceptconn: ~s)", + [Port, F(acceptconn)]), case socket:listen(Sock) of ok -> + i("listening (acceptconn: ~s)", + [F(acceptconn)]), Sock; {error, LReason} -> throw({listen, LReason}) -- cgit v1.2.3 From 6031321a78e3df5304f555ba356a4482469e7d56 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 9 Jul 2018 15:28:09 +0200 Subject: [socket-nif] Add support for socket (level socket) option debug The socket option (level socket) debug is now supported. To actually set this option, the user must have the proper "authority" (CAP_NET_ADMIN capability or an effective user ID of 0). OTP-14831 --- lib/kernel/test/socket_server.erl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 52b0d5b558..54e13cc92d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -260,17 +260,24 @@ acceptor_do_init(Domain, Type, Proto) -> end, F = fun(X) -> case socket:getopt(Sock, socket, X) of {ok, V} -> f("~p", [V]); - {error, _} -> f("~w", [X]) + {error, _} -> "-" end end, - i("(socket) open (~s,~s,~s) - try find (local) address", - [F(domain), F(type), F(protocol)]), + i("(socket) open (~s,~s,~s): " + "~n debug: ~s" + "~n prio: ~s" + "~n try find (local) address", + [F(domain), F(type), F(protocol), F(debug), F(priority)]), Addr = which_addr(Domain), SA = #{family => Domain, addr => Addr}, i("found (~p) - 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 {ok, P} -> + %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!! + %% ok = socket:setopt(Sock, otp, debug, false), P; {error, BReason} -> throw({bind, BReason}) -- cgit v1.2.3 From 5329726352f8b983e419b6206a85c15cc8836676 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 9 Jul 2018 18:41:07 +0200 Subject: [socket-nif] Add support for socket (level socket) option peek_off The socket option (level socket) peek_off is now supported. OTP-14831 --- lib/kernel/test/socket_server.erl | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 54e13cc92d..e5338644b1 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -99,6 +99,25 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> i("try open socket"), case socket:open(Domain, Type, Proto) of {ok, Sock} -> + F = fun(X) -> case socket:getopt(Sock, socket, X) of + {ok, V} -> f("~p", [V]); + {error, _} -> "-" + end + end, + i("(socket) open (~s,~s,~s): " + "~n broadcast: ~s" + "~n dontroute: ~s" + "~n keepalive: ~s" + "~n reuseaddr: ~s" + "~n linger: ~s" + "~n debug: ~s" + "~n prio: ~s" + "~n rcvbuf: ~s" + "~n sndbuf: ~s" + "~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}, @@ -260,14 +279,22 @@ acceptor_do_init(Domain, Type, Proto) -> end, F = fun(X) -> case socket:getopt(Sock, socket, X) of {ok, V} -> f("~p", [V]); - {error, _} -> "-" + {error, R} -> f("error: ~p", [R]) end end, i("(socket) open (~s,~s,~s): " - "~n debug: ~s" - "~n prio: ~s" - "~n try find (local) address", - [F(domain), F(type), F(protocol), F(debug), F(priority)]), + "~n dontroute: ~s" + "~n keepalive: ~s" + "~n reuseaddr: ~s" + "~n linger: ~s" + "~n debug: ~s" + "~n prio: ~s" + "~n rcvbuf: ~s" + "~n sndbuf: ~s" + "~n => try find (local) address", + [F(domain), F(type), F(protocol), + 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}, -- cgit v1.2.3 From 9110ba256099e6fa55461fc4ca90da5ec4b2966b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 10 Jul 2018 11:28:11 +0200 Subject: [socket-nif] Add support for socket (level socket) option oobinline Added support for socket level socket option oobinline (both get and set). OTP-14831 --- lib/kernel/test/socket_server.erl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index e5338644b1..da5a2ca905 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -438,11 +438,13 @@ handler_init(Manager, ID, Peek, 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), i("got continue when: " - "~n Domain: ~p" - "~n Type: ~p" - "~n Protocol: ~p", [Domain, Type, Proto]), - %% socket:setopt(Socket, otp, debug, true), + "~n Domain: ~p" + "~n Type: ~p" + "~n Protocol: ~p" + "~n OOBInline: ~p", [Domain, Type, Proto, OOBI]), + %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, type = Type, -- cgit v1.2.3 From 8936b71f13b37559600afb5536ff7d7878b9ab0e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 10 Jul 2018 13:42:28 +0200 Subject: [socket-nif] Add support for socket (level ip) option multicast_loop Added support for the IP option MULTICAST_LOOP. OTP-14831 --- lib/kernel/test/socket_server.erl | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index da5a2ca905..9c6ef47fbc 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -439,11 +439,21 @@ handler_init(Manager, ID, Peek, Sock) -> {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, ML} = socket:getopt(Sock, ip, multicast_loop), i("got continue when: " - "~n Domain: ~p" - "~n Type: ~p" - "~n Protocol: ~p" - "~n OOBInline: ~p", [Domain, Type, Proto, OOBI]), + "~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 Loop: ~p", + [Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, ML]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 59586c412340d24188f78730c5b2c45db772c8ca Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 10 Jul 2018 14:01:00 +0200 Subject: [socket-nif] Add support for socket (level ip) option multicast_ttl Added support for the IP option MULTICAST_TTL. OTP-14831 --- lib/kernel/test/socket_server.erl | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 9c6ef47fbc..9e4e355179 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -283,18 +283,10 @@ acceptor_do_init(Domain, Type, Proto) -> end end, i("(socket) open (~s,~s,~s): " - "~n dontroute: ~s" - "~n keepalive: ~s" - "~n reuseaddr: ~s" - "~n linger: ~s" "~n debug: ~s" "~n prio: ~s" - "~n rcvbuf: ~s" - "~n sndbuf: ~s" "~n => try find (local) address", - [F(domain), F(type), F(protocol), - F(dontroute), F(keepalive), F(reuseaddr), F(linger), - F(debug), F(priority), F(rcvbuf), F(sndbuf)]), + [F(domain), F(type), F(protocol), F(debug), F(priority)]), Addr = which_addr(Domain), SA = #{family => Domain, addr => Addr}, @@ -442,7 +434,8 @@ 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, ML} = socket:getopt(Sock, ip, multicast_loop), + {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), + {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -451,9 +444,10 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) SndBuf: ~p" "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" - "~n (ip) Multicast Loop: ~p", + "~n (ip) Multicast Loop: ~p" + "~n (ip) Multicast TTL: ~p", [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, ML]), + OOBI, SndBuf, RcvBuf, Linger, MLoop, MTTL]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 8118227d80fc41efac23d30a5601fdfadb75931f Mon Sep 17 00:00:00 2001 From: Micael Karlberg 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/test') 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 From e5a5cb1025270c265baeda89dd4cd13a1417a262 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 11 Jul 2018 18:20:06 +0200 Subject: [socket-nif] Add support for socket (level ip) option mtu Added support for the IP option MTU. OTP-14831 --- lib/kernel/test/socket_client.erl | 4 +++- lib/kernel/test/socket_server.erl | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 23d3c9956e..dce50682ab 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -80,6 +80,7 @@ do_start(Domain, stream = Type, Proto, SA) -> {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf), {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf), {ok, Linger} = socket:getopt(Sock, socket, linger), + {ok, MTU} = socket:getopt(Sock, ip, mtu), {ok, MIF} = socket:getopt(Sock, ip, multicast_if), {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), @@ -94,13 +95,14 @@ do_start(Domain, stream = Type, Proto, SA) -> "~n (socket) SndBuf: ~p" "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" + "~n (ip) MTU: ~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]), + OOBI, SndBuf, RcvBuf, Linger, MTU, MIF, MLoop, MTTL]), %% Give the server some time... ?LIB:sleep(5000), %% ok = socket:close(Sock), diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 5fd32e040c..f77c91996f 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -442,6 +442,12 @@ 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 = case socket:getopt(Sock, ip, mtu) of + {ok, Val} -> + f("~w", [Val]); + {error, _} -> + "-" % We don't connect UDP (it can be done but we don't) + end, {ok, MIF} = socket:getopt(Sock, ip, multicast_if), {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), @@ -453,11 +459,12 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) SndBuf: ~p" "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" + "~n (ip) MTU: ~s" "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p", [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, MIF, MLoop, MTTL]), + OOBI, SndBuf, RcvBuf, Linger, MTU, MIF, MLoop, MTTL]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From e0f27afac1cb3e3a5567a05081d0cf307c154b0d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 12 Jul 2018 10:24:44 +0200 Subject: [socket-nif] Add support for socket (level ip) option mtu_discover Added support for the IP option MTU_DISCOVER. OTP-14831 --- lib/kernel/test/socket_client.erl | 33 ++++++++++++++++++--------------- lib/kernel/test/socket_server.erl | 21 +++++++++++++-------- 2 files changed, 31 insertions(+), 23 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index dce50682ab..6c6dc0444c 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -71,19 +71,20 @@ 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, MTU} = socket:getopt(Sock, ip, mtu), - {ok, MIF} = socket:getopt(Sock, ip, multicast_if), - {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), - {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), + {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, MTU} = socket:getopt(Sock, ip, mtu), + {ok, MTUDisc} = socket:getopt(Sock, ip, mtu_discover), + {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" @@ -96,13 +97,15 @@ do_start(Domain, stream = Type, Proto, SA) -> "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" "~n (ip) MTU: ~p" + "~n (ip) MTU Discovery: ~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, MTU, MIF, MLoop, MTTL]), + Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, + MTU, MTUDisc, MIF, MLoop, MTTL]), %% Give the server some time... ?LIB:sleep(5000), %% ok = socket:close(Sock), diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index f77c91996f..68a6aebc50 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -435,6 +435,13 @@ handler_init(Manager, ID, Peek, Sock) -> {handler, Pid, Ref, continue} -> i("got continue"), handler_reply(Pid, Ref, ok), + G = fun(K) -> case socket:getopt(Sock, ip, K) of + {ok, Val} -> + f("~w", [Val]); + {error, _} -> + "-" + end + end, {ok, Domain} = socket:getopt(Sock, socket, domain), {ok, Type} = socket:getopt(Sock, socket, type), {ok, Proto} = socket:getopt(Sock, socket, protocol), @@ -442,12 +449,8 @@ 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 = case socket:getopt(Sock, ip, mtu) of - {ok, Val} -> - f("~w", [Val]); - {error, _} -> - "-" % We don't connect UDP (it can be done but we don't) - end, + MTU = G(mtu), + MTUDisc = G(mtu_discover), {ok, MIF} = socket:getopt(Sock, ip, multicast_if), {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), @@ -460,11 +463,13 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" "~n (ip) MTU: ~s" + "~n (ip) MTU Discovery: ~s" "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p", - [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, MTU, MIF, MLoop, MTTL]), + [Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, + MTU, MTUDisc, MIF, MLoop, MTTL]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From ea680e88b967440b2ecd925321ebb5dd48461608 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 12 Jul 2018 10:42:19 +0200 Subject: [socket-nif] Add support for socket (level ip) option multicast_all Added support for the IP option MULTICAST_ALL. OTP-14831 --- lib/kernel/test/socket_client.erl | 15 ++++++++++----- lib/kernel/test/socket_server.erl | 4 +++- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 6c6dc0444c..fa905de954 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -82,6 +82,7 @@ do_start(Domain, stream = Type, Proto, SA) -> {ok, Linger} = socket:getopt(Sock, socket, linger), {ok, MTU} = socket:getopt(Sock, ip, mtu), {ok, MTUDisc} = socket:getopt(Sock, ip, 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), @@ -98,6 +99,7 @@ do_start(Domain, stream = Type, Proto, SA) -> "~n (socket) Linger: ~p" "~n (ip) MTU: ~p" "~n (ip) MTU Discovery: ~p" + "~n (ip) Multicast ALL: ~p" "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p" @@ -105,7 +107,7 @@ do_start(Domain, stream = Type, Proto, SA) -> [Name, Peer, Domain, Type, Proto, OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MIF, MLoop, MTTL]), + MTU, MTUDisc, MALL, MIF, MLoop, MTTL]), %% Give the server some time... ?LIB:sleep(5000), %% ok = socket:close(Sock), @@ -127,6 +129,7 @@ do_start(Domain, dgram = Type, Proto, SA) -> {ok, SndBuf} = socket:getopt(Sock, socket, sndbuf), {ok, RcvBuf} = socket:getopt(Sock, socket, rcvbuf), {ok, Linger} = socket:getopt(Sock, socket, linger), + {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), @@ -138,15 +141,17 @@ do_start(Domain, dgram = Type, Proto, SA) -> "~n (socket) SndBuf: ~p" "~n (socket) RcvBuf: ~p" "~n (socket) Linger: ~p" + "~n (ip) Multicast ALL: ~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]), + "~n => wait some", + [Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, + MALL, MIF, MLoop, MTTL]), ?LIB:sleep(5000), %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, + send_loop(#client{socket = Sock, type = Type, dest = SA}) catch diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 68a6aebc50..f2d63c4dc1 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -451,6 +451,7 @@ handler_init(Manager, ID, Peek, Sock) -> {ok, Linger} = socket:getopt(Sock, socket, linger), 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), @@ -464,12 +465,13 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) Linger: ~p" "~n (ip) MTU: ~s" "~n (ip) MTU Discovery: ~s" + "~n (ip) Multicast ALL: ~p" "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p", [Domain, Type, Proto, OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MIF, MLoop, MTTL]), + MTU, MTUDisc, MALL, MIF, MLoop, MTTL]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 0122d2cafdb6f44c221796f1a6b2a5188dfb153d Mon Sep 17 00:00:00 2001 From: Micael Karlberg 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 --- lib/kernel/test/socket_server.erl | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'lib/kernel/test') 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 From ca81f1d1602cf994fca9fcd61e892c76e4e2742c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 12 Jul 2018 11:22:53 +0200 Subject: [socket-nif] Add support for socket (level ip) option recvttl Added support for the IP option RECVTTL. OTP-14831 --- lib/kernel/test/socket_client.erl | 34 +++++++++++++++++++++------------- lib/kernel/test/socket_server.erl | 8 ++++++-- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index fa905de954..8ec9a02374 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -86,6 +86,7 @@ do_start(Domain, stream = Type, Proto, SA) -> {ok, MIF} = socket:getopt(Sock, ip, multicast_if), {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), + {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), i("connected: " "~n From: ~p" "~n To: ~p" @@ -103,11 +104,13 @@ do_start(Domain, stream = Type, Proto, SA) -> "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p" + "~n (ip) RecvTOS: ~p" "~n => wait some", [Name, Peer, Domain, Type, Proto, OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MALL, MIF, MLoop, MTTL]), + MTU, MTUDisc, MALL, MIF, MLoop, MTTL, + RecvTOS]), %% Give the server some time... ?LIB:sleep(5000), %% ok = socket:close(Sock), @@ -122,17 +125,19 @@ do_start(Domain, dgram = Type, Proto, SA) -> try do_init(Domain, Type, Proto) of Sock -> %% Give the server some time... - {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, 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), + {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, 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), + {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), + {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl), i("initiated when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -145,10 +150,13 @@ do_start(Domain, dgram = Type, Proto, SA) -> "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p" + "~n (ip) RecvTOS: ~p" + "~n (ip) RecvTTL: ~p" "~n => wait some", [Domain, Type, Proto, OOBI, SndBuf, RcvBuf, Linger, - MALL, MIF, MLoop, MTTL]), + MALL, MIF, MLoop, MTTL, + RecvTOS, RecvTTL]), ?LIB:sleep(5000), %% ok = socket:close(Sock), send_loop(#client{socket = Sock, diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 6a207a7b1b..ff8f6575a3 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -460,6 +460,8 @@ handler_init(Manager, ID, Peek, Sock) -> {ok, MLoop} = socket:getopt(Sock, ip, multicast_loop), {ok, MTTL} = socket:getopt(Sock, ip, multicast_ttl), NF = G(nodefrag), % raw only + RecvTOS = G(recvtos), + RecvTTL = G(recvttl), % not stream i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -474,11 +476,13 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Multicast IF: ~p" "~n (ip) Multicast Loop: ~p" "~n (ip) Multicast TTL: ~p" - "~n (ip) NodeFrag: ~s", + "~n (ip) NodeFrag: ~s" + "~n (ip) RecvTOS: ~s" + "~n (ip) RecvTTL: ~s", [Domain, Type, Proto, OOBI, SndBuf, RcvBuf, Linger, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - NF]), + NF, RecvTOS, RecvTTL]), %% socket:setopt(Sock, otp, debug, true), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 5e0a36abaa984358f617541b102b4e4cbb112956 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 13 Jul 2018 14:42:34 +0200 Subject: [socket-nif] Add support for socket (level socket) option bindtodevice Added support for socket level socket option BINDTODEVICE. OTP-14831 --- lib/kernel/test/socket_server.erl | 51 +++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index ff8f6575a3..6d002db38e 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -101,7 +101,7 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> {ok, Sock} -> F = fun(X) -> case socket:getopt(Sock, socket, X) of {ok, V} -> f("~p", [V]); - {error, _} -> "-" + {error, R} -> f("error: ~p", [R]) end end, i("socket opened (~s,~s,~s): " @@ -129,11 +129,16 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> {error, BReason} -> throw({bind, BReason}) end, - i("try start handler for" - "~n ~p", [case socket:sockname(Sock) of - {ok, Name} -> Name; - {error, _} = E -> E - end]), + socket:setopt(Sock, otp, debug, true), + i("bound to: " + "~n ~s" + "~n (socket) Bind To Device: ~s" + "~n => try start handler", + [case socket:sockname(Sock) of + {ok, Name} -> f("~p", [Name]); + {error, R} -> f("error: ~p", [R]) + end, + F(bindtodevice)]), case handler_start(1, Sock, Peek) of {ok, {Pid, MRef}} -> i("handler (~p) started", [Pid]), @@ -435,37 +440,41 @@ handler_init(Manager, ID, Peek, Sock) -> {handler, Pid, Ref, continue} -> i("got continue"), handler_reply(Pid, Ref, ok), - G = fun(K) -> case socket:getopt(Sock, ip, K) of - {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]) + G = fun(L, O) -> case socket:getopt(Sock, L, O) of + {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, + GIP = fun(O) -> G(ip, O) end, + GSO = fun(O) -> G(socket, O) end, {ok, Domain} = socket:getopt(Sock, socket, domain), {ok, Type} = socket:getopt(Sock, socket, type), {ok, Proto} = socket:getopt(Sock, socket, protocol), + B2D = GSO(bindtodevice), {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), - MTU = G(mtu), - MTUDisc = G(mtu_discover), + MTU = GIP(mtu), + MTUDisc = GIP(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 - RecvTOS = G(recvtos), - RecvTTL = G(recvttl), % not stream + NF = GIP(nodefrag), % raw only + RecvTOS = GIP(recvtos), + RecvTTL = GIP(recvttl), % not stream i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" "~n (socket) Protocol: ~p" + "~n (socket) Bind To Device: ~s" "~n (socket) OOBInline: ~p" "~n (socket) SndBuf: ~p" "~n (socket) RcvBuf: ~p" @@ -480,7 +489,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) RecvTOS: ~s" "~n (ip) RecvTTL: ~s", [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, + B2D, OOBI, SndBuf, RcvBuf, Linger, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), %% socket:setopt(Sock, otp, debug, true), -- cgit v1.2.3 From 8de18e84deaed4c9e6e7242ae2550fc6618dc44d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 13 Jul 2018 18:38:53 +0200 Subject: [socket-nif] Add support for socket (level socket) option reuseport Added support for socket level socket option REUSEPORT. OTP-14831 --- lib/kernel/test/socket_server.erl | 49 ++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 6d002db38e..d9bbf00e85 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -129,16 +129,13 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> {error, BReason} -> throw({bind, BReason}) end, - socket:setopt(Sock, otp, debug, true), i("bound to: " "~n ~s" - "~n (socket) Bind To Device: ~s" "~n => try start handler", [case socket:sockname(Sock) of {ok, Name} -> f("~p", [Name]); {error, R} -> f("error: ~p", [R]) - end, - F(bindtodevice)]), + end]), case handler_start(1, Sock, Peek) of {ok, {Pid, MRef}} -> i("handler (~p) started", [Pid]), @@ -457,16 +454,18 @@ handler_init(Manager, ID, Peek, Sock) -> {ok, Type} = socket:getopt(Sock, socket, type), {ok, Proto} = socket:getopt(Sock, socket, protocol), B2D = GSO(bindtodevice), - {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), + RA = GSO(reuseaddr), + RP = GSO(reuseport), + OOBI = GSO(oobinline), + SndBuf = GSO(sndbuf), + RcvBuf = GSO(rcvbuf), + Linger = GSO(linger), MTU = GIP(mtu), MTUDisc = GIP(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), + MALL = GIP(multicast_all), + MIF = GIP(multicast_if), + MLoop = GIP(multicast_loop), + MTTL = GIP(multicast_ttl), NF = GIP(nodefrag), % raw only RecvTOS = GIP(recvtos), RecvTTL = GIP(recvttl), % not stream @@ -474,22 +473,24 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) Domain: ~p" "~n (socket) Type: ~p" "~n (socket) Protocol: ~p" + "~n (socket) Reuse Address: ~s" + "~n (socket) Reuse Port: ~s" "~n (socket) Bind To Device: ~s" - "~n (socket) OOBInline: ~p" - "~n (socket) SndBuf: ~p" - "~n (socket) RcvBuf: ~p" - "~n (socket) Linger: ~p" + "~n (socket) OOBInline: ~s" + "~n (socket) SndBuf: ~s" + "~n (socket) RcvBuf: ~s" + "~n (socket) Linger: ~s" "~n (ip) MTU: ~s" "~n (ip) MTU Discovery: ~s" - "~n (ip) Multicast ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) NodeFrag: ~s" - "~n (ip) RecvTOS: ~s" - "~n (ip) RecvTTL: ~s", + "~n (ip) Multicast ALL: ~s" + "~n (ip) Multicast IF: ~s" + "~n (ip) Multicast Loop: ~s" + "~n (ip) Multicast TTL: ~s" + "~n (ip) Node Frag: ~s" + "~n (ip) Recv TOS: ~s" + "~n (ip) Recv TTL: ~s", [Domain, Type, Proto, - B2D, OOBI, SndBuf, RcvBuf, Linger, + RA, RP, B2D, OOBI, SndBuf, RcvBuf, Linger, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), %% socket:setopt(Sock, otp, debug, true), -- cgit v1.2.3 From 017565203f40860d24b80a54136a160aee460dbe Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 16 Jul 2018 18:21:48 +0200 Subject: [socket-nif] Add support for multiple acceptor processes Its now possible to have multiple (simultaneous) acceptor processes for the same listening socket. OTP-14831 --- lib/kernel/test/socket_server.erl | 313 ++++++++++++++++++++++---------------- 1 file changed, 184 insertions(+), 129 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index d9bbf00e85..8a77b9b3c9 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -28,10 +28,12 @@ -define(LIB, socket_lib). --record(manager, {peek, acceptor, handler_id, handlers}). --record(acceptor, {socket, manager}). +-record(manager, {socket, peek, acceptors, handler_id, handlers}). +-record(acceptor, {id, socket, manager}). -record(handler, {socket, peek, type, manager}). +-define(NUM_ACCEPTORS, 5). + start() -> start_tcp(). @@ -83,17 +85,13 @@ manager_reply(Pid, Ref, Reply) -> manager_init(Domain, stream = Type, Proto, Peek) -> put(sname, "manager"), - i("try start acceptor"), - case acceptor_start(Domain, Type, Proto) of - {ok, {Pid, MRef}} -> - i("acceptor started"), - manager_loop(#manager{peek = Peek, - acceptor = {Pid, MRef}, - handler_id = 1, - handlers = []}); - {error, Reason} -> - exit({failed_starting_acceptor, Reason}) - end; + i("try start acceptor(s)"), + {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto), + manager_loop(#manager{socket = Sock, + peek = Peek, + acceptors = Acceptors, + handler_id = 1, + handlers = []}); manager_init(Domain, dgram = Type, Proto, Peek) -> put(sname, "manager"), i("try open socket"), @@ -142,7 +140,7 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> handler_continue(Pid), manager_loop(#manager{peek = Peek, handler_id = 2, % Just in case - handlers = [{Pid, MRef, 1}]}); + handlers = [{1, Pid, MRef}]}); {error, SReason} -> e("Failed starting handler: " "~n ~p", [SReason]), @@ -155,35 +153,142 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> end. +manager_stream_init(Domain, Type, Proto) -> + i("try (socket) open"), + Sock = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, OReason} -> + throw({open, OReason}) + end, + F = fun(X) -> case socket:getopt(Sock, socket, X) of + {ok, V} -> f("~p", [V]); + {error, R} -> f("error: ~p", [R]) + end + end, + i("(socket) open (~s,~s,~s): " + "~n debug: ~s" + "~n prio: ~s" + "~n => try find (local) address", + [F(domain), F(type), F(protocol), F(debug), F(priority)]), + Addr = which_addr(Domain), + SA = #{family => Domain, + addr => 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 + {ok, P} -> + %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!! + %% ok = socket:setopt(Sock, otp, debug, false), + P; + {error, BReason} -> + throw({bind, BReason}) + end, + i("bound to: " + "~n ~p" + "~n => try (socket) listen (acceptconn: ~s)", + [Port, F(acceptconn)]), + case socket:listen(Sock) of + ok -> + i("listening (acceptconn: ~s)", + [F(acceptconn)]), + manager_stream_init(Sock, 1, ?NUM_ACCEPTORS, []); + {error, LReason} -> + throw({listen, LReason}) + end. + +which_addr(Domain) -> + Iflist = case inet:getifaddrs() of + {ok, IFL} -> + IFL; + {error, Reason} -> + throw({inet,getifaddrs,Reason}) + end, + which_addr(Domain, Iflist). + +which_addr(_Domain, []) -> + throw(no_address); +which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> + which_addr2(Domain, IFO); +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) -> + Addr; +which_addr2(Domain, [_|IFO]) -> + which_addr2(Domain, IFO). + + +manager_stream_init(Sock, ID, NumAcceptors, Acc) + when (NumAcceptors > 0) -> + i("try start acceptor"), + case acceptor_start(Sock, ID) of + {ok, {Pid, MRef}} -> + i("acceptor ~w (~p) started", [ID, Pid]), + ?LIB:sleep(5000), + manager_stream_init(Sock, ID+1, NumAcceptors-1, + [{ID, Pid, MRef}|Acc]); + {error, Reason} -> + exit({failed_starting_acceptor, Reason}) + end; +manager_stream_init(Sock, _ID, 0, Acc) -> + %% Req = {kill_acceptor, length(Acc)}, % Last in the queue + %% Req = {kill_acceptor, 3}, % In the "middle" of the queue + %% Req = {kill_acceptor, 2}, % The first in the queue + %% Req = {kill_acceptor, 1}, % Current acceptor + %% Msg = {manager, self(), make_ref(), Req}, + %% erlang:send_after(timer:seconds(10), self(), Msg), + {Sock, lists:reverse(Acc)}. + + manager_loop(M) -> receive {'DOWN', MRef, process, Pid, Reason} -> M2 = manager_handle_down(M, MRef, Pid, Reason), manager_loop(M2); - + {manager, Pid, Ref, Request} -> M2 = manager_handle_request(M, Pid, Ref, Request), manager_loop(M2) end. -manager_handle_down(#manager{acceptor = {Pid, MRef}}, MRef, Pid, Reason) - when (Reason =/= normal) -> - e("acceptor died: " - "~n ~p", [Reason]), - exit({acceptor_died, Reason}); -manager_handle_down(#manager{acceptor = {Pid, MRef}}, MRef, Pid, Reason) -> - exit(Reason); -manager_handle_down(#manager{handlers = Handlers} = M, _MRef, Pid, Reason) -> - if - (Reason =/= normal) -> - e("handler ~p died: " - "~n ~p", [Pid, Reason]); - true -> - i("handler ~p terminated", [Pid]) - end, - Handlers2 = lists:keydelete(Pid, 1, Handlers), - M#manager{handlers = Handlers2}. +manager_handle_down(#manager{acceptors = Acceptors, + handlers = Handlers} = M, MRef, Pid, Reason) -> + case lists:keysearch(Pid, 2, Acceptors) of + {value, {ID, Pid, MRef}} when (Reason =:= normal) -> + i("acceptor ~w exited (normally)", [ID]), + case lists:keydelete(Pid, 2, Acceptors) of + [] -> + %% We are done + i("the last acceptor - we are done"), + exit(normal); + Acceptors2 -> + M#manager{acceptors = Acceptors2} + end; + {value, {ID, Pid, MRef}} -> + e("acceptor ~w crashed: " + "~n ~p", [ID, Reason]), + exit({acceptor_died, Reason}); + + false -> %% handler! + if + (Reason =/= normal) -> + e("handler ~p died: " + "~n ~p", [Pid, Reason]); + true -> + i("handler ~p terminated", [Pid]) + end, + Handlers2 = lists:keydelete(Pid, 2, Handlers), + M#manager{handlers = Handlers2} + end. manager_handle_request(#manager{peek = Peek, @@ -196,7 +301,7 @@ manager_handle_request(#manager{peek = Peek, i("handler ~w started", [HID]), manager_reply(Pid, Ref, {ok, HPid}), M#manager{handler_id = HID+1, - handlers = [{HPid, HMRef, HID}|Handlers]}; + handlers = [{HID, HPid, HMRef}|Handlers]}; {error, Reason} = ERROR -> e("Failed starting new handler: " "~n Sock: ~p" @@ -204,21 +309,50 @@ manager_handle_request(#manager{peek = Peek, manager_reply(Pid, Ref, ERROR), M end; -manager_handle_request(#manager{acceptor = {Pid, MRef}, - handlers = Handlers}, Pid, Ref, +manager_handle_request(#manager{socket = Sock, + acceptors = [{AID, APid, AMRef}]} = M, _Pid, _Ref, + {kill_acceptor, AID}) -> + i("try kill (only remeining) acceptor ~w", [AID]), + socket:setopt(Sock, otp, debug, true), + manager_stop_acceptor(APid, AMRef, AID, kill), + M#manager{acceptors = []}; +manager_handle_request(#manager{socket = Sock, + acceptors = Acceptors} = M, _Pid, _Ref, + {kill_acceptor, AID}) -> + i("try kill acceptor ~w", [AID]), + case lists:keysearch(AID, 1, Acceptors) of + {value, {AID, APid, AMRef}} -> + socket:setopt(Sock, otp, debug, true), + manager_stop_acceptor(APid, AMRef, AID, kill), + Acceptors2 = lists:keydelete(AID, 1, Acceptors), + M#manager{acceptors = Acceptors2}; + false -> + e("no such acceptor"), + M + end; +manager_handle_request(#manager{acceptors = Acceptors, + handlers = Handlers}, Pid, Ref, {stop, Reason}) -> i("stop"), manager_reply(Pid, Ref, ok), manager_stop_handlers(Handlers, Reason), - i("try stop acceptor ~p: ~p", [Pid, Reason]), - erlang:demonitor(MRef, [flush]), - acceptor_stop(Pid, Reason), - i("stop", []), + manager_stop_acceptors(Acceptors, Reason), + i("stopped", []), exit(Reason). +manager_stop_acceptors(Acceptors, Reason) -> + lists:foreach(fun({ID,P,M}) -> + manager_stop_acceptor(P, M, ID, Reason) + end, Acceptors). + +manager_stop_acceptor(Pid, MRef, ID, Reason) -> + i("try stop acceptor ~w (~p): ~p", [ID, Pid, Reason]), + erlang:demonitor(MRef, [flush]), + acceptor_stop(Pid, Reason), + ok. manager_stop_handlers(Handlers, Reason) -> - lists:foreach(fun({P,M,ID}) -> + lists:foreach(fun({ID,P,M}) -> manager_stop_handler(P, M, ID, Reason) end, Handlers). @@ -232,10 +366,10 @@ manager_stop_handler(Pid, MRef, ID, Reason) -> %% ========================================================================= -acceptor_start(Domain, Type, Proto) -> +acceptor_start(Sock, ID) -> Self = self(), A = {Pid, _} = spawn_monitor(fun() -> - acceptor_init(Self, Domain, Type, Proto) + acceptor_init(Self, Sock, ID) end), receive {acceptor, Pid, ok} -> @@ -258,93 +392,12 @@ acceptor_stop(Pid, _Reason) -> %% reply(acceptor, Pid, Ref, Reply). -acceptor_init(Manager, Domain, Type, Proto) -> - put(sname, "acceptor"), - try acceptor_do_init(Domain, Type, Proto) of - Sock -> - Manager ! {acceptor, self(), ok}, - acceptor_loop(#acceptor{manager = Manager, - socket = Sock}) - catch - throw:E:P -> - e("Failed initiate: " - "~n Error: ~p" - "~n Path: ~p", [E, P]), - Manager ! {acceptor, self(), {error, {catched, E, P}}} - end. - -acceptor_do_init(Domain, Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - F = fun(X) -> case socket:getopt(Sock, socket, X) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - i("(socket) open (~s,~s,~s): " - "~n debug: ~s" - "~n prio: ~s" - "~n => try find (local) address", - [F(domain), F(type), F(protocol), F(debug), F(priority)]), - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => 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 - {ok, P} -> - %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!! - %% ok = socket:setopt(Sock, otp, debug, false), - P; - {error, BReason} -> - throw({bind, BReason}) - end, - i("bound to: " - "~n ~p" - "~n => try (socket) listen (acceptconn: ~s)", - [Port, F(acceptconn)]), - case socket:listen(Sock) of - ok -> - i("listening (acceptconn: ~s)", - [F(acceptconn)]), - Sock; - {error, LReason} -> - throw({listen, LReason}) - end. - -which_addr(Domain) -> - Iflist = case inet:getifaddrs() of - {ok, IFL} -> - IFL; - {error, Reason} -> - throw({inet,getifaddrs,Reason}) - end, - which_addr(Domain, Iflist). - -which_addr(_Domain, []) -> - throw(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -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) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - +acceptor_init(Manager, Sock, ID) -> + put(sname, f("acceptor[~w]", [ID])), + Manager ! {acceptor, self(), ok}, + acceptor_loop(#acceptor{id = ID, + manager = Manager, + socket = Sock}). acceptor_loop(#acceptor{socket = LSock} = A) -> i("try accept"), @@ -600,6 +653,8 @@ send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> f(F, A) -> ?LIB:f(F, A). +e(F) -> + e(F, []). e(F, A) -> ?LIB:e(F, A). -- cgit v1.2.3 From ebd626e7b4259bdfb4ddb34ce2d298d0feb0a1c8 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 18 Jul 2018 11:33:50 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option mtu Added support for the VPv6 socket option MTU. OTP-14831. --- lib/kernel/test/socket_client.erl | 2 +- lib/kernel/test/socket_server.erl | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 8ec9a02374..0d332e8439 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -21,7 +21,7 @@ -module(socket_client). -export([ - start/1, + start/1, start/5, start_tcp/1, start_tcp/2, start_tcp6/1, start_udp/1, start_udp/2, start_udp6/1 ]). diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 8a77b9b3c9..65069df60b 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -22,8 +22,10 @@ -export([ start/0, start/4, - start_tcp/0, start_tcp/1, - start_udp/0, start_udp/1 + start_tcp/0, start_tcp/1, start_tcp/2, + start_tcp4/1, start_tcp6/1, + start_udp/0, start_udp/1, start_udp/2, + start_udp4/1, start_udp6/1 ]). -define(LIB, socket_lib). @@ -41,13 +43,31 @@ start_tcp() -> start_tcp(false). start_tcp(Peek) -> - start(inet, stream, tcp, Peek). + start_tcp4(Peek). + +start_tcp4(Peek) -> + start_tcp(inet, Peek). + +start_tcp6(Peek) -> + start_tcp(inet6, Peek). + +start_tcp(Domain, Peek) when is_boolean(Peek) -> + start(Domain, stream, tcp, Peek). start_udp() -> start_udp(false). -start_udp(Peek) when is_boolean(Peek) -> - start(inet, dgram, udp, Peek). +start_udp(Peek) -> + start_udp4(Peek). + +start_udp4(Peek) -> + start_udp(inet, Peek). + +start_udp6(Peek) -> + start_udp(inet6, Peek). + +start_udp(Domain, Peek) when is_boolean(Peek) -> + start(Domain, dgram, udp, Peek). start(Domain, Type, Proto, Peek) -> put(sname, "starter"), -- cgit v1.2.3 From d28129b7098bce154264937862fcdafb21541433 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 19 Jul 2018 14:00:42 +0200 Subject: [socket-nif] Add support for socket (level sctp) option events Added support for the SCTP option EVENTS. OTP-14831 --- lib/kernel/test/socket_server.erl | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 65069df60b..23f30a0d03 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -25,7 +25,8 @@ start_tcp/0, start_tcp/1, start_tcp/2, start_tcp4/1, start_tcp6/1, start_udp/0, start_udp/1, start_udp/2, - start_udp4/1, start_udp6/1 + start_udp4/1, start_udp6/1, + start_sctp/0, start_sctp/1 ]). -define(LIB, socket_lib). @@ -69,6 +70,13 @@ start_udp6(Peek) -> start_udp(Domain, Peek) when is_boolean(Peek) -> start(Domain, dgram, udp, Peek). + +start_sctp() -> + start_sctp(inet). + +start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) -> + start(Domain, seqpacket, sctp, false). + start(Domain, Type, Proto, Peek) -> put(sname, "starter"), i("try start manager"), @@ -103,8 +111,11 @@ manager_reply(Pid, Ref, Reply) -> ?LIB:reply(manager, Pid, Ref, Reply). -manager_init(Domain, stream = Type, Proto, Peek) -> +manager_init(Domain, Type, Proto, Peek) -> put(sname, "manager"), + do_manager_init(Domain, Type, Proto, Peek). + +do_manager_init(Domain, stream = Type, Proto, Peek) -> i("try start acceptor(s)"), {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto), manager_loop(#manager{socket = Sock, @@ -112,8 +123,7 @@ manager_init(Domain, stream = Type, Proto, Peek) -> acceptors = Acceptors, handler_id = 1, handlers = []}); -manager_init(Domain, dgram = Type, Proto, Peek) -> - put(sname, "manager"), +do_manager_init(Domain, dgram = Type, Proto, Peek) -> i("try open socket"), case socket:open(Domain, Type, Proto) of {ok, Sock} -> @@ -170,9 +180,39 @@ manager_init(Domain, dgram = Type, Proto, Peek) -> e("Failed open socket: " "~n ~p", [OReason]), exit({failed_open_socket, OReason}) + end; +do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> + %% This is as far as I have got with SCTP at the moment... + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + i("(sctp) socket opened: " + "~n ~p", [Sock]), + F = fun(_Desc, Expect, Expect) -> + Expect; + (Desc, Expect, Actual) -> + e("Unexpected result ~w: " + "~n Expect: ~p" + "~n Actual: ~p", [Desc, Expect, Actual]), + exit({Desc, Expect, Actual}) + end, + Events = #{data_in => true, + association => true, + address => true, + send_failure => true, + peer_error => true, + shutdown => true, + partial_delivery => true, + adaptation_layer => true, + authentication => true, + sender_dry => true}, + F(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)), + F(close_socket, ok, socket:close(Sock)); + {error, Reason} -> + exit({failed_open, Reason}) end. + manager_stream_init(Domain, Type, Proto) -> i("try (socket) open"), Sock = case socket:open(Domain, Type, Proto) of -- cgit v1.2.3 From f0a2e68a31ac585780ad05f777f1b7551770420e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 19 Jul 2018 14:36:34 +0200 Subject: [socket-nif] Add support for socket (level sctp) option disable_fragments Added support for the SCTP option DISABLE_FRAGMENTS. OTP-14831 --- lib/kernel/test/socket_server.erl | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 23f30a0d03..a9b4aca5f8 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -187,14 +187,21 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> {ok, Sock} -> i("(sctp) socket opened: " "~n ~p", [Sock]), - F = fun(_Desc, Expect, Expect) -> - Expect; - (Desc, Expect, Actual) -> - e("Unexpected result ~w: " - "~n Expect: ~p" - "~n Actual: ~p", [Desc, Expect, Actual]), - exit({Desc, Expect, Actual}) - end, + EXP = fun(_Desc, Expect, Expect) -> + Expect; + (Desc, Expect, Actual) -> + e("Unexpected result ~w: " + "~n Expect: ~p" + "~n Actual: ~p", [Desc, Expect, Actual]), + exit({Desc, Expect, Actual}) + end, + GO = fun(O) -> case socket:getopt(Sock, sctp, O) of + {ok, V} -> f("~p", [V]); + {error, R} -> f("error: ~p", [R]) + end + end, + i("Miscellaneous options: " + "~n disable-fragments: ~s", [GO(disable_fragments)]), Events = #{data_in => true, association => true, address => true, @@ -205,8 +212,8 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> adaptation_layer => true, authentication => true, sender_dry => true}, - F(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)), - F(close_socket, ok, socket:close(Sock)); + EXP(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)), + EXP(close_socket, ok, socket:close(Sock)); {error, Reason} -> exit({failed_open, Reason}) end. -- cgit v1.2.3 From 7a5b320b5bb5ec45b21839005e8538172908fb57 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 19 Jul 2018 16:39:13 +0200 Subject: [socket-nif] Add (partial) support for socket (level sctp) option associnfo Added support for the SCTP option ASSOCINFO. This option is a bit tricky. As the underlying structure (sctp_assocparams) contains the assoc_id, it begs the question what happens if this option is fetched for: * The own assoc (which means that we might have the assoc id in the descriptor and can initiate that part of the struct accordningly). * Another assoc: From assoc A asks for info with assoc_id set to that of assoc B. * The "owning" endpoint. * Another endpoint (an endpoint to which the assoc does not belong). So, if the user calls socket:[getopt|setopt] for an association socket, shall we require that the assoc_id field is set to -1? Or not set at all and therefor filled in automatically by the nif-code? And, if the user calls socket:[getopt|setopt] for an endpoint socket, shall we require that the assoc_id field is set to a valid id? Or shall it not be allowed? Questions, questions... OTP-14831 --- lib/kernel/test/socket_server.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index a9b4aca5f8..56200e0ae9 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -200,8 +200,14 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> {error, R} -> f("error: ~p", [R]) end end, + %% ok = socket:setopt(Sock, otp, debug, true), i("Miscellaneous options: " - "~n disable-fragments: ~s", [GO(disable_fragments)]), + "~n associnfo: ~s" + "~n autoclose: ~s" + "~n disable-fragments: ~s", + [GO(associnfo), + GO(autoclose), + GO(disable_fragments)]), Events = #{data_in => true, association => true, address => true, -- cgit v1.2.3 From 6bb60f1fecef368991806e25a0022c63b8650f39 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 19 Jul 2018 17:34:15 +0200 Subject: [socket-nif] Add (partial) support for socket (level sctp) option rtoinfo Added support for the SCTP option RTOINFO. We have the same questions for this option as for ASSOCINFO. Maybe the assoc field shall be made 'out' only (that is, it will be ignored for setopt). The assoc id used will be that which is stored in the descriptor (how do we get it to begin with?). Questions, questions... OTP-14831 --- lib/kernel/test/socket_server.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 56200e0ae9..7320192e6a 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -204,10 +204,12 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> i("Miscellaneous options: " "~n associnfo: ~s" "~n autoclose: ~s" - "~n disable-fragments: ~s", + "~n disable-fragments: ~s" + "~n rtoinfo: ~s", [GO(associnfo), GO(autoclose), - GO(disable_fragments)]), + GO(disable_fragments), + GO(rtoinfo)]), Events = #{data_in => true, association => true, address => true, -- cgit v1.2.3 From 08ce39bbc2cd3006475c87807042c2d08a68736f Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 19 Jul 2018 17:54:14 +0200 Subject: [socket-nif] Add support for socket (level sctp) option maxseg Added support for the SCTP option MAXSEG. OTP-14831 --- lib/kernel/test/socket_server.erl | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 7320192e6a..6fc4c60543 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -201,15 +201,21 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> end end, %% ok = socket:setopt(Sock, otp, debug, true), + i("Miscellaneous options: " "~n associnfo: ~s" "~n autoclose: ~s" "~n disable-fragments: ~s" + "~n maxseg: ~s" + "~n nodelay: ~s" "~n rtoinfo: ~s", [GO(associnfo), GO(autoclose), GO(disable_fragments), + GO(maxseg), + GO(nodelay), GO(rtoinfo)]), + Events = #{data_in => true, association => true, address => true, -- cgit v1.2.3 From bd36af21717b138c91724128e592b3fc587bb07a Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 20 Jul 2018 10:10:28 +0200 Subject: [socket-nif] Add support for socket (level sctp) option initmsg Added support for the SCTP option INITMSG. OTP-14831 --- lib/kernel/test/socket_server.erl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 6fc4c60543..986363b56d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -206,12 +206,14 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> "~n associnfo: ~s" "~n autoclose: ~s" "~n disable-fragments: ~s" + "~n initmsg: ~s" "~n maxseg: ~s" "~n nodelay: ~s" "~n rtoinfo: ~s", [GO(associnfo), GO(autoclose), GO(disable_fragments), + GO(initmsg), GO(maxseg), GO(nodelay), GO(rtoinfo)]), -- cgit v1.2.3 From 3f1d17f3031b71ca6ff1f8e051859ad55e55822b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 20 Jul 2018 12:28:19 +0200 Subject: [socket-nif] Add support for socket (level socket) option(s) [rcv|snd]timeo Added support for socket level socket option RCVTIMEO and SNDTIMEO. These are both a little strange, at least on linux. See the man pages for more info. OTP-14831 --- lib/kernel/test/socket_server.erl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 986363b56d..80de3574d1 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -141,11 +141,14 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> "~n debug: ~s" "~n prio: ~s" "~n rcvbuf: ~s" + "~n rcvtimeo: ~s" "~n sndbuf: ~s" + "~n sndtimeo: ~s" "~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)]), + F(debug), F(priority), + F(rcvbuf), F(rcvtimeo), F(sndbuf), F(sndtimeo)]), Addr = which_addr(Domain), SA = #{family => Domain, addr => Addr}, @@ -315,7 +318,7 @@ manager_stream_init(Sock, ID, NumAcceptors, Acc) case acceptor_start(Sock, ID) of {ok, {Pid, MRef}} -> i("acceptor ~w (~p) started", [ID, Pid]), - ?LIB:sleep(5000), + ?LIB:sleep(2000), manager_stream_init(Sock, ID+1, NumAcceptors-1, [{ID, Pid, MRef}|Acc]); {error, Reason} -> @@ -593,8 +596,10 @@ handler_init(Manager, ID, Peek, Sock) -> RA = GSO(reuseaddr), RP = GSO(reuseport), OOBI = GSO(oobinline), - SndBuf = GSO(sndbuf), RcvBuf = GSO(rcvbuf), + RcvTO = GSO(rcvtimeo), + SndBuf = GSO(sndbuf), + SndTO = GSO(sndtimeo), Linger = GSO(linger), MTU = GIP(mtu), MTUDisc = GIP(mtu_discover), @@ -613,8 +618,10 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) Reuse Port: ~s" "~n (socket) Bind To Device: ~s" "~n (socket) OOBInline: ~s" - "~n (socket) SndBuf: ~s" "~n (socket) RcvBuf: ~s" + "~n (socket) RcvTO: ~s" + "~n (socket) SndBuf: ~s" + "~n (socket) SndTO: ~s" "~n (socket) Linger: ~s" "~n (ip) MTU: ~s" "~n (ip) MTU Discovery: ~s" @@ -626,10 +633,12 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s", [Domain, Type, Proto, - RA, RP, B2D, OOBI, SndBuf, RcvBuf, Linger, + RA, RP, B2D, OOBI, + RcvBuf, RcvTO, SndBuf, SndTO, + Linger, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), - %% socket:setopt(Sock, otp, debug, true), + handler_loop(#handler{peek = Peek, manager = Manager, type = Type, -- cgit v1.2.3 From 75498c0dd7682bae7787c4e2cd8d2680fa2b9c45 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 20 Jul 2018 13:00:22 +0200 Subject: [socket-nif] Add support for socket (level socket) option(s) [rcv|snd]lowat Added support for socket level socket option RCVLOWAT and SNDLOWAT. These are both a little strange, at least on Linux. See the man pages for more info. For instance, sndlowat cannot be set on Linux. OTP-14831 --- lib/kernel/test/socket_server.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 80de3574d1..10239b0265 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -597,8 +597,10 @@ handler_init(Manager, ID, Peek, Sock) -> RP = GSO(reuseport), OOBI = GSO(oobinline), RcvBuf = GSO(rcvbuf), + RcvLW = GSO(rcvlowat), RcvTO = GSO(rcvtimeo), SndBuf = GSO(sndbuf), + SndLW = GSO(sndlowat), SndTO = GSO(sndtimeo), Linger = GSO(linger), MTU = GIP(mtu), @@ -619,8 +621,10 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) Bind To Device: ~s" "~n (socket) OOBInline: ~s" "~n (socket) RcvBuf: ~s" + "~n (socket) RcvLW: ~s" "~n (socket) RcvTO: ~s" "~n (socket) SndBuf: ~s" + "~n (socket) SndLW: ~s" "~n (socket) SndTO: ~s" "~n (socket) Linger: ~s" "~n (ip) MTU: ~s" @@ -634,11 +638,11 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv TTL: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, - RcvBuf, RcvTO, SndBuf, SndTO, + RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), - + handler_loop(#handler{peek = Peek, manager = Manager, type = Type, -- cgit v1.2.3 From 84f62ae80dd08874d0d5fbedc532605394e897c1 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 20 Jul 2018 14:01:14 +0200 Subject: [socket-nif] Add support for socket (level socket) option timestamp Added support for socket level socket option TIMESTAMP. OTP-14831 --- lib/kernel/test/socket_server.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 10239b0265..6aa26494f7 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -603,6 +603,7 @@ handler_init(Manager, ID, Peek, Sock) -> SndLW = GSO(sndlowat), SndTO = GSO(sndtimeo), Linger = GSO(linger), + Timestamp = GSO(timestamp), MTU = GIP(mtu), MTUDisc = GIP(mtu_discover), MALL = GIP(multicast_all), @@ -627,6 +628,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) SndLW: ~s" "~n (socket) SndTO: ~s" "~n (socket) Linger: ~s" + "~n (socket) Timestamp: ~s" "~n (ip) MTU: ~s" "~n (ip) MTU Discovery: ~s" "~n (ip) Multicast ALL: ~s" @@ -639,7 +641,7 @@ handler_init(Manager, ID, Peek, Sock) -> [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, - Linger, + Linger, Timestamp, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), -- cgit v1.2.3 From 1c26ae984a79224ce64b40dbc7239bf9721bb096 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 20 Jul 2018 15:14:06 +0200 Subject: [socket-nif] Add support for socket (level ip) option freebind Added support for ip level socket option FREEBIND. Note that there is an option available on FreeBSD called IP_BINDANY, which seems to have similar properties (FREEBIND is *not* available on FreeBSD). There are some restrictions for this option though (which is not mentioned in the Linux man page). OTP-14831 --- lib/kernel/test/socket_server.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 6aa26494f7..971ceb2093 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -604,6 +604,7 @@ handler_init(Manager, ID, Peek, Sock) -> SndTO = GSO(sndtimeo), Linger = GSO(linger), Timestamp = GSO(timestamp), + FreeBind = GIP(freebind), MTU = GIP(mtu), MTUDisc = GIP(mtu_discover), MALL = GIP(multicast_all), @@ -629,6 +630,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (socket) SndTO: ~s" "~n (socket) Linger: ~s" "~n (socket) Timestamp: ~s" + "~n (ip) FreeBind: ~s" "~n (ip) MTU: ~s" "~n (ip) MTU Discovery: ~s" "~n (ip) Multicast ALL: ~s" @@ -642,7 +644,7 @@ handler_init(Manager, ID, Peek, Sock) -> RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, - MTU, MTUDisc, MALL, MIF, MLoop, MTTL, + FreeBind, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, NF, RecvTOS, RecvTTL]), handler_loop(#handler{peek = Peek, -- cgit v1.2.3 From 31ef72ceda0bf5bba902bf18f3b445950516d6af Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 23 Jul 2018 10:57:25 +0200 Subject: [socket-nif] Add support for socket (level ip) option recvopts Added support for ip level socket option RECVOPTS. OTP-14831 --- lib/kernel/test/socket_server.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 971ceb2093..aa577b6289 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -612,6 +612,8 @@ handler_init(Manager, ID, Peek, Sock) -> MLoop = GIP(multicast_loop), MTTL = GIP(multicast_ttl), NF = GIP(nodefrag), % raw only + RecvIF = GIP(recvif), % Only dgram and raw (and FreeBSD) + RecvOPTS = GIP(recvopts), % Not stream RecvTOS = GIP(recvtos), RecvTTL = GIP(recvttl), % not stream i("got continue when: " @@ -638,6 +640,8 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Multicast Loop: ~s" "~n (ip) Multicast TTL: ~s" "~n (ip) Node Frag: ~s" + "~n (ip) Recv IF: ~s" + "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s", [Domain, Type, Proto, @@ -645,8 +649,8 @@ handler_init(Manager, ID, Peek, Sock) -> RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - NF, RecvTOS, RecvTTL]), - + NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL]), + handler_loop(#handler{peek = Peek, manager = Manager, type = Type, -- cgit v1.2.3 From 2f99a47953404a18965fe6fe434593ee851e8677 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 23 Jul 2018 14:26:25 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option multicast_hops Added support for the IPv6 socket option MULTICAST_HOPS. OTP-14831. --- lib/kernel/test/socket_server.erl | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index aa577b6289..28e21c3b8b 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -587,8 +587,9 @@ handler_init(Manager, ID, Peek, Sock) -> f("error: ~p", [R]) end end, - GIP = fun(O) -> G(ip, O) end, - GSO = fun(O) -> G(socket, O) end, + GSO = fun(O) -> G(socket, O) end, + GIP4 = fun(O) -> G(ip, O) end, + GIP6 = fun(O) -> G(ipv6, O) end, {ok, Domain} = socket:getopt(Sock, socket, domain), {ok, Type} = socket:getopt(Sock, socket, type), {ok, Proto} = socket:getopt(Sock, socket, protocol), @@ -604,18 +605,19 @@ handler_init(Manager, ID, Peek, Sock) -> SndTO = GSO(sndtimeo), Linger = GSO(linger), Timestamp = GSO(timestamp), - FreeBind = GIP(freebind), - MTU = GIP(mtu), - MTUDisc = GIP(mtu_discover), - MALL = GIP(multicast_all), - MIF = GIP(multicast_if), - MLoop = GIP(multicast_loop), - MTTL = GIP(multicast_ttl), - NF = GIP(nodefrag), % raw only - RecvIF = GIP(recvif), % Only dgram and raw (and FreeBSD) - RecvOPTS = GIP(recvopts), % Not stream - RecvTOS = GIP(recvtos), - RecvTTL = GIP(recvttl), % not stream + FreeBind = GIP4(freebind), + MTU = GIP4(mtu), + MTUDisc = GIP4(mtu_discover), + MALL = GIP4(multicast_all), + MIF = GIP4(multicast_if), + MLoop = GIP4(multicast_loop), + MTTL = GIP4(multicast_ttl), + NF = GIP4(nodefrag), % raw only + RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) + RecvOPTS = GIP4(recvopts), % Not stream + RecvTOS = GIP4(recvtos), + RecvTTL = GIP4(recvttl), % not stream + MHops = GIP6(multicast_hops), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -643,13 +645,15 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv IF: ~s" "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" - "~n (ip) Recv TTL: ~s", + "~n (ip) Recv TTL: ~s" + "~n (ipv6) Multicast Hops: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL]), + NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, + MHops]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From c077834b1465a8285f0c18e1d164c812aaadac9c Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 23 Jul 2018 15:02:39 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option multicast_if Added support for the IPv6 socket option MULTICAST_IF. OTP-14831. --- lib/kernel/test/socket_server.erl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 28e21c3b8b..cf13620997 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -609,7 +609,7 @@ handler_init(Manager, ID, Peek, Sock) -> MTU = GIP4(mtu), MTUDisc = GIP4(mtu_discover), MALL = GIP4(multicast_all), - MIF = GIP4(multicast_if), + MIF4 = GIP4(multicast_if), MLoop = GIP4(multicast_loop), MTTL = GIP4(multicast_ttl), NF = GIP4(nodefrag), % raw only @@ -618,6 +618,7 @@ handler_init(Manager, ID, Peek, Sock) -> RecvTOS = GIP4(recvtos), RecvTTL = GIP4(recvttl), % not stream MHops = GIP6(multicast_hops), + MIF6 = GIP6(multicast_if), % Only dgram and raw i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -646,14 +647,15 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s" - "~n (ipv6) Multicast Hops: ~s", + "~n (ipv6) Multicast Hops: ~s" + "~n (ipv6) Multicast IF: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, - FreeBind, MTU, MTUDisc, MALL, MIF, MLoop, MTTL, + FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop, MTTL, NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, - MHops]), + MHops, MIF6]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 4d14b84183c3c17f0ec03bf3631f1fd8575f07b9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 23 Jul 2018 17:36:16 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option multicast_loop Added support for the IPv6 socket option MULTICAST_LOOP. OTP-14831. --- lib/kernel/test/socket_server.erl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index cf13620997..f3f397aa20 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -154,7 +154,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> addr => Addr}, i("try bind to: " "~n ~p", [Addr]), - case socket:bind(Sock, SA) of + case socket:bind(Sock, any) of {ok, _P} -> ok; {error, BReason} -> @@ -610,7 +610,7 @@ handler_init(Manager, ID, Peek, Sock) -> MTUDisc = GIP4(mtu_discover), MALL = GIP4(multicast_all), MIF4 = GIP4(multicast_if), - MLoop = GIP4(multicast_loop), + MLoop4 = GIP4(multicast_loop), MTTL = GIP4(multicast_ttl), NF = GIP4(nodefrag), % raw only RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) @@ -619,6 +619,7 @@ handler_init(Manager, ID, Peek, Sock) -> RecvTTL = GIP4(recvttl), % not stream MHops = GIP6(multicast_hops), MIF6 = GIP6(multicast_if), % Only dgram and raw + MLoop6 = GIP6(multicast_loop), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -648,14 +649,15 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s" "~n (ipv6) Multicast Hops: ~s" - "~n (ipv6) Multicast IF: ~s", + "~n (ipv6) Multicast IF: ~s" + "~n (ipv6) Multicast Loop: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, - FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop, MTTL, + FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, - MHops, MIF6]), + MHops, MIF6, MLoop6]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From de82310c32063b8556add3fe7cf62b26eef27841 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 23 Jul 2018 18:26:42 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option recvpktinfo Added support for the IPv6 socket option RECVPKTINFO. This option is called PKTINFO on FreeBSD, so that value will also be accepted. OTP-14831. --- lib/kernel/test/socket_server.erl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index f3f397aa20..ba74964ed1 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -154,7 +154,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> addr => Addr}, i("try bind to: " "~n ~p", [Addr]), - case socket:bind(Sock, any) of + case socket:bind(Sock, SA) of {ok, _P} -> ok; {error, BReason} -> @@ -620,6 +620,7 @@ handler_init(Manager, ID, Peek, Sock) -> MHops = GIP6(multicast_hops), MIF6 = GIP6(multicast_if), % Only dgram and raw MLoop6 = GIP6(multicast_loop), + RecvPktInfo = GIP6(recvpktinfo), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -650,14 +651,16 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv TTL: ~s" "~n (ipv6) Multicast Hops: ~s" "~n (ipv6) Multicast IF: ~s" - "~n (ipv6) Multicast Loop: ~s", + "~n (ipv6) Multicast Loop: ~s" + "~n (ipv6) Recv Pkt Info: ~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]), + MHops, MIF6, MLoop6, + RecvPktInfo]), handler_loop(#handler{peek = Peek, manager = Manager, @@ -665,6 +668,7 @@ handler_init(Manager, ID, Peek, Sock) -> socket = Sock}) end. + handler_loop(H) -> i("try read message"), case recv(H) of -- cgit v1.2.3 From d7ca5ba9d8a7f094037878acfecb52b0bfbacc2e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 10:25:25 +0200 Subject: [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. --- lib/kernel/test/socket_server.erl | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'lib/kernel/test') 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, -- cgit v1.2.3 From 8b61022bdca354e541380391e3b0b2606f7af3f8 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 11:08:20 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option authhdr & hopopts Added support for the IPv6 socket option(s) AUTHHDR and HOPOPTS. Its possible that the option is AUTHHDR is obsolete. It says so in the include files and when trying to get it (getsockopt) it returns with enoprotoopt. The option HOPOPTS returns with einval when calling setsockopt, so either you need to be a privileged user to update, or its not actually possible to update this option (even though it says nothing about that in the man page. It only talks about set). This is the same behaviour as with RTHDR and HOPLIMIT. On FreeBSD, it says that HOPOPTS requires superuser privileges. Needs furher checking. OTP-14831. --- lib/kernel/test/socket_server.erl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 75cede75e5..1cd0ec1202 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -634,6 +634,8 @@ handler_init(Manager, ID, Peek, Sock) -> MLoop6 = GIP6(multicast_loop), RecvPktInfo = GIP6(recvpktinfo), RtHdr = GIP6(rthdr), + AuthHdr = GIP6(authhdr), + HopOpts = GIP6(hopopts), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -666,14 +668,17 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ipv6) Multicast IF: ~s" "~n (ipv6) Multicast Loop: ~s" "~n (ipv6) Recv Pkt Info: ~s" - "~n (ipv6) RT Hdr: ~s", + "~n (ipv6) RT Hdr: ~s" + "~n (ipv6) Auth Hdr: ~s" + "~n (ipv6) Hop Opts: ~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, RtHdr]), + MHops, MIF6, MLoop6, RecvPktInfo, + RtHdr, AuthHdr, HopOpts]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 9ca6de6efbe844bcf7dc996cfcf51bcd50325007 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 11:49:12 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option dstopts Added support for the IPv6 socket option(s) DSTOPTS. The option returns with einval when calling setsockopt, so either you need to be a privileged user to update, or its not actually possible to update this option (even though it says nothing about that in the man page. It only talks about set). This is the same behaviour as with RTHDR and HOPLIMIT. On FreeBSD, it says that HOPOPTS requires superuser privileges. Needs furher checking. OTP-14831. --- lib/kernel/test/socket_server.erl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 1cd0ec1202..8436b39372 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -635,7 +635,9 @@ handler_init(Manager, ID, Peek, Sock) -> RecvPktInfo = GIP6(recvpktinfo), RtHdr = GIP6(rthdr), AuthHdr = GIP6(authhdr), + HopLimit = GIP6(hoplimit), HopOpts = GIP6(hopopts), + DstOpts = GIP6(dstopts), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -670,7 +672,9 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ipv6) Recv Pkt Info: ~s" "~n (ipv6) RT Hdr: ~s" "~n (ipv6) Auth Hdr: ~s" - "~n (ipv6) Hop Opts: ~s", + "~n (ipv6) Hop Limit: ~s" + "~n (ipv6) Hop Opts: ~s" + "~n (ipv6) Dst Opts: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, @@ -678,7 +682,7 @@ handler_init(Manager, ID, Peek, Sock) -> FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, MHops, MIF6, MLoop6, RecvPktInfo, - RtHdr, AuthHdr, HopOpts]), + RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From e54642b537177941ff361b1eebdec10e02cfc22d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 12:05:00 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option flowinfo Added support for the IPv6 socket option(s) FLOWINFO. The option returns with einval when calling setsockopt, so either you need to be a privileged user to update, or its not actually possible to update this option (even though it says nothing about that in the man page. It only talks about set). This is the same behaviour as with DSTOPTS. Needs furher checking. OTP-14831. --- lib/kernel/test/socket_server.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 8436b39372..a1be73593b 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -166,7 +166,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> addr => Addr}, i("try bind to: " "~n ~p", [Addr]), - case socket:bind(Sock, SA) of + case socket:bind(Sock, any) of {ok, _P} -> ok; {error, BReason} -> @@ -638,6 +638,7 @@ handler_init(Manager, ID, Peek, Sock) -> HopLimit = GIP6(hoplimit), HopOpts = GIP6(hopopts), DstOpts = GIP6(dstopts), + FlowInfo = GIP6(flowinfo), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -674,7 +675,8 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ipv6) Auth Hdr: ~s" "~n (ipv6) Hop Limit: ~s" "~n (ipv6) Hop Opts: ~s" - "~n (ipv6) Dst Opts: ~s", + "~n (ipv6) Dst Opts: ~s" + "~n (ipv6) Flow Info: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, @@ -682,7 +684,7 @@ handler_init(Manager, ID, Peek, Sock) -> FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, MHops, MIF6, MLoop6, RecvPktInfo, - RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts]), + RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From b598160c2f1162658ea948284aee5b53951a3b9e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 12:29:22 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option unicast_hops Added support for the IPv6 socket option UNICAST_HOPS. OTP-14831. --- lib/kernel/test/socket_server.erl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index a1be73593b..2cb505cabc 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -166,7 +166,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> addr => Addr}, i("try bind to: " "~n ~p", [Addr]), - case socket:bind(Sock, any) of + case socket:bind(Sock, SA) of {ok, _P} -> ok; {error, BReason} -> @@ -639,6 +639,7 @@ handler_init(Manager, ID, Peek, Sock) -> HopOpts = GIP6(hopopts), DstOpts = GIP6(dstopts), FlowInfo = GIP6(flowinfo), + UHops = GIP6(unicast_hops), i("got continue when: " "~n (socket) Domain: ~p" "~n (socket) Type: ~p" @@ -676,7 +677,8 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ipv6) Hop Limit: ~s" "~n (ipv6) Hop Opts: ~s" "~n (ipv6) Dst Opts: ~s" - "~n (ipv6) Flow Info: ~s", + "~n (ipv6) Flow Info: ~s" + "~n (ipv6) Unicast Hops: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, @@ -684,7 +686,8 @@ handler_init(Manager, ID, Peek, Sock) -> FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, MHops, MIF6, MLoop6, RecvPktInfo, - RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo]), + RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, + UHops]), handler_loop(#handler{peek = Peek, manager = Manager, -- cgit v1.2.3 From 7d5b6e7bf640eb5d64679e3bf7b440b8e21e3a4d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 15:03:36 +0200 Subject: [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. --- lib/kernel/test/socket_server.erl | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib/kernel/test') 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. -- cgit v1.2.3 From 00a2425bde77ddb9ae4c03b8c4e5470064773981 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 16:40:55 +0200 Subject: [socket-nif] Add support for socket (level ip) option recverr Added support for the IP socket option RECVERR. To actually make use of this option, we need the recvmsg function, which we don't have yet. Baby steps. OTP-14831. --- lib/kernel/test/socket_server.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 54e9244d19..43f6f5ac75 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -636,6 +636,7 @@ handler_init(Manager, ID, Peek, Sock) -> MLoop4 = GIP4(multicast_loop), MTTL = GIP4(multicast_ttl), NF = GIP4(nodefrag), % raw only + RecvErr4 = GIP4(recverr), RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) RecvOPTS = GIP4(recvopts), % Not stream RecvTOS = GIP4(recvtos), @@ -675,6 +676,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Multicast Loop: ~s" "~n (ip) Multicast TTL: ~s" "~n (ip) Node Frag: ~s" + "~n (ip) Recv Err: ~s" "~n (ip) Recv IF: ~s" "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" @@ -695,7 +697,7 @@ handler_init(Manager, ID, Peek, Sock) -> RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, RecvIF, RecvOPTS, RecvTOS, RecvTTL, + NF, RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, MHops, MIF6, MLoop6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), -- cgit v1.2.3 From 4e24993aff4c5a0cb2bec96e5499131a660a79f9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 24 Jul 2018 17:01:46 +0200 Subject: [socket-nif] Add support for socket (level ipv6) option recverr Added support for the IPv6 socket option RECVERR. To actually make use of this option, we need the recvmsg function, which we don't have yet. Baby steps. OTP-14831. --- lib/kernel/test/socket_server.erl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 43f6f5ac75..4b032c586c 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -644,6 +644,7 @@ handler_init(Manager, ID, Peek, Sock) -> MHops = GIP6(multicast_hops), MIF6 = GIP6(multicast_if), % Only dgram and raw MLoop6 = GIP6(multicast_loop), + RecvErr6 = GIP6(recverr), RecvPktInfo = GIP6(recvpktinfo), RtHdr = GIP6(rthdr), AuthHdr = GIP6(authhdr), @@ -684,6 +685,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ipv6) Multicast Hops: ~s" "~n (ipv6) Multicast IF: ~s" "~n (ipv6) Multicast Loop: ~s" + "~n (ipv6) Recv Err: ~s" "~n (ipv6) Recv Pkt Info: ~s" "~n (ipv6) RT Hdr: ~s" "~n (ipv6) Auth Hdr: ~s" @@ -698,7 +700,7 @@ handler_init(Manager, ID, Peek, Sock) -> Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, - MHops, MIF6, MLoop6, RecvPktInfo, + MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), -- cgit v1.2.3 From 70a5b8d6a01b91a6044c6a5a0f8ed8919afd509b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 25 Jul 2018 12:29:41 +0200 Subject: [socket-nif] Add support for socket (level ip) option pktinfo Added support for ip level socket option PKTINFO. This option requires sendmsg and/or recvmsg to actually use, so we cannot test this fully at the moment (although both set and get works). OTP-14831 --- lib/kernel/test/socket_server.erl | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 4b032c586c..0ae6bb2dd0 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -636,6 +636,7 @@ handler_init(Manager, ID, Peek, Sock) -> MLoop4 = GIP4(multicast_loop), MTTL = GIP4(multicast_ttl), NF = GIP4(nodefrag), % raw only + PktInfo = GIP4(pktinfo), % dgram only RecvErr4 = GIP4(recverr), RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) RecvOPTS = GIP4(recvopts), % Not stream @@ -677,6 +678,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Multicast Loop: ~s" "~n (ip) Multicast TTL: ~s" "~n (ip) Node Frag: ~s" + "~n (ip) Pkt Info: ~s" "~n (ip) Recv Err: ~s" "~n (ip) Recv IF: ~s" "~n (ip) Recv OPTS: ~s" @@ -699,17 +701,28 @@ handler_init(Manager, ID, Peek, Sock) -> RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, + NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), - + handler_loop(#handler{peek = Peek, manager = Manager, type = Type, socket = Sock}) end. +%% so(Sock, Lvl, Opt, Val) -> +%% ok = socket:setopt(Sock, Lvl, Opt, Val). + +%% soso(Sock, Opt, Val) -> +%% so(Sock, socket, Opt, Val). + +%% soip(Sock, Opt, Val) -> +%% so(Sock, ip, Opt, Val). + +%% soipv6(Sock, Opt, Val) -> +%% so(Sock, ipv6, Opt, Val). handler_loop(H) -> i("try read message"), -- cgit v1.2.3 From 673367a0c17349a8b57dfad5dbc349c68417c6a5 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 25 Jul 2018 13:07:34 +0200 Subject: [socket-nif] Add support for socket (level ip) option transparent Added support for ip level socket option TRANSPARENT. OTP-14831 --- lib/kernel/test/socket_server.erl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 0ae6bb2dd0..447e742895 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -642,6 +642,9 @@ handler_init(Manager, ID, Peek, Sock) -> RecvOPTS = GIP4(recvopts), % Not stream RecvTOS = GIP4(recvtos), RecvTTL = GIP4(recvttl), % not stream + TOS = GIP4(tos), + Transparent = GIP4(transparent), + TTL = GIP4(ttl), MHops = GIP6(multicast_hops), MIF6 = GIP6(multicast_if), % Only dgram and raw MLoop6 = GIP6(multicast_loop), @@ -684,6 +687,9 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s" + "~n (ip) TOS: ~s" + "~n (ip) Transparent: ~s" + "~n (ip) TTL: ~s" "~n (ipv6) Multicast Hops: ~s" "~n (ipv6) Multicast IF: ~s" "~n (ipv6) Multicast Loop: ~s" @@ -702,6 +708,7 @@ handler_init(Manager, ID, Peek, Sock) -> Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, + TOS, Transparent, TTL, MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), -- cgit v1.2.3 From cb8877a5561ac64704337441936b62c8c87f8d13 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 25 Jul 2018 14:09:24 +0200 Subject: [socket-nif] Add support for socket (level ip) option retopts Added support for ip level socket option RETOPTS. OTP-14831 --- lib/kernel/test/socket_client.erl | 10 ++++++++-- lib/kernel/test/socket_server.erl | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 0d332e8439..094b7eebc5 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -22,8 +22,8 @@ -export([ start/1, start/5, - start_tcp/1, start_tcp/2, start_tcp6/1, - start_udp/1, start_udp/2, start_udp6/1 + start_tcp/1, start_tcp/2, start_tcp4/1, start_tcp6/1, + start_udp/1, start_udp/2, start_udp4/1, start_udp6/1 ]). -define(LIB, socket_lib). @@ -34,6 +34,9 @@ start(Port) -> start_tcp(Port). start_tcp(Port) -> + start_tcp4(Port). + +start_tcp4(Port) -> start(inet, stream, tcp, Port). start_tcp6(Port) -> @@ -46,6 +49,9 @@ start_tcp(Addr, Port) when (size(Addr) =:= 8) -> start_udp(Port) -> + start_udp4(Port). + +start_udp4(Port) -> start(inet, dgram, udp, Port). start_udp6(Port) -> diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 447e742895..8087a0ddda 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -642,6 +642,7 @@ handler_init(Manager, ID, Peek, Sock) -> RecvOPTS = GIP4(recvopts), % Not stream RecvTOS = GIP4(recvtos), RecvTTL = GIP4(recvttl), % not stream + RetOpts = GIP4(retopts), % not stream TOS = GIP4(tos), Transparent = GIP4(transparent), TTL = GIP4(ttl), @@ -687,6 +688,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv OPTS: ~s" "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s" + "~n (ip) Ret Opts: ~s" "~n (ip) TOS: ~s" "~n (ip) Transparent: ~s" "~n (ip) TTL: ~s" @@ -707,12 +709,12 @@ handler_init(Manager, ID, Peek, Sock) -> RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, + NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, RetOpts, TOS, Transparent, TTL, MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), - + handler_loop(#handler{peek = Peek, manager = Manager, type = Type, -- cgit v1.2.3 From 8ed757c8df2df54e19e67ca0a0734cd5a0f9ab23 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 26 Jul 2018 10:10:16 +0200 Subject: [socket-nif] Add support for socket (level ip) option recvorigdstaddr Added support for ip level socket option RECVORIGDSTADDR. This option requires recvmsg to actually use, so we cannot test this fully at the moment (although both set and get works). OTP-14831 --- lib/kernel/test/socket_server.erl | 103 ++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 50 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 8087a0ddda..3dad94b751 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -640,6 +640,7 @@ handler_init(Manager, ID, Peek, Sock) -> RecvErr4 = GIP4(recverr), RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) RecvOPTS = GIP4(recvopts), % Not stream + RecvOrigDstAddr = GIP4(recvorigdstaddr), RecvTOS = GIP4(recvtos), RecvTTL = GIP4(recvttl), % not stream RetOpts = GIP4(retopts), % not stream @@ -659,57 +660,59 @@ handler_init(Manager, ID, Peek, Sock) -> FlowInfo = GIP6(flowinfo), UHops = GIP6(unicast_hops), i("got continue when: " - "~n (socket) Domain: ~p" - "~n (socket) Type: ~p" - "~n (socket) Protocol: ~p" - "~n (socket) Reuse Address: ~s" - "~n (socket) Reuse Port: ~s" - "~n (socket) Bind To Device: ~s" - "~n (socket) OOBInline: ~s" - "~n (socket) RcvBuf: ~s" - "~n (socket) RcvLW: ~s" - "~n (socket) RcvTO: ~s" - "~n (socket) SndBuf: ~s" - "~n (socket) SndLW: ~s" - "~n (socket) SndTO: ~s" - "~n (socket) Linger: ~s" - "~n (socket) Timestamp: ~s" - "~n (ip) FreeBind: ~s" - "~n (ip) MTU: ~s" - "~n (ip) MTU Discovery: ~s" - "~n (ip) Multicast ALL: ~s" - "~n (ip) Multicast IF: ~s" - "~n (ip) Multicast Loop: ~s" - "~n (ip) Multicast TTL: ~s" - "~n (ip) Node Frag: ~s" - "~n (ip) Pkt Info: ~s" - "~n (ip) Recv Err: ~s" - "~n (ip) Recv IF: ~s" - "~n (ip) Recv OPTS: ~s" - "~n (ip) Recv TOS: ~s" - "~n (ip) Recv TTL: ~s" - "~n (ip) Ret Opts: ~s" - "~n (ip) TOS: ~s" - "~n (ip) Transparent: ~s" - "~n (ip) TTL: ~s" - "~n (ipv6) Multicast Hops: ~s" - "~n (ipv6) Multicast IF: ~s" - "~n (ipv6) Multicast Loop: ~s" - "~n (ipv6) Recv Err: ~s" - "~n (ipv6) Recv Pkt Info: ~s" - "~n (ipv6) RT Hdr: ~s" - "~n (ipv6) Auth Hdr: ~s" - "~n (ipv6) Hop Limit: ~s" - "~n (ipv6) Hop Opts: ~s" - "~n (ipv6) Dst Opts: ~s" - "~n (ipv6) Flow Info: ~s" - "~n (ipv6) Unicast Hops: ~s", + "~n (socket) Domain: ~p" + "~n (socket) Type: ~p" + "~n (socket) Protocol: ~p" + "~n (socket) Reuse Address: ~s" + "~n (socket) Reuse Port: ~s" + "~n (socket) Bind To Device: ~s" + "~n (socket) OOBInline: ~s" + "~n (socket) RcvBuf: ~s" + "~n (socket) RcvLW: ~s" + "~n (socket) RcvTO: ~s" + "~n (socket) SndBuf: ~s" + "~n (socket) SndLW: ~s" + "~n (socket) SndTO: ~s" + "~n (socket) Linger: ~s" + "~n (socket) Timestamp: ~s" + "~n (ip) FreeBind: ~s" + "~n (ip) MTU: ~s" + "~n (ip) MTU Discovery: ~s" + "~n (ip) Multicast ALL: ~s" + "~n (ip) Multicast IF: ~s" + "~n (ip) Multicast Loop: ~s" + "~n (ip) Multicast TTL: ~s" + "~n (ip) Node Frag: ~s" + "~n (ip) Pkt Info: ~s" + "~n (ip) Recv Err: ~s" + "~n (ip) Recv IF: ~s" + "~n (ip) Recv OPTS: ~s" + "~n (ip) Recv Orig Dst Addr: ~s" + "~n (ip) Recv TOS: ~s" + "~n (ip) Recv TTL: ~s" + "~n (ip) Ret Opts: ~s" + "~n (ip) TOS: ~s" + "~n (ip) Transparent: ~s" + "~n (ip) TTL: ~s" + "~n (ipv6) Multicast Hops: ~s" + "~n (ipv6) Multicast IF: ~s" + "~n (ipv6) Multicast Loop: ~s" + "~n (ipv6) Recv Err: ~s" + "~n (ipv6) Recv Pkt Info: ~s" + "~n (ipv6) RT Hdr: ~s" + "~n (ipv6) Auth Hdr: ~s" + "~n (ipv6) Hop Limit: ~s" + "~n (ipv6) Hop Opts: ~s" + "~n (ipv6) Dst Opts: ~s" + "~n (ipv6) Flow Info: ~s" + "~n (ipv6) Unicast Hops: ~s", [Domain, Type, Proto, RA, RP, B2D, OOBI, RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, Linger, Timestamp, FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvTOS, RecvTTL, RetOpts, + NF, PktInfo,RecvErr4, + RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts, TOS, Transparent, TTL, MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, @@ -721,14 +724,14 @@ handler_init(Manager, ID, Peek, Sock) -> socket = Sock}) end. -%% so(Sock, Lvl, Opt, Val) -> -%% ok = socket:setopt(Sock, Lvl, Opt, Val). +so(Sock, Lvl, Opt, Val) -> + ok = socket:setopt(Sock, Lvl, Opt, Val). %% soso(Sock, Opt, Val) -> %% so(Sock, socket, Opt, Val). -%% soip(Sock, Opt, Val) -> -%% so(Sock, ip, Opt, Val). +soip(Sock, Opt, Val) -> + so(Sock, ip, Opt, Val). %% soipv6(Sock, Opt, Val) -> %% so(Sock, ipv6, Opt, Val). -- cgit v1.2.3 From 6b01561dc13a0152f56da0a2c61ad88236f87de7 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 26 Jul 2018 11:07:05 +0200 Subject: [socket-nif] Add support for socket (level ip) option sendsrcaddr Added support for ip level socket option SENDSRCADDR. This option requires sendmsg to actually use, so we cannot test this fully at the moment. OTP-14831 --- lib/kernel/test/socket_server.erl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 3dad94b751..88b63ecf2d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -644,6 +644,7 @@ handler_init(Manager, ID, Peek, Sock) -> RecvTOS = GIP4(recvtos), RecvTTL = GIP4(recvttl), % not stream RetOpts = GIP4(retopts), % not stream + SendSrcAddr = GIP4(sendsrcaddr), TOS = GIP4(tos), Transparent = GIP4(transparent), TTL = GIP4(ttl), @@ -691,6 +692,7 @@ handler_init(Manager, ID, Peek, Sock) -> "~n (ip) Recv TOS: ~s" "~n (ip) Recv TTL: ~s" "~n (ip) Ret Opts: ~s" + "~n (ip) Send Src Addr: ~s" "~n (ip) TOS: ~s" "~n (ip) Transparent: ~s" "~n (ip) TTL: ~s" @@ -713,7 +715,7 @@ handler_init(Manager, ID, Peek, Sock) -> FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, NF, PktInfo,RecvErr4, RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts, - TOS, Transparent, TTL, + SendSrcAddr, TOS, Transparent, TTL, MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), @@ -724,14 +726,14 @@ handler_init(Manager, ID, Peek, Sock) -> socket = Sock}) end. -so(Sock, Lvl, Opt, Val) -> - ok = socket:setopt(Sock, Lvl, Opt, Val). +%% so(Sock, Lvl, Opt, Val) -> +%% ok = socket:setopt(Sock, Lvl, Opt, Val). %% soso(Sock, Opt, Val) -> %% so(Sock, socket, Opt, Val). -soip(Sock, Opt, Val) -> - so(Sock, ip, Opt, Val). +%% soip(Sock, Opt, Val) -> +%% so(Sock, ip, Opt, Val). %% soipv6(Sock, Opt, Val) -> %% so(Sock, ipv6, Opt, Val). -- cgit v1.2.3 From d4c6b555aea77198d662822c7f5a134a16cff8af Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 31 Jul 2018 12:53:52 +0200 Subject: [socket-nif] Debugged and stuff It seems to work, with atleast some of the cmsg options. More testing needed... OTP-14831 --- lib/kernel/test/socket_server.erl | 45 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 11 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 88b63ecf2d..5d00f78b2a 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -33,7 +33,7 @@ -record(manager, {socket, peek, acceptors, handler_id, handlers}). -record(acceptor, {id, socket, manager}). --record(handler, {socket, peek, type, manager}). +-record(handler, {socket, peek, msg, type, manager}). -define(NUM_ACCEPTORS, 5). @@ -179,7 +179,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> {ok, Name} -> f("~p", [Name]); {error, R} -> f("error: ~p", [R]) end]), - case handler_start(1, Sock, Peek) of + case handler_start(1, true, Sock, Peek) of {ok, {Pid, MRef}} -> i("handler (~p) started", [Pid]), handler_continue(Pid), @@ -405,7 +405,7 @@ manager_handle_request(#manager{peek = Peek, handlers = Handlers} = M, Pid, Ref, {start_handler, Sock}) -> i("try start handler (~w)", [HID]), - case handler_start(HID, Sock, Peek) of + case handler_start(HID, false, Sock, Peek) of {ok, {HPid, HMRef}} -> i("handler ~w started", [HID]), manager_reply(Pid, Ref, {ok, HPid}), @@ -564,10 +564,10 @@ acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> %% ========================================================================= -handler_start(ID, Sock, Peek) -> +handler_start(ID, Msg, Sock, Peek) -> Self = self(), H = {Pid, _} = spawn_monitor(fun() -> - handler_init(Self, ID, Peek, Sock) + handler_init(Self, ID, Msg, Peek, Sock) end), receive {handler, Pid, ok} -> @@ -591,7 +591,7 @@ handler_reply(Pid, Ref, Reply) -> ?LIB:reply(handler, Pid, Ref, Reply). -handler_init(Manager, ID, Peek, Sock) -> +handler_init(Manager, ID, Msg, Peek, Sock) -> put(sname, f("handler:~w", [ID])), i("starting"), Manager ! {handler, self(), ok}, @@ -720,20 +720,26 @@ handler_init(Manager, ID, Peek, Sock) -> RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), - handler_loop(#handler{peek = Peek, + ok = soip(Sock, pktinfo, true), + ok = soip(Sock, recvtos, true), + ok = soip(Sock, recvttl, true), + %% ok = soip(Sock, recvopts, true), + + handler_loop(#handler{msg = Msg, + peek = Peek, manager = Manager, type = Type, socket = Sock}) end. -%% so(Sock, Lvl, Opt, Val) -> -%% ok = socket:setopt(Sock, Lvl, Opt, Val). +so(Sock, Lvl, Opt, Val) -> + ok = socket:setopt(Sock, Lvl, Opt, Val). %% soso(Sock, Opt, Val) -> %% so(Sock, socket, Opt, Val). -%% soip(Sock, Opt, Val) -> -%% so(Sock, ip, Opt, Val). +soip(Sock, Opt, Val) -> + so(Sock, ip, Opt, Val). %% soipv6(Sock, Opt, Val) -> %% so(Sock, ipv6, Opt, Val). @@ -779,6 +785,23 @@ recv(#handler{peek = true, socket = Sock, type = stream}) -> peek_recv(Sock); recv(#handler{peek = false, socket = Sock, type = stream}) -> do_recv(Sock); +recv(#handler{socket = Sock, msg = true, type = dgram}) -> + ok = socket:setopt(Sock, otp, debug, true), + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + iov := [Data], + ctrl := CMsgHdrs, + flags := Flags}} -> + ok = socket:setopt(Sock, otp, debug, false), + i("received message: " + "~n CMsgHdrs: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]), + {ok, {Source, Data}}; + {ok, X} -> + {error, {unexpected, X}}; + {error, _} = ERROR -> + ERROR + end; recv(#handler{peek = Peek, socket = Sock, type = dgram}) when (Peek =:= true) -> %% ok = socket:setopt(Sock, otp, debug, true), -- cgit v1.2.3 From 25c38eff5c1e8d4dc6325afa62031874e23262dc Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 31 Jul 2018 18:01:55 +0200 Subject: [socket-nif] Add more control message decoding Added decoding of the "known" control message options: pktinfo, recvtos, recvttl and recvorigdstaddr). OTP-14831 --- lib/kernel/test/socket_server.erl | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 5d00f78b2a..a804078917 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -720,10 +720,18 @@ handler_init(Manager, ID, Msg, Peek, Sock) -> RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), - ok = soip(Sock, pktinfo, true), + SIP = + fun(O, V) -> + if + (Type =:= dgram) -> + ok = soip(Sock, O, V); + true -> + ok + end + end, ok = soip(Sock, recvtos, true), - ok = soip(Sock, recvttl, true), - %% ok = soip(Sock, recvopts, true), + SIP(recvttl, true), + ok = soip(Sock, recvorigdstaddr, true), handler_loop(#handler{msg = Msg, peek = Peek, @@ -786,13 +794,13 @@ recv(#handler{peek = true, socket = Sock, type = stream}) -> recv(#handler{peek = false, socket = Sock, type = stream}) -> do_recv(Sock); recv(#handler{socket = Sock, msg = true, type = dgram}) -> - ok = socket:setopt(Sock, otp, debug, true), + %% ok = socket:setopt(Sock, otp, debug, true), case socket:recvmsg(Sock) of {ok, #{addr := Source, iov := [Data], ctrl := CMsgHdrs, flags := Flags}} -> - ok = socket:setopt(Sock, otp, debug, false), + %% ok = socket:setopt(Sock, otp, debug, false), i("received message: " "~n CMsgHdrs: ~p" "~n Flags: ~p", [CMsgHdrs, Flags]), -- cgit v1.2.3 From 90a150771faa3cf01e82919b0c17854de9987783 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 1 Aug 2018 19:42:32 +0200 Subject: [socket-nif] Processing of more cmsg headers Added processing or more cmsg headers (for more options). Now (also) supports: socket:timestamp. Also various fixes and cleanups. For some reason calling getopt(Sock, 0, {13, int}) (or similar) fails with badarg even though the nif-function (nif_getopt) actually returns a valid value (for instance: {ok, 0}). OTP-14831 --- lib/kernel/test/socket_server.erl | 123 +++++++++++++++++++++++++------------- 1 file changed, 83 insertions(+), 40 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index a804078917..f252be1683 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -21,17 +21,19 @@ -module(socket_server). -export([ - start/0, start/4, - start_tcp/0, start_tcp/1, start_tcp/2, - start_tcp4/0, start_tcp4/1, start_tcp6/0, start_tcp6/1, - start_udp/0, start_udp/1, start_udp/2, - start_udp4/0, start_udp4/1, start_udp6/0, start_udp6/1, + start/0, start/5, + start_tcp/0, start_tcp/1, start_tcp/3, + start_tcp4/0, start_tcp4/1, start_tcp4/2, + start_tcp6/0, start_tcp6/1, start_tcp6/2, + start_udp/0, start_udp/1, start_udp/3, + start_udp4/0, start_udp4/1, start_udp4/2, + start_udp6/0, start_udp6/1, start_udp6/2, start_sctp/0, start_sctp/1 ]). -define(LIB, socket_lib). --record(manager, {socket, peek, acceptors, handler_id, handlers}). +-record(manager, {socket, msg, peek, acceptors, handler_id, handlers}). -record(acceptor, {id, socket, manager}). -record(handler, {socket, peek, msg, type, manager}). @@ -50,16 +52,22 @@ start_tcp4() -> start_tcp4(false). start_tcp4(Peek) -> - start_tcp(inet, Peek). + start_tcp4(false, Peek). + +start_tcp4(UseMsg, Peek) -> + start_tcp(inet, UseMsg, Peek). start_tcp6() -> start_tcp6(false). start_tcp6(Peek) -> - start_tcp(inet6, Peek). + start_tcp6(false, Peek). + +start_tcp6(UseMsg, Peek) -> + start_tcp(inet6, UseMsg, Peek). -start_tcp(Domain, Peek) when is_boolean(Peek) -> - start(Domain, stream, tcp, Peek). +start_tcp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> + start(Domain, stream, tcp, UseMsg, Peek). start_udp() -> start_udp4(). @@ -71,28 +79,34 @@ start_udp4() -> start_udp4(false). start_udp4(Peek) -> - start_udp(inet, Peek). + start_udp4(false, Peek). + +start_udp4(UseMsg, Peek) -> + start_udp(inet, UseMsg, Peek). start_udp6() -> - start_udp6(false). + start_udp6(false, false). start_udp6(Peek) -> - start_udp(inet6, Peek). + start_udp6(false, Peek). + +start_udp6(UseMsg, Peek) -> + start_udp(inet6, UseMsg, Peek). -start_udp(Domain, Peek) when is_boolean(Peek) -> - start(Domain, dgram, udp, Peek). +start_udp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> + start(Domain, dgram, udp, UseMsg, Peek). start_sctp() -> start_sctp(inet). start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) -> - start(Domain, seqpacket, sctp, false). + start(Domain, seqpacket, sctp, true, false). -start(Domain, Type, Proto, Peek) -> +start(Domain, Type, Proto, UseMsg, Peek) -> put(sname, "starter"), i("try start manager"), - {Pid, MRef} = manager_start(Domain, Type, Proto, Peek), + {Pid, MRef} = manager_start(Domain, Type, Proto, UseMsg, Peek), i("manager (~p) started", [Pid]), loop(Pid, MRef). @@ -107,8 +121,8 @@ loop(Pid, MRef) -> %% ========================================================================= -manager_start(Domain, Type, Proto, Peek) -> - spawn_monitor(fun() -> manager_init(Domain, Type, Proto, Peek) end). +manager_start(Domain, Type, Proto, UseMsg, Peek) -> + spawn_monitor(fun() -> manager_init(Domain, Type, Proto, UseMsg, Peek) end). manager_start_handler(Pid, Sock) -> manager_request(Pid, {start_handler, Sock}). @@ -123,19 +137,20 @@ manager_reply(Pid, Ref, Reply) -> ?LIB:reply(manager, Pid, Ref, Reply). -manager_init(Domain, Type, Proto, Peek) -> +manager_init(Domain, Type, Proto, UseMsg, Peek) -> put(sname, "manager"), - do_manager_init(Domain, Type, Proto, Peek). + do_manager_init(Domain, Type, Proto, UseMsg, Peek). -do_manager_init(Domain, stream = Type, Proto, Peek) -> +do_manager_init(Domain, stream = Type, Proto, UseMsg, Peek) -> i("try start acceptor(s)"), {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto), manager_loop(#manager{socket = Sock, + msg = UseMsg, peek = Peek, acceptors = Acceptors, handler_id = 1, handlers = []}); -do_manager_init(Domain, dgram = Type, Proto, Peek) -> +do_manager_init(Domain, dgram = Type, Proto, UseMsg, Peek) -> i("try open socket"), case socket:open(Domain, Type, Proto) of {ok, Sock} -> @@ -179,11 +194,12 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> {ok, Name} -> f("~p", [Name]); {error, R} -> f("error: ~p", [R]) end]), - case handler_start(1, true, Sock, Peek) of + case handler_start(1, Sock, UseMsg, Peek) of {ok, {Pid, MRef}} -> i("handler (~p) started", [Pid]), handler_continue(Pid), manager_loop(#manager{peek = Peek, + msg = UseMsg, handler_id = 2, % Just in case handlers = [{1, Pid, MRef}]}); {error, SReason} -> @@ -196,7 +212,7 @@ do_manager_init(Domain, dgram = Type, Proto, Peek) -> "~n ~p", [OReason]), exit({failed_open_socket, OReason}) end; -do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> +do_manager_init(Domain, seqpacket = Type, sctp = Proto, _UseMsg, _Peek) -> %% This is as far as I have got with SCTP at the moment... case socket:open(Domain, Type, Proto) of {ok, Sock} -> @@ -248,9 +264,9 @@ do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) -> {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) -> +do_manager_init(Domain, raw = Type, Proto, UseMsg, Peek) when is_integer(Proto) -> + do_manager_init(Domain, Type, {raw, Proto}, UseMsg, Peek); +do_manager_init(Domain, raw = Type, Proto, _UseMsg, _Peek) -> case socket:open(Domain, Type, Proto) of {ok, Sock} -> i("(sctp) socket opened: " @@ -401,11 +417,12 @@ manager_handle_down(#manager{acceptors = Acceptors, manager_handle_request(#manager{peek = Peek, + msg = UseMsg, handler_id = HID, handlers = Handlers} = M, Pid, Ref, {start_handler, Sock}) -> i("try start handler (~w)", [HID]), - case handler_start(HID, false, Sock, Peek) of + case handler_start(HID, Sock, UseMsg, Peek) of {ok, {HPid, HMRef}} -> i("handler ~w started", [HID]), manager_reply(Pid, Ref, {ok, HPid}), @@ -564,10 +581,10 @@ acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> %% ========================================================================= -handler_start(ID, Msg, Sock, Peek) -> +handler_start(ID, Sock, UseMsg, Peek) -> Self = self(), H = {Pid, _} = spawn_monitor(fun() -> - handler_init(Self, ID, Msg, Peek, Sock) + handler_init(Self, ID, UseMsg, Peek, Sock) end), receive {handler, Pid, ok} -> @@ -720,7 +737,16 @@ handler_init(Manager, ID, Msg, Peek, Sock) -> RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, UHops]), - SIP = + %% ok = socket:setopt(Sock, otp, debug, true), + %% case socket:getopt(Sock, 0, {13, int}) of + %% {ok, Val} -> + %% i("PktOpts ok: ~p", [Val]); + %% {error, Reason} -> + %% e("PktOpts err: ~p", [Reason]) + %% end, + %% ok = socket:setopt(Sock, otp, debug, false), + SSO = fun(O, V) -> soso(Sock, O, V) end, + SIP4 = fun(O, V) -> if (Type =:= dgram) -> @@ -729,8 +755,10 @@ handler_init(Manager, ID, Msg, Peek, Sock) -> ok end end, + SSO(timestamp, true), + SIP4(pktinfo, true), ok = soip(Sock, recvtos, true), - SIP(recvttl, true), + SIP4(recvttl, true), ok = soip(Sock, recvorigdstaddr, true), handler_loop(#handler{msg = Msg, @@ -743,8 +771,8 @@ handler_init(Manager, ID, Msg, Peek, Sock) -> so(Sock, Lvl, Opt, Val) -> ok = socket:setopt(Sock, Lvl, Opt, Val). -%% soso(Sock, Opt, Val) -> -%% so(Sock, socket, Opt, Val). +soso(Sock, Opt, Val) -> + so(Sock, socket, Opt, Val). soip(Sock, Opt, Val) -> so(Sock, ip, Opt, Val). @@ -791,16 +819,29 @@ handler_loop(H) -> recv(#handler{peek = true, socket = Sock, type = stream}) -> peek_recv(Sock); -recv(#handler{peek = false, socket = Sock, type = stream}) -> - do_recv(Sock); +recv(#handler{socket = Sock, msg = true, type = stream}) -> + case socket:recvmsg(Sock) of + {ok, #{addr := undefined = Source, + iov := [Data], + ctrl := CMsgHdrs, + flags := Flags}} -> + i("received message: " + "~n CMsgHdrs: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]), + {ok, {Source, Data}}; + {ok, X} -> + e("received *unexpected* message: " + "~n ~p", [X]), + {error, {unexpected, X}}; + {error, _} = ERROR -> + ERROR + end; recv(#handler{socket = Sock, msg = true, type = dgram}) -> - %% ok = socket:setopt(Sock, otp, debug, true), case socket:recvmsg(Sock) of {ok, #{addr := Source, iov := [Data], ctrl := CMsgHdrs, flags := Flags}} -> - %% ok = socket:setopt(Sock, otp, debug, false), i("received message: " "~n CMsgHdrs: ~p" "~n Flags: ~p", [CMsgHdrs, Flags]), @@ -810,6 +851,8 @@ recv(#handler{socket = Sock, msg = true, type = dgram}) -> {error, _} = ERROR -> ERROR end; +recv(#handler{peek = false, socket = Sock, type = stream}) -> + do_recv(Sock); recv(#handler{peek = Peek, socket = Sock, type = dgram}) when (Peek =:= true) -> %% ok = socket:setopt(Sock, otp, debug, true), -- cgit v1.2.3 From d8b1eace1cfe3184497752f345e5f6bc5def9769 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 3 Aug 2018 12:33:22 +0200 Subject: [socket-nif] Add preliminary support for sendmsg Added function sendmsg/2,3,4. Actually worked on the first try. Something must be wrong... Still no supported cmsghdr's (only support headers where the data part is already a binary, which therefor does not require any processing). So if the cmsghdrs actually work is unclear. OTP-14831 --- lib/kernel/test/socket_client.erl | 15 ++++++++++++++- lib/kernel/test/socket_server.erl | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 094b7eebc5..56424457e0 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -71,6 +71,10 @@ start(Domain, Type, Proto, Addr, Port) -> SA = #{family => Domain, addr => Addr, port => Port}, + %% The way we use tos only works because we + %% send so few messages (a new value for every + %% message). + put(tos, 1), do_start(Domain, Type, Proto, SA). do_start(Domain, stream = Type, Proto, SA) -> @@ -186,6 +190,7 @@ do_init(Domain, stream = Type, Proto) -> i("try (socket) bind"), case socket:bind(Sock, any) of {ok, _P} -> + ok = socket:setopt(Sock, ip, tos, mincost), Sock; {error, BReason} -> throw({bind, BReason}) @@ -271,7 +276,15 @@ send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> %% i("try send to: " %% "~n ~p", [Dest]), %% ok = socket:setopt(Sock, otp, debug, true), - socket:sendto(Sock, Msg, Dest). + TOS = get(tos), + ok = socket:setopt(Sock, ip, tos, TOS), + case socket:sendto(Sock, Msg, Dest) of + ok = OK -> + put(tos, TOS+1), + OK; + {error, _} = ERROR -> + ERROR + end. recv(#client{socket = Sock, type = stream}) -> case socket:recv(Sock) of diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index f252be1683..34f354be32 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -900,8 +900,18 @@ peek_recvfrom(Sock, BufSz) -> end. +send(#handler{socket = Sock, msg = true, type = stream}, Msg, _) -> + MsgHdr = #{iov => [Msg]}, + socket:sendmsg(Sock, MsgHdr); send(#handler{socket = Sock, type = stream}, Msg, _) -> socket:send(Sock, Msg); +send(#handler{socket = Sock, msg = true, type = dgram}, Msg, Dest) -> + MsgHdr = #{addr => Dest, + iov => [Msg]}, + %% ok = socket:setopt(Sock, otp, debug, true), + Res = socket:sendmsg(Sock, MsgHdr), + %% ok = socket:setopt(Sock, otp, debug, false), + Res; send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> socket:sendto(Sock, Msg, Dest). -- cgit v1.2.3 From 01601a4db44b3adccfbcc07129a4584649252736 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 3 Aug 2018 15:08:30 +0200 Subject: [socket-nif] Add more data types (with doc) and (C) debug Add more debug printouts for the new sendmsg. Also added new (erlang) types with doc. OTP-14831 --- lib/kernel/test/socket_server.erl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 34f354be32..b43642131b 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -915,6 +915,9 @@ send(#handler{socket = Sock, msg = true, type = dgram}, Msg, Dest) -> send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> socket:sendto(Sock, Msg, Dest). +%% filler() -> +%% list_to_binary(lists:duplicate(2048, " FILLER ")). + %% ========================================================================= -- cgit v1.2.3 From c14eca1d556926677dc03357c248dc4cf3dc38ed Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 18 Sep 2018 12:43:02 +0200 Subject: [socket-nif] Added (more) tests for [recv|send]msg Added some more tests for sendmsg (with cmsghdr). OTP-14831 --- lib/kernel/test/socket_client.erl | 44 ++++++++++++++++++++++++++++++++++----- lib/kernel/test/socket_server.erl | 16 ++++++++++---- 2 files changed, 51 insertions(+), 9 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 56424457e0..58d70b6181 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -28,7 +28,7 @@ -define(LIB, socket_lib). --record(client, {socket, type, dest, msg_id = 1}). +-record(client, {socket, msg = true, type, dest, msg_id = 1}). start(Port) -> start_tcp(Port). @@ -190,7 +190,9 @@ do_init(Domain, stream = Type, Proto) -> i("try (socket) bind"), case socket:bind(Sock, any) of {ok, _P} -> - ok = socket:setopt(Sock, ip, tos, mincost), + ok = socket:setopt(Sock, socket, timestamp, true), + ok = socket:setopt(Sock, ip, tos, mincost), + ok = socket:setopt(Sock, ip, recvtos, true), Sock; {error, BReason} -> throw({bind, BReason}) @@ -205,6 +207,10 @@ do_init(Domain, dgram = Type, Proto) -> end, case socket:bind(Sock, any) of {ok, _} -> + ok = socket:setopt(Sock, socket, timestamp, true), + ok = socket:setopt(Sock, ip, tos, mincost), + ok = socket:setopt(Sock, ip, recvtos, true), + ok = socket:setopt(Sock, ip, recvttl, true), Sock; {error, BReason} -> throw({bind, BReason}) @@ -286,15 +292,43 @@ send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> ERROR end. -recv(#client{socket = Sock, type = stream}) -> +recv(#client{socket = Sock, type = stream, msg = false}) -> case socket:recv(Sock) of {ok, Msg} -> {ok, {undefined, Msg}}; {error, _} = ERROR -> ERROR end; -recv(#client{socket = Sock, type = dgram}) -> - socket:recvfrom(Sock). +recv(#client{socket = Sock, type = stream, msg = true}) -> + case socket:recvmsg(Sock) of + %% An iov of length 1 is an simplification... + {ok, #{addr := undefined = Source, + iov := [Msg], + ctrl := CMsgHdrs, + flags := Flags}} -> + i("received message: " + "~n CMsgHdr: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]), + {ok, {Source, Msg}}; + {error, _} = ERROR -> + ERROR + end; +recv(#client{socket = Sock, type = dgram, msg = false}) -> + socket:recvfrom(Sock); +recv(#client{socket = Sock, type = dgram, msg = true}) -> + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + iov := [Msg], + ctrl := CMsgHdrs, + flags := Flags}} -> + i("received message: " + "~n CMsgHdr: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]), + {ok, {Source, Msg}}; + {error, _} = ERROR -> + ERROR + end. + which_addr(_Domain, []) -> diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index b43642131b..ea2bdc8e0d 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -901,13 +901,21 @@ peek_recvfrom(Sock, BufSz) -> send(#handler{socket = Sock, msg = true, type = stream}, Msg, _) -> - MsgHdr = #{iov => [Msg]}, - socket:sendmsg(Sock, MsgHdr); + CMsgHdr = #{level => ip, type => tos, data => reliability}, + CMsgHdrs = [CMsgHdr], + MsgHdr = #{iov => [Msg], ctrl => CMsgHdrs}, + %% socket:setopt(Sock, otp, debug, true), + Res = socket:sendmsg(Sock, MsgHdr), + %% socket:setopt(Sock, otp, debug, false), + Res; send(#handler{socket = Sock, type = stream}, Msg, _) -> socket:send(Sock, Msg); send(#handler{socket = Sock, msg = true, type = dgram}, Msg, Dest) -> - MsgHdr = #{addr => Dest, - iov => [Msg]}, + CMsgHdr = #{level => ip, type => tos, data => reliability}, + CMsgHdrs = [CMsgHdr], + MsgHdr = #{addr => Dest, + iov => [Msg], + ctrl => CMsgHdrs}, %% ok = socket:setopt(Sock, otp, debug, true), Res = socket:sendmsg(Sock, MsgHdr), %% ok = socket:setopt(Sock, otp, debug, false), -- cgit v1.2.3 From e01a856c993b55c3fbc76fd429783d4aad5bfc80 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 19 Sep 2018 18:21:47 +0200 Subject: [socket-nif] Add proper connect and accept timeout handling Added proper connect and accept timeout handling. Made use of the enif_select(mode = cancel) feature. Each time a timeout expires, the previous operation (connect or accept) has to be cancelled (actually its the select operation that has to be cancelled). Only partial implementation of cancel for now (connect and accept). More to follow... OTP-14831 --- lib/kernel/test/socket_client.erl | 21 ++++++++++++++++++--- lib/kernel/test/socket_server.erl | 10 +++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 58d70b6181..6cd353fd07 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -74,7 +74,7 @@ start(Domain, Type, Proto, Addr, Port) -> %% The way we use tos only works because we %% send so few messages (a new value for every %% message). - put(tos, 1), + tos_init(), do_start(Domain, Type, Proto, SA). do_start(Domain, stream = Type, Proto, SA) -> @@ -282,11 +282,10 @@ send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> %% i("try send to: " %% "~n ~p", [Dest]), %% ok = socket:setopt(Sock, otp, debug, true), - TOS = get(tos), + TOS = tos_next(), ok = socket:setopt(Sock, ip, tos, TOS), case socket:sendto(Sock, Msg, Dest) of ok = OK -> - put(tos, TOS+1), OK; {error, _} = ERROR -> ERROR @@ -400,6 +399,22 @@ which_addr2(Domain, [_|IFO]) -> %% lists:flatten(FormatDate). +%% --- + +tos_init() -> + put(tos, 1). + +tos_next() -> + case get(tos) of + TOS when (TOS < 100) -> + put(tos, TOS + 1), + TOS; + _ -> + put(tos, 1), + 1 + end. + + %% --- e(F, A) -> diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index ea2bdc8e0d..3e5c4e5d95 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -34,7 +34,7 @@ -define(LIB, socket_lib). -record(manager, {socket, msg, peek, acceptors, handler_id, handlers}). --record(acceptor, {id, socket, manager}). +-record(acceptor, {id, socket, manager, atimeout = 5000}). -record(handler, {socket, peek, msg, type, manager}). -define(NUM_ACCEPTORS, 5). @@ -521,13 +521,14 @@ acceptor_stop(Pid, _Reason) -> acceptor_init(Manager, Sock, ID) -> put(sname, f("acceptor[~w]", [ID])), Manager ! {acceptor, self(), ok}, + %% ok = socket:setopt(Sock, otp, debug, true), acceptor_loop(#acceptor{id = ID, manager = Manager, socket = Sock}). -acceptor_loop(#acceptor{socket = LSock} = A) -> +acceptor_loop(#acceptor{socket = LSock, atimeout = Timeout} = A) -> i("try accept"), - case socket:accept(LSock, infinity) of + case socket:accept(LSock, Timeout) of {ok, Sock} -> i("accepted: " "~n ~p" @@ -542,6 +543,9 @@ acceptor_loop(#acceptor{socket = LSock} = A) -> socket:close(Sock), exit({failed_starting_handler, Reason}) end; + {error, timeout} -> + i("timeout"), + acceptor_loop(A); {error, Reason} -> e("accept failure: " "~n ~p", [Reason]), -- cgit v1.2.3 From 13d10bc60a41f98647d802524ea8ef8fa9af6b39 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 20 Sep 2018 15:37:37 +0200 Subject: [socket-nif] Add proper send timeout handling Added proper send timeout handling. Made use of the enif_select(mode = cancel) feature. Each time a timeout expires, the "active" send (the surrent write select) has to be cancelled. OTP-14831 --- lib/kernel/test/socket_client.erl | 344 +++++++++++++++++++++++++------------- lib/kernel/test/socket_server.erl | 24 +-- 2 files changed, 241 insertions(+), 127 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl index 6cd353fd07..1c07e799b8 100644 --- a/lib/kernel/test/socket_client.erl +++ b/lib/kernel/test/socket_client.erl @@ -21,53 +21,126 @@ -module(socket_client). -export([ - start/1, start/5, - start_tcp/1, start_tcp/2, start_tcp4/1, start_tcp6/1, - start_udp/1, start_udp/2, start_udp4/1, start_udp6/1 + start/1, start/2, start/5, start/6, + start_tcp/1, start_tcp/2, start_tcp/3, + start_tcp4/1, start_tcp4/2, start_tcp6/1, start_tcp6/2, + start_udp/1, start_udp/2, start_udp/3, + start_udp4/1, start_udp4/2, start_udp6/1, start_udp6/2 ]). -define(LIB, socket_lib). --record(client, {socket, msg = true, type, dest, msg_id = 1}). +-record(client, {socket, verbose = true, msg = true, type, dest, msg_id = 1}). start(Port) -> - start_tcp(Port). + start(Port, 1). + +start(Port, Num) -> + start_tcp(Port, Num). start_tcp(Port) -> - start_tcp4(Port). + start_tcp(Port, 1). + +start_tcp(Port, Num) -> + start_tcp4(Port, Num). start_tcp4(Port) -> - start(inet, stream, tcp, Port). + start_tcp4(Port, 1). + +start_tcp4(Port, Num) -> + start(inet, stream, tcp, Port, Num). start_tcp6(Port) -> - start(inet6, stream, tcp, Port). + start_tcp6(Port, 1). + +start_tcp6(Port, Num) -> + start(inet6, stream, tcp, Port, Num). -start_tcp(Addr, Port) when (size(Addr) =:= 4) -> - start(inet, stream, tcp, Addr, Port); -start_tcp(Addr, Port) when (size(Addr) =:= 8) -> - start(inet6, stream, tcp, Addr, Port). +start_tcp(Addr, Port, Num) when (size(Addr) =:= 4) andalso + is_integer(Num) andalso + (Num > 0) -> + start(inet, stream, tcp, Addr, Port, Num); +start_tcp(Addr, Port, Num) when (size(Addr) =:= 8) andalso + is_integer(Num) andalso + (Num > 0) -> + start(inet6, stream, tcp, Addr, Port, Num). start_udp(Port) -> - start_udp4(Port). + start_udp(Port, 1). + +start_udp(Port, Num) -> + start_udp4(Port, Num). start_udp4(Port) -> - start(inet, dgram, udp, Port). + start_udp4(Port, 1). + +start_udp4(Port, Num) -> + start(inet, dgram, udp, Port, Num). start_udp6(Port) -> - start(inet6, dgram, udp, Port). + start_udp6(Port, 1). -start_udp(Addr, Port) when (size(Addr) =:= 4) -> - start(inet, dgram, udp, Addr, Port); -start_udp(Addr, Port) when (size(Addr) =:= 8) -> - start(inet6, dgram, udp, Addr, Port). +start_udp6(Port, Num) -> + start(inet6, dgram, udp, Port, Num). +start_udp(Addr, Port, Num) when (size(Addr) =:= 4) -> + start(inet, dgram, udp, Addr, Port, Num); +start_udp(Addr, Port, Num) when (size(Addr) =:= 8) -> + start(inet6, dgram, udp, Addr, Port, Num). -start(Domain, Type, Proto, Port) -> - start(Domain, Type, Proto, which_addr(Domain), Port). + +start(Domain, Type, Proto, Port, Num) + when is_integer(Port) andalso is_integer(Num) -> + start(Domain, Type, Proto, which_addr(Domain), Port, Num); start(Domain, Type, Proto, Addr, Port) -> + start(Domain, Type, Proto, Addr, Port, 1). + +start(Domain, Type, Proto, Addr, Port, 1 = Num) -> + start(Domain, Type, Proto, Addr, Port, Num, true); +start(Domain, Type, Proto, Addr, Port, Num) + when is_integer(Num) andalso (Num > 1) -> + start(Domain, Type, Proto, Addr, Port, Num, false). + +start(Domain, Type, Proto, Addr, Port, Num, Verbose) -> put(sname, "starter"), + Clients = start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose), + await_clients(Clients). + +start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose) -> + start_clients(Num, 1, Domain, Type, Proto, Addr, Port, Verbose, []). + +start_clients(Num, ID, Domain, Type, Proto, Addr, Port, Verbose, Acc) + when (Num > 0) -> + StartClient = fun() -> + start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) + end, + {Pid, _} = spawn_monitor(StartClient), + ?LIB:sleep(500), + i("start client ~w", [ID]), + start_clients(Num-1, ID+1, Domain, Type, Proto, Addr, Port, Verbose, [Pid|Acc]); +start_clients(_, _, _, _, _, _, _, _, Acc) -> + i("all client(s) started"), + lists:reverse(Acc). + +await_clients([]) -> + i("all clients done"); +await_clients(Clients) -> + receive + {'DOWN', _MRef, process, Pid, _Reason} -> + case lists:delete(Pid, Clients) of + Clients2 when (Clients2 =/= Clients) -> + i("client ~p done", [Pid]), + await_clients(Clients2); + _ -> + await_clients(Clients) + end + end. + + +start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) -> + put(sname, ?LIB:f("client[~w]", [ID])), SA = #{family => Domain, addr => Addr, port => Port}, @@ -75,110 +148,119 @@ start(Domain, Type, Proto, Addr, Port) -> %% send so few messages (a new value for every %% message). tos_init(), - do_start(Domain, Type, Proto, SA). + do_start(Domain, Type, Proto, SA, Verbose). -do_start(Domain, stream = Type, Proto, SA) -> +do_start(Domain, stream = Type, Proto, SA, Verbose) -> 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, MTU} = socket:getopt(Sock, ip, mtu), - {ok, MTUDisc} = socket:getopt(Sock, ip, 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), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - i("connected: " - "~n From: ~p" - "~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) MTU: ~p" - "~n (ip) MTU Discovery: ~p" - "~n (ip) Multicast ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n => wait some", - [Name, Peer, - Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - RecvTOS]), + maybe_print_start_info(Verbose, Sock, Type), %% Give the server some time... ?LIB:sleep(5000), %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type}) + send_loop(#client{socket = Sock, + type = Type, + verbose = Verbose}) catch throw:E -> e("Failed initiate: " "~n Error: ~p", [E]) end; -do_start(Domain, dgram = Type, Proto, SA) -> +do_start(Domain, dgram = Type, Proto, SA, Verbose) -> try do_init(Domain, Type, Proto) of Sock -> + maybe_print_start_info(Verbose, Sock, Type), %% Give the server some time... - {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, 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), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl), - 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 ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n (ip) RecvTTL: ~p" - "~n => wait some", - [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MALL, MIF, MLoop, MTTL, - RecvTOS, RecvTTL]), ?LIB:sleep(5000), %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type, - dest = SA}) + send_loop(#client{socket = Sock, + type = Type, + dest = SA, + verbose = Verbose}) catch throw:E -> e("Failed initiate: " "~n Error: ~p", [E]) end. +maybe_print_start_info(true = _Verbose, Sock, stream = _Type) -> + {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, MTU} = socket:getopt(Sock, ip, mtu), + {ok, MTUDisc} = socket:getopt(Sock, ip, 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), + {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), + i("connected: " + "~n From: ~p" + "~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) MTU: ~p" + "~n (ip) MTU Discovery: ~p" + "~n (ip) Multicast ALL: ~p" + "~n (ip) Multicast IF: ~p" + "~n (ip) Multicast Loop: ~p" + "~n (ip) Multicast TTL: ~p" + "~n (ip) RecvTOS: ~p" + "~n => wait some", + [Name, Peer, + Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, + MTU, MTUDisc, MALL, MIF, MLoop, MTTL, + RecvTOS]); +maybe_print_start_info(true = _Verbose, Sock, dgram = _Type) -> + {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, 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), + {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), + {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl), + 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 ALL: ~p" + "~n (ip) Multicast IF: ~p" + "~n (ip) Multicast Loop: ~p" + "~n (ip) Multicast TTL: ~p" + "~n (ip) RecvTOS: ~p" + "~n (ip) RecvTTL: ~p" + "~n => wait some", + [Domain, Type, Proto, + OOBI, SndBuf, RcvBuf, Linger, + MALL, MIF, MLoop, MTTL, + RecvTOS, RecvTTL]); +maybe_print_start_info(_Verbose, _Sock, _Type) -> + ok. + do_init(Domain, stream = Type, Proto) -> i("try (socket) open"), Sock = case socket:open(Domain, Type, Proto) of @@ -248,14 +330,25 @@ send_loop(#client{msg_id = N} = C) when (N =< 10) -> i("request ~w sent - now try read answer", [N]), case recv(C) of {ok, {Source, Msg}} -> - i("received ~w bytes of data~s", - [size(Msg), case Source of - undefined -> ""; - _ -> ?LIB:f(" from:~n ~p", [Source]) - end]), + if + (C#client.verbose =:= true) -> + i("received ~w bytes of data~s", + [size(Msg), case Source of + undefined -> ""; + _ -> ?LIB:f(" from:~n ~p", [Source]) + end]); + true -> + i("received ~w bytes", [size(Msg)]) + end, case ?LIB:dec_msg(Msg) of {reply, N, Reply} -> - i("received reply ~w: ~p", [N, Reply]), + if + (C#client.verbose =:= true) -> + i("received reply ~w: ~p", [N, Reply]); + true -> + i("received reply ~w", [N]) + end, + ?LIB:sleep(500), % Just to spread it out a bit send_loop(C#client{msg_id = N+1}) end; {error, RReason} -> @@ -268,13 +361,20 @@ send_loop(#client{msg_id = N} = C) when (N =< 10) -> "~n ~p", [N, SReason]), exit({failed_send, SReason}) end; -send_loop(#client{socket = Sock}) -> +send_loop(Client) -> + sock_close(Client). + +sock_close(#client{socket = Sock, verbose = true}) -> i("we are done - close the socket when: " "~n ~p", [socket:info()]), ok = socket:close(Sock), i("we are done - socket closed when: " - "~n ~p", [socket:info()]). + "~n ~p", [socket:info()]); +sock_close(#client{socket = Sock}) -> + i("we are done"), + ok = socket:close(Sock). + send(#client{socket = Sock, type = stream}, Msg) -> socket:send(Sock, Msg); @@ -298,31 +398,41 @@ recv(#client{socket = Sock, type = stream, msg = false}) -> {error, _} = ERROR -> ERROR end; -recv(#client{socket = Sock, type = stream, msg = true}) -> +recv(#client{socket = Sock, verbose = Verbose, type = stream, msg = true}) -> case socket:recvmsg(Sock) of %% An iov of length 1 is an simplification... {ok, #{addr := undefined = Source, iov := [Msg], ctrl := CMsgHdrs, flags := Flags}} -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), + if + (Verbose =:= true) -> + i("received message: " + "~n CMsgHdr: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]); + true -> + ok + end, {ok, {Source, Msg}}; {error, _} = ERROR -> ERROR end; recv(#client{socket = Sock, type = dgram, msg = false}) -> socket:recvfrom(Sock); -recv(#client{socket = Sock, type = dgram, msg = true}) -> +recv(#client{socket = Sock, verbose = Verbose, type = dgram, msg = true}) -> case socket:recvmsg(Sock) of {ok, #{addr := Source, iov := [Msg], ctrl := CMsgHdrs, flags := Flags}} -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), + if + (Verbose =:= true) -> + i("received message: " + "~n CMsgHdr: ~p" + "~n Flags: ~p", [CMsgHdrs, Flags]); + true -> + ok + end, {ok, {Source, Msg}}; {error, _} = ERROR -> ERROR diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 3e5c4e5d95..9142942428 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -34,8 +34,10 @@ -define(LIB, socket_lib). -record(manager, {socket, msg, peek, acceptors, handler_id, handlers}). --record(acceptor, {id, socket, manager, atimeout = 5000}). --record(handler, {socket, peek, msg, type, manager}). +-record(acceptor, {id, socket, manager, + atimeout = 5000}). +-record(handler, {socket, peek, msg, type, manager, + stimeout = 5000, rtimeout = 5000}). -define(NUM_ACCEPTORS, 5). @@ -904,28 +906,30 @@ peek_recvfrom(Sock, BufSz) -> end. -send(#handler{socket = Sock, msg = true, type = stream}, Msg, _) -> +send(#handler{socket = Sock, msg = true, type = stream, stimeout = Timeout}, + Msg, _) -> CMsgHdr = #{level => ip, type => tos, data => reliability}, CMsgHdrs = [CMsgHdr], MsgHdr = #{iov => [Msg], ctrl => CMsgHdrs}, %% socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr), + Res = socket:sendmsg(Sock, MsgHdr, Timeout), %% socket:setopt(Sock, otp, debug, false), Res; -send(#handler{socket = Sock, type = stream}, Msg, _) -> - socket:send(Sock, Msg); -send(#handler{socket = Sock, msg = true, type = dgram}, Msg, Dest) -> +send(#handler{socket = Sock, type = stream, stimeout = Timeout}, Msg, _) -> + socket:send(Sock, Msg, Timeout); +send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout}, + Msg, Dest) -> CMsgHdr = #{level => ip, type => tos, data => reliability}, CMsgHdrs = [CMsgHdr], MsgHdr = #{addr => Dest, iov => [Msg], ctrl => CMsgHdrs}, %% ok = socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr), + Res = socket:sendmsg(Sock, MsgHdr, Timeout), %% ok = socket:setopt(Sock, otp, debug, false), Res; -send(#handler{socket = Sock, type = dgram}, Msg, Dest) -> - socket:sendto(Sock, Msg, Dest). +send(#handler{socket = Sock, type = dgram, stimeout = Timeout}, Msg, Dest) -> + socket:sendto(Sock, Msg, Dest, Timeout). %% filler() -> %% list_to_binary(lists:duplicate(2048, " FILLER ")). -- cgit v1.2.3 From 91ffcbf2bee63cd5314132edee56825973a62f72 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 25 Sep 2018 12:49:57 +0200 Subject: [socket-nif|test] Add first preliminary socket test suite Add a proper but very basic test suite. The only (6) test cases now are very basic (open-close and send-receive). OTP-14831 --- lib/kernel/test/Makefile | 4 + lib/kernel/test/socket_SUITE.erl | 426 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 lib/kernel/test/socket_SUITE.erl (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 051fac25af..28edf4889b 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -96,6 +96,7 @@ MODULES= \ standard_error_SUITE \ multi_load_SUITE \ zzz_SUITE \ + socket_SUITE \ $(SOCKET_MODULES) APP_FILES = \ @@ -134,6 +135,7 @@ ERL_COMPILE_FLAGS += EBIN = . SOCKET_TARGETS = $(SOCKET_MODULES:%=$(EBIN)/%.$(EMULATOR)) +TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) # ---------------------------------------------------- @@ -156,6 +158,8 @@ clean: docs: +targets: $(TARGETS) + socket: $(SOCKET_TARGETS) diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl new file mode 100644 index 0000000000..1bf12693fe --- /dev/null +++ b/lib/kernel/test/socket_SUITE.erl @@ -0,0 +1,426 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2018. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(socket_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +%% Suite exports +-export([suite/0, all/0, groups/0]). + +%% Test cases +-export([ + %% Basic + api_b_open_and_close_udp4/1, + api_b_open_and_close_tcp4/1, + api_b_sendto_and_recvfrom_udp4/1, + api_b_sendmsg_and_recvmsg_udp4/1, + api_b_send_and_recv_tcp4/1, + api_b_sendmsg_and_recvmsg_tcp4/1 + + %% Tickets + ]). + +%% Internal exports +%% -export([]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(BASIC_REQ, <<"hejsan">>). +-define(BASIC_REP, <<"hoppsan">>). + +-define(FAIL(R), exit(R)). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + +all() -> + [ + {group, api} + %% {group, tickets} + ]. + +groups() -> + [{api, [], api_cases()}, + {api_basic, [], api_basic_cases()} + %% {tickets, [], ticket_cases()} + ]. + +api_cases() -> + [ + {group, api_basic} + ]. + +api_basic_cases() -> + [api_b_open_and_close_udp4, + api_b_open_and_close_tcp4, + api_b_sendto_and_recvfrom_udp4, + api_b_sendmsg_and_recvmsg_udp4, + api_b_send_and_recv_tcp4, + api_b_sendmsg_and_recvmsg_tcp4 + ]. + +%% ticket_cases() -> +%% []. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and close an IPv4 UDP (dgram) socket. +%% With some extra checks... +api_b_open_and_close_udp4(suite) -> + []; +api_b_open_and_close_udp4(doc) -> + []; +api_b_open_and_close_udp4(_Config) when is_list(_Config) -> + tc_begin(api_b_open_and_close_udp4), + ok = api_b_open_and_close(inet, dgram, udp), + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically open (create) and close an IPv4 TCP (stream) socket. +%% With some extra checks... +api_b_open_and_close_tcp4(suite) -> + []; +api_b_open_and_close_tcp4(doc) -> + []; +api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_b_open_and_close_tcp4), + ok = api_b_open_and_close(inet, stream, tcp), + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_b_open_and_close(Domain, Type, Proto) -> + Socket = case socket:open(Domain, Type, Proto) of + {ok, S} -> + S; + {error, Reason} -> + ?FAIL({open, Reason}) + end, + {ok, Domain} = socket:getopt(Socket, socket, domain), + {ok, Type} = socket:getopt(Socket, socket, type), + {ok, Proto} = socket:getopt(Socket, socket, protocol), + Self = self(), + {ok, Self} = socket:getopt(Socket, otp, controlling_process), + ok = socket:close(Socket), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically send and receive on an IPv4 UDP (dgram) socket using +%% sendto and recvfrom.. +api_b_sendto_and_recvfrom_udp4(suite) -> + []; +api_b_sendto_and_recvfrom_udp4(doc) -> + []; +api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> + tc_begin(api_b_sendto_and_recvfrom_udp4), + Send = fun(Sock, Data, Dest) -> + socket:sendto(Sock, Data, Dest) + end, + Recv = fun(Sock) -> + socket:recvfrom(Sock) + end, + ok = api_b_send_and_recv_udp(inet, Send, Recv), + tc_end(). + + +%% Basically send and receive on an IPv4 UDP (dgram) socket +%% using sendmsg and recvmsg. +api_b_sendmsg_and_recvmsg_udp4(suite) -> + []; +api_b_sendmsg_and_recvmsg_udp4(doc) -> + []; +api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> + tc_begin(api_b_sendmsg_and_recvmsg_udp4), + Send = fun(Sock, Data, Dest) -> + %% CMsgHdr = #{level => ip, type => tos, data => reliability}, + %% CMsgHdrs = [CMsgHdr], + MsgHdr = #{addr => Dest, + %% ctrl => CMsgHdrs, + iov => [Data]}, + socket:sendmsg(Sock, MsgHdr) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + iov := [Data]}} -> + {ok, {Source, Data}}; + {error, _} = ERROR -> + ERROR + end + end, + ok = api_b_send_and_recv_udp(inet, Send, Recv), + tc_end(). + + +api_b_send_and_recv_udp(Domain, Send, Recv) -> + SockSrc = case socket:open(Domain, dgram, udp) of + {ok, S1} -> + S1; + {error, OR1} -> + ?FAIL({open, src, OR1}) + end, + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + case socket:bind(SockSrc, LSA) of + {ok, _} -> + ok; + {error, BR1} -> + ?FAIL({bind, src, BR1}) + end, + SockDst = case socket:open(Domain, dgram, udp) of + {ok, S2} -> + S2; + {error, OR2} -> + ?FAIL({open, dst, OR2}) + end, + case socket:bind(SockDst, LSA) of + {ok, _} -> + ok; + {error, BR2} -> + ?FAIL({bind, dst, BR2}) + end, + Dst = case socket:sockname(SockDst) of + {ok, SA} -> + SA; + {ok, SNR} -> + ?FAIL({sockname, dst, SNR}) + end, + ok = Send(SockSrc, ?BASIC_REQ, Dst), + {ok, {Src, ?BASIC_REQ}} = Recv(SockDst), + ok = Send(SockDst, ?BASIC_REP, Src), + {ok, {Dst, ?BASIC_REP}} = Recv(SockSrc), + socket:close(SockSrc), + socket:close(SockDst), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Basically send and receive using the "common" functions (send and recv) +%% on an IPv4 TCP (stream) socket. +api_b_send_and_recv_tcp4(suite) -> + []; +api_b_send_and_recv_tcp4(doc) -> + []; +api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_b_send_and_recv_tcp4), + Send = fun(Sock, Data) -> + socket:send(Sock, Data) + end, + Recv = fun(Sock) -> + socket:recv(Sock) + end, + ok = api_b_send_and_recv_tcp(inet, Send, Recv), + tc_end(). + + +%% Basically send and receive using the msg functions (sendmsg and recvmsg) +%% on an IPv4 TCP (stream) socket. +api_b_sendmsg_and_recvmsg_tcp4(suite) -> + []; +api_b_sendmsg_and_recvmsg_tcp4(doc) -> + []; +api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_b_sendmsg_and_recvmsg_tcp4), + Send = fun(Sock, Data) -> + MsgHdr = #{iov => [Data]}, + socket:sendmsg(Sock, MsgHdr) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := undefined, + iov := [Data]}} -> + {ok, Data}; + {error, _} = ERROR -> + ERROR + end + end, + ok = api_b_send_and_recv_tcp(inet, Send, Recv), + tc_end(). + + +api_b_send_and_recv_tcp(Domain, Send, Recv) -> + process_flag(trap_exit, true), + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + Starter = self(), + ServerFun = fun() -> + %% Create the listen socket + ServerLSock = + case socket:open(Domain, stream, tcp) of + {ok, S1} -> + S1; + {error, ServerOR} -> + ?FAIL({server, open, ServerOR}) + end, + %% And bind it to the local address + SP = + case socket:bind(ServerLSock, LSA) of + {ok, P} -> + P; + {error, ServerBR} -> + ?FAIL({server, bind, ServerBR}) + end, + %% Listen for connecting clients + case socket:listen(ServerLSock) of + ok -> + ok; + {error, ServerLR} -> + ?FAIL({server, listen, ServerLR}) + end, + %% We are ready + Starter ! {self(), {ok, SP}}, + %% Accept connections + ServerSock = + case socket:accept(ServerLSock) of + {ok, Sock} -> + Sock; + {error, ServerAR} -> + ?FAIL({server, accept, ServerAR}) + end, + %% Wait for a message + case Recv(ServerSock) of + {ok, ?BASIC_REQ} -> + ok; + {error, ServerRR} -> + ?FAIL({server, recv, ServerRR}) + end, + %% Send the reply + case Send(ServerSock, ?BASIC_REP) of + ok -> + ok; + {error, ServerSR} -> + ?FAIL({server, send, ServerSR}) + end, + %% Close the sockets + socket:close(ServerSock), + socket:close(ServerLSock), + %% We are done + exit(normal) + end, + Server = spawn_link(ServerFun), + ServerPort = + receive + {Server, {ok, P}} -> + P; + {'EXIT', Server, ServerStartReason} -> + ?FAIL({server, start, ServerStartReason}) + end, + ClientSock = + case socket:open(Domain, stream, tcp) of + {ok, S2} -> + S2; + {error, ClientOR} -> + ?FAIL({client, open, ClientOR}) + end, + case socket:bind(ClientSock, LSA) of + {ok, _} -> + ok; + {error, ClientBR} -> + ?FAIL({client, bind, ClientBR}) + end, + case socket:connect(ClientSock, LSA#{port => ServerPort}) of + ok -> + ok; + {error, ClientCR} -> + ?FAIL({client, connect, ClientCR}) + end, + case Send(ClientSock, ?BASIC_REQ) of + ok -> + ok; + {error, ClientSR} -> + ?FAIL({client, send, ClientSR}) + end, + case Recv(ClientSock) of + {ok, ?BASIC_REP} -> + ok; + {ok, Msg} -> + ?FAIL({client, recv, {unexpected, Msg}}) + end, + receive + {'EXIT', Server, normal} -> + ok; + {'EXIT', Server, ServerStopReason} -> + ?FAIL({server, stop, ServerStopReason}) + end, + socket:close(ClientSock), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% 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) -> + case inet:getifaddrs() of + {ok, IFL} -> + which_addr(Domain, IFL); + {error, Reason} -> + ?FAIL({inet, getifaddrs, Reason}) + end. + +which_addr(_Domain, []) -> + ?FAIL(no_address); +which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> + which_addr2(Domain, IFO); +which_addr(Domain, [_|IFL]) -> + which_addr(Domain, IFL). + +which_addr2(_Domain, []) -> + ?FAIL(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) -> + Addr; +which_addr2(Domain, [_|IFO]) -> + which_addr2(Domain, IFO). + + +tc_begin(TC) -> + put(tc_name, TC), + p("begin"). + +tc_end() -> + ok. + +p(F) -> + p(F, []). + +p(F, A) -> + io:format(user, "*** ~w " ++ F ++ "~n", [get(tc_name)|A]). + -- cgit v1.2.3 From 742a210ace9625646386eb71b8d33e9938eeaec1 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 25 Sep 2018 16:34:55 +0200 Subject: [socket-nif] Add proper recv timeout handling Added proper recv timeout handling. Made use of the enif_select(mode = cancel) feature. Each time a timeout expires, the "active" recv (the surrent reader select) has to be cancelled. Not yet tested...something for the new test suite... Also, added support for getopt(controlling_pprocess) that, for some reason, was not yet implemented. OTP-14831 --- lib/kernel/test/socket_server.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl index 9142942428..45adffc5e6 100644 --- a/lib/kernel/test/socket_server.erl +++ b/lib/kernel/test/socket_server.erl @@ -922,8 +922,8 @@ send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout}, CMsgHdr = #{level => ip, type => tos, data => reliability}, CMsgHdrs = [CMsgHdr], MsgHdr = #{addr => Dest, - iov => [Msg], - ctrl => CMsgHdrs}, + ctrl => CMsgHdrs, + iov => [Msg]}, %% ok = socket:setopt(Sock, otp, debug, true), Res = socket:sendmsg(Sock, MsgHdr, Timeout), %% ok = socket:setopt(Sock, otp, debug, false), -- cgit v1.2.3 From 18305496c064c8d9d32448a6425bdd39eaa20c7f Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 26 Sep 2018 15:02:53 +0200 Subject: [socket-nif|test] Add operation timeout test cases Add a number of *basic* operation (connect, accept, send and recv). All of which are not yet implemented (skipped with 'not-yet-implemented'). All of these are basic and only local (both sides on the same host). OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 777 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 735 insertions(+), 42 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 1bf12693fe..e4f9d2c8b2 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -25,6 +25,8 @@ %% Suite exports -export([suite/0, all/0, groups/0]). +-export([init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2]). %% Test cases -export([ @@ -34,7 +36,29 @@ api_b_sendto_and_recvfrom_udp4/1, api_b_sendmsg_and_recvmsg_udp4/1, api_b_send_and_recv_tcp4/1, - api_b_sendmsg_and_recvmsg_tcp4/1 + api_b_sendmsg_and_recvmsg_tcp4/1, + + %% Operation Timeout + to_connect_tcp4/1, + to_connect_tcp6/1, + to_accept_tcp4/1, + to_accept_tcp6/1, + to_send_tcp4/1, + to_send_tcp6/1, + to_sendto_udp4/1, + to_sendto_udp6/1, + to_sendmsg_tcp4/1, + to_sendmsg_tcp6/1, + to_recv_udp4/1, + to_recv_udp6/1, + to_recv_tcp4/1, + to_recv_tcp6/1, + to_recvfrom_udp4/1, + to_recvfrom_udp6/1, + to_recvmsg_udp4/1, + to_recvmsg_udp6/1, + to_recvmsg_tcp4/1, + to_recvmsg_tcp6/1 %% Tickets ]). @@ -64,18 +88,21 @@ all() -> ]. groups() -> - [{api, [], api_cases()}, - {api_basic, [], api_basic_cases()} + [{api, [], api_cases()}, + {api_basic, [], api_basic_cases()}, + {op_with_timeout, [], op_with_timeout_cases()} %% {tickets, [], ticket_cases()} ]. api_cases() -> [ - {group, api_basic} + {group, api_basic}, + {group, op_with_timeout} ]. api_basic_cases() -> - [api_b_open_and_close_udp4, + [ + api_b_open_and_close_udp4, api_b_open_and_close_tcp4, api_b_sendto_and_recvfrom_udp4, api_b_sendmsg_and_recvmsg_udp4, @@ -83,11 +110,52 @@ api_basic_cases() -> api_b_sendmsg_and_recvmsg_tcp4 ]. +op_with_timeout_cases() -> + [ + to_connect_tcp4, + to_connect_tcp6, + to_accept_tcp4, + to_accept_tcp6, + to_send_tcp4, + to_send_tcp6, + to_sendto_udp4, + to_sendto_udp6, + to_sendmsg_tcp4, + to_sendmsg_tcp6, + to_recv_udp4, + to_recv_udp6, + to_recv_tcp4, + to_recv_tcp6, + to_recvfrom_udp4, + to_recvfrom_udp6, + to_recvmsg_udp4, + to_recvmsg_udp6, + to_recvmsg_tcp4, + to_recvmsg_tcp6 + ]. + + %% ticket_cases() -> %% []. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init_per_suite(Config) -> + Config. + +end_per_suite(_) -> + ok. + +init_per_testcase(_TC, Config) -> + Config. + +end_per_testcase(_TC, Config) -> + Config. + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically open (create) and close an IPv4 UDP (dgram) socket. @@ -154,6 +222,8 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> tc_end(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Basically send and receive on an IPv4 UDP (dgram) socket %% using sendmsg and recvmsg. api_b_sendmsg_and_recvmsg_udp4(suite) -> @@ -183,42 +253,19 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> tc_end(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + api_b_send_and_recv_udp(Domain, Send, Recv) -> - SockSrc = case socket:open(Domain, dgram, udp) of - {ok, S1} -> - S1; - {error, OR1} -> - ?FAIL({open, src, OR1}) - end, - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - case socket:bind(SockSrc, LSA) of - {ok, _} -> - ok; - {error, BR1} -> - ?FAIL({bind, src, BR1}) - end, - SockDst = case socket:open(Domain, dgram, udp) of - {ok, S2} -> - S2; - {error, OR2} -> - ?FAIL({open, dst, OR2}) - end, - case socket:bind(SockDst, LSA) of - {ok, _} -> - ok; - {error, BR2} -> - ?FAIL({bind, dst, BR2}) - end, - Dst = case socket:sockname(SockDst) of - {ok, SA} -> - SA; - {ok, SNR} -> - ?FAIL({sockname, dst, SNR}) - end, - ok = Send(SockSrc, ?BASIC_REQ, Dst), + SockSrc = sock_open(Domain, dgram, udp), + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + sock_bind(SockSrc, LSA), + SockDst = sock_open(Domain, dgram, udp), + sock_bind(SockDst, LSA), + Dst = sock_sockname(SockDst), + ok = Send(SockSrc, ?BASIC_REQ, Dst), {ok, {Src, ?BASIC_REQ}} = Recv(SockDst), - ok = Send(SockDst, ?BASIC_REP, Src), + ok = Send(SockDst, ?BASIC_REP, Src), {ok, {Dst, ?BASIC_REP}} = Recv(SockSrc), socket:close(SockSrc), socket:close(SockDst), @@ -246,6 +293,8 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> tc_end(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Basically send and receive using the msg functions (sendmsg and recvmsg) %% on an IPv4 TCP (stream) socket. api_b_sendmsg_and_recvmsg_tcp4(suite) -> @@ -271,6 +320,8 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> tc_end(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + api_b_send_and_recv_tcp(Domain, Send, Recv) -> process_flag(trap_exit, true), LAddr = which_local_addr(Domain), @@ -380,6 +431,528 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the connect timeout option +%% on an IPv4 TCP (stream) socket. +to_connect_tcp4(suite) -> + []; +to_connect_tcp4(doc) -> + []; +to_connect_tcp4(_Config) when is_list(_Config) -> + tc_begin(to_connect_tcp4), + ok = to_connect_tcp(inet), + tc_end(). + %% not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the connect timeout option +%% on an IPv6 TCP (stream) socket. +to_connect_tcp6(suite) -> + []; +to_connect_tcp6(doc) -> + []; +to_connect_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_connect_tcp6), + %% ok = to_connect_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +to_connect_tcp(Domain) -> + process_flag(trap_exit, true), + p("init"), + Client = self(), + LocalAddr = which_local_addr(Domain), + LocalSA = #{family => Domain, addr => LocalAddr}, + ServerName = f("~s:server", [get_tc_name()]), + Server = spawn_link(fun() -> + set_tc_name(ServerName), + p("open"), + LSock = sock_open(Domain, stream, tcp), + p("bind"), + ServerLPort = sock_bind(LSock, LocalSA), + p("listen on ~w", [ServerLPort]), + sock_listen(LSock, 1), + p("inform client"), + Client ! {self(), ServerLPort}, + p("await termination command"), + receive + die -> + p("terminating"), + exit(normal) + end + end), + + p("await server port"), + ServerLPort = + receive + {Server, Port} -> + Port + end, + p("open(s)"), + CSock1 = sock_open(Domain, stream, tcp), + CSock2 = sock_open(Domain, stream, tcp), + CSock3 = sock_open(Domain, stream, tcp), + p("bind(s)"), + _ClientPort1 = sock_bind(CSock1, LocalSA), + _ClientPort2 = sock_bind(CSock2, LocalSA), + _ClientPort3 = sock_bind(CSock3, LocalSA), + ServerSA = LocalSA#{port => ServerLPort}, + to_connect_tcp_await_timeout([CSock1, CSock2, CSock3], ServerSA), + p("terminate server"), + Server ! die, + receive + {'EXIT', Server, _} -> + p("server terminated"), + ok + end, + ok. + + +to_connect_tcp_await_timeout(Socks, ServerSA) -> + to_connect_tcp_await_timeout(Socks, ServerSA, 1). + +to_connect_tcp_await_timeout([], _ServerSA, _ID) -> + ?FAIL(unexpected_success); +to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> + p("~w: try connect", [ID]), + case socket:connect(Sock, ServerSA, 5000) of + {error, timeout} -> + p("expected timeout (~w)", [ID]), + ok; + {error, Reason} -> + p("failed connecting: ~p", [Reason]), + ?FAIL({recv, Reason}); + ok -> + p("unexpected success (~w) - try next", [ID]), + to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) + end. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the accept timeout option +%% on an IPv4 TCP (stream) socket. +to_accept_tcp4(suite) -> + []; +to_accept_tcp4(doc) -> + []; +to_accept_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(to_accept_tcp4), + %% ok = to_accept_tcp(inet), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the accept timeout option +%% on an IPv6 TCP (stream) socket. +to_accept_tcp6(suite) -> + []; +to_accept_tcp6(doc) -> + []; +to_accept_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_accept_tcp6), + %% ok = to_accept_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the send timeout option +%% on an IPv4 TCP (stream) socket. +to_send_tcp4(suite) -> + []; +to_send_tcp4(doc) -> + []; +to_send_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(to_send_tcp4), + %% ok = to_send_tcp(inet), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the send timeout option +%% on an IPv6 TCP (stream) socket. +to_send_tcp6(suite) -> + []; +to_send_tcp6(doc) -> + []; +to_send_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_send_tcp6), + %% ok = to_send_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the sendto timeout option +%% on an IPv4 UDP (dgram) socket. +to_sendto_udp4(suite) -> + []; +to_sendto_udp4(doc) -> + []; +to_sendto_udp4(_Config) when is_list(_Config) -> + %% tc_begin(to_sendto_udp4), + %% ok = to_sendto_udp(inet), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the sendto timeout option +%% on an IPv6 UDP (dgram) socket. +to_sendto_udp6(suite) -> + []; +to_sendto_udp6(doc) -> + []; +to_sendto_udp6(_Config) when is_list(_Config) -> + %% tc_begin(to_sendto_udp6), + %% ok = to_sendto_udp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the sendmsg timeout option +%% on an IPv4 TCP (stream) socket. +to_sendmsg_tcp4(suite) -> + []; +to_sendmsg_tcp4(doc) -> + []; +to_sendmsg_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(to_sendmsg_tcp4), + %% ok = to_sendmsg_tcp(inet), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the sendmsg timeout option +%% on an IPv6 TCP (stream) socket. +to_sendmsg_tcp6(suite) -> + []; +to_sendmsg_tcp6(doc) -> + []; +to_sendmsg_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_sendmsg_tcp6), + %% ok = to_sendmsg_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recv timeout option +%% on an IPv4 UDP (dgram) socket. To test this we must connect +%% the socket. +to_recv_udp4(suite) -> + []; +to_recv_udp4(doc) -> + []; +to_recv_udp4(_Config) when is_list(_Config) -> + %% tc_begin(to_recv_udp4), + %% ok = to_recv_udp(inet), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recv timeout option +%% on an IPv6 UDP (dgram) socket. To test this we must connect +%% the socket. +to_recv_udp6(suite) -> + []; +to_recv_udp6(doc) -> + []; +to_recv_udp6(_Config) when is_list(_Config) -> + %% tc_begin(to_recv_udp6), + %% ok = to_recv_udp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recv timeout option +%% on an IPv4 TCP (stream) socket. +to_recv_tcp4(suite) -> + []; +to_recv_tcp4(doc) -> + []; +to_recv_tcp4(_Config) when is_list(_Config) -> + tc_begin(to_recv_tcp4), + ok = to_recv_tcp(inet), + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recv timeout option +%% on an IPv6 TCP (stream) socket. +to_recv_tcp6(suite) -> + []; +to_recv_tcp6(doc) -> + []; +to_recv_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_recv_tcp6), + %% ok = to_recv_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +to_recv_tcp(Domain) -> + process_flag(trap_exit, true), + p("server -> open"), + LSock = sock_open(Domain, stream, tcp), + LocalAddr = which_local_addr(Domain), + LocalSA = #{family => Domain, addr => LocalAddr}, + p("server -> bind"), + ServerLPort = sock_bind(LSock, LocalSA), + p("server(~w) -> listen", [ServerLPort]), + sock_listen(LSock), + ClientName = f("~s:client", [get_tc_name()]), + Client = spawn_link(fun() -> + set_tc_name(ClientName), + p("open"), + CSock = sock_open(Domain, stream, tcp), + p("bind"), + ClientPort = sock_bind(CSock, LocalSA), + p("[~w] connect to ~w", + [ClientPort, ServerLPort]), + sock_connect(CSock, LocalSA#{port => ServerLPort}), + p("await termination command"), + receive + die -> + p("terminating"), + exit(normal) + end + end), + p("server -> accept on ~w", [ServerLPort]), + Sock = sock_accept(LSock), + p("server -> recv"), + %% The zero (0) represents "give me everything you have" + case socket:recv(Sock, 0, 5000) of + {error, timeout} -> + p("server -> expected timeout"), + ok; + {ok, _Data} -> + ?FAIL(unexpected_success); + {error, Reason} -> + ?FAIL({recv, Reason}) + end, + Client ! die, + receive + {'EXIT', Client, _} -> + ok + end, + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvfrom timeout option +%% on an IPv4 UDP (dgram) socket. +to_recvfrom_udp4(suite) -> + []; +to_recvfrom_udp4(doc) -> + []; +to_recvfrom_udp4(_Config) when is_list(_Config) -> + tc_begin(to_recvfrom_udp4), + ok = to_recvfrom_udp(inet), + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvfrom timeout option +%% on an IPv6 UDP (dgram) socket. +to_recvfrom_udp6(suite) -> + []; +to_recvfrom_udp6(doc) -> + []; +to_recvfrom_udp6(_Config) when is_list(_Config) -> + %% tc_begin(to_recvfrom_udp6), + %% ok = to_recvfrom_udp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +to_recvfrom_udp(Domain) -> + process_flag(trap_exit, true), + p("init"), + LocalAddr = which_local_addr(Domain), + LocalSA = #{family => Domain, addr => LocalAddr}, + p("open"), + Sock = sock_open(Domain, dgram, udp), + p("bind"), + _Port = sock_bind(Sock, LocalSA), + p("recv"), + case socket:recvfrom(Sock, 0, 5000) of + {error, timeout} -> + p("expected timeout"), + ok; + {ok, _SrcData} -> + ?FAIL(unexpected_success); + {error, Reason} -> + ?FAIL({recv, Reason}) + end, + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvmsg timeout option +%% on an IPv4 UDP (dgram) socket. +to_recvmsg_udp4(suite) -> + []; +to_recvmsg_udp4(doc) -> + []; +to_recvmsg_udp4(_Config) when is_list(_Config) -> + %% not_yet_implemented(). + tc_begin(to_recvmsg_udp4), + ok = to_recvmsg_udp(inet), + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvmsg timeout option +%% on an IPv6 UDP (dgram) socket. +to_recvmsg_udp6(suite) -> + []; +to_recvmsg_udp6(doc) -> + []; +to_recvmsg_udp6(_Config) when is_list(_Config) -> + %% tc_begin(to_recvmsg_udp6), + %% ok = to_recvmsg_udp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +to_recvmsg_udp(Domain) -> + process_flag(trap_exit, true), + p("init"), + LocalAddr = which_local_addr(Domain), + LocalSA = #{family => Domain, addr => LocalAddr}, + p("open"), + Sock = sock_open(Domain, dgram, udp), + p("bind"), + _Port = sock_bind(Sock, LocalSA), + p("recv"), + case socket:recvmsg(Sock, 5000) of + {error, timeout} -> + p("expected timeout"), + ok; + {ok, _MsgHdr} -> + ?FAIL(unexpected_success); + {error, Reason} -> + ?FAIL({recv, Reason}) + end, + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvmsg timeout option +%% on an IPv4 TCP (stream) socket. +to_recvmsg_tcp4(suite) -> + []; +to_recvmsg_tcp4(doc) -> + []; +to_recvmsg_tcp4(_Config) when is_list(_Config) -> + tc_begin(to_recvmsg_tcp4), + ok = to_recvmsg_tcp(inet), + tc_end(). + %% not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the recvmsg timeout option +%% on an IPv6 TCP (stream) socket. +to_recvmsg_tcp6(suite) -> + []; +to_recvmsg_tcp6(doc) -> + []; +to_recvmsg_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(to_recvmsg_tcp6), + %% ok = to_recvmsg_tcp(inet6), + %% tc_end(). + not_yet_implemented(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +to_recvmsg_tcp(Domain) -> + process_flag(trap_exit, true), + p("server -> open"), + LSock = sock_open(Domain, stream, tcp), + LocalAddr = which_local_addr(Domain), + LocalSA = #{family => Domain, addr => LocalAddr}, + p("server -> bind"), + ServerLPort = sock_bind(LSock, LocalSA), + p("server(~w) -> listen", [ServerLPort]), + sock_listen(LSock), + ClientName = f("~s:client", [get_tc_name()]), + Client = spawn_link(fun() -> + set_tc_name(ClientName), + p("open"), + CSock = sock_open(Domain, stream, tcp), + p("bind"), + ClientPort = sock_bind(CSock, LocalSA), + p("[~w] connect to ~w", + [ClientPort, ServerLPort]), + sock_connect(CSock, LocalSA#{port => ServerLPort}), + p("await termination command"), + receive + die -> + p("terminating"), + exit(normal) + end + end), + p("server -> accept on ~w", [ServerLPort]), + Sock = sock_accept(LSock), + p("server -> recv"), + %% The zero (0) represents "give me everything you have" + case socket:recvmsg(Sock, 5000) of + {error, timeout} -> + p("server -> expected timeout"), + ok; + {ok, _Data} -> + ?FAIL(unexpected_success); + {error, Reason} -> + ?FAIL({recv, Reason}) + end, + Client ! die, + receive + {'EXIT', Client, _} -> + ok + end, + ok. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -411,16 +984,136 @@ which_addr2(Domain, [_|IFO]) -> which_addr2(Domain, IFO). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +sock_open(Domain, Type, Proto) -> + try socket:open(Domain, Type, Proto) of + {ok, Socket} -> + Socket; + {error, Reason} -> + ?FAIL({open, Reason}) + catch + C:E:S -> + ?FAIL({open, C, E, S}) + end. + + +sock_bind(Sock, SockAddr) -> + try socket:bind(Sock, SockAddr) of + {ok, Port} -> + Port; + {error, Reason} -> + p("sock_bind -> error: ~p", [Reason]), + ?FAIL({bind, Reason}) + catch + C:E:S -> + p("sock_bind -> failed: ~p, ~p, ~p", [C, E, S]), + ?FAIL({bind, C, E, S}) + end. + +sock_connect(Sock, SockAddr) -> + try socket:connect(Sock, SockAddr) of + ok -> + ok; + {error, Reason} -> + ?FAIL({connect, Reason}) + catch + C:E:S -> + ?FAIL({connect, C, E, S}) + end. + +sock_sockname(Sock) -> + try socket:sockname(Sock) of + {ok, SockAddr} -> + SockAddr; + {error, Reason} -> + ?FAIL({sockname, Reason}) + catch + C:E:S -> + ?FAIL({sockname, C, E, S}) + end. + + +sock_listen(Sock) -> + sock_listen2(fun() -> socket:listen(Sock) end). + +sock_listen(Sock, BackLog) -> + sock_listen2(fun() -> socket:listen(Sock, BackLog) end). + +sock_listen2(Listen) -> + try Listen() of + ok -> + ok; + {error, Reason} -> + ?FAIL({listen, Reason}) + catch + C:E:S -> + ?FAIL({listen, C, E, S}) + end. + + +sock_accept(LSock) -> + try socket:accept(LSock) of + {ok, Sock} -> + Sock; + {error, Reason} -> + p("sock_accept -> error: ~p", [Reason]), + ?FAIL({accept, Reason}) + catch + C:E:S -> + p("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]), + ?FAIL({accept, C, E, S}) + end. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +not_yet_implemented() -> + {skip, "not yet implemented"}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +set_tc_name(N) when is_atom(N) -> + set_tc_name(atom_to_list(N)); +set_tc_name(N) when is_list(N) -> + put(tc_name, N). + +get_tc_name() -> + get(tc_name). + tc_begin(TC) -> - put(tc_name, TC), - p("begin"). + set_tc_name(TC), + p("begin ***"). tc_end() -> + p("done ***"), ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +f(F, A) -> + lists:flatten(io_lib:format(F, A)). + p(F) -> p(F, []). p(F, A) -> - io:format(user, "*** ~w " ++ F ++ "~n", [get(tc_name)|A]). + TcName = + case get(tc_name) of + undefined -> + ""; + Name when is_list(Name) -> + Name + end, + i("*** ~s[~p] " ++ F, [TcName,self()|A]). + + +%% i(F) -> +%% i(F, []). +i(F, A) -> + io:format(user, F ++ "~n", A). -- cgit v1.2.3 From 4d8504a7c33133ea9f7ade7b9eb763406e0d60fa Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 27 Sep 2018 12:38:23 +0200 Subject: [socket-nif|test] Test case grouping The test cases has been slighly regrouped. The to-group has moved into the api-group. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 318 +++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 159 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index e4f9d2c8b2..0255c8ef75 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -30,7 +30,7 @@ %% Test cases -export([ - %% Basic + %% API Basic api_b_open_and_close_udp4/1, api_b_open_and_close_tcp4/1, api_b_sendto_and_recvfrom_udp4/1, @@ -38,27 +38,27 @@ api_b_send_and_recv_tcp4/1, api_b_sendmsg_and_recvmsg_tcp4/1, - %% Operation Timeout - to_connect_tcp4/1, - to_connect_tcp6/1, - to_accept_tcp4/1, - to_accept_tcp6/1, - to_send_tcp4/1, - to_send_tcp6/1, - to_sendto_udp4/1, - to_sendto_udp6/1, - to_sendmsg_tcp4/1, - to_sendmsg_tcp6/1, - to_recv_udp4/1, - to_recv_udp6/1, - to_recv_tcp4/1, - to_recv_tcp6/1, - to_recvfrom_udp4/1, - to_recvfrom_udp6/1, - to_recvmsg_udp4/1, - to_recvmsg_udp6/1, - to_recvmsg_tcp4/1, - to_recvmsg_tcp6/1 + %% API Operation Timeout + api_to_connect_tcp4/1, + api_to_connect_tcp6/1, + api_to_accept_tcp4/1, + api_to_accept_tcp6/1, + api_to_send_tcp4/1, + api_to_send_tcp6/1, + api_to_sendapi_to_udp4/1, + api_to_sendapi_to_udp6/1, + api_to_sendmsg_tcp4/1, + api_to_sendmsg_tcp6/1, + api_to_recv_udp4/1, + api_to_recv_udp6/1, + api_to_recv_tcp4/1, + api_to_recv_tcp6/1, + api_to_recvfrom_udp4/1, + api_to_recvfrom_udp6/1, + api_to_recvmsg_udp4/1, + api_to_recvmsg_udp6/1, + api_to_recvmsg_tcp4/1, + api_to_recvmsg_tcp6/1 %% Tickets ]). @@ -88,16 +88,16 @@ all() -> ]. groups() -> - [{api, [], api_cases()}, - {api_basic, [], api_basic_cases()}, - {op_with_timeout, [], op_with_timeout_cases()} - %% {tickets, [], ticket_cases()} + [{api, [], api_cases()}, + {api_basic, [], api_basic_cases()}, + {api_op_with_timeout, [], api_op_with_timeout_cases()} + %% {tickets, [], ticket_cases()} ]. api_cases() -> [ {group, api_basic}, - {group, op_with_timeout} + {group, api_op_with_timeout} ]. api_basic_cases() -> @@ -110,28 +110,28 @@ api_basic_cases() -> api_b_sendmsg_and_recvmsg_tcp4 ]. -op_with_timeout_cases() -> +api_op_with_timeout_cases() -> [ - to_connect_tcp4, - to_connect_tcp6, - to_accept_tcp4, - to_accept_tcp6, - to_send_tcp4, - to_send_tcp6, - to_sendto_udp4, - to_sendto_udp6, - to_sendmsg_tcp4, - to_sendmsg_tcp6, - to_recv_udp4, - to_recv_udp6, - to_recv_tcp4, - to_recv_tcp6, - to_recvfrom_udp4, - to_recvfrom_udp6, - to_recvmsg_udp4, - to_recvmsg_udp6, - to_recvmsg_tcp4, - to_recvmsg_tcp6 + api_to_connect_tcp4, + api_to_connect_tcp6, + api_to_accept_tcp4, + api_to_accept_tcp6, + api_to_send_tcp4, + api_to_send_tcp6, + api_to_sendapi_to_udp4, + api_to_sendapi_to_udp6, + api_to_sendmsg_tcp4, + api_to_sendmsg_tcp6, + api_to_recv_udp4, + api_to_recv_udp6, + api_to_recv_tcp4, + api_to_recv_tcp6, + api_to_recvfrom_udp4, + api_to_recvfrom_udp6, + api_to_recvmsg_udp4, + api_to_recvmsg_udp6, + api_to_recvmsg_tcp4, + api_to_recvmsg_tcp6 ]. @@ -435,13 +435,13 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) -> %% This test case is intended to test the connect timeout option %% on an IPv4 TCP (stream) socket. -to_connect_tcp4(suite) -> +api_to_connect_tcp4(suite) -> []; -to_connect_tcp4(doc) -> +api_to_connect_tcp4(doc) -> []; -to_connect_tcp4(_Config) when is_list(_Config) -> - tc_begin(to_connect_tcp4), - ok = to_connect_tcp(inet), +api_to_connect_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_to_connect_tcp4), + ok = api_to_connect_tcp(inet), tc_end(). %% not_yet_implemented(). @@ -450,20 +450,20 @@ to_connect_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the connect timeout option %% on an IPv6 TCP (stream) socket. -to_connect_tcp6(suite) -> +api_to_connect_tcp6(suite) -> []; -to_connect_tcp6(doc) -> +api_to_connect_tcp6(doc) -> []; -to_connect_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_connect_tcp6), - %% ok = to_connect_tcp(inet6), +api_to_connect_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_connect_tcp6), + %% ok = api_to_connect_tcp(inet6), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_connect_tcp(Domain) -> +api_to_connect_tcp(Domain) -> process_flag(trap_exit, true), p("init"), Client = self(), @@ -503,7 +503,7 @@ to_connect_tcp(Domain) -> _ClientPort2 = sock_bind(CSock2, LocalSA), _ClientPort3 = sock_bind(CSock3, LocalSA), ServerSA = LocalSA#{port => ServerLPort}, - to_connect_tcp_await_timeout([CSock1, CSock2, CSock3], ServerSA), + api_to_connect_tcp_await_timeout([CSock1, CSock2, CSock3], ServerSA), p("terminate server"), Server ! die, receive @@ -514,12 +514,12 @@ to_connect_tcp(Domain) -> ok. -to_connect_tcp_await_timeout(Socks, ServerSA) -> - to_connect_tcp_await_timeout(Socks, ServerSA, 1). +api_to_connect_tcp_await_timeout(Socks, ServerSA) -> + api_to_connect_tcp_await_timeout(Socks, ServerSA, 1). -to_connect_tcp_await_timeout([], _ServerSA, _ID) -> +api_to_connect_tcp_await_timeout([], _ServerSA, _ID) -> ?FAIL(unexpected_success); -to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> +api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> p("~w: try connect", [ID]), case socket:connect(Sock, ServerSA, 5000) of {error, timeout} -> @@ -530,7 +530,7 @@ to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> ?FAIL({recv, Reason}); ok -> p("unexpected success (~w) - try next", [ID]), - to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) + api_to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) end. @@ -539,13 +539,13 @@ to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> %% This test case is intended to test the accept timeout option %% on an IPv4 TCP (stream) socket. -to_accept_tcp4(suite) -> +api_to_accept_tcp4(suite) -> []; -to_accept_tcp4(doc) -> +api_to_accept_tcp4(doc) -> []; -to_accept_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(to_accept_tcp4), - %% ok = to_accept_tcp(inet), +api_to_accept_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(api_to_accept_tcp4), + %% ok = api_to_accept_tcp(inet), %% tc_end(). not_yet_implemented(). @@ -554,13 +554,13 @@ to_accept_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the accept timeout option %% on an IPv6 TCP (stream) socket. -to_accept_tcp6(suite) -> +api_to_accept_tcp6(suite) -> []; -to_accept_tcp6(doc) -> +api_to_accept_tcp6(doc) -> []; -to_accept_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_accept_tcp6), - %% ok = to_accept_tcp(inet6), +api_to_accept_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_accept_tcp6), + %% ok = api_to_accept_tcp(inet6), %% tc_end(). not_yet_implemented(). @@ -569,13 +569,13 @@ to_accept_tcp6(_Config) when is_list(_Config) -> %% This test case is intended to test the send timeout option %% on an IPv4 TCP (stream) socket. -to_send_tcp4(suite) -> +api_to_send_tcp4(suite) -> []; -to_send_tcp4(doc) -> +api_to_send_tcp4(doc) -> []; -to_send_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(to_send_tcp4), - %% ok = to_send_tcp(inet), +api_to_send_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(api_to_send_tcp4), + %% ok = api_to_send_tcp(inet), %% tc_end(). not_yet_implemented(). @@ -584,13 +584,13 @@ to_send_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the send timeout option %% on an IPv6 TCP (stream) socket. -to_send_tcp6(suite) -> +api_to_send_tcp6(suite) -> []; -to_send_tcp6(doc) -> +api_to_send_tcp6(doc) -> []; -to_send_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_send_tcp6), - %% ok = to_send_tcp(inet6), +api_to_send_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_send_tcp6), + %% ok = api_to_send_tcp(inet6), %% tc_end(). not_yet_implemented(). @@ -599,13 +599,13 @@ to_send_tcp6(_Config) when is_list(_Config) -> %% This test case is intended to test the sendto timeout option %% on an IPv4 UDP (dgram) socket. -to_sendto_udp4(suite) -> +api_to_sendapi_to_udp4(suite) -> []; -to_sendto_udp4(doc) -> +api_to_sendapi_to_udp4(doc) -> []; -to_sendto_udp4(_Config) when is_list(_Config) -> - %% tc_begin(to_sendto_udp4), - %% ok = to_sendto_udp(inet), +api_to_sendapi_to_udp4(_Config) when is_list(_Config) -> + %% tc_begin(api_to_sendapi_to_udp4), + %% ok = api_to_sendapi_to_udp(inet), %% tc_end(). not_yet_implemented(). @@ -614,13 +614,13 @@ to_sendto_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the sendto timeout option %% on an IPv6 UDP (dgram) socket. -to_sendto_udp6(suite) -> +api_to_sendapi_to_udp6(suite) -> []; -to_sendto_udp6(doc) -> +api_to_sendapi_to_udp6(doc) -> []; -to_sendto_udp6(_Config) when is_list(_Config) -> - %% tc_begin(to_sendto_udp6), - %% ok = to_sendto_udp(inet6), +api_to_sendapi_to_udp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_sendapi_to_udp6), + %% ok = api_to_sendapi_to_udp(inet6), %% tc_end(). not_yet_implemented(). @@ -629,13 +629,13 @@ to_sendto_udp6(_Config) when is_list(_Config) -> %% This test case is intended to test the sendmsg timeout option %% on an IPv4 TCP (stream) socket. -to_sendmsg_tcp4(suite) -> +api_to_sendmsg_tcp4(suite) -> []; -to_sendmsg_tcp4(doc) -> +api_to_sendmsg_tcp4(doc) -> []; -to_sendmsg_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(to_sendmsg_tcp4), - %% ok = to_sendmsg_tcp(inet), +api_to_sendmsg_tcp4(_Config) when is_list(_Config) -> + %% tc_begin(api_to_sendmsg_tcp4), + %% ok = api_to_sendmsg_tcp(inet), %% tc_end(). not_yet_implemented(). @@ -644,13 +644,13 @@ to_sendmsg_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the sendmsg timeout option %% on an IPv6 TCP (stream) socket. -to_sendmsg_tcp6(suite) -> +api_to_sendmsg_tcp6(suite) -> []; -to_sendmsg_tcp6(doc) -> +api_to_sendmsg_tcp6(doc) -> []; -to_sendmsg_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_sendmsg_tcp6), - %% ok = to_sendmsg_tcp(inet6), +api_to_sendmsg_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_sendmsg_tcp6), + %% ok = api_to_sendmsg_tcp(inet6), %% tc_end(). not_yet_implemented(). @@ -660,13 +660,13 @@ to_sendmsg_tcp6(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv4 UDP (dgram) socket. To test this we must connect %% the socket. -to_recv_udp4(suite) -> +api_to_recv_udp4(suite) -> []; -to_recv_udp4(doc) -> +api_to_recv_udp4(doc) -> []; -to_recv_udp4(_Config) when is_list(_Config) -> - %% tc_begin(to_recv_udp4), - %% ok = to_recv_udp(inet), +api_to_recv_udp4(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recv_udp4), + %% ok = api_to_recv_udp(inet), %% tc_end(). not_yet_implemented(). @@ -676,13 +676,13 @@ to_recv_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv6 UDP (dgram) socket. To test this we must connect %% the socket. -to_recv_udp6(suite) -> +api_to_recv_udp6(suite) -> []; -to_recv_udp6(doc) -> +api_to_recv_udp6(doc) -> []; -to_recv_udp6(_Config) when is_list(_Config) -> - %% tc_begin(to_recv_udp6), - %% ok = to_recv_udp(inet6), +api_to_recv_udp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recv_udp6), + %% ok = api_to_recv_udp(inet6), %% tc_end(). not_yet_implemented(). @@ -691,13 +691,13 @@ to_recv_udp6(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv4 TCP (stream) socket. -to_recv_tcp4(suite) -> +api_to_recv_tcp4(suite) -> []; -to_recv_tcp4(doc) -> +api_to_recv_tcp4(doc) -> []; -to_recv_tcp4(_Config) when is_list(_Config) -> - tc_begin(to_recv_tcp4), - ok = to_recv_tcp(inet), +api_to_recv_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_to_recv_tcp4), + ok = api_to_recv_tcp(inet), tc_end(). @@ -705,20 +705,20 @@ to_recv_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recv timeout option %% on an IPv6 TCP (stream) socket. -to_recv_tcp6(suite) -> +api_to_recv_tcp6(suite) -> []; -to_recv_tcp6(doc) -> +api_to_recv_tcp6(doc) -> []; -to_recv_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_recv_tcp6), - %% ok = to_recv_tcp(inet6), +api_to_recv_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recv_tcp6), + %% ok = api_to_recv_tcp(inet6), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_recv_tcp(Domain) -> +api_to_recv_tcp(Domain) -> process_flag(trap_exit, true), p("server -> open"), LSock = sock_open(Domain, stream, tcp), @@ -770,13 +770,13 @@ to_recv_tcp(Domain) -> %% This test case is intended to test the recvfrom timeout option %% on an IPv4 UDP (dgram) socket. -to_recvfrom_udp4(suite) -> +api_to_recvfrom_udp4(suite) -> []; -to_recvfrom_udp4(doc) -> +api_to_recvfrom_udp4(doc) -> []; -to_recvfrom_udp4(_Config) when is_list(_Config) -> - tc_begin(to_recvfrom_udp4), - ok = to_recvfrom_udp(inet), +api_to_recvfrom_udp4(_Config) when is_list(_Config) -> + tc_begin(api_to_recvfrom_udp4), + ok = api_to_recvfrom_udp(inet), tc_end(). @@ -784,20 +784,20 @@ to_recvfrom_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvfrom timeout option %% on an IPv6 UDP (dgram) socket. -to_recvfrom_udp6(suite) -> +api_to_recvfrom_udp6(suite) -> []; -to_recvfrom_udp6(doc) -> +api_to_recvfrom_udp6(doc) -> []; -to_recvfrom_udp6(_Config) when is_list(_Config) -> - %% tc_begin(to_recvfrom_udp6), - %% ok = to_recvfrom_udp(inet6), +api_to_recvfrom_udp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recvfrom_udp6), + %% ok = api_to_recvfrom_udp(inet6), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_recvfrom_udp(Domain) -> +api_to_recvfrom_udp(Domain) -> process_flag(trap_exit, true), p("init"), LocalAddr = which_local_addr(Domain), @@ -823,14 +823,14 @@ to_recvfrom_udp(Domain) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv4 UDP (dgram) socket. -to_recvmsg_udp4(suite) -> +api_to_recvmsg_udp4(suite) -> []; -to_recvmsg_udp4(doc) -> +api_to_recvmsg_udp4(doc) -> []; -to_recvmsg_udp4(_Config) when is_list(_Config) -> +api_to_recvmsg_udp4(_Config) when is_list(_Config) -> %% not_yet_implemented(). - tc_begin(to_recvmsg_udp4), - ok = to_recvmsg_udp(inet), + tc_begin(api_to_recvmsg_udp4), + ok = api_to_recvmsg_udp(inet), tc_end(). @@ -838,20 +838,20 @@ to_recvmsg_udp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv6 UDP (dgram) socket. -to_recvmsg_udp6(suite) -> +api_to_recvmsg_udp6(suite) -> []; -to_recvmsg_udp6(doc) -> +api_to_recvmsg_udp6(doc) -> []; -to_recvmsg_udp6(_Config) when is_list(_Config) -> - %% tc_begin(to_recvmsg_udp6), - %% ok = to_recvmsg_udp(inet6), +api_to_recvmsg_udp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recvmsg_udp6), + %% ok = api_to_recvmsg_udp(inet6), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_recvmsg_udp(Domain) -> +api_to_recvmsg_udp(Domain) -> process_flag(trap_exit, true), p("init"), LocalAddr = which_local_addr(Domain), @@ -877,13 +877,13 @@ to_recvmsg_udp(Domain) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv4 TCP (stream) socket. -to_recvmsg_tcp4(suite) -> +api_to_recvmsg_tcp4(suite) -> []; -to_recvmsg_tcp4(doc) -> +api_to_recvmsg_tcp4(doc) -> []; -to_recvmsg_tcp4(_Config) when is_list(_Config) -> - tc_begin(to_recvmsg_tcp4), - ok = to_recvmsg_tcp(inet), +api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> + tc_begin(api_to_recvmsg_tcp4), + ok = api_to_recvmsg_tcp(inet), tc_end(). %% not_yet_implemented(). @@ -892,20 +892,20 @@ to_recvmsg_tcp4(_Config) when is_list(_Config) -> %% This test case is intended to test the recvmsg timeout option %% on an IPv6 TCP (stream) socket. -to_recvmsg_tcp6(suite) -> +api_to_recvmsg_tcp6(suite) -> []; -to_recvmsg_tcp6(doc) -> +api_to_recvmsg_tcp6(doc) -> []; -to_recvmsg_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(to_recvmsg_tcp6), - %% ok = to_recvmsg_tcp(inet6), +api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> + %% tc_begin(api_to_recvmsg_tcp6), + %% ok = api_to_recvmsg_tcp(inet6), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -to_recvmsg_tcp(Domain) -> +api_to_recvmsg_tcp(Domain) -> process_flag(trap_exit, true), p("server -> open"), LSock = sock_open(Domain, stream, tcp), -- cgit v1.2.3 From 1c412c62ba3be17b7a818f264049a7ee7942351e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 28 Sep 2018 18:40:08 +0200 Subject: [socket-nif] Add support for socket (level otp) buffer options Add support for otp level socket options rcvbuf, rcvctrlbuf and sndctrlbuf. These options define default sizes for these buffers. The 'rcvbuf' is used when receiving messages when calling the recv, recvfrom and recvmsg functions. The 'rcvctrlbuf' is used for the control message header info when calling the recvmsg function. The 'sndctrlbuf' is used for the control message header info when calling the sendmsg function. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 112 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 0255c8ef75..d4cd144168 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -38,6 +38,9 @@ api_b_send_and_recv_tcp4/1, api_b_sendmsg_and_recvmsg_tcp4/1, + %% API Options + api_opt_simple_otp_options/1, + %% API Operation Timeout api_to_connect_tcp4/1, api_to_connect_tcp6/1, @@ -90,13 +93,15 @@ all() -> groups() -> [{api, [], api_cases()}, {api_basic, [], api_basic_cases()}, - {api_op_with_timeout, [], api_op_with_timeout_cases()} + {api_op_with_timeout, [], api_op_with_timeout_cases()}, + {api_options, [], api_options_cases()} %% {tickets, [], ticket_cases()} ]. api_cases() -> [ {group, api_basic}, + {group, api_options}, {group, api_op_with_timeout} ]. @@ -110,6 +115,11 @@ api_basic_cases() -> api_b_sendmsg_and_recvmsg_tcp4 ]. +api_options_cases() -> + [ + api_opt_simple_otp_options + ]. + api_op_with_timeout_cases() -> [ api_to_connect_tcp4, @@ -431,6 +441,92 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Perform some simple getopt and setopt with the level = otp options +api_opt_simple_otp_options(suite) -> + []; +api_opt_simple_otp_options(doc) -> + []; +api_opt_simple_otp_options(_Config) when is_list(_Config) -> + tc_begin(api_opt_simple_otp_options), + + p("Create sockets"), + S1 = sock_open(inet, stream, tcp), + S2 = sock_open(inet, dgram, udp), + + Get = fun(S, Key) -> + socket:getopt(S, otp, Key) + end, + Set = fun(S, Key, Val) -> + socket:setopt(S, otp, Key, Val) + end, + + p("Create dummy process"), + Pid = spawn_link(fun() -> + receive + die -> + exit(normal) + end + end), + + F = fun(Sock) -> + p("Test IOW"), + {ok, IOW} = Get(Sock, iow), + NotIOW = not IOW, + ok = Set(Sock, iow, NotIOW), + {ok, NotIOW} = Get(Sock, iow), + + p("Test rcvbuf"), + {ok, RcvBuf} = Get(Sock, rcvbuf), + RcvBuf2 = RcvBuf*2, + ok = Set(Sock, rcvbuf, RcvBuf2), + {ok, RcvBuf2} = Get(Sock, rcvbuf), + ok = Set(Sock, rcvbuf, default), + {ok, RcvBuf} = Get(Sock, rcvbuf), + + p("Test rcvctrlbuf"), + {ok, RcvCtrlBuf} = Get(Sock, rcvctrlbuf), + RcvCtrlBuf2 = RcvCtrlBuf*2, + ok = Set(Sock, rcvctrlbuf, RcvCtrlBuf2), + {ok, RcvCtrlBuf2} = Get(Sock, rcvctrlbuf), + ok = Set(Sock, rcvctrlbuf, default), + {ok, RcvCtrlBuf} = Get(Sock, rcvctrlbuf), + + p("Test sndctrlbuf"), + {ok, SndCtrlBuf} = Get(Sock, sndctrlbuf), + SndCtrlBuf2 = SndCtrlBuf*2, + ok = Set(Sock, sndctrlbuf, SndCtrlBuf2), + {ok, SndCtrlBuf2} = Get(Sock, sndctrlbuf), + ok = Set(Sock, sndctrlbuf, default), + {ok, RcvCtrlBuf} = Get(Sock, sndctrlbuf), + + p("Test controlling-process"), + Self = self(), + {ok, Self} = Get(Sock, controlling_process), + ok = Set(Sock, controlling_process, Pid), + {ok, Pid} = Get(Sock, controlling_process) + + end, + + p("Test stream/tcp "), + F(S1), + + p("Test dgram/udp "), + F(S2), + + p("kill dummy process"), + %% This will also close its sockets (S1 and S2), + %% This should really be tested explicitly... + Pid ! die, + + %% p("close sockets"), + %% sock_close(S1), + %% sock_close(S2), + + tc_end(). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the connect timeout option @@ -1067,6 +1163,20 @@ sock_accept(LSock) -> end. +sock_close(Sock) -> + try socket:close(Sock) of + ok -> + ok; + {error, Reason} -> + p("sock_close -> error: ~p", [Reason]), + ?FAIL({close, Reason}) + catch + C:E:S -> + p("sock_close -> failed: ~p, ~p, ~p", [C, E, S]), + ?FAIL({close, C, E, S}) + end. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From e698436942c7aaf4f2872c19df2555275be169d1 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Oct 2018 12:03:35 +0200 Subject: [socket-nif|test] Updated test case for connect timeout The connect timeout test case uses the listen backlog argument to test connect timeout (its set to 1). The idea is that when the server backlog is full, it should not reply. The client attempting to connect will then get a timeout. But as it turns out, this behaviour is not "set in stone". On FreeBSD 11.2, the result is instead a 'econnreset'. It should also be noted that this local connections. That is, both end of the connection is on the same machine. So, test case has been updated to also accept a econnreset (even though that is not what it is testing). OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index d4cd144168..f3a7d84e81 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -203,7 +203,15 @@ api_b_open_and_close(Domain, Type, Proto) -> {error, Reason} -> ?FAIL({open, Reason}) end, - {ok, Domain} = socket:getopt(Socket, socket, domain), + %% Domain is not available on all platforms: + case socket:getopt(Socket, socket, domain) of + {ok, Domain} -> + ok; + {error, einval} -> + ok; + Else -> + ?FAIL({getopt, domain, Else}) + end, {ok, Type} = socket:getopt(Socket, socket, type), {ok, Proto} = socket:getopt(Socket, socket, protocol), Self = self(), @@ -558,6 +566,11 @@ api_to_connect_tcp6(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% We use the backlog (listen) argument to test this. +%% Note that the behaviour of the TCP "server side" can vary when +%% a client connect to a "busy" server (full backlog). +%% For instance, on FreeBSD (11.2) the reponse when the backlog is full +%% is a econreset. api_to_connect_tcp(Domain) -> process_flag(trap_exit, true), @@ -621,6 +634,9 @@ api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> {error, timeout} -> p("expected timeout (~w)", [ID]), ok; + {error, econnreset = Reason} -> + p("failed connecting: ~p - giving up", [Reason]), + ok; {error, Reason} -> p("failed connecting: ~p", [Reason]), ?FAIL({recv, Reason}); -- cgit v1.2.3 From 8daa980d92a17e7bb948971b2048c7758e5dd2e6 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Oct 2018 14:54:07 +0200 Subject: [socket-nif|test] Add controlling_process test case Added a test case that specifically tested setting the controlling_process. Also, ensure that invalid updates of controlling-process (not owner) actually fails. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 150 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 6 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index d4cd144168..95b58892c1 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -40,6 +40,7 @@ %% API Options api_opt_simple_otp_options/1, + api_opt_simple_otp_controlling_process/1, %% API Operation Timeout api_to_connect_tcp4/1, @@ -117,7 +118,8 @@ api_basic_cases() -> api_options_cases() -> [ - api_opt_simple_otp_options + api_opt_simple_otp_options, + api_opt_simple_otp_controlling_process ]. api_op_with_timeout_cases() -> @@ -338,6 +340,7 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) -> LSA = #{family => Domain, addr => LAddr}, Starter = self(), ServerFun = fun() -> + put(sname, "server"), %% Create the listen socket ServerLSock = case socket:open(Domain, stream, tcp) of @@ -454,7 +457,7 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> p("Create sockets"), S1 = sock_open(inet, stream, tcp), S2 = sock_open(inet, dgram, udp), - + Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -464,6 +467,7 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> p("Create dummy process"), Pid = spawn_link(fun() -> + put(sname, "dummy"), receive die -> exit(normal) @@ -527,6 +531,135 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> tc_end(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Perform some simple getopt and setopt with the level = otp options +api_opt_simple_otp_controlling_process(suite) -> + []; +api_opt_simple_otp_controlling_process(doc) -> + []; +api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> + tc_begin(api_opt_simple_otp_controlling_process), + + p("Create sockets"), + S1 = sock_open(inet, stream, tcp), + S2 = sock_open(inet, dgram, udp), + + Get = fun(S, Key) -> + socket:getopt(S, otp, Key) + end, + Set = fun(S, Key, Val) -> + socket:setopt(S, otp, Key, Val) + end, + + AwaitStart = + fun() -> + p("await start command"), + receive + {start, P, S} -> + {P, S} + end + end, + AwaitContinue = + fun(Pid) -> + p("await continue command"), + receive + {continue, Pid} -> + ok + end + end, + AwaitReady = + fun(Pid) -> + p("await ready confirmation from ~p", [Pid]), + receive + {ready, Pid} -> + ok + end + end, + AwaitDie = + fun(Pid) -> + p("await die command"), + receive + {die, Pid} -> + ok + end + end, + ClientStarter = + fun() -> + put(sname, "client"), + Self = self(), + {Parent, Sock} = AwaitStart(), + p("verify parent ~p controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("verify parent ~p (still) controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("announce ready"), + Parent ! {ready, self()}, + + AwaitContinue(Parent), + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("transfer control to parent ~p", [Parent]), + ok = Set(Sock, controlling_process, Parent), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("verify parent ~p controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("announce ready"), + Parent ! {ready, self()}, + + AwaitDie(Parent), + p("done"), + exit(normal) + end, + + Tester = + fun(Sock, Client) -> + p("start"), + Self = self(), + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("announce start"), + Client ! {start, Self, Sock}, + AwaitReady(Client), + + p("transfer control to client ~p", [Client]), + ok = Set(Sock, controlling_process, Client), + p("verify client ~p controlling", [Client]), + {ok, Client} = Get(Sock, controlling_process), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("announce continue"), + Client ! {continue, Self}, + AwaitReady(Client), + + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("announce die"), + Client ! {die, Self}, + p("done"), + ok + end, + + p("Create Worker Process(s)"), + Pid1 = spawn_link(ClientStarter), + Pid2 = spawn_link(ClientStarter), + + p("Test stream/tcp "), + Tester(S1, Pid1), + + p("Test dgram/udp "), + Tester(S2, Pid2), + + p("close sockets"), + sock_close(S1), + sock_close(S2), + + tc_end(). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the connect timeout option @@ -567,7 +700,7 @@ api_to_connect_tcp(Domain) -> LocalSA = #{family => Domain, addr => LocalAddr}, ServerName = f("~s:server", [get_tc_name()]), Server = spawn_link(fun() -> - set_tc_name(ServerName), + put(sname, ServerName), p("open"), LSock = sock_open(Domain, stream, tcp), p("bind"), @@ -826,7 +959,7 @@ api_to_recv_tcp(Domain) -> sock_listen(LSock), ClientName = f("~s:client", [get_tc_name()]), Client = spawn_link(fun() -> - set_tc_name(ClientName), + put(sname, ClientName), p("open"), CSock = sock_open(Domain, stream, tcp), p("bind"), @@ -1013,7 +1146,7 @@ api_to_recvmsg_tcp(Domain) -> sock_listen(LSock), ClientName = f("~s:client", [get_tc_name()]), Client = spawn_link(fun() -> - set_tc_name(ClientName), + put(sname, ClientName), p("open"), CSock = sock_open(Domain, stream, tcp), p("bind"), @@ -1215,7 +1348,12 @@ p(F, A) -> TcName = case get(tc_name) of undefined -> - ""; + case get(sname) of + undefined -> + ""; + SName when is_list(SName) -> + SName + end; Name when is_list(Name) -> Name end, -- cgit v1.2.3 From b98a1e312db1393aa5dd9cdd2e1a5f3daaf954bf Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 4 Oct 2018 18:16:38 +0200 Subject: [socket-nif|test] begin rework socket suite Begin rework socket test suite using a command evaluator. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 222 ++++++++++++++++++++++++++++++++++----- 1 file changed, 198 insertions(+), 24 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 1fff17cf8c..70810f5f3d 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -71,6 +71,17 @@ %% -export([]). +-type evaluator_state() :: term(). +-type command_fun() :: + fun((State :: evaluator_state()) -> ok) | + fun((State :: evaluator_state()) -> {ok, evaluator_state()}) | + fun((State :: evaluator_state()) -> {error, term()}). + +-type command() :: #{desc := string(), + cmd := command_fun() + }. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(BASIC_REQ, <<"hejsan">>). @@ -178,7 +189,10 @@ api_b_open_and_close_udp4(doc) -> []; api_b_open_and_close_udp4(_Config) when is_list(_Config) -> tc_begin(api_b_open_and_close_udp4), - ok = api_b_open_and_close(inet, dgram, udp), + State = #{domain => inet, + type => dgram, + protocol => udp}, + ok = api_b_open_and_close(State), tc_end(). @@ -192,34 +206,103 @@ api_b_open_and_close_tcp4(doc) -> []; api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> tc_begin(api_b_open_and_close_tcp4), - ok = api_b_open_and_close(inet, stream, tcp), + State = #{domain => inet, + type => stream, + protocol => tcp}, + ok = api_b_open_and_close(State), tc_end(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_b_open_and_close(Domain, Type, Proto) -> - Socket = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, Reason} -> - ?FAIL({open, Reason}) - end, - %% Domain is not available on all platforms: - case socket:getopt(Socket, socket, domain) of - {ok, Domain} -> - ok; - {error, einval} -> - ok; - Else -> - ?FAIL({getopt, domain, Else}) - end, - {ok, Type} = socket:getopt(Socket, socket, type), - {ok, Proto} = socket:getopt(Socket, socket, protocol), - Self = self(), - {ok, Self} = socket:getopt(Socket, otp, controlling_process), - ok = socket:close(Socket), - ok. +api_b_open_and_close(InitState) -> + Seq = + [ + #{desc => "open", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Protocol} = S) -> + Res = socket:open(Domain, Type, Protocol), + {ok, {S, Res}} + end}, + #{desc => "validate open", + cmd => fun({S, {ok, Sock}}) -> + NewS = S#{socket => Sock}, + {ok, NewS}; + ({_, {error, _} = ERROR}) -> + ERROR + end}, + #{desc => "get domain (maybe)", + cmd => fun(#{socket := Sock} = S) -> + Res = socket:getopt(Sock, socket, domain), + {ok, {S, Res}} + end}, + #{desc => "validate domain (maybe)", + cmd => fun({#{domain := Domain} = S, {ok, Domain}}) -> + {ok, S}; + ({#{domain := ExpDomain}, {ok, Domain}}) -> + {error, {unexpected_domain, ExpDomain, Domain}}; + %% Some platforms do not support this option + ({S, {error, einval}}) -> + {ok, S}; + ({_, {error, _} = ERROR}) -> + ERROR + end}, + #{desc => "get type", + cmd => fun(#{socket := Sock} = State) -> + Res = socket:getopt(Sock, socket, type), + {ok, {State, Res}} + end}, + #{desc => "validate type", + cmd => fun({#{type := Type} = State, {ok, Type}}) -> + {ok, State}; + ({#{type := ExpType}, {ok, Type}}) -> + {error, {unexpected_type, ExpType, Type}}; + ({_, {error, _} = ERROR}) -> + ERROR + end}, + #{desc => "get protocol", + cmd => fun(#{socket := Sock} = State) -> + Res = socket:getopt(Sock, socket, protocol), + {ok, {State, Res}} + end}, + #{desc => "validate protocol", + cmd => fun({#{protocol := Protocol} = State, {ok, Protocol}}) -> + {ok, State}; + ({#{protocol := ExpProtocol}, {ok, Protocol}}) -> + {error, {unexpected_type, ExpProtocol, Protocol}}; + ({_, {error, _} = ERROR}) -> + ERROR + end}, + #{desc => "get controlling-process", + cmd => fun(#{socket := Sock} = State) -> + Res = socket:getopt(Sock, otp, controlling_process), + {ok, {State, Res}} + end}, + #{desc => "validate controlling-process", + cmd => fun({State, {ok, Pid}}) -> + case self() of + Pid -> + {ok, State}; + _ -> + {error, {unexpected_owner, Pid}} + end; + ({_, {error, _} = ERROR}) -> + ERROR + end}, + #{desc => "close socket", + cmd => fun(#{socket := Sock} = State) -> + Res = socket:close(Sock), + {ok, {State, Res}} + end}, + #{desc => "validate socket close", + cmd => fun({_, ok}) -> + {ok, normal}; + ({_, {error, _} = ERROR}) -> + ERROR + end}], + Evaluator = evaluator_start("tester", Seq, InitState), + ok = await_evaluator_finish([Evaluator]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1230,6 +1313,97 @@ which_addr2(Domain, [_|IFO]) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% An evaluator is a process that executes a command sequence. +%% A test case will consist of atleast one evaluator (one for +%% each actor). +%% The evaluator process *always* run locally. Which means that +%% it will act as a "proxy" for remote nodes in necessary. +%% When the command sequence has been processed, the final state +%% will be used as exit reason. +%% A successful command shall evaluate to ok | {ok, NewState} + +-spec evaluator_start(Name, Seq, Init) -> {Pid, MRef} when + Name :: string(), + Seq :: [command()], + Init :: evaluator_state(), + Pid :: pid(), + MRef :: reference(). + +evaluator_start(Name, Seq, Init) + when is_list(Name) andalso is_list(Seq) andalso (Seq =/= []) -> + erlang:spawn_monitor(fun() -> evaluator_init(Name, Seq, Init) end). + +evaluator_init(Name, Seq, Init) -> + put(sname, Name), + evaluator_loop(1, Seq, Init). + +evaluator_loop(_ID, [], FinalState) -> + exit(FinalState); +evaluator_loop(ID, [#{desc := Desc, + cmd := Cmd}|Cmds], State) when is_function(Cmd, 1) -> + ei("evaluate command ~2w: ~s", [ID, Desc]), + try Cmd(State) of + ok -> + evaluator_loop(ID + 1, Cmds, State); + {ok, NewState} -> + evaluator_loop(ID + 1, Cmds, NewState); + {error, Reason} -> + ee("command ~w failed: " + "~n Reason: ~p", [ID, Reason]), + exit({command_failed, ID, Reason, State}) + catch + C:E:S -> + ee("command ~w crashed: " + "~n Class: ~p" + "~n Error: ~p" + "~n Call Stack: ~p", [ID, C, E, S]), + exit({command_crashed, ID, {C,E,S}, State}) + end. + +await_evaluator_finish(Evs) -> + await_evaluator_finish(Evs, []). + +await_evaluator_finish([], []) -> + ok; +await_evaluator_finish([], Fails) -> + Fails; +await_evaluator_finish(Evs, Fails) -> + receive + {'DOWN', _MRef, process, Pid, normal} -> + case lists:keydelete(Pid, 1, Evs) of + Evs -> + p("unknown process ~p died (normal)", [Pid]), + await_evaluator_finish(Evs, Fails); + NewEvs -> + p("evaluator ~p success", [Pid]), + await_evaluator_finish(NewEvs, Fails) + end; + {'DOWN', _MRef, process, Pid, Reason} -> + case lists:keydelete(Pid, 1, Evs) of + Evs -> + p("unknown process ~p died: " + "~n ~p", [Pid, Reason]), + await_evaluator_finish(Evs, Fails); + NewEvs -> + p("Evaluator ~p failed", [Pid]), + await_evaluator_finish(NewEvs, [{Pid, Reason}|Fails]) + end + end. + + +ei(F, A) -> + eprint("", F, A). + +ee(F, A) -> + eprint(" ", F, A). + +eprint(Prefix, F, A) -> + io:format(user, "[~s][~p] ~s" ++ F ++ "~n", [get(sname), self(), Prefix | A]). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% sock_open(Domain, Type, Proto) -> -- cgit v1.2.3 From 8210ffc460a0bfab8b3007afe3e1141c1bb9dec6 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 5 Oct 2018 11:07:55 +0200 Subject: [socket-nif|test] Two more test cases (udp) reworked Two test cases where reworked using the command evaluator. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 111 +++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 17 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 70810f5f3d..ed5722f008 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -305,6 +305,7 @@ api_b_open_and_close(InitState) -> ok = await_evaluator_finish([Evaluator]). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically send and receive on an IPv4 UDP (dgram) socket using @@ -321,7 +322,10 @@ api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> Recv = fun(Sock) -> socket:recvfrom(Sock) end, - ok = api_b_send_and_recv_udp(inet, Send, Recv), + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_udp(InitState), tc_end(). @@ -352,27 +356,100 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> ERROR end end, - ok = api_b_send_and_recv_udp(inet, Send, Recv), + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_udp(InitState), tc_end(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_b_send_and_recv_udp(Domain, Send, Recv) -> - SockSrc = sock_open(Domain, dgram, udp), - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - sock_bind(SockSrc, LSA), - SockDst = sock_open(Domain, dgram, udp), - sock_bind(SockDst, LSA), - Dst = sock_sockname(SockDst), - ok = Send(SockSrc, ?BASIC_REQ, Dst), - {ok, {Src, ?BASIC_REQ}} = Recv(SockDst), - ok = Send(SockDst, ?BASIC_REP, Src), - {ok, {Dst, ?BASIC_REP}} = Recv(SockSrc), - socket:close(SockSrc), - socket:close(SockDst), - ok. +api_b_send_and_recv_udp(InitState) -> + %% SockSrc = sock_open(Domain, dgram, udp), + %% LAddr = which_local_addr(Domain), + %% LSA = #{family => Domain, addr => LAddr}, + %% sock_bind(SockSrc, LSA), + %% SockDst = sock_open(Domain, dgram, udp), + %% sock_bind(SockDst, LSA), + %% Dst = sock_sockname(SockDst), + %% ok = Send(SockSrc, ?BASIC_REQ, Dst), + %% {ok, {Src, ?BASIC_REQ}} = Recv(SockDst), + %% ok = Send(SockDst, ?BASIC_REP, Src), + %% {ok, {Dst, ?BASIC_REP}} = Recv(SockSrc), + %% socket:close(SockSrc), + %% socket:close(SockDst), + Seq = + [ + #{desc => "local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "open src socket", + cmd => fun(#{domain := Domain} = State) -> + Sock = sock_open(Domain, dgram, udp), + SASrc = sock_sockname(Sock), + {ok, State#{sock_src => Sock, sa_src => SASrc}} + end}, + #{desc => "bind src", + cmd => fun(#{sock_src := Sock, lsa := LSA}) -> + sock_bind(Sock, LSA), + ok + end}, + #{desc => "sockname src socket", + cmd => fun(#{sock_src := Sock} = State) -> + SASrc = sock_sockname(Sock), + %% ei("src sockaddr: ~p", [SASrc]), + {ok, State#{sa_src => SASrc}} + end}, + #{desc => "open dst socket", + cmd => fun(#{domain := Domain} = State) -> + Sock = sock_open(Domain, dgram, udp), + {ok, State#{sock_dst => Sock}} + end}, + #{desc => "bind dst", + cmd => fun(#{sock_dst := Sock, lsa := LSA}) -> + sock_bind(Sock, LSA), + ok + end}, + #{desc => "sockname dst socket", + cmd => fun(#{sock_dst := Sock} = State) -> + SADst = sock_sockname(Sock), + %% ei("dst sockaddr: ~p", [SADst]), + {ok, State#{sa_dst => SADst}} + end}, + #{desc => "send req (to dst)", + cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> + ok = Send(Sock, ?BASIC_REQ, Dst) + end}, + #{desc => "recv req (from src)", + cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv} = State) -> + {ok, {Src, ?BASIC_REQ}} = Recv(Sock), + ok + end}, + #{desc => "send rep (to src)", + cmd => fun(#{sock_dst := Sock, sa_src := Src, send := Send}) -> + ok = Send(Sock, ?BASIC_REP, Src) + end}, + #{desc => "recv rep (from dst)", + cmd => fun(#{sock_src := Sock, sa_dst := Dst, recv := Recv}) -> + {ok, {Dst, ?BASIC_REP}} = Recv(Sock), + ok + end}, + #{desc => "close src socket", + cmd => fun(#{sock_src := Sock}) -> + ok = socket:close(Sock) + end}, + #{desc => "close dst socket", + cmd => fun(#{sock_dst := Sock}) -> + ok = socket:close(Sock), + {ok, normal} + end} + ], + Evaluator = evaluator_start("tester", Seq, InitState), + ok = await_evaluator_finish([Evaluator]). -- cgit v1.2.3 From d4cedb9fa86db720cc247b9201d5c7e1e8aab461 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 5 Oct 2018 14:23:47 +0200 Subject: [socket-nif|test] Two more test cases (tcp) reworked Two (tcp) test cases where reworked using the command evaluator. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 288 ++++++++++++++++++++++----------------- 1 file changed, 160 insertions(+), 128 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index ed5722f008..e50daaf367 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -71,6 +71,7 @@ %% -export([]). +-type initial_evaluator_state() :: map(). -type evaluator_state() :: term(). -type command_fun() :: fun((State :: evaluator_state()) -> ok) | @@ -78,8 +79,7 @@ fun((State :: evaluator_state()) -> {error, term()}). -type command() :: #{desc := string(), - cmd := command_fun() - }. + cmd := command_fun()}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -89,6 +89,8 @@ -define(FAIL(R), exit(R)). +-define(SLEEP(T), receive after T -> ok end). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -366,19 +368,6 @@ api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% api_b_send_and_recv_udp(InitState) -> - %% SockSrc = sock_open(Domain, dgram, udp), - %% LAddr = which_local_addr(Domain), - %% LSA = #{family => Domain, addr => LAddr}, - %% sock_bind(SockSrc, LSA), - %% SockDst = sock_open(Domain, dgram, udp), - %% sock_bind(SockDst, LSA), - %% Dst = sock_sockname(SockDst), - %% ok = Send(SockSrc, ?BASIC_REQ, Dst), - %% {ok, {Src, ?BASIC_REQ}} = Recv(SockDst), - %% ok = Send(SockDst, ?BASIC_REP, Src), - %% {ok, {Dst, ?BASIC_REP}} = Recv(SockSrc), - %% socket:close(SockSrc), - %% socket:close(SockDst), Seq = [ #{desc => "local address", @@ -425,7 +414,7 @@ api_b_send_and_recv_udp(InitState) -> ok = Send(Sock, ?BASIC_REQ, Dst) end}, #{desc => "recv req (from src)", - cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv} = State) -> + cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> {ok, {Src, ?BASIC_REQ}} = Recv(Sock), ok end}, @@ -469,7 +458,10 @@ api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> Recv = fun(Sock) -> socket:recv(Sock) end, - ok = api_b_send_and_recv_tcp(inet, Send, Recv), + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_tcp(InitState), tc_end(). @@ -496,119 +488,157 @@ api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> ERROR end end, - ok = api_b_send_and_recv_tcp(inet, Send, Recv), + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_tcp(InitState), tc_end(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_b_send_and_recv_tcp(Domain, Send, Recv) -> +api_b_send_and_recv_tcp(InitState) -> process_flag(trap_exit, true), - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - Starter = self(), - ServerFun = fun() -> - put(sname, "server"), - %% Create the listen socket - ServerLSock = - case socket:open(Domain, stream, tcp) of - {ok, S1} -> - S1; - {error, ServerOR} -> - ?FAIL({server, open, ServerOR}) - end, - %% And bind it to the local address - SP = - case socket:bind(ServerLSock, LSA) of - {ok, P} -> - P; - {error, ServerBR} -> - ?FAIL({server, bind, ServerBR}) - end, - %% Listen for connecting clients - case socket:listen(ServerLSock) of - ok -> - ok; - {error, ServerLR} -> - ?FAIL({server, listen, ServerLR}) - end, - %% We are ready - Starter ! {self(), {ok, SP}}, - %% Accept connections - ServerSock = - case socket:accept(ServerLSock) of - {ok, Sock} -> - Sock; - {error, ServerAR} -> - ?FAIL({server, accept, ServerAR}) - end, - %% Wait for a message - case Recv(ServerSock) of - {ok, ?BASIC_REQ} -> - ok; - {error, ServerRR} -> - ?FAIL({server, recv, ServerRR}) - end, - %% Send the reply - case Send(ServerSock, ?BASIC_REP) of - ok -> - ok; - {error, ServerSR} -> - ?FAIL({server, send, ServerSR}) - end, - %% Close the sockets - socket:close(ServerSock), - socket:close(ServerLSock), - %% We are done - exit(normal) - end, - Server = spawn_link(ServerFun), - ServerPort = - receive - {Server, {ok, P}} -> - P; - {'EXIT', Server, ServerStartReason} -> - ?FAIL({server, start, ServerStartReason}) - end, - ClientSock = - case socket:open(Domain, stream, tcp) of - {ok, S2} -> - S2; - {error, ClientOR} -> - ?FAIL({client, open, ClientOR}) - end, - case socket:bind(ClientSock, LSA) of - {ok, _} -> - ok; - {error, ClientBR} -> - ?FAIL({client, bind, ClientBR}) - end, - case socket:connect(ClientSock, LSA#{port => ServerPort}) of - ok -> - ok; - {error, ClientCR} -> - ?FAIL({client, connect, ClientCR}) - end, - case Send(ClientSock, ?BASIC_REQ) of - ok -> - ok; - {error, ClientSR} -> - ?FAIL({client, send, ClientSR}) - end, - case Recv(ClientSock) of - {ok, ?BASIC_REP} -> - ok; - {ok, Msg} -> - ?FAIL({client, recv, {unexpected, Msg}}) - end, - receive - {'EXIT', Server, normal} -> - ok; - {'EXIT', Server, ServerStopReason} -> - ?FAIL({server, stop, ServerStopReason}) - end, - socket:close(ClientSock), - ok. + ServerSeq = + [ + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create listen socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> + case socket:bind(LSock, LSA) of + {ok, Port} -> + {ok, State#{lport => Port}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock) + end}, + #{desc => "announce server port", + cmd => fun(#{parent := Parent, lport := Port}) -> + ei("announcing port to parent (~p)", [Parent]), + Parent ! {server_port, self(), Port}, + ok + end}, + #{desc => "await connection", + cmd => fun(#{lsock := LSock} = State) -> + case socket:accept(LSock) of + {ok, Sock} -> + ei("accepted: ~p", [Sock]), + {ok, State#{tsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "await request", + cmd => fun(#{tsock := Sock, recv := Recv}) -> + case Recv(Sock) of + {ok, ?BASIC_REQ} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "send reply", + cmd => fun(#{tsock := Sock, send := Send}) -> + Send(Sock, ?BASIC_REP) + end}, + #{desc => "sleep some", + cmd => fun(_) -> + ?SLEEP(1000), + ok + end}, + #{desc => "close traffic socket", + cmd => fun(#{tsock := Sock}) -> + socket:close(Sock) + end}, + #{desc => "close listen socket", + cmd => fun(#{lsock := Sock}) -> + socket:close(Sock) + end}, + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + ClientSeq = + [ + #{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}, + {ok, State#{lsa => LSA, ssa => SSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := Sock, lsa := LSA} = State) -> + case socket:bind(Sock, LSA) of + {ok, Port} -> + {ok, State#{port => Port}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "connect to server", + cmd => fun(#{sock := Sock, ssa := SSA}) -> + socket:connect(Sock, SSA) + end}, + #{desc => "send request (to server)", + cmd => fun(#{sock := Sock, send := Send}) -> + Send(Sock, ?BASIC_REQ) + end}, + #{desc => "recv reply (from server)", + cmd => fun(#{sock := Sock, recv := Recv}) -> + {ok, ?BASIC_REP} = Recv(Sock), + ok + end}, + #{desc => "close socket", + cmd => fun(#{sock := Sock}) -> + socket:close(Sock) + end}, + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("start server evaluator"), + Server = evaluator_start("server", ServerSeq, InitState), + p("await server (~p) port", [Server]), + SPort = receive + {server_port, Server, Port} -> + Port + end, + p("start client evaluator"), + Client = evaluator_start("client", ClientSeq, InitState#{server_port => SPort}), + p("await evaluator(s)"), + ok = await_evaluator_finish([Server, Client]). @@ -1404,13 +1434,15 @@ which_addr2(Domain, [_|IFO]) -> -spec evaluator_start(Name, Seq, Init) -> {Pid, MRef} when Name :: string(), Seq :: [command()], - Init :: evaluator_state(), + Init :: initial_evaluator_state(), Pid :: pid(), MRef :: reference(). evaluator_start(Name, Seq, Init) when is_list(Name) andalso is_list(Seq) andalso (Seq =/= []) -> - erlang:spawn_monitor(fun() -> evaluator_init(Name, Seq, Init) end). + Init2 = Init#{parent => self()}, + {Pid, _} = erlang:spawn_monitor(fun() -> evaluator_init(Name, Seq, Init2) end), + Pid. evaluator_init(Name, Seq, Init) -> put(sname, Name), @@ -1449,7 +1481,7 @@ await_evaluator_finish([], Fails) -> await_evaluator_finish(Evs, Fails) -> receive {'DOWN', _MRef, process, Pid, normal} -> - case lists:keydelete(Pid, 1, Evs) of + case lists:delete(Pid, Evs) of Evs -> p("unknown process ~p died (normal)", [Pid]), await_evaluator_finish(Evs, Fails); @@ -1458,7 +1490,7 @@ await_evaluator_finish(Evs, Fails) -> await_evaluator_finish(NewEvs, Fails) end; {'DOWN', _MRef, process, Pid, Reason} -> - case lists:keydelete(Pid, 1, Evs) of + case lists:delete(Pid, Evs) of Evs -> p("unknown process ~p died: " "~n ~p", [Pid, Reason]), -- cgit v1.2.3 From 2a10a95dc380b41deffa060e30c0c461dfc3df8d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 10 Oct 2018 17:59:55 +0200 Subject: [socket-nif|test] Reworked simple otp options test case --- lib/kernel/test/socket_SUITE.erl | 295 +++++++++++++++++++++++++++++++-------- 1 file changed, 234 insertions(+), 61 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index e50daaf367..a9f51cd11f 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -652,10 +652,6 @@ api_opt_simple_otp_options(doc) -> api_opt_simple_otp_options(_Config) when is_list(_Config) -> tc_begin(api_opt_simple_otp_options), - p("Create sockets"), - S1 = sock_open(inet, stream, tcp), - S2 = sock_open(inet, dgram, udp), - Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -663,68 +659,245 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> socket:setopt(S, otp, Key, Val) end, - p("Create dummy process"), - Pid = spawn_link(fun() -> - put(sname, "dummy"), - receive - die -> - exit(normal) - end - end), - - F = fun(Sock) -> - p("Test IOW"), - {ok, IOW} = Get(Sock, iow), - NotIOW = not IOW, - ok = Set(Sock, iow, NotIOW), - {ok, NotIOW} = Get(Sock, iow), - - p("Test rcvbuf"), - {ok, RcvBuf} = Get(Sock, rcvbuf), - RcvBuf2 = RcvBuf*2, - ok = Set(Sock, rcvbuf, RcvBuf2), - {ok, RcvBuf2} = Get(Sock, rcvbuf), - ok = Set(Sock, rcvbuf, default), - {ok, RcvBuf} = Get(Sock, rcvbuf), - - p("Test rcvctrlbuf"), - {ok, RcvCtrlBuf} = Get(Sock, rcvctrlbuf), - RcvCtrlBuf2 = RcvCtrlBuf*2, - ok = Set(Sock, rcvctrlbuf, RcvCtrlBuf2), - {ok, RcvCtrlBuf2} = Get(Sock, rcvctrlbuf), - ok = Set(Sock, rcvctrlbuf, default), - {ok, RcvCtrlBuf} = Get(Sock, rcvctrlbuf), - - p("Test sndctrlbuf"), - {ok, SndCtrlBuf} = Get(Sock, sndctrlbuf), - SndCtrlBuf2 = SndCtrlBuf*2, - ok = Set(Sock, sndctrlbuf, SndCtrlBuf2), - {ok, SndCtrlBuf2} = Get(Sock, sndctrlbuf), - ok = Set(Sock, sndctrlbuf, default), - {ok, RcvCtrlBuf} = Get(Sock, sndctrlbuf), - - p("Test controlling-process"), - Self = self(), - {ok, Self} = Get(Sock, controlling_process), - ok = Set(Sock, controlling_process, Pid), - {ok, Pid} = Get(Sock, controlling_process) + Seq = + [ + %% *** Init part *** + #{desc => "create socket", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Protocol} = State) -> + Sock = sock_open(Domain, Type, Protocol), + {ok, State#{sock => Sock}} + end}, + #{desc => "create dummy process", + cmd => fun(State) -> + Pid = spawn_link(fun() -> + put(sname, "dummy"), + receive + die -> + exit(normal) + end + end), + {ok, State#{dummy => Pid}} + end}, - end, + %% *** Check iow part *** + #{desc => "get iow", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock, iow) of + {ok, IOW} when is_boolean(IOW) -> + {ok, State#{iow => IOW}}; + {ok, InvalidIOW} -> + {error, {invalid, InvalidIOW}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set (new) iow", + cmd => fun(#{sock := Sock, iow := OldIOW} = State) -> + NewIOW = not OldIOW, + case Set(Sock, iow, NewIOW) of + ok -> + {ok, State#{iow => NewIOW}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get (new) iow", + cmd => fun(#{sock := Sock, iow := IOW}) -> + case Get(Sock, iow) of + {ok, IOW} -> + ok; + {ok, InvalidIOW} -> + {error, {invalid, InvalidIOW}}; + {error, _} = ERROR -> + ERROR + end + end}, - p("Test stream/tcp "), - F(S1), + %% *** Check rcvbuf part *** + #{desc => "get rcvbuf", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock, rcvbuf) of + {ok, RcvBuf} when is_integer(RcvBuf) -> + {ok, State#{rcvbuf => RcvBuf}}; + {ok, InvalidRcvBuf} -> + {error, {invalid, InvalidRcvBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set (new) rcvbuf", + cmd => fun(#{sock := Sock, rcvbuf := OldRcvBuf} = State) -> + NewRcvBuf = 2 * OldRcvBuf, + case Set(Sock, rcvbuf, NewRcvBuf) of + ok -> + {ok, State#{rcvbuf => NewRcvBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get (new) rcvbuf", + cmd => fun(#{sock := Sock, rcvbuf := RcvBuf}) -> + case Get(Sock, rcvbuf) of + {ok, RcvBuf} -> + ok; + {ok, InvalidRcvBuf} -> + {error, {invalid, InvalidRcvBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, - p("Test dgram/udp "), - F(S2), + %% *** Check rcvctrlbuf part *** + #{desc => "get rcvctrlbuf", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock, rcvctrlbuf) of + {ok, RcvCtrlBuf} when is_integer(RcvCtrlBuf) -> + {ok, State#{rcvctrlbuf => RcvCtrlBuf}}; + {ok, InvalidRcvCtrlBuf} -> + {error, {invalid, InvalidRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set (new) rcvctrlbuf", + cmd => fun(#{sock := Sock, rcvctrlbuf := OldRcvCtrlBuf} = State) -> + NewRcvCtrlBuf = 2 * OldRcvCtrlBuf, + case Set(Sock, rcvctrlbuf, NewRcvCtrlBuf) of + ok -> + {ok, State#{rcvctrlbuf => NewRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get (new) rcvctrlbuf", + cmd => fun(#{sock := Sock, rcvctrlbuf := RcvCtrlBuf}) -> + case Get(Sock, rcvctrlbuf) of + {ok, RcvCtrlBuf} -> + ok; + {ok, InvalidRcvCtrlBuf} -> + {error, {invalid, InvalidRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + %% *** Check rcvctrlbuf part *** + #{desc => "get rcvctrlbuf", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock, rcvctrlbuf) of + {ok, RcvCtrlBuf} when is_integer(RcvCtrlBuf) -> + {ok, State#{rcvctrlbuf => RcvCtrlBuf}}; + {ok, InvalidRcvCtrlBuf} -> + {error, {invalid, InvalidRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set (new) rcvctrlbuf", + cmd => fun(#{sock := Sock, rcvctrlbuf := OldRcvCtrlBuf} = State) -> + NewRcvCtrlBuf = 2 * OldRcvCtrlBuf, + case Set(Sock, rcvctrlbuf, NewRcvCtrlBuf) of + ok -> + {ok, State#{rcvctrlbuf => NewRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get (new) rcvctrlbuf", + cmd => fun(#{sock := Sock, rcvctrlbuf := RcvCtrlBuf}) -> + case Get(Sock, rcvctrlbuf) of + {ok, RcvCtrlBuf} -> + ok; + {ok, InvalidRcvCtrlBuf} -> + {error, {invalid, InvalidRcvCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, - p("kill dummy process"), - %% This will also close its sockets (S1 and S2), - %% This should really be tested explicitly... - Pid ! die, - %% p("close sockets"), - %% sock_close(S1), - %% sock_close(S2), + %% *** Check sndctrlbuf part *** + #{desc => "get sndctrlbuf", + cmd => fun(#{sock := Sock} = State) -> + case Get(Sock, sndctrlbuf) of + {ok, SndCtrlBuf} when is_integer(SndCtrlBuf) -> + {ok, State#{sndctrlbuf => SndCtrlBuf}}; + {ok, InvalidSndCtrlBuf} -> + {error, {invalid, InvalidSndCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set (new) sndctrlbuf", + cmd => fun(#{sock := Sock, sndctrlbuf := OldSndCtrlBuf} = State) -> + NewSndCtrlBuf = 2 * OldSndCtrlBuf, + case Set(Sock, sndctrlbuf, NewSndCtrlBuf) of + ok -> + {ok, State#{sndctrlbuf => NewSndCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "get (new) sndctrlbuf", + cmd => fun(#{sock := Sock, sndctrlbuf := SndCtrlBuf}) -> + case Get(Sock, sndctrlbuf) of + {ok, SndCtrlBuf} -> + ok; + {ok, InvalidSndCtrlBuf} -> + {error, {invalid, InvalidSndCtrlBuf}}; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** Check controlling-process part *** + #{desc => "verify self as controlling-process", + cmd => fun(#{sock := Sock}) -> + Self = self(), + case Get(Sock, controlling_process) of + {ok, Self} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "set dummy as controlling-process", + cmd => fun(#{sock := Sock, dummy := Dummy}) -> + Set(Sock, controlling_process, Dummy) + end}, + #{desc => "verify dummy as controlling-process", + cmd => fun(#{sock := Sock, dummy := Dummy}) -> + case Get(Sock, controlling_process) of + {ok, Dummy} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("Run test for stream/tcp socket"), + InitState1 = #{domain => inet, type => stream, protocol => tcp}, + Tester1 = evaluator_start("tcp-tester", Seq, InitState1), + p("await evaluator 1"), + ok = await_evaluator_finish([Tester1]), + + p("Run test for dgram/udp socket"), + InitState2 = #{domain => inet, type => dgram, protocol => udp}, + Tester2 = evaluator_start("udp-tester", Seq, InitState2), + p("await evaluator 2"), + ok = await_evaluator_finish([Tester2]), tc_end(). -- cgit v1.2.3 From 8092cb3bb4e3a90be52df03fff211a2e29dc8784 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Wed, 10 Oct 2018 18:55:33 +0200 Subject: [socket-nif|test] Reworked otp controlling process option test case --- lib/kernel/test/socket_SUITE.erl | 327 +++++++++++++++++++++++++++------------ 1 file changed, 224 insertions(+), 103 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index a9f51cd11f..23a77f428c 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -912,10 +912,6 @@ api_opt_simple_otp_controlling_process(doc) -> api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> tc_begin(api_opt_simple_otp_controlling_process), - p("Create sockets"), - S1 = sock_open(inet, stream, tcp), - S2 = sock_open(inet, dgram, udp), - Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -923,110 +919,235 @@ api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> socket:setopt(S, otp, Key, Val) end, - AwaitStart = - fun() -> - p("await start command"), - receive - {start, P, S} -> - {P, S} - end - end, - AwaitContinue = - fun(Pid) -> - p("await continue command"), - receive - {continue, Pid} -> - ok - end - end, - AwaitReady = - fun(Pid) -> - p("await ready confirmation from ~p", [Pid]), - receive - {ready, Pid} -> - ok - end - end, - AwaitDie = - fun(Pid) -> - p("await die command"), - receive - {die, Pid} -> - ok - end - end, - ClientStarter = - fun() -> - put(sname, "client"), - Self = self(), - {Parent, Sock} = AwaitStart(), - p("verify parent ~p controlling", [Parent]), - {ok, Parent} = Get(Sock, controlling_process), - p("attempt invalid control transfer (to self)"), - {error, not_owner} = Set(Sock, controlling_process, self()), - p("verify parent ~p (still) controlling", [Parent]), - {ok, Parent} = Get(Sock, controlling_process), - p("announce ready"), - Parent ! {ready, self()}, - - AwaitContinue(Parent), - p("verify self controlling"), - {ok, Self} = Get(Sock, controlling_process), - p("transfer control to parent ~p", [Parent]), - ok = Set(Sock, controlling_process, Parent), - p("attempt invalid control transfer (to self)"), - {error, not_owner} = Set(Sock, controlling_process, self()), - p("verify parent ~p controlling", [Parent]), - {ok, Parent} = Get(Sock, controlling_process), - p("announce ready"), - Parent ! {ready, self()}, - - AwaitDie(Parent), - p("done"), - exit(normal) - end, + ClientSeq = + [ + %% *** Init part *** + #{desc => "await start", + cmd => fun(State) -> + receive + {start, Tester, Socket} -> + {ok, State#{tester => Tester, + sock => Socket}} + end + end}, + #{desc => "verify tester as controlling-process", + cmd => fun(#{tester := Tester, sock := Sock} = _State) -> + case Get(Sock, controlling_process) of + {ok, Tester} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "attempt invalid controlling-process transfer (to self)", + cmd => fun(#{sock := Sock} = _State) -> + case Set(Sock, controlling_process, self()) of + {error, not_owner} -> + ok; + ok -> + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (1)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "await continue", + cmd => fun(#{tester := Tester} = _State) -> + receive + {continue, Tester} -> + ok + end + end}, + #{desc => "verify self as controlling-process", + cmd => fun(#{sock := Sock} = _State) -> + Self = self(), + case Get(Sock, controlling_process) of + {ok, Self} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "attempt controlling-process transfer to tester", + cmd => fun(#{tester := Tester, sock := Sock} = _State) -> + Set(Sock, controlling_process, Tester) + end}, + #{desc => "attempt invalid controlling-process transfer (to self)", + cmd => fun(#{sock := Sock} = _State) -> + case Set(Sock, controlling_process, self()) of + {error, not_owner} -> + ok; + ok -> + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (2)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "await termination", + cmd => fun(#{tester := Tester} = State) -> + receive + {terminate, Tester} -> + State1 = maps:remove(tester, State), + State2 = maps:remove(sock, State1), + {ok, State2} + end + end}, - Tester = - fun(Sock, Client) -> - p("start"), - Self = self(), - p("verify self controlling"), - {ok, Self} = Get(Sock, controlling_process), - p("announce start"), - Client ! {start, Self, Sock}, - AwaitReady(Client), - - p("transfer control to client ~p", [Client]), - ok = Set(Sock, controlling_process, Client), - p("verify client ~p controlling", [Client]), - {ok, Client} = Get(Sock, controlling_process), - p("attempt invalid control transfer (to self)"), - {error, not_owner} = Set(Sock, controlling_process, self()), - p("announce continue"), - Client ! {continue, Self}, - AwaitReady(Client), - - p("verify self controlling"), - {ok, Self} = Get(Sock, controlling_process), - p("announce die"), - Client ! {die, Self}, - p("done"), - ok - end, + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], - p("Create Worker Process(s)"), - Pid1 = spawn_link(ClientStarter), - Pid2 = spawn_link(ClientStarter), + TesterSeq = + [ + %% *** Init part *** + #{desc => "create socket", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Protocol} = State) -> + Sock = sock_open(Domain, Type, Protocol), + {ok, State#{sock => Sock}} + end}, + #{desc => "verify self as controlling-process", + cmd => fun(#{sock := Sock} = _State) -> + Self = self(), + case Get(Sock, controlling_process) of + {ok, Self} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "order (client) start", + cmd => fun(#{client := Client, sock := Sock} = _State) -> + Client ! {start, self(), Sock}, + ok + end}, + #{desc => "await (client) ready (1)", + cmd => fun(#{client := Client} = _State) -> + receive + {ready, Client} -> + ok + end + end}, + #{desc => "attempt controlling-process transfer to client", + cmd => fun(#{client := Client, sock := Sock} = _State) -> + Set(Sock, controlling_process, Client) + end}, + #{desc => "verify client as controlling-process", + cmd => fun(#{client := Client, sock := Sock} = _State) -> + case Get(Sock, controlling_process) of + {ok, Client} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "attempt invalid controlling-process transfer (to self)", + cmd => fun(#{sock := Sock} = _State) -> + case Set(Sock, controlling_process, self()) of + {error, not_owner} -> + ok; + ok -> + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "order (client) continue", + cmd => fun(#{client := Client} = _State) -> + Client ! {continue, self()}, + ok + end}, + #{desc => "await (client) ready (2)", + cmd => fun(#{client := Client} = _State) -> + receive + {ready, Client} -> + ok + end + end}, + #{desc => "verify self as controlling-process", + cmd => fun(#{sock := Sock} = _State) -> + Self = self(), + case Get(Sock, controlling_process) of + {ok, Self} -> + ok; + {ok, InvalidPid} -> + {error, {invalid, InvalidPid}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "monitor client", + cmd => fun(#{client := Client} = State) -> + MRef = erlang:monitor(process, Client), + {ok, State#{client_mref => MRef}} + end}, + #{desc => "order (client) terminate", + cmd => fun(#{client := Client} = _State) -> + Client ! {terminate, self()}, + ok + end}, + #{desc => "await (client) down", + cmd => fun(#{client := Client} = State) -> + receive + {'DOWN', _, process, Client, _} -> + {ok, maps:remove(client, State)} + end + end}, + #{desc => "close socket", + cmd => fun(#{sock := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock, State)} + end}, - p("Test stream/tcp "), - Tester(S1, Pid1), + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], - p("Test dgram/udp "), - Tester(S2, Pid2), + p("Run test for stream/tcp socket"), + ClientInitState1 = #{}, + Client1 = evaluator_start("tcp-client", ClientSeq, ClientInitState1), + TesterInitState1 = #{domain => inet, + type => stream, + protocol => tcp, + client => Client1}, + Tester1 = evaluator_start("tcp-tester", TesterSeq, TesterInitState1), + p("await stream/tcp evaluator"), + ok = await_evaluator_finish([Tester1, Client1]), - p("close sockets"), - sock_close(S1), - sock_close(S2), + p("Run test for dgram/udp socket"), + ClientInitState2 = #{}, + Client2 = evaluator_start("udp-client", ClientSeq, ClientInitState2), + TesterInitState2 = #{domain => inet, + type => dgram, + protocol => udp, + client => Client2}, + Tester2 = evaluator_start("udp-tester", TesterSeq, TesterInitState2), + p("await dgram/udp evaluator"), + ok = await_evaluator_finish([Tester2, Client2]), tc_end(). -- cgit v1.2.3 From 3ccba221981a6ae61cb2b7222fe7ea56aa56a923 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 11 Oct 2018 12:06:41 +0200 Subject: [socket-nif|test] Reworked the connect timeout test case --- lib/kernel/test/socket_SUITE.erl | 281 +++++++++++++++++++++++++++++++-------- 1 file changed, 226 insertions(+), 55 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 23a77f428c..2d406458f0 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1162,7 +1162,8 @@ api_to_connect_tcp4(doc) -> []; api_to_connect_tcp4(_Config) when is_list(_Config) -> tc_begin(api_to_connect_tcp4), - ok = api_to_connect_tcp(inet), + InitState = #{domain => inet}, + ok = api_to_connect_tcp(InitState), tc_end(). %% not_yet_implemented(). @@ -1177,7 +1178,8 @@ api_to_connect_tcp6(doc) -> []; api_to_connect_tcp6(_Config) when is_list(_Config) -> %% tc_begin(api_to_connect_tcp6), - %% ok = api_to_connect_tcp(inet6), + %% InitState = #{domain => inet6}, + %% ok = api_to_connect_tcp(InitState), %% tc_end(). not_yet_implemented(). @@ -1189,54 +1191,223 @@ api_to_connect_tcp6(_Config) when is_list(_Config) -> %% For instance, on FreeBSD (11.2) the reponse when the backlog is full %% is a econreset. -api_to_connect_tcp(Domain) -> +api_to_connect_tcp(InitState) -> process_flag(trap_exit, true), - p("init"), - Client = self(), - LocalAddr = which_local_addr(Domain), - LocalSA = #{family => Domain, addr => LocalAddr}, - ServerName = f("~s:server", [get_tc_name()]), - Server = spawn_link(fun() -> - put(sname, ServerName), - p("open"), - LSock = sock_open(Domain, stream, tcp), - p("bind"), - ServerLPort = sock_bind(LSock, LocalSA), - p("listen on ~w", [ServerLPort]), - sock_listen(LSock, 1), - p("inform client"), - Client ! {self(), ServerLPort}, - p("await termination command"), - receive - die -> - p("terminating"), - exit(normal) - end - end), - - p("await server port"), - ServerLPort = - receive - {Server, Port} -> - Port - end, - p("open(s)"), - CSock1 = sock_open(Domain, stream, tcp), - CSock2 = sock_open(Domain, stream, tcp), - CSock3 = sock_open(Domain, stream, tcp), - p("bind(s)"), - _ClientPort1 = sock_bind(CSock1, LocalSA), - _ClientPort2 = sock_bind(CSock2, LocalSA), - _ClientPort3 = sock_bind(CSock3, LocalSA), - ServerSA = LocalSA#{port => ServerLPort}, - api_to_connect_tcp_await_timeout([CSock1, CSock2, CSock3], ServerSA), - p("terminate server"), - Server ! die, - receive - {'EXIT', Server, _} -> - p("server terminated"), - ok - end, + + ServerSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create listen socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> + case socket:bind(LSock, LSA) of + {ok, Port} -> + {ok, State#{lport => Port}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket (with backlog = 1)", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock, 1) + end}, + #{desc => "monitor server", + cmd => fun(#{tester := Tester} = State) -> + MRef = erlang:monitor(process, Tester), + {ok, State#{tester_mref => MRef}} + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester, lport := Port}) -> + ei("announcing ready to tester (~p)", [Tester]), + Tester ! {ready, self(), Port}, + ok + end}, + #{desc => "await terminate (from tester)", + cmd => fun(#{tester := Tester}) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_tester_exit, Reason}}; + {terminate, Tester} -> + ok + end + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + TesterSeq = + [ + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket 1", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{sock1 => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "create socket 2", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{sock2 => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "create socket 3", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{sock3 => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind socket 1 to local address", + cmd => fun(#{sock1 := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind socket 2 to local address", + cmd => fun(#{sock2 := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind socket 3 to local address", + cmd => fun(#{sock3 := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** Synchronize with the server *** + #{desc => "order (server) start", + cmd => fun(#{server := Server}) -> + Server ! {start, self()}, + ok + end}, + #{desc => "await ready (from server)", + cmd => fun(#{server := Server, lsa := LSA} = State) -> + receive + {ready, Server, Port} -> + {ok, State#{ssa => LSA#{port => Port}}} + end + end}, + + %% *** Connect sequence *** + #{desc => "order (server) start", + cmd => fun(#{sock1 := Sock1, + sock2 := Sock2, + sock3 := Sock3, + ssa := SSA}) -> + Socks = [Sock1, Sock2, Sock3], + api_to_connect_tcp_await_timeout(Socks, SSA) + end}, + + %% *** Terminate server *** + #{desc => "monitor server", + cmd => fun(#{server := Server} = State) -> + MRef = erlang:monitor(process, Server), + {ok, State#{server_mref => MRef}} + end}, + #{desc => "order (server) terminate", + cmd => fun(#{server := Server} = _State) -> + Server ! {terminate, self()}, + ok + end}, + #{desc => "await (server) down", + cmd => fun(#{server := Server} = State) -> + receive + {'DOWN', _, process, Server, _} -> + State1 = maps:remove(server, State), + State2 = maps:remove(ssa, State1), + {ok, State2} + end + end}, + + %% *** Close our sockets *** + #{desc => "close socket 3", + cmd => fun(#{sock3 := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock3, State)} + + end}, + #{desc => "close socket 2", + cmd => fun(#{sock2 := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock2, State)} + + end}, + #{desc => "close socket 1", + cmd => fun(#{sock1 := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock1, State)} + + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("create server evaluator"), + ServerInitState = InitState, + Server = evaluator_start("server", ServerSeq, ServerInitState), + + p("create tester evaluator"), + TesterInitState = InitState#{server => Server}, + Tester = evaluator_start("tester", TesterSeq, TesterInitState), + + p("await evaluator(s)"), + ok = await_evaluator_finish([Server, Tester]), ok. @@ -1246,19 +1417,19 @@ api_to_connect_tcp_await_timeout(Socks, ServerSA) -> api_to_connect_tcp_await_timeout([], _ServerSA, _ID) -> ?FAIL(unexpected_success); api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> - p("~w: try connect", [ID]), + ei("~w: try connect", [ID]), case socket:connect(Sock, ServerSA, 5000) of {error, timeout} -> - p("expected timeout (~w)", [ID]), + ei("expected timeout (~w)", [ID]), ok; {error, econnreset = Reason} -> - p("failed connecting: ~p - giving up", [Reason]), + ei("failed connecting: ~p - giving up", [Reason]), ok; {error, Reason} -> - p("failed connecting: ~p", [Reason]), - ?FAIL({recv, Reason}); + ee("failed connecting: ~p", [Reason]), + ?FAIL({connect, Reason}); ok -> - p("unexpected success (~w) - try next", [ID]), + ei("unexpected success (~w) - try next", [ID]), api_to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) end. -- cgit v1.2.3 From 51d0d80c96d29445713a026870e3e0124f3380a4 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 11 Oct 2018 15:06:54 +0200 Subject: [socket-nif|test] Reworked tcp (IPv4) recv timeout test case --- lib/kernel/test/socket_SUITE.erl | 384 ++++++++++++++++++++++++++++++++++----- 1 file changed, 334 insertions(+), 50 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 2d406458f0..9a4b263ea0 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1246,12 +1246,12 @@ api_to_connect_tcp(InitState) -> ok end}, #{desc => "await terminate (from tester)", - cmd => fun(#{tester := Tester}) -> + cmd => fun(#{tester := Tester} = State) -> receive {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_tester_exit, Reason}}; + {error, {unexpected_exit, tester, Reason}}; {terminate, Tester} -> - ok + {ok, maps:remove(tester, State)} end end}, @@ -1597,7 +1597,8 @@ api_to_recv_tcp4(doc) -> []; api_to_recv_tcp4(_Config) when is_list(_Config) -> tc_begin(api_to_recv_tcp4), - ok = api_to_recv_tcp(inet), + InitState = #{domain => inet}, + ok = api_to_recv_tcp(InitState), tc_end(). @@ -1611,59 +1612,342 @@ api_to_recv_tcp6(doc) -> []; api_to_recv_tcp6(_Config) when is_list(_Config) -> %% tc_begin(api_to_recv_tcp6), - %% ok = api_to_recv_tcp(inet6), + %% InitState = #{domain => inet6}, + %% ok = api_to_recv_tcp(InitState), %% tc_end(). not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_to_recv_tcp(Domain) -> +api_to_recv_tcp(InitState) -> process_flag(trap_exit, true), - p("server -> open"), - LSock = sock_open(Domain, stream, tcp), - LocalAddr = which_local_addr(Domain), - LocalSA = #{family => Domain, addr => LocalAddr}, - p("server -> bind"), - ServerLPort = sock_bind(LSock, LocalSA), - p("server(~w) -> listen", [ServerLPort]), - sock_listen(LSock), - ClientName = f("~s:client", [get_tc_name()]), - Client = spawn_link(fun() -> - put(sname, ClientName), - p("open"), - CSock = sock_open(Domain, stream, tcp), - p("bind"), - ClientPort = sock_bind(CSock, LocalSA), - p("[~w] connect to ~w", - [ClientPort, ServerLPort]), - sock_connect(CSock, LocalSA#{port => ServerLPort}), - p("await termination command"), - receive - die -> - p("terminating"), - exit(normal) - end - end), - p("server -> accept on ~w", [ServerLPort]), - Sock = sock_accept(LSock), - p("server -> recv"), - %% The zero (0) represents "give me everything you have" - case socket:recv(Sock, 0, 5000) of - {error, timeout} -> - p("server -> expected timeout"), - ok; - {ok, _Data} -> - ?FAIL(unexpected_success); - {error, Reason} -> - ?FAIL({recv, Reason}) - end, - Client ! die, - receive - {'EXIT', Client, _} -> - ok - end, - ok. + + ServerSeq = + [ + %% *** Wait for start order *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create listen socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> + case socket:bind(LSock, LSA) of + {ok, Port} -> + {ok, State#{lport => Port}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket (with backlog = 1)", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock, 1) + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester} = State) -> + MRef = erlang:monitor(process, Tester), + {ok, State#{tester_mref => MRef}} + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester, lport := Port}) -> + Tester ! {ready, self(), Port}, + ok + end}, + #{desc => "await continue", + cmd => fun(#{tester := Tester}) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {continue, Tester} -> + ok + end + end}, + + %% *** The actual test *** + #{desc => "await accept", + cmd => fun(#{lsock := LSock} = State) -> + case socket:accept(LSock) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "attempt to recv (without success)", + cmd => fun(#{sock := Sock} = _State) -> + case socket:recv(Sock, 0, 5000) of + {error, timeout} -> + ok; + {ok, _Data} -> + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready (recv timeout success)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + + %% *** Termination *** + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {terminate, Tester} -> + {ok, maps:remove(tester, State)} + end + end}, + #{desc => "close (traffic) socket", + cmd => fun(#{sock := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock, State)} + end}, + #{desc => "close (listen) socket", + cmd => fun(#{lsock := LSock} = State) -> + sock_close(LSock), + {ok, maps:remove(lsock, State)} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + ClientSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester, Port} when is_pid(Tester) -> + {ok, State#{tester => Tester, + server_port => Port}} + end + end}, + + %% *** 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}, + {ok, State#{lsa => LSA, ssa => SSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester} = State) -> + MRef = erlang:monitor(process, Tester), + {ok, State#{tester_mref => MRef}} + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + + %% *** The actual test *** + #{desc => "await continue (with connect)", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {continue, Tester} -> + ok + end + end}, + #{desc => "connect", + cmd => fun(#{sock := Sock, ssa := SSA}) -> + sock_connect(Sock, SSA), + ok + end}, + + %% *** Termination *** + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {terminate, Tester} -> + {ok, maps:remove(tester, State)} + end + end}, + #{desc => "close socket", + cmd => fun(#{sock := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + TesterSeq = + [ + %% *** Init part *** + #{desc => "monitor server", + cmd => fun(#{server := Server} = State) -> + MRef = erlang:monitor(process, Server), + {ok, State#{server_mref => MRef}} + end}, + #{desc => "monitor client", + cmd => fun(#{client := Client} = State) -> + MRef = erlang:monitor(process, Client), + {ok, State#{client_mref => MRef}} + end}, + + %% *** Activate server *** + #{desc => "start server", + cmd => fun(#{server := Server} = _State) -> + Server ! {start, self()}, + ok + end}, + #{desc => "await server ready (init)", + cmd => fun(#{server := Server} = State) -> + receive + {'DOWN', _, process, Server, Reason} -> + {error, {unexpected_exit, server, Reason}}; + {ready, Server, Port} -> + {ok, State#{server_port => Port}} + end + end}, + #{desc => "order server to continue (with accept)", + cmd => fun(#{server := Server} = _State) -> + Server ! {continue, self()}, + ok + end}, + + %% *** Activate client *** + #{desc => "start client", + cmd => fun(#{client := Client, server_port := Port} = _State) -> + Client ! {start, self(), Port}, + ok + end}, + #{desc => "await client ready", + cmd => fun(#{client := Client} = _State) -> + receive + {'DOWN', _, process, Client, Reason} -> + {error, {unexpected_exit, client, Reason}}; + {ready, Client} -> + ok + end + end}, + + %% *** The actual test *** + #{desc => "order client to continue (with connect)", + cmd => fun(#{client := Client} = _State) -> + Client ! {continue, self()}, + ok + end}, + #{desc => "await server ready (accept/recv)", + cmd => fun(#{server := Server} = _State) -> + receive + {'DOWN', _, process, Server, Reason} -> + {error, {unexpected_exit, server, Reason}}; + {ready, Server} -> + ok + end + end}, + + %% *** Termination *** + #{desc => "order client to terminate", + cmd => fun(#{client := Client} = _State) -> + Client ! {terminate, self()}, + ok + end}, + #{desc => "await client termination", + cmd => fun(#{client := Client} = State) -> + receive + {'DOWN', _, process, Client, _Reason} -> + State1 = maps:remove(client, State), + State2 = maps:remove(client_mref, State1), + {ok, State2} + end + end}, + #{desc => "order server to terminate", + cmd => fun(#{server := Server} = State) -> + Server ! {terminate, self()}, + ok + end}, + #{desc => "await server termination", + cmd => fun(#{server := Server} = State) -> + receive + {'DOWN', _, process, Server, _Reason} -> + State1 = maps:remove(server, State), + State2 = maps:remove(server_mref, State1), + State3 = maps:remove(server_port, State2), + {ok, State3} + end + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + + p("start server evaluator"), + ServerInitState = InitState, + Server = evaluator_start("server", ServerSeq, ServerInitState), + + p("start client evaluator"), + ClientInitState = InitState, + Client = evaluator_start("client", ClientSeq, ClientInitState), + + p("start tester evaluator"), + TesterInitState = #{server => Server, client => Client}, + Tester = evaluator_start("tester", TesterSeq, TesterInitState), + + p("await evaluator(s)"), + ok = await_evaluator_finish([Server, Client, Tester]). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From d66f69c98404b8c299e98237839a35b351d454ca Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 11 Oct 2018 15:27:31 +0200 Subject: [socket-nif|test] Reworked (IPv4) tcp recvmsg timeout test case --- lib/kernel/test/socket_SUITE.erl | 152 +++++++++++++++------------------------ 1 file changed, 57 insertions(+), 95 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 9a4b263ea0..a432473f01 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1597,8 +1597,9 @@ api_to_recv_tcp4(doc) -> []; api_to_recv_tcp4(_Config) when is_list(_Config) -> tc_begin(api_to_recv_tcp4), - InitState = #{domain => inet}, - ok = api_to_recv_tcp(InitState), + Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_tcp(InitState), tc_end(). @@ -1612,15 +1613,22 @@ api_to_recv_tcp6(doc) -> []; api_to_recv_tcp6(_Config) when is_list(_Config) -> %% tc_begin(api_to_recv_tcp6), - %% InitState = #{domain => inet6}, - %% ok = api_to_recv_tcp(InitState), - %% tc_end(). + %% Res = case socket:supports(ipv6) of + %% true -> + %% Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, + %% InitState = #{domain => inet6, recv => Recv}, + %% ok = api_to_receive_tcp(InitState); + %% false -> + %% {skip, ipv6_not_supported} + %% end, + %% tc_end(), + %% Res. not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_to_recv_tcp(InitState) -> +api_to_receive_tcp(InitState) -> process_flag(trap_exit, true), ServerSeq = @@ -1694,8 +1702,8 @@ api_to_recv_tcp(InitState) -> end end}, #{desc => "attempt to recv (without success)", - cmd => fun(#{sock := Sock} = _State) -> - case socket:recv(Sock, 0, 5000) of + cmd => fun(#{sock := Sock, recv := Recv} = _State) -> + case Recv(Sock) of {error, timeout} -> ok; {ok, _Data} -> @@ -1910,7 +1918,7 @@ api_to_recv_tcp(InitState) -> end end}, #{desc => "order server to terminate", - cmd => fun(#{server := Server} = State) -> + cmd => fun(#{server := Server} = _State) -> Server ! {terminate, self()}, ok end}, @@ -2067,9 +2075,10 @@ api_to_recvmsg_tcp4(doc) -> []; api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> tc_begin(api_to_recvmsg_tcp4), - ok = api_to_recvmsg_tcp(inet), + Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_tcp(InitState), tc_end(). - %% not_yet_implemented(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2082,60 +2091,13 @@ api_to_recvmsg_tcp6(doc) -> []; api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> %% tc_begin(api_to_recvmsg_tcp6), - %% ok = api_to_recvmsg_tcp(inet6), + %% Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + %% InitState = #{domain => inet6, recv => Recv}, + %% ok = api_to_receive_tcp(InitState), %% tc_end(). not_yet_implemented(). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_recvmsg_tcp(Domain) -> - process_flag(trap_exit, true), - p("server -> open"), - LSock = sock_open(Domain, stream, tcp), - LocalAddr = which_local_addr(Domain), - LocalSA = #{family => Domain, addr => LocalAddr}, - p("server -> bind"), - ServerLPort = sock_bind(LSock, LocalSA), - p("server(~w) -> listen", [ServerLPort]), - sock_listen(LSock), - ClientName = f("~s:client", [get_tc_name()]), - Client = spawn_link(fun() -> - put(sname, ClientName), - p("open"), - CSock = sock_open(Domain, stream, tcp), - p("bind"), - ClientPort = sock_bind(CSock, LocalSA), - p("[~w] connect to ~w", - [ClientPort, ServerLPort]), - sock_connect(CSock, LocalSA#{port => ServerLPort}), - p("await termination command"), - receive - die -> - p("terminating"), - exit(normal) - end - end), - p("server -> accept on ~w", [ServerLPort]), - Sock = sock_accept(LSock), - p("server -> recv"), - %% The zero (0) represents "give me everything you have" - case socket:recvmsg(Sock, 5000) of - {error, timeout} -> - p("server -> expected timeout"), - ok; - {ok, _Data} -> - ?FAIL(unexpected_success); - {error, Reason} -> - ?FAIL({recv, Reason}) - end, - Client ! die, - receive - {'EXIT', Client, _} -> - ok - end, - ok. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2312,36 +2274,36 @@ sock_sockname(Sock) -> end. -sock_listen(Sock) -> - sock_listen2(fun() -> socket:listen(Sock) end). - -sock_listen(Sock, BackLog) -> - sock_listen2(fun() -> socket:listen(Sock, BackLog) end). - -sock_listen2(Listen) -> - try Listen() of - ok -> - ok; - {error, Reason} -> - ?FAIL({listen, Reason}) - catch - C:E:S -> - ?FAIL({listen, C, E, S}) - end. - - -sock_accept(LSock) -> - try socket:accept(LSock) of - {ok, Sock} -> - Sock; - {error, Reason} -> - p("sock_accept -> error: ~p", [Reason]), - ?FAIL({accept, Reason}) - catch - C:E:S -> - p("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]), - ?FAIL({accept, C, E, S}) - end. +%% sock_listen(Sock) -> +%% sock_listen2(fun() -> socket:listen(Sock) end). + +%% sock_listen(Sock, BackLog) -> +%% sock_listen2(fun() -> socket:listen(Sock, BackLog) end). + +%% sock_listen2(Listen) -> +%% try Listen() of +%% ok -> +%% ok; +%% {error, Reason} -> +%% ?FAIL({listen, Reason}) +%% catch +%% C:E:S -> +%% ?FAIL({listen, C, E, S}) +%% end. + + +%% sock_accept(LSock) -> +%% try socket:accept(LSock) of +%% {ok, Sock} -> +%% Sock; +%% {error, Reason} -> +%% p("sock_accept -> error: ~p", [Reason]), +%% ?FAIL({accept, Reason}) +%% catch +%% C:E:S -> +%% p("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]), +%% ?FAIL({accept, C, E, S}) +%% end. sock_close(Sock) -> @@ -2372,8 +2334,8 @@ set_tc_name(N) when is_atom(N) -> set_tc_name(N) when is_list(N) -> put(tc_name, N). -get_tc_name() -> - get(tc_name). +%% get_tc_name() -> +%% get(tc_name). tc_begin(TC) -> set_tc_name(TC), @@ -2386,8 +2348,8 @@ tc_end() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -f(F, A) -> - lists:flatten(io_lib:format(F, A)). +%% f(F, A) -> +%% lists:flatten(io_lib:format(F, A)). p(F) -> p(F, []). -- cgit v1.2.3 From c4c1f1d2bd307a88c5668a489d131dc6b74bf3af Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 11 Oct 2018 19:13:31 +0200 Subject: [socket-nif|test] Wrapped each test case in try Each test case is wrapped in a try catch in the ttc_try function. It handles entry, exit and skip. --- lib/kernel/test/socket_SUITE.erl | 428 ++++++++++++++++++++++----------------- 1 file changed, 238 insertions(+), 190 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index a432473f01..dc9d5240ca 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -49,8 +49,8 @@ api_to_accept_tcp6/1, api_to_send_tcp4/1, api_to_send_tcp6/1, - api_to_sendapi_to_udp4/1, - api_to_sendapi_to_udp6/1, + api_to_sendto_udp4/1, + api_to_sendto_udp6/1, api_to_sendmsg_tcp4/1, api_to_sendmsg_tcp6/1, api_to_recv_udp4/1, @@ -143,8 +143,8 @@ api_op_with_timeout_cases() -> api_to_accept_tcp6, api_to_send_tcp4, api_to_send_tcp6, - api_to_sendapi_to_udp4, - api_to_sendapi_to_udp6, + api_to_sendto_udp4, + api_to_sendto_udp6, api_to_sendmsg_tcp4, api_to_sendmsg_tcp6, api_to_recv_udp4, @@ -190,12 +190,13 @@ api_b_open_and_close_udp4(suite) -> api_b_open_and_close_udp4(doc) -> []; api_b_open_and_close_udp4(_Config) when is_list(_Config) -> - tc_begin(api_b_open_and_close_udp4), - State = #{domain => inet, - type => dgram, - protocol => udp}, - ok = api_b_open_and_close(State), - tc_end(). + tc_try(api_b_open_and_close_udp4, + fun() -> + InitState = #{domain => inet, + type => dgram, + protocol => udp}, + ok = api_b_open_and_close(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -207,12 +208,13 @@ api_b_open_and_close_tcp4(suite) -> api_b_open_and_close_tcp4(doc) -> []; api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_b_open_and_close_tcp4), - State = #{domain => inet, - type => stream, - protocol => tcp}, - ok = api_b_open_and_close(State), - tc_end(). + tc_try(api_b_open_and_close_tcp4, + fun() -> + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = api_b_open_and_close(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -317,18 +319,19 @@ api_b_sendto_and_recvfrom_udp4(suite) -> api_b_sendto_and_recvfrom_udp4(doc) -> []; api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> - tc_begin(api_b_sendto_and_recvfrom_udp4), - Send = fun(Sock, Data, Dest) -> - socket:sendto(Sock, Data, Dest) - end, - Recv = fun(Sock) -> - socket:recvfrom(Sock) - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_udp(InitState), - tc_end(). + tc_try(api_b_sendto_and_recvfrom_udp4, + fun() -> + Send = fun(Sock, Data, Dest) -> + socket:sendto(Sock, Data, Dest) + end, + Recv = fun(Sock) -> + socket:recvfrom(Sock) + end, + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_udp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -340,29 +343,32 @@ api_b_sendmsg_and_recvmsg_udp4(suite) -> api_b_sendmsg_and_recvmsg_udp4(doc) -> []; api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> - tc_begin(api_b_sendmsg_and_recvmsg_udp4), - Send = fun(Sock, Data, Dest) -> - %% CMsgHdr = #{level => ip, type => tos, data => reliability}, - %% CMsgHdrs = [CMsgHdr], + tc_try(api_b_sendmsg_and_recvmsg_udp4, + fun() -> + Send = fun(Sock, Data, Dest) -> + %% CMsgHdr = #{level => ip, + %% type => tos, + %% data => reliability}, + %% CMsgHdrs = [CMsgHdr], MsgHdr = #{addr => Dest, %% ctrl => CMsgHdrs, iov => [Data]}, - socket:sendmsg(Sock, MsgHdr) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Data]}} -> - {ok, {Source, Data}}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_udp(InitState), - tc_end(). + socket:sendmsg(Sock, MsgHdr) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := Source, + iov := [Data]}} -> + {ok, {Source, Data}}; + {error, _} = ERROR -> + ERROR + end + end, + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_udp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -451,18 +457,19 @@ api_b_send_and_recv_tcp4(suite) -> api_b_send_and_recv_tcp4(doc) -> []; api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_b_send_and_recv_tcp4), - Send = fun(Sock, Data) -> - socket:send(Sock, Data) - end, - Recv = fun(Sock) -> - socket:recv(Sock) - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_tcp(InitState), - tc_end(). + tc_try(api_b_send_and_recv_tcp4, + fun() -> + Send = fun(Sock, Data) -> + socket:send(Sock, Data) + end, + Recv = fun(Sock) -> + socket:recv(Sock) + end, + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -474,25 +481,26 @@ api_b_sendmsg_and_recvmsg_tcp4(suite) -> api_b_sendmsg_and_recvmsg_tcp4(doc) -> []; api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_b_sendmsg_and_recvmsg_tcp4), - Send = fun(Sock, Data) -> - MsgHdr = #{iov => [Data]}, - socket:sendmsg(Sock, MsgHdr) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := undefined, - iov := [Data]}} -> - {ok, Data}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_tcp(InitState), - tc_end(). + tc_try(api_b_sendmsg_and_recvmsg_tcp4, + fun() -> + Send = fun(Sock, Data) -> + MsgHdr = #{iov => [Data]}, + socket:sendmsg(Sock, MsgHdr) + end, + Recv = fun(Sock) -> + case socket:recvmsg(Sock) of + {ok, #{addr := undefined, + iov := [Data]}} -> + {ok, Data}; + {error, _} = ERROR -> + ERROR + end + end, + InitState = #{domain => inet, + send => Send, + recv => Recv}, + ok = api_b_send_and_recv_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -650,8 +658,10 @@ api_opt_simple_otp_options(suite) -> api_opt_simple_otp_options(doc) -> []; api_opt_simple_otp_options(_Config) when is_list(_Config) -> - tc_begin(api_opt_simple_otp_options), + tc_try(api_opt_simple_otp_options, + fun() -> api_opt_simple_otp_options() end). +api_opt_simple_otp_options() -> Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -897,9 +907,7 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> InitState2 = #{domain => inet, type => dgram, protocol => udp}, Tester2 = evaluator_start("udp-tester", Seq, InitState2), p("await evaluator 2"), - ok = await_evaluator_finish([Tester2]), - - tc_end(). + ok = await_evaluator_finish([Tester2]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -910,8 +918,10 @@ api_opt_simple_otp_controlling_process(suite) -> api_opt_simple_otp_controlling_process(doc) -> []; api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> - tc_begin(api_opt_simple_otp_controlling_process), + tc_try(api_opt_simple_otp_controlling_process, + fun() -> api_opt_simple_otp_controlling_process() end). +api_opt_simple_otp_controlling_process() -> Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -1147,9 +1157,8 @@ api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> client => Client2}, Tester2 = evaluator_start("udp-tester", TesterSeq, TesterInitState2), p("await dgram/udp evaluator"), - ok = await_evaluator_finish([Tester2, Client2]), + ok = await_evaluator_finish([Tester2, Client2]). - tc_end(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1161,11 +1170,11 @@ api_to_connect_tcp4(suite) -> api_to_connect_tcp4(doc) -> []; api_to_connect_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_to_connect_tcp4), - InitState = #{domain => inet}, - ok = api_to_connect_tcp(InitState), - tc_end(). - %% not_yet_implemented(). + tc_try(api_to_connect_tcp4, + fun() -> + InitState = #{domain => inet}, + ok = api_to_connect_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1177,11 +1186,12 @@ api_to_connect_tcp6(suite) -> api_to_connect_tcp6(doc) -> []; api_to_connect_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_connect_tcp6), - %% InitState = #{domain => inet6}, - %% ok = api_to_connect_tcp(InitState), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_connect_tcp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6}, + ok = api_to_connect_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1429,7 +1439,7 @@ api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> ee("failed connecting: ~p", [Reason]), ?FAIL({connect, Reason}); ok -> - ei("unexpected success (~w) - try next", [ID]), + ei("unexpected success (~w) - try next", [ID]), api_to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) end. @@ -1444,10 +1454,11 @@ api_to_accept_tcp4(suite) -> api_to_accept_tcp4(doc) -> []; api_to_accept_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(api_to_accept_tcp4), - %% ok = api_to_accept_tcp(inet), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_accept_tcp4, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_accept_tcp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1459,10 +1470,11 @@ api_to_accept_tcp6(suite) -> api_to_accept_tcp6(doc) -> []; api_to_accept_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_accept_tcp6), - %% ok = api_to_accept_tcp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_accept_tcp4, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_accept_tcp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1474,10 +1486,11 @@ api_to_send_tcp4(suite) -> api_to_send_tcp4(doc) -> []; api_to_send_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(api_to_send_tcp4), - %% ok = api_to_send_tcp(inet), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_send_tcp4, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_send_tcp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1489,40 +1502,43 @@ api_to_send_tcp6(suite) -> api_to_send_tcp6(doc) -> []; api_to_send_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_send_tcp6), - %% ok = api_to_send_tcp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_send_tcp6, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_send_tcp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the sendto timeout option %% on an IPv4 UDP (dgram) socket. -api_to_sendapi_to_udp4(suite) -> +api_to_sendto_udp4(suite) -> []; -api_to_sendapi_to_udp4(doc) -> +api_to_sendto_udp4(doc) -> []; -api_to_sendapi_to_udp4(_Config) when is_list(_Config) -> - %% tc_begin(api_to_sendapi_to_udp4), - %% ok = api_to_sendapi_to_udp(inet), - %% tc_end(). - not_yet_implemented(). +api_to_sendto_udp4(_Config) when is_list(_Config) -> + tc_try(api_to_sendto_udp4, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_sendto_to_udp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the sendto timeout option %% on an IPv6 UDP (dgram) socket. -api_to_sendapi_to_udp6(suite) -> +api_to_sendto_udp6(suite) -> []; -api_to_sendapi_to_udp6(doc) -> +api_to_sendto_udp6(doc) -> []; -api_to_sendapi_to_udp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_sendapi_to_udp6), - %% ok = api_to_sendapi_to_udp(inet6), - %% tc_end(). - not_yet_implemented(). +api_to_sendto_udp6(_Config) when is_list(_Config) -> + tc_try(api_to_sendto_udp6, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_sendto_to_udp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1534,10 +1550,11 @@ api_to_sendmsg_tcp4(suite) -> api_to_sendmsg_tcp4(doc) -> []; api_to_sendmsg_tcp4(_Config) when is_list(_Config) -> - %% tc_begin(api_to_sendmsg_tcp4), - %% ok = api_to_sendmsg_tcp(inet), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_sendmsg_tcp4, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_sendmsg_tcp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1549,10 +1566,11 @@ api_to_sendmsg_tcp6(suite) -> api_to_sendmsg_tcp6(doc) -> []; api_to_sendmsg_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_sendmsg_tcp6), - %% ok = api_to_sendmsg_tcp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_sendmsg_tcp6, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_sendmsg_tcp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1565,10 +1583,11 @@ api_to_recv_udp4(suite) -> api_to_recv_udp4(doc) -> []; api_to_recv_udp4(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recv_udp4), - %% ok = api_to_recv_udp(inet), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_recv_udp4, + fun() -> + not_yet_implemented()%%, + %%ok = api_to_recv_udp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1581,10 +1600,11 @@ api_to_recv_udp6(suite) -> api_to_recv_udp6(doc) -> []; api_to_recv_udp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recv_udp6), - %% ok = api_to_recv_udp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_recv_udp6, + fun() -> + not_yet_implemented()%% , + %% ok = api_to_recv_udp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1596,11 +1616,12 @@ api_to_recv_tcp4(suite) -> api_to_recv_tcp4(doc) -> []; api_to_recv_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_to_recv_tcp4), - Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, - InitState = #{domain => inet, recv => Recv}, - ok = api_to_receive_tcp(InitState), - tc_end(). + tc_try(api_to_recv_tcp4, + fun() -> + Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1612,18 +1633,20 @@ api_to_recv_tcp6(suite) -> api_to_recv_tcp6(doc) -> []; api_to_recv_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recv_tcp6), - %% Res = case socket:supports(ipv6) of - %% true -> - %% Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, - %% InitState = #{domain => inet6, recv => Recv}, - %% ok = api_to_receive_tcp(InitState); - %% false -> - %% {skip, ipv6_not_supported} - %% end, - %% tc_end(), - %% Res. - not_yet_implemented(). + tc_try(api_to_recv_tcp6, + fun() -> + not_yet_implemented(), + case socket:supports(ipv6) of + true -> + Recv = fun(Sock) -> + socket:recv(Sock, 0, 5000) + end, + InitState = #{domain => inet6, recv => Recv}, + ok = api_to_receive_tcp(InitState); + false -> + skip("ipv6 not supported") + end + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1967,9 +1990,10 @@ api_to_recvfrom_udp4(suite) -> api_to_recvfrom_udp4(doc) -> []; api_to_recvfrom_udp4(_Config) when is_list(_Config) -> - tc_begin(api_to_recvfrom_udp4), - ok = api_to_recvfrom_udp(inet), - tc_end(). + tc_try(api_to_recvfrom_udp4, + fun() -> + ok = api_to_recvfrom_udp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1981,10 +2005,11 @@ api_to_recvfrom_udp6(suite) -> api_to_recvfrom_udp6(doc) -> []; api_to_recvfrom_udp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recvfrom_udp6), - %% ok = api_to_recvfrom_udp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_recvfrom_udp6, + fun() -> + not_yet_implemented(), + ok = api_to_recvfrom_udp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2020,10 +2045,10 @@ api_to_recvmsg_udp4(suite) -> api_to_recvmsg_udp4(doc) -> []; api_to_recvmsg_udp4(_Config) when is_list(_Config) -> - %% not_yet_implemented(). - tc_begin(api_to_recvmsg_udp4), - ok = api_to_recvmsg_udp(inet), - tc_end(). + tc_try(api_to_recvmsg_udp4, + fun() -> + ok = api_to_recvmsg_udp(inet) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2035,10 +2060,11 @@ api_to_recvmsg_udp6(suite) -> api_to_recvmsg_udp6(doc) -> []; api_to_recvmsg_udp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recvmsg_udp6), - %% ok = api_to_recvmsg_udp(inet6), - %% tc_end(). - not_yet_implemented(). + tc_try(api_to_recvmsg_udp6, + fun() -> + not_yet_implemented(), + ok = api_to_recvmsg_udp(inet6) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2074,11 +2100,12 @@ api_to_recvmsg_tcp4(suite) -> api_to_recvmsg_tcp4(doc) -> []; api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> - tc_begin(api_to_recvmsg_tcp4), - Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - InitState = #{domain => inet, recv => Recv}, - ok = api_to_receive_tcp(InitState), - tc_end(). + tc_try(api_to_recvmsg_tcp4, + fun() -> + Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2090,13 +2117,13 @@ api_to_recvmsg_tcp6(suite) -> api_to_recvmsg_tcp6(doc) -> []; api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> - %% tc_begin(api_to_recvmsg_tcp6), - %% Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - %% InitState = #{domain => inet6, recv => Recv}, - %% ok = api_to_receive_tcp(InitState), - %% tc_end(). - not_yet_implemented(). - + tc_try(api_to_recvmsg_tcp6, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + InitState = #{domain => inet6, recv => Recv}, + ok = api_to_receive_tcp(InitState) + end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2324,7 +2351,10 @@ sock_close(Sock) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% not_yet_implemented() -> - {skip, "not yet implemented"}. + skip("not yet implemented"). + +skip(Reason) -> + throw({skip, Reason}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2341,11 +2371,29 @@ tc_begin(TC) -> set_tc_name(TC), p("begin ***"). -tc_end() -> - p("done ***"), +tc_end(Result) when is_list(Result) -> + p("done: ~s", [Result]), ok. +tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) -> + tc_begin(Case), + try + begin + Fun(), + tc_end("ok") + end + catch + throw:{skip, _} = SKIP -> + tc_end("skipping"), + SKIP; + Class:Error:Stack -> + tc_end("failed"), + erlang:raise(Class, Error, Stack) + end. + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% f(F, A) -> -- cgit v1.2.3 From cb2d61a99ff3613f9b47598844a0274049859b7e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 12 Oct 2018 10:48:00 +0200 Subject: [socket-nif|test] Reworked (IPv4) udp recvfrom timeout test case --- lib/kernel/test/socket_SUITE.erl | 88 ++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 22 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index dc9d5240ca..724bbc9539 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1992,7 +1992,8 @@ api_to_recvfrom_udp4(doc) -> api_to_recvfrom_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp4, fun() -> - ok = api_to_recvfrom_udp(inet) + InitState = #{domain => inet}, + ok = api_to_recvfrom_udp(InitState) end). @@ -2008,32 +2009,75 @@ api_to_recvfrom_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp6, fun() -> not_yet_implemented(), - ok = api_to_recvfrom_udp(inet6) + InitState = #{domain => inet6}, + ok = api_to_recvfrom_udp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_to_recvfrom_udp(Domain) -> - process_flag(trap_exit, true), - p("init"), - LocalAddr = which_local_addr(Domain), - LocalSA = #{family => Domain, addr => LocalAddr}, - p("open"), - Sock = sock_open(Domain, dgram, udp), - p("bind"), - _Port = sock_bind(Sock, LocalSA), - p("recv"), - case socket:recvfrom(Sock, 0, 5000) of - {error, timeout} -> - p("expected timeout"), - ok; - {ok, _SrcData} -> - ?FAIL(unexpected_success); - {error, Reason} -> - ?FAIL({recv, Reason}) - end, - ok. +api_to_recvfrom_udp(InitState) -> + TesterSeq = + [ + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, dgram, udp) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _Port} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** The actual test *** + #{desc => "attempt to read (without success)", + cmd => fun(#{sock := Sock} = _State) -> + case socket:recvfrom(Sock, 0, 5000) of + {error, timeout} -> + ok; + {ok, _SrcData} -> + {error, unexpected_sucsess}; + {error, _} = ERROR -> + ERROR + end + end}, + + %% *** Termination *** + #{desc => "close socket", + cmd => fun(#{sock := Sock} = _State) -> + sock_close(Sock), + ok + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("start tester evaluator"), + Tester = evaluator_start("tester", TesterSeq, InitState), + + p("await evaluator"), + ok = await_evaluator_finish([Tester]). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From 227eb3efe1cd42324c315dc14d9945ffcd935069 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 12 Oct 2018 11:05:26 +0200 Subject: [socket-nif|test] Reworked (IPv4) udp recvmsg timeout test case --- lib/kernel/test/socket_SUITE.erl | 63 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 34 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 724bbc9539..82d79ef32b 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1992,8 +1992,9 @@ api_to_recvfrom_udp4(doc) -> api_to_recvfrom_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp4, fun() -> - InitState = #{domain => inet}, - ok = api_to_recvfrom_udp(InitState) + Recv = fun(Sock) -> socket:recvfrom(Sock, 0, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_udp(InitState) end). @@ -2009,14 +2010,15 @@ api_to_recvfrom_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp6, fun() -> not_yet_implemented(), - InitState = #{domain => inet6}, - ok = api_to_recvfrom_udp(InitState) + Recv = fun(Sock) -> socket:recvfrom(Sock, 0, 5000) end, + InitState = #{domain => inet6, recv => Recv}, + ok = api_to_receive_udp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -api_to_recvfrom_udp(InitState) -> +api_to_receive_udp(InitState) -> TesterSeq = [ %% *** Init part *** @@ -2047,11 +2049,11 @@ api_to_recvfrom_udp(InitState) -> %% *** The actual test *** #{desc => "attempt to read (without success)", - cmd => fun(#{sock := Sock} = _State) -> - case socket:recvfrom(Sock, 0, 5000) of + cmd => fun(#{sock := Sock, recv := Recv} = _State) -> + case Recv(Sock) of {error, timeout} -> ok; - {ok, _SrcData} -> + {ok, _} -> {error, unexpected_sucsess}; {error, _} = ERROR -> ERROR @@ -2091,7 +2093,9 @@ api_to_recvmsg_udp4(doc) -> api_to_recvmsg_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_udp4, fun() -> - ok = api_to_recvmsg_udp(inet) + Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + InitState = #{domain => inet, recv => Recv}, + ok = api_to_receive_udp(InitState) end). @@ -2107,34 +2111,12 @@ api_to_recvmsg_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_udp6, fun() -> not_yet_implemented(), - ok = api_to_recvmsg_udp(inet6) + Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, + InitState = #{domain => inet6, recv => Recv}, + ok = api_to_receive_udp(InitState) end). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_recvmsg_udp(Domain) -> - process_flag(trap_exit, true), - p("init"), - LocalAddr = which_local_addr(Domain), - LocalSA = #{family => Domain, addr => LocalAddr}, - p("open"), - Sock = sock_open(Domain, dgram, udp), - p("bind"), - _Port = sock_bind(Sock, LocalSA), - p("recv"), - case socket:recvmsg(Sock, 5000) of - {error, timeout} -> - p("expected timeout"), - ok; - {ok, _MsgHdr} -> - ?FAIL(unexpected_success); - {error, Reason} -> - ?FAIL({recv, Reason}) - end, - ok. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the recvmsg timeout option @@ -2401,6 +2383,19 @@ skip(Reason) -> throw({skip, Reason}). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% t() -> +%% os:timestamp(). + + +%% tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) -> +%% T1 = A1*1000000000+B1*1000+(C1 div 1000), +%% T2 = A2*1000000000+B2*1000+(C2 div 1000), +%% T2 - T1. + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_tc_name(N) when is_atom(N) -> -- cgit v1.2.3 From 22336422d7a014db53dcba7ff1b6e71a1729d89a Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 12 Oct 2018 11:59:16 +0200 Subject: [socket-nif|test] Add accept timeout test case and update other timeout test cases(s) Added simple accept timeout testcase. Updated timeout test cases(s) with a timeout validation. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 249 ++++++++++++++++++++++++++++++--------- 1 file changed, 196 insertions(+), 53 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 82d79ef32b..de6a20e60b 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -1172,7 +1172,7 @@ api_to_connect_tcp4(doc) -> api_to_connect_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_connect_tcp4, fun() -> - InitState = #{domain => inet}, + InitState = #{domain => inet, timeout => 5000}, ok = api_to_connect_tcp(InitState) end). @@ -1189,7 +1189,7 @@ api_to_connect_tcp6(_Config) when is_list(_Config) -> tc_try(api_to_connect_tcp6, fun() -> not_yet_implemented(), - InitState = #{domain => inet6}, + InitState = #{domain => inet6, timeout => 5000}, ok = api_to_connect_tcp(InitState) end). @@ -1352,12 +1352,13 @@ api_to_connect_tcp(InitState) -> %% *** Connect sequence *** #{desc => "order (server) start", - cmd => fun(#{sock1 := Sock1, - sock2 := Sock2, - sock3 := Sock3, - ssa := SSA}) -> + cmd => fun(#{sock1 := Sock1, + sock2 := Sock2, + sock3 := Sock3, + ssa := SSA, + timeout := To}) -> Socks = [Sock1, Sock2, Sock3], - api_to_connect_tcp_await_timeout(Socks, SSA) + api_to_connect_tcp_await_timeout(Socks, To, SSA) end}, %% *** Terminate server *** @@ -1417,21 +1418,28 @@ api_to_connect_tcp(InitState) -> Tester = evaluator_start("tester", TesterSeq, TesterInitState), p("await evaluator(s)"), - ok = await_evaluator_finish([Server, Tester]), - ok. + ok = await_evaluator_finish([Server, Tester]). -api_to_connect_tcp_await_timeout(Socks, ServerSA) -> - api_to_connect_tcp_await_timeout(Socks, ServerSA, 1). +api_to_connect_tcp_await_timeout(Socks, To, ServerSA) -> + api_to_connect_tcp_await_timeout(Socks, To, ServerSA, 1). -api_to_connect_tcp_await_timeout([], _ServerSA, _ID) -> +api_to_connect_tcp_await_timeout([], _To, _ServerSA, _ID) -> ?FAIL(unexpected_success); -api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> +api_to_connect_tcp_await_timeout([Sock|Socks], To, ServerSA, ID) -> ei("~w: try connect", [ID]), - case socket:connect(Sock, ServerSA, 5000) of + Start = t(), + case socket:connect(Sock, ServerSA, To) of {error, timeout} -> ei("expected timeout (~w)", [ID]), - ok; + Stop = t(), + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end; {error, econnreset = Reason} -> ei("failed connecting: ~p - giving up", [Reason]), ok; @@ -1440,7 +1448,7 @@ api_to_connect_tcp_await_timeout([Sock|Socks], ServerSA, ID) -> ?FAIL({connect, Reason}); ok -> ei("unexpected success (~w) - try next", [ID]), - api_to_connect_tcp_await_timeout(Socks, ServerSA, ID+1) + api_to_connect_tcp_await_timeout(Socks, To, ServerSA, ID+1) end. @@ -1456,8 +1464,8 @@ api_to_accept_tcp4(doc) -> api_to_accept_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_accept_tcp4, fun() -> - not_yet_implemented()%% , - %% ok = api_to_accept_tcp(inet) + InitState = #{domain => inet, timeout => 5000}, + ok = api_to_accept_tcp(InitState) end). @@ -1472,11 +1480,94 @@ api_to_accept_tcp6(doc) -> api_to_accept_tcp6(_Config) when is_list(_Config) -> tc_try(api_to_accept_tcp4, fun() -> - not_yet_implemented()%% , - %% ok = api_to_accept_tcp(inet6) + not_yet_implemented(), + InitState = #{domain => inet6, timeout => 5000}, + ok = api_to_accept_tcp(InitState) end). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_to_accept_tcp(InitState) -> + TesterSeq = + [ + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create (listen) socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = _State) -> + case socket:bind(LSock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock) + end}, + + %% *** The actual test part *** + #{desc => "attempt to accept (without success)", + cmd => fun(#{lsock := LSock, timeout := To} = State) -> + Start = t(), + case socket:accept(LSock, To) of + {error, timeout} -> + {ok, State#{start => Start, stop => t()}}; + {ok, Sock} -> + (catch socket:close(Sock)), + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "validate timeout time", + cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end + end}, + + %% *** Close (listen) socket *** + #{desc => "close (listen) socket", + cmd => fun(#{lsock := LSock} = State) -> + sock_close(LSock), + {ok, maps:remove(sock3, State)} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("create tester evaluator"), + Tester = evaluator_start("tester", TesterSeq, InitState), + + p("await evaluator"), + ok = await_evaluator_finish([Tester]). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the send timeout option @@ -1618,8 +1709,10 @@ api_to_recv_tcp4(doc) -> api_to_recv_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_recv_tcp4, fun() -> - Recv = fun(Sock) -> socket:recv(Sock, 0, 5000) end, - InitState = #{domain => inet, recv => Recv}, + Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end, + InitState = #{domain => inet, + recv => Recv, + timeout => 5000}, ok = api_to_receive_tcp(InitState) end). @@ -1638,10 +1731,12 @@ api_to_recv_tcp6(_Config) when is_list(_Config) -> not_yet_implemented(), case socket:supports(ipv6) of true -> - Recv = fun(Sock) -> - socket:recv(Sock, 0, 5000) + Recv = fun(Sock, To) -> + socket:recv(Sock, 0, To) end, - InitState = #{domain => inet6, recv => Recv}, + InitState = #{domain => inet6, + recv => Recv, + timeout => 5000}, ok = api_to_receive_tcp(InitState); false -> skip("ipv6 not supported") @@ -1725,16 +1820,27 @@ api_to_receive_tcp(InitState) -> end end}, #{desc => "attempt to recv (without success)", - cmd => fun(#{sock := Sock, recv := Recv} = _State) -> - case Recv(Sock) of + cmd => fun(#{sock := Sock, recv := Recv, timeout := To} = State) -> + Start = t(), + case Recv(Sock, To) of {error, timeout} -> - ok; + {ok, State#{start => Start, stop => t()}}; {ok, _Data} -> {error, unexpected_success}; {error, _} = ERROR -> ERROR end end}, + #{desc => "validate timeout time", + cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end + end}, #{desc => "announce ready (recv timeout success)", cmd => fun(#{tester := Tester} = _State) -> Tester ! {ready, self()}, @@ -1992,8 +2098,10 @@ api_to_recvfrom_udp4(doc) -> api_to_recvfrom_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp4, fun() -> - Recv = fun(Sock) -> socket:recvfrom(Sock, 0, 5000) end, - InitState = #{domain => inet, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end, + InitState = #{domain => inet, + recv => Recv, + timeout => 5000}, ok = api_to_receive_udp(InitState) end). @@ -2010,8 +2118,10 @@ api_to_recvfrom_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recvfrom_udp6, fun() -> not_yet_implemented(), - Recv = fun(Sock) -> socket:recvfrom(Sock, 0, 5000) end, - InitState = #{domain => inet6, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end, + InitState = #{domain => inet6, + recv => Recv, + timeout => 5000}, ok = api_to_receive_udp(InitState) end). @@ -2049,17 +2159,28 @@ api_to_receive_udp(InitState) -> %% *** The actual test *** #{desc => "attempt to read (without success)", - cmd => fun(#{sock := Sock, recv := Recv} = _State) -> - case Recv(Sock) of + cmd => fun(#{sock := Sock, recv := Recv, timeout := To} = State) -> + Start = t(), + case Recv(Sock, To) of {error, timeout} -> - ok; + {ok, State#{start => Start, stop => t()}}; {ok, _} -> {error, unexpected_sucsess}; {error, _} = ERROR -> ERROR end end}, - + #{desc => "validate timeout time", + cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end + end}, + %% *** Termination *** #{desc => "close socket", cmd => fun(#{sock := Sock} = _State) -> @@ -2093,8 +2214,10 @@ api_to_recvmsg_udp4(doc) -> api_to_recvmsg_udp4(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_udp4, fun() -> - Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - InitState = #{domain => inet, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, + InitState = #{domain => inet, + recv => Recv, + timeout => 5000}, ok = api_to_receive_udp(InitState) end). @@ -2111,8 +2234,10 @@ api_to_recvmsg_udp6(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_udp6, fun() -> not_yet_implemented(), - Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - InitState = #{domain => inet6, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, + InitState = #{domain => inet6, + recv => Recv, + timeout => 5000}, ok = api_to_receive_udp(InitState) end). @@ -2128,8 +2253,10 @@ api_to_recvmsg_tcp4(doc) -> api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_tcp4, fun() -> - Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - InitState = #{domain => inet, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, + InitState = #{domain => inet, + recv => Recv, + timeout => 5000}, ok = api_to_receive_tcp(InitState) end). @@ -2146,8 +2273,10 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> tc_try(api_to_recvmsg_tcp6, fun() -> not_yet_implemented(), - Recv = fun(Sock) -> socket:recvmsg(Sock, 5000) end, - InitState = #{domain => inet6, recv => Recv}, + Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, + InitState = #{domain => inet6, + recv => Recv, + timeout => 5000}, ok = api_to_receive_tcp(InitState) end). @@ -2273,7 +2402,8 @@ ee(F, A) -> eprint(" ", F, A). eprint(Prefix, F, A) -> - io:format(user, "[~s][~p] ~s" ++ F ++ "~n", [get(sname), self(), Prefix | A]). + io:format(user, "[~s][~s][~p] ~s" ++ F ++ "~n", + [formated_timestamp(), get(sname), self(), Prefix | A]). @@ -2385,17 +2515,30 @@ skip(Reason) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% t() -> -%% os:timestamp(). +t() -> + os:timestamp(). -%% tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) -> -%% T1 = A1*1000000000+B1*1000+(C1 div 1000), -%% T2 = A2*1000000000+B2*1000+(C2 div 1000), -%% T2 - T1. +tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) -> + T1 = A1*1000000000+B1*1000+(C1 div 1000), + T2 = A2*1000000000+B2*1000+(C2 div 1000), + T2 - T1. - +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp({_N1, _N2, _N3} = TS) -> + {_Date, Time} = calendar:now_to_local_time(TS), + %% {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + %% FormatTS = + %% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w", + %% [YYYY, MM, DD, Hour, Min, Sec, N3]), + FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]), + lists:flatten(FormatTS). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_tc_name(N) when is_atom(N) -> @@ -2454,7 +2597,7 @@ p(F, A) -> Name when is_list(Name) -> Name end, - i("*** ~s[~p] " ++ F, [TcName,self()|A]). + i("*** [~s][~s][~p] " ++ F, [formated_timestamp(),TcName,self()|A]). %% i(F) -> -- cgit v1.2.3 From 09168a9d0a78319639d62254da717090e21c47ab Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 12 Oct 2018 15:54:46 +0200 Subject: [socket-nif|test] Add multi accept timeout test case Added simple multi-accept (multiple acceptors) timeout testcase. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 436 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index de6a20e60b..3f4347c52f 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -47,6 +47,8 @@ api_to_connect_tcp6/1, api_to_accept_tcp4/1, api_to_accept_tcp6/1, + api_to_maccept_tcp4/1, + api_to_maccept_tcp6/1, api_to_send_tcp4/1, api_to_send_tcp6/1, api_to_sendto_udp4/1, @@ -1568,6 +1570,440 @@ api_to_accept_tcp(InitState) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the multi accept timeout option +%% on an IPv4 TCP (stream) socket with multiple acceptor processes +%% (three in this case). +api_to_maccept_tcp4(suite) -> + []; +api_to_maccept_tcp4(doc) -> + []; +api_to_maccept_tcp4(_Config) when is_list(_Config) -> + tc_try(api_to_maccept_tcp4, + fun() -> + InitState = #{domain => inet, timeout => 5000}, + ok = api_to_maccept_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% This test case is intended to test the accept timeout option +%% on an IPv6 TCP (stream) socket. +api_to_maccept_tcp6(suite) -> + []; +api_to_maccept_tcp6(doc) -> + []; +api_to_maccept_tcp6(_Config) when is_list(_Config) -> + tc_try(api_to_maccept_tcp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6, timeout => 5000}, + ok = api_to_maccept_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +api_to_maccept_tcp(InitState) -> + PrimAcceptorSeq = + [ + %% *** Init part *** + #{desc => "await start", + cmd => fun(State) -> + receive + {start, Tester} -> + MRef = erlang:monitor(process, Tester), + {ok, State#{tester => Tester, + tester_mref => MRef}} + end + end}, + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create (listen) socket", + cmd => fun(#{domain := Domain} = State) -> + case socket:open(Domain, stream, tcp) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = _State) -> + case socket:bind(LSock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock) + end}, + + #{desc => "announce ready", + cmd => fun(#{lsock := LSock, tester := Tester}) -> + ei("announcing port to tester (~p)", [Tester]), + Tester ! {ready, self(), LSock}, + ok + end}, + #{desc => "await continue", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {continue, Tester} -> + ok + end + end}, + + %% *** The actual test part *** + #{desc => "attempt to accept (without success)", + cmd => fun(#{lsock := LSock, timeout := To} = State) -> + Start = t(), + case socket:accept(LSock, To) of + {error, timeout} -> + {ok, State#{start => Start, stop => t()}}; + {ok, Sock} -> + (catch socket:close(Sock)), + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "validate timeout time", + cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester}) -> + ei("announcing port to tester (~p)", [Tester]), + Tester ! {ready, self()}, + ok + end}, + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + {error, {unexpected_exit, tester, Reason}}; + {terminate, Tester} -> + ok + end + end}, + + %% *** Close (listen) socket *** + #{desc => "close (listen) socket", + cmd => fun(#{lsock := LSock} = State) -> + sock_close(LSock), + {ok, maps:remove(sock3, State)} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + + SecAcceptorSeq = + [ + %% *** Init part *** + #{desc => "await start", + cmd => fun(State) -> + receive + {start, Tester, LSock} -> + MRef = erlang:monitor(process, Tester), + {ok, State#{tester => Tester, + lsock => LSock, + tester_mref => MRef}} + end + end}, + #{desc => "announce ready (1)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "await continue", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester, Reason}}; + {continue, Tester} -> + ok + end + end}, + + %% *** The actual test part *** + #{desc => "attempt to accept (without success)", + cmd => fun(#{lsock := LSock, timeout := To} = State) -> + Start = t(), + case socket:accept(LSock, To) of + {error, timeout} -> + {ok, State#{start => Start, stop => t()}}; + {ok, Sock} -> + (catch socket:close(Sock)), + {error, unexpected_success}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "validate timeout time", + cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> + TDiff = tdiff(Start, Stop), + if + (TDiff >= To) -> + ok; + true -> + {error, {unexpected_timeout, TDiff, To}} + end + end}, + #{desc => "announce ready (2)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester, Reason}}; + {terminate, Tester} -> + ok + end + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + + TesterSeq = + [ + %% Init part + #{desc => "monitor prim-acceptor", + cmd => fun(#{prim_acceptor := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + #{desc => "monitor sec-acceptor 1", + cmd => fun(#{sec_acceptor1 := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + #{desc => "monitor sec-acceptor 2", + cmd => fun(#{sec_acceptor2 := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + + + %% Start the prim-acceptor + #{desc => "start prim-acceptor", + cmd => fun(#{prim_acceptor := Pid} = _State) -> + Pid ! {start, self()}, + ok + end}, + #{desc => "await prim-acceptor ready (1)", + cmd => fun(#{prim_acceptor := Pid} = State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding prim-acceptor ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, prim_acceptor}}; + {ready, Pid, LSock} -> + {ok, State#{lsock => LSock}} + end + end}, + + %% Start sec-acceptor-1 + #{desc => "start sec-acceptor 1", + cmd => fun(#{sec_acceptor1 := Pid, lsock := LSock} = _State) -> + Pid ! {start, self(), LSock}, + ok + end}, + #{desc => "await sec-acceptor 1 ready (1)", + cmd => fun(#{sec_acceptor1 := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding sec-acceptor 1 ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, sec_acceptor_1}}; + {ready, Pid} -> + ok + end + end}, + + %% Start sec-acceptor-2 + #{desc => "start sec-acceptor 2", + cmd => fun(#{sec_acceptor2 := Pid, lsock := LSock} = _State) -> + Pid ! {start, self(), LSock}, + ok + end}, + #{desc => "await sec-acceptor 2 ready (1)", + cmd => fun(#{sec_acceptor2 := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding sec-acceptor 2 ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, sec_acceptor_2}}; + {ready, Pid} -> + ok + end + end}, + + %% Activate the acceptor(s) + #{desc => "active prim-acceptor", + cmd => fun(#{prim_acceptor := Pid} = _State) -> + Pid ! {continue, self()}, + ok + end}, + #{desc => "active sec-acceptor 1", + cmd => fun(#{sec_acceptor1 := Pid} = _State) -> + Pid ! {continue, self()}, + ok + end}, + #{desc => "active sec-acceptor 2", + cmd => fun(#{sec_acceptor2 := Pid} = _State) -> + Pid ! {continue, self()}, + ok + end}, + + %% Await acceptor(s) completions + #{desc => "await prim-acceptor ready (2)", + cmd => fun(#{prim_acceptor := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding prim-acceptor ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, prim_acceptor}}; + {ready, Pid} -> + ok + end + end}, + #{desc => "await sec-acceptor 1 ready (2)", + cmd => fun(#{sec_acceptor1 := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding sec-acceptor 1 ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, sec_acceptor_1}}; + {ready, Pid} -> + ok + end + end}, + #{desc => "await sec-acceptor 2 ready (2)", + cmd => fun(#{sec_acceptor2 := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding sec-acceptor 2 ~p:" + "~n ~p", [Reason]), + {error, {unexpected_exit, sec_acceptor_2}}; + {ready, Pid} -> + ok + end + end}, + + + %% Terminate the acceptor(s) + #{desc => "order prim-acceptor to terminate", + cmd => fun(#{prim_acceptor := Pid} = _State) -> + ei("send terminate command to prim-acceptor (~p)", [Pid]), + Pid ! {terminate, self()}, + ok + end}, + #{desc => "order sec-acceptor 1 to terminate", + cmd => fun(#{sec_acceptor1 := Pid} = _State) -> + ei("send terminate command to sec-acceptor-1 (~p)", [Pid]), + Pid ! {terminate, self()}, + ok + end}, + #{desc => "order sec-acceptor 2 to terminate", + cmd => fun(#{sec_acceptor2 := Pid} = _State) -> + ei("send terminate command to sec-acceptor-2 (~p)", [Pid]), + Pid ! {terminate, self()}, + ok + end}, + + %% Await acceptor(s) termination + #{desc => "await prim-acceptor termination", + cmd => fun(#{prim_acceptor := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + State1 = maps:remove(prim_acceptor, State), + {ok, State1} + end + end}, + #{desc => "await sec-acceptor 1 termination", + cmd => fun(#{sec_acceptor1 := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + State1 = maps:remove(sec_acceptor1, State), + {ok, State1} + end + end}, + #{desc => "await sec-acceptor 2 termination", + cmd => fun(#{sec_acceptor2 := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + State1 = maps:remove(sec_acceptor2, State), + {ok, State1} + end + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("create prim-acceptor evaluator"), + PrimAInitState = InitState, + PrimAcceptor = evaluator_start("prim-acceptor", + PrimAcceptorSeq, PrimAInitState), + + p("create prim-acceptor 1 evaluator"), + SecAInitState1 = maps:remove(domain, InitState), + SecAcceptor1 = evaluator_start("sec-acceptor-1", + SecAcceptorSeq, SecAInitState1), + + p("create prim-acceptor 2 evaluator"), + SecAInitState2 = SecAInitState1, + SecAcceptor2 = evaluator_start("sec-acceptor-2", + SecAcceptorSeq, SecAInitState2), + + p("create tester evaluator"), + TesterInitState = #{prim_acceptor => PrimAcceptor, + sec_acceptor1 => SecAcceptor1, + sec_acceptor2 => SecAcceptor2}, + Tester = evaluator_start("tester", TesterSeq, TesterInitState), + + p("await evaluator(s)"), + ok = await_evaluator_finish([PrimAcceptor, SecAcceptor1, SecAcceptor2, Tester]). + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the send timeout option -- cgit v1.2.3 From ac1e27ce82fde99519a9cf271144179e4a2ef373 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 12 Oct 2018 16:59:28 +0200 Subject: [socket-nif|test] Add skeletons for controlling-process test cases --- lib/kernel/test/socket_SUITE.erl | 560 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 556 insertions(+), 4 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 3f4347c52f..71e6dff174 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -64,7 +64,29 @@ api_to_recvmsg_udp4/1, api_to_recvmsg_udp6/1, api_to_recvmsg_tcp4/1, - api_to_recvmsg_tcp6/1 + api_to_recvmsg_tcp6/1, + + %% Controlling Process + socket_cleanup_tcp4/1, + socket_cleanup_tcp6/1, + socket_cleanup_udp4/1, + socket_cleanup_udp6/1, + socket_close_tcp4/1, + socket_close_tcp6/1, + socket_close_udp4/1, + socket_close_udp6/1, + recv_response_local_close_tcp4/1, + recv_response_local_close_tcp6/1, + recv_response_remote_close_tcp4/1, + recv_response_remote_close_tcp6/1, + recvmsg_response_local_close_tcp4/1, + recvmsg_response_local_close_tcp6/1, + recvmsg_response_remote_close_tcp4/1, + recvmsg_response_remote_close_tcp6/1, + acceptor_response_local_close_tcp4/1, + acceptor_response_local_close_tcp6/1, + acceptor_response_remote_close_tcp4/1, + acceptor_response_remote_close_tcp6/1 %% Tickets ]). @@ -102,15 +124,17 @@ suite() -> all() -> [ - {group, api} + {group, api}, + {group, controlling_process} %% {group, tickets} ]. groups() -> [{api, [], api_cases()}, {api_basic, [], api_basic_cases()}, + {api_options, [], api_options_cases()}, {api_op_with_timeout, [], api_op_with_timeout_cases()}, - {api_options, [], api_options_cases()} + {controlling_process, [], controlling_process_cases()} %% {tickets, [], ticket_cases()} ]. @@ -161,6 +185,34 @@ api_op_with_timeout_cases() -> api_to_recvmsg_tcp6 ]. +%% These cases tests what happens when the controlling process dies +controlling_process_cases() -> + [ + socket_cleanup_tcp4, + socket_cleanup_tcp6, + socket_cleanup_udp4, + socket_cleanup_udp6, + + socket_close_tcp4, + socket_close_tcp6, + socket_close_udp4, + socket_close_udp6, + + recv_response_local_close_tcp4, + recv_response_local_close_tcp6, + recv_response_remote_close_tcp4, + recv_response_remote_close_tcp6, + + recvmsg_response_local_close_tcp4, + recvmsg_response_local_close_tcp6, + recvmsg_response_remote_close_tcp4, + recvmsg_response_remote_close_tcp6, + + acceptor_response_local_close_tcp4, + acceptor_response_local_close_tcp6, + acceptor_response_remote_close_tcp4, + acceptor_response_remote_close_tcp6 + ]. %% ticket_cases() -> %% []. @@ -183,6 +235,14 @@ end_per_testcase(_TC, Config) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% API BASIC %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Basically open (create) and close an IPv4 UDP (dgram) socket. @@ -549,7 +609,7 @@ api_b_send_and_recv_tcp(InitState) -> cmd => fun(#{lsock := LSock} = State) -> case socket:accept(LSock) of {ok, Sock} -> - ei("accepted: ~p", [Sock]), + ei("accepted: ~n ~p", [Sock]), {ok, State#{tsock => Sock}}; {error, _} = ERROR -> ERROR @@ -652,6 +712,14 @@ api_b_send_and_recv_tcp(InitState) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% API OPTIONS %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Perform some simple getopt and setopt with the level = otp options @@ -1163,6 +1231,14 @@ api_opt_simple_otp_controlling_process() -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% API OPERATIONS WITH TIMEOUT %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test the connect timeout option @@ -2717,6 +2793,482 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> end). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% CONTROLLING PROCESS %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test that the sockets are cleaned up +%% (removed) when the controlling process terminates (without explicitly +%% calling the close function). For a IPv4 TCP (stream) socket. + +socket_cleanup_tcp4(suite) -> + []; +socket_cleanup_tcp4(doc) -> + []; +socket_cleanup_tcp4(_Config) when is_list(_Config) -> + tc_try(socket_cleanup_tcp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = socket_cleanup(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test that the sockets are cleaned up +%% (removed) when the controlling process terminates (without explicitly +%% calling the close function). For a IPv6 TCP (stream) socket. + +socket_cleanup_tcp6(suite) -> + []; +socket_cleanup_tcp6(doc) -> + []; +socket_cleanup_tcp6(_Config) when is_list(_Config) -> + tc_try(socket_cleanup_tcp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6, + type => stream, + protocol => tcp}, + ok = socket_cleanup(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test that the sockets are cleaned up +%% (removed) when the controlling process terminates (without explicitly +%% calling the close function). For a IPv4 UDP (dgram) socket. + +socket_cleanup_udp4(suite) -> + []; +socket_cleanup_udp4(doc) -> + []; +socket_cleanup_udp4(_Config) when is_list(_Config) -> + tc_try(socket_cleanup_udp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => dgram, + protocol => udp}, + ok = socket_cleanup(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test that the sockets are cleaned up +%% (removed) when the controlling process terminates (without explicitly +%% calling the close function). For a IPv6 UDP (dgram) socket. + +socket_cleanup_udp6(suite) -> + []; +socket_cleanup_udp6(doc) -> + []; +socket_cleanup_udp6(_Config) when is_list(_Config) -> + tc_try(socket_cleanup_udp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6, + type => dgram, + protocol => udp}, + ok = socket_cleanup(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +socket_cleanup(_InitState) -> + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a process other +%% than the controlling process closes a socket. +%% For a IPv4 TCP (stream) socket. + +socket_close_tcp4(suite) -> + []; +socket_close_tcp4(doc) -> + []; +socket_close_tcp4(_Config) when is_list(_Config) -> + tc_try(socket_close_tcp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = socket_close(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a process other +%% than the controlling process closes a socket. +%% For a IPv6 TCP (stream) socket. + +socket_close_tcp6(suite) -> + []; +socket_close_tcp6(doc) -> + []; +socket_close_tcp6(_Config) when is_list(_Config) -> + tc_try(socket_close_tcp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6, + type => stream, + protocol => tcp}, + ok = socket_close(InitState) + end). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a process other +%% than the controlling process closes a socket. +%% For a IPv4 UDP (dgram) socket. + +socket_close_udp4(suite) -> + []; +socket_close_udp4(doc) -> + []; +socket_close_udp4(_Config) when is_list(_Config) -> + tc_try(socket_close_udp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => dgram, + protocol => udp}, + ok = socket_close(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a process other +%% than the controlling process closes a socket. +%% For a IPv6 UDP (dgram) socket. + +socket_close_udp6(suite) -> + []; +socket_close_udp6(doc) -> + []; +socket_close_udp6(_Config) when is_list(_Config) -> + tc_try(socket_close_udp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet6, + type => dgram, + protocol => udp}, + ok = socket_close(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +socket_close(_InitState) -> + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the recv function. +%% Socket is IPv4. + +recv_response_local_close_tcp4(suite) -> + []; +recv_response_local_close_tcp4(doc) -> + []; +recv_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(recv_response_local_close_tcp4, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recv(Sock) end, + InitState = #{domain => inet, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the recv function. +%% Socket is IPv6. + +recv_response_local_close_tcp6(suite) -> + []; +recv_response_local_close_tcp6(doc) -> + []; +recv_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(recv_response_local_close_tcp6, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recv(Sock) end, + InitState = #{domain => inet6, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +receive_response_local_close_tcp(_InitState) -> + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the recv function. +%% Socket is IPv4. + +recv_response_remote_close_tcp4(suite) -> + []; +recv_response_remote_close_tcp4(doc) -> + []; +recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(recv_response_remote_close_tcp4, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recv(Sock) end, + InitState = #{domain => inet, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the recv function. +%% Socket is IPv6. + +recv_response_remote_close_tcp6(suite) -> + []; +recv_response_remote_close_tcp6(doc) -> + []; +recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> + tc_try(recv_response_remote_close_tcp6, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recv(Sock) end, + InitState = #{domain => inet6, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +receive_response_remote_close_tcp(_InitState) -> + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the recvmsg function. +%% Socket is IPv4. + +recvmsg_response_local_close_tcp4(suite) -> + []; +recvmsg_response_local_close_tcp4(doc) -> + []; +recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(recvmsg_response_local_close_tcp4, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recvmsg(Sock) end, + InitState = #{domain => inet, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the recvmsg function. +%% Socket is IPv6. + +recvmsg_response_local_close_tcp6(suite) -> + []; +recvmsg_response_local_close_tcp6(doc) -> + []; +recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(recvmsg_response_local_close_tcp6, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recvmsg(Sock) end, + InitState = #{domain => inet6, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the recvmsg function. +%% Socket is IPv4. + +recvmsg_response_remote_close_tcp4(suite) -> + []; +recvmsg_response_remote_close_tcp4(doc) -> + []; +recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(recvmsg_response_remote_close_tcp4, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recvmsg(Sock) end, + InitState = #{domain => inet, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the recvmsg function. +%% Socket is IPv6. + +recvmsg_response_remote_close_tcp6(suite) -> + []; +recvmsg_response_remote_close_tcp6(doc) -> + []; +recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> + tc_try(recvmsg_response_remote_close_tcp6, + fun() -> + not_yet_implemented(), + Recv = fun(Sock) -> socket:recvmsg(Sock) end, + InitState = #{domain => inet6, + type => stream, + protocol => tcp, + recv => Recv}, + ok = receive_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the accept function. +%% We test what happens with a non-controlling_process also, since we +%% git the setup anyway. +%% Socket is IPv4. + +acceptor_response_local_close_tcp4(suite) -> + []; +acceptor_response_local_close_tcp4(doc) -> + []; +acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(acceptor_response_local_close_tcp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = acceptor_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% locally closed while the process is calling the accept function. +%% We test what happens with a non-controlling_process also, since we +%% git the setup anyway. +%% Socket is IPv6. + +acceptor_response_local_close_tcp6(suite) -> + []; +acceptor_response_local_close_tcp6(doc) -> + []; +acceptor_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(acceptor_response_local_close_tcp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = acceptor_response_local_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +acceptor_response_local_close_tcp(_InitState) -> + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the accept function. +%% We test what happens with a non-controlling_process also, since we +%% git the setup anyway. +%% Socket is IPv4. + +acceptor_response_remote_close_tcp4(suite) -> + []; +acceptor_response_remote_close_tcp4(doc) -> + []; +acceptor_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(acceptor_response_remote_close_tcp4, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = acceptor_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This test case is intended to test what happens when a socket is +%% remotely closed while the process is calling the accept function. +%% We test what happens with a non-controlling_process also, since we +%% git the setup anyway. +%% Socket is IPv6. + +acceptor_response_remote_close_tcp6(suite) -> + []; +acceptor_response_remote_close_tcp6(doc) -> + []; +acceptor_response_remote_close_tcp6(_Config) when is_list(_Config) -> + tc_try(acceptor_response_remote_close_tcp6, + fun() -> + not_yet_implemented(), + InitState = #{domain => inet, + type => stream, + protocol => tcp}, + ok = acceptor_response_remote_close_tcp(InitState) + end). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +acceptor_response_remote_close_tcp(_InitState) -> + ok. + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From f2481d58a2fb64b8f3c7cbb26e09cb17c04726e0 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 15 Oct 2018 18:31:43 +0200 Subject: [socket-nif|test] Added two test cases regarding exiting owner Added two (working) test cases for testing "socket cleanup" when the controlling-process exits. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 487 +++++++++++++++++++++------------------ 1 file changed, 265 insertions(+), 222 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 71e6dff174..42420a37dc 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -67,26 +67,22 @@ api_to_recvmsg_tcp6/1, %% Controlling Process - socket_cleanup_tcp4/1, - socket_cleanup_tcp6/1, - socket_cleanup_udp4/1, - socket_cleanup_udp6/1, - socket_close_tcp4/1, - socket_close_tcp6/1, - socket_close_udp4/1, - socket_close_udp6/1, - recv_response_local_close_tcp4/1, - recv_response_local_close_tcp6/1, - recv_response_remote_close_tcp4/1, - recv_response_remote_close_tcp6/1, - recvmsg_response_local_close_tcp4/1, - recvmsg_response_local_close_tcp6/1, - recvmsg_response_remote_close_tcp4/1, - recvmsg_response_remote_close_tcp6/1, - acceptor_response_local_close_tcp4/1, - acceptor_response_local_close_tcp6/1, - acceptor_response_remote_close_tcp4/1, - acceptor_response_remote_close_tcp6/1 + sc_socket_cleanup_tcp4/1, + sc_socket_cleanup_tcp6/1, + sc_socket_cleanup_udp4/1, + sc_socket_cleanup_udp6/1, + sc_recv_response_local_close_tcp4/1, + sc_recv_response_local_close_tcp6/1, + sc_recv_response_remote_close_tcp4/1, + sc_recv_response_remote_close_tcp6/1, + sc_recvmsg_response_local_close_tcp4/1, + sc_recvmsg_response_local_close_tcp6/1, + sc_recvmsg_response_remote_close_tcp4/1, + sc_recvmsg_response_remote_close_tcp6/1, + sc_acceptor_response_local_close_tcp4/1, + sc_acceptor_response_local_close_tcp6/1, + sc_acceptor_response_remote_close_tcp4/1, + sc_acceptor_response_remote_close_tcp6/1 %% Tickets ]). @@ -125,7 +121,7 @@ suite() -> all() -> [ {group, api}, - {group, controlling_process} + {group, socket_closure} %% {group, tickets} ]. @@ -134,7 +130,7 @@ groups() -> {api_basic, [], api_basic_cases()}, {api_options, [], api_options_cases()}, {api_op_with_timeout, [], api_op_with_timeout_cases()}, - {controlling_process, [], controlling_process_cases()} + {socket_closure, [], socket_closure_cases()} %% {tickets, [], ticket_cases()} ]. @@ -185,33 +181,29 @@ api_op_with_timeout_cases() -> api_to_recvmsg_tcp6 ]. -%% These cases tests what happens when the controlling process dies -controlling_process_cases() -> +%% These cases tests what happens when the socket is closed, locally or +%% remotely. +socket_closure_cases() -> [ - socket_cleanup_tcp4, - socket_cleanup_tcp6, - socket_cleanup_udp4, - socket_cleanup_udp6, - - socket_close_tcp4, - socket_close_tcp6, - socket_close_udp4, - socket_close_udp6, - - recv_response_local_close_tcp4, - recv_response_local_close_tcp6, - recv_response_remote_close_tcp4, - recv_response_remote_close_tcp6, - - recvmsg_response_local_close_tcp4, - recvmsg_response_local_close_tcp6, - recvmsg_response_remote_close_tcp4, - recvmsg_response_remote_close_tcp6, - - acceptor_response_local_close_tcp4, - acceptor_response_local_close_tcp6, - acceptor_response_remote_close_tcp4, - acceptor_response_remote_close_tcp6 + sc_socket_cleanup_tcp4, + sc_socket_cleanup_tcp6, + sc_socket_cleanup_udp4, + sc_socket_cleanup_udp6, + + sc_recv_response_local_close_tcp4, + sc_recv_response_local_close_tcp6, + sc_recv_response_remote_close_tcp4, + sc_recv_response_remote_close_tcp6, + + sc_recvmsg_response_local_close_tcp4, + sc_recvmsg_response_local_close_tcp6, + sc_recvmsg_response_remote_close_tcp4, + sc_recvmsg_response_remote_close_tcp6, + + sc_acceptor_response_local_close_tcp4, + sc_acceptor_response_local_close_tcp6, + sc_acceptor_response_remote_close_tcp4, + sc_acceptor_response_remote_close_tcp6 ]. %% ticket_cases() -> @@ -1337,7 +1329,9 @@ api_to_connect_tcp(InitState) -> cmd => fun(#{tester := Tester} = State) -> receive {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; {terminate, Tester} -> {ok, maps:remove(tester, State)} end @@ -1734,7 +1728,9 @@ api_to_maccept_tcp(InitState) -> cmd => fun(#{tester := Tester} = _State) -> receive {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; {continue, Tester} -> ok end @@ -1774,7 +1770,9 @@ api_to_maccept_tcp(InitState) -> cmd => fun(#{tester := Tester} = _State) -> receive {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; {terminate, Tester} -> ok end @@ -2797,68 +2795,67 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% -%% CONTROLLING PROCESS %% +%% SOCKET CLOSURE %% %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test that the sockets are cleaned up -%% (removed) when the controlling process terminates (without explicitly +%% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 TCP (stream) socket. -socket_cleanup_tcp4(suite) -> +sc_socket_cleanup_tcp4(suite) -> []; -socket_cleanup_tcp4(doc) -> +sc_socket_cleanup_tcp4(doc) -> []; -socket_cleanup_tcp4(_Config) when is_list(_Config) -> - tc_try(socket_cleanup_tcp4, +sc_socket_cleanup_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_socket_cleanup_tcp4, fun() -> - not_yet_implemented(), + %% not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = socket_cleanup(InitState) + ok = sc_socket_cleanup(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test that the sockets are cleaned up -%% (removed) when the controlling process terminates (without explicitly +%% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 TCP (stream) socket. -socket_cleanup_tcp6(suite) -> +sc_socket_cleanup_tcp6(suite) -> []; -socket_cleanup_tcp6(doc) -> +sc_socket_cleanup_tcp6(doc) -> []; -socket_cleanup_tcp6(_Config) when is_list(_Config) -> - tc_try(socket_cleanup_tcp6, +sc_socket_cleanup_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_socket_cleanup_tcp6, fun() -> not_yet_implemented(), InitState = #{domain => inet6, type => stream, protocol => tcp}, - ok = socket_cleanup(InitState) + ok = sc_socket_cleanup(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test that the sockets are cleaned up -%% (removed) when the controlling process terminates (without explicitly +%% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 UDP (dgram) socket. -socket_cleanup_udp4(suite) -> +sc_socket_cleanup_udp4(suite) -> []; -socket_cleanup_udp4(doc) -> +sc_socket_cleanup_udp4(doc) -> []; -socket_cleanup_udp4(_Config) when is_list(_Config) -> - tc_try(socket_cleanup_udp4, +sc_socket_cleanup_udp4(_Config) when is_list(_Config) -> + tc_try(sc_socket_cleanup_udp4, fun() -> - not_yet_implemented(), InitState = #{domain => inet, type => dgram, protocol => udp}, - ok = socket_cleanup(InitState) + ok = sc_socket_cleanup(InitState) end). @@ -2868,113 +2865,159 @@ socket_cleanup_udp4(_Config) when is_list(_Config) -> %% (removed) when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 UDP (dgram) socket. -socket_cleanup_udp6(suite) -> +sc_socket_cleanup_udp6(suite) -> []; -socket_cleanup_udp6(doc) -> +sc_socket_cleanup_udp6(doc) -> []; -socket_cleanup_udp6(_Config) when is_list(_Config) -> - tc_try(socket_cleanup_udp6, +sc_socket_cleanup_udp6(_Config) when is_list(_Config) -> + tc_try(sc_socket_cleanup_udp6, fun() -> not_yet_implemented(), InitState = #{domain => inet6, type => dgram, protocol => udp}, - ok = socket_cleanup(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -socket_cleanup(_InitState) -> - ok. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a process other -%% than the controlling process closes a socket. -%% For a IPv4 TCP (stream) socket. - -socket_close_tcp4(suite) -> - []; -socket_close_tcp4(doc) -> - []; -socket_close_tcp4(_Config) when is_list(_Config) -> - tc_try(socket_close_tcp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = socket_close(InitState) + ok = sc_socket_cleanup(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a process other -%% than the controlling process closes a socket. -%% For a IPv6 TCP (stream) socket. - -socket_close_tcp6(suite) -> - []; -socket_close_tcp6(doc) -> - []; -socket_close_tcp6(_Config) when is_list(_Config) -> - tc_try(socket_close_tcp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, - type => stream, - protocol => tcp}, - ok = socket_close(InitState) - end). +sc_socket_cleanup(InitState) -> + OwnerSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + %% *** Init part *** + #{desc => "monitor tester", + cmd => fun(#{tester := Tester} = _State) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Proto} = State) -> + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester, sock := Sock} = _State) -> + Tester ! {ready, self(), Sock}, + ok + end}, -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a process other -%% than the controlling process closes a socket. -%% For a IPv4 UDP (dgram) socket. - -socket_close_udp4(suite) -> - []; -socket_close_udp4(doc) -> - []; -socket_close_udp4(_Config) when is_list(_Config) -> - tc_try(socket_close_udp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => dgram, - protocol => udp}, - ok = socket_close(InitState) - end). - + %% *** The actual test *** + %% We intentially leave the socket "as is", no explicit close + #{desc => "await terminate (from tester)", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {terminate, Tester} -> + {ok, maps:remove(tester, State)} + end + end}, + #{desc => "enable (otp) debug", + cmd => fun(#{sock := Sock} = _State) -> + ok = socket:setopt(Sock, otp, debug, true) + end}, -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a process other -%% than the controlling process closes a socket. -%% For a IPv6 UDP (dgram) socket. + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], -socket_close_udp6(suite) -> - []; -socket_close_udp6(doc) -> - []; -socket_close_udp6(_Config) when is_list(_Config) -> - tc_try(socket_close_udp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, - type => dgram, - protocol => udp}, - ok = socket_close(InitState) - end). + TesterSeq = + [ + %% *** Init part *** + #{desc => "monitor owner", + cmd => fun(#{owner := Owner} = _State) -> + _MRef = erlang:monitor(process, Owner), + ok + end}, + #{desc => "order (owner) start", + cmd => fun(#{owner := Pid} = _State) -> + Pid ! {start, self()}, + ok + end}, + #{desc => "await (owner) ready", + cmd => fun(#{owner := Owner} = State) -> + receive + {'DOWN', _, process, Owner, Reason} -> + ee("Unexpected DOWN regarding owner ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, owner}}; + {ready, Owner, Sock} -> + {ok, State#{sock => Sock}} + end + end}, + #{desc => "verify owner as controlling-process", + cmd => fun(#{owner := Owner, sock := Sock} = _State) -> + case socket:getopt(Sock, otp, controlling_process) of + {ok, Owner} -> + ok; + {ok, Other} -> + {error, {unexpected_owner, Other}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "order (owner) terminate", + cmd => fun(#{owner := Pid} = _State) -> + Pid ! {terminate, self()}, + ok + end}, + #{desc => "await (owner) termination", + cmd => fun(#{owner := Owner} = _State) -> + receive + {'DOWN', _, process, Owner, _} -> + ok + end + end}, + #{desc => "verify no socket (closed)", + cmd => fun(#{owner := Owner, sock := Sock} = _State) -> + case socket:getopt(Sock, otp, controlling_process) of + {ok, Pid} -> + {error, {unexpected_success, Owner, Pid}}; + {error, closed} -> + ok; + {error, Reason} -> + ei("expected failure: ~p", [Reason]), + {error, {unexpected_failure, Reason}} + end + end}, + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + p("start (socket) owner evaluator"), + Owner = evaluator_start("owner", OwnerSeq, InitState), -socket_close(_InitState) -> - ok. + p("start tester evaluator"), + TesterInitState = #{owner => Owner}, + Tester = evaluator_start("tester", TesterSeq, TesterInitState), + p("await evaluator"), + ok = await_evaluator_finish([Owner, Tester]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2982,12 +3025,12 @@ socket_close(_InitState) -> %% locally closed while the process is calling the recv function. %% Socket is IPv4. -recv_response_local_close_tcp4(suite) -> +sc_recv_response_local_close_tcp4(suite) -> []; -recv_response_local_close_tcp4(doc) -> +sc_recv_response_local_close_tcp4(doc) -> []; -recv_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(recv_response_local_close_tcp4, +sc_recv_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_recv_response_local_close_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -2995,7 +3038,7 @@ recv_response_local_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_local_close_tcp(InitState) + ok = sc_receive_response_local_close_tcp(InitState) end). @@ -3004,12 +3047,12 @@ recv_response_local_close_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is IPv6. -recv_response_local_close_tcp6(suite) -> +sc_recv_response_local_close_tcp6(suite) -> []; -recv_response_local_close_tcp6(doc) -> +sc_recv_response_local_close_tcp6(doc) -> []; -recv_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(recv_response_local_close_tcp6, +sc_recv_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_recv_response_local_close_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3017,13 +3060,13 @@ recv_response_local_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_local_close_tcp(InitState) + ok = sc_receive_response_local_close_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -receive_response_local_close_tcp(_InitState) -> +sc_receive_response_local_close_tcp(_InitState) -> ok. @@ -3033,12 +3076,12 @@ receive_response_local_close_tcp(_InitState) -> %% remotely closed while the process is calling the recv function. %% Socket is IPv4. -recv_response_remote_close_tcp4(suite) -> +sc_recv_response_remote_close_tcp4(suite) -> []; -recv_response_remote_close_tcp4(doc) -> +sc_recv_response_remote_close_tcp4(doc) -> []; -recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(recv_response_remote_close_tcp4, +sc_recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_recv_response_remote_close_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3046,7 +3089,7 @@ recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_remote_close_tcp(InitState) + ok = sc_receive_response_remote_close_tcp(InitState) end). @@ -3055,12 +3098,12 @@ recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recv function. %% Socket is IPv6. -recv_response_remote_close_tcp6(suite) -> +sc_recv_response_remote_close_tcp6(suite) -> []; -recv_response_remote_close_tcp6(doc) -> +sc_recv_response_remote_close_tcp6(doc) -> []; -recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> - tc_try(recv_response_remote_close_tcp6, +sc_recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_recv_response_remote_close_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3068,13 +3111,13 @@ recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_remote_close_tcp(InitState) + ok = sc_receive_response_remote_close_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -receive_response_remote_close_tcp(_InitState) -> +sc_receive_response_remote_close_tcp(_InitState) -> ok. @@ -3084,12 +3127,12 @@ receive_response_remote_close_tcp(_InitState) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv4. -recvmsg_response_local_close_tcp4(suite) -> +sc_recvmsg_response_local_close_tcp4(suite) -> []; -recvmsg_response_local_close_tcp4(doc) -> +sc_recvmsg_response_local_close_tcp4(doc) -> []; -recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(recvmsg_response_local_close_tcp4, +sc_recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_recvmsg_response_local_close_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3097,7 +3140,7 @@ recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_local_close_tcp(InitState) + ok = sc_receive_response_local_close_tcp(InitState) end). @@ -3106,12 +3149,12 @@ recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv6. -recvmsg_response_local_close_tcp6(suite) -> +sc_recvmsg_response_local_close_tcp6(suite) -> []; -recvmsg_response_local_close_tcp6(doc) -> +sc_recvmsg_response_local_close_tcp6(doc) -> []; -recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(recvmsg_response_local_close_tcp6, +sc_recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_recvmsg_response_local_close_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3119,7 +3162,7 @@ recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_local_close_tcp(InitState) + ok = sc_receive_response_local_close_tcp(InitState) end). @@ -3128,12 +3171,12 @@ recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv4. -recvmsg_response_remote_close_tcp4(suite) -> +sc_recvmsg_response_remote_close_tcp4(suite) -> []; -recvmsg_response_remote_close_tcp4(doc) -> +sc_recvmsg_response_remote_close_tcp4(doc) -> []; -recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(recvmsg_response_remote_close_tcp4, +sc_recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_recvmsg_response_remote_close_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3141,7 +3184,7 @@ recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_remote_close_tcp(InitState) + ok = sc_receive_response_remote_close_tcp(InitState) end). @@ -3150,12 +3193,12 @@ recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv6. -recvmsg_response_remote_close_tcp6(suite) -> +sc_recvmsg_response_remote_close_tcp6(suite) -> []; -recvmsg_response_remote_close_tcp6(doc) -> +sc_recvmsg_response_remote_close_tcp6(doc) -> []; -recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> - tc_try(recvmsg_response_remote_close_tcp6, +sc_recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_recvmsg_response_remote_close_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3163,7 +3206,7 @@ recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = receive_response_remote_close_tcp(InitState) + ok = sc_receive_response_remote_close_tcp(InitState) end). @@ -3174,18 +3217,18 @@ recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv4. -acceptor_response_local_close_tcp4(suite) -> +sc_acceptor_response_local_close_tcp4(suite) -> []; -acceptor_response_local_close_tcp4(doc) -> +sc_acceptor_response_local_close_tcp4(doc) -> []; -acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(acceptor_response_local_close_tcp4, +sc_acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_acceptor_response_local_close_tcp4, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = acceptor_response_local_close_tcp(InitState) + ok = sc_acceptor_response_local_close_tcp(InitState) end). @@ -3196,24 +3239,24 @@ acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv6. -acceptor_response_local_close_tcp6(suite) -> +sc_acceptor_response_local_close_tcp6(suite) -> []; -acceptor_response_local_close_tcp6(doc) -> +sc_acceptor_response_local_close_tcp6(doc) -> []; -acceptor_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(acceptor_response_local_close_tcp6, +sc_acceptor_response_local_close_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_acceptor_response_local_close_tcp6, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = acceptor_response_local_close_tcp(InitState) + ok = sc_acceptor_response_local_close_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -acceptor_response_local_close_tcp(_InitState) -> +sc_acceptor_response_local_close_tcp(_InitState) -> ok. @@ -3225,18 +3268,18 @@ acceptor_response_local_close_tcp(_InitState) -> %% git the setup anyway. %% Socket is IPv4. -acceptor_response_remote_close_tcp4(suite) -> +sc_acceptor_response_remote_close_tcp4(suite) -> []; -acceptor_response_remote_close_tcp4(doc) -> +sc_acceptor_response_remote_close_tcp4(doc) -> []; -acceptor_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(acceptor_response_remote_close_tcp4, +sc_acceptor_response_remote_close_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_acceptor_response_remote_close_tcp4, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = acceptor_response_remote_close_tcp(InitState) + ok = sc_acceptor_response_remote_close_tcp(InitState) end). @@ -3247,24 +3290,24 @@ acceptor_response_remote_close_tcp4(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv6. -acceptor_response_remote_close_tcp6(suite) -> +sc_acceptor_response_remote_close_tcp6(suite) -> []; -acceptor_response_remote_close_tcp6(doc) -> +sc_acceptor_response_remote_close_tcp6(doc) -> []; -acceptor_response_remote_close_tcp6(_Config) when is_list(_Config) -> +sc_acceptor_response_remote_close_tcp6(_Config) when is_list(_Config) -> tc_try(acceptor_response_remote_close_tcp6, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = acceptor_response_remote_close_tcp(InitState) + ok = sc_acceptor_response_remote_close_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -acceptor_response_remote_close_tcp(_InitState) -> +sc_acceptor_response_remote_close_tcp(_InitState) -> ok. -- cgit v1.2.3 From f945aa4a8067d745ee75fe695272104e220d7bc3 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Tue, 16 Oct 2018 15:57:17 +0200 Subject: [socket-nif|test] Added test case for closed socket while recv Added a test cases for testing "socket cleanup" while process is reading using recv. OTP-14831 --- lib/kernel/test/socket_SUITE.erl | 632 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 596 insertions(+), 36 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 42420a37dc..8ab39f6ffe 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -66,11 +66,11 @@ api_to_recvmsg_tcp4/1, api_to_recvmsg_tcp6/1, - %% Controlling Process - sc_socket_cleanup_tcp4/1, - sc_socket_cleanup_tcp6/1, - sc_socket_cleanup_udp4/1, - sc_socket_cleanup_udp6/1, + %% Socket Closure + sc_cpe_socket_cleanup_tcp4/1, + sc_cpe_socket_cleanup_tcp6/1, + sc_cpe_socket_cleanup_udp4/1, + sc_cpe_socket_cleanup_udp6/1, sc_recv_response_local_close_tcp4/1, sc_recv_response_local_close_tcp6/1, sc_recv_response_remote_close_tcp4/1, @@ -130,7 +130,8 @@ groups() -> {api_basic, [], api_basic_cases()}, {api_options, [], api_options_cases()}, {api_op_with_timeout, [], api_op_with_timeout_cases()}, - {socket_closure, [], socket_closure_cases()} + {socket_closure, [], socket_closure_cases()}, + {sc_ctrl_proc_exit, [], sc_cp_exit_cases()} %% {tickets, [], ticket_cases()} ]. @@ -185,10 +186,7 @@ api_op_with_timeout_cases() -> %% remotely. socket_closure_cases() -> [ - sc_socket_cleanup_tcp4, - sc_socket_cleanup_tcp6, - sc_socket_cleanup_udp4, - sc_socket_cleanup_udp6, + {group, sc_ctrl_proc_exit}, sc_recv_response_local_close_tcp4, sc_recv_response_local_close_tcp6, @@ -206,6 +204,16 @@ socket_closure_cases() -> sc_acceptor_response_remote_close_tcp6 ]. +%% These cases are all about socket cleanup after the controlling process +%% exits *without* calling socket:close/1. +sc_cp_exit_cases() -> + [ + sc_cpe_socket_cleanup_tcp4, + sc_cpe_socket_cleanup_tcp6, + sc_cpe_socket_cleanup_udp4, + sc_cpe_socket_cleanup_udp6 + ]. + %% ticket_cases() -> %% []. @@ -1782,7 +1790,7 @@ api_to_maccept_tcp(InitState) -> #{desc => "close (listen) socket", cmd => fun(#{lsock := LSock} = State) -> sock_close(LSock), - {ok, maps:remove(sock3, State)} + {ok, maps:remove(lsock, State)} end}, %% *** We are done *** @@ -2805,18 +2813,18 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 TCP (stream) socket. -sc_socket_cleanup_tcp4(suite) -> +sc_cpe_socket_cleanup_tcp4(suite) -> []; -sc_socket_cleanup_tcp4(doc) -> +sc_cpe_socket_cleanup_tcp4(doc) -> []; -sc_socket_cleanup_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_socket_cleanup_tcp4, +sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_cpe_socket_cleanup_tcp4, fun() -> %% not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = sc_socket_cleanup(InitState) + ok = sc_cpe_socket_cleanup(InitState) end). @@ -2825,18 +2833,18 @@ sc_socket_cleanup_tcp4(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 TCP (stream) socket. -sc_socket_cleanup_tcp6(suite) -> +sc_cpe_socket_cleanup_tcp6(suite) -> []; -sc_socket_cleanup_tcp6(doc) -> +sc_cpe_socket_cleanup_tcp6(doc) -> []; -sc_socket_cleanup_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_socket_cleanup_tcp6, +sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_cpe_socket_cleanup_tcp6, fun() -> not_yet_implemented(), InitState = #{domain => inet6, type => stream, protocol => tcp}, - ok = sc_socket_cleanup(InitState) + ok = sc_cpe_socket_cleanup(InitState) end). @@ -2845,17 +2853,17 @@ sc_socket_cleanup_tcp6(_Config) when is_list(_Config) -> %% ("removed") when the controlling process terminates (without explicitly %% calling the close function). For a IPv4 UDP (dgram) socket. -sc_socket_cleanup_udp4(suite) -> +sc_cpe_socket_cleanup_udp4(suite) -> []; -sc_socket_cleanup_udp4(doc) -> +sc_cpe_socket_cleanup_udp4(doc) -> []; -sc_socket_cleanup_udp4(_Config) when is_list(_Config) -> - tc_try(sc_socket_cleanup_udp4, +sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) -> + tc_try(sc_cpe_socket_cleanup_udp4, fun() -> InitState = #{domain => inet, type => dgram, protocol => udp}, - ok = sc_socket_cleanup(InitState) + ok = sc_cpe_socket_cleanup(InitState) end). @@ -2865,24 +2873,24 @@ sc_socket_cleanup_udp4(_Config) when is_list(_Config) -> %% (removed) when the controlling process terminates (without explicitly %% calling the close function). For a IPv6 UDP (dgram) socket. -sc_socket_cleanup_udp6(suite) -> +sc_cpe_socket_cleanup_udp6(suite) -> []; -sc_socket_cleanup_udp6(doc) -> +sc_cpe_socket_cleanup_udp6(doc) -> []; -sc_socket_cleanup_udp6(_Config) when is_list(_Config) -> - tc_try(sc_socket_cleanup_udp6, +sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) -> + tc_try(sc_cpe_socket_cleanup_udp6, fun() -> not_yet_implemented(), InitState = #{domain => inet6, type => dgram, protocol => udp}, - ok = sc_socket_cleanup(InitState) + ok = sc_cpe_socket_cleanup(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sc_socket_cleanup(InitState) -> +sc_cpe_socket_cleanup(InitState) -> OwnerSeq = [ %% *** Wait for start order part *** @@ -3022,8 +3030,16 @@ sc_socket_cleanup(InitState) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the recv function. +%% locally closed while a process is calling the recv function. %% Socket is IPv4. +%% +%% +%% +%% We should really have a similar test cases for when the controlling +%% process exits and there are other processes in recv, accept, and +%% all the other functions. +%% +%% sc_recv_response_local_close_tcp4(suite) -> []; @@ -3032,7 +3048,7 @@ sc_recv_response_local_close_tcp4(doc) -> sc_recv_response_local_close_tcp4(_Config) when is_list(_Config) -> tc_try(sc_recv_response_local_close_tcp4, fun() -> - not_yet_implemented(), + %% not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, InitState = #{domain => inet, type => stream, @@ -3066,8 +3082,548 @@ sc_recv_response_local_close_tcp6(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sc_receive_response_local_close_tcp(_InitState) -> - ok. +sc_receive_response_local_close_tcp(InitState) -> + %% This is the server that accepts connections. + %% But it is also suppose to close the connection socket, + %% and trigger the read failure for the handler process. + AcceptorSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + #{desc => "monitor tester", + cmd => fun(#{tester := Tester} = _State) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + + %% *** Init part *** + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create (listen) socket", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Proto} = State) -> + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + {ok, State#{lsock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind to local address", + cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> + case socket:bind(LSock, LSA) of + {ok, Port} -> + {ok, State#{lport => Port}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "make listen socket", + cmd => fun(#{lsock := LSock}) -> + socket:listen(LSock) + end}, + #{desc => "announce ready (init)", + cmd => fun(#{tester := Tester, lport := Port}) -> + Tester ! {ready, self(), Port}, + ok + end}, + + %% The actual test + #{desc => "await continue (connection)", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {continue, Tester, Handler} -> + {ok, State#{handler => Handler}} + end + end}, + #{desc => "await connection", + cmd => fun(#{lsock := LSock} = State) -> + case socket:accept(LSock) of + {ok, Sock} -> + ei("connection accepted"), + {ok, State#{csock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "transfer new connection to handler", + cmd => fun(#{handler := Handler, csock := Sock}) -> + ok = socket:setopt(Sock, + otp, controlling_process, + Handler), + Handler ! {connection, Sock}, + ok + end}, + #{desc => "announce ready (connection)", + cmd => fun(#{tester := Tester}) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "await continue (close)", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {continue, Tester} -> + ok + end + end}, + %% #{desc => "enable debug", + %% cmd => fun(#{csock := Sock}) -> + %% socket:setopt(Sock, otp, debug, true) + %% end}, + #{desc => "close (the connection) socket", + cmd => fun(#{csock := Sock}) -> + socket:close(Sock) + end}, + + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {terminate, Tester} -> + {ok, maps:remove(tester, State)} + end + end}, + #{desc => "socket cleanup", + cmd => fun(#{lsock := Sock} = State) -> + ok = socket:close(Sock), + State1 = maps:remove(csock, State), + State2 = maps:remove(lsock, State1), + State3 = maps:remove(lport, State2), + {ok, State3} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + %% The point of this is to perform the recv for which we are testing the reponse + HandlerSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + #{desc => "monitor server", + cmd => fun(#{tester := Tester} = _State) -> + _MRef = erlang:monitor(process, Tester), + ok + end}, + #{desc => "announce ready (init)", + cmd => fun(#{tester := Tester}) -> + Tester ! {ready, self()}, + ok + end}, + + %% The actual test + #{desc => "await connection socket", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {connection, Sock} -> + {ok, State#{sock => Sock}} + end + end}, + #{desc => "announce ready (connection)", + cmd => fun(#{tester := Tester}) -> + Tester ! {ready, self()}, + ok + end}, + %% #{desc => "enable debug", + %% cmd => fun(#{sock := Sock}) -> + %% socket:setopt(Sock, otp, debug, true) + %% end}, + %% #{desc => "monitored-by", + %% cmd => fun(_) -> + %% {_, Mons} = process_info(self(), monitored_by), + %% ei("Monitored By: ~p", [Mons]), + %% ok + %% end}, + #{desc => "attempt recv", + cmd => fun(#{sock := Sock} = State) -> + case socket:recv(Sock) of + {ok, _Data} -> + ee("Unexpected data received"), + {error, unexpected_data}; + {error, closed} -> + State1 = maps:remove(sock, State), + {ok, State1}; + {error, Reason} = ERROR -> + ee("Unexpected read faulure: " + "~n ~p", [Reason]), + ERROR + end + end}, + %% #{desc => "monitored-by", + %% cmd => fun(_) -> + %% {_, Mons} = process_info(self(), monitored_by), + %% ei("Monitored By: ~p", [Mons]), + %% ok + %% end}, + #{desc => "announce ready (close)", + cmd => fun(#{tester := Tester}) -> + Tester ! {ready, self()}, + ok + end}, + #{desc => "sleep some", + cmd => fun(_) -> + ?SLEEP(1000), + ok + end}, + %% #{desc => "monitored-by", + %% cmd => fun(_) -> + %% {_, Mons} = process_info(self(), monitored_by), + %% ei("Monitored By: ~p", [Mons]), + %% ok + %% end}, + #{desc => "await terminate", + cmd => fun(#{tester := Tester} = _State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, tester}}; + {terminate, Tester} -> + ok + end + end}, + + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + %% The point of this is basically just to create the connection. + ClientSeq = + [ + %% *** Wait for start order part *** + #{desc => "await start (from tester)", + cmd => fun(State) -> + receive + {start, Tester} when is_pid(Tester) -> + {ok, State#{tester => Tester}} + end + end}, + + %% Init + #{desc => "which local address", + cmd => fun(#{domain := Domain} = State) -> + LAddr = which_local_addr(Domain), + LSA = #{family => Domain, addr => LAddr}, + {ok, State#{lsa => LSA}} + end}, + #{desc => "create socket", + cmd => fun(#{domain := Domain, + type := Type, + protocol := Proto} = State) -> + case socket:open(Domain, Type, Proto) of + {ok, Sock} -> + {ok, State#{sock => Sock}}; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "bind socket to local address", + cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> + case socket:bind(Sock, LSA) of + {ok, _} -> + ok; + {error, _} = ERROR -> + ERROR + end + end}, + #{desc => "announce ready", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + + %% The actual test + #{desc => "await continue", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Tester, Reason]), + {error, {unexpected_exit, tester, Reason}}; + {continue, Tester, Port} -> + {ok, State#{lport => Port}} + end + end}, + #{desc => "connect to server", + cmd => fun(#{sock := Sock, lsa := LSA, lport := LPort}) -> + socket:connect(Sock, LSA#{port => LPort}) + end}, + #{desc => "announce ready (connection)", + cmd => fun(#{tester := Tester} = _State) -> + Tester ! {ready, self()}, + ok + end}, + + %% Cleaning up + #{desc => "await terminate (from tester)", + cmd => fun(#{tester := Tester} = State) -> + receive + {'DOWN', _, process, Tester, Reason} -> + ee("Unexpected DOWN regarding tester ~p: " + "~n ~p", [Tester, Reason]), + {error, {unexpected_exit, tester}}; + {terminate, Tester} -> + {ok, maps:remove(tester, State)} + end + end}, + #{desc => "close socket", + cmd => fun(#{sock := Sock} = State) -> + sock_close(Sock), + {ok, maps:remove(sock, State)} + end}, + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + TesterSeq = + [ + %% *** Init part *** + #{desc => "monitor acceptor", + cmd => fun(#{acceptor := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + #{desc => "monitor handler", + cmd => fun(#{handler := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + #{desc => "monitor client", + cmd => fun(#{client := Pid} = _State) -> + _MRef = erlang:monitor(process, Pid), + ok + end}, + + %% Start the acceptor + #{desc => "order acceptor start", + cmd => fun(#{acceptor := Pid} = _State) -> + Pid ! {start, self()}, + ok + end}, + #{desc => "await acceptor ready (init)", + cmd => fun(#{acceptor := Pid} = State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding acceptor ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid, Port} -> + {ok, State#{lport => Port}} + end + end}, + + %% Start the handler + #{desc => "order handler start", + cmd => fun(#{handler := Pid} = _State) -> + Pid ! {start, self()}, + ok + end}, + #{desc => "await handler ready (init)", + cmd => fun(#{handler := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding handler ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + + %% Start the client + #{desc => "order client start", + cmd => fun(#{client := Pid} = _State) -> + Pid ! {start, self()}, + ok + end}, + #{desc => "await client ready (init)", + cmd => fun(#{client := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding cient ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + + %% The actual test + #{desc => "order acceptor to continue", + cmd => fun(#{acceptor := Pid, handler := Handler} = _State) -> + Pid ! {continue, self(), Handler}, + ok + end}, + #{desc => "order client to continue", + cmd => fun(#{client := Pid, lport := Port} = _State) -> + Pid ! {continue, self(), Port}, + ok + end}, + #{desc => "await acceptor ready (connection)", + cmd => fun(#{acceptor := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding acceptor ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + #{desc => "await client ready (connection)", + cmd => fun(#{client := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding client ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + #{desc => "await handler ready (connection)", + cmd => fun(#{handler := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding handler ~p: " + "~n ~p", [Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + #{desc => "sleep some", + cmd => fun(_State) -> + ?SLEEP(1000), + ok + end}, + #{desc => "order acceptor to continue (close)", + cmd => fun(#{acceptor := Pid} = _State) -> + Pid ! {continue, self()}, + ok + end}, + #{desc => "await handler ready (close)", + cmd => fun(#{handler := Pid} = _State) -> + receive + {'DOWN', _, process, Pid, Reason} -> + ee("Unexpected DOWN regarding handler ~p: " + "~n ~p", [Pid, Reason]), + {error, {unexpected_exit, acceptor}}; + {ready, Pid} -> + ok + end + end}, + + %% Terminations + #{desc => "order handler to terminate", + cmd => fun(#{handler := Pid} = _State) -> + Pid ! {terminate, self()}, + ok + end}, + #{desc => "await handler termination", + cmd => fun(#{handler := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + {ok, maps:remove(handler, State)} + end + end}, + #{desc => "order client to terminate", + cmd => fun(#{client := Pid} = _State) -> + Pid ! {terminate, self()}, + ok + end}, + #{desc => "await client termination", + cmd => fun(#{client := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + {ok, maps:remove(client, State)} + end + end}, + #{desc => "order acceptor to terminate", + cmd => fun(#{acceptor := Pid} = _State) -> + Pid ! {terminate, self()}, + ok + end}, + #{desc => "await acceptor termination", + cmd => fun(#{acceptor := Pid} = State) -> + receive + {'DOWN', _, process, Pid, _} -> + {ok, maps:remove(acceptor, State)} + end + end}, + + + %% *** We are done *** + #{desc => "finish", + cmd => fun(_) -> + {ok, normal} + end} + ], + + p("start acceptor evaluator"), + AccInitState = InitState, + Acceptor = evaluator_start("acceptor", AcceptorSeq, AccInitState), + + p("start handler evaluator"), + HandlerInitState = #{}, + Handler = evaluator_start("handler", HandlerSeq, HandlerInitState), + + p("start client evaluator"), + ClientInitState = InitState, + Client = evaluator_start("client", ClientSeq, ClientInitState), + + p("start tester evaluator"), + TesterInitState = #{acceptor => Acceptor, + handler => Handler, + client => Client}, + Tester = evaluator_start("tester", TesterSeq, TesterInitState), + + p("await evaluator"), + ok = await_evaluator_finish([Acceptor, Handler, Client, Tester]). @@ -3426,9 +3982,13 @@ await_evaluator_finish(Evs, Fails) -> end. +ei(F) -> + ei(F, []). ei(F, A) -> eprint("", F, A). +ee(F) -> + ee(F, []). ee(F, A) -> eprint(" ", F, A). -- cgit v1.2.3 From 598ecec8b59509f223807d36e9dd1244d7d80fa2 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 18 Oct 2018 16:25:47 +0200 Subject: [socket-nif|test] Some minor test case re-grouping --- lib/kernel/test/socket_SUITE.erl | 267 +++++++++++++++++++-------------------- 1 file changed, 128 insertions(+), 139 deletions(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 8ab39f6ffe..4ee2eec39a 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -71,18 +71,16 @@ sc_cpe_socket_cleanup_tcp6/1, sc_cpe_socket_cleanup_udp4/1, sc_cpe_socket_cleanup_udp6/1, - sc_recv_response_local_close_tcp4/1, - sc_recv_response_local_close_tcp6/1, - sc_recv_response_remote_close_tcp4/1, - sc_recv_response_remote_close_tcp6/1, - sc_recvmsg_response_local_close_tcp4/1, - sc_recvmsg_response_local_close_tcp6/1, - sc_recvmsg_response_remote_close_tcp4/1, - sc_recvmsg_response_remote_close_tcp6/1, - sc_acceptor_response_local_close_tcp4/1, - sc_acceptor_response_local_close_tcp6/1, - sc_acceptor_response_remote_close_tcp4/1, - sc_acceptor_response_remote_close_tcp6/1 + sc_lc_recv_response_tcp4/1, + sc_lc_recv_response_tcp6/1, + sc_lc_recvmsg_response_tcp4/1, + sc_lc_recvmsg_response_tcp6/1, + sc_lc_acceptor_response_tcp4/1, + sc_lc_acceptor_response_tcp6/1, + sc_rc_recv_response_tcp4/1, + sc_rc_recv_response_tcp6/1, + sc_rc_recvmsg_response_tcp4/1, + sc_rc_recvmsg_response_tcp6/1 %% Tickets ]). @@ -131,7 +129,9 @@ groups() -> {api_options, [], api_options_cases()}, {api_op_with_timeout, [], api_op_with_timeout_cases()}, {socket_closure, [], socket_closure_cases()}, - {sc_ctrl_proc_exit, [], sc_cp_exit_cases()} + {sc_ctrl_proc_exit, [], sc_cp_exit_cases()}, + {sc_local_close, [], sc_lc_cases()}, + {sc_remote_close, [], sc_rc_cases()} %% {tickets, [], ticket_cases()} ]. @@ -187,21 +187,8 @@ api_op_with_timeout_cases() -> socket_closure_cases() -> [ {group, sc_ctrl_proc_exit}, - - sc_recv_response_local_close_tcp4, - sc_recv_response_local_close_tcp6, - sc_recv_response_remote_close_tcp4, - sc_recv_response_remote_close_tcp6, - - sc_recvmsg_response_local_close_tcp4, - sc_recvmsg_response_local_close_tcp6, - sc_recvmsg_response_remote_close_tcp4, - sc_recvmsg_response_remote_close_tcp6, - - sc_acceptor_response_local_close_tcp4, - sc_acceptor_response_local_close_tcp6, - sc_acceptor_response_remote_close_tcp4, - sc_acceptor_response_remote_close_tcp6 + {group, sc_local_close}, + {group, sc_remote_close} ]. %% These cases are all about socket cleanup after the controlling process @@ -214,6 +201,30 @@ sc_cp_exit_cases() -> sc_cpe_socket_cleanup_udp6 ]. +%% These cases tests what happens when the socket is closed locally. +sc_lc_cases() -> + [ + sc_lc_recv_response_tcp4, + sc_lc_recv_response_tcp6, + + sc_lc_recvmsg_response_tcp4, + sc_lc_recvmsg_response_tcp6, + + sc_lc_acceptor_response_tcp4, + sc_lc_acceptor_response_tcp6 + ]. + +%% These cases tests what happens when the socket is closed remotely. +sc_rc_cases() -> + [ + sc_rc_recv_response_tcp4, + sc_rc_recv_response_tcp6, + + sc_rc_recvmsg_response_tcp4, + sc_rc_recvmsg_response_tcp6 + ]. + + %% ticket_cases() -> %% []. @@ -2332,6 +2343,7 @@ api_to_receive_tcp(InitState) -> cmd => fun(#{lsock := LSock} = State) -> case socket:accept(LSock) of {ok, Sock} -> + %% ok = socket:setopt(Sock, otp, debug, true), {ok, State#{sock => Sock}}; {error, _} = ERROR -> ERROR @@ -2375,16 +2387,44 @@ api_to_receive_tcp(InitState) -> {ok, maps:remove(tester, State)} end end}, + %% #{desc => "sleep some (before traffic close)", + %% cmd => fun(_) -> + %% ?SLEEP(1000), + %% ok + %% end}, + %% #{desc => "monitored-by", + %% cmd => fun(_) -> + %% {_, Mons} = process_info(self(), monitored_by), + %% ei("Monitored By: ~p", [Mons]), + %% ok + %% end}, #{desc => "close (traffic) socket", cmd => fun(#{sock := Sock} = State) -> + %% ok = socket:setopt(Sock, otp, debug, true), sock_close(Sock), {ok, maps:remove(sock, State)} end}, + %% #{desc => "monitored-by", + %% cmd => fun(_) -> + %% {_, Mons} = process_info(self(), monitored_by), + %% ei("Monitored By: ~p", [Mons]), + %% ok + %% end}, + %% #{desc => "sleep some (before listen close)", + %% cmd => fun(_) -> + %% ?SLEEP(1000), + %% ok + %% end}, #{desc => "close (listen) socket", cmd => fun(#{lsock := LSock} = State) -> sock_close(LSock), {ok, maps:remove(lsock, State)} end}, + %% #{desc => "sleep some (after listen close)", + %% cmd => fun(_) -> + %% ?SLEEP(1000), + %% ok + %% end}, %% *** We are done *** #{desc => "finish", @@ -2938,10 +2978,10 @@ sc_cpe_socket_cleanup(InitState) -> {ok, maps:remove(tester, State)} end end}, - #{desc => "enable (otp) debug", - cmd => fun(#{sock := Sock} = _State) -> - ok = socket:setopt(Sock, otp, debug, true) - end}, + %% #{desc => "enable (otp) debug", + %% cmd => fun(#{sock := Sock} = _State) -> + %% ok = socket:setopt(Sock, otp, debug, true) + %% end}, %% *** We are done *** #{desc => "finish", @@ -3041,12 +3081,12 @@ sc_cpe_socket_cleanup(InitState) -> %% %% -sc_recv_response_local_close_tcp4(suite) -> +sc_lc_recv_response_tcp4(suite) -> []; -sc_recv_response_local_close_tcp4(doc) -> +sc_lc_recv_response_tcp4(doc) -> []; -sc_recv_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_recv_response_local_close_tcp4, +sc_lc_recv_response_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_lc_recv_response_tcp4, fun() -> %% not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3054,7 +3094,7 @@ sc_recv_response_local_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_local_close_tcp(InitState) + ok = sc_lc_receive_response_tcp(InitState) end). @@ -3063,12 +3103,12 @@ sc_recv_response_local_close_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recv function. %% Socket is IPv6. -sc_recv_response_local_close_tcp6(suite) -> +sc_lc_recv_response_tcp6(suite) -> []; -sc_recv_response_local_close_tcp6(doc) -> +sc_lc_recv_response_tcp6(doc) -> []; -sc_recv_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_recv_response_local_close_tcp6, +sc_lc_recv_response_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_lc_recv_response_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3076,13 +3116,13 @@ sc_recv_response_local_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_local_close_tcp(InitState) + ok = sc_lc_receive_response_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sc_receive_response_local_close_tcp(InitState) -> +sc_lc_receive_response_tcp(InitState) -> %% This is the server that accepts connections. %% But it is also suppose to close the connection socket, %% and trigger the read failure for the handler process. @@ -3271,8 +3311,8 @@ sc_receive_response_local_close_tcp(InitState) -> %% ok %% end}, #{desc => "attempt recv", - cmd => fun(#{sock := Sock} = State) -> - case socket:recv(Sock) of + cmd => fun(#{sock := Sock, recv := Recv} = State) -> + case Recv(Sock) of {ok, _Data} -> ee("Unexpected data received"), {error, unexpected_data}; @@ -3609,7 +3649,7 @@ sc_receive_response_local_close_tcp(InitState) -> Acceptor = evaluator_start("acceptor", AcceptorSeq, AccInitState), p("start handler evaluator"), - HandlerInitState = #{}, + HandlerInitState = #{recv => maps:get(recv, InitState)}, Handler = evaluator_start("handler", HandlerSeq, HandlerInitState), p("start client evaluator"), @@ -3632,12 +3672,12 @@ sc_receive_response_local_close_tcp(InitState) -> %% remotely closed while the process is calling the recv function. %% Socket is IPv4. -sc_recv_response_remote_close_tcp4(suite) -> +sc_rc_recv_response_tcp4(suite) -> []; -sc_recv_response_remote_close_tcp4(doc) -> +sc_rc_recv_response_tcp4(doc) -> []; -sc_recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_recv_response_remote_close_tcp4, +sc_rc_recv_response_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_rc_recv_response_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3645,7 +3685,7 @@ sc_recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_remote_close_tcp(InitState) + ok = sc_rc_receive_response_tcp(InitState) end). @@ -3654,12 +3694,12 @@ sc_recv_response_remote_close_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recv function. %% Socket is IPv6. -sc_recv_response_remote_close_tcp6(suite) -> +sc_rc_recv_response_tcp6(suite) -> []; -sc_recv_response_remote_close_tcp6(doc) -> +sc_rc_recv_response_tcp6(doc) -> []; -sc_recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_recv_response_remote_close_tcp6, +sc_rc_recv_response_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_rc_recv_response_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recv(Sock) end, @@ -3667,13 +3707,13 @@ sc_recv_response_remote_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_remote_close_tcp(InitState) + ok = sc_rc_receive_response_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sc_receive_response_remote_close_tcp(_InitState) -> +sc_rc_receive_response_tcp(_InitState) -> ok. @@ -3683,12 +3723,12 @@ sc_receive_response_remote_close_tcp(_InitState) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv4. -sc_recvmsg_response_local_close_tcp4(suite) -> +sc_lc_recvmsg_response_tcp4(suite) -> []; -sc_recvmsg_response_local_close_tcp4(doc) -> +sc_lc_recvmsg_response_tcp4(doc) -> []; -sc_recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_recvmsg_response_local_close_tcp4, +sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_lc_recvmsg_response_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3696,7 +3736,7 @@ sc_recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_local_close_tcp(InitState) + ok = sc_lc_receive_response_tcp(InitState) end). @@ -3705,12 +3745,12 @@ sc_recvmsg_response_local_close_tcp4(_Config) when is_list(_Config) -> %% locally closed while the process is calling the recvmsg function. %% Socket is IPv6. -sc_recvmsg_response_local_close_tcp6(suite) -> +sc_lc_recvmsg_response_tcp6(suite) -> []; -sc_recvmsg_response_local_close_tcp6(doc) -> +sc_lc_recvmsg_response_tcp6(doc) -> []; -sc_recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_recvmsg_response_local_close_tcp6, +sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_recvmsg_response_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3718,7 +3758,7 @@ sc_recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_local_close_tcp(InitState) + ok = sc_lc_receive_response_tcp(InitState) end). @@ -3727,12 +3767,12 @@ sc_recvmsg_response_local_close_tcp6(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv4. -sc_recvmsg_response_remote_close_tcp4(suite) -> +sc_rc_recvmsg_response_tcp4(suite) -> []; -sc_recvmsg_response_remote_close_tcp4(doc) -> +sc_rc_recvmsg_response_tcp4(doc) -> []; -sc_recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_recvmsg_response_remote_close_tcp4, +sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_rc_recvmsg_response_tcp4, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3740,7 +3780,7 @@ sc_recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_remote_close_tcp(InitState) + ok = sc_rc_receive_response_tcp(InitState) end). @@ -3749,12 +3789,12 @@ sc_recvmsg_response_remote_close_tcp4(_Config) when is_list(_Config) -> %% remotely closed while the process is calling the recvmsg function. %% Socket is IPv6. -sc_recvmsg_response_remote_close_tcp6(suite) -> +sc_rc_recvmsg_response_tcp6(suite) -> []; -sc_recvmsg_response_remote_close_tcp6(doc) -> +sc_rc_recvmsg_response_tcp6(doc) -> []; -sc_recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_recvmsg_response_remote_close_tcp6, +sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_rc_recvmsg_response_tcp6, fun() -> not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, @@ -3762,7 +3802,7 @@ sc_recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> type => stream, protocol => tcp, recv => Recv}, - ok = sc_receive_response_remote_close_tcp(InitState) + ok = sc_rc_receive_response_tcp(InitState) end). @@ -3773,18 +3813,18 @@ sc_recvmsg_response_remote_close_tcp6(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv4. -sc_acceptor_response_local_close_tcp4(suite) -> +sc_lc_acceptor_response_tcp4(suite) -> []; -sc_acceptor_response_local_close_tcp4(doc) -> +sc_lc_acceptor_response_tcp4(doc) -> []; -sc_acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_acceptor_response_local_close_tcp4, +sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) -> + tc_try(sc_lc_acceptor_response_tcp4, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = sc_acceptor_response_local_close_tcp(InitState) + ok = sc_lc_acceptor_response_tcp(InitState) end). @@ -3795,75 +3835,24 @@ sc_acceptor_response_local_close_tcp4(_Config) when is_list(_Config) -> %% git the setup anyway. %% Socket is IPv6. -sc_acceptor_response_local_close_tcp6(suite) -> - []; -sc_acceptor_response_local_close_tcp6(doc) -> - []; -sc_acceptor_response_local_close_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_acceptor_response_local_close_tcp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = sc_acceptor_response_local_close_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sc_acceptor_response_local_close_tcp(_InitState) -> - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the accept function. -%% We test what happens with a non-controlling_process also, since we -%% git the setup anyway. -%% Socket is IPv4. - -sc_acceptor_response_remote_close_tcp4(suite) -> - []; -sc_acceptor_response_remote_close_tcp4(doc) -> - []; -sc_acceptor_response_remote_close_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_acceptor_response_remote_close_tcp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = sc_acceptor_response_remote_close_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the accept function. -%% We test what happens with a non-controlling_process also, since we -%% git the setup anyway. -%% Socket is IPv6. - -sc_acceptor_response_remote_close_tcp6(suite) -> +sc_lc_acceptor_response_tcp6(suite) -> []; -sc_acceptor_response_remote_close_tcp6(doc) -> +sc_lc_acceptor_response_tcp6(doc) -> []; -sc_acceptor_response_remote_close_tcp6(_Config) when is_list(_Config) -> - tc_try(acceptor_response_remote_close_tcp6, +sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) -> + tc_try(sc_lc_acceptor_response_tcp6, fun() -> not_yet_implemented(), InitState = #{domain => inet, type => stream, protocol => tcp}, - ok = sc_acceptor_response_remote_close_tcp(InitState) + ok = sc_lc_acceptor_response_tcp(InitState) end). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sc_acceptor_response_remote_close_tcp(_InitState) -> +sc_lc_acceptor_response_tcp(_InitState) -> ok. -- cgit v1.2.3 From 3c4c36587df5a847dd6f03011a4ecb76d0b70b40 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 18 Oct 2018 17:21:11 +0200 Subject: [socket-nif|test] Enables test case sc_lc_recvmsg_response_tcp4 --- lib/kernel/test/socket_SUITE.erl | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index 4ee2eec39a..022e83a944 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -3730,7 +3730,6 @@ sc_lc_recvmsg_response_tcp4(doc) -> sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> tc_try(sc_lc_recvmsg_response_tcp4, fun() -> - not_yet_implemented(), Recv = fun(Sock) -> socket:recvmsg(Sock) end, InitState = #{domain => inet, type => stream, -- cgit v1.2.3 From b4d61414565e6c6aa34249bf5d6eb3d5e5952b76 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 19 Oct 2018 12:13:26 +0200 Subject: [socket-nif|test] Moved socket tests from kernel to erts/emulator OTP-14831 --- lib/kernel/test/Makefile | 12 +- lib/kernel/test/socket_SUITE.erl | 4186 ------------------------------------- lib/kernel/test/socket_client.erl | 538 ----- lib/kernel/test/socket_lib.erl | 133 -- lib/kernel/test/socket_server.erl | 954 --------- 5 files changed, 1 insertion(+), 5822 deletions(-) delete mode 100644 lib/kernel/test/socket_SUITE.erl delete mode 100644 lib/kernel/test/socket_client.erl delete mode 100644 lib/kernel/test/socket_lib.erl delete mode 100644 lib/kernel/test/socket_server.erl (limited to 'lib/kernel/test') diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 28edf4889b..8b16e83707 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -24,11 +24,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Target Specs # ---------------------------------------------------- -SOCKET_MODULES = \ - socket_lib \ - socket_server \ - socket_client - MODULES= \ rpc_SUITE \ pdict_SUITE \ @@ -95,9 +90,7 @@ MODULES= \ sendfile_SUITE \ standard_error_SUITE \ multi_load_SUITE \ - zzz_SUITE \ - socket_SUITE \ - $(SOCKET_MODULES) + zzz_SUITE APP_FILES = \ appinc.app \ @@ -134,7 +127,6 @@ ERL_COMPILE_FLAGS += EBIN = . -SOCKET_TARGETS = $(SOCKET_MODULES:%=$(EBIN)/%.$(EMULATOR)) TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) @@ -160,8 +152,6 @@ docs: targets: $(TARGETS) -socket: $(SOCKET_TARGETS) - # ---------------------------------------------------- # Release Target diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl deleted file mode 100644 index 022e83a944..0000000000 --- a/lib/kernel/test/socket_SUITE.erl +++ /dev/null @@ -1,4186 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(socket_SUITE). - --include_lib("common_test/include/ct.hrl"). --include_lib("common_test/include/ct_event.hrl"). - -%% Suite exports --export([suite/0, all/0, groups/0]). --export([init_per_suite/1, end_per_suite/1, - init_per_testcase/2, end_per_testcase/2]). - -%% Test cases --export([ - %% API Basic - api_b_open_and_close_udp4/1, - api_b_open_and_close_tcp4/1, - api_b_sendto_and_recvfrom_udp4/1, - api_b_sendmsg_and_recvmsg_udp4/1, - api_b_send_and_recv_tcp4/1, - api_b_sendmsg_and_recvmsg_tcp4/1, - - %% API Options - api_opt_simple_otp_options/1, - api_opt_simple_otp_controlling_process/1, - - %% API Operation Timeout - api_to_connect_tcp4/1, - api_to_connect_tcp6/1, - api_to_accept_tcp4/1, - api_to_accept_tcp6/1, - api_to_maccept_tcp4/1, - api_to_maccept_tcp6/1, - api_to_send_tcp4/1, - api_to_send_tcp6/1, - api_to_sendto_udp4/1, - api_to_sendto_udp6/1, - api_to_sendmsg_tcp4/1, - api_to_sendmsg_tcp6/1, - api_to_recv_udp4/1, - api_to_recv_udp6/1, - api_to_recv_tcp4/1, - api_to_recv_tcp6/1, - api_to_recvfrom_udp4/1, - api_to_recvfrom_udp6/1, - api_to_recvmsg_udp4/1, - api_to_recvmsg_udp6/1, - api_to_recvmsg_tcp4/1, - api_to_recvmsg_tcp6/1, - - %% Socket Closure - sc_cpe_socket_cleanup_tcp4/1, - sc_cpe_socket_cleanup_tcp6/1, - sc_cpe_socket_cleanup_udp4/1, - sc_cpe_socket_cleanup_udp6/1, - sc_lc_recv_response_tcp4/1, - sc_lc_recv_response_tcp6/1, - sc_lc_recvmsg_response_tcp4/1, - sc_lc_recvmsg_response_tcp6/1, - sc_lc_acceptor_response_tcp4/1, - sc_lc_acceptor_response_tcp6/1, - sc_rc_recv_response_tcp4/1, - sc_rc_recv_response_tcp6/1, - sc_rc_recvmsg_response_tcp4/1, - sc_rc_recvmsg_response_tcp6/1 - - %% Tickets - ]). - -%% Internal exports -%% -export([]). - - --type initial_evaluator_state() :: map(). --type evaluator_state() :: term(). --type command_fun() :: - fun((State :: evaluator_state()) -> ok) | - fun((State :: evaluator_state()) -> {ok, evaluator_state()}) | - fun((State :: evaluator_state()) -> {error, term()}). - --type command() :: #{desc := string(), - cmd := command_fun()}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --define(BASIC_REQ, <<"hejsan">>). --define(BASIC_REP, <<"hoppsan">>). - --define(FAIL(R), exit(R)). - --define(SLEEP(T), receive after T -> ok end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -suite() -> - [{ct_hooks,[ts_install_cth]}, - {timetrap,{minutes,1}}]. - -all() -> - [ - {group, api}, - {group, socket_closure} - %% {group, tickets} - ]. - -groups() -> - [{api, [], api_cases()}, - {api_basic, [], api_basic_cases()}, - {api_options, [], api_options_cases()}, - {api_op_with_timeout, [], api_op_with_timeout_cases()}, - {socket_closure, [], socket_closure_cases()}, - {sc_ctrl_proc_exit, [], sc_cp_exit_cases()}, - {sc_local_close, [], sc_lc_cases()}, - {sc_remote_close, [], sc_rc_cases()} - %% {tickets, [], ticket_cases()} - ]. - -api_cases() -> - [ - {group, api_basic}, - {group, api_options}, - {group, api_op_with_timeout} - ]. - -api_basic_cases() -> - [ - api_b_open_and_close_udp4, - api_b_open_and_close_tcp4, - api_b_sendto_and_recvfrom_udp4, - api_b_sendmsg_and_recvmsg_udp4, - api_b_send_and_recv_tcp4, - api_b_sendmsg_and_recvmsg_tcp4 - ]. - -api_options_cases() -> - [ - api_opt_simple_otp_options, - api_opt_simple_otp_controlling_process - ]. - -api_op_with_timeout_cases() -> - [ - api_to_connect_tcp4, - api_to_connect_tcp6, - api_to_accept_tcp4, - api_to_accept_tcp6, - api_to_send_tcp4, - api_to_send_tcp6, - api_to_sendto_udp4, - api_to_sendto_udp6, - api_to_sendmsg_tcp4, - api_to_sendmsg_tcp6, - api_to_recv_udp4, - api_to_recv_udp6, - api_to_recv_tcp4, - api_to_recv_tcp6, - api_to_recvfrom_udp4, - api_to_recvfrom_udp6, - api_to_recvmsg_udp4, - api_to_recvmsg_udp6, - api_to_recvmsg_tcp4, - api_to_recvmsg_tcp6 - ]. - -%% These cases tests what happens when the socket is closed, locally or -%% remotely. -socket_closure_cases() -> - [ - {group, sc_ctrl_proc_exit}, - {group, sc_local_close}, - {group, sc_remote_close} - ]. - -%% These cases are all about socket cleanup after the controlling process -%% exits *without* calling socket:close/1. -sc_cp_exit_cases() -> - [ - sc_cpe_socket_cleanup_tcp4, - sc_cpe_socket_cleanup_tcp6, - sc_cpe_socket_cleanup_udp4, - sc_cpe_socket_cleanup_udp6 - ]. - -%% These cases tests what happens when the socket is closed locally. -sc_lc_cases() -> - [ - sc_lc_recv_response_tcp4, - sc_lc_recv_response_tcp6, - - sc_lc_recvmsg_response_tcp4, - sc_lc_recvmsg_response_tcp6, - - sc_lc_acceptor_response_tcp4, - sc_lc_acceptor_response_tcp6 - ]. - -%% These cases tests what happens when the socket is closed remotely. -sc_rc_cases() -> - [ - sc_rc_recv_response_tcp4, - sc_rc_recv_response_tcp6, - - sc_rc_recvmsg_response_tcp4, - sc_rc_recvmsg_response_tcp6 - ]. - - -%% ticket_cases() -> -%% []. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -init_per_suite(Config) -> - Config. - -end_per_suite(_) -> - ok. - -init_per_testcase(_TC, Config) -> - Config. - -end_per_testcase(_TC, Config) -> - Config. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% API BASIC %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically open (create) and close an IPv4 UDP (dgram) socket. -%% With some extra checks... -api_b_open_and_close_udp4(suite) -> - []; -api_b_open_and_close_udp4(doc) -> - []; -api_b_open_and_close_udp4(_Config) when is_list(_Config) -> - tc_try(api_b_open_and_close_udp4, - fun() -> - InitState = #{domain => inet, - type => dgram, - protocol => udp}, - ok = api_b_open_and_close(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically open (create) and close an IPv4 TCP (stream) socket. -%% With some extra checks... -api_b_open_and_close_tcp4(suite) -> - []; -api_b_open_and_close_tcp4(doc) -> - []; -api_b_open_and_close_tcp4(_Config) when is_list(_Config) -> - tc_try(api_b_open_and_close_tcp4, - fun() -> - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = api_b_open_and_close(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_b_open_and_close(InitState) -> - Seq = - [ - #{desc => "open", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Protocol} = S) -> - Res = socket:open(Domain, Type, Protocol), - {ok, {S, Res}} - end}, - #{desc => "validate open", - cmd => fun({S, {ok, Sock}}) -> - NewS = S#{socket => Sock}, - {ok, NewS}; - ({_, {error, _} = ERROR}) -> - ERROR - end}, - #{desc => "get domain (maybe)", - cmd => fun(#{socket := Sock} = S) -> - Res = socket:getopt(Sock, socket, domain), - {ok, {S, Res}} - end}, - #{desc => "validate domain (maybe)", - cmd => fun({#{domain := Domain} = S, {ok, Domain}}) -> - {ok, S}; - ({#{domain := ExpDomain}, {ok, Domain}}) -> - {error, {unexpected_domain, ExpDomain, Domain}}; - %% Some platforms do not support this option - ({S, {error, einval}}) -> - {ok, S}; - ({_, {error, _} = ERROR}) -> - ERROR - end}, - #{desc => "get type", - cmd => fun(#{socket := Sock} = State) -> - Res = socket:getopt(Sock, socket, type), - {ok, {State, Res}} - end}, - #{desc => "validate type", - cmd => fun({#{type := Type} = State, {ok, Type}}) -> - {ok, State}; - ({#{type := ExpType}, {ok, Type}}) -> - {error, {unexpected_type, ExpType, Type}}; - ({_, {error, _} = ERROR}) -> - ERROR - end}, - #{desc => "get protocol", - cmd => fun(#{socket := Sock} = State) -> - Res = socket:getopt(Sock, socket, protocol), - {ok, {State, Res}} - end}, - #{desc => "validate protocol", - cmd => fun({#{protocol := Protocol} = State, {ok, Protocol}}) -> - {ok, State}; - ({#{protocol := ExpProtocol}, {ok, Protocol}}) -> - {error, {unexpected_type, ExpProtocol, Protocol}}; - ({_, {error, _} = ERROR}) -> - ERROR - end}, - #{desc => "get controlling-process", - cmd => fun(#{socket := Sock} = State) -> - Res = socket:getopt(Sock, otp, controlling_process), - {ok, {State, Res}} - end}, - #{desc => "validate controlling-process", - cmd => fun({State, {ok, Pid}}) -> - case self() of - Pid -> - {ok, State}; - _ -> - {error, {unexpected_owner, Pid}} - end; - ({_, {error, _} = ERROR}) -> - ERROR - end}, - #{desc => "close socket", - cmd => fun(#{socket := Sock} = State) -> - Res = socket:close(Sock), - {ok, {State, Res}} - end}, - #{desc => "validate socket close", - cmd => fun({_, ok}) -> - {ok, normal}; - ({_, {error, _} = ERROR}) -> - ERROR - end}], - Evaluator = evaluator_start("tester", Seq, InitState), - ok = await_evaluator_finish([Evaluator]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically send and receive on an IPv4 UDP (dgram) socket using -%% sendto and recvfrom.. -api_b_sendto_and_recvfrom_udp4(suite) -> - []; -api_b_sendto_and_recvfrom_udp4(doc) -> - []; -api_b_sendto_and_recvfrom_udp4(_Config) when is_list(_Config) -> - tc_try(api_b_sendto_and_recvfrom_udp4, - fun() -> - Send = fun(Sock, Data, Dest) -> - socket:sendto(Sock, Data, Dest) - end, - Recv = fun(Sock) -> - socket:recvfrom(Sock) - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically send and receive on an IPv4 UDP (dgram) socket -%% using sendmsg and recvmsg. -api_b_sendmsg_and_recvmsg_udp4(suite) -> - []; -api_b_sendmsg_and_recvmsg_udp4(doc) -> - []; -api_b_sendmsg_and_recvmsg_udp4(_Config) when is_list(_Config) -> - tc_try(api_b_sendmsg_and_recvmsg_udp4, - fun() -> - Send = fun(Sock, Data, Dest) -> - %% CMsgHdr = #{level => ip, - %% type => tos, - %% data => reliability}, - %% CMsgHdrs = [CMsgHdr], - MsgHdr = #{addr => Dest, - %% ctrl => CMsgHdrs, - iov => [Data]}, - socket:sendmsg(Sock, MsgHdr) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Data]}} -> - {ok, {Source, Data}}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_b_send_and_recv_udp(InitState) -> - Seq = - [ - #{desc => "local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "open src socket", - cmd => fun(#{domain := Domain} = State) -> - Sock = sock_open(Domain, dgram, udp), - SASrc = sock_sockname(Sock), - {ok, State#{sock_src => Sock, sa_src => SASrc}} - end}, - #{desc => "bind src", - cmd => fun(#{sock_src := Sock, lsa := LSA}) -> - sock_bind(Sock, LSA), - ok - end}, - #{desc => "sockname src socket", - cmd => fun(#{sock_src := Sock} = State) -> - SASrc = sock_sockname(Sock), - %% ei("src sockaddr: ~p", [SASrc]), - {ok, State#{sa_src => SASrc}} - end}, - #{desc => "open dst socket", - cmd => fun(#{domain := Domain} = State) -> - Sock = sock_open(Domain, dgram, udp), - {ok, State#{sock_dst => Sock}} - end}, - #{desc => "bind dst", - cmd => fun(#{sock_dst := Sock, lsa := LSA}) -> - sock_bind(Sock, LSA), - ok - end}, - #{desc => "sockname dst socket", - cmd => fun(#{sock_dst := Sock} = State) -> - SADst = sock_sockname(Sock), - %% ei("dst sockaddr: ~p", [SADst]), - {ok, State#{sa_dst => SADst}} - end}, - #{desc => "send req (to dst)", - cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) -> - ok = Send(Sock, ?BASIC_REQ, Dst) - end}, - #{desc => "recv req (from src)", - cmd => fun(#{sock_dst := Sock, sa_src := Src, recv := Recv}) -> - {ok, {Src, ?BASIC_REQ}} = Recv(Sock), - ok - end}, - #{desc => "send rep (to src)", - cmd => fun(#{sock_dst := Sock, sa_src := Src, send := Send}) -> - ok = Send(Sock, ?BASIC_REP, Src) - end}, - #{desc => "recv rep (from dst)", - cmd => fun(#{sock_src := Sock, sa_dst := Dst, recv := Recv}) -> - {ok, {Dst, ?BASIC_REP}} = Recv(Sock), - ok - end}, - #{desc => "close src socket", - cmd => fun(#{sock_src := Sock}) -> - ok = socket:close(Sock) - end}, - #{desc => "close dst socket", - cmd => fun(#{sock_dst := Sock}) -> - ok = socket:close(Sock), - {ok, normal} - end} - ], - Evaluator = evaluator_start("tester", Seq, InitState), - ok = await_evaluator_finish([Evaluator]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically send and receive using the "common" functions (send and recv) -%% on an IPv4 TCP (stream) socket. -api_b_send_and_recv_tcp4(suite) -> - []; -api_b_send_and_recv_tcp4(doc) -> - []; -api_b_send_and_recv_tcp4(_Config) when is_list(_Config) -> - tc_try(api_b_send_and_recv_tcp4, - fun() -> - Send = fun(Sock, Data) -> - socket:send(Sock, Data) - end, - Recv = fun(Sock) -> - socket:recv(Sock) - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Basically send and receive using the msg functions (sendmsg and recvmsg) -%% on an IPv4 TCP (stream) socket. -api_b_sendmsg_and_recvmsg_tcp4(suite) -> - []; -api_b_sendmsg_and_recvmsg_tcp4(doc) -> - []; -api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) -> - tc_try(api_b_sendmsg_and_recvmsg_tcp4, - fun() -> - Send = fun(Sock, Data) -> - MsgHdr = #{iov => [Data]}, - socket:sendmsg(Sock, MsgHdr) - end, - Recv = fun(Sock) -> - case socket:recvmsg(Sock) of - {ok, #{addr := undefined, - iov := [Data]}} -> - {ok, Data}; - {error, _} = ERROR -> - ERROR - end - end, - InitState = #{domain => inet, - send => Send, - recv => Recv}, - ok = api_b_send_and_recv_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_b_send_and_recv_tcp(InitState) -> - process_flag(trap_exit, true), - ServerSeq = - [ - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create listen socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> - case socket:bind(LSock, LSA) of - {ok, Port} -> - {ok, State#{lport => Port}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock) - end}, - #{desc => "announce server port", - cmd => fun(#{parent := Parent, lport := Port}) -> - ei("announcing port to parent (~p)", [Parent]), - Parent ! {server_port, self(), Port}, - ok - end}, - #{desc => "await connection", - cmd => fun(#{lsock := LSock} = State) -> - case socket:accept(LSock) of - {ok, Sock} -> - ei("accepted: ~n ~p", [Sock]), - {ok, State#{tsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "await request", - cmd => fun(#{tsock := Sock, recv := Recv}) -> - case Recv(Sock) of - {ok, ?BASIC_REQ} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "send reply", - cmd => fun(#{tsock := Sock, send := Send}) -> - Send(Sock, ?BASIC_REP) - end}, - #{desc => "sleep some", - cmd => fun(_) -> - ?SLEEP(1000), - ok - end}, - #{desc => "close traffic socket", - cmd => fun(#{tsock := Sock}) -> - socket:close(Sock) - end}, - #{desc => "close listen socket", - cmd => fun(#{lsock := Sock}) -> - socket:close(Sock) - end}, - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - ClientSeq = - [ - #{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}, - {ok, State#{lsa => LSA, ssa => SSA}} - end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{sock := Sock, lsa := LSA} = State) -> - case socket:bind(Sock, LSA) of - {ok, Port} -> - {ok, State#{port => Port}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "connect to server", - cmd => fun(#{sock := Sock, ssa := SSA}) -> - socket:connect(Sock, SSA) - end}, - #{desc => "send request (to server)", - cmd => fun(#{sock := Sock, send := Send}) -> - Send(Sock, ?BASIC_REQ) - end}, - #{desc => "recv reply (from server)", - cmd => fun(#{sock := Sock, recv := Recv}) -> - {ok, ?BASIC_REP} = Recv(Sock), - ok - end}, - #{desc => "close socket", - cmd => fun(#{sock := Sock}) -> - socket:close(Sock) - end}, - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("start server evaluator"), - Server = evaluator_start("server", ServerSeq, InitState), - p("await server (~p) port", [Server]), - SPort = receive - {server_port, Server, Port} -> - Port - end, - p("start client evaluator"), - Client = evaluator_start("client", ClientSeq, InitState#{server_port => SPort}), - p("await evaluator(s)"), - ok = await_evaluator_finish([Server, Client]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% API OPTIONS %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Perform some simple getopt and setopt with the level = otp options -api_opt_simple_otp_options(suite) -> - []; -api_opt_simple_otp_options(doc) -> - []; -api_opt_simple_otp_options(_Config) when is_list(_Config) -> - tc_try(api_opt_simple_otp_options, - fun() -> api_opt_simple_otp_options() end). - -api_opt_simple_otp_options() -> - Get = fun(S, Key) -> - socket:getopt(S, otp, Key) - end, - Set = fun(S, Key, Val) -> - socket:setopt(S, otp, Key, Val) - end, - - Seq = - [ - %% *** Init part *** - #{desc => "create socket", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Protocol} = State) -> - Sock = sock_open(Domain, Type, Protocol), - {ok, State#{sock => Sock}} - end}, - #{desc => "create dummy process", - cmd => fun(State) -> - Pid = spawn_link(fun() -> - put(sname, "dummy"), - receive - die -> - exit(normal) - end - end), - {ok, State#{dummy => Pid}} - end}, - - %% *** Check iow part *** - #{desc => "get iow", - cmd => fun(#{sock := Sock} = State) -> - case Get(Sock, iow) of - {ok, IOW} when is_boolean(IOW) -> - {ok, State#{iow => IOW}}; - {ok, InvalidIOW} -> - {error, {invalid, InvalidIOW}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set (new) iow", - cmd => fun(#{sock := Sock, iow := OldIOW} = State) -> - NewIOW = not OldIOW, - case Set(Sock, iow, NewIOW) of - ok -> - {ok, State#{iow => NewIOW}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "get (new) iow", - cmd => fun(#{sock := Sock, iow := IOW}) -> - case Get(Sock, iow) of - {ok, IOW} -> - ok; - {ok, InvalidIOW} -> - {error, {invalid, InvalidIOW}}; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** Check rcvbuf part *** - #{desc => "get rcvbuf", - cmd => fun(#{sock := Sock} = State) -> - case Get(Sock, rcvbuf) of - {ok, RcvBuf} when is_integer(RcvBuf) -> - {ok, State#{rcvbuf => RcvBuf}}; - {ok, InvalidRcvBuf} -> - {error, {invalid, InvalidRcvBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set (new) rcvbuf", - cmd => fun(#{sock := Sock, rcvbuf := OldRcvBuf} = State) -> - NewRcvBuf = 2 * OldRcvBuf, - case Set(Sock, rcvbuf, NewRcvBuf) of - ok -> - {ok, State#{rcvbuf => NewRcvBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "get (new) rcvbuf", - cmd => fun(#{sock := Sock, rcvbuf := RcvBuf}) -> - case Get(Sock, rcvbuf) of - {ok, RcvBuf} -> - ok; - {ok, InvalidRcvBuf} -> - {error, {invalid, InvalidRcvBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** Check rcvctrlbuf part *** - #{desc => "get rcvctrlbuf", - cmd => fun(#{sock := Sock} = State) -> - case Get(Sock, rcvctrlbuf) of - {ok, RcvCtrlBuf} when is_integer(RcvCtrlBuf) -> - {ok, State#{rcvctrlbuf => RcvCtrlBuf}}; - {ok, InvalidRcvCtrlBuf} -> - {error, {invalid, InvalidRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set (new) rcvctrlbuf", - cmd => fun(#{sock := Sock, rcvctrlbuf := OldRcvCtrlBuf} = State) -> - NewRcvCtrlBuf = 2 * OldRcvCtrlBuf, - case Set(Sock, rcvctrlbuf, NewRcvCtrlBuf) of - ok -> - {ok, State#{rcvctrlbuf => NewRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "get (new) rcvctrlbuf", - cmd => fun(#{sock := Sock, rcvctrlbuf := RcvCtrlBuf}) -> - case Get(Sock, rcvctrlbuf) of - {ok, RcvCtrlBuf} -> - ok; - {ok, InvalidRcvCtrlBuf} -> - {error, {invalid, InvalidRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - %% *** Check rcvctrlbuf part *** - #{desc => "get rcvctrlbuf", - cmd => fun(#{sock := Sock} = State) -> - case Get(Sock, rcvctrlbuf) of - {ok, RcvCtrlBuf} when is_integer(RcvCtrlBuf) -> - {ok, State#{rcvctrlbuf => RcvCtrlBuf}}; - {ok, InvalidRcvCtrlBuf} -> - {error, {invalid, InvalidRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set (new) rcvctrlbuf", - cmd => fun(#{sock := Sock, rcvctrlbuf := OldRcvCtrlBuf} = State) -> - NewRcvCtrlBuf = 2 * OldRcvCtrlBuf, - case Set(Sock, rcvctrlbuf, NewRcvCtrlBuf) of - ok -> - {ok, State#{rcvctrlbuf => NewRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "get (new) rcvctrlbuf", - cmd => fun(#{sock := Sock, rcvctrlbuf := RcvCtrlBuf}) -> - case Get(Sock, rcvctrlbuf) of - {ok, RcvCtrlBuf} -> - ok; - {ok, InvalidRcvCtrlBuf} -> - {error, {invalid, InvalidRcvCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - - - %% *** Check sndctrlbuf part *** - #{desc => "get sndctrlbuf", - cmd => fun(#{sock := Sock} = State) -> - case Get(Sock, sndctrlbuf) of - {ok, SndCtrlBuf} when is_integer(SndCtrlBuf) -> - {ok, State#{sndctrlbuf => SndCtrlBuf}}; - {ok, InvalidSndCtrlBuf} -> - {error, {invalid, InvalidSndCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set (new) sndctrlbuf", - cmd => fun(#{sock := Sock, sndctrlbuf := OldSndCtrlBuf} = State) -> - NewSndCtrlBuf = 2 * OldSndCtrlBuf, - case Set(Sock, sndctrlbuf, NewSndCtrlBuf) of - ok -> - {ok, State#{sndctrlbuf => NewSndCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "get (new) sndctrlbuf", - cmd => fun(#{sock := Sock, sndctrlbuf := SndCtrlBuf}) -> - case Get(Sock, sndctrlbuf) of - {ok, SndCtrlBuf} -> - ok; - {ok, InvalidSndCtrlBuf} -> - {error, {invalid, InvalidSndCtrlBuf}}; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** Check controlling-process part *** - #{desc => "verify self as controlling-process", - cmd => fun(#{sock := Sock}) -> - Self = self(), - case Get(Sock, controlling_process) of - {ok, Self} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "set dummy as controlling-process", - cmd => fun(#{sock := Sock, dummy := Dummy}) -> - Set(Sock, controlling_process, Dummy) - end}, - #{desc => "verify dummy as controlling-process", - cmd => fun(#{sock := Sock, dummy := Dummy}) -> - case Get(Sock, controlling_process) of - {ok, Dummy} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("Run test for stream/tcp socket"), - InitState1 = #{domain => inet, type => stream, protocol => tcp}, - Tester1 = evaluator_start("tcp-tester", Seq, InitState1), - p("await evaluator 1"), - ok = await_evaluator_finish([Tester1]), - - p("Run test for dgram/udp socket"), - InitState2 = #{domain => inet, type => dgram, protocol => udp}, - Tester2 = evaluator_start("udp-tester", Seq, InitState2), - p("await evaluator 2"), - ok = await_evaluator_finish([Tester2]). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Perform some simple getopt and setopt with the level = otp options -api_opt_simple_otp_controlling_process(suite) -> - []; -api_opt_simple_otp_controlling_process(doc) -> - []; -api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> - tc_try(api_opt_simple_otp_controlling_process, - fun() -> api_opt_simple_otp_controlling_process() end). - -api_opt_simple_otp_controlling_process() -> - Get = fun(S, Key) -> - socket:getopt(S, otp, Key) - end, - Set = fun(S, Key, Val) -> - socket:setopt(S, otp, Key, Val) - end, - - ClientSeq = - [ - %% *** Init part *** - #{desc => "await start", - cmd => fun(State) -> - receive - {start, Tester, Socket} -> - {ok, State#{tester => Tester, - sock => Socket}} - end - end}, - #{desc => "verify tester as controlling-process", - cmd => fun(#{tester := Tester, sock := Sock} = _State) -> - case Get(Sock, controlling_process) of - {ok, Tester} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "attempt invalid controlling-process transfer (to self)", - cmd => fun(#{sock := Sock} = _State) -> - case Set(Sock, controlling_process, self()) of - {error, not_owner} -> - ok; - ok -> - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "announce ready (1)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "await continue", - cmd => fun(#{tester := Tester} = _State) -> - receive - {continue, Tester} -> - ok - end - end}, - #{desc => "verify self as controlling-process", - cmd => fun(#{sock := Sock} = _State) -> - Self = self(), - case Get(Sock, controlling_process) of - {ok, Self} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "attempt controlling-process transfer to tester", - cmd => fun(#{tester := Tester, sock := Sock} = _State) -> - Set(Sock, controlling_process, Tester) - end}, - #{desc => "attempt invalid controlling-process transfer (to self)", - cmd => fun(#{sock := Sock} = _State) -> - case Set(Sock, controlling_process, self()) of - {error, not_owner} -> - ok; - ok -> - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "announce ready (2)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "await termination", - cmd => fun(#{tester := Tester} = State) -> - receive - {terminate, Tester} -> - State1 = maps:remove(tester, State), - State2 = maps:remove(sock, State1), - {ok, State2} - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - TesterSeq = - [ - %% *** Init part *** - #{desc => "create socket", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Protocol} = State) -> - Sock = sock_open(Domain, Type, Protocol), - {ok, State#{sock => Sock}} - end}, - #{desc => "verify self as controlling-process", - cmd => fun(#{sock := Sock} = _State) -> - Self = self(), - case Get(Sock, controlling_process) of - {ok, Self} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "order (client) start", - cmd => fun(#{client := Client, sock := Sock} = _State) -> - Client ! {start, self(), Sock}, - ok - end}, - #{desc => "await (client) ready (1)", - cmd => fun(#{client := Client} = _State) -> - receive - {ready, Client} -> - ok - end - end}, - #{desc => "attempt controlling-process transfer to client", - cmd => fun(#{client := Client, sock := Sock} = _State) -> - Set(Sock, controlling_process, Client) - end}, - #{desc => "verify client as controlling-process", - cmd => fun(#{client := Client, sock := Sock} = _State) -> - case Get(Sock, controlling_process) of - {ok, Client} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "attempt invalid controlling-process transfer (to self)", - cmd => fun(#{sock := Sock} = _State) -> - case Set(Sock, controlling_process, self()) of - {error, not_owner} -> - ok; - ok -> - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "order (client) continue", - cmd => fun(#{client := Client} = _State) -> - Client ! {continue, self()}, - ok - end}, - #{desc => "await (client) ready (2)", - cmd => fun(#{client := Client} = _State) -> - receive - {ready, Client} -> - ok - end - end}, - #{desc => "verify self as controlling-process", - cmd => fun(#{sock := Sock} = _State) -> - Self = self(), - case Get(Sock, controlling_process) of - {ok, Self} -> - ok; - {ok, InvalidPid} -> - {error, {invalid, InvalidPid}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "monitor client", - cmd => fun(#{client := Client} = State) -> - MRef = erlang:monitor(process, Client), - {ok, State#{client_mref => MRef}} - end}, - #{desc => "order (client) terminate", - cmd => fun(#{client := Client} = _State) -> - Client ! {terminate, self()}, - ok - end}, - #{desc => "await (client) down", - cmd => fun(#{client := Client} = State) -> - receive - {'DOWN', _, process, Client, _} -> - {ok, maps:remove(client, State)} - end - end}, - #{desc => "close socket", - cmd => fun(#{sock := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock, State)} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("Run test for stream/tcp socket"), - ClientInitState1 = #{}, - Client1 = evaluator_start("tcp-client", ClientSeq, ClientInitState1), - TesterInitState1 = #{domain => inet, - type => stream, - protocol => tcp, - client => Client1}, - Tester1 = evaluator_start("tcp-tester", TesterSeq, TesterInitState1), - p("await stream/tcp evaluator"), - ok = await_evaluator_finish([Tester1, Client1]), - - p("Run test for dgram/udp socket"), - ClientInitState2 = #{}, - Client2 = evaluator_start("udp-client", ClientSeq, ClientInitState2), - TesterInitState2 = #{domain => inet, - type => dgram, - protocol => udp, - client => Client2}, - Tester2 = evaluator_start("udp-tester", TesterSeq, TesterInitState2), - p("await dgram/udp evaluator"), - ok = await_evaluator_finish([Tester2, Client2]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% API OPERATIONS WITH TIMEOUT %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the connect timeout option -%% on an IPv4 TCP (stream) socket. -api_to_connect_tcp4(suite) -> - []; -api_to_connect_tcp4(doc) -> - []; -api_to_connect_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_connect_tcp4, - fun() -> - InitState = #{domain => inet, timeout => 5000}, - ok = api_to_connect_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the connect timeout option -%% on an IPv6 TCP (stream) socket. -api_to_connect_tcp6(suite) -> - []; -api_to_connect_tcp6(doc) -> - []; -api_to_connect_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_connect_tcp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, timeout => 5000}, - ok = api_to_connect_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% We use the backlog (listen) argument to test this. -%% Note that the behaviour of the TCP "server side" can vary when -%% a client connect to a "busy" server (full backlog). -%% For instance, on FreeBSD (11.2) the reponse when the backlog is full -%% is a econreset. - -api_to_connect_tcp(InitState) -> - process_flag(trap_exit, true), - - ServerSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create listen socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> - case socket:bind(LSock, LSA) of - {ok, Port} -> - {ok, State#{lport => Port}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket (with backlog = 1)", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock, 1) - end}, - #{desc => "monitor server", - cmd => fun(#{tester := Tester} = State) -> - MRef = erlang:monitor(process, Tester), - {ok, State#{tester_mref => MRef}} - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester, lport := Port}) -> - ei("announcing ready to tester (~p)", [Tester]), - Tester ! {ready, self(), Port}, - ok - end}, - #{desc => "await terminate (from tester)", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - TesterSeq = - [ - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create socket 1", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{sock1 => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "create socket 2", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{sock2 => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "create socket 3", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{sock3 => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind socket 1 to local address", - cmd => fun(#{sock1 := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind socket 2 to local address", - cmd => fun(#{sock2 := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind socket 3 to local address", - cmd => fun(#{sock3 := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** Synchronize with the server *** - #{desc => "order (server) start", - cmd => fun(#{server := Server}) -> - Server ! {start, self()}, - ok - end}, - #{desc => "await ready (from server)", - cmd => fun(#{server := Server, lsa := LSA} = State) -> - receive - {ready, Server, Port} -> - {ok, State#{ssa => LSA#{port => Port}}} - end - end}, - - %% *** Connect sequence *** - #{desc => "order (server) start", - cmd => fun(#{sock1 := Sock1, - sock2 := Sock2, - sock3 := Sock3, - ssa := SSA, - timeout := To}) -> - Socks = [Sock1, Sock2, Sock3], - api_to_connect_tcp_await_timeout(Socks, To, SSA) - end}, - - %% *** Terminate server *** - #{desc => "monitor server", - cmd => fun(#{server := Server} = State) -> - MRef = erlang:monitor(process, Server), - {ok, State#{server_mref => MRef}} - end}, - #{desc => "order (server) terminate", - cmd => fun(#{server := Server} = _State) -> - Server ! {terminate, self()}, - ok - end}, - #{desc => "await (server) down", - cmd => fun(#{server := Server} = State) -> - receive - {'DOWN', _, process, Server, _} -> - State1 = maps:remove(server, State), - State2 = maps:remove(ssa, State1), - {ok, State2} - end - end}, - - %% *** Close our sockets *** - #{desc => "close socket 3", - cmd => fun(#{sock3 := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock3, State)} - - end}, - #{desc => "close socket 2", - cmd => fun(#{sock2 := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock2, State)} - - end}, - #{desc => "close socket 1", - cmd => fun(#{sock1 := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock1, State)} - - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("create server evaluator"), - ServerInitState = InitState, - Server = evaluator_start("server", ServerSeq, ServerInitState), - - p("create tester evaluator"), - TesterInitState = InitState#{server => Server}, - Tester = evaluator_start("tester", TesterSeq, TesterInitState), - - p("await evaluator(s)"), - ok = await_evaluator_finish([Server, Tester]). - - -api_to_connect_tcp_await_timeout(Socks, To, ServerSA) -> - api_to_connect_tcp_await_timeout(Socks, To, ServerSA, 1). - -api_to_connect_tcp_await_timeout([], _To, _ServerSA, _ID) -> - ?FAIL(unexpected_success); -api_to_connect_tcp_await_timeout([Sock|Socks], To, ServerSA, ID) -> - ei("~w: try connect", [ID]), - Start = t(), - case socket:connect(Sock, ServerSA, To) of - {error, timeout} -> - ei("expected timeout (~w)", [ID]), - Stop = t(), - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end; - {error, econnreset = Reason} -> - ei("failed connecting: ~p - giving up", [Reason]), - ok; - {error, Reason} -> - ee("failed connecting: ~p", [Reason]), - ?FAIL({connect, Reason}); - ok -> - ei("unexpected success (~w) - try next", [ID]), - api_to_connect_tcp_await_timeout(Socks, To, ServerSA, ID+1) - end. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the accept timeout option -%% on an IPv4 TCP (stream) socket. -api_to_accept_tcp4(suite) -> - []; -api_to_accept_tcp4(doc) -> - []; -api_to_accept_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_accept_tcp4, - fun() -> - InitState = #{domain => inet, timeout => 5000}, - ok = api_to_accept_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the accept timeout option -%% on an IPv6 TCP (stream) socket. -api_to_accept_tcp6(suite) -> - []; -api_to_accept_tcp6(doc) -> - []; -api_to_accept_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_accept_tcp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, timeout => 5000}, - ok = api_to_accept_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_accept_tcp(InitState) -> - TesterSeq = - [ - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create (listen) socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = _State) -> - case socket:bind(LSock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock) - end}, - - %% *** The actual test part *** - #{desc => "attempt to accept (without success)", - cmd => fun(#{lsock := LSock, timeout := To} = State) -> - Start = t(), - case socket:accept(LSock, To) of - {error, timeout} -> - {ok, State#{start => Start, stop => t()}}; - {ok, Sock} -> - (catch socket:close(Sock)), - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "validate timeout time", - cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end - end}, - - %% *** Close (listen) socket *** - #{desc => "close (listen) socket", - cmd => fun(#{lsock := LSock} = State) -> - sock_close(LSock), - {ok, maps:remove(sock3, State)} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("create tester evaluator"), - Tester = evaluator_start("tester", TesterSeq, InitState), - - p("await evaluator"), - ok = await_evaluator_finish([Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the multi accept timeout option -%% on an IPv4 TCP (stream) socket with multiple acceptor processes -%% (three in this case). -api_to_maccept_tcp4(suite) -> - []; -api_to_maccept_tcp4(doc) -> - []; -api_to_maccept_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_maccept_tcp4, - fun() -> - InitState = #{domain => inet, timeout => 5000}, - ok = api_to_maccept_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the accept timeout option -%% on an IPv6 TCP (stream) socket. -api_to_maccept_tcp6(suite) -> - []; -api_to_maccept_tcp6(doc) -> - []; -api_to_maccept_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_maccept_tcp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, timeout => 5000}, - ok = api_to_maccept_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_maccept_tcp(InitState) -> - PrimAcceptorSeq = - [ - %% *** Init part *** - #{desc => "await start", - cmd => fun(State) -> - receive - {start, Tester} -> - MRef = erlang:monitor(process, Tester), - {ok, State#{tester => Tester, - tester_mref => MRef}} - end - end}, - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create (listen) socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = _State) -> - case socket:bind(LSock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock) - end}, - - #{desc => "announce ready", - cmd => fun(#{lsock := LSock, tester := Tester}) -> - ei("announcing port to tester (~p)", [Tester]), - Tester ! {ready, self(), LSock}, - ok - end}, - #{desc => "await continue", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {continue, Tester} -> - ok - end - end}, - - %% *** The actual test part *** - #{desc => "attempt to accept (without success)", - cmd => fun(#{lsock := LSock, timeout := To} = State) -> - Start = t(), - case socket:accept(LSock, To) of - {error, timeout} -> - {ok, State#{start => Start, stop => t()}}; - {ok, Sock} -> - (catch socket:close(Sock)), - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "validate timeout time", - cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester}) -> - ei("announcing port to tester (~p)", [Tester]), - Tester ! {ready, self()}, - ok - end}, - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - ok - end - end}, - - %% *** Close (listen) socket *** - #{desc => "close (listen) socket", - cmd => fun(#{lsock := LSock} = State) -> - sock_close(LSock), - {ok, maps:remove(lsock, State)} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - - SecAcceptorSeq = - [ - %% *** Init part *** - #{desc => "await start", - cmd => fun(State) -> - receive - {start, Tester, LSock} -> - MRef = erlang:monitor(process, Tester), - {ok, State#{tester => Tester, - lsock => LSock, - tester_mref => MRef}} - end - end}, - #{desc => "announce ready (1)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "await continue", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester, Reason}}; - {continue, Tester} -> - ok - end - end}, - - %% *** The actual test part *** - #{desc => "attempt to accept (without success)", - cmd => fun(#{lsock := LSock, timeout := To} = State) -> - Start = t(), - case socket:accept(LSock, To) of - {error, timeout} -> - {ok, State#{start => Start, stop => t()}}; - {ok, Sock} -> - (catch socket:close(Sock)), - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "validate timeout time", - cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end - end}, - #{desc => "announce ready (2)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester, Reason}}; - {terminate, Tester} -> - ok - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - - TesterSeq = - [ - %% Init part - #{desc => "monitor prim-acceptor", - cmd => fun(#{prim_acceptor := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - #{desc => "monitor sec-acceptor 1", - cmd => fun(#{sec_acceptor1 := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - #{desc => "monitor sec-acceptor 2", - cmd => fun(#{sec_acceptor2 := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - - - %% Start the prim-acceptor - #{desc => "start prim-acceptor", - cmd => fun(#{prim_acceptor := Pid} = _State) -> - Pid ! {start, self()}, - ok - end}, - #{desc => "await prim-acceptor ready (1)", - cmd => fun(#{prim_acceptor := Pid} = State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding prim-acceptor ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, prim_acceptor}}; - {ready, Pid, LSock} -> - {ok, State#{lsock => LSock}} - end - end}, - - %% Start sec-acceptor-1 - #{desc => "start sec-acceptor 1", - cmd => fun(#{sec_acceptor1 := Pid, lsock := LSock} = _State) -> - Pid ! {start, self(), LSock}, - ok - end}, - #{desc => "await sec-acceptor 1 ready (1)", - cmd => fun(#{sec_acceptor1 := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding sec-acceptor 1 ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, sec_acceptor_1}}; - {ready, Pid} -> - ok - end - end}, - - %% Start sec-acceptor-2 - #{desc => "start sec-acceptor 2", - cmd => fun(#{sec_acceptor2 := Pid, lsock := LSock} = _State) -> - Pid ! {start, self(), LSock}, - ok - end}, - #{desc => "await sec-acceptor 2 ready (1)", - cmd => fun(#{sec_acceptor2 := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding sec-acceptor 2 ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, sec_acceptor_2}}; - {ready, Pid} -> - ok - end - end}, - - %% Activate the acceptor(s) - #{desc => "active prim-acceptor", - cmd => fun(#{prim_acceptor := Pid} = _State) -> - Pid ! {continue, self()}, - ok - end}, - #{desc => "active sec-acceptor 1", - cmd => fun(#{sec_acceptor1 := Pid} = _State) -> - Pid ! {continue, self()}, - ok - end}, - #{desc => "active sec-acceptor 2", - cmd => fun(#{sec_acceptor2 := Pid} = _State) -> - Pid ! {continue, self()}, - ok - end}, - - %% Await acceptor(s) completions - #{desc => "await prim-acceptor ready (2)", - cmd => fun(#{prim_acceptor := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding prim-acceptor ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, prim_acceptor}}; - {ready, Pid} -> - ok - end - end}, - #{desc => "await sec-acceptor 1 ready (2)", - cmd => fun(#{sec_acceptor1 := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding sec-acceptor 1 ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, sec_acceptor_1}}; - {ready, Pid} -> - ok - end - end}, - #{desc => "await sec-acceptor 2 ready (2)", - cmd => fun(#{sec_acceptor2 := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding sec-acceptor 2 ~p:" - "~n ~p", [Reason]), - {error, {unexpected_exit, sec_acceptor_2}}; - {ready, Pid} -> - ok - end - end}, - - - %% Terminate the acceptor(s) - #{desc => "order prim-acceptor to terminate", - cmd => fun(#{prim_acceptor := Pid} = _State) -> - ei("send terminate command to prim-acceptor (~p)", [Pid]), - Pid ! {terminate, self()}, - ok - end}, - #{desc => "order sec-acceptor 1 to terminate", - cmd => fun(#{sec_acceptor1 := Pid} = _State) -> - ei("send terminate command to sec-acceptor-1 (~p)", [Pid]), - Pid ! {terminate, self()}, - ok - end}, - #{desc => "order sec-acceptor 2 to terminate", - cmd => fun(#{sec_acceptor2 := Pid} = _State) -> - ei("send terminate command to sec-acceptor-2 (~p)", [Pid]), - Pid ! {terminate, self()}, - ok - end}, - - %% Await acceptor(s) termination - #{desc => "await prim-acceptor termination", - cmd => fun(#{prim_acceptor := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - State1 = maps:remove(prim_acceptor, State), - {ok, State1} - end - end}, - #{desc => "await sec-acceptor 1 termination", - cmd => fun(#{sec_acceptor1 := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - State1 = maps:remove(sec_acceptor1, State), - {ok, State1} - end - end}, - #{desc => "await sec-acceptor 2 termination", - cmd => fun(#{sec_acceptor2 := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - State1 = maps:remove(sec_acceptor2, State), - {ok, State1} - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("create prim-acceptor evaluator"), - PrimAInitState = InitState, - PrimAcceptor = evaluator_start("prim-acceptor", - PrimAcceptorSeq, PrimAInitState), - - p("create prim-acceptor 1 evaluator"), - SecAInitState1 = maps:remove(domain, InitState), - SecAcceptor1 = evaluator_start("sec-acceptor-1", - SecAcceptorSeq, SecAInitState1), - - p("create prim-acceptor 2 evaluator"), - SecAInitState2 = SecAInitState1, - SecAcceptor2 = evaluator_start("sec-acceptor-2", - SecAcceptorSeq, SecAInitState2), - - p("create tester evaluator"), - TesterInitState = #{prim_acceptor => PrimAcceptor, - sec_acceptor1 => SecAcceptor1, - sec_acceptor2 => SecAcceptor2}, - Tester = evaluator_start("tester", TesterSeq, TesterInitState), - - p("await evaluator(s)"), - ok = await_evaluator_finish([PrimAcceptor, SecAcceptor1, SecAcceptor2, Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the send timeout option -%% on an IPv4 TCP (stream) socket. -api_to_send_tcp4(suite) -> - []; -api_to_send_tcp4(doc) -> - []; -api_to_send_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_send_tcp4, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_send_tcp(inet) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the send timeout option -%% on an IPv6 TCP (stream) socket. -api_to_send_tcp6(suite) -> - []; -api_to_send_tcp6(doc) -> - []; -api_to_send_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_send_tcp6, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_send_tcp(inet6) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the sendto timeout option -%% on an IPv4 UDP (dgram) socket. -api_to_sendto_udp4(suite) -> - []; -api_to_sendto_udp4(doc) -> - []; -api_to_sendto_udp4(_Config) when is_list(_Config) -> - tc_try(api_to_sendto_udp4, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_sendto_to_udp(inet) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the sendto timeout option -%% on an IPv6 UDP (dgram) socket. -api_to_sendto_udp6(suite) -> - []; -api_to_sendto_udp6(doc) -> - []; -api_to_sendto_udp6(_Config) when is_list(_Config) -> - tc_try(api_to_sendto_udp6, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_sendto_to_udp(inet6) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the sendmsg timeout option -%% on an IPv4 TCP (stream) socket. -api_to_sendmsg_tcp4(suite) -> - []; -api_to_sendmsg_tcp4(doc) -> - []; -api_to_sendmsg_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_sendmsg_tcp4, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_sendmsg_tcp(inet) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the sendmsg timeout option -%% on an IPv6 TCP (stream) socket. -api_to_sendmsg_tcp6(suite) -> - []; -api_to_sendmsg_tcp6(doc) -> - []; -api_to_sendmsg_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_sendmsg_tcp6, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_sendmsg_tcp(inet6) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recv timeout option -%% on an IPv4 UDP (dgram) socket. To test this we must connect -%% the socket. -api_to_recv_udp4(suite) -> - []; -api_to_recv_udp4(doc) -> - []; -api_to_recv_udp4(_Config) when is_list(_Config) -> - tc_try(api_to_recv_udp4, - fun() -> - not_yet_implemented()%%, - %%ok = api_to_recv_udp(inet) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recv timeout option -%% on an IPv6 UDP (dgram) socket. To test this we must connect -%% the socket. -api_to_recv_udp6(suite) -> - []; -api_to_recv_udp6(doc) -> - []; -api_to_recv_udp6(_Config) when is_list(_Config) -> - tc_try(api_to_recv_udp6, - fun() -> - not_yet_implemented()%% , - %% ok = api_to_recv_udp(inet6) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recv timeout option -%% on an IPv4 TCP (stream) socket. -api_to_recv_tcp4(suite) -> - []; -api_to_recv_tcp4(doc) -> - []; -api_to_recv_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_recv_tcp4, - fun() -> - Recv = fun(Sock, To) -> socket:recv(Sock, 0, To) end, - InitState = #{domain => inet, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recv timeout option -%% on an IPv6 TCP (stream) socket. -api_to_recv_tcp6(suite) -> - []; -api_to_recv_tcp6(doc) -> - []; -api_to_recv_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_recv_tcp6, - fun() -> - not_yet_implemented(), - case socket:supports(ipv6) of - true -> - Recv = fun(Sock, To) -> - socket:recv(Sock, 0, To) - end, - InitState = #{domain => inet6, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_tcp(InitState); - false -> - skip("ipv6 not supported") - end - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_receive_tcp(InitState) -> - process_flag(trap_exit, true), - - ServerSeq = - [ - %% *** Wait for start order *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create listen socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> - case socket:bind(LSock, LSA) of - {ok, Port} -> - {ok, State#{lport => Port}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket (with backlog = 1)", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock, 1) - end}, - #{desc => "monitor tester", - cmd => fun(#{tester := Tester} = State) -> - MRef = erlang:monitor(process, Tester), - {ok, State#{tester_mref => MRef}} - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester, lport := Port}) -> - Tester ! {ready, self(), Port}, - ok - end}, - #{desc => "await continue", - cmd => fun(#{tester := Tester}) -> - receive - {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; - {continue, Tester} -> - ok - end - end}, - - %% *** The actual test *** - #{desc => "await accept", - cmd => fun(#{lsock := LSock} = State) -> - case socket:accept(LSock) of - {ok, Sock} -> - %% ok = socket:setopt(Sock, otp, debug, true), - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "attempt to recv (without success)", - cmd => fun(#{sock := Sock, recv := Recv, timeout := To} = State) -> - Start = t(), - case Recv(Sock, To) of - {error, timeout} -> - {ok, State#{start => Start, stop => t()}}; - {ok, _Data} -> - {error, unexpected_success}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "validate timeout time", - cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end - end}, - #{desc => "announce ready (recv timeout success)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - - %% *** Termination *** - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - %% #{desc => "sleep some (before traffic close)", - %% cmd => fun(_) -> - %% ?SLEEP(1000), - %% ok - %% end}, - %% #{desc => "monitored-by", - %% cmd => fun(_) -> - %% {_, Mons} = process_info(self(), monitored_by), - %% ei("Monitored By: ~p", [Mons]), - %% ok - %% end}, - #{desc => "close (traffic) socket", - cmd => fun(#{sock := Sock} = State) -> - %% ok = socket:setopt(Sock, otp, debug, true), - sock_close(Sock), - {ok, maps:remove(sock, State)} - end}, - %% #{desc => "monitored-by", - %% cmd => fun(_) -> - %% {_, Mons} = process_info(self(), monitored_by), - %% ei("Monitored By: ~p", [Mons]), - %% ok - %% end}, - %% #{desc => "sleep some (before listen close)", - %% cmd => fun(_) -> - %% ?SLEEP(1000), - %% ok - %% end}, - #{desc => "close (listen) socket", - cmd => fun(#{lsock := LSock} = State) -> - sock_close(LSock), - {ok, maps:remove(lsock, State)} - end}, - %% #{desc => "sleep some (after listen close)", - %% cmd => fun(_) -> - %% ?SLEEP(1000), - %% ok - %% end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - ClientSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester, Port} when is_pid(Tester) -> - {ok, State#{tester => Tester, - server_port => Port}} - end - end}, - - %% *** 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}, - {ok, State#{lsa => LSA, ssa => SSA}} - end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, stream, tcp) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "monitor tester", - cmd => fun(#{tester := Tester} = State) -> - MRef = erlang:monitor(process, Tester), - {ok, State#{tester_mref => MRef}} - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - - %% *** The actual test *** - #{desc => "await continue (with connect)", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; - {continue, Tester} -> - ok - end - end}, - #{desc => "connect", - cmd => fun(#{sock := Sock, ssa := SSA}) -> - sock_connect(Sock, SSA), - ok - end}, - - %% *** Termination *** - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - {error, {unexpected_exit, tester, Reason}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - #{desc => "close socket", - cmd => fun(#{sock := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock, State)} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - TesterSeq = - [ - %% *** Init part *** - #{desc => "monitor server", - cmd => fun(#{server := Server} = State) -> - MRef = erlang:monitor(process, Server), - {ok, State#{server_mref => MRef}} - end}, - #{desc => "monitor client", - cmd => fun(#{client := Client} = State) -> - MRef = erlang:monitor(process, Client), - {ok, State#{client_mref => MRef}} - end}, - - %% *** Activate server *** - #{desc => "start server", - cmd => fun(#{server := Server} = _State) -> - Server ! {start, self()}, - ok - end}, - #{desc => "await server ready (init)", - cmd => fun(#{server := Server} = State) -> - receive - {'DOWN', _, process, Server, Reason} -> - {error, {unexpected_exit, server, Reason}}; - {ready, Server, Port} -> - {ok, State#{server_port => Port}} - end - end}, - #{desc => "order server to continue (with accept)", - cmd => fun(#{server := Server} = _State) -> - Server ! {continue, self()}, - ok - end}, - - %% *** Activate client *** - #{desc => "start client", - cmd => fun(#{client := Client, server_port := Port} = _State) -> - Client ! {start, self(), Port}, - ok - end}, - #{desc => "await client ready", - cmd => fun(#{client := Client} = _State) -> - receive - {'DOWN', _, process, Client, Reason} -> - {error, {unexpected_exit, client, Reason}}; - {ready, Client} -> - ok - end - end}, - - %% *** The actual test *** - #{desc => "order client to continue (with connect)", - cmd => fun(#{client := Client} = _State) -> - Client ! {continue, self()}, - ok - end}, - #{desc => "await server ready (accept/recv)", - cmd => fun(#{server := Server} = _State) -> - receive - {'DOWN', _, process, Server, Reason} -> - {error, {unexpected_exit, server, Reason}}; - {ready, Server} -> - ok - end - end}, - - %% *** Termination *** - #{desc => "order client to terminate", - cmd => fun(#{client := Client} = _State) -> - Client ! {terminate, self()}, - ok - end}, - #{desc => "await client termination", - cmd => fun(#{client := Client} = State) -> - receive - {'DOWN', _, process, Client, _Reason} -> - State1 = maps:remove(client, State), - State2 = maps:remove(client_mref, State1), - {ok, State2} - end - end}, - #{desc => "order server to terminate", - cmd => fun(#{server := Server} = _State) -> - Server ! {terminate, self()}, - ok - end}, - #{desc => "await server termination", - cmd => fun(#{server := Server} = State) -> - receive - {'DOWN', _, process, Server, _Reason} -> - State1 = maps:remove(server, State), - State2 = maps:remove(server_mref, State1), - State3 = maps:remove(server_port, State2), - {ok, State3} - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - - p("start server evaluator"), - ServerInitState = InitState, - Server = evaluator_start("server", ServerSeq, ServerInitState), - - p("start client evaluator"), - ClientInitState = InitState, - Client = evaluator_start("client", ClientSeq, ClientInitState), - - p("start tester evaluator"), - TesterInitState = #{server => Server, client => Client}, - Tester = evaluator_start("tester", TesterSeq, TesterInitState), - - p("await evaluator(s)"), - ok = await_evaluator_finish([Server, Client, Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvfrom timeout option -%% on an IPv4 UDP (dgram) socket. -api_to_recvfrom_udp4(suite) -> - []; -api_to_recvfrom_udp4(doc) -> - []; -api_to_recvfrom_udp4(_Config) when is_list(_Config) -> - tc_try(api_to_recvfrom_udp4, - fun() -> - Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end, - InitState = #{domain => inet, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvfrom timeout option -%% on an IPv6 UDP (dgram) socket. -api_to_recvfrom_udp6(suite) -> - []; -api_to_recvfrom_udp6(doc) -> - []; -api_to_recvfrom_udp6(_Config) when is_list(_Config) -> - tc_try(api_to_recvfrom_udp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock, To) -> socket:recvfrom(Sock, 0, To) end, - InitState = #{domain => inet6, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -api_to_receive_udp(InitState) -> - TesterSeq = - [ - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain} = State) -> - case socket:open(Domain, dgram, udp) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _Port} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - - %% *** The actual test *** - #{desc => "attempt to read (without success)", - cmd => fun(#{sock := Sock, recv := Recv, timeout := To} = State) -> - Start = t(), - case Recv(Sock, To) of - {error, timeout} -> - {ok, State#{start => Start, stop => t()}}; - {ok, _} -> - {error, unexpected_sucsess}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "validate timeout time", - cmd => fun(#{start := Start, stop := Stop, timeout := To} = _State) -> - TDiff = tdiff(Start, Stop), - if - (TDiff >= To) -> - ok; - true -> - {error, {unexpected_timeout, TDiff, To}} - end - end}, - - %% *** Termination *** - #{desc => "close socket", - cmd => fun(#{sock := Sock} = _State) -> - sock_close(Sock), - ok - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("start tester evaluator"), - Tester = evaluator_start("tester", TesterSeq, InitState), - - p("await evaluator"), - ok = await_evaluator_finish([Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvmsg timeout option -%% on an IPv4 UDP (dgram) socket. -api_to_recvmsg_udp4(suite) -> - []; -api_to_recvmsg_udp4(doc) -> - []; -api_to_recvmsg_udp4(_Config) when is_list(_Config) -> - tc_try(api_to_recvmsg_udp4, - fun() -> - Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, - InitState = #{domain => inet, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvmsg timeout option -%% on an IPv6 UDP (dgram) socket. -api_to_recvmsg_udp6(suite) -> - []; -api_to_recvmsg_udp6(doc) -> - []; -api_to_recvmsg_udp6(_Config) when is_list(_Config) -> - tc_try(api_to_recvmsg_udp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, - InitState = #{domain => inet6, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_udp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvmsg timeout option -%% on an IPv4 TCP (stream) socket. -api_to_recvmsg_tcp4(suite) -> - []; -api_to_recvmsg_tcp4(doc) -> - []; -api_to_recvmsg_tcp4(_Config) when is_list(_Config) -> - tc_try(api_to_recvmsg_tcp4, - fun() -> - Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, - InitState = #{domain => inet, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% This test case is intended to test the recvmsg timeout option -%% on an IPv6 TCP (stream) socket. -api_to_recvmsg_tcp6(suite) -> - []; -api_to_recvmsg_tcp6(doc) -> - []; -api_to_recvmsg_tcp6(_Config) when is_list(_Config) -> - tc_try(api_to_recvmsg_tcp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock, To) -> socket:recvmsg(Sock, To) end, - InitState = #{domain => inet6, - recv => Recv, - timeout => 5000}, - ok = api_to_receive_tcp(InitState) - end). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% %% -%% SOCKET CLOSURE %% -%% %% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test that the sockets are cleaned up -%% ("removed") when the controlling process terminates (without explicitly -%% calling the close function). For a IPv4 TCP (stream) socket. - -sc_cpe_socket_cleanup_tcp4(suite) -> - []; -sc_cpe_socket_cleanup_tcp4(doc) -> - []; -sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_cpe_socket_cleanup_tcp4, - fun() -> - %% not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = sc_cpe_socket_cleanup(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test that the sockets are cleaned up -%% ("removed") when the controlling process terminates (without explicitly -%% calling the close function). For a IPv6 TCP (stream) socket. - -sc_cpe_socket_cleanup_tcp6(suite) -> - []; -sc_cpe_socket_cleanup_tcp6(doc) -> - []; -sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_cpe_socket_cleanup_tcp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, - type => stream, - protocol => tcp}, - ok = sc_cpe_socket_cleanup(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test that the sockets are cleaned up -%% ("removed") when the controlling process terminates (without explicitly -%% calling the close function). For a IPv4 UDP (dgram) socket. - -sc_cpe_socket_cleanup_udp4(suite) -> - []; -sc_cpe_socket_cleanup_udp4(doc) -> - []; -sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) -> - tc_try(sc_cpe_socket_cleanup_udp4, - fun() -> - InitState = #{domain => inet, - type => dgram, - protocol => udp}, - ok = sc_cpe_socket_cleanup(InitState) - end). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test that the sockets are cleaned up -%% (removed) when the controlling process terminates (without explicitly -%% calling the close function). For a IPv6 UDP (dgram) socket. - -sc_cpe_socket_cleanup_udp6(suite) -> - []; -sc_cpe_socket_cleanup_udp6(doc) -> - []; -sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) -> - tc_try(sc_cpe_socket_cleanup_udp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet6, - type => dgram, - protocol => udp}, - ok = sc_cpe_socket_cleanup(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sc_cpe_socket_cleanup(InitState) -> - OwnerSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - - %% *** Init part *** - #{desc => "monitor tester", - cmd => fun(#{tester := Tester} = _State) -> - _MRef = erlang:monitor(process, Tester), - ok - end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Proto} = State) -> - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester, sock := Sock} = _State) -> - Tester ! {ready, self(), Sock}, - ok - end}, - - %% *** The actual test *** - %% We intentially leave the socket "as is", no explicit close - #{desc => "await terminate (from tester)", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - %% #{desc => "enable (otp) debug", - %% cmd => fun(#{sock := Sock} = _State) -> - %% ok = socket:setopt(Sock, otp, debug, true) - %% end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - TesterSeq = - [ - %% *** Init part *** - #{desc => "monitor owner", - cmd => fun(#{owner := Owner} = _State) -> - _MRef = erlang:monitor(process, Owner), - ok - end}, - #{desc => "order (owner) start", - cmd => fun(#{owner := Pid} = _State) -> - Pid ! {start, self()}, - ok - end}, - #{desc => "await (owner) ready", - cmd => fun(#{owner := Owner} = State) -> - receive - {'DOWN', _, process, Owner, Reason} -> - ee("Unexpected DOWN regarding owner ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, owner}}; - {ready, Owner, Sock} -> - {ok, State#{sock => Sock}} - end - end}, - #{desc => "verify owner as controlling-process", - cmd => fun(#{owner := Owner, sock := Sock} = _State) -> - case socket:getopt(Sock, otp, controlling_process) of - {ok, Owner} -> - ok; - {ok, Other} -> - {error, {unexpected_owner, Other}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "order (owner) terminate", - cmd => fun(#{owner := Pid} = _State) -> - Pid ! {terminate, self()}, - ok - end}, - #{desc => "await (owner) termination", - cmd => fun(#{owner := Owner} = _State) -> - receive - {'DOWN', _, process, Owner, _} -> - ok - end - end}, - #{desc => "verify no socket (closed)", - cmd => fun(#{owner := Owner, sock := Sock} = _State) -> - case socket:getopt(Sock, otp, controlling_process) of - {ok, Pid} -> - {error, {unexpected_success, Owner, Pid}}; - {error, closed} -> - ok; - {error, Reason} -> - ei("expected failure: ~p", [Reason]), - {error, {unexpected_failure, Reason}} - end - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("start (socket) owner evaluator"), - Owner = evaluator_start("owner", OwnerSeq, InitState), - - p("start tester evaluator"), - TesterInitState = #{owner => Owner}, - Tester = evaluator_start("tester", TesterSeq, TesterInitState), - - p("await evaluator"), - ok = await_evaluator_finish([Owner, Tester]). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while a process is calling the recv function. -%% Socket is IPv4. -%% -%% -%% -%% We should really have a similar test cases for when the controlling -%% process exits and there are other processes in recv, accept, and -%% all the other functions. -%% -%% - -sc_lc_recv_response_tcp4(suite) -> - []; -sc_lc_recv_response_tcp4(doc) -> - []; -sc_lc_recv_response_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_lc_recv_response_tcp4, - fun() -> - %% not_yet_implemented(), - Recv = fun(Sock) -> socket:recv(Sock) end, - InitState = #{domain => inet, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_lc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the recv function. -%% Socket is IPv6. - -sc_lc_recv_response_tcp6(suite) -> - []; -sc_lc_recv_response_tcp6(doc) -> - []; -sc_lc_recv_response_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_lc_recv_response_tcp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recv(Sock) end, - InitState = #{domain => inet6, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_lc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sc_lc_receive_response_tcp(InitState) -> - %% This is the server that accepts connections. - %% But it is also suppose to close the connection socket, - %% and trigger the read failure for the handler process. - AcceptorSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - #{desc => "monitor tester", - cmd => fun(#{tester := Tester} = _State) -> - _MRef = erlang:monitor(process, Tester), - ok - end}, - - %% *** Init part *** - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create (listen) socket", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Proto} = State) -> - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - {ok, State#{lsock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind to local address", - cmd => fun(#{lsock := LSock, lsa := LSA} = State) -> - case socket:bind(LSock, LSA) of - {ok, Port} -> - {ok, State#{lport => Port}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "make listen socket", - cmd => fun(#{lsock := LSock}) -> - socket:listen(LSock) - end}, - #{desc => "announce ready (init)", - cmd => fun(#{tester := Tester, lport := Port}) -> - Tester ! {ready, self(), Port}, - ok - end}, - - %% The actual test - #{desc => "await continue (connection)", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {continue, Tester, Handler} -> - {ok, State#{handler => Handler}} - end - end}, - #{desc => "await connection", - cmd => fun(#{lsock := LSock} = State) -> - case socket:accept(LSock) of - {ok, Sock} -> - ei("connection accepted"), - {ok, State#{csock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "transfer new connection to handler", - cmd => fun(#{handler := Handler, csock := Sock}) -> - ok = socket:setopt(Sock, - otp, controlling_process, - Handler), - Handler ! {connection, Sock}, - ok - end}, - #{desc => "announce ready (connection)", - cmd => fun(#{tester := Tester}) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "await continue (close)", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {continue, Tester} -> - ok - end - end}, - %% #{desc => "enable debug", - %% cmd => fun(#{csock := Sock}) -> - %% socket:setopt(Sock, otp, debug, true) - %% end}, - #{desc => "close (the connection) socket", - cmd => fun(#{csock := Sock}) -> - socket:close(Sock) - end}, - - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - #{desc => "socket cleanup", - cmd => fun(#{lsock := Sock} = State) -> - ok = socket:close(Sock), - State1 = maps:remove(csock, State), - State2 = maps:remove(lsock, State1), - State3 = maps:remove(lport, State2), - {ok, State3} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - %% The point of this is to perform the recv for which we are testing the reponse - HandlerSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - #{desc => "monitor server", - cmd => fun(#{tester := Tester} = _State) -> - _MRef = erlang:monitor(process, Tester), - ok - end}, - #{desc => "announce ready (init)", - cmd => fun(#{tester := Tester}) -> - Tester ! {ready, self()}, - ok - end}, - - %% The actual test - #{desc => "await connection socket", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {connection, Sock} -> - {ok, State#{sock => Sock}} - end - end}, - #{desc => "announce ready (connection)", - cmd => fun(#{tester := Tester}) -> - Tester ! {ready, self()}, - ok - end}, - %% #{desc => "enable debug", - %% cmd => fun(#{sock := Sock}) -> - %% socket:setopt(Sock, otp, debug, true) - %% end}, - %% #{desc => "monitored-by", - %% cmd => fun(_) -> - %% {_, Mons} = process_info(self(), monitored_by), - %% ei("Monitored By: ~p", [Mons]), - %% ok - %% end}, - #{desc => "attempt recv", - cmd => fun(#{sock := Sock, recv := Recv} = State) -> - case Recv(Sock) of - {ok, _Data} -> - ee("Unexpected data received"), - {error, unexpected_data}; - {error, closed} -> - State1 = maps:remove(sock, State), - {ok, State1}; - {error, Reason} = ERROR -> - ee("Unexpected read faulure: " - "~n ~p", [Reason]), - ERROR - end - end}, - %% #{desc => "monitored-by", - %% cmd => fun(_) -> - %% {_, Mons} = process_info(self(), monitored_by), - %% ei("Monitored By: ~p", [Mons]), - %% ok - %% end}, - #{desc => "announce ready (close)", - cmd => fun(#{tester := Tester}) -> - Tester ! {ready, self()}, - ok - end}, - #{desc => "sleep some", - cmd => fun(_) -> - ?SLEEP(1000), - ok - end}, - %% #{desc => "monitored-by", - %% cmd => fun(_) -> - %% {_, Mons} = process_info(self(), monitored_by), - %% ei("Monitored By: ~p", [Mons]), - %% ok - %% end}, - #{desc => "await terminate", - cmd => fun(#{tester := Tester} = _State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - ok - end - end}, - - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - %% The point of this is basically just to create the connection. - ClientSeq = - [ - %% *** Wait for start order part *** - #{desc => "await start (from tester)", - cmd => fun(State) -> - receive - {start, Tester} when is_pid(Tester) -> - {ok, State#{tester => Tester}} - end - end}, - - %% Init - #{desc => "which local address", - cmd => fun(#{domain := Domain} = State) -> - LAddr = which_local_addr(Domain), - LSA = #{family => Domain, addr => LAddr}, - {ok, State#{lsa => LSA}} - end}, - #{desc => "create socket", - cmd => fun(#{domain := Domain, - type := Type, - protocol := Proto} = State) -> - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - {ok, State#{sock => Sock}}; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "bind socket to local address", - cmd => fun(#{sock := Sock, lsa := LSA} = _State) -> - case socket:bind(Sock, LSA) of - {ok, _} -> - ok; - {error, _} = ERROR -> - ERROR - end - end}, - #{desc => "announce ready", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - - %% The actual test - #{desc => "await continue", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Tester, Reason]), - {error, {unexpected_exit, tester, Reason}}; - {continue, Tester, Port} -> - {ok, State#{lport => Port}} - end - end}, - #{desc => "connect to server", - cmd => fun(#{sock := Sock, lsa := LSA, lport := LPort}) -> - socket:connect(Sock, LSA#{port => LPort}) - end}, - #{desc => "announce ready (connection)", - cmd => fun(#{tester := Tester} = _State) -> - Tester ! {ready, self()}, - ok - end}, - - %% Cleaning up - #{desc => "await terminate (from tester)", - cmd => fun(#{tester := Tester} = State) -> - receive - {'DOWN', _, process, Tester, Reason} -> - ee("Unexpected DOWN regarding tester ~p: " - "~n ~p", [Tester, Reason]), - {error, {unexpected_exit, tester}}; - {terminate, Tester} -> - {ok, maps:remove(tester, State)} - end - end}, - #{desc => "close socket", - cmd => fun(#{sock := Sock} = State) -> - sock_close(Sock), - {ok, maps:remove(sock, State)} - end}, - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - TesterSeq = - [ - %% *** Init part *** - #{desc => "monitor acceptor", - cmd => fun(#{acceptor := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - #{desc => "monitor handler", - cmd => fun(#{handler := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - #{desc => "monitor client", - cmd => fun(#{client := Pid} = _State) -> - _MRef = erlang:monitor(process, Pid), - ok - end}, - - %% Start the acceptor - #{desc => "order acceptor start", - cmd => fun(#{acceptor := Pid} = _State) -> - Pid ! {start, self()}, - ok - end}, - #{desc => "await acceptor ready (init)", - cmd => fun(#{acceptor := Pid} = State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding acceptor ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid, Port} -> - {ok, State#{lport => Port}} - end - end}, - - %% Start the handler - #{desc => "order handler start", - cmd => fun(#{handler := Pid} = _State) -> - Pid ! {start, self()}, - ok - end}, - #{desc => "await handler ready (init)", - cmd => fun(#{handler := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding handler ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - - %% Start the client - #{desc => "order client start", - cmd => fun(#{client := Pid} = _State) -> - Pid ! {start, self()}, - ok - end}, - #{desc => "await client ready (init)", - cmd => fun(#{client := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding cient ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - - %% The actual test - #{desc => "order acceptor to continue", - cmd => fun(#{acceptor := Pid, handler := Handler} = _State) -> - Pid ! {continue, self(), Handler}, - ok - end}, - #{desc => "order client to continue", - cmd => fun(#{client := Pid, lport := Port} = _State) -> - Pid ! {continue, self(), Port}, - ok - end}, - #{desc => "await acceptor ready (connection)", - cmd => fun(#{acceptor := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding acceptor ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - #{desc => "await client ready (connection)", - cmd => fun(#{client := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding client ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - #{desc => "await handler ready (connection)", - cmd => fun(#{handler := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding handler ~p: " - "~n ~p", [Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - #{desc => "sleep some", - cmd => fun(_State) -> - ?SLEEP(1000), - ok - end}, - #{desc => "order acceptor to continue (close)", - cmd => fun(#{acceptor := Pid} = _State) -> - Pid ! {continue, self()}, - ok - end}, - #{desc => "await handler ready (close)", - cmd => fun(#{handler := Pid} = _State) -> - receive - {'DOWN', _, process, Pid, Reason} -> - ee("Unexpected DOWN regarding handler ~p: " - "~n ~p", [Pid, Reason]), - {error, {unexpected_exit, acceptor}}; - {ready, Pid} -> - ok - end - end}, - - %% Terminations - #{desc => "order handler to terminate", - cmd => fun(#{handler := Pid} = _State) -> - Pid ! {terminate, self()}, - ok - end}, - #{desc => "await handler termination", - cmd => fun(#{handler := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - {ok, maps:remove(handler, State)} - end - end}, - #{desc => "order client to terminate", - cmd => fun(#{client := Pid} = _State) -> - Pid ! {terminate, self()}, - ok - end}, - #{desc => "await client termination", - cmd => fun(#{client := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - {ok, maps:remove(client, State)} - end - end}, - #{desc => "order acceptor to terminate", - cmd => fun(#{acceptor := Pid} = _State) -> - Pid ! {terminate, self()}, - ok - end}, - #{desc => "await acceptor termination", - cmd => fun(#{acceptor := Pid} = State) -> - receive - {'DOWN', _, process, Pid, _} -> - {ok, maps:remove(acceptor, State)} - end - end}, - - - %% *** We are done *** - #{desc => "finish", - cmd => fun(_) -> - {ok, normal} - end} - ], - - p("start acceptor evaluator"), - AccInitState = InitState, - Acceptor = evaluator_start("acceptor", AcceptorSeq, AccInitState), - - p("start handler evaluator"), - HandlerInitState = #{recv => maps:get(recv, InitState)}, - Handler = evaluator_start("handler", HandlerSeq, HandlerInitState), - - p("start client evaluator"), - ClientInitState = InitState, - Client = evaluator_start("client", ClientSeq, ClientInitState), - - p("start tester evaluator"), - TesterInitState = #{acceptor => Acceptor, - handler => Handler, - client => Client}, - Tester = evaluator_start("tester", TesterSeq, TesterInitState), - - p("await evaluator"), - ok = await_evaluator_finish([Acceptor, Handler, Client, Tester]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the recv function. -%% Socket is IPv4. - -sc_rc_recv_response_tcp4(suite) -> - []; -sc_rc_recv_response_tcp4(doc) -> - []; -sc_rc_recv_response_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_rc_recv_response_tcp4, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recv(Sock) end, - InitState = #{domain => inet, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_rc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the recv function. -%% Socket is IPv6. - -sc_rc_recv_response_tcp6(suite) -> - []; -sc_rc_recv_response_tcp6(doc) -> - []; -sc_rc_recv_response_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_rc_recv_response_tcp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recv(Sock) end, - InitState = #{domain => inet6, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_rc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sc_rc_receive_response_tcp(_InitState) -> - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the recvmsg function. -%% Socket is IPv4. - -sc_lc_recvmsg_response_tcp4(suite) -> - []; -sc_lc_recvmsg_response_tcp4(doc) -> - []; -sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_lc_recvmsg_response_tcp4, - fun() -> - Recv = fun(Sock) -> socket:recvmsg(Sock) end, - InitState = #{domain => inet, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_lc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the recvmsg function. -%% Socket is IPv6. - -sc_lc_recvmsg_response_tcp6(suite) -> - []; -sc_lc_recvmsg_response_tcp6(doc) -> - []; -sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_recvmsg_response_tcp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recvmsg(Sock) end, - InitState = #{domain => inet6, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_lc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the recvmsg function. -%% Socket is IPv4. - -sc_rc_recvmsg_response_tcp4(suite) -> - []; -sc_rc_recvmsg_response_tcp4(doc) -> - []; -sc_rc_recvmsg_response_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_rc_recvmsg_response_tcp4, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recvmsg(Sock) end, - InitState = #{domain => inet, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_rc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% remotely closed while the process is calling the recvmsg function. -%% Socket is IPv6. - -sc_rc_recvmsg_response_tcp6(suite) -> - []; -sc_rc_recvmsg_response_tcp6(doc) -> - []; -sc_rc_recvmsg_response_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_rc_recvmsg_response_tcp6, - fun() -> - not_yet_implemented(), - Recv = fun(Sock) -> socket:recvmsg(Sock) end, - InitState = #{domain => inet6, - type => stream, - protocol => tcp, - recv => Recv}, - ok = sc_rc_receive_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the accept function. -%% We test what happens with a non-controlling_process also, since we -%% git the setup anyway. -%% Socket is IPv4. - -sc_lc_acceptor_response_tcp4(suite) -> - []; -sc_lc_acceptor_response_tcp4(doc) -> - []; -sc_lc_acceptor_response_tcp4(_Config) when is_list(_Config) -> - tc_try(sc_lc_acceptor_response_tcp4, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = sc_lc_acceptor_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This test case is intended to test what happens when a socket is -%% locally closed while the process is calling the accept function. -%% We test what happens with a non-controlling_process also, since we -%% git the setup anyway. -%% Socket is IPv6. - -sc_lc_acceptor_response_tcp6(suite) -> - []; -sc_lc_acceptor_response_tcp6(doc) -> - []; -sc_lc_acceptor_response_tcp6(_Config) when is_list(_Config) -> - tc_try(sc_lc_acceptor_response_tcp6, - fun() -> - not_yet_implemented(), - InitState = #{domain => inet, - type => stream, - protocol => tcp}, - ok = sc_lc_acceptor_response_tcp(InitState) - end). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sc_lc_acceptor_response_tcp(_InitState) -> - ok. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% 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) -> - case inet:getifaddrs() of - {ok, IFL} -> - which_addr(Domain, IFL); - {error, Reason} -> - ?FAIL({inet, getifaddrs, Reason}) - end. - -which_addr(_Domain, []) -> - ?FAIL(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -which_addr(Domain, [_|IFL]) -> - which_addr(Domain, IFL). - -which_addr2(_Domain, []) -> - ?FAIL(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) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% An evaluator is a process that executes a command sequence. -%% A test case will consist of atleast one evaluator (one for -%% each actor). -%% The evaluator process *always* run locally. Which means that -%% it will act as a "proxy" for remote nodes in necessary. -%% When the command sequence has been processed, the final state -%% will be used as exit reason. -%% A successful command shall evaluate to ok | {ok, NewState} - --spec evaluator_start(Name, Seq, Init) -> {Pid, MRef} when - Name :: string(), - Seq :: [command()], - Init :: initial_evaluator_state(), - Pid :: pid(), - MRef :: reference(). - -evaluator_start(Name, Seq, Init) - when is_list(Name) andalso is_list(Seq) andalso (Seq =/= []) -> - Init2 = Init#{parent => self()}, - {Pid, _} = erlang:spawn_monitor(fun() -> evaluator_init(Name, Seq, Init2) end), - Pid. - -evaluator_init(Name, Seq, Init) -> - put(sname, Name), - evaluator_loop(1, Seq, Init). - -evaluator_loop(_ID, [], FinalState) -> - exit(FinalState); -evaluator_loop(ID, [#{desc := Desc, - cmd := Cmd}|Cmds], State) when is_function(Cmd, 1) -> - ei("evaluate command ~2w: ~s", [ID, Desc]), - try Cmd(State) of - ok -> - evaluator_loop(ID + 1, Cmds, State); - {ok, NewState} -> - evaluator_loop(ID + 1, Cmds, NewState); - {error, Reason} -> - ee("command ~w failed: " - "~n Reason: ~p", [ID, Reason]), - exit({command_failed, ID, Reason, State}) - catch - C:E:S -> - ee("command ~w crashed: " - "~n Class: ~p" - "~n Error: ~p" - "~n Call Stack: ~p", [ID, C, E, S]), - exit({command_crashed, ID, {C,E,S}, State}) - end. - -await_evaluator_finish(Evs) -> - await_evaluator_finish(Evs, []). - -await_evaluator_finish([], []) -> - ok; -await_evaluator_finish([], Fails) -> - Fails; -await_evaluator_finish(Evs, Fails) -> - receive - {'DOWN', _MRef, process, Pid, normal} -> - case lists:delete(Pid, Evs) of - Evs -> - p("unknown process ~p died (normal)", [Pid]), - await_evaluator_finish(Evs, Fails); - NewEvs -> - p("evaluator ~p success", [Pid]), - await_evaluator_finish(NewEvs, Fails) - end; - {'DOWN', _MRef, process, Pid, Reason} -> - case lists:delete(Pid, Evs) of - Evs -> - p("unknown process ~p died: " - "~n ~p", [Pid, Reason]), - await_evaluator_finish(Evs, Fails); - NewEvs -> - p("Evaluator ~p failed", [Pid]), - await_evaluator_finish(NewEvs, [{Pid, Reason}|Fails]) - end - end. - - -ei(F) -> - ei(F, []). -ei(F, A) -> - eprint("", F, A). - -ee(F) -> - ee(F, []). -ee(F, A) -> - eprint(" ", F, A). - -eprint(Prefix, F, A) -> - io:format(user, "[~s][~s][~p] ~s" ++ F ++ "~n", - [formated_timestamp(), get(sname), self(), Prefix | A]). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -sock_open(Domain, Type, Proto) -> - try socket:open(Domain, Type, Proto) of - {ok, Socket} -> - Socket; - {error, Reason} -> - ?FAIL({open, Reason}) - catch - C:E:S -> - ?FAIL({open, C, E, S}) - end. - - -sock_bind(Sock, SockAddr) -> - try socket:bind(Sock, SockAddr) of - {ok, Port} -> - Port; - {error, Reason} -> - p("sock_bind -> error: ~p", [Reason]), - ?FAIL({bind, Reason}) - catch - C:E:S -> - p("sock_bind -> failed: ~p, ~p, ~p", [C, E, S]), - ?FAIL({bind, C, E, S}) - end. - -sock_connect(Sock, SockAddr) -> - try socket:connect(Sock, SockAddr) of - ok -> - ok; - {error, Reason} -> - ?FAIL({connect, Reason}) - catch - C:E:S -> - ?FAIL({connect, C, E, S}) - end. - -sock_sockname(Sock) -> - try socket:sockname(Sock) of - {ok, SockAddr} -> - SockAddr; - {error, Reason} -> - ?FAIL({sockname, Reason}) - catch - C:E:S -> - ?FAIL({sockname, C, E, S}) - end. - - -%% sock_listen(Sock) -> -%% sock_listen2(fun() -> socket:listen(Sock) end). - -%% sock_listen(Sock, BackLog) -> -%% sock_listen2(fun() -> socket:listen(Sock, BackLog) end). - -%% sock_listen2(Listen) -> -%% try Listen() of -%% ok -> -%% ok; -%% {error, Reason} -> -%% ?FAIL({listen, Reason}) -%% catch -%% C:E:S -> -%% ?FAIL({listen, C, E, S}) -%% end. - - -%% sock_accept(LSock) -> -%% try socket:accept(LSock) of -%% {ok, Sock} -> -%% Sock; -%% {error, Reason} -> -%% p("sock_accept -> error: ~p", [Reason]), -%% ?FAIL({accept, Reason}) -%% catch -%% C:E:S -> -%% p("sock_accept -> failed: ~p, ~p, ~p", [C, E, S]), -%% ?FAIL({accept, C, E, S}) -%% end. - - -sock_close(Sock) -> - try socket:close(Sock) of - ok -> - ok; - {error, Reason} -> - p("sock_close -> error: ~p", [Reason]), - ?FAIL({close, Reason}) - catch - C:E:S -> - p("sock_close -> failed: ~p, ~p, ~p", [C, E, S]), - ?FAIL({close, C, E, S}) - end. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -not_yet_implemented() -> - skip("not yet implemented"). - -skip(Reason) -> - throw({skip, Reason}). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -t() -> - os:timestamp(). - - -tdiff({A1, B1, C1} = _T1x, {A2, B2, C2} = _T2x) -> - T1 = A1*1000000000+B1*1000+(C1 div 1000), - T2 = A2*1000000000+B2*1000+(C2 div 1000), - T2 - T1. - - -formated_timestamp() -> - format_timestamp(os:timestamp()). - -format_timestamp({_N1, _N2, _N3} = TS) -> - {_Date, Time} = calendar:now_to_local_time(TS), - %% {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - %% FormatTS = - %% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~w", - %% [YYYY, MM, DD, Hour, Min, Sec, N3]), - FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w", [Hour, Min, Sec]), - lists:flatten(FormatTS). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -set_tc_name(N) when is_atom(N) -> - set_tc_name(atom_to_list(N)); -set_tc_name(N) when is_list(N) -> - put(tc_name, N). - -%% get_tc_name() -> -%% get(tc_name). - -tc_begin(TC) -> - set_tc_name(TC), - p("begin ***"). - -tc_end(Result) when is_list(Result) -> - p("done: ~s", [Result]), - ok. - - -tc_try(Case, Fun) when is_atom(Case) andalso is_function(Fun, 0) -> - tc_begin(Case), - try - begin - Fun(), - tc_end("ok") - end - catch - throw:{skip, _} = SKIP -> - tc_end("skipping"), - SKIP; - Class:Error:Stack -> - tc_end("failed"), - erlang:raise(Class, Error, Stack) - end. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% f(F, A) -> -%% lists:flatten(io_lib:format(F, A)). - -p(F) -> - p(F, []). - -p(F, A) -> - TcName = - case get(tc_name) of - undefined -> - case get(sname) of - undefined -> - ""; - SName when is_list(SName) -> - SName - end; - Name when is_list(Name) -> - Name - end, - i("*** [~s][~s][~p] " ++ F, [formated_timestamp(),TcName,self()|A]). - - -%% i(F) -> -%% i(F, []). - -i(F, A) -> - io:format(user, F ++ "~n", A). diff --git a/lib/kernel/test/socket_client.erl b/lib/kernel/test/socket_client.erl deleted file mode 100644 index 1c07e799b8..0000000000 --- a/lib/kernel/test/socket_client.erl +++ /dev/null @@ -1,538 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(socket_client). - --export([ - start/1, start/2, start/5, start/6, - start_tcp/1, start_tcp/2, start_tcp/3, - start_tcp4/1, start_tcp4/2, start_tcp6/1, start_tcp6/2, - start_udp/1, start_udp/2, start_udp/3, - start_udp4/1, start_udp4/2, start_udp6/1, start_udp6/2 - ]). - --define(LIB, socket_lib). - --record(client, {socket, verbose = true, msg = true, type, dest, msg_id = 1}). - -start(Port) -> - start(Port, 1). - -start(Port, Num) -> - start_tcp(Port, Num). - -start_tcp(Port) -> - start_tcp(Port, 1). - -start_tcp(Port, Num) -> - start_tcp4(Port, Num). - -start_tcp4(Port) -> - start_tcp4(Port, 1). - -start_tcp4(Port, Num) -> - start(inet, stream, tcp, Port, Num). - -start_tcp6(Port) -> - start_tcp6(Port, 1). - -start_tcp6(Port, Num) -> - start(inet6, stream, tcp, Port, Num). - -start_tcp(Addr, Port, Num) when (size(Addr) =:= 4) andalso - is_integer(Num) andalso - (Num > 0) -> - start(inet, stream, tcp, Addr, Port, Num); -start_tcp(Addr, Port, Num) when (size(Addr) =:= 8) andalso - is_integer(Num) andalso - (Num > 0) -> - start(inet6, stream, tcp, Addr, Port, Num). - - -start_udp(Port) -> - start_udp(Port, 1). - -start_udp(Port, Num) -> - start_udp4(Port, Num). - -start_udp4(Port) -> - start_udp4(Port, 1). - -start_udp4(Port, Num) -> - start(inet, dgram, udp, Port, Num). - -start_udp6(Port) -> - start_udp6(Port, 1). - -start_udp6(Port, Num) -> - start(inet6, dgram, udp, Port, Num). - -start_udp(Addr, Port, Num) when (size(Addr) =:= 4) -> - start(inet, dgram, udp, Addr, Port, Num); -start_udp(Addr, Port, Num) when (size(Addr) =:= 8) -> - start(inet6, dgram, udp, Addr, Port, Num). - - -start(Domain, Type, Proto, Port, Num) - when is_integer(Port) andalso is_integer(Num) -> - start(Domain, Type, Proto, which_addr(Domain), Port, Num); - -start(Domain, Type, Proto, Addr, Port) -> - start(Domain, Type, Proto, Addr, Port, 1). - -start(Domain, Type, Proto, Addr, Port, 1 = Num) -> - start(Domain, Type, Proto, Addr, Port, Num, true); -start(Domain, Type, Proto, Addr, Port, Num) - when is_integer(Num) andalso (Num > 1) -> - start(Domain, Type, Proto, Addr, Port, Num, false). - -start(Domain, Type, Proto, Addr, Port, Num, Verbose) -> - put(sname, "starter"), - Clients = start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose), - await_clients(Clients). - -start_clients(Num, Domain, Type, Proto, Addr, Port, Verbose) -> - start_clients(Num, 1, Domain, Type, Proto, Addr, Port, Verbose, []). - -start_clients(Num, ID, Domain, Type, Proto, Addr, Port, Verbose, Acc) - when (Num > 0) -> - StartClient = fun() -> - start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) - end, - {Pid, _} = spawn_monitor(StartClient), - ?LIB:sleep(500), - i("start client ~w", [ID]), - start_clients(Num-1, ID+1, Domain, Type, Proto, Addr, Port, Verbose, [Pid|Acc]); -start_clients(_, _, _, _, _, _, _, _, Acc) -> - i("all client(s) started"), - lists:reverse(Acc). - -await_clients([]) -> - i("all clients done"); -await_clients(Clients) -> - receive - {'DOWN', _MRef, process, Pid, _Reason} -> - case lists:delete(Pid, Clients) of - Clients2 when (Clients2 =/= Clients) -> - i("client ~p done", [Pid]), - await_clients(Clients2); - _ -> - await_clients(Clients) - end - end. - - -start_client(ID, Domain, Type, Proto, Addr, Port, Verbose) -> - put(sname, ?LIB:f("client[~w]", [ID])), - SA = #{family => Domain, - addr => Addr, - port => Port}, - %% The way we use tos only works because we - %% send so few messages (a new value for every - %% message). - tos_init(), - do_start(Domain, Type, Proto, SA, Verbose). - -do_start(Domain, stream = Type, Proto, SA, Verbose) -> - try do_init(Domain, Type, Proto) of - Sock -> - connect(Sock, SA), - maybe_print_start_info(Verbose, Sock, Type), - %% Give the server some time... - ?LIB:sleep(5000), - %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type, - verbose = Verbose}) - catch - throw:E -> - e("Failed initiate: " - "~n Error: ~p", [E]) - end; -do_start(Domain, dgram = Type, Proto, SA, Verbose) -> - try do_init(Domain, Type, Proto) of - Sock -> - maybe_print_start_info(Verbose, Sock, Type), - %% Give the server some time... - ?LIB:sleep(5000), - %% ok = socket:close(Sock), - send_loop(#client{socket = Sock, - type = Type, - dest = SA, - verbose = Verbose}) - catch - throw:E -> - e("Failed initiate: " - "~n Error: ~p", [E]) - end. - -maybe_print_start_info(true = _Verbose, Sock, stream = _Type) -> - {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, MTU} = socket:getopt(Sock, ip, mtu), - {ok, MTUDisc} = socket:getopt(Sock, ip, 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), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - i("connected: " - "~n From: ~p" - "~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) MTU: ~p" - "~n (ip) MTU Discovery: ~p" - "~n (ip) Multicast ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n => wait some", - [Name, Peer, - Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MTU, MTUDisc, MALL, MIF, MLoop, MTTL, - RecvTOS]); -maybe_print_start_info(true = _Verbose, Sock, dgram = _Type) -> - {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, 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), - {ok, RecvTOS} = socket:getopt(Sock, ip, recvtos), - {ok, RecvTTL} = socket:getopt(Sock, ip, recvttl), - 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 ALL: ~p" - "~n (ip) Multicast IF: ~p" - "~n (ip) Multicast Loop: ~p" - "~n (ip) Multicast TTL: ~p" - "~n (ip) RecvTOS: ~p" - "~n (ip) RecvTTL: ~p" - "~n => wait some", - [Domain, Type, Proto, - OOBI, SndBuf, RcvBuf, Linger, - MALL, MIF, MLoop, MTTL, - RecvTOS, RecvTTL]); -maybe_print_start_info(_Verbose, _Sock, _Type) -> - ok. - - -do_init(Domain, stream = Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - i("try (socket) bind"), - case socket:bind(Sock, any) of - {ok, _P} -> - ok = socket:setopt(Sock, socket, timestamp, true), - ok = socket:setopt(Sock, ip, tos, mincost), - ok = socket:setopt(Sock, ip, recvtos, true), - Sock; - {error, BReason} -> - throw({bind, BReason}) - end; -do_init(Domain, dgram = Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - case socket:bind(Sock, any) of - {ok, _} -> - ok = socket:setopt(Sock, socket, timestamp, true), - ok = socket:setopt(Sock, ip, tos, mincost), - ok = socket:setopt(Sock, ip, recvtos, true), - ok = socket:setopt(Sock, ip, recvttl, true), - Sock; - {error, BReason} -> - throw({bind, BReason}) - end. - - -which_addr(Domain) -> - Iflist = case inet:getifaddrs() of - {ok, IFL} -> - IFL; - {error, Reason} -> - throw({inet,getifaddrs,Reason}) - end, - which_addr(Domain, Iflist). - - -connect(Sock, SA) -> - i("try (socket) connect to:" - "~n ~p", [SA]), - case socket:connect(Sock, SA) of - ok -> - ok; - {error, Reason} -> - e("connect failure: " - "~n ~p", [Reason]), - exit({connect, Reason}) - end. - - -send_loop(#client{msg_id = N} = C) when (N =< 10) -> - i("try send request ~w", [N]), - Req = ?LIB:enc_req_msg(N, "hejsan"), - case send(C, Req) of - ok -> - i("request ~w sent - now try read answer", [N]), - case recv(C) of - {ok, {Source, Msg}} -> - if - (C#client.verbose =:= true) -> - i("received ~w bytes of data~s", - [size(Msg), case Source of - undefined -> ""; - _ -> ?LIB:f(" from:~n ~p", [Source]) - end]); - true -> - i("received ~w bytes", [size(Msg)]) - end, - case ?LIB:dec_msg(Msg) of - {reply, N, Reply} -> - if - (C#client.verbose =:= true) -> - i("received reply ~w: ~p", [N, Reply]); - true -> - i("received reply ~w", [N]) - end, - ?LIB:sleep(500), % Just to spread it out a bit - send_loop(C#client{msg_id = N+1}) - end; - {error, RReason} -> - e("Failed recv response for request ~w: " - "~n ~p", [N, RReason]), - exit({failed_recv, RReason}) - end; - {error, SReason} -> - e("Failed send request ~w: " - "~n ~p", [N, SReason]), - exit({failed_send, SReason}) - end; -send_loop(Client) -> - sock_close(Client). - -sock_close(#client{socket = Sock, verbose = true}) -> - i("we are done - close the socket when: " - "~n ~p", [socket:info()]), - ok = socket:close(Sock), - i("we are done - socket closed when: " - "~n ~p", [socket:info()]); -sock_close(#client{socket = Sock}) -> - i("we are done"), - ok = socket:close(Sock). - - - -send(#client{socket = Sock, type = stream}, Msg) -> - socket:send(Sock, Msg); -send(#client{socket = Sock, type = dgram, dest = Dest}, Msg) -> - %% i("try send to: " - %% "~n ~p", [Dest]), - %% ok = socket:setopt(Sock, otp, debug, true), - TOS = tos_next(), - ok = socket:setopt(Sock, ip, tos, TOS), - case socket:sendto(Sock, Msg, Dest) of - ok = OK -> - OK; - {error, _} = ERROR -> - ERROR - end. - -recv(#client{socket = Sock, type = stream, msg = false}) -> - case socket:recv(Sock) of - {ok, Msg} -> - {ok, {undefined, Msg}}; - {error, _} = ERROR -> - ERROR - end; -recv(#client{socket = Sock, verbose = Verbose, type = stream, msg = true}) -> - case socket:recvmsg(Sock) of - %% An iov of length 1 is an simplification... - {ok, #{addr := undefined = Source, - iov := [Msg], - ctrl := CMsgHdrs, - flags := Flags}} -> - if - (Verbose =:= true) -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]); - true -> - ok - end, - {ok, {Source, Msg}}; - {error, _} = ERROR -> - ERROR - end; -recv(#client{socket = Sock, type = dgram, msg = false}) -> - socket:recvfrom(Sock); -recv(#client{socket = Sock, verbose = Verbose, type = dgram, msg = true}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Msg], - ctrl := CMsgHdrs, - flags := Flags}} -> - if - (Verbose =:= true) -> - i("received message: " - "~n CMsgHdr: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]); - true -> - ok - end, - {ok, {Source, Msg}}; - {error, _} = ERROR -> - ERROR - end. - - - -which_addr(_Domain, []) -> - throw(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -which_addr(Domain, [_|IFL]) -> - which_addr(Domain, IFL). - -which_addr2(inet = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 4) -> - Addr; -which_addr2(inet6 = _Domain, [{addr, Addr}|_IFO]) when (size(Addr) =:= 8) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - - -%% --- - -%% enc_req_msg(N, Data) -> -%% enc_msg(?REQ, N, Data). - -%% enc_rep_msg(N, Data) -> -%% enc_msg(?REP, N, Data). - -%% enc_msg(Type, N, Data) when is_list(Data) -> -%% enc_msg(Type, N, list_to_binary(Data)); -%% enc_msg(Type, N, Data) -%% when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> -%% <>. - -%% dec_msg(<>) -> -%% {request, N, Data}; -%% dec_msg(<>) -> -%% {reply, N, Data}. - - -%% --- - -%% sleep(T) -> -%% receive after T -> ok end. - - -%% --- - -%% formated_timestamp() -> -%% format_timestamp(os:timestamp()). - -%% format_timestamp(Now) -> -%% N2T = fun(N) -> calendar:now_to_local_time(N) end, -%% format_timestamp(Now, N2T, true). - -%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> -%% FormatExtra = ".~.2.0w", -%% ArgsExtra = [N3 div 10000], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); -%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> -%% FormatExtra = "", -%% ArgsExtra = [], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> -%% {Date, Time} = N2T(N), -%% {YYYY,MM,DD} = Date, -%% {Hour,Min,Sec} = Time, -%% FormatDate = -%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, -%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), -%% lists:flatten(FormatDate). - - -%% --- - -tos_init() -> - put(tos, 1). - -tos_next() -> - case get(tos) of - TOS when (TOS < 100) -> - put(tos, TOS + 1), - TOS; - _ -> - put(tos, 1), - 1 - end. - - -%% --- - -e(F, A) -> - ?LIB:e(F, A). - -i(F) -> - ?LIB:i(F). - -i(F, A) -> - ?LIB:i(F, A). - diff --git a/lib/kernel/test/socket_lib.erl b/lib/kernel/test/socket_lib.erl deleted file mode 100644 index 9d6524d467..0000000000 --- a/lib/kernel/test/socket_lib.erl +++ /dev/null @@ -1,133 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(socket_lib). - --export([ - sleep/1, - req/0, rep/0, - enc_req_msg/2, enc_rep_msg/2, - enc_msg/3, dec_msg/1, - request/3, reply/4, - f/2, - i/1, i/2, - e/2 - ]). - - --define(REQ, 0). --define(REP, 1). - - -%% --- - -sleep(T) -> - receive after T -> ok end. - - -%% --- - -req() -> ?REQ. -rep() -> ?REP. - -enc_req_msg(N, Data) -> - enc_msg(?REQ, N, Data). - -enc_rep_msg(N, Data) -> - enc_msg(?REP, N, Data). - -enc_msg(Type, N, Data) when is_list(Data) -> - enc_msg(Type, N, list_to_binary(Data)); -enc_msg(Type, N, Data) - when is_integer(Type) andalso is_integer(N) andalso is_binary(Data) -> - <>. - -dec_msg(<>) -> - {request, N, Data}; -dec_msg(<>) -> - {reply, N, Data}. - - -%% --- - -request(Tag, Pid, Request) -> - Ref = make_ref(), - Pid ! {Tag, self(), Ref, Request}, - receive - {Tag, Pid, Ref, Reply} -> - Reply - end. - -reply(Tag, Pid, Ref, Reply) -> - Pid ! {Tag, self(), Ref, Reply}. - - -%% --- - -f(F, A) -> - lists:flatten(io_lib:format(F, A)). - - -%% --- - -e(F, A) -> - p(" " ++ F, A). - -i(F) -> - i(F, []). -i(F, A) -> - p("*** " ++ F, A). - -p(F, A) -> - p(get(sname), F, A). - -p(SName, F, A) -> - io:format("[~s,~p][~s] " ++ F ++ "~n", - [SName,self(),formated_timestamp()|A]). - - -%% --- - -formated_timestamp() -> - format_timestamp(os:timestamp()). - -format_timestamp(Now) -> - N2T = fun(N) -> calendar:now_to_local_time(N) end, - format_timestamp(Now, N2T, true). - -format_timestamp({_N1, _N2, N3} = N, N2T, true) -> - FormatExtra = ".~.2.0w", - ArgsExtra = [N3 div 10000], - format_timestamp(N, N2T, FormatExtra, ArgsExtra); -format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> - FormatExtra = "", - ArgsExtra = [], - format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> - {Date, Time} = N2T(N), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, - [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), - lists:flatten(FormatDate). - - diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl deleted file mode 100644 index 45adffc5e6..0000000000 --- a/lib/kernel/test/socket_server.erl +++ /dev/null @@ -1,954 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2018. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(socket_server). - --export([ - start/0, start/5, - start_tcp/0, start_tcp/1, start_tcp/3, - start_tcp4/0, start_tcp4/1, start_tcp4/2, - start_tcp6/0, start_tcp6/1, start_tcp6/2, - start_udp/0, start_udp/1, start_udp/3, - start_udp4/0, start_udp4/1, start_udp4/2, - start_udp6/0, start_udp6/1, start_udp6/2, - start_sctp/0, start_sctp/1 - ]). - --define(LIB, socket_lib). - --record(manager, {socket, msg, peek, acceptors, handler_id, handlers}). --record(acceptor, {id, socket, manager, - atimeout = 5000}). --record(handler, {socket, peek, msg, type, manager, - stimeout = 5000, rtimeout = 5000}). - --define(NUM_ACCEPTORS, 5). - -start() -> - start_tcp(). - -start_tcp() -> - start_tcp4(). - -start_tcp(Peek) -> - start_tcp4(Peek). - -start_tcp4() -> - start_tcp4(false). - -start_tcp4(Peek) -> - start_tcp4(false, Peek). - -start_tcp4(UseMsg, Peek) -> - start_tcp(inet, UseMsg, Peek). - -start_tcp6() -> - start_tcp6(false). - -start_tcp6(Peek) -> - start_tcp6(false, Peek). - -start_tcp6(UseMsg, Peek) -> - start_tcp(inet6, UseMsg, Peek). - -start_tcp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> - start(Domain, stream, tcp, UseMsg, Peek). - -start_udp() -> - start_udp4(). - -start_udp(Peek) -> - start_udp4(Peek). - -start_udp4() -> - start_udp4(false). - -start_udp4(Peek) -> - start_udp4(false, Peek). - -start_udp4(UseMsg, Peek) -> - start_udp(inet, UseMsg, Peek). - -start_udp6() -> - start_udp6(false, false). - -start_udp6(Peek) -> - start_udp6(false, Peek). - -start_udp6(UseMsg, Peek) -> - start_udp(inet6, UseMsg, Peek). - -start_udp(Domain, UseMsg, Peek) when is_boolean(UseMsg) andalso is_boolean(Peek) -> - start(Domain, dgram, udp, UseMsg, Peek). - - -start_sctp() -> - start_sctp(inet). - -start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) -> - start(Domain, seqpacket, sctp, true, false). - -start(Domain, Type, Proto, UseMsg, Peek) -> - put(sname, "starter"), - i("try start manager"), - {Pid, MRef} = manager_start(Domain, Type, Proto, UseMsg, Peek), - i("manager (~p) started", [Pid]), - loop(Pid, MRef). - -loop(Pid, MRef) -> - receive - {'DOWN', MRef, process, Pid, Reason} -> - i("manager process exited: " - "~n ~p", [Reason]), - ok - end. - - -%% ========================================================================= - -manager_start(Domain, Type, Proto, UseMsg, Peek) -> - spawn_monitor(fun() -> manager_init(Domain, Type, Proto, UseMsg, Peek) end). - -manager_start_handler(Pid, Sock) -> - manager_request(Pid, {start_handler, Sock}). - -manager_stop(Pid, Reason) -> - manager_request(Pid, {stop, Reason}). - -manager_request(Pid, Request) -> - ?LIB:request(manager, Pid, Request). - -manager_reply(Pid, Ref, Reply) -> - ?LIB:reply(manager, Pid, Ref, Reply). - - -manager_init(Domain, Type, Proto, UseMsg, Peek) -> - put(sname, "manager"), - do_manager_init(Domain, Type, Proto, UseMsg, Peek). - -do_manager_init(Domain, stream = Type, Proto, UseMsg, Peek) -> - i("try start acceptor(s)"), - {Sock, Acceptors} = manager_stream_init(Domain, Type, Proto), - manager_loop(#manager{socket = Sock, - msg = UseMsg, - peek = Peek, - acceptors = Acceptors, - handler_id = 1, - handlers = []}); -do_manager_init(Domain, dgram = Type, Proto, UseMsg, Peek) -> - i("try open socket"), - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - F = fun(X) -> case socket:getopt(Sock, socket, X) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - i("socket opened (~s,~s,~s): " - "~n broadcast: ~s" - "~n dontroute: ~s" - "~n keepalive: ~s" - "~n reuseaddr: ~s" - "~n linger: ~s" - "~n debug: ~s" - "~n prio: ~s" - "~n rcvbuf: ~s" - "~n rcvtimeo: ~s" - "~n sndbuf: ~s" - "~n sndtimeo: ~s" - "~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(rcvtimeo), F(sndbuf), F(sndtimeo)]), - 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; - {error, BReason} -> - throw({bind, BReason}) - end, - i("bound to: " - "~n ~s" - "~n => try start handler", - [case socket:sockname(Sock) of - {ok, Name} -> f("~p", [Name]); - {error, R} -> f("error: ~p", [R]) - end]), - case handler_start(1, Sock, UseMsg, Peek) of - {ok, {Pid, MRef}} -> - i("handler (~p) started", [Pid]), - handler_continue(Pid), - manager_loop(#manager{peek = Peek, - msg = UseMsg, - handler_id = 2, % Just in case - handlers = [{1, Pid, MRef}]}); - {error, SReason} -> - e("Failed starting handler: " - "~n ~p", [SReason]), - exit({failed_start_handler, SReason}) - end; - {error, OReason} -> - e("Failed open socket: " - "~n ~p", [OReason]), - exit({failed_open_socket, OReason}) - end; -do_manager_init(Domain, seqpacket = Type, sctp = Proto, _UseMsg, _Peek) -> - %% This is as far as I have got with SCTP at the moment... - case socket:open(Domain, Type, Proto) of - {ok, Sock} -> - i("(sctp) socket opened: " - "~n ~p", [Sock]), - EXP = fun(_Desc, Expect, Expect) -> - Expect; - (Desc, Expect, Actual) -> - e("Unexpected result ~w: " - "~n Expect: ~p" - "~n Actual: ~p", [Desc, Expect, Actual]), - exit({Desc, Expect, Actual}) - end, - GO = fun(O) -> case socket:getopt(Sock, sctp, O) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - %% ok = socket:setopt(Sock, otp, debug, true), - - i("Miscellaneous options: " - "~n associnfo: ~s" - "~n autoclose: ~s" - "~n disable-fragments: ~s" - "~n initmsg: ~s" - "~n maxseg: ~s" - "~n nodelay: ~s" - "~n rtoinfo: ~s", - [GO(associnfo), - GO(autoclose), - GO(disable_fragments), - GO(initmsg), - GO(maxseg), - GO(nodelay), - GO(rtoinfo)]), - - Events = #{data_in => true, - association => true, - address => true, - send_failure => true, - peer_error => true, - shutdown => true, - partial_delivery => true, - adaptation_layer => true, - authentication => true, - sender_dry => true}, - EXP(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)), - EXP(close_socket, ok, socket:close(Sock)); - {error, Reason} -> - exit({failed_open, Reason}) - end; -do_manager_init(Domain, raw = Type, Proto, UseMsg, Peek) when is_integer(Proto) -> - do_manager_init(Domain, Type, {raw, Proto}, UseMsg, Peek); -do_manager_init(Domain, raw = Type, Proto, _UseMsg, _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. - - - -manager_stream_init(Domain, Type, Proto) -> - i("try (socket) open"), - Sock = case socket:open(Domain, Type, Proto) of - {ok, S} -> - S; - {error, OReason} -> - throw({open, OReason}) - end, - F = fun(X) -> case socket:getopt(Sock, socket, X) of - {ok, V} -> f("~p", [V]); - {error, R} -> f("error: ~p", [R]) - end - end, - i("(socket) open (~s,~s,~s): " - "~n debug: ~s" - "~n prio: ~s" - "~n => try find (local) address", - [F(domain), F(type), F(protocol), F(debug), F(priority)]), - Addr = which_addr(Domain), - SA = #{family => Domain, - addr => 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 - {ok, P} -> - %% ok = socket:setopt(Sock, socket, debug, 0), %% must have rights!! - %% ok = socket:setopt(Sock, otp, debug, false), - P; - {error, BReason} -> - throw({bind, BReason}) - end, - i("bound to: " - "~n ~p" - "~n => try (socket) listen (acceptconn: ~s)", - [Port, F(acceptconn)]), - case socket:listen(Sock) of - ok -> - i("listening (acceptconn: ~s)", - [F(acceptconn)]), - manager_stream_init(Sock, 1, ?NUM_ACCEPTORS, []); - {error, LReason} -> - throw({listen, LReason}) - end. - -which_addr(Domain) -> - Iflist = case inet:getifaddrs() of - {ok, IFL} -> - IFL; - {error, Reason} -> - throw({inet,getifaddrs,Reason}) - end, - which_addr(Domain, Iflist). - -which_addr(_Domain, []) -> - throw(no_address); -which_addr(Domain, [{Name, IFO}|_IFL]) when (Name =/= "lo") -> - which_addr2(Domain, IFO); -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) -> - Addr; -which_addr2(Domain, [_|IFO]) -> - which_addr2(Domain, IFO). - - -manager_stream_init(Sock, ID, NumAcceptors, Acc) - when (NumAcceptors > 0) -> - i("try start acceptor"), - case acceptor_start(Sock, ID) of - {ok, {Pid, MRef}} -> - i("acceptor ~w (~p) started", [ID, Pid]), - ?LIB:sleep(2000), - manager_stream_init(Sock, ID+1, NumAcceptors-1, - [{ID, Pid, MRef}|Acc]); - {error, Reason} -> - exit({failed_starting_acceptor, Reason}) - end; -manager_stream_init(Sock, _ID, 0, Acc) -> - %% Req = {kill_acceptor, length(Acc)}, % Last in the queue - %% Req = {kill_acceptor, 3}, % In the "middle" of the queue - %% Req = {kill_acceptor, 2}, % The first in the queue - %% Req = {kill_acceptor, 1}, % Current acceptor - %% Msg = {manager, self(), make_ref(), Req}, - %% erlang:send_after(timer:seconds(10), self(), Msg), - {Sock, lists:reverse(Acc)}. - - -manager_loop(M) -> - receive - {'DOWN', MRef, process, Pid, Reason} -> - M2 = manager_handle_down(M, MRef, Pid, Reason), - manager_loop(M2); - - {manager, Pid, Ref, Request} -> - M2 = manager_handle_request(M, Pid, Ref, Request), - manager_loop(M2) - end. - - -manager_handle_down(#manager{acceptors = Acceptors, - handlers = Handlers} = M, MRef, Pid, Reason) -> - case lists:keysearch(Pid, 2, Acceptors) of - {value, {ID, Pid, MRef}} when (Reason =:= normal) -> - i("acceptor ~w exited (normally)", [ID]), - case lists:keydelete(Pid, 2, Acceptors) of - [] -> - %% We are done - i("the last acceptor - we are done"), - exit(normal); - Acceptors2 -> - M#manager{acceptors = Acceptors2} - end; - {value, {ID, Pid, MRef}} -> - e("acceptor ~w crashed: " - "~n ~p", [ID, Reason]), - exit({acceptor_died, Reason}); - - false -> %% handler! - if - (Reason =/= normal) -> - e("handler ~p died: " - "~n ~p", [Pid, Reason]); - true -> - i("handler ~p terminated", [Pid]) - end, - Handlers2 = lists:keydelete(Pid, 2, Handlers), - M#manager{handlers = Handlers2} - end. - - -manager_handle_request(#manager{peek = Peek, - msg = UseMsg, - handler_id = HID, - handlers = Handlers} = M, Pid, Ref, - {start_handler, Sock}) -> - i("try start handler (~w)", [HID]), - case handler_start(HID, Sock, UseMsg, Peek) of - {ok, {HPid, HMRef}} -> - i("handler ~w started", [HID]), - manager_reply(Pid, Ref, {ok, HPid}), - M#manager{handler_id = HID+1, - handlers = [{HID, HPid, HMRef}|Handlers]}; - {error, Reason} = ERROR -> - e("Failed starting new handler: " - "~n Sock: ~p" - "~n Reason: ~p", [Sock, Reason]), - manager_reply(Pid, Ref, ERROR), - M - end; -manager_handle_request(#manager{socket = Sock, - acceptors = [{AID, APid, AMRef}]} = M, _Pid, _Ref, - {kill_acceptor, AID}) -> - i("try kill (only remeining) acceptor ~w", [AID]), - socket:setopt(Sock, otp, debug, true), - manager_stop_acceptor(APid, AMRef, AID, kill), - M#manager{acceptors = []}; -manager_handle_request(#manager{socket = Sock, - acceptors = Acceptors} = M, _Pid, _Ref, - {kill_acceptor, AID}) -> - i("try kill acceptor ~w", [AID]), - case lists:keysearch(AID, 1, Acceptors) of - {value, {AID, APid, AMRef}} -> - socket:setopt(Sock, otp, debug, true), - manager_stop_acceptor(APid, AMRef, AID, kill), - Acceptors2 = lists:keydelete(AID, 1, Acceptors), - M#manager{acceptors = Acceptors2}; - false -> - e("no such acceptor"), - M - end; -manager_handle_request(#manager{acceptors = Acceptors, - handlers = Handlers}, Pid, Ref, - {stop, Reason}) -> - i("stop"), - manager_reply(Pid, Ref, ok), - manager_stop_handlers(Handlers, Reason), - manager_stop_acceptors(Acceptors, Reason), - i("stopped", []), - exit(Reason). - -manager_stop_acceptors(Acceptors, Reason) -> - lists:foreach(fun({ID,P,M}) -> - manager_stop_acceptor(P, M, ID, Reason) - end, Acceptors). - -manager_stop_acceptor(Pid, MRef, ID, Reason) -> - i("try stop acceptor ~w (~p): ~p", [ID, Pid, Reason]), - erlang:demonitor(MRef, [flush]), - acceptor_stop(Pid, Reason), - ok. - -manager_stop_handlers(Handlers, Reason) -> - lists:foreach(fun({ID,P,M}) -> - manager_stop_handler(P, M, ID, Reason) - end, Handlers). - -manager_stop_handler(Pid, MRef, ID, Reason) -> - i("try stop handler ~w (~p): ~p", [ID, Pid, Reason]), - erlang:demonitor(MRef, [flush]), - handler_stop(Pid, Reason), - ok. - - - -%% ========================================================================= - -acceptor_start(Sock, ID) -> - Self = self(), - A = {Pid, _} = spawn_monitor(fun() -> - acceptor_init(Self, Sock, ID) - end), - receive - {acceptor, Pid, ok} -> - {ok, A}; - {acceptor, Pid, {error, _} = Error} -> - exit(Pid, kill), % Just in case - Error; - {'DOWN', _MRef, process, Pid, Reason} -> - {error, {crashed, Reason}} - end. - -acceptor_stop(Pid, _Reason) -> - %% acceptor_request(Pid, {stop, Reason}). - exit(Pid, kill). - -%% acceptor_request(Pid, Request) -> -%% request(acceptor, Pid, Request). - -%% acceptor_reply(Pid, Ref, Reply) -> -%% reply(acceptor, Pid, Ref, Reply). - - -acceptor_init(Manager, Sock, ID) -> - put(sname, f("acceptor[~w]", [ID])), - Manager ! {acceptor, self(), ok}, - %% ok = socket:setopt(Sock, otp, debug, true), - acceptor_loop(#acceptor{id = ID, - manager = Manager, - socket = Sock}). - -acceptor_loop(#acceptor{socket = LSock, atimeout = Timeout} = A) -> - i("try accept"), - case socket:accept(LSock, Timeout) of - {ok, Sock} -> - i("accepted: " - "~n ~p" - "~nwhen" - "~n ~p", [Sock, socket:info()]), - case acceptor_handle_accept_success(A, Sock) of - ok -> - acceptor_loop(A); - {error, Reason} -> - e("Failed starting handler: " - "~n ~p", [Reason]), - socket:close(Sock), - exit({failed_starting_handler, Reason}) - end; - {error, timeout} -> - i("timeout"), - acceptor_loop(A); - {error, Reason} -> - e("accept failure: " - "~n ~p", [Reason]), - exit({accept, Reason}) - end. - -acceptor_handle_accept_success(#acceptor{manager = Manager}, Sock) -> - i("try start handler for peer" - "~n ~p", [case socket:peername(Sock) of - {ok, Peer} -> Peer; - {error, _} = E -> E - end]), - case manager_start_handler(Manager, Sock) of - {ok, Pid} -> - i("handler (~p) started - now change 'ownership'", [Pid]), - case socket:setopt(Sock, otp, controlling_process, Pid) of - ok -> - %% Normally we should have a msgs collection here - %% (of messages we receive before the control was - %% handled over to Handler), but since we don't - %% have active implemented yet... - i("new handler (~p) now controlling process", [Pid]), - handler_continue(Pid), - ok; - {error, _} = ERROR -> - exit(Pid, kill), - ERROR - end; - {error, Reason2} -> - e("failed starting handler: " - "~n (new) Socket: ~p" - "~n Reason: ~p", [Sock, Reason2]), - exit({failed_starting_handler, Reason2}) - end. - - - -%% ========================================================================= - -handler_start(ID, Sock, UseMsg, Peek) -> - Self = self(), - H = {Pid, _} = spawn_monitor(fun() -> - handler_init(Self, ID, UseMsg, Peek, Sock) - end), - receive - {handler, Pid, ok} -> - {ok, H}; - {handler, Pid, {error, _} = ERROR} -> - exit(Pid, kill), % Just in case - ERROR - end. - -handler_stop(Pid, _Reason) -> - %% handler_request(Pid, {stop, Reason}). - exit(Pid, kill). - -handler_continue(Pid) -> - handler_request(Pid, continue). - -handler_request(Pid, Request) -> - ?LIB:request(handler, Pid, Request). - -handler_reply(Pid, Ref, Reply) -> - ?LIB:reply(handler, Pid, Ref, Reply). - - -handler_init(Manager, ID, Msg, Peek, Sock) -> - put(sname, f("handler:~w", [ID])), - i("starting"), - Manager ! {handler, self(), ok}, - receive - {handler, Pid, Ref, continue} -> - i("got continue"), - handler_reply(Pid, Ref, ok), - G = fun(L, O) -> case socket:getopt(Sock, L, O) of - {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, - GSO = fun(O) -> G(socket, O) end, - GIP4 = fun(O) -> G(ip, O) end, - GIP6 = fun(O) -> G(ipv6, O) end, - {ok, Domain} = socket:getopt(Sock, socket, domain), - {ok, Type} = socket:getopt(Sock, socket, type), - {ok, Proto} = socket:getopt(Sock, socket, protocol), - B2D = GSO(bindtodevice), - RA = GSO(reuseaddr), - RP = GSO(reuseport), - OOBI = GSO(oobinline), - RcvBuf = GSO(rcvbuf), - RcvLW = GSO(rcvlowat), - RcvTO = GSO(rcvtimeo), - SndBuf = GSO(sndbuf), - SndLW = GSO(sndlowat), - SndTO = GSO(sndtimeo), - Linger = GSO(linger), - Timestamp = GSO(timestamp), - FreeBind = GIP4(freebind), - MTU = GIP4(mtu), - MTUDisc = GIP4(mtu_discover), - MALL = GIP4(multicast_all), - MIF4 = GIP4(multicast_if), - MLoop4 = GIP4(multicast_loop), - MTTL = GIP4(multicast_ttl), - NF = GIP4(nodefrag), % raw only - PktInfo = GIP4(pktinfo), % dgram only - RecvErr4 = GIP4(recverr), - RecvIF = GIP4(recvif), % Only dgram and raw (and FreeBSD) - RecvOPTS = GIP4(recvopts), % Not stream - RecvOrigDstAddr = GIP4(recvorigdstaddr), - RecvTOS = GIP4(recvtos), - RecvTTL = GIP4(recvttl), % not stream - RetOpts = GIP4(retopts), % not stream - SendSrcAddr = GIP4(sendsrcaddr), - TOS = GIP4(tos), - Transparent = GIP4(transparent), - TTL = GIP4(ttl), - MHops = GIP6(multicast_hops), - MIF6 = GIP6(multicast_if), % Only dgram and raw - MLoop6 = GIP6(multicast_loop), - RecvErr6 = GIP6(recverr), - RecvPktInfo = GIP6(recvpktinfo), - RtHdr = GIP6(rthdr), - AuthHdr = GIP6(authhdr), - HopLimit = GIP6(hoplimit), - HopOpts = GIP6(hopopts), - DstOpts = GIP6(dstopts), - FlowInfo = GIP6(flowinfo), - UHops = GIP6(unicast_hops), - i("got continue when: " - "~n (socket) Domain: ~p" - "~n (socket) Type: ~p" - "~n (socket) Protocol: ~p" - "~n (socket) Reuse Address: ~s" - "~n (socket) Reuse Port: ~s" - "~n (socket) Bind To Device: ~s" - "~n (socket) OOBInline: ~s" - "~n (socket) RcvBuf: ~s" - "~n (socket) RcvLW: ~s" - "~n (socket) RcvTO: ~s" - "~n (socket) SndBuf: ~s" - "~n (socket) SndLW: ~s" - "~n (socket) SndTO: ~s" - "~n (socket) Linger: ~s" - "~n (socket) Timestamp: ~s" - "~n (ip) FreeBind: ~s" - "~n (ip) MTU: ~s" - "~n (ip) MTU Discovery: ~s" - "~n (ip) Multicast ALL: ~s" - "~n (ip) Multicast IF: ~s" - "~n (ip) Multicast Loop: ~s" - "~n (ip) Multicast TTL: ~s" - "~n (ip) Node Frag: ~s" - "~n (ip) Pkt Info: ~s" - "~n (ip) Recv Err: ~s" - "~n (ip) Recv IF: ~s" - "~n (ip) Recv OPTS: ~s" - "~n (ip) Recv Orig Dst Addr: ~s" - "~n (ip) Recv TOS: ~s" - "~n (ip) Recv TTL: ~s" - "~n (ip) Ret Opts: ~s" - "~n (ip) Send Src Addr: ~s" - "~n (ip) TOS: ~s" - "~n (ip) Transparent: ~s" - "~n (ip) TTL: ~s" - "~n (ipv6) Multicast Hops: ~s" - "~n (ipv6) Multicast IF: ~s" - "~n (ipv6) Multicast Loop: ~s" - "~n (ipv6) Recv Err: ~s" - "~n (ipv6) Recv Pkt Info: ~s" - "~n (ipv6) RT Hdr: ~s" - "~n (ipv6) Auth Hdr: ~s" - "~n (ipv6) Hop Limit: ~s" - "~n (ipv6) Hop Opts: ~s" - "~n (ipv6) Dst Opts: ~s" - "~n (ipv6) Flow Info: ~s" - "~n (ipv6) Unicast Hops: ~s", - [Domain, Type, Proto, - RA, RP, B2D, OOBI, - RcvBuf, RcvLW, RcvTO, SndBuf, SndLW, SndTO, - Linger, Timestamp, - FreeBind, MTU, MTUDisc, MALL, MIF4, MLoop4, MTTL, - NF, PktInfo,RecvErr4, - RecvIF, RecvOPTS, RecvOrigDstAddr, RecvTOS, RecvTTL, RetOpts, - SendSrcAddr, TOS, Transparent, TTL, - MHops, MIF6, MLoop6, RecvErr6, RecvPktInfo, - RtHdr, AuthHdr, HopLimit, HopOpts, DstOpts, FlowInfo, - UHops]), - - %% ok = socket:setopt(Sock, otp, debug, true), - %% case socket:getopt(Sock, 0, {13, int}) of - %% {ok, Val} -> - %% i("PktOpts ok: ~p", [Val]); - %% {error, Reason} -> - %% e("PktOpts err: ~p", [Reason]) - %% end, - %% ok = socket:setopt(Sock, otp, debug, false), - SSO = fun(O, V) -> soso(Sock, O, V) end, - SIP4 = - fun(O, V) -> - if - (Type =:= dgram) -> - ok = soip(Sock, O, V); - true -> - ok - end - end, - SSO(timestamp, true), - SIP4(pktinfo, true), - ok = soip(Sock, recvtos, true), - SIP4(recvttl, true), - ok = soip(Sock, recvorigdstaddr, true), - - handler_loop(#handler{msg = Msg, - peek = Peek, - manager = Manager, - type = Type, - socket = Sock}) - end. - -so(Sock, Lvl, Opt, Val) -> - ok = socket:setopt(Sock, Lvl, Opt, Val). - -soso(Sock, Opt, Val) -> - so(Sock, socket, Opt, Val). - -soip(Sock, Opt, Val) -> - so(Sock, ip, Opt, Val). - -%% soipv6(Sock, Opt, Val) -> -%% so(Sock, ipv6, Opt, Val). - -handler_loop(H) -> - i("try read message"), - case recv(H) of - {ok, {Source, Msg}} -> - i("received ~w bytes of data~s", - [size(Msg), case Source of - undefined -> ""; - _ -> f(" from:~n ~p", [Source]) - end]), - case ?LIB:dec_msg(Msg) of - {request, N, Req} -> - i("received request ~w: " - "~n ~p", [N, Req]), - Reply = ?LIB:enc_rep_msg(N, "hoppsan"), - case send(H, Reply, Source) of - ok -> - i("successfully sent reply ~w", [N]), - handler_loop(H); - {error, SReason} -> - e("failed sending reply ~w:" - "~n ~p", [N, SReason]), - exit({failed_sending_reply, SReason}) - end - end; - - {error, closed} -> - i("closed when" - "~n ~p", [socket:info()]), - exit(normal); - - {error, RReason} -> - e("failed reading request: " - "~n ~p", [RReason]), - exit({failed_reading_request, RReason}) - end. - - -recv(#handler{peek = true, socket = Sock, type = stream}) -> - peek_recv(Sock); -recv(#handler{socket = Sock, msg = true, type = stream}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := undefined = Source, - iov := [Data], - ctrl := CMsgHdrs, - flags := Flags}} -> - i("received message: " - "~n CMsgHdrs: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), - {ok, {Source, Data}}; - {ok, X} -> - e("received *unexpected* message: " - "~n ~p", [X]), - {error, {unexpected, X}}; - {error, _} = ERROR -> - ERROR - end; -recv(#handler{socket = Sock, msg = true, type = dgram}) -> - case socket:recvmsg(Sock) of - {ok, #{addr := Source, - iov := [Data], - ctrl := CMsgHdrs, - flags := Flags}} -> - i("received message: " - "~n CMsgHdrs: ~p" - "~n Flags: ~p", [CMsgHdrs, Flags]), - {ok, {Source, Data}}; - {ok, X} -> - {error, {unexpected, X}}; - {error, _} = ERROR -> - ERROR - end; -recv(#handler{peek = false, socket = Sock, type = stream}) -> - do_recv(Sock); -recv(#handler{peek = Peek, socket = Sock, type = dgram}) - when (Peek =:= true) -> - %% ok = socket:setopt(Sock, otp, debug, true), - RES = peek_recvfrom(Sock, 5), - %% ok = socket:setopt(Sock, otp, debug, false), - RES; -recv(#handler{peek = Peek, socket = Sock, type = dgram}) - when (Peek =:= false) -> - %% ok = socket:setopt(Sock, otp, debug, true), - socket:recvfrom(Sock). - -do_recv(Sock) -> - case socket:recv(Sock) of - {ok, Msg} -> - {ok, {undefined, Msg}}; - {error, _} = ERROR -> - ERROR - end. - -peek_recv(Sock) -> - i("try peek on the message type (expect request)"), - Type = ?LIB:req(), - case socket:recv(Sock, 4, [peek]) of - {ok, <>} -> - i("was request - do proper recv"), - do_recv(Sock); - {error, _} = ERROR -> - ERROR - end. - -peek_recvfrom(Sock, BufSz) -> - i("try peek recvfrom with buffer size ~w", [BufSz]), - case socket:recvfrom(Sock, BufSz, [peek]) of - {ok, {_Source, Msg}} when (BufSz =:= size(Msg)) -> - %% i("we filled the buffer: " - %% "~n ~p", [Msg]), - %% It *may not* fit => try again with double size - peek_recvfrom(Sock, BufSz*2); - {ok, _} -> - %% It fits => read for real - i("we did *not* fill the buffer - do the 'real' read"), - socket:recvfrom(Sock); - {error, _} = ERROR -> - ERROR - end. - - -send(#handler{socket = Sock, msg = true, type = stream, stimeout = Timeout}, - Msg, _) -> - CMsgHdr = #{level => ip, type => tos, data => reliability}, - CMsgHdrs = [CMsgHdr], - MsgHdr = #{iov => [Msg], ctrl => CMsgHdrs}, - %% socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr, Timeout), - %% socket:setopt(Sock, otp, debug, false), - Res; -send(#handler{socket = Sock, type = stream, stimeout = Timeout}, Msg, _) -> - socket:send(Sock, Msg, Timeout); -send(#handler{socket = Sock, msg = true, type = dgram, stimeout = Timeout}, - Msg, Dest) -> - CMsgHdr = #{level => ip, type => tos, data => reliability}, - CMsgHdrs = [CMsgHdr], - MsgHdr = #{addr => Dest, - ctrl => CMsgHdrs, - iov => [Msg]}, - %% ok = socket:setopt(Sock, otp, debug, true), - Res = socket:sendmsg(Sock, MsgHdr, Timeout), - %% ok = socket:setopt(Sock, otp, debug, false), - Res; -send(#handler{socket = Sock, type = dgram, stimeout = Timeout}, Msg, Dest) -> - socket:sendto(Sock, Msg, Dest, Timeout). - -%% filler() -> -%% list_to_binary(lists:duplicate(2048, " FILLER ")). - - - -%% ========================================================================= - -f(F, A) -> - ?LIB:f(F, A). - -e(F) -> - e(F, []). -e(F, A) -> - ?LIB:e(F, A). - -i(F) -> - ?LIB:i(F). - -i(F, A) -> - ?LIB:i(F, A). - -- cgit v1.2.3