aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src/ssh_connection_handler.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/src/ssh_connection_handler.erl')
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl236
1 files changed, 168 insertions, 68 deletions
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 84bb7dc23f..74e14a233f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -365,7 +365,7 @@ init_connection_handler(Role, Socket, Opts) ->
{ok, StartState, D} ->
process_flag(trap_exit, true),
gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
+ [], %%[{debug,[trace,log,statistics,debug]} ], %% []
StartState,
D);
@@ -453,7 +453,9 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
PeerName = case ?GET_INTERNAL_OPT(host, Opts) of
PeerIP when is_tuple(PeerIP) ->
inet_parse:ntoa(PeerIP);
- PeerName0 ->
+ PeerName0 when is_atom(PeerName0) ->
+ atom_to_list(PeerName0);
+ PeerName0 when is_list(PeerName0) ->
PeerName0
end,
S0#ssh{c_vsn = Vsn,
@@ -462,6 +464,7 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
true -> ssh_io;
false -> ssh_no_io
end,
+ userauth_pubkeys = ?GET_OPT(pref_public_key_algs, Opts),
userauth_quiet_mode = ?GET_OPT(quiet_mode, Opts),
peer = {PeerName, PeerAddr}
};
@@ -487,25 +490,42 @@ init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
-type renegotiate_flag() :: init | renegotiate.
-type state_name() ::
- {hello, role()}
- | {kexinit, role(), renegotiate_flag()}
- | {key_exchange, role(), renegotiate_flag()}
- | {key_exchange_dh_gex_init, server, renegotiate_flag()}
+ {hello, role() }
+ | {kexinit, role(), renegotiate_flag()}
+ | {key_exchange, role(), renegotiate_flag()}
+ | {key_exchange_dh_gex_init, server, renegotiate_flag()}
| {key_exchange_dh_gex_reply, client, renegotiate_flag()}
- | {new_keys, role()}
- | {service_request, role()}
- | {userauth, role()}
- | {userauth_keyboard_interactive, role()}
- | {connected, role()}
+ | {new_keys, role(), renegotiate_flag()}
+ | {ext_info, role(), renegotiate_flag()}
+ | {service_request, role() }
+ | {userauth, role() }
+ | {userauth_keyboard_interactive, role() }
+ | {userauth_keyboard_interactive_extra, server }
+ | {userauth_keyboard_interactive_info_response, client }
+ | {connected, role() }
.
--type handle_event_result() :: gen_statem:handle_event_result().
+%% The state names must fulfill some rules regarding
+%% where the role() and the renegotiate_flag() is placed:
+
+-spec role(state_name()) -> role().
+role({_,Role}) -> Role;
+role({_,Role,_}) -> Role.
+
+-spec renegotiation(state_name()) -> boolean().
+renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
+renegotiation(_) -> false.
+
+
+-define(CONNECTED(StateName),
+ (element(1,StateName) == connected orelse
+ element(1,StateName) == ext_info ) ).
-spec handle_event(gen_statem:event_type(),
event_content(),
state_name(),
#data{}
- ) -> handle_event_result().
+ ) -> gen_statem:event_handler_result(state_name()) .
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@@ -589,13 +609,17 @@ handle_event(_, {#ssh_msg_kexinit{}=Kex, Payload}, {kexinit,Role,ReNeg},
handle_event(_, #ssh_msg_kexdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexdhReply, Ssh1} = ssh_transport:handle_kexdh_init(Msg, D#data.ssh_params),
send_bytes(KexdhReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kexdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
- {ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
+ {ok, NewKeys, Ssh1} = ssh_transport:handle_kexdh_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%%---- diffie-hellman group exchange
@@ -620,13 +644,17 @@ handle_event(_, #ssh_msg_kex_dh_gex_group{} = Msg, {key_exchange,client,ReNeg},
handle_event(_, #ssh_msg_kex_ecdh_init{} = Msg, {key_exchange,server,ReNeg}, D) ->
{ok, KexEcdhReply, Ssh1} = ssh_transport:handle_kex_ecdh_init(Msg, D#data.ssh_params),
send_bytes(KexEcdhReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D) ->
- {ok, NewKeys, Ssh} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
+ {ok, NewKeys, Ssh1} = ssh_transport:handle_kex_ecdh_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
@@ -635,8 +663,10 @@ handle_event(_, #ssh_msg_kex_ecdh_reply{} = Msg, {key_exchange,client,ReNeg}, D)
handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,server,ReNeg}, D) ->
{ok, KexGexReply, Ssh1} = ssh_transport:handle_kex_dh_gex_init(Msg, D#data.ssh_params),
send_bytes(KexGexReply, D),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ {ok, NewKeys, Ssh2} = ssh_transport:new_keys_message(Ssh1),
send_bytes(NewKeys, D),
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh2),
+ send_bytes(ExtInfo, D),
{next_state, {new_keys,server,ReNeg}, D#data{ssh_params=Ssh}};
@@ -645,30 +675,60 @@ handle_event(_, #ssh_msg_kex_dh_gex_init{} = Msg, {key_exchange_dh_gex_init,serv
handle_event(_, #ssh_msg_kex_dh_gex_reply{} = Msg, {key_exchange_dh_gex_reply,client,ReNeg}, D) ->
{ok, NewKeys, Ssh1} = ssh_transport:handle_kex_dh_gex_reply(Msg, D#data.ssh_params),
send_bytes(NewKeys, D),
- {next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh1}};
+ {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ send_bytes(ExtInfo, D),
+ {next_state, {new_keys,client,ReNeg}, D#data{ssh_params=Ssh}};
%%% ######## {new_keys, client|server} ####
%% First key exchange round:
-handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,init}, D) ->
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,client,init}, D) ->
{ok, Ssh1} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
- Ssh = case Role of
- client ->
- {MsgReq, Ssh2} = ssh_auth:service_request_msg(Ssh1),
- send_bytes(MsgReq, D),
- Ssh2;
- server ->
- Ssh1
- end,
- {next_state, {service_request,Role}, D#data{ssh_params=Ssh}};
+ %% {ok, ExtInfo, Ssh2} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {MsgReq, Ssh} = ssh_auth:service_request_msg(Ssh1),
+ send_bytes(MsgReq, D),
+ {next_state, {ext_info,client,init}, D#data{ssh_params=Ssh}};
+
+handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,server,init}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ %% {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {next_state, {ext_info,server,init}, D#data{ssh_params=Ssh}};
%% Subsequent key exchange rounds (renegotiation):
handle_event(_, #ssh_msg_newkeys{} = Msg, {new_keys,Role,renegotiate}, D) ->
{ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
- {next_state, {connected,Role}, D#data{ssh_params=Ssh}};
+ %% {ok, ExtInfo, Ssh} = ssh_transport:ext_info_message(Ssh1),
+ %% send_bytes(ExtInfo, D),
+ {next_state, {ext_info,Role,renegotiate}, D#data{ssh_params=Ssh}};
+
+
+%%% ######## {ext_info, client|server, init|renegotiate} ####
+
+handle_event(_, #ssh_msg_ext_info{}=Msg, {ext_info,Role,init}, D0) ->
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {next_state, {service_request,Role}, D};
+
+handle_event(_, #ssh_msg_ext_info{}=Msg, {ext_info,Role,renegotiate}, D0) ->
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {next_state, {connected,Role}, D};
+
+handle_event(_, #ssh_msg_newkeys{}=Msg, {ext_info,_Role,renegotiate}, D) ->
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, D#data.ssh_params),
+ {keep_state, D#data{ssh_params = Ssh}};
+
+
+handle_event(internal, Msg, {ext_info,Role,init}, D) when is_tuple(Msg) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {service_request,Role}, D, [postpone]};
-%%% ######## {service_request, client|server}
+handle_event(internal, Msg, {ext_info,Role,_ReNegFlag}, D) when is_tuple(Msg) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {connected,Role}, D, [postpone]};
+
+%%% ######## {service_request, client|server} ####
handle_event(_, Msg = #ssh_msg_service_request{name=ServiceName}, StateName = {service_request,server}, D) ->
case ServiceName of
@@ -747,6 +807,11 @@ handle_event(_,
end;
%%---- userauth success to client
+handle_event(_, #ssh_msg_ext_info{}=Msg, {userauth,client}, D0) ->
+ %% FIXME: need new state to receive this msg!
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {keep_state, D};
+
handle_event(_, #ssh_msg_userauth_success{}, {userauth,client}, D=#data{ssh_params = Ssh}) ->
D#data.starter ! ssh_connected,
{next_state, {connected,client}, D#data{ssh_params=Ssh#ssh{authenticated = true}}};
@@ -849,6 +914,11 @@ handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info
end,
{next_state, {userauth,client}, D, [postpone]};
+handle_event(_, #ssh_msg_ext_info{}=Msg, {userauth_keyboard_interactive_info_response, client}, D0) ->
+ %% FIXME: need new state to receive this msg!
+ D = handle_ssh_msg_ext_info(Msg, D0),
+ {keep_state, D};
+
handle_event(_, #ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
{next_state, {userauth,client}, D, [postpone]};
@@ -967,12 +1037,10 @@ handle_event(cast, data_size, _, _) ->
-handle_event(cast, _, StateName, _) when StateName /= {connected,server},
- StateName /= {connected,client} ->
+handle_event(cast, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
-
-handle_event(cast, {adjust_window,ChannelId,Bytes}, {connected,_}, D) ->
+handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_window_pending = Pending,
@@ -998,7 +1066,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, {connected,_}, D) ->
keep_state_and_data
end;
-handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
+handle_event(cast, {reply_request,success,ChannelId}, StateName, D) when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = RemoteId} ->
Msg = ssh_connection:channel_success_msg(RemoteId),
@@ -1009,13 +1077,13 @@ handle_event(cast, {reply_request,success,ChannelId}, {connected,_}, D) ->
keep_state_and_data
end;
-handle_event(cast, {request,ChannelPid, ChannelId, Type, Data}, {connected,_}, D) ->
+handle_event(cast, {request,ChannelPid, ChannelId, Type, Data}, StateName, D) when ?CONNECTED(StateName) ->
{keep_state, handle_request(ChannelPid, ChannelId, Type, Data, false, none, D)};
-handle_event(cast, {request,ChannelId,Type,Data}, {connected,_}, D) ->
+handle_event(cast, {request,ChannelId,Type,Data}, StateName, D) when ?CONNECTED(StateName) ->
{keep_state, handle_request(ChannelId, Type, Data, false, none, D)};
-handle_event(cast, {unknown,Data}, {connected,_}, D) ->
+handle_event(cast, {unknown,Data}, StateName, D) when ?CONNECTED(StateName) ->
Msg = #ssh_msg_unimplemented{sequence = Data},
{keep_state, send_msg(Msg,D)};
@@ -1076,30 +1144,34 @@ handle_event({call,From}, stop, StateName, D0) ->
{Repls,D} = send_replies(Replies, D0),
{stop_and_reply, normal, [{reply,From,ok}|Repls], D#data{connection_state=Connection}};
-handle_event({call,_}, _, StateName, _) when StateName /= {connected,server},
- StateName /= {connected,client} ->
+
+handle_event({call,_}, _, StateName, _) when not ?CONNECTED(StateName) ->
{keep_state_and_data, [postpone]};
-handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {request, ChannelPid, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when ?CONNECTED(StateName) ->
D = handle_request(ChannelPid, ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
-handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {request, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when ?CONNECTED(StateName) ->
D = handle_request(ChannelId, Type, Data, true, From, D0),
%% Note reply to channel will happen later when reply is recived from peer on the socket
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_request_idle_timer_check(D)};
-handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, {connected,_}, D0) ->
+handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0)
+ when ?CONNECTED(StateName) ->
{{replies, Replies}, Connection} =
ssh_connection:channel_data(ChannelId, Type, Data, D0#data.connection_state, From),
{Repls,D} = send_replies(Replies, D0#data{connection_state = Connection}),
start_channel_request_timer(ChannelId, From, Timeout), % FIXME: No message exchange so why?
{keep_state, D, Repls};
-handle_event({call,From}, {eof, ChannelId}, {connected,_}, D0) ->
+handle_event({call,From}, {eof, ChannelId}, StateName, D0)
+ when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id, sent_close = false} ->
D = send_msg(ssh_connection:channel_eof_msg(Id), D0),
@@ -1110,8 +1182,8 @@ handle_event({call,From}, {eof, ChannelId}, {connected,_}, D0) ->
handle_event({call,From},
{open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout},
- {connected,_},
- D0) ->
+ StateName,
+ D0) when ?CONNECTED(StateName) ->
erlang:monitor(process, ChannelPid),
{ChannelId, D1} = new_channel_id(D0),
D2 = send_msg(ssh_connection:channel_open_msg(Type, ChannelId,
@@ -1131,7 +1203,8 @@ handle_event({call,From},
start_channel_request_timer(ChannelId, From, Timeout),
{keep_state, cache_cancel_idle_timer(D)};
-handle_event({call,From}, {send_window, ChannelId}, {connected,_}, D) ->
+handle_event({call,From}, {send_window, ChannelId}, StateName, D)
+ when ?CONNECTED(StateName) ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{send_window_size = WinSize,
send_packet_size = Packsize} ->
@@ -1141,7 +1214,8 @@ handle_event({call,From}, {send_window, ChannelId}, {connected,_}, D) ->
end,
{keep_state_and_data, [{reply,From,Reply}]};
-handle_event({call,From}, {recv_window, ChannelId}, {connected,_}, D) ->
+handle_event({call,From}, {recv_window, ChannelId}, StateName, D)
+ when ?CONNECTED(StateName) ->
Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{recv_window_size = WinSize,
recv_packet_size = Packsize} ->
@@ -1151,7 +1225,8 @@ handle_event({call,From}, {recv_window, ChannelId}, {connected,_}, D) ->
end,
{keep_state_and_data, [{reply,From,Reply}]};
-handle_event({call,From}, {close, ChannelId}, {connected,_}, D0) ->
+handle_event({call,From}, {close, ChannelId}, StateName, D0)
+ when ?CONNECTED(StateName) ->
case ssh_channel:cache_lookup(cache(D0), ChannelId) of
#channel{remote_id = Id} = Channel ->
D1 = send_msg(ssh_connection:channel_close_msg(Id), D0),
@@ -1319,11 +1394,16 @@ handle_event(info, UnexpectedMessage, StateName, D = #data{ssh_params = Ssh}) ->
handle_event(internal, {disconnect,Msg,_Reason}, StateName, D) ->
disconnect(Msg, StateName, D);
+handle_event(_Type, _Msg, {ext_info,Role,_ReNegFlag}, D) ->
+ %% If something else arrives, goto next state and handle the event in that one
+ {next_state, {connected,Role}, D, [postpone]};
+
handle_event(Type, Ev, StateName, D) ->
Descr =
case catch atom_to_list(element(1,Ev)) of
"ssh_msg_" ++_ when Type==internal ->
- "Message in wrong state";
+%% "Message in wrong state";
+ lists:flatten(io_lib:format("Message ~p in wrong state (~p)", [element(1,Ev), StateName]));
_ ->
"Internal error"
end,
@@ -1463,16 +1543,6 @@ peer_role(client) -> server;
peer_role(server) -> client.
%%--------------------------------------------------------------------
-%% StateName to Role
-role({_,Role}) -> Role;
-role({_,Role,_}) -> Role.
-
-%%--------------------------------------------------------------------
-%% Check the StateName to see if we are in the renegotiation phase
-renegotiation({_,_,ReNeg}) -> ReNeg == renegotiation;
-renegotiation(_) -> false.
-
-%%--------------------------------------------------------------------
supported_host_keys(client, _, Options) ->
try
find_sup_hkeys(Options)
@@ -1508,14 +1578,19 @@ find_sup_hkeys(Options) ->
%% Alg :: atom()
available_host_key({KeyCb,KeyCbOpts}, Alg, Opts) ->
UserOpts = ?GET_OPT(user_options, Opts),
- element(1,
- catch KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts])) == ok.
+ case KeyCb:host_key(Alg, [{key_cb_private,KeyCbOpts}|UserOpts]) of
+ {ok,_} -> true;
+ _ -> false
+ end.
+
send_msg(Msg, State=#data{ssh_params=Ssh0}) when is_tuple(Msg) ->
{Bytes, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
send_bytes(Bytes, State),
State#data{ssh_params=Ssh}.
+send_bytes("", _D) ->
+ ok;
send_bytes(Bytes, #data{socket = Socket, transport_cb = Transport}) ->
_ = Transport:send(Socket, Bytes),
ok.
@@ -1622,6 +1697,29 @@ cache(#data{connection_state=C}) -> C#connection.channel_cache.
%%%----------------------------------------------------------------
+handle_ssh_msg_ext_info(#ssh_msg_ext_info{}, D=#data{ssh_params = #ssh{recv_ext_info=false}} ) ->
+ % The peer sent this although we didn't allow it!
+ D;
+
+handle_ssh_msg_ext_info(#ssh_msg_ext_info{data=Data}, D0) ->
+ lists:foldl(fun ext_info/2, D0, Data).
+
+
+ext_info({"server-sig-algs",SigAlgs}, D0 = #data{ssh_params=#ssh{role=client}=Ssh0}) ->
+ %% Make strings to eliminate risk of beeing bombed with odd strings that fills the atom table:
+ SupportedAlgs = lists:map(fun erlang:atom_to_list/1, ssh_transport:supported_algorithms(public_key)),
+ Ssh = Ssh0#ssh{userauth_pubkeys =
+ [list_to_atom(SigAlg) || SigAlg <- string:tokens(SigAlgs,","),
+ %% length of SigAlg is implicitly checked by member:
+ lists:member(SigAlg, SupportedAlgs)
+ ]},
+ D0#data{ssh_params = Ssh};
+
+ext_info(_, D0) ->
+ %% Not implemented
+ D0.
+
+%%%----------------------------------------------------------------
handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) ->
case ssh_channel:cache_lookup(cache(D), ChannelId) of
#channel{remote_id = Id} = Channel ->
@@ -1911,12 +2009,14 @@ handshake(Pid, Ref, Timeout) ->
end.
update_inet_buffers(Socket) ->
- {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
- MinVal = 655360,
- case
- [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
- Val < MinVal]
+ try
+ {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]),
+ MinVal = 655360,
+ [{Tag,MinVal} || {Tag,Val} <- BufSzs0,
+ Val < MinVal]
of
[] -> ok;
NewOpts -> inet:setopts(Socket, NewOpts)
+ catch
+ _:_ -> ok
end.