aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/nifs/common/socket_int.h11
-rw-r--r--erts/emulator/nifs/common/socket_nif.c14
-rw-r--r--lib/kernel/test/socket_SUITE.erl150
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,