X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=43625fe0d22c85ccb76f8226fdcc2cf7cad9629e;hp=a9873e4fc87b25b0e29e992fa9d1a2057b1053e1;hb=6626395c88fc46eeb110942b17eb9245a1d0021b;hpb=65f3adca21aa7066bea2e8842e533aa0e25583f4 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index a9873e4f..43625fe0 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -2,21 +2,20 @@ * ngIRCd -- The Next Generation IRC Daemon * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de) * - * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen - * der GNU General Public License (GPL), wie von der Free Software Foundation - * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2 - * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version. - * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste - * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * Please read the file COPYING, README and AUTHORS for more information. * - * $Id: conn.c,v 1.96 2002/11/26 23:07:24 alex Exp $ - * - * connect.h: Verwaltung aller Netz-Verbindungen ("connections") + * Connection management */ #include "portab.h" +static char UNUSED id[] = "$Id: conn.c,v 1.108 2002/12/26 16:48:14 alex Exp $"; + #include "imp.h" #include #include @@ -89,11 +88,13 @@ typedef struct _Connection CHAR wbuf[WRITEBUFFER_LEN]; /* Schreibpuffer */ INT wdatalen; /* Laenge der Daten im Schreibpuffer */ INT our_server; /* wenn von uns zu connectender Server: ID */ + time_t starttime; /* Startzeit des Links */ time_t lastdata; /* Letzte Aktivitaet */ time_t lastping; /* Letzter PING */ time_t lastprivmsg; /* Letzte PRIVMSG */ time_t delaytime; /* Nicht beachten bis ("penalty") */ - LONG bytes_in, bytes_out; /* Counter fuer Statistik */ + LONG bytes_in, bytes_out; /* Empfangene uns gesendete Bytes */ + LONG msg_in, msg_out; /* Empfangene uns gesendete Nachtichten */ INT flag; /* "Markierungs-Flag" (vgl. "irc-write"-Modul) */ INT options; /* Link-Optionen */ #ifdef USE_ZLIB @@ -128,7 +129,7 @@ LOCAL fd_set My_Sockets; LOCAL fd_set My_Connects; LOCAL CONNECTION *My_Connections; -LOCAL LONG Pool_Size; +LOCAL LONG Pool_Size, WCounter; GLOBAL VOID @@ -152,7 +153,7 @@ Conn_Init( VOID ) Log( LOG_EMERG, "Can't allocate memory! [Conn_Init]" ); exit( 1 ); } - Log( LOG_DEBUG, "Allocted connection pool for %ld items.", Pool_Size ); + Log( LOG_DEBUG, "Allocted connection pool for %ld items (%ld bytes).", Pool_Size, sizeof( CONNECTION ) * Pool_Size ); /* zu Beginn haben wir keine Verbindungen */ FD_ZERO( &My_Listeners ); @@ -164,6 +165,9 @@ Conn_Init( VOID ) /* Connection-Struktur initialisieren */ for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i ); + + /* Global write counter */ + WCounter = 0; } /* Conn_Init */ @@ -198,7 +202,7 @@ Conn_Exit( VOID ) } else if( idx < Pool_Size ) { - if( NGIRCd_Restart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE ); + if( NGIRCd_SignalRestart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE ); else Conn_Close( idx, NULL, "Server going down", TRUE ); } else @@ -328,12 +332,15 @@ Conn_Handler( VOID ) BOOLEAN timeout; start = time( NULL ); - while(( ! NGIRCd_Quit ) && ( ! NGIRCd_Restart )) + while(( ! NGIRCd_SignalQuit ) && ( ! NGIRCd_SignalRestart )) { timeout = TRUE; - - Check_Servers( ); + /* Should the configuration be reloaded? */ + if( NGIRCd_SignalRehash ) NGIRCd_Rehash( ); + + /* Check configured servers and established links */ + Check_Servers( ); Check_Connections( ); /* noch volle Lese-Buffer suchen */ @@ -444,6 +451,9 @@ Conn_Handler( VOID ) if( FD_ISSET( i, &read_sockets )) Handle_Read( i ); } } + + if( NGIRCd_SignalQuit ) Log( LOG_NOTICE|LOG_snotice, "Server going down NOW!" ); + else if( NGIRCd_SignalRestart ) Log( LOG_NOTICE|LOG_snotice, "Server restarting NOW!" ); } /* Conn_Handler */ @@ -485,8 +495,9 @@ va_dcl if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer ); #endif - strcat( buffer, "\r\n" ); + strlcat( buffer, "\r\n", sizeof( buffer )); ok = Conn_Write( Idx, buffer, strlen( buffer )); + My_Connections[Idx].msg_out++; va_end( ap ); return ok; @@ -546,6 +557,9 @@ Conn_Write( CONN_ID Idx, CHAR *Data, INT Len ) My_Connections[Idx].bytes_out += Len; } + /* Adjust global write counter */ + WCounter += Len; + return TRUE; } /* Conn_Write */ @@ -570,11 +584,13 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) if( InformClient ) { +#ifndef STRICT_RFC /* Statistik an Client melden, wenn User */ if(( c != NULL ) && ( Client_Type( c ) == CLIENT_USER )) { Conn_WriteStr( Idx, "NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb.", Client_ThisServer( ), NOTICE_TXTPREFIX, (DOUBLE)My_Connections[Idx].bytes_in / 1024, (DOUBLE)My_Connections[Idx].bytes_out / 1024 ); } +#endif /* ERROR an Client schicken (von RFC so vorgesehen!) */ if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg ); @@ -582,6 +598,10 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) if( My_Connections[Idx].sock == NONE ) return; } + /* zunaechst versuchen, noch im Schreibpuffer vorhandene + * Daten auf den Socket zu schreiben ... */ + Try_Write( Idx ); + if( close( My_Connections[Idx].sock ) != 0 ) { Log( LOG_ERR, "Error closing connection %d (socket %d) with %s:%d - %s!", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), strerror( errno )); @@ -597,12 +617,12 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) out_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_out / 1024; in_p = (INT)(( in_k * 100 ) / in_z_k ); out_p = (INT)(( out_k * 100 ) / out_z_k ); - Log( LOG_INFO, "Connection %d (socket %d) with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, in_z_k, in_p, out_k, out_z_k, out_p ); + Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, in_z_k, in_p, out_k, out_z_k, out_p ); } else #endif { - Log( LOG_INFO, "Connection %d (socket %d) with %s:%d closed (in: %.1fk, out: %.1fk).", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, out_k ); + Log( LOG_INFO, "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).", Idx, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), in_k, out_k ); } } @@ -858,21 +878,142 @@ Conn_InitZip( CONN_ID Idx ) return TRUE; } /* Conn_InitZip */ + +GLOBAL LONG +Conn_SendBytesZip( CONN_ID Idx ) +{ + /* Anzahl gesendeter Bytes (komprimiert!) liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].zip.bytes_out; +} /* Conn_SendBytesZip */ + + +GLOBAL LONG +Conn_RecvBytesZip( CONN_ID Idx ) +{ + /* Anzahl gesendeter Bytes (komprimiert!) liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].zip.bytes_in; +} /* Conn_RecvBytesZip */ + +#endif + + +GLOBAL time_t +Conn_StartTime( CONN_ID Idx ) +{ + /* Zeitpunkt des Link-Starts liefern (in Sekunden) */ + + assert( Idx > NONE ); + return My_Connections[Idx].starttime; +} /* Conn_Uptime */ + + +GLOBAL INT +Conn_SendQ( CONN_ID Idx ) +{ + /* Laenge der Daten im Schreibbuffer liefern */ + + assert( Idx > NONE ); +#ifdef USE_ZLIB + if( My_Connections[Idx].options & CONN_ZIP ) return My_Connections[Idx].zip.wdatalen; + else +#endif + return My_Connections[Idx].wdatalen; +} /* Conn_SendQ */ + + +GLOBAL LONG +Conn_SendMsg( CONN_ID Idx ) +{ + /* Anzahl gesendeter Nachrichten liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].msg_out; +} /* Conn_SendMsg */ + + +GLOBAL LONG +Conn_SendBytes( CONN_ID Idx ) +{ + /* Anzahl gesendeter Bytes (unkomprimiert) liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].bytes_out; +} /* Conn_SendBytes */ + + +GLOBAL INT +Conn_RecvQ( CONN_ID Idx ) +{ + /* Laenge der Daten im Lesebuffer liefern */ + + assert( Idx > NONE ); +#ifdef USE_ZLIB + if( My_Connections[Idx].options & CONN_ZIP ) return My_Connections[Idx].zip.rdatalen; + else #endif + return My_Connections[Idx].rdatalen; +} /* Conn_RecvQ */ + + +GLOBAL LONG +Conn_RecvMsg( CONN_ID Idx ) +{ + /* Anzahl empfangener Nachrichten liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].msg_in; +} /* Conn_RecvMsg */ + + +GLOBAL LONG +Conn_RecvBytes( CONN_ID Idx ) +{ + /* Anzahl empfangener Bytes (unkomprimiert) liefern */ + + assert( Idx > NONE ); + return My_Connections[Idx].bytes_in; +} /* Conn_RecvBytes */ + + +GLOBAL VOID +Conn_ResetWCounter( VOID ) +{ + WCounter = 0; +} /* Conn_ResetWCounter */ + + +GLOBAL LONG +Conn_WCounter( VOID ) +{ + return WCounter; +} /* Conn_WCounter */ LOCAL BOOLEAN Try_Write( CONN_ID Idx ) { - /* Versuchen, Daten aus dem Schreib-Puffer in den - * Socket zu schreiben. */ + /* Versuchen, Daten aus dem Schreib-Puffer in den Socket zu + * schreiben. TRUE wird geliefert, wenn entweder keine Daten + * zum Versenden vorhanden sind oder erfolgreich bearbeitet + * werden konnten. Im Fehlerfall wird FALSE geliefert und + * die Verbindung geschlossen. */ fd_set write_socket; struct timeval tv; assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); - assert( My_Connections[Idx].wdatalen > 0 ); + + /* sind ueberhaupt Daten vorhanden? */ +#ifdef USE_ZLIB + if(( ! My_Connections[Idx].wdatalen > 0 ) && ( ! My_Connections[Idx].zip.wdatalen )) return TRUE; +#else + if( ! My_Connections[Idx].wdatalen > 0 ) return TRUE; +#endif /* Timeout initialisieren: 0 Sekunden, also nicht blockieren */ tv.tv_sec = 0; tv.tv_usec = 0; @@ -1074,11 +1215,18 @@ New_Connection( INT Sock ) /* Struktur umkopieren ... */ memcpy( ptr, My_Connections, sizeof( CONNECTION ) * Pool_Size ); - Log( LOG_DEBUG, "Allocated new connection pool for %ld items. [malloc()/memcpy()]", new_size ); + Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [malloc()/memcpy()]", new_size, sizeof( CONNECTION ) * new_size ); } - else Log( LOG_DEBUG, "Allocated new connection pool for %ld items. [realloc()]", new_size ); + else Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [realloc()]", new_size, sizeof( CONNECTION ) * new_size ); + /* Adjust pointer to new block */ My_Connections = ptr; + + /* Initialize new items */ + for( idx = Pool_Size; idx < new_size; idx++ ) Init_Conn_Struct( idx ); + idx = Pool_Size; + + /* Adjust new pool size */ Pool_Size = new_size; } @@ -1109,7 +1257,6 @@ New_Connection( INT Sock ) if( s ) { /* Sub-Prozess wurde asyncron gestartet */ - Conn_WriteStr( idx, "NOTICE AUTH :%sLooking up your hostname ...", NOTICE_TXTPREFIX ); My_Connections[idx].res_stat = s; } @@ -1146,15 +1293,26 @@ Read_Request( CONN_ID Idx ) /* Daten von Socket einlesen und entsprechend behandeln. * Tritt ein Fehler auf, so wird der Socket geschlossen. */ - INT len; + INT len, bsize; +#ifdef USE_ZLIB + CLIENT *c; +#endif assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); + /* wenn noch nicht registriert: maximal mit ZREADBUFFER_LEN arbeiten, + * ansonsten koennen Daten ggf. nicht umkopiert werden. */ + bsize = READBUFFER_LEN; #ifdef USE_ZLIB - if(( READBUFFER_LEN - My_Connections[Idx].rdatalen - 1 < 1 ) || ( ZREADBUFFER_LEN - My_Connections[Idx].zip.rdatalen < 1 )) + c = Client_GetFromConn( Idx ); + if(( Client_Type( c ) != CLIENT_USER ) && ( Client_Type( c ) != CLIENT_SERVER ) && ( Client_Type( c ) != CLIENT_SERVICE ) && ( bsize > ZREADBUFFER_LEN )) bsize = ZREADBUFFER_LEN; +#endif + +#ifdef USE_ZLIB + if(( bsize - My_Connections[Idx].rdatalen - 1 < 1 ) || ( ZREADBUFFER_LEN - My_Connections[Idx].zip.rdatalen < 1 )) #else - if( READBUFFER_LEN - My_Connections[Idx].rdatalen - 1 < 1 ) + if( bsize - My_Connections[Idx].rdatalen - 1 < 1 ) #endif { /* Der Lesepuffer ist voll */ @@ -1172,14 +1330,14 @@ Read_Request( CONN_ID Idx ) else #endif { - len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, READBUFFER_LEN - My_Connections[Idx].rdatalen - 1, 0 ); + len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, bsize - My_Connections[Idx].rdatalen - 1, 0 ); if( len > 0 ) My_Connections[Idx].rdatalen += len; } if( len == 0 ) { /* Socket wurde geschlossen */ - Log( LOG_INFO, "%s:%d is closing the connection ...", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port)); + 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; } @@ -1218,6 +1376,9 @@ Handle_Buffer( CONN_ID Idx ) CHAR *ptr; INT len, delta; BOOLEAN action, result; +#ifdef USE_ZLIB + BOOLEAN old_z; +#endif result = FALSE; do @@ -1267,17 +1428,44 @@ Handle_Buffer( CONN_ID Idx ) Conn_Close( Idx, NULL, "Request too long", TRUE ); return FALSE; } - + +#ifdef USE_ZLIB + /* merken, ob Stream bereits komprimiert wird */ + old_z = My_Connections[Idx].options & CONN_ZIP; +#endif + if( len > delta ) { /* Es wurde ein Request gelesen */ + My_Connections[Idx].msg_in++; if( ! Parse_Request( Idx, My_Connections[Idx].rbuf )) return FALSE; else action = TRUE; } - + /* Puffer anpassen */ My_Connections[Idx].rdatalen -= len; memmove( My_Connections[Idx].rbuf, My_Connections[Idx].rbuf + len, My_Connections[Idx].rdatalen ); + +#ifdef USE_ZLIB + if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) && ( My_Connections[Idx].rdatalen > 0 )) + { + /* Mit dem letzten Befehl wurde Socket-Kompression aktiviert. + * Evtl. schon vom Socket gelesene Daten in den Unzip-Puffer + * umkopieren, damit diese nun zunaechst entkomprimiert werden */ + { + if( My_Connections[Idx].rdatalen > ZREADBUFFER_LEN ) + { + /* Hupsa! Soviel Platz haben wir aber gar nicht! */ + Log( LOG_ALERT, "Can't move read buffer: No space left in unzip buffer (need %d bytes)!", My_Connections[Idx].rdatalen ); + return FALSE; + } + memcpy( My_Connections[Idx].zip.rbuf, My_Connections[Idx].rbuf, My_Connections[Idx].rdatalen ); + My_Connections[Idx].zip.rdatalen = My_Connections[Idx].rdatalen; + My_Connections[Idx].rdatalen = 0; + Log( LOG_DEBUG, "Moved already received data (%d bytes) to uncompression buffer.", My_Connections[Idx].zip.rdatalen ); + } + } +#endif } if( action ) result = TRUE; @@ -1513,12 +1701,15 @@ Init_Conn_Struct( LONG Idx ) My_Connections[Idx].wbuf[0] = '\0'; My_Connections[Idx].wdatalen = 0; My_Connections[Idx].our_server = NONE; + My_Connections[Idx].starttime = time( NULL ); My_Connections[Idx].lastdata = time( NULL ); My_Connections[Idx].lastping = 0; My_Connections[Idx].lastprivmsg = time( NULL ); My_Connections[Idx].delaytime = 0; My_Connections[Idx].bytes_in = 0; My_Connections[Idx].bytes_out = 0; + My_Connections[Idx].msg_in = 0; + My_Connections[Idx].msg_out = 0; My_Connections[Idx].flag = 0; My_Connections[Idx].options = 0; @@ -1610,8 +1801,6 @@ Read_Resolver_Result( INT r_fd ) assert( c != NULL ); strcpy( My_Connections[i].host, result ); Client_SetHostname( c, result ); - - Conn_WriteStr( i, "NOTICE AUTH :%sGot your hostname.", NOTICE_TXTPREFIX ); } else { @@ -1710,7 +1899,7 @@ Unzip_Buffer( CONN_ID Idx ) result = inflate( in, Z_SYNC_FLUSH ); if( result != Z_OK ) { - Log( LOG_ALERT, "Decompression error: code %d!?", result ); + Log( LOG_ALERT, "Decompression error: code %d (ni=%d, ai=%d, no=%d, ao=%d)!?", result, in->next_in, in->avail_in, in->next_out, in->avail_out ); Conn_Close( Idx, "Decompression error!", NULL, FALSE ); return FALSE; }