6cbb513ba5dc445e5e06056a5a9757f036c0eaff
[sip-router] / main.c
1 /*
2  * $Id$
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <netdb.h>
11 #include <unistd.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <sys/utsname.h>
16 #include <sys/types.h>
17 #include <sys/mman.h>
18 #include <sys/fcntl.h>
19 #include <sys/time.h>
20
21 #include "config.h"
22 #include "dprint.h"
23 #include "route.h"
24 #include "udp_server.h"
25 #include "globals.h"
26 #include "mem.h"
27 #ifdef SHM_MEM
28 #include "shm_mem.h"
29 #endif
30 #include "sr_module.h"
31 #include "timer.h"
32
33
34 #include <signal.h>
35
36 #ifdef STATS
37 #include "stats.h"
38 #endif
39
40 #ifdef DEBUG_DMALLOC
41 #include <dmalloc.h>
42 #endif
43
44
45 static char id[]="@(#) $Id$";
46 static char version[]="ser 0.8.3.9";
47 static char flags[]=
48 "STATS:"
49 #ifdef STATS
50 "On"
51 #else
52 "Off"
53 #endif
54 #ifdef NO_DEBUG
55 ", NO_DEBUG"
56 #endif
57 #ifdef NO_LOG
58 ", NO_LOG"
59 #endif
60 #ifdef EXTRA_DEBUG
61 ", EXTRA_DEBUG"
62 #endif
63 #ifdef DNS_IP_HACK
64 ", DNS_IP_HACK"
65 #endif
66 #ifdef SHM_MEM
67 ", SHM_MEM"
68 #endif
69 #ifdef PKG_MALLOC
70 ", PKG_MALLOC"
71 #endif
72 #ifdef USE_SHM_MEM
73 ", USE_SHM_MEM"
74 #endif
75 #ifdef DBG_QM_MALLOC
76 ", DBG_QM_MALLOC"
77 #endif
78 #ifdef DEBUG_DMALLOC
79 ", DEBUG_DMALLOC"
80 #endif
81 ;
82
83 static char help_msg[]= "\
84 Usage: ser -l address [-l address] [options]\n\
85 Options:\n\
86     -c           Perform loop checks and compute branches\n\
87     -f file      Configuration file (default " CFG_FILE ")\n\
88     -p port      Listen on the specified port (default: 5060)\n\
89     -l address   Listen on the specified address (multiple -l mean\n\
90                  listening on more addresses). The default behaviour\n\
91                  is to listen on the addresses returned by uname(2)\n\
92 \n\
93     -n processes Number of child processes to fork per interface\n\
94                  (default: 8)\n\
95 \n\
96     -r           Use dns to check if is necessary to add a \"received=\"\n\
97                  field to a via\n\
98     -R           Same as `-r´ but use reverse dns;\n\
99                  (to use both use `-rR´)\n\
100 \n\
101     -v           Turn on \"via:\" host checking when forwarding replies\n\
102     -d           Debugging mode (multiple -d increase the level)\n\
103     -D           Do not fork into daemon mode\n\
104     -E           Log to stderr\n\
105     -V           Version number\n\
106     -h           This help message\n\
107     -b nr        Maximum receive buffer size which will not be exceeded by\n\
108                  auto-probing procedure even if  OS allows\n"
109 #ifdef STATS
110 "    -s file     File to which statistics is dumped (disabled otherwise)\n"
111 #endif
112 ;
113
114 /* print compile-time constants */
115 void print_ct_constants()
116 {
117         printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d, MAX_URI_SIZE %d\n",
118                 MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE );
119 }
120
121 /* debuging function */
122 /*
123 void receive_stdin_loop()
124 {
125         #define BSIZE 1024
126         char buf[BSIZE+1];
127         int len;
128         
129         while(1){
130                 len=fread(buf,1,BSIZE,stdin);
131                 buf[len+1]=0;
132                 receive_msg(buf, len);
133                 printf("-------------------------\n");
134         }
135 }
136 */
137
138 /* global vars */
139
140 char* cfg_file = 0;
141 unsigned short port_no = 0; /* port on which we listen */
142 char port_no_str[MAX_PORT_LEN];
143 int port_no_str_len=0;
144 unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed
145                                                 durig the auto-probing procedure; may be
146                                                 re-configured */
147 int children_no = 0;           /* number of children processing requests */
148 int debug = 0;
149 int dont_fork = 0;
150 int log_stderr = 0;
151 int check_via =  0;        /* check if reply first via host==us */
152 int loop_checks = 0;    /* calculate branches and check for loops/spirals */
153 int received_dns = 0;      /* use dns and/or rdns or to see if we need to 
154                               add a ;received=x.x.x.x to via: */
155
156 char* names[MAX_LISTEN];               /* our names */
157 int names_len[MAX_LISTEN];    /* lengths of the names*/
158 unsigned long addresses[MAX_LISTEN];   /* our ips */
159 int addresses_no=0;                    /* number of names/ips */
160
161 /* ipc related globals */
162 int process_no = 0;
163 #ifdef ROUTE_SRV
164 #endif
165
166 /* cfg parsing */
167 int cfg_errors=0;
168
169 #ifdef PKG_MALLOC
170 char mem_pool[PKG_MEM_POOL_SIZE];
171 struct qm_block* mem_block;
172 #endif
173
174
175 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
176                     (normally it shouldn't  be bigger  than 3) */
177
178
179 extern FILE* yyin;
180 extern int yyparse();
181
182
183 static int is_main=0; /* flag = is this the  "main" process? */
184
185 /* daemon init, return 0 on success, -1 on error */
186 int daemonize(char*  name)
187 {
188         pid_t pid;
189         int r;
190         
191         if (log_stderr==0)
192                 openlog(name, LOG_PID, LOG_DAEMON); /* LOG_CONS, LOG_PERRROR ? */
193
194         if (chdir("/")<0){
195                 LOG(L_CRIT,"cannot chroot:%s\n", strerror(errno));
196                 goto error;
197         }
198         
199         /* fork to become!= group leader*/
200         if ((pid=fork())<0){
201                 LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
202                 goto error;
203         }
204         if (pid!=0){
205                 /* parent process => exit*/
206                 exit(0);
207         }
208         /* become session leader to drop the ctrl. terminal */
209         if (setsid()<0){
210                 LOG(L_WARN, "setsid failed: %s\n",strerror(errno));
211         }
212         /* fork again to drop group  leadership */
213         if ((pid=fork())<0){
214                 LOG(L_CRIT, "Cannot  fork:%s\n", strerror(errno));
215                 goto error;
216         }
217         if (pid!=0){
218                 /*parent process => exit */
219                 exit(0);
220         }
221         
222         /* close any open file descriptors */
223         for (r=0;r<MAX_FD; r++){
224                 if ((r==3) && log_stderr)  continue;
225                 close(r);
226         }
227         return  0;
228
229 error:
230         return -1;
231 }
232
233
234
235 /* main loop */
236 int main_loop()
237 {
238         int r, i;
239         pid_t pid;
240
241         /* one "main" process and n children handling i/o */
242
243
244         if (dont_fork){
245 #ifdef STATS
246                 setstats( 0 );
247 #endif
248                 /* only one address */
249                 if (udp_init(addresses[0],port_no)==-1) goto error;
250
251                 /* we need another process to act as the timer*/
252                 if (timer_list){
253                                 if ((pid=fork())<0){
254                                         LOG(L_CRIT,  "main_loop: Cannot fork\n");
255                                         goto error;
256                                 }
257                                 if (pid==0){
258                                         /* child */
259                                         /* timer!*/
260                                         for(;;){
261                                                 sleep(TIMER_TICK);
262                                                 timer_ticker();
263                                         }
264                                 }
265                 }
266                 /* main process, receive loop */
267                 is_main=1;
268                 udp_rcv_loop();
269         }else{
270                 for(r=0;r<addresses_no;r++){
271                         /* create the listening socket (for each address)*/
272                         if (udp_init(addresses[r], port_no)==-1) goto error;
273                         for(i=0;i<children_no;i++){
274                                 if ((pid=fork())<0){
275                                         LOG(L_CRIT,  "main_loop: Cannot fork\n");
276                                         goto error;
277                                 }
278                                 if (pid==0){
279                                         /* child */
280 #ifdef STATS
281                                         setstats( i );
282 #endif
283                                         return udp_rcv_loop();
284                                 }
285                         }
286                         close(udp_sock); /*parent*/
287                 }
288         }
289         /*this is the main process*/
290         is_main=1;
291         if (timer_list){
292                 for(;;){
293                         /* debug:  instead of doing something usefull */
294                         /* (placeholder for timers, etc.) */
295                         sleep(TIMER_TICK);
296                         /* if we received a signal => TIMER_TICK may have not elapsed*/
297                         timer_ticker();
298                 }
299         }else{
300                 for(;;) sleep(LONG_SLEEP);
301         }
302         
303         return 0;
304  error:
305         return -1;
306
307 }
308
309
310 /* added by jku; allows for regular exit on a specific signal;
311    good for profiling which only works if exited regularly and
312    not by default signal handlers
313 */      
314
315 static void sig_usr(int signo)
316 {
317         DPrint("INT received, program terminates\n");
318         if (signo==SIGINT) {    /* exit gracefuly */
319 #ifdef STATS
320                 /* print statistics on exit only for the first process */
321
322                 if (stats->process_index==0 && stat_file )
323                         if (dump_all_statistic()==0)
324                                 printf("statistic dumped to %s\n", stat_file );
325                         else
326                                 printf("statistics dump to %s failed\n", stat_file );
327 #endif
328                 /* WARNING: very dangerous, might be unsafe*/
329                 if (is_main)
330                         destroy_modules();
331 #ifdef PKG_MALLOC
332                 LOG(L_INFO, "Memory status (pkg):\n");
333                 pkg_status();
334 #endif
335 #ifdef SHM_MEM
336                 if (is_main){
337                         LOG(L_INFO, "Memory status (shm):\n");
338                         shm_status();
339                 }
340 #endif
341 #ifdef SHM_MEM
342                 if (is_main)
343                         shm_mem_destroy();
344 #endif
345                 goto bye;
346         } else if (signo==SIGUSR1) { /* statistic */
347 #ifdef STATS
348                 dump_all_statistic();
349 #endif
350 #ifdef PKG_MALLOC
351                 LOG(L_INFO, "Memory status (pkg):\n");
352                 pkg_status();
353 #endif
354 #ifdef SHM_MEM
355                 LOG(L_INFO, "Memory status (shm):\n");
356                 shm_status();
357 #endif
358         }
359 bye:
360         DPrint("Thank you for flying ser\n");
361         exit(0);
362 }
363
364
365
366 int main(int argc, char** argv)
367 {
368
369         FILE* cfg_stream;
370         struct hostent* he;
371         int c,r;
372         char *tmp;
373         struct utsname myname;
374         char *options;
375
376         /* added by jku: add exit handler */
377         if (signal(SIGINT, sig_usr) == SIG_ERR ) {
378                 DPrint("ERROR: no SIGINT signal handler can be installed\n");
379                 goto error;
380         }
381
382         if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
383                 DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
384                 goto error;
385         }
386
387
388         /* process command line (get port no, cfg. file path etc) */
389         opterr=0;
390         options=
391 #ifdef STATS
392         "s:"
393 #endif
394         "f:p:b:l:n:rRvcdDEVh";
395         
396         while((c=getopt(argc,argv,options))!=-1){
397                 switch(c){
398                         case 'f':
399                                         cfg_file=optarg;
400                                         break;
401                         case 's':
402                                 #ifdef STATS
403                                         stat_file=optarg;
404                                 #endif
405                                         break;
406                         case 'p':
407                                         port_no=strtol(optarg, &tmp, 10);
408                                         if (tmp &&(*tmp)){
409                                                 fprintf(stderr, "bad port number: -p %s\n", optarg);
410                                                 goto error;
411                                         }
412                                         break;
413
414                         case 'b':
415                                         maxbuffer=strtol(optarg, &tmp, 10);
416                                         if (tmp &&(*tmp)){
417                                                 fprintf(stderr, "bad max buffer size number: -p %s\n", optarg);
418                                                 goto error;
419                                         }
420                                         break;
421                         case 'l':
422                                         /* add a new addr. to out address list */
423                                         if (addresses_no < MAX_LISTEN){
424                                                 names[addresses_no]=(char*)malloc(strlen(optarg)+1);
425                                                 if (names[addresses_no]==0){
426                                                         fprintf(stderr, "Out of memory.\n");
427                                                         goto error;
428                                                 }
429                                                 strncpy(names[addresses_no], optarg, strlen(optarg)+1);
430                                                 addresses_no++;
431                                         }else{
432                                                 fprintf(stderr, 
433                                                                         "Too many addresses (max. %d).\n",
434                                                                         MAX_LISTEN);
435                                                 goto error;
436                                         }
437                                         break;
438                         case 'n':
439                                         children_no=strtol(optarg, &tmp, 10);
440                                         if ((tmp==0) ||(*tmp)){
441                                                 fprintf(stderr, "bad process number: -n %s\n", optarg);
442                                                 goto error;
443                                         }
444                                         break;
445                         case 'v':
446                                         check_via=1;
447                                         break;
448                         case 'c':
449                                         loop_checks=1;
450                                         break;
451                         case 'r':
452                                         received_dns|=DO_DNS;
453                                         break;
454                         case 'R':
455                                         received_dns|=DO_REV_DNS;
456                         case 'd':
457                                         debug++;
458                                         break;
459                         case 'D':
460                                         dont_fork=1;
461                                         break;
462                         case 'E':
463                                         log_stderr=1;
464                                         break;
465                         case 'V':
466                                         printf("version: %s\n", version);
467                                         printf("flags: %s\n", flags );
468                                         print_ct_constants();
469                                         printf("%s\n",id);
470                                         exit(0);
471                                         break;
472                         case 'h':
473                                         printf("version: %s\n", version);
474                                         printf("%s",help_msg);
475                                         exit(0);
476                                         break;
477                         case '?':
478                                         if (isprint(optopt))
479                                                 fprintf(stderr, "Unknown option `-%c´.\n", optopt);
480                                         else
481                                                 fprintf(stderr, 
482                                                                 "Unknown option character `\\x%x´.\n",
483                                                                 optopt);
484                                         goto error;
485                         case ':':
486                                         fprintf(stderr, 
487                                                                 "Option `-%c´ requires an argument.\n",
488                                                                 optopt);
489                                         goto error;
490                         default:
491                                         abort();
492                 }
493         }
494         
495         /* fill missing arguments with the default values*/
496         if (cfg_file==0) cfg_file=CFG_FILE;
497
498         /* load config file or die */
499         cfg_stream=fopen (cfg_file, "r");
500         if (cfg_stream==0){
501                 fprintf(stderr, "ERROR: loading config file(%s): %s\n", cfg_file,
502                                 strerror(errno));
503                 goto error;
504         }
505
506         /*init mallocs (before parsing cfg !)*/
507 #ifdef PKG_MALLOC
508         /*init mem*/
509         mem_block=qm_malloc_init(mem_pool, PKG_MEM_POOL_SIZE);
510         if (mem_block==0){
511                 LOG(L_CRIT, "could not initialize memory pool\n");
512                 goto error;
513         }
514 #endif
515
516 #ifdef SHM_MEM
517         if (shm_mem_init()==-1) {
518                 LOG(L_CRIT, "could not initialize shared memory pool, exiting...\n");
519                 goto error;
520         }
521 #endif
522
523         yyin=cfg_stream;
524         if ((yyparse()!=0)||(cfg_errors)){
525                 fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
526                 goto error;
527         }
528         
529         
530         print_rl();
531         /* fix routing lists */
532         if ( (r=fix_rls())!=0){
533                 fprintf(stderr, "ERROR: error %x while trying to fix configuration\n",
534                                                 r);
535                 goto error;
536         };
537
538         /* fix parameters */
539         if (port_no<=0) port_no=SIP_PORT;
540         port_no_str_len=snprintf(port_no_str, MAX_PORT_LEN, ":%d", 
541                                 (unsigned short) port_no);
542         if (port_no_str_len<0){
543                 fprintf(stderr, "ERROR: bad port number: %d\n", port_no);
544                 goto error;
545         }
546         /* on some system snprintf return really strange things if it does not have
547          * enough space */
548         port_no_str_len=
549                                 (port_no_str_len<MAX_PORT_LEN)?port_no_str_len:MAX_PORT_LEN;
550
551         
552         if (children_no<=0) children_no=CHILD_NO;
553         if (addresses_no==0) {
554                 /* get our address, only the first one */
555                 if (uname (&myname) <0){
556                         fprintf(stderr, "cannot determine hostname, try -l address\n");
557                         goto error;
558                 }
559                 names[addresses_no]=(char*)malloc(strlen(myname.nodename)+1);
560                 if (names[addresses_no]==0){
561                         fprintf(stderr, "Out of memory.\n");
562                         goto error;
563                 }
564                 strncpy(names[addresses_no], myname.nodename,
565                                 strlen(myname.nodename)+1);
566                 addresses_no++;
567         }
568
569         /*get name lens*/
570         for(r=0; r<addresses_no; r++){
571                 names_len[r]=strlen(names[r]);
572         }
573
574         
575         /* get ips */
576         printf("Listening on ");
577         for (r=0; r<addresses_no;r++){
578                 he=gethostbyname(names[r]);
579                 if (he==0){
580                         DPrint("ERROR: could not resolve %s\n", names[r]);
581                         goto error;
582                 }
583                 addresses[r]=*((long*)he->h_addr_list[0]);
584                 printf("%s [%s] : %d\n",names[r],
585                                 inet_ntoa(*(struct in_addr*)&addresses[r]),
586                                 (unsigned short)port_no);
587         }
588
589 #ifdef STATS
590         if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
591 #endif
592
593         
594         /* init_daemon? */
595         if (!dont_fork){
596                 if ( daemonize(argv[0]) <0 ) goto error;
597         }
598
599         return main_loop();
600
601
602 error:
603         return -1;
604
605 }