summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Nilsson <hans@erlang.org>2021-04-19 08:48:34 +0200
committerHans Nilsson <hans@erlang.org>2021-04-26 11:55:45 +0200
commit2f9fca1414e5858c376446b2aa59d6682b2c2959 (patch)
tree50eafb2e2ba861fc84c257a7d84f87e2dc534078
parentcceb8e4f2b292c19b90f613be46f2fd0e24e2d06 (diff)
downloaderlang-2f9fca1414e5858c376446b2aa59d6682b2c2959.tar.gz
ssh: New window init strategy
-rw-r--r--lib/ssh/src/ssh_connect.hrl2
-rw-r--r--lib/ssh/src/ssh_connection.erl45
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl49
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.