File 0239-kernel-esock-tcp-Tweaked-open-to-properly-handle-the.patch of Package erlang
From 80192660db335427f0c5db846234d0d215507500 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Fri, 6 Dec 2024 18:28:41 +0100
Subject: [PATCH 4/5] [kernel|esock|tcp] Tweaked open to properly handle the
debug option
OTP-19386
---
lib/kernel/src/gen_tcp_socket.erl | 131 ++++++++++++++++++------------
1 file changed, 79 insertions(+), 52 deletions(-)
diff --git a/lib/kernel/src/gen_tcp_socket.erl b/lib/kernel/src/gen_tcp_socket.erl
index cea9740bcb..e873be62bb 100644
--- a/lib/kernel/src/gen_tcp_socket.erl
+++ b/lib/kernel/src/gen_tcp_socket.erl
@@ -152,7 +152,8 @@ connect_lookup(Address, Port, Opts0, Timer) ->
connect_lookup(Domain, Address, Port, Mod, Opts0, Timer) ->
%% ?DBG([{domain, Domain}, {addr, Address}, {port, Port},
%% {mod, Mod}, {opts0, Opts0}, {timer, Timer}]),
- {StartOpts, Opts} = split_start_opts(Opts0),
+ {StartOpts, Opts1} = split_start_opts(Opts0),
+ {OpenOpts0, Opts2} = split_open_opts(Opts1),
ErrRef = make_ref(),
try
%% ?DBG(['try getaddrs']),
@@ -160,7 +161,7 @@ connect_lookup(Domain, Address, Port, Mod, Opts0, Timer) ->
%% ?DBG(['try getserv']),
TP = val(ErrRef, Mod:getserv(Port)),
%% ?DBG(['process connect options']),
- CO = val(ErrRef, inet:connect_options(Opts, Mod)),
+ CO = val(ErrRef, inet:connect_options(Opts2, Mod)),
%% ?DBG(['process sockaddrs']),
SAs = sockaddrs(IPs, TP, Domain),
%% ?DBG([{sas, SAs}, {co, CO}]),
@@ -174,33 +175,30 @@ connect_lookup(Domain, Address, Port, Mod, Opts0, Timer) ->
%%
%% ?DBG([{domain, Domain}, {bind_ip, BindAddr}]),
BindSockaddr = bind_addr(Domain, BindAddr, BindPort),
- ExtraOpts = extra_opts(Fd),
+ OpenOpts = open_opts(OpenOpts0, open_opts(Fd)),
connect_open(
- Addrs, Domain, ConnectOpts, StartOpts, ExtraOpts,
+ Addrs, Domain, ConnectOpts, StartOpts, OpenOpts,
Timer, BindSockaddr)
catch
throw : {ErrRef, Reason} ->
?badarg_exit({error, Reason})
end.
-connect_open(
- Addrs, Domain, ConnectOpts, StartOpts, ExtraOpts, Timer, BindAddr) ->
+connect_open(Addrs, Domain,
+ ConnectOpts, StartOpts0, OpenOpts,
+ Timer, BindAddr) ->
%%
%% The {netns, File} option is passed in Fd by inet:connect_options/2,
%% and then over to ExtraOpts.
%%
- case
- start_server(
- Domain,
- [{timeout, inet:timeout(Timer)} | StartOpts],
- ExtraOpts)
- of
+ StartOpts = [{timeout, inet:timeout(Timer)} | StartOpts0],
+ case start_server(Domain, StartOpts, OpenOpts) of
{ok, Server} ->
%% ?DBG(['server started', {server, Server}]),
ErrRef = make_ref(),
try
try_setopts(ErrRef, Server, StartOpts, ConnectOpts),
- try_bind(ErrRef, Server, Domain, BindAddr, ExtraOpts),
+ try_bind(ErrRef, Server, Domain, BindAddr, OpenOpts),
Socket = try_connect(ErrRef, Server, Addrs, Timer),
MSock = ?MODULE_socket(Server, Socket),
%% ?DBG(['done', {msock, MSock}]),
@@ -241,19 +239,27 @@ connect_loop([Addr | Addrs], Server, _Error, Timer) ->
end.
-extra_opts(Fd) when is_integer(Fd) ->
+open_opts(Fd) when is_integer(Fd) ->
if
Fd < 0 ->
#{};
true ->
#{fd => Fd}
end;
-extra_opts(OpenOpts) when is_list(OpenOpts) ->
+open_opts(OpenOpts) when is_list(OpenOpts) ->
%% This is an **ugly** hack.
%% inet:{connect,listen,udp,sctp}_options/2 has the bad taste
%% to use this for [{netns,BinNS}] if that option is used...
maps:from_list(OpenOpts).
+%% Should we verify the options or just accept them?
+open_opts([], OpenOpts)
+ when is_map(OpenOpts) ->
+ OpenOpts;
+open_opts([{Opt, Val}|Opts], OpenOpts)
+ when is_list(Opts) andalso is_map(OpenOpts) ->
+ open_opts(Opts, OpenOpts#{Opt => Val}).
+
default_any(_Domain, undefined, #{fd := _}) ->
undefined;
@@ -367,18 +373,21 @@ default_active_true(Opts) ->
%% -------------------------------------------------------------------------
-listen(Port, Opts) ->
- %% ?DBG([{port, Port}, {opts, Opts}]),
- Opts_1 = internalize_setopts(Opts),
- %% ?DBG([{opts_1, Opts_1}]),
- {Mod, Opts_2} = inet:tcp_module(Opts_1),
- %% ?DBG([{mod, Mod}, {opts_2, Opts_2}]),
- {StartOpts, Opts_3} = split_start_opts(Opts_2),
- %% ?DBG([{start_opts, StartOpts}, {opts_3, Opts_3}]),
+listen(Port, Opts0) ->
+ %% ?DBG([{port, Port}, {opts0, Opts0}]),
+ Opts1 = internalize_setopts(Opts0),
+ %% ?DBG([{opts1, Opts1}]),
+ {Mod, Opts2} = inet:tcp_module(Opts1),
+ %% ?DBG([{mod, Mod}, {opts2, Opts2}]),
+ {StartOpts, Opts3} = split_start_opts(Opts2),
+ {OpenOpts0, Opts4} = split_open_opts(Opts3),
+ %% ?DBG([{start_opts, StartOpts},
+ %% {open_opts0, OpenOpts0},
+ %% {opts4, Opts4}]),
case Mod:getserv(Port) of
{ok, TP} ->
%% ?DBG([{tp, TP}]),
- case inet:listen_options([{port, TP} | Opts_3], Mod) of
+ case inet:listen_options([{port, TP} | Opts4], Mod) of
{error, badarg} ->
exit(badarg);
{ok,
@@ -393,10 +402,10 @@ listen(Port, Opts) ->
%% {listen_opts, ListenOpts}, {backlog, Backlog}]),
BindSockaddr = bind_addr(Domain, BindAddr, BindPort),
%% ?DBG([{bind_sock_addr, BindSockaddr}]),
- ExtraOpts = extra_opts(Fd),
- %% ?DBG([{extra_opts, ExtraOpts}]),
+ OpenOpts = open_opts(OpenOpts0, open_opts(Fd)),
+ %% ?DBG([{open_opts, OpenOpts}]),
listen_open(
- Domain, ListenOpts, StartOpts, ExtraOpts,
+ Domain, ListenOpts, StartOpts, OpenOpts,
Backlog, BindSockaddr)
end;
{error, _} = Error ->
@@ -406,14 +415,13 @@ listen(Port, Opts) ->
%% Helpers -------
-listen_open(Domain, ListenOpts, StartOpts, ExtraOpts, BackLog, BindAddr) ->
+listen_open(Domain, ListenOpts, StartOpts0, OpenOpts, BackLog, BindAddr) ->
%% ?DBG(['start server',
- %% {listen_opts, ListenOpts},
- %% {start_opts, StartOpts},
- %% {extra_opts, ExtraOpts}]),
- case
- start_server(Domain, [{timeout, infinity} | StartOpts], ExtraOpts)
- of
+ %% {listen_opts, ListenOpts},
+ %% {start_opts0, StartOpts0},
+ %% {open_opts, OpenOpts}]),
+ StartOpts = [{timeout, infinity} | StartOpts0],
+ case start_server(Domain, StartOpts, OpenOpts) of
{ok, Server} ->
%% ?DBG([{server, Server}]),
ErrRef = make_ref(),
@@ -422,7 +430,7 @@ listen_open(Domain, ListenOpts, StartOpts, ExtraOpts, BackLog, BindAddr) ->
{win32, nt} ->
%% On *Windows*
%% we need to bind before everything else...
- try_bind(ErrRef, Server, Domain, BindAddr, ExtraOpts),
+ try_bind(ErrRef, Server, Domain, BindAddr, OpenOpts),
try_setopts(ErrRef, Server, StartOpts, ListenOpts),
Socket = try_listen(ErrRef, Server, BackLog),
MSock = ?MODULE_socket(Server, Socket),
@@ -431,7 +439,7 @@ listen_open(Domain, ListenOpts, StartOpts, ExtraOpts, BackLog, BindAddr) ->
_ ->
try_setopts(ErrRef, Server, StartOpts, ListenOpts),
- try_bind(ErrRef, Server, Domain, BindAddr, ExtraOpts),
+ try_bind(ErrRef, Server, Domain, BindAddr, OpenOpts),
Socket = try_listen(ErrRef, Server, BackLog),
MSock = ?MODULE_socket(Server, Socket),
%% ?DBG(['done', {msock, MSock}]),
@@ -452,19 +460,19 @@ listen_open(Domain, ListenOpts, StartOpts, ExtraOpts, BackLog, BindAddr) ->
end.
-try_bind(ErrRef, Server, Domain, BindAddr0, ExtraOpts) ->
+try_bind(ErrRef, Server, Domain, BindAddr0, OpenOpts) ->
%% ?DBG(['process bind-address',
%% {domain, Domain},
%% {bind_addr0, BindAddr0},
- %% {extra_opts, ExtraOpts}]),
- BindAddr1 = default_any(Domain, BindAddr0, ExtraOpts),
+ %% {open_opts, OpenOpts}]),
+ BindAddr1 = default_any(Domain, BindAddr0, OpenOpts),
%% ?DBG(['try bind', {bind_addr1, BindAddr1}]),
ok(ErrRef, call_bind(Server, BindAddr1)).
try_setopts(ErrRef, Server, StartOpts, OperationOpts) ->
%% ?DBG(['process options',
%% {start_opts, StartOpts},
- %% {operation_opts, listenOpts}]),
+ %% {operation_opts, OperationOpts}]),
SetOpts = default_active_true([{start_opts, StartOpts} |
setopts_opts(ErrRef, OperationOpts)]),
%% ?DBG(['try setopts', {set_opts, SetOpts}]),
@@ -811,20 +819,20 @@ which_packet_type(?MODULE_socket(_Server, Socket)) ->
unrecv(?MODULE_socket(_Server, _Socket), _Data) ->
{error, enotsup}.
-fdopen(Fd, Opts) when is_integer(Fd), 0 =< Fd, is_list(Opts) ->
- Opts_1 = internalize_setopts(Opts),
- {Mod, Opts_2} = inet:tcp_module(Opts_1),
+fdopen(Fd, Opts0) when is_integer(Fd), 0 =< Fd, is_list(Opts0) ->
+ Opts1 = internalize_setopts(Opts0),
+ {Mod, Opts2} = inet:tcp_module(Opts1),
Domain = domain(Mod),
- {StartOpts, Opts_3} = split_start_opts(Opts_2),
- ExtraOpts = extra_opts(Fd),
- case
- start_server(Domain, [{timeout, infinity} | StartOpts], ExtraOpts)
- of
+ {StartOpts0, Opts3} = split_start_opts(Opts2),
+ {Opts4, OpenOpts0} = split_open_opts(Opts3),
+ OpenOpts = open_opts(OpenOpts0, open_opts(Fd)),
+ StartOpts = [{timeout, infinity} | StartOpts0],
+ case start_server(Domain, StartOpts, OpenOpts) of
{ok, Server} ->
ErrRef = make_ref(),
try
Setopts =
- [{start_opts, StartOpts} | setopts_opts(ErrRef, Opts_3)],
+ [{start_opts, StartOpts} | setopts_opts(ErrRef, Opts4)],
ok(ErrRef, call(Server, {setopts, Setopts})),
Socket = val(ErrRef, call(Server, fdopen)),
{ok, ?MODULE_socket(Server, Socket)}
@@ -1031,6 +1039,21 @@ split_start_opts(Opts) ->
end || Opt <- StartOpts],
NonStartOpts}.
+
+%% No need to (at this point) do something fancy here,
+%% since we really only got one option we need to pick out; the debug
+%% option.
+split_open_opts(Opts) ->
+ split_open_opts(Opts, [], []).
+
+split_open_opts([], OpenOpts, OtherOpts) ->
+ {lists:reverse(OpenOpts), lists:reverse(OtherOpts)};
+split_open_opts([{debug, _} = Opt|Opts], OpenOpts, OtherOpts) ->
+ split_open_opts(Opts, [Opt|OpenOpts], OtherOpts);
+split_open_opts([Opt|Opts], OpenOpts, OtherOpts) ->
+ split_open_opts(Opts, OpenOpts, [Opt|OtherOpts]).
+
+
%%
%% -------
%% Verify that all options can be set with setopts/2 after
@@ -1383,10 +1406,14 @@ meta_opts() -> maps:keys(server_write_opts()).
%% State Machine Engine Call Interface
%% Start for connect or listen - create a socket
-start_server(Domain, StartOpts, ExtraOpts) ->
- %% ?DBG([{domain, Domain}, {start_opts, StartOpts}, {extra_opts, ExtraOpts}]),
+%% StartOpts - Options for gen_statem (start the gen_statem server)
+%% OpenOpts - Options for socket:open
+start_server(Domain, StartOpts, OpenOpts) ->
+ %% ?DBG([{domain, Domain},
+ %% {start_opts, StartOpts},
+ %% {open_opts, OpenOpts}]),
Owner = self(),
- Arg = {open, Domain, ExtraOpts, Owner},
+ Arg = {open, Domain, OpenOpts, Owner},
case gen_statem:start(?MODULE, Arg, StartOpts) of
{ok, Server} ->
%% ?DBG([{server, Server}]),
--
2.43.0