RejectedSoftware Forums

Sign up

Integrating C libraries (libssh2) with vibe-d

I have some code which uses libssh2 to execute commands via ssh and transfer files via scp. Right now I'm using the
libssh2 asynchronous mode and select calls (to create a blocking API with timeout support). I'd like to move this code to vibe-d
now and create a vibe-libssh2 project. Executing remote ssh commands requires reading(stdout/stderr) and writing(stdin) at the same time so
vibe-d is a perfect fit.

The libssh2 async API works like this:

  • The user creates a socket in non-blocking mode
  • All calls to libssh2 are now non-blocking. If not enough data is available they return an EAGAIN code
  • The user code is then expected to 'wait' until the socket is readable or writeable.
    libssh2 provides a way to know whether we should wait for read/write or both kinds of events
  • However, the usercode may not read from the socket. We only have to wait until it's readable, then call the libssh functions again.

AFAICS there are currently two main problems in vibe which prevent using libssh2 with it (*):

  • There's no way to get the socket handle from a TcpConnection
  • There's no way to simply wait for readable/writeable/both events, we always have to actually read or write data

Is there any chance to get these things supported in vibe? If there are concerns that some eventloops may not offer access to the socket handle
and the socket should therefore not be available in the public API in TcpConnection we could probably add a new Interface SystemTcpConnection
which exposes those details but may not be available with every event loop.

(*) There's also a small problem with libssh2: libssh2 supports mutliple channels per connection. But the API doesn't provide event/callback information which channel is readable/writeable
so I have to loop through all channels all the time and poll them. This is not nice regarding performance, but it's always possible to use few channels and more ssh connections.

Re: Integrating C libraries (libssh2) with vibe-d

Am 30.12.2013 16:36, schrieb Johannes Pfau:

I have some code which uses libssh2 to execute commands via ssh and transfer files via scp. Right now I'm using the
libssh2 asynchronous mode and select calls (to create a blocking API with timeout support). I'd like to move this code to vibe-d
now and create a vibe-libssh2 project. Executing remote ssh commands requires reading(stdout/stderr) and writing(stdin) at the same time so
vibe-d is a perfect fit.

The libssh2 async API works like this:

  • The user creates a socket in non-blocking mode
  • All calls to libssh2 are now non-blocking. If not enough data is available they return an EAGAIN code
  • The user code is then expected to 'wait' until the socket is readable or writeable.

libssh2 provides a way to know whether we should wait for read/write or both kinds of events

  • However, the usercode may not read from the socket. We only have to wait until it's readable, then call the libssh functions again.

AFAICS there are currently two main problems in vibe which prevent using libssh2 with it (*):

  • There's no way to get the socket handle from a TcpConnection
  • There's no way to simply wait for readable/writeable/both events, we always have to actually read or write data

Is there any chance to get these things supported in vibe? If there are concerns that some eventloops may not offer access to the socket handle
and the socket should therefore not be available in the public API in TcpConnection we could probably add a new Interface SystemTcpConnection
which exposes those details but may not be available with every event loop.

(*) There's also a small problem with libssh2: libssh2 supports mutliple channels per connection. But the API doesn't provide event/callback information which channel is readable/writeable
so I have to loop through all channels all the time and poll them. This is not nice regarding performance, but it's always possible to use few channels and more ssh connections.

There is one issue that may prevent TCPConnection from being used for
this in a "sane" way. In the libevent driver it uses bufferevent,
which has an internal prefetch buffer, so it would steal the incoming
data. But it should be possible to manually adopt a socket into the
libevent loop using a manually created event without problems. That
would then just need to be encapsulated cleanly somehow. Maybe like this:

interface SocketEventListener {
	enum Event {
		read = 1<<0,
		write = 1<<1,
		status = 1<<2,
		any = read|write|status
	}
	
	void wait(Event which = Event.any);
}

SocketEventListener createSocketEventListener(int socket);

Any idea for a better name or anything that would be missing?

Re: Integrating C libraries (libssh2) with vibe-d

On Mon, 30 Dec 2013 17:04:01 +0100, Sönke Ludwig wrote:

There is one issue that may prevent TCPConnection from being used for
this in a "sane" way. In the libevent driver it uses bufferevent,
which has an internal prefetch buffer, so it would steal the incoming
data. But it should be possible to manually adopt a socket into the
libevent loop using a manually created event without problems. That
would then just need to be encapsulated cleanly somehow. Maybe like this:

interface SocketEventListener {
	enum Event {
		read = 1<<0,
		write = 1<<1,
		status = 1<<2,
		any = read|write|status
	}
	
	void wait(Event which = Event.any);
}

SocketEventListener createSocketEventListener(int socket);

Any idea for a better name or anything that would be missing?

Sounds good.
Timeout support would probably be good. Although I think this could be implemented outside of SocketEventListener it's probably easier to add support in SocketEventListener.

Re: Integrating C libraries (libssh2) with vibe-d

On Mon, 30 Dec 2013 16:50:20 GMT, Johannes Pfau wrote:

On Mon, 30 Dec 2013 17:04:01 +0100, Sönke Ludwig wrote:

There is one issue that may prevent TCPConnection from being used for
this in a "sane" way. In the libevent driver it uses bufferevent,
which has an internal prefetch buffer, so it would steal the incoming
data. But it should be possible to manually adopt a socket into the
libevent loop using a manually created event without problems. That
would then just need to be encapsulated cleanly somehow. Maybe like this:

interface SocketEventListener {
	enum Event {
		read = 1<<0,
		write = 1<<1,
		status = 1<<2,
		any = read|write|status
	}
	
	void wait(Event which = Event.any);
}

SocketEventListener createSocketEventListener(int socket);

Any idea for a better name or anything that would be missing?

Sounds good.
Timeout support would probably be good. Although I think this could be implemented outside of SocketEventListener it's probably easier to add support in SocketEventListener.

Implemented now as of daf853f. It's called vibe.core.core.createFileDescriptorEvent() and includes an optional timeout parameter. I'm also using it now to integrate the vibe.d event loop with the X11 event loop on Linux.

Re: Integrating C libraries (libssh2) with vibe-d

Hi,

this is a bit of a grave-digging, but right now I am trying to integrate libssh2 with vibe.d's asynchronous model and I am hitting a strange error.

Consider this code:

auto socket = new TcpSocket(address);
socket.blocking = false;

auto fileDescriptorEvent = createFileDescriptorEvent(socket.handle, FileDescriptorEvent.Trigger.any);

libssh2_session_set_blocking(session, 0);

int rc;
while ((rc = libssh2_session_handshake(session, socket.handle)) == LIBSSH2_ERROR_EAGAIN)
{
  fileDescriptorEvent.wait(100.msecs);
}

if (rc != 0)
{
  // Report error
}
 
while ((rc = libssh2_userauth_password(session, username, password)) == LIBSSH2_ERROR_EAGAIN)
{
  // ˇˇˇ The source of troubles ˇˇˇ
  // fileDescriptorEvent.wait(100.msecs);
}

If I leave the last call to wait commented, then everything works fine (except that I lose asynchronous processing), but if I uncomment it, I basically break the event loop. I am calling processEvents() by myself and the thing is that when I uncomment it the processEvents() call gets stuck and does not return at all. And I am not seeing any error messages or exceptions.

So, my first question is - am I using the FileDescriptorEvent correctly? If not, how should I do it? If so, what can I do to catch the bug?

Thanks,
Martin

Re: Integrating C libraries (libssh2) with vibe-d

Hmpf... it seems that the problem was in setting the trigger to any instead of read. Once I set it to read, everything works like charm.

Martin

Re: Integrating C libraries (libssh2) with vibe-d

Am 08.10.2015 um 22:33 schrieb Martin Drasar:

Hmpf... it seems that the problem was in setting the trigger to any instead of read. Once I set it to read, everything works like charm.

Martin

Sorry, I didn't have time to look into this, yet. But this is
interesting - if anything, I would expect any to trigger more often
than read, but not the other way around. I'll review that part of the
code when I get some time.

Re: Integrating C libraries (libssh2) with vibe-d

On Fri, 9 Oct 2015 19:32:11 +0200, Sönke Ludwig wrote:

Sorry, I didn't have time to look into this, yet. But this is
interesting - if anything, I would expect any to trigger more often
than read, but not the other way around. I'll review that part of the
code when I get some time.

Hi, there must be some misunderstanding. any was indeed triggering more often. In fact when it was set to any, it was in some state of perma-trigger. And that was probably the reason, why the processEvents() call failed.