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