]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn.c
- Log-Funktionen fuer Resolver-Sub-Prozess implementiert.
[ngircd-alex.git] / src / ngircd / conn.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001 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 comBase beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: conn.c,v 1.17 2001/12/29 03:06:16 alex Exp $
13  *
14  * connect.h: Verwaltung aller Netz-Verbindungen ("connections")
15  *
16  * $Log: conn.c,v $
17  * Revision 1.17  2001/12/29 03:06:16  alex
18  * - Loglevel (nochmal) angepasst.
19  *
20  * Revision 1.16  2001/12/27 19:32:44  alex
21  * - bei "Null-Requests" wird nichts mehr geloggt. Uberfluessig, da normal.
22  *
23  * Revision 1.15  2001/12/27 16:35:04  alex
24  * - vergessene Variable bei Ping-Timeout-Logmeldung ergaenzt. Opsa.
25  *
26  * Revision 1.14  2001/12/26 14:45:37  alex
27  * - "Code Cleanups".
28  *
29  * Revision 1.13  2001/12/26 03:36:57  alex
30  * - Verbindungen mit Lesefehlern werden nun korrekt terminiert.
31  *
32  * Revision 1.12  2001/12/26 03:20:53  alex
33  * - PING/PONG-Timeout implementiert.
34  *
35  * Revision 1.11  2001/12/25 23:15:16  alex
36  * - buffer werden nun periodisch geprueft, keine haengenden Clients mehr.
37  *
38  * Revision 1.10  2001/12/25 22:03:47  alex
39  * - Conn_Close() eingefuehrt: war die lokale Funktion Close_Connection().
40  *
41  * Revision 1.9  2001/12/24 01:32:33  alex
42  * - in Conn_WriteStr() wurde das CR+LF nicht angehaengt!
43  * - Fehler-Ausgaben vereinheitlicht.
44  *
45  * Revision 1.8  2001/12/23 22:02:54  alex
46  * - Conn_WriteStr() nimmt nun variable Parameter,
47  * - diverse kleinere Aenderungen.
48  *
49  * Revision 1.7  2001/12/21 22:24:25  alex
50  * - kleinere Aenderungen an den Log-Meldungen,
51  * - Parse_Request() wird aufgerufen.
52  *
53  * Revision 1.6  2001/12/15 00:11:55  alex
54  * - Lese- und Schreib-Puffer implementiert.
55  * - einige neue (Unter-)Funktionen eingefuehrt.
56  * - diverse weitere kleinere Aenderungen.
57  *
58  * Revision 1.5  2001/12/14 08:16:47  alex
59  * - Begonnen, Client-spezifische Lesepuffer zu implementieren.
60  * - Umstellung auf Datentyp "CONN_ID".
61  *
62  * Revision 1.4  2001/12/13 02:04:16  alex
63  * - boesen "Speicherschiesser" in Log() gefixt.
64  *
65  * Revision 1.3  2001/12/13 01:33:09  alex
66  * - Conn_Handler() unterstuetzt nun einen Timeout.
67  * - fuer Verbindungen werden keine FILE-Handles mehr benutzt.
68  * - kleinere "Code Cleanups" ;-)
69  *
70  * Revision 1.2  2001/12/12 23:32:02  alex
71  * - diverse Erweiterungen und Verbesserungen (u.a. sind nun mehrere
72  *   Verbindungen und Listen-Sockets moeglich).
73  *
74  * Revision 1.1  2001/12/12 17:18:38  alex
75  * - Modul zur Verwaltung aller Netzwerk-Verbindungen begonnen.
76  */
77
78
79 #include <portab.h>
80 #include "global.h"
81
82 #include <imp.h>
83 #include <assert.h>
84 #include <stdarg.h>
85 #include <stdio.h>
86 #include <unistd.h>
87 #include <errno.h>
88 #include <fcntl.h>
89 #include <string.h>
90 #include <sys/socket.h>
91 #include <sys/time.h>
92 #include <sys/types.h>
93 #include <time.h>
94 #include <netinet/in.h>
95 #include <arpa/inet.h>
96
97 #ifdef HAVE_STDINT_H
98 #include <stdint.h>                     /* u.a. fuer Mac OS X */
99 #endif
100
101 #include "ngircd.h"
102 #include "client.h"
103 #include "conf.h"
104 #include "log.h"
105 #include "parse.h"
106 #include "tool.h"
107
108 #include <exp.h>
109 #include "conn.h"
110
111
112 #define MAX_CONNECTIONS 100             /* max. Anzahl von Verbindungen an diesem Server */
113
114 #define MAX_CMDLEN 512                  /* max. Laenge eines Befehls, vgl. RFC 2812, 3.2 */
115
116 #define READBUFFER_LEN 2 * MAX_CMDLEN   /* Laenge des Lesepuffers je Verbindung (Bytes) */
117 #define WRITEBUFFER_LEN 4096            /* Laenge des Schreibpuffers je Verbindung (Bytes) */
118
119
120 typedef struct _Connection
121 {
122         INT sock;                       /* Socket Handle */
123         struct sockaddr_in addr;        /* Adresse des Client */
124         CHAR rbuf[READBUFFER_LEN + 1];  /* Lesepuffer */
125         INT rdatalen;                   /* Laenge der Daten im Lesepuffer */
126         CHAR wbuf[WRITEBUFFER_LEN + 1]; /* Schreibpuffer */
127         INT wdatalen;                   /* Laenge der Daten im Schreibpuffer */
128         time_t lastdata;                /* Letzte Aktivitaet */
129         time_t lastping;                /* Letzter PING */
130 } CONNECTION;
131
132
133 LOCAL VOID Handle_Read( INT sock );
134 LOCAL BOOLEAN Handle_Write( CONN_ID Idx );
135 LOCAL VOID New_Connection( INT Sock );
136 LOCAL CONN_ID Socket2Index( INT Sock );
137 LOCAL VOID Read_Request( CONN_ID Idx );
138 LOCAL BOOLEAN Try_Write( CONN_ID Idx );
139 LOCAL VOID Handle_Buffer( CONN_ID Idx );
140 LOCAL VOID Check_Connections( VOID );
141
142
143 LOCAL fd_set My_Listener;
144 LOCAL fd_set My_Sockets;
145
146 LOCAL INT My_Max_Fd;
147
148 LOCAL CONNECTION My_Connections[MAX_CONNECTIONS];
149
150
151 GLOBAL VOID Conn_Init( VOID )
152 {
153         CONN_ID i;
154
155         /* zu Beginn haben wir keine Verbindungen */
156         FD_ZERO( &My_Listener );
157         FD_ZERO( &My_Sockets );
158
159         My_Max_Fd = 0;
160
161         /* Connection-Struktur initialisieren */
162         for( i = 0; i < MAX_CONNECTIONS; i++ ) My_Connections[i].sock = NONE;
163 } /* Conn_Init */
164
165
166 GLOBAL VOID Conn_Exit( VOID )
167 {
168         CONN_ID idx;
169         INT i;
170
171         /* Sockets schliessen */
172         for( i = 0; i < My_Max_Fd + 1; i++ )
173         {
174                 if( FD_ISSET( i, &My_Sockets ))
175                 {
176                         for( idx = 0; idx < MAX_CONNECTIONS; idx++ )
177                         {
178                                 if( My_Connections[idx].sock == i ) break;
179                         }
180                         if( idx < MAX_CONNECTIONS ) Conn_Close( idx, "Server going down ..." );
181                         else if( FD_ISSET( i, &My_Listener ))
182                         {
183                                 close( i );
184                                 Log( LOG_INFO, "Listening socket %d closed.", i );
185                         }
186                         else
187                         {
188                                 close( i );
189                                 Log( LOG_WARNING, "Unknown connection %d closed.", i );
190                         }
191                 }
192         }
193 } /* Conn_Exit */
194
195
196 GLOBAL BOOLEAN Conn_NewListener( CONST INT Port )
197 {
198         /* Neuen Listen-Socket erzeugen: der Server wartet dann
199          * auf dem angegebenen Port auf Verbindungen. */
200
201         struct sockaddr_in addr;
202         INT sock, on = 1;
203
204         /* Server-"Listen"-Socket initialisieren */
205         memset( &addr, 0, sizeof( addr ));
206         addr.sin_family = AF_INET;
207         addr.sin_port = htons( Port );
208         addr.sin_addr.s_addr = htonl( INADDR_ANY );
209
210         /* Socket erzeugen */
211         sock = socket( PF_INET, SOCK_STREAM, 0);
212         if( sock < 0 )
213         {
214                 Log( LOG_ALERT, "Can't create socket: %s!", strerror( errno ));
215                 return FALSE;
216         }
217
218         /* Socket-Optionen setzen */
219         if( fcntl( sock, F_SETFL, O_NONBLOCK ) != 0 )
220         {
221                 Log( LOG_ALERT, "Can't enable non-blocking mode: %s!", strerror( errno ));
222                 close( sock );
223                 return FALSE;
224         }
225         if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0)
226         {
227                 Log( LOG_CRIT, "Can't set socket options: %s!", strerror( errno ));
228                 /* dieser Fehler kann ignoriert werden. */
229         }
230
231         /* an Port binden */
232         if( bind( sock, (struct sockaddr *)&addr, (socklen_t)sizeof( addr )) != 0 )
233         {
234                 Log( LOG_ALERT, "Can't bind socket: %s!", strerror( errno ));
235                 close( sock );
236                 return FALSE;
237         }
238
239         /* in "listen mode" gehen :-) */
240         if( listen( sock, 10 ) != 0 )
241         {
242                 Log( LOG_ALERT, "Can't listen on soecket: %s!", strerror( errno ));
243                 close( sock );
244                 return FALSE;
245         }
246
247         /* Neuen Listener in Strukturen einfuegen */
248         FD_SET( sock, &My_Listener );
249         FD_SET( sock, &My_Sockets );
250
251         if( sock > My_Max_Fd ) My_Max_Fd = sock;
252
253         Log( LOG_INFO, "Now listening on port %d, socket %d.", Port, sock );
254
255         return TRUE;
256 } /* Conn_NewListener */
257
258
259 GLOBAL VOID Conn_Handler( INT Timeout )
260 {
261         fd_set read_sockets, write_sockets;
262         struct timeval tv;
263         time_t start;
264         INT i;
265
266         start = time( NULL );
267         while(( time( NULL ) - start < Timeout ) && ( ! NGIRCd_Quit ))
268         {
269                 Check_Connections( );
270
271                 /* Timeout initialisieren */
272                 tv.tv_sec = 0;
273                 tv.tv_usec = 50000;
274
275                 /* noch volle Lese-Buffer suchen */
276                 for( i = 0; i < MAX_CONNECTIONS; i++ )
277                 {
278                         if(( My_Connections[i].sock >= 0 ) && ( My_Connections[i].rdatalen > 0 ))
279                         {
280                                 /* Kann aus dem Buffer noch ein Befehl extrahiert werden? */
281                                 Handle_Buffer( i );
282                         }
283                 }
284                 
285                 /* noch volle Schreib-Puffer suchen */
286                 FD_ZERO( &write_sockets );
287                 for( i = 0; i < MAX_CONNECTIONS; i++ )
288                 {
289                         if(( My_Connections[i].sock >= 0 ) && ( My_Connections[i].wdatalen > 0 ))
290                         {
291                                 /* Socket der Verbindung in Set aufnehmen */
292                                 FD_SET( My_Connections[i].sock, &write_sockets );
293                         }
294                 }
295                 
296                 read_sockets = My_Sockets;
297                 if( select( My_Max_Fd + 1, &read_sockets, &write_sockets, NULL, &tv ) == -1 )
298                 {
299                         if( errno != EINTR ) Log( LOG_ALERT, "select(): %s!", strerror( errno ));
300                         return;
301                 }
302
303                 /* Koennen Daten geschrieben werden? */
304                 for( i = 0; i < My_Max_Fd + 1; i++ )
305                 {
306                         if( FD_ISSET( i, &write_sockets )) Handle_Write( Socket2Index( i ));
307                 }
308
309                 /* Daten zum Lesen vorhanden? */
310                 for( i = 0; i < My_Max_Fd + 1; i++ )
311                 {
312                         if( FD_ISSET( i, &read_sockets )) Handle_Read( i );
313                 }
314         }
315 } /* Conn_Handler */
316
317
318 GLOBAL BOOLEAN Conn_WriteStr( CONN_ID Idx, CHAR *Format, ... )
319 {
320         /* String in Socket schreiben. CR+LF wird von dieser Funktion
321          * automatisch angehaengt. Im Fehlerfall wird dir Verbindung
322          * getrennt und FALSE geliefert. */
323
324         CHAR buffer[MAX_CMDLEN];
325         BOOLEAN ok;
326         va_list ap;
327
328         va_start( ap, Format );
329         if( vsnprintf( buffer, MAX_CMDLEN - 2, Format, ap ) == MAX_CMDLEN - 2 )
330         {
331                 Log( LOG_ALERT, "String too long to send (connection %d)!", Idx );
332                 Conn_Close( Idx, "Server error: String too long to send!" );
333                 return FALSE;
334         }
335
336 #ifdef SNIFFER
337         Log( LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer );
338 #endif
339
340         strcat( buffer, "\r\n" );
341         ok = Conn_Write( Idx, buffer, strlen( buffer ));
342
343         va_end( ap );
344         return ok;
345 } /* Conn_WriteStr */
346
347
348 GLOBAL BOOLEAN Conn_Write( CONN_ID Idx, CHAR *Data, INT Len )
349 {
350         /* Daten in Socket schreiben. Bei "fatalen" Fehlern wird
351          * der Client disconnectiert und FALSE geliefert. */
352
353         assert( Idx >= 0 );
354         assert( My_Connections[Idx].sock >= 0 );
355         assert( Data != NULL );
356         assert( Len > 0 );
357
358         /* pruefen, ob Daten im Schreibpuffer sind. Wenn ja, zunaechst
359          * pruefen, ob diese gesendet werden koennen */
360         if( My_Connections[Idx].wdatalen > 0 )
361         {
362                 if( ! Try_Write( Idx )) return FALSE;
363         }
364
365         /* pruefen, ob im Schreibpuffer genuegend Platz ist */
366         if( WRITEBUFFER_LEN - My_Connections[Idx].wdatalen - Len <= 0 )
367         {
368                 /* der Puffer ist dummerweise voll ... */
369                 Log( LOG_NOTICE, "Write buffer overflow (connection %d)!", Idx );
370                 Conn_Close( Idx, NULL );
371                 return FALSE;
372         }
373
374         /* Daten in Puffer kopieren */
375         memcpy( My_Connections[Idx].wbuf + My_Connections[Idx].wdatalen, Data, Len );
376         My_Connections[Idx].wdatalen += Len;
377
378         /* pruefen, on Daten vorhanden sind und geschrieben werden koennen */
379         if( My_Connections[Idx].wdatalen > 0 )
380         {
381                 if( ! Try_Write( Idx )) return FALSE;
382         }
383
384         return TRUE;
385 } /* Conn_Write */
386
387
388 GLOBAL VOID Conn_Close( CONN_ID Idx, CHAR *Msg )
389 {
390         /* Verbindung schliessen */
391
392         assert( Idx >= 0 );
393         assert( My_Connections[Idx].sock >= 0 );
394
395         if( Msg ) Conn_WriteStr( Idx, "ERROR :%s", Msg );
396
397         if( close( My_Connections[Idx].sock ) != 0 )
398         {
399                 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 ));
400                 return;
401         }
402         else
403         {
404                 Log( LOG_NOTICE, "Connection %d with %s:%d closed.", Idx, inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port ));
405         }
406
407         Client_Destroy( Client_GetFromConn( Idx ));
408
409         FD_CLR( My_Connections[Idx].sock, &My_Sockets );
410         My_Connections[Idx].sock = NONE;
411 } /* Conn_Close */
412
413
414 LOCAL BOOLEAN Try_Write( CONN_ID Idx )
415 {
416         /* Versuchen, Daten aus dem Schreib-Puffer in den
417          * Socket zu schreiben. */
418
419         fd_set write_socket;
420
421         assert( Idx >= 0 );
422         assert( My_Connections[Idx].sock >= 0 );
423         assert( My_Connections[Idx].wdatalen > 0 );
424
425         FD_ZERO( &write_socket );
426         FD_SET( My_Connections[Idx].sock, &write_socket );
427         if( select( My_Connections[Idx].sock + 1, NULL, &write_socket, NULL, 0 ) == -1 )
428         {
429                 /* Fehler! */
430                 if( errno != EINTR )
431                 {
432                         Log( LOG_ALERT, "select(): %s!", strerror( errno ));
433                         Conn_Close( Idx, NULL );
434                         return FALSE;
435                 }
436         }
437
438         if( FD_ISSET( My_Connections[Idx].sock, &write_socket )) return Handle_Write( Idx );
439         else return TRUE;
440 } /* Try_Write */
441
442
443 LOCAL VOID Handle_Read( INT Sock )
444 {
445         /* Aktivitaet auf einem Socket verarbeiten */
446
447         CONN_ID idx;
448
449         assert( Sock >= 0 );
450
451         if( FD_ISSET( Sock, &My_Listener ))
452         {
453                 /* es ist einer unserer Listener-Sockets: es soll
454                  * also eine neue Verbindung aufgebaut werden. */
455
456                 New_Connection( Sock );
457         }
458         else
459         {
460                 /* Ein Client Socket: entweder ein User oder Server */
461
462                 idx = Socket2Index( Sock );
463                 Read_Request( idx );
464         }
465 } /* Handle_Read */
466
467
468 LOCAL BOOLEAN Handle_Write( CONN_ID Idx )
469 {
470         /* Daten aus Schreibpuffer versenden */
471
472         INT len;
473
474         assert( Idx >= 0 );
475         assert( My_Connections[Idx].sock >= 0 );
476         assert( My_Connections[Idx].wdatalen > 0 );
477
478         /* Daten schreiben */
479         len = send( My_Connections[Idx].sock, My_Connections[Idx].wbuf, My_Connections[Idx].wdatalen, 0 );
480         if( len < 0 )
481         {
482                 /* Oops, ein Fehler! */
483                 Log( LOG_ALERT, "Write error (buffer) on connection %d: %s!", Idx, strerror( errno ));
484                 Conn_Close( Idx, NULL );
485                 return FALSE;
486         }
487
488         /* Puffer anpassen */
489         My_Connections[Idx].wdatalen -= len;
490         memmove( My_Connections[Idx].wbuf, My_Connections[Idx].wbuf + len, My_Connections[Idx].wdatalen );
491
492         return TRUE;
493 } /* Handle_Write */
494
495
496 LOCAL VOID New_Connection( INT Sock )
497 {
498         /* Neue Client-Verbindung von Listen-Socket annehmen und
499          * CLIENT-Struktur anlegen. */
500
501         struct sockaddr_in new_addr;
502         INT new_sock, new_sock_len;
503         CONN_ID idx;
504
505         assert( Sock >= 0 );
506
507         new_sock_len = sizeof( new_addr );
508         new_sock = accept( Sock, (struct sockaddr *)&new_addr, (socklen_t *)&new_sock_len );
509         if( new_sock < 0 )
510         {
511                 Log( LOG_CRIT, "Can't accept connection: %s!", strerror( errno ));
512                 return;
513         }
514
515         /* Freie Connection-Struktur suschen */
516         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock < 0 ) break;
517         if( idx >= MAX_CONNECTIONS )
518         {
519                 Log( LOG_ALERT, "Can't accept connection: limit reached (%d)!", MAX_CONNECTIONS );
520                 close( new_sock );
521                 return;
522         }
523
524         /* Client-Struktur initialisieren */
525         if( ! Client_NewLocal( idx, inet_ntoa( new_addr.sin_addr )))
526         {
527                 Log( LOG_ALERT, "Can't accept connection: can't create client structure!" );
528                 close( new_sock );
529                 return;
530         }
531
532         /* Verbindung registrieren */
533         My_Connections[idx].sock = new_sock;
534         My_Connections[idx].addr = new_addr;
535         My_Connections[idx].rdatalen = 0;
536         My_Connections[idx].wdatalen = 0;
537         My_Connections[idx].lastdata = time( NULL );
538         My_Connections[idx].lastping = 0;
539
540         /* Neuen Socket registrieren */
541         FD_SET( new_sock, &My_Sockets );
542
543         if( new_sock > My_Max_Fd ) My_Max_Fd = new_sock;
544
545         Log( LOG_NOTICE, "Accepted connection %d from %s:%d on socket %d.", idx, inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock );
546 } /* New_Connection */
547
548
549 LOCAL CONN_ID Socket2Index( INT Sock )
550 {
551         /* zum Socket passende Connection suchen */
552
553         CONN_ID idx;
554
555         assert( Sock >= 0 );
556
557         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == Sock ) break;
558
559         assert( idx < MAX_CONNECTIONS );
560         return idx;
561 } /* Socket2Index */
562
563
564 LOCAL VOID Read_Request( CONN_ID Idx )
565 {
566         /* Daten von Socket einlesen und entsprechend behandeln.
567          * Tritt ein Fehler auf, so wird der Socket geschlossen. */
568
569         INT len;
570
571         assert( Idx >= 0 );
572         assert( My_Connections[Idx].sock >= 0 );
573
574         len = recv( My_Connections[Idx].sock, My_Connections[Idx].rbuf + My_Connections[Idx].rdatalen, READBUFFER_LEN - My_Connections[Idx].rdatalen, 0 );
575         My_Connections[Idx].rbuf[READBUFFER_LEN] = '\0';
576
577         if( len == 0 )
578         {
579                 /* Socket wurde geschlossen */
580                 Log( LOG_INFO, "%s:%d is closing the connection ...", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port));
581                 Conn_Close( Idx, NULL );
582                 return;
583         }
584
585         if( len < 0 )
586         {
587                 /* Fehler beim Lesen */
588                 Log( LOG_ALERT, "Read error on connection %d: %s!", Idx, strerror( errno ));
589                 Conn_Close( Idx, NULL );
590                 return;
591         }
592
593         /* Lesebuffer updaten */
594         My_Connections[Idx].rdatalen += len;
595         assert( My_Connections[Idx].rdatalen <= READBUFFER_LEN );
596         My_Connections[Idx].rbuf[My_Connections[Idx].rdatalen] = '\0';
597
598         if( My_Connections[Idx].rdatalen > MAX_CMDLEN )
599         {
600                 /* Eine Anfrage darf(!) nicht laenger als 512 Zeichen
601                  * (incl. CR+LF!) werden; vgl. RFC 2812. Wenn soetwas
602                  * empfangen wird, wird der Client disconnectiert. */
603                 Log( LOG_ALERT, "Request too long (connection %d)!", Idx );
604                 Conn_Close( Idx, "Request too long!" );
605                 return;
606         }
607
608         /* Timestamp aktualisieren */
609         My_Connections[Idx].lastdata = time( NULL );
610
611         Handle_Buffer( Idx );
612 } /* Read_Request */
613
614
615 LOCAL VOID Handle_Buffer( CONN_ID Idx )
616 {
617         CHAR *ptr, *ptr1, *ptr2;
618         INT len, delta;
619         
620         /* Eine komplette Anfrage muss mit CR+LF enden, vgl.
621          * RFC 2812. Haben wir eine? */
622         ptr = strstr( My_Connections[Idx].rbuf, "\r\n" );
623
624         if( ptr ) delta = 2;
625         else
626         {
627                 /* Nicht RFC-konforme Anfrage mit nur CR oder LF? Leider
628                  * machen soetwas viele Clients, u.a. "mIRC" :-( */
629                 ptr1 = strchr( My_Connections[Idx].rbuf, '\r' );
630                 ptr2 = strchr( My_Connections[Idx].rbuf, '\n' );
631                 delta = 1;
632                 if( ptr1 && ptr2 ) ptr = ptr1 > ptr2 ? ptr2 : ptr1;
633                 else if( ptr1 ) ptr = ptr1;
634                 else if( ptr2 ) ptr = ptr2;
635         }
636
637         if( ptr )
638         {
639                 /* Ende der Anfrage wurde gefunden */
640                 *ptr = '\0';
641                 len = ( ptr - My_Connections[Idx].rbuf ) + delta;
642                 if( len > delta )
643                 {
644                         /* Es wurde ein Request gelesen */
645                         if( ! Parse_Request( Idx, My_Connections[Idx].rbuf )) return;
646                 }
647
648                 /* Puffer anpassen */
649                 My_Connections[Idx].rdatalen -= len;
650                 memmove( My_Connections[Idx].rbuf, My_Connections[Idx].rbuf + len, My_Connections[Idx].rdatalen );
651         }
652 } /* Handle_Buffer */
653
654
655 LOCAL VOID Check_Connections( VOID )
656 {
657         /* Pruefen, ob Verbindungen noch "alive" sind */
658
659         INT i;
660
661         for( i = 0; i < MAX_CONNECTIONS; i++ )
662         {
663                 if( My_Connections[i].sock != NONE )
664                 {
665                         if( My_Connections[i].lastping > My_Connections[i].lastdata )
666                         {
667                                 /* es wurde bereits ein PING gesendet */
668                                 if( My_Connections[i].lastping < time( NULL ) - Conf_PongTimeout )
669                                 {
670                                         /* Timeout */
671                                         Log( LOG_INFO, "Connection %d: Ping timeout.", i );
672                                         Conn_Close( i, "Ping timeout" );
673                                 }
674                         }
675                         else if( My_Connections[i].lastdata < time( NULL ) - Conf_PingTimeout )
676                         {
677                                 /* es muss ein PING gesendet werden */
678                                 Log( LOG_DEBUG, "Connection %d: sending PING ...", i );
679                                 My_Connections[i].lastping = time( NULL );
680                                 Conn_WriteStr( i, "PING :%s", This_Server->nick );
681                         }
682                 }
683         }
684 } /* Conn_Check */
685
686
687 /* -eof- */