From 82e9e2ba0fc81fa250b47d6f2abadd9d0fc9d5e9 Mon Sep 17 00:00:00 2001 From: Sara Golemon Date: Wed, 8 Dec 2004 03:39:29 +0000 Subject: [PATCH] Add "ignore extended data" option to avoid having stderr data fill up the receive window and leaving no room for stdio data. --- include/libssh2.h | 1 + include/libssh2_priv.h | 2 +- src/channel.c | 68 +++++++++++++++++++++++++++++++++++++----- src/packet.c | 18 +++++++++++ 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/include/libssh2.h b/include/libssh2.h index abe9d36..ee66794 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -202,6 +202,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id #define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking); +LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore); LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); diff --git a/include/libssh2_priv.h b/include/libssh2_priv.h index 7625471..ef5b42d 100644 --- a/include/libssh2_priv.h +++ b/include/libssh2_priv.h @@ -98,7 +98,7 @@ typedef struct _libssh2_channel_data { unsigned long window_size_initial, window_size, packet_size; /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */ - int close, eof; + char close, eof, ignore_extended_data; } libssh2_channel_data; struct _LIBSSH2_CHANNEL { diff --git a/src/channel.c b/src/channel.c index 23ab9df..3f14647 100644 --- a/src/channel.c +++ b/src/channel.c @@ -434,6 +434,56 @@ LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int bloc } /* }}} */ +/* {{{ libssh2_channel_ignore_extended_data + * Ignore (or stop ignoring) extended data + */ +LIBSSH2_API void libssh2_channel_ignore_extended_data(LIBSSH2_CHANNEL *channel, int ignore) +{ + channel->remote.ignore_extended_data = ignore; + + if (ignore) { + /* Flush queued extended data */ + LIBSSH2_PACKET *packet = channel->session->packets.head; + unsigned long refund_bytes = 0; + + while (packet) { + LIBSSH2_PACKET *next = packet->next; + + if ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) { + refund_bytes += packet->data_len - 13; + LIBSSH2_FREE(channel->session, packet->data); + if (packet->prev) { + packet->prev->next = packet->next; + } else { + channel->session->packets.head = packet->next; + } + if (packet->next) { + packet->next->prev = packet->prev; + } else { + channel->session->packets.tail = packet->prev; + } + LIBSSH2_FREE(channel->session, packet); + } + packet = next; + } + 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); + + if (libssh2_packet_write(channel->session, adjust, 9)) { + libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); + } else { + channel->remote.window_size += refund_bytes; + } + } + } +} +/* }}} */ + /* {{{ libssh2_channel_read_ex * Read data from a channel */ @@ -481,16 +531,18 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, } LIBSSH2_FREE(session, packet->data); - /* 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 (channel->remote.window_size_initial) { + /* 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); + if (libssh2_packet_write(session, adjust, 9)) { + libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send transfer-window adjustment packet", 0); + } + + LIBSSH2_FREE(session, packet); } - - LIBSSH2_FREE(session, packet); } } packet = next; diff --git a/src/packet.c b/src/packet.c index 8c0ae5b..4190d3c 100644 --- a/src/packet.c +++ b/src/packet.c @@ -153,6 +153,24 @@ static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, siz LIBSSH2_FREE(session, data); return 0; } + if (channel->remote.ignore_extended_data && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) { + /* Pretend we didn't receive this */ + LIBSSH2_FREE(session, data); + + if (channel->remote.window_size_initial) { + /* Adjust the window based on the block we just freed */ + unsigned char adjust[9]; + + 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); + } + } + return 0; + } /* REMEMBER! remote means remote as source of data, NOT remote window! */ if (channel->remote.packet_size < (datalen - data_head)) {