Subject: Re: Multiple channels and epoll(7)

Re: Multiple channels and epoll(7)

From: Jason Ni <>
Date: Mon, 16 Nov 2020 10:23:29 +0800

 Dear folks,

I was trying to use async-ssh2, which is an async wrapper of libssh2, to
implement a remote port forward proxy.
However, I may encounter the same issue as talked in this thread 6 years
Could any one help to confirm that is there any rework or fix of this issue?

Thanks a lot!

Best regards,
Jason Ni

From: Henrik Nordström <

Date: Fri, 27 Jun 2014 11:19:11 +0200

tor 2014-06-26 klockan 23:24 -0600 skrev Eduardo Silva:

*> but there is a remaining problem, when i get the notification that *
*> some data is available, after try to accept a channel and then read *
*> all channels, i need a timeout in the event loop to re-check if *
*> something was pending. Still wondering how to avoid that re-check. *

Looking at your code, and thinking and ugh... the libssh2 API is borked
when it comes to handling of multiple concurrent channels.

What I said earlier might work if you set epoll into edge triggered mode
unless kernel cancels events if they get cleared before processed (I do
not remember what happens, maybe kernel release dependent even). But
current libssh2 API makes any level triggered non-blocking I/O on
multiple channels unreliable (including poll/select) and requires a
short timeout to avoid blocking due to incoming packets being held in
the libssh2 packets queue without the application being aware.

Looping over all channels until all report EAGAIN shortens the window
where this may happen, but do not eleminate it as packets may still
arrive into the packet queue while you process later channels.

The earlier discussed API addition of giving access to inspect the
packet queue would help solving this. You then loop processing until
internal packet queue is drained. When internal packet queue is drained
you know that libssh is actually waiting for the socket.

Separating I/O from processing would also solve this problem and likely
scale better with number of channels, removing the implicit socket read
from libssh2_channel_read() and friends, requiring a explicit separate
call to read the socket.

Another interesting thought would be to aim to rework the libssh2 API to
the level that it can support libevent buffered I/O events and similar
I/O loops by delegating all actual I/O to the application. Above is
likely a first step towards that.


Received on 2020-11-16