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