aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-10-19 12:13:26 +0200
committerMicael Karlberg <[email protected]>2018-10-19 12:13:26 +0200
commitb4d61414565e6c6aa34249bf5d6eb3d5e5952b76 (patch)
tree4d9f86f9282b465a1a693cf9afbdb4ec5fd167e7 /lib/kernel/test
parent890b7523ad3119415fecc6fbaaa5b07b9c973b35 (diff)
downloadotp-b4d61414565e6c6aa34249bf5d6eb3d5e5952b76.tar.gz
otp-b4d61414565e6c6aa34249bf5d6eb3d5e5952b76.tar.bz2
otp-b4d61414565e6c6aa34249bf5d6eb3d5e5952b76.zip
[socket-nif|test] Moved socket tests from kernel to erts/emulator
OTP-14831
Diffstat (limited to 'lib/kernel/test')
-rw-r--r--lib/kernel/test/Makefile12
-rw-r--r--lib/kernel/test/socket_SUITE.erl4186
-rw-r--r--lib/kernel/test/socket_client.erl538
-rw-r--r--lib/kernel/test/socket_lib.erl133
-rw-r--r--lib/kernel/test/socket_server.erl954
5 files changed, 1 insertions, 5822 deletions
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.
-%%
-%% <KOLLA>
-%%
-%% 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.
-%%
-%% </KOLLA>
-
-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("<ERROR> ", 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) ->
-%% <<Type:32/integer, N:32/integer, Data/binary>>.
-
-%% dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) ->
-%% {request, N, Data};
-%% dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) ->
-%% {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) ->
- <<Type:32/integer, N:32/integer, Data/binary>>.
-
-dec_msg(<<?REQ:32/integer, N:32/integer, Data/binary>>) ->
- {request, N, Data};
-dec_msg(<<?REP:32/integer, N:32/integer, Data/binary>>) ->
- {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("<ERROR> " ++ 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, <<Type:32>>} ->
- 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).
-