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