1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%
22%%----------------------------------------------------------------------
23%% Purpose: Ssh channel supervisor.
24%%----------------------------------------------------------------------
25-module(ssh_channel_sup).
26
27-behaviour(supervisor).
28-include("ssh.hrl").
29
30-export([start_link/1, start_child/8]).
31
32%% Supervisor callback
33-export([init/1]).
34
35%%%=========================================================================
36%%%  Internal API
37%%%=========================================================================
38start_link(Args) ->
39    supervisor:start_link(?MODULE, [Args]).
40
41
42start_child(client, ChannelSup, ConnRef, Callback, Id, Args, Exec, _Opts) when is_pid(ConnRef) ->
43    start_the_child(ssh_client_channel, ChannelSup, ConnRef, Callback, Id, Args, Exec);
44start_child(server, ChannelSup, ConnRef, Callback, Id, Args, Exec, Opts) when is_pid(ConnRef) ->
45     case max_num_channels_not_exceeded(ChannelSup, Opts) of
46         true ->
47             start_the_child(ssh_server_channel, ChannelSup, ConnRef, Callback, Id, Args, Exec);
48         false ->
49             {error, max_num_channels_exceeded}
50    end.
51
52
53start_the_child(ChanMod, ChannelSup, ConnRef, Callback, Id, Args, Exec) ->
54    ChildSpec =
55        #{id       => make_ref(),
56          start    => {ChanMod, start_link, [ConnRef, Id, Callback, Args, Exec]},
57          restart  => temporary,
58          type     => worker,
59          modules  => [ChanMod]
60         },
61    case supervisor:start_child(ChannelSup, ChildSpec) of
62        {ok, Pid} ->
63            {ok, Pid};
64        {ok, Pid, _Info} ->
65            {ok,Pid};
66        {error, {Error,_Info}} ->
67            {error, Error};
68        {error, Error} ->
69            {error, Error}
70    end.
71
72%%%=========================================================================
73%%%  Supervisor callback
74%%%=========================================================================
75init(_Args) ->
76    RestartStrategy = one_for_one,
77    MaxR = 10,
78    MaxT = 3600,
79    Children = [],
80    {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
81
82%%%=========================================================================
83%%%  Internal functions
84%%%=========================================================================
85max_num_channels_not_exceeded(ChannelSup, Opts) ->
86    MaxNumChannels = ?GET_OPT(max_channels, Opts),
87    NumChannels = length([x || {_,_,worker,[ssh_server_channel]} <-
88				   supervisor:which_children(ChannelSup)]),
89    %% Note that NumChannels is BEFORE starting a new one
90    NumChannels < MaxNumChannels.
91