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