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