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