ae9b7a85eccd8cd3eb1769184de360e3e7afb273
[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.15 2004/10/19 19:23:00 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);
284           argv++, argc--;
285
286           while((argc) && (**argv != '-'))
287             {
288               queue_if(*argv);
289               argv++; argc--;
290             }
291
292           continue;
293         }
294       /*
295        * Set the hello interval to be used by olsrd.
296        * 
297        */
298       if (strcmp(*argv, "-hint") == 0) 
299         {
300           argv++, argc--;
301           sscanf(*argv,"%f", &default_ifcnf->hello_params.emission_interval);
302           default_ifcnf->hello_params.validity_time = default_ifcnf->hello_params.emission_interval * 3;
303           argv++, argc--;
304           continue;
305         }
306
307       /*
308        * Set the HNA interval to be used by olsrd.
309        * 
310        */
311       if (strcmp(*argv, "-hnaint") == 0) 
312         {
313           argv++, argc--;
314           sscanf(*argv,"%f", &default_ifcnf->hna_params.emission_interval);
315           default_ifcnf->hna_params.validity_time = default_ifcnf->hna_params.emission_interval * 3;
316           argv++, argc--;
317           continue;
318         }
319
320       /*
321        * Set the MID interval to be used by olsrd.
322        * 
323        */
324       if (strcmp(*argv, "-midint") == 0) 
325         {
326           argv++, argc--;
327           sscanf(*argv,"%f", &default_ifcnf->mid_params.emission_interval);
328           default_ifcnf->mid_params.validity_time = default_ifcnf->mid_params.emission_interval * 3;
329           argv++, argc--;
330           continue;
331         }
332
333       /*
334        * Set the tc interval to be used by olsrd.
335        * 
336        */
337       if (strcmp(*argv, "-tcint") == 0) 
338         {
339           argv++, argc--;
340           sscanf(*argv,"%f", &default_ifcnf->tc_params.emission_interval);
341           default_ifcnf->tc_params.validity_time = default_ifcnf->tc_params.emission_interval * 3;
342           argv++, argc--;
343           continue;
344         }
345
346       /*
347        * Set the tos bits to be used by olsrd.
348        * 
349        */
350       if (strcmp(*argv, "-tos") == 0) 
351         {
352           argv++, argc--;
353           sscanf(*argv,"%d",(int *)&olsr_cnf->tos);
354           argv++, argc--;
355           continue;
356         }
357
358
359       /*
360        * Set the polling interval to be used by olsrd.
361        */
362       if (strcmp(*argv, "-T") == 0) 
363         {
364           argv++, argc--;
365           sscanf(*argv,"%f",&olsr_cnf->pollrate);
366           argv++, argc--;
367           continue;
368         }
369
370
371       /*
372        * Should we display the contents of packages beeing sent?
373        */
374       if (strcmp(*argv, "-dispin") == 0) 
375         {
376           argv++, argc--;
377           disp_pack_in = 1;
378           continue;
379         }
380
381       /*
382        * Should we display the contents of incoming packages?
383        */
384       if (strcmp(*argv, "-dispout") == 0) 
385         {
386           argv++, argc--;
387           disp_pack_out = 1;
388           continue;
389         }
390
391
392       /*
393        * Should we set up and send on a IPC socket for the front-end?
394        */
395       if (strcmp(*argv, "-ipc") == 0) 
396         {
397           argv++, argc--;
398           olsr_cnf->open_ipc = 1;
399           continue;
400         }
401
402
403       /*
404        * Display link-layer info(experimental)
405        */
406       if (strcmp(*argv, "-llinfo") == 0) 
407         {
408           argv++, argc--;
409           llinfo = 1;
410           continue;
411         }
412
413       /*
414        * Use Internet gateway tunneling?
415        */
416       if (strcmp(*argv, "-tnl") == 0) 
417         {
418           argv++, argc--;
419           use_tunnel = 1;
420
421           continue;
422         }
423 #if 0
424
425       /*
426        * IPv6 multicast addr
427        */
428       if (strcmp(*argv, "-multi") == 0) 
429         {
430           argv++, argc--;
431           strncpy(ipv6_mult, *argv, 50);
432
433           argv++, argc--;
434
435           continue;
436         }
437 #endif
438
439       /*
440        * Should we display the contents of packages beeing sent?
441        */
442       if (strcmp(*argv, "-delgw") == 0) 
443         {
444           argv++, argc--;
445           del_gws = 1;
446           continue;
447         }
448
449
450       print_usage();
451       olsr_exit(__func__, EXIT_FAILURE);
452     }
453
454
455   /*
456    *Interfaces need to be specified
457    */
458   if(olsr_cnf->interfaces == NULL)
459     {
460       fprintf(stderr, "OLSRD: no interfaces specified!\nuse the -i switch to specify interface(s)\nor set interface(s) in the configuration file!\n");
461       print_usage();
462       olsr_exit(__func__, EXIT_FAILURE);
463     }
464
465   /*
466    *socket for icotl calls
467    */
468   if ((ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) 
469     {
470       olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
471       close(ioctl_s);
472       olsr_exit(__func__, 0);
473     }
474
475
476   /* Type of service */
477   precedence = IPTOS_PREC(olsr_cnf->tos);
478   tos_bits = IPTOS_TOS(olsr_cnf->tos);
479
480
481   /*
482    *enable ip forwarding on host
483    */
484   enable_ip_forwarding(olsr_cnf->ip_version);
485
486   /* Initialize scheduler MUST HAPPEN BEFORE REGISTERING ANY FUNCTIONS! */
487   init_scheduler(olsr_cnf->pollrate);
488
489   /* Initialize parser */
490   olsr_init_parser();
491
492   /* Initialize message sequencnumber */
493   init_msg_seqno();
494
495   /* Initialize dynamic willingness calculation */
496   olsr_init_willingness();
497
498   /* printout settings */
499   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);
500       
501   if(olsr_cnf->use_hysteresis)
502     {
503       olsr_printf(1, "hysteresis scaling factor = %0.2f\nhysteresis threshold high = %0.2f\nhysteresis threshold low  = %0.2f\n\n",
504                   olsr_cnf->hysteresis_param.scaling,
505                   olsr_cnf->hysteresis_param.thr_high,
506                   olsr_cnf->hysteresis_param.thr_low);
507
508       if(olsr_cnf->hysteresis_param.thr_high <= olsr_cnf->hysteresis_param.thr_low)
509         {
510           printf("Hysteresis threshold high lower than threshold low!!\nEdit the configuration file to fix this!\n\n");
511           olsr_exit(__func__, EXIT_FAILURE);
512         }
513     }
514
515   /*
516    *Set up willingness/APM
517    */
518   if(olsr_cnf->willingness_auto)
519     {
520       if(apm_init() < 0)
521         {
522           olsr_printf(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
523
524           olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
525
526           olsr_cnf->willingness_auto = 0;
527           olsr_cnf->willingness = WILL_DEFAULT;
528         }
529       else
530         {
531           olsr_cnf->willingness = olsr_calculate_willingness();
532
533           olsr_printf(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, will_int);
534         }
535     }
536
537   /**
538    *Set ipsize and minimum packetsize
539    */
540   if(olsr_cnf->ip_version == AF_INET6)
541     {
542       olsr_printf(1, "Using IP version 6\n");
543       ipsize = sizeof(struct in6_addr);
544
545       minsize = (int)sizeof(olsr_u8_t) * 7; /* Minimum packetsize IPv6 */
546     }
547   else
548     {
549       olsr_printf(1, "Using IP version 4\n");
550       ipsize = sizeof(olsr_u32_t);
551
552       minsize = (int)sizeof(olsr_u8_t) * 4; /* Minimum packetsize IPv4 */
553     }
554
555
556   /* Initializing networkinterfaces */
557
558   if(!ifinit())
559     {
560       if(olsr_cnf->allow_no_interfaces)
561         {
562           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");
563           sleep(5);
564         }
565       else
566         {
567           fprintf(stderr, "No interfaces detected!\nBailing out!\n");
568           olsr_exit(__func__, EXIT_FAILURE);
569         }
570     }
571
572
573   /* Initialize values for emission data 
574    * This also initiates message generation
575    */
576   /*
577   olsr_set_hello_interval(hello_int);
578   olsr_set_hello_nw_interval(hello_int_nw);
579   olsr_set_tc_interval(tc_int);
580   olsr_set_mid_interval(mid_int);
581   olsr_set_hna_interval(hna_int);
582   */
583   /* Print tables to stdout */
584   if(olsr_cnf->debug_level > 0)
585     olsr_register_scheduler_event(&generate_tabledisplay, NULL, HELLO_INTERVAL, 0, NULL);
586   
587   
588   gettimeofday(&now, NULL);
589
590
591   /* Initialize the IPC socket */
592
593   if(olsr_cnf->open_ipc)
594       ipc_init();
595
596 #ifndef WIN32
597   /* Initialize link-layer notifications */
598   if(llinfo)
599     init_link_layer_notification();
600 #endif
601
602   /* Initialisation of different tables to be used.*/
603   olsr_init_tables();
604
605   /* Load plugins */
606   olsr_load_plugins();
607
608   /* Set up recieving tunnel if Inet gw */
609   if(use_tunnel && check_inet_gw())
610     set_up_gw_tunnel(&main_addr);
611
612   olsr_printf(1, "Main address: %s\n\n", olsr_ip_to_string(&main_addr));
613
614   olsr_printf(1, "NEIGHBORS: l=linkstate, m=MPR, w=willingness\n\n");
615
616
617   /* daemon mode */
618 #ifndef WIN32
619   if (olsr_cnf->debug_level == 0)
620     {
621       printf("%s detattching from the current process...\n", SOFTWARE_VERSION);
622       if (fork() != 0)
623         {
624           exit(EXIT_SUCCESS);
625         }
626       setsid();
627     }
628 #endif
629   /* Starting scheduler */
630   start_scheduler(&thread);
631
632   /*
633    *signal-handlers
634    */
635
636   /* ctrl-C and friends */
637 #ifdef WIN32
638   SetConsoleCtrlHandler(SignalHandler, TRUE);
639 #else
640   signal(SIGINT, olsr_shutdown);  
641   signal(SIGTERM, olsr_shutdown);  
642 #endif
643
644   /* Go into listenloop */
645   listen_loop();
646
647   /* Like we're ever going to reach this ;-) */
648   return 1;
649
650 } /* main */
651
652
653
654
655
656
657 /**
658  *Function called at shutdown
659  *
660  */
661 #ifdef WIN32
662 int __stdcall
663 SignalHandler(unsigned long signal)
664 #else
665 void
666 olsr_shutdown(int signal)
667 #endif
668 {
669   struct interface *ifn;
670 #ifndef WIN32
671   if(main_thread != pthread_self())
672     {
673       pthread_exit(0);
674     }
675 #endif
676
677   olsr_printf(1, "Received signal %d - shutting down\n", signal);
678
679   olsr_delete_all_kernel_routes();
680
681   olsr_printf(1, "Closing sockets...\n");
682
683   /* front-end IPC socket */
684   if(olsr_cnf->open_ipc)
685     shutdown_ipc();
686
687   /* OLSR sockets */
688   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
689     close(ifn->olsr_socket);
690
691   /* Closing plug-ins */
692   olsr_close_plugins();
693
694   /* Reset network settings */
695   restore_settings(olsr_cnf->ip_version);
696
697   /* ioctl socket */
698   close(ioctl_s);
699
700   olsr_syslog(OLSR_LOG_INFO, "%s stopped", SOFTWARE_VERSION);
701
702   olsr_printf(1, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", SOFTWARE_VERSION);
703
704   exit(exit_value);
705 }
706
707
708
709
710
711 /**
712  *Sets the default values of variables at startup
713  */
714 static void
715 set_default_values()
716 {
717   memset(&main_addr, 0, sizeof(union olsr_ip_addr));
718   memset(&null_addr6, 0, sizeof (union olsr_ip_addr));
719
720   exit_value = EXIT_SUCCESS; 
721   /* If the application exits by signal it is concidered success,
722    * if not, exit_value is set by the function calling olsr_exit.
723    */
724
725   max_jitter = 0;
726   max_tc_vtime = 0;
727   dup_hold_time = DUP_HOLD_TIME;
728
729   sending_tc = 0;
730
731   will_int = 10 * HELLO_INTERVAL; /* Willingness update interval */
732
733   llinfo = 0;
734   del_gws = 0;
735
736 #ifndef WIN32
737   /* Get main thread ID */
738   main_thread = pthread_self();
739 #endif
740
741   /* Gateway tunneling */
742   use_tunnel = 0;
743   inet_tnl_added = 0;
744   gw_tunnel = 0;
745
746   /* Display packet content */
747   disp_pack_in = 0;
748   disp_pack_out = 0;
749 }
750
751
752
753
754 static void
755 print_usage()
756 {
757
758   fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n"); 
759   fprintf(stderr, "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n");
760   fprintf(stderr, "  [-d <debug_level>] [-ipv6] [-tnl] [-multi <IPv6 multicast address>]\n"); 
761   fprintf(stderr, "  [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n");
762   fprintf(stderr, "  [-midint <mid interval value (secs)>] [-hnaint <hna interval value (secs)>]\n");
763   fprintf(stderr, "  [-hint <hello interval value (secs)>] [-tcint <tc interval value (secs)>]\n");
764   fprintf(stderr, "  [-tos value (int)] [-T <Polling Rate (secs)>]\n"); 
765
766 }