4755cb36ccfb43ec7ca3523d32f970645e71acc3
[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 "ipcalc.h"
49 #include "defs.h"
50 #include "olsr.h"
51 #include "log.h"
52 #include "scheduler.h"
53 #include "parser.h"
54 #include "generate_msg.h"
55 #include "plugin_loader.h"
56 #include "apm.h"
57 #include "net_os.h"
58 #include "build_msg.h"
59 #include "net_olsr.h"
60 #include "ipc_frontend.h"
61 #include "misc.h"
62 #include "olsr_cfg_gen.h"
63 #include "common/string.h"
64 #include "mid_set.h"
65 #include "duplicate_set.h"
66
67 #if defined linux
68 #include <linux/types.h>
69 #include <linux/rtnetlink.h>
70 #include <fcntl.h>
71 #endif
72
73 #ifdef WIN32
74 int __stdcall SignalHandler(unsigned long signo);
75 void DisableIcmpRedirects(void);
76 #else
77 static void signal_shutdown(int);
78 #endif
79 static void olsr_shutdown(void);
80
81 /*
82  * Local function prototypes
83  */
84 #ifndef WIN32
85 static void signal_reconfigure(int);
86 #endif
87
88 /* Global stuff externed in olsr_cfg.h */
89 FILE *debug_handle;                    /* Where to send debug(defaults to stdout) */
90 struct olsr_config *olsr_cnf;          /* The global configuration */
91
92 volatile enum app_state app_state = STATE_RUNNING;
93
94 static char copyright_string[] __attribute__ ((unused)) =
95   "The olsr.org Optimized Link-State Routing daemon(olsrd) Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org) All rights reserved.";
96
97 /**
98  * Main entrypoint
99  */
100
101 int
102 main(int argc, char *argv[])
103 {
104   /* Some cookies for stats keeping */
105   static struct olsr_cookie_info *pulse_timer_cookie = NULL;
106
107   char conf_file_name[FILENAME_MAX];
108   char parse_msg[FILENAME_MAX + 256];
109   struct ipaddr_str buf;
110   int exitcode = 0;
111 #ifdef WIN32
112   WSADATA WsaData;
113   size_t len;
114 #endif
115
116   /* paranoia checks */
117   assert(sizeof(uint8_t) == 1);
118   assert(sizeof(uint16_t) == 2);
119   assert(sizeof(uint32_t) == 4);
120   assert(sizeof(int8_t) == 1);
121   assert(sizeof(int16_t) == 2);
122   assert(sizeof(int32_t) == 4);
123
124   debug_handle = stdout;
125   setbuf(stdout, NULL);
126   setbuf(stderr, NULL);
127
128 #ifndef WIN32
129   /* Check if user is root */
130   if (geteuid()) {
131     fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
132     exit(EXIT_FAILURE);
133   }
134 #else
135   DisableIcmpRedirects();
136
137   if (WSAStartup(0x0202, &WsaData)) {
138     fprintf(stderr, "Could not initialize WinSock.\n");
139     olsr_exit(__func__, EXIT_FAILURE);
140   }
141 #endif
142
143   /* Open syslog */
144   olsr_openlog("olsrd");
145
146   /* Initialize timers and scheduler part */
147   olsr_init_timers();
148
149   printf("\n *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
150
151   /* Using PID as random seed */
152   srandom(getpid());
153
154   /*
155    * Set configfile name and
156    * check if a configfile name was given as parameter
157    */
158 #ifdef WIN32
159 #ifndef WINCE
160   GetWindowsDirectory(conf_file_name, sizeof(conf_file_name) - 1 - strlen(OLSRD_CONF_FILE_NAME));
161 #else
162   conf_file_name[0] = 0;
163 #endif
164
165   len = strlen(conf_file_name);
166
167   if (len == 0 || conf_file_name[len - 1] != '\\') {
168     conf_file_name[len++] = '\\';
169   }
170
171   strscpy(conf_file_name + len, OLSRD_CONF_FILE_NAME, sizeof(conf_file_name) - len);
172 #else
173   strscpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, sizeof(conf_file_name));
174 #endif
175
176   /*
177    * set up configuration prior to processing commandline options
178    */
179   switch (olsr_parse_cfg(argc, argv, conf_file_name, parse_msg, &olsr_cnf)) {
180     case CFG_ERROR:
181       if (parse_msg[0])
182         fprintf(stderr, "Error: %s\n", parse_msg);
183       exit(EXIT_FAILURE);
184     break;
185     case CFG_WARN:
186       if (parse_msg[0])
187         fprintf(stderr, "Warning: %s\n", parse_msg);
188       /* No exit */
189     break;
190     case CFG_EXIT:
191       exit(EXIT_SUCCESS);
192     break;
193     case CFG_OK:
194       /* Continue */
195     break;
196   } /* switch */
197
198   /* initialize logging */
199   olsr_log_init();
200
201   /* Set avl tree comparator */
202   if (olsr_cnf->ipsize == 4) {
203     avl_comp_default = avl_comp_ipv4;
204     avl_comp_prefix_default = avl_comp_ipv4_prefix;
205     avl_comp_prefix_origin_default = avl_comp_ipv4_prefix_origin;
206   } else {
207     avl_comp_default = avl_comp_ipv6;
208     avl_comp_prefix_default = avl_comp_ipv6_prefix;
209     avl_comp_prefix_origin_default = avl_comp_ipv6_prefix_origin;
210   }
211
212   /* Initialize tick resolution */
213 #ifndef WIN32
214   olsr_cnf->system_tick_divider = 1000 / sysconf(_SC_CLK_TCK);
215 #else
216   olsr_cnf->system_tick_divider = 1;
217 #endif
218
219   /* Initialize net */
220   init_net();
221
222   /* Sanity check configuration */
223   if (olsr_sanity_check_cfg(olsr_cnf) < 0) {
224     olsr_exit(__func__, EXIT_FAILURE);
225   }
226
227 #ifndef WIN32
228   /* Disable redirects globally */
229   disable_redirects_global(olsr_cnf->ip_version);
230 #endif
231
232   /*
233    * socket for ioctl calls
234    */
235   olsr_cnf->ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0);
236   if (olsr_cnf->ioctl_s < 0) {
237     olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
238     olsr_exit(__func__, 0);
239   }
240 #if defined linux
241   olsr_cnf->rts_linux = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
242   if (olsr_cnf->rts_linux < 0) {
243     olsr_syslog(OLSR_LOG_ERR, "rtnetlink socket: %m");
244     olsr_exit(__func__, 0);
245   }
246   set_nonblocking(olsr_cnf->rts_linux);
247 #endif
248
249 /*
250  * create routing socket
251  */
252 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
253   olsr_cnf->rts_bsd = socket(PF_ROUTE, SOCK_RAW, 0);
254   if (olsr_cnf->rts_bsd < 0) {
255     olsr_syslog(OLSR_LOG_ERR, "routing socket: %m");
256     olsr_exit(__func__, 0);
257   }
258 #endif
259
260   /*
261    *enable ip forwarding on host
262    */
263   enable_ip_forwarding(olsr_cnf->ip_version);
264
265   /* Initialize parser */
266   olsr_init_parser();
267
268   /* Initialize route-exporter */
269   olsr_init_export_route();
270
271   /* Initialize message sequencnumber */
272   init_msg_seqno();
273
274   /* Initialize dynamic willingness calculation */
275   olsr_init_willingness();
276
277   /*
278    *Set up willingness/APM
279    */
280   if (olsr_cnf->willingness_auto) {
281     if (apm_init() < 0) {
282       OLSR_PRINTF(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
283
284       olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
285
286       olsr_cnf->willingness_auto = 0;
287       olsr_cnf->willingness = WILL_DEFAULT;
288     } else {
289       olsr_cnf->willingness = olsr_calculate_willingness();
290
291       OLSR_PRINTF(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, olsr_cnf->will_int);
292     }
293   }
294
295   /* Initializing networkinterfaces */
296   if (!ifinit()) {
297     if (olsr_cnf->allow_no_interfaces) {
298       fprintf(stderr,
299               "No interfaces detected! This might be intentional, but it also might mean that your configuration is fubar.\nI will continue after 5 seconds...\n");
300       sleep(5);
301     } else {
302       fprintf(stderr, "No interfaces detected!\nBailing out!\n");
303       olsr_exit(__func__, EXIT_FAILURE);
304     }
305   }
306
307   /* Print heartbeat to stdout */
308
309 #if !defined WINCE
310   if (olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO)) {
311     pulse_timer_cookie = olsr_alloc_cookie("Pulse", OLSR_COOKIE_TYPE_TIMER);
312     olsr_start_timer(STDOUT_PULSE_INT, 0, OLSR_TIMER_PERIODIC, &generate_stdout_pulse, NULL, pulse_timer_cookie->ci_id);
313   }
314 #endif
315
316   /* Initialize the IPC socket */
317
318   if (olsr_cnf->ipc_connections > 0) {
319     ipc_init();
320   }
321   /* Initialisation of different tables to be used. */
322   olsr_init_tables();
323
324   /* daemon mode */
325 #ifndef WIN32
326   if (olsr_cnf->debug_level == 0 && !olsr_cnf->no_fork) {
327     printf("%s detaching from the current process...\n", olsrd_version);
328     if (daemon(0, 0) < 0) {
329       printf("daemon(3) failed: %s\n", strerror(errno));
330       exit(EXIT_FAILURE);
331     }
332   }
333 #endif
334
335   /* Load plugins */
336   olsr_load_plugins();
337
338   /* activate LQ algorithm */
339   init_lq_handler();
340
341   OLSR_PRINTF(1, "Main address: %s\n\n", olsr_ip_to_string(&buf, &olsr_cnf->router_id));
342
343   /* Start syslog entry */
344   olsr_syslog(OLSR_LOG_INFO, "%s successfully started", olsrd_version);
345
346   /*
347    *signal-handlers
348    */
349
350   /* ctrl-C and friends */
351 #ifdef WIN32
352 #ifndef WINCE
353   SetConsoleCtrlHandler(SignalHandler, true);
354 #endif
355 #else
356   {
357     struct sigaction act;
358     sigemptyset(&act.sa_mask);
359     act.sa_flags = 0;
360     act.sa_handler = signal_reconfigure;
361     sigaction(SIGHUP, &act, NULL);
362     act.sa_handler = signal_shutdown;
363     sigaction(SIGINT, &act, NULL);
364     sigaction(SIGQUIT, &act, NULL);
365     sigaction(SIGILL, &act, NULL);
366     sigaction(SIGABRT, &act, NULL);
367 //  sigaction(SIGSEGV, &act, NULL);
368     sigaction(SIGTERM, &act, NULL);
369     act.sa_handler = SIG_IGN;
370     sigaction(SIGPIPE, &act, NULL);
371   }
372 #endif
373
374   link_changes = false;
375
376   /* Starting scheduler */
377   olsr_scheduler();
378
379   exitcode = olsr_cnf->exit_value;
380   switch (app_state) {
381   case STATE_RUNNING:
382     olsr_syslog(OLSR_LOG_ERR, "terminating and got \"running\"?");
383     exitcode = EXIT_FAILURE;
384     break;
385 #ifndef WIN32
386   case STATE_RECONFIGURE:
387     /* if we are started with -nofork, we do not weant to go into the
388      * background here. So we can simply be the child process.
389      */
390     switch (olsr_cnf->no_fork ? 0 : fork()) {
391       int i;
392     case 0:
393       /* child process */
394       for (i = sysconf(_SC_OPEN_MAX); --i > STDERR_FILENO;) {
395         close(i);
396       }
397       sleep(1);
398       printf("Restarting %s\n", argv[0]);
399       execv(argv[0], argv);
400       /* if we reach this, the exev() failed */
401       olsr_syslog(OLSR_LOG_ERR, "execv() failed: %s", strerror(errno));
402       /* and we simply shutdown */
403       exitcode = EXIT_FAILURE;
404       break;
405     case -1:
406       /* fork() failes */
407       olsr_syslog(OLSR_LOG_ERR, "fork() failed: %s", strerror(errno));
408       /* and we simply shutdown */
409       exitcode = EXIT_FAILURE;
410       break;
411     default:
412       /* parent process */
413       printf("RECONFIGURING!\n");
414       break;
415     }
416     /* fall through */
417 #endif
418   case STATE_SHUTDOWN:
419     olsr_shutdown();
420     break;
421   };
422
423   return exitcode;
424 }                               /* main */
425
426 #ifndef WIN32
427
428 /**
429  * Request reconfiguration of olsrd.
430  *
431  *@param signal the signal that triggered this callback
432  */
433 static void
434 signal_reconfigure(int signo)
435 {
436   const int save_errno = errno;
437   olsr_syslog(OLSR_LOG_INFO, "Received signal %d - requesting reconfiguration", signo);
438   app_state = STATE_RECONFIGURE;
439   errno = save_errno;
440 }
441
442 #endif
443
444 /**
445  *Function called at shutdown. Signal handler
446  *
447  * @param signal the signal that triggered this call
448  */
449 #ifdef WIN32
450 int __stdcall
451 SignalHandler(unsigned long signo)
452 #else
453 static void
454 signal_shutdown(int signo)
455 #endif
456 {
457   const int save_errno = errno;
458   olsr_syslog(OLSR_LOG_INFO, "Received signal %d - requesting shutdown", (int)signo);
459   app_state = STATE_SHUTDOWN;
460   errno = save_errno;
461 #ifdef WIN32
462   return 0;
463 #endif
464 }
465
466 static void
467 olsr_shutdown(void)
468 {
469   struct tc_entry *tc;
470   struct mid_entry *mid;
471   struct olsr_if_config *iface;
472
473   olsr_delete_all_kernel_routes();
474
475   /* Flush link state database */
476   OLSR_FOR_ALL_TC_ENTRIES(tc) {
477     olsr_delete_tc_entry(tc);
478   } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
479
480   /* Flush MID database */
481   OLSR_FOR_ALL_MID_ENTRIES(mid) {
482     olsr_delete_mid_entry(mid);
483   } OLSR_FOR_ALL_MID_ENTRIES_END(mid);
484
485   OLSR_PRINTF(1, "Closing sockets...\n");
486
487   /* Flush duplicate set */
488   olsr_flush_duplicate_entries();
489
490   /* front-end IPC socket */
491   if (olsr_cnf->ipc_connections > 0) {
492     shutdown_ipc();
493   }
494
495   /* Shut down LQ plugin */
496   deinit_lq_handler();
497
498   /* Closing plug-ins */
499   olsr_close_plugins();
500
501   /* Remove active interfaces */
502   for (iface = olsr_cnf->if_configs; iface != NULL; iface = iface->next) {
503     remove_interface(&iface->interf);
504   }
505
506   /* Reset network settings */
507   restore_settings(olsr_cnf->ip_version);
508
509   /* ioctl socket */
510   CLOSESOCKET(olsr_cnf->ioctl_s);
511
512 #if defined linux
513   CLOSESOCKET(olsr_cnf->rts_linux);
514 #endif
515
516 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
517   /* routing socket */
518   CLOSESOCKET(olsr_cnf->rts_bsd);
519 #endif
520
521   /* Close and delete all sockets */
522   olsr_flush_sockets();
523
524   /* Stop and delete all timers. */
525   olsr_flush_timers();
526
527   /* Free cookies and memory pools attached. */
528   olsr_delete_all_cookies();
529
530   /* Remove parser hooks */
531   olsr_deinit_parser();
532
533   /* Remove IP filters */
534   deinit_netfilters();
535
536   olsr_syslog(OLSR_LOG_INFO, "%s stopped", olsrd_version);
537
538   OLSR_PRINTF(1, "\n <<<< %s - terminating >>>>\n           http://www.olsr.org\n", olsrd_version);
539
540   olsr_log_cleanup();
541
542   /* Flush config */
543   olsr_free_cfg(olsr_cnf);
544 }
545
546 /*
547  * Local Variables:
548  * c-basic-offset: 2
549  * indent-tabs-mode: nil
550  * End:
551  */