From 8bf1bd07face1af84fbded1281e4877f28e0e9fa Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 27 Jun 2019 15:17:57 +0200 Subject: ssh: The ssh_sftpd documentation is now generated --- lib/ssh/doc/src/ssh_sftpd.xml | 33 ++++++++++----------------------- lib/ssh/src/ssh_sftpd.erl | 12 +++++++++++- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml index ee72784add..0d7b340399 100644 --- a/lib/ssh/doc/src/ssh_sftpd.xml +++ b/lib/ssh/doc/src/ssh_sftpd.xml @@ -35,36 +35,23 @@

Specifies a channel process to handle an SFTP subsystem.

-
- DATA TYPES - - subsystem_spec() = -

{subsystem_name(), {channel_callback(), channel_init_args()}}

- subsystem_name() = -

"sftp"

- channel_callback() = -

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

- channel_init_args() = -

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

-
-
- subsystem_spec(Options) -> subsystem_spec() + Returns the subsystem specification that allows an SSH daemon to handle the subsystem "sftp". - - Options = [{Option, Value}] -

Is to be used together with ssh:daemon/[1,2,3]

+

The Name is "sftp" and + CbMod is the name of the Erlang module implementing the subsystem using the + ssh_server_channel (replaces ssh_daemon_channel) behaviour. +

Options:

- + cwd

Sets the initial current working directory for the server.

- + file_handler

Determines which module to call for accessing the file server. The default value is ssh_sftpd_file, which uses the @@ -72,13 +59,13 @@ APIs to access the standard OTP file server. This option can be used to plug in other file servers.

- + max_files

The default value is 0, which means that there is no upper limit. If supplied, the number of filenames returned to the SFTP client per READDIR request is limited to at most the given value.

- + root

Sets the SFTP root directory. Then the user cannot see any files above this root. If, for example, the root directory is set to /tmp, @@ -86,7 +73,7 @@ cd /etc, the user moves to /tmp/etc.

- + sftpd_vsn

Sets the SFTP version to use. Defaults to 5. Version 6 is under development and limited.

diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index 5ec12e2d04..bf921f0ff3 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -58,7 +58,17 @@ %%==================================================================== %% API %%==================================================================== --spec subsystem_spec(list()) -> subsystem_spec(). +-spec subsystem_spec(Options) -> Spec when + Options :: [ {cwd, string()} | + {file_handler, CallbackModule::string()} | + {max_files, integer()} | + {root, string()} | + {sftpd_vsn, integer()} + ], + Spec :: {Name, {CbMod,Options}}, + Name :: string(), + CbMod :: atom() . + subsystem_spec(Options) -> {"sftp", {?MODULE, Options}}. -- cgit v1.2.3 From 42a916716671d6f553f5c25d8a8c98d34a7f1da5 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 27 Jun 2019 16:29:19 +0200 Subject: ssh: The ssh_sftp documentation is now generated --- lib/ssh/doc/src/ssh_sftp.xml | 436 +++++++++++++++--------------------------- lib/ssh/doc/src/using_ssh.xml | 14 +- lib/ssh/src/ssh_sftp.erl | 326 ++++++++++++++++++++++++++++++- 3 files changed, 485 insertions(+), 291 deletions(-) diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index c89092798d..76d2b21946 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -37,60 +37,106 @@ SSH.

-
- DATA TYPES -

Type definitions that are used more than once in this module, - or abstractions to indicate the intended use of the data type, or both: -

- - - reason() - -

= atom() | string() | tuple() A description of the reason why an operation failed.

-

- The atom() value is formed from the sftp error codes in the protocol-level responses as defined in - draft-ietf-secsh-filexfer-13.txt - section 9.1. -

-

+ + Error cause + + + +

A description of the reason why an operation failed.

+

The atom() value is formed from the sftp error codes in the protocol-level responses as defined in + draft-ietf-secsh-filexfer-13 + section 9.1. The codes are named as SSH_FX_* which are transformed into lowercase of the star-part. E.g. the error code SSH_FX_NO_SUCH_FILE will cause the reason() to be no_such_file.

The string() reason is the error information from the server in case of an exit-signal. If that information is empty, the reason is the exit signal name.

-

The tuple() reason are other errors like the {exit_status,integer()} if the exit status is not 0. +

The tuple() reason are other errors like for example {exit_status,1}. +

+ + + + Crypto operations for open_tar + + + + + +

Specifies the encryption or decryption applied to tar files when using + open_tar/3 or + open_tar/4. +

+

The encryption or decryption is applied to the generated stream of + bytes prior to sending the resulting stream to the SFTP server. +

+

For code examples see Section + Example with encryption + in the ssh Users Guide.

-
+ + - connection_ref() = -

opaque() - as returned by - ssh:connect/3

+ + + + + +

The init_fun() in the + tar_crypto_spec + is applied once prior to any other crypto + operation. The intention is that this function initiates the encryption or + decryption for example by calling + crypto:crypto_init/4 + or similar. The crypto_state() is the state such a function may return. +

+

If the selected cipher needs to have the input data partioned into + blocks of a certain size, the init_fun() should return the second + form of return value with the chunk_size() set to the block size. + If the chunk_size() is undefined, the size of the PlainBins varies, + because this is intended for stream crypto, whereas a fixed chunk_size() is intended for block crypto. + A chunk_size() can be changed in the return from the crypto_fun(). + The value can be changed between pos_integer() and undefined. +

+
+
- timeout() -

= infinity | integer() in milliseconds. Default infinity.

-
-
+ + + + +

The initial crypto_state() returned from the + init_fun() + is folded into repeated applications of the crypto_fun() in the + tar_crypto_spec. + The binary returned from that fun is sent to the remote SFTP server and + the new crypto_state() is used in the next call of the + crypto_fun(). +

+

If the crypto_fun() reurns a chunk_size(), that value + is as block size for further blocks in calls to crypto_fun(). +

+
+
-
- Time-outs -

If the request functions for the SFTP channel return {error, timeout}, - no answer was received from the server within the expected time.

-

The request may have reached the server and may have been performed. - However, no answer was received from the server within the expected time.

-
+ + + +

If doing encryption, + the final_fun() in the + tar_crypto_spec + is applied to the last piece of data. + The final_fun() is responsible for padding (if needed) and + encryption of that last piece. +

+
+
+ - apread(ChannelPid, Handle, Position, Len) -> {async, N} | {error, reason()} + Reads asynchronously from an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Len = integer() - N = term() -

The function reads from a specified position, combining the position/3 and aread/3 functions.

@@ -98,17 +144,8 @@
- apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | {error, reason()} + Writes asynchronously to an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Len = integer() - Data = binary() - Timeout = timeout() - N = term() -

The function writes to a specified position, combining the position/3 and awrite/3 functions.

@@ -116,15 +153,8 @@
- aread(ChannelPid, Handle, Len) -> {async, N} | {error, reason()} + Reads asynchronously from an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Len = integer() - N = term() -

Reads from an open file, without waiting for the result. If the handle is valid, the function returns , where N @@ -137,16 +167,8 @@ - awrite(ChannelPid, Handle, Data) -> {async, N} | {error, reason()} + Writes asynchronously to an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Len = integer() - Data = binary() - Timeout = timeout() -

Writes to an open file, without waiting for the result. If the handle is valid, the function returns , where N @@ -159,28 +181,18 @@ - close(ChannelPid, Handle) -> - close(ChannelPid, Handle, Timeout) -> ok | {error, reason()} + + Closes an open handle. - - ChannelPid = pid() - Handle = term() - Timeout = timeout() -

Closes a handle to an open file or directory on the server.

- delete(ChannelPid, Name) -> - delete(ChannelPid, Name, Timeout) -> ok | {error, reason()} + + Deletes a file. - - ChannelPid = pid() - Name = string() - Timeout = timeout() -

Deletes the file specified by .

@@ -188,14 +200,9 @@
- del_dir(ChannelPid, Name) -> - del_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()} + + Deletes an empty directory. - - ChannelPid = pid() - Name = string() - Timeout = timeout() -

Deletes a directory specified by . The directory must be empty before it can be successfully deleted. @@ -204,16 +211,9 @@ - list_dir(ChannelPid, Path) -> - list_dir(ChannelPid, Path, Timeout) -> {ok, Filenames} | {error, reason()} + + Lists the directory. - - ChannelPid = pid() - Path = string() - Filenames = [Filename] - Filename = string() - Timeout = timeout() -

Lists the given directory on the server, returning the filenames as a list of strings.

@@ -221,14 +221,9 @@
- make_dir(ChannelPid, Name) -> - make_dir(ChannelPid, Name, Timeout) -> ok | {error, reason()} + + Creates a directory. - - ChannelPid = pid() - Name = string() - Timeout = timeout() -

Creates a directory specified by . must be a full path to a new directory. The directory can only be @@ -237,14 +232,9 @@ - make_symlink(ChannelPid, Name, Target) -> - make_symlink(ChannelPid, Name, Target, Timeout) -> ok | {error, reason()} + + Creates a symbolic link. - - ChannelPid = pid() - Name = string() - Target = string() -

Creates a symbolic link pointing to with the name . @@ -252,32 +242,19 @@ - - open(ChannelPid, File, Mode) -> - open(ChannelPid, File, Mode, Timeout) -> {ok, Handle} | {error, reason()} + + + Opens a file and returns a handle. - - ChannelPid = pid() - File = string() - Mode = [Modeflag] - Modeflag = read | write | creat | trunc | append | binary - Timeout = timeout() - Handle = term() -

Opens a file on the server and returns a handle, which can be used for reading or writing.

- opendir(ChannelPid, Path) -> - opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | {error, reason()} + + Opens a directory and returns a handle. - - ChannelPid = pid() - Path = string() - Timeout = timeout() -

Opens a handle to a directory on the server. The handle can be used for reading directory contents.

@@ -285,72 +262,36 @@
- open_tar(ChannelPid, Path, Mode) -> - open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | {error, reason()} + + Opens a tar file on the server to which ChannelPid is connected and returns a handle. - - ChannelPid = pid() - Path = string() - Mode = [read] | [write] | [read,EncryptOpt] | [write,DecryptOpt] - EncryptOpt = {crypto,{InitFun,EncryptFun,CloseFun}} - DecryptOpt = {crypto,{InitFun,DecryptFun}} - InitFun = (fun() -> {ok,CryptoState}) | (fun() -> {ok,CryptoState,ChunkSize}) - CryptoState = any() - ChunkSize = undefined | pos_integer() - EncryptFun = (fun(PlainBin,CryptoState) -> EncryptResult) - EncryptResult = {ok,EncryptedBin,CryptoState} | {ok,EncryptedBin,CryptoState,ChunkSize} - PlainBin = binary() - EncryptedBin = binary() - DecryptFun = (fun(EncryptedBin,CryptoState) -> DecryptResult) - DecryptResult = {ok,PlainBin,CryptoState} | {ok,PlainBin,CryptoState,ChunkSize} - CloseFun = (fun(PlainBin,CryptoState) -> {ok,EncryptedBin}) - Timeout = timeout() -

Opens a handle to a tar file on the server, associated with ChannelPid. - The handle can be used for remote tar creation and extraction, as defined by the - erl_tar:init/3 function. -

- -

For code exampel see Section - SFTP Client with TAR Compression and Encryption in - the ssh Users Guide.

- -

The crypto mode option is applied to the generated stream of bytes prior to sending - them to the SFTP server. This is intended for encryption but can be used for other - purposes. + The handle can be used for remote tar creation and extraction. The actual writing + and reading is performed by calls to + erl_tar:add/3,4 and + erl_tar:extract/2. + Note: The + erl_tar:init/3 function should not + be called, that one is called by this open_tar function.

-

The InitFun is applied once - prior to any other crypto operation. The returned CryptoState is then folded into - repeated applications of the EncryptFun or DecryptFun. The binary returned - from those funs are sent further to the remote SFTP server. Finally, if doing encryption, - the CloseFun is applied to the last piece of data. The CloseFun is - responsible for padding (if needed) and encryption of that last piece. +

For code examples see Section + SFTP Client with TAR Compression + in the ssh Users Guide.

-

The ChunkSize defines the size of the PlainBins that EncodeFun is applied - to. If the ChunkSize is undefined, the size of the PlainBins varies, - because this is intended for stream crypto, whereas a fixed ChunkSize is intended for block crypto. - ChunkSizes can be changed in the return from the EncryptFun or - DecryptFun. The value can be changed between pos_integer() and undefined. +

The crypto mode option is explained in the data types section above, see + Crypto operations for open_tar. + Encryption is assumed if the Mode contains write, and + decryption if the Mode contains read.

-
- position(ChannelPid, Handle, Location) -> - position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, reason()} + + Sets the file position of a file. - - ChannelPid = pid() - Handle = term() - Location = Offset - | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof - Offset = integer() - Timeout = timeout() - NewPosition = integer() -

Sets the file position of the file referenced by . Returns (as an absolute offset) if @@ -384,17 +325,9 @@ - pread(ChannelPid, Handle, Position, Len) -> - pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | {error, reason()} + + Reads from an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Len = integer() - Timeout = timeout() - Data = string() | binary() -

The function reads from a specified position, combining the position/3 and read/3,4 functions.

@@ -402,16 +335,9 @@
- pwrite(ChannelPid, Handle, Position, Data) -> ok - pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, reason()} + + Writes to an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Data = iolist() - Timeout = timeout() -

The function writes to a specified position, combining the position/3 and write/3,4 functions.

@@ -419,16 +345,9 @@
- read(ChannelPid, Handle, Len) -> - read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | {error, reason()} + + Reads from an open file. - - ChannelPid = pid() - Handle = term() - Len = integer() - Timeout = timeout() - Data = string() | binary() -

Reads bytes from the file referenced by . Returns , , or @@ -440,32 +359,19 @@ - - read_file(ChannelPid, File) -> - read_file(ChannelPid, File, Timeout) -> {ok, Data} | {error, reason()} + + + Reads a file. - - ChannelPid = pid() - File = string() - Data = binary() - Timeout = timeout() -

Reads a file from the server, and returns the data in a binary.

- - read_file_info(ChannelPid, Name) -> - read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()} + + + Gets information about a file. - - ChannelPid = pid() - Name = string() - Handle = term() - Timeout = timeout() - FileInfo = record() -

Returns a record from the file system object specified by or . See @@ -474,38 +380,26 @@

Depending on the underlying OS:es links might be followed and info on the final file, directory - etc is returned. See ssh_sftp::read_link_info/2 + etc is returned. See read_link_info/2 on how to get information on links instead.

- read_link(ChannelPid, Name) -> - read_link(ChannelPid, Name, Timeout) -> {ok, Target} | {error, reason()} + + Reads symbolic link. - - ChannelPid = pid() - Name = string() - Target = string() -

Reads the link target from the symbolic link specified by .

- - read_link_info(ChannelPid, Name) -> {ok, FileInfo} | {error, reason()} - read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | {error, reason()} + + + Gets information about a symbolic link. - - ChannelPid = pid() - Name = string() - Handle = term() - Timeout = timeout() - FileInfo = record() -

Returns a record from the symbolic link specified by or . @@ -517,15 +411,9 @@ - rename(ChannelPid, OldName, NewName) -> - rename(ChannelPid, OldName, NewName, Timeout) -> ok | {error, reason()} + + Renames a file. - - ChannelPid = pid() - OldName = string() - NewName = string() - Timeout = timeout() -

Renames a file named and gives it the name . @@ -594,11 +482,8 @@ - stop_channel(ChannelPid) -> ok + Stops the SFTP client channel. - - ChannelPid = pid() -

Stops an SFTP channel. Does not close the SSH connection. Use ssh:close/1 to close it.

@@ -606,16 +491,9 @@
- write(ChannelPid, Handle, Data) -> - write(ChannelPid, Handle, Data, Timeout) -> ok | {error, reason()} + + Writes to an open file. - - ChannelPid = pid() - Handle = term() - Position = integer() - Data = iolist() - Timeout = timeout() -

Writes to the file referenced by . The file is to be opened with or @@ -625,15 +503,9 @@ - write_file(ChannelPid, File, Iolist) -> - write_file(ChannelPid, File, Iolist, Timeout) -> ok | {error, reason()} + + Writes a file. - - ChannelPid = pid() - File = string() - Iolist = iolist() - Timeout = timeout() -

Writes a file to the server. The file is created if it does not exist but overwritten if it exists.

@@ -641,15 +513,9 @@
- write_file_info(ChannelPid, Name, Info) -> - write_file_info(ChannelPid, Name, Info, Timeout) -> ok | {error, reason()} + + Writes information for a file. - - ChannelPid = pid() - Name = string() - Info = record() - Timeout = timeout() -

Writes file information from a record to the file specified by . See diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml index 4455d5ecc5..5c56dee81d 100644 --- a/lib/ssh/doc/src/using_ssh.xml +++ b/lib/ssh/doc/src/using_ssh.xml @@ -232,9 +232,10 @@

- SFTP Client with TAR Compression and Encryption - -

Example of writing and then reading a tar file follows:

+ SFTP Client with TAR Compression +
+ Basic example +

This is an example of writing and then reading a tar file:

{ok,HandleWrite} = ssh_sftp:open_tar(ChannelPid, ?tar_file_name, [write]), ok = erl_tar:add(HandleWrite, .... ), @@ -248,8 +249,12 @@ {ok,NameValueList} = erl_tar:extract(HandleRead,[memory]), ok = erl_tar:close(HandleRead), +
-

The previous write and read example can be extended with encryption and decryption as follows:

+
+ Example with encryption +

The previous Basic example + can be extended with encryption and decryption as follows:

%% First three parameters depending on which crypto type we select: Key = <<"This is a 256 bit key. abcdefghi">>, @@ -297,6 +302,7 @@ Cr = {InitFun,DecryptFun}, ok = erl_tar:close(HandleRead),
+
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index 1b2ba5a50b..9162de3487 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -92,16 +92,26 @@ -define(XF(S), S#state.xf). -define(REQID(S), S#state.req_id). + +-type reason() :: atom() | string() | tuple() . + %%==================================================================== %% API %%==================================================================== start_channel(Cm) when is_pid(Cm) -> start_channel(Cm, []); + start_channel(Socket) when is_port(Socket) -> start_channel(Socket, []); + start_channel(Host) when is_list(Host) -> start_channel(Host, []). + +-spec start_channel(ssh:connection_ref() | gen_tcp:socket() | string(), + ssh:client_options() + ) -> {ok,pid()} | {ok,pid(),ssh:connection_ref()} | {error,term()}. + start_channel(Socket, UserOptions) when is_port(Socket) -> {SshOpts, _ChanOpts, SftpOpts} = handle_options(UserOptions), Timeout = % A mixture of ssh:connect and ssh_sftp:start_channel: @@ -144,6 +154,10 @@ start_channel(Cm, UserOptions) when is_pid(Cm) -> start_channel(Host, UserOptions) -> start_channel(Host, 22, UserOptions). + +-spec start_channel(string(), integer(), ssh:client_options()) -> + {ok,pid(),ssh:connection_ref()} | {error,term()}. + start_channel(Host, Port, UserOptions) -> {SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), Timeout = % A mixture of ssh:connect and ssh_sftp:start_channel: @@ -168,6 +182,10 @@ start_channel(Host, Port, UserOptions) -> Error end. + +-spec stop_channel(ChannelPid) -> ok when + ChannelPid :: pid(). + stop_channel(Pid) -> case is_process_alive(Pid) of true -> @@ -188,17 +206,62 @@ stop_channel(Pid) -> wait_for_version_negotiation(Pid, Timeout) -> call(Pid, wait_for_version_negotiation, Timeout). +-spec open(ChannelPid, Name, Mode) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Name :: string(), + Mode :: [read | write | append | binary | raw], + Handle :: term(), + Error :: {error, reason()} . open(Pid, File, Mode) -> open(Pid, File, Mode, ?FILEOP_TIMEOUT). +-spec open(ChannelPid, Name, Mode, Timeout) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Name :: string(), + Mode :: [read | write | append | binary | raw], + Timeout :: timeout(), + Handle :: term(), + Error :: {error, reason()} . open(Pid, File, Mode, FileOpTimeout) -> call(Pid, {open, false, File, Mode}, FileOpTimeout). + +-type tar_crypto_spec() :: encrypt_spec() | decrypt_spec() . + +-type encrypt_spec() :: {init_fun(), crypto_fun(), final_fun()} . +-type decrypt_spec() :: {init_fun(), crypto_fun()} . + +-type init_fun() :: fun(() -> {ok,crypto_state()}) + | fun(() -> {ok,crypto_state(),chunk_size()}) . + +-type crypto_fun() :: fun((TextIn::binary(), crypto_state()) -> crypto_result()) . +-type crypto_result() :: {ok,TextOut::binary(),crypto_state()} + | {ok,TextOut::binary(),crypto_state(),chunk_size()} . + +-type final_fun() :: fun((FinalTextIn::binary(),crypto_state()) -> {ok,FinalTextOut::binary()}) . + +-type chunk_size() :: undefined | pos_integer(). +-type crypto_state() :: any() . + + +-spec open_tar(ChannelPid, Path, Mode) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Path :: string(), + Mode :: [read | write | {crypto, tar_crypto_spec()} ], + Handle :: term(), + Error :: {error, reason()} . open_tar(Pid, File, Mode) -> open_tar(Pid, File, Mode, ?FILEOP_TIMEOUT). +-spec open_tar(ChannelPid, Path, Mode, Timeout) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Path :: string(), + Mode :: [read | write | {crypto, tar_crypto_spec()} ], + Timeout :: timeout(), + Handle :: term(), + Error :: {error, reason()} . open_tar(Pid, File, Mode, FileOpTimeout) -> case {lists:member(write,Mode), lists:member(read,Mode), - Mode -- [read,write]} of + Mode -- [write,read]} of {true,false,[]} -> {ok,Handle} = open(Pid, File, [write], FileOpTimeout), erl_tar:init(Pid, write, @@ -264,13 +327,33 @@ open_tar(Pid, File, Mode, FileOpTimeout) -> end. +-spec opendir(ChannelPid, Path) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Path :: string(), + Handle :: term(), + Error :: {error, reason()} . opendir(Pid, Path) -> opendir(Pid, Path, ?FILEOP_TIMEOUT). +-spec opendir(ChannelPid, Path, Timeout) -> {ok, Handle} | Error when + ChannelPid :: pid(), + Path :: string(), + Timeout :: timeout(), + Handle :: term(), + Error :: {error, reason()} . opendir(Pid, Path, FileOpTimeout) -> call(Pid, {opendir, false, Path}, FileOpTimeout). +-spec close(ChannelPid, Handle) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Error :: {error, reason()} . close(Pid, Handle) -> close(Pid, Handle, ?FILEOP_TIMEOUT). +-spec close(ChannelPid, Handle, Timeout) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Timeout :: timeout(), + Error :: {error, reason()} . close(Pid, Handle, FileOpTimeout) -> call(Pid, {close,false,Handle}, FileOpTimeout). @@ -279,47 +362,149 @@ readdir(Pid,Handle) -> readdir(Pid,Handle, FileOpTimeout) -> call(Pid, {readdir,false,Handle}, FileOpTimeout). +-spec pread(ChannelPid, Handle, Position, Len) -> {ok, Data} | eof | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Len :: integer(), + Data :: string() | binary(), + Error :: {error, reason()}. pread(Pid, Handle, Offset, Len) -> pread(Pid, Handle, Offset, Len, ?FILEOP_TIMEOUT). + +-spec pread(ChannelPid, Handle, Position, Len, Timeout) -> {ok, Data} | eof | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Len :: integer(), + Timeout :: timeout(), + Data :: string() | binary(), + Error :: {error, reason()}. pread(Pid, Handle, Offset, Len, FileOpTimeout) -> call(Pid, {pread,false,Handle, Offset, Len}, FileOpTimeout). + +-spec read(ChannelPid, Handle, Len) -> {ok, Data} | eof | Error when + ChannelPid :: pid(), + Handle :: term(), + Len :: integer(), + Data :: string() | binary(), + Error :: {error, reason()}. read(Pid, Handle, Len) -> read(Pid, Handle, Len, ?FILEOP_TIMEOUT). + +-spec read(ChannelPid, Handle, Len, Timeout) -> {ok, Data} | eof | Error when + ChannelPid :: pid(), + Handle :: term(), + Len :: integer(), + Timeout :: timeout(), + Data :: string() | binary(), + Error :: {error, reason()}. read(Pid, Handle, Len, FileOpTimeout) -> call(Pid, {read,false,Handle, Len}, FileOpTimeout). + %% TODO this ought to be a cast! Is so in all practical meaning %% even if it is obscure! +-spec apread(ChannelPid, Handle, Position, Len) -> {async, N} | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Len :: integer(), + Error :: {error, reason()}, + N :: term() . apread(Pid, Handle, Offset, Len) -> call(Pid, {pread,true,Handle, Offset, Len}, infinity). %% TODO this ought to be a cast! +-spec aread(ChannelPid, Handle, Len) -> {async, N} | Error when + ChannelPid :: pid(), + Handle :: term(), + Len :: integer(), + Error :: {error, reason()}, + N :: term() . aread(Pid, Handle, Len) -> call(Pid, {read,true,Handle, Len}, infinity). + +-spec pwrite(ChannelPid, Handle, Position, Data) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Data :: iolist(), + Error :: {error, reason()}. pwrite(Pid, Handle, Offset, Data) -> pwrite(Pid, Handle, Offset, Data, ?FILEOP_TIMEOUT). + +-spec pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Data :: iolist(), + Timeout :: timeout(), + Error :: {error, reason()}. pwrite(Pid, Handle, Offset, Data, FileOpTimeout) -> call(Pid, {pwrite,false,Handle,Offset,Data}, FileOpTimeout). + +-spec write(ChannelPid, Handle, Data) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Data :: iodata(), + Error :: {error, reason()}. write(Pid, Handle, Data) -> write(Pid, Handle, Data, ?FILEOP_TIMEOUT). + +-spec write(ChannelPid, Handle, Data, Timeout) -> ok | Error when + ChannelPid :: pid(), + Handle :: term(), + Data :: iodata(), + Timeout :: timeout(), + Error :: {error, reason()}. write(Pid, Handle, Data, FileOpTimeout) -> call(Pid, {write,false,Handle,Data}, FileOpTimeout). %% TODO this ought to be a cast! Is so in all practical meaning %% even if it is obscure! +-spec apwrite(ChannelPid, Handle, Position, Data) -> {async, N} | Error when + ChannelPid :: pid(), + Handle :: term(), + Position :: integer(), + Data :: binary(), + Error :: {error, reason()}, + N :: term() . apwrite(Pid, Handle, Offset, Data) -> call(Pid, {pwrite,true,Handle,Offset,Data}, infinity). %% TODO this ought to be a cast! Is so in all practical meaning %% even if it is obscure! +-spec awrite(ChannelPid, Handle, Data) -> {async, N} | Error when + ChannelPid :: pid(), + Handle :: term(), + Data :: binary(), + Error :: {error, reason()}, + N :: term() . awrite(Pid, Handle, Data) -> call(Pid, {write,true,Handle,Data}, infinity). +-spec position(ChannelPid, Handle, Location) -> {ok, NewPosition} | Error when + ChannelPid :: pid(), + Handle :: term(), + Location :: Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof, + Offset :: integer(), + NewPosition :: integer(), + Error :: {error, reason()}. position(Pid, Handle, Pos) -> position(Pid, Handle, Pos, ?FILEOP_TIMEOUT). + +-spec position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition} | Error when + ChannelPid :: pid(), + Handle :: term(), + Location :: Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof, + Timeout :: timeout(), + Offset :: integer(), + NewPosition :: integer(), + Error :: {error, reason()}. position(Pid, Handle, Pos, FileOpTimeout) -> call(Pid, {position, Handle, Pos}, FileOpTimeout). @@ -328,8 +513,21 @@ real_path(Pid, Path) -> real_path(Pid, Path, FileOpTimeout) -> call(Pid, {real_path, false, Path}, FileOpTimeout). + +-spec read_file_info(ChannelPid, Name) -> {ok, FileInfo} | Error when + ChannelPid :: pid(), + Name :: string(), + FileInfo :: file:file_info(), + Error :: {error, reason()}. read_file_info(Pid, Name) -> read_file_info(Pid, Name, ?FILEOP_TIMEOUT). + +-spec read_file_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | Error when + ChannelPid :: pid(), + Name :: string(), + Timeout :: timeout(), + FileInfo :: file:file_info(), + Error :: {error, reason()}. read_file_info(Pid, Name, FileOpTimeout) -> call(Pid, {read_file_info,false,Name}, FileOpTimeout). @@ -338,18 +536,57 @@ get_file_info(Pid, Handle) -> get_file_info(Pid, Handle, FileOpTimeout) -> call(Pid, {get_file_info,false,Handle}, FileOpTimeout). + +-spec write_file_info(ChannelPid, Name, FileInfo) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + FileInfo :: file:file_info(), + Error :: {error, reason()}. write_file_info(Pid, Name, Info) -> write_file_info(Pid, Name, Info, ?FILEOP_TIMEOUT). + +-spec write_file_info(ChannelPid, Name, FileInfo, Timeout) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + FileInfo :: file:file_info(), + Timeout :: timeout(), + Error :: {error, reason()}. write_file_info(Pid, Name, Info, FileOpTimeout) -> call(Pid, {write_file_info,false,Name, Info}, FileOpTimeout). + +-spec read_link_info(ChannelPid, Name) -> {ok, FileInfo} | Error when + ChannelPid :: pid(), + Name :: string(), + FileInfo :: file:file_info(), + Error :: {error, reason()}. read_link_info(Pid, Name) -> read_link_info(Pid, Name, ?FILEOP_TIMEOUT). + +-spec read_link_info(ChannelPid, Name, Timeout) -> {ok, FileInfo} | Error when + ChannelPid :: pid(), + Name :: string(), + FileInfo :: file:file_info(), + Timeout :: timeout(), + Error :: {error, reason()}. read_link_info(Pid, Name, FileOpTimeout) -> call(Pid, {read_link_info,false,Name}, FileOpTimeout). + +-spec read_link(ChannelPid, Name) -> {ok, Target} | Error when + ChannelPid :: pid(), + Name :: string(), + Target :: string(), + Error :: {error, reason()}. read_link(Pid, LinkName) -> read_link(Pid, LinkName, ?FILEOP_TIMEOUT). + +-spec read_link(ChannelPid, Name, Timeout) -> {ok, Target} | Error when + ChannelPid :: pid(), + Name :: string(), + Target :: string(), + Timeout :: timeout(), + Error :: {error, reason()}. read_link(Pid, LinkName, FileOpTimeout) -> case call(Pid, {read_link,false,LinkName}, FileOpTimeout) of {ok, [{Name, _Attrs}]} -> @@ -358,28 +595,79 @@ read_link(Pid, LinkName, FileOpTimeout) -> ErrMsg end. +-spec make_symlink(ChannelPid, Name, Target) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Target :: string(), + Error :: {error, reason()} . make_symlink(Pid, Name, Target) -> make_symlink(Pid, Name, Target, ?FILEOP_TIMEOUT). +-spec make_symlink(ChannelPid, Name, Target, Timeout) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Target :: string(), + Timeout :: timeout(), + Error :: {error, reason()} . make_symlink(Pid, Name, Target, FileOpTimeout) -> call(Pid, {make_symlink,false, Name, Target}, FileOpTimeout). + +-spec rename(ChannelPid, OldName, NewName) -> ok | Error when + ChannelPid :: pid(), + OldName :: string(), + NewName :: string(), + Error :: {error, reason()}. rename(Pid, FromFile, ToFile) -> rename(Pid, FromFile, ToFile, ?FILEOP_TIMEOUT). + +-spec rename(ChannelPid, OldName, NewName, Timeout) -> ok | Error when + ChannelPid :: pid(), + OldName :: string(), + NewName :: string(), + Timeout :: timeout(), + Error :: {error, reason()}. rename(Pid, FromFile, ToFile, FileOpTimeout) -> call(Pid, {rename,false,FromFile, ToFile}, FileOpTimeout). +-spec delete(ChannelPid, Name) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Error :: {error, reason()} . delete(Pid, Name) -> delete(Pid, Name, ?FILEOP_TIMEOUT). +-spec delete(ChannelPid, Name, Timeout) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Timeout :: timeout(), + Error :: {error, reason()} . delete(Pid, Name, FileOpTimeout) -> call(Pid, {delete,false,Name}, FileOpTimeout). +-spec make_dir(ChannelPid, Name) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Error :: {error, reason()} . make_dir(Pid, Name) -> make_dir(Pid, Name, ?FILEOP_TIMEOUT). +-spec make_dir(ChannelPid, Name, Timeout) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Timeout :: timeout(), + Error :: {error, reason()} . make_dir(Pid, Name, FileOpTimeout) -> call(Pid, {make_dir,false,Name}, FileOpTimeout). +-spec del_dir(ChannelPid, Name) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Error :: {error, reason()} . del_dir(Pid, Name) -> del_dir(Pid, Name, ?FILEOP_TIMEOUT). +-spec del_dir(ChannelPid, Name, Timeout) -> ok | Error when + ChannelPid :: pid(), + Name :: string(), + Timeout :: timeout(), + Error :: {error, reason()} . del_dir(Pid, Name, FileOpTimeout) -> call(Pid, {del_dir,false,Name}, FileOpTimeout). @@ -396,9 +684,21 @@ recv_window(Pid, FileOpTimeout) -> call(Pid, recv_window, FileOpTimeout). +-spec list_dir(ChannelPid, Path) -> {ok,FileNames} | Error when + ChannelPid :: pid(), + Path :: string(), + FileNames :: [FileName], + FileName :: string(), + Error :: {error, reason()} . list_dir(Pid, Name) -> list_dir(Pid, Name, ?FILEOP_TIMEOUT). - +-spec list_dir(ChannelPid, Path, Timeout) -> {ok,FileNames} | Error when + ChannelPid :: pid(), + Path :: string(), + Timeout :: timeout(), + FileNames :: [FileName], + FileName :: string(), + Error :: {error, reason()} . list_dir(Pid, Name, FileOpTimeout) -> case opendir(Pid, Name, FileOpTimeout) of {ok,Handle} -> @@ -429,9 +729,20 @@ do_list_dir(Pid, Handle, FileOpTimeout, Acc) -> end. +-spec read_file(ChannelPid, File) -> {ok, Data} | Error when + ChannelPid :: pid(), + File :: string(), + Data :: binary(), + Error :: {error, reason()}. read_file(Pid, Name) -> read_file(Pid, Name, ?FILEOP_TIMEOUT). +-spec read_file(ChannelPid, File, Timeout) -> {ok, Data} | Error when + ChannelPid :: pid(), + File :: string(), + Data :: binary(), + Timeout :: timeout(), + Error :: {error, reason()}. read_file(Pid, Name, FileOpTimeout) -> case open(Pid, Name, [read, binary], FileOpTimeout) of {ok, Handle} -> @@ -453,9 +764,20 @@ read_file_loop(Pid, Handle, PacketSz, FileOpTimeout, Acc) -> Error end. +-spec write_file(ChannelPid, File, Data) -> ok | Error when + ChannelPid :: pid(), + File :: string(), + Data :: iodata(), + Error :: {error, reason()}. write_file(Pid, Name, List) -> write_file(Pid, Name, List, ?FILEOP_TIMEOUT). +-spec write_file(ChannelPid, File, Data, Timeout) -> ok | Error when + ChannelPid :: pid(), + File :: string(), + Data :: iodata(), + Timeout :: timeout(), + Error :: {error, reason()}. write_file(Pid, Name, List, FileOpTimeout) when is_list(List) -> write_file(Pid, Name, list_to_binary(List), FileOpTimeout); write_file(Pid, Name, Bin, FileOpTimeout) -> -- cgit v1.2.3 From edbbc40fc3e4d5698408e109ac6f9fd301aae05f Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Mon, 5 Aug 2019 12:41:17 +0200 Subject: ssh: Update ssh_sftp:start_channel documentation and code The Typing in the old documentation was not up-to-date. The option handling and definition is slightly re-worked in the code also. Some comments added and a function moved inside the module. --- lib/ssh/doc/src/ssh_sftp.xml | 32 ++++++++++++++--------- lib/ssh/src/ssh.erl | 2 ++ lib/ssh/src/ssh_sftp.erl | 62 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index 76d2b21946..f9f1e0953b 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -38,6 +38,12 @@ + + + + + + Error cause @@ -423,25 +429,27 @@ start_channel(ConnectionRef) -> - start_channel(ConnectionRef, Options) -> - {ok, Pid} | {error, reason()|term()} + start_channel(ConnectionRef, SftpOptions) -> + {ok, ChannelPid} | Error + start_channel(Host) -> start_channel(Host, Options) -> - start_channel(Host, Port, Options) -> - {ok, Pid, ConnectionRef} | {error, reason()|term()} - + start_channel(Host, Port, Options) -> start_channel(TcpSocket) -> start_channel(TcpSocket, Options) -> - {ok, Pid, ConnectionRef} | {error, reason()|term()} + {ok, ChannelPid, ConnectionRef} | Error Starts an SFTP client. - Host = string() - ConnectionRef = connection_ref() - Port = integer() - TcpSocket = port() - The socket is supposed to be from gen_tcp:connect or gen_tcp:accept with option {active,false} - Options = [{Option, Value}] + Host = ssh:host() + Port = inet:port_number() + TcpSocket = ssh:open_socket() + Options = [ sftp_option() + | ssh:client_option() ] + SftpOptions = [ sftp_option() ] + ChannelPid = pid() + ConnectionRef = ssh:connection_ref() + Error = {error, reason()}

If no connection reference is provided, a connection is set diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index ff5aee14d7..32f10c797d 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -66,6 +66,8 @@ cipher_alg/0, mac_alg/0, compression_alg/0, + host/0, + open_socket/0, ip_port/0 ]). diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl index 9162de3487..4b6e187c3a 100644 --- a/lib/ssh/src/ssh_sftp.erl +++ b/lib/ssh/src/ssh_sftp.erl @@ -92,34 +92,63 @@ -define(XF(S), S#state.xf). -define(REQID(S), S#state.req_id). +-type sftp_option() :: {timeout, timeout()} + | {sftp_vsn, pos_integer()} + | {window_size, pos_integer()} + | {packet_size, pos_integer()} . -type reason() :: atom() | string() | tuple() . %%==================================================================== %% API %%==================================================================== + + +%%%================================================================ +%%% + +%%%---------------------------------------------------------------- +%%% start_channel/1 + start_channel(Cm) when is_pid(Cm) -> start_channel(Cm, []); - + start_channel(Socket) when is_port(Socket) -> start_channel(Socket, []); -start_channel(Host) when is_list(Host) -> +start_channel(Host) -> start_channel(Host, []). --spec start_channel(ssh:connection_ref() | gen_tcp:socket() | string(), - ssh:client_options() - ) -> {ok,pid()} | {ok,pid(),ssh:connection_ref()} | {error,term()}. +%%%---------------------------------------------------------------- +%%% start_channel/2 + +%%% -spec:s are as if Dialyzer handled signatures for separate +%%% function clauses. + +-spec start_channel(ssh:open_socket(), + [ssh:client_options() | sftp_option()] + ) + -> {ok,pid(),ssh:connection_ref()} | {error,reason()}; + + (ssh:connection_ref(), + [sftp_option()] + ) + -> {ok,pid()} | {ok,pid(),ssh:connection_ref()} | {error,reason()}; + + (ssh:host(), + [ssh:client_options() | sftp_option()] + ) + -> {ok,pid(),ssh:connection_ref()} | {error,reason()} . start_channel(Socket, UserOptions) when is_port(Socket) -> - {SshOpts, _ChanOpts, SftpOpts} = handle_options(UserOptions), + {SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), Timeout = % A mixture of ssh:connect and ssh_sftp:start_channel: proplists:get_value(connect_timeout, SshOpts, proplists:get_value(timeout, SftpOpts, infinity)), case ssh:connect(Socket, SshOpts, Timeout) of {ok,Cm} -> - case start_channel(Cm, UserOptions) of + case start_channel(Cm, ChanOpts ++ SftpOpts) of {ok, Pid} -> {ok, Pid, Cm}; Error -> @@ -155,8 +184,14 @@ start_channel(Host, UserOptions) -> start_channel(Host, 22, UserOptions). --spec start_channel(string(), integer(), ssh:client_options()) -> - {ok,pid(),ssh:connection_ref()} | {error,term()}. +%%%---------------------------------------------------------------- +%%% start_channel/3 + +-spec start_channel(ssh:host(), + inet:port_number(), + [ssh:client_option() | sftp_option()] + ) + -> {ok,pid(),ssh:connection_ref()} | {error,reason()}. start_channel(Host, Port, UserOptions) -> {SshOpts, ChanOpts, SftpOpts} = handle_options(UserOptions), @@ -182,7 +217,12 @@ start_channel(Host, Port, UserOptions) -> Error end. +%%% Helper for start_channel +wait_for_version_negotiation(Pid, Timeout) -> + call(Pid, wait_for_version_negotiation, Timeout). + +%%%---------------------------------------------------------------- -spec stop_channel(ChannelPid) -> ok when ChannelPid :: pid(). @@ -203,9 +243,7 @@ stop_channel(Pid) -> ok end. -wait_for_version_negotiation(Pid, Timeout) -> - call(Pid, wait_for_version_negotiation, Timeout). - +%%%---------------------------------------------------------------- -spec open(ChannelPid, Name, Mode) -> {ok, Handle} | Error when ChannelPid :: pid(), Name :: string(), -- cgit v1.2.3 From e7abd910a9cd94677bbcb19cdf5a2bdc2cb83279 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Wed, 7 Aug 2019 17:17:54 +0200 Subject: ssh: The ssh_connection documentation is now generated --- lib/ssh/doc/src/ssh_connection.xml | 411 +++++++++++++++++++------------------ lib/ssh/src/ssh_connection.erl | 160 ++++++++++++--- 2 files changed, 345 insertions(+), 226 deletions(-) diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index 2a701929f6..ea41ccf252 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -40,105 +40,148 @@

The SSH Connection Protocol is used by clients and servers, that is, SSH channels, to communicate over the SSH connection. The API functions in this module send SSH Connection Protocol events, - which are received as messages by the remote channel. - If the receiving channel is an Erlang process, the - messages have the format - . + which are received as messages by the remote channel handling the remote channel. + The Erlang format of thoose messages is + (see also below): +

+

{ssh_cm, ssh:connection_ref(), ssh_event_msg()} +

+

If the ssh_client_channel behavior is used to implement the channel process, these messages are handled by handle_ssh_msg/2.

-
- DATA TYPES - -

Type definitions that are used more than once in this module, - or abstractions to indicate the intended use of the data - type, or both:

- - - boolean() = -

true | false

- string() = -

list of ASCII characters

- timeout() = -

infinity | integer() in milliseconds

- connection_ref() = -

opaque() -as returned by - ssh:connect/3 or sent to an SSH channel processes

- channel_id() = -

integer()

- ssh_data_type_code() = -

1 ("stderr") | 0 ("normal") are - valid values, see - RFC 4254 Section 5.2.

- ssh_request_status() = -

success | failure

- event() = -

{ssh_cm, connection_ref(), ssh_event_msg()}

- ssh_event_msg() = -

data_events() | status_events() | terminal_events()

- reason() = -

timeout | closed

-
- - - data_events() - - - -

Data has arrived on the channel. This event is sent as a - result of calling - ssh_connection:send/[3,4,5].

- - -

Indicates that the other side sends no more data. - This event is sent as a result of calling ssh_connection:send_eof/2. -

-
-
+ + + + +

The valid values are 0 ("normal") and 1 ("stderr"), see + RFC 4254, Section 5.2.

+
+
+ + + + + +

The result of a call.

+

If the request reached the peer, was handled and the response + reached the requesting node the req_status() + is the status reported from the peer.

+

If not, the reason() indicates what went wrong:

+ + closed + indicates that the channel or connection was closed when trying to send the request + + timeout + indicates that the operation exceeded a time limit + + +
+
+ + + + +

The status of a request. + Coresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in + RFC 4254, Section 5.4. +

+
+
+ + SSH Connection Protocol: General + + + + +

As mentioned in the introduction, the + SSH Connection Protocol + events are handled as messages. When writing a channel handling process without using + the support by the ssh_client_channel + behavior the process must handle thoose messages. +

+
+
- status_events() - + SSH Connection Protocol: Data Events + + + + + + + + + +

Data has arrived on the channel. This event is sent as a result of calling + ssh_connection:send/[3,4,5]. +

+
+
+ + + +

Indicates that the other side sends no more data. This event is sent as a result of calling + ssh_connection:send_eof/2. +

+
+
+ + SSH Connection Protocol: Status Events + + + + + - - -

A signal can be delivered to the remote process/service + + + +

A signal can be delivered to the remote process/service using the following message. Some systems do not support signals, in which case they are to ignore this message. There is currently no function to generate this event as the signals referred to are on OS-level and not something generated by an - Erlang program.

- - + Erlang program.

+ + -

A remote execution can terminate violently because of a signal. + + + +

A remote execution can terminate violently because of a signal. Then this message can be received. For details on valid string values, see RFC 4254 - Section 6.10, which shows a special case of these signals.

- - -

When the command running at the other end terminates, the + Section 6.10, which shows a special case of these signals.

+ + + + + +

When the command running at the other end terminates, the following message can be sent to return the exit status of the command. A zero exit_status usually means that the command terminated successfully. This event is sent as a result of calling - ssh_connection:exit_status/3.

- - -

This event is sent as a result of calling + ssh_connection:exit_status/3.

+ + + + + +

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_client_channel behavior.

- -
-
- - terminal_events() + ssh_client_channel behavior.

+ + - + SSH Connection Protocol: Terminal Events + + +

Channels implementing a shell and command execution on the server side are to handle the following messages that can be sent by client- channel processes.

@@ -146,22 +189,24 @@

Events that include a WantReply expect the event handling process to call ssh_connection:reply_request/4 - with the boolean value of WantReply as the second argument.

+ with the boolean value of WantReply as the second argument.

+
+
- - -

Environment variables can be passed to the shell/command + + + +

Environment variables can be passed to the shell/command to be started later. This event is sent as a result of calling ssh_connection:setenv/5. -

- - -

A pseudo-terminal has been requested for the +

+ + + + + + +

A pseudo-terminal has been requested for the session. Terminal is the value of the TERM environment variable value, that is, vt100. Zero dimension parameters must be ignored. The character/row dimensions override the pixel @@ -173,42 +218,48 @@ It can also be an Opcode if the mnemonic name is not listed in the RFC. Example: OP code: 53, mnemonic name ECHO erlang atom: echo. This event is sent as a result of calling ssh_connection:ptty_alloc/4.

+ marker="ssh_connection#ptty_alloc/4">ssh_connection:ptty_alloc/4.

+ + - -

This message requests that the user default shell + + + +

This message requests that the user default shell is started at the other end. This event is sent as a result of calling ssh_connection:shell/2. -

+

+ + - -

When the window (terminal) size changes on the client + + + +

When the window (terminal) size changes on the client side, it can send a message to the server side to inform it of - the new dimensions. No API function generates this event.

+ the new dimensions. No API function generates this event.

+ + - -

This message requests that the server starts + + + +

This message requests that the server starts execution of the given command. This event is sent as a result of calling ssh_connection:exec/4 . -

-
-
-
-
+

+
+
+ +
+ - adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok + Adjusts the SSH flow control window. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - NumOfBytes = integer() - - +

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

@@ -221,17 +272,12 @@
- close(ConnectionRef, ChannelId) -> ok + Sends a close message on the channel ChannelId. - - ConnectionRef = connection_ref() - ChannelId = channel_id() -

A server- or client-channel process can choose to close their session by sending a close event.

-

This function is called by the ssh_client_channel behavior when the channel is terminated, see ssh_client_channel(3). Thus, channels implemented @@ -240,57 +286,61 @@ - exec(ConnectionRef, ChannelId, Command, TimeOut) -> ssh_request_status() | - {error, reason()} + Requests that the server starts the execution of the given command. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - Command = string() - Timeout = timeout() -

Is to be called by a client-channel process to request that the server starts executing the given command. The result is several messages according to the following pattern. The last message is a channel close message, as the exec request is a one-time execution that closes the channel when it is done.

- - N x {ssh_cm, connection_ref(), - {data, channel_id(), ssh_data_type_code(), Data :: binary()}} + + + + N x data message(s) +

The result of executing the command can be only one line + or thousands of lines depending on the command.

+ + 0 or 1 x eof message +

Indicates that no more data is to be sent.

+ + 0 or 1 x exit signal message +

Not all systems send signals. For details on valid string + values, see RFC 4254, Section 6.10

+ + 0 or 1 x exit status message +

It is recommended by the SSH Connection Protocol to send this + message, but that is not always the case.

+ + 1 x closed status message +

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

- exit_status(ConnectionRef, ChannelId, Status) -> ok + Sends the exit status of a command to the client. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - Status = integer() -

Is to be called by a server-channel process to send the exit status of a command to the client.

@@ -298,16 +348,10 @@
- ptty_alloc(ConnectionRef, ChannelId, Options) -> - ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> > ssh_request_status() | - {error, reason()} + + Sends an SSH Connection Protocol pty_req, to allocate a pseudo-terminal. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - Options = proplists:proplist() -

Sends an SSH Connection Protocol pty_req, to allocate a pseudo-terminal. Is to be called by an SSH client process.

@@ -339,14 +383,8 @@
- reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok + Sends status replies to requests that want such replies. - - ConnectionRef = connection_ref() - WantReply = boolean() - Status = ssh_request_status() - ChannelId = channel_id() -

Sends status replies to requests where the requester has stated that it wants a status report, that is, WantReply = true. @@ -361,14 +399,15 @@ send(ConnectionRef, ChannelId, Data, Timeout) -> send(ConnectionRef, ChannelId, Type, Data) -> send(ConnectionRef, ChannelId, Type, Data, TimeOut) -> - ok | {error, timeout} | {error, closed} + ok | Error Sends channel data. - ConnectionRef = connection_ref() - ChannelId = channel_id() + ConnectionRef = ssh:connection_ref() + ChannelId = ssh:channel_id() Data = binary() - Type = ssh_data_type_code() + Type = ssh_data_type_code() Timeout = timeout() + Error = {error, reason()}

Is to be called by client- and server-channel processes to send data to each other. @@ -380,29 +419,17 @@ - send_eof(ConnectionRef, ChannelId) -> ok | {error, closed} + Sends EOF on channel ChannelId. - - ConnectionRef = connection_ref() - ChannelId = channel_id() -

Sends EOF on channel ChannelId.

- session_channel(ConnectionRef, Timeout) -> - session_channel(ConnectionRef, InitialWindowSize, - MaxPacketSize, Timeout) -> {ok, channel_id()} | {error, reason()} + + Opens a channel for an SSH session. - - ConnectionRef = connection_ref() - InitialWindowSize = integer() - MaxPacketSize = integer() - Timeout = timeout() - Reason = term() -

Opens a channel for an SSH session. The channel id returned from this function is the id used as input to the other functions in this module.

@@ -410,17 +437,9 @@
- setenv(ConnectionRef, ChannelId, Var, Value, TimeOut) -> ssh_request_status() | - {error, reason()} + Environment variables can be passed to the shell/command to be started later. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - Var = string() - Value = string() - Timeout = timeout() -

Environment variables can be passed before starting the shell/command. Is to be called by a client channel processes.

@@ -428,14 +447,9 @@
- shell(ConnectionRef, ChannelId) -> ok | failure | {error, closed} - + Requests that the user default shell (typically defined in /etc/passwd in Unix systems) is to be executed at the server end. - - ConnectionRef = connection_ref() - ChannelId = channel_id() -

Is to be called by a client channel process to request that the user default shell (typically defined in /etc/passwd in Unix systems) is executed @@ -448,15 +462,8 @@ - subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> ssh_request_status() | - {error, reason()} + Requests to execute a predefined subsystem on the server. - - ConnectionRef = connection_ref() - ChannelId = channel_id() - Subsystem = string() - Timeout = timeout() -

Is to be called by a client-channel process for requesting to execute a predefined subsystem on the server. diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 83f85b1d8e..1e54be2a16 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -67,6 +67,79 @@ -type connection_ref() :: ssh:connection_ref(). -type channel_id() :: ssh:channel_id(). +-type req_status() :: success | failure . +-type reason() :: closed | timeout . + +-type result() :: req_status() | {error, reason()} . + +-type ssh_data_type_code() :: non_neg_integer(). % Only 0 and 1 are used + + +%%% The SSH Connection Protocol + +-export_type([event/0, + ssh_event_msg/0, + data_event/0, + data_data_event/0, + data_eof_event/0, + status_event/0, + status_signal_event/0, + status_exit_signal_event/0, + status_exit_status_event/0, + status_closed_event/0, + terminal_event/0, + terminal_env_event/0, + terminal_pty_event/0, + terminal_shell_event/0, + terminal_window_change_event/0, + terminal_exec_event/0 + ]). + +-type event() :: {ssh_cm, ssh:connection_ref(), ssh_event_msg()}. +-type ssh_event_msg() :: data_event() | status_event() | terminal_event() . + +-type data_event() :: data_data_event() + | data_eof_event() . +-type data_data_event() :: {data, ssh:channel_id(), ssh_data_type_code(), Data :: binary()} . +-type data_eof_event() :: {eof, ssh:channel_id()} . + + +-type status_event() :: status_signal_event() + | status_exit_signal_event() + | status_exit_status_event() + | status_closed_event() . + +-type status_signal_event() :: {signal, ssh:channel_id(), SignalName::string()} . +-type status_exit_signal_event() :: {exit_signal, ssh:channel_id(), + ExitSignal :: string(), + ErrorMsg ::string(), + LanguageString :: string()} . +-type status_exit_status_event() :: {exit_status, ssh:channel_id(), ExitStatus :: integer()} . +-type status_closed_event() :: {closed, ssh:channel_id()} . + +-type terminal_event() :: terminal_env_event() + | terminal_pty_event() + | terminal_shell_event() + | terminal_window_change_event() + | terminal_exec_event() . + +-type terminal_env_event() :: {env, ssh:channel_id(), WantReply :: boolean(), Var ::string(), Value :: string()} . +-type terminal_pty_event() :: {pty, ssh:channel_id(), + WantReply :: boolean(), + {Terminal :: string(), CharWidth :: integer(), RowHeight :: integer(), PixelWidth :: integer(), PixelHeight :: integer(), + TerminalModes :: [{Opcode :: atom() | integer(), + Value :: integer()}]}} . +-type terminal_shell_event() :: {shell, WantReply :: boolean()} . +-type terminal_window_change_event() :: {window_change, ssh:channel_id(), CharWidth :: integer(), + RowHeight :: integer(), PixWidth :: integer(), PixHeight :: integer()} . +-type terminal_exec_event() :: {exec, ssh:channel_id(), WantReply :: boolean(), Cmd :: string()} . + +%%% This function is soley to convince all +%%% checks that the type event() exists... +-export([dummy/1]). +-spec dummy(event()) -> false. +dummy(_) -> false. + %%-------------------------------------------------------------------- %%% API %%-------------------------------------------------------------------- @@ -77,14 +150,21 @@ %% application, a system command, or some built-in subsystem. %% -------------------------------------------------------------------- --spec session_channel(connection_ref(), timeout()) -> - {ok, channel_id()} | {error, timeout | closed}. +-spec session_channel(ConnectionRef, Timeout) -> Result when + ConnectionRef :: ssh:connection_ref(), + Timeout :: timeout(), + Result :: {ok, ssh:channel_id()} | {error, reason()} . session_channel(ConnectionHandler, Timeout) -> session_channel(ConnectionHandler, ?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout). --spec session_channel(connection_ref(), integer(), integer(), timeout()) -> - {ok, channel_id()} | {error, timeout | closed}. + +-spec session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout) -> Result when + ConnectionRef :: ssh:connection_ref(), + InitialWindowSize :: pos_integer(), + MaxPacketSize :: pos_integer(), + Timeout :: timeout(), + Result :: {ok, ssh:channel_id()} | {error, reason()} . session_channel(ConnectionHandler, InitialWindowSize, MaxPacketSize, Timeout) -> case ssh_connection_handler:open_channel(ConnectionHandler, "session", <<>>, @@ -100,8 +180,11 @@ session_channel(ConnectionHandler, InitialWindowSize, MaxPacketSize, Timeout) -> %% Description: Will request that the server start the %% execution of the given command. %%-------------------------------------------------------------------- --spec exec(connection_ref(), channel_id(), string(), timeout()) -> - success | failure | {error, timeout | closed}. +-spec exec(ConnectionRef, ChannelId, Command, Timeout) -> result() when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Command :: string(), + Timeout :: timeout(). exec(ConnectionHandler, ChannelId, Command, TimeOut) -> ssh_connection_handler:request(ConnectionHandler, self(), ChannelId, "exec", @@ -112,8 +195,10 @@ exec(ConnectionHandler, ChannelId, Command, TimeOut) -> %% defined in /etc/passwd in UNIX systems) be started at the other %% end. %%-------------------------------------------------------------------- --spec shell(connection_ref(), channel_id()) -> - ok | success | failure | {error, timeout}. +-spec shell(ConnectionRef, ChannelId) -> Result when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Result :: ok | success | failure | {error, timeout} . shell(ConnectionHandler, ChannelId) -> ssh_connection_handler:request(ConnectionHandler, self(), ChannelId, @@ -122,8 +207,11 @@ shell(ConnectionHandler, ChannelId) -> %% %% Description: Executes a predefined subsystem. %%-------------------------------------------------------------------- --spec subsystem(connection_ref(), channel_id(), string(), timeout()) -> - success | failure | {error, timeout | closed}. +-spec subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> result() when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Subsystem :: string(), + Timeout :: timeout(). subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) -> ssh_connection_handler:request(ConnectionHandler, self(), @@ -134,12 +222,13 @@ subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) -> %%-------------------------------------------------------------------- -spec send(connection_ref(), channel_id(), iodata()) -> ok | {error, timeout | closed}. + send(ConnectionHandler, ChannelId, Data) -> send(ConnectionHandler, ChannelId, 0, Data, infinity). --spec send(connection_ref(), channel_id(), integer()| iodata(), timeout() | iodata()) -> - ok | {error, timeout | closed}. +-spec send(connection_ref(), channel_id(), iodata(), timeout()) -> ok | {error, reason()}; + (connection_ref(), channel_id(), ssh_data_type_code(), iodata()) -> ok | {error, reason()}. send(ConnectionHandler, ChannelId, Data, TimeOut) when is_integer(TimeOut) -> send(ConnectionHandler, ChannelId, 0, Data, TimeOut); @@ -151,14 +240,15 @@ send(ConnectionHandler, ChannelId, Type, Data) -> send(ConnectionHandler, ChannelId, Type, Data, infinity). --spec send(connection_ref(), channel_id(), integer(), iodata(), timeout()) -> - ok | {error, timeout | closed}. +-spec send(connection_ref(), channel_id(), ssh_data_type_code(), iodata(), timeout()) -> ok | {error, reason()}. send(ConnectionHandler, ChannelId, Type, Data, TimeOut) -> ssh_connection_handler:send(ConnectionHandler, ChannelId, Type, Data, TimeOut). %%-------------------------------------------------------------------- --spec send_eof(connection_ref(), channel_id()) -> ok | {error, closed}. +-spec send_eof(ConnectionRef, ChannelId) -> ok | {error, closed} when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(). %% %% %% Description: Sends eof on the channel . @@ -167,7 +257,10 @@ send_eof(ConnectionHandler, Channel) -> ssh_connection_handler:send_eof(ConnectionHandler, Channel). %%-------------------------------------------------------------------- --spec adjust_window(connection_ref(), channel_id(), integer()) -> ok. +-spec adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + NumOfBytes :: integer(). %% %% %% Description: Adjusts the ssh flowcontrol window. @@ -176,8 +269,12 @@ adjust_window(ConnectionHandler, Channel, Bytes) -> ssh_connection_handler:adjust_window(ConnectionHandler, Channel, Bytes). %%-------------------------------------------------------------------- --spec setenv(connection_ref(), channel_id(), string(), string(), timeout()) -> - success | failure | {error, timeout | closed}. +-spec setenv(ConnectionRef, ChannelId, Var, Value, Timeout) -> result() when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Var :: string(), + Value :: string(), + Timeout :: timeout(). %% %% %% Description: Environment variables may be passed to the shell/command to be @@ -189,7 +286,9 @@ setenv(ConnectionHandler, ChannelId, Var, Value, TimeOut) -> %%-------------------------------------------------------------------- --spec close(connection_ref(), channel_id()) -> ok. +-spec close(ConnectionRef, ChannelId) -> ok when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(). %% %% %% Description: Sends a close message on the channel . @@ -198,7 +297,11 @@ close(ConnectionHandler, ChannelId) -> ssh_connection_handler:close(ConnectionHandler, ChannelId). %%-------------------------------------------------------------------- --spec reply_request(connection_ref(), boolean(), success | failure, channel_id()) -> ok. +-spec reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok when + ConnectionRef :: ssh:connection_ref(), + WantReply :: boolean(), + Status :: req_status(), + ChannelId :: ssh:channel_id(). %% %% %% Description: Send status replies to requests that want such replies. @@ -211,15 +314,20 @@ reply_request(_,false, _, _) -> %%-------------------------------------------------------------------- %% Description: Sends a ssh connection protocol pty_req. %%-------------------------------------------------------------------- --spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist()) -> - success | failure | {error, timeout}. +-spec ptty_alloc(ConnectionRef, ChannelId, Options) -> result() when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Options :: proplists:proplist(). ptty_alloc(ConnectionHandler, Channel, Options) -> ptty_alloc(ConnectionHandler, Channel, Options, infinity). --spec ptty_alloc(connection_ref(), channel_id(), proplists:proplist(), timeout()) -> - success | failure | {error, timeout | closed}. +-spec ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> result() when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Options :: proplists:proplist(), + Timeout :: timeout(). ptty_alloc(ConnectionHandler, Channel, Options0, TimeOut) -> TermData = backwards_compatible(Options0, []), % FIXME @@ -252,6 +360,10 @@ signal(ConnectionHandler, Channel, Sig) -> "signal", false, [?string(Sig)], 0). +-spec exit_status(ConnectionRef, ChannelId, Status) -> ok when + ConnectionRef :: ssh:connection_ref(), + ChannelId :: ssh:channel_id(), + Status :: integer(). exit_status(ConnectionHandler, Channel, Status) -> ssh_connection_handler:request(ConnectionHandler, Channel, "exit-status", false, [?uint32(Status)], 0). -- cgit v1.2.3 From 21b50e6bc78f26dd103ca2df1da51f9e1b3b5147 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Mon, 12 Aug 2019 15:30:22 +0200 Subject: ssh: change type names --- lib/ssh/doc/src/ssh_connection.xml | 167 ++++++++++++++++++------------------- lib/ssh/src/ssh_connection.erl | 142 +++++++++++++++++++------------ 2 files changed, 171 insertions(+), 138 deletions(-) diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml index ea41ccf252..9fa1da659c 100644 --- a/lib/ssh/doc/src/ssh_connection.xml +++ b/lib/ssh/doc/src/ssh_connection.xml @@ -44,7 +44,7 @@ The Erlang format of thoose messages is (see also below):

-

{ssh_cm, ssh:connection_ref(), ssh_event_msg()} +

{ssh_cm, ssh:connection_ref(), channel_msg()}

If the ssh_client_channel behavior is used to @@ -94,7 +94,7 @@ SSH Connection Protocol: General - +

As mentioned in the introduction, the SSH Connection Protocol @@ -105,71 +105,39 @@ - SSH Connection Protocol: Data Events - + +

Messages that include a WantReply expect the channel handling + process to call + ssh_connection:reply_request/4 + with the boolean value of WantReply as the second argument.

+ + Data Transfer (RFC 4254, section 5.2) - +

Data has arrived on the channel. This event is sent as a result of calling ssh_connection:send/[3,4,5].

+ + + Closing a Channel (RFC 4254, section 5.3) - +

Indicates that the other side sends no more data. This event is sent as a result of calling ssh_connection:send_eof/2.

- - SSH Connection Protocol: Status Events - - - - - - - - -

A signal can be delivered to the remote process/service - using the following message. Some systems do not support - signals, in which case they are to ignore this message. There is - currently no function to generate this event as the signals - referred to are on OS-level and not something generated by an - Erlang program.

-
-
- - - - -

A remote execution can terminate violently because of a signal. - Then this message can be received. For details on valid string - values, see RFC 4254 - Section 6.10, which shows a special case of these signals.

-
-
- - - -

When the command running at the other end terminates, the - following message can be sent to return the exit status of the - command. A zero exit_status usually means that the command - terminated successfully. This event is sent as a result of calling - - ssh_connection:exit_status/3.

-
-
- - +

This event is sent as a result of calling ssh_connection:close/2. @@ -178,33 +146,11 @@ - SSH Connection Protocol: Terminal Events - - - -

Channels implementing a shell and command execution on the - server side are to handle the following messages that can be sent by client- - channel processes.

- -

Events that include a WantReply expect the event handling - process to call - ssh_connection:reply_request/4 - with the boolean value of WantReply as the second argument.

-
-
- - - - -

Environment variables can be passed to the shell/command - to be started later. This event is sent as a result of calling ssh_connection:setenv/5. -

-
-
+ Requesting a Pseudo-Terminal (RFC 4254, section 6.2) - + +

A pseudo-terminal has been requested for the session. Terminal is the value of the TERM environment @@ -214,7 +160,7 @@ drawable area of the window. Opcode in the TerminalModes list is the mnemonic name, represented as a lowercase Erlang atom, defined in - RFC 4254, Section 8. + RFC 4254, Section 8. It can also be an Opcode if the mnemonic name is not listed in the RFC. Example: OP code: 53, mnemonic name ECHO erlang atom: echo. This event is sent as a result of calling + + Environment Variable Passing (RFC 4254, section 6.4) - + + +

Environment variables can be passed to the shell/command + to be started later. This event is sent as a result of calling ssh_connection:setenv/5. +

+
+
+ + + Starting a Shell or Command (RFC 4254, section 6.5) + +

This message requests that the user default shell is started at the other end. This event is sent as a result of calling @@ -231,9 +191,20 @@

+ + + +

This message requests that the server starts + execution of the given command. This event is sent as a result of calling ssh_connection:exec/4 . +

+
+
+ + Window Dimension Change Message (RFC 4254, section 6.7) - +

When the window (terminal) size changes on the client side, it can send a message to the server side to inform it of @@ -241,13 +212,39 @@ + Signals (RFC 4254, section 6.9) - + -

This message requests that the server starts - execution of the given command. This event is sent as a result of calling ssh_connection:exec/4 . -

+

A signal can be delivered to the remote process/service + using the following message. Some systems do not support + signals, in which case they are to ignore this message. There is + currently no function to generate this event as the signals + referred to are on OS-level and not something generated by an + Erlang program.

+
+
+ + + Returning Exit Status (RFC 4254, section 6.10) + + + +

When the command running at the other end terminates, the + following message can be sent to return the exit status of the + command. A zero exit_status usually means that the command + terminated successfully. This event is sent as a result of calling + + ssh_connection:exit_status/3.

+
+
+ + + +

A remote execution can terminate violently because of a signal. + Then this message can be received. For details on valid string + values, see RFC 4254 + Section 6.10, which shows a special case of these signals.

@@ -316,22 +313,22 @@ - N x data message(s) + N x data message(s)

The result of executing the command can be only one line or thousands of lines depending on the command.

- 0 or 1 x eof message + 0 or 1 x eof message

Indicates that no more data is to be sent.

- 0 or 1 x exit signal message + 0 or 1 x exit signal message

Not all systems send signals. For details on valid string values, see RFC 4254, Section 6.10

- 0 or 1 x exit status message + 0 or 1 x exit status message

It is recommended by the SSH Connection Protocol to send this message, but that is not always the case.

- 1 x closed status message + 1 x closed status message

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

diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 1e54be2a16..e6de9dd054 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -78,61 +78,97 @@ %%% The SSH Connection Protocol -export_type([event/0, - ssh_event_msg/0, - data_event/0, - data_data_event/0, - data_eof_event/0, - status_event/0, - status_signal_event/0, - status_exit_signal_event/0, - status_exit_status_event/0, - status_closed_event/0, - terminal_event/0, - terminal_env_event/0, - terminal_pty_event/0, - terminal_shell_event/0, - terminal_window_change_event/0, - terminal_exec_event/0 + channel_msg/0, + want_reply/0, + data_ch_msg/0, + eof_ch_msg/0, + signal_ch_msg/0, + exit_signal_ch_msg/0, + exit_status_ch_msg/0, + closed_ch_msg/0, + env_ch_msg/0, + pty_ch_msg/0, + shell_ch_msg/0, + window_change_ch_msg/0, + exec_ch_msg/0 ]). --type event() :: {ssh_cm, ssh:connection_ref(), ssh_event_msg()}. --type ssh_event_msg() :: data_event() | status_event() | terminal_event() . - --type data_event() :: data_data_event() - | data_eof_event() . --type data_data_event() :: {data, ssh:channel_id(), ssh_data_type_code(), Data :: binary()} . --type data_eof_event() :: {eof, ssh:channel_id()} . - - --type status_event() :: status_signal_event() - | status_exit_signal_event() - | status_exit_status_event() - | status_closed_event() . - --type status_signal_event() :: {signal, ssh:channel_id(), SignalName::string()} . --type status_exit_signal_event() :: {exit_signal, ssh:channel_id(), - ExitSignal :: string(), - ErrorMsg ::string(), - LanguageString :: string()} . --type status_exit_status_event() :: {exit_status, ssh:channel_id(), ExitStatus :: integer()} . --type status_closed_event() :: {closed, ssh:channel_id()} . - --type terminal_event() :: terminal_env_event() - | terminal_pty_event() - | terminal_shell_event() - | terminal_window_change_event() - | terminal_exec_event() . - --type terminal_env_event() :: {env, ssh:channel_id(), WantReply :: boolean(), Var ::string(), Value :: string()} . --type terminal_pty_event() :: {pty, ssh:channel_id(), - WantReply :: boolean(), - {Terminal :: string(), CharWidth :: integer(), RowHeight :: integer(), PixelWidth :: integer(), PixelHeight :: integer(), - TerminalModes :: [{Opcode :: atom() | integer(), - Value :: integer()}]}} . --type terminal_shell_event() :: {shell, WantReply :: boolean()} . --type terminal_window_change_event() :: {window_change, ssh:channel_id(), CharWidth :: integer(), - RowHeight :: integer(), PixWidth :: integer(), PixHeight :: integer()} . --type terminal_exec_event() :: {exec, ssh:channel_id(), WantReply :: boolean(), Cmd :: string()} . +-type event() :: {ssh_cm, ssh:connection_ref(), channel_msg()}. +-type channel_msg() :: data_ch_msg() + | eof_ch_msg() + | closed_ch_msg() + | pty_ch_msg() + | env_ch_msg() + | shell_ch_msg() + | exec_ch_msg() + | signal_ch_msg() + | window_change_ch_msg() + | exit_status_ch_msg() + | exit_signal_ch_msg() + . + +-type want_reply() :: boolean(). + +-type data_ch_msg() :: {data, + ssh:channel_id(), + ssh_data_type_code(), + Data :: binary() + } . +-type eof_ch_msg() :: {eof, + ssh:channel_id() + } . +-type signal_ch_msg() :: {signal, + ssh:channel_id(), + SignalName :: string() + } . +-type exit_signal_ch_msg() :: {exit_signal, ssh:channel_id(), + ExitSignal :: string(), + ErrorMsg :: string(), + LanguageString :: string()} . +-type exit_status_ch_msg() :: {exit_status, + ssh:channel_id(), + ExitStatus :: non_neg_integer() + } . +-type closed_ch_msg() :: {closed, + ssh:channel_id() + } . +-type env_ch_msg() :: {env, + ssh:channel_id(), + want_reply(), + Var :: string(), + Value :: string() + } . +-type pty_ch_msg() :: {pty, + ssh:channel_id(), + want_reply(), + {Terminal :: string(), + CharWidth :: non_neg_integer(), + RowHeight :: non_neg_integer(), + PixelWidth :: non_neg_integer(), + PixelHeight :: non_neg_integer(), + TerminalModes :: [term_mode()] + } + } . + +-type term_mode() :: {Opcode :: atom() | byte(), + Value :: non_neg_integer()} . + +-type shell_ch_msg() :: {shell, + ssh:channel_id(), + want_reply() + } . +-type window_change_ch_msg() :: {window_change, + ssh:channel_id(), + CharWidth :: non_neg_integer(), + RowHeight :: non_neg_integer(), + PixelWidth :: non_neg_integer(), + PixelHeight :: non_neg_integer() + } . +-type exec_ch_msg() :: {exec, + ssh:channel_id(), + want_reply(), + Command :: string() + } . %%% This function is soley to convince all %%% checks that the type event() exists... -- cgit v1.2.3 From a5f5feb9b4c4bedfa027b07e33a5d1ccc9fb240b Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 8 Aug 2019 13:37:05 +0200 Subject: ssh: Use new ssh_connection:event() type in channel defs --- lib/ssh/doc/src/ssh_client_channel.xml | 14 +++++++------- lib/ssh/doc/src/ssh_server_channel.xml | 8 ++++---- lib/ssh/src/ssh_client_channel.erl | 2 +- lib/ssh/src/ssh_server_channel.erl | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ssh/doc/src/ssh_client_channel.xml b/lib/ssh/doc/src/ssh_client_channel.xml index cd28b95fd3..e6683dbd0b 100644 --- a/lib/ssh/doc/src/ssh_client_channel.xml +++ b/lib/ssh/doc/src/ssh_client_channel.xml @@ -150,12 +150,12 @@ {init_args(), list()}

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

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

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

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

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

@@ -198,7 +198,7 @@ {ok, ChannelRef} | {error, Reason}
Starts a process that handles an SSH channel. - SshConnection = ssh:connection_ref() + SshConnection = ssh:connection_ref() As returned by ssh:connect/3 ChannelId = ssh:channel_id() @@ -374,7 +374,7 @@ function and all channels are to handle the following message.

- {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} + {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 @@ -393,21 +393,21 @@ ChannelId, State} Handles ssh connection protocol messages. - Msg = ssh_connection:event() + 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(). + see ssh_connection:event().

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

- {closed, ssh:channel_id()} + {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.

diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml index a4e18bbfbf..87c745c9fb 100644 --- a/lib/ssh/doc/src/ssh_server_channel.xml +++ b/lib/ssh/doc/src/ssh_server_channel.xml @@ -112,7 +112,7 @@ function and all channels are to handle the following message.

- {ssh_channel_up, ssh:channel_id(), ssh:connection_ref()} + {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 @@ -129,21 +129,21 @@ ChannelId, State} Handles ssh connection protocol messages. - Msg = ssh_connection:event() + 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(). + see ssh_connection:event().

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

- {closed, ssh:channel_id()} + {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.

diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl index f985d8e273..3bd1e1fdf1 100644 --- a/lib/ssh/src/ssh_client_channel.erl +++ b/lib/ssh/src/ssh_client_channel.erl @@ -52,7 +52,7 @@ -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()}, +-callback handle_ssh_msg(ssh_connection:event(), State::term()) -> {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}. diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl index 555080e9ee..1905c40c98 100644 --- a/lib/ssh/src/ssh_server_channel.erl +++ b/lib/ssh/src/ssh_server_channel.erl @@ -37,7 +37,7 @@ -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()}, +-callback handle_ssh_msg(ssh_connection:event(), State::term()) -> {ok, State::term()} | {stop, ChannelId::ssh:channel_id(), State::term()}. -- cgit v1.2.3