ssh_connection(3)
π NAME π
ssh_connection β this module is the one that gives you API functions to send SSH Connection Protocol events over to the other side of an SSH channel. It's giving bridge energy, fr. π«Ά
πΈ DESCRIPTION πΈ
The SSH Connection Protocol (RFC 4254) is what clients and servers β aka SSH channels β use to communicate over the SSH connection. The API functions in this module send SSH Connection Protocol events, and those events show up as messages on the remote channel that's handling the remote channel. The Erlang format of those messages is (see also below):
{ssh_cm, ssh:connection_ref/0 , channel_msg/0 }
If you're using the ssh_client_channel behavior to implement the channel process, these messages get handled by handle_ssh_msg/2. slay. β¨
π¦ DATA TYPES π¦
channel_id()
channel_id() :: ssh:channel_id().
channel_msg()
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().
Okay so like the intro said, SSH Connection Protocol events get handled as messages. If you're writing a channel handling process without the ssh_client_channel behavior helping you out, your process has to handle those messages itself. iykyk. π
closed_ch_msg()
closed_ch_msg() :: {closed, ssh:channel_id()}.
This event gets sent when someone calls ssh_connection:close/2. Both handling this event and sending it are already taken care of by the ssh_client_channel behavior. so you can chill. π
connection_ref()
connection_ref() :: ssh:connection_ref().
data_ch_msg()
data_ch_msg() ::
{data,
ssh:channel_id(),
ssh_data_type_code(),
Data :: binary()}.
Data has arrived on the channel, bestie. This event gets sent when ssh_connection:send/3,4,5 is called. π₯
env_ch_msg()
env_ch_msg() ::
{env,
ssh:channel_id(),
want_reply(),
Var :: string(),
Value :: string()}.
Environment variables can be passed to the shell/command that's gonna start later. This event gets sent when ssh_connection:setenv/5 is called. π
eof_ch_msg()
eof_ch_msg() :: {eof, ssh:channel_id()}.
This one means the other side is sending no more data. It gets sent when ssh_connection:send_eof/2 is called. π
event()
event() :: {ssh_cm, ssh:connection_ref(), channel_msg()}.
exec_ch_msg()
exec_ch_msg() ::
{exec, ssh:channel_id(), want_reply(), Command :: string()}.
This message is like "hey server, start running this command." It gets sent when ssh_connection:exec/4 is called. periodt. π
exit_signal_ch_msg()
exit_signal_ch_msg() ::
{exit_signal,
ssh:channel_id(),
ExitSignal :: string(),
ErrorMsg :: string(),
LanguageString :: string()}.
A remote execution can go out violently because of a signal. When that happens, this message can be received. For the deets on valid string values, peep RFC 4254 Section 6.10, which shows a special case of these signals. π
exit_status_ch_msg()
exit_status_ch_msg() ::
{exit_status,
ssh:channel_id(),
ExitStatus :: non_neg_integer()}.
When the command running at the other end finishes, this message can be sent to return the command's exit status. A zero exit_status usually means the command ended successfully. This event gets sent when ssh_connection:exit_status/3 is called. π
pty_ch_msg()
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()]}}.
reason()
reason() :: closed | timeout.
This is the result of a call.
If the request reached the peer, got handled, and the response made it back to the requesting node, then req_status/0 is the status reported from the peer.
If not, reason/0 tells you what went wrong:
closedβ means the channel or connection was closed when trying to send the request.timeoutβ means the operation exceeded a time limit.
req_status()
req_status() :: success | failure.
The status of a request. It corresponds to the SSH_MSG_CHANNEL_SUCCESS and SSH_MSG_CHANNEL_FAILURE values in RFC 4254, Section 5.4. π
result()
result() :: req_status() | {error, reason()}.
shell_ch_msg()
shell_ch_msg() :: {shell, ssh:channel_id(), want_reply()}.
This message is asking for the user default shell to be started at the other end. It gets sent when ssh_connection:shell/2 is called. β¨
signal_ch_msg()
signal_ch_msg() ::
{signal, ssh:channel_id(), SignalName :: string()}.
You can deliver a signal to the remote process/service with this message. Some systems don't support signals, and if that's the case they're supposed to ignore this message. Right now there's no function to generate this event, because the signals it's talking about are OS-level and not something an Erlang program makes. π
ssh_data_type_code()
ssh_data_type_code() :: non_neg_integer().
The valid values are 0 ("normal") and 1 ("stderr"), see RFC 4254, Section 5.2. π
term_mode()
term_mode() ::
{Opcode :: atom() | byte(), Value :: non_neg_integer()}.
So a pseudo-terminal got requested for the session. Terminal is the value of the TERM environment variable value, aka vt100. Zero dimension parameters must be ignored. The character/row dimensions override the pixel dimensions (when non-zero). Pixel dimensions refer to the 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. 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 gets sent when ssh_connection:ptty_alloc/4 is called. πΈ
want_reply()
want_reply() :: boolean().
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. π
window_change_ch_msg()
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()}.
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. π
πΈ FUNCTIONS πΈ
β¨ adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok
adjust_window(ConnectionRef, ChannelId, NumOfBytes) -> ok
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
NumOfBytes :: integer().
Okay so this one tweaks the SSH flow-control window π§ β and bestie, both the client-side AND server-side channel processes need to do this, it's a two-hands situation fr fr.
β οΈ NOTE: if your channels are built with thessh_client_channelbehavior, you usually do not need to call this at all, because flow control is already handled by the behavior, iykyk π The behavior bumps the window every single time the callbackhandle_ssh_msg/2returns after it's done processing channel data. Considerate of it honestly.
β¨ close(ConnectionRef, ChannelId) -> ok
close(ConnectionRef, ChannelId) -> ok
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id().
A server- or client-channel process can peace out of their session whenever it wants by yeeting a close event π
β οΈ NOTE: this function gets called by thessh_client_channelbehavior when the channel is terminated β seessh_client_channel. So if you're using the behavior, girly pop, do not call this yourself. It's handled. Let it cook.
β¨ exec(ConnectionRef, ChannelId, Command, Timeout) -> result()
exec(ConnectionRef, ChannelId, Command, Timeout) -> result()
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Command :: string(),
Timeout :: timeout().
This is what a client-channel process calls to ask the server "hey babe, go run this command for me π«Ά". And the result isn't one single reply β it's a whole lil' parade of messages, in this exact pattern. The very last one is a channel close message, because an exec request is a one-time execution: it finishes the job, then shuts the channel down. Done and dusted. β¨
- N x data message(s) β the output of the command can be a single line or thousands of lines, depends entirely on the command tbh.
- 0 or 1 x eof message β says no more data is coming.
- 0 or 1 x exit signal message β not every system sends signals. For the details on valid string values, hit up RFC 4254, Section 6.10.
- 0 or 1 x exit status message β the SSH Connection Protocol recommends sending this one, but that is lowkey not always the case π
- 1 x closed status message β tells you that the
ssh_client_channelstarted for running this command has now been shut down.
Peep the User's Guide section on One-Time Execution for examples, it's giving tutorial energy.
β οΈ NOTE: if the command generates a big ol' pile of output data, you might have to adjust the window manually to actually receive all of it. See ssh_connectino:adjust_window/3.
β¨ exit_status(ConnectionRef, ChannelId, Status) -> ok
exit_status(ConnectionRef, ChannelId, Status) -> ok
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Status :: integer().
A server-channel process calls this to send the exit status of a command back to the client. Communication queen behavior. π
β¨ ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> result()
ptty_alloc(ConnectionRef, ChannelId, Options, Timeout) -> result()
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Options :: proplists:proplist(),
Timeout :: timeout().
Sends an SSH Connection Protocol pty_req to allocate a pseudo-terminal π An SSH client process is the one that calls this.
Options:
{term, string()}β defaults toos:getenv("TERM"), orvt100if that comes back undefined.{width, integer()}β defaults to80ifpixel_widthisn't defined.{height, integer()}β defaults to24ifpixel_heightisn't defined.{pixel_width, integer()}β straight up disregarded ifwidthis defined. ignored. ghosted. π{pixel_height, integer()}β disregarded ifheightis defined.{pty_opts, [{posix_atom(), integer()}]}β this one can just be an empty list, no pressure. Otherwise, go see the possible POSIX names in Section 8 in RFC 4254.
β¨ reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok
reply_request(ConnectionRef, WantReply, Status, ChannelId) -> ok
when
ConnectionRef :: ssh:connection_ref(),
WantReply :: boolean(),
Status :: req_status(),
ChannelId :: ssh:channel_id().
Sends status replies to requests where the requester has explicitly said they want a status report β that means WantReply = true. If WantReply is false, calling this just becomes a "noop" π΄ (nothing happens, all vibes, no function). You call this while you're handling an SSH Connection Protocol message that contains a WantReply boolean value.
β¨ send(connection_ref(), channel_id(), iodata(), timeout()) -> ok | {error, reason()}; (connection_ref(), channel_id(), ssh_data_type_code(), iodata()) -> ok | {error, reason()}.
send(connection_ref(), channel_id(), iodata(), timeout()) ->
ok | {error, reason()};
(connection_ref(),
channel_id(),
ssh_data_type_code(),
iodata()) ->
ok | {error, reason()}.
Depending on the input arguments you pass, this is equivalent to one of the send/5 calls listed below. Basically it's the choose-your-own-adventure version. π¦
- Equivalent to
send(ConnectionRef, ChannelId, 0, Data, TimeOut)if you call it withTimeOutbeing an integer. - Equivalent to
send(ConnectionRef, ChannelId, 0, Data, infinity)if you call it withTimeOutbeing the atominfinity. - Equivalent to
send(ConnectionRef, ChannelId, Type, Data, infinity)if you call it with a last argument that is not an integer and not the atominfinity.
β¨ send(connection_ref(), channel_id(), ssh_data_type_code(), iodata(), timeout()) -> ok | {error, reason()}.
send(connection_ref(),
channel_id(),
ssh_data_type_code(),
iodata(),
timeout()) ->
ok | {error, reason()}.
Client- and server-channel processes call this to send data to each other π«Ά
β οΈ IMPORTANT: the functionsubsystem/4and any subsequent calls tosend/3,4,5must be executed in the same process. Same process bestie, no splitting up, that's the rule. π€
β¨ send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}
send_eof(ConnectionRef, ChannelId) -> ok | {error, closed}
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id().
Sends EOF on channel ChannelId. That's it, that's the whole thing. Short and iconic. β¨
β¨ session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize, Timeout) -> Result
session_channel(ConnectionRef, InitialWindowSize, MaxPacketSize,
Timeout) ->
Result
when
ConnectionRef :: ssh:connection_ref(),
InitialWindowSize ::
pos_integer() | undefined,
MaxPacketSize :: pos_integer() | undefined,
Timeout :: timeout(),
Result ::
{ok, ssh:channel_id()} |
{error, reason()}.
Opens a channel for an SSH session π And listen β the channel id you get back from this function is the exact id you plug in as input to all the other functions in this module. It's the key to the whole group chat, fr fr.
β¨ setenv(ConnectionRef, ChannelId, Var, Value, Timeout) -> success
setenv(ConnectionRef, ChannelId, Var, Value, Timeout) -> success
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Var :: string(),
Value :: string(),
Timeout :: timeout().
You can pass environment variables before starting up the shell or the command π A client channel process is the one that calls this.
β¨ shell(ConnectionRef, ChannelId) -> Result
shell(ConnectionRef, ChannelId) -> Result
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Result :: ok | success | failure | {error, timeout}.
A client channel process calls this to request that the user's default shell (typically the one defined in /etc/passwd on Unix systems π) gets executed over on the server end.
π Note: the return value here isok, and notsuccesslike the other functions in this module. This is a fault that was introduced so long ago that changing it now would break a large number of existing software. So we all just live with it. It's canon. Historical artifact era. π
β¨ subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) -> result()
subsystem(ConnectionRef, ChannelId, Subsystem, Timeout) ->
result()
when
ConnectionRef :: ssh:connection_ref(),
ChannelId :: ssh:channel_id(),
Subsystem :: string(),
Timeout :: timeout().
A client-channel process calls this to request that a predefined subsystem gets executed on the server π§
β οΈ The functionsubsystem/4and any subsequent calls tosend/3,4,5must be executed in the same process. (Yes, same warning as before. It really means it. π)
And that's a wrap on ssh_connection(3), bestie!! π Written by Ericsson AB, from ssh 6.0.5, and this manual page is dated... well, the version is right there and the page is filed under ssh_connection(3). Go forth and multiplex your channels responsibly, you gorgeous little network gremlin ππ¦β¨
π¦ where this page comes from
- ubuntu stonking: erlang-doc 1:29.0.6+dfsg-1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms