From 7f740368f4410ebe336673204507607018da9549 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 15 Apr 2010 01:12:22 +0200 Subject: [PATCH] channel/transport: we now drain the outgoing send buffer when we ignore EAGAIN When we ignore the EAGAIN from the transport layer within channel_write, we now drain the outgoing transport layer buffer so that remainders in that won't cause any problems in the next invoke of _libssh2_transport_write() --- src/channel.c | 31 +++++++++++++++++-------------- src/transport.c | 16 +++++++++++++++- src/transport.h | 8 +++++++- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/channel.c b/src/channel.c index 7cabf27..284506f 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1979,6 +1979,17 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, while (buflen > 0) { if (channel->write_state == libssh2_NB_state_allocated) { + + /* drain the incoming flow first */ + do + rc = _libssh2_transport_read(session); + while (rc > 0); + + if(channel->local.window_size <= 0) { + /* there's no more room for data so we stop sending now */ + break; + } + channel->write_bufwrite = buflen; channel->write_s = channel->write_packet; @@ -1992,16 +2003,6 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, channel->write_s += 4; } - /* drain the incoming flow first */ - do - rc = _libssh2_transport_read(session); - while (rc > 0); - - if(channel->local.window_size <= 0) { - /* there's no more room for data so we stop sending now */ - break; - } - /* Don't exceed the remote end's limits */ /* REMEMBER local means local as the SOURCE of the data */ if (channel->write_bufwrite > channel->local.window_size) { @@ -2038,11 +2039,13 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, channel->write_s - channel->write_packet); if (rc == PACKET_EAGAIN) { - if(wrote) - /* some pieces of data was sent before the EAGAIN so - we return that amount! */ + 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"); } diff --git a/src/transport.c b/src/transport.c index 605e002..575a44b 100644 --- a/src/transport.c +++ b/src/transport.c @@ -1,5 +1,5 @@ /* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009 by Daniel Stenberg + * Copyright (C) 2009-2010 by Daniel Stenberg * Author: Daniel Stenberg * * Redistribution and use in source and binary forms, @@ -600,6 +600,20 @@ int _libssh2_transport_read(LIBSSH2_SESSION * session) return PACKET_FAIL; /* we never reach this point */ } +/* + * _libssh2_transport_drain() empties the outgoing send buffer if there + * is any. + */ +void _libssh2_transport_drain(LIBSSH2_SESSION * session) +{ + struct transportpacket *p = &session->packet; + if(p->outbuf) { + LIBSSH2_FREE(session, p->outbuf); + p->outbuf = NULL; + p->ototal_num = 0; + } +} + static int send_existing(LIBSSH2_SESSION * session, unsigned char *data, unsigned long data_len, ssize_t * ret) diff --git a/src/transport.h b/src/transport.h index 0752afd..95ab526 100644 --- a/src/transport.h +++ b/src/transport.h @@ -2,7 +2,7 @@ #define __LIBSSH2_TRANSPORT_H /* Copyright (C) 2007 The Written Word, Inc. All rights reserved. - * Copyright (C) 2009 by Daniel Stenberg + * Copyright (C) 2009-2010 by Daniel Stenberg * Author: Daniel Stenberg * * Redistribution and use in source and binary forms, @@ -77,4 +77,10 @@ int _libssh2_transport_write(LIBSSH2_SESSION * session, unsigned char *data, */ int _libssh2_transport_read(LIBSSH2_SESSION * session); +/* + * _libssh2_transport_drain() empties the outgoing send buffer if there + * is any. + */ +void _libssh2_transport_drain(LIBSSH2_SESSION *session); + #endif /* __LIBSSH2_TRANSPORT_H */