2001-12-12 18:18:38 +01:00
/*
* ngIRCd - - The Next Generation IRC Daemon
2005-07-02 16:36:03 +02:00
* Copyright ( c ) 2001 - 2005 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"
2005-07-07 20:49:04 +02:00
# include "io.h"
2001-12-12 18:18:38 +01:00
2005-09-11 13:42:48 +02:00
static char UNUSED id [ ] = " $Id: conn.c,v 1.180 2005/09/11 11:42:48 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 <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
2005-07-07 20:49:04 +02:00
# include "array.h"
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
2005-07-08 18:18:38 +02:00
# ifdef ZEROCONF
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-07-31 22:13:07 +02:00
static bool Handle_Write PARAMS ( ( CONN_ID Idx ) ) ;
static int New_Connection PARAMS ( ( int Sock ) ) ;
static CONN_ID Socket2Index PARAMS ( ( int Sock ) ) ;
static void Read_Request PARAMS ( ( CONN_ID Idx ) ) ;
static bool Handle_Buffer PARAMS ( ( CONN_ID Idx ) ) ;
static void Check_Connections PARAMS ( ( void ) ) ;
static void Check_Servers PARAMS ( ( void ) ) ;
static void Init_Conn_Struct PARAMS ( ( CONN_ID Idx ) ) ;
static bool Init_Socket PARAMS ( ( int Sock ) ) ;
static void New_Server PARAMS ( ( int Server , CONN_ID Idx ) ) ;
static void Simple_Message PARAMS ( ( int Sock , char * Msg ) ) ;
static int Count_Connections PARAMS ( ( struct sockaddr_in addr ) ) ;
static int NewListener PARAMS ( ( const UINT16 Port ) ) ;
2001-12-13 00:32:02 +01:00
2005-07-07 20:49:04 +02:00
static array My_Listeners ;
2001-12-13 00:32:02 +01:00
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-07-29 11:29:47 +02:00
static void server_login PARAMS ( ( CONN_ID idx ) ) ;
2005-07-07 20:49:04 +02:00
static void cb_clientserver PARAMS ( ( int sock , short what ) ) ;
static void
cb_listen ( int sock , short irrelevant )
{
( void ) irrelevant ;
New_Connection ( sock ) ;
}
static void
2005-07-22 23:31:05 +02:00
cb_connserver ( int sock , UNUSED short what )
2005-07-07 20:49:04 +02:00
{
int res , err ;
socklen_t sock_len ;
CLIENT * c ;
CONN_ID idx = Socket2Index ( sock ) ;
if ( idx < = NONE ) {
# ifdef DEBUG
Log ( LOG_DEBUG , " cb_connserver wants to write on unknown socket?! " ) ;
# endif
io_close ( sock ) ;
return ;
}
assert ( what & IO_WANTWRITE ) ;
/* connect() finished, get result. */
sock_len = sizeof ( err ) ;
res = getsockopt ( My_Connections [ idx ] . sock , SOL_SOCKET , SO_ERROR , & err , & sock_len ) ;
assert ( sock_len = = sizeof ( err ) ) ;
/* Fehler aufgetreten? */
if ( ( res ! = 0 ) | | ( err ! = 0 ) ) {
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 [ Conf_GetServer ( idx ) ] . port ,
idx , strerror ( err ) ) ;
/* Clean up socket, connection and client structures */
c = Client_GetFromConn ( idx ) ;
if ( c ) Client_DestroyNow ( c ) ;
io_close ( My_Connections [ idx ] . sock ) ;
Init_Conn_Struct ( idx ) ;
/* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */
Conf_Server [ Conf_GetServer ( idx ) ] . lasttry = time ( NULL ) ;
Conf_UnsetServer ( idx ) ;
return ;
}
Conn_OPTION_DEL ( & My_Connections [ idx ] , CONN_ISCONNECTING ) ;
2005-07-29 11:29:47 +02:00
server_login ( idx ) ;
}
2005-07-07 20:49:04 +02:00
2005-07-29 11:29:47 +02:00
static void
server_login ( CONN_ID idx )
{
2005-07-07 20:49:04 +02:00
Log ( LOG_INFO , " Connection %d with \" %s:%d \" established. Now logging in ... " , idx ,
My_Connections [ idx ] . host , Conf_Server [ Conf_GetServer ( idx ) ] . port ) ;
io_event_setcb ( My_Connections [ idx ] . sock , cb_clientserver ) ;
io_event_add ( My_Connections [ idx ] . sock , IO_WANTREAD | IO_WANTWRITE ) ;
/* Send PASS and SERVER command to peer */
Conn_WriteStr ( idx , " PASS %s %s " , Conf_Server [ Conf_GetServer ( idx ) ] . pwd_out , NGIRCd_ProtoID ) ;
Conn_WriteStr ( idx , " SERVER %s :%s " , Conf_ServerName , Conf_ServerInfo ) ;
}
static void
cb_clientserver ( int sock , short what )
{
CONN_ID idx = Socket2Index ( sock ) ;
if ( idx < = NONE ) {
# ifdef DEBUG
Log ( LOG_WARNING , " WTF: cb_clientserver wants to write on unknown socket?! " ) ;
# endif
io_close ( sock ) ;
return ;
2005-07-09 23:35:20 +02:00
}
2005-07-07 20:49:04 +02:00
if ( what & IO_WANTREAD )
Read_Request ( idx ) ;
if ( what & IO_WANTWRITE )
Handle_Write ( idx ) ;
}
2005-07-31 22:13:07 +02:00
static void
2005-06-01 23:28:50 +02:00
FreeRes_stat ( CONNECTION * c )
{
assert ( c ! = NULL ) ;
assert ( c - > res_stat ! = NULL ) ;
if ( ! c - > res_stat ) return ;
2005-07-07 20:49:04 +02:00
io_close ( c - > res_stat - > pipe [ 0 ] ) ;
2005-06-01 23:28:50 +02:00
2005-07-28 18:13:09 +02:00
array_free ( & c - > res_stat - > buffer ) ;
2005-06-01 23:28:50 +02:00
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
2005-07-07 20:49:04 +02:00
array_free ( & My_Listeners ) ;
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 ;
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
2005-07-07 20:49:04 +02:00
Conn_ExitListeners ( ) ;
2003-04-25 18:47:52 +02:00
2003-02-23 13:04:05 +01:00
/* Sockets schliessen */
2005-07-07 20:49:04 +02:00
for ( idx = 0 ; idx < Pool_Size ; idx + + ) {
if ( My_Connections [ idx ] . sock > NONE ) {
Conn_Close ( idx , NULL , NGIRCd_SignalRestart ?
" Server going down (restarting) " : " Server going down " , true ) ;
continue ;
2001-12-13 00:32:02 +01:00
}
}
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 ;
2005-07-07 20:49:04 +02:00
io_library_shutdown ( ) ;
2001-12-12 18:18:38 +01:00
} /* Conn_Exit */
2005-07-29 11:29:47 +02:00
static unsigned int
ports_initlisteners ( array * a , void ( * func ) ( int , short ) )
{
unsigned int created = 0 , len ;
int fd ;
UINT16 * port ;
len = array_length ( a , sizeof ( UINT16 ) ) ;
port = array_start ( a ) ;
while ( len - - ) {
fd = NewListener ( * port ) ;
if ( fd < 0 ) {
port + + ;
continue ;
}
if ( ! io_event_create ( fd , IO_WANTREAD , func ) ) {
Log ( LOG_ERR , " io_event_create(): Could not add listening fd %d (port %u): %s! " ,
fd , ( unsigned int ) * port , strerror ( errno ) ) ;
close ( fd ) ;
port + + ;
continue ;
}
created + + ;
port + + ;
}
return created ;
}
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-07-29 11:29:47 +02:00
unsigned int created ;
2002-11-22 18:58:19 +01:00
2005-07-07 20:49:04 +02:00
if ( ! io_library_init ( CONNECTION_POOL ) ) {
Log ( LOG_EMERG , " Cannot initialize IO routines: %s " , strerror ( errno ) ) ;
return - 1 ;
}
2005-07-29 11:29:47 +02:00
created = ports_initlisteners ( & Conf_ListenPorts , cb_listen ) ;
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 */
2005-07-07 20:49:04 +02:00
int * fd ;
unsigned int arraylen ;
2005-07-08 18:18:38 +02:00
# ifdef ZEROCONF
2003-02-23 13:04:05 +01:00
Rendezvous_UnregisterListeners ( ) ;
# endif
2003-04-25 18:47:52 +02:00
2005-07-07 20:49:04 +02:00
arraylen = array_length ( & My_Listeners , sizeof ( int ) ) ;
Log ( LOG_INFO , " Shutting down all listening sockets (%d)... " , arraylen ) ;
while ( arraylen - - ) {
fd = ( int * ) array_get ( & My_Listeners , sizeof ( int ) , arraylen ) ;
if ( fd ) {
close ( * fd ) ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2005-07-09 23:35:20 +02:00
Log ( LOG_DEBUG , " Listening socket %d closed. " , * fd ) ;
2005-07-07 20:49:04 +02:00
} else {
Log ( LOG_DEBUG , " array_get pos %d returned NULL " , arraylen ) ;
2003-11-06 00:24:48 +01:00
# endif
2002-11-22 18:58:19 +01:00
}
}
2005-07-07 20:49:04 +02:00
array_free ( & My_Listeners ) ;
2002-11-22 18:58:19 +01:00
} /* Conn_ExitListeners */
2005-07-12 22:44:46 +02:00
/* return new listening port file descriptor or -1 on failure */
2005-07-31 22:13:07 +02:00
static int
2005-07-11 16:56:38 +02:00
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 ;
2005-07-08 18:18:38 +02:00
# ifdef ZEROCONF
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-07-11 16:56:38 +02:00
return - 1 ;
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-07-11 16:56:38 +02:00
return - 1 ;
2001-12-12 18:18:38 +01:00
}
2005-07-11 16:56:38 +02:00
if ( ! Init_Socket ( sock ) ) return - 1 ;
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-07-11 16:56:38 +02:00
return - 1 ;
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-07-11 16:56:38 +02:00
return - 1 ;
2001-12-12 18:18:38 +01:00
}
2001-12-13 00:32:02 +01:00
/* Neuen Listener in Strukturen einfuegen */
2005-07-07 20:49:04 +02:00
if ( ! array_catb ( & My_Listeners , ( char * ) & sock , sizeof ( int ) ) ) {
Log ( LOG_CRIT , " Can't add socket to My_Listeners array: %s! " , strerror ( errno ) ) ;
close ( sock ) ;
2005-07-11 16:56:38 +02:00
return - 1 ;
2005-07-07 20:49:04 +02:00
}
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
2005-07-08 18:18:38 +02:00
# ifdef ZEROCONF
2003-02-23 13:04:05 +01:00
/* 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 */
2005-07-08 18:18:38 +02:00
Rendezvous_Register ( name , MDNS_TYPE , Port ) ;
2003-02-23 13:04:05 +01:00
# endif
2005-07-11 16:56:38 +02:00
return sock ;
} /* 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
{
2005-07-12 22:44:46 +02:00
/* "Main Loop.": Loop until a signal (for shutdown or restart) arrives.
* Call io_dispatch ( ) to check for read / writeable sockets every second
* Wait for status change on pending connections ( e . g : when the hostname has been resolved )
* check for penalty / timeouts
* handle input buffers
2001-12-29 23:33:36 +01:00
*/
2005-07-07 20:49:04 +02:00
int i ;
unsigned int wdatalen ;
2001-12-13 02:33:09 +01:00
struct timeval tv ;
2002-08-26 02:03:15 +02:00
time_t start , t ;
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
2005-07-08 18:18:38 +02:00
# ifdef ZEROCONF
2003-02-23 13:04:05 +01:00
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
{
2005-07-07 20:49:04 +02:00
if ( ( My_Connections [ i ] . sock > NONE ) & & ( array_bytes ( & My_Connections [ i ] . rbuf ) > 0 ) & &
2003-11-06 00:24:48 +01:00
( 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-07-07 20:49:04 +02: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 */
2005-07-07 20:49:04 +02:00
for ( i = 0 ; i < Pool_Size ; i + + ) {
if ( My_Connections [ i ] . sock < = NONE )
continue ;
2005-07-12 22:44:46 +02:00
2005-07-07 20:49:04 +02:00
wdatalen = array_bytes ( & My_Connections [ i ] . wbuf ) ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-07-07 20:49:04 +02:00
if ( ( wdatalen > 0 ) | | ( array_bytes ( & My_Connections [ i ] . zip . wbuf ) > 0 ) )
2002-11-27 00:07:24 +01:00
# else
2005-07-07 20:49:04 +02:00
if ( 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 */
2005-07-07 20:49:04 +02:00
io_event_add ( My_Connections [ i ] . sock , IO_WANTWRITE ) ;
2005-04-23 16:28:44 +02:00
}
2002-03-02 01:23:32 +01:00
}
2001-12-29 21:17:25 +01:00
/* von welchen Sockets koennte gelesen werden? */
2005-07-07 20:49:04 +02:00
for ( i = 0 ; i < Pool_Size ; i + + ) {
if ( My_Connections [ i ] . sock < = NONE )
continue ;
if ( My_Connections [ i ] . res_stat ) {
/* wait for completion of Resolver Sub-Process */
io_event_del ( My_Connections [ i ] . sock , IO_WANTREAD ) ;
continue ;
2002-03-02 01:23:32 +01:00
}
2005-07-07 20:49:04 +02:00
if ( Conn_OPTION_ISSET ( & My_Connections [ i ] , CONN_ISCONNECTING ) )
continue ; /* wait for completion of connect() */
if ( My_Connections [ i ] . delaytime > t ) {
2002-08-26 02:03:15 +02:00
/* Fuer die Verbindung ist eine "Penalty-Zeit" gesetzt */
2005-07-07 20:49:04 +02:00
io_event_del ( My_Connections [ i ] . sock , IO_WANTREAD ) ;
continue ;
2001-12-29 21:17:25 +01:00
}
2005-07-07 20:49:04 +02:00
io_event_add ( My_Connections [ i ] . sock , IO_WANTREAD ) ;
2001-12-29 21:17:25 +01:00
}
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 */
2005-07-07 20:49:04 +02:00
i = io_dispatch ( & tv ) ;
if ( i = = - 1 & & errno ! = EINTR ) {
Log ( LOG_EMERG , " Conn_Handler(): io_dispatch(): %s! " , strerror ( errno ) ) ;
Log ( LOG_ALERT , " %s exiting due to fatal errors! " , PACKAGE_NAME ) ;
exit ( 1 ) ;
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 */
2005-07-02 16:36:03 +02:00
/**
* Write a text string into the socket of a connection .
* This function automatically appends CR + LF to the string and validates that
* the result is a valid IRC message ( oversized messages are shortened , for
* example ) . Then it calls the Conn_Write ( ) function to do the actual sending .
* @ param Idx Index fo the connection .
* @ param Format Format string , see printf ( ) .
* @ return true on success , false otherwise .
*/
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
{
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-07-07 20:49:04 +02:00
if ( vsnprintf ( buffer , COMMAND_LEN - 2 , Format , ap ) > = COMMAND_LEN - 2 ) {
2005-07-02 16:36:03 +02:00
/*
* The string that should be written to the socket is longer
* than the allowed size of COMMAND_LEN bytes ( including both
* the CR and LF characters ) . This can be caused by the
* IRC_WriteXXX ( ) functions when the prefix of this server had
* to be added to an already " quite long " command line which
* has been received from a regular IRC client , for example .
*
* We are not allowed to send such " oversized " messages to
* other servers and clients , see RFC 2812 2.3 and 2813 3.3
* ( " these messages SHALL NOT exceed 512 characters in length,
* counting all characters including the trailing CR - LF " ).
*
* So we have a big problem here : we should send more bytes
* to the network than we are allowed to and we don ' t know
* the originator ( any more ) . The " old " behaviour of blaming
* the receiver ( " next hop " ) is a bad idea ( it could be just
* an other server only routing the message ! ) , so the only
* option left is to shorten the string and to hope that the
* result is still somewhat useful . . .
* - alex -
*/
strcpy ( buffer + sizeof ( buffer ) - strlen ( CUT_TXTSUFFIX ) - 2 - 1 ,
CUT_TXTSUFFIX ) ;
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
2005-07-02 16:36:03 +02: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
2005-07-07 20:49:04 +02:00
Conn_Write ( CONN_ID Idx , char * Data , unsigned 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 ) . */
2005-07-07 20:49:04 +02:00
if ( array_bytes ( & My_Connections [ Idx ] . wbuf ) > = WRITEBUFFER_LEN ) {
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
2005-07-07 20:49:04 +02:00
/* check again: if our writebuf is twice als large as the initial limit: Kill connection */
if ( array_bytes ( & My_Connections [ Idx ] . wbuf ) > = ( WRITEBUFFER_LEN * 2 ) ) {
2002-11-27 00:07:24 +01:00
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 */
2005-07-07 20:49:04 +02:00
if ( ! array_catb ( & My_Connections [ Idx ] . wbuf , Data , Len ) )
return false ;
2002-11-27 00:07:24 +01:00
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? */
2005-08-16 01:02:40 +02:00
if ( InformClient ) {
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: */
2005-08-16 01:02:40 +02:00
if ( ( c ! = NULL ) & & ( Client_Type ( c ) = = CLIENT_USER ) ) {
Conn_WriteStr ( Idx ,
2005-08-29 13:11:15 +02:00
" :%s NOTICE %s :%sConnection statistics: client %.1f kb, server %.1f kb. " ,
Client_ID ( Client_ThisServer ( ) ) , Client_ID ( c ) ,
NOTICE_TXTPREFIX ,
2005-08-16 01:02:40 +02:00
( 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!) */
2005-08-16 01:02:40 +02: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 ) ;
2005-07-12 22:44:46 +02:00
2002-12-27 14:20:13 +01:00
/* Shut down socket */
2005-07-07 20:49:04 +02:00
if ( ! io_close ( My_Connections [ Idx ] . sock ) )
2001-12-25 23:03:47 +01:00
{
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
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 ) ;
2005-07-07 20:49:04 +02:00
array_free ( & My_Connections [ Idx ] . zip . rbuf ) ;
array_free ( & My_Connections [ Idx ] . zip . wbuf ) ;
2002-11-27 00:07:24 +01:00
}
# endif
2005-07-07 20:49:04 +02:00
array_free ( & My_Connections [ Idx ] . rbuf ) ;
array_free ( & My_Connections [ Idx ] . wbuf ) ;
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-07-31 22:13:07 +02:00
static 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-07-07 20:49:04 +02:00
int len ;
unsigned int wdatalen ;
2001-12-15 01:11:55 +01:00
2002-10-15 11:24:54 +02:00
assert ( Idx > NONE ) ;
2005-07-07 20:49:04 +02:00
if ( My_Connections [ Idx ] . sock < 0 ) {
2005-09-05 11:10:08 +02:00
# ifdef DEBUG
Log ( LOG_DEBUG ,
2005-09-02 15:28:30 +02:00
" Handle_Write() on closed socket, connection %d " , Idx ) ;
2005-09-05 11:10:08 +02:00
# endif
2005-07-07 20:49:04 +02:00
return false ;
}
2002-03-02 01:23:32 +01:00
2005-09-02 15:28:30 +02:00
# ifdef DEBUG
Log ( LOG_DEBUG , " Handle_Write() called for connection %d ... " , Idx ) ;
# endif
2005-07-07 20:49:04 +02:00
wdatalen = array_bytes ( & My_Connections [ Idx ] . wbuf ) ;
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-09-02 15:28:30 +02:00
if ( wdatalen = = 0 & & ! array_bytes ( & My_Connections [ Idx ] . zip . wbuf ) ) {
2005-07-07 20:49:04 +02:00
io_event_del ( My_Connections [ Idx ] . sock , IO_WANTWRITE ) ;
2005-06-04 13:49:20 +02:00
return true ;
2005-07-07 20:49:04 +02:00
}
2005-06-04 13:49:20 +02:00
2005-09-02 15:28:30 +02:00
/* write buffer empty, but not compression buffer?
* - > flush compression buffer ! */
if ( wdatalen = = 0 )
Zip_Flush ( Idx ) ;
2005-06-04 13:49:20 +02:00
# else
2005-09-02 15:28:30 +02:00
if ( wdatalen = = 0 ) {
2005-07-07 20:49:04 +02:00
io_event_del ( My_Connections [ Idx ] . sock , IO_WANTWRITE ) ;
2005-06-04 13:49:20 +02:00
return true ;
2005-07-07 20:49:04 +02:00
}
2002-11-27 00:07:24 +01:00
# endif
2005-09-02 15:28:30 +02:00
/* Zip_Flush() may have changed the write buffer ... */
wdatalen = array_bytes ( & My_Connections [ Idx ] . wbuf ) ;
len = write ( My_Connections [ Idx ] . sock ,
array_start ( & My_Connections [ Idx ] . wbuf ) , wdatalen ) ;
2005-06-04 13:49:20 +02:00
if ( len < 0 ) {
2005-09-02 15:28:30 +02:00
if ( errno = = EAGAIN | | errno = = EINTR )
2005-06-04 13:49:20 +02:00
return true ;
2002-11-20 16:48:41 +01:00
2005-09-02 15:28:30 +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 ) ;
2005-03-19 19:43:48 +01:00
return false ;
2001-12-15 01:11:55 +01:00
}
2001-12-26 00:15:16 +01:00
2005-07-07 20:49:04 +02:00
/* move any data not yet written to beginning */
array_moveleft ( & My_Connections [ Idx ] . wbuf , 1 , len ) ;
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-07-31 22:13:07 +02:00
static int
2005-03-19 19:43:48 +01:00
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 ) ;
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 ) ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2001-12-13 00:32:02 +01:00
}
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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2003-03-07 15:35:52 +01:00
}
# 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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2003-11-05 22:41:01 +01:00
}
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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2002-11-03 00:00:45 +01:00
}
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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2002-12-30 17:07:23 +01:00
}
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 ) ;
2005-07-12 22:44:46 +02: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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
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 ) ;
2005-07-12 22:44:46 +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 ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2001-12-23 23:02:54 +01:00
}
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 */
2005-07-12 22:44:46 +02:00
if ( ! io_event_create ( new_sock , IO_WANTREAD , cb_clientserver ) ) {
Simple_Message ( new_sock , " ERROR :Internal error " ) ;
Conn_Close ( idx , " io_event_create() failed " , NULL , false ) ;
2005-07-29 11:29:47 +02:00
return - 1 ;
2005-07-12 22:44:46 +02:00
}
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 ) ;
2005-07-29 11:29:47 +02:00
return new_sock ;
2001-12-13 00:32:02 +01:00
} /* New_Connection */
2005-07-31 22:13:07 +02:00
static 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-07-31 22:13:07 +02:00
static 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-07-07 20:49:04 +02:00
int len ;
char readbuf [ 1024 ] ;
2005-08-28 01:33:10 +02:00
CLIENT * c ;
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
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-07-07 20:49:04 +02:00
if ( ( array_bytes ( & My_Connections [ Idx ] . rbuf ) > = READBUFFER_LEN ) | |
( array_bytes ( & My_Connections [ Idx ] . zip . rbuf ) > = ZREADBUFFER_LEN ) )
2002-11-27 00:07:24 +01:00
# else
2005-07-07 20:49:04 +02:00
if ( array_bytes ( & My_Connections [ Idx ] . rbuf ) > = READBUFFER_LEN )
2002-11-27 00:07:24 +01:00
# endif
2002-01-03 03:25:36 +01:00
{
/* Der Lesepuffer ist voll */
2005-07-07 20:49:04 +02:00
Log ( LOG_ERR , " Receive buffer overflow (connection %d): %d bytes! " , Idx ,
array_bytes ( & My_Connections [ Idx ] . rbuf ) ) ;
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 ;
}
2005-07-11 22:58:05 +02:00
len = read ( My_Connections [ Idx ] . sock , readbuf , sizeof readbuf - 1 ) ;
2005-07-07 20:49:04 +02:00
if ( len = = 0 ) {
Log ( LOG_INFO , " %s:%d (%s) is closing the connection ... " ,
2005-07-12 22:44:46 +02:00
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 ;
}
2005-07-12 22:44:46 +02:00
2005-07-07 20:49:04 +02:00
if ( len < 0 ) {
2002-11-20 16:48:41 +01:00
if ( errno = = EAGAIN ) return ;
2005-07-07 20:49:04 +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 ;
}
2005-07-07 20:49:04 +02:00
# ifdef ZLIB
if ( Conn_OPTION_ISSET ( & My_Connections [ Idx ] , CONN_ZIP ) ) {
if ( ! array_catb ( & My_Connections [ Idx ] . zip . rbuf , readbuf , len ) ) {
Log ( LOG_ERR , " Could not append recieved data to zip input buffer (connn %d): %d bytes! " , Idx , len ) ;
Conn_Close ( Idx , " Receive buffer overflow! " , NULL , false ) ;
return ;
}
} else
# endif
{
readbuf [ len ] = 0 ;
if ( ! array_cats ( & My_Connections [ Idx ] . rbuf , readbuf ) ) {
Log ( LOG_ERR , " Could not append recieved data to input buffer (connn %d): %d bytes! " , Idx , len ) ;
Conn_Close ( Idx , " Receive buffer overflow! " , NULL , false ) ;
}
}
2001-12-14 09:16:47 +01:00
2005-08-28 01:33:10 +02:00
/* Update connection statistics */
2002-10-09 15:15:08 +02:00
My_Connections [ Idx ] . bytes_in + = len ;
2005-08-28 01:33:10 +02:00
/* Update timestamp of last data received if this connection is
* registered as a user , server or service connection . Don ' t update
* otherwise , so users have at least Conf_PongTimeout seconds time to
* register with the IRC server - - see Check_Connections ( ) . */
c = Client_GetFromConn ( Idx ) ;
if ( c & & ( Client_Type ( c ) = = CLIENT_USER
| | Client_Type ( c ) = = CLIENT_SERVER
| | Client_Type ( c ) = = CLIENT_SERVICE ) )
My_Connections [ Idx ] . lastdata = time ( NULL ) ;
/* Look at the data in the (read-) buffer of this connection */
Handle_Buffer ( Idx ) ;
2001-12-26 00:15:16 +01:00
} /* Read_Request */
2005-07-31 22:13:07 +02:00
static bool
2002-05-27 15:09:26 +02:00
Handle_Buffer ( CONN_ID Idx )
2001-12-26 00:15:16 +01:00
{
2005-07-07 20:49:04 +02:00
/* Handle Data in Connections Read-Buffer.
* Return true if a reuqest was handled , false otherwise ( also returned on errors ) . */
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 ;
2005-08-28 18:51:20 +02:00
bool 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 ;
2005-08-28 18:51:20 +02:00
for ( ; ; ) {
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
2005-07-07 20:49:04 +02:00
/* unpack compressed data */
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
2005-07-28 18:13:09 +02:00
if ( 0 = = array_bytes ( & My_Connections [ Idx ] . rbuf ) )
2005-07-07 20:49:04 +02:00
break ;
2005-07-28 18:13:09 +02:00
if ( ! array_cat0_temporary ( & My_Connections [ Idx ] . rbuf ) ) /* make sure buf is NULL terminated */
2005-07-07 20:49:04 +02:00
return false ;
/* A Complete Request end with CR+LF, see RFC 2812. */
ptr = strstr ( array_start ( & My_Connections [ Idx ] . rbuf ) , " \r \n " ) ;
if ( ptr ) delta = 2 ; /* complete request */
2002-11-27 00:07:24 +01:00
# ifndef STRICT_RFC
2005-07-07 20:49:04 +02:00
else {
/* Check for non-RFC-compliant request (only CR or LF)? Unfortunately,
* there are quite a few clients that do this ( incl . " mIRC " : - ( */
ptr1 = strchr ( array_start ( & My_Connections [ Idx ] . rbuf ) , ' \r ' ) ;
ptr2 = strchr ( array_start ( & My_Connections [ Idx ] . rbuf ) , ' \n ' ) ;
2002-11-27 00:07:24 +01:00
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-07-07 20:49:04 +02:00
if ( ! ptr )
break ;
/* End of request found */
* ptr = ' \0 ' ;
len = ( ptr - ( char * ) array_start ( & My_Connections [ Idx ] . rbuf ) ) + delta ;
if ( len < 0 | | len > ( COMMAND_LEN - 1 ) ) {
/* Request must not exceed 512 chars (incl. CR+LF!), see
* RFC 2812. Disconnect Client if this happens . */
Log ( LOG_ERR , " Request too long (connection %d): %d bytes (max. %d expected)! " ,
Idx , array_bytes ( & My_Connections [ Idx ] . rbuf ) , COMMAND_LEN - 1 ) ;
Conn_Close ( Idx , NULL , " Request too long " , true ) ;
return false ;
}
2002-11-28 13:17:38 +01:00
2005-08-28 02:19:29 +02:00
if ( len < = 2 ) { /* request was empty (only '\r\n') */
array_moveleft ( & My_Connections [ Idx ] . rbuf , 1 , delta ) ; /* delta is either 1 or 2 */
2005-08-28 01:42:23 +02:00
break ;
}
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-07-07 20:49:04 +02:00
/* remember if stream is already compressed */
old_z = My_Connections [ Idx ] . options & CONN_ZIP ;
2002-11-28 13:17:38 +01:00
# endif
2005-08-28 18:51:20 +02:00
My_Connections [ Idx ] . msg_in + + ;
if ( ! Parse_Request ( Idx , ( char * ) array_start ( & My_Connections [ Idx ] . rbuf ) ) )
return false ;
result = true ;
2005-07-12 22:44:46 +02:00
2005-08-28 18:51:20 +02:00
array_moveleft ( & My_Connections [ Idx ] . rbuf , 1 , len ) ;
2005-07-07 20:49:04 +02:00
# ifdef DEBUG
2005-09-02 15:28:30 +02:00
Log ( LOG_DEBUG ,
" Connection %d: %d bytes left in read buffer. " ,
Idx , array_bytes ( & My_Connections [ Idx ] . rbuf ) ) ;
2005-07-07 20:49:04 +02:00
# endif
2003-12-26 16:55:07 +01:00
# ifdef ZLIB
2005-08-28 18:51:20 +02:00
if ( ( ! old_z ) & & ( My_Connections [ Idx ] . options & CONN_ZIP ) & &
( array_bytes ( & My_Connections [ Idx ] . rbuf ) > 0 ) )
2005-07-07 20:49:04 +02:00
{
/* The last Command activated Socket-Compression.
* Data that was read after that needs to be copied to Unzip - buf
* for decompression */
if ( array_bytes ( & My_Connections [ Idx ] . rbuf ) > ZREADBUFFER_LEN ) {
2005-08-28 18:51:20 +02:00
Log ( LOG_ALERT , " Connection %d: No space left in unzip buf (need %u bytes)! " ,
Idx , array_bytes ( & My_Connections [ Idx ] . rbuf ) ) ;
2005-07-07 20:49:04 +02:00
return false ;
}
if ( ! array_copy ( & My_Connections [ Idx ] . zip . rbuf , & My_Connections [ Idx ] . rbuf ) )
return false ;
array_trunc ( & My_Connections [ Idx ] . rbuf ) ;
2004-12-22 18:37:41 +01:00
# ifdef DEBUG
2005-08-28 18:51:20 +02:00
Log ( LOG_DEBUG , " Moved already received data (%u bytes) to uncompression buffer. " ,
array_bytes ( & My_Connections [ Idx ] . zip . rbuf ) ) ;
2004-12-22 18:37:41 +01:00
# endif /* DEBUG */
2001-12-13 02:33:09 +01:00
}
2005-07-07 20:49:04 +02:00
# endif /* ZLIB */
2005-08-28 18:51:20 +02:00
}
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-07-31 22:13:07 +02:00
static void
2005-03-19 19:43:48 +01:00
Check_Connections ( void )
2001-12-26 04:20:53 +01:00
{
2005-07-09 23:35:20 +02:00
/* check if connections are alive. if not, play PING-PONG first.
* if this doesn ' t help either , disconnect client . */
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
2005-07-09 23:35:20 +02:00
for ( i = 0 ; i < Pool_Size ; i + + ) {
2005-09-11 13:42:48 +02:00
if ( My_Connections [ i ] . sock < 0 )
continue ;
2002-01-02 03:44:36 +01:00
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
{
2005-07-09 23:35:20 +02:00
/* connected User, Server or Service */
if ( My_Connections [ i ] . lastping > My_Connections [ i ] . lastdata ) {
/* we already sent a ping */
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
}
}
2005-07-09 23:35:20 +02:00
else if ( My_Connections [ i ] . lastdata < time ( NULL ) - Conf_PingTimeout ) {
/* we need to sent a PING */
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
{
2005-08-28 01:33:10 +02:00
/* The connection is not fully established yet, so
* we don ' t do the PING - PONG game here but instead
* disconnect the client after " a short time " if it ' s
* still not registered . */
if ( My_Connections [ i ] . lastdata <
time ( NULL ) - Conf_PongTimeout ) {
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2005-08-28 01:33:10 +02:00
Log ( LOG_DEBUG ,
" Unregistered connection %d timed out ... " ,
i ) ;
2003-11-06 00:24:48 +01:00
# endif
2005-08-28 01:33:10 +02:00
Conn_Close ( i , NULL , " Timeout " , false ) ;
2002-01-02 03:44:36 +01:00
}
}
}
} /* Check_Connections */
2005-07-31 22:13:07 +02:00
static void
2005-03-19 19:43:48 +01:00
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
2005-08-31 00:08:00 +02:00
/* Search all connections, are there results from the resolver? */
for ( idx = 0 ; idx < Pool_Size ; idx + + ) {
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 */
2005-08-31 00:08:00 +02:00
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? */
2005-08-31 00:08:00 +02:00
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? */
2005-08-31 00:08:00 +02:00
if ( Conf_Server [ i ] . group > NONE ) {
2005-09-02 19:01:23 +02:00
for ( n = 0 ; n < MAX_SERVERS ; n + + ) {
if ( n = = i ) continue ;
if ( ( Conf_Server [ n ] . conn_id > NONE ) & &
( Conf_Server [ n ] . group = = Conf_Server [ i ] . group ) )
2005-08-31 00:08:00 +02:00
break ;
2002-03-10 18:50:48 +01:00
}
2005-08-31 00:08:00 +02: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? */
2005-09-11 13:42:48 +02:00
if ( Conf_Server [ i ] . lasttry > time ( NULL ) - Conf_ConnectRetry )
continue ;
2002-01-02 03:44:36 +01:00
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 ;
2005-09-11 13:42:48 +02:00
if ( idx > = Pool_Size ) {
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-07-31 22:13:07 +02:00
static void
2005-03-19 19:43:48 +01:00
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? */
2005-07-12 22:44:46 +02:00
if ( ! Conf_Server [ Server ] . ip [ 0 ] ) {
2003-04-25 18:47:52 +02:00
/* No. Free connection structure and abort: */
2005-08-31 00:08:00 +02:00
Log ( LOG_ERR , " Can't connect to \" %s \" : ip address unknown! " , Conf_Server [ Server ] . host ) ;
Init_Conn_Struct ( Idx ) ;
Conf_Server [ Server ] . conn_id = NONE ;
return ;
2002-01-02 03:44:36 +01:00
}
2002-03-11 01:04:48 +01:00
2005-08-31 00:08:00 +02:00
Log ( LOG_INFO , " Establishing connection to \" %s \" , %s, port %d ... " , Conf_Server [ Server ] . host ,
Conf_Server [ Server ] . ip , Conf_Server [ Server ] . port ) ;
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
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 ) ;
2005-07-12 22:44:46 +02:00
goto out ;
2002-01-02 03:44:36 +01:00
}
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 ) ;
2005-07-11 22:58:05 +02:00
if ( new_sock < 0 ) {
2003-04-25 18:47:52 +02:00
/* Can't create socket */
2002-01-06 16:18:14 +01:00
Log ( LOG_CRIT , " Can't create socket: %s! " , strerror ( errno ) ) ;
2005-07-12 22:44:46 +02:00
goto out ;
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 ) ) ;
2005-07-11 22:58:05 +02:00
if ( ( res ! = 0 ) & & ( errno ! = EINPROGRESS ) ) {
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 ) ;
2005-07-12 22:44:46 +02:00
goto out ;
2002-01-02 03:44:36 +01:00
}
/* Client-Struktur initialisieren */
2005-03-19 19:43:48 +01:00
c = Client_NewLocal ( Idx , inet_ntoa ( new_addr . sin_addr ) , CLIENT_UNKNOWNSERVER , false ) ;
2005-07-11 22:58:05 +02:00
if ( ! c ) {
2003-04-25 18:47:52 +02:00
/* Can't create new client structure */
2002-01-02 03:44:36 +01:00
Log ( LOG_ALERT , " Can't establish connection: can't create client structure! " ) ;
2005-07-12 22:44:46 +02:00
close ( new_sock ) ;
goto out ;
2002-01-02 03:44:36 +01:00
}
2005-07-12 22:44:46 +02:00
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 */
2005-07-12 22:44:46 +02:00
if ( ! io_event_create ( new_sock , IO_WANTWRITE , cb_connserver ) ) {
Log ( LOG_ALERT , " io_event_create(): could not add fd %d " , strerror ( errno ) ) ;
Conn_Close ( Idx , " io_event_create() failed " , NULL , false ) ;
goto out ;
}
2005-04-23 16:28:44 +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
2005-07-12 22:44:46 +02:00
Conn_OPTION_ADD ( & My_Connections [ Idx ] , CONN_ISCONNECTING ) ;
return ;
out :
Init_Conn_Struct ( Idx ) ;
Conf_Server [ Server ] . conn_id = NONE ;
2002-01-02 03:44:36 +01:00
} /* New_Server */
2001-12-26 04:20:53 +01:00
2005-07-31 22:13:07 +02:00
static 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-07-31 22:13:07 +02:00
static bool
2005-03-19 19:43:48 +01:00
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
2005-07-07 20:49:04 +02:00
if ( ! io_setnonblock ( Sock ) ) {
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
}
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-07-07 20:49:04 +02:00
GLOBAL
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-07-28 18:13:09 +02:00
int bytes_read , i , n ;
unsigned int len ;
2004-05-11 02:01:11 +02:00
RES_STAT * s ;
2005-03-19 19:43:48 +01:00
char * ptr ;
2005-07-28 18:13:09 +02:00
char * bufptr ;
char readbuf [ HOST_LEN ] ;
2001-12-29 21:17:25 +01:00
2005-08-03 00:48:57 +02:00
Log ( LOG_DEBUG , " Resolver: started, fd %d " , r_fd ) ;
2003-12-27 14:01:12 +01:00
/* Search associated connection ... */
2005-08-31 00:08:00 +02:00
for ( i = 0 ; i < Pool_Size ; i + + ) {
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
}
2005-09-11 13:42:48 +02:00
if ( i > = Pool_Size ) {
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 . . . */
2005-07-07 20:49:04 +02:00
io_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 */
2005-07-28 18:13:09 +02:00
bytes_read = read ( r_fd , readbuf , sizeof readbuf - 1 ) ;
2005-07-29 11:29:47 +02:00
if ( bytes_read < 0 ) {
2004-05-11 02:01:11 +02:00
/* 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 ;
}
2005-07-28 18:13:09 +02:00
len = ( unsigned int ) bytes_read ;
readbuf [ len ] = ' \0 ' ;
2005-07-29 11:29:47 +02:00
if ( ! array_catb ( & s - > buffer , readbuf , len ) ) {
2005-07-28 18:13:09 +02:00
Log ( LOG_CRIT , " Resolver: Can't append result %s to buffer: %s " , readbuf , strerror ( errno ) ) ;
FreeRes_stat ( & My_Connections [ i ] ) ;
return ;
}
if ( ! array_cat0_temporary ( & s - > buffer ) ) {
Log ( LOG_CRIT , " Resolver: Can't append result %s to buffer: %s " , readbuf , strerror ( errno ) ) ;
FreeRes_stat ( & My_Connections [ i ] ) ;
return ;
}
2004-05-11 02:01:11 +02:00
/* 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
2005-07-28 18:13:09 +02:00
bufptr = ( char * ) array_start ( & s - > buffer ) ;
assert ( bufptr ! = NULL ) ;
ptr = strchr ( bufptr , ' \n ' ) ;
2004-05-11 02:01:11 +02:00
if ( ! ptr ) return ;
* ptr = ' \0 ' ;
2003-11-06 00:24:48 +01:00
# ifdef DEBUG
2005-07-28 18:13:09 +02:00
Log ( LOG_DEBUG , " Got result from resolver: \" %s \" (%u bytes read), stage %d. " , bufptr , 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 */
2005-07-28 18:13:09 +02:00
strlcpy ( My_Connections [ i ] . host , bufptr , sizeof ( My_Connections [ i ] . host ) ) ;
Client_SetHostname ( c , bufptr ) ;
2003-12-27 14:01:12 +01:00
# ifdef IDENTAUTH
2004-05-11 02:01:11 +02:00
/* clean up buffer for IDENT result */
2005-07-28 18:13:09 +02:00
len = strlen ( bufptr ) + 1 ;
assert ( len < = array_bytes ( & s - > buffer ) ) ;
array_moveleft ( & s - > buffer , 1 , len ) ;
2004-05-11 02:01:11 +02:00
/* 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 */
2005-07-28 18:13:09 +02:00
if ( array_bytes ( & s - > buffer ) ) {
bufptr = ( char * ) array_start ( & s - > buffer ) ;
Log ( LOG_INFO , " IDENT lookup for connection %ld: \" %s \" . " , i , bufptr ) ;
Client_SetUser ( c , bufptr , 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 ) ;
2005-07-29 11:29:47 +02:00
2005-07-28 18:13:09 +02:00
bufptr = ( char * ) array_start ( & s - > buffer ) ;
strlcpy ( Conf_Server [ n ] . ip , bufptr , 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-07-31 22:13:07 +02:00
static void
2005-03-19 19:43:48 +01:00
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-07-31 22:13:07 +02:00
static 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 ;
2005-09-11 13:42:48 +02:00
for ( i = 0 ; i < Pool_Size ; i + + ) {
2003-11-05 22:41:01 +01:00
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 */
2005-07-07 20:49:04 +02:00
2001-12-12 18:18:38 +01:00
/* -eof- */