Of course, having a pool means we'll have SSH sessions sitting idle in the pool, until we use them. And idle connections are always a source of problems. Speaking of which...
I've been testing last post's libssh2/asio example. While it runs fine if we run a command and exit, in a scenario where we want to reuse the same SSH session to run several commands (i.e., open/close several channels), it doesn't work. So far, I've been concentrating on the channel life cycle, as this is where most of the action (and, naturally, problems) happens.
So, in all operations concerning channels, I've eliminated the
async_read_some(), keeping only the
async_write_some(). I've run two tests on this:
- One, where a command is executed every 10 seconds. This ran flawlessly for about 20 minutes, until I CTRL+C'd it.
- The other was similar, but the interval doubled between executions; so, the first interval was 10 seconds; the second was 20 seconds; and so on. This one crashed with an exception after being idle for nearly 3 hours. So, it remained idle and valid for 1.5 hours. The error was
LIBSSH2_ERROR_SOCKET_SEND, which seems to indicate the socket was closed by inactivity.
Testing will continue, naturally. I've added code to check the socket's status when an exception occurs (basically, check
socket::is_open(), to see if the asio socket is aware that the conection was terminated), and I'll enable the socket's
keepaliveoption, to see if it makes a difference.
I'm using an Ubuntu guest on VirtualBox as remote server. Checking its
sshd_config, it has
TCPKeepAliveon, and it's not using
ClientAliveInterval. I'll have to test these settings, too.
Still a lot of work ahead, but so far, so good.
Further along on the horizon:
- Multithreading (I'm not going to mess with this until I get single-threading working correctly).
- Recovering from a dead connection. It's bound to happen, so I better be ready to deal with it.