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-03-13 01:15:55 +01:00
* $ Id : conn . c , v 1.55 2002 / 03 / 13 00 : 15 : 55 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>
2001-12-29 21:17:25 +01:00
# include <netdb.h>
2001-12-12 18:18:38 +01:00
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
2001-12-13 00:32:02 +01:00
# include "ngircd.h"
2001-12-23 23:02:54 +01:00
# include "client.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
# include "conn.h"
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 */
2001-12-13 00:32:02 +01:00
} CONNECTION ;
2001-12-15 01:11:55 +01:00
LOCAL VOID Handle_Read ( INT sock ) ;
LOCAL BOOLEAN Handle_Write ( CONN_ID Idx ) ;
2001-12-13 00:32:02 +01:00
LOCAL VOID New_Connection ( INT Sock ) ;
2001-12-14 09:16:47 +01:00
LOCAL CONN_ID Socket2Index ( INT Sock ) ;
LOCAL VOID Read_Request ( CONN_ID Idx ) ;
2001-12-15 01:11:55 +01:00
LOCAL BOOLEAN Try_Write ( CONN_ID Idx ) ;
2001-12-26 00:15:16 +01:00
LOCAL VOID Handle_Buffer ( CONN_ID Idx ) ;
2001-12-26 04:20:53 +01:00
LOCAL VOID Check_Connections ( VOID ) ;
2002-01-02 03:44:36 +01:00
LOCAL VOID Check_Servers ( VOID ) ;
2001-12-29 21:17:25 +01:00
LOCAL VOID Init_Conn_Struct ( INT Idx ) ;
2002-03-02 01:23:32 +01:00
LOCAL BOOLEAN Init_Socket ( INT Sock ) ;
2002-01-02 03:44:36 +01:00
LOCAL VOID New_Server ( INT Server , CONN_ID Idx ) ;
2001-12-29 21:17:25 +01:00
2002-01-02 03:44:36 +01:00
LOCAL RES_STAT * ResolveAddr ( struct sockaddr_in * Addr ) ;
LOCAL RES_STAT * ResolveName ( CHAR * Host ) ;
LOCAL VOID Do_ResolveAddr ( struct sockaddr_in * Addr , INT w_fd ) ;
LOCAL VOID Do_ResolveName ( CHAR * Host , INT w_fd ) ;
2001-12-29 21:17:25 +01:00
LOCAL VOID Read_Resolver_Result ( INT r_fd ) ;
2002-01-02 03:44:36 +01:00
LOCAL CHAR * Resolv_Error ( INT H_Error ) ;
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 ;
2001-12-29 21:17:25 +01:00
LOCAL fd_set My_Resolvers ;
2002-03-02 01:23:32 +01:00
LOCAL fd_set My_Connects ;
2001-12-13 00:32:02 +01:00
LOCAL INT My_Max_Fd ;
LOCAL CONNECTION My_Connections [ MAX_CONNECTIONS ] ;
2001-12-12 18:18:38 +01:00
GLOBAL VOID Conn_Init ( VOID )
{
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 ) ;
2001-12-29 21:17:25 +01:00
FD_ZERO ( & My_Resolvers ) ;
2002-03-02 01:23:32 +01:00
FD_ZERO ( & My_Connects ) ;
2001-12-26 00:15:16 +01:00
2001-12-13 00:32:02 +01:00
My_Max_Fd = 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 */
GLOBAL VOID Conn_Exit ( VOID )
{
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 ... " ) ;
2001-12-13 00:32:02 +01:00
for ( i = 0 ; i < My_Max_Fd + 1 ; i + + )
{
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 ) ;
}
else if ( idx < MAX_CONNECTIONS ) 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 */
2001-12-26 15:45:37 +01:00
GLOBAL BOOLEAN Conn_NewListener ( CONST INT 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
2001-12-13 00:32:02 +01:00
if ( sock > My_Max_Fd ) My_Max_Fd = sock ;
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
2001-12-13 02:33:09 +01:00
GLOBAL VOID Conn_Handler ( INT Timeout )
2001-12-12 18:18:38 +01:00
{
2001-12-29 23:33:36 +01:00
/* Aktive Verbindungen ueberwachen. Mindestens alle "Timeout"
* Sekunden wird die Funktion verlassen . Folgende Aktionen
* werden durchgefuehrt :
* - 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 ;
2001-12-26 00:15:16 +01:00
time_t start ;
2001-12-13 00:32:02 +01:00
INT i ;
2001-12-13 02:33:09 +01:00
2001-12-26 00:15:16 +01:00
start = time ( NULL ) ;
2001-12-26 04:20:53 +01:00
while ( ( time ( NULL ) - start < Timeout ) & & ( ! NGIRCd_Quit ) )
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 ( ) ;
/* Timeout initialisieren */
2002-03-02 04:32:08 +01:00
tv . tv_sec = 0 ;
tv . tv_usec = 50000 ;
2001-12-26 04:20:53 +01:00
/* 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? */
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 ) ;
}
2001-12-29 21:17:25 +01:00
}
for ( i = 0 ; i < My_Max_Fd + 1 ; i + + )
{
/* Pipes von Resolver Sub-Prozessen aufnehmen */
if ( FD_ISSET ( i , & My_Resolvers ) )
{
FD_SET ( i , & read_sockets ) ;
}
}
/* Auf Aktivitaet warten */
2001-12-26 00:15:16 +01:00
if ( select ( My_Max_Fd + 1 , & read_sockets , & write_sockets , NULL , & tv ) = = - 1 )
{
2002-01-05 20:15:03 +01:00
if ( errno ! = EINTR )
{
2002-01-06 16:18:14 +01:00
Log ( LOG_EMERG , " select(): %s! " , strerror ( errno ) ) ;
2002-01-05 20:15:03 +01:00
Log ( LOG_ALERT , PACKAGE " exiting due to fatal errors! " ) ;
exit ( 1 ) ;
}
continue ;
2001-12-26 00:15:16 +01:00
}
/* Koennen Daten geschrieben werden? */
for ( i = 0 ; i < My_Max_Fd + 1 ; i + + )
{
if ( FD_ISSET ( i , & write_sockets ) ) Handle_Write ( Socket2Index ( i ) ) ;
}
/* Daten zum Lesen vorhanden? */
for ( i = 0 ; i < My_Max_Fd + 1 ; i + + )
{
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 */
2001-12-23 23:02:54 +01:00
GLOBAL BOOLEAN Conn_WriteStr ( CONN_ID Idx , CHAR * Format , . . . )
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 ;
va_start ( ap , Format ) ;
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 */
GLOBAL BOOLEAN Conn_Write ( CONN_ID Idx , CHAR * Data , INT Len )
{
/* 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 ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2001-12-15 01:11:55 +01:00
assert ( Data ! = NULL ) ;
assert ( Len > 0 ) ;
/* 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-01-06 16:18:14 +01: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-01-06 16:18:14 +01:00
if ( InformClient )
2002-01-02 03:44:36 +01:00
{
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 )
{
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 ) ) ;
}
else
{
2002-01-04 02:36:40 +01:00
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 ) ) ;
2001-12-25 23:03:47 +01:00
}
2002-01-02 03:44:36 +01:00
c = Client_GetFromConn ( Idx ) ;
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 */
2001-12-29 22:53:57 +01:00
FD_CLR ( My_Connections [ Idx ] . res_stat - > pipe [ 0 ] , & My_Resolvers ) ;
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-03-02 01:43:31 +01:00
/* Bei Server-Verbindungen lasttry-Zeitpunkt so setzen, dass
* der naechste Verbindungsversuch in RECONNECT_DELAY Sekunden
2002-03-11 01:04:48 +01:00
* gestartet wird . */
if ( ( My_Connections [ Idx ] . our_server > = 0 ) & & ( Conf_Server [ My_Connections [ Idx ] . our_server ] . lasttry < time ( NULL ) ) )
{
/* Okay, die Verbindung stand schon "genuegend lange" */
Conf_Server [ My_Connections [ Idx ] . our_server ] . lasttry = time ( NULL ) - Conf_ConnectRetry + RECONNECT_DELAY ;
}
2002-01-02 03:44:36 +01:00
2001-12-25 23:03:47 +01:00
FD_CLR ( My_Connections [ Idx ] . sock , & My_Sockets ) ;
2002-03-02 03:44:01 +01:00
FD_CLR ( My_Connections [ Idx ] . sock , & My_Connects ) ;
2001-12-25 23:03:47 +01:00
My_Connections [ Idx ] . sock = NONE ;
} /* Conn_Close */
2001-12-31 03:18:51 +01:00
GLOBAL VOID Conn_UpdateIdle ( CONN_ID Idx )
{
/* Idle-Timer zuruecksetzen */
assert ( Idx > = 0 ) ;
My_Connections [ Idx ] . lastprivmsg = time ( NULL ) ;
}
2002-02-23 01:03:54 +01: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-02-23 01:03:54 +01: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 */
2001-12-15 01:11:55 +01:00
LOCAL BOOLEAN Try_Write ( CONN_ID Idx )
{
/* 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-01-06 16:18:14 +01:00
Log ( LOG_ALERT , " select() failed: %s! " , strerror ( errno ) ) ;
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 */
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 ) ;
}
2001-12-29 21:17:25 +01:00
else if ( FD_ISSET ( Sock , & My_Resolvers ) )
{
/* 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 ) ;
2001-12-13 02:33:09 +01:00
Read_Request ( idx ) ;
2001-12-13 00:32:02 +01:00
}
2001-12-15 01:11:55 +01:00
} /* Handle_Read */
LOCAL BOOLEAN Handle_Write ( CONN_ID Idx )
{
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
assert ( Idx > = 0 ) ;
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 */
Conn_WriteStr ( Idx , " PASS %s " PASSSERVERADD , Conf_Server [ My_Connections [ Idx ] . our_server ] . pwd ) ;
Conn_WriteStr ( Idx , " SERVER %s :%s " , Conf_ServerName , Conf_ServerInfo ) ;
return TRUE ;
}
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-01-06 16:18:14 +01:00
Log ( LOG_ERR , " Write error (buffer) on connection %d: %s! " , Idx , strerror ( errno ) ) ;
Conn_Close ( Idx , " Write error (buffer)! " , NULL , FALSE ) ;
2001-12-15 01:11:55 +01:00
return FALSE ;
}
2001-12-26 00:15:16 +01:00
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
LOCAL VOID New_Connection ( INT Sock )
{
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-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
2001-12-13 00:32:02 +01:00
/* Freie Connection-Struktur suschen */
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-01-06 00:25:25 +01:00
if ( ! Client_NewLocal ( idx , inet_ntoa ( new_addr . sin_addr ) , CLIENT_UNKNOWN , FALSE ) )
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 ) ;
if ( new_sock > My_Max_Fd ) My_Max_Fd = 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-01-02 03:44:36 +01:00
s = ResolveAddr ( & new_addr ) ;
2001-12-29 21:17:25 +01:00
if ( s )
{
/* Sub-Prozess wurde asyncron gestartet */
My_Connections [ idx ] . res_stat = s ;
}
else
{
/* kann Namen nicht aufloesen */
strcpy ( My_Connections [ idx ] . host , inet_ntoa ( new_addr . sin_addr ) ) ;
}
2001-12-13 00:32:02 +01:00
} /* New_Connection */
2001-12-14 09:16:47 +01: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
2001-12-15 01:11:55 +01:00
assert ( idx < MAX_CONNECTIONS ) ;
2001-12-13 00:32:02 +01:00
return idx ;
} /* Socket2Index */
2001-12-14 09:16:47 +01: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-01-06 16:18:14 +01:00
Log ( LOG_ERR , " Read error on connection %d: %s! " , Idx , 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
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 */
LOCAL VOID Handle_Buffer ( CONN_ID Idx )
{
2001-12-29 23:33:36 +01:00
/* Daten im Lese-Puffer einer Verbindung verarbeiten. */
2001-12-26 00:15:16 +01:00
CHAR * ptr , * ptr1 , * ptr2 ;
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-01-03 03:25:36 +01:00
if ( len > COMMAND_LEN )
{
/* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
* ( incl . CR + LF ! ) werden ; vgl . RFC 2812. Wenn soetwas
* empfangen wird , wird der Client disconnectiert . */
2002-01-06 16:18:14 +01:00
Log ( LOG_ERR , " Request too long (connection %d): %d bytes! " , Idx , My_Connections [ Idx ] . rdatalen ) ;
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
2001-12-26 04:20:53 +01:00
LOCAL VOID Check_Connections ( VOID )
{
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-01-06 16:18:14 +01:00
Log ( LOG_DEBUG , " Connection %d: Ping timeout. " , i ) ;
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 */
LOCAL VOID Check_Servers ( VOID )
{
/* 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 */
s = ResolveName ( Conf_Server [ i ] . host ) ;
if ( s )
{
/* Sub-Prozess wurde asyncron gestartet */
My_Connections [ idx ] . res_stat = s ;
}
else
{
/* kann Namen nicht aufloesen: Connection-Struktur freigeben */
Init_Conn_Struct ( idx ) ;
}
}
} /* Check_Servers */
LOCAL VOID New_Server ( INT Server , CONN_ID Idx )
{
/* 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
if ( inet_aton ( Conf_Server [ Server ] . ip , & inaddr ) = = 0 )
{
/* 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-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-01-02 03:44:36 +01:00
if ( new_sock > My_Max_Fd ) My_Max_Fd = new_sock ;
} /* New_Server */
2001-12-26 04:20:53 +01:00
2001-12-29 21:17:25 +01:00
LOCAL VOID Init_Conn_Struct ( INT Idx )
{
/* 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 ) ;
2001-12-29 21:17:25 +01:00
} /* Init_Conn_Struct */
2002-03-02 01:23:32 +01:00
LOCAL BOOLEAN Init_Socket ( INT Sock )
{
/* 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-01-02 03:44:36 +01:00
LOCAL RES_STAT * ResolveAddr ( struct sockaddr_in * Addr )
2001-12-29 21:17:25 +01:00
{
2002-01-02 03:44:36 +01:00
/* IP (asyncron!) aufloesen. Bei Fehler, z.B. wenn der
2001-12-29 21:17:25 +01:00
* Child - Prozess nicht erzeugt werden kann , wird NULL geliefert .
* Der Host kann dann nicht aufgeloest werden . */
RES_STAT * s ;
INT pid ;
2001-12-29 23:33:36 +01:00
/* Speicher anfordern */
2001-12-29 21:17:25 +01:00
s = malloc ( sizeof ( RES_STAT ) ) ;
if ( ! s )
{
2002-01-06 16:18:14 +01:00
Log ( LOG_EMERG , " Resolver: Can't allocate memory! " ) ;
2001-12-29 21:17:25 +01:00
return NULL ;
}
2001-12-29 23:33:36 +01:00
/* Pipe fuer Antwort initialisieren */
2001-12-29 22:53:57 +01:00
if ( pipe ( s - > pipe ) ! = 0 )
2001-12-29 21:17:25 +01:00
{
free ( s ) ;
Log ( LOG_ALERT , " Resolver: Can't create output pipe: %s! " , strerror ( errno ) ) ;
return NULL ;
}
2001-12-29 23:33:36 +01:00
/* Sub-Prozess erzeugen */
2001-12-29 21:17:25 +01:00
pid = fork ( ) ;
if ( pid > 0 )
{
/* Haupt-Prozess */
2001-12-29 23:33:36 +01:00
Log ( LOG_DEBUG , " Resolver for %s created (PID %d). " , inet_ntoa ( Addr - > sin_addr ) , pid ) ;
2001-12-29 22:53:57 +01:00
FD_SET ( s - > pipe [ 0 ] , & My_Resolvers ) ;
if ( s - > pipe [ 0 ] > My_Max_Fd ) My_Max_Fd = s - > pipe [ 0 ] ;
2001-12-29 21:17:25 +01:00
s - > pid = pid ;
return s ;
}
else if ( pid = = 0 )
{
/* Sub-Prozess */
Log_Init_Resolver ( ) ;
2002-01-02 03:44:36 +01:00
Do_ResolveAddr ( Addr , s - > pipe [ 1 ] ) ;
Log_Exit_Resolver ( ) ;
exit ( 0 ) ;
}
else
{
/* Fehler */
free ( s ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Resolver: Can't fork: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
return NULL ;
}
} /* ResolveAddr */
LOCAL RES_STAT * ResolveName ( CHAR * Host )
{
/* Hostnamen (asyncron!) aufloesen. Bei Fehler, z.B. wenn der
* Child - Prozess nicht erzeugt werden kann , wird NULL geliefert .
* Der Host kann dann nicht aufgeloest werden . */
RES_STAT * s ;
INT pid ;
/* Speicher anfordern */
s = malloc ( sizeof ( RES_STAT ) ) ;
if ( ! s )
{
2002-01-06 16:18:14 +01:00
Log ( LOG_EMERG , " Resolver: Can't allocate memory! " ) ;
2002-01-02 03:44:36 +01:00
return NULL ;
}
/* Pipe fuer Antwort initialisieren */
if ( pipe ( s - > pipe ) ! = 0 )
{
free ( s ) ;
Log ( LOG_ALERT , " Resolver: Can't create output pipe: %s! " , strerror ( errno ) ) ;
return NULL ;
}
/* Sub-Prozess erzeugen */
pid = fork ( ) ;
if ( pid > 0 )
{
/* Haupt-Prozess */
Log ( LOG_DEBUG , " Resolver for \" %s \" created (PID %d). " , Host , pid ) ;
FD_SET ( s - > pipe [ 0 ] , & My_Resolvers ) ;
if ( s - > pipe [ 0 ] > My_Max_Fd ) My_Max_Fd = s - > pipe [ 0 ] ;
s - > pid = pid ;
return s ;
}
else if ( pid = = 0 )
{
/* Sub-Prozess */
Log_Init_Resolver ( ) ;
Do_ResolveName ( Host , s - > pipe [ 1 ] ) ;
2001-12-29 21:17:25 +01:00
Log_Exit_Resolver ( ) ;
exit ( 0 ) ;
}
else
{
/* Fehler */
free ( s ) ;
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Resolver: Can't fork: %s! " , strerror ( errno ) ) ;
2001-12-29 21:17:25 +01:00
return NULL ;
}
2002-01-02 03:44:36 +01:00
} /* ResolveName */
LOCAL VOID Do_ResolveAddr ( struct sockaddr_in * Addr , INT w_fd )
{
/* Resolver Sub-Prozess: IP aufloesen und Ergebnis in Pipe schreiben. */
CHAR hostname [ HOST_LEN ] ;
struct hostent * h ;
Log_Resolver ( LOG_DEBUG , " Now resolving %s ... " , inet_ntoa ( Addr - > sin_addr ) ) ;
/* Namen aufloesen */
h = gethostbyaddr ( ( CHAR * ) & Addr - > sin_addr , sizeof ( Addr - > sin_addr ) , AF_INET ) ;
if ( h ) strcpy ( hostname , h - > h_name ) ;
else
{
Log_Resolver ( LOG_WARNING , " Can't resolve address %s: code %s! " , inet_ntoa ( Addr - > sin_addr ) , Resolv_Error ( h_errno ) ) ;
strcpy ( hostname , inet_ntoa ( Addr - > sin_addr ) ) ;
}
/* Antwort an Parent schreiben */
if ( write ( w_fd , hostname , strlen ( hostname ) + 1 ) ! = ( strlen ( hostname ) + 1 ) )
{
2002-01-06 16:18:14 +01:00
Log_Resolver ( LOG_CRIT , " Resolver: Can't write to parent: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
close ( w_fd ) ;
return ;
}
Log_Resolver ( LOG_DEBUG , " Ok, translated %s to \" %s \" . " , inet_ntoa ( Addr - > sin_addr ) , hostname ) ;
} /* Do_ResolveAddr */
LOCAL VOID Do_ResolveName ( CHAR * Host , INT w_fd )
{
/* Resolver Sub-Prozess: Name aufloesen und Ergebnis in Pipe schreiben. */
CHAR ip [ 16 ] ;
struct hostent * h ;
struct in_addr * addr ;
Log_Resolver ( LOG_DEBUG , " Now resolving \" %s \" ... " , Host ) ;
/* Namen aufloesen */
h = gethostbyname ( Host ) ;
if ( h )
{
addr = ( struct in_addr * ) h - > h_addr ;
strcpy ( ip , inet_ntoa ( * addr ) ) ;
}
else
{
Log_Resolver ( LOG_WARNING , " Can't resolve \" %s \" : %s! " , Host , Resolv_Error ( h_errno ) ) ;
strcpy ( ip , " " ) ;
}
/* Antwort an Parent schreiben */
if ( write ( w_fd , ip , strlen ( ip ) + 1 ) ! = ( strlen ( ip ) + 1 ) )
{
2002-01-06 16:18:14 +01:00
Log_Resolver ( LOG_CRIT , " Resolver: Can't write to parent: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
close ( w_fd ) ;
return ;
}
if ( ip [ 0 ] ) Log_Resolver ( LOG_DEBUG , " Ok, translated \" %s \" to %s. " , Host , ip ) ;
} /* Do_ResolveName */
2001-12-29 21:17:25 +01:00
LOCAL VOID Read_Resolver_Result ( INT r_fd )
{
/* Ergebnis von Resolver Sub-Prozess aus Pipe lesen
2002-01-02 03:44:36 +01: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
FD_CLR ( r_fd , & My_Resolvers ) ;
/* Anfrage vom Parent lesen */
2002-01-02 03:44:36 +01:00
len = read ( r_fd , result , HOST_LEN ) ;
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
* 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-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-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
LOCAL CHAR * Resolv_Error ( INT H_Error )
{
/* Fehlerbeschreibung fuer H_Error liefern */
switch ( H_Error )
2001-12-29 21:17:25 +01:00
{
2002-01-02 03:44:36 +01:00
case HOST_NOT_FOUND :
return " host not found " ;
2002-01-05 16:56:23 +01:00
case NO_DATA :
2002-01-02 03:44:36 +01:00
return " name valid but no IP address defined " ;
case NO_RECOVERY :
return " name server error " ;
case TRY_AGAIN :
return " name server temporary not available " ;
default :
return " unknown error " ;
2001-12-29 21:17:25 +01:00
}
2002-01-02 03:44:36 +01:00
} /* Resolv_Error */
2001-12-29 21:17:25 +01:00
2001-12-12 18:18:38 +01:00
/* -eof- */