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