2001-12-12 18:18:38 +01:00
/*
* ngIRCd - - The Next Generation IRC Daemon
2002-01-02 03:44:36 +01:00
* Copyright ( c ) 2001 , 2002 by Alexander Barton ( alex @ barton . de )
2001-12-12 18:18:38 +01:00
*
* Dieses Programm ist freie Software . Sie koennen es unter den Bedingungen
* der GNU General Public License ( GPL ) , wie von der Free Software Foundation
* 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
2001-12-31 03:18:51 +01:00
* der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS .
2001-12-12 18:18:38 +01:00
*
2002-10-21 15:45:07 +02:00
* $ Id : conn . c , v 1.84 2002 / 10 / 21 13 : 45 : 07 alex Exp $
2001-12-12 18:18:38 +01:00
*
* connect . h : Verwaltung aller Netz - Verbindungen ( " connections " )
*/
2002-03-12 15:37:51 +01:00
# include "portab.h"
2001-12-12 18:18:38 +01:00
2002-03-12 15:37:51 +01:00
# include "imp.h"
2001-12-12 18:18:38 +01:00
# include <assert.h>
2001-12-23 23:02:54 +01:00
# include <stdarg.h>
2001-12-12 18:18:38 +01:00
# include <stdio.h>
2002-01-01 19:25:44 +01:00
# include <stdlib.h>
2001-12-12 18:18:38 +01:00
# include <unistd.h>
# include <errno.h>
# include <fcntl.h>
# include <string.h>
2001-12-26 00:15:16 +01:00
# include <sys/socket.h>
2001-12-12 18:18:38 +01:00
# include <sys/time.h>
2001-12-26 00:15:16 +01:00
# include <sys/types.h>
2001-12-26 04:36:57 +01:00
# include <time.h>
2001-12-12 18:18:38 +01:00
# include <netinet/in.h>
2002-01-05 16:56:23 +01:00
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
# else
# define PF_INET AF_INET
# endif
2001-12-12 18:18:38 +01:00
# ifdef HAVE_STDINT_H
# include <stdint.h> /* u.a. fuer Mac OS X */
# endif
2002-05-27 15:09:26 +02:00
# include "exp.h"
# include "conn.h"
# include "imp.h"
2001-12-13 00:32:02 +01:00
# include "ngircd.h"
2001-12-23 23:02:54 +01:00
# include "client.h"
2002-05-27 15:09:26 +02:00
# include "resolve.h"
2001-12-26 04:20:53 +01:00
# include "conf.h"
2001-12-12 18:18:38 +01:00
# include "log.h"
2001-12-21 23:24:25 +01:00
# include "parse.h"
2001-12-13 00:32:02 +01:00
# include "tool.h"
2001-12-12 18:18:38 +01:00
2002-03-12 15:37:51 +01:00
# include "exp.h"
2001-12-12 18:18:38 +01:00
2002-03-13 00:45:30 +01:00
# define SERVER_WAIT (NONE - 1)
2001-12-29 21:17:25 +01:00
2001-12-13 00:32:02 +01:00
typedef struct _Connection
{
INT sock ; /* Socket Handle */
struct sockaddr_in addr ; /* Adresse des Client */
2001-12-29 21:17:25 +01:00
RES_STAT * res_stat ; /* "Resolver-Status", s.o. */
CHAR host [ HOST_LEN ] ; /* Hostname */
2001-12-31 03:18:51 +01:00
CHAR rbuf [ READBUFFER_LEN ] ; /* Lesepuffer */
2001-12-15 01:11:55 +01:00
INT rdatalen ; /* Laenge der Daten im Lesepuffer */
2001-12-31 03:18:51 +01:00
CHAR wbuf [ WRITEBUFFER_LEN ] ; /* Schreibpuffer */
2001-12-15 01:11:55 +01:00
INT wdatalen ; /* Laenge der Daten im Schreibpuffer */
2002-01-02 03:44:36 +01:00
INT our_server ; /* wenn von uns zu connectender Server: ID */
2001-12-26 04:20:53 +01:00
time_t lastdata ; /* Letzte Aktivitaet */
time_t lastping ; /* Letzter PING */
2001-12-31 03:18:51 +01:00
time_t lastprivmsg ; /* Letzte PRIVMSG */
2002-08-26 02:03:15 +02:00
time_t delaytime ; /* Nicht beachten bis ("penalty") */
2002-10-09 18:53:02 +02:00
LONG bytes_in , bytes_out ; /* Counter fuer Statistik */
2001-12-13 00:32:02 +01:00
} CONNECTION ;
2002-05-27 15:09:26 +02:00
LOCAL VOID Handle_Read PARAMS ( ( INT sock ) ) ;
LOCAL BOOLEAN 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 BOOLEAN Try_Write PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL VOID 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 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 ) ) ;
2001-12-13 00:32:02 +01:00
2001-12-29 21:17:25 +01:00
LOCAL fd_set My_Listeners ;
2001-12-13 00:32:02 +01:00
LOCAL fd_set My_Sockets ;
2002-03-02 01:23:32 +01:00
LOCAL fd_set My_Connects ;
2001-12-13 00:32:02 +01:00
LOCAL CONNECTION My_Connections [ MAX_CONNECTIONS ] ;
2001-12-12 18:18:38 +01:00
2002-05-27 15:09:26 +02:00
GLOBAL VOID
Conn_Init ( VOID )
2001-12-12 18:18:38 +01:00
{
2001-12-29 23:33:36 +01:00
/* Modul initialisieren: statische Strukturen "ausnullen". */
2001-12-14 09:16:47 +01:00
CONN_ID i ;
2001-12-13 00:32:02 +01:00
/* zu Beginn haben wir keine Verbindungen */
2001-12-29 21:17:25 +01:00
FD_ZERO ( & My_Listeners ) ;
2001-12-13 00:32:02 +01:00
FD_ZERO ( & My_Sockets ) ;
2002-03-02 01:23:32 +01:00
FD_ZERO ( & My_Connects ) ;
2001-12-26 00:15:16 +01:00
2002-05-27 15:09:26 +02:00
Conn_MaxFD = 0 ;
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
/* Connection-Struktur initialisieren */
2001-12-29 21:17:25 +01:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + ) Init_Conn_Struct ( i ) ;
2001-12-12 18:18:38 +01:00
} /* Conn_Init */
2002-05-27 15:09:26 +02:00
GLOBAL VOID
Conn_Exit ( VOID )
2001-12-12 18:18:38 +01:00
{
2001-12-29 23:33:36 +01:00
/* Modul abmelden: alle noch offenen Connections
* schliessen und freigeben . */
2001-12-14 09:16:47 +01:00
CONN_ID idx ;
INT i ;
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
/* Sockets schliessen */
2002-01-06 16:18:14 +01:00
Log ( LOG_DEBUG , " Shutting down all connections ... " ) ;
2002-05-27 15:09:26 +02:00
for ( i = 0 ; i < Conn_MaxFD + 1 ; i + + )
2001-12-13 00:32:02 +01:00
{
if ( FD_ISSET ( i , & My_Sockets ) )
{
for ( idx = 0 ; idx < MAX_CONNECTIONS ; idx + + )
{
if ( My_Connections [ idx ] . sock = = i ) break ;
}
2002-03-02 01:23:32 +01:00
if ( FD_ISSET ( i , & My_Listeners ) )
2001-12-13 00:32:02 +01:00
{
close ( i ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_DEBUG , " Listening socket %d closed. " , i ) ;
2001-12-13 00:32:02 +01:00
}
2002-03-02 01:23:32 +01:00
else if ( FD_ISSET ( i , & My_Connects ) )
{
close ( i ) ;
Log ( LOG_DEBUG , " Connection %d closed during creation (socket %d). " , idx , i ) ;
}
2002-06-02 19:03:08 +02:00
else if ( idx < MAX_CONNECTIONS )
{
if ( NGIRCd_Restart ) Conn_Close ( idx , NULL , " Server going down (restarting) " , TRUE ) ;
else Conn_Close ( idx , NULL , " Server going down " , TRUE ) ;
}
2001-12-13 00:32:02 +01:00
else
{
2002-03-02 01:23:32 +01:00
Log ( LOG_WARNING , " Closing unknown connection %d ... " , i ) ;
2001-12-13 00:32:02 +01:00
close ( i ) ;
}
}
}
2001-12-12 18:18:38 +01:00
} /* Conn_Exit */
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
Conn_NewListener ( CONST UINT Port )
2001-12-12 18:18:38 +01:00
{
2001-12-29 23:33:36 +01:00
/* 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 . */
2001-12-12 18:18:38 +01:00
2001-12-13 00:32:02 +01:00
struct sockaddr_in addr ;
2002-03-02 01:23:32 +01:00
INT sock ;
2001-12-13 00:32:02 +01:00
2001-12-12 18:18:38 +01:00
/* Server-"Listen"-Socket initialisieren */
2001-12-13 00:32:02 +01:00
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( Port ) ;
addr . sin_addr . s_addr = htonl ( INADDR_ANY ) ;
2001-12-12 18:18:38 +01:00
/* Socket erzeugen */
2001-12-13 00:32:02 +01:00
sock = socket ( PF_INET , SOCK_STREAM , 0 ) ;
2001-12-13 03:04:16 +01:00
if ( sock < 0 )
2001-12-12 18:18:38 +01:00
{
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't create socket: %s! " , strerror ( errno ) ) ;
2001-12-12 18:18:38 +01:00
return FALSE ;
}
2002-03-02 01:23:32 +01:00
if ( ! Init_Socket ( sock ) ) return FALSE ;
2001-12-13 00:32:02 +01:00
2001-12-12 18:18:38 +01:00
/* an Port binden */
2001-12-13 00:32:02 +01:00
if ( bind ( sock , ( struct sockaddr * ) & addr , ( socklen_t ) sizeof ( addr ) ) ! = 0 )
2001-12-12 18:18:38 +01:00
{
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't bind socket: %s! " , strerror ( errno ) ) ;
2001-12-13 00:32:02 +01:00
close ( sock ) ;
2001-12-12 18:18:38 +01:00
return FALSE ;
}
/* in "listen mode" gehen :-) */
2001-12-13 00:32:02 +01:00
if ( listen ( sock , 10 ) ! = 0 )
2001-12-12 18:18:38 +01:00
{
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't listen on soecket: %s! " , strerror ( errno ) ) ;
2001-12-13 00:32:02 +01:00
close ( sock ) ;
2001-12-12 18:18:38 +01:00
return FALSE ;
}
2001-12-13 00:32:02 +01:00
/* Neuen Listener in Strukturen einfuegen */
2001-12-29 21:17:25 +01:00
FD_SET ( sock , & My_Listeners ) ;
2001-12-13 00:32:02 +01:00
FD_SET ( sock , & My_Sockets ) ;
2001-12-26 00:15:16 +01:00
2002-05-27 15:09:26 +02:00
if ( sock > Conn_MaxFD ) Conn_MaxFD = sock ;
2001-12-13 00:32:02 +01:00
2001-12-30 20:26:11 +01:00
Log ( LOG_INFO , " Now listening on port %d (socket %d). " , Port , sock ) ;
2001-12-13 00:32:02 +01:00
2001-12-12 18:18:38 +01:00
return TRUE ;
2001-12-26 15:45:37 +01:00
} /* Conn_NewListener */
2001-12-12 18:18:38 +01:00
2002-05-27 15:09:26 +02:00
GLOBAL VOID
2002-06-02 19:03:08 +02:00
Conn_Handler ( VOID )
2001-12-12 18:18:38 +01:00
{
2002-09-07 23:13:38 +02:00
/* "Hauptschleife": Aktive Verbindungen ueberwachen. Folgende Aktionen
* werden dabei durchgefuehrt , bis der Server terminieren oder neu
* starten soll :
*
2001-12-29 23:33:36 +01:00
* - neue Verbindungen annehmen ,
2002-01-02 03:44:36 +01:00
* - Server - Verbindungen aufbauen ,
2001-12-29 23:33:36 +01:00
* - geschlossene Verbindungen loeschen ,
* - volle Schreibpuffer versuchen zu schreiben ,
* - volle Lesepuffer versuchen zu verarbeiten ,
* - Antworten von Resolver Sub - Prozessen annehmen .
*/
2001-12-15 01:11:55 +01:00
fd_set read_sockets , write_sockets ;
2001-12-13 02:33:09 +01:00
struct timeval tv ;
2002-08-26 02:03:15 +02:00
time_t start , t ;
2002-10-15 00:21:00 +02:00
INT i , idx ;
2001-12-13 02:33:09 +01:00
2001-12-26 00:15:16 +01:00
start = time ( NULL ) ;
2002-06-02 19:03:08 +02:00
while ( ( ! NGIRCd_Quit ) & & ( ! NGIRCd_Restart ) )
2001-12-15 01:11:55 +01:00
{
2002-01-02 03:44:36 +01:00
Check_Servers ( ) ;
2001-12-26 04:20:53 +01:00
Check_Connections ( ) ;
/* noch volle Lese-Buffer suchen */
2001-12-26 00:15:16 +01:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
2001-12-15 01:11:55 +01:00
{
2002-01-02 03:44:36 +01:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . rdatalen > 0 ) )
2001-12-26 00:15:16 +01:00
{
2001-12-26 04:20:53 +01:00
/* Kann aus dem Buffer noch ein Befehl extrahiert werden? */
Handle_Buffer ( i ) ;
2001-12-26 00:15:16 +01:00
}
}
2002-03-11 01:04:48 +01:00
2001-12-26 04:20:53 +01:00
/* noch volle Schreib-Puffer suchen */
FD_ZERO ( & write_sockets ) ;
2001-12-26 00:15:16 +01:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
2002-01-02 03:44:36 +01:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . wdatalen > 0 ) )
2001-12-26 00:15:16 +01:00
{
2001-12-26 04:20:53 +01:00
/* Socket der Verbindung in Set aufnehmen */
FD_SET ( My_Connections [ i ] . sock , & write_sockets ) ;
2001-12-26 00:15:16 +01:00
}
}
2002-03-02 01:23:32 +01:00
/* Sockets mit im Aufbau befindlichen ausgehenden Verbindungen suchen */
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
if ( ( My_Connections [ i ] . sock > NONE ) & & ( FD_ISSET ( My_Connections [ i ] . sock , & My_Connects ) ) ) FD_SET ( My_Connections [ i ] . sock , & write_sockets ) ;
}
2001-12-29 21:17:25 +01:00
/* von welchen Sockets koennte gelesen werden? */
2002-08-26 02:03:15 +02:00
t = time ( NULL ) ;
2001-12-26 00:15:16 +01:00
read_sockets = My_Sockets ;
2001-12-29 21:17:25 +01:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
2002-01-02 03:44:36 +01:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . host [ 0 ] = = ' \0 ' ) )
2001-12-29 21:17:25 +01:00
{
/* Hier muss noch auf den Resolver Sub-Prozess gewartet werden */
FD_CLR ( My_Connections [ i ] . sock , & read_sockets ) ;
}
2002-03-02 01:23:32 +01:00
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 ) ;
}
2002-08-26 02:03:15 +02:00
if ( My_Connections [ i ] . delaytime > t )
{
/* Fuer die Verbindung ist eine "Penalty-Zeit" gesetzt */
FD_CLR ( My_Connections [ i ] . sock , & read_sockets ) ;
2002-09-08 00:34:44 +02:00
FD_CLR ( My_Connections [ i ] . sock , & write_sockets ) ;
2002-08-26 02:03:15 +02:00
}
2001-12-29 21:17:25 +01:00
}
2002-05-27 15:09:26 +02:00
for ( i = 0 ; i < Conn_MaxFD + 1 ; i + + )
2001-12-29 21:17:25 +01:00
{
/* Pipes von Resolver Sub-Prozessen aufnehmen */
2002-05-27 15:09:26 +02:00
if ( FD_ISSET ( i , & Resolver_FDs ) )
2001-12-29 21:17:25 +01:00
{
FD_SET ( i , & read_sockets ) ;
}
}
2002-09-07 23:13:38 +02:00
/* Timeout initialisieren */
2002-09-07 23:35:06 +02:00
tv . tv_sec = 1 ;
2002-09-07 23:13:38 +02:00
tv . tv_usec = 0 ;
2001-12-29 21:17:25 +01:00
/* Auf Aktivitaet warten */
2002-09-08 00:34:44 +02:00
i = select ( Conn_MaxFD + 1 , & read_sockets , & write_sockets , NULL , & tv ) ;
if ( i = = 0 )
2001-12-26 00:15:16 +01:00
{
2002-09-08 00:34:44 +02:00
/* keine Veraenderung an den Sockets */
continue ;
}
if ( i = = - 1 )
{
/* Fehler (z.B. Interrupt) */
2002-01-05 20:15:03 +01:00
if ( errno ! = EINTR )
{
2002-10-15 11:24:54 +02:00
Log ( LOG_EMERG , " Conn_Handler(): select(): %s! " , strerror ( errno ) ) ;
2002-05-30 18:52:20 +02:00
Log ( LOG_ALERT , " %s exiting due to fatal errors! " , PACKAGE ) ;
2002-01-05 20:15:03 +01:00
exit ( 1 ) ;
}
2002-09-08 00:34:44 +02:00
continue ;
2001-12-26 00:15:16 +01:00
}
/* Koennen Daten geschrieben werden? */
2002-05-27 15:09:26 +02:00
for ( i = 0 ; i < Conn_MaxFD + 1 ; i + + )
2001-12-26 00:15:16 +01:00
{
2002-10-15 00:21:00 +02:00
if ( ! FD_ISSET ( i , & write_sockets ) ) continue ;
2002-10-15 11:24:54 +02:00
2002-10-15 00:21:00 +02:00
/* Es kann geschrieben werden ... */
idx = Socket2Index ( i ) ;
2002-10-15 11:24:54 +02:00
if ( idx = = NONE ) continue ;
2002-10-15 00:21:00 +02:00
if ( ! Handle_Write ( idx ) )
{
/* Fehler beim Schreiben! Diesen Socket nun
* auch aus dem Read - Set entfernen : */
FD_CLR ( i , & read_sockets ) ;
}
2001-12-26 00:15:16 +01:00
}
/* Daten zum Lesen vorhanden? */
2002-05-27 15:09:26 +02:00
for ( i = 0 ; i < Conn_MaxFD + 1 ; i + + )
2001-12-26 00:15:16 +01:00
{
if ( FD_ISSET ( i , & read_sockets ) ) Handle_Read ( i ) ;
2001-12-15 01:11:55 +01:00
}
2001-12-13 00:32:02 +01:00
}
} /* Conn_Handler */
2002-05-30 18:52:20 +02:00
# ifdef PROTOTYPES
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
Conn_WriteStr ( CONN_ID Idx , CHAR * Format , . . . )
2002-05-30 18:52:20 +02:00
# else
GLOBAL BOOLEAN
Conn_WriteStr ( Idx , Format , va_alist )
CONN_ID Idx ;
CHAR * Format ;
va_dcl
# endif
2001-12-15 01:11:55 +01:00
{
/* String in Socket schreiben. CR+LF wird von dieser Funktion
2001-12-23 23:02:54 +01:00
* automatisch angehaengt . Im Fehlerfall wird dir Verbindung
* getrennt und FALSE geliefert . */
2001-12-26 00:15:16 +01:00
2001-12-31 03:18:51 +01:00
CHAR buffer [ COMMAND_LEN ] ;
2001-12-23 23:02:54 +01:00
BOOLEAN ok ;
va_list ap ;
2002-03-14 14:42:33 +01:00
assert ( Idx > = 0 ) ;
assert ( Format ! = NULL ) ;
2002-05-30 18:52:20 +02:00
# ifdef PROTOTYPES
2001-12-23 23:02:54 +01:00
va_start ( ap , Format ) ;
2002-05-30 18:52:20 +02:00
# else
va_start ( ap ) ;
# endif
2001-12-31 03:18:51 +01:00
if ( vsnprintf ( buffer , COMMAND_LEN - 2 , Format , ap ) = = COMMAND_LEN - 2 )
2001-12-15 01:11:55 +01:00
{
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Text too long to send (connection %d)! " , Idx ) ;
Conn_Close ( Idx , " Text too long to send! " , NULL , FALSE ) ;
2001-12-15 01:11:55 +01:00
return FALSE ;
}
2001-12-23 23:02:54 +01:00
2001-12-25 23:03:47 +01:00
# ifdef SNIFFER
2002-01-18 12:12:11 +01:00
if ( NGIRCd_Sniffer ) Log ( LOG_DEBUG , " -> connection %d: '%s'. " , Idx , buffer ) ;
2001-12-23 23:02:54 +01:00
# endif
2001-12-26 00:15:16 +01:00
2001-12-24 02:32:33 +01:00
strcat ( buffer , " \r \n " ) ;
ok = Conn_Write ( Idx , buffer , strlen ( buffer ) ) ;
2001-12-23 23:02:54 +01:00
va_end ( ap ) ;
return ok ;
2001-12-15 01:11:55 +01:00
} /* Conn_WriteStr */
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
Conn_Write ( CONN_ID Idx , CHAR * Data , INT Len )
2001-12-15 01:11:55 +01:00
{
/* Daten in Socket schreiben. Bei "fatalen" Fehlern wird
* der Client disconnectiert und FALSE geliefert . */
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
assert ( Idx > = 0 ) ;
assert ( Data ! = NULL ) ;
assert ( Len > 0 ) ;
2002-09-26 17:59:02 +02:00
/* 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 . */
2002-09-26 18:11:26 +02:00
if ( My_Connections [ Idx ] . sock < = NONE )
2002-09-26 17:59:02 +02:00
{
Log ( LOG_DEBUG , " Skipped write on closed socket (connection %d). " , Idx ) ;
return FALSE ;
}
2001-12-15 01:11:55 +01:00
/* pruefen, ob Daten im Schreibpuffer sind. Wenn ja, zunaechst
* pruefen , ob diese gesendet werden koennen */
if ( My_Connections [ Idx ] . wdatalen > 0 )
{
if ( ! Try_Write ( Idx ) ) return FALSE ;
}
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
/* pruefen, ob im Schreibpuffer genuegend Platz ist */
if ( WRITEBUFFER_LEN - My_Connections [ Idx ] . wdatalen - Len < = 0 )
{
/* der Puffer ist dummerweise voll ... */
Log ( LOG_NOTICE , " Write buffer overflow (connection %d)! " , Idx ) ;
2002-01-06 16:18:14 +01:00
Conn_Close ( Idx , " Write buffer overflow! " , NULL , FALSE ) ;
2001-12-15 01:11:55 +01:00
return FALSE ;
}
/* Daten in Puffer kopieren */
memcpy ( My_Connections [ Idx ] . wbuf + My_Connections [ Idx ] . wdatalen , Data , Len ) ;
My_Connections [ Idx ] . wdatalen + = Len ;
/* pruefen, on Daten vorhanden sind und geschrieben werden koennen */
if ( My_Connections [ Idx ] . wdatalen > 0 )
{
if ( ! Try_Write ( Idx ) ) return FALSE ;
}
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
return TRUE ;
} /* Conn_Write */
2002-05-27 15:09:26 +02:00
GLOBAL VOID
Conn_Close ( CONN_ID Idx , CHAR * LogMsg , CHAR * FwdMsg , BOOLEAN InformClient )
2001-12-25 23:03:47 +01:00
{
2001-12-29 23:33:36 +01:00
/* Verbindung schliessen. Evtl. noch von Resolver
* Sub - Prozessen offene Pipes werden geschlossen . */
2001-12-25 23:03:47 +01:00
2002-01-02 03:44:36 +01:00
CLIENT * c ;
2002-03-11 01:04:48 +01:00
2001-12-25 23:03:47 +01:00
assert ( Idx > = 0 ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2001-12-25 23:03:47 +01:00
2002-10-09 15:15:08 +02:00
c = Client_GetFromConn ( Idx ) ;
2002-01-06 16:18:14 +01:00
if ( InformClient )
2002-01-02 03:44:36 +01:00
{
2002-10-09 15:15:08 +02:00
/* Statistik an Client melden, wenn User */
if ( ( c ! = NULL ) & & ( Client_Type ( c ) = = CLIENT_USER ) )
{
2002-10-09 19:02:49 +02:00
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 ) ;
2002-10-09 15:15:08 +02:00
}
/* ERROR an Client schicken (von RFC so vorgesehen!) */
2002-01-06 16:18:14 +01:00
if ( FwdMsg ) Conn_WriteStr ( Idx , " ERROR :%s " , FwdMsg ) ;
else Conn_WriteStr ( Idx , " ERROR :Closing connection. " ) ;
2002-01-02 03:44:36 +01:00
if ( My_Connections [ Idx ] . sock = = NONE ) return ;
}
2001-12-25 23:03:47 +01:00
if ( close ( My_Connections [ Idx ] . sock ) ! = 0 )
{
2002-10-15 00:21:00 +02:00
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 ) ) ;
2001-12-25 23:03:47 +01:00
}
else
{
2002-10-15 00:21:00 +02:00
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 ) ) ;
2001-12-25 23:03:47 +01:00
}
2002-10-15 00:21:00 +02:00
/* 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 ;
2001-12-25 23:03:47 +01:00
2002-03-11 23:04:10 +01:00
if ( c ) Client_Destroy ( c , LogMsg , FwdMsg , TRUE ) ;
2001-12-25 23:03:47 +01:00
2001-12-29 21:17:25 +01:00
if ( My_Connections [ Idx ] . res_stat )
{
/* Resolver-Strukturen freigeben, wenn noch nicht geschehen */
2002-05-27 15:09:26 +02:00
FD_CLR ( My_Connections [ Idx ] . res_stat - > pipe [ 0 ] , & Resolver_FDs ) ;
2001-12-29 22:53:57 +01:00
close ( My_Connections [ Idx ] . res_stat - > pipe [ 0 ] ) ;
close ( My_Connections [ Idx ] . res_stat - > pipe [ 1 ] ) ;
2001-12-29 21:17:25 +01:00
free ( My_Connections [ Idx ] . res_stat ) ;
}
2002-01-02 03:44:36 +01:00
2002-10-09 19:07:22 +02:00
/* 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 ) )
2002-03-11 01:04:48 +01:00
{
2002-10-09 19:07:22 +02:00
/* Okay, die Verbindung stand schon "genuegend lange":
* lasttry - Zeitpunkt so setzen , dass der naechste
* Verbindungsversuch in RECONNECT_DELAY Sekunden
* gestartet wird . */
2002-03-11 01:04:48 +01:00
Conf_Server [ My_Connections [ Idx ] . our_server ] . lasttry = time ( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY ;
}
2002-01-02 03:44:36 +01:00
2002-10-15 00:21:00 +02:00
/* Connection-Struktur loeschen (=freigeben) */
Init_Conn_Struct ( Idx ) ;
2001-12-25 23:03:47 +01:00
} /* Conn_Close */
2002-05-27 15:09:26 +02:00
GLOBAL VOID
Conn_UpdateIdle ( CONN_ID Idx )
2001-12-31 03:18:51 +01:00
{
/* Idle-Timer zuruecksetzen */
assert ( Idx > = 0 ) ;
My_Connections [ Idx ] . lastprivmsg = time ( NULL ) ;
}
2002-05-27 15:09:26 +02:00
GLOBAL time_t
Conn_GetIdle ( CONN_ID Idx )
2001-12-31 03:18:51 +01:00
{
/* Idle-Time einer Verbindung liefern (in Sekunden) */
assert ( Idx > = 0 ) ;
return time ( NULL ) - My_Connections [ Idx ] . lastprivmsg ;
} /* Conn_GetIdle */
2002-05-27 15:09:26 +02:00
GLOBAL time_t
Conn_LastPing ( CONN_ID Idx )
2002-02-11 02:00:50 +01:00
{
/* Zeitpunkt des letzten PING liefern */
assert ( Idx > = 0 ) ;
return My_Connections [ Idx ] . lastping ;
} /* Conn_LastPing */
2002-08-26 02:03:15 +02:00
GLOBAL VOID
Conn_SetPenalty ( CONN_ID Idx , time_t Seconds )
{
/* Penalty-Delay fuer eine Verbindung (in Sekunden) setzen;
* waehrend dieser Zeit wird der entsprechende Socket vom Server
* bei Lese - Operationen komplett ignoriert . Der Delay kann mit
* dieser Funktion nur erhoeht , nicht aber verringert werden . */
time_t t ;
assert ( Idx > = 0 ) ;
assert ( Seconds > = 0 ) ;
t = time ( NULL ) + Seconds ;
if ( t > My_Connections [ Idx ] . delaytime ) My_Connections [ Idx ] . delaytime = t ;
} /* Conn_SetPenalty */
2002-10-10 17:01:12 +02:00
GLOBAL VOID
Conn_ResetPenalty ( CONN_ID Idx )
{
assert ( Idx > = 0 ) ;
My_Connections [ Idx ] . delaytime = 0 ;
} /* Conn_ResetPenalty */
2002-05-27 15:09:26 +02:00
LOCAL BOOLEAN
Try_Write ( CONN_ID Idx )
2001-12-15 01:11:55 +01:00
{
/* Versuchen, Daten aus dem Schreib-Puffer in den
* Socket zu schreiben . */
fd_set write_socket ;
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
assert ( Idx > = 0 ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2001-12-15 01:11:55 +01:00
assert ( My_Connections [ Idx ] . wdatalen > 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 )
{
/* Fehler! */
if ( errno ! = EINTR )
{
2002-10-15 11:24:54 +02:00
Log ( LOG_ALERT , " Try_Write(): select() failed: %s (con=%d, sock=%d)! " , strerror ( errno ) , Idx , My_Connections [ Idx ] . sock ) ;
2002-01-06 16:18:14 +01:00
Conn_Close ( Idx , " Server error! " , NULL , FALSE ) ;
2001-12-15 01:11:55 +01:00
return FALSE ;
}
}
if ( FD_ISSET ( My_Connections [ Idx ] . sock , & write_socket ) ) return Handle_Write ( Idx ) ;
else return TRUE ;
} /* Try_Write */
2002-05-27 15:09:26 +02:00
LOCAL VOID
Handle_Read ( INT Sock )
2001-12-13 00:32:02 +01:00
{
2001-12-29 23:33:36 +01:00
/* Aktivitaet auf einem Socket verarbeiten:
* - neue Clients annehmen ,
* - Daten von Clients verarbeiten ,
* - Resolver - Rueckmeldungen annehmen . */
2001-12-13 00:32:02 +01:00
2001-12-14 09:16:47 +01:00
CONN_ID idx ;
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
assert ( Sock > = 0 ) ;
2002-03-11 01:04:48 +01:00
2001-12-29 21:17:25 +01:00
if ( FD_ISSET ( Sock , & My_Listeners ) )
2001-12-13 00:32:02 +01:00
{
/* es ist einer unserer Listener-Sockets: es soll
* also eine neue Verbindung aufgebaut werden . */
New_Connection ( Sock ) ;
}
2002-05-27 15:09:26 +02:00
else if ( FD_ISSET ( Sock , & Resolver_FDs ) )
2001-12-29 21:17:25 +01:00
{
/* Rueckmeldung von einem Resolver Sub-Prozess */
Read_Resolver_Result ( Sock ) ;
}
2001-12-13 00:32:02 +01:00
else
{
/* Ein Client Socket: entweder ein User oder Server */
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
idx = Socket2Index ( Sock ) ;
2002-10-15 00:21:00 +02:00
if ( idx > NONE ) Read_Request ( idx ) ;
2001-12-13 00:32:02 +01:00
}
2001-12-15 01:11:55 +01:00
} /* Handle_Read */
2002-05-27 15:09:26 +02:00
LOCAL BOOLEAN
Handle_Write ( CONN_ID Idx )
2001-12-15 01:11:55 +01:00
{
2002-03-02 01:23:32 +01:00
/* Daten aus Schreibpuffer versenden bzw. Connection aufbauen */
2001-12-26 00:15:16 +01:00
2002-03-02 01:23:32 +01:00
INT len , res , err ;
2001-12-15 01:11:55 +01:00
2002-10-15 11:24:54 +02:00
assert ( Idx > NONE ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2002-03-02 01:23:32 +01:00
if ( FD_ISSET ( My_Connections [ Idx ] . sock , & My_Connects ) )
{
/* es soll nichts geschrieben werden, sondern ein
* connect ( ) hat ein Ergebnis geliefert */
FD_CLR ( My_Connections [ Idx ] . sock , & My_Connects ) ;
/* Ergebnis des connect() ermitteln */
len = sizeof ( err ) ;
res = getsockopt ( My_Connections [ Idx ] . sock , SOL_SOCKET , SO_ERROR , & err , & len ) ;
assert ( len = = sizeof ( err ) ) ;
/* Fehler aufgetreten? */
if ( ( res ! = 0 ) | | ( err ! = 0 ) )
{
/* Fehler! */
if ( res ! = 0 ) Log ( LOG_CRIT , " getsockopt (connection %d): %s! " , Idx , strerror ( errno ) ) ;
else Log ( LOG_CRIT , " Can't connect socket to \" %s:%d \" (connection %d) : % s ! " , My_Connections[Idx].host, Conf_Server[My_Connections[Idx].our_server].port, Idx, strerror( err )) ;
/* Socket etc. pp. aufraeumen */
FD_CLR ( My_Connections [ Idx ] . sock , & My_Sockets ) ;
close ( My_Connections [ Idx ] . sock ) ;
Init_Conn_Struct ( Idx ) ;
2002-03-02 01:29:11 +01:00
/* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */
Conf_Server [ My_Connections [ Idx ] . our_server ] . lasttry = time ( NULL ) ;
2002-03-02 01:23:32 +01:00
return FALSE ;
}
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 */
2002-09-02 21:03:09 +02:00
Conn_WriteStr ( Idx , " PASS %s %s " , Conf_Server [ My_Connections [ Idx ] . our_server ] . pwd , NGIRCd_ProtoID ) ;
2002-10-15 00:21:00 +02:00
return Conn_WriteStr ( Idx , " SERVER %s :%s " , Conf_ServerName , Conf_ServerInfo ) ;
2002-03-02 01:23:32 +01:00
}
2001-12-15 01:11:55 +01:00
assert ( My_Connections [ Idx ] . wdatalen > 0 ) ;
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
/* Daten schreiben */
len = send ( My_Connections [ Idx ] . sock , My_Connections [ Idx ] . wbuf , My_Connections [ Idx ] . wdatalen , 0 ) ;
if ( len < 0 )
{
/* Oops, ein Fehler! */
2002-10-15 00:21:00 +02:00
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 ) ;
2001-12-15 01:11:55 +01:00
return FALSE ;
}
2001-12-26 00:15:16 +01:00
2002-10-09 15:15:08 +02:00
/* Connection-Statistik aktualisieren */
My_Connections [ Idx ] . bytes_out + = len ;
2001-12-15 01:11:55 +01:00
/* Puffer anpassen */
My_Connections [ Idx ] . wdatalen - = len ;
memmove ( My_Connections [ Idx ] . wbuf , My_Connections [ Idx ] . wbuf + len , My_Connections [ Idx ] . wdatalen ) ;
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
return TRUE ;
} /* Handle_Write */
2001-12-13 00:32:02 +01:00
2002-05-27 15:09:26 +02:00
LOCAL VOID
New_Connection ( INT Sock )
2001-12-13 00:32:02 +01:00
{
2001-12-23 23:02:54 +01:00
/* Neue Client-Verbindung von Listen-Socket annehmen und
* CLIENT - Struktur anlegen . */
2001-12-15 01:11:55 +01:00
2001-12-13 00:32:02 +01:00
struct sockaddr_in new_addr ;
2001-12-14 09:16:47 +01:00
INT new_sock , new_sock_len ;
2001-12-29 21:17:25 +01:00
RES_STAT * s ;
2001-12-14 09:16:47 +01:00
CONN_ID idx ;
2002-05-19 15:05:22 +02:00
CLIENT * c ;
2002-03-11 01:04:48 +01:00
2001-12-15 01:11:55 +01:00
assert ( Sock > = 0 ) ;
2001-12-12 18:18:38 +01:00
2001-12-13 00:32:02 +01:00
new_sock_len = sizeof ( new_addr ) ;
2001-12-13 03:04:16 +01:00
new_sock = accept ( Sock , ( struct sockaddr * ) & new_addr , ( socklen_t * ) & new_sock_len ) ;
2001-12-13 00:32:02 +01:00
if ( new_sock < 0 )
{
2001-12-24 02:32:33 +01:00
Log ( LOG_CRIT , " Can't accept connection: %s! " , strerror ( errno ) ) ;
2001-12-13 00:32:02 +01:00
return ;
}
2001-12-26 00:15:16 +01:00
2002-10-15 00:21:00 +02:00
/* Freie Connection-Struktur suchen */
2002-01-02 03:44:36 +01:00
for ( idx = 0 ; idx < MAX_CONNECTIONS ; idx + + ) if ( My_Connections [ idx ] . sock = = NONE ) break ;
2001-12-13 00:32:02 +01:00
if ( idx > = MAX_CONNECTIONS )
2001-12-12 18:18:38 +01:00
{
2001-12-15 01:11:55 +01:00
Log ( LOG_ALERT , " Can't accept connection: limit reached (%d)! " , MAX_CONNECTIONS ) ;
2001-12-13 00:32:02 +01:00
close ( new_sock ) ;
2001-12-12 18:18:38 +01:00
return ;
}
2001-12-26 00:15:16 +01:00
2001-12-23 23:02:54 +01:00
/* Client-Struktur initialisieren */
2002-05-19 15:05:22 +02:00
c = Client_NewLocal ( idx , inet_ntoa ( new_addr . sin_addr ) , CLIENT_UNKNOWN , FALSE ) ;
if ( ! c )
2001-12-23 23:02:54 +01:00
{
Log ( LOG_ALERT , " Can't accept connection: can't create client structure! " ) ;
close ( new_sock ) ;
return ;
}
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
/* Verbindung registrieren */
2001-12-29 21:17:25 +01:00
Init_Conn_Struct ( idx ) ;
2001-12-13 00:32:02 +01:00
My_Connections [ idx ] . sock = new_sock ;
My_Connections [ idx ] . addr = new_addr ;
/* Neuen Socket registrieren */
FD_SET ( new_sock , & My_Sockets ) ;
2002-05-27 15:09:26 +02:00
if ( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock ;
2001-12-12 18:18:38 +01:00
2002-01-04 02:36:40 +01:00
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 ) ;
2001-12-29 21:17:25 +01:00
/* Hostnamen ermitteln */
2002-05-27 15:09:26 +02:00
s = Resolve_Addr ( & new_addr ) ;
2001-12-29 21:17:25 +01:00
if ( s )
{
/* Sub-Prozess wurde asyncron gestartet */
2002-10-09 15:34:19 +02:00
Conn_WriteStr ( idx , " NOTICE AUTH :%sLooking up your hostname ... " , NOTICE_TXTPREFIX ) ;
2001-12-29 21:17:25 +01:00
My_Connections [ idx ] . res_stat = s ;
}
else
{
2002-05-19 15:05:22 +02:00
/* kann Namen nicht aufloesen, daher wird die IP-Adresse verwendet */
2001-12-29 21:17:25 +01:00
strcpy ( My_Connections [ idx ] . host , inet_ntoa ( new_addr . sin_addr ) ) ;
2002-05-19 15:05:22 +02:00
Client_SetHostname ( c , My_Connections [ idx ] . host ) ;
2001-12-29 21:17:25 +01:00
}
2002-08-26 02:03:15 +02:00
/* Penalty-Zeit setzen */
2002-10-10 17:01:12 +02:00
Conn_SetPenalty ( idx , 4 ) ;
2001-12-13 00:32:02 +01:00
} /* New_Connection */
2002-05-27 15:09:26 +02:00
LOCAL CONN_ID
Socket2Index ( INT Sock )
2001-12-13 00:32:02 +01:00
{
2001-12-15 01:11:55 +01:00
/* zum Socket passende Connection suchen */
2001-12-14 09:16:47 +01:00
CONN_ID idx ;
2001-12-26 00:15:16 +01:00
2001-12-15 01:11:55 +01:00
assert ( Sock > = 0 ) ;
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
for ( idx = 0 ; idx < MAX_CONNECTIONS ; idx + + ) if ( My_Connections [ idx ] . sock = = Sock ) break ;
2001-12-26 00:15:16 +01:00
2002-10-15 11:24:54 +02:00
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 ;
}
2002-10-15 00:21:00 +02:00
else return idx ;
2001-12-13 00:32:02 +01:00
} /* Socket2Index */
2002-05-27 15:09:26 +02:00
LOCAL VOID
Read_Request ( CONN_ID Idx )
2001-12-13 00:32:02 +01:00
{
2001-12-13 02:33:09 +01:00
/* Daten von Socket einlesen und entsprechend behandeln.
* Tritt ein Fehler auf , so wird der Socket geschlossen . */
2001-12-13 00:32:02 +01:00
2001-12-13 02:33:09 +01:00
INT len ;
2001-12-15 01:11:55 +01:00
assert ( Idx > = 0 ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2001-12-26 00:15:16 +01:00
2002-01-03 03:25:36 +01:00
if ( READBUFFER_LEN - My_Connections [ Idx ] . rdatalen - 2 < 0 )
{
/* Der Lesepuffer ist voll */
2002-01-06 16:18:14 +01:00
Log ( LOG_ERR , " Read buffer overflow (connection %d): %d bytes! " , Idx , My_Connections [ Idx ] . rdatalen ) ;
Conn_Close ( Idx , " Read buffer overflow! " , NULL , FALSE ) ;
2002-01-03 03:25:36 +01:00
return ;
}
len = recv ( My_Connections [ Idx ] . sock , My_Connections [ Idx ] . rbuf + My_Connections [ Idx ] . rdatalen , READBUFFER_LEN - My_Connections [ Idx ] . rdatalen - 2 , 0 ) ;
2001-12-13 02:33:09 +01:00
if ( len = = 0 )
{
/* Socket wurde geschlossen */
2001-12-21 23:24:25 +01:00
Log ( LOG_INFO , " %s:%d is closing the connection ... " , inet_ntoa ( My_Connections [ Idx ] . addr . sin_addr ) , ntohs ( My_Connections [ Idx ] . addr . sin_port ) ) ;
2002-03-05 00:16:23 +01:00
Conn_Close ( Idx , " Socket closed! " , " Client closed connection " , FALSE ) ;
2001-12-13 02:33:09 +01:00
return ;
}
if ( len < 0 )
2001-12-13 00:32:02 +01:00
{
2001-12-13 02:33:09 +01:00
/* Fehler beim Lesen */
2002-10-15 00:21:00 +02:00
Log ( LOG_ERR , " Read error on connection %d (socket %d): %s! " , Idx , My_Connections [ Idx ] . sock , strerror ( errno ) ) ;
2002-03-05 00:16:23 +01:00
Conn_Close ( Idx , " Read error! " , " Client closed connection " , FALSE ) ;
2001-12-13 00:32:02 +01:00
return ;
}
2001-12-14 09:16:47 +01:00
2002-10-09 15:15:08 +02:00
/* Connection-Statistik aktualisieren */
My_Connections [ Idx ] . bytes_in + = len ;
2001-12-26 04:20:53 +01:00
/* Lesebuffer updaten */
2001-12-15 01:11:55 +01:00
My_Connections [ Idx ] . rdatalen + = len ;
2002-01-03 03:25:36 +01:00
assert ( My_Connections [ Idx ] . rdatalen < READBUFFER_LEN ) ;
2001-12-15 01:11:55 +01:00
My_Connections [ Idx ] . rbuf [ My_Connections [ Idx ] . rdatalen ] = ' \0 ' ;
2001-12-12 18:18:38 +01:00
2001-12-26 04:20:53 +01:00
/* Timestamp aktualisieren */
My_Connections [ Idx ] . lastdata = time ( NULL ) ;
2001-12-26 00:15:16 +01:00
Handle_Buffer ( Idx ) ;
} /* Read_Request */
2002-05-27 15:09:26 +02:00
LOCAL VOID
Handle_Buffer ( CONN_ID Idx )
2001-12-26 00:15:16 +01:00
{
2001-12-29 23:33:36 +01:00
/* Daten im Lese-Puffer einer Verbindung verarbeiten. */
2002-10-21 15:45:07 +02:00
# ifndef STRICT_RFC
CHAR * ptr1 , * ptr2 ;
# endif
CHAR * ptr ;
2001-12-26 00:15:16 +01:00
INT len , delta ;
2002-03-11 01:04:48 +01:00
2001-12-15 01:11:55 +01:00
/* Eine komplette Anfrage muss mit CR+LF enden, vgl.
* RFC 2812. Haben wir eine ? */
ptr = strstr ( My_Connections [ Idx ] . rbuf , " \r \n " ) ;
2001-12-26 00:15:16 +01:00
if ( ptr ) delta = 2 ;
2002-01-03 03:25:36 +01:00
# ifndef STRICT_RFC
2001-12-26 00:15:16 +01:00
else
{
/* Nicht RFC-konforme Anfrage mit nur CR oder LF? Leider
* machen soetwas viele Clients , u . a . " mIRC " : - ( */
ptr1 = strchr ( My_Connections [ Idx ] . rbuf , ' \r ' ) ;
ptr2 = strchr ( My_Connections [ Idx ] . rbuf , ' \n ' ) ;
delta = 1 ;
if ( ptr1 & & ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1 ;
else if ( ptr1 ) ptr = ptr1 ;
else if ( ptr2 ) ptr = ptr2 ;
}
2002-01-03 03:25:36 +01:00
# endif
2002-03-11 01:04:48 +01:00
2001-12-15 01:11:55 +01:00
if ( ptr )
2001-12-13 02:33:09 +01:00
{
2001-12-26 00:15:16 +01:00
/* Ende der Anfrage wurde gefunden */
2001-12-15 01:11:55 +01:00
* ptr = ' \0 ' ;
2001-12-26 00:15:16 +01:00
len = ( ptr - My_Connections [ Idx ] . rbuf ) + delta ;
2002-05-27 15:09:26 +02:00
if ( len > ( COMMAND_LEN - 1 ) )
2002-01-03 03:25:36 +01:00
{
/* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
* ( incl . CR + LF ! ) werden ; vgl . RFC 2812. Wenn soetwas
* empfangen wird , wird der Client disconnectiert . */
2002-08-26 02:03:15 +02:00
Log ( LOG_ERR , " Request too long (connection %d): %d bytes (max. %d expected)! " , Idx , My_Connections [ Idx ] . rdatalen , COMMAND_LEN - 1 ) ;
2002-01-06 16:18:14 +01:00
Conn_Close ( Idx , NULL , " Request too long " , TRUE ) ;
2002-01-03 03:25:36 +01:00
return ;
}
2002-03-11 01:04:48 +01:00
2001-12-26 00:15:16 +01:00
if ( len > delta )
2001-12-13 02:33:09 +01:00
{
2001-12-21 23:24:25 +01:00
/* Es wurde ein Request gelesen */
if ( ! Parse_Request ( Idx , My_Connections [ Idx ] . rbuf ) ) return ;
2001-12-13 02:33:09 +01:00
}
2001-12-15 01:11:55 +01:00
/* Puffer anpassen */
My_Connections [ Idx ] . rdatalen - = len ;
memmove ( My_Connections [ Idx ] . rbuf , My_Connections [ Idx ] . rbuf + len , My_Connections [ Idx ] . rdatalen ) ;
2001-12-13 02:33:09 +01:00
}
2001-12-26 00:15:16 +01:00
} /* Handle_Buffer */
2001-12-13 02:33:09 +01:00
2002-05-27 15:09:26 +02:00
LOCAL VOID
Check_Connections ( VOID )
2001-12-26 04:20:53 +01:00
{
2001-12-29 23:33:36 +01:00
/* Pruefen, ob Verbindungen noch "alive" sind. Ist dies
* nicht der Fall , zunaechst PING - PONG spielen und , wenn
* auch das nicht " hilft " , Client disconnectieren . */
2001-12-26 04:20:53 +01:00
2002-01-02 03:44:36 +01:00
CLIENT * c ;
2001-12-26 04:20:53 +01:00
INT i ;
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
2002-01-02 03:44:36 +01:00
if ( My_Connections [ i ] . sock = = NONE ) continue ;
c = Client_GetFromConn ( i ) ;
2002-01-04 02:20:02 +01:00
if ( c & & ( ( Client_Type ( c ) = = CLIENT_USER ) | | ( Client_Type ( c ) = = CLIENT_SERVER ) | | ( Client_Type ( c ) = = CLIENT_SERVICE ) ) )
2001-12-26 04:20:53 +01:00
{
2002-01-02 03:44:36 +01:00
/* verbundener User, Server oder Service */
2001-12-26 04:20:53 +01:00
if ( My_Connections [ i ] . lastping > My_Connections [ i ] . lastdata )
{
/* es wurde bereits ein PING gesendet */
2001-12-26 15:45:37 +01:00
if ( My_Connections [ i ] . lastping < time ( NULL ) - Conf_PongTimeout )
2001-12-26 04:20:53 +01:00
{
/* Timeout */
2002-03-27 00:47:45 +01:00
Log ( LOG_DEBUG , " Connection %d: Ping timeout: %d seconds. " , i , Conf_PongTimeout ) ;
2002-01-06 16:18:14 +01:00
Conn_Close ( i , NULL , " Ping timeout " , TRUE ) ;
2001-12-26 04:20:53 +01:00
}
}
2001-12-26 15:45:37 +01:00
else if ( My_Connections [ i ] . lastdata < time ( NULL ) - Conf_PingTimeout )
2001-12-26 04:20:53 +01:00
{
/* es muss ein PING gesendet werden */
Log ( LOG_DEBUG , " Connection %d: sending PING ... " , i ) ;
My_Connections [ i ] . lastping = time ( NULL ) ;
2002-01-04 02:20:02 +01:00
Conn_WriteStr ( i , " PING :%s " , Client_ID ( Client_ThisServer ( ) ) ) ;
2001-12-26 04:20:53 +01:00
}
}
2002-01-02 03:44:36 +01:00
else
{
/* noch nicht vollstaendig aufgebaute Verbindung */
if ( My_Connections [ i ] . lastdata < time ( NULL ) - Conf_PingTimeout )
{
/* Timeout */
2002-02-27 15:47:04 +01:00
Log ( LOG_DEBUG , " Connection %d timed out ... " , i ) ;
2002-03-02 03:44:01 +01:00
Conn_Close ( i , NULL , " Timeout " , FALSE ) ;
2002-01-02 03:44:36 +01:00
}
}
}
} /* Check_Connections */
2002-05-27 15:09:26 +02:00
LOCAL VOID
Check_Servers ( VOID )
2002-01-02 03:44:36 +01:00
{
/* Pruefen, ob Server-Verbindungen aufgebaut werden
* muessen bzw . koennen */
INT idx , i , n ;
RES_STAT * s ;
2002-02-19 21:05:37 +01:00
/* Wenn "Passive-Mode" aktiv: nicht verbinden */
if ( NGIRCd_Passive ) return ;
2002-03-11 01:04:48 +01:00
2002-01-02 03:44:36 +01:00
for ( i = 0 ; i < Conf_Server_Count ; i + + )
{
/* Ist ein Hostname und Port definiert? */
if ( ( ! Conf_Server [ i ] . host [ 0 ] ) | | ( ! Conf_Server [ i ] . port > 0 ) ) continue ;
2002-03-11 01:04:48 +01:00
2002-01-02 03:44:36 +01:00
/* Haben wir schon eine Verbindung? */
for ( n = 0 ; n < MAX_CONNECTIONS ; n + + )
{
2002-03-13 00:42:59 +01:00
if ( My_Connections [ n ] . sock = = NONE ) continue ;
2002-03-10 18:50:48 +01:00
/* Verbindung zu diesem Server? */
2002-03-13 00:42:59 +01:00
if ( My_Connections [ n ] . our_server = = i )
2002-01-02 03:44:36 +01:00
{
/* Komplett aufgebaute Verbindung? */
if ( My_Connections [ n ] . sock > NONE ) break ;
/* IP schon aufgeloest? */
if ( My_Connections [ n ] . res_stat = = NULL ) New_Server ( i , n ) ;
}
2002-03-10 18:50:48 +01:00
/* Verbindung in dieser Server-Gruppe? */
2002-03-13 00:42:59 +01:00
if ( ( My_Connections [ n ] . our_server ! = NONE ) & & ( Conf_Server [ i ] . group ! = NONE ) )
2002-03-10 18:50:48 +01:00
{
2002-03-13 00:42:59 +01:00
if ( Conf_Server [ My_Connections [ n ] . our_server ] . group = = Conf_Server [ i ] . group ) break ;
2002-03-10 18:50:48 +01:00
}
2002-01-02 03:44:36 +01:00
}
if ( n < MAX_CONNECTIONS ) continue ;
2002-03-11 01:04:48 +01:00
2002-01-02 03:44:36 +01:00
/* Wann war der letzte Connect-Versuch? */
if ( Conf_Server [ i ] . lasttry > time ( NULL ) - Conf_ConnectRetry ) continue ;
/* Okay, Verbindungsaufbau versuchen */
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 )
{
Log ( LOG_ALERT , " Can't establist server connection: connection limit reached (%d)! " , MAX_CONNECTIONS ) ;
return ;
}
Log ( LOG_DEBUG , " Preparing connection %d for \" %s \" ... " , idx , Conf_Server [ i ] . host ) ;
/* Verbindungs-Struktur initialisieren */
Init_Conn_Struct ( idx ) ;
My_Connections [ idx ] . sock = SERVER_WAIT ;
My_Connections [ idx ] . our_server = i ;
2002-03-11 01:04:48 +01:00
2002-01-02 03:44:36 +01:00
/* Hostnamen in IP aufloesen */
2002-05-27 15:09:26 +02:00
s = Resolve_Name ( Conf_Server [ i ] . host ) ;
2002-01-02 03:44:36 +01:00
if ( s )
{
/* Sub-Prozess wurde asyncron gestartet */
My_Connections [ idx ] . res_stat = s ;
}
else
{
2002-05-19 15:05:22 +02:00
/* 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 ) ;
2002-01-02 03:44:36 +01:00
}
}
} /* Check_Servers */
2002-05-27 15:09:26 +02:00
LOCAL VOID
New_Server ( INT Server , CONN_ID Idx )
2002-01-02 03:44:36 +01:00
{
/* Neue Server-Verbindung aufbauen */
struct sockaddr_in new_addr ;
struct in_addr inaddr ;
INT new_sock ;
2002-01-03 03:25:36 +01:00
CLIENT * c ;
2002-01-02 03:44:36 +01:00
assert ( Server > = 0 ) ;
assert ( Idx > = 0 ) ;
/* Wurde eine gueltige IP-Adresse gefunden? */
if ( ! Conf_Server [ Server ] . ip [ 0 ] )
{
/* Nein. Verbindung wieder freigeben: */
Init_Conn_Struct ( Idx ) ;
Log ( LOG_ERR , " Can't connect to \" %s \" (connection %d): ip address unknown! " , Conf_Server [ Server ] . host , Idx ) ;
return ;
}
2002-03-11 01:04:48 +01:00
2002-02-19 21:34:31 +01:00
Log ( LOG_INFO , " Establishing connection to \" %s \" , %s, port %d (connection %d) ... " , Conf_Server [ Server ] . host , Conf_Server [ Server ] . ip , Conf_Server [ Server ] . port , Idx ) ;
2002-01-02 03:44:36 +01:00
2002-05-19 12:44:02 +02:00
# ifdef HAVE_INET_ATON
2002-01-02 03:44:36 +01:00
if ( inet_aton ( Conf_Server [ Server ] . ip , & inaddr ) = = 0 )
2002-05-19 12:44:02 +02:00
# else
memset ( & inaddr , 0 , sizeof ( inaddr ) ) ;
inaddr . s_addr = inet_addr ( Conf_Server [ Server ] . ip ) ;
if ( inaddr . s_addr = = ( unsigned ) - 1 )
# endif
2002-01-02 03:44:36 +01:00
{
/* Konnte Adresse nicht konvertieren */
Init_Conn_Struct ( Idx ) ;
Log ( LOG_ERR , " Can't connect to \" %s \" (connection %d): can't convert ip address %s! " , Conf_Server [ Server ] . host , Idx , Conf_Server [ Server ] . ip ) ;
return ;
}
memset ( & new_addr , 0 , sizeof ( new_addr ) ) ;
new_addr . sin_family = AF_INET ;
new_addr . sin_addr = inaddr ;
new_addr . sin_port = htons ( Conf_Server [ Server ] . port ) ;
new_sock = socket ( PF_INET , SOCK_STREAM , 0 ) ;
if ( new_sock < 0 )
{
Init_Conn_Struct ( Idx ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't create socket: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
return ;
2001-12-26 04:20:53 +01:00
}
2002-03-02 01:23:32 +01:00
if ( ! Init_Socket ( new_sock ) ) return ;
connect ( new_sock , ( struct sockaddr * ) & new_addr , sizeof ( new_addr ) ) ;
if ( errno ! = EINPROGRESS )
2002-01-02 03:44:36 +01:00
{
2002-03-11 01:04:48 +01:00
2002-01-02 03:44:36 +01:00
close ( new_sock ) ;
Init_Conn_Struct ( Idx ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't connect socket: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
return ;
}
/* Client-Struktur initialisieren */
2002-01-06 00:25:25 +01:00
c = Client_NewLocal ( Idx , inet_ntoa ( new_addr . sin_addr ) , CLIENT_UNKNOWNSERVER , FALSE ) ;
2002-01-03 03:25:36 +01:00
if ( ! c )
2002-01-02 03:44:36 +01:00
{
close ( new_sock ) ;
Init_Conn_Struct ( Idx ) ;
Log ( LOG_ALERT , " Can't establish connection: can't create client structure! " ) ;
return ;
}
2002-01-04 02:20:02 +01:00
Client_SetIntroducer ( c , c ) ;
2002-04-08 03:17:54 +02:00
Client_SetToken ( c , TOKEN_OUTBOUND ) ;
2002-03-02 01:23:32 +01:00
2002-01-02 03:44:36 +01:00
/* Verbindung registrieren */
My_Connections [ Idx ] . sock = new_sock ;
My_Connections [ Idx ] . addr = new_addr ;
strcpy ( My_Connections [ Idx ] . host , Conf_Server [ Server ] . host ) ;
/* Neuen Socket registrieren */
FD_SET ( new_sock , & My_Sockets ) ;
2002-03-02 01:23:32 +01:00
FD_SET ( new_sock , & My_Connects ) ;
2002-05-27 15:09:26 +02:00
if ( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock ;
2002-10-15 11:24:54 +02:00
Log ( LOG_DEBUG , " Registered new connection %d on socket %d. " , Idx , My_Connections [ Idx ] . sock ) ;
2002-01-02 03:44:36 +01:00
} /* New_Server */
2001-12-26 04:20:53 +01:00
2002-05-27 15:09:26 +02:00
LOCAL VOID
Init_Conn_Struct ( INT Idx )
2001-12-29 21:17:25 +01:00
{
/* Connection-Struktur initialisieren */
My_Connections [ Idx ] . sock = NONE ;
My_Connections [ Idx ] . res_stat = NULL ;
My_Connections [ Idx ] . host [ 0 ] = ' \0 ' ;
My_Connections [ Idx ] . rbuf [ 0 ] = ' \0 ' ;
My_Connections [ Idx ] . rdatalen = 0 ;
My_Connections [ Idx ] . wbuf [ 0 ] = ' \0 ' ;
My_Connections [ Idx ] . wdatalen = 0 ;
2002-03-10 18:50:48 +01:00
My_Connections [ Idx ] . our_server = NONE ;
2001-12-29 21:17:25 +01:00
My_Connections [ Idx ] . lastdata = time ( NULL ) ;
My_Connections [ Idx ] . lastping = 0 ;
2001-12-31 03:18:51 +01:00
My_Connections [ Idx ] . lastprivmsg = time ( NULL ) ;
2002-08-26 02:03:15 +02:00
My_Connections [ Idx ] . delaytime = 0 ;
2002-10-09 15:15:08 +02:00
My_Connections [ Idx ] . bytes_in = 0 ;
My_Connections [ Idx ] . bytes_out = 0 ;
2001-12-29 21:17:25 +01:00
} /* Init_Conn_Struct */
2002-05-27 15:09:26 +02:00
LOCAL BOOLEAN
Init_Socket ( INT Sock )
2002-03-02 01:23:32 +01:00
{
/* Socket-Optionen setzen */
INT on = 1 ;
2002-03-13 01:15:55 +01:00
# ifdef O_NONBLOCK /* A/UX kennt das nicht? */
2002-03-02 01:23:32 +01:00
if ( fcntl ( Sock , F_SETFL , O_NONBLOCK ) ! = 0 )
{
Log ( LOG_CRIT , " Can't enable non-blocking mode: %s! " , strerror ( errno ) ) ;
close ( Sock ) ;
return FALSE ;
}
2002-03-13 01:15:55 +01:00
# endif
2002-03-02 01:23:32 +01:00
if ( setsockopt ( Sock , SOL_SOCKET , SO_REUSEADDR , & on , ( socklen_t ) sizeof ( on ) ) ! = 0 )
{
Log ( LOG_ERR , " Can't set socket options: %s! " , strerror ( errno ) ) ;
/* dieser Fehler kann ignoriert werden. */
}
return TRUE ;
} /* Init_Socket */
2002-05-27 15:09:26 +02:00
LOCAL VOID
Read_Resolver_Result ( INT r_fd )
2001-12-29 21:17:25 +01:00
{
/* Ergebnis von Resolver Sub-Prozess aus Pipe lesen
2002-05-27 15:09:26 +02:00
* und entsprechende Connection aktualisieren */
2001-12-29 21:17:25 +01:00
2002-01-02 03:44:36 +01:00
CHAR result [ HOST_LEN ] ;
2001-12-29 21:17:25 +01:00
CLIENT * c ;
2002-01-02 03:44:36 +01:00
INT len , i ;
2001-12-29 21:17:25 +01:00
2002-05-27 15:09:26 +02:00
FD_CLR ( r_fd , & Resolver_FDs ) ;
2001-12-29 21:17:25 +01:00
/* Anfrage vom Parent lesen */
2002-10-03 23:03:11 +02:00
len = read ( r_fd , result , HOST_LEN - 1 ) ;
2002-01-02 03:44:36 +01:00
if ( len < 0 )
2001-12-29 21:17:25 +01:00
{
/* Fehler beim Lesen aus der Pipe */
close ( r_fd ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Resolver: Can't read result: %s! " , strerror ( errno ) ) ;
2001-12-29 21:17:25 +01:00
return ;
}
2002-01-02 03:44:36 +01:00
result [ len ] = ' \0 ' ;
2001-12-29 21:17:25 +01:00
2001-12-29 23:33:36 +01:00
/* zugehoerige Connection suchen */
2001-12-29 21:17:25 +01:00
for ( i = 0 ; i < MAX_CONNECTIONS ; i + + )
{
2002-01-02 03:44:36 +01:00
if ( ( My_Connections [ i ] . sock ! = NONE ) & & ( My_Connections [ i ] . res_stat ) & & ( My_Connections [ i ] . res_stat - > pipe [ 0 ] = = r_fd ) ) break ;
2001-12-29 21:17:25 +01:00
}
if ( i > = MAX_CONNECTIONS )
{
2002-01-02 03:44:36 +01:00
/* Opsa! Keine passende Connection gefunden!? Vermutlich
2002-10-15 11:24:54 +02:00
* wurde sie schon wieder geschlossen . */
2001-12-29 21:17:25 +01:00
close ( r_fd ) ;
2002-01-02 03:44:36 +01:00
Log ( LOG_DEBUG , " Resolver: Got result for unknown connection!? " ) ;
2001-12-29 21:17:25 +01:00
return ;
}
/* Aufraeumen */
2001-12-29 22:53:57 +01:00
close ( My_Connections [ i ] . res_stat - > pipe [ 0 ] ) ;
close ( My_Connections [ i ] . res_stat - > pipe [ 1 ] ) ;
2001-12-29 21:17:25 +01:00
free ( My_Connections [ i ] . res_stat ) ;
My_Connections [ i ] . res_stat = NULL ;
2002-01-02 03:44:36 +01:00
if ( My_Connections [ i ] . sock > NONE )
{
/* Eingehende Verbindung: Hostnamen setzen */
c = Client_GetFromConn ( i ) ;
2002-01-03 03:25:36 +01:00
assert ( c ! = NULL ) ;
strcpy ( My_Connections [ i ] . host , result ) ;
Client_SetHostname ( c , result ) ;
2002-10-09 15:34:19 +02:00
Conn_WriteStr ( i , " NOTICE AUTH :%sGot your hostname. " , NOTICE_TXTPREFIX ) ;
2002-01-02 03:44:36 +01:00
}
2001-12-29 21:17:25 +01:00
else
{
2002-01-02 03:44:36 +01:00
/* Ausgehende Verbindung (=Server): IP setzen */
assert ( My_Connections [ i ] . our_server > = 0 ) ;
strcpy ( Conf_Server [ My_Connections [ i ] . our_server ] . ip , result ) ;
2001-12-29 21:17:25 +01:00
}
2002-10-10 17:01:12 +02:00
/* Penalty-Zeit zurueck setzen */
Conn_ResetPenalty ( i ) ;
2002-01-02 03:44:36 +01:00
} /* Read_Resolver_Result */
2001-12-29 21:17:25 +01:00
2002-01-02 03:44:36 +01:00
2001-12-12 18:18:38 +01:00
/* -eof- */