2001-12-12 18:18:38 +01:00
/*
* ngIRCd - - The Next Generation IRC Daemon
2004-02-28 03:01:01 +01:00
* Copyright ( c ) 2001 - 2004 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-12-30 18:14:59 +01:00
# define CONN_MODULE
2002-12-30 17:07:23 +01:00
2002-03-12 15:37:51 +01:00
# include "portab.h"
2001-12-12 18:18:38 +01:00
2005-06-12 19:21:46 +02:00
static char UNUSED id [ ] = " $Id: conn.c,v 1.154 2005/06/12 17:21:46 fw 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>
2004-10-20 15:47:32 +02:00
# ifdef PROTOTYPES
# include <stdarg.h>
# else
# include <varargs.h>
# endif
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>
2004-01-25 17:06:34 +01:00
# ifdef HAVE_NETINET_IP_H
# include <netinet / ip.h>
# endif
2002-01-05 16:56:23 +01:00
# ifdef HAVE_ARPA_INET_H
2004-01-25 17:06:34 +01:00
# include <arpa / inet.h>
2002-01-05 16:56:23 +01:00
# else
2004-01-25 17:06:34 +01:00
# define PF_INET AF_INET
2002-01-05 16:56:23 +01:00
# endif
2001-12-12 18:18:38 +01:00
# ifdef HAVE_STDINT_H
2004-01-25 17:06:34 +01:00
# include <stdint.h> /* e.g. for Mac OS X */
2003-03-07 15:35:52 +01:00
# endif
2003-12-26 16:55:07 +01:00
# ifdef TCPWRAP
2004-01-25 17:06:34 +01:00
# include <tcpd.h> /* for TCP Wrappers */
2001-12-12 18:18:38 +01:00
# endif
2002-12-30 17:07:23 +01:00
# include "defines.h"
# include "resolve.h"
2002-11-27 00:07:24 +01:00
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"
2001-12-26 04:20:53 +01:00
# include "conf.h"
2002-12-30 17:07:23 +01:00
# include "conn-zip.h"
2002-12-30 18:14:59 +01:00
# include "conn-func.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
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
2004-01-25 17:06:34 +01:00
# include "rendezvous.h"
2003-02-23 13:04:05 +01:00
# endif
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
2005-03-19 19:43:48 +01:00
LOCAL void Handle_Read PARAMS ( ( int sock ) ) ;
LOCAL bool Handle_Write PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL void New_Connection PARAMS ( ( int Sock ) ) ;
LOCAL CONN_ID Socket2Index PARAMS ( ( int Sock ) ) ;
LOCAL void Read_Request PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL bool Handle_Buffer PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL void Check_Connections PARAMS ( ( void ) ) ;
LOCAL void Check_Servers PARAMS ( ( void ) ) ;
LOCAL void Init_Conn_Struct PARAMS ( ( CONN_ID Idx ) ) ;
LOCAL bool Init_Socket PARAMS ( ( int Sock ) ) ;
LOCAL void New_Server PARAMS ( ( int Server , CONN_ID Idx ) ) ;
LOCAL void Read_Resolver_Result PARAMS ( ( int r_fd ) ) ;
LOCAL void Simple_Message PARAMS ( ( int Sock , char * Msg ) ) ;
LOCAL int Count_Connections PARAMS ( ( struct sockaddr_in addr ) ) ;
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 ;
2003-12-26 16:55:07 +01:00
# ifdef TCPWRAP
2005-03-19 19:43:48 +01:00
int allow_severity = LOG_INFO ;
int deny_severity = LOG_ERR ;
2003-03-07 15:35:52 +01:00
# endif
2005-06-01 23:28:50 +02:00
LOCAL void
FreeRes_stat ( CONNECTION * c )
{
assert ( c ! = NULL ) ;
assert ( c - > res_stat ! = NULL ) ;
if ( ! c - > res_stat ) return ;
FD_CLR ( c - > res_stat - > pipe [ 0 ] , & Resolver_FDs ) ;
close ( c - > res_stat - > pipe [ 0 ] ) ;
close ( c - > res_stat - > pipe [ 1 ] ) ;
free ( c - > res_stat ) ;
c - > res_stat = NULL ;
}
2001-12-12 18:18:38 +01:00
2005-03-19 19:43:48 +01: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 ;
}
2005-04-16 11:19:49 +02:00
My_Connections = ( CONNECTION * ) calloc ( Pool_Size , sizeof ( CONNECTION ) ) ;
2002-11-03 00:00:45 +01:00
if ( ! My_Connections )
{
/* Speicher konnte nicht alloziert werden! */
Log ( LOG_EMERG , " Can't allocate memory! [Conn_Init] " ) ;
exit ( 1 ) ;
}
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2003-08-30 22:28:54 +02:00
Log ( LOG_DEBUG , " Allocated connection pool for %d items (%ld bytes). " , Pool_Size , sizeof ( CONNECTION ) * Pool_Size ) ;
2003-11-06 00:24:48 +01:00
# endif
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 ) ;
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 */
2005-03-19 19:43:48 +01: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 ;
2005-03-19 19:43:48 +01:00
int i ;
2001-12-26 00:15:16 +01:00
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-01-06 16:18:14 +01:00
Log ( LOG_DEBUG , " Shutting down all connections ... " ) ;
2003-11-06 00:24:48 +01:00
# endif
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
Rendezvous_UnregisterListeners ( ) ;
# endif
2003-04-25 18:47:52 +02:00
2003-02-23 13:04:05 +01:00
/* Sockets schliessen */
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 ) ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-01-06 16:18:14 +01:00
Log ( LOG_DEBUG , " Listening socket %d closed. " , i ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-03-02 01:23:32 +01:00
}
2002-11-03 00:00:45 +01:00
else if ( idx < Pool_Size )
2002-06-02 19:03:08 +02:00
{
2005-03-19 19:43:48 +01:00
if ( NGIRCd_SignalRestart ) Conn_Close ( idx , NULL , " Server going down (restarting) " , true ) ;
else Conn_Close ( idx , NULL , " Server going down " , true ) ;
2002-06-02 19:03:08 +02:00
}
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 ) ;
}
}
}
2003-04-25 18:47:52 +02:00
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 */
2005-03-19 19:43:48 +01:00
GLOBAL int
Conn_InitListeners ( void )
2002-11-22 18:58:19 +01:00
{
2002-12-30 17:07:23 +01:00
/* Initialize ports on which the server should accept connections */
2002-11-22 18:58:19 +01:00
2005-03-19 19:43:48 +01:00
int created , i ;
2002-11-22 18:58:19 +01:00
created = 0 ;
for ( i = 0 ; i < Conf_ListenPorts_Count ; i + + )
{
if ( Conn_NewListener ( Conf_ListenPorts [ i ] ) ) created + + ;
2005-03-20 14:54:06 +01:00
else Log ( LOG_ERR , " Can't listen on port %u! " , ( unsigned int ) Conf_ListenPorts [ i ] ) ;
2002-11-22 18:58:19 +01:00
}
return created ;
} /* Conn_InitListeners */
2005-03-19 19:43:48 +01:00
GLOBAL void
Conn_ExitListeners ( void )
2002-11-22 18:58:19 +01:00
{
2002-12-30 17:07:23 +01:00
/* Close down all listening sockets */
2002-11-22 18:58:19 +01:00
2005-03-19 19:43:48 +01:00
int i ;
2002-11-22 18:58:19 +01:00
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
Rendezvous_UnregisterListeners ( ) ;
# endif
2003-04-25 18:47:52 +02:00
2002-11-22 18:58:19 +01:00
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 ) ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-11-22 18:58:19 +01:00
Log ( LOG_DEBUG , " Listening socket %d closed. " , i ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-11-22 18:58:19 +01:00
}
}
} /* Conn_ExitListeners */
2005-03-19 19:43:48 +01:00
GLOBAL bool
Conn_NewListener ( const UINT16 Port )
2001-12-12 18:18:38 +01:00
{
2002-12-30 17:07:23 +01:00
/* Create new listening socket on specified port */
2001-12-12 18:18:38 +01:00
2001-12-13 00:32:02 +01:00
struct sockaddr_in addr ;
2003-09-11 14:05:28 +02:00
struct in_addr inaddr ;
2005-03-19 19:43:48 +01:00
int sock ;
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
2005-03-19 19:43:48 +01:00
char name [ CLIENT_ID_LEN ] , * info ;
2003-02-23 13:04:05 +01:00
# endif
2003-04-25 18:47:52 +02: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 ) ) ;
2003-09-11 14:05:28 +02:00
memset ( & inaddr , 0 , sizeof ( inaddr ) ) ;
2001-12-13 00:32:02 +01:00
addr . sin_family = AF_INET ;
addr . sin_port = htons ( Port ) ;
2003-09-11 14:05:28 +02:00
if ( Conf_ListenAddress [ 0 ] )
{
# ifdef HAVE_INET_ATON
if ( inet_aton ( Conf_ListenAddress , & inaddr ) = = 0 )
# else
inaddr . s_addr = inet_addr ( Conf_ListenAddress ) ;
if ( inaddr . s_addr = = ( unsigned ) - 1 )
# endif
{
Log ( LOG_CRIT , " Can't listen on %s:%u: can't convert ip address %s! " , Conf_ListenAddress , Port , Conf_ListenAddress ) ;
2005-03-19 19:43:48 +01:00
return false ;
2003-09-11 14:05:28 +02:00
}
}
else inaddr . s_addr = htonl ( INADDR_ANY ) ;
addr . sin_addr = inaddr ;
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 ) ) ;
2005-03-19 19:43:48 +01:00
return false ;
2001-12-12 18:18:38 +01:00
}
2005-03-19 19:43:48 +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 ) ;
2005-03-19 19:43:48 +01:00
return false ;
2001-12-12 18:18:38 +01:00
}
/* 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 ) ;
2005-03-19 19:43:48 +01:00
return false ;
2001-12-12 18:18:38 +01:00
}
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
2003-09-11 14:05:28 +02:00
if ( Conf_ListenAddress [ 0 ] ) Log ( LOG_INFO , " Now listening on %s:%d (socket %d). " , Conf_ListenAddress , Port , sock ) ;
else Log ( LOG_INFO , " Now listening on 0.0.0.0:%d (socket %d) . " , Port, sock ) ;
2001-12-13 00:32:02 +01:00
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
/* Get best server description text */
if ( ! Conf_ServerInfo [ 0 ] ) info = Conf_ServerName ;
else
{
/* Use server info string */
info = NULL ;
if ( Conf_ServerInfo [ 0 ] = = ' [ ' )
{
/* Cut off leading hostname part in "[]" */
info = strchr ( Conf_ServerInfo , ' ] ' ) ;
if ( info )
{
info + + ;
while ( * info = = ' ' ) info + + ;
}
}
if ( ! info ) info = Conf_ServerInfo ;
}
/* Add port number to description if non-standard */
if ( Port ! = 6667 ) snprintf ( name , sizeof ( name ) , " %s (port %u) " , info , Port ) ;
else strlcpy ( name , info , sizeof ( name ) ) ;
/* Register service */
Rendezvous_Register ( name , RENDEZVOUS_TYPE , Port ) ;
# endif
2005-03-19 19:43:48 +01:00
return true ;
2001-12-26 15:45:37 +01:00
} /* Conn_NewListener */
2001-12-12 18:18:38 +01:00
2005-03-19 19:43:48 +01:00
GLOBAL void
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-12-30 17:07:23 +01:00
CONN_ID i , idx ;
2005-03-19 19:43:48 +01:00
bool 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
{
2005-03-19 19:43:48 +01:00
timeout = true ;
2002-01-02 03:44:36 +01:00
2003-02-23 13:04:05 +01:00
# ifdef RENDEZVOUS
Rendezvous_Handler ( ) ;
# endif
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 ( ) ;
2003-11-06 00:24:48 +01:00
t = time ( NULL ) ;
2001-12-26 04:20:53 +01:00
/* 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
{
2003-11-06 00:24:48 +01:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . rdatalen > 0 ) & &
( My_Connections [ i ] . delaytime < t ) )
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? */
2005-03-19 19:43:48 +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
{
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-11-27 00:07:24 +01:00
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-12-30 17:07:23 +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
{
2005-04-23 16:28:44 +02:00
if ( My_Connections [ i ] . sock > NONE ) {
if ( Conn_OPTION_ISSET ( & My_Connections [ i ] , CONN_ISCONNECTING ) ) {
FD_SET ( My_Connections [ i ] . sock , & write_sockets ) ;
}
}
2002-03-02 01:23:32 +01:00
}
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 ;
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-29 21:17:25 +01:00
{
2005-04-23 16:28:44 +02:00
if ( My_Connections [ i ] . sock > NONE ) {
2005-06-01 23:28:50 +02:00
if ( My_Connections [ i ] . res_stat ) {
2005-04-23 16:28:44 +02:00
/* wait for completion of Resolver Sub-Process */
FD_CLR ( My_Connections [ i ] . sock , & read_sockets ) ;
continue ;
}
if ( Conn_OPTION_ISSET ( & My_Connections [ i ] , CONN_ISCONNECTING ) ) {
/* wait for completion of connect() */
FD_CLR ( My_Connections [ i ] . sock , & read_sockets ) ;
continue ;
}
2002-03-02 01:23:32 +01:00
}
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 ) ;
}
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 ;
2003-11-06 00:24:48 +01:00
if ( timeout ) tv . tv_sec = 1 ;
2002-11-23 18:04:07 +01:00
else tv . tv_sec = 0 ;
2003-04-25 18:47:52 +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 ) ) ;
2003-03-31 17:54:21 +02:00
Log ( LOG_ALERT , " %s exiting due to fatal errors! " , PACKAGE_NAME ) ;
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 ;
2003-04-25 18:47:52 +02:00
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
2005-03-19 19:43:48 +01:00
GLOBAL bool
Conn_WriteStr ( CONN_ID Idx , char * Format , . . . )
2002-05-30 18:52:20 +02:00
# else
2005-03-19 19:43:48 +01:00
GLOBAL bool
2002-05-30 18:52:20 +02:00
Conn_WriteStr ( Idx , Format , va_alist )
CONN_ID Idx ;
2005-03-19 19:43:48 +01:00
char * Format ;
2002-05-30 18:52:20 +02:00
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
2005-03-19 19:43:48 +01:00
* getrennt und false geliefert . */
2001-12-26 00:15:16 +01:00
2005-03-19 19:43:48 +01:00
char buffer [ COMMAND_LEN ] ;
bool ok ;
2001-12-23 23:02:54 +01:00
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
2005-01-20 00:33:53 +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 ) ;
2005-03-19 19:43:48 +01:00
Conn_Close ( Idx , " Text too long to send! " , NULL , false ) ;
return false ;
2001-12-15 01:11:55 +01:00
}
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
2002-12-26 17:48:14 +01:00
strlcat ( buffer , " \r \n " , sizeof ( buffer ) ) ;
2001-12-24 02:32:33 +01:00
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 */
2005-03-19 19:43:48 +01:00
GLOBAL bool
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
2005-03-19 19:43:48 +01:00
* 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
{
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-09-26 17:59:02 +02:00
Log ( LOG_DEBUG , " Skipped write on closed socket (connection %d). " , Idx ) ;
2003-11-06 00:24:48 +01:00
# endif
2005-03-19 19:43:48 +01:00
return false ;
2002-09-26 17:59:02 +02:00
}
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 . . . */
2005-06-04 13:49:20 +02:00
if ( ! Handle_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 ) ;
2005-03-19 19:43:48 +01:00
Conn_Close ( Idx , " Write buffer overflow! " , NULL , false ) ;
return false ;
2002-11-27 00:07:24 +01:00
}
2001-12-15 01:11:55 +01:00
}
2001-12-26 00:15:16 +01:00
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) ) {
2002-11-27 00:07:24 +01:00
/* Daten komprimieren und in Puffer kopieren */
2005-03-19 19:43:48 +01:00
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 ;
2005-03-19 19:43:48 +01:00
return true ;
2001-12-15 01:11:55 +01:00
} /* Conn_Write */
2005-03-19 19:43:48 +01:00
GLOBAL void
Conn_Close ( CONN_ID Idx , char * LogMsg , char * FwdMsg , bool InformClient )
2001-12-25 23:03:47 +01:00
{
2002-12-27 14:20:13 +01:00
/* Close connection. Open pipes of asyncronous resolver
* sub - processes are closed down . */
2001-12-25 23:03:47 +01:00
2002-01-02 03:44:36 +01:00
CLIENT * c ;
2005-03-19 19:43:48 +01:00
char * txt ;
double in_k , out_k ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-03-19 19:43:48 +01:00
double in_z_k , out_z_k ;
int in_p , out_p ;
2002-11-27 00:07:24 +01:00
# endif
2002-03-11 01:04:48 +01:00
2002-11-05 15:18:39 +01:00
assert ( Idx > NONE ) ;
2001-12-25 23:03:47 +01:00
2003-02-21 20:19:27 +01:00
/* Is this link already shutting down? */
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ISCLOSING ) ) {
2003-02-21 20:19:27 +01:00
/* Conn_Close() has been called recursively for this link;
2005-06-04 13:49:20 +02:00
* probabe reason : Handle_Write ( ) failed - - see below . */
2004-12-22 18:37:41 +01:00
# ifdef DEBUG
Log ( LOG_DEBUG , " Recursive request to close connection: %d " , Idx ) ;
# endif
2003-02-21 20:19:27 +01:00
return ;
}
2004-04-25 16:06:11 +02:00
assert ( My_Connections [ Idx ] . sock > NONE ) ;
2003-02-21 20:19:27 +01:00
/* Mark link as "closing" */
2005-04-23 16:28:44 +02:00
Conn_OPTION_ADD ( & My_Connections [ Idx ] , CONN_ISCLOSING ) ;
2004-02-28 03:01:01 +01:00
if ( LogMsg ) txt = LogMsg ;
else txt = FwdMsg ;
if ( ! txt ) txt = " Reason unknown " ;
Log ( LOG_INFO , " Shutting down connection %d (%s) with %s:%d ... " , Idx , LogMsg ? LogMsg : FwdMsg , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) ) ;
2003-02-21 20:19:27 +01:00
2002-12-27 14:20:13 +01:00
/* Search client, if any */
2002-10-09 15:15:08 +02:00
c = Client_GetFromConn ( Idx ) ;
2002-12-27 14:20:13 +01:00
/* Should the client be informed? */
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-12-27 14:20:13 +01:00
/* Send statistics to client if registered as user: */
2002-10-09 15:15:08 +02:00
if ( ( c ! = NULL ) & & ( Client_Type ( c ) = = CLIENT_USER ) )
{
2005-03-19 19:43:48 +01: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
2002-12-27 14:20:13 +01:00
/* Send ERROR to client (see RFC!) */
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
}
2001-12-25 23:03:47 +01:00
2002-12-27 14:20:13 +01:00
/* Try to write out the write buffer */
2005-06-04 13:49:20 +02:00
( void ) Handle_Write ( Idx ) ;
2002-11-28 17:56:20 +01:00
2002-12-27 14:20:13 +01:00
/* Shut down socket */
2001-12-25 23:03:47 +01:00
if ( close ( My_Connections [ Idx ] . sock ) ! = 0 )
{
2005-05-23 01:55:57 +02:00
/* Oops, we can't close the socket!? This is ... ugly! */
Log ( LOG_CRIT , " Error closing connection %d (socket %d) with %s:%d - %s! (ignored) " , Idx , My_Connections [ Idx ] . sock , My_Connections [ Idx ] . host , ntohs ( My_Connections [ Idx ] . addr . sin_port ) , strerror ( errno ) ) ;
2001-12-25 23:03:47 +01:00
}
2002-12-27 14:20:13 +01:00
/* Mark socket as invalid: */
2002-10-15 00:21:00 +02:00
FD_CLR ( My_Connections [ Idx ] . sock , & My_Sockets ) ;
My_Connections [ Idx ] . sock = NONE ;
2001-12-25 23:03:47 +01:00
2002-12-27 14:20:13 +01:00
/* If there is still a client, unregister it now */
2005-03-19 19:43:48 +01:00
if ( c ) Client_Destroy ( c , LogMsg , FwdMsg , true ) ;
2001-12-25 23:03:47 +01:00
2002-12-27 14:20:13 +01:00
/* Calculate statistics and log information */
2005-03-19 19:43:48 +01:00
in_k = ( double ) My_Connections [ Idx ] . bytes_in / 1024 ;
out_k = ( double ) My_Connections [ Idx ] . bytes_out / 1024 ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) ) {
2005-03-19 19:43:48 +01:00
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-27 14:20:13 +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 ) ;
}
else
# endif
{
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 ) ;
}
/* Is there a resolver sub-process running? */
2001-12-29 21:17:25 +01:00
if ( My_Connections [ Idx ] . res_stat )
2005-06-01 23:28:50 +02:00
FreeRes_stat ( & My_Connections [ Idx ] ) ;
2002-01-02 03:44:36 +01:00
2002-12-27 14:20:13 +01:00
/* Servers: Modify time of next connect attempt? */
2002-12-30 01:01:42 +01:00
Conf_UnsetServer ( Idx ) ;
2002-01-02 03:44:36 +01:00
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-12-27 14:20:13 +01:00
/* Clean up zlib, if link was compressed */
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) ) {
2002-11-27 00:07:24 +01:00
inflateEnd ( & My_Connections [ Idx ] . zip . in ) ;
deflateEnd ( & My_Connections [ Idx ] . zip . out ) ;
}
# endif
2002-12-27 14:20:13 +01:00
/* Clean up connection structure (=free it) */
2002-10-15 00:21:00 +02:00
Init_Conn_Struct ( Idx ) ;
2004-12-22 18:37:41 +01:00
# ifdef DEBUG
Log ( LOG_DEBUG , " Shutdown of connection %d completed. " , Idx ) ;
# endif
2001-12-25 23:03:47 +01:00
} /* Conn_Close */
2005-03-19 19:43:48 +01:00
GLOBAL void
Conn_SyncServerStruct ( void )
2003-03-27 02:20:22 +01:00
{
/* Synchronize server structures (connection IDs):
* connections < - > configuration */
CLIENT * client ;
CONN_ID i ;
2005-03-19 19:43:48 +01:00
int c ;
2003-03-27 02:20:22 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
{
/* Established connection? */
if ( My_Connections [ i ] . sock < = NONE ) continue ;
/* Server connection? */
client = Client_GetFromConn ( i ) ;
if ( ( ! client ) | | ( Client_Type ( client ) ! = CLIENT_SERVER ) ) continue ;
for ( c = 0 ; c < MAX_SERVERS ; c + + )
{
/* Configured server? */
if ( ! Conf_Server [ c ] . host [ 0 ] ) continue ;
/* Duplicate? */
if ( strcmp ( Conf_Server [ c ] . name , Client_ID ( client ) ) = = 0 ) Conf_Server [ c ] . conn_id = i ;
}
}
} /* SyncServerStruct */
2005-03-19 19:43:48 +01: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 */
2005-03-19 19:43:48 +01:00
LOCAL bool
2002-05-27 15:09:26 +02:00
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
2005-03-19 19:43:48 +01:00
int len , res , err ;
2003-04-21 12:52:26 +02:00
socklen_t sock_len ;
2003-01-15 15:28:59 +01:00
CLIENT * c ;
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
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ISCONNECTING ) ) {
/* connect() has finished, check result */
2002-03-02 01:23:32 +01:00
2005-04-23 16:28:44 +02:00
Conn_OPTION_DEL ( & My_Connections [ Idx ] , CONN_ISCONNECTING ) ;
2002-03-02 01:23:32 +01:00
/* Ergebnis des connect() ermitteln */
2003-04-21 12:52:26 +02:00
sock_len = sizeof ( err ) ;
res = getsockopt ( My_Connections [ Idx ] . sock , SOL_SOCKET , SO_ERROR , & err , & sock_len ) ;
assert ( sock_len = = sizeof ( err ) ) ;
2002-03-02 01:23:32 +01:00
/* Fehler aufgetreten? */
if ( ( res ! = 0 ) | | ( err ! = 0 ) )
{
/* Fehler! */
if ( res ! = 0 ) Log ( LOG_CRIT , " getsockopt (connection %d): %s! " , Idx , strerror ( errno ) ) ;
2002-12-30 01:01:42 +01:00
else Log ( LOG_CRIT , " Can't connect socket to \" %s:%d \" (connection %d) : % s ! " , My_Connections[Idx].host, Conf_Server[Conf_GetServer( Idx )].port, Idx, strerror( err )) ;
2002-03-02 01:23:32 +01:00
2003-01-15 15:28:59 +01:00
/* Clean up socket, connection and client structures */
2002-03-02 01:23:32 +01:00
FD_CLR ( My_Connections [ Idx ] . sock , & My_Sockets ) ;
2003-01-15 15:28:59 +01:00
c = Client_GetFromConn ( Idx ) ;
if ( c ) Client_DestroyNow ( c ) ;
2002-03-02 01:23:32 +01:00
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 */
2002-12-30 01:01:42 +01:00
Conf_Server [ Conf_GetServer ( Idx ) ] . lasttry = time ( NULL ) ;
Conf_UnsetServer ( Idx ) ;
2002-03-02 01:29:11 +01:00
2005-03-19 19:43:48 +01:00
return false ;
2002-03-02 01:23:32 +01:00
}
2004-02-28 03:01:01 +01:00
Log ( LOG_INFO , " Connection %d with \" %s:%d \" established. Now logging in ... " , Idx , My_Connections [ Idx ] . host , Conf_Server [ Conf_GetServer ( Idx ) ] . port ) ;
2002-03-02 01:23:32 +01:00
2004-02-28 03:01:01 +01:00
/* Send PASS and SERVER command to peer */
2002-12-30 01:01:42 +01:00
Conn_WriteStr ( Idx , " PASS %s %s " , Conf_Server [ Conf_GetServer ( Idx ) ] . 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
}
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-06-04 13:49:20 +02:00
if ( ( My_Connections [ Idx ] . wdatalen < = 0 ) & & ( ! My_Connections [ Idx ] . zip . wdatalen ) )
return true ;
/* write buffer empty, but not compression buf? -> flush compression buf. */
2002-11-27 00:07:24 +01:00
if ( My_Connections [ Idx ] . wdatalen = = 0 ) Zip_Flush ( Idx ) ;
2005-06-04 13:49:20 +02:00
# else
if ( My_Connections [ Idx ] . wdatalen < = 0 )
return true ;
2002-11-27 00:07:24 +01:00
# endif
2005-06-01 23:28:50 +02:00
len = write ( My_Connections [ Idx ] . sock , My_Connections [ Idx ] . wbuf , My_Connections [ Idx ] . wdatalen ) ;
2005-06-04 13:49:20 +02:00
if ( len < 0 ) {
if ( errno = = EAGAIN | | errno = = EINTR )
return true ;
2002-11-20 16:48:41 +01:00
2005-06-04 13:49:20 +02:00
Log ( LOG_ERR , " Write error on connection %d (socket %d): %s! " , Idx ,
My_Connections [ Idx ] . sock , strerror ( errno ) ) ;
2005-03-19 19:43:48 +01:00
Conn_Close ( Idx , " Write error! " , NULL , false ) ;
return false ;
2001-12-15 01:11:55 +01:00
}
2001-12-26 00:15:16 +01:00
2005-06-04 13:49:20 +02:00
/* Update buffer len and move any data not yet written to beginning of buf */
2001-12-15 01:11:55 +01:00
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
2005-03-19 19:43:48 +01:00
return true ;
2001-12-15 01:11:55 +01:00
} /* Handle_Write */
2001-12-13 00:32:02 +01:00
2005-03-19 19:43:48 +01: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
2003-12-26 16:55:07 +01:00
# ifdef TCPWRAP
2003-03-07 15:35:52 +01:00
struct request_info req ;
# endif
2001-12-13 00:32:02 +01:00
struct sockaddr_in new_addr ;
2005-03-19 19:43:48 +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 ;
2005-03-19 19:43:48 +01:00
long new_size , cnt ;
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 ;
}
2003-04-25 18:47:52 +02:00
2003-12-26 16:55:07 +01:00
# ifdef TCPWRAP
2003-03-07 15:35:52 +01:00
/* Validate socket using TCP Wrappers */
2003-03-31 17:54:21 +02:00
request_init ( & req , RQ_DAEMON , PACKAGE_NAME , RQ_FILE , new_sock , RQ_CLIENT_SIN , & new_addr , NULL ) ;
2004-02-03 21:28:30 +01:00
fromhost ( & req ) ;
2003-03-07 15:35:52 +01:00
if ( ! hosts_access ( & req ) )
{
/* Access denied! */
Log ( deny_severity , " Refused connection from %s (by TCP Wrappers)! " , inet_ntoa ( new_addr . sin_addr ) ) ;
2003-03-07 18:16:49 +01:00
Simple_Message ( new_sock , " ERROR :Connection refused " ) ;
2003-03-07 15:35:52 +01:00
close ( new_sock ) ;
return ;
}
# endif
2001-12-26 00:15:16 +01:00
2002-11-20 16:48:41 +01:00
/* Socket initialisieren */
Init_Socket ( new_sock ) ;
2003-11-05 22:41:01 +01:00
/* Check IP-based connection limit */
cnt = Count_Connections ( new_addr ) ;
if ( ( Conf_MaxConnectionsIP > 0 ) & & ( cnt > = Conf_MaxConnectionsIP ) )
{
2004-10-05 01:09:04 +02:00
/* Access denied, too many connections from this IP address! */
Log ( LOG_ERR , " Refused connection from %s: too may connections (%ld) from this IP address! " , inet_ntoa ( new_addr . sin_addr ) , cnt ) ;
Simple_Message ( new_sock , " ERROR :Connection refused, too many connections from your IP address! " ) ;
2003-11-05 22:41:01 +01:00
close ( new_sock ) ;
return ;
}
2002-11-20 16:48:41 +01:00
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 ;
2003-04-25 18:47:52 +02:00
2002-11-03 00:00:45 +01:00
/* Im bisherigen Pool wurde keine freie Connection-Struktur mehr gefunden.
* Wenn erlaubt und moeglich muss nun der Pool vergroessert werden : */
2003-04-25 18:47:52 +02:00
2002-11-03 00:00:45 +01:00
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 ) ;
2003-03-07 18:16:49 +01:00
Simple_Message ( new_sock , " ERROR :Connection limit reached " ) ;
2002-11-03 00:00:45 +01:00
close ( new_sock ) ;
return ;
}
if ( new_size > Conf_MaxConnections ) new_size = Conf_MaxConnections ;
}
2002-12-30 17:07:23 +01:00
if ( new_size < Pool_Size )
{
2005-04-16 22:50:03 +02:00
Log ( LOG_ALERT , " Can't accept connection: limit (%d) reached -- overflow! " , Pool_Size ) ;
2003-03-07 18:16:49 +01:00
Simple_Message ( new_sock , " ERROR :Connection limit reached " ) ;
2002-12-30 17:07:23 +01:00
close ( new_sock ) ;
return ;
}
2003-04-25 18:47:52 +02:00
2004-03-11 23:16:31 +01:00
ptr = ( POINTER * ) realloc ( My_Connections , sizeof ( CONNECTION ) * new_size ) ;
2002-11-03 00:00:45 +01:00
if ( ! ptr )
{
2005-01-17 12:57:39 +01:00
Log ( LOG_EMERG , " Can't allocate memory! [New_Connection] " ) ;
Simple_Message ( new_sock , " ERROR: Internal error " ) ;
close ( new_sock ) ;
return ;
2002-11-03 00:00:45 +01:00
}
2005-01-17 12:57:39 +01:00
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2005-01-17 12:57:39 +01:00
Log ( LOG_DEBUG , " Allocated new connection pool for %ld items (%ld bytes). [realloc()] " , new_size , sizeof ( CONNECTION ) * new_size ) ;
2003-11-06 00:24:48 +01:00
# endif
2003-04-25 18:47:52 +02:00
2002-12-17 12:46:54 +01:00
/* Adjust pointer to new block */
2004-03-11 23:16:31 +01:00
My_Connections = ( CONNECTION * ) ptr ;
2003-04-25 18:47:52 +02:00
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 ;
2003-04-25 18:47:52 +02:00
2002-12-17 12:46:54 +01:00
/* 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 */
2005-03-19 19:43:48 +01:00
c = Client_NewLocal ( idx , inet_ntoa ( new_addr . sin_addr ) , CLIENT_UNKNOWN , false ) ;
2002-05-19 15:05:22 +02:00
if ( ! c )
2001-12-23 23:02:54 +01:00
{
Log ( LOG_ALERT , " Can't accept connection: can't create client structure! " ) ;
2003-03-07 18:16:49 +01:00
Simple_Message ( new_sock , " ERROR :Internal error " ) ;
2001-12-23 23:02:54 +01:00
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-12-26 18:04:54 +01:00
strlcpy ( My_Connections [ idx ] . host , inet_ntoa ( new_addr . sin_addr ) , sizeof ( My_Connections [ idx ] . host ) ) ;
2002-11-22 17:35:19 +01:00
Client_SetHostname ( c , My_Connections [ idx ] . host ) ;
2003-12-27 14:01:12 +01:00
# ifdef IDENTAUTH
s = Resolve_Addr ( & new_addr , My_Connections [ idx ] . sock ) ;
# else
2002-05-27 15:09:26 +02:00
s = Resolve_Addr ( & new_addr ) ;
2003-12-27 14:01:12 +01:00
# endif
2005-06-01 23:28:50 +02:00
/* resolver process has been started */
if ( s ) My_Connections [ idx ] . res_stat = s ;
2003-04-25 18:47:52 +02:00
2002-08-26 02:03:15 +02:00
/* Penalty-Zeit setzen */
2002-10-10 17:01:12 +02:00
Conn_SetPenalty ( idx , 4 ) ;
2001-12-13 00:32:02 +01:00
} /* New_Connection */
2002-05-27 15:09:26 +02:00
LOCAL CONN_ID
2005-03-19 19:43:48 +01:00
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 . . . */
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-10-15 11:24:54 +02:00
Log ( LOG_DEBUG , " Socket2Index: can't get connection for socket %d! " , Sock ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-10-15 11:24:54 +02:00
return NONE ;
}
2002-10-15 00:21:00 +02:00
else return idx ;
2001-12-13 00:32:02 +01:00
} /* Socket2Index */
2005-03-19 19:43:48 +01:00
LOCAL void
2002-05-27 15:09:26 +02:00
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
2005-03-19 19:43:48 +01:00
int len , bsize ;
2003-12-26 16:55:07 +01:00
# ifdef 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 ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-11-28 13:17:38 +01:00
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
2003-12-26 16:55:07 +01:00
# ifdef 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 */
2004-10-05 01:23:41 +02:00
Log ( LOG_ERR , " Receive buffer overflow (connection %d): %d bytes! " , Idx , My_Connections [ Idx ] . rdatalen ) ;
2005-03-19 19:43:48 +01:00
Conn_Close ( Idx , " Receive buffer overflow! " , NULL , false ) ;
2002-01-03 03:25:36 +01:00
return ;
}
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) ) {
2002-11-27 00:07:24 +01:00
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 ) ) ;
2005-03-19 19:43:48 +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 ) ) ;
2005-03-19 19:43:48 +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 */
2005-03-19 19:43:48 +01:00
LOCAL bool
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.
2005-03-19 19:43:48 +01:00
* 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
2005-03-19 19:43:48 +01:00
char * ptr1 , * ptr2 ;
2002-10-21 15:45:07 +02:00
# endif
2005-03-19 19:43:48 +01:00
char * ptr ;
int len , delta ;
bool action , result ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-03-19 19:43:48 +01:00
bool old_z ;
2002-11-28 13:17:38 +01:00
# endif
2001-12-26 00:15:16 +01:00
2005-03-19 19:43:48 +01:00
result = false ;
2002-11-27 00:07:24 +01:00
do
2001-12-26 00:15:16 +01:00
{
2003-11-06 00:24:48 +01:00
/* Check penalty */
if ( My_Connections [ Idx ] . delaytime > time ( NULL ) ) return result ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-11-27 00:07:24 +01:00
/* ggf. noch unkomprimiete Daten weiter entpacken */
2005-04-23 16:28:44 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) )
2005-03-19 19:43:48 +01:00
if ( ! Unzip_Buffer ( Idx ) ) return false ;
2002-01-03 03:25:36 +01:00
# endif
2003-04-25 18:47:52 +02:00
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 " ) ;
2003-04-25 18:47:52 +02:00
2002-11-27 00:07:24 +01:00
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
2003-04-25 18:47:52 +02:00
2005-03-19 19:43:48 +01:00
action = false ;
2002-11-27 00:07:24 +01:00
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 ) ;
2005-03-19 19:43:48 +01:00
Conn_Close ( Idx , NULL , " Request too long " , true ) ;
return false ;
2002-11-27 00:07:24 +01:00
}
2002-11-28 13:17:38 +01:00
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-11-28 13:17:38 +01:00
/* 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 + + ;
2005-03-19 19:43:48 +01:00
if ( ! Parse_Request ( Idx , My_Connections [ Idx ] . rbuf ) ) return false ;
else action = true ;
2002-11-27 00:07:24 +01:00
}
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
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2002-11-28 13:17:38 +01:00
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 */
2004-12-22 18:37:41 +01:00
if ( My_Connections [ Idx ] . rdatalen > ZREADBUFFER_LEN )
2002-11-28 13:17:38 +01:00
{
2004-12-22 18:37:41 +01:00
/* Hupsa! Soviel Platz haben wir aber gar nicht! */
Log ( LOG_ALERT , " Can't move receive buffer: No space left in unzip buffer (need %d bytes)! " , My_Connections [ Idx ] . rdatalen ) ;
2005-03-19 19:43:48 +01:00
return false ;
2002-11-28 13:17:38 +01:00
}
2004-12-22 18:37:41 +01:00
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 ;
# ifdef DEBUG
Log ( LOG_DEBUG , " Moved already received data (%d bytes) to uncompression buffer. " , My_Connections [ Idx ] . zip . rdatalen ) ;
# endif /* DEBUG */
2002-11-28 13:17:38 +01:00
}
2004-12-22 18:37:41 +01:00
# endif /* ZLIB */
2001-12-13 02:33:09 +01:00
}
2003-04-25 18:47:52 +02:00
2005-03-19 19:43:48 +01:00
if ( action ) result = true ;
2002-11-27 00:07:24 +01:00
} while ( action ) ;
2003-04-25 18:47:52 +02: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
2005-03-19 19:43:48 +01: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-12-30 17:07:23 +01:00
CONN_ID 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 */
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-03-27 00:47:45 +01:00
Log ( LOG_DEBUG , " Connection %d: Ping timeout: %d seconds. " , i , Conf_PongTimeout ) ;
2003-11-06 00:24:48 +01:00
# endif
2005-03-19 19:43:48 +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 */
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2001-12-26 04:20:53 +01:00
Log ( LOG_DEBUG , " Connection %d: sending PING ... " , i ) ;
2003-11-06 00:24:48 +01:00
# endif
2001-12-26 04:20:53 +01:00
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 */
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-02-27 15:47:04 +01:00
Log ( LOG_DEBUG , " Connection %d timed out ... " , i ) ;
2003-11-06 00:24:48 +01:00
# endif
2005-03-19 19:43:48 +01:00
Conn_Close ( i , NULL , " Timeout " , false ) ;
2002-01-02 03:44:36 +01:00
}
}
}
} /* Check_Connections */
2005-03-19 19:43:48 +01:00
LOCAL void
Check_Servers ( void )
2002-01-02 03:44:36 +01:00
{
2002-12-30 01:01:42 +01:00
/* Check if we can establish further server links */
2002-01-02 03:44:36 +01:00
RES_STAT * s ;
2002-12-30 01:01:42 +01:00
CONN_ID idx ;
2005-03-19 19:43:48 +01:00
int i , n ;
2002-02-19 21:05:37 +01:00
2002-12-30 01:01:42 +01:00
/* Serach all connections, are there results from the resolver? */
for ( idx = 0 ; idx < Pool_Size ; idx + + )
2002-01-02 03:44:36 +01:00
{
2002-12-30 01:01:42 +01:00
if ( My_Connections [ idx ] . sock ! = SERVER_WAIT ) continue ;
2002-03-11 01:04:48 +01:00
2002-12-30 01:01:42 +01:00
/* IP resolved? */
if ( My_Connections [ idx ] . res_stat = = NULL ) New_Server ( Conf_GetServer ( idx ) , idx ) ;
}
2002-01-02 03:44:36 +01:00
2002-12-30 01:01:42 +01:00
/* Check all configured servers */
for ( i = 0 ; i < MAX_SERVERS ; i + + )
{
2002-12-31 17:13:29 +01:00
/* Valid outgoing server which isn't already connected or disabled? */
if ( ( ! Conf_Server [ i ] . host [ 0 ] ) | | ( ! Conf_Server [ i ] . port > 0 ) | | ( Conf_Server [ i ] . conn_id > NONE ) | | ( Conf_Server [ i ] . flags & CONF_SFLAG_DISABLED ) ) continue ;
2002-03-10 18:50:48 +01:00
2002-12-30 01:01:42 +01:00
/* Is there already a connection in this group? */
if ( Conf_Server [ i ] . group > NONE )
{
for ( n = 0 ; n < MAX_SERVERS ; n + + )
2002-03-10 18:50:48 +01:00
{
2002-12-30 01:01:42 +01:00
if ( n = = i ) continue ;
if ( ( Conf_Server [ n ] . conn_id > NONE ) & & ( Conf_Server [ n ] . group = = Conf_Server [ i ] . group ) ) break ;
2002-03-10 18:50:48 +01:00
}
2002-12-30 01:01:42 +01:00
if ( n < MAX_SERVERS ) continue ;
2002-01-02 03:44:36 +01:00
}
2002-03-11 01:04:48 +01:00
2002-12-30 01:01:42 +01:00
/* Check last connect attempt? */
2002-01-02 03:44:36 +01:00
if ( Conf_Server [ i ] . lasttry > time ( NULL ) - Conf_ConnectRetry ) continue ;
2002-12-30 01:01:42 +01:00
/* Okay, try to connect now */
2002-01-02 03:44:36 +01:00
Conf_Server [ i ] . lasttry = time ( NULL ) ;
2002-12-30 01:01:42 +01:00
/* Search free connection structure */
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 ;
}
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-01-02 03:44:36 +01:00
Log ( LOG_DEBUG , " Preparing connection %d for \" %s \" ... " , idx , Conf_Server [ i ] . host ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-01-02 03:44:36 +01:00
/* Verbindungs-Struktur initialisieren */
Init_Conn_Struct ( idx ) ;
My_Connections [ idx ] . sock = SERVER_WAIT ;
2002-12-30 01:01:42 +01:00
Conf_Server [ i ] . conn_id = idx ;
2002-03-11 01:04:48 +01:00
2002-12-30 01:01:42 +01:00
/* Resolve Hostname. If this fails, try to use it as an IP address */
strlcpy ( Conf_Server [ i ] . ip , Conf_Server [ i ] . host , sizeof ( Conf_Server [ i ] . ip ) ) ;
2002-12-26 18:04:54 +01:00
strlcpy ( My_Connections [ idx ] . host , Conf_Server [ i ] . host , sizeof ( My_Connections [ idx ] . host ) ) ;
2002-05-27 15:09:26 +02:00
s = Resolve_Name ( Conf_Server [ i ] . host ) ;
2005-06-01 23:28:50 +02:00
/* resolver process running? */
if ( s ) My_Connections [ idx ] . res_stat = s ;
2002-01-02 03:44:36 +01:00
}
} /* Check_Servers */
2005-03-19 19:43:48 +01:00
LOCAL void
New_Server ( int Server , CONN_ID Idx )
2002-01-02 03:44:36 +01:00
{
2003-04-25 18:47:52 +02:00
/* Establish new server link */
2002-01-02 03:44:36 +01:00
struct sockaddr_in new_addr ;
struct in_addr inaddr ;
2005-03-19 19:43:48 +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
2003-04-25 18:47:52 +02:00
/* Did we get a valid IP address? */
2002-01-02 03:44:36 +01:00
if ( ! Conf_Server [ Server ] . ip [ 0 ] )
{
2003-04-25 18:47:52 +02:00
/* No. Free connection structure and abort: */
2002-01-02 03:44:36 +01:00
Init_Conn_Struct ( Idx ) ;
2003-04-25 18:47:52 +02:00
Conf_Server [ Server ] . conn_id = NONE ;
2002-01-02 03:44:36 +01:00
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
{
2003-04-25 18:47:52 +02:00
/* Can't convert IP address */
2002-01-02 03:44:36 +01:00
Init_Conn_Struct ( Idx ) ;
2003-04-25 18:47:52 +02:00
Conf_Server [ Server ] . conn_id = NONE ;
2002-01-02 03:44:36 +01:00
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 )
{
2003-04-25 18:47:52 +02:00
/* Can't create socket */
2002-01-02 03:44:36 +01:00
Init_Conn_Struct ( Idx ) ;
2003-04-25 18:47:52 +02:00
Conf_Server [ Server ] . conn_id = NONE ;
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
{
2003-04-25 18:47:52 +02:00
/* Can't connect socket */
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 ) ;
2003-04-25 18:47:52 +02:00
Conf_Server [ Server ] . conn_id = NONE ;
2002-01-02 03:44:36 +01:00
return ;
}
/* Client-Struktur initialisieren */
2005-03-19 19:43:48 +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
{
2003-04-25 18:47:52 +02:00
/* Can't create new client structure */
2002-01-02 03:44:36 +01:00
close ( new_sock ) ;
Init_Conn_Struct ( Idx ) ;
2003-04-25 18:47:52 +02:00
Conf_Server [ Server ] . conn_id = NONE ;
2002-01-02 03:44:36 +01:00
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
2003-04-25 18:47:52 +02:00
/* Register connection */
2002-01-02 03:44:36 +01:00
My_Connections [ Idx ] . sock = new_sock ;
My_Connections [ Idx ] . addr = new_addr ;
2002-12-26 18:04:54 +01:00
strlcpy ( My_Connections [ Idx ] . host , Conf_Server [ Server ] . host , sizeof ( My_Connections [ Idx ] . host ) ) ;
2002-01-02 03:44:36 +01:00
2003-04-25 18:47:52 +02:00
/* Register new socket */
2002-01-02 03:44:36 +01:00
FD_SET ( new_sock , & My_Sockets ) ;
2005-04-23 16:28:44 +02:00
Conn_OPTION_ADD ( & My_Connections [ Idx ] , CONN_ISCONNECTING ) ;
2002-05-27 15:09:26 +02:00
if ( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock ;
2003-04-25 18:47:52 +02:00
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-10-15 11:24:54 +02:00
Log ( LOG_DEBUG , " Registered new connection %d on socket %d. " , Idx , My_Connections [ Idx ] . sock ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-01-02 03:44:36 +01:00
} /* New_Server */
2001-12-26 04:20:53 +01:00
2005-03-19 19:43:48 +01:00
LOCAL void
2002-12-30 17:07:23 +01:00
Init_Conn_Struct ( CONN_ID Idx )
2001-12-29 21:17:25 +01:00
{
2005-03-20 12:00:31 +01:00
time_t now = time ( NULL ) ;
2001-12-29 21:17:25 +01:00
/* Connection-Struktur initialisieren */
2005-03-20 12:00:31 +01:00
memset ( & My_Connections [ Idx ] , 0 , sizeof ( CONNECTION ) ) ;
2001-12-29 21:17:25 +01:00
My_Connections [ Idx ] . sock = NONE ;
2005-03-20 12:00:31 +01:00
My_Connections [ Idx ] . lastdata = now ;
My_Connections [ Idx ] . lastprivmsg = now ;
2001-12-29 21:17:25 +01:00
} /* Init_Conn_Struct */
2005-03-19 19:43:48 +01:00
LOCAL bool
Init_Socket ( int Sock )
2002-03-02 01:23:32 +01:00
{
2004-01-25 17:06:34 +01:00
/* Initialize socket (set options) */
2002-03-02 01:23:32 +01:00
2005-03-19 19:43:48 +01:00
int value ;
2002-03-02 01:23:32 +01:00
2004-01-25 17:06:34 +01:00
# ifdef O_NONBLOCK /* unknown on A/UX */
2002-03-02 01:23:32 +01:00
if ( fcntl ( Sock , F_SETFL , O_NONBLOCK ) ! = 0 )
{
2004-01-25 17:06:34 +01:00
Log ( LOG_CRIT , " Can't enable non-blocking mode for socket: %s! " , strerror ( errno ) ) ;
2002-03-02 01:23:32 +01:00
close ( Sock ) ;
2005-03-19 19:43:48 +01:00
return false ;
2002-03-02 01:23:32 +01:00
}
2002-03-13 01:15:55 +01:00
# endif
2004-01-25 17:06:34 +01:00
/* Don't block this port after socket shutdown */
value = 1 ;
if ( setsockopt ( Sock , SOL_SOCKET , SO_REUSEADDR , & value , ( socklen_t ) sizeof ( value ) ) ! = 0 )
2002-03-02 01:23:32 +01:00
{
2004-01-25 17:06:34 +01:00
Log ( LOG_ERR , " Can't set socket option SO_REUSEADDR: %s! " , strerror ( errno ) ) ;
/* ignore this error */
2002-03-02 01:23:32 +01:00
}
2004-01-25 17:06:34 +01:00
/* Set type of service (TOS) */
# if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
value = IPTOS_LOWDELAY ;
# ifdef DEBUG
Log ( LOG_DEBUG , " Setting option IP_TOS on socket %d to IPTOS_LOWDELAY (%d). " , Sock , value ) ;
# endif
if ( setsockopt ( Sock , SOL_IP , IP_TOS , & value , ( socklen_t ) sizeof ( value ) ) ! = 0 )
{
Log ( LOG_ERR , " Can't set socket option IP_TOS: %s! " , strerror ( errno ) ) ;
/* ignore this error */
}
# endif
2005-03-19 19:43:48 +01:00
return true ;
2002-03-02 01:23:32 +01:00
} /* Init_Socket */
2005-03-19 19:43:48 +01:00
LOCAL void
Read_Resolver_Result ( int r_fd )
2001-12-29 21:17:25 +01:00
{
2004-05-11 02:01:11 +02:00
/* Read result of resolver sub-process from pipe and update the
* apropriate connection / client structure ( s ) : hostname and / or
* IDENT user name . */
2001-12-29 21:17:25 +01:00
CLIENT * c ;
2005-03-19 19:43:48 +01:00
int len , i , n ;
2004-05-11 02:01:11 +02:00
RES_STAT * s ;
2005-03-19 19:43:48 +01:00
char * ptr ;
2001-12-29 21:17:25 +01:00
2003-12-27 14:01:12 +01:00
/* Search associated connection ... */
2002-11-03 00:00:45 +01:00
for ( i = 0 ; i < Pool_Size ; i + + )
2001-12-29 21:17:25 +01:00
{
2004-05-11 02:01:11 +02:00
if ( ( My_Connections [ i ] . sock ! = NONE )
& & ( My_Connections [ i ] . res_stat ! = NULL )
& & ( 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
{
2003-12-27 14:01:12 +01:00
/* Ops, none found? Probably the connection has already
2004-05-11 02:01:11 +02:00
* been closed ! ? We ' ll ignore that . . . */
FD_CLR ( r_fd , & Resolver_FDs ) ;
2001-12-29 21:17:25 +01:00
close ( r_fd ) ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2002-01-02 03:44:36 +01:00
Log ( LOG_DEBUG , " Resolver: Got result for unknown connection!? " ) ;
2003-11-06 00:24:48 +01:00
# endif
2001-12-29 21:17:25 +01:00
return ;
}
2004-05-11 02:01:11 +02:00
/* Get resolver structure */
s = My_Connections [ i ] . res_stat ;
assert ( s ! = NULL ) ;
/* Read result from pipe */
2004-05-30 18:25:51 +02:00
len = read ( r_fd , s - > buffer + s - > bufpos , sizeof ( s - > buffer ) - s - > bufpos - 1 ) ;
2004-05-11 02:01:11 +02:00
if ( len < 0 )
{
/* Error! */
Log ( LOG_CRIT , " Resolver: Can't read result: %s! " , strerror ( errno ) ) ;
2005-06-01 23:28:50 +02:00
FreeRes_stat ( & My_Connections [ i ] ) ;
2004-05-11 02:01:11 +02:00
return ;
}
s - > bufpos + = len ;
s - > buffer [ s - > bufpos ] = ' \0 ' ;
/* If the result string is incomplete, return to main loop and
* wait until we can read in more bytes . */
2004-05-11 02:53:14 +02:00
# ifdef IDENTAUTH
2004-05-11 02:01:11 +02:00
try_resolve :
2004-05-11 02:53:14 +02:00
# endif
2004-05-11 02:01:11 +02:00
ptr = strchr ( s - > buffer , ' \n ' ) ;
if ( ! ptr ) return ;
* ptr = ' \0 ' ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2004-05-11 02:01:11 +02:00
Log ( LOG_DEBUG , " Got result from resolver: \" %s \" (%d bytes), stage %d. " , s - > buffer , len , s - > stage ) ;
2003-11-06 00:24:48 +01:00
# endif
2003-04-25 18:47:52 +02:00
2004-05-11 02:01:11 +02:00
/* Okay, we got a complete result: this is a host name for outgoing
* connections and a host name or IDENT user name ( if enabled ) for
2005-06-01 23:28:50 +02:00
* incoming connections . */
2002-01-02 03:44:36 +01:00
if ( My_Connections [ i ] . sock > NONE )
{
2005-06-01 23:28:50 +02:00
/* Incoming connection. Search client ... */
2002-01-02 03:44:36 +01:00
c = Client_GetFromConn ( i ) ;
2002-01-03 03:25:36 +01:00
assert ( c ! = NULL ) ;
2004-02-28 03:01:01 +01:00
/* Only update client information of unregistered clients */
2004-05-11 02:01:11 +02:00
if ( Client_Type ( c ) = = CLIENT_UNKNOWN )
2004-02-28 03:01:01 +01:00
{
2005-06-01 23:28:50 +02:00
switch ( s - > stage ) {
case 0 : /* host name */
2004-05-11 02:01:11 +02:00
strlcpy ( My_Connections [ i ] . host , s - > buffer , sizeof ( My_Connections [ i ] . host ) ) ;
Client_SetHostname ( c , s - > buffer ) ;
2003-12-27 14:01:12 +01:00
# ifdef IDENTAUTH
2004-05-11 02:01:11 +02:00
/* clean up buffer for IDENT result */
len = strlen ( s - > buffer ) + 1 ;
2005-06-01 23:28:50 +02:00
assert ( len < = sizeof ( s - > buffer ) ) ;
2004-05-11 02:01:11 +02:00
memmove ( s - > buffer , s - > buffer + len , sizeof ( s - > buffer ) - len ) ;
2005-06-01 23:28:50 +02:00
assert ( len < = s - > bufpos ) ;
2004-05-11 02:01:11 +02:00
s - > bufpos - = len ;
/* Don't close pipe and clean up, but
* instead wait for IDENT result */
s - > stage = 1 ;
goto try_resolve ;
2005-06-01 23:28:50 +02:00
case 1 : /* IDENT user name */
2004-05-11 02:01:11 +02:00
if ( s - > buffer [ 0 ] )
{
Log ( LOG_INFO , " IDENT lookup for connection %ld: \" %s \" . " , i , s - > buffer ) ;
2005-03-19 19:43:48 +01:00
Client_SetUser ( c , s - > buffer , true ) ;
2004-05-11 02:01:11 +02:00
}
else Log ( LOG_INFO , " IDENT lookup for connection %ld: no result. " , i ) ;
# endif
2005-06-01 23:28:50 +02:00
break ;
default :
Log ( LOG_ERR , " Resolver: got result for unknown stage %d!? " , s - > stage ) ;
2004-05-11 02:01:11 +02:00
}
2003-12-27 14:01:12 +01:00
}
2004-05-11 02:01:11 +02:00
# ifdef DEBUG
else Log ( LOG_DEBUG , " Resolver: discarding result for already registered connection %d. " , i ) ;
2003-12-27 14:01:12 +01:00
# endif
2002-01-02 03:44:36 +01:00
}
2001-12-29 21:17:25 +01:00
else
{
2004-05-11 02:01:11 +02:00
/* Outgoing connection (server link): set the IP address
* so that we can connect to it in the main loop . */
/* Search server ... */
2002-12-30 01:01:42 +01:00
n = Conf_GetServer ( i ) ;
2004-02-28 03:01:01 +01:00
assert ( n > NONE ) ;
2004-05-11 02:01:11 +02:00
strlcpy ( Conf_Server [ n ] . ip , s - > buffer , sizeof ( Conf_Server [ n ] . ip ) ) ;
2001-12-29 21:17:25 +01:00
}
2002-10-10 17:01:12 +02:00
2004-05-11 02:01:11 +02:00
/* Clean up ... */
2005-06-01 23:28:50 +02:00
FreeRes_stat ( & My_Connections [ i ] ) ;
2004-05-11 02:01:11 +02:00
2003-12-27 14:01:12 +01:00
/* Reset penalty time */
2002-10-10 17:01:12 +02:00
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
2005-03-19 19:43:48 +01:00
LOCAL void
Simple_Message ( int Sock , char * Msg )
2003-03-07 18:16:49 +01:00
{
2005-06-12 19:21:46 +02:00
char buf [ COMMAND_LEN ] ;
2003-03-07 18:16:49 +01:00
/* Write "simple" message to socket, without using compression
* or even the connection write buffers . Used e . g . for error
* messages by New_Connection ( ) . */
assert ( Sock > NONE ) ;
assert ( Msg ! = NULL ) ;
2005-06-12 19:21:46 +02:00
strlcpy ( buf , Msg , sizeof buf - 2 ) ;
strlcat ( buf , " \r \n " , sizeof buf ) ;
( void ) write ( Sock , buf , strlen ( buf ) ) ;
2003-03-07 18:16:49 +01:00
} /* Simple_Error */
2005-03-19 19:43:48 +01:00
LOCAL int
2003-11-05 22:41:01 +01:00
Count_Connections ( struct sockaddr_in addr_in )
{
2005-03-19 19:43:48 +01:00
int i , cnt ;
2003-11-05 22:41:01 +01:00
cnt = 0 ;
for ( i = 0 ; i < Pool_Size ; i + + )
{
if ( ( My_Connections [ i ] . sock > NONE ) & & ( My_Connections [ i ] . addr . sin_addr . s_addr = = addr_in . sin_addr . s_addr ) ) cnt + + ;
}
return cnt ;
} /* Count_Connections */
2001-12-12 18:18:38 +01:00
/* -eof- */