Sunday 9 September 2012

libssh2/boost::asio progresses

One of my goals is to have a pool of open SSH sessions. Since the authentication is measured in seconds, I've thought it would be a good idea to avoid repeating it as much as possible; so, I open the session once and reuse it. I'm still working on the design, but these sessions will probably be stored in a multimap, the key being by host + port (usually, 22) + user. I'll be using a multimap because you can have more than one operation running on the same host/port/user.

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 keepalive option, to see if it makes a difference.

I'm using an Ubuntu guest on VirtualBox as remote server. Checking its sshd_config, it has TCPKeepAlive on, 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.

2 comments:

  1. Hi there! I'm trying to achieve the exact same goal as you. I'm teaching myself c++, and I wish to create a wrapper for libssh2 to help with my learning. Using boost is a fantastic idea, and I've just installed that on my system. I'm particularly interested in boost's regex capabilities as I will be using the wrapper to parse logs on remote systems. Your two posts have really helped - thank you kindly!

    ReplyDelete
  2. Hallo, Peter.

    You're quite welcome. This is still a WIP, and I'm changing the design a bit (I'll post it here when it's complete), but the backbone is still the same - drive the libssh2 interaction via boost.

    I'm glad you found it useful. In the end, that's why we code, to help solve our problems and, hopefully, someone else's.

    I'll be using it for something similar, too, as I'm working with log files as well.

    ReplyDelete