]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
- ausgehende Verbindungen mit ID 0 konnten nicht aufgebaut werden ... :-/
[ngircd-alex.git] / src / ngircd / conn.c
index aeef7a3e00d5bb4c0314c138d3f1a5fbe1c3447f..91ee25981fb0f7283f8573c1c878f4f4a4c0ceb7 100644 (file)
@@ -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.73 2002/09/26 15:59:02 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;
 
 
@@ -235,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 ))
@@ -317,7 +318,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 );
                        }
@@ -327,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? */
@@ -400,7 +412,7 @@ Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
         * 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 )
+       if( My_Connections[Idx].sock <= NONE )
        {
                Log( LOG_DEBUG, "Skipped write on closed socket (connection %d).", Idx );
                return FALSE;
@@ -447,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;
@@ -456,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 )
@@ -475,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 */
 
 
@@ -538,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 )
 {
@@ -557,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;
                }
@@ -598,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 */
 
@@ -610,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 ))
@@ -646,9 +679,7 @@ Handle_Write( CONN_ID Idx )
 
                /* 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;
+               return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
        }
 
        assert( My_Connections[Idx].wdatalen > 0 );
@@ -658,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 );
@@ -693,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 )
        {
@@ -727,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
@@ -737,7 +772,7 @@ New_Connection( INT Sock )
        }
        
        /* Penalty-Zeit setzen */
-       Conn_SetPenalty( idx, 1 );
+       Conn_SetPenalty( idx, 4 );
 } /* New_Connection */
 
 
@@ -752,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 */
 
 
@@ -789,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 );
@@ -1072,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 */
 
 
@@ -1092,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 */
 
 
@@ -1133,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 */
@@ -1151,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;
@@ -1170,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
        {
@@ -1177,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 */