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
*
2002-12-12 13:24:18 +01:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
* Please read the file COPYING , README and AUTHORS for more information .
2001-12-12 18:18:38 +01:00
*
2002-12-12 13:24:18 +01:00
* Connection management
2001-12-12 18:18:38 +01:00
*/
2002-03-12 15:37:51 +01:00
# include "portab.h"
2001-12-12 18:18:38 +01:00
2002-12-19 05:35:26 +01:00
static char UNUSED id [ ] = " $Id: conn.c,v 1.107 2002/12/19 04:35:26 alex Exp $ " ;
2002-12-12 13:24:18 +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-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
# include <zlib.h>
# 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
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
typedef struct _ZipData
{
z_stream in ; /* "Handle" fuer Input-Stream */
z_stream out ; /* "Handle" fuer Output-Stream */
CHAR rbuf [ READBUFFER_LEN ] ; /* Lesepuffer */
INT rdatalen ; /* Laenge der Daten im Lesepuffer (komprimiert) */
CHAR wbuf [ WRITEBUFFER_LEN ] ; /* Schreibpuffer */
INT wdatalen ; /* Laenge der Daten im Schreibpuffer (unkomprimiert) */
LONG bytes_in , bytes_out ; /* Counter fuer Statistik (unkomprimiert!) */
} ZIPDATA ;
# endif
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 */
2002-12-02 14:19:37 +01:00
time_t starttime ; /* Startzeit des Links */
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-12-02 14:19:37 +01:00
LONG bytes_in , bytes_out ; /* Empfangene uns gesendete Bytes */
LONG msg_in , msg_out ; /* Empfangene uns gesendete Nachtichten */
2002-11-27 00:07:24 +01:00
INT flag ; /* "Markierungs-Flag" (vgl. "irc-write"-Modul) */
INT options ; /* Link-Optionen */
# ifdef USE_ZLIB
ZIPDATA zip ; /* Kompressionsinformationen */
# endif
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 ) ) ;
2002-11-23 18:04:07 +01:00
LOCAL BOOLEAN Handle_Buffer PARAMS ( ( CONN_ID Idx ) ) ;
2002-05-27 15:09:26 +02:00
LOCAL VOID Check_Connections PARAMS ( ( VOID ) ) ;
LOCAL VOID Check_Servers PARAMS ( ( VOID ) ) ;
2002-11-03 00:00:45 +01:00
LOCAL VOID Init_Conn_Struct PARAMS ( ( LONG Idx ) ) ;
2002-05-27 15:09:26 +02:00
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
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
LOCAL BOOLEAN Zip_Buffer PARAMS ( ( CONN_ID Idx , CHAR * Data , INT Len ) ) ;
LOCAL BOOLEAN Zip_Flush PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL BOOLEAN Unzip_Buffer PARAMS ( ( CONN_ID Idx ) ) ;
# endif
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
2002-11-03 00:00:45 +01:00
LOCAL CONNECTION * My_Connections ;
2002-12-18 14:50:22 +01:00
LOCAL LONG Pool_Size , WCounter ;
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
2002-11-03 00:00:45 +01:00
/* Speicher fuer Verbindungs-Pool anfordern */
Pool_Size = CONNECTION_POOL ;
if ( Conf_MaxConnections > 0 )
{
/* konfiguriertes Limit beachten */
if ( Pool_Size > Conf_MaxConnections ) Pool_Size = Conf_MaxConnections ;
}
My_Connections = malloc ( sizeof ( CONNECTION ) * Pool_Size ) ;
if ( ! My_Connections )
{
/* Speicher konnte nicht alloziert werden! */
Log ( LOG_EMERG , " Can't allocate memory! [Conn_Init] " ) ;
exit ( 1 ) ;
}
2002-12-17 12:46:54 +01:00
Log ( LOG_DEBUG , " Allocted connection pool for %ld items (%ld bytes). " , Pool_Size , sizeof ( CONNECTION ) * Pool_Size ) ;
2002-11-03 00:00:45 +01:00
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-11-03 00:00:45 +01:00
/* Groesster File-Descriptor fuer select() */
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 */
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + ) Init_Conn_Struct ( i ) ;
2002-12-18 14:50:22 +01:00
/* Global write counter */
WCounter = 0 ;
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 ) )
{
2002-11-03 00:00:45 +01:00
for ( idx = 0 ; idx < Pool_Size ; idx + + )
2001-12-13 00:32:02 +01:00
{
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-11-03 00:00:45 +01:00
else if ( idx < Pool_Size )
2002-06-02 19:03:08 +02:00
{
2002-12-19 05:35:26 +01:00
if ( NGIRCd_SignalRestart ) Conn_Close ( idx , NULL , " Server going down (restarting) " , TRUE ) ;
2002-06-02 19:03:08 +02:00
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 ) ;
}
}
}
2002-11-03 00:00:45 +01:00
free ( My_Connections ) ;
My_Connections = NULL ;
Pool_Size = 0 ;
2001-12-12 18:18:38 +01:00
} /* Conn_Exit */
2002-11-22 18:58:19 +01:00
GLOBAL INT
Conn_InitListeners ( VOID )
{
/* Ports, auf denen der Server Verbindungen entgegennehmen
* soll , initialisieren */
INT created , i ;
created = 0 ;
for ( i = 0 ; i < Conf_ListenPorts_Count ; i + + )
{
if ( Conn_NewListener ( Conf_ListenPorts [ i ] ) ) created + + ;
else Log ( LOG_ERR , " Can't listen on port %u! " , Conf_ListenPorts [ i ] ) ;
}
return created ;
} /* Conn_InitListeners */
GLOBAL VOID
Conn_ExitListeners ( VOID )
{
/* Alle "Listen-Sockets" schliessen */
INT i ;
Log ( LOG_INFO , " Shutting down all listening sockets ... " ) ;
for ( i = 0 ; i < Conn_MaxFD + 1 ; i + + )
{
if ( FD_ISSET ( i , & My_Sockets ) & & FD_ISSET ( i , & My_Listeners ) )
{
close ( i ) ;
Log ( LOG_DEBUG , " Listening socket %d closed. " , i ) ;
}
}
} /* Conn_ExitListeners */
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-11-03 00:00:45 +01:00
LONG i , idx ;
2002-11-23 18:04:07 +01:00
BOOLEAN timeout ;
2001-12-13 02:33:09 +01:00
2001-12-26 00:15:16 +01:00
start = time ( NULL ) ;
2002-12-19 05:35:26 +01:00
while ( ( ! NGIRCd_SignalQuit ) & & ( ! NGIRCd_SignalRestart ) )
2001-12-15 01:11:55 +01:00
{
2002-11-23 18:04:07 +01:00
timeout = TRUE ;
2002-01-02 03:44:36 +01:00
2002-12-19 05:35:26 +01:00
/* Should the configuration be reloaded? */
if ( NGIRCd_SignalRehash ) NGIRCd_Rehash ( ) ;
/* Check configured servers and established links */
Check_Servers ( ) ;
2001-12-26 04:20:53 +01:00
Check_Connections ( ) ;
/* noch volle Lese-Buffer suchen */
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; 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? */
2002-11-23 18:04:07 +01:00
if ( Handle_Buffer ( i ) ) timeout = FALSE ;
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 ) ;
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-26 00:15:16 +01:00
{
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
if ( ( My_Connections [ i ] . sock > NONE ) & & ( ( My_Connections [ i ] . wdatalen > 0 ) | | ( My_Connections [ i ] . zip . wdatalen > 0 ) ) )
# else
2002-01-02 03:44:36 +01:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . wdatalen > 0 ) )
2002-11-27 00:07:24 +01:00
# endif
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 */
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2002-03-02 01:23:32 +01:00
{
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 ;
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-29 21:17:25 +01:00
{
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-11-23 18:04:07 +01:00
tv . tv_usec = 0 ;
if ( timeout ) tv . tv_sec = TIME_RES ;
else tv . tv_sec = 0 ;
2002-09-07 23:13:38 +02:00
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
}
2002-12-19 05:35:26 +01:00
if ( NGIRCd_SignalQuit ) Log ( LOG_NOTICE | LOG_snotice , " Server going down NOW! " ) ;
else if ( NGIRCd_SignalRestart ) Log ( LOG_NOTICE | LOG_snotice , " Server restarting NOW! " ) ;
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-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-03-14 14:42:33 +01:00
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 ) ) ;
2002-12-02 14:19:37 +01:00
My_Connections [ Idx ] . msg_out + + ;
2001-12-24 02:32:33 +01:00
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
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2001-12-15 01:11:55 +01:00
assert ( Data ! = NULL ) ;
assert ( Len > 0 ) ;
2002-11-27 00:07:24 +01: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 ;
}
2002-11-27 00:07:24 +01:00
/* Pruefen, ob im Schreibpuffer genuegend Platz ist. Ziel ist es,
* moeglichts viel im Puffer zu haben und _nicht_ gleich alles auf den
* Socket zu schreiben ( u . a . wg . Komprimierung ) . */
if ( WRITEBUFFER_LEN - My_Connections [ Idx ] . wdatalen - Len < = 0 )
2001-12-15 01:11:55 +01:00
{
2002-11-27 00:07:24 +01:00
/* Der Puffer ist dummerweise voll. Jetzt versuchen, den Puffer
* zu schreiben , wenn das nicht klappt , haben wir ein Problem . . . */
2001-12-15 01:11:55 +01:00
if ( ! Try_Write ( Idx ) ) return FALSE ;
2002-11-27 00:07:24 +01:00
/* nun neu pruefen: */
if ( WRITEBUFFER_LEN - My_Connections [ Idx ] . wdatalen - Len < = 0 )
{
Log ( LOG_NOTICE , " Write buffer overflow (connection %d)! " , Idx ) ;
Conn_Close ( Idx , " Write buffer overflow! " , NULL , FALSE ) ;
return FALSE ;
}
2001-12-15 01:11:55 +01:00
}
2001-12-26 00:15:16 +01:00
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
if ( My_Connections [ Idx ] . options & CONN_ZIP )
2001-12-15 01:11:55 +01:00
{
2002-11-27 00:07:24 +01:00
/* Daten komprimieren und in Puffer kopieren */
if ( ! Zip_Buffer ( Idx , Data , Len ) ) return FALSE ;
2001-12-15 01:11:55 +01:00
}
2002-11-27 00:07:24 +01:00
else
# endif
2001-12-15 01:11:55 +01:00
{
2002-11-27 00:07:24 +01:00
/* Daten in Puffer kopieren */
memcpy ( My_Connections [ Idx ] . wbuf + My_Connections [ Idx ] . wdatalen , Data , Len ) ;
My_Connections [ Idx ] . wdatalen + = Len ;
My_Connections [ Idx ] . bytes_out + = Len ;
2001-12-15 01:11:55 +01:00
}
2001-12-26 00:15:16 +01:00
2002-12-18 14:50:22 +01:00
/* Adjust global write counter */
WCounter + = Len ;
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-11-27 00:07:24 +01:00
DOUBLE in_k , out_k ;
# ifdef USE_ZLIB
DOUBLE in_z_k , out_z_k ;
INT in_p , out_p ;
# endif
2002-03-11 01:04:48 +01:00
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
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-11-29 14:13:42 +01:00
# ifndef STRICT_RFC
2002-10-09 15:15:08 +02:00
/* Statistik an Client melden, wenn User */
if ( ( c ! = NULL ) & & ( Client_Type ( c ) = = CLIENT_USER ) )
{
2002-10-23 01:25:29 +02:00
Conn_WriteStr ( Idx , " NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb. " , 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
}
2002-11-29 14:13:42 +01:00
# endif
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
2002-11-28 17:56:20 +01:00
/* zunaechst versuchen, noch im Schreibpuffer vorhandene
* Daten auf den Socket zu schreiben . . . */
Try_Write ( Idx ) ;
2001-12-25 23:03:47 +01:00
if ( close ( My_Connections [ Idx ] . sock ) ! = 0 )
{
2002-11-22 17:35:19 +01:00
Log ( LOG_ERR , " Error closing connection %d (socket %d) with %s:%d - %s! " , Idx , My_Connections [ Idx ] . sock , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) , strerror ( errno ) ) ;
2001-12-25 23:03:47 +01:00
}
else
{
2002-11-27 00:07:24 +01:00
in_k = ( DOUBLE ) My_Connections [ Idx ] . bytes_in / 1024 ;
out_k = ( DOUBLE ) My_Connections [ Idx ] . bytes_out / 1024 ;
# ifdef USE_ZLIB
if ( My_Connections [ Idx ] . options & CONN_ZIP )
{
in_z_k = ( DOUBLE ) My_Connections [ Idx ] . zip . bytes_in / 1024 ;
out_z_k = ( DOUBLE ) My_Connections [ Idx ] . zip . bytes_out / 1024 ;
in_p = ( INT ) ( ( in_k * 100 ) / in_z_k ) ;
out_p = ( INT ) ( ( out_k * 100 ) / out_z_k ) ;
2002-12-03 19:57:10 +01:00
Log ( LOG_INFO , " Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%). " , Idx , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) , in_k , in_z_k , in_p , out_k , out_z_k , out_p ) ;
2002-11-27 00:07:24 +01:00
}
else
# endif
{
2002-12-03 19:57:10 +01:00
Log ( LOG_INFO , " Connection %d with %s:%d closed (in: %.1fk, out: %.1fk). " , Idx , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) , in_k , out_k ) ;
2002-11-27 00:07:24 +01:00
}
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? */
2002-11-05 15:18:39 +01:00
if ( ( My_Connections [ Idx ] . our_server > NONE ) & & ( 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-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
/* Ggf. zlib abmelden */
if ( Conn_Options ( Idx ) & CONN_ZIP )
{
inflateEnd ( & My_Connections [ Idx ] . zip . in ) ;
deflateEnd ( & My_Connections [ Idx ] . zip . out ) ;
}
# endif
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 */
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2001-12-31 03:18:51 +01:00
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) */
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2001-12-31 03:18:51 +01:00
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 */
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-02-11 02:00:50 +01:00
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 ;
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-08-26 02:03:15 +02:00
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 )
{
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-10-10 17:01:12 +02:00
My_Connections [ Idx ] . delaytime = 0 ;
} /* Conn_ResetPenalty */
2002-11-03 00:00:45 +01:00
GLOBAL VOID
Conn_ClearFlags ( VOID )
{
/* Alle Connection auf "nicht-markiert" setzen */
LONG i ;
2002-11-04 13:31:27 +01:00
for ( i = 0 ; i < Pool_Size ; i + + ) My_Connections [ i ] . flag = 0 ;
2002-11-03 00:00:45 +01:00
} /* Conn_ClearFlags */
2002-11-04 13:31:27 +01:00
GLOBAL INT
2002-11-03 00:00:45 +01:00
Conn_Flag ( CONN_ID Idx )
{
/* Ist eine Connection markiert (TRUE) oder nicht? */
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-11-04 13:31:27 +01:00
return My_Connections [ Idx ] . flag ;
2002-11-03 00:00:45 +01:00
} /* Conn_Flag */
GLOBAL VOID
2002-11-04 13:31:27 +01:00
Conn_SetFlag ( CONN_ID Idx , INT Flag )
2002-11-03 00:00:45 +01:00
{
/* Connection markieren */
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-11-04 13:31:27 +01:00
My_Connections [ Idx ] . flag = Flag ;
2002-11-03 00:00:45 +01:00
} /* Conn_SetFlag */
GLOBAL CONN_ID
Conn_First ( VOID )
{
/* Connection-Struktur der ersten Verbindung liefern;
* Ist keine Verbindung vorhanden , wird NONE geliefert . */
LONG i ;
for ( i = 0 ; i < Pool_Size ; i + + )
{
if ( My_Connections [ i ] . sock ! = NONE ) return i ;
}
return NONE ;
} /* Conn_First */
GLOBAL CONN_ID
Conn_Next ( CONN_ID Idx )
{
/* Naechste Verbindungs-Struktur liefern; existiert keine
* weitere , so wird NONE geliefert . */
LONG i = NONE ;
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-11-03 00:00:45 +01:00
for ( i = Idx + 1 ; i < Pool_Size ; i + + )
{
if ( My_Connections [ i ] . sock ! = NONE ) return i ;
}
return NONE ;
} /* Conn_Next */
2002-11-05 15:18:39 +01:00
GLOBAL VOID
Conn_SetServer ( CONN_ID Idx , INT ConfServer )
{
/* Connection als Server markieren: Index des konfigurierten
* Servers speichern . Verbindung muss bereits bestehen ! */
assert ( Idx > NONE ) ;
assert ( My_Connections [ Idx ] . sock > NONE ) ;
My_Connections [ Idx ] . our_server = ConfServer ;
} /* Conn_SetServer */
2002-11-27 00:07:24 +01:00
GLOBAL VOID
Conn_SetOption ( CONN_ID Idx , INT Option )
{
/* Option fuer Verbindung setzen.
* Initial sind alle Optionen _nicht_ gesetzt . */
assert ( Idx > NONE ) ;
assert ( Option ! = 0 ) ;
My_Connections [ Idx ] . options | = Option ;
} /* Conn_SetOption */
GLOBAL VOID
Conn_UnsetOption ( CONN_ID Idx , INT Option )
{
/* Option fuer Verbindung loeschen */
assert ( Idx > NONE ) ;
assert ( Option ! = 0 ) ;
My_Connections [ Idx ] . options & = ~ Option ;
} /* Conn_UnsetOption */
GLOBAL INT
Conn_Options ( CONN_ID Idx )
{
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . options ;
} /* Conn_Options */
# ifdef USE_ZLIB
GLOBAL BOOLEAN
Conn_InitZip ( CONN_ID Idx )
{
/* Kompression fuer Link initialisieren */
assert ( Idx > NONE ) ;
My_Connections [ Idx ] . zip . in . avail_in = 0 ;
My_Connections [ Idx ] . zip . in . total_in = 0 ;
My_Connections [ Idx ] . zip . in . total_out = 0 ;
My_Connections [ Idx ] . zip . in . zalloc = NULL ;
My_Connections [ Idx ] . zip . in . zfree = NULL ;
My_Connections [ Idx ] . zip . in . data_type = Z_ASCII ;
if ( inflateInit ( & My_Connections [ Idx ] . zip . in ) ! = Z_OK )
{
/* Fehler! */
Log ( LOG_ALERT , " Can't initialize compression on connection %d (zlib inflate)! " , Idx ) ;
return FALSE ;
}
My_Connections [ Idx ] . zip . out . total_in = 0 ;
My_Connections [ Idx ] . zip . out . total_in = 0 ;
My_Connections [ Idx ] . zip . out . zalloc = NULL ;
My_Connections [ Idx ] . zip . out . zfree = NULL ;
My_Connections [ Idx ] . zip . out . data_type = Z_ASCII ;
if ( deflateInit ( & My_Connections [ Idx ] . zip . out , Z_DEFAULT_COMPRESSION ) ! = Z_OK )
{
/* Fehler! */
Log ( LOG_ALERT , " Can't initialize compression on connection %d (zlib deflate)! " , Idx ) ;
return FALSE ;
}
My_Connections [ Idx ] . zip . bytes_in = My_Connections [ Idx ] . bytes_in ;
My_Connections [ Idx ] . zip . bytes_out = My_Connections [ Idx ] . bytes_out ;
Log ( LOG_INFO , " Enabled link compression (zlib) on connection %d. " , Idx ) ;
Conn_SetOption ( Idx , CONN_ZIP ) ;
return TRUE ;
} /* Conn_InitZip */
2002-12-02 14:19:37 +01:00
GLOBAL LONG
Conn_SendBytesZip ( CONN_ID Idx )
{
/* Anzahl gesendeter Bytes (komprimiert!) liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . zip . bytes_out ;
} /* Conn_SendBytesZip */
GLOBAL LONG
Conn_RecvBytesZip ( CONN_ID Idx )
{
/* Anzahl gesendeter Bytes (komprimiert!) liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . zip . bytes_in ;
} /* Conn_RecvBytesZip */
# endif
GLOBAL time_t
Conn_StartTime ( CONN_ID Idx )
{
/* Zeitpunkt des Link-Starts liefern (in Sekunden) */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . starttime ;
} /* Conn_Uptime */
GLOBAL INT
Conn_SendQ ( CONN_ID Idx )
{
/* Laenge der Daten im Schreibbuffer liefern */
assert ( Idx > NONE ) ;
# ifdef USE_ZLIB
2002-12-02 14:56:24 +01:00
if ( My_Connections [ Idx ] . options & CONN_ZIP ) return My_Connections [ Idx ] . zip . wdatalen ;
else
2002-12-02 14:19:37 +01:00
# endif
2002-12-02 14:56:24 +01:00
return My_Connections [ Idx ] . wdatalen ;
2002-12-02 14:19:37 +01:00
} /* Conn_SendQ */
GLOBAL LONG
Conn_SendMsg ( CONN_ID Idx )
{
/* Anzahl gesendeter Nachrichten liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . msg_out ;
} /* Conn_SendMsg */
GLOBAL LONG
Conn_SendBytes ( CONN_ID Idx )
{
/* Anzahl gesendeter Bytes (unkomprimiert) liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . bytes_out ;
} /* Conn_SendBytes */
GLOBAL INT
Conn_RecvQ ( CONN_ID Idx )
{
/* Laenge der Daten im Lesebuffer liefern */
assert ( Idx > NONE ) ;
# ifdef USE_ZLIB
2002-12-02 14:56:24 +01:00
if ( My_Connections [ Idx ] . options & CONN_ZIP ) return My_Connections [ Idx ] . zip . rdatalen ;
else
2002-11-27 00:07:24 +01:00
# endif
2002-12-02 14:56:24 +01:00
return My_Connections [ Idx ] . rdatalen ;
2002-12-02 14:19:37 +01:00
} /* Conn_RecvQ */
GLOBAL LONG
Conn_RecvMsg ( CONN_ID Idx )
{
/* Anzahl empfangener Nachrichten liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . msg_in ;
} /* Conn_RecvMsg */
GLOBAL LONG
Conn_RecvBytes ( CONN_ID Idx )
{
/* Anzahl empfangener Bytes (unkomprimiert) liefern */
assert ( Idx > NONE ) ;
return My_Connections [ Idx ] . bytes_in ;
} /* Conn_RecvBytes */
2002-11-27 00:07:24 +01:00
2002-12-18 14:50:22 +01:00
GLOBAL VOID
Conn_ResetWCounter ( VOID )
{
WCounter = 0 ;
} /* Conn_ResetWCounter */
GLOBAL LONG
Conn_WCounter ( VOID )
{
return WCounter ;
} /* Conn_WCounter */
2002-05-27 15:09:26 +02:00
LOCAL BOOLEAN
Try_Write ( CONN_ID Idx )
2001-12-15 01:11:55 +01:00
{
2002-11-28 17:56:20 +01:00
/* Versuchen, Daten aus dem Schreib-Puffer in den Socket zu
* schreiben . TRUE wird geliefert , wenn entweder keine Daten
* zum Versenden vorhanden sind oder erfolgreich bearbeitet
* werden konnten . Im Fehlerfall wird FALSE geliefert und
* die Verbindung geschlossen . */
2001-12-15 01:11:55 +01:00
fd_set write_socket ;
2002-11-23 17:09:57 +01:00
struct timeval tv ;
2001-12-26 00:15:16 +01:00
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2002-11-28 17:56:20 +01:00
/* sind ueberhaupt Daten vorhanden? */
# ifdef USE_ZLIB
if ( ( ! My_Connections [ Idx ] . wdatalen > 0 ) & & ( ! My_Connections [ Idx ] . zip . wdatalen ) ) return TRUE ;
# else
if ( ! My_Connections [ Idx ] . wdatalen > 0 ) return TRUE ;
# endif
2001-12-15 01:11:55 +01:00
2002-11-23 17:09:57 +01:00
/* Timeout initialisieren: 0 Sekunden, also nicht blockieren */
tv . tv_sec = 0 ; tv . tv_usec = 0 ;
2001-12-15 01:11:55 +01:00
FD_ZERO ( & write_socket ) ;
FD_SET ( My_Connections [ Idx ] . sock , & write_socket ) ;
2002-11-23 17:09:57 +01:00
if ( select ( My_Connections [ Idx ] . sock + 1 , NULL , & write_socket , NULL , & tv ) = = - 1 )
2001-12-15 01:11:55 +01:00
{
/* 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
2002-11-05 15:18:39 +01:00
assert ( Sock > NONE ) ;
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-11-19 13:50:20 +01:00
Conn_WriteStr ( Idx , " PASS %s %s " , Conf_Server [ My_Connections [ Idx ] . our_server ] . pwd_out , 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
}
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
/* Schreibpuffer leer, aber noch Daten im Kompressionsbuffer?
* Dann muss dieser nun geflushed werden ! */
if ( My_Connections [ Idx ] . wdatalen = = 0 ) Zip_Flush ( Idx ) ;
# endif
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 )
{
2002-11-20 16:48:41 +01:00
/* Operation haette Socket "nur" blockiert ... */
if ( errno = = EAGAIN ) return TRUE ;
2001-12-15 01:11:55 +01:00
/* 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
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-11-03 00:00:45 +01:00
POINTER * ptr ;
LONG new_size ;
2002-03-11 01:04:48 +01:00
2002-11-05 15:18:39 +01:00
assert ( Sock > NONE ) ;
2001-12-12 18:18:38 +01:00
2002-11-20 16:48:41 +01:00
/* Connection auf Listen-Socket annehmen */
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-11-20 16:48:41 +01:00
/* Socket initialisieren */
Init_Socket ( new_sock ) ;
2002-10-15 00:21:00 +02:00
/* Freie Connection-Struktur suchen */
2002-11-03 00:00:45 +01:00
for ( idx = 0 ; idx < Pool_Size ; idx + + ) if ( My_Connections [ idx ] . sock = = NONE ) break ;
if ( idx > = Pool_Size )
2001-12-12 18:18:38 +01:00
{
2002-11-03 00:00:45 +01:00
new_size = Pool_Size + CONNECTION_POOL ;
/* Im bisherigen Pool wurde keine freie Connection-Struktur mehr gefunden.
* Wenn erlaubt und moeglich muss nun der Pool vergroessert werden : */
if ( Conf_MaxConnections > 0 )
{
/* Es ist ein Limit konfiguriert */
if ( Pool_Size > = Conf_MaxConnections )
{
/* Mehr Verbindungen duerfen wir leider nicht mehr annehmen ... */
Log ( LOG_ALERT , " Can't accept connection: limit (%d) reached! " , Pool_Size ) ;
close ( new_sock ) ;
return ;
}
if ( new_size > Conf_MaxConnections ) new_size = Conf_MaxConnections ;
}
/* zunaechst realloc() versuchen; wenn das scheitert, malloc() versuchen
* und Daten ggf . " haendisch " umkopieren . ( Haesslich ! Eine wirklich
* dynamische Verwaltung waere wohl _deutlich_ besser . . . ) */
ptr = realloc ( My_Connections , sizeof ( CONNECTION ) * new_size ) ;
if ( ! ptr )
{
/* realloc() ist fehlgeschlagen. Nun malloc() probieren: */
ptr = malloc ( sizeof ( CONNECTION ) * new_size ) ;
if ( ! ptr )
{
/* Offenbar steht kein weiterer Sepeicher zur Verfuegung :-( */
Log ( LOG_EMERG , " Can't allocate memory! [New_Connection] " ) ;
close ( new_sock ) ;
return ;
}
/* Struktur umkopieren ... */
memcpy ( ptr , My_Connections , sizeof ( CONNECTION ) * Pool_Size ) ;
2002-12-17 12:46:54 +01:00
Log ( LOG_DEBUG , " Allocated new connection pool for %ld items (%ld bytes). [malloc()/memcpy()] " , new_size , sizeof ( CONNECTION ) * new_size ) ;
2002-11-03 00:00:45 +01:00
}
2002-12-17 12:46:54 +01:00
else Log ( LOG_DEBUG , " Allocated new connection pool for %ld items (%ld bytes) . [ realloc ( ) ] " , new_size, sizeof( CONNECTION ) * new_size ) ;
2002-11-03 00:00:45 +01:00
2002-12-17 12:46:54 +01:00
/* Adjust pointer to new block */
2002-11-03 00:00:45 +01:00
My_Connections = ptr ;
2002-12-17 12:46:54 +01:00
/* Initialize new items */
for ( idx = Pool_Size ; idx < new_size ; idx + + ) Init_Conn_Struct ( idx ) ;
idx = Pool_Size ;
/* Adjust new pool size */
2002-11-03 00:00:45 +01:00
Pool_Size = new_size ;
2001-12-12 18:18:38 +01:00
}
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-11-22 17:35:19 +01:00
strcpy ( My_Connections [ idx ] . host , inet_ntoa ( new_addr . sin_addr ) ) ;
Client_SetHostname ( c , My_Connections [ idx ] . host ) ;
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 */
My_Connections [ idx ] . res_stat = s ;
}
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
2002-11-05 15:18:39 +01:00
assert ( Sock > NONE ) ;
2001-12-26 00:15:16 +01:00
2002-11-03 00:00:45 +01:00
for ( idx = 0 ; idx < Pool_Size ; idx + + ) if ( My_Connections [ idx ] . sock = = Sock ) break ;
2001-12-26 00:15:16 +01:00
2002-11-03 00:00:45 +01:00
if ( idx > = Pool_Size )
2002-10-15 11:24:54 +02:00
{
/* 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
2002-11-28 13:17:38 +01:00
INT len , bsize ;
2002-11-29 14:13:42 +01:00
# ifdef USE_ZLIB
2002-11-28 13:17:38 +01:00
CLIENT * c ;
2002-11-29 14:13:42 +01:00
# endif
2001-12-15 01:11:55 +01:00
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2002-01-02 03:44:36 +01:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2001-12-26 00:15:16 +01:00
2002-11-28 13:17:38 +01:00
/* wenn noch nicht registriert: maximal mit ZREADBUFFER_LEN arbeiten,
* ansonsten koennen Daten ggf . nicht umkopiert werden . */
bsize = READBUFFER_LEN ;
# ifdef USE_ZLIB
c = Client_GetFromConn ( Idx ) ;
if ( ( Client_Type ( c ) ! = CLIENT_USER ) & & ( Client_Type ( c ) ! = CLIENT_SERVER ) & & ( Client_Type ( c ) ! = CLIENT_SERVICE ) & & ( bsize > ZREADBUFFER_LEN ) ) bsize = ZREADBUFFER_LEN ;
# endif
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
2002-11-28 13:17:38 +01:00
if ( ( bsize - My_Connections [ Idx ] . rdatalen - 1 < 1 ) | | ( ZREADBUFFER_LEN - My_Connections [ Idx ] . zip . rdatalen < 1 ) )
2002-11-27 00:07:24 +01:00
# else
2002-11-28 13:17:38 +01:00
if ( bsize - My_Connections [ Idx ] . rdatalen - 1 < 1 )
2002-11-27 00:07:24 +01:00
# endif
2002-01-03 03:25:36 +01:00
{
/* 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 ;
}
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
if ( My_Connections [ Idx ] . options & CONN_ZIP )
{
len = recv ( My_Connections [ Idx ] . sock , My_Connections [ Idx ] . zip . rbuf + My_Connections [ Idx ] . zip . rdatalen , ( ZREADBUFFER_LEN - My_Connections [ Idx ] . zip . rdatalen ) , 0 ) ;
if ( len > 0 ) My_Connections [ Idx ] . zip . rdatalen + = len ;
}
else
# endif
{
2002-11-28 13:17:38 +01:00
len = recv ( My_Connections [ Idx ] . sock , My_Connections [ Idx ] . rbuf + My_Connections [ Idx ] . rdatalen , bsize - My_Connections [ Idx ] . rdatalen - 1 , 0 ) ;
2002-11-27 00:07:24 +01:00
if ( len > 0 ) My_Connections [ Idx ] . rdatalen + = len ;
}
2001-12-13 02:33:09 +01:00
if ( len = = 0 )
{
/* Socket wurde geschlossen */
2002-12-03 19:57:10 +01:00
Log ( LOG_INFO , " %s:%d (%s) is closing the connection ... " , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) , inet_ntoa ( My_Connections [ Idx ] . addr . sin_addr ) ) ;
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
{
2002-11-20 16:48:41 +01:00
/* Operation haette Socket "nur" blockiert ... */
if ( errno = = EAGAIN ) return ;
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
/* Timestamp aktualisieren */
My_Connections [ Idx ] . lastdata = time ( NULL ) ;
2001-12-26 00:15:16 +01:00
Handle_Buffer ( Idx ) ;
} /* Read_Request */
2002-11-23 18:04:07 +01:00
LOCAL BOOLEAN
2002-05-27 15:09:26 +02:00
Handle_Buffer ( CONN_ID Idx )
2001-12-26 00:15:16 +01:00
{
2002-11-23 18:04:07 +01:00
/* Daten im Lese-Puffer einer Verbindung verarbeiten.
* Wurde ein Request verarbeitet , so wird TRUE geliefert ,
* ansonsten FALSE ( auch bei Fehlern ) . */
2001-12-29 23:33:36 +01:00
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-11-27 00:07:24 +01:00
BOOLEAN action , result ;
2002-11-28 13:17:38 +01:00
# ifdef USE_ZLIB
BOOLEAN old_z ;
# endif
2001-12-26 00:15:16 +01:00
2002-11-27 00:07:24 +01:00
result = FALSE ;
do
2001-12-26 00:15:16 +01:00
{
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
/* ggf. noch unkomprimiete Daten weiter entpacken */
if ( My_Connections [ Idx ] . options & CONN_ZIP )
{
if ( ! Unzip_Buffer ( Idx ) ) return FALSE ;
}
2002-01-03 03:25:36 +01:00
# endif
2002-11-27 00:07:24 +01:00
if ( My_Connections [ Idx ] . rdatalen < 1 ) break ;
2002-03-11 01:04:48 +01:00
2002-11-27 00:07:24 +01:00
/* Eine komplette Anfrage muss mit CR+LF enden, vgl.
* RFC 2812. Haben wir eine ? */
My_Connections [ Idx ] . rbuf [ My_Connections [ Idx ] . rdatalen ] = ' \0 ' ;
ptr = strstr ( My_Connections [ Idx ] . rbuf , " \r \n " ) ;
if ( ptr ) delta = 2 ;
# ifndef STRICT_RFC
else
2002-01-03 03:25:36 +01:00
{
2002-11-27 00:07:24 +01:00
/* 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
}
2002-11-27 00:07:24 +01:00
# endif
action = FALSE ;
if ( ptr )
2001-12-13 02:33:09 +01:00
{
2002-11-27 00:07:24 +01:00
/* Ende der Anfrage wurde gefunden */
* ptr = ' \0 ' ;
len = ( ptr - My_Connections [ Idx ] . rbuf ) + delta ;
if ( len > ( COMMAND_LEN - 1 ) )
{
/* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
* ( incl . CR + LF ! ) werden ; vgl . RFC 2812. Wenn soetwas
* empfangen wird , wird der Client disconnectiert . */
Log ( LOG_ERR , " Request too long (connection %d): %d bytes (max. %d expected)! " , Idx , My_Connections [ Idx ] . rdatalen , COMMAND_LEN - 1 ) ;
Conn_Close ( Idx , NULL , " Request too long " , TRUE ) ;
return FALSE ;
}
2002-11-28 13:17:38 +01:00
# ifdef USE_ZLIB
/* merken, ob Stream bereits komprimiert wird */
old_z = My_Connections [ Idx ] . options & CONN_ZIP ;
# endif
2002-11-27 00:07:24 +01:00
if ( len > delta )
{
/* Es wurde ein Request gelesen */
2002-12-02 14:19:37 +01:00
My_Connections [ Idx ] . msg_in + + ;
2002-11-27 00:07:24 +01:00
if ( ! Parse_Request ( Idx , My_Connections [ Idx ] . rbuf ) ) return FALSE ;
else action = TRUE ;
}
2002-11-28 13:17:38 +01:00
2002-11-27 00:07:24 +01:00
/* Puffer anpassen */
My_Connections [ Idx ] . rdatalen - = len ;
memmove ( My_Connections [ Idx ] . rbuf , My_Connections [ Idx ] . rbuf + len , My_Connections [ Idx ] . rdatalen ) ;
2002-11-28 13:17:38 +01:00
# ifdef USE_ZLIB
if ( ( ! old_z ) & & ( My_Connections [ Idx ] . options & CONN_ZIP ) & & ( My_Connections [ Idx ] . rdatalen > 0 ) )
{
/* Mit dem letzten Befehl wurde Socket-Kompression aktiviert.
* Evtl . schon vom Socket gelesene Daten in den Unzip - Puffer
* umkopieren , damit diese nun zunaechst entkomprimiert werden */
{
if ( My_Connections [ Idx ] . rdatalen > ZREADBUFFER_LEN )
{
/* Hupsa! Soviel Platz haben wir aber gar nicht! */
Log ( LOG_ALERT , " Can't move read buffer: No space left in unzip buffer (need %d bytes)! " , My_Connections [ Idx ] . rdatalen ) ;
return FALSE ;
}
memcpy ( My_Connections [ Idx ] . zip . rbuf , My_Connections [ Idx ] . rbuf , My_Connections [ Idx ] . rdatalen ) ;
My_Connections [ Idx ] . zip . rdatalen = My_Connections [ Idx ] . rdatalen ;
My_Connections [ Idx ] . rdatalen = 0 ;
Log ( LOG_DEBUG , " Moved already received data (%d bytes) to uncompression buffer. " , My_Connections [ Idx ] . zip . rdatalen ) ;
}
}
# endif
2001-12-13 02:33:09 +01:00
}
2002-11-27 00:07:24 +01:00
if ( action ) result = TRUE ;
} while ( action ) ;
2002-11-23 18:04:07 +01:00
2002-11-27 00:07:24 +01:00
return result ;
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 ;
2002-11-03 00:00:45 +01:00
LONG i ;
2001-12-26 04:20:53 +01:00
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-26 04:20:53 +01:00
{
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 */
RES_STAT * s ;
2002-11-03 00:00:45 +01:00
LONG idx , n ;
INT i ;
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? */
2002-11-03 00:00:45 +01:00
for ( n = 0 ; n < Pool_Size ; n + + )
2002-01-02 03:44:36 +01:00
{
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
}
2002-11-03 00:00:45 +01:00
if ( n < Pool_Size ) 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 */
2002-11-03 00:00:45 +01:00
for ( idx = 0 ; idx < Pool_Size ; idx + + ) if ( My_Connections [ idx ] . sock = = NONE ) break ;
if ( idx > = Pool_Size )
2002-01-02 03:44:36 +01:00
{
2002-11-03 00:00:45 +01:00
Log ( LOG_ALERT , " Can't establist server connection: connection limit reached (%d)! " , Pool_Size ) ;
2002-01-02 03:44:36 +01:00
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-11-22 17:35:19 +01:00
/* Hostnamen in IP aufloesen (Default bzw. im Fehlerfall: versuchen, den
* konfigurierten Text direkt als IP - Adresse zu verwenden . . . */
strcpy ( Conf_Server [ My_Connections [ idx ] . our_server ] . ip , Conf_Server [ i ] . host ) ;
strcpy ( My_Connections [ idx ] . host , Conf_Server [ i ] . host ) ;
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 ;
}
}
} /* 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 ;
2002-11-11 01:54:25 +01:00
INT res , new_sock ;
2002-01-03 03:25:36 +01:00
CLIENT * c ;
2002-01-02 03:44:36 +01:00
2002-11-05 15:18:39 +01:00
assert ( Server > NONE ) ;
assert ( Idx > NONE ) ;
2002-01-02 03:44:36 +01:00
/* 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 ;
2002-11-11 01:54:25 +01:00
res = connect ( new_sock , ( struct sockaddr * ) & new_addr , sizeof ( new_addr ) ) ;
if ( ( res ! = 0 ) & & ( errno ! = EINPROGRESS ) )
2002-01-02 03:44:36 +01:00
{
2002-11-11 01:54:25 +01:00
Log ( LOG_CRIT , " Can't connect socket: %s! " , strerror ( errno ) ) ;
2002-01-02 03:44:36 +01:00
close ( new_sock ) ;
Init_Conn_Struct ( Idx ) ;
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
2002-11-03 00:00:45 +01:00
Init_Conn_Struct ( LONG 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 ;
2002-12-02 14:19:37 +01:00
My_Connections [ Idx ] . starttime = time ( NULL ) ;
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 ;
2002-12-02 14:19:37 +01:00
My_Connections [ Idx ] . msg_in = 0 ;
My_Connections [ Idx ] . msg_out = 0 ;
2002-11-04 13:31:27 +01:00
My_Connections [ Idx ] . flag = 0 ;
2002-11-27 00:07:24 +01:00
My_Connections [ Idx ] . options = 0 ;
# ifdef USE_ZLIB
My_Connections [ Idx ] . zip . rbuf [ 0 ] = ' \0 ' ;
My_Connections [ Idx ] . zip . rdatalen = 0 ;
My_Connections [ Idx ] . zip . wbuf [ 0 ] = ' \0 ' ;
My_Connections [ Idx ] . zip . wdatalen = 0 ;
My_Connections [ Idx ] . zip . bytes_in = 0 ;
My_Connections [ Idx ] . zip . bytes_out = 0 ;
# endif
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 */
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-29 21:17:25 +01:00
{
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
}
2002-11-03 00:00:45 +01:00
if ( i > = Pool_Size )
2001-12-29 21:17:25 +01:00
{
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 ;
}
2002-11-22 17:35:19 +01:00
Log ( LOG_DEBUG , " Resolver: %s is \" %s \" . " , My_Connections [ i ] . host , result ) ;
2001-12-29 21:17:25 +01:00
/* 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 */
2002-11-05 15:18:39 +01:00
assert ( My_Connections [ i ] . our_server > NONE ) ;
2002-01-02 03:44:36 +01:00
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
2002-11-27 00:07:24 +01:00
# ifdef USE_ZLIB
LOCAL BOOLEAN
Zip_Buffer ( CONN_ID Idx , CHAR * Data , INT Len )
{
/* Daten zum Komprimieren im "Kompressions-Puffer" sammeln.
* Es wird TRUE bei Erfolg , sonst FALSE geliefert . */
assert ( Idx > NONE ) ;
assert ( Data ! = NULL ) ;
assert ( Len > 0 ) ;
/* Ist noch Platz im Kompressions-Puffer? */
if ( ZWRITEBUFFER_LEN - My_Connections [ Idx ] . zip . wdatalen < Len + 50 )
{
/* Nein! Puffer zunaechst leeren ...*/
if ( ! Zip_Flush ( Idx ) ) return FALSE ;
}
/* Daten kopieren */
memmove ( My_Connections [ Idx ] . zip . wbuf + My_Connections [ Idx ] . zip . wdatalen , Data , Len ) ;
My_Connections [ Idx ] . zip . wdatalen + = Len ;
return TRUE ;
} /* Zip_Buffer */
LOCAL BOOLEAN
Zip_Flush ( CONN_ID Idx )
{
/* Daten komprimieren und in Schreibpuffer kopieren.
* Es wird TRUE bei Erfolg , sonst FALSE geliefert . */
INT result , out_len ;
z_stream * out ;
out = & My_Connections [ Idx ] . zip . out ;
out - > next_in = My_Connections [ Idx ] . zip . wbuf ;
out - > avail_in = My_Connections [ Idx ] . zip . wdatalen ;
out - > next_out = My_Connections [ Idx ] . wbuf + My_Connections [ Idx ] . wdatalen ;
out - > avail_out = WRITEBUFFER_LEN - My_Connections [ Idx ] . wdatalen ;
result = deflate ( out , Z_SYNC_FLUSH ) ;
if ( ( result ! = Z_OK ) | | ( out - > avail_in > 0 ) )
{
Log ( LOG_ALERT , " Compression error: code %d!? " , result ) ;
Conn_Close ( Idx , " Compression error! " , NULL , FALSE ) ;
return FALSE ;
}
out_len = WRITEBUFFER_LEN - My_Connections [ Idx ] . wdatalen - out - > avail_out ;
My_Connections [ Idx ] . wdatalen + = out_len ;
My_Connections [ Idx ] . bytes_out + = out_len ;
My_Connections [ Idx ] . zip . bytes_out + = My_Connections [ Idx ] . zip . wdatalen ;
My_Connections [ Idx ] . zip . wdatalen = 0 ;
return TRUE ;
} /* Zip_Flush */
LOCAL BOOLEAN
Unzip_Buffer ( CONN_ID Idx )
{
/* Daten entpacken und in Lesepuffer kopieren. Bei Fehlern
* wird FALSE geliefert , ansonsten TRUE . Der Fall , dass keine
* Daten mehr zu entpacken sind , ist _kein_ Fehler ! */
INT result , in_len , out_len ;
z_stream * in ;
assert ( Idx > NONE ) ;
if ( My_Connections [ Idx ] . zip . rdatalen < = 0 ) return TRUE ;
in = & My_Connections [ Idx ] . zip . in ;
in - > next_in = My_Connections [ Idx ] . zip . rbuf ;
in - > avail_in = My_Connections [ Idx ] . zip . rdatalen ;
in - > next_out = My_Connections [ Idx ] . rbuf + My_Connections [ Idx ] . rdatalen ;
in - > avail_out = READBUFFER_LEN - My_Connections [ Idx ] . rdatalen - 1 ;
result = inflate ( in , Z_SYNC_FLUSH ) ;
if ( result ! = Z_OK )
{
2002-11-28 13:17:38 +01:00
Log ( LOG_ALERT , " Decompression error: code %d (ni=%d, ai=%d, no=%d, ao=%d)!? " , result , in - > next_in , in - > avail_in , in - > next_out , in - > avail_out ) ;
2002-11-27 00:07:24 +01:00
Conn_Close ( Idx , " Decompression error! " , NULL , FALSE ) ;
return FALSE ;
}
in_len = My_Connections [ Idx ] . zip . rdatalen - in - > avail_in ;
out_len = READBUFFER_LEN - My_Connections [ Idx ] . rdatalen - 1 - in - > avail_out ;
My_Connections [ Idx ] . rdatalen + = out_len ;
if ( in - > avail_in > 0 )
{
/* es konnten nicht alle Daten entpackt werden, vermutlich war
* im Ziel - Puffer kein Platz mehr . Umkopieren . . . */
My_Connections [ Idx ] . zip . rdatalen - = in_len ;
memmove ( My_Connections [ Idx ] . zip . rbuf , My_Connections [ Idx ] . zip . rbuf + in_len , My_Connections [ Idx ] . zip . rdatalen ) ;
}
else My_Connections [ Idx ] . zip . rdatalen = 0 ;
My_Connections [ Idx ] . zip . bytes_in + = out_len ;
return TRUE ;
} /* Unzip_Buffer */
# endif
2001-12-12 18:18:38 +01:00
/* -eof- */