IETF-SSH archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: closing a channel



"denis bider" <ietf-ssh%denisbider.com@localhost> writes:

> This looks very reasonable. Does your server behave the same if the client
> sends EOF immediately after issuing the exec request? That's what my clients
> do - when issuing an exec request, they let the server know immediately that
> they're not going to send any data.

The client's EOF request doesn't matter here, the server will close
the channel as soon as the all of three events EOF on process stdout, EOF on
process stderr, death of process, have occured.

Earlier versions waited for the client to send EOF, but not all
clients do that. It makes some sense to wait for the client's EOF, but
for that to work we need the client to respont to exit-status with
EOF, and exit-status isn't mandatory, so that gets pretty fragile. So
I changed that behaviour a while ago after discussion on this list.

> But if I knew that I can rely on the server to send 'exit-status' or to
> close the channel upon child process termination, I would prefer not to rush
> with my own CHANNEL_CLOSE so that I can possibly catch the program's exit
> code.

I think the best you can do is to rely on the server to send
CHANNEL_CLOSE when the remote process is gone.

I include the description on channel close from lsh/doc/NOTES below.

Regards,
/Niels

EOF ON CHANNELS

A typical channel (i.e. all channels created in the current
implementation) are, at each end, connected to one or more fd:s for
reading and writing. When the source fd(:s), i.e. the fd:s that we are
reading, have no more data available, a CHANNEL_EOF message should be
sent. As there may be several such fd:s, we use a counter SOURCES in
the channel struct to keep track of the number of active source fd:s.
When an fd is closed, the counter is decremented, and when it reaches
zero, the CHANNEL_EOF message is sent.

The decrementing of the counter is done by the close-callback for the
fd, not by the read handler, as this is the easiest way to
ensure that it is called exactly once whenever a fd dies. However, the
sending of the CHANNEL_EOF message is done by the read handlers
do_channel_write() and do_channel_write_extended(). This is because
otherwise, eof on bidirectional fd:s migth be delayed until it is
closed also for writing. There are more unsolved issues with
bidirectional fd:s though, in particular tcp connections where one
direction is closed (with shutdown()) long before the other.


CLOSING CHANNELS

The right conditions for closing a channel, and in particular a
session, are even more subtle. The basic rules are:

1. When SSH_MSG_CHANNEL_CLOSE is both sent and received, the channel
   is killed. This is unconditionally required by the spec.

2. When SSH_MSG_CHANNEL_EOF is both sent and received,
   SSH_MSG_CHANNEL_CLOSE is sent. This is a rule with a few
   exceptions, controlled by the CHANNEL_CLOSE_AT_EOF flag, see below.

These two rules are sufficient for most channel types.

When looking at the channel close logic for session channels, one has
to consider these three events that may occur in arbitrary order:

 * The client sends SSH_MSG_CHANNEL_EOF on the channel.

 * The server sends SSH_MSG_CHANNEL_EOF on the channel (this happens
   when there are no more processes which have the files the server
   has opened for stdout or stderr open).

 * The child process created by the server dies. An exit-status or
   exit-signal message is sent to the client.

Previous versions of lshd handled these conditions as follows: It
closed the channel according to rule (2) above, no exceptions. This
causes other clients to hang, because they never send any
SSH_MSG_CHANNEL_EOF. Using lsh did work right, only because it
responded to the exit-status message with a SSH_MSG_CHANNEL_EOF.

But the server can't rely on clients sending SSH_MSG_CHANNEL_EOF.
Instead, it must treat process death in much the same way as reception
of SSH_MSG_CHANNEL_EOF. The channel is closed once the server has both
encountered EOF on the process' stdout and stderr (resulting in a
SSH_MSG_CHANNEL_EOF), and sent an exit-status or exit-signal message.

As a further complication, rule (2) must be relaxed, because otherwise
the channel may get closed before the exit-status message is sent.



Home | Main Index | Thread Index | Old Index