General cleanups in header files
[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.62 2005/02/20 18:52:18 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 "net_os.h"
57
58 #ifdef WIN32
59 #define close(x) closesocket(x)
60 int __stdcall SignalHandler(unsigned long signal);
61 void ListInterfaces(void);
62 void DisableIcmpRedirects(void);
63 #else
64 static void
65 olsr_shutdown(int);
66 #endif
67
68 /*
69  * Local function prototypes
70  */
71 void
72 olsr_reconfigure(int);
73
74 static void
75 print_usage(void);
76
77 static void
78 set_default_values(void);
79
80 static int
81 set_default_ifcnfs(struct olsr_if *, struct if_config_options *);
82
83 static char **olsr_argv;
84
85 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.";
86
87 /**
88  * Main entrypoint
89  */
90
91 int
92 main(int argc, char *argv[])
93 {
94   struct if_config_options *default_ifcnf;
95   char conf_file_name[FILENAME_MAX];
96   struct tms tms_buf;
97
98   olsr_argv = argv;
99
100 #ifdef WIN32
101   WSADATA WsaData;
102   int len;
103 #endif
104
105   setbuf(stdout, NULL);
106   setbuf(stderr, NULL);
107
108 #ifndef WIN32
109   /* Initialize tick resolution */
110   system_tick_divider = 1000/sysconf(_SC_CLK_TCK);
111
112   /* Check if user is root */
113   if(getuid() || getgid())
114     {
115       fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
116       exit(EXIT_FAILURE);
117     }
118 #else
119   system_tick_divider = 1;
120
121   DisableIcmpRedirects();
122
123   if (WSAStartup(0x0202, &WsaData))
124     {
125       fprintf(stderr, "Could not initialize WinSock.\n");
126       olsr_exit(__func__, EXIT_FAILURE);
127     }
128 #endif
129
130   /* Grab initial timestamp */
131   now_times = times(&tms_buf);
132
133   /* Open syslog */
134   olsr_openlog("olsrd");
135
136   /* Set default values */
137   set_default_values();
138  
139   /* Get initial timestep */
140   nowtm = NULL;
141   while (nowtm == NULL)
142     {
143       nowtm = gmtime((time_t *)&now.tv_sec);
144     }
145     
146   /* The port to use for OLSR traffic */
147   olsr_udp_port = htons(OLSRPORT);
148     
149   printf("\n *** %s ***\n Build date: %s\n http://www.olsr.org\n\n", 
150          SOFTWARE_VERSION, 
151          __DATE__);
152     
153   /* Using PID as random seed */
154   srandom(getpid());
155
156
157   /*
158    * Set configfile name and
159    * check if a configfile name was given as parameter
160    */
161 #ifdef WIN32
162   GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11);
163   
164   len = strlen(conf_file_name);
165   
166   if (conf_file_name[len - 1] != '\\')
167     conf_file_name[len++] = '\\';
168   
169   strcpy(conf_file_name + len, "olsrd.conf");
170 #else
171   strncpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, FILENAME_MAX);
172 #endif
173
174   if ((argc > 1) && (strcmp(argv[1], "-f") == 0)) 
175     {
176       struct stat statbuf;
177
178       argv++; argc--;
179       if(argc == 1)
180         {
181           fprintf(stderr, "You must provide a filename when using the -f switch!\n");
182           exit(EXIT_FAILURE);
183         }
184
185       if (stat(argv[1], &statbuf) < 0)
186         {
187           fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", argv[1], strerror(errno));
188           exit(EXIT_FAILURE);
189         }
190                  
191       strncpy(conf_file_name, argv[1], FILENAME_MAX);
192       argv++; argc--;
193
194     }
195
196   /*
197    * set up configuration prior to processing commandline options
198    */
199   if((olsr_cnf = olsrd_parse_cnf(conf_file_name)) == NULL)
200     {
201       printf("Using default config values(no configfile)\n");
202       olsr_cnf = olsrd_get_default_cnf();
203     }
204   if((default_ifcnf = get_default_if_config()) == NULL)
205     {
206       fprintf(stderr, "No default ifconfig found!\n");
207       exit(EXIT_FAILURE);
208     }
209
210   /*
211    * Process olsrd options.
212    */
213   
214   argv++; argc--;
215   while (argc > 0 && **argv == '-')
216     {
217 #ifdef WIN32
218       /*
219        *Interface list
220        */
221       if (strcmp(*argv, "-int") == 0)
222         {
223           ListInterfaces();
224           exit(0);
225         }
226 #endif
227
228       /*
229        *Configfilename
230        */
231       if(strcmp(*argv, "-f") == 0) 
232         {
233           fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n");
234           olsr_exit(__func__, EXIT_FAILURE);
235         }
236
237       /*
238        *Use IP version 6
239        */
240       if(strcmp(*argv, "-ipv6") == 0) 
241         {
242           olsr_cnf->ip_version = AF_INET6;
243           argv++; argc--;
244           continue;
245         }
246
247       /*
248        *Broadcast address
249        */
250       if(strcmp(*argv, "-bcast") == 0) 
251         {
252           struct in_addr in;
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 polling interval to be used by olsrd.
358        */
359       if (strcmp(*argv, "-T") == 0) 
360         {
361           argv++; argc--;
362           sscanf(*argv,"%f",&olsr_cnf->pollrate);
363           argv++; argc--;
364           continue;
365         }
366
367
368       /*
369        * Should we display the contents of packages beeing sent?
370        */
371       if (strcmp(*argv, "-dispin") == 0) 
372         {
373           argv++; argc--;
374           disp_pack_in = OLSR_TRUE;
375           continue;
376         }
377
378       /*
379        * Should we display the contents of incoming packages?
380        */
381       if (strcmp(*argv, "-dispout") == 0) 
382         {
383           argv++; argc--;
384           disp_pack_out = OLSR_TRUE;
385           continue;
386         }
387
388
389       /*
390        * Should we set up and send on a IPC socket for the front-end?
391        */
392       if (strcmp(*argv, "-ipc") == 0) 
393         {
394           argv++; argc--;
395           olsr_cnf->ipc_connections = 1;
396           olsr_cnf->open_ipc = OLSR_TRUE;
397           continue;
398         }
399
400       /*
401        * IPv6 multicast addr
402        */
403       if (strcmp(*argv, "-multi") == 0) 
404         {
405           struct in6_addr in6;
406
407           argv++; argc--;
408           if(inet_pton(AF_INET6, *argv, &in6) < 0)
409             {
410               fprintf(stderr, "Failed converting IP address %s\n", *argv);
411               exit(EXIT_FAILURE);
412             }
413
414           memcpy(&default_ifcnf->ipv6_multi_glbl, &in6, sizeof(struct in6_addr));
415
416           argv++; argc--;
417
418           continue;
419         }
420
421
422       /*
423        * Delete possible default GWs
424        */
425       if (strcmp(*argv, "-delgw") == 0) 
426         {
427           argv++; argc--;
428           del_gws = OLSR_TRUE;
429           continue;
430         }
431
432
433       print_usage();
434       olsr_exit(__func__, EXIT_FAILURE);
435     }
436
437   /*
438    * Set configuration for command-line specified interfaces
439    */
440   set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf);
441
442   /* Sanity check configuration */
443   if(olsrd_sanity_check_cnf(olsr_cnf) < 0)
444     {
445       fprintf(stderr, "Bad configuration!\n");
446       olsr_exit(__func__, EXIT_FAILURE);      
447     }
448
449   /*
450    * Print configuration 
451    */
452   olsrd_print_cnf(olsr_cnf);  
453
454   /*
455    *socket for icotl calls
456    */
457   if ((ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) 
458
459     {
460       olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
461       olsr_exit(__func__, 0);
462     }
463
464 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__
465   if ((rts = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
466     {
467       olsr_syslog(OLSR_LOG_ERR, "routing socket: %m");
468       olsr_exit(__func__, 0);
469     }
470 #endif
471
472   /*
473    *enable ip forwarding on host
474    */
475   enable_ip_forwarding(olsr_cnf->ip_version);
476
477   /* Initialize parser */
478   olsr_init_parser();
479
480   /* Initialize message sequencnumber */
481   init_msg_seqno();
482
483   /* Initialize dynamic willingness calculation */
484   olsr_init_willingness();
485
486   /*
487    *Set up willingness/APM
488    */
489   if(olsr_cnf->willingness_auto)
490     {
491       if(apm_init() < 0)
492         {
493           olsr_printf(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
494
495           olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
496
497           olsr_cnf->willingness_auto = 0;
498           olsr_cnf->willingness = WILL_DEFAULT;
499         }
500       else
501         {
502           olsr_cnf->willingness = olsr_calculate_willingness();
503
504           olsr_printf(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, will_int);
505         }
506     }
507
508   /* Set ipsize and minimum packetsize */
509   if(olsr_cnf->ip_version == AF_INET6)
510     {
511       olsr_printf(1, "Using IP version 6\n");
512       ipsize = sizeof(struct in6_addr);
513
514       minsize = (int)sizeof(olsr_u8_t) * 7; /* Minimum packetsize IPv6 */
515     }
516   else
517     {
518       olsr_printf(1, "Using IP version 4\n");
519       ipsize = sizeof(olsr_u32_t);
520
521       minsize = (int)sizeof(olsr_u8_t) * 4; /* Minimum packetsize IPv4 */
522     }
523
524
525   /* Initializing networkinterfaces */
526
527   if(!ifinit())
528     {
529       if(olsr_cnf->allow_no_interfaces)
530         {
531           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");
532           sleep(5);
533         }
534       else
535         {
536           fprintf(stderr, "No interfaces detected!\nBailing out!\n");
537           olsr_exit(__func__, EXIT_FAILURE);
538         }
539     }
540
541   /* Print heartbeat to stdout */
542
543   if(olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO))
544     olsr_register_scheduler_event(&generate_stdout_pulse, NULL, STDOUT_PULSE_INT, 0, NULL);
545   
546   gettimeofday(&now, NULL);
547
548
549   /* Initialize the IPC socket */
550
551   if(olsr_cnf->open_ipc)
552       ipc_init();
553
554   /* Initialisation of different tables to be used.*/
555   olsr_init_tables();
556
557   /* daemon mode */
558 #ifndef WIN32
559   if (olsr_cnf->debug_level == 0)
560     {
561       printf("%s detattching from the current process...\n", SOFTWARE_VERSION);
562       if (fork() != 0)
563         {
564           exit(EXIT_SUCCESS);
565         }
566       setsid();
567     }
568 #endif
569
570   /* Load plugins */
571   olsr_load_plugins();
572
573   olsr_printf(1, "Main address: %s\n\n", olsr_ip_to_string(&main_addr));
574
575
576   /* Start syslog entry */
577   olsr_syslog(OLSR_LOG_INFO, "%s successfully started", SOFTWARE_VERSION);
578
579   /*
580    *signal-handlers
581    */
582
583   /* ctrl-C and friends */
584 #ifdef WIN32
585   SetConsoleCtrlHandler(SignalHandler, OLSR_TRUE);
586 #else
587   signal(SIGHUP, olsr_reconfigure);  
588   signal(SIGINT, olsr_shutdown);  
589   signal(SIGTERM, olsr_shutdown);  
590 #endif
591
592   /* Register socket poll event */
593   olsr_register_timeout_function(&poll_sockets);
594
595   /* Starting scheduler */
596   scheduler();
597
598   /* Stop the compiler from complaining */
599   strlen(copyright_string);
600
601   /* Like we're ever going to reach this ;-) */
602   return 1;
603
604 } /* main */
605
606
607
608 /**
609  * Reconfigure olsrd. Currently kind of a hack...
610  *
611  *@param signal the signal that triggered this callback
612  */
613 #ifndef WIN32
614 void
615 olsr_reconfigure(int signal)
616 {
617   if(!fork())
618     {
619       /* New process */
620       sleep(3);
621       printf("Restarting %s\n", olsr_argv[0]);
622       execv(olsr_argv[0], olsr_argv);
623     }
624   olsr_shutdown(0);
625
626   printf("RECONFIGURING!\n");
627 }
628 #endif
629
630
631 /**
632  *Function called at shutdown. Signal handler
633  *
634  * @param signal the signal that triggered this call
635  */
636 #ifdef WIN32
637 int __stdcall
638 SignalHandler(unsigned long signal)
639 #else
640 static void
641 olsr_shutdown(int signal)
642 #endif
643 {
644   struct interface *ifn;
645
646   olsr_printf(1, "Received signal %d - shutting down\n", signal);
647
648   olsr_delete_all_kernel_routes();
649
650   olsr_printf(1, "Closing sockets...\n");
651
652   /* front-end IPC socket */
653   if(olsr_cnf->open_ipc)
654     shutdown_ipc();
655
656   /* OLSR sockets */
657   for (ifn = ifnet; ifn; ifn = ifn->int_next) 
658     close(ifn->olsr_socket);
659
660   /* Closing plug-ins */
661   olsr_close_plugins();
662
663   /* Reset network settings */
664   restore_settings(olsr_cnf->ip_version);
665
666   /* ioctl socket */
667   close(ioctl_s);
668
669 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__
670   /* routing socket */
671   close(rts);
672 #endif
673
674   olsr_syslog(OLSR_LOG_INFO, "%s stopped", SOFTWARE_VERSION);
675
676   olsr_printf(1, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", SOFTWARE_VERSION);
677
678   exit(exit_value);
679 }
680
681
682
683
684
685 /**
686  *Sets the default values of variables at startup
687  *
688  */
689 static void
690 set_default_values()
691 {
692
693   memset(&main_addr, 0, sizeof(union olsr_ip_addr));
694
695   exit_value = EXIT_SUCCESS; 
696   /* If the application exits by signal it is concidered success,
697    * if not, exit_value is set by the function calling olsr_exit.
698    */
699
700   max_jitter = 0;
701   max_tc_vtime = 0;
702
703   will_int = 10 * HELLO_INTERVAL; /* Willingness update interval */
704
705   del_gws = OLSR_FALSE;
706
707   /* Display packet content */
708   disp_pack_in = OLSR_FALSE;
709   disp_pack_out = OLSR_FALSE;
710
711   /* Initialize empty TC timer */
712   send_empty_tc = GET_TIMESTAMP(0);
713 }
714
715
716
717 /**
718  * Print the command line usage
719  */
720 static void
721 print_usage()
722 {
723
724   fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n"); 
725   fprintf(stderr, "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n");
726   fprintf(stderr, "  [-d <debug_level>] [-ipv6] [-multi <IPv6 multicast address>]\n"); 
727   fprintf(stderr, "  [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n");
728   fprintf(stderr, "  [-hint <hello interval (secs)>] [-tcint <tc interval (secs)>]\n");
729   fprintf(stderr, "  [-midint <mid interval (secs)>] [-hnaint <hna interval (secs)>]\n");
730   fprintf(stderr, "  [-T <Polling Rate (secs)>]\n"); 
731
732 }
733
734
735 /**
736  * Sets the provided configuration on all unconfigured
737  * interfaces
738  *
739  * @param ifs a linked list of interfaces to check and possible update
740  * @param cnf the default configuration to set on unconfigured interfaces
741  */
742 int
743 set_default_ifcnfs(struct olsr_if *ifs, struct if_config_options *cnf)
744 {
745   int changes = 0;
746
747   while(ifs)
748     {
749       if(ifs->cnf == NULL)
750         {
751           ifs->cnf = olsr_malloc(sizeof(struct if_config_options), "Set default config");
752           *ifs->cnf = *cnf;
753           changes++;
754         }
755       ifs = ifs->next;
756     }
757   return changes;
758 }