X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=91ee25981fb0f7283f8573c1c878f4f4a4c0ceb7;hp=d4ecc1ade8fb87a53db4a4ee60f71d7f7aaa8d7a;hb=b840be9875a5fb218d4363e5900c68bf4a901808;hpb=7b6cfc17c428b9c9b58fcb9204337d5c4329f98b;ds=sidebyside diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index d4ecc1ad..91ee2598 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.68 2002/08/26 00:03:15 alex Exp $ + * $Id: conn.c,v 1.83 2002/10/15 09:24:54 alex Exp $ * * connect.h: Verwaltung aller Netz-Verbindungen ("connections") */ @@ -75,6 +75,7 @@ typedef struct _Connection 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 */ } CONNECTION; @@ -220,8 +221,10 @@ Conn_NewListener( CONST UINT Port ) GLOBAL VOID Conn_Handler( VOID ) { - /* Aktive Verbindungen ueberwachen. Folgende Aktionen - * werden durchgefuehrt: + /* "Hauptschleife": Aktive Verbindungen ueberwachen. Folgende Aktionen + * werden dabei durchgefuehrt, bis der Server terminieren oder neu + * starten soll: + * * - neue Verbindungen annehmen, * - Server-Verbindungen aufbauen, * - geschlossene Verbindungen loeschen, @@ -233,7 +236,7 @@ Conn_Handler( VOID ) fd_set read_sockets, write_sockets; struct timeval tv; time_t start, t; - INT i; + INT i, idx; start = time( NULL ); while(( ! NGIRCd_Quit ) && ( ! NGIRCd_Restart )) @@ -242,10 +245,6 @@ Conn_Handler( VOID ) Check_Connections( ); - /* Timeout initialisieren */ - tv.tv_sec = 1; - tv.tv_usec = 0; - /* noch volle Lese-Buffer suchen */ for( i = 0; i < MAX_CONNECTIONS; i++ ) { @@ -291,6 +290,7 @@ Conn_Handler( VOID ) { /* Fuer die Verbindung ist eine "Penalty-Zeit" gesetzt */ FD_CLR( My_Connections[i].sock, &read_sockets ); + FD_CLR( My_Connections[i].sock, &write_sockets ); } } for( i = 0; i < Conn_MaxFD + 1; i++ ) @@ -302,12 +302,23 @@ Conn_Handler( VOID ) } } + /* Timeout initialisieren */ + tv.tv_sec = 1; + tv.tv_usec = 0; + /* Auf Aktivitaet warten */ - if( select( Conn_MaxFD + 1, &read_sockets, &write_sockets, NULL, &tv ) == -1 ) + i = select( Conn_MaxFD + 1, &read_sockets, &write_sockets, NULL, &tv ); + if( i == 0 ) + { + /* keine Veraenderung an den Sockets */ + continue; + } + if( i == -1 ) { + /* 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 ); } @@ -317,7 +328,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? */ @@ -349,7 +371,6 @@ va_dcl va_list ap; assert( Idx >= 0 ); - assert( My_Connections[Idx].sock > NONE ); assert( Format != NULL ); #ifdef PROTOTYPES @@ -383,10 +404,20 @@ Conn_Write( CONN_ID Idx, CHAR *Data, INT Len ) * der Client disconnectiert und FALSE geliefert. */ assert( Idx >= 0 ); - assert( My_Connections[Idx].sock > NONE ); assert( Data != NULL ); assert( Len > 0 ); + /* Ist der entsprechende Socket ueberhaupt noch offen? + * In einem "Handler-Durchlauf" kann es passieren, dass + * dem nicht mehr so ist, wenn einer von mehreren + * Conn_Write()'s fehlgeschlagen ist. In diesem Fall + * wird hier einfach ein Fehler geliefert. */ + if( My_Connections[Idx].sock <= NONE ) + { + Log( LOG_DEBUG, "Skipped write on closed socket (connection %d).", Idx ); + return FALSE; + } + /* pruefen, ob Daten im Schreibpuffer sind. Wenn ja, zunaechst * pruefen, ob diese gesendet werden koennen */ if( My_Connections[Idx].wdatalen > 0 ) @@ -428,8 +459,17 @@ Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient ) assert( Idx >= 0 ); assert( My_Connections[Idx].sock > NONE ); + c = Client_GetFromConn( Idx ); + if( 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 ); + } + + /* ERROR an Client schicken (von RFC so vorgesehen!) */ if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg ); else Conn_WriteStr( Idx, "ERROR :Closing connection." ); if( My_Connections[Idx].sock == NONE ) return; @@ -437,14 +477,18 @@ 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, inet_ntoa( My_Connections[Idx].addr.sin_addr ), 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.", Idx, My_Connections[Idx].sock, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port )); } + + /* 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; - c = Client_GetFromConn( Idx ); if( c ) Client_Destroy( c, LogMsg, FwdMsg, TRUE ); if( My_Connections[Idx].res_stat ) @@ -456,18 +500,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 >= 0 ) && ( 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 */ @@ -519,6 +563,14 @@ Conn_SetPenalty( CONN_ID Idx, time_t Seconds ) } /* Conn_SetPenalty */ +GLOBAL VOID +Conn_ResetPenalty( CONN_ID Idx ) +{ + assert( Idx >= 0 ); + My_Connections[Idx].delaytime = 0; +} /* Conn_ResetPenalty */ + + LOCAL BOOLEAN Try_Write( CONN_ID Idx ) { @@ -538,7 +590,7 @@ Try_Write( CONN_ID Idx ) /* 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; } @@ -579,7 +631,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 */ @@ -591,7 +643,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 )) @@ -626,10 +678,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, PASSSERVERADD ); - 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, NGIRCd_ProtoID ); + return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo ); } assert( My_Connections[Idx].wdatalen > 0 ); @@ -639,11 +689,14 @@ Handle_Write( CONN_ID Idx ) if( len < 0 ) { /* 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; } + /* Connection-Statistik aktualisieren */ + My_Connections[Idx].bytes_out += len; + /* Puffer anpassen */ My_Connections[Idx].wdatalen -= len; memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen ); @@ -674,7 +727,7 @@ New_Connection( INT Sock ) return; } - /* Freie Connection-Struktur suschen */ + /* Freie Connection-Struktur suchen */ for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == NONE ) break; if( idx >= MAX_CONNECTIONS ) { @@ -708,6 +761,7 @@ 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; } else @@ -718,7 +772,7 @@ New_Connection( INT Sock ) } /* Penalty-Zeit setzen */ - Conn_SetPenalty( idx, 1 ); + Conn_SetPenalty( idx, 4 ); } /* New_Connection */ @@ -733,8 +787,14 @@ Socket2Index( INT Sock ) for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == Sock ) break; - assert( idx < MAX_CONNECTIONS ); - return idx; + if( idx >= MAX_CONNECTIONS ) + { + /* 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 */ @@ -770,11 +830,14 @@ Read_Request( CONN_ID Idx ) if( len < 0 ) { /* 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; } + /* Connection-Statistik aktualisieren */ + My_Connections[Idx].bytes_in += len; + /* Lesebuffer updaten */ My_Connections[Idx].rdatalen += len; assert( My_Connections[Idx].rdatalen < READBUFFER_LEN ); @@ -1053,6 +1116,8 @@ 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 */ @@ -1073,6 +1138,8 @@ Init_Conn_Struct( INT Idx ) 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; } /* Init_Conn_Struct */ @@ -1114,7 +1181,7 @@ Read_Resolver_Result( INT r_fd ) FD_CLR( r_fd, &Resolver_FDs ); /* Anfrage vom Parent lesen */ - len = read( r_fd, result, HOST_LEN); + len = read( r_fd, result, HOST_LEN - 1 ); if( len < 0 ) { /* Fehler beim Lesen aus der Pipe */ @@ -1132,7 +1199,7 @@ Read_Resolver_Result( INT r_fd ) if( i >= MAX_CONNECTIONS ) { /* 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; @@ -1151,6 +1218,8 @@ 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 { @@ -1158,6 +1227,9 @@ Read_Resolver_Result( INT r_fd ) assert( My_Connections[i].our_server >= 0 ); strcpy( Conf_Server[My_Connections[i].our_server].ip, result ); } + + /* Penalty-Zeit zurueck setzen */ + Conn_ResetPenalty( i ); } /* Read_Resolver_Result */