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