]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn.c
2c65f26e1f52204cffd87e16b60407d482326c6c
[ngircd-alex.git] / src / ngircd / conn.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2003 by Alexander Barton (alex@barton.de)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  *
11  * Connection management
12  */
13
14
15 #define CONN_MODULE
16
17 #include "portab.h"
18
19 static char UNUSED id[] = "$Id: conn.c,v 1.126 2003/11/05 21:41:02 alex Exp $";
20
21 #include "imp.h"
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <time.h>
34 #include <netinet/in.h>
35
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
38 #else
39 #define PF_INET AF_INET
40 #endif
41
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>                     /* e.g. for Mac OS X */
44 #endif
45
46 #ifdef USE_TCPWRAP
47 #include <tcpd.h>                       /* for TCP Wrappers */
48 #endif
49
50 #include "defines.h"
51 #include "resolve.h"
52
53 #include "exp.h"
54 #include "conn.h"
55
56 #include "imp.h"
57 #include "ngircd.h"
58 #include "client.h"
59 #include "conf.h"
60 #include "conn-zip.h"
61 #include "conn-func.h"
62 #include "log.h"
63 #include "parse.h"
64 #include "tool.h"
65
66 #ifdef RENDEZVOUS
67 #include "rendezvous.h"
68 #endif
69
70 #include "exp.h"
71
72
73 #define SERVER_WAIT (NONE - 1)
74
75
76 LOCAL VOID Handle_Read PARAMS(( INT sock ));
77 LOCAL BOOLEAN Handle_Write PARAMS(( CONN_ID Idx ));
78 LOCAL VOID New_Connection PARAMS(( INT Sock ));
79 LOCAL CONN_ID Socket2Index PARAMS(( INT Sock ));
80 LOCAL VOID Read_Request PARAMS(( CONN_ID Idx ));
81 LOCAL BOOLEAN Try_Write PARAMS(( CONN_ID Idx ));
82 LOCAL BOOLEAN Handle_Buffer PARAMS(( CONN_ID Idx ));
83 LOCAL VOID Check_Connections PARAMS(( VOID ));
84 LOCAL VOID Check_Servers PARAMS(( VOID ));
85 LOCAL VOID Init_Conn_Struct PARAMS(( CONN_ID Idx ));
86 LOCAL BOOLEAN Init_Socket PARAMS(( INT Sock ));
87 LOCAL VOID New_Server PARAMS(( INT Server, CONN_ID Idx ));
88 LOCAL VOID Read_Resolver_Result PARAMS(( INT r_fd ));
89 LOCAL VOID Simple_Message PARAMS(( INT Sock, CHAR *Msg ));
90 LOCAL INT Count_Connections PARAMS(( struct sockaddr_in addr ));
91
92 LOCAL fd_set My_Listeners;
93 LOCAL fd_set My_Sockets;
94 LOCAL fd_set My_Connects;
95
96 #ifdef USE_TCPWRAP
97 INT allow_severity = LOG_INFO;
98 INT deny_severity = LOG_ERR;
99 #endif
100
101
102 GLOBAL VOID
103 Conn_Init( VOID )
104 {
105         /* Modul initialisieren: statische Strukturen "ausnullen". */
106
107         CONN_ID i;
108
109         /* Speicher fuer Verbindungs-Pool anfordern */
110         Pool_Size = CONNECTION_POOL;
111         if( Conf_MaxConnections > 0 )
112         {
113                 /* konfiguriertes Limit beachten */
114                 if( Pool_Size > Conf_MaxConnections ) Pool_Size = Conf_MaxConnections;
115         }
116         My_Connections = malloc( sizeof( CONNECTION ) * Pool_Size );
117         if( ! My_Connections )
118         {
119                 /* Speicher konnte nicht alloziert werden! */
120                 Log( LOG_EMERG, "Can't allocate memory! [Conn_Init]" );
121                 exit( 1 );
122         }
123         Log( LOG_DEBUG, "Allocated connection pool for %d items (%ld bytes).", Pool_Size, sizeof( CONNECTION ) * Pool_Size );
124
125         /* zu Beginn haben wir keine Verbindungen */
126         FD_ZERO( &My_Listeners );
127         FD_ZERO( &My_Sockets );
128         FD_ZERO( &My_Connects );
129
130         /* Groesster File-Descriptor fuer select() */
131         Conn_MaxFD = 0;
132
133         /* Connection-Struktur initialisieren */
134         for( i = 0; i < Pool_Size; i++ ) Init_Conn_Struct( i );
135
136         /* Global write counter */
137         WCounter = 0;
138 } /* Conn_Init */
139
140
141 GLOBAL VOID
142 Conn_Exit( VOID )
143 {
144         /* Modul abmelden: alle noch offenen Connections
145          * schliessen und freigeben. */
146
147         CONN_ID idx;
148         INT i;
149
150         Log( LOG_DEBUG, "Shutting down all connections ..." );
151
152 #ifdef RENDEZVOUS
153         Rendezvous_UnregisterListeners( );
154 #endif
155
156         /* Sockets schliessen */
157         for( i = 0; i < Conn_MaxFD + 1; i++ )
158         {
159                 if( FD_ISSET( i, &My_Sockets ))
160                 {
161                         for( idx = 0; idx < Pool_Size; idx++ )
162                         {
163                                 if( My_Connections[idx].sock == i ) break;
164                         }
165                         if( FD_ISSET( i, &My_Listeners ))
166                         {
167                                 close( i );
168                                 Log( LOG_DEBUG, "Listening socket %d closed.", i );
169                         }
170                         else if( FD_ISSET( i, &My_Connects ))
171                         {
172                                 close( i );
173                                 Log( LOG_DEBUG, "Connection %d closed during creation (socket %d).", idx, i );
174                         }
175                         else if( idx < Pool_Size )
176                         {
177                                 if( NGIRCd_SignalRestart ) Conn_Close( idx, NULL, "Server going down (restarting)", TRUE );
178                                 else Conn_Close( idx, NULL, "Server going down", TRUE );
179                         }
180                         else
181                         {
182                                 Log( LOG_WARNING, "Closing unknown connection %d ...", i );
183                                 close( i );
184                         }
185                 }
186         }
187
188         free( My_Connections );
189         My_Connections = NULL;
190         Pool_Size = 0;
191 } /* Conn_Exit */
192
193
194 GLOBAL INT
195 Conn_InitListeners( VOID )
196 {
197         /* Initialize ports on which the server should accept connections */
198
199         INT created, i;
200
201         created = 0;
202         for( i = 0; i < Conf_ListenPorts_Count; i++ )
203         {
204                 if( Conn_NewListener( Conf_ListenPorts[i] )) created++;
205                 else Log( LOG_ERR, "Can't listen on port %u!", Conf_ListenPorts[i] );
206         }
207         return created;
208 } /* Conn_InitListeners */
209
210
211 GLOBAL VOID
212 Conn_ExitListeners( VOID )
213 {
214         /* Close down all listening sockets */
215
216         INT i;
217
218 #ifdef RENDEZVOUS
219         Rendezvous_UnregisterListeners( );
220 #endif
221
222         Log( LOG_INFO, "Shutting down all listening sockets ..." );
223         for( i = 0; i < Conn_MaxFD + 1; i++ )
224         {
225                 if( FD_ISSET( i, &My_Sockets ) && FD_ISSET( i, &My_Listeners ))
226                 {
227                         close( i );
228                         Log( LOG_DEBUG, "Listening socket %d closed.", i );
229                 }
230         }
231 } /* Conn_ExitListeners */
232
233
234 GLOBAL BOOLEAN
235 Conn_NewListener( CONST UINT Port )
236 {
237         /* Create new listening socket on specified port */
238
239         struct sockaddr_in addr;
240         struct in_addr inaddr;
241         INT sock;
242 #ifdef RENDEZVOUS
243         CHAR name[CLIENT_ID_LEN], *info;
244 #endif
245
246         /* Server-"Listen"-Socket initialisieren */
247         memset( &addr, 0, sizeof( addr ));
248         memset( &inaddr, 0, sizeof( inaddr ));
249         addr.sin_family = AF_INET;
250         addr.sin_port = htons( Port );
251         if( Conf_ListenAddress[0] )
252         {
253 #ifdef HAVE_INET_ATON
254                 if( inet_aton( Conf_ListenAddress, &inaddr ) == 0 )
255 #else
256                 inaddr.s_addr = inet_addr( Conf_ListenAddress );
257                 if( inaddr.s_addr == (unsigned)-1 )
258 #endif
259                 {
260                         Log( LOG_CRIT, "Can't listen on %s:%u: can't convert ip address %s!", Conf_ListenAddress, Port, Conf_ListenAddress );
261                         return FALSE;
262                 }
263         }
264         else inaddr.s_addr = htonl( INADDR_ANY );
265         addr.sin_addr = inaddr;
266
267         /* Socket erzeugen */
268         sock = socket( PF_INET, SOCK_STREAM, 0);
269         if( sock < 0 )
270         {
271                 Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
272                 return FALSE;
273         }
274
275         if( ! Init_Socket( sock )) return FALSE;
276
277         /* an Port binden */
278         if( bind( sock, (struct sockaddr *)&addr, (socklen_t)sizeof( addr )) != 0 )
279         {
280                 Log( LOG_CRIT, "Can't bind socket: %s!", strerror( errno ));
281                 close( sock );
282                 return FALSE;
283         }
284
285         /* in "listen mode" gehen :-) */
286         if( listen( sock, 10 ) != 0 )
287         {
288                 Log( LOG_CRIT, "Can't listen on soecket: %s!", strerror( errno ));
289                 close( sock );
290                 return FALSE;
291         }
292
293         /* Neuen Listener in Strukturen einfuegen */
294         FD_SET( sock, &My_Listeners );
295         FD_SET( sock, &My_Sockets );
296
297         if( sock > Conn_MaxFD ) Conn_MaxFD = sock;
298
299         if( Conf_ListenAddress[0]) Log( LOG_INFO, "Now listening on %s:%d (socket %d).", Conf_ListenAddress, Port, sock );
300         else Log( LOG_INFO, "Now listening on 0.0.0.0:%d (socket %d).", Port, sock );
301
302 #ifdef RENDEZVOUS
303         /* Get best server description text */
304         if( ! Conf_ServerInfo[0] ) info = Conf_ServerName;
305         else
306         {
307                 /* Use server info string */
308                 info = NULL;
309                 if( Conf_ServerInfo[0] == '[' )
310                 {
311                         /* Cut off leading hostname part in "[]" */
312                         info = strchr( Conf_ServerInfo, ']' );
313                         if( info )
314                         {
315                                 info++;
316                                 while( *info == ' ' ) info++;
317                         }
318                 }
319                 if( ! info ) info = Conf_ServerInfo;
320         }
321
322         /* Add port number to description if non-standard */
323         if( Port != 6667 ) snprintf( name, sizeof( name ), "%s (port %u)", info, Port );
324         else strlcpy( name, info, sizeof( name ));
325
326         /* Register service */
327         Rendezvous_Register( name, RENDEZVOUS_TYPE, Port );
328 #endif
329
330         return TRUE;
331 } /* Conn_NewListener */
332
333
334 GLOBAL VOID
335 Conn_Handler( VOID )
336 {
337         /* "Hauptschleife": Aktive Verbindungen ueberwachen. Folgende Aktionen
338          * werden dabei durchgefuehrt, bis der Server terminieren oder neu
339          * starten soll:
340          *
341          *  - neue Verbindungen annehmen,
342          *  - Server-Verbindungen aufbauen,
343          *  - geschlossene Verbindungen loeschen,
344          *  - volle Schreibpuffer versuchen zu schreiben,
345          *  - volle Lesepuffer versuchen zu verarbeiten,
346          *  - Antworten von Resolver Sub-Prozessen annehmen.
347          */
348
349         fd_set read_sockets, write_sockets;
350         struct timeval tv;
351         time_t start, t;
352         CONN_ID i, idx;
353         BOOLEAN timeout;
354
355         start = time( NULL );
356         while(( ! NGIRCd_SignalQuit ) && ( ! NGIRCd_SignalRestart ))
357         {
358                 timeout = TRUE;
359
360 #ifdef RENDEZVOUS
361                 Rendezvous_Handler( );
362 #endif
363
364                 /* Should the configuration be reloaded? */
365                 if( NGIRCd_SignalRehash ) NGIRCd_Rehash( );
366
367                 /* Check configured servers and established links */
368                 Check_Servers( );
369                 Check_Connections( );
370
371                 /* noch volle Lese-Buffer suchen */
372                 for( i = 0; i < Pool_Size; i++ )
373                 {
374                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].rdatalen > 0 ))
375                         {
376                                 /* Kann aus dem Buffer noch ein Befehl extrahiert werden? */
377                                 if( Handle_Buffer( i )) timeout = FALSE;
378                         }
379                 }
380
381                 /* noch volle Schreib-Puffer suchen */
382                 FD_ZERO( &write_sockets );
383                 for( i = 0; i < Pool_Size; i++ )
384                 {
385 #ifdef USE_ZLIB
386                         if(( My_Connections[i].sock > NONE ) && (( My_Connections[i].wdatalen > 0 ) || ( My_Connections[i].zip.wdatalen > 0 )))
387 #else
388                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].wdatalen > 0 ))
389 #endif
390                         {
391                                 /* Socket der Verbindung in Set aufnehmen */
392                                 FD_SET( My_Connections[i].sock, &write_sockets );
393                         }
394                 }
395
396                 /* Sockets mit im Aufbau befindlichen ausgehenden Verbindungen suchen */
397                 for( i = 0; i < Pool_Size; i++ )
398                 {
399                         if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects ))) FD_SET( My_Connections[i].sock, &write_sockets );
400                 }
401
402                 /* von welchen Sockets koennte gelesen werden? */
403                 t = time( NULL );
404                 read_sockets = My_Sockets;
405                 for( i = 0; i < Pool_Size; i++ )
406                 {
407                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].host[0] == '\0' ))
408                         {
409                                 /* Hier muss noch auf den Resolver Sub-Prozess gewartet werden */
410                                 FD_CLR( My_Connections[i].sock, &read_sockets );
411                         }
412                         if(( My_Connections[i].sock > NONE ) && ( FD_ISSET( My_Connections[i].sock, &My_Connects )))
413                         {
414                                 /* Hier laeuft noch ein asyncrones connect() */
415                                 FD_CLR( My_Connections[i].sock, &read_sockets );
416                         }
417                         if( My_Connections[i].delaytime > t )
418                         {
419                                 /* Fuer die Verbindung ist eine "Penalty-Zeit" gesetzt */
420                                 FD_CLR( My_Connections[i].sock, &read_sockets );
421                         }
422                 }
423                 for( i = 0; i < Conn_MaxFD + 1; i++ )
424                 {
425                         /* Pipes von Resolver Sub-Prozessen aufnehmen */
426                         if( FD_ISSET( i, &Resolver_FDs ))
427                         {
428                                 FD_SET( i, &read_sockets );
429                         }
430                 }
431
432                 /* Timeout initialisieren */
433                 tv.tv_usec = 0;
434                 if( timeout ) tv.tv_sec = TIME_RES;
435                 else tv.tv_sec = 0;
436
437                 /* Auf Aktivitaet warten */
438                 i = select( Conn_MaxFD + 1, &read_sockets, &write_sockets, NULL, &tv );
439                 if( i == 0 )
440                 {
441                         /* keine Veraenderung an den Sockets */
442                         continue;
443                 }
444                 if( i == -1 )
445                 {
446                         /* Fehler (z.B. Interrupt) */
447                         if( errno != EINTR )
448                         {
449                                 Log( LOG_EMERG, "Conn_Handler(): select(): %s!", strerror( errno ));
450                                 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
451                                 exit( 1 );
452                         }
453                         continue;
454                 }
455
456                 /* Koennen Daten geschrieben werden? */
457                 for( i = 0; i < Conn_MaxFD + 1; i++ )
458                 {
459                         if( ! FD_ISSET( i, &write_sockets )) continue;
460
461                         /* Es kann geschrieben werden ... */
462                         idx = Socket2Index( i );
463                         if( idx == NONE ) continue;
464
465                         if( ! Handle_Write( idx ))
466                         {
467                                 /* Fehler beim Schreiben! Diesen Socket nun
468                                  * auch aus dem Read-Set entfernen: */
469                                 FD_CLR( i, &read_sockets );
470                         }
471                 }
472
473                 /* Daten zum Lesen vorhanden? */
474                 for( i = 0; i < Conn_MaxFD + 1; i++ )
475                 {
476                         if( FD_ISSET( i, &read_sockets )) Handle_Read( i );
477                 }
478         }
479
480         if( NGIRCd_SignalQuit ) Log( LOG_NOTICE|LOG_snotice, "Server going down NOW!" );
481         else if( NGIRCd_SignalRestart ) Log( LOG_NOTICE|LOG_snotice, "Server restarting NOW!" );
482 } /* Conn_Handler */
483
484
485 #ifdef PROTOTYPES
486 GLOBAL BOOLEAN
487 Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... )
488 #else
489 GLOBAL BOOLEAN
490 Conn_WriteStr( Idx, Format, va_alist )
491 CONN_ID Idx;
492 CHAR *Format;
493 va_dcl
494 #endif
495 {
496         /* String in Socket schreiben. CR+LF wird von dieser Funktion
497          * automatisch angehaengt. Im Fehlerfall wird dir Verbindung
498          * getrennt und FALSE geliefert. */
499
500         CHAR buffer[COMMAND_LEN];
501         BOOLEAN ok;
502         va_list ap;
503
504         assert( Idx > NONE );
505         assert( Format != NULL );
506
507 #ifdef PROTOTYPES
508         va_start( ap, Format );
509 #else
510         va_start( ap );
511 #endif
512         if( vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) == COMMAND_LEN - 2 )
513         {
514                 Log( LOG_CRIT, "Text too long to send (connection %d)!", Idx );
515                 Conn_Close( Idx, "Text too long to send!", NULL, FALSE );
516                 return FALSE;
517         }
518
519 #ifdef SNIFFER
520         if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer );
521 #endif
522
523         strlcat( buffer, "\r\n", sizeof( buffer ));
524         ok = Conn_Write( Idx, buffer, strlen( buffer ));
525         My_Connections[Idx].msg_out++;
526
527         va_end( ap );
528         return ok;
529 } /* Conn_WriteStr */
530
531
532 GLOBAL BOOLEAN
533 Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
534 {
535         /* Daten in Socket schreiben. Bei "fatalen" Fehlern wird
536          * der Client disconnectiert und FALSE geliefert. */
537
538         assert( Idx > NONE );
539         assert( Data != NULL );
540         assert( Len > 0 );
541
542         /* Ist der entsprechende Socket ueberhaupt noch offen? In einem
543          * "Handler-Durchlauf" kann es passieren, dass dem nicht mehr so
544          * ist, wenn einer von mehreren Conn_Write()'s fehlgeschlagen ist.
545          * In diesem Fall wird hier einfach ein Fehler geliefert. */
546         if( My_Connections[Idx].sock <= NONE )
547         {
548                 Log( LOG_DEBUG, "Skipped write on closed socket (connection %d).", Idx );
549                 return FALSE;
550         }
551
552         /* Pruefen, ob im Schreibpuffer genuegend Platz ist. Ziel ist es,
553          * moeglichts viel im Puffer zu haben und _nicht_ gleich alles auf den
554          * Socket zu schreiben (u.a. wg. Komprimierung). */
555         if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
556         {
557                 /* Der Puffer ist dummerweise voll. Jetzt versuchen, den Puffer
558                  * zu schreiben, wenn das nicht klappt, haben wir ein Problem ... */
559                 if( ! Try_Write( Idx )) return FALSE;
560
561                 /* nun neu pruefen: */
562                 if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
563                 {
564                         Log( LOG_NOTICE, "Write buffer overflow (connection %d)!", Idx );
565                         Conn_Close( Idx, "Write buffer overflow!", NULL, FALSE );
566                         return FALSE;
567                 }
568         }
569
570 #ifdef USE_ZLIB
571         if( My_Connections[Idx].options & CONN_ZIP )
572         {
573                 /* Daten komprimieren und in Puffer kopieren */
574                 if( ! Zip_Buffer( Idx, Data, Len )) return FALSE;
575         }
576         else
577 #endif
578         {
579                 /* Daten in Puffer kopieren */
580                 memcpy( My_Connections[Idx].wbuf + My_Connections[Idx].wdatalen, Data, Len );
581                 My_Connections[Idx].wdatalen += Len;
582                 My_Connections[Idx].bytes_out += Len;
583         }
584
585         /* Adjust global write counter */
586         WCounter += Len;
587
588         return TRUE;
589 } /* Conn_Write */
590
591
592 GLOBAL VOID
593 Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient )
594 {
595         /* Close connection. Open pipes of asyncronous resolver
596          * sub-processes are closed down. */
597
598         CLIENT *c;
599         DOUBLE in_k, out_k;
600 #ifdef USE_ZLIB
601         DOUBLE in_z_k, out_z_k;
602         INT in_p, out_p;
603 #endif
604
605         assert( Idx > NONE );
606         assert( My_Connections[Idx].sock > NONE );
607
608         /* Is this link already shutting down? */
609         if( My_Connections[Idx].options & CONN_ISCLOSING )
610         {
611                 /* Conn_Close() has been called recursively for this link;
612                  * probabe reason: Try_Write() failed  -- see below. */
613                 return;
614         }
615
616         /* Mark link as "closing" */
617         My_Connections[Idx].options |= CONN_ISCLOSING;
618
619         /* Search client, if any */
620         c = Client_GetFromConn( Idx );
621
622         /* Should the client be informed? */
623         if( InformClient )
624         {
625 #ifndef STRICT_RFC
626                 /* Send statistics to client if registered as user: */
627                 if(( c != NULL ) && ( Client_Type( c ) == CLIENT_USER ))
628                 {
629                         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 );
630                 }
631 #endif
632
633                 /* Send ERROR to client (see RFC!) */
634                 if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg );
635                 else Conn_WriteStr( Idx, "ERROR :Closing connection." );
636                 if( My_Connections[Idx].sock == NONE ) return;
637         }
638
639         /* Try to write out the write buffer */
640         (VOID)Try_Write( Idx );
641
642         /* Shut down socket */
643         if( close( My_Connections[Idx].sock ) != 0 )
644         {
645                 /* Oops, we can't close the socket!? This is fatal! */
646                 Log( LOG_EMERG, "Error closing connection %d (socket %d) with %s:%d - %s!", Idx, My_Connections[Idx].sock, My_Connections[Idx].host, ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
647                 Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
648                 exit( 1 );
649         }
650
651         /* Mark socket as invalid: */
652         FD_CLR( My_Connections[Idx].sock, &My_Sockets );
653         FD_CLR( My_Connections[Idx].sock, &My_Connects );
654         My_Connections[Idx].sock = NONE;
655
656         /* If there is still a client, unregister it now */
657         if( c ) Client_Destroy( c, LogMsg, FwdMsg, TRUE );
658
659         /* Calculate statistics and log information */
660         in_k = (DOUBLE)My_Connections[Idx].bytes_in / 1024;
661         out_k = (DOUBLE)My_Connections[Idx].bytes_out / 1024;
662 #ifdef USE_ZLIB
663         if( My_Connections[Idx].options & CONN_ZIP )
664         {
665                 in_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_in / 1024;
666                 out_z_k = (DOUBLE)My_Connections[Idx].zip.bytes_out / 1024;
667                 in_p = (INT)(( in_k * 100 ) / in_z_k );
668                 out_p = (INT)(( out_k * 100 ) / out_z_k );
669                 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 );
670         }
671         else
672 #endif
673         {
674                 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 );
675         }
676
677         /* Is there a resolver sub-process running? */
678         if( My_Connections[Idx].res_stat )
679         {
680                 /* Free resolver structures */
681                 FD_CLR( My_Connections[Idx].res_stat->pipe[0], &Resolver_FDs );
682                 close( My_Connections[Idx].res_stat->pipe[0] );
683                 close( My_Connections[Idx].res_stat->pipe[1] );
684                 free( My_Connections[Idx].res_stat );
685         }
686
687         /* Servers: Modify time of next connect attempt? */
688         Conf_UnsetServer( Idx );
689
690 #ifdef USE_ZLIB
691         /* Clean up zlib, if link was compressed */
692         if( Conn_Options( Idx ) & CONN_ZIP )
693         {
694                 inflateEnd( &My_Connections[Idx].zip.in );
695                 deflateEnd( &My_Connections[Idx].zip.out );
696         }
697 #endif
698
699         /* Clean up connection structure (=free it) */
700         Init_Conn_Struct( Idx );
701 } /* Conn_Close */
702
703
704 GLOBAL VOID
705 Conn_SyncServerStruct( VOID )
706 {
707         /* Synchronize server structures (connection IDs):
708          * connections <-> configuration */
709
710         CLIENT *client;
711         CONN_ID i;
712         INT c;
713
714         for( i = 0; i < Pool_Size; i++ )
715         {
716                 /* Established connection? */
717                 if( My_Connections[i].sock <= NONE ) continue;
718
719                 /* Server connection? */
720                 client = Client_GetFromConn( i );
721                 if(( ! client ) || ( Client_Type( client ) != CLIENT_SERVER )) continue;
722
723                 for( c = 0; c < MAX_SERVERS; c++ )
724                 {
725                         /* Configured server? */
726                         if( ! Conf_Server[c].host[0] ) continue;
727
728                         /* Duplicate? */
729                         if( strcmp( Conf_Server[c].name, Client_ID( client )) == 0 ) Conf_Server[c].conn_id = i;
730                 }
731         }
732 } /* SyncServerStruct */
733
734
735 LOCAL BOOLEAN
736 Try_Write( CONN_ID Idx )
737 {
738         /* Versuchen, Daten aus dem Schreib-Puffer in den Socket zu
739          * schreiben. TRUE wird geliefert, wenn entweder keine Daten
740          * zum Versenden vorhanden sind oder erfolgreich bearbeitet
741          * werden konnten. Im Fehlerfall wird FALSE geliefert und
742          * die Verbindung geschlossen. */
743
744         fd_set write_socket;
745         struct timeval tv;
746
747         assert( Idx > NONE );
748         assert( My_Connections[Idx].sock > NONE );
749
750         /* sind ueberhaupt Daten vorhanden? */
751 #ifdef USE_ZLIB
752         if(( ! My_Connections[Idx].wdatalen > 0 ) && ( ! My_Connections[Idx].zip.wdatalen )) return TRUE;
753 #else
754         if( ! My_Connections[Idx].wdatalen > 0 ) return TRUE;
755 #endif
756
757         /* Timeout initialisieren: 0 Sekunden, also nicht blockieren */
758         tv.tv_sec = 0; tv.tv_usec = 0;
759
760         FD_ZERO( &write_socket );
761         FD_SET( My_Connections[Idx].sock, &write_socket );
762         if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, &tv ) == -1 )
763         {
764                 /* Fehler! */
765                 if( errno != EINTR )
766                 {
767                         Log( LOG_ALERT, "Try_Write(): select() failed: %s (con=%d, sock=%d)!", strerror( errno ), Idx, My_Connections[Idx].sock );
768                         Conn_Close( Idx, "Server error!", NULL, FALSE );
769                         return FALSE;
770                 }
771         }
772
773         if( FD_ISSET( My_Connections[Idx].sock, &write_socket )) return Handle_Write( Idx );
774         else return TRUE;
775 } /* Try_Write */
776
777
778 LOCAL VOID
779 Handle_Read( INT Sock )
780 {
781         /* Aktivitaet auf einem Socket verarbeiten:
782          *  - neue Clients annehmen,
783          *  - Daten von Clients verarbeiten,
784          *  - Resolver-Rueckmeldungen annehmen. */
785
786         CONN_ID idx;
787
788         assert( Sock > NONE );
789
790         if( FD_ISSET( Sock, &My_Listeners ))
791         {
792                 /* es ist einer unserer Listener-Sockets: es soll
793                  * also eine neue Verbindung aufgebaut werden. */
794
795                 New_Connection( Sock );
796         }
797         else if( FD_ISSET( Sock, &Resolver_FDs ))
798         {
799                 /* Rueckmeldung von einem Resolver Sub-Prozess */
800
801                 Read_Resolver_Result( Sock );
802         }
803         else
804         {
805                 /* Ein Client Socket: entweder ein User oder Server */
806
807                 idx = Socket2Index( Sock );
808                 if( idx > NONE ) Read_Request( idx );
809         }
810 } /* Handle_Read */
811
812
813 LOCAL BOOLEAN
814 Handle_Write( CONN_ID Idx )
815 {
816         /* Daten aus Schreibpuffer versenden bzw. Connection aufbauen */
817
818         INT len, res, err;
819         socklen_t sock_len;
820         CLIENT *c;
821
822         assert( Idx > NONE );
823         assert( My_Connections[Idx].sock > NONE );
824
825         if( FD_ISSET( My_Connections[Idx].sock, &My_Connects ))
826         {
827                 /* es soll nichts geschrieben werden, sondern ein
828                  * connect() hat ein Ergebnis geliefert */
829
830                 FD_CLR( My_Connections[Idx].sock, &My_Connects );
831
832                 /* Ergebnis des connect() ermitteln */
833                 sock_len = sizeof( err );
834                 res = getsockopt( My_Connections[Idx].sock, SOL_SOCKET, SO_ERROR, &err, &sock_len );
835                 assert( sock_len == sizeof( err ));
836
837                 /* Fehler aufgetreten? */
838                 if(( res != 0 ) || ( err != 0 ))
839                 {
840                         /* Fehler! */
841                         if( res != 0 ) Log( LOG_CRIT, "getsockopt (connection %d): %s!", Idx, strerror( errno ));
842                         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 ));
843
844                         /* Clean up socket, connection and client structures */
845                         FD_CLR( My_Connections[Idx].sock, &My_Sockets );
846                         c = Client_GetFromConn( Idx );
847                         if( c ) Client_DestroyNow( c );
848                         close( My_Connections[Idx].sock );
849                         Init_Conn_Struct( Idx );
850
851                         /* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */
852                         Conf_Server[Conf_GetServer( Idx )].lasttry = time( NULL );
853                         Conf_UnsetServer( Idx );
854
855                         return FALSE;
856                 }
857                 Log( LOG_DEBUG, "Connection %d with \"%s:%d\" established, now sendig PASS and SERVER ...", Idx, My_Connections[Idx].host, Conf_Server[Conf_GetServer( Idx )].port );
858
859                 /* PASS und SERVER verschicken */
860                 Conn_WriteStr( Idx, "PASS %s %s", Conf_Server[Conf_GetServer( Idx )].pwd_out, NGIRCd_ProtoID );
861                 return Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
862         }
863
864 #ifdef USE_ZLIB
865         /* Schreibpuffer leer, aber noch Daten im Kompressionsbuffer?
866          * Dann muss dieser nun geflushed werden! */
867         if( My_Connections[Idx].wdatalen == 0 ) Zip_Flush( Idx );
868 #endif
869
870         assert( My_Connections[Idx].wdatalen > 0 );
871
872         /* Daten schreiben */
873         len = send( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen, 0 );
874         if( len < 0 )
875         {
876                 /* Operation haette Socket "nur" blockiert ... */
877                 if( errno == EAGAIN ) return TRUE;
878
879                 /* Oops, ein Fehler! */
880                 Log( LOG_ERR, "Write error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror( errno ));
881                 Conn_Close( Idx, "Write error!", NULL, FALSE );
882                 return FALSE;
883         }
884
885         /* Puffer anpassen */
886         My_Connections[Idx].wdatalen -= len;
887         memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen );
888
889         return TRUE;
890 } /* Handle_Write */
891
892
893 LOCAL VOID
894 New_Connection( INT Sock )
895 {
896         /* Neue Client-Verbindung von Listen-Socket annehmen und
897          * CLIENT-Struktur anlegen. */
898
899 #ifdef USE_TCPWRAP
900         struct request_info req;
901 #endif
902         struct sockaddr_in new_addr;
903         INT new_sock, new_sock_len;
904         RES_STAT *s;
905         CONN_ID idx;
906         CLIENT *c;
907         POINTER *ptr;
908         LONG new_size, cnt;
909
910         assert( Sock > NONE );
911
912         /* Connection auf Listen-Socket annehmen */
913         new_sock_len = sizeof( new_addr );
914         new_sock = accept( Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len );
915         if( new_sock < 0 )
916         {
917                 Log( LOG_CRIT, "Can't accept connection: %s!", strerror( errno ));
918                 return;
919         }
920
921 #ifdef USE_TCPWRAP
922         /* Validate socket using TCP Wrappers */
923         request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL );
924         if( ! hosts_access( &req ))
925         {
926                 /* Access denied! */
927                 Log( deny_severity, "Refused connection from %s (by TCP Wrappers)!", inet_ntoa( new_addr.sin_addr ));
928                 Simple_Message( new_sock, "ERROR :Connection refused" );
929                 close( new_sock );
930                 return;
931         }
932 #endif
933
934         /* Socket initialisieren */
935         Init_Socket( new_sock );
936         
937         /* Check IP-based connection limit */
938         cnt = Count_Connections( new_addr );
939         if(( Conf_MaxConnectionsIP > 0 ) && ( cnt >= Conf_MaxConnectionsIP ))
940         {
941                 /* Access denied, too many connections from this IP! */
942                 Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP!", inet_ntoa( new_addr.sin_addr ), cnt);
943                 Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP!" );
944                 close( new_sock );
945                 return;
946         }
947
948         /* Freie Connection-Struktur suchen */
949         for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
950         if( idx >= Pool_Size )
951         {
952                 new_size = Pool_Size + CONNECTION_POOL;
953
954                 /* Im bisherigen Pool wurde keine freie Connection-Struktur mehr gefunden.
955                  * Wenn erlaubt und moeglich muss nun der Pool vergroessert werden: */
956
957                 if( Conf_MaxConnections > 0 )
958                 {
959                         /* Es ist ein Limit konfiguriert */
960                         if( Pool_Size >= Conf_MaxConnections )
961                         {
962                                 /* Mehr Verbindungen duerfen wir leider nicht mehr annehmen ... */
963                                 Log( LOG_ALERT, "Can't accept connection: limit (%d) reached!", Pool_Size );
964                                 Simple_Message( new_sock, "ERROR :Connection limit reached" );
965                                 close( new_sock );
966                                 return;
967                         }
968                         if( new_size > Conf_MaxConnections ) new_size = Conf_MaxConnections;
969                 }
970                 if( new_size < Pool_Size )
971                 {
972                         Log( LOG_ALERT, "Can't accespt connection: limit (%d) reached -- overflow!", Pool_Size );
973                         Simple_Message( new_sock, "ERROR :Connection limit reached" );
974                         close( new_sock );
975                         return;
976                 }
977
978                 /* zunaechst realloc() versuchen; wenn das scheitert, malloc() versuchen
979                  * und Daten ggf. "haendisch" umkopieren. (Haesslich! Eine wirklich
980                  * dynamische Verwaltung waere wohl _deutlich_ besser ...) */
981                 ptr = realloc( My_Connections, sizeof( CONNECTION ) * new_size );
982                 if( ! ptr )
983                 {
984                         /* realloc() ist fehlgeschlagen. Nun malloc() probieren: */
985                         ptr = malloc( sizeof( CONNECTION ) * new_size );
986                         if( ! ptr )
987                         {
988                                 /* Offenbar steht kein weiterer Sepeicher zur Verfuegung :-( */
989                                 Log( LOG_EMERG, "Can't allocate memory! [New_Connection]" );
990                                 Simple_Message( new_sock, "ERROR: Internal error" );
991                                 close( new_sock );
992                                 return;
993                         }
994
995                         /* Struktur umkopieren ... */
996                         memcpy( ptr, My_Connections, sizeof( CONNECTION ) * Pool_Size );
997
998                         Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [malloc()/memcpy()]", new_size, sizeof( CONNECTION ) * new_size );
999                 }
1000                 else Log( LOG_DEBUG, "Allocated new connection pool for %ld items (%ld bytes). [realloc()]", new_size, sizeof( CONNECTION ) * new_size );
1001
1002                 /* Adjust pointer to new block */
1003                 My_Connections = ptr;
1004
1005                 /* Initialize new items */
1006                 for( idx = Pool_Size; idx < new_size; idx++ ) Init_Conn_Struct( idx );
1007                 idx = Pool_Size;
1008
1009                 /* Adjust new pool size */
1010                 Pool_Size = new_size;
1011         }
1012
1013         /* Client-Struktur initialisieren */
1014         c = Client_NewLocal( idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, FALSE );
1015         if( ! c )
1016         {
1017                 Log( LOG_ALERT, "Can't accept connection: can't create client structure!" );
1018                 Simple_Message( new_sock, "ERROR :Internal error" );
1019                 close( new_sock );
1020                 return;
1021         }
1022
1023         /* Verbindung registrieren */
1024         Init_Conn_Struct( idx );
1025         My_Connections[idx].sock = new_sock;
1026         My_Connections[idx].addr = new_addr;
1027
1028         /* Neuen Socket registrieren */
1029         FD_SET( new_sock, &My_Sockets );
1030         if( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock;
1031
1032         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 );
1033
1034         /* Hostnamen ermitteln */
1035         strlcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr ), sizeof( My_Connections[idx].host ));
1036         Client_SetHostname( c, My_Connections[idx].host );
1037         s = Resolve_Addr( &new_addr );
1038         if( s )
1039         {
1040                 /* Sub-Prozess wurde asyncron gestartet */
1041                 My_Connections[idx].res_stat = s;
1042         }
1043
1044         /* Penalty-Zeit setzen */
1045         Conn_SetPenalty( idx, 4 );
1046 } /* New_Connection */
1047
1048
1049 LOCAL CONN_ID
1050 Socket2Index( INT Sock )
1051 {
1052         /* zum Socket passende Connection suchen */
1053
1054         CONN_ID idx;
1055
1056         assert( Sock > NONE );
1057
1058         for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == Sock ) break;
1059
1060         if( idx >= Pool_Size )
1061         {
1062                 /* die Connection wurde vermutlich (wegen eines
1063                  * Fehlers) bereits wieder abgebaut ... */
1064                 Log( LOG_DEBUG, "Socket2Index: can't get connection for socket %d!", Sock );
1065                 return NONE;
1066         }
1067         else return idx;
1068 } /* Socket2Index */
1069
1070
1071 LOCAL VOID
1072 Read_Request( CONN_ID Idx )
1073 {
1074         /* Daten von Socket einlesen und entsprechend behandeln.
1075          * Tritt ein Fehler auf, so wird der Socket geschlossen. */
1076
1077         INT len, bsize;
1078 #ifdef USE_ZLIB
1079         CLIENT *c;
1080 #endif
1081
1082         assert( Idx > NONE );
1083         assert( My_Connections[Idx].sock > NONE );
1084
1085         /* wenn noch nicht registriert: maximal mit ZREADBUFFER_LEN arbeiten,
1086          * ansonsten koennen Daten ggf. nicht umkopiert werden. */
1087         bsize = READBUFFER_LEN;
1088 #ifdef USE_ZLIB
1089         c = Client_GetFromConn( Idx );
1090         if(( Client_Type( c ) != CLIENT_USER ) && ( Client_Type( c ) != CLIENT_SERVER ) && ( Client_Type( c ) != CLIENT_SERVICE ) && ( bsize > ZREADBUFFER_LEN )) bsize = ZREADBUFFER_LEN;
1091 #endif
1092
1093 #ifdef USE_ZLIB
1094         if(( bsize - My_Connections[Idx].rdatalen - 1 < 1 ) || ( ZREADBUFFER_LEN - My_Connections[Idx].zip.rdatalen < 1 ))
1095 #else
1096         if( bsize - My_Connections[Idx].rdatalen - 1 < 1 )
1097 #endif
1098         {
1099                 /* Der Lesepuffer ist voll */
1100                 Log( LOG_ERR, "Read buffer overflow (connection %d): %d bytes!", Idx, My_Connections[Idx].rdatalen );
1101                 Conn_Close( Idx, "Read buffer overflow!", NULL, FALSE );
1102                 return;
1103         }
1104
1105 #ifdef USE_ZLIB
1106         if( My_Connections[Idx].options & CONN_ZIP )
1107         {
1108                 len = recv( My_Connections[Idx].sock, My_Connections[Idx].zip.rbuf + My_Connections[Idx].zip.rdatalen, ( ZREADBUFFER_LEN - My_Connections[Idx].zip.rdatalen ), 0 );
1109                 if( len > 0 ) My_Connections[Idx].zip.rdatalen += len;
1110         }
1111         else
1112 #endif
1113         {
1114                 len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, bsize - My_Connections[Idx].rdatalen - 1, 0 );
1115                 if( len > 0 ) My_Connections[Idx].rdatalen += len;
1116         }
1117
1118         if( len == 0 )
1119         {
1120                 /* Socket wurde geschlossen */
1121                 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 ));
1122                 Conn_Close( Idx, "Socket closed!", "Client closed connection", FALSE );
1123                 return;
1124         }
1125
1126         if( len < 0 )
1127         {
1128                 /* Operation haette Socket "nur" blockiert ... */
1129                 if( errno == EAGAIN ) return;
1130
1131                 /* Fehler beim Lesen */
1132                 Log( LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror( errno ));
1133                 Conn_Close( Idx, "Read error!", "Client closed connection", FALSE );
1134                 return;
1135         }
1136
1137         /* Connection-Statistik aktualisieren */
1138         My_Connections[Idx].bytes_in += len;
1139
1140         /* Timestamp aktualisieren */
1141         My_Connections[Idx].lastdata = time( NULL );
1142
1143         Handle_Buffer( Idx );
1144 } /* Read_Request */
1145
1146
1147 LOCAL BOOLEAN
1148 Handle_Buffer( CONN_ID Idx )
1149 {
1150         /* Daten im Lese-Puffer einer Verbindung verarbeiten.
1151          * Wurde ein Request verarbeitet, so wird TRUE geliefert,
1152          * ansonsten FALSE (auch bei Fehlern). */
1153
1154 #ifndef STRICT_RFC
1155         CHAR *ptr1, *ptr2;
1156 #endif
1157         CHAR *ptr;
1158         INT len, delta;
1159         BOOLEAN action, result;
1160 #ifdef USE_ZLIB
1161         BOOLEAN old_z;
1162 #endif
1163
1164         result = FALSE;
1165         do
1166         {
1167 #ifdef USE_ZLIB
1168                 /* ggf. noch unkomprimiete Daten weiter entpacken */
1169                 if( My_Connections[Idx].options & CONN_ZIP )
1170                 {
1171                         if( ! Unzip_Buffer( Idx )) return FALSE;
1172                 }
1173 #endif
1174
1175                 if( My_Connections[Idx].rdatalen < 1 ) break;
1176
1177                 /* Eine komplette Anfrage muss mit CR+LF enden, vgl.
1178                  * RFC 2812. Haben wir eine? */
1179                 My_Connections[Idx].rbuf[My_Connections[Idx].rdatalen] = '\0';
1180                 ptr = strstr( My_Connections[Idx].rbuf, "\r\n" );
1181
1182                 if( ptr ) delta = 2;
1183 #ifndef STRICT_RFC
1184                 else
1185                 {
1186                         /* Nicht RFC-konforme Anfrage mit nur CR oder LF? Leider
1187                          * machen soetwas viele Clients, u.a. "mIRC" :-( */
1188                         ptr1 = strchr( My_Connections[Idx].rbuf, '\r' );
1189                         ptr2 = strchr( My_Connections[Idx].rbuf, '\n' );
1190                         delta = 1;
1191                         if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
1192                         else if( ptr1 ) ptr = ptr1;
1193                         else if( ptr2 ) ptr = ptr2;
1194                 }
1195 #endif
1196
1197                 action = FALSE;
1198                 if( ptr )
1199                 {
1200                         /* Ende der Anfrage wurde gefunden */
1201                         *ptr = '\0';
1202                         len = ( ptr - My_Connections[Idx].rbuf ) + delta;
1203                         if( len > ( COMMAND_LEN - 1 ))
1204                         {
1205                                 /* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
1206                                  * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas
1207                                  * empfangen wird, wird der Client disconnectiert. */
1208                                 Log( LOG_ERR, "Request too long (connection %d): %d bytes (max. %d expected)!", Idx, My_Connections[Idx].rdatalen, COMMAND_LEN - 1 );
1209                                 Conn_Close( Idx, NULL, "Request too long", TRUE );
1210                                 return FALSE;
1211                         }
1212
1213 #ifdef USE_ZLIB
1214                         /* merken, ob Stream bereits komprimiert wird */
1215                         old_z = My_Connections[Idx].options & CONN_ZIP;
1216 #endif
1217
1218                         if( len > delta )
1219                         {
1220                                 /* Es wurde ein Request gelesen */
1221                                 My_Connections[Idx].msg_in++;
1222                                 if( ! Parse_Request( Idx, My_Connections[Idx].rbuf )) return FALSE;
1223                                 else action = TRUE;
1224                         }
1225
1226                         /* Puffer anpassen */
1227                         My_Connections[Idx].rdatalen -= len;
1228                         memmove( My_Connections[Idx].rbuf, My_Connections[Idx].rbuf + len, My_Connections[Idx].rdatalen );
1229
1230 #ifdef USE_ZLIB
1231                         if(( ! old_z ) && ( My_Connections[Idx].options & CONN_ZIP ) && ( My_Connections[Idx].rdatalen > 0 ))
1232                         {
1233                                 /* Mit dem letzten Befehl wurde Socket-Kompression aktiviert.
1234                                  * Evtl. schon vom Socket gelesene Daten in den Unzip-Puffer
1235                                  * umkopieren, damit diese nun zunaechst entkomprimiert werden */
1236                                 {
1237                                         if( My_Connections[Idx].rdatalen > ZREADBUFFER_LEN )
1238                                         {
1239                                                 /* Hupsa! Soviel Platz haben wir aber gar nicht! */
1240                                                 Log( LOG_ALERT, "Can't move read buffer: No space left in unzip buffer (need %d bytes)!", My_Connections[Idx].rdatalen );
1241                                                 return FALSE;
1242                                         }
1243                                         memcpy( My_Connections[Idx].zip.rbuf, My_Connections[Idx].rbuf, My_Connections[Idx].rdatalen );
1244                                         My_Connections[Idx].zip.rdatalen = My_Connections[Idx].rdatalen;
1245                                         My_Connections[Idx].rdatalen = 0;
1246                                         Log( LOG_DEBUG, "Moved already received data (%d bytes) to uncompression buffer.", My_Connections[Idx].zip.rdatalen );
1247                                 }
1248                         }
1249 #endif
1250                 }
1251
1252                 if( action ) result = TRUE;
1253         } while( action );
1254
1255         return result;
1256 } /* Handle_Buffer */
1257
1258
1259 LOCAL VOID
1260 Check_Connections( VOID )
1261 {
1262         /* Pruefen, ob Verbindungen noch "alive" sind. Ist dies
1263          * nicht der Fall, zunaechst PING-PONG spielen und, wenn
1264          * auch das nicht "hilft", Client disconnectieren. */
1265
1266         CLIENT *c;
1267         CONN_ID i;
1268
1269         for( i = 0; i < Pool_Size; i++ )
1270         {
1271                 if( My_Connections[i].sock == NONE ) continue;
1272
1273                 c = Client_GetFromConn( i );
1274                 if( c && (( Client_Type( c ) == CLIENT_USER ) || ( Client_Type( c ) == CLIENT_SERVER ) || ( Client_Type( c ) == CLIENT_SERVICE )))
1275                 {
1276                         /* verbundener User, Server oder Service */
1277                         if( My_Connections[i].lastping > My_Connections[i].lastdata )
1278                         {
1279                                 /* es wurde bereits ein PING gesendet */
1280                                 if( My_Connections[i].lastping < time( NULL ) - Conf_PongTimeout )
1281                                 {
1282                                         /* Timeout */
1283                                         Log( LOG_DEBUG, "Connection %d: Ping timeout: %d seconds.", i, Conf_PongTimeout );
1284                                         Conn_Close( i, NULL, "Ping timeout", TRUE );
1285                                 }
1286                         }
1287                         else if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
1288                         {
1289                                 /* es muss ein PING gesendet werden */
1290                                 Log( LOG_DEBUG, "Connection %d: sending PING ...", i );
1291                                 My_Connections[i].lastping = time( NULL );
1292                                 Conn_WriteStr( i, "PING :%s", Client_ID( Client_ThisServer( )));
1293                         }
1294                 }
1295                 else
1296                 {
1297                         /* noch nicht vollstaendig aufgebaute Verbindung */
1298                         if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
1299                         {
1300                                 /* Timeout */
1301                                 Log( LOG_DEBUG, "Connection %d timed out ...", i );
1302                                 Conn_Close( i, NULL, "Timeout", FALSE );
1303                         }
1304                 }
1305         }
1306 } /* Check_Connections */
1307
1308
1309 LOCAL VOID
1310 Check_Servers( VOID )
1311 {
1312         /* Check if we can establish further server links */
1313
1314         RES_STAT *s;
1315         CONN_ID idx;
1316         INT i, n;
1317
1318         /* Serach all connections, are there results from the resolver? */
1319         for( idx = 0; idx < Pool_Size; idx++ )
1320         {
1321                 if( My_Connections[idx].sock != SERVER_WAIT ) continue;
1322
1323                 /* IP resolved? */
1324                 if( My_Connections[idx].res_stat == NULL ) New_Server( Conf_GetServer( idx ), idx );
1325         }
1326
1327         /* Check all configured servers */
1328         for( i = 0; i < MAX_SERVERS; i++ )
1329         {
1330                 /* Valid outgoing server which isn't already connected or disabled? */
1331                 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;
1332
1333                 /* Is there already a connection in this group? */
1334                 if( Conf_Server[i].group > NONE )
1335                 {
1336                         for( n = 0; n < MAX_SERVERS; n++ )
1337                         {
1338                                 if( n == i ) continue;
1339                                 if(( Conf_Server[n].conn_id > NONE ) && ( Conf_Server[n].group == Conf_Server[i].group )) break;
1340                         }
1341                         if( n < MAX_SERVERS ) continue;
1342                 }
1343
1344                 /* Check last connect attempt? */
1345                 if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue;
1346
1347                 /* Okay, try to connect now */
1348                 Conf_Server[i].lasttry = time( NULL );
1349
1350                 /* Search free connection structure */
1351                 for( idx = 0; idx < Pool_Size; idx++ ) if( My_Connections[idx].sock == NONE ) break;
1352                 if( idx >= Pool_Size )
1353                 {
1354                         Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", Pool_Size );
1355                         return;
1356                 }
1357                 Log( LOG_DEBUG, "Preparing connection %d for \"%s\" ...", idx, Conf_Server[i].host );
1358
1359                 /* Verbindungs-Struktur initialisieren */
1360                 Init_Conn_Struct( idx );
1361                 My_Connections[idx].sock = SERVER_WAIT;
1362                 Conf_Server[i].conn_id = idx;
1363
1364                 /* Resolve Hostname. If this fails, try to use it as an IP address */
1365                 strlcpy( Conf_Server[i].ip, Conf_Server[i].host, sizeof( Conf_Server[i].ip ));
1366                 strlcpy( My_Connections[idx].host, Conf_Server[i].host, sizeof( My_Connections[idx].host ));
1367                 s = Resolve_Name( Conf_Server[i].host );
1368                 if( s )
1369                 {
1370                         /* Sub-Prozess wurde asyncron gestartet */
1371                         My_Connections[idx].res_stat = s;
1372                 }
1373         }
1374 } /* Check_Servers */
1375
1376
1377 LOCAL VOID
1378 New_Server( INT Server, CONN_ID Idx )
1379 {
1380         /* Establish new server link */
1381
1382         struct sockaddr_in new_addr;
1383         struct in_addr inaddr;
1384         INT res, new_sock;
1385         CLIENT *c;
1386
1387         assert( Server > NONE );
1388         assert( Idx > NONE );
1389
1390         /* Did we get a valid IP address? */
1391         if( ! Conf_Server[Server].ip[0] )
1392         {
1393                 /* No. Free connection structure and abort: */
1394                 Init_Conn_Struct( Idx );
1395                 Conf_Server[Server].conn_id = NONE;
1396                 Log( LOG_ERR, "Can't connect to \"%s\" (connection %d): ip address unknown!", Conf_Server[Server].host, Idx );
1397                 return;
1398         }
1399
1400         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 );
1401
1402 #ifdef HAVE_INET_ATON
1403         if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 )
1404 #else
1405         memset( &inaddr, 0, sizeof( inaddr ));
1406         inaddr.s_addr = inet_addr( Conf_Server[Server].ip );
1407         if( inaddr.s_addr == (unsigned)-1 )
1408 #endif
1409         {
1410                 /* Can't convert IP address */
1411                 Init_Conn_Struct( Idx );
1412                 Conf_Server[Server].conn_id = NONE;
1413                 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 );
1414                 return;
1415         }
1416
1417         memset( &new_addr, 0, sizeof( new_addr ));
1418         new_addr.sin_family = AF_INET;
1419         new_addr.sin_addr = inaddr;
1420         new_addr.sin_port = htons( Conf_Server[Server].port );
1421
1422         new_sock = socket( PF_INET, SOCK_STREAM, 0 );
1423         if ( new_sock < 0 )
1424         {
1425                 /* Can't create socket */
1426                 Init_Conn_Struct( Idx );
1427                 Conf_Server[Server].conn_id = NONE;
1428                 Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
1429                 return;
1430         }
1431
1432         if( ! Init_Socket( new_sock )) return;
1433
1434         res = connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr ));
1435         if(( res != 0 ) && ( errno != EINPROGRESS ))
1436         {
1437                 /* Can't connect socket */
1438                 Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
1439                 close( new_sock );
1440                 Init_Conn_Struct( Idx );
1441                 Conf_Server[Server].conn_id = NONE;
1442                 return;
1443         }
1444
1445         /* Client-Struktur initialisieren */
1446         c = Client_NewLocal( Idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, FALSE );
1447         if( ! c )
1448         {
1449                 /* Can't create new client structure */
1450                 close( new_sock );
1451                 Init_Conn_Struct( Idx );
1452                 Conf_Server[Server].conn_id = NONE;
1453                 Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
1454                 return;
1455         }
1456         Client_SetIntroducer( c, c );
1457         Client_SetToken( c, TOKEN_OUTBOUND );
1458
1459         /* Register connection */
1460         My_Connections[Idx].sock = new_sock;
1461         My_Connections[Idx].addr = new_addr;
1462         strlcpy( My_Connections[Idx].host, Conf_Server[Server].host, sizeof( My_Connections[Idx].host ));
1463
1464         /* Register new socket */
1465         FD_SET( new_sock, &My_Sockets );
1466         FD_SET( new_sock, &My_Connects );
1467         if( new_sock > Conn_MaxFD ) Conn_MaxFD = new_sock;
1468
1469         Log( LOG_DEBUG, "Registered new connection %d on socket %d.", Idx, My_Connections[Idx].sock );
1470 } /* New_Server */
1471
1472
1473 LOCAL VOID
1474 Init_Conn_Struct( CONN_ID Idx )
1475 {
1476         /* Connection-Struktur initialisieren */
1477
1478         My_Connections[Idx].sock = NONE;
1479         My_Connections[Idx].res_stat = NULL;
1480         My_Connections[Idx].host[0] = '\0';
1481         My_Connections[Idx].rbuf[0] = '\0';
1482         My_Connections[Idx].rdatalen = 0;
1483         My_Connections[Idx].wbuf[0] = '\0';
1484         My_Connections[Idx].wdatalen = 0;
1485         My_Connections[Idx].starttime = time( NULL );
1486         My_Connections[Idx].lastdata = time( NULL );
1487         My_Connections[Idx].lastping = 0;
1488         My_Connections[Idx].lastprivmsg = time( NULL );
1489         My_Connections[Idx].delaytime = 0;
1490         My_Connections[Idx].bytes_in = 0;
1491         My_Connections[Idx].bytes_out = 0;
1492         My_Connections[Idx].msg_in = 0;
1493         My_Connections[Idx].msg_out = 0;
1494         My_Connections[Idx].flag = 0;
1495         My_Connections[Idx].options = 0;
1496
1497 #ifdef USE_ZLIB
1498         My_Connections[Idx].zip.rbuf[0] = '\0';
1499         My_Connections[Idx].zip.rdatalen = 0;
1500         My_Connections[Idx].zip.wbuf[0] = '\0';
1501         My_Connections[Idx].zip.wdatalen = 0;
1502         My_Connections[Idx].zip.bytes_in = 0;
1503         My_Connections[Idx].zip.bytes_out = 0;
1504 #endif
1505 } /* Init_Conn_Struct */
1506
1507
1508 LOCAL BOOLEAN
1509 Init_Socket( INT Sock )
1510 {
1511         /* Socket-Optionen setzen */
1512
1513         INT on = 1;
1514
1515 #ifdef O_NONBLOCK       /* A/UX kennt das nicht? */
1516         if( fcntl( Sock, F_SETFL, O_NONBLOCK ) != 0 )
1517         {
1518                 Log( LOG_CRIT, "Can't enable non-blocking mode: %s!", strerror( errno ));
1519                 close( Sock );
1520                 return FALSE;
1521         }
1522 #endif
1523         if( setsockopt( Sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0)
1524         {
1525                 Log( LOG_ERR, "Can't set socket options: %s!", strerror( errno ));
1526                 /* dieser Fehler kann ignoriert werden. */
1527         }
1528
1529         return TRUE;
1530 } /* Init_Socket */
1531
1532
1533 LOCAL VOID
1534 Read_Resolver_Result( INT r_fd )
1535 {
1536         /* Ergebnis von Resolver Sub-Prozess aus Pipe lesen
1537          * und entsprechende Connection aktualisieren */
1538
1539         CHAR result[HOST_LEN];
1540         CLIENT *c;
1541         INT len, i, n;
1542
1543         FD_CLR( r_fd, &Resolver_FDs );
1544
1545         /* Anfrage vom Parent lesen */
1546         len = read( r_fd, result, HOST_LEN - 1 );
1547         if( len < 0 )
1548         {
1549                 /* Fehler beim Lesen aus der Pipe */
1550                 close( r_fd );
1551                 Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror( errno ));
1552                 return;
1553         }
1554         result[len] = '\0';
1555
1556         /* zugehoerige Connection suchen */
1557         for( i = 0; i < Pool_Size; i++ )
1558         {
1559                 if(( My_Connections[i].sock != NONE ) && ( My_Connections[i].res_stat ) && ( My_Connections[i].res_stat->pipe[0] == r_fd )) break;
1560         }
1561         if( i >= Pool_Size )
1562         {
1563                 /* Opsa! Keine passende Connection gefunden!? Vermutlich
1564                  * wurde sie schon wieder geschlossen. */
1565                 close( r_fd );
1566                 Log( LOG_DEBUG, "Resolver: Got result for unknown connection!?" );
1567                 return;
1568         }
1569
1570         Log( LOG_DEBUG, "Resolver: %s is \"%s\".", My_Connections[i].host, result );
1571
1572         /* Aufraeumen */
1573         close( My_Connections[i].res_stat->pipe[0] );
1574         close( My_Connections[i].res_stat->pipe[1] );
1575         free( My_Connections[i].res_stat );
1576         My_Connections[i].res_stat = NULL;
1577
1578         if( My_Connections[i].sock > NONE )
1579         {
1580                 /* Eingehende Verbindung: Hostnamen setzen */
1581                 c = Client_GetFromConn( i );
1582                 assert( c != NULL );
1583                 strlcpy( My_Connections[i].host, result, sizeof( My_Connections[i].host ));
1584                 Client_SetHostname( c, result );
1585         }
1586         else
1587         {
1588                 /* Ausgehende Verbindung (=Server): IP setzen */
1589                 n = Conf_GetServer( i );
1590                 if( n > NONE ) strlcpy( Conf_Server[n].ip, result, sizeof( Conf_Server[n].ip ));
1591                 else Log( LOG_ERR, "Got resolver result for non-configured server!?" );
1592         }
1593
1594         /* Penalty-Zeit zurueck setzen */
1595         Conn_ResetPenalty( i );
1596 } /* Read_Resolver_Result */
1597
1598
1599 LOCAL VOID
1600 Simple_Message( INT Sock, CHAR *Msg )
1601 {
1602         /* Write "simple" message to socket, without using compression
1603          * or even the connection write buffers. Used e.g. for error
1604          * messages by New_Connection(). */
1605
1606         assert( Sock > NONE );
1607         assert( Msg != NULL );
1608
1609         (VOID)send( Sock, Msg, strlen( Msg ), 0 );
1610         (VOID)send( Sock, "\r\n", 2, 0 );
1611 } /* Simple_Error */
1612
1613
1614 LOCAL INT
1615 Count_Connections( struct sockaddr_in addr_in )
1616 {
1617         INT i, cnt;
1618         
1619         cnt = 0;
1620         for( i = 0; i < Pool_Size; i++ )
1621         {
1622                 if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].addr.sin_addr.s_addr == addr_in.sin_addr.s_addr )) cnt++;
1623         }
1624         return cnt;
1625 } /* Count_Connections */
1626
1627
1628 /* -eof- */