]> arthur.barton.de Git - ngircd-alex.git/commitdiff
Reworked read and write buffer handling, introduced WRITEBUFFER_SLINK_LEN.
authorAlexander Barton <alex@barton.de>
Thu, 17 May 2007 23:34:24 +0000 (23:34 +0000)
committerAlexander Barton <alex@barton.de>
Thu, 17 May 2007 23:34:24 +0000 (23:34 +0000)
src/ngircd/conn-zip.c
src/ngircd/conn.c
src/ngircd/defines.h

index f162d2bc90e9a1ac3b72ed3854d4dae39b490360..826383b0732a310d6ef6837756e5694c2d595a71 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2006 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2007 Alexander Barton (alex@barton.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
 /* enable more zlib related debug messages: */
 /* #define DEBUG_ZLIB */
 
-static char UNUSED id[] = "$Id: conn-zip.c,v 1.15 2007/05/17 15:16:47 alex Exp $";
+static char UNUSED id[] = "$Id: conn-zip.c,v 1.16 2007/05/17 23:34:24 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -82,6 +82,16 @@ Zip_InitConn( CONN_ID Idx )
 } /* Zip_InitConn */
 
 
+/**
+ * Copy data to the compression buffer of a connection. We do collect
+ * some data there until it's full so that we can achieve better
+ * compression ratios.
+ * If the (pre-)compression buffer is full, we try to flush it ("actually
+ * compress some data") and to add the new (uncompressed) data afterwards.
+ * @param Idx Connection handle.
+ * @param Data Pointer to the data.
+ * @param Len Length of the data to add.
+ * @return true on success, false otherwise. */
 GLOBAL bool
 Zip_Buffer( CONN_ID Idx, char *Data, size_t Len )
 {
@@ -92,7 +102,7 @@ Zip_Buffer( CONN_ID Idx, char *Data, size_t Len )
        assert( Len > 0 );
 
        buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
-       if (buflen >= WRITEBUFFER_LEN) {
+       if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
                /* compression buffer is full, flush */
                if( ! Zip_Flush( Idx )) return false;
        }
@@ -100,8 +110,9 @@ Zip_Buffer( CONN_ID Idx, char *Data, size_t Len )
        /* check again; if zip buf is still too large do not append data:
         * otherwise the zip wbuf would grow too large */
        buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
-       if (buflen >= WRITEBUFFER_LEN)
+       if (buflen + Len >= WRITEBUFFER_SLINK_LEN)
                return false;
+
        return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len);
 } /* Zip_Buffer */
 
@@ -116,7 +127,7 @@ GLOBAL bool
 Zip_Flush( CONN_ID Idx )
 {
        int result;
-       unsigned char zipbuf[WRITEBUFFER_LEN];
+       unsigned char zipbuf[WRITEBUFFER_SLINK_LEN];
        int zipbuf_used = 0;
        z_stream *out;
 
@@ -152,9 +163,9 @@ Zip_Flush( CONN_ID Idx )
                return false;
        }
 
-       assert(out->avail_out <= WRITEBUFFER_LEN);
+       assert(out->avail_out <= WRITEBUFFER_SLINK_LEN);
 
-       zipbuf_used = WRITEBUFFER_LEN - out->avail_out;
+       zipbuf_used = WRITEBUFFER_SLINK_LEN - out->avail_out;
 #ifdef DEBUG_ZIP
        Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used);
 #endif
index 912ac3afe0fe26106cdf7411e1439fca67ad22e8..b904e2e49689f03c393ebdddab576839cf9f4320 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2005 Alexander Barton <alex@barton.de>
+ * Copyright (c)2001-2007 Alexander Barton (alex@barton.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
 #include "portab.h"
 #include "io.h"
 
-static char UNUSED id[] = "$Id: conn.c,v 1.208 2007/05/17 12:39:25 fw Exp $";
+static char UNUSED id[] = "$Id: conn.c,v 1.209 2007/05/17 23:34:24 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -609,10 +609,10 @@ va_dcl
 
 
 /**
- * Append Data to outbound write buf.
- * @param Idx Index fo the connection.
- * @param Data pointer to data
- * @param Len length of Data
+ * Append Data to the outbound write buffer of a connection.
+ * @param Idx Index of the connection.
+ * @param Data pointer to the data.
+ * @param Len length of Data.
  * @return true on success, false otherwise.
  */
 static bool
@@ -626,42 +626,56 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len )
 
        c = Conn_GetClient(Idx);
        assert( c != NULL);
+
+       /* Servers do get special write buffer limits, so they can generate
+        * all the messages that are required while peering. */
        if (Client_Type(c) == CLIENT_SERVER)
-               writebuf_limit = WRITEBUFFER_LEN * 10;
+               writebuf_limit = WRITEBUFFER_SLINK_LEN;
+
        /* Is the socket still open? A previous call to Conn_Write()
         * may have closed the connection due to a fatal error.
-        * In this case it is sufficient to return an error */
+        * In this case it is sufficient to return an error, as well. */
        if( My_Connections[Idx].sock <= NONE ) {
-               LogDebug("Skipped write on closed socket (connection %d).", Idx );
+               LogDebug("Skipped write on closed socket (connection %d).", Idx);
                return false;
        }
 
-       /* check if outbound buffer has enough space for data.
-        * the idea is to keep data buffered  before sending, e.g. to improve
-        * compression */
-       if (array_bytes(&My_Connections[Idx].wbuf) >= writebuf_limit) {
-               /* Buffer is full, flush. Handle_Write deals with low-level errors, if any. */
-               if( ! Handle_Write( Idx )) return false;
-
-               /* check again: if our writebuf is twice als large as the initial limit: Kill connection */
-               if (array_bytes(&My_Connections[Idx].wbuf) >= (writebuf_limit*2)) {
-                       Log(LOG_NOTICE, "Write buffer overflow (connection %d, size %lu byte)!", Idx,
-                                       (unsigned long) array_bytes(&My_Connections[Idx].wbuf));
-                       Conn_Close( Idx, "Write buffer overflow!", NULL, false );
-                       return false;
-               }
-       }
-
 #ifdef ZLIB
        if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
-               /* compress and move data to write buffer */
-               if( ! Zip_Buffer( Idx, Data, Len )) return false;
+               /* Compressed link:
+                * Zip_Buffer() does all the dirty work for us: it flushes
+                * the (pre-)compression buffers if required and handles
+                * all error conditions. */
+               if (!Zip_Buffer(Idx, Data, Len))
+                       return false;
        }
        else
 #endif
        {
-               /* copy data to write buffer */
-               if (!array_catb( &My_Connections[Idx].wbuf, Data, Len ))
+               /* Uncompressed link:
+                * Check if outbound buffer has enough space for the data. */
+               if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
+                   writebuf_limit) {
+                       /* Buffer is full, flush it. Handle_Write deals with
+                        * low-level errors, if any. */
+                       if (!Handle_Write(Idx))
+                               return false;
+               }
+
+               /* When the write buffer is still too big after flushing it,
+                * the connection will be killed. */
+               if (array_bytes(&My_Connections[Idx].wbuf) + Len >=
+                   writebuf_limit) {
+                       Log(LOG_NOTICE,
+                           "Write buffer overflow (connection %d, size %lu byte)!",
+                           Idx,
+                           (unsigned long)array_bytes(&My_Connections[Idx].wbuf));
+                       Conn_Close(Idx, "Write buffer overflow!", NULL, false);
+                       return false;
+               }
+
+               /* Copy data to write buffer */
+               if (!array_catb(&My_Connections[Idx].wbuf, Data, Len))
                        return false;
 
                My_Connections[Idx].bytes_out += Len;
@@ -873,24 +887,23 @@ Handle_Write( CONN_ID Idx )
        wdatalen = array_bytes(&My_Connections[Idx].wbuf );
 
 #ifdef ZLIB
-       if (wdatalen == 0 && !array_bytes(&My_Connections[Idx].zip.wbuf)) {
-               io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
-               return true;
+       if (wdatalen == 0) {
+               /* Write buffer is empty, so we try to flush the compression
+                * buffer and get some data to work with from there :-) */
+               if (!Zip_Flush(Idx))
+                       return false;
+
+               /* Now the write buffer most probably has changed: */
+               wdatalen = array_bytes(&My_Connections[Idx].wbuf);
        }
+#endif
 
-       /* write buffer empty, but not compression buffer?
-         * -> flush compression buffer! */
-       if (wdatalen == 0)
-               Zip_Flush(Idx);
-#else
        if (wdatalen == 0) {
+               /* Still no data, fine. */
                io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
                return true;
        }
-#endif
 
-       /* Zip_Flush() may have changed the write buffer ... */
-       wdatalen = array_bytes(&My_Connections[Idx].wbuf);
        LogDebug
            ("Handle_Write() called for connection %d, %ld bytes pending ...",
             Idx, wdatalen);
@@ -1052,12 +1065,13 @@ Socket2Index( int Sock )
 } /* Socket2Index */
 
 
+/**
+ * Read data from the network to the read buffer. If an error occures,
+ * the socket of this connection will be shut down.
+ */
 static void
 Read_Request( CONN_ID Idx )
 {
-       /* Daten von Socket einlesen und entsprechend behandeln.
-        * Tritt ein Fehler auf, so wird der Socket geschlossen. */
-
        ssize_t len;
        char readbuf[READBUFFER_LEN];
        CLIENT *c;
@@ -1071,27 +1085,32 @@ Read_Request( CONN_ID Idx )
        if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN)
 #endif
        {
-               /* Der Lesepuffer ist voll */
-               Log( LOG_ERR, "Receive buffer overflow (connection %d): %d bytes!", Idx,
-                                               array_bytes(&My_Connections[Idx].rbuf));
+               /* Read buffer is full */
+               Log(LOG_ERR,
+                   "Receive buffer overflow (connection %d): %d bytes!",
+                   Idx, array_bytes(&My_Connections[Idx].rbuf));
                Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
                return;
        }
 
        len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
-       if( len == 0 ) {
-               Log( LOG_INFO, "%s:%d (%s) is closing the connection ...",
-                       My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port),
-                                       inet_ntoa( My_Connections[Idx].addr.sin_addr ));
-               Conn_Close( Idx, "Socket closed!", "Client closed connection", false );
+       if (len == 0) {
+               Log(LOG_INFO, "%s:%d (%s) is closing the connection ...",
+                   My_Connections[Idx].host,
+                   ntohs(My_Connections[Idx].addr.sin_port),
+                   inet_ntoa( My_Connections[Idx].addr.sin_addr));
+               Conn_Close(Idx,
+                          "Socket closed!", "Client closed connection",
+                          false);
                return;
        }
 
-       if( len < 0 ) {
+       if (len < 0) {
                if( errno == EAGAIN ) return;
-               Log( LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx,
-                                       My_Connections[Idx].sock, strerror( errno ));
-               Conn_Close( Idx, "Read error!", "Client closed connection", false );
+               Log(LOG_ERR, "Read error on connection %d (socket %d): %s!",
+                   Idx, My_Connections[Idx].sock, strerror(errno));
+               Conn_Close(Idx, "Read error!", "Client closed connection",
+                          false);
                return;
        }
 #ifdef ZLIB
index b25ab1b5c1ea02eec64c85e0ebb8bda6c8514b35..b686f883a12d4577b9828641e7ca599f7254bbe7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2005 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2007 Alexander Barton (alex@barton.de)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -8,7 +8,7 @@
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
  *
- * $Id: defines.h,v 1.59 2007/05/09 08:55:14 fw Exp $
+ * $Id: defines.h,v 1.60 2007/05/17 23:34:25 alex Exp $
  */
 
 
 #define COMMAND_LEN 513                        /* Max. IRC command length, see. RFC
                                           2812 section 3.2 */
 
-#define READBUFFER_LEN 4096            /* Size of the read buffer of a
+#define READBUFFER_LEN 2048            /* Size of the read buffer of a
                                           connection in bytes. */
 #define WRITEBUFFER_LEN 4096           /* Size of the write buffer of a
                                           connection in bytes. */
+#define WRITEBUFFER_SLINK_LEN 51200    /* Size of the write buffer of a
+                                          server link connection in bytes. */
 
 #define PROTOVER "0210"                        /* Implemented IRC protocol version,
                                           see RFC 2813 section 4.1.1. */