From 33b282356b786b831fe8f5414fa60397c4c7eaf9 Mon Sep 17 00:00:00 2001 From: Daniil Fedotov Date: Tue, 3 May 2016 13:28:09 +0100 Subject: Ignore tcp errors during close request to eldap If underlying tcp connection is closed and LDAP operation returned tcp error, then client applications tend to close ldap handle with eldap:close. This will cause do_unbind to throw gen_tcp_error, which is unhandled and will be sent to linked process as {nocatch, {gen_tcp_error, ...}}. eldap should ignore gen_tcp_error during close, because it will be closing anyway. --- lib/eldap/src/eldap.erl | 7 ++++++- lib/eldap/test/eldap_basic_SUITE.erl | 27 ++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index dc236f8a44..8994df10eb 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -564,7 +564,12 @@ loop(Cpid, Data) -> ?MODULE:loop(Cpid, NewData); {_From, close} -> - {no_reply,_NewData} = do_unbind(Data), + % Ignore tcp error if connection is already closed. + try do_unbind(Data) of + {no_reply,_NewData} -> ok + catch + throw:{gen_tcp_error, _TcpErr} -> ok + end, unlink(Cpid), exit(closed); diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl index 9a23f74e22..536e891a1e 100644 --- a/lib/eldap/test/eldap_basic_SUITE.erl +++ b/lib/eldap/test/eldap_basic_SUITE.erl @@ -94,7 +94,8 @@ connection_tests() -> client_side_start_tls_timeout, client_side_bind_timeout, client_side_add_timeout, - client_side_search_timeout + client_side_search_timeout, + close_after_tcp_error ]. @@ -311,6 +312,30 @@ tcp_connection(Config) -> Other -> ct:fail("eldap:open failed: ~p",[Other]) end. +%%%---------------------------------------------------------------- + +close_after_tcp_error(Config) -> + Host = proplists:get_value(listen_host, Config), + Port = proplists:get_value(listen_port, Config), + Opts = proplists:get_value(tcp_connect_opts, Config), + T = 1000, + case eldap:open([Host], [{timeout,T},{port,Port}|Opts]) of + {ok,H} -> + Sl = proplists:get_value(listen_socket, Config), + gen_tcp:close(Sl), + {error,{gen_tcp_error,closed}} = eldap:simple_bind(H, anon, anon), + ok = eldap:close(H), + wait_for_close(H); + Other -> ct:fail("eldap:open failed: ~p",[Other]) + end. + +wait_for_close(H) -> + case erlang:is_process_alive(H) of + true -> timer:sleep(100), + wait_for_close(H); + false -> ok + end. + %%%---------------------------------------------------------------- ssl_connection(Config) -> Host = proplists:get_value(listen_host, Config), -- cgit v1.2.3