Package: bip Version: 0.8.1-1 Severity: normal Tags: patch commit 94d6a02407f260f78f4f9276080e8413ff77ff89 Author: Zygo Blaxell <zygo.blax...@xandros.com> Date: Tue Aug 18 12:56:43 2009 -0400
We can't loop forever waiting for a slow client because the upstream IRC server will drop our connection. We can't send a partial message because it will corrupt the data stream. We can't defer a partial message easily. This could be done by passing an extra return value from _write_sock() to its caller, or by letting _write_sock() manipulate the connection's outgoing message queue directly. If a downstream client is on the wrong end of a slow connection which is just good enough to prevent TCP connections from resetting but not good enough to keep up with the bandwidth demands of IRC, we can end up in a situation where that downstream client causes failure of the proxied IRC session. So, if write() returns EAGAIN or similar errors, retry 10 times, once per second. If the downstream client consumes a complete line of text during those 10 seconds, we let them keep their connection--otherwise, we drop the client. Currently this is done within the _write_socket function, so if multiple clients are having this problem we might block too long and the upstream server will drop us. Note that downstream client connection dropping can only happen if the TCP socket to the downstream client is blocking, which means we have already sent somewhere between 128K and 4096K of data to the client (the TCP buffer size range on Linux), and the downstream client is consuming less than one line (512 bytes max) per 10 seconds. It would be nice to send an error message explaining why we are doing this to the client, but that requires us to send even more data toward a client that is causing problems for us by not keeping up with data already sent. There is probably a similar issue with the SSL code, but I don't use SSL so I don't know how bip behaves in those cases. --- diff --git a/src/connection.c b/src/connection.c index 77edd05..1c3d163 100644 --- a/src/connection.c +++ b/src/connection.c @@ -234,6 +234,7 @@ static int _write_socket(connection_t *cn, char *message) size_t tcount = 0; size_t p_tcount = 0; ssize_t count; + int error_count = 0; size = strlen(message); do { @@ -250,8 +251,16 @@ static int _write_socket(connection_t *cn, char *message) } p_tcount = tcount; } + if (count < 0 && + (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS)) { + ++error_count; + mylog(LOG_DEBUGVERB, "write(fd %d) : %s - try #%d", cn->handle, + strerror(errno), error_count); + sleep(1); + } } while (count < 0 && - (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS)); + (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS) && + error_count < 10); #if 0 if (count <= 0 && tcount > 0) @@ -272,6 +281,7 @@ static int _write_socket(connection_t *cn, char *message) if (cn_is_connected(cn)) { mylog(LOG_DEBUGVERB, "write(fd %d) : %s", cn->handle, strerror(errno)); + connection_close(cn); cn->connected = CONN_ERROR; } mylog(LOG_DEBUGVERB, "write : %s", strerror(errno)); -- System Information: Debian Release: 5.0.2 APT prefers stable APT policy: (500, 'stable'), (189, 'testing'), (179, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 2.6.30.1-zb64 (SMP w/4 CPU cores; PREEMPT) Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) Shell: /bin/sh linked to /bin/bash -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org