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