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