diff options
author | Hans Nilsson <hans@erlang.org> | 2021-04-19 08:48:34 +0200 |
---|---|---|
committer | Hans Nilsson <hans@erlang.org> | 2021-04-26 11:55:45 +0200 |
commit | 2f9fca1414e5858c376446b2aa59d6682b2c2959 (patch) | |
tree | 50eafb2e2ba861fc84c257a7d84f87e2dc534078 | |
parent | cceb8e4f2b292c19b90f613be46f2fd0e24e2d06 (diff) | |
download | erlang-2f9fca1414e5858c376446b2aa59d6682b2c2959.tar.gz |
ssh: New window init strategy
-rw-r--r-- | lib/ssh/src/ssh_connect.hrl | 2 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection.erl | 45 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 49 |
3 files changed, 62 insertions, 34 deletions
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl index 38e2b2de0b..687fd6c510 100644 --- a/lib/ssh/src/ssh_connect.hrl +++ b/lib/ssh/src/ssh_connect.hrl @@ -266,6 +266,8 @@ channel_id_seed, cli_spec, options, + suggest_window_size, + suggest_packet_size, exec, sub_system_supervisor }). diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index b8dd091c94..03a5d31f99 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -199,13 +199,13 @@ dummy(_) -> false. Result :: {ok, ssh:channel_id()} | {error, reason()} . session_channel(ConnectionHandler, Timeout) -> - session_channel(ConnectionHandler, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). + session_channel(ConnectionHandler, undefined, undefined, Timeout). -spec session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout) -> Result when ConnectionRef :: ssh:connection_ref(), - InitialWindowSize :: pos_integer(), - MaxPacketSize :: pos_integer(), + InitialWindowSize :: pos_integer() | undefined, + MaxPacketSize :: pos_integer() | undefined, Timeout :: timeout(), Result :: {ok, ssh:channel_id()} | {error, reason()} . @@ -219,7 +219,7 @@ session_channel(ConnectionHandler, InitialWindowSize, MaxPacketSize, Timeout) -> %% Description: Opens a channel for the given type. %% -------------------------------------------------------------------- open_channel(ConnectionHandler, Type, ChanData, Timeout) -> - open_channel(ConnectionHandler, Type, ChanData, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). + open_channel(ConnectionHandler, Type, ChanData, undefined, undefined, Timeout). open_channel(ConnectionHandler, Type, ChanData, InitialWindowSize, MaxPacketSize, Timeout) -> case ssh_connection_handler:open_channel(ConnectionHandler, Type, ChanData, @@ -603,6 +603,8 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip", }, #connection{channel_cache = Cache, channel_id_seed = ChId, + suggest_window_size = WinSz, + suggest_packet_size = PktSz, options = Options, sub_system_supervisor = SubSysSup } = C, @@ -621,17 +623,15 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip", local_id = ChId, remote_id = RemoteId, user = Pid, - recv_window_size = ?DEFAULT_WINDOW_SIZE, - recv_packet_size = ?DEFAULT_PACKET_SIZE, + recv_window_size = WinSz, + recv_packet_size = PktSz, send_window_size = WindowSize, send_packet_size = PacketSize, send_buf = queue:new() }), gen_tcp:controlling_process(Sock, Pid), inet:setopts(Sock, [{active,once}]), - {channel_open_confirmation_msg(RemoteId, ChId, - ?DEFAULT_WINDOW_SIZE, - ?DEFAULT_PACKET_SIZE), + {channel_open_confirmation_msg(RemoteId, ChId, WinSz, PktSz), ChId + 1}; {error,Error} -> @@ -661,6 +661,8 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip", }, #connection{channel_cache = Cache, channel_id_seed = ChId, + suggest_window_size = WinSz, + suggest_packet_size = PktSz, options = Options, sub_system_supervisor = SubSysSup } = C, @@ -687,8 +689,8 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip", local_id = ChId, remote_id = RemoteId, user = Pid, - recv_window_size = ?DEFAULT_WINDOW_SIZE, - recv_packet_size = ?DEFAULT_PACKET_SIZE, + recv_window_size = WinSz, + recv_packet_size = PktSz, send_window_size = WindowSize, send_packet_size = PacketSize, send_buf = queue:new() @@ -696,9 +698,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "direct-tcpip", gen_tcp:controlling_process(Sock, Pid), inet:setopts(Sock, [{active,once}]), - {channel_open_confirmation_msg(RemoteId, ChId, - ?DEFAULT_WINDOW_SIZE, - ?DEFAULT_PACKET_SIZE), + {channel_open_confirmation_msg(RemoteId, ChId, WinSz, PktSz), ChId + 1}; {error,Error} -> @@ -1101,16 +1101,19 @@ encode_ip(Addr) when is_list(Addr) -> %%% of "session" typ is handled %%% setup_session(#connection{channel_cache = Cache, - channel_id_seed = NewChannelID + channel_id_seed = NewChannelID, + suggest_window_size = WinSz, + suggest_packet_size = PktSz } = C, - RemoteId, Type, WindowSize, PacketSize) -> + RemoteId, Type, WindowSize, PacketSize) when is_integer(WinSz), + is_integer(PktSz) -> NextChannelID = NewChannelID + 1, Channel = #channel{type = Type, sys = "ssh", local_id = NewChannelID, - recv_window_size = ?DEFAULT_WINDOW_SIZE, - recv_packet_size = ?DEFAULT_PACKET_SIZE, + recv_window_size = WinSz, + recv_packet_size = PktSz, send_window_size = WindowSize, send_packet_size = PacketSize, send_buf = queue:new(), @@ -1118,9 +1121,9 @@ setup_session(#connection{channel_cache = Cache, }, ssh_client_channel:cache_update(Cache, Channel), OpenConfMsg = channel_open_confirmation_msg(RemoteId, NewChannelID, - ?DEFAULT_WINDOW_SIZE, - ?DEFAULT_PACKET_SIZE), - Reply = {connection_reply, OpenConfMsg}, + WinSz, + PktSz), + Reply = {connection_reply, OpenConfMsg}, {[Reply], C#connection{channel_id_seed = NextChannelID}}. diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 13790157c7..14738cbd03 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -171,8 +171,8 @@ disconnect(Code, DetailedText, Module, Line) -> -spec open_channel(connection_ref(), string(), iodata(), - pos_integer(), - pos_integer(), + pos_integer() | undefined, + pos_integer() | undefined, timeout() ) -> {open, channel_id()} | {error, term()}. @@ -409,7 +409,7 @@ init([Role, Socket, Opts]) when Role==client ; Role==server -> transport_cb = Callback, transport_close_tag = CloseTag, ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts), - connection_state = init_connection_record(Role, Opts) + connection_state = init_connection_record(Role, Socket, Opts) }, process_flag(trap_exit, true), {ok, {hello,Role}, D} @@ -425,9 +425,12 @@ init([Role, Socket, Opts]) when Role==client ; Role==server -> %%%---------------------------------------------------------------- %%% Connection start and initalization helpers -init_connection_record(Role, Opts) -> +init_connection_record(Role, Socket, Opts) -> + {WinSz, PktSz} = init_inet_buffers_window(Socket), C = #connection{channel_cache = ssh_client_channel:cache_create(), channel_id_seed = 0, + suggest_window_size = WinSz, + suggest_packet_size = PktSz, requests = [], options = Opts, sub_system_supervisor = ?GET_INTERNAL_OPT(subsystem_sup, Opts) @@ -441,8 +444,6 @@ init_connection_record(Role, Opts) -> client -> C end. - - init_ssh_record(Role, Socket, Opts) -> %% Export of this internal function is @@ -1003,20 +1004,26 @@ handle_event({call,From}, get_misc, StateName, handle_event({call,From}, {open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout}, StateName, - D0) when ?CONNECTED(StateName) -> + D0 = #data{connection_state = C}) when ?CONNECTED(StateName) -> erlang:monitor(process, ChannelPid), {ChannelId, D1} = new_channel_id(D0), - D2 = send_msg(ssh_connection:channel_open_msg(Type, ChannelId, - InitialWindowSize, - MaxPacketSize, Data), + WinSz = case InitialWindowSize of + undefined -> C#connection.suggest_window_size; + _ -> InitialWindowSize + end, + PktSz = case MaxPacketSize of + undefined -> C#connection.suggest_packet_size; + _ -> MaxPacketSize + end, + D2 = send_msg(ssh_connection:channel_open_msg(Type, ChannelId, WinSz, PktSz, Data), D1), ssh_client_channel:cache_update(cache(D2), #channel{type = Type, sys = "none", user = ChannelPid, local_id = ChannelId, - recv_window_size = InitialWindowSize, - recv_packet_size = MaxPacketSize, + recv_window_size = WinSz, + recv_packet_size = PktSz, send_buf = queue:new() }), D = add_request(true, ChannelId, From, D2), @@ -1967,6 +1974,18 @@ start_channel_request_timer(Channel, From, Time) -> erlang:send_after(Time, self(), {timeout, {Channel, From}}). %%%---------------------------------------------------------------- + +init_inet_buffers_window(Socket) -> + %% Initialize the inet buffer handling. First try to increase the buffers: + update_inet_buffers(Socket), + %% then get good start values for the window handling: + {ok,SockOpts} = inet:getopts(Socket, [buffer,recbuf]), + WinSz = proplists:get_value(recbuf, SockOpts, ?DEFAULT_WINDOW_SIZE), + PktSz = min(proplists:get_value(buffer, SockOpts, ?DEFAULT_PACKET_SIZE), + ?DEFAULT_PACKET_SIZE), % Too large packet size might cause deadlock + % between sending and receiving + {WinSz, PktSz}. + update_inet_buffers(Socket) -> try {ok, BufSzs0} = inet:getopts(Socket, [sndbuf,recbuf]), @@ -1975,7 +1994,11 @@ update_inet_buffers(Socket) -> Val < MinVal] of [] -> ok; - NewOpts -> inet:setopts(Socket, NewOpts) + NewOpts -> + inet:setopts(Socket, NewOpts), + %% Note that buffers might be of different size than we just requested, + %% the OS has the last word. + ok catch _:_ -> ok end. |