diff options
-rw-r--r-- | erts/emulator/nifs/common/socket_int.h | 11 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_nif.c | 14 | ||||
-rw-r--r-- | lib/kernel/test/socket_SUITE.erl | 150 |
3 files changed, 168 insertions, 7 deletions
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h index c3595e495d..f9246856fa 100644 --- a/erts/emulator/nifs/common/socket_int.h +++ b/erts/emulator/nifs/common/socket_int.h @@ -103,8 +103,10 @@ typedef unsigned int BOOLEAN_T; /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * "Global" atoms */ +extern ERL_NIF_TERM esock_atom_accept; extern ERL_NIF_TERM esock_atom_addr; extern ERL_NIF_TERM esock_atom_any; +extern ERL_NIF_TERM esock_atom_connect; extern ERL_NIF_TERM esock_atom_credentials; extern ERL_NIF_TERM esock_atom_ctrl; extern ERL_NIF_TERM esock_atom_ctrunc; @@ -129,6 +131,8 @@ extern ERL_NIF_TERM esock_atom_local; extern ERL_NIF_TERM esock_atom_loopback; extern ERL_NIF_TERM esock_atom_lowdelay; extern ERL_NIF_TERM esock_atom_mincost; +extern ERL_NIF_TERM esock_atom_not_found; +extern ERL_NIF_TERM esock_atom_not_owner; extern ERL_NIF_TERM esock_atom_ok; extern ERL_NIF_TERM esock_atom_oob; extern ERL_NIF_TERM esock_atom_origdstaddr; @@ -138,11 +142,18 @@ extern ERL_NIF_TERM esock_atom_port; extern ERL_NIF_TERM esock_atom_protocol; extern ERL_NIF_TERM esock_atom_raw; extern ERL_NIF_TERM esock_atom_rdm; +extern ERL_NIF_TERM esock_atom_recv; +extern ERL_NIF_TERM esock_atom_recvfrom; +extern ERL_NIF_TERM esock_atom_recvmsg; extern ERL_NIF_TERM esock_atom_reliability; extern ERL_NIF_TERM esock_atom_rights; extern ERL_NIF_TERM esock_atom_scope_id; extern ERL_NIF_TERM esock_atom_sctp; extern ERL_NIF_TERM esock_atom_sec; +extern ERL_NIF_TERM esock_atom_select_sent; +extern ERL_NIF_TERM esock_atom_send; +extern ERL_NIF_TERM esock_atom_sendmsg; +extern ERL_NIF_TERM esock_atom_sendto; extern ERL_NIF_TERM esock_atom_seqpacket; extern ERL_NIF_TERM esock_atom_socket; extern ERL_NIF_TERM esock_atom_spec_dst; diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index 4fd10e1ae6..0ef88162bc 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -2400,6 +2400,7 @@ ERL_NIF_TERM esock_atom_loopback; ERL_NIF_TERM esock_atom_lowdelay; ERL_NIF_TERM esock_atom_mincost; ERL_NIF_TERM esock_atom_not_found; +ERL_NIF_TERM esock_atom_not_owner; ERL_NIF_TERM esock_atom_ok; ERL_NIF_TERM esock_atom_oob; ERL_NIF_TERM esock_atom_origdstaddr; @@ -5101,7 +5102,7 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env, SocketDescriptor* descP, ERL_NIF_TERM eVal) { - ErlNifPid newCtrlPid; + ErlNifPid caller, newCtrlPid; ErlNifMonitor newCtrlMon; int xres; @@ -5110,6 +5111,16 @@ ERL_NIF_TERM nsetopt_otp_ctrl_proc(ErlNifEnv* env, "\r\n eVal: %T" "\r\n", eVal) ); + /* Before we begin, ensure that caller is (current) controlling-process */ + if (enif_self(env, &caller) == NULL) + return esock_make_error(env, atom_exself); + + if (!compare_pids(env, &descP->ctrlPid, &caller)) { + SSDBG( descP, ("SOCKET", "nsetopt_otp_ctrl_proc -> not owner (%T)\r\n", + descP->ctrlPid) ); + return esock_make_error(env, esock_atom_not_owner); + } + if (!GET_LPID(env, eVal, &newCtrlPid)) { esock_warning_msg("Failed get pid of new controlling process\r\n"); return esock_make_error(env, esock_atom_einval); @@ -15582,6 +15593,7 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) esock_atom_lowdelay = MKA(env, "lowdelay"); esock_atom_mincost = MKA(env, "mincost"); esock_atom_not_found = MKA(env, "not_found"); + esock_atom_not_owner = MKA(env, "not_owner"); esock_atom_ok = MKA(env, "ok"); esock_atom_oob = MKA(env, "oob"); esock_atom_origdstaddr = MKA(env, "origdstaddr"); diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl index f3a7d84e81..1fff17cf8c 100644 --- a/lib/kernel/test/socket_SUITE.erl +++ b/lib/kernel/test/socket_SUITE.erl @@ -40,6 +40,7 @@ %% API Options api_opt_simple_otp_options/1, + api_opt_simple_otp_controlling_process/1, %% API Operation Timeout api_to_connect_tcp4/1, @@ -117,7 +118,8 @@ api_basic_cases() -> api_options_cases() -> [ - api_opt_simple_otp_options + api_opt_simple_otp_options, + api_opt_simple_otp_controlling_process ]. api_op_with_timeout_cases() -> @@ -346,6 +348,7 @@ api_b_send_and_recv_tcp(Domain, Send, Recv) -> LSA = #{family => Domain, addr => LAddr}, Starter = self(), ServerFun = fun() -> + put(sname, "server"), %% Create the listen socket ServerLSock = case socket:open(Domain, stream, tcp) of @@ -462,7 +465,7 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> p("Create sockets"), S1 = sock_open(inet, stream, tcp), S2 = sock_open(inet, dgram, udp), - + Get = fun(S, Key) -> socket:getopt(S, otp, Key) end, @@ -472,6 +475,7 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> p("Create dummy process"), Pid = spawn_link(fun() -> + put(sname, "dummy"), receive die -> exit(normal) @@ -537,6 +541,135 @@ api_opt_simple_otp_options(_Config) when is_list(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Perform some simple getopt and setopt with the level = otp options +api_opt_simple_otp_controlling_process(suite) -> + []; +api_opt_simple_otp_controlling_process(doc) -> + []; +api_opt_simple_otp_controlling_process(_Config) when is_list(_Config) -> + tc_begin(api_opt_simple_otp_controlling_process), + + p("Create sockets"), + S1 = sock_open(inet, stream, tcp), + S2 = sock_open(inet, dgram, udp), + + Get = fun(S, Key) -> + socket:getopt(S, otp, Key) + end, + Set = fun(S, Key, Val) -> + socket:setopt(S, otp, Key, Val) + end, + + AwaitStart = + fun() -> + p("await start command"), + receive + {start, P, S} -> + {P, S} + end + end, + AwaitContinue = + fun(Pid) -> + p("await continue command"), + receive + {continue, Pid} -> + ok + end + end, + AwaitReady = + fun(Pid) -> + p("await ready confirmation from ~p", [Pid]), + receive + {ready, Pid} -> + ok + end + end, + AwaitDie = + fun(Pid) -> + p("await die command"), + receive + {die, Pid} -> + ok + end + end, + ClientStarter = + fun() -> + put(sname, "client"), + Self = self(), + {Parent, Sock} = AwaitStart(), + p("verify parent ~p controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("verify parent ~p (still) controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("announce ready"), + Parent ! {ready, self()}, + + AwaitContinue(Parent), + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("transfer control to parent ~p", [Parent]), + ok = Set(Sock, controlling_process, Parent), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("verify parent ~p controlling", [Parent]), + {ok, Parent} = Get(Sock, controlling_process), + p("announce ready"), + Parent ! {ready, self()}, + + AwaitDie(Parent), + p("done"), + exit(normal) + end, + + Tester = + fun(Sock, Client) -> + p("start"), + Self = self(), + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("announce start"), + Client ! {start, Self, Sock}, + AwaitReady(Client), + + p("transfer control to client ~p", [Client]), + ok = Set(Sock, controlling_process, Client), + p("verify client ~p controlling", [Client]), + {ok, Client} = Get(Sock, controlling_process), + p("attempt invalid control transfer (to self)"), + {error, not_owner} = Set(Sock, controlling_process, self()), + p("announce continue"), + Client ! {continue, Self}, + AwaitReady(Client), + + p("verify self controlling"), + {ok, Self} = Get(Sock, controlling_process), + p("announce die"), + Client ! {die, Self}, + p("done"), + ok + end, + + p("Create Worker Process(s)"), + Pid1 = spawn_link(ClientStarter), + Pid2 = spawn_link(ClientStarter), + + p("Test stream/tcp "), + Tester(S1, Pid1), + + p("Test dgram/udp "), + Tester(S2, Pid2), + + p("close sockets"), + sock_close(S1), + sock_close(S2), + + tc_end(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% This test case is intended to test the connect timeout option %% on an IPv4 TCP (stream) socket. api_to_connect_tcp4(suite) -> @@ -580,7 +713,7 @@ api_to_connect_tcp(Domain) -> LocalSA = #{family => Domain, addr => LocalAddr}, ServerName = f("~s:server", [get_tc_name()]), Server = spawn_link(fun() -> - set_tc_name(ServerName), + put(sname, ServerName), p("open"), LSock = sock_open(Domain, stream, tcp), p("bind"), @@ -842,7 +975,7 @@ api_to_recv_tcp(Domain) -> sock_listen(LSock), ClientName = f("~s:client", [get_tc_name()]), Client = spawn_link(fun() -> - set_tc_name(ClientName), + put(sname, ClientName), p("open"), CSock = sock_open(Domain, stream, tcp), p("bind"), @@ -1029,7 +1162,7 @@ api_to_recvmsg_tcp(Domain) -> sock_listen(LSock), ClientName = f("~s:client", [get_tc_name()]), Client = spawn_link(fun() -> - set_tc_name(ClientName), + put(sname, ClientName), p("open"), CSock = sock_open(Domain, stream, tcp), p("bind"), @@ -1231,7 +1364,12 @@ p(F, A) -> TcName = case get(tc_name) of undefined -> - ""; + case get(sname) of + undefined -> + ""; + SName when is_list(SName) -> + SName + end; Name when is_list(Name) -> Name end, |