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