]> arthur.barton.de Git - ngircd.git/blobdiff - src/ngircd/conn.c
Fix compiler warning "comparision between signed and unsigned".
[ngircd.git] / src / ngircd / conn.c
index a3960877d70723479dd59e37eed51fa781225894..627c6402b0520e0e148b014825f8de0ffc720a03 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: conn.c,v 1.145 2005/03/20 11:00:31 fw Exp $";
+static char UNUSED id[] = "$Id: conn.c,v 1.155 2005/06/26 13:43:59 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
@@ -86,7 +86,6 @@ LOCAL bool Handle_Write PARAMS(( CONN_ID Idx ));
 LOCAL void New_Connection PARAMS(( int Sock ));
 LOCAL CONN_ID Socket2Index PARAMS(( int Sock ));
 LOCAL void Read_Request PARAMS(( CONN_ID Idx ));
-LOCAL bool Try_Write PARAMS(( CONN_ID Idx ));
 LOCAL bool Handle_Buffer PARAMS(( CONN_ID Idx ));
 LOCAL void Check_Connections PARAMS(( void ));
 LOCAL void Check_Servers PARAMS(( void ));
@@ -99,13 +98,29 @@ LOCAL int Count_Connections PARAMS(( struct sockaddr_in addr ));
 
 LOCAL fd_set My_Listeners;
 LOCAL fd_set My_Sockets;
-LOCAL fd_set My_Connects;
 
 #ifdef TCPWRAP
 int allow_severity = LOG_INFO;
 int deny_severity = LOG_ERR;
 #endif
 
+LOCAL void
+FreeRes_stat( CONNECTION *c )
+{
+       assert( c != NULL );
+       assert( c->res_stat != NULL );
+
+       if (!c->res_stat) return;
+
+       FD_CLR( c->res_stat->pipe[0], &Resolver_FDs );
+
+       close( c->res_stat->pipe[0] );
+       close( c->res_stat->pipe[1] );
+
+       free( c->res_stat );
+       c->res_stat = NULL;
+}
+
 
 GLOBAL void
 Conn_Init( void )
@@ -121,7 +136,7 @@ Conn_Init( void )
                /* konfiguriertes Limit beachten */
                if( Pool_Size > Conf_MaxConnections ) Pool_Size = Conf_MaxConnections;
        }
-       My_Connections = (CONNECTION *)malloc( sizeof( CONNECTION ) * Pool_Size );
+       My_Connections = (CONNECTION *) calloc( Pool_Size,  sizeof( CONNECTION ) );
        if( ! My_Connections )
        {
                /* Speicher konnte nicht alloziert werden! */
@@ -135,7 +150,6 @@ Conn_Init( void )
        /* 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;
@@ -179,13 +193,6 @@ Conn_Exit( void )
                                close( i );
 #ifdef DEBUG
                                Log( LOG_DEBUG, "Listening socket %d closed.", i );
-#endif
-                       }
-                       else if( FD_ISSET( i, &My_Connects ))
-                       {
-                               close( i );
-#ifdef DEBUG
-                               Log( LOG_DEBUG, "Connection %d closed during creation (socket %d).", idx, i );
 #endif
                        }
                        else if( idx < Pool_Size )
@@ -218,7 +225,7 @@ Conn_InitListeners( void )
        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] );
+               else Log( LOG_ERR, "Can't listen on port %u!", (unsigned int) Conf_ListenPorts[i] );
        }
        return created;
 } /* Conn_InitListeners */
@@ -417,22 +424,30 @@ Conn_Handler( void )
                /* Sockets mit im Aufbau befindlichen ausgehenden Verbindungen suchen */
                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 );
+                       if ( My_Connections[i].sock > NONE ) {
+                               if ( Conn_OPTION_ISSET( &My_Connections[i], CONN_ISCONNECTING )) {
+                                       FD_SET( My_Connections[i].sock, &write_sockets );
+                               }
+                       }
+
                }
 
                /* von welchen Sockets koennte gelesen werden? */
                read_sockets = My_Sockets;
                for( i = 0; i < Pool_Size; i++ )
                {
-                       if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].host[0] == '\0' ))
-                       {
-                               /* Hier muss noch auf den Resolver Sub-Prozess gewartet werden */
-                               FD_CLR( My_Connections[i].sock, &read_sockets );
-                       }
-                       if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects )))
-                       {
-                               /* Hier laeuft noch ein asyncrones connect() */
-                               FD_CLR( My_Connections[i].sock, &read_sockets );
+                       if ( My_Connections[i].sock > NONE ) {
+                               if ( My_Connections[i].res_stat ) {
+                                       /* wait for completion of Resolver Sub-Process */
+                                       FD_CLR( My_Connections[i].sock, &read_sockets );
+                                       continue;
+                               }
+
+                               if ( Conn_OPTION_ISSET( &My_Connections[i], CONN_ISCONNECTING )) {
+                                       /* wait for completion of connect() */
+                                       FD_CLR( My_Connections[i].sock, &read_sockets );
+                                       continue;
+                                }
                        }
                        if( My_Connections[i].delaytime > t )
                        {
@@ -578,7 +593,7 @@ Conn_Write( CONN_ID Idx, char *Data, int Len )
        {
                /* Der Puffer ist dummerweise voll. Jetzt versuchen, den Puffer
                 * zu schreiben, wenn das nicht klappt, haben wir ein Problem ... */
-               if( ! Try_Write( Idx )) return false;
+               if( ! Handle_Write( Idx )) return false;
 
                /* nun neu pruefen: */
                if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
@@ -590,8 +605,7 @@ Conn_Write( CONN_ID Idx, char *Data, int Len )
        }
 
 #ifdef ZLIB
-       if( My_Connections[Idx].options & CONN_ZIP )
-       {
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
                /* Daten komprimieren und in Puffer kopieren */
                if( ! Zip_Buffer( Idx, Data, Len )) return false;
        }
@@ -628,10 +642,9 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
        assert( Idx > NONE );
 
        /* Is this link already shutting down? */
-       if( My_Connections[Idx].options & CONN_ISCLOSING )
-       {
+       if( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ISCLOSING )) {
                /* Conn_Close() has been called recursively for this link;
-                * probabe reason: Try_Write() failed  -- see below. */
+                * probabe reason: Handle_Write() failed  -- see below. */
 #ifdef DEBUG
                Log( LOG_DEBUG, "Recursive request to close connection: %d", Idx );
 #endif
@@ -641,7 +654,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
        assert( My_Connections[Idx].sock > NONE );
 
        /* Mark link as "closing" */
-       My_Connections[Idx].options |= CONN_ISCLOSING;
+       Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING );
                
        if( LogMsg ) txt = LogMsg;
        else txt = FwdMsg;
@@ -669,20 +682,17 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
        }
 
        /* Try to write out the write buffer */
-       (void)Try_Write( Idx );
+       (void)Handle_Write( Idx );
 
        /* Shut down socket */
        if( close( My_Connections[Idx].sock ) != 0 )
        {
-               /* Oops, we can't close the socket!? This is fatal! */
-               Log( LOG_EMERG, "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 ));
-               Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
-               exit( 1 );
+               /* Oops, we can't close the socket!? This is ... ugly! */
+               Log( LOG_CRIT, "Error closing connection %d (socket %d) with %s:%d - %s! (ignored)", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
        }
 
        /* Mark socket as invalid: */
        FD_CLR( My_Connections[Idx].sock, &My_Sockets );
-       FD_CLR( My_Connections[Idx].sock, &My_Connects );
        My_Connections[Idx].sock = NONE;
 
        /* If there is still a client, unregister it now */
@@ -692,8 +702,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
        in_k = (double)My_Connections[Idx].bytes_in / 1024;
        out_k = (double)My_Connections[Idx].bytes_out / 1024;
 #ifdef ZLIB
-       if( My_Connections[Idx].options & CONN_ZIP )
-       {
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
                in_z_k = (double)My_Connections[Idx].zip.bytes_in / 1024;
                out_z_k = (double)My_Connections[Idx].zip.bytes_out / 1024;
                in_p = (int)(( in_k * 100 ) / in_z_k );
@@ -708,21 +717,14 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
 
        /* Is there a resolver sub-process running? */
        if( My_Connections[Idx].res_stat )
-       {
-               /* Free resolver structures */
-               FD_CLR( My_Connections[Idx].res_stat->pipe[0], &Resolver_FDs );
-               close( My_Connections[Idx].res_stat->pipe[0] );
-               close( My_Connections[Idx].res_stat->pipe[1] );
-               free( My_Connections[Idx].res_stat );
-       }
+               FreeRes_stat( &My_Connections[Idx] );
 
        /* Servers: Modify time of next connect attempt? */
        Conf_UnsetServer( Idx );
 
 #ifdef ZLIB
        /* Clean up zlib, if link was compressed */
-       if( Conn_Options( Idx ) & CONN_ZIP )
-       {
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
                inflateEnd( &My_Connections[Idx].zip.in );
                deflateEnd( &My_Connections[Idx].zip.out );
        }
@@ -768,49 +770,6 @@ Conn_SyncServerStruct( void )
 } /* SyncServerStruct */
 
 
-LOCAL bool
-Try_Write( CONN_ID Idx )
-{
-       /* 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 );
-
-       /* sind ueberhaupt Daten vorhanden? */
-#ifdef 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;
-
-       FD_ZERO( &write_socket );
-       FD_SET( My_Connections[Idx].sock, &write_socket );
-       if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, &tv ) == -1 )
-       {
-               /* Fehler! */
-               if( errno != EINTR )
-               {
-                       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;
-               }
-       }
-
-       if( FD_ISSET( My_Connections[Idx].sock, &write_socket )) return Handle_Write( Idx );
-       else return true;
-} /* Try_Write */
-
-
 LOCAL void
 Handle_Read( int Sock )
 {
@@ -858,12 +817,10 @@ Handle_Write( CONN_ID Idx )
        assert( Idx > NONE );
        assert( My_Connections[Idx].sock > NONE );
 
-       if( FD_ISSET( My_Connections[Idx].sock, &My_Connects ))
-       {
-               /* es soll nichts geschrieben werden, sondern ein
-                * connect() hat ein Ergebnis geliefert */
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ISCONNECTING )) {
+               /* connect() has finished, check result */
 
-               FD_CLR( My_Connections[Idx].sock, &My_Connects );
+               Conn_OPTION_DEL( &My_Connections[Idx], CONN_ISCONNECTING );
 
                /* Ergebnis des connect() ermitteln */
                sock_len = sizeof( err );
@@ -898,27 +855,28 @@ Handle_Write( CONN_ID Idx )
        }
 
 #ifdef ZLIB
-       /* Schreibpuffer leer, aber noch Daten im Kompressionsbuffer?
-        * Dann muss dieser nun geflushed werden! */
+       if(( My_Connections[Idx].wdatalen <= 0 ) && ( ! My_Connections[Idx].zip.wdatalen ))
+               return true;
+
+       /* write buffer empty, but not compression buf? -> flush compression buf. */
        if( My_Connections[Idx].wdatalen == 0 ) Zip_Flush( Idx );
+#else
+       if( My_Connections[Idx].wdatalen <= 0 )
+               return true;
 #endif
 
-       assert( My_Connections[Idx].wdatalen > 0 );
+       len = write( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen );
+       if( len < 0 ) {
+               if( errno == EAGAIN || errno == EINTR)
+                       return true;
 
-       /* Daten schreiben */
-       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 on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror( errno ));
+               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;
        }
 
-       /* Puffer anpassen */
+       /* Update buffer len and move any data not yet written to beginning of buf */
        My_Connections[Idx].wdatalen -= len;
        memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen );
 
@@ -1006,7 +964,7 @@ New_Connection( int Sock )
                }
                if( new_size < Pool_Size )
                {
-                       Log( LOG_ALERT, "Can't accespt connection: limit (%d) reached -- overflow!", Pool_Size );
+                       Log( LOG_ALERT, "Can't accept connection: limit (%d) reached -- overflow!", Pool_Size );
                        Simple_Message( new_sock, "ERROR :Connection limit reached" );
                        close( new_sock );
                        return;
@@ -1065,11 +1023,8 @@ New_Connection( int Sock )
 #else
        s = Resolve_Addr( &new_addr );
 #endif
-       if( s )
-       {
-               /* Sub-Prozess wurde asyncron gestartet */
-               My_Connections[idx].res_stat = s;
-       }
+       /* resolver process has been started */
+       if( s ) My_Connections[idx].res_stat = s;
 
        /* Penalty-Zeit setzen */
        Conn_SetPenalty( idx, 4 );
@@ -1135,8 +1090,7 @@ Read_Request( CONN_ID Idx )
        }
 
 #ifdef ZLIB
-       if( My_Connections[Idx].options & CONN_ZIP )
-       {
+       if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) {
                len = recv( My_Connections[Idx].sock, My_Connections[Idx].zip.rbuf + My_Connections[Idx].zip.rdatalen, ( ZREADBUFFER_LEN - My_Connections[Idx].zip.rdatalen ), 0 );
                if( len > 0 ) My_Connections[Idx].zip.rdatalen += len;
        }
@@ -1201,10 +1155,8 @@ Handle_Buffer( CONN_ID Idx )
                
 #ifdef ZLIB
                /* ggf. noch unkomprimiete Daten weiter entpacken */
-               if( My_Connections[Idx].options & CONN_ZIP )
-               {
+               if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP ))
                        if( ! Unzip_Buffer( Idx )) return false;
-               }
 #endif
 
                if( My_Connections[Idx].rdatalen < 1 ) break;
@@ -1408,11 +1360,9 @@ Check_Servers( void )
                strlcpy( Conf_Server[i].ip, Conf_Server[i].host, sizeof( Conf_Server[i].ip ));
                strlcpy( My_Connections[idx].host, Conf_Server[i].host, sizeof( My_Connections[idx].host ));
                s = Resolve_Name( Conf_Server[i].host );
-               if( s )
-               {
-                       /* Sub-Prozess wurde asyncron gestartet */
-                       My_Connections[idx].res_stat = s;
-               }
+
+               /* resolver process running? */
+               if( s ) My_Connections[idx].res_stat = s;
        }
 } /* Check_Servers */
 
@@ -1506,7 +1456,8 @@ New_Server( int Server, CONN_ID Idx )
 
        /* Register new socket */
        FD_SET( new_sock, &My_Sockets );
-       FD_SET( new_sock, &My_Connects );
+       Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCONNECTING );
+
        if( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock;
 
 #ifdef DEBUG
@@ -1523,7 +1474,6 @@ Init_Conn_Struct( CONN_ID Idx )
 
        memset( &My_Connections[Idx], 0, sizeof ( CONNECTION ));
        My_Connections[Idx].sock = NONE;
-       My_Connections[Idx].starttime = now;
        My_Connections[Idx].lastdata = now;
        My_Connections[Idx].lastprivmsg = now;
 } /* Init_Conn_Struct */
@@ -1611,8 +1561,8 @@ Read_Resolver_Result( int r_fd )
        if( len < 0 )
        {
                /* Error! */
-               close( r_fd );
                Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror( errno ));
+               FreeRes_stat( &My_Connections[i] );
                return;
        }
        s->bufpos += len;
@@ -1633,38 +1583,34 @@ try_resolve:
 
        /* Okay, we got a complete result: this is a host name for outgoing
         * connections and a host name or IDENT user name (if enabled) for
-        * incoming conneciions.*/
+        * incoming connections.*/
        if( My_Connections[i].sock > NONE )
        {
-               /* Incoming connection */
-
-               /* Search client ... */
+               /* Incoming connection. Search client ... */
                c = Client_GetFromConn( i );
                assert( c != NULL );
 
                /* Only update client information of unregistered clients */
                if( Client_Type( c ) == CLIENT_UNKNOWN )
                {
-                       if( s->stage == 0 )
-                       {
-                               /* host name */
+                       switch(s->stage) {
+                               case 0: /* host name */
                                strlcpy( My_Connections[i].host, s->buffer, sizeof( My_Connections[i].host ));
                                Client_SetHostname( c, s->buffer );
-
 #ifdef IDENTAUTH
                                /* clean up buffer for IDENT result */
                                len = strlen( s->buffer ) + 1;
+                               assert((size_t)len <= sizeof( s->buffer ));
                                memmove( s->buffer, s->buffer + len, sizeof( s->buffer ) - len );
+                               assert(len <= s->bufpos );
                                s->bufpos -= len;
 
                                /* Don't close pipe and clean up, but
                                 * instead wait for IDENT result */
                                s->stage = 1;
                                goto try_resolve;
-                       }
-                       else if( s->stage == 1 )
-                       {
-                               /* IDENT user name */
+
+                               case 1: /* IDENT user name */
                                if( s->buffer[0] )
                                {
                                        Log( LOG_INFO, "IDENT lookup for connection %ld: \"%s\".", i, s->buffer );
@@ -1672,8 +1618,10 @@ try_resolve:
                                }
                                else Log( LOG_INFO, "IDENT lookup for connection %ld: no result.", i );
 #endif
+                               break;
+                               default:
+                               Log( LOG_ERR, "Resolver: got result for unknown stage %d!?", s->stage );
                        }
-                       else Log( LOG_ERR, "Resolver: got result for unknown stage %d!?", s->stage );
                }
 #ifdef DEBUG
                else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );
@@ -1692,11 +1640,7 @@ try_resolve:
        }
 
        /* Clean up ... */
-       FD_CLR( r_fd, &Resolver_FDs );
-       close( My_Connections[i].res_stat->pipe[0] );
-       close( My_Connections[i].res_stat->pipe[1] );
-       free( My_Connections[i].res_stat );
-       My_Connections[i].res_stat = NULL;
+       FreeRes_stat( &My_Connections[i] );
 
        /* Reset penalty time */
        Conn_ResetPenalty( i );
@@ -1706,15 +1650,16 @@ try_resolve:
 LOCAL void
 Simple_Message( int Sock, char *Msg )
 {
+       char buf[COMMAND_LEN];
        /* Write "simple" message to socket, without using compression
         * or even the connection write buffers. Used e.g. for error
         * messages by New_Connection(). */
-
        assert( Sock > NONE );
        assert( Msg != NULL );
 
-       (void)send( Sock, Msg, strlen( Msg ), 0 );
-       (void)send( Sock, "\r\n", 2, 0 );
+       strlcpy( buf, Msg, sizeof buf - 2);
+       strlcat( buf, "\r\n", sizeof buf);
+       (void)write( Sock, buf, strlen( buf ) );
 } /* Simple_Error */