[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Async Socket Interface


Hello Preston,

I did some work during the holiday and as you will see I have made some work in this direction.

Just check out the branch libssh_async which can be found on
git clone http://www.0xbadc0de.be/git/libssh/libssh_async.git
(or some git add trickery if you manage to make it work.)
It's the skeleton of the future asyncronous libssh. Don't try to run it, it doesn't really work (only some part of the calls have been made async and there is not yet an integrated main loop provider).

The callback systems (that is, reverse calls) are all made virtual through function pointers, between the different layers of the library. The forward calls (ie. send_packet() and al) are still hardcoded but could be set the same way.

Please feel free to comment on what you think about this, if I am going in the good direction or not. I really think it is.

Regards,

Aris

Preston A. Elder a écrit :
I just realized in the below code I refer to 'OpenSSL' and 'LibSSL'. Both should be 'libssh'.

Sorry for the confusion.

PreZ :)

Preston A. Elder wrote:
Aris et al,

Here is the interface I conceived of for a communications layer that is
both a) replaceable and b) easy to adapt to any situation (including not
using TCP sockets for communications).  Not to mention easy to implement
;)  I posted this in IRC a while back, but you mentioned you lost it.

Two key concepts here are that there is a handle provided by the comms
implementation to libssl upon a connection being established, and libssl
provides back another handle (ssh_session) back to the comms layer which
is used for future communications.  Both of these handles should be
opaque to the other (ie. the imeplementation does not matter).  This
allows libssl to change the implementation of ssh_session, or the comms
implementor to change the implementation of their handle at will without
affecting the other at all.

The interface itself consists of only 3 function calls and 2 callbacks. ALL the details regarding how to setup the socket, whether it's blocking
or not, how to send or receive data, or anything of the like are in the
complete control of the comms layer implementor.  I also made sure that
all buffering (in both directions) of data is done in the comms layer.

This, though, requires that libssl itself must be 'reactionary' to
received data, and not have any wait calls or anything that will require
libssl to have to block waiting for more data to arrive before being
able to do anything.  This may mean some functions such as ssh_accept
need to be split up and/or rewritten to be able to handle that the send
and receive operations are separate entities.

Proposed Interface:

// ---------------------------------------------------------------------
// Callbacks
// ---------------------------------------------------------------------

// Description:
//     Callback to have data sent over the wire to the other side.
//
//     It is the implementor's responsibility to ensure that all data
//     gets to the other side.  This could mean blocking while waiting
//     for the send to complete, or it could mean the data has been
//     buffered and will be sent asynchronously.
// Arguments:
//     void * handle  - Opaque (to libssl) handle for socket.
//     void * buffer  - Raw buffer to be sent over the wire.
//     size_t size    - Size of raw buffer.
// Return:
//     int            - 0 on success, otherwise -1
typedef int (*comm_send_data)(void *, void *, size_t);

// Description:
//     Callback to request the communications channel be closed.
// Arguments:
//     void * handle   - Opaque (to libssl) handle for socket.
typedef void (*comm_close)(void *);

// ---------------------------------------------------------------------
// LibSSL API
// ---------------------------------------------------------------------

// Description:
//     Create a libssl session from a newly created comms channel.
// Arguments:
//     handle         - Opaque (to libssl) handle for socket.
//     send_func      - Function pointer (see above) for sending data.
//     close_func     - Function pointer (see above) for closing socket.
// Return:
//     ssl_esssion *  - Opaque (to comms implementation) handle for an
//                      OpenSSL session.
ssl_session *session_create(void *handle, comm_send_data send_func,
                            comm_close close_func);

// Description:
//     Process data received over the wire.
//
//     It is expected that LibSSL will take what it wants from the
//     buffer and tell you how much it has taken.  It is then assumed
//     the caller will, if the entire buffer was not consumed, prepend
//     the unconsumed data to the next invocation of this function call.
//     The next invocation only need be made when there is additional
//     date come over the wire (ie. there is no need to call this in a
//     loop until 0 is returned), LibSSL will always consume as much as
//     it can while still having fully-formed messages.
// Arguments:
//     handle         - Opaque (to comms implementation) handle for an
//                      OpenSSL session.
//     buffer         - Raw buffer received over the wire.
//     size           - Size of raw buffer.
// Return:
//     int            - The amount of data consumed.  Or -1 on error.
int session_receive(ssl_session *handle, void *data, size_t sz);

// Description:
//     Callback to indicate the comms channel has been closed by the
//     other side (ie. unsolicited closure).
// Arguments:
//     handle         - Opaque (to comms implementation) handle for an
//                      OpenSSL session.
void session_close(ssl_session *handle);






Archive administrator: postmaster@lists.cynapses.org