From 867e9db15f3d3e5e430e3adda577364e455b9dac Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 25 Apr 2018 15:31:55 +0200 Subject: ssh: Create doc for the ssh_daemon_channel behaviour --- lib/ssh/doc/src/Makefile | 1 + lib/ssh/doc/src/ref_man.xml | 1 + lib/ssh/doc/src/specs.xml | 1 + lib/ssh/doc/src/ssh.xml | 7 +- lib/ssh/doc/src/ssh_channel.xml | 49 ++++++---- lib/ssh/doc/src/ssh_daemon_channel.xml | 169 +++++++++++++++++++++++++++++++++ lib/ssh/doc/src/ssh_protocol.xml | 6 +- lib/ssh/doc/src/ssh_sftpd.xml | 3 +- 8 files changed, 210 insertions(+), 27 deletions(-) create mode 100644 lib/ssh/doc/src/ssh_daemon_channel.xml diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile index 0063484f72..f47a1bfb40 100644 --- a/lib/ssh/doc/src/Makefile +++ b/lib/ssh/doc/src/Makefile @@ -40,6 +40,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) XML_APPLICATION_FILES = ref_man.xml XML_REF3_FILES = ssh.xml \ ssh_channel.xml \ + ssh_daemon_channel.xml \ ssh_connection.xml \ ssh_client_key_api.xml \ ssh_server_key_api.xml \ diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml index 140ebd8c76..1e1cff9119 100644 --- a/lib/ssh/doc/src/ref_man.xml +++ b/lib/ssh/doc/src/ref_man.xml @@ -36,6 +36,7 @@ + diff --git a/lib/ssh/doc/src/specs.xml b/lib/ssh/doc/src/specs.xml index 3ab4f43aec..f7837f9c5c 100644 --- a/lib/ssh/doc/src/specs.xml +++ b/lib/ssh/doc/src/specs.xml @@ -1,6 +1,7 @@ + diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 03078cfd83..c403989ba9 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -68,8 +68,8 @@ ssh_sftp:start_channel/1,2,3.

To write your own client channel handler, use the behaviour - ssh_channel. For own server channel handlers use the ssh_daemon_channel - behaviour: see the note in ssh_channel. + ssh_channel. and server channel handlers use + ssh_daemon_channel behaviour.

Both clients and daemons accepts options that controls the exact behaviour. Some options are common to both. The three sets are called @@ -378,7 +378,8 @@

The subsystem_name is the name that a client requests to start with for example ssh_connection:subsystem/4.

-

The channel_callback is the module that implements the ssh_daemon_channel +

The channel_callback is the module that implements the + ssh_daemon_channel behaviour in the daemon. See the section Creating a Subsystem in the User's Guide for more information and an example. diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml index 0355f7bf52..2ee6ab566b 100644 --- a/lib/ssh/doc/src/ssh_channel.xml +++ b/lib/ssh/doc/src/ssh_channel.xml @@ -37,7 +37,7 @@ that are multiplexed over an SSH connection and communicates over the SSH Connection Protocol. This module provides a callback API - that takes care of generic channel aspects, such as flow control + that takes care of generic channel aspects for clients, such as flow control and close messages. It lets the callback functions take care of the service (application) specific parts. This behavior also ensures that the channel process honors the principal of an OTP-process so @@ -46,14 +46,17 @@ the ssh applications supervisor tree.

- -

When implementing an ssh subsystem, use - -behaviour(ssh_daemon_channel) instead of -behaviour(ssh_channel). - The reason is that the only relevant callback functions for subsystems are - init/1, handle_ssh_msg/2, handle_msg/2, and terminate/2. - So, the ssh_daemon_channel behaviour is a limited version of the - ssh_channel behaviour. -

+

When implementing a ssh subsystem for daemons, use + -behaviour(ssh_daemon_channel) instead. +

+
+ + +

Functions in this module are not supposed to be called outside a module implementing this + behaviour! +

+
+ @@ -100,7 +103,7 @@ - + enter_loop(State) -> _ Makes an existing process an ssh_channel process. @@ -217,13 +220,19 @@
- - CALLBACK TIME-OUTS - -

The time-out values that can be returned by the callback functions - have the same semantics as in a gen_server. - If the time-out occurs, handle_msg/2 - is called as handle_msg(timeout, State).

+ Callback Functions +

+ The following functions are to be exported from a + ssh_daemon_channel callback module. +

+
+ + Callback timeouts +

The timeout values that can be returned by the callback functions + have the same semantics as in a gen_server. + If the time-out occurs, handle_msg/2 + is called as handle_msg(timeout, State).

+
@@ -286,7 +295,7 @@ state if the initializations succeed.

For more detailed information on time-outs, see Section - CALLBACK TIME-OUTS.

+ Callback timeouts.

@@ -313,7 +322,7 @@ call/[2,3]

For more detailed information on time-outs,, see Section - CALLBACK TIME-OUTS.

+ Callback timeouts.

@@ -334,7 +343,7 @@ cast/2.

For more detailed information on time-outs, see Section - CALLBACK TIME-OUTS.

+ Callback timeouts.

diff --git a/lib/ssh/doc/src/ssh_daemon_channel.xml b/lib/ssh/doc/src/ssh_daemon_channel.xml new file mode 100644 index 0000000000..8b0ff93f5f --- /dev/null +++ b/lib/ssh/doc/src/ssh_daemon_channel.xml @@ -0,0 +1,169 @@ + + + + +
+ + 2009 + 2016 + Ericsson AB, All Rights Reserved + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + ssh_daemon_channel + + + + +
+ ssh_daemon_channel + -behaviour(ssh_daemon_channel). + + +

SSH services (clients and servers) are implemented as channels + that are multiplexed over an SSH connection and communicates over + the SSH + Connection Protocol. This module provides a callback API + that takes care of generic channel aspects for daemons, such as flow control + and close messages. It lets the callback functions take care of + the service (application) specific parts. This behavior also ensures + that the channel process honors the principal of an OTP-process so + that it can be part of a supervisor tree. This is a requirement of + channel processes implementing a subsystem that will be added to + the ssh applications supervisor tree. +

+ +

When implementing a client subsystem handler, use + -behaviour(ssh_channel) instead. +

+
+ +
+ +
+ Callback Functions +

+ The following functions are to be exported from a + ssh_daemon_channel callback module. +

+
+ + + + Module:init(Args) -> {ok, State} | {ok, State, timeout()} | + {stop, Reason} + Makes necessary initializations and returns the + initial channel state if the initializations succeed. + + Args = term() + Last argument to start_link/4. + State = term() + Reason = term() + + +

Makes necessary initializations and returns the initial channel + state if the initializations succeed. +

+

The time-out values that can be returned + have the same semantics as in a gen_server. + If the time-out occurs, handle_msg/2 + is called as handle_msg(timeout, State). +

+
+
+ + + Module:handle_msg(Msg, State) -> {ok, State} | + {stop, ChannelId, State} + + Handles other messages than SSH connection protocol, + call, or cast messages sent to the channel. + + Msg = timeout | term() + ChannelId = ssh:channel_id() + State = term() + + +

Handles other messages than SSH Connection Protocol, call, or + cast messages sent to the channel. +

+ +

Possible Erlang 'EXIT' messages is to be handled by this + function and all channels are to handle the following message.

+ + + {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} +

This is the first message that the channel receives. + This is especially useful if the + server wants to send a message to the client without first + receiving a message from it. If the message is not + useful for your particular scenario, ignore it by + immediately returning {ok, State}. +

+
+
+
+ + + Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + ChannelId, State} + Handles ssh connection protocol messages. + + Msg = ssh_connection:event() + ChannelId = ssh:channel_id() + State = term() + + +

Handles SSH Connection Protocol messages that may need + service-specific attention. For details, + see ssh_connection:event(). +

+ +

The following message is taken care of by the + ssh_daemon_channel behavior.

+ + + {closed, ssh:channel_id()} +

The channel behavior sends a close message to the + other side, if such a message has not already been sent. + Then it terminates the channel with reason normal.

+
+
+
+ + + Module:terminate(Reason, State) -> _ + Does cleaning up before channel process termination. + + + Reason = term() + State = term() + + +

This function is called by a channel process when it is + about to terminate. Before this function is called, ssh_connection:close/2 + is called, if it has not been called earlier. + This function does any necessary cleaning + up. When it returns, the channel process terminates with + reason Reason. The return value is ignored. +

+
+
+ +
+ +
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml index a0032ab449..21c755b48e 100644 --- a/lib/ssh/doc/src/ssh_protocol.xml +++ b/lib/ssh/doc/src/ssh_protocol.xml @@ -87,8 +87,10 @@ connection, and all channels are flow-controlled. Typically an SSH client will open a channel, send data/commands, receive data/"control information" and when it is done close the - channel. The ssh_channel behaviour makes it easy to + channel. The + ssh_channel / + ssh_daemon_channel + behaviours makes it easy to write your own SSH client/server processes that use flow control. It handles generic parts of SSH channel management and lets you focus on the application logic. diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index 1be29b3b29..4c599a7fb9 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -44,8 +44,7 @@

"sftp"

channel_callback() =

atom() - Name of the Erlang module implementing the subsystem using the - ssh_channel behavior, see the - ssh_channel(3) manual page.

+ ssh_daemon_channel behaviour.

channel_init_args() =

list() - The one given as argument to function subsystem_spec/1.

-- cgit v1.2.3 From 8b50978cdc82d404f68384e1aadf7685a9d86af4 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 25 Apr 2018 15:51:03 +0200 Subject: ssh: Use ssh_daemon_channel_sup and ssh_damon_channel --- lib/ssh/doc/src/ssh_channel.xml | 2 +- lib/ssh/src/Makefile | 4 +-- lib/ssh/src/ssh.app.src | 2 +- lib/ssh/src/ssh_channel_sup.erl | 62 ---------------------------------- lib/ssh/src/ssh_cli.erl | 4 +-- lib/ssh/src/ssh_connection.erl | 4 +-- lib/ssh/src/ssh_daemon_channel.erl | 29 ++++------------ lib/ssh/src/ssh_daemon_channel_sup.erl | 62 ++++++++++++++++++++++++++++++++++ lib/ssh/src/ssh_info.erl | 8 ++--- lib/ssh/src/ssh_shell.erl | 4 +-- lib/ssh/src/ssh_subsystem_sup.erl | 12 +++---- lib/ssh/test/ssh_sup_SUITE.erl | 12 +++---- 12 files changed, 95 insertions(+), 110 deletions(-) delete mode 100644 lib/ssh/src/ssh_channel_sup.erl create mode 100644 lib/ssh/src/ssh_daemon_channel_sup.erl diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml index 2ee6ab566b..b4bcd148f3 100644 --- a/lib/ssh/doc/src/ssh_channel.xml +++ b/lib/ssh/doc/src/ssh_channel.xml @@ -225,8 +225,8 @@ The following functions are to be exported from a ssh_daemon_channel callback module.

+
- Callback timeouts

The timeout values that can be returned by the callback functions have the same semantics as in a gen_server. diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index bcd13213b3..a2cefe7c15 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -59,7 +59,7 @@ MODULES= \ ssh_shell \ ssh_system_sup \ ssh_subsystem_sup \ - ssh_channel_sup \ + ssh_daemon_channel_sup \ ssh_acceptor_sup \ ssh_acceptor \ ssh_app \ @@ -169,7 +169,7 @@ $(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \ $(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl $(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl $(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl -$(EBIN)/ssh_channel_sup.$(EMULATOR): ssh_channel_sup.erl +$(EBIN)/ssh_daemon_channel_sup.$(EMULATOR): ssh_daemon_channel_sup.erl $(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl $(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl $(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index 4a22322333..b935ea94d5 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -14,7 +14,7 @@ ssh_cli, ssh_client_key_api, ssh_channel, - ssh_channel_sup, + ssh_daemon_channel_sup, ssh_connection, ssh_connection_handler, ssh_connection_sup, diff --git a/lib/ssh/src/ssh_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl deleted file mode 100644 index 7a12f34049..0000000000 --- a/lib/ssh/src/ssh_channel_sup.erl +++ /dev/null @@ -1,62 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Ssh channel supervisor. -%%---------------------------------------------------------------------- --module(ssh_channel_sup). - --behaviour(supervisor). - --export([start_link/1, start_child/5]). - -%% Supervisor callback --export([init/1]). - -%%%========================================================================= -%%% Internal API -%%%========================================================================= -start_link(Args) -> - supervisor:start_link(?MODULE, [Args]). - -start_child(Sup, Callback, Id, Args, Exec) -> - ChildSpec = - #{id => make_ref(), - start => {ssh_channel, start_link, [self(), Id, Callback, Args, Exec]}, - restart => temporary, - type => worker, - modules => [ssh_channel] - }, - supervisor:start_child(Sup, ChildSpec). - -%%%========================================================================= -%%% Supervisor callback -%%%========================================================================= -init(_Args) -> - RestartStrategy = one_for_one, - MaxR = 10, - MaxT = 3600, - Children = [], - {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. - -%%%========================================================================= -%%% Internal functions -%%%========================================================================= diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index 382de90ae1..31f6194bf9 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -30,7 +30,7 @@ -include("ssh.hrl"). -include("ssh_connect.hrl"). -%% ssh_channel callbacks +%% ssh_daemon_channel callbacks -export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]). -export([dbg_trace/3]). @@ -47,7 +47,7 @@ }). %%==================================================================== -%% ssh_channel callbacks +%% ssh_daemon_channel callbacks %%==================================================================== %%-------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 2261d37d6a..0a07ea778d 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -822,14 +822,14 @@ start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) -> ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup), case max_num_channels_not_exceeded(ChannelSup, Opts) of true -> - ssh_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec); + ssh_daemon_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec); false -> throw(max_num_channels_exceeded) end. max_num_channels_not_exceeded(ChannelSup, Opts) -> MaxNumChannels = ?GET_OPT(max_channels, Opts), - NumChannels = length([x || {_,_,worker,[ssh_channel]} <- + NumChannels = length([x || {_,_,worker,[ssh_daemon_channel]} <- supervisor:which_children(ChannelSup)]), %% Note that NumChannels is BEFORE starting a new one NumChannels < MaxNumChannels. diff --git a/lib/ssh/src/ssh_daemon_channel.erl b/lib/ssh/src/ssh_daemon_channel.erl index 72853f2d6a..e1d6906bbc 100644 --- a/lib/ssh/src/ssh_daemon_channel.erl +++ b/lib/ssh/src/ssh_daemon_channel.erl @@ -25,7 +25,7 @@ -module(ssh_daemon_channel). -%% API to special server side channel that can be pluged into the erlang ssh daemeon +%% API to server side channel that can be pluged into the erlang ssh daemeon -callback init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | {stop, Reason :: term()} | ignore. @@ -42,29 +42,14 @@ {stop, ChannelId::ssh:channel_id(), State::term()}. -%%% API --export([start/4, start/5, start_link/4, start_link/5, enter_loop/1]). - -%% gen_server callbacks --export([init/1, terminate/2]). - --spec start(ssh:connection_ref(), ssh:channel_id(), atom(), term()) -> term(). -start(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> - ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). - -start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> - ssh_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). - -start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> - ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). +%%% Internal API +-export([start_link/5, + get_print_info/1 + ]). start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). -enter_loop(State) -> - ssh_channel:enter_loop(State). -init(Args) -> - ssh_channel:init(Args). -terminate(Reason, State) -> - ssh_channel:terminate(Reason, State). +get_print_info(Pid) -> + ssh_channel:get_print_info(Pid). diff --git a/lib/ssh/src/ssh_daemon_channel_sup.erl b/lib/ssh/src/ssh_daemon_channel_sup.erl new file mode 100644 index 0000000000..cd86347501 --- /dev/null +++ b/lib/ssh/src/ssh_daemon_channel_sup.erl @@ -0,0 +1,62 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Ssh channel supervisor. +%%---------------------------------------------------------------------- +-module(ssh_daemon_channel_sup). + +-behaviour(supervisor). + +-export([start_link/1, start_child/5]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% Internal API +%%%========================================================================= +start_link(Args) -> + supervisor:start_link(?MODULE, [Args]). + +start_child(Sup, Callback, Id, Args, Exec) -> + ChildSpec = + #{id => make_ref(), + start => {ssh_daemon_channel, start_link, [self(), Id, Callback, Args, Exec]}, + restart => temporary, + type => worker, + modules => [ssh_daemon_channel] + }, + supervisor:start_child(Sup, ChildSpec). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init(_Args) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Children = [], + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl index d464def6fa..e1613f0599 100644 --- a/lib/ssh/src/ssh_info.erl +++ b/lib/ssh/src/ssh_info.erl @@ -140,15 +140,15 @@ print_system_sup({{ssh_acceptor_sup,_LocalHost,_LocalPort,_Profile}, Pid, superv -print_channels({{server,ssh_channel_sup,_,_},Pid,supervisor,[ssh_channel_sup]}) when is_pid(Pid) -> +print_channels({{server,ssh_daemon_channel_sup,_,_},Pid,supervisor,[ssh_daemon_channel_sup]}) when is_pid(Pid) -> Children = supervisor:which_children(Pid), - ChannelPids = [P || {R,P,worker,[ssh_channel]} <- Children, + ChannelPids = [P || {R,P,worker,[ssh_daemon_channel]} <- Children, is_pid(P), is_reference(R)], case ChannelPids of [] -> io_lib:format(?INDENT?INDENT"No channels~n",[]); [Ch1Pid|_] -> - {{ConnManager,_}, _Str} = ssh_channel:get_print_info(Ch1Pid), + {{ConnManager,_}, _Str} = ssh_daemon_channel:get_print_info(Ch1Pid), {{_,Remote},_} = ssh_connection_handler:get_print_info(ConnManager), [io_lib:format(?INDENT?INDENT"Remote: ~s ConnectionRef = ~p~n",[fmt_host_port(Remote),ConnManager]), lists:map(fun print_ch/1, ChannelPids) @@ -159,7 +159,7 @@ print_channels({{server,ssh_connection_sup,_,_},Pid,supervisor,[ssh_connection_s print_ch(Pid) -> try - {{ConnManager,ChannelID}, Str} = ssh_channel:get_print_info(Pid), + {{ConnManager,ChannelID}, Str} = ssh_daemon_channel:get_print_info(Pid), {_LocalRemote,StrM} = ssh_connection_handler:get_print_info(ConnManager), io_lib:format(?INDENT?INDENT?INDENT"ch ~p ~p: ~s ~s~n",[ChannelID, Pid, StrM, Str]) catch diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl index c7c63c5c43..6470f4c492 100644 --- a/lib/ssh/src/ssh_shell.erl +++ b/lib/ssh/src/ssh_shell.erl @@ -29,7 +29,7 @@ %%% channel inspite of it being a client. -behaviour(ssh_daemon_channel). -%% ssh_channel callbacks +%% ssh_daemon_channel callbacks -export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). %% Spawn export @@ -46,7 +46,7 @@ ). %%==================================================================== -%% ssh_channel callbacks +%% ssh_daemon_channel callbacks %%==================================================================== %%-------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl index 77da240a66..f1e74a24ac 100644 --- a/lib/ssh/src/ssh_subsystem_sup.erl +++ b/lib/ssh/src/ssh_subsystem_sup.erl @@ -48,7 +48,7 @@ connection_supervisor(SupPid) -> channel_supervisor(SupPid) -> Children = supervisor:which_children(SupPid), - ssh_channel_sup(Children). + ssh_daemon_channel_sup(Children). %%%========================================================================= %%% Supervisor callback @@ -78,8 +78,8 @@ ssh_connection_child_spec(Role, Address, Port, _Profile, Options) -> }. ssh_channel_child_spec(Role, Address, Port, _Profile, Options) -> - #{id => id(Role, ssh_channel_sup, Address, Port), - start => {ssh_channel_sup, start_link, [Options]}, + #{id => id(Role, ssh_daemon_channel_sup, Address, Port), + start => {ssh_daemon_channel_sup, start_link, [Options]}, restart => temporary, type => supervisor }. @@ -92,10 +92,10 @@ ssh_connection_sup([{_, Child, _, [ssh_connection_sup]} | _]) -> ssh_connection_sup([_ | Rest]) -> ssh_connection_sup(Rest). -ssh_channel_sup([{_, Child, _, [ssh_channel_sup]} | _]) -> +ssh_daemon_channel_sup([{_, Child, _, [ssh_daemon_channel_sup]} | _]) -> Child; -ssh_channel_sup([_ | Rest]) -> - ssh_channel_sup(Rest). +ssh_daemon_channel_sup([_ | Rest]) -> + ssh_daemon_channel_sup(Rest). diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl index 4e7169d927..ed1840640b 100644 --- a/lib/ssh/test/ssh_sup_SUITE.erl +++ b/lib/ssh/test/ssh_sup_SUITE.erl @@ -290,7 +290,7 @@ shell_channel_tree(Config) -> {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), ok = ssh_connection:shell(ConnectionRef,ChannelId0), - ?wait_match([{_, GroupPid,worker,[ssh_channel]}], + ?wait_match([{_, GroupPid,worker,[ssh_daemon_channel]}], supervisor:which_children(ChannelSup), [GroupPid]), {links,GroupLinks} = erlang:process_info(GroupPid, links), @@ -339,9 +339,9 @@ chk_empty_con_daemon(Daemon) -> ?wait_match([{{server,ssh_connection_sup, _,_}, ConnectionSup, supervisor, [ssh_connection_sup]}, - {{server,ssh_channel_sup,_ ,_}, + {{server,ssh_daemon_channel_sup,_ ,_}, ChannelSup,supervisor, - [ssh_channel_sup]}], + [ssh_daemon_channel_sup]}], supervisor:which_children(SubSysSup), [ConnectionSup,ChannelSup]), ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}], @@ -372,9 +372,9 @@ check_sshd_system_tree(Daemon, Config) -> ?wait_match([{{server,ssh_connection_sup, _,_}, ConnectionSup, supervisor, [ssh_connection_sup]}, - {{server,ssh_channel_sup,_ ,_}, + {{server,ssh_daemon_channel_sup,_ ,_}, ChannelSup,supervisor, - [ssh_channel_sup]}], + [ssh_daemon_channel_sup]}], supervisor:which_children(SubSysSup), [ConnectionSup,ChannelSup]), @@ -388,7 +388,7 @@ check_sshd_system_tree(Daemon, Config) -> ssh_sftp:start_channel(Client), - ?wait_match([{_, _,worker,[ssh_channel]}], + ?wait_match([{_, _,worker,[ssh_daemon_channel]}], supervisor:which_children(ChannelSup)), ssh:close(Client). -- cgit v1.2.3 From d2f4de0a8e36e6a25cfd7446ea6fc3623b7f1495 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 26 Apr 2018 11:50:11 +0200 Subject: ssh: ssh_daemon_channel replaced by ssh_server_channel --- lib/ssh/doc/src/Makefile | 15 ++- lib/ssh/doc/src/ref_man.xml | 3 +- lib/ssh/doc/src/specs.xml | 7 +- lib/ssh/doc/src/ssh.xml | 6 +- lib/ssh/doc/src/ssh_channel.xml | 5 +- lib/ssh/doc/src/ssh_daemon_channel.xml | 127 +------------------ lib/ssh/doc/src/ssh_protocol.xml | 2 +- lib/ssh/doc/src/ssh_server_channel.xml | 176 ++++++++++++++++++++++++++ lib/ssh/doc/src/ssh_sftpd.xml | 2 +- lib/ssh/doc/src/using_ssh.xml | 2 +- lib/ssh/src/Makefile | 42 +++--- lib/ssh/src/ssh.app.src | 3 +- lib/ssh/src/ssh_cli.erl | 6 +- lib/ssh/src/ssh_connection.erl | 4 +- lib/ssh/src/ssh_daemon_channel.erl | 4 +- lib/ssh/src/ssh_daemon_channel_sup.erl | 62 --------- lib/ssh/src/ssh_info.erl | 8 +- lib/ssh/src/ssh_server_channel.erl | 55 ++++++++ lib/ssh/src/ssh_server_channel_sup.erl | 62 +++++++++ lib/ssh/src/ssh_sftpd.erl | 2 +- lib/ssh/src/ssh_shell.erl | 6 +- lib/ssh/src/ssh_subsystem_sup.erl | 12 +- lib/ssh/test/property_test/ssh_eqc_subsys.erl | 2 +- lib/ssh/test/ssh_bench_dev_null.erl | 2 +- lib/ssh/test/ssh_echo_server.erl | 2 +- lib/ssh/test/ssh_peername_sockname_server.erl | 2 +- lib/ssh/test/ssh_sup_SUITE.erl | 12 +- 27 files changed, 377 insertions(+), 254 deletions(-) create mode 100644 lib/ssh/doc/src/ssh_server_channel.xml delete mode 100644 lib/ssh/src/ssh_daemon_channel_sup.erl create mode 100644 lib/ssh/src/ssh_server_channel.erl create mode 100644 lib/ssh/src/ssh_server_channel_sup.erl diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile index f47a1bfb40..9b5bee34fa 100644 --- a/lib/ssh/doc/src/Makefile +++ b/lib/ssh/doc/src/Makefile @@ -38,20 +38,23 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = ref_man.xml -XML_REF3_FILES = ssh.xml \ +XML_REF3_FILES = \ + ssh.xml \ ssh_channel.xml \ - ssh_daemon_channel.xml \ - ssh_connection.xml \ ssh_client_key_api.xml \ + ssh_connection.xml \ + ssh_daemon_channel.xml \ + ssh_server_channel.xml \ ssh_server_key_api.xml \ ssh_sftp.xml \ ssh_sftpd.xml \ XML_REF6_FILES = ssh_app.xml -XML_PART_FILES = \ - usersguide.xml -XML_CHAPTER_FILES = notes.xml \ +XML_PART_FILES = usersguide.xml + +XML_CHAPTER_FILES = \ + notes.xml \ introduction.xml \ using_ssh.xml \ configure_algos.xml diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml index 1e1cff9119..3351699c66 100644 --- a/lib/ssh/doc/src/ref_man.xml +++ b/lib/ssh/doc/src/ref_man.xml @@ -36,7 +36,8 @@ - + + diff --git a/lib/ssh/doc/src/specs.xml b/lib/ssh/doc/src/specs.xml index f7837f9c5c..15e76cb5fa 100644 --- a/lib/ssh/doc/src/specs.xml +++ b/lib/ssh/doc/src/specs.xml @@ -1,13 +1,14 @@ + - + + - - + diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index c403989ba9..da122b6081 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -68,8 +68,8 @@ ssh_sftp:start_channel/1,2,3.

To write your own client channel handler, use the behaviour - ssh_channel. and server channel handlers use - ssh_daemon_channel behaviour. + ssh_channel. For server channel handlers use + ssh_server_channel behaviour (replaces ssh_daemon_channel).

Both clients and daemons accepts options that controls the exact behaviour. Some options are common to both. The three sets are called @@ -379,7 +379,7 @@ ssh_connection:subsystem/4.

The channel_callback is the module that implements the - ssh_daemon_channel + ssh_server_channel (replaces ssh_daemon_channel) behaviour in the daemon. See the section Creating a Subsystem in the User's Guide for more information and an example. diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml index b4bcd148f3..63a480d747 100644 --- a/lib/ssh/doc/src/ssh_channel.xml +++ b/lib/ssh/doc/src/ssh_channel.xml @@ -47,7 +47,8 @@

When implementing a ssh subsystem for daemons, use - -behaviour(ssh_daemon_channel) instead. + -behaviour(ssh_server_channel) (Replaces ssh_daemon_channel) + instead.

@@ -223,7 +224,7 @@ Callback Functions

The following functions are to be exported from a - ssh_daemon_channel callback module. + ssh_channel callback module.

diff --git a/lib/ssh/doc/src/ssh_daemon_channel.xml b/lib/ssh/doc/src/ssh_daemon_channel.xml index 8b0ff93f5f..254f75a4de 100644 --- a/lib/ssh/doc/src/ssh_daemon_channel.xml +++ b/lib/ssh/doc/src/ssh_daemon_channel.xml @@ -33,137 +33,20 @@ -behaviour(ssh_daemon_channel). -

SSH services (clients and servers) are implemented as channels - that are multiplexed over an SSH connection and communicates over - the SSH - Connection Protocol. This module provides a callback API - that takes care of generic channel aspects for daemons, such as flow control - and close messages. It lets the callback functions take care of - the service (application) specific parts. This behavior also ensures - that the channel process honors the principal of an OTP-process so - that it can be part of a supervisor tree. This is a requirement of - channel processes implementing a subsystem that will be added to - the ssh applications supervisor tree. +

This behaviour should NOT be used for new programs but is kept for compatibility.

- -

When implementing a client subsystem handler, use - -behaviour(ssh_channel) instead. -

-
- +

It is replaced by ssh_server_channel.

-
- Callback Functions -

- The following functions are to be exported from a - ssh_daemon_channel callback module. -

-
- - Module:init(Args) -> {ok, State} | {ok, State, timeout()} | - {stop, Reason} - Makes necessary initializations and returns the - initial channel state if the initializations succeed. - - Args = term() - Last argument to start_link/4. - State = term() - Reason = term() - - -

Makes necessary initializations and returns the initial channel - state if the initializations succeed. -

-

The time-out values that can be returned - have the same semantics as in a gen_server. - If the time-out occurs, handle_msg/2 - is called as handle_msg(timeout, State). -

-
-
- - - Module:handle_msg(Msg, State) -> {ok, State} | - {stop, ChannelId, State} - - Handles other messages than SSH connection protocol, - call, or cast messages sent to the channel. - - Msg = timeout | term() - ChannelId = ssh:channel_id() - State = term() - - -

Handles other messages than SSH Connection Protocol, call, or - cast messages sent to the channel. -

- -

Possible Erlang 'EXIT' messages is to be handled by this - function and all channels are to handle the following message.

- - - {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} -

This is the first message that the channel receives. - This is especially useful if the - server wants to send a message to the client without first - receiving a message from it. If the message is not - useful for your particular scenario, ignore it by - immediately returning {ok, State}. -

-
-
-
- - - Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, - ChannelId, State} - Handles ssh connection protocol messages. - - Msg = ssh_connection:event() - ChannelId = ssh:channel_id() - State = term() - - -

Handles SSH Connection Protocol messages that may need - service-specific attention. For details, - see ssh_connection:event(). -

- -

The following message is taken care of by the - ssh_daemon_channel behavior.

- - - {closed, ssh:channel_id()} -

The channel behavior sends a close message to the - other side, if such a message has not already been sent. - Then it terminates the channel with reason normal.

-
-
-
- - - Module:terminate(Reason, State) -> _ - Does cleaning up before channel process termination. - - - Reason = term() - State = term() - + Module:CALLBACK(..) + ssh_daemon_channel is replaced by ssh_server_channel -

This function is called by a channel process when it is - about to terminate. Before this function is called, ssh_connection:close/2 - is called, if it has not been called earlier. - This function does any necessary cleaning - up. When it returns, the channel process terminates with - reason Reason. The return value is ignored. +

See ssh_server_channel which replaces this module.

-
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml index 21c755b48e..4548d7bbb6 100644 --- a/lib/ssh/doc/src/ssh_protocol.xml +++ b/lib/ssh/doc/src/ssh_protocol.xml @@ -89,7 +89,7 @@ data/"control information" and when it is done close the channel. The ssh_channel / - ssh_daemon_channel + ssh_server_channel (Replaces ssh_daemon_channel) behaviours makes it easy to write your own SSH client/server processes that use flow control. It handles generic parts of SSH channel management and diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml new file mode 100644 index 0000000000..19fc20fcda --- /dev/null +++ b/lib/ssh/doc/src/ssh_server_channel.xml @@ -0,0 +1,176 @@ + + + + +
+ + 2009 + 2016 + Ericsson AB, All Rights Reserved + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + ssh_server_channel + + + + +
+ ssh_server_channel + -behaviour(ssh_server_channel). (Replaces ssh_daemon_channel) + + + +

This module replaces ssh_daemon_channel.

+

The old module is still available for compatibility, but should not be used for new programs. + The old module will not be maintained except for some error corrections +

+
+ +

SSH services (clients and servers) are implemented as channels + that are multiplexed over an SSH connection and communicates over + the SSH + Connection Protocol. This module provides a callback API + that takes care of generic channel aspects for daemons, such as flow control + and close messages. It lets the callback functions take care of + the service (application) specific parts. This behavior also ensures + that the channel process honors the principal of an OTP-process so + that it can be part of a supervisor tree. This is a requirement of + channel processes implementing a subsystem that will be added to + the ssh applications supervisor tree. +

+ +

When implementing a client subsystem handler, use + -behaviour(ssh_channel) instead. +

+
+ +
+ +
+ Callback Functions +

+ The following functions are to be exported from a + ssh_server_channel callback module. +

+
+ + + + Module:init(Args) -> {ok, State} | {ok, State, timeout()} | + {stop, Reason} + Makes necessary initializations and returns the + initial channel state if the initializations succeed. + + Args = term() + Last argument to start_link/4. + State = term() + Reason = term() + + +

Makes necessary initializations and returns the initial channel + state if the initializations succeed. +

+

The time-out values that can be returned + have the same semantics as in a gen_server. + If the time-out occurs, handle_msg/2 + is called as handle_msg(timeout, State). +

+
+
+ + + Module:handle_msg(Msg, State) -> {ok, State} | + {stop, ChannelId, State} + + Handles other messages than SSH connection protocol, + call, or cast messages sent to the channel. + + Msg = timeout | term() + ChannelId = ssh:channel_id() + State = term() + + +

Handles other messages than SSH Connection Protocol, call, or + cast messages sent to the channel. +

+ +

Possible Erlang 'EXIT' messages is to be handled by this + function and all channels are to handle the following message.

+ + + {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} +

This is the first message that the channel receives. + This is especially useful if the + server wants to send a message to the client without first + receiving a message from it. If the message is not + useful for your particular scenario, ignore it by + immediately returning {ok, State}. +

+
+
+
+ + + Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + ChannelId, State} + Handles ssh connection protocol messages. + + Msg = ssh_connection:event() + ChannelId = ssh:channel_id() + State = term() + + +

Handles SSH Connection Protocol messages that may need + service-specific attention. For details, + see ssh_connection:event(). +

+ +

The following message is taken care of by the + ssh_server_channel behavior.

+ + + {closed, ssh:channel_id()} +

The channel behavior sends a close message to the + other side, if such a message has not already been sent. + Then it terminates the channel with reason normal.

+
+
+
+ + + Module:terminate(Reason, State) -> _ + Does cleaning up before channel process termination. + + + Reason = term() + State = term() + + +

This function is called by a channel process when it is + about to terminate. Before this function is called, ssh_connection:close/2 + is called, if it has not been called earlier. + This function does any necessary cleaning + up. When it returns, the channel process terminates with + reason Reason. The return value is ignored. +

+
+
+ +
+ +
diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index 4c599a7fb9..a25ce123b3 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -44,7 +44,7 @@

"sftp"

channel_callback() =

atom() - Name of the Erlang module implementing the subsystem using the - ssh_daemon_channel behaviour.

+ ssh_server_channel (replaces ssh_daemon_channel) behaviour.

channel_init_args() =

list() - The one given as argument to function subsystem_spec/1.

diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index bde2aaaf99..fef0784eb6 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -306,7 +306,7 @@ ok = erl_tar:close(HandleRead), -module(ssh_echo_server). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). % replaces ssh_daemon_channel -record(state, { n, id, diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index a2cefe7c15..1665e8b554 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -40,42 +40,43 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN) # Behaviour (api) modules are first so they are compiled when # the compiler reaches a callback module using them. BEHAVIOUR_MODULES= \ - ssh_sftpd_file_api \ - ssh_channel \ - ssh_daemon_channel \ ssh_client_key_api \ - ssh_server_key_api + ssh_daemon_channel \ + ssh_server_channel \ + ssh_server_key_api \ + ssh_sftpd_file_api \ + ssh_channel MODULES= \ ssh \ - ssh_sup \ - sshc_sup \ - sshd_sup \ - ssh_options \ - ssh_connection_sup \ - ssh_connection \ - ssh_connection_handler \ - ssh_dbg \ - ssh_shell \ - ssh_system_sup \ - ssh_subsystem_sup \ - ssh_daemon_channel_sup \ - ssh_acceptor_sup \ ssh_acceptor \ + ssh_acceptor_sup \ ssh_app \ ssh_auth\ ssh_bits \ ssh_cli \ + ssh_connection \ + ssh_connection_handler \ + ssh_connection_sup \ + ssh_dbg \ ssh_file \ - ssh_io \ ssh_info \ + ssh_io \ ssh_message \ ssh_no_io \ + ssh_options \ + ssh_server_channel_sup \ ssh_sftp \ ssh_sftpd \ ssh_sftpd_file\ + ssh_shell \ + ssh_subsystem_sup \ + ssh_sup \ + ssh_system_sup \ ssh_transport \ - ssh_xfer + ssh_xfer \ + sshc_sup \ + sshd_sup HRL_FILES = @@ -169,7 +170,7 @@ $(EBIN)/ssh_connection_handler.$(EMULATOR): ssh_connection_handler.erl ssh.hrl \ $(EBIN)/ssh_shell.$(EMULATOR): ssh_shell.erl ssh_connect.hrl $(EBIN)/ssh_system_sup.$(EMULATOR): ssh_system_sup.erl ssh.hrl $(EBIN)/ssh_subsystem_sup.$(EMULATOR): ssh_subsystem_sup.erl -$(EBIN)/ssh_daemon_channel_sup.$(EMULATOR): ssh_daemon_channel_sup.erl +$(EBIN)/ssh_server_channel_sup.$(EMULATOR): ssh_server_channel_sup.erl $(EBIN)/ssh_acceptor_sup.$(EMULATOR): ssh_acceptor_sup.erl ssh.hrl $(EBIN)/ssh_acceptor.$(EMULATOR): ssh_acceptor.erl ssh.hrl $(EBIN)/ssh_app.$(EMULATOR): ssh_app.erl @@ -210,6 +211,7 @@ $(EBIN)/ssh_xfer.$(EMULATOR): ssh_xfer.erl ssh.hrl ssh_xfer.hrl $(EBIN)/ssh_sftpd_file_api.$(EMULATOR): ssh_sftpd_file_api.erl $(EBIN)/ssh_channel.$(EMULATOR): ssh_channel.erl ssh_connect.hrl $(EBIN)/ssh_daemon_channel.$(EMULATOR): ssh_daemon_channel.erl +$(EBIN)/ssh_server_channel.$(EMULATOR): ssh_server_channel.erl $(EBIN)/ssh_client_key_api.$(EMULATOR): ssh_client_key_api.erl \ ../../public_key/include/public_key.hrl \ ../../public_key/include/OTP-PUB-KEY.hrl \ diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index b935ea94d5..897235e054 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -14,7 +14,6 @@ ssh_cli, ssh_client_key_api, ssh_channel, - ssh_daemon_channel_sup, ssh_connection, ssh_connection_handler, ssh_connection_sup, @@ -27,6 +26,8 @@ ssh_io, ssh_info, ssh_no_io, + ssh_server_channel, + ssh_server_channel_sup, ssh_server_key_api, ssh_sftp, ssh_sftpd, diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index 31f6194bf9..fcc1d3d59f 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -25,12 +25,12 @@ -module(ssh_cli). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -include("ssh.hrl"). -include("ssh_connect.hrl"). -%% ssh_daemon_channel callbacks +%% ssh_server_channel callbacks -export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]). -export([dbg_trace/3]). @@ -47,7 +47,7 @@ }). %%==================================================================== -%% ssh_daemon_channel callbacks +%% ssh_server_channel callbacks %%==================================================================== %%-------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 0a07ea778d..cff9ec3a61 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -822,14 +822,14 @@ start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) -> ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup), case max_num_channels_not_exceeded(ChannelSup, Opts) of true -> - ssh_daemon_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec); + ssh_server_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec); false -> throw(max_num_channels_exceeded) end. max_num_channels_not_exceeded(ChannelSup, Opts) -> MaxNumChannels = ?GET_OPT(max_channels, Opts), - NumChannels = length([x || {_,_,worker,[ssh_daemon_channel]} <- + NumChannels = length([x || {_,_,worker,[ssh_server_channel]} <- supervisor:which_children(ChannelSup)]), %% Note that NumChannels is BEFORE starting a new one NumChannels < MaxNumChannels. diff --git a/lib/ssh/src/ssh_daemon_channel.erl b/lib/ssh/src/ssh_daemon_channel.erl index e1d6906bbc..fdb6c10971 100644 --- a/lib/ssh/src/ssh_daemon_channel.erl +++ b/lib/ssh/src/ssh_daemon_channel.erl @@ -48,8 +48,8 @@ ]). start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> - ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). + ssh_server_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). get_print_info(Pid) -> - ssh_channel:get_print_info(Pid). + ssh_server_channel:get_print_info(Pid). diff --git a/lib/ssh/src/ssh_daemon_channel_sup.erl b/lib/ssh/src/ssh_daemon_channel_sup.erl deleted file mode 100644 index cd86347501..0000000000 --- a/lib/ssh/src/ssh_daemon_channel_sup.erl +++ /dev/null @@ -1,62 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2016. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - -%% -%%---------------------------------------------------------------------- -%% Purpose: Ssh channel supervisor. -%%---------------------------------------------------------------------- --module(ssh_daemon_channel_sup). - --behaviour(supervisor). - --export([start_link/1, start_child/5]). - -%% Supervisor callback --export([init/1]). - -%%%========================================================================= -%%% Internal API -%%%========================================================================= -start_link(Args) -> - supervisor:start_link(?MODULE, [Args]). - -start_child(Sup, Callback, Id, Args, Exec) -> - ChildSpec = - #{id => make_ref(), - start => {ssh_daemon_channel, start_link, [self(), Id, Callback, Args, Exec]}, - restart => temporary, - type => worker, - modules => [ssh_daemon_channel] - }, - supervisor:start_child(Sup, ChildSpec). - -%%%========================================================================= -%%% Supervisor callback -%%%========================================================================= -init(_Args) -> - RestartStrategy = one_for_one, - MaxR = 10, - MaxT = 3600, - Children = [], - {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. - -%%%========================================================================= -%%% Internal functions -%%%========================================================================= diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl index e1613f0599..ee244f1432 100644 --- a/lib/ssh/src/ssh_info.erl +++ b/lib/ssh/src/ssh_info.erl @@ -140,15 +140,15 @@ print_system_sup({{ssh_acceptor_sup,_LocalHost,_LocalPort,_Profile}, Pid, superv -print_channels({{server,ssh_daemon_channel_sup,_,_},Pid,supervisor,[ssh_daemon_channel_sup]}) when is_pid(Pid) -> +print_channels({{server,ssh_server_channel_sup,_,_},Pid,supervisor,[ssh_server_channel_sup]}) when is_pid(Pid) -> Children = supervisor:which_children(Pid), - ChannelPids = [P || {R,P,worker,[ssh_daemon_channel]} <- Children, + ChannelPids = [P || {R,P,worker,[ssh_server_channel]} <- Children, is_pid(P), is_reference(R)], case ChannelPids of [] -> io_lib:format(?INDENT?INDENT"No channels~n",[]); [Ch1Pid|_] -> - {{ConnManager,_}, _Str} = ssh_daemon_channel:get_print_info(Ch1Pid), + {{ConnManager,_}, _Str} = ssh_server_channel:get_print_info(Ch1Pid), {{_,Remote},_} = ssh_connection_handler:get_print_info(ConnManager), [io_lib:format(?INDENT?INDENT"Remote: ~s ConnectionRef = ~p~n",[fmt_host_port(Remote),ConnManager]), lists:map(fun print_ch/1, ChannelPids) @@ -159,7 +159,7 @@ print_channels({{server,ssh_connection_sup,_,_},Pid,supervisor,[ssh_connection_s print_ch(Pid) -> try - {{ConnManager,ChannelID}, Str} = ssh_daemon_channel:get_print_info(Pid), + {{ConnManager,ChannelID}, Str} = ssh_server_channel:get_print_info(Pid), {_LocalRemote,StrM} = ssh_connection_handler:get_print_info(ConnManager), io_lib:format(?INDENT?INDENT?INDENT"ch ~p ~p: ~s ~s~n",[ChannelID, Pid, StrM, Str]) catch diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl new file mode 100644 index 0000000000..117b7855e2 --- /dev/null +++ b/lib/ssh/src/ssh_server_channel.erl @@ -0,0 +1,55 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Description: a gen_server implementing a simple +%% terminal (using the group module) for a CLI +%% over SSH + +-module(ssh_server_channel). + +%% API to server side channel that can be pluged into the erlang ssh daemeon +-callback init(Args :: term()) -> + {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | + {stop, Reason :: term()} | ignore. + +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | + term()), + State :: term()) -> + term(). + +-callback handle_msg(Msg ::term(), State :: term()) -> + {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}. +-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()}, + State::term()) -> {ok, State::term()} | + {stop, ChannelId::ssh:channel_id(), + State::term()}. + +%%% Internal API +-export([start_link/5, + get_print_info/1 + ]). + +start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> + ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). + + +get_print_info(Pid) -> + ssh_channel:get_print_info(Pid). diff --git a/lib/ssh/src/ssh_server_channel_sup.erl b/lib/ssh/src/ssh_server_channel_sup.erl new file mode 100644 index 0000000000..70799db714 --- /dev/null +++ b/lib/ssh/src/ssh_server_channel_sup.erl @@ -0,0 +1,62 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Ssh channel supervisor. +%%---------------------------------------------------------------------- +-module(ssh_server_channel_sup). + +-behaviour(supervisor). + +-export([start_link/1, start_child/5]). + +%% Supervisor callback +-export([init/1]). + +%%%========================================================================= +%%% Internal API +%%%========================================================================= +start_link(Args) -> + supervisor:start_link(?MODULE, [Args]). + +start_child(Sup, Callback, Id, Args, Exec) -> + ChildSpec = + #{id => make_ref(), + start => {ssh_server_channel, start_link, [self(), Id, Callback, Args, Exec]}, + restart => temporary, + type => worker, + modules => [ssh_server_channel] + }, + supervisor:start_child(Sup, ChildSpec). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init(_Args) -> + RestartStrategy = one_for_one, + MaxR = 10, + MaxT = 3600, + Children = [], + {ok, {{RestartStrategy, MaxR, MaxT}, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index fda9a38a43..cb2eab1fec 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -24,7 +24,7 @@ -module(ssh_sftpd). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -include_lib("kernel/include/file.hrl"). diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl index 6470f4c492..084daa6821 100644 --- a/lib/ssh/src/ssh_shell.erl +++ b/lib/ssh/src/ssh_shell.erl @@ -27,9 +27,9 @@ %%% As this is an user interactive client it behaves like a daemon %%% channel inspite of it being a client. --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -%% ssh_daemon_channel callbacks +%% ssh_server_channel callbacks -export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). %% Spawn export @@ -46,7 +46,7 @@ ). %%==================================================================== -%% ssh_daemon_channel callbacks +%% ssh_server_channel callbacks %%==================================================================== %%-------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl index f1e74a24ac..f80be7f20b 100644 --- a/lib/ssh/src/ssh_subsystem_sup.erl +++ b/lib/ssh/src/ssh_subsystem_sup.erl @@ -48,7 +48,7 @@ connection_supervisor(SupPid) -> channel_supervisor(SupPid) -> Children = supervisor:which_children(SupPid), - ssh_daemon_channel_sup(Children). + ssh_server_channel_sup(Children). %%%========================================================================= %%% Supervisor callback @@ -78,8 +78,8 @@ ssh_connection_child_spec(Role, Address, Port, _Profile, Options) -> }. ssh_channel_child_spec(Role, Address, Port, _Profile, Options) -> - #{id => id(Role, ssh_daemon_channel_sup, Address, Port), - start => {ssh_daemon_channel_sup, start_link, [Options]}, + #{id => id(Role, ssh_server_channel_sup, Address, Port), + start => {ssh_server_channel_sup, start_link, [Options]}, restart => temporary, type => supervisor }. @@ -92,10 +92,10 @@ ssh_connection_sup([{_, Child, _, [ssh_connection_sup]} | _]) -> ssh_connection_sup([_ | Rest]) -> ssh_connection_sup(Rest). -ssh_daemon_channel_sup([{_, Child, _, [ssh_daemon_channel_sup]} | _]) -> +ssh_server_channel_sup([{_, Child, _, [ssh_server_channel_sup]} | _]) -> Child; -ssh_daemon_channel_sup([_ | Rest]) -> - ssh_daemon_channel_sup(Rest). +ssh_server_channel_sup([_ | Rest]) -> + ssh_server_channel_sup(Rest). diff --git a/lib/ssh/test/property_test/ssh_eqc_subsys.erl b/lib/ssh/test/property_test/ssh_eqc_subsys.erl index 30b254b9c0..e7de3ea068 100644 --- a/lib/ssh/test/property_test/ssh_eqc_subsys.erl +++ b/lib/ssh/test/property_test/ssh_eqc_subsys.erl @@ -21,7 +21,7 @@ -module(ssh_eqc_subsys). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). diff --git a/lib/ssh/test/ssh_bench_dev_null.erl b/lib/ssh/test/ssh_bench_dev_null.erl index 5166247714..f9da80b6d7 100644 --- a/lib/ssh/test/ssh_bench_dev_null.erl +++ b/lib/ssh/test/ssh_bench_dev_null.erl @@ -22,7 +22,7 @@ %%% Description: Example ssh server -module(ssh_bench_dev_null). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -record(state, { cm, diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl index 5387d21efd..d03fe9543e 100644 --- a/lib/ssh/test/ssh_echo_server.erl +++ b/lib/ssh/test/ssh_echo_server.erl @@ -22,7 +22,7 @@ %%% Description: Example ssh server -module(ssh_echo_server). --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -record(state, { n, id, diff --git a/lib/ssh/test/ssh_peername_sockname_server.erl b/lib/ssh/test/ssh_peername_sockname_server.erl index 8731d80f62..5e35fd6612 100644 --- a/lib/ssh/test/ssh_peername_sockname_server.erl +++ b/lib/ssh/test/ssh_peername_sockname_server.erl @@ -26,7 +26,7 @@ %% ssh connection. --behaviour(ssh_daemon_channel). +-behaviour(ssh_server_channel). -record(state, {}). -export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]). diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl index ed1840640b..b81f66948d 100644 --- a/lib/ssh/test/ssh_sup_SUITE.erl +++ b/lib/ssh/test/ssh_sup_SUITE.erl @@ -290,7 +290,7 @@ shell_channel_tree(Config) -> {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), ok = ssh_connection:shell(ConnectionRef,ChannelId0), - ?wait_match([{_, GroupPid,worker,[ssh_daemon_channel]}], + ?wait_match([{_, GroupPid,worker,[ssh_server_channel]}], supervisor:which_children(ChannelSup), [GroupPid]), {links,GroupLinks} = erlang:process_info(GroupPid, links), @@ -339,9 +339,9 @@ chk_empty_con_daemon(Daemon) -> ?wait_match([{{server,ssh_connection_sup, _,_}, ConnectionSup, supervisor, [ssh_connection_sup]}, - {{server,ssh_daemon_channel_sup,_ ,_}, + {{server,ssh_server_channel_sup,_ ,_}, ChannelSup,supervisor, - [ssh_daemon_channel_sup]}], + [ssh_server_channel_sup]}], supervisor:which_children(SubSysSup), [ConnectionSup,ChannelSup]), ?wait_match([{{ssh_acceptor_sup,_,_,_},_,worker,[ssh_acceptor]}], @@ -372,9 +372,9 @@ check_sshd_system_tree(Daemon, Config) -> ?wait_match([{{server,ssh_connection_sup, _,_}, ConnectionSup, supervisor, [ssh_connection_sup]}, - {{server,ssh_daemon_channel_sup,_ ,_}, + {{server,ssh_server_channel_sup,_ ,_}, ChannelSup,supervisor, - [ssh_daemon_channel_sup]}], + [ssh_server_channel_sup]}], supervisor:which_children(SubSysSup), [ConnectionSup,ChannelSup]), @@ -388,7 +388,7 @@ check_sshd_system_tree(Daemon, Config) -> ssh_sftp:start_channel(Client), - ?wait_match([{_, _,worker,[ssh_daemon_channel]}], + ?wait_match([{_, _,worker,[ssh_server_channel]}], supervisor:which_children(ChannelSup)), ssh:close(Client). -- cgit v1.2.3 From c2ca477c85e0e88732f634ddfb01ac675a97dddb Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 26 Apr 2018 13:43:45 +0200 Subject: ssh: ssh_channel replaced by ssh_client_channel --- lib/ssh/doc/src/Makefile | 3 +- lib/ssh/doc/src/introduction.xml | 2 +- lib/ssh/doc/src/ref_man.xml | 3 +- lib/ssh/doc/src/specs.xml | 3 +- lib/ssh/doc/src/ssh.xml | 2 +- lib/ssh/doc/src/ssh_channel.xml | 434 ------------------------------- lib/ssh/doc/src/ssh_client_channel.xml | 440 +++++++++++++++++++++++++++++++ lib/ssh/doc/src/ssh_connection.xml | 16 +- lib/ssh/doc/src/ssh_daemon_channel.xml | 52 ---- lib/ssh/doc/src/ssh_protocol.xml | 2 +- lib/ssh/doc/src/ssh_server_channel.xml | 2 +- lib/ssh/doc/src/using_ssh.xml | 2 +- lib/ssh/src/Makefile | 4 +- lib/ssh/src/ssh.app.src | 1 + lib/ssh/src/ssh.erl | 4 +- lib/ssh/src/ssh_channel.erl | 382 +-------------------------- lib/ssh/src/ssh_client_channel.erl | 456 +++++++++++++++++++++++++++++++++ lib/ssh/src/ssh_connection.erl | 46 ++-- lib/ssh/src/ssh_connection_handler.erl | 44 ++-- lib/ssh/src/ssh_server_channel.erl | 4 +- lib/ssh/src/ssh_sftp.erl | 18 +- 21 files changed, 983 insertions(+), 937 deletions(-) delete mode 100644 lib/ssh/doc/src/ssh_channel.xml create mode 100644 lib/ssh/doc/src/ssh_client_channel.xml delete mode 100644 lib/ssh/doc/src/ssh_daemon_channel.xml create mode 100644 lib/ssh/src/ssh_client_channel.erl diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile index 9b5bee34fa..7c4dbd7af8 100644 --- a/lib/ssh/doc/src/Makefile +++ b/lib/ssh/doc/src/Makefile @@ -40,10 +40,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) XML_APPLICATION_FILES = ref_man.xml XML_REF3_FILES = \ ssh.xml \ - ssh_channel.xml \ + ssh_client_channel.xml \ ssh_client_key_api.xml \ ssh_connection.xml \ - ssh_daemon_channel.xml \ ssh_server_channel.xml \ ssh_server_key_api.xml \ ssh_sftp.xml \ diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml index b7a73e2597..6fd8425adf 100644 --- a/lib/ssh/doc/src/introduction.xml +++ b/lib/ssh/doc/src/introduction.xml @@ -145,7 +145,7 @@ data that can be sent to the channel peer without adjusting the window. Typically, an SSH client opens a channel, sends data (commands), receives data (control information), and then closes the channel. - The ssh_channel behaviour + The ssh_client_channel behaviour handles generic parts of SSH channel management. This makes it easy to write your own SSH client/server processes that use flow-control and thus opens for more focus on the application logic. diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml index 3351699c66..76e6520f94 100644 --- a/lib/ssh/doc/src/ref_man.xml +++ b/lib/ssh/doc/src/ref_man.xml @@ -35,9 +35,8 @@ - + - diff --git a/lib/ssh/doc/src/specs.xml b/lib/ssh/doc/src/specs.xml index 15e76cb5fa..acdbe2ddfd 100644 --- a/lib/ssh/doc/src/specs.xml +++ b/lib/ssh/doc/src/specs.xml @@ -1,10 +1,9 @@ - + - diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index da122b6081..0223831cb1 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -68,7 +68,7 @@ ssh_sftp:start_channel/1,2,3.

To write your own client channel handler, use the behaviour - ssh_channel. For server channel handlers use + ssh_client_channel. For server channel handlers use ssh_server_channel behaviour (replaces ssh_daemon_channel).

Both clients and daemons accepts options that controls the exact behaviour. Some options are common to both. diff --git a/lib/ssh/doc/src/ssh_channel.xml b/lib/ssh/doc/src/ssh_channel.xml deleted file mode 100644 index 63a480d747..0000000000 --- a/lib/ssh/doc/src/ssh_channel.xml +++ /dev/null @@ -1,434 +0,0 @@ - - - - -

- - 2009 - 2016 - Ericsson AB, All Rights Reserved - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - ssh_channel - - - - -
- ssh_channel - -behaviour(ssh_channel). - - -

SSH services (clients and servers) are implemented as channels - that are multiplexed over an SSH connection and communicates over - the SSH - Connection Protocol. This module provides a callback API - that takes care of generic channel aspects for clients, such as flow control - and close messages. It lets the callback functions take care of - the service (application) specific parts. This behavior also ensures - that the channel process honors the principal of an OTP-process so - that it can be part of a supervisor tree. This is a requirement of - channel processes implementing a subsystem that will be added to - the ssh applications supervisor tree. -

- -

When implementing a ssh subsystem for daemons, use - -behaviour(ssh_server_channel) (Replaces ssh_daemon_channel) - instead. -

-
- - -

Functions in this module are not supposed to be called outside a module implementing this - behaviour! -

-
- -
- - - - call(ChannelRef, Msg) -> - call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason} - Makes a synchronous call to a channel. - - ChannelRef = pid() - As returned by start_link/4 - Msg = term() - Timeout = timeout() - Reply = term() - Reason = closed | timeout - - - -

Makes a synchronous call to the channel process by sending - a message and waiting until a reply arrives, or a time-out - occurs. The channel calls Module:handle_call/3 - to handle the message. If the channel process does not exist, - {error, closed} is returned. -

-
-
- - - cast(ChannelRef, Msg) -> ok - Sends an asynchronous message to the channel - ChannelRef and returns ok. - - ChannelRef = pid() - As returned by start_link/4 - Msg = term() - - -

Sends an asynchronous message to the channel process and - returns ok immediately, ignoring if the destination node or - channel process does not exist. The channel calls - Module:handle_cast/2 - to handle the message. -

-
-
- - - enter_loop(State) -> _ - Makes an existing process an ssh_channel process. - - State = term() - as returned by init/1 - - -

Makes an existing process an ssh_channel - process. Does not return, instead the calling process - enters the ssh_channel process receive loop and become an - ssh_channel process. The process must have been started using - one of the start functions in proc_lib, see the proc_lib(3) manual page in STDLIB. - The user is responsible for any initialization of the process - and must call init/1. -

-
-
- - - init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} - Initiates an ssh_channel process. - - Options = [{Option, Value}] - State = term() - Timeout = timeout() - Reason = term() - - -

- The following options must be present: -

- - {channel_cb, atom()} -

The module that implements the channel behaviour.

- - {init_args(), list()} -

The list of arguments to the init function of the callback module.

- - {cm, ssh:connection_ref()} -

Reference to the ssh connection as returned by - ssh:connect/3. -

- - {channel_id, ssh:channel_id()} -

Id of the ssh channel as returned by - ssh_connection:session_channel/2,4. -

- -
- -

This function is normally not called by the - user. The user only needs to call if the - channel process needs to be started with help of - proc_lib instead of calling - start/4 or - start_link/4.

-
-
-
- - - reply(Client, Reply) -> _ - Sends a reply to a client. - - Client = opaque() - Reply = term() - - -

This function can be used by a channel to send a - reply to a client that called call/[2,3] when the reply - cannot be defined in the return value of - Module:handle_call/3.

-

Client must be the From argument provided to - the callback function handle_call/3. - Reply is an arbitrary term, - which is given back to the client as the return value of - call/[2,3].

-
-
- - - start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> - start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> - {ok, ChannelRef} | {error, Reason} - Starts a process that handles an SSH channel. - - SshConnection = ssh:connection_ref() - As returned by ssh:connect/3 - - ChannelId = ssh:channel_id() - As returned by - - ssh_connection:session_channel/[2,4]. - - ChannelCb = atom() - Name of the module implementing the service-specific parts - of the channel. - - CbInitArgs = [term()] - Argument list for the init function in the callback module. - - ChannelRef = pid() - - -

Starts a process that handles an SSH channel. It is - called internally, by the ssh daemon, or explicitly by the ssh - client implementations. The behavior sets the - trap_exit flag to true. -

-
-
- -
- -
- Callback Functions -

- The following functions are to be exported from a - ssh_channel callback module. -

- -
- Callback timeouts -

The timeout values that can be returned by the callback functions - have the same semantics as in a gen_server. - If the time-out occurs, handle_msg/2 - is called as handle_msg(timeout, State).

-
-
- - - - Module:code_change(OldVsn, State, Extra) -> {ok, - NewState} - Converts process state when code is changed. - - OldVsn = term() - In the case of an upgrade, OldVsn is Vsn, and - in the case of a downgrade, OldVsn is - {down,Vsn}. Vsn is defined by the vsn - attribute(s) of the old version of the callback module - Module. If no such attribute is defined, the version is - the checksum of the BEAM file. - State = term() - Internal state of the channel. - Extra = term() - Passed "as-is" from the {advanced,Extra} - part of the update instruction. - - -

Converts process state when code is changed.

- -

This function is called by a client-side channel when it - is to update its internal state during a release - upgrade or downgrade, that is, when the instruction - {update,Module,Change,...}, where - Change={advanced,Extra}, is given in the appup - file. For more information, refer to Section 9.11.6 - Release Handling Instructions in the - System Documentation. -

- -

Soft upgrade according to the OTP release concept - is not straight forward for the server side, as subsystem - channel processes are spawned by the ssh application and - hence added to its supervisor tree. The subsystem channels can - be upgraded when upgrading the user application, if the callback - functions can handle two versions of the state, but this function - cannot be used in the normal way.

-
- -
-
- - - Module:init(Args) -> {ok, State} | {ok, State, timeout()} | - {stop, Reason} - Makes necessary initializations and returns the - initial channel state if the initializations succeed. - - Args = term() - Last argument to start_link/4. - State = term() - Reason = term() - - -

Makes necessary initializations and returns the initial channel - state if the initializations succeed. -

-

For more detailed information on time-outs, see Section - Callback timeouts.

-
-
- - - Module:handle_call(Msg, From, State) -> Result - Handles messages sent by calling - call/[2,3]. - - Msg = term() - From = opaque() - Is to be used as argument to - reply/2 - State = term() - Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()} - | {noreply, NewState} | {noreply , NewState, timeout()} - | {stop, Reason, Reply, NewState} | {stop, Reason, NewState} - Reply = term() - Will be the return value of call/[2,3] - NewState = term() - Reason = term() - - -

Handles messages sent by calling - call/[2,3] -

-

For more detailed information on time-outs,, see Section - Callback timeouts.

-
-
- - - Module:handle_cast(Msg, State) -> Result - Handles messages sent by calling - cast/2. - - Msg = term() - State = term() - Result = {noreply, NewState} | {noreply, NewState, timeout()} - | {stop, Reason, NewState} - NewState = term() - Reason = term() - - -

Handles messages sent by calling - cast/2. -

-

For more detailed information on time-outs, see Section - Callback timeouts.

-
-
- - - Module:handle_msg(Msg, State) -> {ok, State} | - {stop, ChannelId, State} - - Handles other messages than SSH connection protocol, - call, or cast messages sent to the channel. - - Msg = timeout | term() - ChannelId = ssh:channel_id() - State = term() - - -

Handles other messages than SSH Connection Protocol, call, or - cast messages sent to the channel. -

- -

Possible Erlang 'EXIT' messages is to be handled by this - function and all channels are to handle the following message.

- - - {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} -

This is the first message that the channel receives. - It is sent just before the init/1 function - returns successfully. This is especially useful if the - server wants to send a message to the client without first - receiving a message from it. If the message is not - useful for your particular scenario, ignore it by - immediately returning {ok, State}. -

-
-
-
- - - Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, - ChannelId, State} - Handles ssh connection protocol messages. - - Msg = ssh_connection:event() - ChannelId = ssh:channel_id() - State = term() - - -

Handles SSH Connection Protocol messages that may need - service-specific attention. For details, - see ssh_connection:event(). -

- -

The following message is taken care of by the - ssh_channel behavior.

- - - {closed, ssh:channel_id()} -

The channel behavior sends a close message to the - other side, if such a message has not already been sent. - Then it terminates the channel with reason normal.

-
-
-
- - - Module:terminate(Reason, State) -> _ - Does cleaning up before channel process termination. - - - Reason = term() - State = term() - - -

This function is called by a channel process when it is - about to terminate. Before this function is called, ssh_connection:close/2 - is called, if it has not been called earlier. - This function does any necessary cleaning - up. When it returns, the channel process terminates with - reason Reason. The return value is ignored. -

-
-
- -
- - diff --git a/lib/ssh/doc/src/ssh_client_channel.xml b/lib/ssh/doc/src/ssh_client_channel.xml new file mode 100644 index 0000000000..eed49beffa --- /dev/null +++ b/lib/ssh/doc/src/ssh_client_channel.xml @@ -0,0 +1,440 @@ + + + + +
+ + 2009 + 2016 + Ericsson AB, All Rights Reserved + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + The Initial Developer of the Original Code is Ericsson AB. + + ssh_client_channel + + + + +
+ ssh_client_channel + -behaviour(ssh_client_channel). (Replaces ssh_channel) + + + +

This module replaces ssh_channel.

+

The old module is still available for compatibility, but should not be used for new programs. + The old module will not be maintained except for some error corrections +

+
+

SSH services (clients and servers) are implemented as channels + that are multiplexed over an SSH connection and communicates over + the SSH + Connection Protocol. This module provides a callback API + that takes care of generic channel aspects for clients, such as flow control + and close messages. It lets the callback functions take care of + the service (application) specific parts. This behavior also ensures + that the channel process honors the principal of an OTP-process so + that it can be part of a supervisor tree. This is a requirement of + channel processes implementing a subsystem that will be added to + the ssh applications supervisor tree. +

+ +

When implementing a ssh subsystem for daemons, use + -behaviour(ssh_server_channel) (Replaces ssh_daemon_channel) + instead. +

+
+ + +

Functions in this module are not supposed to be called outside a module implementing this + behaviour! +

+
+ +
+ + + + call(ChannelRef, Msg) -> + call(ChannelRef, Msg, Timeout) -> Reply | {error, Reason} + Makes a synchronous call to a channel. + + ChannelRef = pid() + As returned by start_link/4 + Msg = term() + Timeout = timeout() + Reply = term() + Reason = closed | timeout + + + +

Makes a synchronous call to the channel process by sending + a message and waiting until a reply arrives, or a time-out + occurs. The channel calls Module:handle_call/3 + to handle the message. If the channel process does not exist, + {error, closed} is returned. +

+
+
+ + + cast(ChannelRef, Msg) -> ok + Sends an asynchronous message to the channel + ChannelRef and returns ok. + + ChannelRef = pid() + As returned by start_link/4 + Msg = term() + + +

Sends an asynchronous message to the channel process and + returns ok immediately, ignoring if the destination node or + channel process does not exist. The channel calls + Module:handle_cast/2 + to handle the message. +

+
+
+ + + enter_loop(State) -> _ + Makes an existing process an ssh_client_channel (replaces ssh_channel) process. + + State = term() + as returned by init/1 + + +

Makes an existing process an ssh_client_channel (replaces ssh_channel) + process. Does not return, instead the calling process + enters the ssh_client_channel (replaces ssh_channel) process receive loop and become an + ssh_client_channel process. The process must have been started using + one of the start functions in proc_lib, see the proc_lib(3) manual page in STDLIB. + The user is responsible for any initialization of the process + and must call init/1. +

+
+
+ + + init(Options) -> {ok, State} | {ok, State, Timeout} | {stop, Reason} + Initiates an ssh_client_channel process. + + Options = [{Option, Value}] + State = term() + Timeout = timeout() + Reason = term() + + +

+ The following options must be present: +

+ + {channel_cb, atom()} +

The module that implements the channel behaviour.

+ + {init_args(), list()} +

The list of arguments to the init function of the callback module.

+ + {cm, ssh:connection_ref()} +

Reference to the ssh connection as returned by + ssh:connect/3. +

+ + {channel_id, ssh:channel_id()} +

Id of the ssh channel as returned by + ssh_connection:session_channel/2,4. +

+ +
+ +

This function is normally not called by the + user. The user only needs to call if the + channel process needs to be started with help of + proc_lib instead of calling + start/4 or + start_link/4.

+
+
+
+ + + reply(Client, Reply) -> _ + Sends a reply to a client. + + Client = opaque() + Reply = term() + + +

This function can be used by a channel to send a + reply to a client that called call/[2,3] when the reply + cannot be defined in the return value of + Module:handle_call/3.

+

Client must be the From argument provided to + the callback function handle_call/3. + Reply is an arbitrary term, + which is given back to the client as the return value of + call/[2,3].

+
+
+ + + start(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> + start_link(SshConnection, ChannelId, ChannelCb, CbInitArgs) -> + {ok, ChannelRef} | {error, Reason} + Starts a process that handles an SSH channel. + + SshConnection = ssh:connection_ref() + As returned by ssh:connect/3 + + ChannelId = ssh:channel_id() + As returned by + + ssh_connection:session_channel/[2,4]. + + ChannelCb = atom() + Name of the module implementing the service-specific parts + of the channel. + + CbInitArgs = [term()] + Argument list for the init function in the callback module. + + ChannelRef = pid() + + +

Starts a process that handles an SSH channel. It is + called internally, by the ssh daemon, or explicitly by the ssh + client implementations. The behavior sets the + trap_exit flag to true. +

+
+
+ +
+ +
+ Callback Functions +

+ The following functions are to be exported from a + ssh_client_channel callback module. +

+ +
+ Callback timeouts +

The timeout values that can be returned by the callback functions + have the same semantics as in a gen_server. + If the time-out occurs, handle_msg/2 + is called as handle_msg(timeout, State).

+
+
+ + + + Module:code_change(OldVsn, State, Extra) -> {ok, + NewState} + Converts process state when code is changed. + + OldVsn = term() + In the case of an upgrade, OldVsn is Vsn, and + in the case of a downgrade, OldVsn is + {down,Vsn}. Vsn is defined by the vsn + attribute(s) of the old version of the callback module + Module. If no such attribute is defined, the version is + the checksum of the BEAM file. + State = term() + Internal state of the channel. + Extra = term() + Passed "as-is" from the {advanced,Extra} + part of the update instruction. + + +

Converts process state when code is changed.

+ +

This function is called by a client-side channel when it + is to update its internal state during a release + upgrade or downgrade, that is, when the instruction + {update,Module,Change,...}, where + Change={advanced,Extra}, is given in the appup + file. For more information, refer to Section 9.11.6 + Release Handling Instructions in the + System Documentation. +

+ +

Soft upgrade according to the OTP release concept + is not straight forward for the server side, as subsystem + channel processes are spawned by the ssh application and + hence added to its supervisor tree. The subsystem channels can + be upgraded when upgrading the user application, if the callback + functions can handle two versions of the state, but this function + cannot be used in the normal way.

+
+ +
+
+ + + Module:init(Args) -> {ok, State} | {ok, State, timeout()} | + {stop, Reason} + Makes necessary initializations and returns the + initial channel state if the initializations succeed. + + Args = term() + Last argument to start_link/4. + State = term() + Reason = term() + + +

Makes necessary initializations and returns the initial channel + state if the initializations succeed. +

+

For more detailed information on time-outs, see Section + Callback timeouts.

+
+
+ + + Module:handle_call(Msg, From, State) -> Result + Handles messages sent by calling + call/[2,3]. + + Msg = term() + From = opaque() + Is to be used as argument to + reply/2 + State = term() + Result = {reply, Reply, NewState} | {reply, Reply, NewState, timeout()} + | {noreply, NewState} | {noreply , NewState, timeout()} + | {stop, Reason, Reply, NewState} | {stop, Reason, NewState} + Reply = term() + Will be the return value of call/[2,3] + NewState = term() + Reason = term() + + +

Handles messages sent by calling + call/[2,3] +

+

For more detailed information on time-outs,, see Section + Callback timeouts.

+
+
+ + + Module:handle_cast(Msg, State) -> Result + Handles messages sent by calling + cast/2. + + Msg = term() + State = term() + Result = {noreply, NewState} | {noreply, NewState, timeout()} + | {stop, Reason, NewState} + NewState = term() + Reason = term() + + +

Handles messages sent by calling + cast/2. +

+

For more detailed information on time-outs, see Section + Callback timeouts.

+
+
+ + + Module:handle_msg(Msg, State) -> {ok, State} | + {stop, ChannelId, State} + + Handles other messages than SSH connection protocol, + call, or cast messages sent to the channel. + + Msg = timeout | term() + ChannelId = ssh:channel_id() + State = term() + + +

Handles other messages than SSH Connection Protocol, call, or + cast messages sent to the channel. +

+ +

Possible Erlang 'EXIT' messages is to be handled by this + function and all channels are to handle the following message.

+ + + {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} +

This is the first message that the channel receives. + It is sent just before the init/1 function + returns successfully. This is especially useful if the + server wants to send a message to the client without first + receiving a message from it. If the message is not + useful for your particular scenario, ignore it by + immediately returning {ok, State}. +

+
+
+
+ + + Module:handle_ssh_msg(Msg, State) -> {ok, State} | {stop, + ChannelId, State} + Handles ssh connection protocol messages. + + Msg = ssh_connection:event() + ChannelId = ssh:channel_id() + State = term() + + +

Handles SSH Connection Protocol messages that may need + service-specific attention. For details, + see ssh_connection:event(). +

+ +

The following message is taken care of by the + ssh_client_channel behavior.

+ + + {closed, ssh:channel_id()} +

The channel behavior sends a close message to the + other side, if such a message has not already been sent. + Then it terminates the channel with reason normal.

+
+
+
+ + + Module:terminate(Reason, State) -> _ + Does cleaning up before channel process termination. + + + Reason = term() + State = term() + + +

This function is called by a channel process when it is + about to terminate. Before this function is called, ssh_connection:close/2 + is called, if it has not been called earlier. + This function does any necessary cleaning + up. When it returns, the channel process terminates with + reason Reason. The return value is ignored. +

+
+
+ +
+ +
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index cfe5385eb4..821dfef93d 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -44,9 +44,9 @@ If the receiving channel is an Erlang process, the messages have the format . - If the ssh_channel behavior is used to + If the ssh_client_channel behavior is used to implement the channel process, these messages are handled by - handle_ssh_msg/2.

+ handle_ssh_msg/2.

@@ -131,7 +131,7 @@

This event is sent as a result of calling ssh_connection:close/2. Both the handling of this event and sending it are taken care of by the - ssh_channel behavior.

+ ssh_client_channel behavior.

@@ -212,10 +212,10 @@

Adjusts the SSH flow control window. This is to be done by both the client- and server-side channel processes.

-

Channels implemented with the ssh_channel +

Channels implemented with the ssh_client_channel behavior do not normally need to call this function as flow control is handled by the behavior. The behavior adjusts the window every time - the callback + the callback handle_ssh_msg/2 returns after processing channel data.

@@ -232,9 +232,9 @@ sending a close event.

-

This function is called by the ssh_channel +

This function is called by the ssh_client_channel behavior when the channel is terminated, see ssh_channel(3). Thus, channels implemented + marker="ssh_client_channel"> ssh_client_channel(3). Thus, channels implemented with the behavior are not to call this function explicitly.

@@ -277,7 +277,7 @@ 1 x {ssh_cm, connection_ref(), {closed, channel_id()}} -

Indicates that the ssh_channel started for the +

Indicates that the ssh_client_channel started for the execution of the command has now been shut down.

diff --git a/lib/ssh/doc/src/ssh_daemon_channel.xml b/lib/ssh/doc/src/ssh_daemon_channel.xml deleted file mode 100644 index 254f75a4de..0000000000 --- a/lib/ssh/doc/src/ssh_daemon_channel.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - -
- - 2009 - 2016 - Ericsson AB, All Rights Reserved - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - ssh_daemon_channel - - - - -
- ssh_daemon_channel - -behaviour(ssh_daemon_channel). - - -

This behaviour should NOT be used for new programs but is kept for compatibility. -

-

It is replaced by ssh_server_channel.

-
- - - - Module:CALLBACK(..) - ssh_daemon_channel is replaced by ssh_server_channel - -

See ssh_server_channel which replaces this module. -

-
-
-
- -
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml index 4548d7bbb6..53f0524b97 100644 --- a/lib/ssh/doc/src/ssh_protocol.xml +++ b/lib/ssh/doc/src/ssh_protocol.xml @@ -88,7 +88,7 @@ SSH client will open a channel, send data/commands, receive data/"control information" and when it is done close the channel. The - ssh_channel / + ssh_client_channel / ssh_server_channel (Replaces ssh_daemon_channel) behaviours makes it easy to write your own SSH client/server processes that use flow diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml index 19fc20fcda..af51ec470b 100644 --- a/lib/ssh/doc/src/ssh_server_channel.xml +++ b/lib/ssh/doc/src/ssh_server_channel.xml @@ -54,7 +54,7 @@

When implementing a client subsystem handler, use - -behaviour(ssh_channel) instead. + -behaviour(ssh_client_channel) instead.

diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index fef0784eb6..efd2a997f5 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -384,7 +384,7 @@ terminate(_Reason, _State) -> {ssh_msg, <0.57.0>, {closed, 0}} 7> {error, closed} = ssh_connection:send(ConnectionRef, ChannelId, "10", infinity).
-

See also ssh_channel(3).

+

See also ssh_client_channel(3) (replaces ssh_channel(3)).

diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index 1665e8b554..5e4efb6b99 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -45,7 +45,8 @@ BEHAVIOUR_MODULES= \ ssh_server_channel \ ssh_server_key_api \ ssh_sftpd_file_api \ - ssh_channel + ssh_channel \ + ssh_client_channel MODULES= \ ssh \ @@ -209,6 +210,7 @@ $(EBIN)/ssh_transport.$(EMULATOR): ssh_transport.erl \ ssh_transport.hrl ssh.hrl $(EBIN)/ssh_xfer.$(EMULATOR): ssh_xfer.erl ssh.hrl ssh_xfer.hrl $(EBIN)/ssh_sftpd_file_api.$(EMULATOR): ssh_sftpd_file_api.erl +$(EBIN)/ssh_client_channel.$(EMULATOR): ssh_client_channel.erl ssh_connect.hrl $(EBIN)/ssh_channel.$(EMULATOR): ssh_channel.erl ssh_connect.hrl $(EBIN)/ssh_daemon_channel.$(EMULATOR): ssh_daemon_channel.erl $(EBIN)/ssh_server_channel.$(EMULATOR): ssh_server_channel.erl diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index 897235e054..410061cded 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -12,6 +12,7 @@ ssh_message, ssh_bits, ssh_cli, + ssh_client_channel, ssh_client_key_api, ssh_channel, ssh_connection, diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 209f53d249..7ddb1ca5be 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -426,9 +426,9 @@ start_shell({ok, ConnectionRef}) -> Args = [{channel_cb, ssh_shell}, {init_args,[ConnectionRef, ChannelId]}, {cm, ConnectionRef}, {channel_id, ChannelId}], - {ok, State} = ssh_channel:init([Args]), + {ok, State} = ssh_client_channel:init([Args]), try - ssh_channel:enter_loop(State) + ssh_client_channel:enter_loop(State) catch exit:normal -> ok diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl index 359e29fdbe..81c495a815 100644 --- a/lib/ssh/src/ssh_channel.erl +++ b/lib/ssh/src/ssh_channel.erl @@ -56,401 +56,37 @@ State::term()) -> {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}. --behaviour(gen_server). - %%% API -export([start/4, start/5, start_link/4, start_link/5, call/2, call/3, cast/2, reply/2, enter_loop/1]). -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). - -%% Internal application API --export([cache_create/0, cache_lookup/2, cache_update/2, - cache_delete/1, cache_delete/2, cache_foldl/3, - cache_info/2, cache_find/2, - get_print_info/1]). - --export([dbg_trace/3]). - --record(state, { - cm, - channel_cb, - channel_state, - channel_id, - close_sent = false - }). - %%==================================================================== %% API %%==================================================================== call(ChannelPid, Msg) -> - call(ChannelPid, Msg, infinity). + ssh_client_channel:call(ChannelPid, Msg). call(ChannelPid, Msg, TimeOute) -> - try gen_server:call(ChannelPid, Msg, TimeOute) of - Result -> - Result - catch - exit:{noproc, _} -> - {error, closed}; - exit:{normal, _} -> - {error, closed}; - exit:{shutdown, _} -> - {error, closed}; - exit:{{shutdown, _}, _} -> - {error, closed}; - exit:{timeout, _} -> - {error, timeout} - end. + ssh_client_channel:call(ChannelPid, Msg, TimeOute). cast(ChannelPid, Msg) -> - gen_server:cast(ChannelPid, Msg). - + ssh_client_channel:cast(ChannelPid, Msg). reply(From, Msg) -> - gen_server:reply(From, Msg). + ssh_client_channel:reply(From, Msg). -%%==================================================================== -%% Internal application API -%%==================================================================== - -%%-------------------------------------------------------------------- -%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} -%% Description: Starts the server -%%-------------------------------------------------------------------- start(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> - start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + ssh_client_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs). start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> - Options = [{channel_cb, CallBack}, - {channel_id, ChannelId}, - {init_args, CbInitArgs}, - {cm, ConnectionManager}, - {exec, Exec}], - gen_server:start(?MODULE, [Options], []). + ssh_client_channel:start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> - start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs). start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> - Options = [{channel_cb, CallBack}, - {channel_id, ChannelId}, - {init_args, CbInitArgs}, - {cm, ConnectionManager}, - {exec, Exec}], - gen_server:start_link(?MODULE, [Options], []). + ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). enter_loop(State) -> - gen_server:enter_loop(?MODULE, [], State). - -%%==================================================================== -%% gen_server callbacks -%%==================================================================== - -%%-------------------------------------------------------------------- -%% Function: init(Args) -> {ok, State} | -%% {ok, State, Timeout} | -%% ignore | -%% {stop, Reason} -%% Description: Initiates the server -%%-------------------------------------------------------------------- -init([Options]) -> - Cb = proplists:get_value(channel_cb, Options), - ConnectionManager = proplists:get_value(cm, Options), - ChannelId = proplists:get_value(channel_id, Options), - process_flag(trap_exit, true), - try Cb:init(channel_cb_init_args(Options)) of - {ok, ChannelState} -> - State = #state{cm = ConnectionManager, - channel_cb = Cb, - channel_id = ChannelId, - channel_state = ChannelState}, - self() ! {ssh_channel_up, ChannelId, ConnectionManager}, - {ok, State}; - {ok, ChannelState, Timeout} -> - State = #state{cm = ConnectionManager, - channel_cb = Cb, - channel_id = ChannelId, - channel_state = ChannelState}, - self() ! {ssh_channel_up, ChannelId, ConnectionManager}, - {ok, State, Timeout}; - {stop, Why} -> - {stop, Why} - catch - _:Reason -> - {stop, Reason} - end. - -channel_cb_init_args(Options) -> - case proplists:get_value(exec, Options) of - undefined -> - proplists:get_value(init_args, Options); - Exec -> - proplists:get_value(init_args, Options) ++ [Exec] - end. - -%%-------------------------------------------------------------------- -%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | -%% {reply, Reply, State, Timeout} | -%% {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, Reply, State} | -%% {stop, Reason, State} -%% Description: Handling call messages -%%-------------------------------------------------------------------- -handle_call(get_print_info, _From, State) -> - Reply = - {{State#state.cm, - State#state.channel_id}, - io_lib:format('CB=~p',[State#state.channel_cb]) - }, - {reply, Reply, State}; - -handle_call(Request, From, #state{channel_cb = Module, - channel_state = ChannelState} = State) -> - try Module:handle_call(Request, From, ChannelState) of - Result -> - handle_cb_result(Result, State) - catch - error:{undef, _} -> - {noreply, State} - end. - - -%%-------------------------------------------------------------------- -%% Function: handle_cast(Msg, State) -> {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} -%% Description: Handling cast messages -%%-------------------------------------------------------------------- -handle_cast(Msg, #state{channel_cb = Module, - channel_state = ChannelState} = State) -> - - try Module:handle_cast(Msg, ChannelState) of - Result -> - handle_cb_result(Result, State) - catch - error:{undef, _} -> - {noreply, State} - end. - -%%-------------------------------------------------------------------- -%% Function: handle_info(Info, State) -> {noreply, State} | -%% {noreply, State, Timeout} | -%% {stop, Reason, State} -%% Description: Handling all non call/cast messages -%%-------------------------------------------------------------------- -handle_info({ssh_cm, ConnectionManager, {closed, _ChannelId}}, - #state{cm = ConnectionManager, - close_sent = true} = State) -> - {stop, normal, State}; -handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}}, - #state{cm = ConnectionManager, - close_sent = false} = State) -> - %% To be on the safe side, i.e. the manager has already been terminated. - (catch ssh_connection:close(ConnectionManager, ChannelId)), - {stop, normal, State#state{close_sent = true}}; - -handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, - channel_cb = Module, - channel_state = ChannelState0} = State) -> - case Module:handle_ssh_msg(Msg, ChannelState0) of - {ok, ChannelState} -> - adjust_window(Msg), - {noreply, State#state{channel_state = ChannelState}}; - {ok, ChannelState, Timeout} -> - adjust_window(Msg), - {noreply, State#state{channel_state = ChannelState}, Timeout}; - {stop, ChannelId, ChannelState} -> - catch ssh_connection:close(ConnectionManager, ChannelId), - {stop, normal, State#state{close_sent = true, - channel_state = ChannelState}} - end; - -handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module, - channel_state = ChannelState0} = State) -> - case Module:handle_msg(Msg, ChannelState0) of - {ok, ChannelState} -> - {noreply, State#state{channel_state = ChannelState}}; - {ok, ChannelState, Timeout} -> - {noreply, State#state{channel_state = ChannelState}, Timeout}; - {stop, Reason, ChannelState} when is_atom(Reason)-> - {stop, Reason, State#state{close_sent = true, - channel_state = ChannelState}}; - {stop, ChannelId, ChannelState} -> - Reason = - case Msg of - {'EXIT', _Pid, shutdown} -> - shutdown; - _ -> - normal - end, - (catch ssh_connection:close(ConnectionManager, ChannelId)), - {stop, Reason, State#state{close_sent = true, - channel_state = ChannelState}} - end. - -%%-------------------------------------------------------------------- -%% Function: terminate(Reason, State) -> void() -%% Description: This function is called by a gen_server when it is about to -%% terminate. It should be the opposite of Module:init/1 and do any necessary -%% cleaning up. When it returns, the gen_server terminates with Reason. -%% The return value is ignored. -%%-------------------------------------------------------------------- -terminate(Reason, #state{cm = ConnectionManager, - channel_id = ChannelId, - close_sent = false} = State) -> - catch ssh_connection:close(ConnectionManager, ChannelId), - terminate(Reason, State#state{close_sent = true}); -terminate(_, #state{channel_cb = Cb, channel_state = ChannelState}) -> - catch Cb:terminate(Cb, ChannelState), - ok. - -%%-------------------------------------------------------------------- -%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} -%% Description: Convert process state when code is changed -%%-------------------------------------------------------------------- -code_change(OldVsn, #state{channel_cb = Module, - channel_state = ChannelState0} = State, Extra) -> - {ok, ChannelState} = Module:code_change(OldVsn, ChannelState0, Extra), - {ok, State#state{channel_state = ChannelState}}. - -%%==================================================================== -%% Internal application API -%%==================================================================== -cache_create() -> - ets:new(cm_tab, [set,{keypos, #channel.local_id}]). - -cache_lookup(Cache, Key) -> - case ets:lookup(Cache, Key) of - [Channel] -> - Channel; - [] -> - undefined - end. - -cache_update(Cache, #channel{local_id = Id} = Entry) when Id =/= undefined -> - ets:insert(Cache, Entry). - -cache_delete(Cache, Key) -> - ets:delete(Cache, Key). - -cache_delete(Cache) -> - ets:delete(Cache). - -cache_foldl(Fun, Acc, Cache) -> - ets:foldl(Fun, Acc, Cache). - -cache_info(num_entries, Cache) -> - proplists:get_value(size, ets:info(Cache)). - -cache_find(ChannelPid, Cache) -> - case ets:match_object(Cache, #channel{user = ChannelPid}) of - [] -> - undefined; - [Channel] -> - Channel - end. - -get_print_info(Pid) -> - call(Pid, get_print_info, 1000). - -%%-------------------------------------------------------------------- -%%% Internal functions -%%-------------------------------------------------------------------- -handle_cb_result({reply, Reply, ChannelState}, State) -> - {reply, Reply, State#state{channel_state = ChannelState}}; -handle_cb_result({reply, Reply, ChannelState, Timeout}, State) -> - {reply, Reply,State#state{channel_state = ChannelState}, Timeout}; -handle_cb_result({noreply, ChannelState}, State) -> - {noreply, State#state{channel_state = ChannelState}}; -handle_cb_result({noreply, ChannelState, Timeout}, State) -> - {noreply, State#state{channel_state = ChannelState}, Timeout}; -handle_cb_result({stop, Reason, Reply, ChannelState}, State) -> - {stop, Reason, Reply, State#state{channel_state = ChannelState}}; -handle_cb_result({stop, Reason, ChannelState}, State) -> - {stop, Reason, State#state{channel_state = ChannelState}}. - -adjust_window({ssh_cm, ConnectionManager, - {data, ChannelId, _, Data}}) -> - ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data)); -adjust_window(_) -> - ok. - - -%%%################################################################ -%%%# -%%%# Tracing -%%%# - -dbg_trace(points, _, _) -> [terminate, channels, channel_events]; - - -dbg_trace(flags, channels, A) -> [c] ++ dbg_trace(flags, terminate, A); -dbg_trace(on, channels, A) -> dbg:tp(?MODULE, init, 1, x), - dbg_trace(on, terminate, A); -dbg_trace(off, channels, A) -> dbg:ctpg(?MODULE, init, 1), - dbg_trace(off, terminate, A); -dbg_trace(format, channels, {call, {?MODULE,init, [[KVs]]}}) -> - ["Server Channel Starting:\n", - io_lib:format("Connection: ~p, ChannelId: ~p, CallBack: ~p\nCallBack init args = ~p", - [proplists:get_value(K,KVs) || K <- [cm, channel_id, channel_cb]] - ++ [channel_cb_init_args(KVs)]) - ]; -dbg_trace(format, channels, {return_from, {?MODULE,init,1}, {stop,Reason}}) -> - ["Server Channel Start FAILED!\n", - io_lib:format("Reason = ~p", [Reason]) - ]; -dbg_trace(format, channels, F) -> - dbg_trace(format, terminate, F); - - -dbg_trace(flags, terminate, _) -> [c]; -dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x); -dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2); -dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) -> - ["Server Channel Terminating:\n", - io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)]) - ]; - -dbg_trace(flags, channel_events, _) -> [c]; -dbg_trace(on, channel_events, _) -> dbg:tp(?MODULE, handle_call, 3, x), - dbg:tp(?MODULE, handle_cast, 2, x), - dbg:tp(?MODULE, handle_info, 2, x); -dbg_trace(off, channel_events, _) -> dbg:ctpg(?MODULE, handle_call, 3), - dbg:ctpg(?MODULE, handle_cast, 2), - dbg:ctpg(?MODULE, handle_info, 2); -dbg_trace(format, channel_events, {call, {?MODULE,handle_call, [Call,From,State]}}) -> - [hdr("is called", State), - io_lib:format("From: ~p~nCall: ~p~n", [From, Call]) - ]; -dbg_trace(format, channel_events, {return_from, {?MODULE,handle_call,3}, Ret}) -> - ["Server Channel call returned:\n", - io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) - ]; -dbg_trace(format, channel_events, {call, {?MODULE,handle_cast, [Cast,State]}}) -> - [hdr("got cast", State), - io_lib:format("Cast: ~p~n", [Cast]) - ]; -dbg_trace(format, channel_events, {return_from, {?MODULE,handle_cast,2}, Ret}) -> - ["Server Channel cast returned:\n", - io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) - ]; -dbg_trace(format, channel_events, {call, {?MODULE,handle_info, [Info,State]}}) -> - [hdr("got info", State), - io_lib:format("Info: ~p~n", [Info]) - ]; -dbg_trace(format, channel_events, {return_from, {?MODULE,handle_info,2}, Ret}) -> - ["Server Channel info returned:\n", - io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) - ]. - -hdr(Title, S) -> - io_lib:format("Server Channel (Id=~p, CB=~p) ~s:\n", [S#state.channel_id, S#state.channel_cb, Title]). - -?wr_record(state). - - + ssh_client_channel:enter_loop(State). diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl new file mode 100644 index 0000000000..f20007baaf --- /dev/null +++ b/lib/ssh/src/ssh_client_channel.erl @@ -0,0 +1,456 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_client_channel). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). + +-callback init(Args :: term()) -> + {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} | + {stop, Reason :: term()} | ignore. +-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: term()) -> + {reply, Reply :: term(), NewState :: term()} | + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: term()} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_cast(Request :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. + +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | + term()), + State :: term()) -> + term(). +-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), + Extra :: term()) -> + {ok, NewState :: term()} | {error, Reason :: term()}. + +-callback handle_msg(Msg ::term(), State :: term()) -> + {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}. + +-callback handle_ssh_msg({ssh_cm, ConnectionRef::ssh:connection_ref(), SshMsg::term()}, + State::term()) -> {ok, State::term()} | + {stop, ChannelId::ssh:channel_id(), + State::term()}. +-behaviour(gen_server). + +%%% API +-export([start/4, start/5, start_link/4, start_link/5, call/2, call/3, + cast/2, reply/2, enter_loop/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +%% Internal application API +-export([cache_create/0, cache_lookup/2, cache_update/2, + cache_delete/1, cache_delete/2, cache_foldl/3, + cache_info/2, cache_find/2, + get_print_info/1]). + +-export([dbg_trace/3]). + +-record(state, { + cm, + channel_cb, + channel_state, + channel_id, + close_sent = false + }). + +%%==================================================================== +%% API +%%==================================================================== + +call(ChannelPid, Msg) -> + call(ChannelPid, Msg, infinity). + +call(ChannelPid, Msg, TimeOute) -> + try gen_server:call(ChannelPid, Msg, TimeOute) of + Result -> + Result + catch + exit:{noproc, _} -> + {error, closed}; + exit:{normal, _} -> + {error, closed}; + exit:{shutdown, _} -> + {error, closed}; + exit:{{shutdown, _}, _} -> + {error, closed}; + exit:{timeout, _} -> + {error, timeout} + end. + +cast(ChannelPid, Msg) -> + gen_server:cast(ChannelPid, Msg). + + +reply(From, Msg) -> + gen_server:reply(From, Msg). + +%%==================================================================== +%% Internal application API +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: start_link() -> {ok,Pid} | ignore | {error,Error} +%% Description: Starts the server +%%-------------------------------------------------------------------- +start(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> + start(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + +start(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> + Options = [{channel_cb, CallBack}, + {channel_id, ChannelId}, + {init_args, CbInitArgs}, + {cm, ConnectionManager}, + {exec, Exec}], + gen_server:start(?MODULE, [Options], []). + +start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs) -> + start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, undefined). + +start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> + Options = [{channel_cb, CallBack}, + {channel_id, ChannelId}, + {init_args, CbInitArgs}, + {cm, ConnectionManager}, + {exec, Exec}], + gen_server:start_link(?MODULE, [Options], []). + +enter_loop(State) -> + gen_server:enter_loop(?MODULE, [], State). + +%%==================================================================== +%% gen_server callbacks +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: init(Args) -> {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%-------------------------------------------------------------------- +init([Options]) -> + Cb = proplists:get_value(channel_cb, Options), + ConnectionManager = proplists:get_value(cm, Options), + ChannelId = proplists:get_value(channel_id, Options), + process_flag(trap_exit, true), + try Cb:init(channel_cb_init_args(Options)) of + {ok, ChannelState} -> + State = #state{cm = ConnectionManager, + channel_cb = Cb, + channel_id = ChannelId, + channel_state = ChannelState}, + self() ! {ssh_channel_up, ChannelId, ConnectionManager}, + {ok, State}; + {ok, ChannelState, Timeout} -> + State = #state{cm = ConnectionManager, + channel_cb = Cb, + channel_id = ChannelId, + channel_state = ChannelState}, + self() ! {ssh_channel_up, ChannelId, ConnectionManager}, + {ok, State, Timeout}; + {stop, Why} -> + {stop, Why} + catch + _:Reason -> + {stop, Reason} + end. + +channel_cb_init_args(Options) -> + case proplists:get_value(exec, Options) of + undefined -> + proplists:get_value(init_args, Options); + Exec -> + proplists:get_value(init_args, Options) ++ [Exec] + end. + +%%-------------------------------------------------------------------- +%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | +%% {reply, Reply, State, Timeout} | +%% {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, Reply, State} | +%% {stop, Reason, State} +%% Description: Handling call messages +%%-------------------------------------------------------------------- +handle_call(get_print_info, _From, State) -> + Reply = + {{State#state.cm, + State#state.channel_id}, + io_lib:format('CB=~p',[State#state.channel_cb]) + }, + {reply, Reply, State}; + +handle_call(Request, From, #state{channel_cb = Module, + channel_state = ChannelState} = State) -> + try Module:handle_call(Request, From, ChannelState) of + Result -> + handle_cb_result(Result, State) + catch + error:{undef, _} -> + {noreply, State} + end. + + +%%-------------------------------------------------------------------- +%% Function: handle_cast(Msg, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling cast messages +%%-------------------------------------------------------------------- +handle_cast(Msg, #state{channel_cb = Module, + channel_state = ChannelState} = State) -> + + try Module:handle_cast(Msg, ChannelState) of + Result -> + handle_cb_result(Result, State) + catch + error:{undef, _} -> + {noreply, State} + end. + +%%-------------------------------------------------------------------- +%% Function: handle_info(Info, State) -> {noreply, State} | +%% {noreply, State, Timeout} | +%% {stop, Reason, State} +%% Description: Handling all non call/cast messages +%%-------------------------------------------------------------------- +handle_info({ssh_cm, ConnectionManager, {closed, _ChannelId}}, + #state{cm = ConnectionManager, + close_sent = true} = State) -> + {stop, normal, State}; +handle_info({ssh_cm, ConnectionManager, {closed, ChannelId}}, + #state{cm = ConnectionManager, + close_sent = false} = State) -> + %% To be on the safe side, i.e. the manager has already been terminated. + (catch ssh_connection:close(ConnectionManager, ChannelId)), + {stop, normal, State#state{close_sent = true}}; + +handle_info({ssh_cm, _, _} = Msg, #state{cm = ConnectionManager, + channel_cb = Module, + channel_state = ChannelState0} = State) -> + case Module:handle_ssh_msg(Msg, ChannelState0) of + {ok, ChannelState} -> + adjust_window(Msg), + {noreply, State#state{channel_state = ChannelState}}; + {ok, ChannelState, Timeout} -> + adjust_window(Msg), + {noreply, State#state{channel_state = ChannelState}, Timeout}; + {stop, ChannelId, ChannelState} -> + catch ssh_connection:close(ConnectionManager, ChannelId), + {stop, normal, State#state{close_sent = true, + channel_state = ChannelState}} + end; + +handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module, + channel_state = ChannelState0} = State) -> + case Module:handle_msg(Msg, ChannelState0) of + {ok, ChannelState} -> + {noreply, State#state{channel_state = ChannelState}}; + {ok, ChannelState, Timeout} -> + {noreply, State#state{channel_state = ChannelState}, Timeout}; + {stop, Reason, ChannelState} when is_atom(Reason)-> + {stop, Reason, State#state{close_sent = true, + channel_state = ChannelState}}; + {stop, ChannelId, ChannelState} -> + Reason = + case Msg of + {'EXIT', _Pid, shutdown} -> + shutdown; + _ -> + normal + end, + (catch ssh_connection:close(ConnectionManager, ChannelId)), + {stop, Reason, State#state{close_sent = true, + channel_state = ChannelState}} + end. + +%%-------------------------------------------------------------------- +%% Function: terminate(Reason, State) -> void() +%% Description: This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any necessary +%% cleaning up. When it returns, the gen_server terminates with Reason. +%% The return value is ignored. +%%-------------------------------------------------------------------- +terminate(Reason, #state{cm = ConnectionManager, + channel_id = ChannelId, + close_sent = false} = State) -> + catch ssh_connection:close(ConnectionManager, ChannelId), + terminate(Reason, State#state{close_sent = true}); +terminate(_, #state{channel_cb = Cb, channel_state = ChannelState}) -> + catch Cb:terminate(Cb, ChannelState), + ok. + +%%-------------------------------------------------------------------- +%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} +%% Description: Convert process state when code is changed +%%-------------------------------------------------------------------- +code_change(OldVsn, #state{channel_cb = Module, + channel_state = ChannelState0} = State, Extra) -> + {ok, ChannelState} = Module:code_change(OldVsn, ChannelState0, Extra), + {ok, State#state{channel_state = ChannelState}}. + +%%==================================================================== +%% Internal application API +%%==================================================================== +cache_create() -> + ets:new(cm_tab, [set,{keypos, #channel.local_id}]). + +cache_lookup(Cache, Key) -> + case ets:lookup(Cache, Key) of + [Channel] -> + Channel; + [] -> + undefined + end. + +cache_update(Cache, #channel{local_id = Id} = Entry) when Id =/= undefined -> + ets:insert(Cache, Entry). + +cache_delete(Cache, Key) -> + ets:delete(Cache, Key). + +cache_delete(Cache) -> + ets:delete(Cache). + +cache_foldl(Fun, Acc, Cache) -> + ets:foldl(Fun, Acc, Cache). + +cache_info(num_entries, Cache) -> + proplists:get_value(size, ets:info(Cache)). + +cache_find(ChannelPid, Cache) -> + case ets:match_object(Cache, #channel{user = ChannelPid}) of + [] -> + undefined; + [Channel] -> + Channel + end. + +get_print_info(Pid) -> + call(Pid, get_print_info, 1000). + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +handle_cb_result({reply, Reply, ChannelState}, State) -> + {reply, Reply, State#state{channel_state = ChannelState}}; +handle_cb_result({reply, Reply, ChannelState, Timeout}, State) -> + {reply, Reply,State#state{channel_state = ChannelState}, Timeout}; +handle_cb_result({noreply, ChannelState}, State) -> + {noreply, State#state{channel_state = ChannelState}}; +handle_cb_result({noreply, ChannelState, Timeout}, State) -> + {noreply, State#state{channel_state = ChannelState}, Timeout}; +handle_cb_result({stop, Reason, Reply, ChannelState}, State) -> + {stop, Reason, Reply, State#state{channel_state = ChannelState}}; +handle_cb_result({stop, Reason, ChannelState}, State) -> + {stop, Reason, State#state{channel_state = ChannelState}}. + +adjust_window({ssh_cm, ConnectionManager, + {data, ChannelId, _, Data}}) -> + ssh_connection:adjust_window(ConnectionManager, ChannelId, size(Data)); +adjust_window(_) -> + ok. + + +%%%################################################################ +%%%# +%%%# Tracing +%%%# + +dbg_trace(points, _, _) -> [terminate, channels, channel_events]; + + +dbg_trace(flags, channels, A) -> [c] ++ dbg_trace(flags, terminate, A); +dbg_trace(on, channels, A) -> dbg:tp(?MODULE, init, 1, x), + dbg_trace(on, terminate, A); +dbg_trace(off, channels, A) -> dbg:ctpg(?MODULE, init, 1), + dbg_trace(off, terminate, A); +dbg_trace(format, channels, {call, {?MODULE,init, [[KVs]]}}) -> + ["Server Channel Starting:\n", + io_lib:format("Connection: ~p, ChannelId: ~p, CallBack: ~p\nCallBack init args = ~p", + [proplists:get_value(K,KVs) || K <- [cm, channel_id, channel_cb]] + ++ [channel_cb_init_args(KVs)]) + ]; +dbg_trace(format, channels, {return_from, {?MODULE,init,1}, {stop,Reason}}) -> + ["Server Channel Start FAILED!\n", + io_lib:format("Reason = ~p", [Reason]) + ]; +dbg_trace(format, channels, F) -> + dbg_trace(format, terminate, F); + + +dbg_trace(flags, terminate, _) -> [c]; +dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x); +dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2); +dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) -> + ["Server Channel Terminating:\n", + io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)]) + ]; + +dbg_trace(flags, channel_events, _) -> [c]; +dbg_trace(on, channel_events, _) -> dbg:tp(?MODULE, handle_call, 3, x), + dbg:tp(?MODULE, handle_cast, 2, x), + dbg:tp(?MODULE, handle_info, 2, x); +dbg_trace(off, channel_events, _) -> dbg:ctpg(?MODULE, handle_call, 3), + dbg:ctpg(?MODULE, handle_cast, 2), + dbg:ctpg(?MODULE, handle_info, 2); +dbg_trace(format, channel_events, {call, {?MODULE,handle_call, [Call,From,State]}}) -> + [hdr("is called", State), + io_lib:format("From: ~p~nCall: ~p~n", [From, Call]) + ]; +dbg_trace(format, channel_events, {return_from, {?MODULE,handle_call,3}, Ret}) -> + ["Server Channel call returned:\n", + io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) + ]; +dbg_trace(format, channel_events, {call, {?MODULE,handle_cast, [Cast,State]}}) -> + [hdr("got cast", State), + io_lib:format("Cast: ~p~n", [Cast]) + ]; +dbg_trace(format, channel_events, {return_from, {?MODULE,handle_cast,2}, Ret}) -> + ["Server Channel cast returned:\n", + io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) + ]; +dbg_trace(format, channel_events, {call, {?MODULE,handle_info, [Info,State]}}) -> + [hdr("got info", State), + io_lib:format("Info: ~p~n", [Info]) + ]; +dbg_trace(format, channel_events, {return_from, {?MODULE,handle_info,2}, Ret}) -> + ["Server Channel info returned:\n", + io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)]) + ]. + +hdr(Title, S) -> + io_lib:format("Server Channel (Id=~p, CB=~p) ~s:\n", [S#state.channel_id, S#state.channel_cb, Title]). + +?wr_record(state). + + diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index cff9ec3a61..ed03b4e2ed 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -271,7 +271,7 @@ channel_data(ChannelId, DataType, Data, Connection, From) when is_list(Data)-> channel_data(ChannelId, DataType, Data, #connection{channel_cache = Cache} = Connection, From) -> - case ssh_channel:cache_lookup(Cache, ChannelId) of + case ssh_client_channel:cache_lookup(Cache, ChannelId) of #channel{remote_id = Id, sent_close = false} = Channel0 -> {SendList, Channel} = update_send_window(Channel0#channel{flow_control = From}, DataType, @@ -303,9 +303,9 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId, #connection{channel_cache = Cache} = Connection0, _) -> #channel{remote_id = undefined} = Channel = - ssh_channel:cache_lookup(Cache, ChannelId), + ssh_client_channel:cache_lookup(Cache, ChannelId), - ssh_channel:cache_update(Cache, Channel#channel{ + ssh_client_channel:cache_update(Cache, Channel#channel{ remote_id = RemoteId, recv_packet_size = max(32768, % rfc4254/5.2 min(PacketSz, Channel#channel.recv_packet_size) @@ -319,8 +319,8 @@ handle_msg(#ssh_msg_channel_open_failure{recipient_channel = ChannelId, description = Descr, lang = Lang}, #connection{channel_cache = Cache} = Connection0, _) -> - Channel = ssh_channel:cache_lookup(Cache, ChannelId), - ssh_channel:cache_delete(Cache, ChannelId), + Channel = ssh_client_channel:cache_lookup(Cache, ChannelId), + ssh_client_channel:cache_delete(Cache, ChannelId), reply_msg(Channel, Connection0, {open_error, Reason, Descr, Lang}); handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId}, Connection, _) -> @@ -335,10 +335,10 @@ handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId}, Connection, _) - handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId}, #connection{channel_cache = Cache} = Connection0, _) -> - case ssh_channel:cache_lookup(Cache, ChannelId) of + case ssh_client_channel:cache_lookup(Cache, ChannelId) of #channel{sent_close = Closed, remote_id = RemoteId, flow_control = FlowControl} = Channel -> - ssh_channel:cache_delete(Cache, ChannelId), + ssh_client_channel:cache_delete(Cache, ChannelId), {CloseMsg, Connection} = reply_msg(Channel, Connection0, {closed, ChannelId}), ConnReplyMsgs = @@ -379,7 +379,7 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId, bytes_to_add = Add}, #connection{channel_cache = Cache} = Connection, _) -> #channel{send_window_size = Size, remote_id = RemoteId} = - Channel0 = ssh_channel:cache_lookup(Cache, ChannelId), + Channel0 = ssh_client_channel:cache_lookup(Cache, ChannelId), {SendList, Channel} = %% TODO: Datatype 0 ? update_send_window(Channel0#channel{send_window_size = Size + Add}, @@ -455,7 +455,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, ?BOOLEAN(_Core), ?DEC_BIN(Err, _ErrLen), ?DEC_BIN(Lang, _LangLen)>> = Data, - Channel = ssh_channel:cache_lookup(Cache, ChannelId), + Channel = ssh_client_channel:cache_lookup(Cache, ChannelId), RemoteId = Channel#channel.remote_id, {Reply, Connection} = reply_msg(Channel, Connection0, {exit_signal, ChannelId, @@ -500,7 +500,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, <> = Data, #channel{remote_id = RemoteId} = Channel0 = - ssh_channel:cache_lookup(Cache, ChannelId), + ssh_client_channel:cache_lookup(Cache, ChannelId), ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)}, @@ -508,7 +508,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, {ok, Pid} = start_subsystem(SsName, Connection, Channel0, ReplyMsg), erlang:monitor(process, Pid), Channel = Channel0#channel{user = Pid}, - ssh_channel:cache_update(Cache, Channel), + ssh_client_channel:cache_update(Cache, Channel), Reply = {connection_reply, channel_success_msg(RemoteId)}, {[Reply], Connection} @@ -588,7 +588,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, want_reply = WantReply}, #connection{channel_cache = Cache} = Connection, _) -> if WantReply == true -> - case ssh_channel:cache_lookup(Cache, ChannelId) of + case ssh_client_channel:cache_lookup(Cache, ChannelId) of #channel{remote_id = RemoteId} -> FailMsg = channel_failure_msg(RemoteId), {[{connection_reply, FailMsg}], Connection}; @@ -631,14 +631,14 @@ handle_msg(#ssh_msg_disconnect{code = Code, %%% handle_stop(#connection{channel_cache = Cache} = Connection0) -> {Connection, Replies} = - ssh_channel:cache_foldl( + ssh_client_channel:cache_foldl( fun(Channel, {Connection1, Acc}) -> {Reply, Connection2} = reply_msg(Channel, Connection1, {closed, Channel#channel.local_id}), {Connection2, Reply ++ Acc} end, {Connection0, []}, Cache), - ssh_channel:cache_delete(Cache), + ssh_client_channel:cache_delete(Cache), {Replies, Connection}. %%%---------------------------------------------------------------- @@ -779,7 +779,7 @@ setup_session(#connection{channel_cache = Cache, send_buf = queue:new(), remote_id = RemoteId }, - ssh_channel:cache_update(Cache, Channel), + ssh_client_channel:cache_update(Cache, Channel), OpenConfMsg = channel_open_confirmation_msg(RemoteId, NewChannelID, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE), @@ -868,7 +868,7 @@ update_send_window(#channel{send_buf = SendBuffer} = Channel, DataType, Data, do_update_send_window(Channel0, Cache) -> {SendMsgs, Channel} = get_window(Channel0, []), - ssh_channel:cache_update(Cache, Channel), + ssh_client_channel:cache_update(Cache, Channel), {SendMsgs, Channel}. get_window(#channel{send_window_size = 0 @@ -919,13 +919,13 @@ flow_control(Channel, Cache) -> flow_control([window_adjusted], Channel, Cache). flow_control([], Channel, Cache) -> - ssh_channel:cache_update(Cache, Channel), + ssh_client_channel:cache_update(Cache, Channel), []; flow_control([_|_], #channel{flow_control = From, send_buf = Buffer} = Channel, Cache) when From =/= undefined -> case queue:is_empty(Buffer) of true -> - ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), + ssh_client_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), [{flow_control, Cache, Channel, From, ok}]; false -> [] @@ -1169,14 +1169,14 @@ backwards_compatible([Value| Rest], Acc) -> handle_cli_msg(C0, ChId, Reply0) -> Cache = C0#connection.channel_cache, - Ch0 = ssh_channel:cache_lookup(Cache, ChId), + Ch0 = ssh_client_channel:cache_lookup(Cache, ChId), case Ch0#channel.user of undefined -> case (catch start_cli(C0, ChId)) of {ok, Pid} -> erlang:monitor(process, Pid), Ch = Ch0#channel{user = Pid}, - ssh_channel:cache_update(Cache, Ch), + ssh_client_channel:cache_update(Cache, Ch), reply_msg(Ch, C0, Reply0); _Other -> Reply = {connection_reply, channel_failure_msg(Ch0#channel.remote_id)}, @@ -1194,10 +1194,10 @@ handle_cli_msg(C0, ChId, Reply0) -> %%% channel_data_reply_msg(ChannelId, Connection, DataType, Data) -> - case ssh_channel:cache_lookup(Connection#connection.channel_cache, ChannelId) of + case ssh_client_channel:cache_lookup(Connection#connection.channel_cache, ChannelId) of #channel{recv_window_size = Size} = Channel -> WantedSize = Size - size(Data), - ssh_channel:cache_update(Connection#connection.channel_cache, + ssh_client_channel:cache_update(Connection#connection.channel_cache, Channel#channel{recv_window_size = WantedSize}), reply_msg(Channel, Connection, {data, ChannelId, DataType, Data}); undefined -> @@ -1206,7 +1206,7 @@ channel_data_reply_msg(ChannelId, Connection, DataType, Data) -> reply_msg(ChId, C, Reply) when is_integer(ChId) -> - reply_msg(ssh_channel:cache_lookup(C#connection.channel_cache, ChId), C, Reply); + reply_msg(ssh_client_channel:cache_lookup(C#connection.channel_cache, ChId), C, Reply); reply_msg(Channel, Connection, {open, _} = Reply) -> request_reply_or_data(Channel, Connection, Reply); diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index ab7fc1cf46..57641cf74c 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -414,7 +414,7 @@ init([Role,Socket,Opts]) -> case inet:peername(Socket) of {ok, PeerAddr} -> {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts), - C = #connection{channel_cache = ssh_channel:cache_create(), + C = #connection{channel_cache = ssh_client_channel:cache_create(), channel_id_seed = 0, port_bindings = [], requests = [], @@ -1109,13 +1109,13 @@ handle_event(cast, _, StateName, _) when not ?CONNECTED(StateName) -> {keep_state_and_data, [postpone]}; handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTED(StateName) -> - case ssh_channel:cache_lookup(cache(D), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{recv_window_size = WinSize, recv_window_pending = Pending, recv_packet_size = PktSize} = Channel when (WinSize-Bytes) >= 2*PktSize -> %% The peer can send at least two more *full* packet, no hurry. - ssh_channel:cache_update(cache(D), + ssh_client_channel:cache_update(cache(D), Channel#channel{recv_window_pending = Pending + Bytes}), keep_state_and_data; @@ -1123,7 +1123,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTE recv_window_pending = Pending, remote_id = Id} = Channel -> %% Now we have to update the window - we can't receive so many more pkts - ssh_channel:cache_update(cache(D), + ssh_client_channel:cache_update(cache(D), Channel#channel{recv_window_size = WinSize + Bytes + Pending, recv_window_pending = 0}), @@ -1135,7 +1135,7 @@ handle_event(cast, {adjust_window,ChannelId,Bytes}, StateName, D) when ?CONNECTE end; handle_event(cast, {reply_request,success,ChannelId}, StateName, D) when ?CONNECTED(StateName) -> - case ssh_channel:cache_lookup(cache(D), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{remote_id = RemoteId} -> Msg = ssh_connection:channel_success_msg(RemoteId), update_inet_buffers(D#data.socket), @@ -1178,7 +1178,7 @@ handle_event({call,From}, {connection_info, Options}, _, D) -> {keep_state_and_data, [{reply,From,Info}]}; handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) -> - case ssh_channel:cache_lookup(cache(D), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{} = Channel -> Info = fold_keys(Options, fun chann_info/2, Channel), {keep_state_and_data, [{reply,From,Info}]}; @@ -1188,14 +1188,14 @@ handle_event({call,From}, {channel_info,ChannelId,Options}, _, D) -> handle_event({call,From}, {info, all}, _, D) -> - Result = ssh_channel:cache_foldl(fun(Channel, Acc) -> + Result = ssh_client_channel:cache_foldl(fun(Channel, Acc) -> [Channel | Acc] end, [], cache(D)), {keep_state_and_data, [{reply, From, {ok,Result}}]}; handle_event({call,From}, {info, ChannelPid}, _, D) -> - Result = ssh_channel:cache_foldl( + Result = ssh_client_channel:cache_foldl( fun(Channel, Acc) when Channel#channel.user == ChannelPid -> [Channel | Acc]; (_, Acc) -> @@ -1241,7 +1241,7 @@ handle_event({call,From}, {data, ChannelId, Type, Data, Timeout}, StateName, D0) handle_event({call,From}, {eof, ChannelId}, StateName, D0) when ?CONNECTED(StateName) -> - case ssh_channel:cache_lookup(cache(D0), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D0), ChannelId) of #channel{remote_id = Id, sent_close = false} -> D = send_msg(ssh_connection:channel_eof_msg(Id), D0), {keep_state, D, [{reply,From,ok}]}; @@ -1259,7 +1259,7 @@ handle_event({call,From}, InitialWindowSize, MaxPacketSize, Data), D1), - ssh_channel:cache_update(cache(D2), + ssh_client_channel:cache_update(cache(D2), #channel{type = Type, sys = "none", user = ChannelPid, @@ -1274,7 +1274,7 @@ handle_event({call,From}, handle_event({call,From}, {send_window, ChannelId}, StateName, D) when ?CONNECTED(StateName) -> - Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of + Reply = case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{send_window_size = WinSize, send_packet_size = Packsize} -> {ok, {WinSize, Packsize}}; @@ -1285,7 +1285,7 @@ handle_event({call,From}, {send_window, ChannelId}, StateName, D) handle_event({call,From}, {recv_window, ChannelId}, StateName, D) when ?CONNECTED(StateName) -> - Reply = case ssh_channel:cache_lookup(cache(D), ChannelId) of + Reply = case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{recv_window_size = WinSize, recv_packet_size = Packsize} -> {ok, {WinSize, Packsize}}; @@ -1296,10 +1296,10 @@ handle_event({call,From}, {recv_window, ChannelId}, StateName, D) handle_event({call,From}, {close, ChannelId}, StateName, D0) when ?CONNECTED(StateName) -> - case ssh_channel:cache_lookup(cache(D0), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D0), ChannelId) of #channel{remote_id = Id} = Channel -> D1 = send_msg(ssh_connection:channel_close_msg(Id), D0), - ssh_channel:cache_update(cache(D1), Channel#channel{sent_close = true}), + ssh_client_channel:cache_update(cache(D1), Channel#channel{sent_close = true}), {keep_state, cache_request_idle_timer_check(D1), [{reply,From,ok}]}; undefined -> {keep_state_and_data, [{reply,From,ok}]} @@ -1859,7 +1859,7 @@ is_usable_user_pubkey(A, Ssh) -> %%%---------------------------------------------------------------- handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) -> - case ssh_channel:cache_lookup(cache(D), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{remote_id = Id, sent_close = false} = Channel -> update_sys(cache(D), Channel, Type, ChannelPid), @@ -1874,7 +1874,7 @@ handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From, D) -> end. handle_request(ChannelId, Type, Data, WantReply, From, D) -> - case ssh_channel:cache_lookup(cache(D), ChannelId) of + case ssh_client_channel:cache_lookup(cache(D), ChannelId) of #channel{remote_id = Id, sent_close = false} -> send_msg(ssh_connection:channel_request_msg(Id, Type, WantReply, Data), @@ -1890,10 +1890,10 @@ handle_request(ChannelId, Type, Data, WantReply, From, D) -> %%%---------------------------------------------------------------- handle_channel_down(ChannelPid, D) -> Cache = cache(D), - ssh_channel:cache_foldl( + ssh_client_channel:cache_foldl( fun(#channel{user=U, local_id=Id}, Acc) when U == ChannelPid -> - ssh_channel:cache_delete(Cache, Id), + ssh_client_channel:cache_delete(Cache, Id), Acc; (_,Acc) -> Acc @@ -1902,7 +1902,7 @@ handle_channel_down(ChannelPid, D) -> update_sys(Cache, Channel, Type, ChannelPid) -> - ssh_channel:cache_update(Cache, + ssh_client_channel:cache_update(Cache, Channel#channel{sys = Type, user = ChannelPid}). add_request(false, _ChannelId, _From, State) -> @@ -1979,7 +1979,7 @@ conn_info(sockname, #data{ssh_params=S}) -> S#ssh.local; %% dbg options ( = not documented): conn_info(socket, D) -> D#data.socket; conn_info(chan_ids, D) -> - ssh_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) -> + ssh_client_channel:cache_foldl(fun(#channel{local_id=Id}, Acc) -> [Id | Acc] end, [], cache(D)). @@ -2070,7 +2070,7 @@ get_repl({channel_data,Pid,Data}, Acc) -> get_repl({channel_request_reply,From,Data}, {CallRepls,S}) -> {[{reply,From,Data}|CallRepls], S}; get_repl({flow_control,Cache,Channel,From,Msg}, {CallRepls,S}) -> - ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), + ssh_client_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), {[{reply,From,Msg}|CallRepls], S}; get_repl({flow_control,From,Msg}, {CallRepls,S}) -> {[{reply,From,Msg}|CallRepls], S}; @@ -2146,7 +2146,7 @@ cache_init_idle_timer(D) -> cache_check_set_idle_timer(D = #data{idle_timer_ref = undefined, idle_timer_value = IdleTime}) -> %% No timer set - shall we set one? - case ssh_channel:cache_info(num_entries, cache(D)) of + case ssh_client_channel:cache_info(num_entries, cache(D)) of 0 when IdleTime == infinity -> %% No. Meaningless to set a timer that fires in an infinite time... D; diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl index 117b7855e2..f1c9a85639 100644 --- a/lib/ssh/src/ssh_server_channel.erl +++ b/lib/ssh/src/ssh_server_channel.erl @@ -48,8 +48,8 @@ ]). start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec) -> - ssh_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). + ssh_client_channel:start_link(ConnectionManager, ChannelId, CallBack, CbInitArgs, Exec). get_print_info(Pid) -> - ssh_channel:get_print_info(Pid). + ssh_client_channel:get_print_info(Pid). diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index f00c0aed1f..5984713ec9 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -24,7 +24,7 @@ -module(ssh_sftp). --behaviour(ssh_channel). +-behaviour(ssh_client_channel). -include_lib("kernel/include/file.hrl"). -include("ssh.hrl"). @@ -47,7 +47,7 @@ recv_window/1, list_dir/2, read_file/2, write_file/3, recv_window/2, list_dir/3, read_file/3, write_file/4]). -%% ssh_channel callbacks +%% ssh_client_channel callbacks -export([init/1, handle_call/3, handle_cast/2, code_change/3, handle_msg/2, handle_ssh_msg/2, terminate/2]). %% TODO: Should be placed elsewhere ssh_sftpd should not call functions in ssh_sftp! -export([info_to_attr/1, attr_to_info/1]). @@ -123,7 +123,7 @@ start_channel(Cm, UserOptions) when is_pid(Cm) -> {_SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), case ssh_xfer:attach(Cm, [], ChanOpts) of {ok, ChannelId, Cm} -> - case ssh_channel:start(Cm, ChannelId, + case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm, ChannelId, SftpOpts]) of {ok, Pid} -> case wait_for_version_negotiation(Pid, Timeout) of @@ -151,7 +151,7 @@ start_channel(Host, Port, UserOptions) -> proplists:get_value(timeout, SftpOpts, infinity)), case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of {ok, ChannelId, Cm} -> - case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of + case ssh_client_channel:start(Cm, ChannelId, ?MODULE, [Cm,ChannelId,SftpOpts]) of {ok, Pid} -> case wait_for_version_negotiation(Pid, Timeout) of ok -> @@ -825,7 +825,7 @@ handle_msg({ssh_channel_up, _, _}, #state{opts = Options, xf = Xf} = State) -> %% Version negotiation timed out handle_msg({timeout, undefined, From}, #state{xf = #ssh_xfer{channel = ChannelId}} = State) -> - ssh_channel:reply(From, {error, timeout}), + ssh_client_channel:reply(From, {error, timeout}), {stop, ChannelId, State}; handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) -> @@ -834,7 +834,7 @@ handle_msg({timeout, Id, From}, #state{req_list = ReqList0} = State) -> {ok, State}; _ -> ReqList = lists:keydelete(Id, 1, ReqList0), - ssh_channel:reply(From, {error, timeout}), + ssh_client_channel:reply(From, {error, timeout}), {ok, State#state{req_list = ReqList}} end; @@ -882,7 +882,7 @@ handle_options([Opt|Rest], Sftp, Chan, Ssh) -> handle_options(Rest, Sftp, Chan, [Opt|Ssh]). call(Pid, Msg, TimeOut) -> - ssh_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity). + ssh_client_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity). handle_reply(State, <>) -> do_handle_reply(State, Reply, Rest); @@ -901,7 +901,7 @@ do_handle_reply(#state{xf = Xf} = State, true -> ok end, - ssh_channel:reply(From, ok) + ssh_client_channel:reply(From, ok) end, State#state{xf = Xf#ssh_xfer{vsn = Version, ext = Ext}, rep_buf = Rest}; @@ -949,7 +949,7 @@ async_reply(ReqID, Reply, _From={To,_}, State) -> State. sync_reply(Reply, From, State) -> - catch (ssh_channel:reply(From, Reply)), + catch (ssh_client_channel:reply(From, Reply)), State. open2(OrigReqID,FileName,Handle,Mode,Async,From,State) -> -- cgit v1.2.3