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