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