diff options
author | Erlang/OTP <[email protected]> | 2017-06-26 16:03:10 +0200 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2017-06-26 16:03:10 +0200 |
commit | 5f2d536cb2ad0447eca64d91755dd8a4549561ac (patch) | |
tree | fac19ee80c52f21779da5977b68d02878e787fee | |
parent | b1f76e2f15c9d8c741ecb4bddc0b38740f3e7143 (diff) | |
parent | 02c0cf44437df3ed1ff8cdbb48b477b489977b85 (diff) | |
download | otp-5f2d536cb2ad0447eca64d91755dd8a4549561ac.tar.gz otp-5f2d536cb2ad0447eca64d91755dd8a4549561ac.tar.bz2 otp-5f2d536cb2ad0447eca64d91755dd8a4549561ac.zip |
Merge branch 'john/erts/fix-port-leak/OTP-13939/ERL-193' into maint-19
* john/erts/fix-port-leak/OTP-13939/ERL-193:
Add a testcase for OTP-13939/ERL-193
Mark socket disconnected on tcp_send_or_shutdown_error
# Conflicts:
# lib/kernel/test/gen_tcp_misc_SUITE.erl
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 6 | ||||
-rw-r--r-- | lib/kernel/test/gen_tcp_misc_SUITE.erl | 41 |
2 files changed, 46 insertions, 1 deletions
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index ebd13e6f05..edea208857 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -4320,6 +4320,12 @@ static void desc_close(inet_descriptor* desc) desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; + + /* mark as disconnected in case when socket is left lingering due to + * {exit_on_close, false} option in gen_tcp socket creation. Next + * write to socket should produce {error, enotconn} and send a + * message {tcp_error,#Port<>,econnreset} */ + desc->state &= ~INET_STATE_CONNECTED; } } diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 6b64c83fc2..5e08a5ea62 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -52,7 +52,7 @@ active_once_closed/1, send_timeout/1, send_timeout_active/1, otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1, wrapping_oct/0, wrapping_oct/1, - otp_9389/1]). + otp_9389/1, otp_13939/1]). %% Internal exports. -export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1, @@ -3014,3 +3014,42 @@ ok({ok,V}) -> V. get_hostname(Name) -> "@"++Host = lists:dropwhile(fun(C) -> C =/= $@ end, atom_to_list(Name)), Host. + +otp_13939(doc) -> + ["Check that writing to a remotely closed socket doesn't block forever " + "when exit_on_close is false."]; +otp_13939(suite) -> + []; +otp_13939(Config) when is_list(Config) -> + {Pid, Ref} = spawn_opt( + fun() -> + {ok, Listener} = gen_tcp:listen(0, [{exit_on_close, false}]), + {ok, Port} = inet:port(Listener), + + spawn_link( + fun() -> + {ok, Client} = gen_tcp:connect("localhost", Port, + [{active, false}]), + ok = gen_tcp:close(Client) + end), + + {ok, Accepted} = gen_tcp:accept(Listener), + + ok = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>), + + %% The bug surfaces when there's a delay between the send + %% operations; inet:getstat is a red herring. + timer:sleep(100), + + {error, Code} = gen_tcp:send(Accepted, <<0:(10*1024*1024*8)>>), + ct:pal("gen_tcp:send returned ~p~n", [Code]) + end, [link, monitor]), + + receive + {'DOWN', Ref, process, Pid, normal} -> + ok + after 1000 -> + demonitor(Ref, [flush]), + exit(Pid, normal), + ct:fail("Server process blocked on send.") + end. |