From f4d302fdfe9367e60aff530b51a49eceae59e82a Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 7 Oct 2010 13:26:50 +0200 Subject: [PATCH] _libssh2_channel_write: don't iterate over transport writes When a call to _libssh2_transport_write() succeeds, we must return from _libssh2_channel_write() to allow the caller to provide the next chunk of data. We cannot move on to send the next piece of data that may already have been provided in this same function call, as we risk getting EAGAIN for that and we can't return information both about sent data as well as EAGAIN. So, by returning short now, the caller will call this function again with new data to send. --- src/channel.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/channel.c b/src/channel.c index 21ccefc..3393beb 100644 --- a/src/channel.c +++ b/src/channel.c @@ -471,7 +471,7 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host, if (session->fwdLstn_state == libssh2_NB_state_created) { rc = _libssh2_transport_write(session, session->fwdLstn_packet, - session->fwdLstn_packet_len); + session->fwdLstn_packet_len); if (rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block sending global-request packet for " @@ -805,7 +805,7 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel, if (channel->setenv_state == libssh2_NB_state_created) { rc = _libssh2_transport_write(session, channel->setenv_packet, - channel->setenv_packet_len); + channel->setenv_packet_len); if (rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, rc, "Would block sending setenv request"); @@ -1041,7 +1041,7 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, if (channel->reqPTY_state == libssh2_NB_state_created) { rc = _libssh2_transport_write(session, channel->reqPTY_packet, - channel->reqPTY_packet_len); + channel->reqPTY_packet_len); if (rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, rc, "Would block sending window-change request"); @@ -1163,7 +1163,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, if (channel->reqX11_state == libssh2_NB_state_created) { rc = _libssh2_transport_write(session, channel->reqX11_packet, - channel->reqX11_packet_len); + channel->reqX11_packet_len); if (rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, rc, "Would block sending X11-req packet"); @@ -1284,7 +1284,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, if (channel->process_state == libssh2_NB_state_created) { rc = _libssh2_transport_write(session, channel->process_packet, - channel->process_packet_len); + channel->process_packet_len); if (rc == LIBSSH2_ERROR_EAGAIN) { _libssh2_error(session, rc, "Would block sending channel request"); @@ -1918,9 +1918,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) /* * _libssh2_channel_write * - * Send data to a channel. Note that if this returns EAGAIN or simply didn't - * send the entire packet, the caller must call this function again with the - * SAME input arguments. + * Send data to a channel. Note that if this returns EAGAIN, the caller must + * call this function again with the SAME input arguments. * * Returns: number of bytes sent, or if it returns a negative number, that is * the error code! @@ -2034,13 +2033,6 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, channel->write_s - channel->write_packet); if (rc == LIBSSH2_ERROR_EAGAIN) { - if(wrote) { - /* some pieces of data was sent before the EAGAIN so we - return that amount! As we ignore EAGAIN, we must drain - the outgoing transport buffer. */ - _libssh2_transport_drain(session); - goto _channel_write_done; - } return _libssh2_error(session, rc, "Unable to send channel data"); } @@ -2054,18 +2046,21 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, /* Shrink local window size */ channel->local.window_size -= channel->write_bufwrite; - /* Adjust buf for next iteration */ - buflen -= channel->write_bufwrite; - buf += channel->write_bufwrite; - channel->write_bufwrote += channel->write_bufwrite; wrote += channel->write_bufwrite; - channel->write_state = libssh2_NB_state_allocated; + /* Since _libssh2_transport_write() succeeded, we must return + now to allow the caller to provide the next chunk of data. + + We cannot move on to send the next piece of data that may + already have been provided in this same function call, as we + risk getting EAGAIN for that and we can't return information + both about sent data as well as EAGAIN. So, by returning short + now, the caller will call this function again with new data to + send */ + break; } } - _channel_write_done: - LIBSSH2_FREE(session, channel->write_packet); channel->write_packet = NULL;