]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/conn.c
- Copyright-Text ergaenzt bzw. aktualisiert.
[ngircd-alex.git] / src / ngircd / conn.c
index 2c1a4a578d1d23d441b8eefbf81f26bf03b29aa2..95e878853e6afc0a8ef437874d7981daabd8da1e 100644 (file)
@@ -7,13 +7,27 @@
  * 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 comBase beteiligten Autoren finden Sie in der Datei AUTHORS.
+ * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
  *
- * $Id: conn.c,v 1.20 2001/12/29 22:09:43 alex Exp $
+ * $Id: conn.c,v 1.24 2002/01/01 18:25:44 alex Exp $
  *
  * connect.h: Verwaltung aller Netz-Verbindungen ("connections")
  *
  * $Log: conn.c,v $
+ * Revision 1.24  2002/01/01 18:25:44  alex
+ * - #include's fuer stdlib.h ergaenzt.
+ *
+ * Revision 1.23  2001/12/31 02:18:51  alex
+ * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
+ * - neuen Header "defines.h" mit (fast) allen Konstanten.
+ * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
+ *
+ * Revision 1.22  2001/12/30 19:26:11  alex
+ * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
+ *
+ * Revision 1.21  2001/12/29 22:33:36  alex
+ * - bessere Dokumentation des Modules bzw. der Funktionen.
+ *
  * Revision 1.20  2001/12/29 22:09:43  alex
  * - kleinere Aenderungen ("clean-ups") bei Logging (Resolver).
  *
 #include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
 #include "conn.h"
 
 
-#define MAX_CONNECTIONS 100            /* max. Anzahl von Verbindungen an diesem Server */
-
-#define MAX_CMDLEN 512                 /* max. Laenge eines Befehls, vgl. RFC 2812, 3.2 */
-
-#define READBUFFER_LEN 2 * MAX_CMDLEN  /* Laenge des Lesepuffers je Verbindung (Bytes) */
-#define WRITEBUFFER_LEN 4096           /* Laenge des Schreibpuffers je Verbindung (Bytes) */
-
-#define HOST_LEN 256                   /* max. Laenge eines Hostnamen */
-
-
 typedef struct _Res_Stat
 {
        INT pid;                        /* PID des Child-Prozess */
@@ -143,12 +148,13 @@ typedef struct _Connection
        struct sockaddr_in addr;        /* Adresse des Client */
        RES_STAT *res_stat;             /* "Resolver-Status", s.o. */
        CHAR host[HOST_LEN];            /* Hostname */
-       CHAR rbuf[READBUFFER_LEN + 1];  /* Lesepuffer */
+       CHAR rbuf[READBUFFER_LEN];      /* Lesepuffer */
        INT rdatalen;                   /* Laenge der Daten im Lesepuffer */
-       CHAR wbuf[WRITEBUFFER_LEN + 1]; /* Schreibpuffer */
+       CHAR wbuf[WRITEBUFFER_LEN];     /* Schreibpuffer */
        INT wdatalen;                   /* Laenge der Daten im Schreibpuffer */
        time_t lastdata;                /* Letzte Aktivitaet */
        time_t lastping;                /* Letzter PING */
+       time_t lastprivmsg;             /* Letzte PRIVMSG */
 } CONNECTION;
 
 
@@ -178,6 +184,8 @@ LOCAL CONNECTION My_Connections[MAX_CONNECTIONS];
 
 GLOBAL VOID Conn_Init( VOID )
 {
+       /* Modul initialisieren: statische Strukturen "ausnullen". */
+
        CONN_ID i;
 
        /* zu Beginn haben wir keine Verbindungen */
@@ -194,6 +202,9 @@ GLOBAL VOID Conn_Init( VOID )
 
 GLOBAL VOID Conn_Exit( VOID )
 {
+       /* Modul abmelden: alle noch offenen Connections
+        * schliessen und freigeben. */
+
        CONN_ID idx;
        INT i;
 
@@ -224,8 +235,9 @@ GLOBAL VOID Conn_Exit( VOID )
 
 GLOBAL BOOLEAN Conn_NewListener( CONST INT Port )
 {
-       /* Neuen Listen-Socket erzeugen: der Server wartet dann
-        * auf dem angegebenen Port auf Verbindungen. */
+       /* Neuen Listen-Socket erzeugen: der Server wartet dann auf
+        * dem angegebenen Port auf Verbindungen. Kann der Listen-
+        * Socket nicht erteugt werden, so wird NULL geliefert.*/
 
        struct sockaddr_in addr;
        INT sock, on = 1;
@@ -279,7 +291,7 @@ GLOBAL BOOLEAN Conn_NewListener( CONST INT Port )
 
        if( sock > My_Max_Fd ) My_Max_Fd = sock;
 
-       Log( LOG_INFO, "Now listening on port %d, socket %d.", Port, sock );
+       Log( LOG_INFO, "Now listening on port %d (socket %d).", Port, sock );
 
        return TRUE;
 } /* Conn_NewListener */
@@ -287,6 +299,16 @@ GLOBAL BOOLEAN Conn_NewListener( CONST INT Port )
 
 GLOBAL VOID Conn_Handler( INT Timeout )
 {
+       /* Aktive Verbindungen ueberwachen. Mindestens alle "Timeout"
+        * Sekunden wird die Funktion verlassen. Folgende Aktionen
+        * werden durchgefuehrt:
+        *  - neue Verbindungen annehmen,
+        *  - geschlossene Verbindungen loeschen,
+        *  - volle Schreibpuffer versuchen zu schreiben,
+        *  - volle Lesepuffer versuchen zu verarbeiten,
+        *  - Antworten von Resolver Sub-Prozessen annehmen.
+        */
+
        fd_set read_sockets, write_sockets;
        struct timeval tv;
        time_t start;
@@ -369,12 +391,12 @@ GLOBAL BOOLEAN Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... )
         * automatisch angehaengt. Im Fehlerfall wird dir Verbindung
         * getrennt und FALSE geliefert. */
 
-       CHAR buffer[MAX_CMDLEN];
+       CHAR buffer[COMMAND_LEN];
        BOOLEAN ok;
        va_list ap;
 
        va_start( ap, Format );
-       if( vsnprintf( buffer, MAX_CMDLEN - 2, Format, ap ) == MAX_CMDLEN - 2 )
+       if( vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) == COMMAND_LEN - 2 )
        {
                Log( LOG_ALERT, "String too long to send (connection %d)!", Idx );
                Conn_Close( Idx, "Server error: String too long to send!" );
@@ -435,7 +457,8 @@ GLOBAL BOOLEAN Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
 
 GLOBAL VOID Conn_Close( CONN_ID Idx, CHAR *Msg )
 {
-       /* Verbindung schliessen */
+       /* Verbindung schliessen. Evtl. noch von Resolver
+        * Sub-Prozessen offene Pipes werden geschlossen. */
 
        assert( Idx >= 0 );
        assert( My_Connections[Idx].sock >= 0 );
@@ -468,6 +491,24 @@ GLOBAL VOID Conn_Close( CONN_ID Idx, CHAR *Msg )
 } /* Conn_Close */
 
 
+GLOBAL VOID Conn_UpdateIdle( CONN_ID Idx )
+{
+       /* Idle-Timer zuruecksetzen */
+
+       assert( Idx >= 0 );
+       My_Connections[Idx].lastprivmsg = time( NULL );
+}
+
+
+GLOBAL INT32 Conn_GetIdle( CONN_ID Idx )
+{
+       /* Idle-Time einer Verbindung liefern (in Sekunden) */
+
+       assert( Idx >= 0 );
+       return time( NULL ) - My_Connections[Idx].lastprivmsg;
+} /* Conn_GetIdle */
+
+
 LOCAL BOOLEAN Try_Write( CONN_ID Idx )
 {
        /* Versuchen, Daten aus dem Schreib-Puffer in den
@@ -499,7 +540,10 @@ LOCAL BOOLEAN Try_Write( CONN_ID Idx )
 
 LOCAL VOID Handle_Read( INT Sock )
 {
-       /* Aktivitaet auf einem Socket verarbeiten */
+       /* Aktivitaet auf einem Socket verarbeiten:
+        *  - neue Clients annehmen,
+        *  - Daten von Clients verarbeiten,
+        *  - Resolver-Rueckmeldungen annehmen. */
 
        CONN_ID idx;
 
@@ -644,8 +688,8 @@ LOCAL VOID Read_Request( CONN_ID Idx )
        assert( Idx >= 0 );
        assert( My_Connections[Idx].sock >= 0 );
 
-       len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, READBUFFER_LEN - My_Connections[Idx].rdatalen, 0 );
-       My_Connections[Idx].rbuf[READBUFFER_LEN] = '\0';
+       len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, READBUFFER_LEN - My_Connections[Idx].rdatalen - 1, 0 );
+       My_Connections[Idx].rbuf[READBUFFER_LEN - 1] = '\0';
 
        if( len == 0 )
        {
@@ -668,7 +712,7 @@ LOCAL VOID Read_Request( CONN_ID Idx )
        assert( My_Connections[Idx].rdatalen <= READBUFFER_LEN );
        My_Connections[Idx].rbuf[My_Connections[Idx].rdatalen] = '\0';
 
-       if( My_Connections[Idx].rdatalen > MAX_CMDLEN )
+       if( My_Connections[Idx].rdatalen > COMMAND_LEN )
        {
                /* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
                 * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas
@@ -687,6 +731,8 @@ LOCAL VOID Read_Request( CONN_ID Idx )
 
 LOCAL VOID Handle_Buffer( CONN_ID Idx )
 {
+       /* Daten im Lese-Puffer einer Verbindung verarbeiten. */
+
        CHAR *ptr, *ptr1, *ptr2;
        INT len, delta;
        
@@ -727,7 +773,9 @@ LOCAL VOID Handle_Buffer( CONN_ID Idx )
 
 LOCAL VOID Check_Connections( VOID )
 {
-       /* Pruefen, ob Verbindungen noch "alive" sind */
+       /* Pruefen, ob Verbindungen noch "alive" sind. Ist dies
+        * nicht der Fall, zunaechst PING-PONG spielen und, wenn
+        * auch das nicht "hilft", Client disconnectieren. */
 
        INT i;
 
@@ -770,6 +818,7 @@ LOCAL VOID Init_Conn_Struct( INT Idx )
        My_Connections[Idx].wdatalen = 0;
        My_Connections[Idx].lastdata = time( NULL );
        My_Connections[Idx].lastping = 0;
+       My_Connections[Idx].lastprivmsg = time( NULL );
 } /* Init_Conn_Struct */
 
 
@@ -782,6 +831,7 @@ LOCAL RES_STAT *Resolve( struct sockaddr_in *Addr )
        RES_STAT *s;
        INT pid;
 
+       /* Speicher anfordern */
        s = malloc( sizeof( RES_STAT ));
        if( ! s )
        {
@@ -789,6 +839,7 @@ LOCAL RES_STAT *Resolve( struct sockaddr_in *Addr )
                return NULL;
        }
 
+       /* Pipe fuer Antwort initialisieren */
        if( pipe( s->pipe ) != 0 )
        {
                free( s );
@@ -796,11 +847,12 @@ LOCAL RES_STAT *Resolve( struct sockaddr_in *Addr )
                return NULL;
        }
 
+       /* Sub-Prozess erzeugen */
        pid = fork( );
        if( pid > 0 )
        {
                /* Haupt-Prozess */
-               Log( LOG_DEBUG, "Resolver process for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
+               Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
                FD_SET( s->pipe[0], &My_Resolvers );
                if( s->pipe[0] > My_Max_Fd ) My_Max_Fd = s->pipe[0];
                s->pid = pid;
@@ -844,9 +896,9 @@ LOCAL VOID Read_Resolver_Result( INT r_fd )
                return;
        }
 
+       /* zugehoerige Connection suchen */
        for( i = 0; i < MAX_CONNECTIONS; i++ )
        {
-               /* zugehoerige Connection suchen */
                if(( My_Connections[i].sock >= 0 ) && ( My_Connections[i].res_stat ) && ( My_Connections[i].res_stat->pipe[0] == r_fd )) break;
        }