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