Merge branch 'master' into scheduler_cleanup
[olsrd.git] / src / main.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
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  */
41
42 #include <unistd.h>
43 #include <signal.h>
44 #include <sys/stat.h>
45 #include <assert.h>
46 #include <errno.h>
47
48 #include "defs.h"
49 #include "common/avl.h"
50 #include "common/avl_olsr_comp.h"
51 #include "olsr.h"
52 #include "ipcalc.h"
53 #include "olsr_timer.h"
54 #include "olsr_socket.h"
55 #include "parser.h"
56 #include "plugin_loader.h"
57 #include "os_apm.h"
58 #include "net_olsr.h"
59 #include "olsr_cfg_gen.h"
60 #include "common/string.h"
61 #include "mid_set.h"
62 #include "duplicate_set.h"
63 #include "olsr_comport.h"
64 #include "neighbor_table.h"
65 #include "olsr_logging.h"
66 #include "olsr_callbacks.h"
67 #include "os_apm.h"
68 #include "os_net.h"
69 #include "os_kernel_routes.h"
70 #include "os_time.h"
71 #include "os_system.h"
72
73 #if defined linux
74 #include <linux/types.h>
75 #include <linux/rtnetlink.h>
76 #include <fcntl.h>
77 #endif
78
79 #define STDOUT_PULSE_INT 600    /* msec */
80
81 #ifdef WIN32
82 int __stdcall SignalHandler(unsigned long signo);
83 #else
84 static void signal_shutdown(int);
85 #endif
86 static void olsr_shutdown(void);
87
88 /*
89  * Local function prototypes
90  */
91 #ifndef WIN32
92 static void signal_reconfigure(int);
93 #endif
94
95 /* Global stuff externed in olsr_cfg.h */
96 struct olsr_config *olsr_cnf;          /* The global configuration */
97
98 enum app_state app_state = STATE_INIT;
99
100 static char copyright_string[] __attribute__ ((unused)) =
101   "The olsr.org Optimized Link-State Routing daemon(olsrd) Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
102
103 static char pulsedata[] = "\\|/-";
104 static uint8_t pulse_state = 0;
105
106 static struct olsr_timer_entry *hna_gen_timer;
107 static struct olsr_timer_entry *mid_gen_timer;
108 static struct olsr_timer_entry *tc_gen_timer;
109
110 static void
111 generate_stdout_pulse(void *foo __attribute__ ((unused)))
112 {
113   if (pulsedata[++pulse_state] == '\0') {
114     pulse_state = 0;
115   }
116   fprintf(stderr, "%c\r", pulsedata[pulse_state]);
117 }
118
119 /**
120  * Main entrypoint
121  */
122
123 int
124 main(int argc, char *argv[])
125 {
126   /* Some cookies for stats keeping */
127   static struct olsr_timer_info *pulse_timer_info = NULL;
128   static struct olsr_timer_info *tc_gen_timer_info = NULL;
129   static struct olsr_timer_info *mid_gen_timer_info = NULL;
130   static struct olsr_timer_info *hna_gen_timer_info = NULL;
131
132   char conf_file_name[FILENAME_MAX];
133   char parse_msg[FILENAME_MAX + 256];
134   int exitcode = 0;
135 #if !defined(REMOVE_LOG_INFO) || !defined(REMOVE_LOG_ERROR)
136   struct ipaddr_str buf;
137 #endif
138 #ifdef WIN32
139   WSADATA WsaData;
140   size_t len;
141 #endif
142
143   /* paranoia checks */
144   assert(sizeof(uint8_t) == 1);
145   assert(sizeof(uint16_t) == 2);
146   assert(sizeof(uint32_t) == 4);
147   assert(sizeof(int8_t) == 1);
148   assert(sizeof(int16_t) == 2);
149   assert(sizeof(int32_t) == 4);
150
151   setbuf(stdout, NULL);
152   setbuf(stderr, NULL);
153
154   /* Using PID as random seed */
155   srandom(getpid());
156
157   /* call os dependent argument preprocessor */
158   os_arg(&argc, argv);
159
160   /*
161    * Set default configfile name
162    */
163 #ifdef WIN32
164 #ifndef WINCE
165   GetWindowsDirectory(conf_file_name, sizeof(conf_file_name) - 1 - strlen(OLSRD_CONF_FILE_NAME));
166 #else
167   conf_file_name[0] = 0;
168 #endif
169
170   len = strlen(conf_file_name);
171
172   if (len == 0 || conf_file_name[len - 1] != '\\') {
173     conf_file_name[len++] = '\\';
174   }
175
176   strscpy(conf_file_name + len, OLSRD_CONF_FILE_NAME, sizeof(conf_file_name) - len);
177 #else
178   strscpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, sizeof(conf_file_name));
179 #endif
180
181   /*
182    * set up configuration prior to processing commandline options
183    */
184   switch (olsr_parse_cfg(argc, argv, conf_file_name, parse_msg, &olsr_cnf)) {
185   case CFG_ERROR:
186     if (parse_msg[0])
187       fprintf(stderr, "Error: %s\n", parse_msg);
188     os_exit(EXIT_FAILURE);
189     break;
190   case CFG_WARN:
191     if (parse_msg[0])
192       fprintf(stderr, "Warning: %s\n", parse_msg);
193     /* No exit */
194     break;
195   case CFG_EXIT:
196     os_exit(EXIT_SUCCESS);
197     break;
198   case CFG_OK:
199     /* Continue */
200     break;
201   }
202
203   /* Set avl tree comparator */
204   if (olsr_cnf->ipsize == 4) {
205     avl_comp_default = avl_comp_ipv4;
206     avl_comp_addr_origin_default = avl_comp_ipv4_addr_origin;
207     avl_comp_prefix_default = avl_comp_ipv4_prefix;
208     avl_comp_prefix_origin_default = avl_comp_ipv4_prefix_origin;
209   } else {
210     avl_comp_default = avl_comp_ipv6;
211     avl_comp_addr_origin_default = avl_comp_ipv6_addr_origin;
212     avl_comp_prefix_default = avl_comp_ipv6_prefix;
213     avl_comp_prefix_origin_default = avl_comp_ipv6_prefix_origin;
214   }
215
216   /* initialize logging */
217   olsr_log_init();
218
219   OLSR_INFO(LOG_MAIN, "\n *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
220
221   /* Sanity check configuration */
222   if (olsr_sanity_check_cfg(olsr_cnf) < 0) {
223     olsr_exit(EXIT_FAILURE);
224   }
225
226   /* setup os specific global options */
227   os_init();
228
229 #ifndef WIN32
230   /* Check if user is root */
231   if (geteuid()) {
232     OLSR_ERROR(LOG_MAIN, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
233     olsr_exit(EXIT_FAILURE);
234   }
235 #else
236   if (WSAStartup(0x0202, &WsaData)) {
237     OLSR_ERROR(LOG_MAIN, "Could not initialize WinSock.\n");
238     olsr_exit(EXIT_FAILURE);
239   }
240 #endif
241
242   /* initialize cookie system */
243   olsr_memcookie_init();
244
245   /* Initialize timers and scheduler part */
246   olsr_timer_init();
247   olsr_socket_init();
248
249   /* initialize callback system */
250   olsr_callback_init();
251
252   /* generate global timers */
253   pulse_timer_info = olsr_timer_add("Stdout pulse", &generate_stdout_pulse, true);
254   tc_gen_timer_info = olsr_timer_add("TC generation", &olsr_output_lq_tc, true);
255   mid_gen_timer_info = olsr_timer_add("MID generation", &generate_mid, true);
256   hna_gen_timer_info = olsr_timer_add("HNA generation", &generate_hna, true);
257
258   /* initialize plugin system */
259   olsr_init_pluginsystem();
260   olsr_plugins_init(true);
261
262   /* Initialize link set */
263   olsr_init_link_set();
264
265   /* Initialize duplicate table */
266   olsr_init_duplicate_set();
267
268   /* Initialize neighbor table */
269   olsr_init_neighbor_table();
270
271   /* Initialize routing table */
272   olsr_init_routing_table();
273
274   /* Initialize topology */
275   olsr_init_tc();
276
277   /* Initialize MID set */
278   olsr_init_mid_set();
279
280   /* Initialize HNA set */
281   olsr_init_hna_set();
282
283   /* enable lq-plugins */
284   olsr_plugins_enable(PLUGIN_TYPE_LQ, true);
285
286   /* initialize built in server services */
287   olsr_com_init();
288
289   /* Initialize net */
290   init_net();
291
292   /* Initialize SPF */
293   olsr_init_spf();
294
295   /*
296    * socket for ioctl calls
297    */
298   olsr_cnf->ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0);
299   if (olsr_cnf->ioctl_s < 0) {
300     OLSR_ERROR(LOG_MAIN, "ioctl socket: %s\n", strerror(errno));
301     olsr_exit(EXIT_FAILURE);
302   }
303 #if defined linux
304   olsr_cnf->rtnl_s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
305   if (olsr_cnf->rtnl_s < 0) {
306     OLSR_ERROR(LOG_MAIN, "rtnetlink socket: %s\n", strerror(errno));
307     olsr_exit(EXIT_FAILURE);
308   }
309   os_socket_set_nonblocking(olsr_cnf->rtnl_s);
310
311   /* Create rule for RtTable to resolve route insertion problems*/
312   if ( ( olsr_cnf->rt_table < 253) & ( olsr_cnf->rt_table > 0 ) ) {
313     OLSR_WARN(LOG_NETWORKING,"make sure to have correct policy routing rules (destination based rules are required, or a dummy rule with prio like 65535)");
314     /*olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rt_table, RTM_NEWRULE);*/
315   }
316 #endif
317
318 /*
319  * create routing socket
320  */
321 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
322   olsr_cnf->rts_bsd = socket(PF_ROUTE, SOCK_RAW, 0);
323   if (olsr_cnf->rts_bsd < 0) {
324     OLSR_ERROR(LOG_MAIN, "routing socket: %s\n", strerror(errno));
325     olsr_exit(EXIT_FAILURE);
326   }
327 #endif
328
329   /* Initialize parser */
330   olsr_init_parser();
331
332   /* Initialize route-exporter */
333   olsr_init_export_route();
334
335   /* Initialize message sequencnumber */
336   init_msg_seqno();
337
338   /* Initialize dynamic willingness calculation */
339   olsr_init_willingness();
340
341   /*
342    *Set up willingness/APM
343    */
344   if (olsr_cnf->willingness_auto) {
345     olsr_calculate_willingness();
346   }
347
348 #if defined linux
349   /* Initializing lo:olsr if necessary */
350   if (olsr_cnf->source_ip_mode) {
351     OLSR_INFO(LOG_NETWORKING, "Initializing lo:olsr interface for source ip mode...\n");
352     if (olsr_os_localhost_if(&olsr_cnf->router_id, true) <= 0) {
353       OLSR_ERROR(LOG_NETWORKING, "Cannot create lo:olsr interface for ip '%s'\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
354       olsr_exit(EXIT_FAILURE);
355     }
356   }
357 #endif
358
359   /* Initializing networkinterfaces */
360   if (!init_interfaces()) {
361     if (olsr_cnf->allow_no_interfaces) {
362       OLSR_INFO(LOG_MAIN,
363                 "No interfaces detected! This might be intentional, but it also might mean that your configuration is fubar.\nI will continue after 5 seconds...\n");
364       os_sleep(5);
365     } else {
366       OLSR_ERROR(LOG_MAIN, "No interfaces detected!\nBailing out!\n");
367       olsr_exit(EXIT_FAILURE);
368     }
369   }
370
371   /* Print heartbeat to stdout */
372
373 #if !defined WINCE
374   if (olsr_cnf->log_target_stderr > 0 && isatty(STDOUT_FILENO)) {
375     olsr_timer_start(STDOUT_PULSE_INT, 0, NULL, pulse_timer_info);
376   }
377 #endif
378
379   /* daemon mode */
380 #ifndef WIN32
381   if (!olsr_cnf->no_fork) {
382     OLSR_INFO(LOG_MAIN, "%s detaching from the current process...\n", olsrd_version);
383     if (daemon(0, 0) < 0) {
384       OLSR_ERROR(LOG_MAIN, "daemon(3) failed: %s\n", strerror(errno));
385       olsr_exit(EXIT_FAILURE);
386     }
387   }
388 #endif
389
390   /* activate LQ algorithm */
391   init_lq_handler();
392
393   OLSR_INFO(LOG_MAIN, "Main address: %s\n\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
394
395   /* Start syslog entry */
396   OLSR_INFO(LOG_MAIN, "%s successfully started", olsrd_version);
397
398   /*
399    *signal-handlers
400    */
401
402   /* ctrl-C and friends */
403 #ifdef WIN32
404 #ifndef WINCE
405   SetConsoleCtrlHandler(SignalHandler, true);
406 #endif
407 #else
408   {
409     struct sigaction act;
410     sigemptyset(&act.sa_mask);
411     act.sa_flags = 0;
412     act.sa_handler = signal_reconfigure;
413     sigaction(SIGHUP, &act, NULL);
414     act.sa_handler = signal_shutdown;
415     sigaction(SIGINT, &act, NULL);
416     sigaction(SIGQUIT, &act, NULL);
417     sigaction(SIGILL, &act, NULL);
418     sigaction(SIGABRT, &act, NULL);
419 //  sigaction(SIGSEGV, &act, NULL);
420     sigaction(SIGTERM, &act, NULL);
421     act.sa_handler = SIG_IGN;
422     sigaction(SIGPIPE, &act, NULL);
423     // Ignoring SIGUSR1 and SIGUSR1 by default to be able to use them in plugins
424     sigaction(SIGUSR1, &act, NULL);
425     sigaction(SIGUSR2, &act, NULL);
426   }
427 #endif
428
429   link_changes = false;
430
431   tc_gen_timer =
432     olsr_timer_start(olsr_cnf->tc_params.emission_interval, TC_JITTER, NULL, tc_gen_timer_info);
433   mid_gen_timer =
434     olsr_timer_start(olsr_cnf->mid_params.emission_interval, MID_JITTER, NULL, mid_gen_timer_info);
435   hna_gen_timer =
436     olsr_timer_start(olsr_cnf->hna_params.emission_interval, HNA_JITTER, NULL, hna_gen_timer_info);
437
438   /* enable default plugins */
439   olsr_plugins_enable(PLUGIN_TYPE_DEFAULT, true);
440
441   /* Starting scheduler */
442   app_state = STATE_RUNNING;
443   olsr_timer_scheduler();
444
445   olsr_timer_stop(tc_gen_timer);
446   tc_gen_timer = NULL;
447
448   olsr_timer_stop(mid_gen_timer);
449   mid_gen_timer = NULL;
450
451   olsr_timer_stop(hna_gen_timer);
452   hna_gen_timer = NULL;
453
454   exitcode = olsr_cnf->exit_value;
455   switch (app_state) {
456   case STATE_INIT:
457     OLSR_ERROR(LOG_MAIN, "terminating and got \"init\"?");
458     exitcode = EXIT_FAILURE;
459     break;
460   case STATE_RUNNING:
461     OLSR_ERROR(LOG_MAIN, "terminating and got \"running\"?");
462     exitcode = EXIT_FAILURE;
463     break;
464 #ifndef WIN32
465   case STATE_RECONFIGURE:
466     /* if we are started with -nofork, we do not weant to go into the
467      * background here. So we can simply be the child process.
468      */
469     switch (olsr_cnf->no_fork ? 0 : fork()) {
470       int i;
471     case 0:
472       /* child process */
473       for (i = sysconf(_SC_OPEN_MAX); --i > STDERR_FILENO;) {
474         close(i);
475       }
476       os_sleep(1);
477       OLSR_INFO(LOG_MAIN, "Restarting %s\n", argv[0]);
478       execv(argv[0], argv);
479       /* if we reach this, the exev() failed */
480       OLSR_ERROR(LOG_MAIN, "execv() failed: %s", strerror(errno));
481       /* and we simply shutdown */
482       exitcode = EXIT_FAILURE;
483       break;
484     case -1:
485       /* fork() failes */
486       OLSR_ERROR(LOG_MAIN, "fork() failed: %s", strerror(errno));
487       /* and we simply shutdown */
488       exitcode = EXIT_FAILURE;
489       break;
490     default:
491       /* parent process */
492       OLSR_INFO(LOG_MAIN, "Reconfiguring OLSR\n");
493       break;
494     }
495     /* fall through */
496 #endif
497   case STATE_SHUTDOWN:
498     olsr_shutdown();
499     break;
500   };
501
502   return exitcode;
503 }                               /* main */
504
505 #ifndef WIN32
506
507 /**
508  * Request reconfiguration of olsrd.
509  *
510  *@param signal the signal that triggered this callback
511  */
512 static void
513 signal_reconfigure(int signo __attribute__ ((unused)))
514 {
515   const int save_errno = errno;
516   OLSR_INFO(LOG_MAIN, "Received signal %d - requesting reconfiguration", signo);
517   app_state = STATE_RECONFIGURE;
518   errno = save_errno;
519 }
520
521 #endif
522
523 /**
524  *Function called at shutdown. Signal handler
525  *
526  * @param signal the signal that triggered this call
527  */
528 #ifdef WIN32
529 int __stdcall
530 SignalHandler(unsigned long signo)
531 #else
532 static void
533 signal_shutdown(int signo __attribute__ ((unused)))
534 #endif
535 {
536   const int save_errno = errno;
537   OLSR_INFO(LOG_MAIN, "Received signal %d - requesting shutdown", (int)signo);
538   app_state = STATE_SHUTDOWN;
539   errno = save_errno;
540 #ifdef WIN32
541   return 0;
542 #endif
543 }
544
545 static void
546 olsr_shutdown(void)
547 {
548   struct mid_entry *mid, *iterator;
549
550   olsr_delete_all_kernel_routes();
551
552   /* Flush MID database */
553   OLSR_FOR_ALL_MID_ENTRIES(mid, iterator) {
554     olsr_delete_mid_entry(mid);
555   }
556
557   /* Flush TC database */
558   olsr_delete_all_tc_entries();
559
560   OLSR_INFO(LOG_MAIN, "Closing sockets...\n");
561
562   /* kill http/telnet server */
563   olsr_com_destroy();
564
565   /* Flush duplicate set */
566   olsr_flush_duplicate_entries();
567
568   /* Shut down LQ plugin */
569   deinit_lq_handler();
570
571   /* Closing plug-ins */
572   olsr_destroy_pluginsystem();
573
574   /* Remove active interfaces */
575   destroy_interfaces();
576
577 #if defined linux
578   /* delete lo:olsr if neccesarry */
579   if (olsr_cnf->source_ip_mode) {
580     olsr_os_localhost_if(&olsr_cnf->router_id, false);
581   }
582 #endif
583
584   /* ioctl socket */
585   os_close(olsr_cnf->ioctl_s);
586
587 #if defined linux
588   /*if ((olsr_cnf->rttable < 253) & (olsr_cnf->rttable > 0)) {
589     olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_DELRULE);
590   }*/
591
592   os_close(olsr_cnf->rtnl_s);
593 #endif
594
595 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
596   /* routing socket */
597   os_close(olsr_cnf->rts_bsd);
598 #endif
599
600   /* Close and delete all sockets */
601   olsr_socket_cleanup();
602
603   /* Stop and delete all timers. */
604   olsr_timer_cleanup();
605
606   /* Remove parser hooks */
607   olsr_deinit_parser();
608
609   /* Remove IP filters */
610   deinit_netfilters();
611
612   /* release callback system */
613   olsr_callback_cleanup();
614
615   /* Free cookies and memory pools attached. */
616   olsr_memcookie_cleanup();
617
618   /* Reset os_specific global options */
619   os_cleanup();
620
621   OLSR_INFO(LOG_MAIN, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", olsrd_version);
622
623   /* cleanup logging system */
624   olsr_log_cleanup();
625
626   /* Flush config */
627   olsr_free_cfg(olsr_cnf);
628 }
629
630 /*
631  * Local Variables:
632  * c-basic-offset: 2
633  * indent-tabs-mode: nil
634  * End:
635  */