Correct way to free a session _and_ how to do so without blocking or timeout

Evan M etm2131 at columbia.edu
Wed Jan 12 04:55:32 CET 2022


Hi all - apologies for the long email.. I want to make sure I'm explaining
things clearly.

I am working on a wrapper over libssh2 for the Rust programming language.
Rust has RAII similar to C++ where resources for a struct / object are
released when the struct is dropped (i.e. goes out of scope). Since
destructors run in a single shot and should ideally be non-blocking, we
need a way to release session resources without performing blocking IO (or
any IO at all). This is especially important when using libssh2 in a
non-blocking async context.

My question has two parts. First, I want to make sure I understand the
correct way to completely close a session without leaking any memory. I
believe there is some complexity involved since libssh2 mixes SSH protocol
IO with freeing memory in most (maybe all) of the cleanup functions (such
as libssh2_session_free() and libssh2_channel_free()).

Is this the procedure below the correct way to close a session? For each of
these steps I'm assuming the functions are retried until they succeed in
the case of LIBSSH2_ERROR_EAGAIN or LIBSSH2_ERROR_TIMEOUT being returned.

1. Call the appropriate shutdown / free function for any and all objects
associated with the session (i.e. libssh2_sftp_shutdown(),
libssh2_channel_free(), libssh2_channel_forward_cancel(), etc...). These
functions perform IO in addition to freeing memory.

2. Call libssh2_session_disconnect() to send the SSH disconnect message

3. Call libssh2_session_free(); At this point I believe
libssh2_session_free() should not perform any IO since all channels and
listeners have already been closed. I read through the code and this seems
to be the case, but perhaps I missed something.

On this last point, I also didn't see any code preventing libssh2 from
sending data to the server after it has sent a disconnect message, even
though the SSH spec states that no further transmissions are permitted. I'm
therefore assuming that if libssh2_session_disconnect() is called before
the channel_free or similar, libssh2 will continue sending messages to the
server in these cleanup functions. It also looks like libssh2_session_free
will cause IO to close channels if they are still open when it is called.


Second, I'd like to understand how to clean up in a non-blocking context
where we cannot wait for IO to complete, such as in the destructor for a
struct in our Rust library. Is it alright to call
shutdown() in a UNIX environment to close the socket without recycling the
fd and then call the appropriate free/shutdown/cancel functions before
calling libssh2_session_free()? The thought is that after calling shutdown
on the socket any IO performed by the libssh2 code will fail, which from my
understanding will cause libssh2_session_free() to discard the IO error and
proceed through the routine, freeing the session memory. This allows us to
avoid EAGAIN and timeouts in the destructor at the cost of closing the
socket without cleanly ending the SSH session.

Thanks!

- Evan

-- 
Evan Mesterhazy
etm2131 at columbia.edu
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.haxx.se/pipermail/libssh2-devel/attachments/20220111/ae91386b/attachment.htm>


More information about the libssh2-devel mailing list