Yet more minor fixes
[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.23 2004/11/03 07:09:09 kattemat 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 static void
45 olsr_shutdown(int);
46 #elif defined WIN32
47 #define close(x) closesocket(x)
48 #include "win32/tunnel.h"
49 int __stdcall SignalHandler(unsigned long signal);
50 void ListInterfaces(void);
51 #else
52 #       error "Unsupported system"
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
69 /*
70  * Local variable declarations 
71  */
72
73 static pthread_t main_thread;
74
75
76 /**
77  * Main entrypoint
78  */
79
80 int
81 main(int argc, char *argv[])
82 {
83   /* For address convertions */
84   struct in_addr in;
85   struct in6_addr in6;
86
87   /* The thread for the scheduler */
88   pthread_t thread;
89
90   struct if_config_options *default_ifcnf;
91
92   struct stat statbuf;
93   char conf_file_name[FILENAME_MAX];
94   
95 #ifdef WIN32
96   WSADATA WsaData;
97   int len;
98 #endif
99
100   setbuf(stdout, NULL);
101   setbuf(stderr, NULL);
102
103   /* Initialize socket list */
104   olsr_socket_entries = NULL;
105
106 #ifndef WIN32
107   /* Check if user is root */
108   if(getuid() || getgid())
109     {
110       fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
111       exit(EXIT_FAILURE);
112     }
113 #else
114   if (WSAStartup(0x0202, &WsaData))
115     {
116       fprintf(stderr, "Could not initialize WinSock.\n");
117       olsr_exit(__func__, EXIT_FAILURE);
118     }
119 #endif
120
121   /* Open syslog */
122   olsr_openlog("olsrd");
123
124   /*
125    * Start syslog entry
126    */
127   olsr_syslog(OLSR_LOG_INFO, "%s started", SOFTWARE_VERSION);
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(&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 = 1;
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 = 1;
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->open_ipc = 1;
401           continue;
402         }
403
404
405       /*
406        * Display link-layer info(experimental)
407        */
408       if (strcmp(*argv, "-llinfo") == 0) 
409         {
410           argv++; argc--;
411           llinfo = 1;
412           continue;
413         }
414
415       /*
416        * Use Internet gateway tunneling?
417        */
418       if (strcmp(*argv, "-tnl") == 0) 
419         {
420           argv++; argc--;
421           use_tunnel = 1;
422
423           continue;
424         }
425
426       /*
427        * IPv6 multicast addr
428        */
429       if (strcmp(*argv, "-multi") == 0) 
430         {
431           argv++; argc--;
432           if(inet_pton(AF_INET6, *argv, &in6) < 0)
433             {
434               fprintf(stderr, "Failed converting IP address %s\n", *argv);
435               exit(EXIT_FAILURE);
436             }
437
438           memcpy(&default_ifcnf->ipv6_multi_glbl, &in6, sizeof(struct in6_addr));
439
440           argv++; argc--;
441
442           continue;
443         }
444
445
446       /*
447        * Should we display the contents of packages beeing sent?
448        */
449       if (strcmp(*argv, "-delgw") == 0) 
450         {
451           argv++; argc--;
452           del_gws = 1;
453           continue;
454         }
455
456
457       print_usage();
458       olsr_exit(__func__, EXIT_FAILURE);
459     }
460
461
462   /*
463    *Interfaces need to be specified
464    */
465   if(olsr_cnf->interfaces == NULL)
466     {
467       fprintf(stderr, "OLSRD: no interfaces specified!\nuse the -i switch to specify interface(s)\nor set interface(s) in the configuration file!\n");
468       print_usage();
469       olsr_exit(__func__, EXIT_FAILURE);
470     }
471
472   /*
473    * Set configuration for command-line specified interfaces
474    */
475   set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf);
476
477   /*
478    * Print configuration 
479    */
480   olsrd_print_cnf(olsr_cnf);  
481
482   /*
483    *socket for icotl calls
484    */
485   if ((ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) 
486     {
487       olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
488       close(ioctl_s);
489       olsr_exit(__func__, 0);
490     }
491
492   /*
493    *enable ip forwarding on host
494    */
495   enable_ip_forwarding(olsr_cnf->ip_version);
496
497   /* Initialize scheduler MUST HAPPEN BEFORE REGISTERING ANY FUNCTIONS! */
498   init_scheduler(olsr_cnf->pollrate);
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   /* Sanity check for hysteresis values */
510   if((olsr_cnf->use_hysteresis) &&
511      (olsr_cnf->hysteresis_param.thr_high <= olsr_cnf->hysteresis_param.thr_low))
512     {
513       printf("Hysteresis threshold high lower than threshold low!!\nEdit the configuration file to fix this!\n\n");
514       olsr_exit(__func__, EXIT_FAILURE);
515     }
516
517   /*
518    *Set up willingness/APM
519    */
520   if(olsr_cnf->willingness_auto)
521     {
522       if(apm_init() < 0)
523         {
524           olsr_printf(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
525
526           olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
527
528           olsr_cnf->willingness_auto = 0;
529           olsr_cnf->willingness = WILL_DEFAULT;
530         }
531       else
532         {
533           olsr_cnf->willingness = olsr_calculate_willingness();
534
535           olsr_printf(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, will_int);
536         }
537     }
538
539   /**
540    *Set ipsize and minimum packetsize
541    */
542   if(olsr_cnf->ip_version == AF_INET6)
543     {
544       olsr_printf(1, "Using IP version 6\n");
545       ipsize = sizeof(struct in6_addr);
546
547       minsize = (int)sizeof(olsr_u8_t) * 7; /* Minimum packetsize IPv6 */
548     }
549   else
550     {
551       olsr_printf(1, "Using IP version 4\n");
552       ipsize = sizeof(olsr_u32_t);
553
554       minsize = (int)sizeof(olsr_u8_t) * 4; /* Minimum packetsize IPv4 */
555     }
556
557
558   /* Initializing networkinterfaces */
559
560   if(!ifinit())
561     {
562       if(olsr_cnf->allow_no_interfaces)
563         {
564           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");
565           sleep(5);
566         }
567       else
568         {
569           fprintf(stderr, "No interfaces detected!\nBailing out!\n");
570           olsr_exit(__func__, EXIT_FAILURE);
571         }
572     }
573
574   /* Print tables to stdout */
575   if(olsr_cnf->debug_level > 0)
576     olsr_register_scheduler_event(&generate_tabledisplay, NULL, HELLO_INTERVAL, 0, NULL);
577   
578   
579   gettimeofday(&now, NULL);
580
581
582   /* Initialize the IPC socket */
583
584   if(olsr_cnf->open_ipc)
585       ipc_init();
586
587 #ifndef WIN32
588   /* Initialize link-layer notifications */
589   if(llinfo)
590     init_link_layer_notification();
591 #endif
592
593   /* Initialisation of different tables to be used.*/
594   olsr_init_tables();
595
596   /* Load plugins */
597   olsr_load_plugins();
598
599   /* Set up recieving tunnel if Inet gw */
600   if(use_tunnel && check_inet_gw())
601     set_up_gw_tunnel(&main_addr);
602
603   olsr_printf(1, "Main address: %s\n\n", olsr_ip_to_string(&main_addr));
604
605   olsr_printf(1, "NEIGHBORS: l=linkstate, m=MPR, w=willingness\n\n");
606
607
608   /* daemon mode */
609 #ifndef WIN32
610   if (olsr_cnf->debug_level == 0)
611     {
612       printf("%s detattching from the current process...\n", SOFTWARE_VERSION);
613       if (fork() != 0)
614         {
615           exit(EXIT_SUCCESS);
616         }
617       setsid();
618     }
619 #endif
620   /* Starting scheduler */
621   start_scheduler(&thread);
622
623   /*
624    *signal-handlers
625    */
626
627   /* ctrl-C and friends */
628 #ifdef WIN32
629   SetConsoleCtrlHandler(SignalHandler, TRUE);
630 #else
631   signal(SIGINT, olsr_shutdown);  
632   signal(SIGTERM, olsr_shutdown);  
633 #endif
634
635   /* Go into listenloop */
636   listen_loop();
637
638   /* Like we're ever going to reach this ;-) */
639   return 1;
640
641 } /* main */
642
643
644
645
646
647
648 /**
649  *Function called at shutdown
650  *
651  */
652 #ifdef WIN32
653 int __stdcall
654 SignalHandler(unsigned long signal)
655 #else
656 static void
657 olsr_shutdown(int signal)
658 #endif
659 {
660   struct interface *ifn;
661 #ifndef WIN32
662   if(main_thread != pthread_self())
663     {
664       pthread_exit(0);
665     }
666 #endif
667
668   olsr_printf(1, "Received signal %d - shutting down\n", signal);
669
670   olsr_delete_all_kernel_routes();
671
672   olsr_printf(1, "Closing sockets...\n");
673
674   /* front-end IPC socket */
675   if(olsr_cnf->open_ipc)
676     shutdown_ipc();
677
678   /* OLSR sockets */
679   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
680     close(ifn->olsr_socket);
681
682   /* Closing plug-ins */
683   olsr_close_plugins();
684
685   /* Reset network settings */
686   restore_settings(olsr_cnf->ip_version);
687
688   /* ioctl socket */
689   close(ioctl_s);
690
691   olsr_syslog(OLSR_LOG_INFO, "%s stopped", SOFTWARE_VERSION);
692
693   olsr_printf(1, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", SOFTWARE_VERSION);
694
695   exit(exit_value);
696 }
697
698
699
700
701
702 /**
703  *Sets the default values of variables at startup
704  */
705 static void
706 set_default_values()
707 {
708   memset(&main_addr, 0, sizeof(union olsr_ip_addr));
709   memset(&null_addr6, 0, sizeof (union olsr_ip_addr));
710
711   exit_value = EXIT_SUCCESS; 
712   /* If the application exits by signal it is concidered success,
713    * if not, exit_value is set by the function calling olsr_exit.
714    */
715
716   max_jitter = 0;
717   max_tc_vtime = 0;
718   dup_hold_time = DUP_HOLD_TIME;
719
720   will_int = 10 * HELLO_INTERVAL; /* Willingness update interval */
721
722
723 #ifndef WIN32
724   /* Get main thread ID */
725   main_thread = pthread_self();
726 #endif
727
728   /* Gateway tunneling */
729   use_tunnel = 0;
730   inet_tnl_added = 0;
731   gw_tunnel = 0;
732
733   llinfo = 0;
734   del_gws = 0;
735
736   /* Display packet content */
737   disp_pack_in = 0;
738   disp_pack_out = 0;
739 }
740
741
742
743
744 static void
745 print_usage()
746 {
747
748   fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n"); 
749   fprintf(stderr, "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n");
750   fprintf(stderr, "  [-d <debug_level>] [-ipv6] [-tnl] [-multi <IPv6 multicast address>]\n"); 
751   fprintf(stderr, "  [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n");
752   fprintf(stderr, "  [-hint <hello interval value (secs)>] [-tcint <tc interval value (secs)>]\n");
753   fprintf(stderr, "  [-midint <mid interval value (secs)>] [-hnaint <hna interval value (secs)>]\n");
754   fprintf(stderr, "  [-tos value (int)] [-T <Polling Rate (secs)>]\n"); 
755
756 }
757
758
759 /**
760  * Sets the provided configuration on all unconfigured
761  * interfaces
762  */
763 int
764 set_default_ifcnfs(struct olsr_if *ifs, struct if_config_options *cnf)
765 {
766   int changes = 0;
767
768   while(ifs)
769     {
770       if(ifs->cnf == NULL)
771         {
772           ifs->cnf = olsr_malloc(sizeof(struct if_config_options), "Set default config");
773           *ifs->cnf = *cnf;
774           changes++;
775         }
776       ifs = ifs->next;
777     }
778   return changes;
779 }