New configfile parser and configuration scheme integrated
[olsrd.git] / src / main.c
1 /*
2  * OLSR ad-hoc routing table management protocol
3  * Copyright (C) 2004 Andreas T√łnnesen (andreto@ifi.uio.no)
4  *
5  * This file is part of the olsr.org OLSR daemon.
6  *
7  * olsr.org is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * olsr.org is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsr.org; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: main.c,v 1.14 2004/10/18 13:13:37 kattemat Exp $
23  *
24  */
25
26
27 #include "main.h"
28 #include "interfaces.h"
29 #include "configfile.h"
30 #include "mantissa.h"
31 #include "local_hna_set.h"
32 #include "olsr.h"
33 #include "scheduler.h"
34 #include "parser.h"
35 #include "generate_msg.h"
36 #include "plugin_loader.h"
37 #include "socket_parser.h"
38 #include "apm.h"
39 #include "link_layer.h"
40 #include "net_os.h"
41
42 #ifdef linux
43 #include "linux/tunnel.h"
44 #elif defined WIN32
45 #define close(x) closesocket(x)
46 #include "win32/tunnel.h"
47 int __stdcall SignalHandler(unsigned long signal);
48 void ListInterfaces(void);
49 #else
50 #       error "Unsupported system"
51 #endif
52
53 /*
54  * Begin: Local function prototypes
55  */
56
57 static void
58 print_usage(void);
59
60 static void
61 set_default_values(void);
62
63
64 /*
65  * End: Local function prototypes
66  */
67
68 /**
69  * Main entrypoint
70  */
71
72 int
73 main(int argc, char *argv[])
74 {
75
76   /* The thread for the scheduler */
77   pthread_t thread;
78
79   struct if_config_options *default_ifcnf;
80
81   struct stat statbuf;
82   char conf_file_name[FILENAME_MAX];
83   
84 #ifdef WIN32
85   WSADATA WsaData;
86   int len;
87 #endif
88
89   setbuf(stdout, NULL);
90   setbuf(stderr, NULL);
91
92   /* Initialize socket list */
93   olsr_socket_entries = NULL;
94
95 #ifndef WIN32
96   /* Check if user is root */
97   if(getuid() || getgid())
98     {
99       fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
100       exit(EXIT_FAILURE);
101     }
102 #else
103   if (WSAStartup(0x0202, &WsaData))
104     {
105       fprintf(stderr, "Could not initialize WinSock.\n");
106       olsr_exit(__func__, EXIT_FAILURE);
107     }
108 #endif
109
110   /* Open syslog */
111   olsr_openlog("olsrd");
112
113   /*
114    * Start syslog entry
115    */
116   olsr_syslog(OLSR_LOG_INFO, "%s started", SOFTWARE_VERSION);
117
118   /* Set default values */
119   set_default_values();
120
121   /* Initialize network functions */
122   init_net();
123
124   /* Initialize plugin loader */
125   olsr_init_plugin_loader();
126  
127   /* Get initial timestep */
128   nowtm = NULL;
129   while (nowtm == NULL)
130     {
131       nowtm = gmtime(&now.tv_sec);
132     }
133     
134   /* The port to use for OLSR traffic */
135   olsr_udp_port = htons(OLSRPORT);
136     
137   printf("\n *** %s ***\n Build date: %s\n http://www.olsr.org\n\n", 
138          SOFTWARE_VERSION, 
139          __DATE__);
140     
141   /* Using PID as random seed */
142   srandom(getpid());
143
144
145   /*
146    * Set configfile name and
147    * check if a configfile name was given as parameter
148    */
149 #ifdef WIN32
150   GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11);
151   
152   len = strlen(conf_file_name);
153   
154   if (conf_file_name[len - 1] != '\\')
155     conf_file_name[len++] = '\\';
156   
157   strcpy(conf_file_name + len, "olsrd.conf");
158 #else
159   strncpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, FILENAME_MAX);
160 #endif
161
162   if ((argc > 1) && (strcmp(argv[1], "-f") == 0)) 
163     {
164       argv++, argc--;
165       if(argc == 1)
166         {
167           fprintf(stderr, "You must provide a filename when using the -f switch!\n");
168           olsr_exit(__func__, EXIT_FAILURE);
169         }
170
171       if (stat(argv[1], &statbuf) < 0)
172         {
173           fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", argv[1], strerror(errno));
174           olsr_exit(__func__, EXIT_FAILURE);
175         }
176                  
177       strncpy(conf_file_name, argv[1], FILENAME_MAX);
178       argv++, argc--;
179
180     }
181
182   /*
183    * Reading configfile options prior to processing commandline options
184    */
185
186   if(read_config_file(conf_file_name) < 0)
187     {
188       fprintf(stderr, "Error parsing configig file %s!\n", conf_file_name);
189       exit(EXIT_FAILURE);
190     }
191
192   default_ifcnf = get_default_ifcnf(olsr_cnf);
193   
194   if(default_ifcnf == NULL)
195     {
196       fprintf(stderr, "No default ifconfig found!\n");
197       exit(EXIT_FAILURE);
198     }
199
200   /*
201    * Process olsrd options.
202    */
203   
204   argv++, argc--;
205   while (argc > 0 && **argv == '-')
206     {
207 #ifdef WIN32
208       /*
209        *Interface list
210        */
211       if (strcmp(*argv, "-int") == 0)
212         {
213           ListInterfaces();
214           exit(0);
215         }
216 #endif
217
218       /*
219        *Configfilename
220        */
221       if (strcmp(*argv, "-f") == 0) 
222         {
223           fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n");
224           olsr_exit(__func__, EXIT_FAILURE);
225         }
226
227       /*
228        *Use IP version 6
229        */
230       if (strcmp(*argv, "-ipv6") == 0) 
231         {
232           olsr_cnf->ip_version = AF_INET6;
233           argv++, argc--;
234           continue;
235         }
236
237 #if 0
238       /*
239        *Broadcast address
240        */
241       if (strcmp(*argv, "-bcast") == 0) 
242         {
243           argv++, argc--;
244           if(argc == 0)
245             {
246               fprintf(stderr, "You must provide a broadcastaddr when using the -bcast switch!\n");
247               olsr_exit(__func__, EXIT_FAILURE);
248             }
249
250           if (inet_aton(*argv, &in) == 0)
251             {
252               printf("Invalid broadcast address! %s\nSkipping it!\n", *argv);
253               continue;
254             }
255                  
256           memcpy(&bcastaddr.sin_addr, &in.s_addr, sizeof(olsr_u32_t));
257
258
259           continue;
260         }
261 #endif
262
263       /*
264        * Enable additional debugging information to be logged.
265        */
266       if (strcmp(*argv, "-d") == 0) 
267         {
268           argv++, argc--;
269           sscanf(*argv,"%d", &olsr_cnf->debug_level);
270           argv++, argc--;
271           continue;
272         }
273
274
275
276                 
277       /*
278        * Interfaces to be used by olsrd.
279        */
280       if (strcmp(*argv, "-i") == 0) 
281         {
282           argv++, argc--;
283           queue_if(*argv, default_ifcnf);
284           argv++, argc--;
285
286           while((argc) && (**argv != '-'))
287             {
288               queue_if(*argv, default_ifcnf);
289               argv++; argc--;
290             }
291
292           continue;
293         }
294
295       /*
296        * Set the hello interval to be used by olsrd.
297        * 
298        */
299       if (strcmp(*argv, "-hint") == 0) 
300         {
301           argv++, argc--;
302           sscanf(*argv,"%f", &default_ifcnf->hello_params.emission_interval);
303           default_ifcnf->hello_params.validity_time = default_ifcnf->hello_params.emission_interval * 3;
304           argv++, argc--;
305           continue;
306         }
307
308       /*
309        * Set the HNA interval to be used by olsrd.
310        * 
311        */
312       if (strcmp(*argv, "-hnaint") == 0) 
313         {
314           argv++, argc--;
315           sscanf(*argv,"%f", &default_ifcnf->hna_params.emission_interval);
316           default_ifcnf->hna_params.validity_time = default_ifcnf->hna_params.emission_interval * 3;
317           argv++, argc--;
318           continue;
319         }
320
321       /*
322        * Set the MID interval to be used by olsrd.
323        * 
324        */
325       if (strcmp(*argv, "-midint") == 0) 
326         {
327           argv++, argc--;
328           sscanf(*argv,"%f", &default_ifcnf->mid_params.emission_interval);
329           default_ifcnf->mid_params.validity_time = default_ifcnf->mid_params.emission_interval * 3;
330           argv++, argc--;
331           continue;
332         }
333
334       /*
335        * Set the tc interval to be used by olsrd.
336        * 
337        */
338       if (strcmp(*argv, "-tcint") == 0) 
339         {
340           argv++, argc--;
341           sscanf(*argv,"%f", &default_ifcnf->tc_params.emission_interval);
342           default_ifcnf->tc_params.validity_time = default_ifcnf->tc_params.emission_interval * 3;
343           argv++, argc--;
344           continue;
345         }
346
347       /*
348        * Set the tos bits to be used by olsrd.
349        * 
350        */
351       if (strcmp(*argv, "-tos") == 0) 
352         {
353           argv++, argc--;
354           sscanf(*argv,"%d",(int *)&olsr_cnf->tos);
355           argv++, argc--;
356           continue;
357         }
358
359
360       /*
361        * Set the polling interval to be used by olsrd.
362        */
363       if (strcmp(*argv, "-T") == 0) 
364         {
365           argv++, argc--;
366           sscanf(*argv,"%f",&olsr_cnf->pollrate);
367           argv++, argc--;
368           continue;
369         }
370
371
372       /*
373        * Should we display the contents of packages beeing sent?
374        */
375       if (strcmp(*argv, "-dispin") == 0) 
376         {
377           argv++, argc--;
378           disp_pack_in = 1;
379           continue;
380         }
381
382       /*
383        * Should we display the contents of incoming packages?
384        */
385       if (strcmp(*argv, "-dispout") == 0) 
386         {
387           argv++, argc--;
388           disp_pack_out = 1;
389           continue;
390         }
391
392
393       /*
394        * Should we set up and send on a IPC socket for the front-end?
395        */
396       if (strcmp(*argv, "-ipc") == 0) 
397         {
398           argv++, argc--;
399           olsr_cnf->open_ipc = 1;
400           continue;
401         }
402
403
404       /*
405        * Display link-layer info(experimental)
406        */
407       if (strcmp(*argv, "-llinfo") == 0) 
408         {
409           argv++, argc--;
410           llinfo = 1;
411           continue;
412         }
413
414       /*
415        * Use Internet gateway tunneling?
416        */
417       if (strcmp(*argv, "-tnl") == 0) 
418         {
419           argv++, argc--;
420           use_tunnel = 1;
421
422           continue;
423         }
424 #if 0
425
426       /*
427        * IPv6 multicast addr
428        */
429       if (strcmp(*argv, "-multi") == 0) 
430         {
431           argv++, argc--;
432           strncpy(ipv6_mult, *argv, 50);
433
434           argv++, argc--;
435
436           continue;
437         }
438 #endif
439
440       /*
441        * Should we display the contents of packages beeing sent?
442        */
443       if (strcmp(*argv, "-delgw") == 0) 
444         {
445           argv++, argc--;
446           del_gws = 1;
447           continue;
448         }
449
450
451       print_usage();
452       olsr_exit(__func__, EXIT_FAILURE);
453     }
454
455
456   /*
457    *Interfaces need to be specified
458    */
459   if(if_names == NULL)
460     {
461       fprintf(stderr, "OLSRD: no interfaces specified!\nuse the -i switch to specify interface(s)\nor set interface(s) in the configuration file!\n");
462       print_usage();
463       olsr_exit(__func__, EXIT_FAILURE);
464     }
465
466   /*
467    *socket for icotl calls
468    */
469   if ((ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) 
470     {
471       olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
472       close(ioctl_s);
473       olsr_exit(__func__, 0);
474     }
475
476
477   /* Type of service */
478   precedence = IPTOS_PREC(olsr_cnf->tos);
479   tos_bits = IPTOS_TOS(olsr_cnf->tos);
480
481
482   /*
483    *enable ip forwarding on host
484    */
485   enable_ip_forwarding(olsr_cnf->ip_version);
486
487   /* Initialize scheduler MUST HAPPEN BEFORE REGISTERING ANY FUNCTIONS! */
488   init_scheduler(olsr_cnf->pollrate);
489
490   /* Initialize parser */
491   olsr_init_parser();
492
493   /* Initialize message sequencnumber */
494   init_msg_seqno();
495
496   /* Initialize dynamic willingness calculation */
497   olsr_init_willingness();
498
499   /* printout settings */
500   olsr_printf(1, "\npolling interval = %0.2f \ntos setting = %d \ntc_redunadancy = %d\nmpr coverage = %d\n", olsr_cnf->pollrate, olsr_cnf->tos, olsr_cnf->tc_redundancy, olsr_cnf->mpr_coverage);
501       
502   if(olsr_cnf->use_hysteresis)
503     {
504       olsr_printf(1, "hysteresis scaling factor = %0.2f\nhysteresis threshold high = %0.2f\nhysteresis threshold low  = %0.2f\n\n",
505                   olsr_cnf->hysteresis_param.scaling,
506                   olsr_cnf->hysteresis_param.thr_high,
507                   olsr_cnf->hysteresis_param.thr_low);
508
509       if(olsr_cnf->hysteresis_param.thr_high <= olsr_cnf->hysteresis_param.thr_low)
510         {
511           printf("Hysteresis threshold high lower than threshold low!!\nEdit the configuration file to fix this!\n\n");
512           olsr_exit(__func__, EXIT_FAILURE);
513         }
514     }
515
516   /*
517    *Set up willingness/APM
518    */
519   if(olsr_cnf->willingness_auto)
520     {
521       if(apm_init() < 0)
522         {
523           olsr_printf(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
524
525           olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
526
527           olsr_cnf->willingness_auto = 0;
528           olsr_cnf->willingness = WILL_DEFAULT;
529         }
530       else
531         {
532           olsr_cnf->willingness = olsr_calculate_willingness();
533
534           olsr_printf(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, will_int);
535         }
536     }
537
538   /**
539    *Set ipsize and minimum packetsize
540    */
541   if(olsr_cnf->ip_version == AF_INET6)
542     {
543       olsr_printf(1, "Using IP version 6\n");
544       ipsize = sizeof(struct in6_addr);
545
546       minsize = (int)sizeof(olsr_u8_t) * 7; /* Minimum packetsize IPv6 */
547     }
548   else
549     {
550       olsr_printf(1, "Using IP version 4\n");
551       ipsize = sizeof(olsr_u32_t);
552
553       minsize = (int)sizeof(olsr_u8_t) * 4; /* Minimum packetsize IPv4 */
554     }
555
556
557   /* Initializing networkinterfaces */
558
559   if(!ifinit())
560     {
561       if(olsr_cnf->allow_no_interfaces)
562         {
563           fprintf(stderr, "No interfaces detected! This might be intentional, but it also might mean that your configuration is fubar.\nI will continue after 5 seconds...\n");
564           sleep(5);
565         }
566       else
567         {
568           fprintf(stderr, "No interfaces detected!\nBailing out!\n");
569           olsr_exit(__func__, EXIT_FAILURE);
570         }
571     }
572
573
574   /* Initialize values for emission data 
575    * This also initiates message generation
576    */
577   /*
578   olsr_set_hello_interval(hello_int);
579   olsr_set_hello_nw_interval(hello_int_nw);
580   olsr_set_tc_interval(tc_int);
581   olsr_set_mid_interval(mid_int);
582   olsr_set_hna_interval(hna_int);
583   */
584   /* Print tables to stdout */
585   if(olsr_cnf->debug_level > 0)
586     olsr_register_scheduler_event(&generate_tabledisplay, NULL, HELLO_INTERVAL, 0, NULL);
587   
588   
589   gettimeofday(&now, NULL);
590
591
592   /* Initialize the IPC socket */
593
594   if(olsr_cnf->open_ipc)
595       ipc_init();
596
597 #ifndef WIN32
598   /* Initialize link-layer notifications */
599   if(llinfo)
600     init_link_layer_notification();
601 #endif
602
603   /* Initialisation of different tables to be used.*/
604   olsr_init_tables();
605
606   /* Load plugins */
607   olsr_load_plugins();
608
609   /* Set up recieving tunnel if Inet gw */
610   if(use_tunnel && inet_gw)
611     set_up_gw_tunnel(&main_addr);
612
613   olsr_printf(1, "Main address: %s\n\n", olsr_ip_to_string(&main_addr));
614
615   olsr_printf(1, "NEIGHBORS: l=linkstate, m=MPR, w=willingness\n\n");
616
617
618   /* daemon mode */
619 #ifndef WIN32
620   if (olsr_cnf->debug_level == 0)
621     {
622       printf("%s detattching from the current process...\n", SOFTWARE_VERSION);
623       if (fork() != 0)
624         {
625           exit(EXIT_SUCCESS);
626         }
627       setsid();
628     }
629 #endif
630   /* Starting scheduler */
631   start_scheduler(&thread);
632
633   /*
634    *signal-handlers
635    */
636
637   /* ctrl-C and friends */
638 #ifdef WIN32
639   SetConsoleCtrlHandler(SignalHandler, TRUE);
640 #else
641   signal(SIGINT, olsr_shutdown);  
642   signal(SIGTERM, olsr_shutdown);  
643 #endif
644
645   /* Go into listenloop */
646   listen_loop();
647
648   /* Like we're ever going to reach this ;-) */
649   return 1;
650
651 } /* main */
652
653
654
655
656
657
658 /**
659  *Function called at shutdown
660  *
661  */
662 #ifdef WIN32
663 int __stdcall
664 SignalHandler(unsigned long signal)
665 #else
666 void
667 olsr_shutdown(int signal)
668 #endif
669 {
670   struct interface *ifn;
671 #ifndef WIN32
672   if(main_thread != pthread_self())
673     {
674       pthread_exit(0);
675     }
676 #endif
677
678   olsr_printf(1, "Received signal %d - shutting down\n", signal);
679
680   olsr_delete_all_kernel_routes();
681
682   olsr_printf(1, "Closing sockets...\n");
683
684   /* front-end IPC socket */
685   if(olsr_cnf->open_ipc)
686     shutdown_ipc();
687
688   /* OLSR sockets */
689   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
690     close(ifn->olsr_socket);
691
692   /* Closing plug-ins */
693   olsr_close_plugins();
694
695   /* Reset network settings */
696   restore_settings(olsr_cnf->ip_version);
697
698   /* ioctl socket */
699   close(ioctl_s);
700
701   olsr_syslog(OLSR_LOG_INFO, "%s stopped", SOFTWARE_VERSION);
702
703   olsr_printf(1, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", SOFTWARE_VERSION);
704
705   exit(exit_value);
706 }
707
708
709
710
711
712 /**
713  *Sets the default values of variables at startup
714  */
715 static void
716 set_default_values()
717 {
718   memset(&main_addr, 0, sizeof(union olsr_ip_addr));
719   memset(&null_addr6, 0, sizeof (union olsr_ip_addr));
720
721   exit_value = EXIT_SUCCESS; 
722   /* If the application exits by signal it is concidered success,
723    * if not, exit_value is set by the function calling olsr_exit.
724    */
725
726   if_names = NULL;
727
728   max_jitter = 0;
729   max_tc_vtime = 0;
730   dup_hold_time = DUP_HOLD_TIME;
731
732   sending_tc = 0;
733
734   queued_ifs = 0;
735
736   will_int = 10 * HELLO_INTERVAL; /* Willingness update interval */
737
738   llinfo = 0;
739   del_gws = 0;
740
741 #ifndef WIN32
742   /* Get main thread ID */
743   main_thread = pthread_self();
744 #endif
745
746   /* local HNA set must be initialized before reading options */
747   olsr_init_local_hna_set();
748
749   /* Gateway tunneling */
750   use_tunnel = 0;
751   inet_tnl_added = 0;
752   gw_tunnel = 0;
753
754   /* Display packet content */
755   disp_pack_in = 0;
756   disp_pack_out = 0;
757 }
758
759
760
761
762 static void
763 print_usage()
764 {
765
766   fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n"); 
767   fprintf(stderr, "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n");
768   fprintf(stderr, "  [-d <debug_level>] [-ipv6] [-tnl] [-multi <IPv6 multicast address>]\n"); 
769   fprintf(stderr, "  [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n");
770   fprintf(stderr, "  [-midint <mid interval value (secs)>] [-hnaint <hna interval value (secs)>]\n");
771   fprintf(stderr, "  [-hint <hello interval value (secs)>] [-tcint <tc interval value (secs)>]\n");
772   fprintf(stderr, "  [-tos value (int)] [-T <Polling Rate (secs)>]\n"); 
773
774 }