194194 ssl_opts = [], % Arbitrary SSL options, see the erlang SSL
195195 % documentation.
196196 reconnect_interval = ? FIRST_RECONNECT_INTERVAL :: non_neg_integer (),
197- silence_terminate_crash = false :: boolean ()}).
197+ silence_terminate_crash = false :: boolean (),
198+ % Determines the time-out, in seconds,
199+ % for flushing unsent data in the close/1 socket call.
200+ % The first component is if linger is enabled,
201+ % the second component is the flushing time-out, in seconds.
202+ % https://erlang.org/doc/man/inet.html#setopts-2
203+ linger = {false , 0 } :: {boolean (), non_neg_integer ()}}).
198204
199205-export_type ([address / 0 , portnum / 0 ]).
200206
@@ -2187,7 +2193,10 @@ parse_options([{keyfile, File}|Options], State) ->
21872193parse_options ([{ssl_opts , Opts }|Options ], State ) ->
21882194 parse_options (Options , State # state {ssl_opts = Opts });
21892195parse_options ([{silence_terminate_crash ,Bool }|Options ], State ) ->
2190- parse_options (Options , State # state {silence_terminate_crash = Bool }).
2196+ parse_options (Options , State # state {silence_terminate_crash = Bool });
2197+ parse_options ([{linger , {Bool , Timeout }}|Options ], State )
2198+ when Bool =:= true ; Bool =:= false ; Timeout >= 0 ->
2199+ parse_options (Options , State # state {linger = {Bool , Timeout }}).
21912200
21922201maybe_reply ({reply , Reply , State }) ->
21932202 Request = State # state .active ,
@@ -3086,6 +3095,7 @@ connect(State) when State#state.sock =:= undefined ->
30863095 # state {address = Address , port = Port , connects = Connects } = State ,
30873096 case gen_tcp :connect (Address , Port ,
30883097 [binary , {active , once }, {packet , 4 },
3098+ {linger , State # state .linger },
30893099 {keepalive , State # state .keepalive }],
30903100 State # state .connect_timeout ) of
30913101 {ok , Sock } ->
@@ -3138,6 +3148,7 @@ start_tls(State=#state{sock=Sock}) ->
31383148 % % man-in-the-middle proxy that presents insecure
31393149 % % communication to the client, but does secure
31403150 % % communication to the server.
3151+ ensure_connection_closed (State ),
31413152 {error , no_security }
31423153 end
31433154 end .
@@ -3173,16 +3184,8 @@ disconnect(State) ->
31733184 end ,
31743185
31753186 % % Make sure the connection is really closed
3176- case State # state .sock of
3177- undefined ->
3178- ok ;
3179- Sock ->
3180- Transport = State # state .transport ,
3181- Transport :close (Sock )
3182- end ,
3183-
3187+ NewState = ensure_connection_closed (State ),
31843188 % % Decide whether to reconnect or exit
3185- NewState = State # state {sock = undefined , active = undefined },
31863189 case State # state .auto_reconnect of
31873190 true ->
31883191 % % Schedule the reconnect message and return state
@@ -3197,6 +3200,12 @@ disconnect(State) ->
31973200 end
31983201 end .
31993202
3203+ ensure_connection_closed (# state {sock = undefined } = State ) ->
3204+ State ;
3205+ ensure_connection_closed (# state {sock = Sock , transport = Transport } = State ) ->
3206+ Transport :close (Sock ),
3207+ State # state {sock = undefined , active = undefined }.
3208+
32003209% % Double the reconnect interval up to the maximum
32013210increase_reconnect_interval (State ) ->
32023211 case State # state .reconnect_interval of
0 commit comments