From cc7703092fa44ae0b1619659550975b91dae0e90 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Wed, 18 May 2005 17:08:29 +0000 Subject: [PATCH] Save up multiple small refunds in order to cut down on unnecessary WINDOW_ADJUST packets --- include/libssh2.h | 5 ++- include/libssh2_priv.h | 1 + src/channel.c | 80 ++++++++++++++++++++++++++---------------- src/packet.c | 12 ++----- 4 files changed, 56 insertions(+), 42 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index f4c2f76..c37b295 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -67,7 +67,7 @@ typedef unsigned long long libssh2_uint64_t; typedef long long libssh2_int64_t; #endif -#define LIBSSH2_VERSION "0.9" +#define LIBSSH2_VERSION "0.10" #define LIBSSH2_APINO 200503281457 /* Part of every banner, user specified or not */ @@ -279,6 +279,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeou /* Channel API */ #define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536 #define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384 +#define LIBSSH2_CHANNEL_MINADJUST 1024 /* Extended Data Handling */ #define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0 @@ -321,6 +322,8 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial); #define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL) +LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force); + LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen); #define libssh2_channel_write(channel, buf, buflen) libssh2_channel_write_ex((channel), 0, (buf), (buflen)) #define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) diff --git a/include/libssh2_priv.h b/include/libssh2_priv.h index 4f450d9..29e1a6f 100644 --- a/include/libssh2_priv.h +++ b/include/libssh2_priv.h @@ -113,6 +113,7 @@ struct _LIBSSH2_CHANNEL { int blocking; libssh2_channel_data local, remote; + unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */ LIBSSH2_SESSION *session; diff --git a/src/channel.c b/src/channel.c index c22922b..393c137 100644 --- a/src/channel.c +++ b/src/channel.c @@ -780,28 +780,59 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid) } if (refund_bytes && channel->remote.window_size_initial) { - unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ - - /* Adjust the window based on the block we just freed */ - adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; - libssh2_htonu32(adjust + 1, channel->remote.id); - libssh2_htonu32(adjust + 5, refund_bytes); -#ifdef LIBSSH2_DEBUG_CONNECTION - _libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Adjusting window %lu bytes for data flushed from channel %lu/%lu", refund_bytes, channel->local.id, channel->remote.id); -#endif - - if (libssh2_packet_write(channel->session, adjust, 9)) { - libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); - return -1; - } else { - channel->remote.window_size += refund_bytes; - } + libssh2_channel_receive_window_adjust(channel, refund_bytes, 0); } return flush_bytes; } /* }}} */ +/* {{{ libssh2_channel_receive_window_adjust + * Adjust the receive window for a channel by adjustment bytes + * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 + * The adjustment amount will be queued for a later packet + * + * Returns the new size of the receive window (as understood by remote end) + */ +LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force) +{ + unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ + + if (!force && (adjustment + channel->adjust_queue < LIBSSH2_CHANNEL_MINADJUST)) { +#ifdef LIBSSH2_DEBUG_CONNECTION + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Queing %lu bytes for receive window adjustment for channel %lu/%lu", adjustment, channel->local.id, channel->remote.id); +#endif + channel->adjust_queue += adjustment; + return channel->remote.window_size; + } + + if (!adjustment && !channel->adjust_queue) { + return channel->remote.window_size; + } + + adjustment += channel->adjust_queue; + channel->adjust_queue = 0; + + + /* Adjust the window based on the block we just freed */ + adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; + libssh2_htonu32(adjust + 1, channel->remote.id); + libssh2_htonu32(adjust + 5, adjustment); +#ifdef LIBSSH2_DEBUG_CONNECTION + _libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Adjusting window %lu bytes for data flushed from channel %lu/%lu", adjustment, channel->local.id, channel->remote.id); +#endif + + if (libssh2_packet_write(channel->session, adjust, 9)) { + libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet, deferring", 0); + channel->adjust_queue = adjustment; + } else { + channel->remote.window_size += adjustment; + } + + return channel->remote.window_size; +} +/* }}} */ + /* {{{ libssh2_channel_handle_extended_data * How should extended data look to the calling app? * Keep it in separate channels[_read() _read_stdder()]? (NORMAL) @@ -866,8 +897,6 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, bytes_read += want; if (unlink_packet) { - unsigned char adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ - if (packet->prev) { packet->prev->next = packet->next; } else { @@ -881,20 +910,9 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, LIBSSH2_FREE(session, packet->data); #ifdef LIBSSH2_DEBUG_CONNECTION - _libssh2_debug(session, LIBSSH2_DBG_CONN, "Unlinking empty packet buffer from channel %lu/%lu sending window adjust for %d bytes", channel->local.id, channel->remote.id, (int)(packet->data_len - (stream_id ? 13 : 9))); + _libssh2_debug(session, LIBSSH2_DBG_CONN, "Unlinking empty packet buffer from channel %lu/%lu", channel->local.id, channel->remote.id); #endif - /* Adjust the window based on the block we just freed */ - adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; - libssh2_htonu32(adjust + 1, channel->remote.id); - libssh2_htonu32(adjust + 5, packet->data_len - (stream_id ? 13 : 9)); - - if (libssh2_packet_write(session, adjust, 9)) { - libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); - } else { - /* Don't forget to acknowledge the adjust on this end */ - channel->remote.window_size += (packet->data_len - (stream_id ? 13 : 9)); - } - + libssh2_channel_receive_window_adjust(channel, packet->data_len - (stream_id ? 13 : 9), 0); LIBSSH2_FREE(session, packet); } } diff --git a/src/packet.c b/src/packet.c index 0b51474..aaf323b 100644 --- a/src/packet.c +++ b/src/packet.c @@ -446,19 +446,11 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz LIBSSH2_FREE(session, data); if (channel->remote.window_size_initial) { - /* Adjust the window based on the block we just freed */ - unsigned char adjust[9]; - #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13)); #endif - adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; - libssh2_htonu32(adjust + 1, channel->remote.id); - libssh2_htonu32(adjust + 5, datalen - 13); - - if (libssh2_packet_write(channel->session, adjust, 9)) { - libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); - } + /* Adjust the window based on the block we just freed */ + libssh2_channel_receive_window_adjust(channel, datalen - 13, 0); } return 0; }