]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/ngircd.c
- "Passive-Mode" implementiert: kein Auto-Conect zu anderen Servern.
[ngircd-alex.git] / src / ngircd / ngircd.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: ngircd.c,v 1.24 2002/02/19 20:08:24 alex Exp $
13  *
14  * ngircd.c: Hier beginnt alles ;-)
15  *
16  * $Log: ngircd.c,v $
17  * Revision 1.24  2002/02/19 20:08:24  alex
18  * - "Passive-Mode" implementiert: kein Auto-Conect zu anderen Servern.
19  * - NGIRCd_DebugLevel wird (fuer VERSION-Befehl) ermittelt.
20  *
21  * Revision 1.23  2002/02/17 23:40:21  alex
22  * - neue Funktion NGIRCd_VersionAddition(). NGIRCd_Version() aufgespaltet.
23  *
24  * Revision 1.22  2002/01/22 17:15:39  alex
25  * - die Fehlermeldung "interrupted system call" sollte nicht mehr auftreten.
26  *
27  * Revision 1.21  2002/01/21 00:02:11  alex
28  * - Hilfetexte korrigiert und ergaenzt (Sniffer).
29  *
30  * Revision 1.20  2002/01/18 11:12:11  alex
31  * - der Sniffer wird nun nur noch aktiviert, wenn auf Kommandozeile angegeben.
32  *
33  * Revision 1.19  2002/01/12 00:17:28  alex
34  * - ngIRCd wandelt sich nun selber in einen Daemon (Hintergrundprozess) um.
35  *
36  * Revision 1.18  2002/01/11 14:45:18  alex
37  * - Kommandozeilen-Parser implementiert: Debug- und No-Daemon-Modus, Hilfe.
38  *
39  * Revision 1.17  2002/01/02 02:51:16  alex
40  * - Signal-Handler fuer SIGCHLD: so sollten Zombies nicht mehr vorkommen.
41  *
42  * Revision 1.15  2001/12/31 02:18:51  alex
43  * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
44  * - neuen Header "defines.h" mit (fast) allen Konstanten.
45  * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
46  *
47  * Revision 1.14  2001/12/30 19:26:12  alex
48  * - Unterstuetzung fuer die Konfigurationsdatei eingebaut.
49  *
50  * Revision 1.13  2001/12/30 11:42:00  alex
51  * - der Server meldet nun eine ordentliche "Start-Zeit".
52  *
53  * Revision 1.12  2001/12/29 03:07:36  alex
54  * - einige Loglevel geaendert.
55  *
56  * Revision 1.11  2001/12/26 14:45:37  alex
57  * - "Code Cleanups".
58  *
59  * Revision 1.10  2001/12/24 01:34:38  alex
60  * - Signal-Handler aufgeraeumt; u.a. SIGPIPE wird nun korrekt ignoriert.
61  *
62  * Revision 1.9  2001/12/21 22:24:50  alex
63  * - neues Modul "parse" wird initialisiert und abgemeldet.
64  *
65  * Revision 1.8  2001/12/14 08:15:26  alex
66  * - neue Module (irc, client, channel) werden an- und abgemeldet.
67  * - zweiter Listen-Socket wird zu Testzwecken konfiguriert.
68  *
69  * Revision 1.7  2001/12/13 01:31:46  alex
70  * - Conn_Handler() wird nun mit einem Timeout aufgerufen.
71  *
72  * Revision 1.6  2001/12/12 23:30:42  alex
73  * - Log-Meldungen an syslog angepasst.
74  * - NGIRCd_Quit ist nun das Flag zum Beenden des ngircd.
75  *
76  * Revision 1.5  2001/12/12 17:21:21  alex
77  * - mehr Unterfunktionen eingebaut, Modul besser strukturiert & dokumentiert.
78  * - Anpassungen an neue Module.
79  *
80  * Revision 1.4  2001/12/12 01:58:53  alex
81  * - Test auf socklen_t verbessert.
82  *
83  * Revision 1.3  2001/12/12 01:40:39  alex
84  * - ein paar mehr Kommentare; Variablennamen verstaendlicher gemacht.
85  * - fehlenden Header <arpa/inet.h> ergaenz.
86  * - SIGINT und SIGQUIT werden nun ebenfalls behandelt.
87  *
88  * Revision 1.2  2001/12/11 22:04:21  alex
89  * - Test auf stdint.h (HAVE_STDINT_H) hinzugefuegt.
90  *
91  * Revision 1.1.1.1  2001/12/11 21:53:04  alex
92  * - Imported sources to CVS.
93  */
94
95
96 #define PORTAB_CHECK_TYPES              /* Prueffunktion einbinden, s.u. */
97
98
99 #include <portab.h>
100 #include "global.h"
101
102 #include <imp.h>
103
104 #include <assert.h>
105 #include <errno.h>
106 #include <stdio.h>
107 #include <signal.h>
108 #include <string.h>
109 #include <unistd.h>
110 #include <sys/types.h>
111 #include <sys/wait.h>
112 #include <time.h>
113
114 #include "channel.h"
115 #include "client.h"
116 #include "conf.h"
117 #include "conn.h"
118 #include "irc.h"
119 #include "log.h"
120 #include "parse.h"
121
122 #include <exp.h>
123 #include "ngircd.h"
124
125
126 LOCAL VOID Initialize_Signal_Handler( VOID );
127 LOCAL VOID Signal_Handler( INT Signal );
128
129 LOCAL VOID Initialize_Listen_Ports( VOID );
130
131 LOCAL VOID Show_Version( VOID );
132 LOCAL VOID Show_Help( VOID );
133
134
135 GLOBAL INT main( INT argc, CONST CHAR *argv[] )
136 {
137         BOOLEAN ok;
138         INT pid, i, n;
139
140         /* Datentypen der portab-Library ueberpruefen */
141         portab_check_types( );
142
143         NGIRCd_Restart = FALSE;
144         NGIRCd_Quit = FALSE;
145         NGIRCd_NoDaemon = FALSE;
146         NGIRCd_Passive = FALSE;
147 #ifdef DEBUG
148         NGIRCd_Debug = FALSE;
149 #endif
150 #ifdef SNIFFER
151         NGIRCd_Sniffer = FALSE;
152 #endif
153
154         /* Kommandozeile parsen */
155         for( i = 1; i < argc; i++ )
156         {
157                 ok = FALSE;
158                 if(( argv[i][0] == '-' ) && ( argv[i][1] == '-' ))
159                 {
160                         /* Lange Option */
161
162 #ifdef DEBUG
163                         if( strcmp( argv[i], "--debug" ) == 0 )
164                         {
165                                 NGIRCd_Debug = TRUE;
166                                 ok = TRUE;
167                         }
168 #endif
169                         if( strcmp( argv[i], "--help" ) == 0 )
170                         {
171                                 Show_Version( ); puts( "" );
172                                 Show_Help( ); puts( "" );
173                                 exit( 1 );
174                         }
175                         if( strcmp( argv[i], "--nodaemon" ) == 0 )
176                         {
177                                 NGIRCd_NoDaemon = TRUE;
178                                 ok = TRUE;
179                         }
180                         if( strcmp( argv[i], "--passive" ) == 0 )
181                         {
182                                 NGIRCd_Passive = TRUE;
183                                 ok = TRUE;
184                         }
185 #ifdef SNIFFER
186                         if( strcmp( argv[i], "--sniffer" ) == 0 )
187                         {
188                                 NGIRCd_Sniffer = TRUE;
189                                 ok = TRUE;
190                         }
191 #endif
192                         if( strcmp( argv[i], "--version" ) == 0 )
193                         {
194                                 Show_Version( );
195                                 exit( 1 );
196                         }
197                 }
198                 else if(( argv[i][0] == '-' ) && ( argv[i][1] != '-' ))
199                 {
200                         /* Kurze Option */
201                         
202                         for( n = 1; n < strlen( argv[i] ); n++ )
203                         {
204                                 ok = FALSE;
205 #ifdef DEBUG
206                                 if( argv[i][n] == 'd' )
207                                 {
208                                         NGIRCd_Debug = TRUE;
209                                         ok = TRUE;
210                                 }
211 #endif
212                                 if( argv[i][n] == 'n' )
213                                 {
214                                         NGIRCd_NoDaemon = TRUE;
215                                         ok = TRUE;
216                                 }
217                                 if( argv[i][n] == 'p' )
218                                 {
219                                         NGIRCd_Passive = TRUE;
220                                         ok = TRUE;
221                                 }
222 #ifdef SNIFFER
223                                 if( argv[i][n] == 's' )
224                                 {
225                                         NGIRCd_Sniffer = TRUE;
226                                         ok = TRUE;
227                                 }
228 #endif
229
230                                 if( ! ok )
231                                 {
232                                         printf( PACKAGE": invalid option \"-%c\"!\n", argv[i][n] );
233                                         puts( "Try \""PACKAGE" --help\" for more information." );
234                                         exit( 1 );
235                                 }
236                         }
237
238                 }
239                 if( ! ok )
240                 {
241                         printf( PACKAGE": invalid option \"%s\"!\n", argv[i] );
242                         puts( "Try \""PACKAGE" --help\" for more information." );
243                         exit( 1 );
244                 }
245         }
246
247         /* Debug-Level (fuer IRC-Befehl "VERSION") ermitteln */
248         strcpy( NGIRCd_DebugLevel, "" );
249 #ifdef DEBUG
250         if( NGIRCd_Debug ) strcpy( NGIRCd_DebugLevel, "1" );
251 #endif
252 #ifdef SNIFFER
253         if( NGIRCd_Sniffer ) strcpy( NGIRCd_DebugLevel, "2" );
254 #endif
255         
256         while( ! NGIRCd_Quit )
257         {
258                 /* In der Regel wird ein Sub-Prozess ge-fork()'t, der
259                  * nicht mehr mit dem Terminal verbunden ist. Mit der
260                  * Option "--nodaemon" kann dies (z.B. zum Debuggen)
261                  * verhindert werden. */
262                 if( ! NGIRCd_NoDaemon )
263                 {
264                         /* Daemon im Hintergrund erzeugen */
265                         pid = fork( );
266                         if( pid > 0 )
267                         {
268                                 /* "alter" Prozess */
269                                 exit( 0 );
270                         }
271                         if( pid < 0 )
272                         {
273                                 /* Fehler */
274                                 printf( PACKAGE": Can't fork: %s!\nFatal error, exiting now ...", strerror( errno ));
275                                 exit( 1 );
276                         }
277                         setsid( );
278                         chdir( "/" );
279                 }
280         
281                 /* Globale Variablen initialisieren */
282                 NGIRCd_Start = time( NULL );
283                 strftime( NGIRCd_StartStr, 64, "%a %b %d %Y at %H:%M:%S (%Z)", localtime( &NGIRCd_Start ));
284                 NGIRCd_Restart = FALSE;
285                 NGIRCd_Quit = FALSE;
286
287                 /* Module initialisieren */
288                 Log_Init( );
289                 Conf_Init( );
290                 Parse_Init( );
291                 IRC_Init( );
292                 Channel_Init( );
293                 Client_Init( );
294                 Conn_Init( );
295
296                 /* Signal-Handler initialisieren */
297                 Initialize_Signal_Handler( );
298
299                 /* Listen-Ports initialisieren */
300                 Initialize_Listen_Ports( );
301
302                 /* Hauptschleife */
303                 while( TRUE )
304                 {
305                         if( NGIRCd_Quit || NGIRCd_Restart ) break;
306                         Conn_Handler( 5 );
307                 }
308
309                 /* Alles abmelden */
310                 Conn_Exit( );
311                 Client_Exit( );
312                 Channel_Exit( );
313                 IRC_Exit( );
314                 Parse_Exit( );
315                 Conf_Exit( );
316                 Log_Exit( );
317         }
318         return 0;
319 } /* main */
320
321
322 GLOBAL CHAR *NGIRCd_Version( VOID )
323 {
324         STATIC CHAR version[126];
325
326         sprintf( version, PACKAGE" version "VERSION"-%s", NGIRCd_VersionAddition( ));
327         return version;
328 } /* NGIRCd_Version */
329
330
331 GLOBAL CHAR *NGIRCd_VersionAddition( VOID )
332 {
333         STATIC CHAR txt[64];
334
335         strcpy( txt, "" );
336
337 #ifdef USE_SYSLOG
338         if( txt[0] ) strcat( txt, "+" );
339         strcat( txt, "SYSLOG" );
340 #endif
341 #ifdef STRICT_RFC
342         if( txt[0] ) strcat( txt, "+" );
343         strcat( txt, "RFC" );
344 #endif
345 #ifdef DEBUG
346         if( txt[0] ) strcat( txt, "+" );
347         strcat( txt, "DEBUG" );
348 #endif
349 #ifdef SNIFFER
350         if( txt[0] ) strcat( txt, "+" );
351         strcat( txt, "SNIFFER" );
352 #endif
353
354         if( txt[0] ) strcat( txt, "-" );
355         strcat( txt, P_OSNAME"/"P_ARCHNAME );
356
357         return txt;
358 } /* NGIRCd_VersionAddition */
359
360
361 LOCAL VOID Initialize_Signal_Handler( VOID )
362 {
363         /* Signal-Handler initialisieren: einige Signale
364          * werden ignoriert, andere speziell behandelt. */
365
366         struct sigaction saction;
367
368         /* Signal-Struktur initialisieren */
369         memset( &saction, 0, sizeof( saction ));
370         saction.sa_handler = Signal_Handler;
371         saction.sa_flags = SA_RESTART;
372
373         /* Signal-Handler einhaengen */
374         sigaction( SIGINT, &saction, NULL );
375         sigaction( SIGQUIT, &saction, NULL );
376         sigaction( SIGTERM, &saction, NULL);
377         sigaction( SIGHUP, &saction, NULL);
378         sigaction( SIGCHLD, &saction, NULL);
379
380         /* einige Signale ignorieren */
381         saction.sa_handler = SIG_IGN;
382         sigaction( SIGPIPE, &saction, NULL );
383 } /* Initialize_Signal_Handler */
384
385
386 LOCAL VOID Signal_Handler( INT Signal )
387 {
388         /* Signal-Handler. Dieser wird aufgerufen, wenn eines der Signale eintrifft,
389          * fuer das wir uns registriert haben (vgl. Initialize_Signal_Handler). Die
390          * Nummer des eingetroffenen Signals wird der Funktion uebergeben. */
391
392         switch( Signal )
393         {
394                 case SIGTERM:
395                 case SIGINT:
396                 case SIGQUIT:
397                         /* wir soll(t)en uns wohl beenden ... */
398                         if( Signal == SIGTERM ) Log( LOG_WARNING, "Got TERM signal, terminating now ..." );
399                         else if( Signal == SIGINT ) Log( LOG_WARNING, "Got INT signal, terminating now ..." );
400                         else if( Signal == SIGQUIT ) Log( LOG_WARNING, "Got QUIT signal, terminating now ..." );
401                         NGIRCd_Quit = TRUE;
402                         break;
403                 case SIGHUP:
404                         /* neu starten */
405                         Log( LOG_WARNING, "Got HUP signal, restarting now ..." );
406                         NGIRCd_Restart = TRUE;
407                         break;
408                 case SIGCHLD:
409                         /* Child-Prozess wurde beendet. Zombies vermeiden: */
410                         while( waitpid( -1, NULL, WNOHANG ) > 0);
411                         break;
412                 default:
413                         /* unbekanntes bzw. unbehandeltes Signal */
414                         Log( LOG_NOTICE, "Got signal %d! Ignored.", Signal );
415         }
416 } /* Signal_Handler */
417
418
419 LOCAL VOID Initialize_Listen_Ports( VOID )
420 {
421         /* Ports, auf denen der Server Verbindungen entgegennehmen
422          * soll, initialisieren */
423         
424         INT created, i;
425
426         created = 0;
427         for( i = 0; i < Conf_ListenPorts_Count; i++ )
428         {
429                 if( Conn_NewListener( Conf_ListenPorts[i] )) created++;
430                 else Log( LOG_ERR, "Can't listen on port %d!", Conf_ListenPorts[i] );
431         }
432
433         if( created < 1 )
434         {
435                 Log( LOG_ALERT, "Server isn't listening on a single port!" );
436                 Log( LOG_ALERT, PACKAGE" exiting due to fatal errors!" );
437                 exit( 1 );
438         }
439 } /* Initialize_Listen_Ports */
440
441
442 LOCAL VOID Show_Version( VOID )
443 {
444         puts( NGIRCd_Version( ));
445         puts( "Copyright (c)2001,2002 by Alexander Barton (alex@barton.de).\n" );
446         puts( "This is free software; see the source for copying conditions. There is NO" );
447         puts( "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." );
448 } /* Show_Version */
449
450
451 LOCAL VOID Show_Help( VOID )
452 {
453 #ifdef DEBUG
454         puts( "  -d, --debug       log extra debug messages" );
455 #endif
456         puts( "  -n, --nodaemon    don't fork and don't detatch from controlling terminal" );
457         puts( "  -p, --passive     disable automatic connections to other servers" );
458 #ifdef SNIFFER
459         puts( "  -s, --sniffer     enable network sniffer and display all IRC traffic" );
460 #endif
461         puts( "      --version     output version information and exit" );
462         puts( "      --help        display this help and exit" );
463 } /* Show_Help */
464
465
466 /* -eof- */