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