aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2015-10-06 21:18:23 +0200
committerHans Nilsson <[email protected]>2015-10-08 18:57:05 +0200
commit84df3d4d0278e21a36a453bfee94799f0df67c2a (patch)
treecb039b3147502dab3085d3021f60e9e6378598b0 /lib/ssh/src
parenta2c538dee3013bb6285027d9ae45b7f055e8e8eb (diff)
downloadotp-84df3d4d0278e21a36a453bfee94799f0df67c2a.tar.gz
otp-84df3d4d0278e21a36a453bfee94799f0df67c2a.tar.bz2
otp-84df3d4d0278e21a36a453bfee94799f0df67c2a.zip
ssh: Option max_channels added.
It actually counts the number of subsystem alive. Allocating a channel does not consume any resources (except some cpu cycles), but the subsystem start spawns processes.
Diffstat (limited to 'lib/ssh/src')
-rw-r--r--lib/ssh/src/ssh.erl4
-rw-r--r--lib/ssh/src/ssh_connection.erl27
2 files changed, 25 insertions, 6 deletions
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 132de71aed..ee44324c12 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -385,6 +385,8 @@ handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{max_sessions, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{max_channels, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
@@ -443,6 +445,8 @@ handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value
Opt;
handle_ssh_option({max_sessions, Value} = Opt) when is_integer(Value), Value>0 ->
Opt;
+handle_ssh_option({max_channels, Value} = Opt) when is_integer(Value), Value>0 ->
+ Opt;
handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 64d2113125..266c64fd4f 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -935,14 +935,27 @@ encode_ip(Addr) when is_list(Addr) ->
end
end.
-start_channel(Cb, Id, Args, SubSysSup) ->
- start_channel(Cb, Id, Args, SubSysSup, undefined).
+start_channel(Cb, Id, Args, SubSysSup, Opts) ->
+ start_channel(Cb, Id, Args, SubSysSup, undefined, Opts).
-start_channel(Cb, Id, Args, SubSysSup, Exec) ->
+start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) ->
ChildSpec = child_spec(Cb, Id, Args, Exec),
ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup),
+ assert_limit_num_channels_not_exceeded(ChannelSup, Opts),
ssh_channel_sup:start_child(ChannelSup, ChildSpec).
+assert_limit_num_channels_not_exceeded(ChannelSup, Opts) ->
+ MaxNumChannels = proplists:get_value(max_channels, Opts, infinity),
+ NumChannels = length([x || {_,_,worker,[ssh_channel]} <-
+ supervisor:which_children(ChannelSup)]),
+ if
+ %% Note that NumChannels is BEFORE starting a new one
+ NumChannels < MaxNumChannels ->
+ ok;
+ true ->
+ throw(max_num_channels_exceeded)
+ end.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -998,9 +1011,11 @@ child_spec(Callback, Id, Args, Exec) ->
start_cli(#connection{cli_spec = no_cli}, _) ->
{error, cli_disabled};
-start_cli(#connection{cli_spec = {CbModule, Args}, exec = Exec,
+start_cli(#connection{options = Options,
+ cli_spec = {CbModule, Args},
+ exec = Exec,
sub_system_supervisor = SubSysSup}, ChannelId) ->
- start_channel(CbModule, ChannelId, Args, SubSysSup, Exec).
+ start_channel(CbModule, ChannelId, Args, SubSysSup, Exec, Options).
start_subsytem(BinName, #connection{options = Options,
sub_system_supervisor = SubSysSup},
@@ -1008,7 +1023,7 @@ start_subsytem(BinName, #connection{options = Options,
Name = binary_to_list(BinName),
case check_subsystem(Name, Options) of
{Callback, Opts} when is_atom(Callback), Callback =/= none ->
- start_channel(Callback, ChannelId, Opts, SubSysSup);
+ start_channel(Callback, ChannelId, Opts, SubSysSup, Options);
{Other, _} when Other =/= none ->
{error, legacy_option_not_supported}
end.