]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn.c
0ebde84da1af466b396186d4db070c4de89a43ea
[ngircd-alex.git] / src / ngircd / conn.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: conn.c,v 1.34 2002/01/07 15:29:52 alex Exp $
13  *
14  * connect.h: Verwaltung aller Netz-Verbindungen ("connections")
15  *
16  * $Log: conn.c,v $
17  * Revision 1.34  2002/01/07 15:29:52  alex
18  * - PASSSERVERADD definiert, wird beim PASS-Befehl an Server verwendet.
19  *
20  * Revision 1.33  2002/01/06 15:18:14  alex
21  * - Loglevel und Meldungen nochmals geaendert. Level passen nun besser.
22  *
23  * Revision 1.32  2002/01/05 23:25:25  alex
24  * - Vorbereitungen fuer Ident-Abfragen bei neuen Client-Strukturen.
25  *
26  * Revision 1.31  2002/01/05 19:15:03  alex
27  * - Fehlerpruefung bei select() in der "Hauptschleife" korrigiert.
28  *
29  * Revision 1.30  2002/01/05 15:56:23  alex
30  * - "arpa/inet.h" wird nur noch includiert, wenn vorhanden.
31  * - Ein Fehler bei select() fuerht nun zum Abbruch von ngIRCd.
32  * - NO_ADDRESS durch NO_DATA ersetzt: ist wohl portabler.
33  *
34  * Revision 1.29  2002/01/04 01:36:40  alex
35  * - Loglevel ein wenig angepasst.
36  *
37  * Revision 1.28  2002/01/04 01:20:23  alex
38  * - Client-Strukruren werden nur noch ueber Funktionen angesprochen.
39  *
40  * Revision 1.27  2002/01/03 02:25:36  alex
41  * - diverse Aenderungen und Umsetellungen fuer Server-Links.
42  *
43  * Revision 1.26  2002/01/02 02:50:47  alex
44  * - Asyncroner Resolver Hostname->IP.
45  * - Server-Links begonnen zu implementieren. Die Verbindung wird aufgebaut,
46  *   jedoch noch keine SERVER-Befehle verschickt.
47  * - Diverse Bug-Fixes und kleinere Erweiterungen.
48  *
49  * Revision 1.24  2002/01/01 18:25:44  alex
50  * - #include's fuer stdlib.h ergaenzt.
51  *
52  * Revision 1.23  2001/12/31 02:18:51  alex
53  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
54  * - neuen Header "defines.h" mit (fast) allen Konstanten.
55  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
56  *
57  * Revision 1.22  2001/12/30 19:26:11  alex
58  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
59  *
60  * Revision 1.21  2001/12/29 22:33:36  alex
61  * - bessere Dokumentation des Modules bzw. der Funktionen.
62  *
63  * Revision 1.20  2001/12/29 22:09:43  alex
64  * - kleinere Aenderungen ("clean-ups") bei Logging (Resolver).
65  *
66  * Revision 1.19  2001/12/29 21:53:57  alex
67  * - Da hatte ich mich wohl ein wenig verrannt; jetzt sollte der Resolver
68  *   aber tatsaechlich funktionieren.
69  *
70  * Revision 1.18  2001/12/29 20:17:25  alex
71  * - asyncronen Resolver (IP->Name) implementiert, dadurch div. Aenderungen.
72  *
73  * Revision 1.17  2001/12/29 03:06:16  alex
74  * - Loglevel (nochmal) angepasst.
75  *
76  * Revision 1.16  2001/12/27 19:32:44  alex
77  * - bei "Null-Requests" wird nichts mehr geloggt. Uberfluessig, da normal.
78  *
79  * Revision 1.15  2001/12/27 16:35:04  alex
80  * - vergessene Variable bei Ping-Timeout-Logmeldung ergaenzt. Opsa.
81  *
82  * Revision 1.14  2001/12/26 14:45:37  alex
83  * - "Code Cleanups".
84  *
85  * Revision 1.13  2001/12/26 03:36:57  alex
86  * - Verbindungen mit Lesefehlern werden nun korrekt terminiert.
87  *
88  * Revision 1.12  2001/12/26 03:20:53  alex
89  * - PING/PONG-Timeout implementiert.
90  *
91  * Revision 1.11  2001/12/25 23:15:16  alex
92  * - buffer werden nun periodisch geprueft, keine haengenden Clients mehr.
93  *
94  * Revision 1.10  2001/12/25 22:03:47  alex
95  * - Conn_Close() eingefuehrt: war die lokale Funktion Close_Connection().
96  *
97  * Revision 1.9  2001/12/24 01:32:33  alex
98  * - in Conn_WriteStr() wurde das CR+LF nicht angehaengt!
99  * - Fehler-Ausgaben vereinheitlicht.
100  *
101  * Revision 1.8  2001/12/23 22:02:54  alex
102  * - Conn_WriteStr() nimmt nun variable Parameter,
103  * - diverse kleinere Aenderungen.
104  *
105  * Revision 1.7  2001/12/21 22:24:25  alex
106  * - kleinere Aenderungen an den Log-Meldungen,
107  * - Parse_Request() wird aufgerufen.
108  *
109  * Revision 1.6  2001/12/15 00:11:55  alex
110  * - Lese- und Schreib-Puffer implementiert.
111  * - einige neue (Unter-)Funktionen eingefuehrt.
112  * - diverse weitere kleinere Aenderungen.
113  *
114  * Revision 1.5  2001/12/14 08:16:47  alex
115  * - Begonnen, Client-spezifische Lesepuffer zu implementieren.
116  * - Umstellung auf Datentyp "CONN_ID".
117  *
118  * Revision 1.4  2001/12/13 02:04:16  alex
119  * - boesen "Speicherschiesser" in Log() gefixt.
120  *
121  * Revision 1.3  2001/12/13 01:33:09  alex
122  * - Conn_Handler() unterstuetzt nun einen Timeout.
123  * - fuer Verbindungen werden keine FILE-Handles mehr benutzt.
124  * - kleinere "Code Cleanups" ;-)
125  *
126  * Revision 1.2  2001/12/12 23:32:02  alex
127  * - diverse Erweiterungen und Verbesserungen (u.a. sind nun mehrere
128  *   Verbindungen und Listen-Sockets moeglich).
129  *
130  * Revision 1.1  2001/12/12 17:18:38  alex
131  * - Modul zur Verwaltung aller Netzwerk-Verbindungen begonnen.
132  */
133
134
135 #include <portab.h>
136 #include "global.h"
137
138 #include <imp.h>
139 #include <assert.h>
140 #include <stdarg.h>
141 #include <stdio.h>
142 #include <stdlib.h>
143 #include <unistd.h>
144 #include <errno.h>
145 #include <fcntl.h>
146 #include <string.h>
147 #include <sys/socket.h>
148 #include <sys/time.h>
149 #include <sys/types.h>
150 #include <time.h>
151 #include <netinet/in.h>
152 #include <netdb.h>
153
154 #ifdef HAVE_ARPA_INET_H
155 #include <arpa/inet.h>
156 #else
157 #define PF_INET AF_INET
158 #endif
159
160 #ifdef HAVE_STDINT_H
161 #include <stdint.h>                     /* u.a. fuer Mac OS X */
162 #endif
163
164 #include "ngircd.h"
165 #include "client.h"
166 #include "conf.h"
167 #include "log.h"
168 #include "parse.h"
169 #include "tool.h"
170
171 #include <exp.h>
172 #include "conn.h"
173
174
175 #define SERVER_WAIT NONE - 1
176
177
178 typedef struct _Connection
179 {
180         INT sock;                       /* Socket Handle */
181         struct sockaddr_in addr;        /* Adresse des Client */
182         RES_STAT *res_stat;             /* "Resolver-Status", s.o. */
183         CHAR host[HOST_LEN];            /* Hostname */
184         CHAR rbuf[READBUFFER_LEN];      /* Lesepuffer */
185         INT rdatalen;                   /* Laenge der Daten im Lesepuffer */
186         CHAR wbuf[WRITEBUFFER_LEN];     /* Schreibpuffer */
187         INT wdatalen;                   /* Laenge der Daten im Schreibpuffer */
188         INT our_server;                 /* wenn von uns zu connectender Server: ID */
189         time_t lastdata;                /* Letzte Aktivitaet */
190         time_t lastping;                /* Letzter PING */
191         time_t lastprivmsg;             /* Letzte PRIVMSG */
192 } CONNECTION;
193
194
195 LOCAL VOID Handle_Read( INT sock );
196 LOCAL BOOLEAN Handle_Write( CONN_ID Idx );
197 LOCAL VOID New_Connection( INT Sock );
198 LOCAL CONN_ID Socket2Index( INT Sock );
199 LOCAL VOID Read_Request( CONN_ID Idx );
200 LOCAL BOOLEAN Try_Write( CONN_ID Idx );
201 LOCAL VOID Handle_Buffer( CONN_ID Idx );
202 LOCAL VOID Check_Connections( VOID );
203 LOCAL VOID Check_Servers( VOID );
204 LOCAL VOID Init_Conn_Struct( INT Idx );
205 LOCAL VOID New_Server( INT Server, CONN_ID Idx );
206
207 LOCAL RES_STAT *ResolveAddr( struct sockaddr_in *Addr );
208 LOCAL RES_STAT *ResolveName( CHAR *Host );
209 LOCAL VOID Do_ResolveAddr( struct sockaddr_in *Addr, INT w_fd );
210 LOCAL VOID Do_ResolveName( CHAR *Host, INT w_fd );
211 LOCAL VOID Read_Resolver_Result( INT r_fd );
212 LOCAL CHAR *Resolv_Error( INT H_Error );
213
214
215 LOCAL fd_set My_Listeners;
216 LOCAL fd_set My_Sockets;
217 LOCAL fd_set My_Resolvers;
218
219 LOCAL INT My_Max_Fd;
220
221 LOCAL CONNECTION My_Connections[MAX_CONNECTIONS];
222
223
224 GLOBAL VOID Conn_Init( VOID )
225 {
226         /* Modul initialisieren: statische Strukturen "ausnullen". */
227
228         CONN_ID i;
229
230         /* zu Beginn haben wir keine Verbindungen */
231         FD_ZERO( &My_Listeners );
232         FD_ZERO( &My_Sockets );
233         FD_ZERO( &My_Resolvers );
234
235         My_Max_Fd = 0;
236
237         /* Connection-Struktur initialisieren */
238         for( i = 0; i < MAX_CONNECTIONS; i++ ) Init_Conn_Struct( i );
239 } /* Conn_Init */
240
241
242 GLOBAL VOID Conn_Exit( VOID )
243 {
244         /* Modul abmelden: alle noch offenen Connections
245          * schliessen und freigeben. */
246
247         CONN_ID idx;
248         INT i;
249
250         /* Sockets schliessen */
251         Log( LOG_DEBUG, "Shutting down all connections ..." );
252         for( i = 0; i < My_Max_Fd + 1; i++ )
253         {
254                 if( FD_ISSET( i, &My_Sockets ))
255                 {
256                         for( idx = 0; idx < MAX_CONNECTIONS; idx++ )
257                         {
258                                 if( My_Connections[idx].sock == i ) break;
259                         }
260                         if( idx < MAX_CONNECTIONS ) Conn_Close( idx, NULL, "Server going down", TRUE );
261                         else if( FD_ISSET( i, &My_Listeners ))
262                         {
263                                 close( i );
264                                 Log( LOG_DEBUG, "Listening socket %d closed.", i );
265                         }
266                         else
267                         {
268                                 close( i );
269                                 Log( LOG_WARNING, "Unknown connection %d closed.", i );
270                         }
271                 }
272         }
273 } /* Conn_Exit */
274
275
276 GLOBAL BOOLEAN Conn_NewListener( CONST INT Port )
277 {
278         /* Neuen Listen-Socket erzeugen: der Server wartet dann auf
279          * dem angegebenen Port auf Verbindungen. Kann der Listen-
280          * Socket nicht erteugt werden, so wird NULL geliefert.*/
281
282         struct sockaddr_in addr;
283         INT sock, on = 1;
284
285         /* Server-"Listen"-Socket initialisieren */
286         memset( &addr, 0, sizeof( addr ));
287         addr.sin_family = AF_INET;
288         addr.sin_port = htons( Port );
289         addr.sin_addr.s_addr = htonl( INADDR_ANY );
290
291         /* Socket erzeugen */
292         sock = socket( PF_INET, SOCK_STREAM, 0);
293         if( sock < 0 )
294         {
295                 Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
296                 return FALSE;
297         }
298
299         /* Socket-Optionen setzen */
300         if( fcntl( sock, F_SETFL, O_NONBLOCK ) != 0 )
301         {
302                 Log( LOG_CRIT, "Can't enable non-blocking mode: %s!", strerror( errno ));
303                 close( sock );
304                 return FALSE;
305         }
306         if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0)
307         {
308                 Log( LOG_ERR, "Can't set socket options: %s!", strerror( errno ));
309                 /* dieser Fehler kann ignoriert werden. */
310         }
311
312         /* an Port binden */
313         if( bind( sock, (struct sockaddr *)&addr, (socklen_t)sizeof( addr )) != 0 )
314         {
315                 Log( LOG_CRIT, "Can't bind socket: %s!", strerror( errno ));
316                 close( sock );
317                 return FALSE;
318         }
319
320         /* in "listen mode" gehen :-) */
321         if( listen( sock, 10 ) != 0 )
322         {
323                 Log( LOG_CRIT, "Can't listen on soecket: %s!", strerror( errno ));
324                 close( sock );
325                 return FALSE;
326         }
327
328         /* Neuen Listener in Strukturen einfuegen */
329         FD_SET( sock, &My_Listeners );
330         FD_SET( sock, &My_Sockets );
331
332         if( sock > My_Max_Fd ) My_Max_Fd = sock;
333
334         Log( LOG_INFO, "Now listening on port %d (socket %d).", Port, sock );
335
336         return TRUE;
337 } /* Conn_NewListener */
338
339
340 GLOBAL VOID Conn_Handler( INT Timeout )
341 {
342         /* Aktive Verbindungen ueberwachen. Mindestens alle "Timeout"
343          * Sekunden wird die Funktion verlassen. Folgende Aktionen
344          * werden durchgefuehrt:
345          *  - neue Verbindungen annehmen,
346          *  - Server-Verbindungen aufbauen,
347          *  - geschlossene Verbindungen loeschen,
348          *  - volle Schreibpuffer versuchen zu schreiben,
349          *  - volle Lesepuffer versuchen zu verarbeiten,
350          *  - Antworten von Resolver Sub-Prozessen annehmen.
351          */
352
353         fd_set read_sockets, write_sockets;
354         struct timeval tv;
355         time_t start;
356         INT i;
357
358         start = time( NULL );
359         while(( time( NULL ) - start < Timeout ) && ( ! NGIRCd_Quit ))
360         {
361                 Check_Servers( );
362
363                 Check_Connections( );
364
365                 /* Timeout initialisieren */
366                 tv.tv_sec = 0;
367                 tv.tv_usec = 50000;
368
369                 /* noch volle Lese-Buffer suchen */
370                 for( i = 0; i < MAX_CONNECTIONS; i++ )
371                 {
372                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].rdatalen > 0 ))
373                         {
374                                 /* Kann aus dem Buffer noch ein Befehl extrahiert werden? */
375                                 Handle_Buffer( i );
376                         }
377                 }
378                 
379                 /* noch volle Schreib-Puffer suchen */
380                 FD_ZERO( &write_sockets );
381                 for( i = 0; i < MAX_CONNECTIONS; i++ )
382                 {
383                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].wdatalen > 0 ))
384                         {
385                                 /* Socket der Verbindung in Set aufnehmen */
386                                 FD_SET( My_Connections[i].sock, &write_sockets );
387                         }
388                 }
389
390                 /* von welchen Sockets koennte gelesen werden? */
391                 read_sockets = My_Sockets;
392                 for( i = 0; i < MAX_CONNECTIONS; i++ )
393                 {
394                         if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].host[0] == '\0' ))
395                         {
396                                 /* Hier muss noch auf den Resolver Sub-Prozess gewartet werden */
397                                 FD_CLR( My_Connections[i].sock, &read_sockets );
398                         }
399                 }
400                 for( i = 0; i < My_Max_Fd + 1; i++ )
401                 {
402                         /* Pipes von Resolver Sub-Prozessen aufnehmen */
403                         if( FD_ISSET( i, &My_Resolvers ))
404                         {
405                                 FD_SET( i, &read_sockets );
406                         }
407                 }
408
409                 /* Auf Aktivitaet warten */
410                 if( select( My_Max_Fd + 1, &read_sockets, &write_sockets, NULL, &tv ) == -1 )
411                 {
412                         if( errno != EINTR )
413                         {
414                                 Log( LOG_EMERG, "select(): %s!", strerror( errno ));
415                                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
416                                 exit( 1 );
417                         }
418                         continue;
419                 }
420
421                 /* Koennen Daten geschrieben werden? */
422                 for( i = 0; i < My_Max_Fd + 1; i++ )
423                 {
424                         if( FD_ISSET( i, &write_sockets )) Handle_Write( Socket2Index( i ));
425                 }
426
427                 /* Daten zum Lesen vorhanden? */
428                 for( i = 0; i < My_Max_Fd + 1; i++ )
429                 {
430                         if( FD_ISSET( i, &read_sockets )) Handle_Read( i );
431                 }
432         }
433 } /* Conn_Handler */
434
435
436 GLOBAL BOOLEAN Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... )
437 {
438         /* String in Socket schreiben. CR+LF wird von dieser Funktion
439          * automatisch angehaengt. Im Fehlerfall wird dir Verbindung
440          * getrennt und FALSE geliefert. */
441
442         CHAR buffer[COMMAND_LEN];
443         BOOLEAN ok;
444         va_list ap;
445
446         va_start( ap, Format );
447         if( vsnprintf( buffer, COMMAND_LEN - 2, Format, ap ) == COMMAND_LEN - 2 )
448         {
449                 Log( LOG_CRIT, "Text too long to send (connection %d)!", Idx );
450                 Conn_Close( Idx, "Text too long to send!", NULL, FALSE );
451                 return FALSE;
452         }
453
454 #ifdef SNIFFER
455         Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer );
456 #endif
457
458         strcat( buffer, "\r\n" );
459         ok = Conn_Write( Idx, buffer, strlen( buffer ));
460
461         va_end( ap );
462         return ok;
463 } /* Conn_WriteStr */
464
465
466 GLOBAL BOOLEAN Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
467 {
468         /* Daten in Socket schreiben. Bei "fatalen" Fehlern wird
469          * der Client disconnectiert und FALSE geliefert. */
470
471         assert( Idx >= 0 );
472         assert( My_Connections[Idx].sock > NONE );
473         assert( Data != NULL );
474         assert( Len > 0 );
475
476         /* pruefen, ob Daten im Schreibpuffer sind. Wenn ja, zunaechst
477          * pruefen, ob diese gesendet werden koennen */
478         if( My_Connections[Idx].wdatalen > 0 )
479         {
480                 if( ! Try_Write( Idx )) return FALSE;
481         }
482
483         /* pruefen, ob im Schreibpuffer genuegend Platz ist */
484         if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
485         {
486                 /* der Puffer ist dummerweise voll ... */
487                 Log( LOG_NOTICE, "Write buffer overflow (connection %d)!", Idx );
488                 Conn_Close( Idx, "Write buffer overflow!", NULL, FALSE );
489                 return FALSE;
490         }
491
492         /* Daten in Puffer kopieren */
493         memcpy( My_Connections[Idx].wbuf + My_Connections[Idx].wdatalen, Data, Len );
494         My_Connections[Idx].wdatalen += Len;
495
496         /* pruefen, on Daten vorhanden sind und geschrieben werden koennen */
497         if( My_Connections[Idx].wdatalen > 0 )
498         {
499                 if( ! Try_Write( Idx )) return FALSE;
500         }
501
502         return TRUE;
503 } /* Conn_Write */
504
505
506 GLOBAL VOID Conn_Close( CONN_ID Idx, CHAR *LogMsg, CHAR *FwdMsg, BOOLEAN InformClient )
507 {
508         /* Verbindung schliessen. Evtl. noch von Resolver
509          * Sub-Prozessen offene Pipes werden geschlossen. */
510
511         CLIENT *c;
512         
513         assert( Idx >= 0 );
514         assert( My_Connections[Idx].sock > NONE );
515
516         if( InformClient )
517         {
518                 if( FwdMsg ) Conn_WriteStr( Idx, "ERROR :%s", FwdMsg );
519                 else Conn_WriteStr( Idx, "ERROR :Closing connection." );
520                 if( My_Connections[Idx].sock == NONE ) return;
521         }
522
523         if( close( My_Connections[Idx].sock ) != 0 )
524         {
525                 Log( LOG_ERR, "Error closing connection %d with %s:%d - %s!", Idx, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
526         }
527         else
528         {
529                 Log( LOG_INFO, "Connection %d with %s:%d closed.", Idx, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port ));
530         }
531
532         c = Client_GetFromConn( Idx );
533         if( c ) Client_Destroy( c, LogMsg, FwdMsg );
534
535         if( My_Connections[Idx].res_stat )
536         {
537                 /* Resolver-Strukturen freigeben, wenn noch nicht geschehen */
538                 FD_CLR( My_Connections[Idx].res_stat->pipe[0], &My_Resolvers );
539                 close( My_Connections[Idx].res_stat->pipe[0] );
540                 close( My_Connections[Idx].res_stat->pipe[1] );
541                 free( My_Connections[Idx].res_stat );
542         }
543
544         /* Bei Server-Verbindungen lasttry-Zeitpunkt auf "jetzt" setzen */
545         if( My_Connections[Idx].our_server >= 0 ) Conf_Server[My_Connections[Idx].our_server].lasttry = time( NULL );
546
547         FD_CLR( My_Connections[Idx].sock, &My_Sockets );
548         My_Connections[Idx].sock = NONE;
549 } /* Conn_Close */
550
551
552 GLOBAL VOID Conn_UpdateIdle( CONN_ID Idx )
553 {
554         /* Idle-Timer zuruecksetzen */
555
556         assert( Idx >= 0 );
557         My_Connections[Idx].lastprivmsg = time( NULL );
558 }
559
560
561 GLOBAL INT32 Conn_GetIdle( CONN_ID Idx )
562 {
563         /* Idle-Time einer Verbindung liefern (in Sekunden) */
564
565         assert( Idx >= 0 );
566         return time( NULL ) - My_Connections[Idx].lastprivmsg;
567 } /* Conn_GetIdle */
568
569
570 LOCAL BOOLEAN Try_Write( CONN_ID Idx )
571 {
572         /* Versuchen, Daten aus dem Schreib-Puffer in den
573          * Socket zu schreiben. */
574
575         fd_set write_socket;
576
577         assert( Idx >= 0 );
578         assert( My_Connections[Idx].sock > NONE );
579         assert( My_Connections[Idx].wdatalen > 0 );
580
581         FD_ZERO( &write_socket );
582         FD_SET( My_Connections[Idx].sock, &write_socket );
583         if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, 0 ) == -1 )
584         {
585                 /* Fehler! */
586                 if( errno != EINTR )
587                 {
588                         Log( LOG_ALERT, "select() failed: %s!", strerror( errno ));
589                         Conn_Close( Idx, "Server error!", NULL, FALSE );
590                         return FALSE;
591                 }
592         }
593
594         if( FD_ISSET( My_Connections[Idx].sock, &write_socket )) return Handle_Write( Idx );
595         else return TRUE;
596 } /* Try_Write */
597
598
599 LOCAL VOID Handle_Read( INT Sock )
600 {
601         /* Aktivitaet auf einem Socket verarbeiten:
602          *  - neue Clients annehmen,
603          *  - Daten von Clients verarbeiten,
604          *  - Resolver-Rueckmeldungen annehmen. */
605
606         CONN_ID idx;
607
608         assert( Sock >= 0 );
609         
610         if( FD_ISSET( Sock, &My_Listeners ))
611         {
612                 /* es ist einer unserer Listener-Sockets: es soll
613                  * also eine neue Verbindung aufgebaut werden. */
614
615                 New_Connection( Sock );
616         }
617         else if( FD_ISSET( Sock, &My_Resolvers ))
618         {
619                 /* Rueckmeldung von einem Resolver Sub-Prozess */
620
621                 Read_Resolver_Result( Sock );
622         }
623         else
624         {
625                 /* Ein Client Socket: entweder ein User oder Server */
626
627                 idx = Socket2Index( Sock );
628                 Read_Request( idx );
629         }
630 } /* Handle_Read */
631
632
633 LOCAL BOOLEAN Handle_Write( CONN_ID Idx )
634 {
635         /* Daten aus Schreibpuffer versenden */
636
637         INT len;
638
639         assert( Idx >= 0 );
640         assert( My_Connections[Idx].sock > NONE );
641         assert( My_Connections[Idx].wdatalen > 0 );
642
643         /* Daten schreiben */
644         len = send( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen, 0 );
645         if( len < 0 )
646         {
647                 /* Oops, ein Fehler! */
648                 Log( LOG_ERR, "Write error (buffer) on connection %d: %s!", Idx, strerror( errno ));
649                 Conn_Close( Idx, "Write error (buffer)!", NULL, FALSE );
650                 return FALSE;
651         }
652
653         /* Puffer anpassen */
654         My_Connections[Idx].wdatalen -= len;
655         memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen );
656
657         return TRUE;
658 } /* Handle_Write */
659
660
661 LOCAL VOID New_Connection( INT Sock )
662 {
663         /* Neue Client-Verbindung von Listen-Socket annehmen und
664          * CLIENT-Struktur anlegen. */
665
666         struct sockaddr_in new_addr;
667         INT new_sock, new_sock_len;
668         RES_STAT *s;
669         CONN_ID idx;
670         
671         assert( Sock >= 0 );
672
673         new_sock_len = sizeof( new_addr );
674         new_sock = accept( Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len );
675         if( new_sock < 0 )
676         {
677                 Log( LOG_CRIT, "Can't accept connection: %s!", strerror( errno ));
678                 return;
679         }
680
681         /* Freie Connection-Struktur suschen */
682         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == NONE ) break;
683         if( idx >= MAX_CONNECTIONS )
684         {
685                 Log( LOG_ALERT, "Can't accept connection: limit reached (%d)!", MAX_CONNECTIONS );
686                 close( new_sock );
687                 return;
688         }
689
690         /* Client-Struktur initialisieren */
691         if( ! Client_NewLocal( idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, FALSE ))
692         {
693                 Log( LOG_ALERT, "Can't accept connection: can't create client structure!" );
694                 close( new_sock );
695                 return;
696         }
697
698         /* Verbindung registrieren */
699         Init_Conn_Struct( idx );
700         My_Connections[idx].sock = new_sock;
701         My_Connections[idx].addr = new_addr;
702
703         /* Neuen Socket registrieren */
704         FD_SET( new_sock, &My_Sockets );
705         if( new_sock > My_Max_Fd ) My_Max_Fd = new_sock;
706
707         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 );
708
709         /* Hostnamen ermitteln */
710         s = ResolveAddr( &new_addr );
711         if( s )
712         {
713                 /* Sub-Prozess wurde asyncron gestartet */
714                 My_Connections[idx].res_stat = s;
715         }
716         else
717         {
718                 /* kann Namen nicht aufloesen */
719                 strcpy( My_Connections[idx].host, inet_ntoa( new_addr.sin_addr ));
720         }
721 } /* New_Connection */
722
723
724 LOCAL CONN_ID Socket2Index( INT Sock )
725 {
726         /* zum Socket passende Connection suchen */
727
728         CONN_ID idx;
729
730         assert( Sock >= 0 );
731
732         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == Sock ) break;
733
734         assert( idx < MAX_CONNECTIONS );
735         return idx;
736 } /* Socket2Index */
737
738
739 LOCAL VOID Read_Request( CONN_ID Idx )
740 {
741         /* Daten von Socket einlesen und entsprechend behandeln.
742          * Tritt ein Fehler auf, so wird der Socket geschlossen. */
743
744         INT len;
745
746         assert( Idx >= 0 );
747         assert( My_Connections[Idx].sock > NONE );
748
749         if( READBUFFER_LEN - My_Connections[Idx].rdatalen - 2 < 0 )
750         {
751                 /* Der Lesepuffer ist voll */
752                 Log( LOG_ERR, "Read buffer overflow (connection %d): %d bytes!", Idx, My_Connections[Idx].rdatalen );
753                 Conn_Close( Idx, "Read buffer overflow!", NULL, FALSE );
754                 return;
755         }
756
757         len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, READBUFFER_LEN - My_Connections[Idx].rdatalen - 2, 0 );
758
759         if( len == 0 )
760         {
761                 /* Socket wurde geschlossen */
762                 Log( LOG_INFO, "%s:%d is closing the connection ...", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port));
763                 Conn_Close( Idx, "Socket closed.", NULL, FALSE );
764                 return;
765         }
766
767         if( len < 0 )
768         {
769                 /* Fehler beim Lesen */
770                 Log( LOG_ERR, "Read error on connection %d: %s!", Idx, strerror( errno ));
771                 Conn_Close( Idx, "Read error!", NULL, FALSE );
772                 return;
773         }
774
775         /* Lesebuffer updaten */
776         My_Connections[Idx].rdatalen += len;
777         assert( My_Connections[Idx].rdatalen < READBUFFER_LEN );
778         My_Connections[Idx].rbuf[My_Connections[Idx].rdatalen] = '\0';
779
780         /* Timestamp aktualisieren */
781         My_Connections[Idx].lastdata = time( NULL );
782
783         Handle_Buffer( Idx );
784 } /* Read_Request */
785
786
787 LOCAL VOID Handle_Buffer( CONN_ID Idx )
788 {
789         /* Daten im Lese-Puffer einer Verbindung verarbeiten. */
790
791         CHAR *ptr, *ptr1, *ptr2;
792         INT len, delta;
793         
794         /* Eine komplette Anfrage muss mit CR+LF enden, vgl.
795          * RFC 2812. Haben wir eine? */
796         ptr = strstr( My_Connections[Idx].rbuf, "\r\n" );
797
798         if( ptr ) delta = 2;
799 #ifndef STRICT_RFC
800         else
801         {
802                 /* Nicht RFC-konforme Anfrage mit nur CR oder LF? Leider
803                  * machen soetwas viele Clients, u.a. "mIRC" :-( */
804                 ptr1 = strchr( My_Connections[Idx].rbuf, '\r' );
805                 ptr2 = strchr( My_Connections[Idx].rbuf, '\n' );
806                 delta = 1;
807                 if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
808                 else if( ptr1 ) ptr = ptr1;
809                 else if( ptr2 ) ptr = ptr2;
810         }
811 #endif
812         
813         if( ptr )
814         {
815                 /* Ende der Anfrage wurde gefunden */
816                 *ptr = '\0';
817                 len = ( ptr - My_Connections[Idx].rbuf ) + delta;
818                 if( len > COMMAND_LEN )
819                 {
820                         /* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
821                         * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas
822                         * empfangen wird, wird der Client disconnectiert. */
823                         Log( LOG_ERR, "Request too long (connection %d): %d bytes!", Idx, My_Connections[Idx].rdatalen );
824                         Conn_Close( Idx, NULL, "Request too long", TRUE );
825                         return;
826                 }
827                 
828                 if( len > delta )
829                 {
830                         /* Es wurde ein Request gelesen */
831                         if( ! Parse_Request( Idx, My_Connections[Idx].rbuf )) return;
832                 }
833
834                 /* Puffer anpassen */
835                 My_Connections[Idx].rdatalen -= len;
836                 memmove( My_Connections[Idx].rbuf, My_Connections[Idx].rbuf + len, My_Connections[Idx].rdatalen );
837         }
838 } /* Handle_Buffer */
839
840
841 LOCAL VOID Check_Connections( VOID )
842 {
843         /* Pruefen, ob Verbindungen noch "alive" sind. Ist dies
844          * nicht der Fall, zunaechst PING-PONG spielen und, wenn
845          * auch das nicht "hilft", Client disconnectieren. */
846
847         CLIENT *c;
848         INT i;
849
850         for( i = 0; i < MAX_CONNECTIONS; i++ )
851         {
852                 if( My_Connections[i].sock == NONE ) continue;
853
854                 c = Client_GetFromConn( i );
855                 if( c && (( Client_Type( c ) == CLIENT_USER ) || ( Client_Type( c ) == CLIENT_SERVER ) || ( Client_Type( c ) == CLIENT_SERVICE )))
856                 {
857                         /* verbundener User, Server oder Service */
858                         if( My_Connections[i].lastping > My_Connections[i].lastdata )
859                         {
860                                 /* es wurde bereits ein PING gesendet */
861                                 if( My_Connections[i].lastping < time( NULL ) - Conf_PongTimeout )
862                                 {
863                                         /* Timeout */
864                                         Log( LOG_DEBUG, "Connection %d: Ping timeout.", i );
865                                         Conn_Close( i, NULL, "Ping timeout", TRUE );
866                                 }
867                         }
868                         else if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
869                         {
870                                 /* es muss ein PING gesendet werden */
871                                 Log( LOG_DEBUG, "Connection %d: sending PING ...", i );
872                                 My_Connections[i].lastping = time( NULL );
873                                 Conn_WriteStr( i, "PING :%s", Client_ID( Client_ThisServer( )));
874                         }
875                 }
876                 else
877                 {
878                         /* noch nicht vollstaendig aufgebaute Verbindung */
879                         if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
880                         {
881                                 /* Timeout */
882                                 Log( LOG_INFO, "Connection %d: Timeout.", i );
883                                 Conn_Close( i, NULL, "Timeout", TRUE );
884                         }
885                 }
886         }
887 } /* Check_Connections */
888
889
890 LOCAL VOID Check_Servers( VOID )
891 {
892         /* Pruefen, ob Server-Verbindungen aufgebaut werden
893          * muessen bzw. koennen */
894
895         INT idx, i, n;
896         RES_STAT *s;
897         
898         for( i = 0; i < Conf_Server_Count; i++ )
899         {
900                 /* Ist ein Hostname und Port definiert? */
901                 if(( ! Conf_Server[i].host[0] ) || ( ! Conf_Server[i].port > 0 )) continue;
902                 
903                 /* Haben wir schon eine Verbindung? */
904                 for( n = 0; n < MAX_CONNECTIONS; n++ )
905                 {
906                         if(( My_Connections[n].sock != NONE ) && ( My_Connections[n].our_server == i ))
907                         {
908                                 /* Komplett aufgebaute Verbindung? */
909                                 if( My_Connections[n].sock > NONE ) break;
910
911                                 /* IP schon aufgeloest? */
912                                 if( My_Connections[n].res_stat == NULL ) New_Server( i, n );
913                         }
914                 }
915                 if( n < MAX_CONNECTIONS ) continue;
916                 
917                 /* Wann war der letzte Connect-Versuch? */
918                 if( Conf_Server[i].lasttry > time( NULL ) - Conf_ConnectRetry ) continue;
919
920                 /* Okay, Verbindungsaufbau versuchen */
921                 Conf_Server[i].lasttry = time( NULL );
922
923                 /* Freie Connection-Struktur suschen */
924                 for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == NONE ) break;
925                 if( idx >= MAX_CONNECTIONS )
926                 {
927                         Log( LOG_ALERT, "Can't establist server connection: connection limit reached (%d)!", MAX_CONNECTIONS );
928                         return;
929                 }
930                 Log( LOG_DEBUG, "Preparing connection %d for \"%s\" ...", idx, Conf_Server[i].host );
931
932                 /* Verbindungs-Struktur initialisieren */
933                 Init_Conn_Struct( idx );
934                 My_Connections[idx].sock = SERVER_WAIT;
935                 My_Connections[idx].our_server = i;
936                 
937                 /* Hostnamen in IP aufloesen */
938                 s = ResolveName( Conf_Server[i].host );
939                 if( s )
940                 {
941                         /* Sub-Prozess wurde asyncron gestartet */
942                         My_Connections[idx].res_stat = s;
943                 }
944                 else
945                 {
946                         /* kann Namen nicht aufloesen: Connection-Struktur freigeben */
947                         Init_Conn_Struct( idx );
948                 }
949         }
950 } /* Check_Servers */
951
952
953 LOCAL VOID New_Server( INT Server, CONN_ID Idx )
954 {
955         /* Neue Server-Verbindung aufbauen */
956
957         struct sockaddr_in new_addr;
958         struct in_addr inaddr;
959         INT new_sock;
960         CLIENT *c;
961
962         assert( Server >= 0 );
963         assert( Idx >= 0 );
964
965         /* Wurde eine gueltige IP-Adresse gefunden? */
966         if( ! Conf_Server[Server].ip[0] )
967         {
968                 /* Nein. Verbindung wieder freigeben: */
969                 Init_Conn_Struct( Idx );
970                 Log( LOG_ERR, "Can't connect to \"%s\" (connection %d): ip address unknown!", Conf_Server[Server].host, Idx );
971                 return;
972         }
973         
974         Log( LOG_INFO, "Establishing connection to \"%s\", %s (connection %d) ... ", Conf_Server[Server].host, Conf_Server[Server].ip, Idx );
975
976         if( inet_aton( Conf_Server[Server].ip, &inaddr ) == 0 )
977         {
978                 /* Konnte Adresse nicht konvertieren */
979                 Init_Conn_Struct( Idx );
980                 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 );
981                 return;
982         }
983
984         memset( &new_addr, 0, sizeof( new_addr ));
985         new_addr.sin_family = AF_INET;
986         new_addr.sin_addr = inaddr;
987         new_addr.sin_port = htons( Conf_Server[Server].port );
988
989         new_sock = socket( PF_INET, SOCK_STREAM, 0 );
990         if ( new_sock < 0 )
991         {
992                 Init_Conn_Struct( Idx );
993                 Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
994                 return;
995         }
996         if( connect( new_sock, (struct sockaddr *)&new_addr, sizeof( new_addr )) < 0)
997         {
998                 close( new_sock );
999                 Init_Conn_Struct( Idx );
1000                 Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
1001                 return;
1002         }
1003
1004         /* Client-Struktur initialisieren */
1005         c = Client_NewLocal( Idx, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, FALSE );
1006         if( ! c )
1007         {
1008                 close( new_sock );
1009                 Init_Conn_Struct( Idx );
1010                 Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
1011                 return;
1012         }
1013         Client_SetIntroducer( c, c );
1014         
1015         /* Verbindung registrieren */
1016         My_Connections[Idx].sock = new_sock;
1017         My_Connections[Idx].addr = new_addr;
1018         strcpy( My_Connections[Idx].host, Conf_Server[Server].host );
1019
1020         /* Neuen Socket registrieren */
1021         FD_SET( new_sock, &My_Sockets );
1022         if( new_sock > My_Max_Fd ) My_Max_Fd = new_sock;
1023
1024         /* PASS und SERVER verschicken */
1025         Conn_WriteStr( Idx, "PASS %s "PASSSERVERADD, Conf_Server[Server].pwd );
1026         Conn_WriteStr( Idx, "SERVER %s :%s", Conf_ServerName, Conf_ServerInfo );
1027 } /* New_Server */
1028
1029
1030 LOCAL VOID Init_Conn_Struct( INT Idx )
1031 {
1032         /* Connection-Struktur initialisieren */
1033
1034         My_Connections[Idx].sock = NONE;
1035         My_Connections[Idx].res_stat = NULL;
1036         My_Connections[Idx].host[0] = '\0';
1037         My_Connections[Idx].rbuf[0] = '\0';
1038         My_Connections[Idx].rdatalen = 0;
1039         My_Connections[Idx].wbuf[0] = '\0';
1040         My_Connections[Idx].wdatalen = 0;
1041         My_Connections[Idx].our_server = -1;
1042         My_Connections[Idx].lastdata = time( NULL );
1043         My_Connections[Idx].lastping = 0;
1044         My_Connections[Idx].lastprivmsg = time( NULL );
1045 } /* Init_Conn_Struct */
1046
1047
1048 LOCAL RES_STAT *ResolveAddr( struct sockaddr_in *Addr )
1049 {
1050         /* IP (asyncron!) aufloesen. Bei Fehler, z.B. wenn der
1051          * Child-Prozess nicht erzeugt werden kann, wird NULL geliefert.
1052          * Der Host kann dann nicht aufgeloest werden. */
1053
1054         RES_STAT *s;
1055         INT pid;
1056
1057         /* Speicher anfordern */
1058         s = malloc( sizeof( RES_STAT ));
1059         if( ! s )
1060         {
1061                 Log( LOG_EMERG, "Resolver: Can't allocate memory!" );
1062                 return NULL;
1063         }
1064
1065         /* Pipe fuer Antwort initialisieren */
1066         if( pipe( s->pipe ) != 0 )
1067         {
1068                 free( s );
1069                 Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
1070                 return NULL;
1071         }
1072
1073         /* Sub-Prozess erzeugen */
1074         pid = fork( );
1075         if( pid > 0 )
1076         {
1077                 /* Haupt-Prozess */
1078                 Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
1079                 FD_SET( s->pipe[0], &My_Resolvers );
1080                 if( s->pipe[0] > My_Max_Fd ) My_Max_Fd = s->pipe[0];
1081                 s->pid = pid;
1082                 return s;
1083         }
1084         else if( pid == 0 )
1085         {
1086                 /* Sub-Prozess */
1087                 Log_Init_Resolver( );
1088                 Do_ResolveAddr( Addr, s->pipe[1] );
1089                 Log_Exit_Resolver( );
1090                 exit( 0 );
1091         }
1092         else
1093         {
1094                 /* Fehler */
1095                 free( s );
1096                 Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
1097                 return NULL;
1098         }
1099 } /* ResolveAddr */
1100
1101
1102 LOCAL RES_STAT *ResolveName( CHAR *Host )
1103 {
1104         /* Hostnamen (asyncron!) aufloesen. Bei Fehler, z.B. wenn der
1105         * Child-Prozess nicht erzeugt werden kann, wird NULL geliefert.
1106         * Der Host kann dann nicht aufgeloest werden. */
1107
1108         RES_STAT *s;
1109         INT pid;
1110
1111         /* Speicher anfordern */
1112         s = malloc( sizeof( RES_STAT ));
1113         if( ! s )
1114         {
1115                 Log( LOG_EMERG, "Resolver: Can't allocate memory!" );
1116                 return NULL;
1117         }
1118
1119         /* Pipe fuer Antwort initialisieren */
1120         if( pipe( s->pipe ) != 0 )
1121         {
1122                 free( s );
1123                 Log( LOG_ALERT, "Resolver: Can't create output pipe: %s!", strerror( errno ));
1124                 return NULL;
1125         }
1126
1127         /* Sub-Prozess erzeugen */
1128         pid = fork( );
1129         if( pid > 0 )
1130         {
1131                 /* Haupt-Prozess */
1132                 Log( LOG_DEBUG, "Resolver for \"%s\" created (PID %d).", Host, pid );
1133                 FD_SET( s->pipe[0], &My_Resolvers );
1134                 if( s->pipe[0] > My_Max_Fd ) My_Max_Fd = s->pipe[0];
1135                 s->pid = pid;
1136                 return s;
1137         }
1138         else if( pid == 0 )
1139         {
1140                 /* Sub-Prozess */
1141                 Log_Init_Resolver( );
1142                 Do_ResolveName( Host, s->pipe[1] );
1143                 Log_Exit_Resolver( );
1144                 exit( 0 );
1145         }
1146         else
1147         {
1148                 /* Fehler */
1149                 free( s );
1150                 Log( LOG_CRIT, "Resolver: Can't fork: %s!", strerror( errno ));
1151                 return NULL;
1152         }
1153 } /* ResolveName */
1154
1155
1156 LOCAL VOID Do_ResolveAddr( struct sockaddr_in *Addr, INT w_fd )
1157 {
1158         /* Resolver Sub-Prozess: IP aufloesen und Ergebnis in Pipe schreiben. */
1159
1160         CHAR hostname[HOST_LEN];
1161         struct hostent *h;
1162
1163         Log_Resolver( LOG_DEBUG, "Now resolving %s ...", inet_ntoa( Addr->sin_addr ));
1164
1165         /* Namen aufloesen */
1166         h = gethostbyaddr( (CHAR *)&Addr->sin_addr, sizeof( Addr->sin_addr ), AF_INET );
1167         if( h ) strcpy( hostname, h->h_name );
1168         else
1169         {
1170                 Log_Resolver( LOG_WARNING, "Can't resolve address %s: code %s!", inet_ntoa( Addr->sin_addr ), Resolv_Error( h_errno ));
1171                 strcpy( hostname, inet_ntoa( Addr->sin_addr ));
1172         }
1173
1174         /* Antwort an Parent schreiben */
1175         if( write( w_fd, hostname, strlen( hostname ) + 1 ) != ( strlen( hostname ) + 1 ))
1176         {
1177                 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
1178                 close( w_fd );
1179                 return;
1180         }
1181
1182         Log_Resolver( LOG_DEBUG, "Ok, translated %s to \"%s\".", inet_ntoa( Addr->sin_addr ), hostname );
1183 } /* Do_ResolveAddr */
1184
1185
1186 LOCAL VOID Do_ResolveName( CHAR *Host, INT w_fd )
1187 {
1188         /* Resolver Sub-Prozess: Name aufloesen und Ergebnis in Pipe schreiben. */
1189
1190         CHAR ip[16];
1191         struct hostent *h;
1192         struct in_addr *addr;
1193
1194         Log_Resolver( LOG_DEBUG, "Now resolving \"%s\" ...", Host );
1195
1196         /* Namen aufloesen */
1197         h = gethostbyname( Host );
1198         if( h )
1199         {
1200                 addr = (struct in_addr *)h->h_addr;
1201                 strcpy( ip, inet_ntoa( *addr ));
1202         }
1203         else
1204         {
1205                 Log_Resolver( LOG_WARNING, "Can't resolve \"%s\": %s!", Host, Resolv_Error( h_errno ));
1206                 strcpy( ip, "" );
1207         }
1208
1209         /* Antwort an Parent schreiben */
1210         if( write( w_fd, ip, strlen( ip ) + 1 ) != ( strlen( ip ) + 1 ))
1211         {
1212                 Log_Resolver( LOG_CRIT, "Resolver: Can't write to parent: %s!", strerror( errno ));
1213                 close( w_fd );
1214                 return;
1215         }
1216
1217         if( ip[0] ) Log_Resolver( LOG_DEBUG, "Ok, translated \"%s\" to %s.", Host, ip );
1218 } /* Do_ResolveName */
1219
1220
1221 LOCAL VOID Read_Resolver_Result( INT r_fd )
1222 {
1223         /* Ergebnis von Resolver Sub-Prozess aus Pipe lesen
1224         * und entsprechende Connection aktualisieren */
1225
1226         CHAR result[HOST_LEN];
1227         CLIENT *c;
1228         INT len, i;
1229
1230         FD_CLR( r_fd, &My_Resolvers );
1231
1232         /* Anfrage vom Parent lesen */
1233         len = read( r_fd, result, HOST_LEN);
1234         if( len < 0 )
1235         {
1236                 /* Fehler beim Lesen aus der Pipe */
1237                 close( r_fd );
1238                 Log( LOG_CRIT, "Resolver: Can't read result: %s!", strerror( errno ));
1239                 return;
1240         }
1241         result[len] = '\0';
1242
1243         /* zugehoerige Connection suchen */
1244         for( i = 0; i < MAX_CONNECTIONS; i++ )
1245         {
1246                 if(( My_Connections[i].sock != NONE ) && ( My_Connections[i].res_stat ) && ( My_Connections[i].res_stat->pipe[0] == r_fd )) break;
1247         }
1248         if( i >= MAX_CONNECTIONS )
1249         {
1250                 /* Opsa! Keine passende Connection gefunden!? Vermutlich
1251                  * wurde sie schon wieder geschlossen. */
1252                 close( r_fd );
1253                 Log( LOG_DEBUG, "Resolver: Got result for unknown connection!?" );
1254                 return;
1255         }
1256
1257         /* Aufraeumen */
1258         close( My_Connections[i].res_stat->pipe[0] );
1259         close( My_Connections[i].res_stat->pipe[1] );
1260         free( My_Connections[i].res_stat );
1261         My_Connections[i].res_stat = NULL;
1262
1263         if( My_Connections[i].sock > NONE )
1264         {
1265                 /* Eingehende Verbindung: Hostnamen setzen */
1266                 c = Client_GetFromConn( i );
1267                 assert( c != NULL );
1268                 strcpy( My_Connections[i].host, result );
1269                 Client_SetHostname( c, result );
1270         }
1271         else
1272         {
1273                 /* Ausgehende Verbindung (=Server): IP setzen */
1274                 assert( My_Connections[i].our_server >= 0 );
1275                 strcpy( Conf_Server[My_Connections[i].our_server].ip, result );
1276         }
1277 } /* Read_Resolver_Result */
1278
1279
1280 LOCAL CHAR *Resolv_Error( INT H_Error )
1281 {
1282         /* Fehlerbeschreibung fuer H_Error liefern */
1283
1284         switch( H_Error )
1285         {
1286                 case HOST_NOT_FOUND:
1287                         return "host not found";
1288                 case NO_DATA:
1289                         return "name valid but no IP address defined";
1290                 case NO_RECOVERY:
1291                         return "name server error";
1292                 case TRY_AGAIN:
1293                         return "name server temporary not available";
1294                 default:
1295                         return "unknown error";
1296         }
1297 } /* Resolv_Error */
1298
1299
1300 /* -eof- */