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

Reply via email to