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