2a8d4c25c54c2ae46bec4e22daabde4a503bd4be
[olsrd.git] / src / main.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  * $Id: main.c,v 1.59 2005/01/29 23:45:26 kattemat Exp $
41  */
42
43 #include <unistd.h>
44 #include <signal.h>
45 #include <sys/stat.h>
46
47 #include "defs.h"
48 #include "interfaces.h"
49 #include "local_hna_set.h"
50 #include "scheduler.h"
51 #include "parser.h"
52 #include "generate_msg.h"
53 #include "plugin_loader.h"
54 #include "socket_parser.h"
55 #include "apm.h"
56 #include "link_layer.h"
57 #include "net_os.h"
58
59 #ifdef WIN32
60 #define close(x) closesocket(x)
61 int __stdcall SignalHandler(unsigned long signal);
62 void ListInterfaces(void);
63 void DisableIcmpRedirects(void);
64 #else
65 static void
66 olsr_shutdown(int);
67 #endif
68
69 /*
70  * Local function prototypes
71  */
72 void
73 olsr_reconfigure(int);
74
75 static void
76 print_usage(void);
77
78 static void
79 set_default_values(void);
80
81 static int
82 set_default_ifcnfs(struct olsr_if *, struct if_config_options *);
83
84 static char **olsr_argv;
85
86 static char copyright_string[] = "The olsr.org Optimized Link-State Routing daemon(olsrd) Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org) All rights reserved.";
87
88 /**
89  * Main entrypoint
90  */
91
92 int
93 main(int argc, char *argv[])
94 {
95   struct if_config_options *default_ifcnf;
96   char conf_file_name[FILENAME_MAX];
97   struct tms tms_buf;
98
99   olsr_argv = argv;
100
101 #ifdef WIN32
102   WSADATA WsaData;
103   int len;
104 #endif
105
106   setbuf(stdout, NULL);
107   setbuf(stderr, NULL);
108
109 #ifndef WIN32
110   /* Initialize tick resolution */
111   system_tick_divider = 1000/sysconf(_SC_CLK_TCK);
112
113   /* Check if user is root */
114   if(getuid() || getgid())
115     {
116       fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
117       exit(EXIT_FAILURE);
118     }
119 #else
120   system_tick_divider = 1;
121
122   DisableIcmpRedirects();
123
124   if (WSAStartup(0x0202, &WsaData))
125     {
126       fprintf(stderr, "Could not initialize WinSock.\n");
127       olsr_exit(__func__, EXIT_FAILURE);
128     }
129 #endif
130
131   /* Grab initial timestamp */
132   now_times = times(&tms_buf);
133
134   /* Open syslog */
135   olsr_openlog("olsrd");
136
137   /* Set default values */
138   set_default_values();
139  
140   /* Get initial timestep */
141   nowtm = NULL;
142   while (nowtm == NULL)
143     {
144       nowtm = gmtime((time_t *)&now.tv_sec);
145     }
146     
147   /* The port to use for OLSR traffic */
148   olsr_udp_port = htons(OLSRPORT);
149     
150   printf("\n *** %s ***\n Build date: %s\n http://www.olsr.org\n\n", 
151          SOFTWARE_VERSION, 
152          __DATE__);
153     
154   /* Using PID as random seed */
155   srandom(getpid());
156
157
158   /*
159    * Set configfile name and
160    * check if a configfile name was given as parameter
161    */
162 #ifdef WIN32
163   GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11);
164   
165   len = strlen(conf_file_name);
166   
167   if (conf_file_name[len - 1] != '\\')
168     conf_file_name[len++] = '\\';
169   
170   strcpy(conf_file_name + len, "olsrd.conf");
171 #else
172   strncpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, FILENAME_MAX);
173 #endif
174
175   if ((argc > 1) && (strcmp(argv[1], "-f") == 0)) 
176     {
177       struct stat statbuf;
178
179       argv++; argc--;
180       if(argc == 1)
181         {
182           fprintf(stderr, "You must provide a filename when using the -f switch!\n");
183           exit(EXIT_FAILURE);
184         }
185
186       if (stat(argv[1], &statbuf) < 0)
187         {
188           fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", argv[1], strerror(errno));
189           exit(EXIT_FAILURE);
190         }
191                  
192       strncpy(conf_file_name, argv[1], FILENAME_MAX);
193       argv++; argc--;
194
195     }
196
197   /*
198    * set up configuration prior to processing commandline options
199    */
200   if((olsr_cnf = olsrd_parse_cnf(conf_file_name)) == NULL)
201     {
202       printf("Using default config values(no configfile)\n");
203       olsr_cnf = olsrd_get_default_cnf();
204     }
205   if((default_ifcnf = get_default_if_config()) == NULL)
206     {
207       fprintf(stderr, "No default ifconfig found!\n");
208       exit(EXIT_FAILURE);
209     }
210
211   /*
212    * Process olsrd options.
213    */
214   
215   argv++; argc--;
216   while (argc > 0 && **argv == '-')
217     {
218 #ifdef WIN32
219       /*
220        *Interface list
221        */
222       if (strcmp(*argv, "-int") == 0)
223         {
224           ListInterfaces();
225           exit(0);
226         }
227 #endif
228
229       /*
230        *Configfilename
231        */
232       if(strcmp(*argv, "-f") == 0) 
233         {
234           fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n");
235           olsr_exit(__func__, EXIT_FAILURE);
236         }
237
238       /*
239        *Use IP version 6
240        */
241       if(strcmp(*argv, "-ipv6") == 0) 
242         {
243           olsr_cnf->ip_version = AF_INET6;
244           argv++; argc--;
245           continue;
246         }
247
248       /*
249        *Broadcast address
250        */
251       if(strcmp(*argv, "-bcast") == 0) 
252         {
253           struct in_addr in;
254
255           argv++; argc--;
256           if(!argc)
257             {
258               fprintf(stderr, "You must provide a broadcastaddr when using the -bcast switch!\n");
259               olsr_exit(__func__, EXIT_FAILURE);
260             }
261           if (inet_aton(*argv, &in) == 0)
262             {
263               printf("Invalid broadcast address! %s\nSkipping it!\n", *argv);
264               continue;
265             }
266           memcpy(&default_ifcnf->ipv4_broadcast.v4, &in.s_addr, sizeof(olsr_u32_t));  
267           continue;
268         }
269       
270       /*
271        * Enable additional debugging information to be logged.
272        */
273       if (strcmp(*argv, "-d") == 0) 
274         {
275           argv++; argc--;
276           sscanf(*argv,"%d", &olsr_cnf->debug_level);
277           argv++; argc--;
278           continue;
279         }
280
281                 
282       /*
283        * Interfaces to be used by olsrd.
284        */
285       if (strcmp(*argv, "-i") == 0) 
286         {
287           argv++; argc--;
288           if(!argc || (*argv[0] == '-'))
289             {
290               fprintf(stderr, "You must provide an interface label!\n");
291               olsr_exit(__func__, EXIT_FAILURE);
292             }
293
294           queue_if(*argv);
295           argv++; argc--;
296
297           while((argc) && (**argv != '-'))
298             {
299               queue_if(*argv);
300               argv++; argc--;
301             }
302
303           continue;
304         }
305       /*
306        * Set the hello interval to be used by olsrd.
307        * 
308        */
309       if (strcmp(*argv, "-hint") == 0) 
310         {
311           argv++; argc--;
312           sscanf(*argv,"%f", &default_ifcnf->hello_params.emission_interval);
313           default_ifcnf->hello_params.validity_time = default_ifcnf->hello_params.emission_interval * 3;
314           argv++; argc--;
315           continue;
316         }
317
318       /*
319        * Set the HNA interval to be used by olsrd.
320        * 
321        */
322       if (strcmp(*argv, "-hnaint") == 0) 
323         {
324           argv++; argc--;
325           sscanf(*argv,"%f", &default_ifcnf->hna_params.emission_interval);
326           default_ifcnf->hna_params.validity_time = default_ifcnf->hna_params.emission_interval * 3;
327           argv++; argc--;
328           continue;
329         }
330
331       /*
332        * Set the MID interval to be used by olsrd.
333        * 
334        */
335       if (strcmp(*argv, "-midint") == 0) 
336         {
337           argv++; argc--;
338           sscanf(*argv,"%f", &default_ifcnf->mid_params.emission_interval);
339           default_ifcnf->mid_params.validity_time = default_ifcnf->mid_params.emission_interval * 3;
340           argv++; argc--;
341           continue;
342         }
343
344       /*
345        * Set the tc interval to be used by olsrd.
346        * 
347        */
348       if (strcmp(*argv, "-tcint") == 0) 
349         {
350           argv++; argc--;
351           sscanf(*argv,"%f", &default_ifcnf->tc_params.emission_interval);
352           default_ifcnf->tc_params.validity_time = default_ifcnf->tc_params.emission_interval * 3;
353           argv++; argc--;
354           continue;
355         }
356
357       /*
358        * Set the polling interval to be used by olsrd.
359        */
360       if (strcmp(*argv, "-T") == 0) 
361         {
362           argv++; argc--;
363           sscanf(*argv,"%f",&olsr_cnf->pollrate);
364           argv++; argc--;
365           continue;
366         }
367
368
369       /*
370        * Should we display the contents of packages beeing sent?
371        */
372       if (strcmp(*argv, "-dispin") == 0) 
373         {
374           argv++; argc--;
375           disp_pack_in = OLSR_TRUE;
376           continue;
377         }
378
379       /*
380        * Should we display the contents of incoming packages?
381        */
382       if (strcmp(*argv, "-dispout") == 0) 
383         {
384           argv++; argc--;
385           disp_pack_out = OLSR_TRUE;
386           continue;
387         }
388
389
390       /*
391        * Should we set up and send on a IPC socket for the front-end?
392        */
393       if (strcmp(*argv, "-ipc") == 0) 
394         {
395           argv++; argc--;
396           olsr_cnf->ipc_connections = 1;
397           olsr_cnf->open_ipc = OLSR_TRUE;
398           continue;
399         }
400
401
402       /*
403        * Display link-layer info(experimental)
404        */
405       if (strcmp(*argv, "-llinfo") == 0) 
406         {
407           argv++; argc--;
408           llinfo = OLSR_TRUE;
409           continue;
410         }
411
412       /*
413        * IPv6 multicast addr
414        */
415       if (strcmp(*argv, "-multi") == 0) 
416         {
417           struct in6_addr in6;
418
419           argv++; argc--;
420           if(inet_pton(AF_INET6, *argv, &in6) < 0)
421             {
422               fprintf(stderr, "Failed converting IP address %s\n", *argv);
423               exit(EXIT_FAILURE);
424             }
425
426           memcpy(&default_ifcnf->ipv6_multi_glbl, &in6, sizeof(struct in6_addr));
427
428           argv++; argc--;
429
430           continue;
431         }
432
433
434       /*
435        * Delete possible default GWs
436        */
437       if (strcmp(*argv, "-delgw") == 0) 
438         {
439           argv++; argc--;
440           del_gws = OLSR_TRUE;
441           continue;
442         }
443
444
445       print_usage();
446       olsr_exit(__func__, EXIT_FAILURE);
447     }
448
449   /*
450    * Set configuration for command-line specified interfaces
451    */
452   set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf);
453
454   /* Sanity check configuration */
455   if(olsrd_sanity_check_cnf(olsr_cnf) < 0)
456     {
457       fprintf(stderr, "Bad configuration!\n");
458       olsr_exit(__func__, EXIT_FAILURE);      
459     }
460
461   /*
462    * Print configuration 
463    */
464   olsrd_print_cnf(olsr_cnf);  
465
466   /*
467    *socket for icotl calls
468    */
469   if ((ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) 
470
471     {
472       olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
473       olsr_exit(__func__, 0);
474     }
475
476 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__
477   if ((rts = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
478     {
479       olsr_syslog(OLSR_LOG_ERR, "routing socket: %m");
480       olsr_exit(__func__, 0);
481     }
482 #endif
483
484   /*
485    *enable ip forwarding on host
486    */
487   enable_ip_forwarding(olsr_cnf->ip_version);
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   /*
499    *Set up willingness/APM
500    */
501   if(olsr_cnf->willingness_auto)
502     {
503       if(apm_init() < 0)
504         {
505           olsr_printf(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
506
507           olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
508
509           olsr_cnf->willingness_auto = 0;
510           olsr_cnf->willingness = WILL_DEFAULT;
511         }
512       else
513         {
514           olsr_cnf->willingness = olsr_calculate_willingness();
515
516           olsr_printf(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, will_int);
517         }
518     }
519
520   /* Set ipsize and minimum packetsize */
521   if(olsr_cnf->ip_version == AF_INET6)
522     {
523       olsr_printf(1, "Using IP version 6\n");
524       ipsize = sizeof(struct in6_addr);
525
526       minsize = (int)sizeof(olsr_u8_t) * 7; /* Minimum packetsize IPv6 */
527     }
528   else
529     {
530       olsr_printf(1, "Using IP version 4\n");
531       ipsize = sizeof(olsr_u32_t);
532
533       minsize = (int)sizeof(olsr_u8_t) * 4; /* Minimum packetsize IPv4 */
534     }
535
536
537   /* Initializing networkinterfaces */
538
539   if(!ifinit())
540     {
541       if(olsr_cnf->allow_no_interfaces)
542         {
543           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");
544           sleep(5);
545         }
546       else
547         {
548           fprintf(stderr, "No interfaces detected!\nBailing out!\n");
549           olsr_exit(__func__, EXIT_FAILURE);
550         }
551     }
552
553   /* Print heartbeat to stdout */
554
555   if(olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO))
556     olsr_register_scheduler_event(&generate_stdout_pulse, NULL, STDOUT_PULSE_INT, 0, NULL);
557   
558   gettimeofday(&now, NULL);
559
560
561   /* Initialize the IPC socket */
562
563   if(olsr_cnf->open_ipc)
564       ipc_init();
565
566 #ifdef linux
567   /* Initialize link-layer notifications */
568   if(llinfo)
569     init_link_layer_notification();
570 #endif
571
572   /* Initialisation of different tables to be used.*/
573   olsr_init_tables();
574
575   /* daemon mode */
576 #ifndef WIN32
577   if (olsr_cnf->debug_level == 0)
578     {
579       printf("%s detattching from the current process...\n", SOFTWARE_VERSION);
580       if (fork() != 0)
581         {
582           exit(EXIT_SUCCESS);
583         }
584       setsid();
585     }
586 #endif
587
588   /* Load plugins */
589   olsr_load_plugins();
590
591   olsr_printf(1, "Main address: %s\n\n", olsr_ip_to_string(&main_addr));
592
593
594   /* Start syslog entry */
595   olsr_syslog(OLSR_LOG_INFO, "%s successfully started", SOFTWARE_VERSION);
596
597   /*
598    *signal-handlers
599    */
600
601   /* ctrl-C and friends */
602 #ifdef WIN32
603   SetConsoleCtrlHandler(SignalHandler, OLSR_TRUE);
604 #else
605   signal(SIGHUP, olsr_reconfigure);  
606   signal(SIGINT, olsr_shutdown);  
607   signal(SIGTERM, olsr_shutdown);  
608 #endif
609
610   /* Register socket poll event */
611   olsr_register_timeout_function(&poll_sockets);
612
613   /* Starting scheduler */
614   scheduler();
615
616   /* Stop the compiler from complaining */
617   strlen(copyright_string);
618
619   /* Like we're ever going to reach this ;-) */
620   return 1;
621
622 } /* main */
623
624
625
626 /**
627  * Reconfigure olsrd. Currently kind of a hack...
628  *
629  *@param signal the signal that triggered this callback
630  */
631 #ifndef WIN32
632 void
633 olsr_reconfigure(int signal)
634 {
635   if(!fork())
636     {
637       /* New process */
638       sleep(3);
639       printf("Restarting %s\n", olsr_argv[0]);
640       execv(olsr_argv[0], olsr_argv);
641     }
642   olsr_shutdown(0);
643
644   printf("RECONFIGURING!\n");
645 }
646 #endif
647
648
649 /**
650  *Function called at shutdown. Signal handler
651  *
652  * @param signal the signal that triggered this call
653  */
654 #ifdef WIN32
655 int __stdcall
656 SignalHandler(unsigned long signal)
657 #else
658 static void
659 olsr_shutdown(int signal)
660 #endif
661 {
662   struct interface *ifn;
663
664   olsr_printf(1, "Received signal %d - shutting down\n", signal);
665
666   olsr_delete_all_kernel_routes();
667
668   olsr_printf(1, "Closing sockets...\n");
669
670   /* front-end IPC socket */
671   if(olsr_cnf->open_ipc)
672     shutdown_ipc();
673
674   /* OLSR sockets */
675   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
676     close(ifn->olsr_socket);
677
678   /* Closing plug-ins */
679   olsr_close_plugins();
680
681   /* Reset network settings */
682   restore_settings(olsr_cnf->ip_version);
683
684   /* ioctl socket */
685   close(ioctl_s);
686
687 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__
688   /* routing socket */
689   close(rts);
690 #endif
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  */
707 static void
708 set_default_values()
709 {
710
711   memset(&main_addr, 0, sizeof(union olsr_ip_addr));
712   memset(&null_addr6, 0, sizeof (union olsr_ip_addr));
713
714   exit_value = EXIT_SUCCESS; 
715   /* If the application exits by signal it is concidered success,
716    * if not, exit_value is set by the function calling olsr_exit.
717    */
718
719   max_jitter = 0;
720   max_tc_vtime = 0;
721   dup_hold_time = DUP_HOLD_TIME;
722
723   will_int = 10 * HELLO_INTERVAL; /* Willingness update interval */
724
725   llinfo = OLSR_FALSE;
726   del_gws = OLSR_FALSE;
727
728   /* Display packet content */
729   disp_pack_in = OLSR_FALSE;
730   disp_pack_out = OLSR_FALSE;
731
732   /* Initialize empty TC timer */
733   send_empty_tc = GET_TIMESTAMP(0);
734 }
735
736
737
738 /**
739  * Print the command line usage
740  */
741 static void
742 print_usage()
743 {
744
745   fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n"); 
746   fprintf(stderr, "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n");
747   fprintf(stderr, "  [-d <debug_level>] [-ipv6] [-multi <IPv6 multicast address>]\n"); 
748   fprintf(stderr, "  [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n");
749   fprintf(stderr, "  [-hint <hello interval (secs)>] [-tcint <tc interval (secs)>]\n");
750   fprintf(stderr, "  [-midint <mid interval (secs)>] [-hnaint <hna interval (secs)>]\n");
751   fprintf(stderr, "  [-T <Polling Rate (secs)>]\n"); 
752
753 }
754
755
756 /**
757  * Sets the provided configuration on all unconfigured
758  * interfaces
759  *
760  * @param ifs a linked list of interfaces to check and possible update
761  * @param cnf the default configuration to set on unconfigured interfaces
762  */
763 int
764 set_default_ifcnfs(struct olsr_if *ifs, struct if_config_options *cnf)
765 {
766   int changes = 0;
767
768   while(ifs)
769     {
770       if(ifs->cnf == NULL)
771         {
772           ifs->cnf = olsr_malloc(sizeof(struct if_config_options), "Set default config");
773           *ifs->cnf = *cnf;
774           changes++;
775         }
776       ifs = ifs->next;
777     }
778   return changes;
779 }