From 7aa4bfc67151199176bdd91688cefc3ef219371b Mon Sep 17 00:00:00 2001 From: Henrik Nordstrom Date: Thu, 11 Aug 2011 22:26:56 +0200 Subject: [PATCH] Custom callbacks for performing low level socket I/O --- docs/libssh2_session_callback_set.3 | 6 ++++++ include/libssh2.h | 10 ++++++++++ src/agent.c | 8 ++++---- src/libssh2_priv.h | 12 ++++++++++-- src/misc.c | 4 ++-- src/session.c | 15 +++++++++++++-- src/transport.c | 6 +++--- 7 files changed, 48 insertions(+), 13 deletions(-) diff --git a/docs/libssh2_session_callback_set.3 b/docs/libssh2_session_callback_set.3 index 4e5aa9c..1a42401 100644 --- a/docs/libssh2_session_callback_set.3 +++ b/docs/libssh2_session_callback_set.3 @@ -33,6 +33,12 @@ Called when a mismatched MAC has been detected in the transport layer. If the function returns 0, the packet will be accepted nonetheless. .IP LIBSSH2_CALLBACK_X11 Called when an X11 connection has been accepted +.IP LIBSSH2_CALLBACK_SEND +Called when libssh2 wants to send some data on the connection. +Can be set to a custom function to handle I/O your own way. +.IP LIBSSH2_CALLBACK_RECV +Called when libssh2 wants to receive some data from the connection. +Can be set to a custom function to handle I/O your own way. .SH RETURN VALUE Pointer to previous callback handler. Returns NULL if no prior callback handler was set or the callback type was unknown. diff --git a/include/libssh2.h b/include/libssh2.h index 57fe2c6..b44b1e9 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -237,12 +237,22 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE void name(LIBSSH2_SESSION *session, void **session_abstract, \ LIBSSH2_CHANNEL *channel, void **channel_abstract) +/* I/O callbacks */ +#define LIBSSH2_RECV_FUNC(name) ssize_t name(int socket, \ + void *buffer, size_t length, \ + int flags, void **abstract) +#define LIBSSH2_SEND_FUNC(name) ssize_t name(int socket, \ + const void *buffer, size_t length,\ + int flags, void **abstract) + /* libssh2_session_callback_set() constants */ #define LIBSSH2_CALLBACK_IGNORE 0 #define LIBSSH2_CALLBACK_DEBUG 1 #define LIBSSH2_CALLBACK_DISCONNECT 2 #define LIBSSH2_CALLBACK_MACERROR 3 #define LIBSSH2_CALLBACK_X11 4 +#define LIBSSH2_CALLBACK_SEND 5 +#define LIBSSH2_CALLBACK_RECV 6 /* libssh2_session_method_pref() constants */ #define LIBSSH2_METHOD_KEX 0 diff --git a/src/agent.c b/src/agent.c index 7c6eaa3..5a9e81c 100644 --- a/src/agent.c +++ b/src/agent.c @@ -177,7 +177,7 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the length of the request */ if (transctx->state == agent_NB_state_request_created) { _libssh2_htonu32(buf, transctx->request_len); - rc = _libssh2_send(agent->fd, buf, sizeof buf, 0); + rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0); if (rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; else if (rc < 0) @@ -188,7 +188,7 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Send the request body */ if (transctx->state == agent_NB_state_request_length_sent) { - rc = _libssh2_send(agent->fd, transctx->request, + rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request, transctx->request_len, 0); if (rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -200,7 +200,7 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the length of a response */ if (transctx->state == agent_NB_state_request_sent) { - rc = _libssh2_recv(agent->fd, buf, sizeof buf, 0); + rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0); if (rc < 0) { if (rc == -EAGAIN) return LIBSSH2_ERROR_EAGAIN; @@ -218,7 +218,7 @@ agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) /* Receive the response body */ if (transctx->state == agent_NB_state_response_length_received) { - rc = _libssh2_recv(agent->fd, transctx->response, + rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response, transctx->response_len, 0); if (rc < 0) { if (rc == -EAGAIN) diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index 473e9c3..d2f8054 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -171,6 +171,12 @@ static inline int writev(int sock, struct iovec *iov, int nvecs) #define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract) +#define LIBSSH2_SEND_FD(session, fd, buffer, length, flags) session->send(fd, buffer, length, flags, &session->abstract) +#define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) session->recv(fd, buffer, length, flags, &session->abstract) + +#define LIBSSH2_SEND(session, buffer, length, flags) LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) +#define LIBSSH2_RECV(session, buffer, length, flags) LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) + typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD; typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD; @@ -539,6 +545,8 @@ struct _LIBSSH2_SESSION LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); LIBSSH2_MACERROR_FUNC((*macerror)); LIBSSH2_X11_OPEN_FUNC((*x11)); + LIBSSH2_SEND_FUNC((*send)); + LIBSSH2_RECV_FUNC((*recv)); /* Method preferences -- NULL yields "load order" */ char *kex_prefs; @@ -972,9 +980,9 @@ _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) #define SSH_OPEN_RESOURCE_SHORTAGE 4 ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, - size_t length, int flags); + size_t length, int flags, void **abstract); ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, - size_t length, int flags); + size_t length, int flags, void **abstract); #define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when waiting for more data to arrive */ diff --git a/src/misc.c b/src/misc.c index cc07fc6..a9f423a 100644 --- a/src/misc.c +++ b/src/misc.c @@ -94,7 +94,7 @@ static int wsa2errno(void) * Replacement for the standard recv, return -errno on failure. */ ssize_t -_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags) +_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags, void **abstract) { ssize_t rc = recv(sock, buffer, length, flags); #ifdef WIN32 @@ -126,7 +126,7 @@ _libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags) */ ssize_t _libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, - int flags) + int flags, void **abstract) { ssize_t rc = send(sock, buffer, length, flags); #ifdef WIN32 diff --git a/src/session.c b/src/session.c index 46ef016..50d08ee 100644 --- a/src/session.c +++ b/src/session.c @@ -115,7 +115,7 @@ banner_receive(LIBSSH2_SESSION * session) /* no incoming block yet! */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; - ret = _libssh2_recv(session->socket_fd, &c, 1, + ret = LIBSSH2_RECV(session, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session)); if (ret < 0) { if(session->api_block_mode || (ret != -EAGAIN)) @@ -227,7 +227,7 @@ banner_send(LIBSSH2_SESSION * session) /* no outgoing block yet! */ session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; - ret = _libssh2_send(session->socket_fd, + ret = LIBSSH2_SEND(session, banner + session->banner_TxRx_total_send, banner_len - session->banner_TxRx_total_send, LIBSSH2_SOCKET_SEND_FLAGS(session)); @@ -481,6 +481,8 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), session->alloc = local_alloc; session->free = local_free; session->realloc = local_realloc; + session->send = _libssh2_send; + session->recv = _libssh2_recv; session->abstract = abstract; session->api_timeout = 0; /* timeout-free API by default */ session->api_block_mode = 1; /* blocking API by default */ @@ -532,6 +534,15 @@ libssh2_session_callback_set(LIBSSH2_SESSION * session, session->x11 = callback; return oldcb; + case LIBSSH2_CALLBACK_SEND: + oldcb = session->send; + session->send = callback; + return oldcb; + + case LIBSSH2_CALLBACK_RECV: + oldcb = session->recv; + session->recv = callback; + return oldcb; } _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", cbtype); diff --git a/src/transport.c b/src/transport.c index 0cb7b63..057dcf5 100644 --- a/src/transport.c +++ b/src/transport.c @@ -357,7 +357,7 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) /* now read a big chunk from the network into the temp buffer */ nread = - _libssh2_recv(session->socket_fd, &p->buf[remainbuf], + LIBSSH2_RECV(session, &p->buf[remainbuf], PACKETBUFSIZE - remainbuf, LIBSSH2_SOCKET_RECV_FLAGS(session)); if (nread <= 0) { @@ -610,7 +610,7 @@ send_existing(LIBSSH2_SESSION *session, const unsigned char *data, /* number of bytes left to send */ length = p->ototal_num - p->osent; - rc = _libssh2_send(session->socket_fd, &p->outbuf[p->osent], length, + rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, LIBSSH2_SOCKET_SEND_FLAGS(session)); if (rc < 0) _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, @@ -823,7 +823,7 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session, session->local.seqno++; - ret = _libssh2_send(session->socket_fd, p->outbuf, total_length, + ret = LIBSSH2_SEND(session, p->outbuf, total_length, LIBSSH2_SOCKET_SEND_FLAGS(session)); if (ret < 0) _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,