X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=b941aefc8fb82466fd631038e411292f7f09cb09;hp=da7cc63b56fda202bc8166a2b24ae33a32da7c48;hb=5ecb00ed23d047b15744aaabc6d5fdf1a9b75a4d;hpb=b6c049cb3c8fc8268cc9e7ac87b544e510e8b211 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index da7cc63b..b941aefc 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -9,7 +9,7 @@ * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS. * - * $Id: conn.c,v 1.77 2002/10/09 13:34:19 alex Exp $ + * $Id: conn.c,v 1.95 2002/11/23 17:04:07 alex Exp $ * * connect.h: Verwaltung aller Netz-Verbindungen ("connections") */ @@ -75,7 +75,8 @@ typedef struct _Connection time_t lastping; /* Letzter PING */ time_t lastprivmsg; /* Letzte PRIVMSG */ time_t delaytime; /* Nicht beachten bis ("penalty") */ - INT32 bytes_in, bytes_out; /* Counter fuer Statistik */ + LONG bytes_in, bytes_out; /* Counter fuer Statistik */ + INT flag; /* Channel-Flag (vgl. "irc-write"-Modul) */ } CONNECTION; @@ -85,10 +86,10 @@ LOCAL VOID New_Connection PARAMS(( INT Sock )); LOCAL CONN_ID Socket2Index PARAMS(( INT Sock )); LOCAL VOID Read_Request PARAMS(( CONN_ID Idx )); LOCAL BOOLEAN Try_Write PARAMS(( CONN_ID Idx )); -LOCAL VOID Handle_Buffer PARAMS(( CONN_ID Idx )); +LOCAL BOOLEAN Handle_Buffer PARAMS(( CONN_ID Idx )); LOCAL VOID Check_Connections PARAMS(( VOID )); LOCAL VOID Check_Servers PARAMS(( VOID )); -LOCAL VOID Init_Conn_Struct PARAMS(( INT Idx )); +LOCAL VOID Init_Conn_Struct PARAMS(( LONG Idx )); LOCAL BOOLEAN Init_Socket PARAMS(( INT Sock )); LOCAL VOID New_Server PARAMS(( INT Server, CONN_ID Idx )); LOCAL VOID Read_Resolver_Result PARAMS(( INT r_fd )); @@ -98,7 +99,8 @@ LOCAL fd_set My_Listeners; LOCAL fd_set My_Sockets; LOCAL fd_set My_Connects; -LOCAL CONNECTION My_Connections[MAX_CONNECTIONS]; +LOCAL CONNECTION *My_Connections; +LOCAL LONG Pool_Size; GLOBAL VOID @@ -108,15 +110,32 @@ Conn_Init( VOID ) CONN_ID i; + /* Speicher fuer Verbindungs-Pool anfordern */ + Pool_Size = CONNECTION_POOL; + if( Conf_MaxConnections > 0 ) + { + /* konfiguriertes Limit beachten */ + if( Pool_Size > Conf_MaxConnections ) Pool_Size = Conf_MaxConnections; + } + My_Connections = malloc( sizeof( CONNECTION ) * Pool_Size ); + if( ! My_Connections ) + { + /* Speicher konnte nicht alloziert werden! */ + Log( LOG_EMERG, "Can't allocate memory! [Conn_Init]" ); + exit( 1 ); + } + Log( LOG_DEBUG, "Allocted connection pool for %ld items.", Pool_Size ); + /* zu Beginn haben wir keine Verbindungen */ FD_ZERO( &My_Listeners ); FD_ZERO( &My_Sockets ); FD_ZERO( &My_Connects ); + /* Groesster File-Descriptor fuer select() */ Conn_MaxFD = 0; /* Connection-Struktur initialisieren */ - for( i = 0; i < MAX_CONNECTIONS; i++ ) Init_Conn_Struct( i ); + for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i ); } /* Conn_Init */ @@ -135,7 +154,7 @@ Conn_Exit( VOID ) { if( FD_ISSET( i, &My_Sockets )) { - for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) + for( idx = 0; idx < Pool_Size; idx++ ) { if( My_Connections[idx].sock == i ) break; } @@ -149,7 +168,7 @@ Conn_Exit( VOID ) close( i ); Log( LOG_DEBUG, "Connection %d closed during creation (socket %d).", idx, i ); } - else if( idx < MAX_CONNECTIONS ) + else if( idx < Pool_Size ) { if( NGIRCd_Restart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE ); else Conn_Close( idx, NULL, "Server going down", TRUE ); @@ -161,9 +180,50 @@ Conn_Exit( VOID ) } } } + + free( My_Connections ); + My_Connections = NULL; + Pool_Size = 0; } /* Conn_Exit */ +GLOBAL INT +Conn_InitListeners( VOID ) +{ + /* Ports, auf denen der Server Verbindungen entgegennehmen + * soll, initialisieren */ + + INT created, i; + + created = 0; + for( i = 0; i < Conf_ListenPorts_Count; i++ ) + { + if( Conn_NewListener( Conf_ListenPorts[i] )) created++; + else Log( LOG_ERR, "Can't listen on port %u!", Conf_ListenPorts[i] ); + } + return created; +} /* Conn_InitListeners */ + + +GLOBAL VOID +Conn_ExitListeners( VOID ) +{ + /* Alle "Listen-Sockets" schliessen */ + + INT i; + + Log( LOG_INFO, "Shutting down all listening sockets ..." ); + for( i = 0; i < Conn_MaxFD + 1; i++ ) + { + if( FD_ISSET( i, &My_Sockets ) && FD_ISSET( i, &My_Listeners )) + { + close( i ); + Log( LOG_DEBUG, "Listening socket %d closed.", i ); + } + } +} /* Conn_ExitListeners */ + + GLOBAL BOOLEAN Conn_NewListener( CONST UINT Port ) { @@ -236,28 +296,31 @@ Conn_Handler( VOID ) fd_set read_sockets, write_sockets; struct timeval tv; time_t start, t; - INT i; + LONG i, idx; + BOOLEAN timeout; start = time( NULL ); while(( ! NGIRCd_Quit ) && ( ! NGIRCd_Restart )) { + timeout = TRUE; + Check_Servers( ); Check_Connections( ); /* noch volle Lese-Buffer suchen */ - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].rdatalen > 0 )) { /* Kann aus dem Buffer noch ein Befehl extrahiert werden? */ - Handle_Buffer( i ); + if( Handle_Buffer( i )) timeout = FALSE; } } /* noch volle Schreib-Puffer suchen */ FD_ZERO( &write_sockets ); - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].wdatalen > 0 )) { @@ -266,7 +329,7 @@ Conn_Handler( VOID ) } } /* Sockets mit im Aufbau befindlichen ausgehenden Verbindungen suchen */ - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects ))) FD_SET( My_Connections[i].sock, &write_sockets ); } @@ -274,7 +337,7 @@ Conn_Handler( VOID ) /* von welchen Sockets koennte gelesen werden? */ t = time( NULL ); read_sockets = My_Sockets; - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].host[0] == '\0' )) { @@ -303,8 +366,9 @@ Conn_Handler( VOID ) } /* Timeout initialisieren */ - tv.tv_sec = 1; tv.tv_usec = 0; + if( timeout ) tv.tv_sec = TIME_RES; + else tv.tv_sec = 0; /* Auf Aktivitaet warten */ i = select( Conn_MaxFD + 1, &read_sockets, &write_sockets, NULL, &tv ); @@ -318,7 +382,7 @@ Conn_Handler( VOID ) /* Fehler (z.B. Interrupt) */ if( errno != EINTR ) { - Log( LOG_EMERG, "select(): %s!", strerror( errno )); + Log( LOG_EMERG, "Conn_Handler(): select(): %s!", strerror( errno )); Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE ); exit( 1 ); } @@ -328,7 +392,18 @@ Conn_Handler( VOID ) /* Koennen Daten geschrieben werden? */ for( i = 0; i < Conn_MaxFD + 1; i++ ) { - if( FD_ISSET( i, &write_sockets )) Handle_Write( Socket2Index( i )); + if( ! FD_ISSET( i, &write_sockets )) continue; + + /* Es kann geschrieben werden ... */ + idx = Socket2Index( i ); + if( idx == NONE ) continue; + + if( ! Handle_Write( idx )) + { + /* Fehler beim Schreiben! Diesen Socket nun + * auch aus dem Read-Set entfernen: */ + FD_CLR( i, &read_sockets ); + } } /* Daten zum Lesen vorhanden? */ @@ -359,7 +434,7 @@ va_dcl BOOLEAN ok; va_list ap; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( Format != NULL ); #ifdef PROTOTYPES @@ -392,7 +467,7 @@ Conn_Write( CONN_ID Idx, CHAR *Data, INT Len ) /* Daten in Socket schreiben. Bei "fatalen" Fehlern wird * der Client disconnectiert und FALSE geliefert. */ - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( Data != NULL ); assert( Len > 0 ); @@ -445,7 +520,7 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) CLIENT *c; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); c = Client_GetFromConn( Idx ); @@ -455,7 +530,7 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) /* Statistik an Client melden, wenn User */ if(( c != NULL ) && ( Client_Type( c ) == CLIENT_USER )) { - Conn_WriteStr( Idx, "NOTICE %s :%sConnection statistics: %.1f kb received, %.1f kb sent.", Client_ThisServer( ), NOTICE_TXTPREFIX, (double)My_Connections[Idx].bytes_in / 1024, (double)My_Connections[Idx].bytes_out / 1024 ); + 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 ); } /* ERROR an Client schicken (von RFC so vorgesehen!) */ @@ -466,12 +541,17 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) if( close( My_Connections[Idx].sock ) != 0 ) { - Log( LOG_ERR, "Error closing connection %d with %s:%d - %s!", Idx, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port), strerror( errno )); + 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 )); } else { - Log( LOG_INFO, "Connection %d with %s:%d closed.", Idx, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port )); + Log( LOG_INFO, "Connection %d (socket %d) with %s:%d closed (%.1fK in/%.1fK out).", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port ), (DOUBLE)My_Connections[Idx].bytes_in / 1024, (DOUBLE)My_Connections[Idx].bytes_out / 1024 ); } + + /* Socket als "ungueltig" markieren */ + FD_CLR( My_Connections[Idx].sock, &My_Sockets ); + FD_CLR( My_Connections[Idx].sock, &My_Connects ); + My_Connections[Idx].sock = NONE; if( c ) Client_Destroy( c, LogMsg, FwdMsg, TRUE ); @@ -484,18 +564,18 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) free( My_Connections[Idx].res_stat ); } - /* Bei Server-Verbindungen lasttry-Zeitpunkt so setzen, dass - * der naechste Verbindungsversuch in RECONNECT_DELAY Sekunden - * gestartet wird. */ - if(( My_Connections[Idx].our_server >= 0 ) && ( Conf_Server[My_Connections[Idx].our_server].lasttry < time( NULL ))) + /* Startzeit des naechsten Connect-Versuchs modifizieren? */ + if(( My_Connections[Idx].our_server > NONE ) && ( Conf_Server[My_Connections[Idx].our_server].lasttry < time( NULL ) - Conf_ConnectRetry )) { - /* Okay, die Verbindung stand schon "genuegend lange" */ + /* Okay, die Verbindung stand schon "genuegend lange": + * lasttry-Zeitpunkt so setzen, dass der naechste + * Verbindungsversuch in RECONNECT_DELAY Sekunden + * gestartet wird. */ Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY; } - FD_CLR( My_Connections[Idx].sock, &My_Sockets ); - FD_CLR( My_Connections[Idx].sock, &My_Connects ); - My_Connections[Idx].sock = NONE; + /* Connection-Struktur loeschen (=freigeben) */ + Init_Conn_Struct( Idx ); } /* Conn_Close */ @@ -504,7 +584,7 @@ Conn_UpdateIdle( CONN_ID Idx ) { /* Idle-Timer zuruecksetzen */ - assert( Idx >= 0 ); + assert( Idx > NONE ); My_Connections[Idx].lastprivmsg = time( NULL ); } @@ -514,7 +594,7 @@ Conn_GetIdle( CONN_ID Idx ) { /* Idle-Time einer Verbindung liefern (in Sekunden) */ - assert( Idx >= 0 ); + assert( Idx > NONE ); return time( NULL ) - My_Connections[Idx].lastprivmsg; } /* Conn_GetIdle */ @@ -524,7 +604,7 @@ Conn_LastPing( CONN_ID Idx ) { /* Zeitpunkt des letzten PING liefern */ - assert( Idx >= 0 ); + assert( Idx > NONE ); return My_Connections[Idx].lastping; } /* Conn_LastPing */ @@ -539,7 +619,7 @@ Conn_SetPenalty( CONN_ID Idx, time_t Seconds ) time_t t; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( Seconds >= 0 ); t = time( NULL ) + Seconds; @@ -547,6 +627,92 @@ Conn_SetPenalty( CONN_ID Idx, time_t Seconds ) } /* Conn_SetPenalty */ +GLOBAL VOID +Conn_ResetPenalty( CONN_ID Idx ) +{ + assert( Idx > NONE ); + My_Connections[Idx].delaytime = 0; +} /* Conn_ResetPenalty */ + + +GLOBAL VOID +Conn_ClearFlags( VOID ) +{ + /* Alle Connection auf "nicht-markiert" setzen */ + + LONG i; + + for( i = 0; i < Pool_Size; i++ ) My_Connections[i].flag = 0; +} /* Conn_ClearFlags */ + + +GLOBAL INT +Conn_Flag( CONN_ID Idx ) +{ + /* Ist eine Connection markiert (TRUE) oder nicht? */ + + assert( Idx > NONE ); + return My_Connections[Idx].flag; +} /* Conn_Flag */ + + +GLOBAL VOID +Conn_SetFlag( CONN_ID Idx, INT Flag ) +{ + /* Connection markieren */ + + assert( Idx > NONE ); + My_Connections[Idx].flag = Flag; +} /* Conn_SetFlag */ + + +GLOBAL CONN_ID +Conn_First( VOID ) +{ + /* Connection-Struktur der ersten Verbindung liefern; + * Ist keine Verbindung vorhanden, wird NONE geliefert. */ + + LONG i; + + for( i = 0; i < Pool_Size; i++ ) + { + if( My_Connections[i].sock != NONE ) return i; + } + return NONE; +} /* Conn_First */ + + +GLOBAL CONN_ID +Conn_Next( CONN_ID Idx ) +{ + /* Naechste Verbindungs-Struktur liefern; existiert keine + * weitere, so wird NONE geliefert. */ + + LONG i = NONE; + + assert( Idx > NONE ); + + for( i = Idx + 1; i < Pool_Size; i++ ) + { + if( My_Connections[i].sock != NONE ) return i; + } + return NONE; +} /* Conn_Next */ + + +GLOBAL VOID +Conn_SetServer( CONN_ID Idx, INT ConfServer ) +{ + /* Connection als Server markieren: Index des konfigurierten + * Servers speichern. Verbindung muss bereits bestehen! */ + + assert( Idx > NONE ); + assert( My_Connections[Idx].sock > NONE ); + + My_Connections[Idx].our_server = ConfServer; +} /* Conn_SetServer */ + + LOCAL BOOLEAN Try_Write( CONN_ID Idx ) { @@ -554,19 +720,23 @@ Try_Write( CONN_ID Idx ) * Socket zu schreiben. */ fd_set write_socket; + struct timeval tv; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); assert( My_Connections[Idx].wdatalen > 0 ); + /* Timeout initialisieren: 0 Sekunden, also nicht blockieren */ + tv.tv_sec = 0; tv.tv_usec = 0; + FD_ZERO( &write_socket ); FD_SET( My_Connections[Idx].sock, &write_socket ); - if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, 0 ) == -1 ) + if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, &tv ) == -1 ) { /* Fehler! */ if( errno != EINTR ) { - Log( LOG_ALERT, "select() failed: %s!", strerror( errno )); + Log( LOG_ALERT, "Try_Write(): select() failed: %s (con=%d, sock=%d)!", strerror( errno ), Idx, My_Connections[Idx].sock ); Conn_Close( Idx, "Server error!", NULL, FALSE ); return FALSE; } @@ -587,7 +757,7 @@ Handle_Read( INT Sock ) CONN_ID idx; - assert( Sock >= 0 ); + assert( Sock > NONE ); if( FD_ISSET( Sock, &My_Listeners )) { @@ -607,7 +777,7 @@ Handle_Read( INT Sock ) /* Ein Client Socket: entweder ein User oder Server */ idx = Socket2Index( Sock ); - Read_Request( idx ); + if( idx > NONE ) Read_Request( idx ); } } /* Handle_Read */ @@ -619,7 +789,7 @@ Handle_Write( CONN_ID Idx ) INT len, res, err; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); if( FD_ISSET( My_Connections[Idx].sock, &My_Connects )) @@ -654,10 +824,8 @@ Handle_Write( CONN_ID Idx ) Log( LOG_DEBUG, "Connection %d with \"%s:%d\" established, now sendig PASS and SERVER ...", Idx, My_Connections[Idx].host, Conf_Server[My_Connections[Idx].our_server].port ); /* PASS und SERVER verschicken */ - Conn_WriteStr( Idx, "PASS %s %s", Conf_Server[My_Connections[Idx].our_server].pwd, NGIRCd_ProtoID ); - Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo ); - - return TRUE; + Conn_WriteStr( Idx, "PASS %s %s", Conf_Server[My_Connections[Idx].our_server].pwd_out, NGIRCd_ProtoID ); + return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo ); } assert( My_Connections[Idx].wdatalen > 0 ); @@ -666,9 +834,12 @@ Handle_Write( CONN_ID Idx ) len = send( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen, 0 ); if( len < 0 ) { + /* Operation haette Socket "nur" blockiert ... */ + if( errno == EAGAIN ) return TRUE; + /* Oops, ein Fehler! */ - Log( LOG_ERR, "Write error (buffer) on connection %d: %s!", Idx, strerror( errno )); - Conn_Close( Idx, "Write error (buffer)!", NULL, FALSE ); + Log( LOG_ERR, "Write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror( errno )); + Conn_Close( Idx, "Write error!", NULL, FALSE ); return FALSE; } @@ -694,9 +865,12 @@ New_Connection( INT Sock ) RES_STAT *s; CONN_ID idx; CLIENT *c; + POINTER *ptr; + LONG new_size; - assert( Sock >= 0 ); + assert( Sock > NONE ); + /* Connection auf Listen-Socket annehmen */ new_sock_len = sizeof( new_addr ); new_sock = accept( Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len ); if( new_sock < 0 ) @@ -705,13 +879,56 @@ New_Connection( INT Sock ) return; } - /* Freie Connection-Struktur suschen */ - for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == NONE ) break; - if( idx >= MAX_CONNECTIONS ) + /* Socket initialisieren */ + Init_Socket( new_sock ); + + /* Freie Connection-Struktur suchen */ + for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break; + if( idx >= Pool_Size ) { - Log( LOG_ALERT, "Can't accept connection: limit reached (%d)!", MAX_CONNECTIONS ); - close( new_sock ); - return; + new_size = Pool_Size + CONNECTION_POOL; + + /* Im bisherigen Pool wurde keine freie Connection-Struktur mehr gefunden. + * Wenn erlaubt und moeglich muss nun der Pool vergroessert werden: */ + + if( Conf_MaxConnections > 0 ) + { + /* Es ist ein Limit konfiguriert */ + if( Pool_Size >= Conf_MaxConnections ) + { + /* Mehr Verbindungen duerfen wir leider nicht mehr annehmen ... */ + Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Pool_Size ); + close( new_sock ); + return; + } + if( new_size > Conf_MaxConnections ) new_size = Conf_MaxConnections; + } + + /* zunaechst realloc() versuchen; wenn das scheitert, malloc() versuchen + * und Daten ggf. "haendisch" umkopieren. (Haesslich! Eine wirklich + * dynamische Verwaltung waere wohl _deutlich_ besser ...) */ + ptr = realloc( My_Connections, sizeof( CONNECTION ) * new_size ); + if( ! ptr ) + { + /* realloc() ist fehlgeschlagen. Nun malloc() probieren: */ + ptr = malloc( sizeof( CONNECTION ) * new_size ); + if( ! ptr ) + { + /* Offenbar steht kein weiterer Sepeicher zur Verfuegung :-( */ + Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" ); + close( new_sock ); + return; + } + + /* Struktur umkopieren ... */ + memcpy( ptr, My_Connections, sizeof( CONNECTION ) * Pool_Size ); + + Log( LOG_DEBUG, "Allocated new connection pool for %ld items. [malloc()/memcpy()]", new_size ); + } + else Log( LOG_DEBUG, "Allocated new connection pool for %ld items. [realloc()]", new_size ); + + My_Connections = ptr; + Pool_Size = new_size; } /* Client-Struktur initialisieren */ @@ -735,6 +952,8 @@ New_Connection( INT Sock ) Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", idx, inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock ); /* Hostnamen ermitteln */ + strcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr )); + Client_SetHostname( c, My_Connections[idx].host ); s = Resolve_Addr( &new_addr ); if( s ) { @@ -742,15 +961,9 @@ New_Connection( INT Sock ) Conn_WriteStr( idx, "NOTICE AUTH :%sLooking up your hostname ...", NOTICE_TXTPREFIX ); My_Connections[idx].res_stat = s; } - else - { - /* kann Namen nicht aufloesen, daher wird die IP-Adresse verwendet */ - strcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr )); - Client_SetHostname( c, My_Connections[idx].host ); - } /* Penalty-Zeit setzen */ - Conn_SetPenalty( idx, 1 ); + Conn_SetPenalty( idx, 4 ); } /* New_Connection */ @@ -761,12 +974,18 @@ Socket2Index( INT Sock ) CONN_ID idx; - assert( Sock >= 0 ); + assert( Sock > NONE ); - for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == Sock ) break; + for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == Sock ) break; - assert( idx < MAX_CONNECTIONS ); - return idx; + if( idx >= Pool_Size ) + { + /* die Connection wurde vermutlich (wegen eines + * Fehlers) bereits wieder abgebaut ... */ + Log( LOG_DEBUG, "Socket2Index: can't get connection for socket %d!", Sock ); + return NONE; + } + else return idx; } /* Socket2Index */ @@ -778,7 +997,7 @@ Read_Request( CONN_ID Idx ) INT len; - assert( Idx >= 0 ); + assert( Idx > NONE ); assert( My_Connections[Idx].sock > NONE ); if( READBUFFER_LEN - My_Connections[Idx].rdatalen - 2 < 0 ) @@ -801,8 +1020,11 @@ Read_Request( CONN_ID Idx ) if( len < 0 ) { + /* Operation haette Socket "nur" blockiert ... */ + if( errno == EAGAIN ) return; + /* Fehler beim Lesen */ - Log( LOG_ERR, "Read error on connection %d: %s!", Idx, strerror( errno )); + 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; } @@ -822,13 +1044,19 @@ Read_Request( CONN_ID Idx ) } /* Read_Request */ -LOCAL VOID +LOCAL BOOLEAN Handle_Buffer( CONN_ID Idx ) { - /* Daten im Lese-Puffer einer Verbindung verarbeiten. */ + /* Daten im Lese-Puffer einer Verbindung verarbeiten. + * Wurde ein Request verarbeitet, so wird TRUE geliefert, + * ansonsten FALSE (auch bei Fehlern). */ - CHAR *ptr, *ptr1, *ptr2; +#ifndef STRICT_RFC + CHAR *ptr1, *ptr2; +#endif + CHAR *ptr; INT len, delta; + BOOLEAN action; /* Eine komplette Anfrage muss mit CR+LF enden, vgl. * RFC 2812. Haben wir eine? */ @@ -849,6 +1077,7 @@ Handle_Buffer( CONN_ID Idx ) } #endif + action = FALSE; if( ptr ) { /* Ende der Anfrage wurde gefunden */ @@ -857,23 +1086,26 @@ Handle_Buffer( CONN_ID Idx ) if( len > ( COMMAND_LEN - 1 )) { /* Eine Anfrage darf(!) nicht laenger als 512 Zeichen - * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas - * empfangen wird, wird der Client disconnectiert. */ + * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas + * empfangen wird, wird der Client disconnectiert. */ Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!", Idx, My_Connections[Idx].rdatalen, COMMAND_LEN - 1 ); Conn_Close( Idx, NULL, "Request too long", TRUE ); - return; + return FALSE; } if( len > delta ) { /* Es wurde ein Request gelesen */ - if( ! Parse_Request( Idx, My_Connections[Idx].rbuf )) return; + 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 ); } + + return action; } /* Handle_Buffer */ @@ -885,9 +1117,9 @@ Check_Connections( VOID ) * auch das nicht "hilft", Client disconnectieren. */ CLIENT *c; - INT i; + LONG i; - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if( My_Connections[i].sock == NONE ) continue; @@ -933,8 +1165,9 @@ Check_Servers( VOID ) /* Pruefen, ob Server-Verbindungen aufgebaut werden * muessen bzw. koennen */ - INT idx, i, n; RES_STAT *s; + LONG idx, n; + INT i; /* Wenn "Passive-Mode" aktiv: nicht verbinden */ if( NGIRCd_Passive ) return; @@ -945,7 +1178,7 @@ Check_Servers( VOID ) if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 )) continue; /* Haben wir schon eine Verbindung? */ - for( n = 0; n < MAX_CONNECTIONS; n++ ) + for( n = 0; n < Pool_Size; n++ ) { if( My_Connections[n].sock == NONE ) continue; @@ -965,7 +1198,7 @@ Check_Servers( VOID ) if( Conf_Server[My_Connections[n].our_server].group == Conf_Server[i].group ) break; } } - if( n < MAX_CONNECTIONS ) continue; + if( n < Pool_Size ) continue; /* Wann war der letzte Connect-Versuch? */ if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue; @@ -974,10 +1207,10 @@ Check_Servers( VOID ) Conf_Server[i].lasttry = time( NULL ); /* Freie Connection-Struktur suschen */ - for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == NONE ) break; - if( idx >= MAX_CONNECTIONS ) + for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break; + if( idx >= Pool_Size ) { - Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", MAX_CONNECTIONS ); + Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", Pool_Size ); return; } Log( LOG_DEBUG, "Preparing connection %d for \"%s\" ...", idx, Conf_Server[i].host ); @@ -987,19 +1220,16 @@ Check_Servers( VOID ) My_Connections[idx].sock = SERVER_WAIT; My_Connections[idx].our_server = i; - /* Hostnamen in IP aufloesen */ + /* Hostnamen in IP aufloesen (Default bzw. im Fehlerfall: versuchen, den + * konfigurierten Text direkt als IP-Adresse zu verwenden ... */ + strcpy( Conf_Server[My_Connections[idx].our_server].ip, Conf_Server[i].host ); + strcpy( My_Connections[idx].host, Conf_Server[i].host ); s = Resolve_Name( Conf_Server[i].host ); if( s ) { /* Sub-Prozess wurde asyncron gestartet */ My_Connections[idx].res_stat = s; } - else - { - /* kann Namen nicht aufloesen: nun versuchen wir einfach, - * den "Text" direkt als IP-Adresse zu verwenden ... */ - strcpy( Conf_Server[My_Connections[idx].our_server].ip, Conf_Server[i].host ); - } } } /* Check_Servers */ @@ -1011,11 +1241,11 @@ New_Server( INT Server, CONN_ID Idx ) struct sockaddr_in new_addr; struct in_addr inaddr; - INT new_sock; + INT res, new_sock; CLIENT *c; - assert( Server >= 0 ); - assert( Idx >= 0 ); + assert( Server > NONE ); + assert( Idx > NONE ); /* Wurde eine gueltige IP-Adresse gefunden? */ if( ! Conf_Server[Server].ip[0] ) @@ -1057,13 +1287,12 @@ New_Server( INT Server, CONN_ID Idx ) if( ! Init_Socket( new_sock )) return; - connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr )); - if( errno != EINPROGRESS ) + res = connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr )); + if(( res != 0 ) && ( errno != EINPROGRESS )) { - + Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno )); close( new_sock ); Init_Conn_Struct( Idx ); - Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno )); return; } @@ -1088,11 +1317,13 @@ New_Server( INT Server, CONN_ID Idx ) FD_SET( new_sock, &My_Sockets ); FD_SET( new_sock, &My_Connects ); if( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock; + + Log( LOG_DEBUG, "Registered new connection %d on socket %d.", Idx, My_Connections[Idx].sock ); } /* New_Server */ LOCAL VOID -Init_Conn_Struct( INT Idx ) +Init_Conn_Struct( LONG Idx ) { /* Connection-Struktur initialisieren */ @@ -1110,6 +1341,7 @@ Init_Conn_Struct( INT Idx ) My_Connections[Idx].delaytime = 0; My_Connections[Idx].bytes_in = 0; My_Connections[Idx].bytes_out = 0; + My_Connections[Idx].flag = 0; } /* Init_Conn_Struct */ @@ -1162,19 +1394,21 @@ Read_Resolver_Result( INT r_fd ) result[len] = '\0'; /* zugehoerige Connection suchen */ - for( i = 0; i < MAX_CONNECTIONS; i++ ) + for( i = 0; i < Pool_Size; i++ ) { if(( My_Connections[i].sock != NONE ) && ( My_Connections[i].res_stat ) && ( My_Connections[i].res_stat->pipe[0] == r_fd )) break; } - if( i >= MAX_CONNECTIONS ) + if( i >= Pool_Size ) { /* Opsa! Keine passende Connection gefunden!? Vermutlich - * wurde sie schon wieder geschlossen. */ + * wurde sie schon wieder geschlossen. */ close( r_fd ); Log( LOG_DEBUG, "Resolver: Got result for unknown connection!?" ); return; } + Log( LOG_DEBUG, "Resolver: %s is \"%s\".", My_Connections[i].host, result ); + /* Aufraeumen */ close( My_Connections[i].res_stat->pipe[0] ); close( My_Connections[i].res_stat->pipe[1] ); @@ -1194,9 +1428,12 @@ Read_Resolver_Result( INT r_fd ) else { /* Ausgehende Verbindung (=Server): IP setzen */ - assert( My_Connections[i].our_server >= 0 ); + assert( My_Connections[i].our_server > NONE ); strcpy( Conf_Server[My_Connections[i].our_server].ip, result ); } + + /* Penalty-Zeit zurueck setzen */ + Conn_ResetPenalty( i ); } /* Read_Resolver_Result */