1
0
mirror of https://github.com/osmarks/ngircd.git synced 2025-02-15 00:30:16 +00:00

Reworked read and write buffer handling, introduced WRITEBUFFER_SLINK_LEN.

This commit is contained in:
Alexander Barton 2007-05-17 23:34:24 +00:00
parent 5930a29197
commit 255edf7eab
3 changed files with 100 additions and 68 deletions

View File

@ -1,6 +1,6 @@
/* /*
* ngIRCd -- The Next Generation IRC Daemon * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -22,7 +22,7 @@
/* enable more zlib related debug messages: */ /* enable more zlib related debug messages: */
/* #define DEBUG_ZLIB */ /* #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 "imp.h"
#include <assert.h> #include <assert.h>
@ -82,6 +82,16 @@ Zip_InitConn( CONN_ID Idx )
} /* Zip_InitConn */ } /* 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 GLOBAL bool
Zip_Buffer( CONN_ID Idx, char *Data, size_t Len ) 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 ); assert( Len > 0 );
buflen = array_bytes(&My_Connections[Idx].zip.wbuf); buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
if (buflen >= WRITEBUFFER_LEN) { if (buflen + Len >= WRITEBUFFER_SLINK_LEN) {
/* compression buffer is full, flush */ /* compression buffer is full, flush */
if( ! Zip_Flush( Idx )) return false; 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: /* check again; if zip buf is still too large do not append data:
* otherwise the zip wbuf would grow too large */ * otherwise the zip wbuf would grow too large */
buflen = array_bytes(&My_Connections[Idx].zip.wbuf); buflen = array_bytes(&My_Connections[Idx].zip.wbuf);
if (buflen >= WRITEBUFFER_LEN) if (buflen + Len >= WRITEBUFFER_SLINK_LEN)
return false; return false;
return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len); return array_catb(&My_Connections[Idx].zip.wbuf, Data, Len);
} /* Zip_Buffer */ } /* Zip_Buffer */
@ -116,7 +127,7 @@ GLOBAL bool
Zip_Flush( CONN_ID Idx ) Zip_Flush( CONN_ID Idx )
{ {
int result; int result;
unsigned char zipbuf[WRITEBUFFER_LEN]; unsigned char zipbuf[WRITEBUFFER_SLINK_LEN];
int zipbuf_used = 0; int zipbuf_used = 0;
z_stream *out; z_stream *out;
@ -152,9 +163,9 @@ Zip_Flush( CONN_ID Idx )
return false; 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 #ifdef DEBUG_ZIP
Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used); Log(LOG_DEBUG, "zipbuf_used: %d", zipbuf_used);
#endif #endif

View File

@ -1,6 +1,6 @@
/* /*
* ngIRCd -- The Next Generation IRC Daemon * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -17,7 +17,7 @@
#include "portab.h" #include "portab.h"
#include "io.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 "imp.h"
#include <assert.h> #include <assert.h>
@ -609,10 +609,10 @@ va_dcl
/** /**
* Append Data to outbound write buf. * Append Data to the outbound write buffer of a connection.
* @param Idx Index fo the connection. * @param Idx Index of the connection.
* @param Data pointer to data * @param Data pointer to the data.
* @param Len length of Data * @param Len length of Data.
* @return true on success, false otherwise. * @return true on success, false otherwise.
*/ */
static bool static bool
@ -626,42 +626,56 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len )
c = Conn_GetClient(Idx); c = Conn_GetClient(Idx);
assert( c != NULL); 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) 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() /* Is the socket still open? A previous call to Conn_Write()
* may have closed the connection due to a fatal error. * 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 ) { 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; 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 #ifdef ZLIB
if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) { if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
/* compress and move data to write buffer */ /* Compressed link:
if( ! Zip_Buffer( Idx, Data, Len )) return false; * 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 else
#endif #endif
{ {
/* copy data to write buffer */ /* Uncompressed link:
if (!array_catb( &My_Connections[Idx].wbuf, Data, Len )) * 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; return false;
My_Connections[Idx].bytes_out += Len; My_Connections[Idx].bytes_out += Len;
@ -873,24 +887,23 @@ Handle_Write( CONN_ID Idx )
wdatalen = array_bytes(&My_Connections[Idx].wbuf ); wdatalen = array_bytes(&My_Connections[Idx].wbuf );
#ifdef ZLIB #ifdef ZLIB
if (wdatalen == 0 && !array_bytes(&My_Connections[Idx].zip.wbuf)) {
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
return true;
}
/* write buffer empty, but not compression buffer?
* -> flush compression buffer! */
if (wdatalen == 0)
Zip_Flush(Idx);
#else
if (wdatalen == 0) { if (wdatalen == 0) {
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE ); /* Write buffer is empty, so we try to flush the compression
return true; * 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 #endif
/* Zip_Flush() may have changed the write buffer ... */ if (wdatalen == 0) {
wdatalen = array_bytes(&My_Connections[Idx].wbuf); /* Still no data, fine. */
io_event_del(My_Connections[Idx].sock, IO_WANTWRITE );
return true;
}
LogDebug LogDebug
("Handle_Write() called for connection %d, %ld bytes pending ...", ("Handle_Write() called for connection %d, %ld bytes pending ...",
Idx, wdatalen); Idx, wdatalen);
@ -1052,12 +1065,13 @@ Socket2Index( int Sock )
} /* Socket2Index */ } /* 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 static void
Read_Request( CONN_ID Idx ) Read_Request( CONN_ID Idx )
{ {
/* Daten von Socket einlesen und entsprechend behandeln.
* Tritt ein Fehler auf, so wird der Socket geschlossen. */
ssize_t len; ssize_t len;
char readbuf[READBUFFER_LEN]; char readbuf[READBUFFER_LEN];
CLIENT *c; CLIENT *c;
@ -1071,27 +1085,32 @@ Read_Request( CONN_ID Idx )
if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN) if (array_bytes(&My_Connections[Idx].rbuf) >= READBUFFER_LEN)
#endif #endif
{ {
/* Der Lesepuffer ist voll */ /* Read buffer is full */
Log( LOG_ERR, "Receive buffer overflow (connection %d): %d bytes!", Idx, Log(LOG_ERR,
array_bytes(&My_Connections[Idx].rbuf)); "Receive buffer overflow (connection %d): %d bytes!",
Idx, array_bytes(&My_Connections[Idx].rbuf));
Conn_Close( Idx, "Receive buffer overflow!", NULL, false ); Conn_Close( Idx, "Receive buffer overflow!", NULL, false );
return; return;
} }
len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
if( len == 0 ) { if (len == 0) {
Log( LOG_INFO, "%s:%d (%s) is closing the connection ...", Log(LOG_INFO, "%s:%d (%s) is closing the connection ...",
My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), My_Connections[Idx].host,
inet_ntoa( My_Connections[Idx].addr.sin_addr )); ntohs(My_Connections[Idx].addr.sin_port),
Conn_Close( Idx, "Socket closed!", "Client closed connection", false ); inet_ntoa( My_Connections[Idx].addr.sin_addr));
Conn_Close(Idx,
"Socket closed!", "Client closed connection",
false);
return; return;
} }
if( len < 0 ) { if (len < 0) {
if( errno == EAGAIN ) return; if( errno == EAGAIN ) return;
Log( LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx, Log(LOG_ERR, "Read error on connection %d (socket %d): %s!",
My_Connections[Idx].sock, strerror( errno )); Idx, My_Connections[Idx].sock, strerror(errno));
Conn_Close( Idx, "Read error!", "Client closed connection", false ); Conn_Close(Idx, "Read error!", "Client closed connection",
false);
return; return;
} }
#ifdef ZLIB #ifdef ZLIB

View File

@ -1,6 +1,6 @@
/* /*
* ngIRCd -- The Next Generation IRC Daemon * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -8,7 +8,7 @@
* (at your option) any later version. * (at your option) any later version.
* Please read the file COPYING, README and AUTHORS for more information. * 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 $
*/ */
@ -66,10 +66,12 @@
#define COMMAND_LEN 513 /* Max. IRC command length, see. RFC #define COMMAND_LEN 513 /* Max. IRC command length, see. RFC
2812 section 3.2 */ 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. */ connection in bytes. */
#define WRITEBUFFER_LEN 4096 /* Size of the write buffer of a #define WRITEBUFFER_LEN 4096 /* Size of the write buffer of a
connection in bytes. */ 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, #define PROTOVER "0210" /* Implemented IRC protocol version,
see RFC 2813 section 4.1.1. */ see RFC 2813 section 4.1.1. */