3 * The olsr.org Optimized Link-State Routing daemon(olsrd)
4 * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
51 #include "scheduler.h"
53 #include "generate_msg.h"
54 #include "plugin_loader.h"
55 #include "socket_parser.h"
58 #include "build_msg.h"
61 #if LINUX_POLICY_ROUTING
62 #include <linux/types.h>
63 #include <linux/rtnetlink.h>
65 #include "kernel_routes.h"
69 #define close(x) closesocket(x)
70 int __stdcall SignalHandler(unsigned long signal) __attribute__ ((noreturn));
71 void ListInterfaces(void);
72 void DisableIcmpRedirects(void);
73 bool olsr_win32_end_request = false;
74 bool olsr_win32_end_flag = false;
76 static void olsr_shutdown(int) __attribute__ ((noreturn));
80 * Local function prototypes
82 void olsr_reconfigure(int) __attribute__ ((noreturn));
84 static void print_usage(void);
86 static int set_default_ifcnfs(struct olsr_if *, struct if_config_options *);
88 static int olsr_process_arguments(int, char *[], struct olsrd_config *, struct if_config_options *);
91 static char **olsr_argv;
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.";
102 main(int argc, char *argv[])
104 struct if_config_options *default_ifcnf;
105 char conf_file_name[FILENAME_MAX];
106 struct ipaddr_str buf;
112 /* paranoia checks */
113 assert(sizeof(uint8_t) == 1);
114 assert(sizeof(uint16_t) == 2);
115 assert(sizeof(uint32_t) == 4);
116 assert(sizeof(int8_t) == 1);
117 assert(sizeof(int16_t) == 2);
118 assert(sizeof(int32_t) == 4);
120 debug_handle = stdout;
124 setbuf(stdout, NULL);
125 setbuf(stderr, NULL);
128 /* Check if user is root */
130 fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n");
134 DisableIcmpRedirects();
136 if (WSAStartup(0x0202, &WsaData)) {
137 fprintf(stderr, "Could not initialize WinSock.\n");
138 olsr_exit(__func__, EXIT_FAILURE);
143 olsr_openlog("olsrd");
145 /* Grab initial timestamp */
146 now_times = olsr_times();
147 if ((clock_t)-1 == now_times) {
148 const char * const err_msg = strerror(errno);
149 olsr_syslog(OLSR_LOG_ERR, "Error in times(): %s, sleeping for a second", err_msg);
150 OLSR_PRINTF(1, "Error in times(): %s, sleeping for a second", err_msg);
152 now_times = olsr_times();
153 if ((clock_t)-1 == now_times) {
154 olsr_syslog(OLSR_LOG_ERR, "Shutting down because times() does not work");
155 fprintf(stderr, "Shutting down because times() does not work\n");
160 printf("\n *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host);
162 /* Using PID as random seed */
165 /* Init widely used statics */
166 memset(&all_zero, 0, sizeof(union olsr_ip_addr));
169 * Set configfile name and
170 * check if a configfile name was given as parameter
174 GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11);
176 conf_file_name[0] = 0;
179 len = strlen(conf_file_name);
181 if (len == 0 || conf_file_name[len - 1] != '\\')
182 conf_file_name[len++] = '\\';
184 strscpy(conf_file_name + len, "olsrd.conf", sizeof(conf_file_name) - len);
186 strscpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, sizeof(conf_file_name));
189 if ((argc > 1) && (strcmp(argv[1], "-f") == 0)) {
195 fprintf(stderr, "You must provide a filename when using the -f switch!\n");
199 if (stat(argv[1], &statbuf) < 0) {
200 fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", argv[1], strerror(errno));
204 strscpy(conf_file_name, argv[1], sizeof(conf_file_name));
211 * set up configuration prior to processing commandline options
213 if (NULL == (olsr_cnf = olsrd_parse_cnf(conf_file_name))) {
214 printf("Using default config values(no configfile)\n");
215 olsr_cnf = olsrd_get_default_cnf();
218 default_ifcnf = get_default_if_config();
219 if (default_ifcnf == NULL) {
220 fprintf(stderr, "No default ifconfig found!\n");
224 /* Initialize tick resolution */
226 olsr_cnf->system_tick_divider = 1000 / sysconf(_SC_CLK_TCK);
228 olsr_cnf->system_tick_divider = 1;
231 /* Initialize timers */
235 * Process olsrd options.
237 if (olsr_process_arguments(argc, argv, olsr_cnf, default_ifcnf) < 0) {
239 olsr_exit(__func__, EXIT_FAILURE);
243 * Set configuration for command-line specified interfaces
245 set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf);
247 /* free the default ifcnf */
250 /* Sanity check configuration */
251 if (olsrd_sanity_check_cnf(olsr_cnf) < 0) {
252 fprintf(stderr, "Bad configuration!\n");
253 olsr_exit(__func__, EXIT_FAILURE);
257 * Print configuration
259 if (olsr_cnf->debug_level > 1) {
260 olsrd_print_cnf(olsr_cnf);
263 /* Disable redirects globally */
264 disable_redirects_global(olsr_cnf->ip_version);
268 * socket for ioctl calls
270 olsr_cnf->ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0);
271 if (olsr_cnf->ioctl_s < 0) {
272 olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m");
273 olsr_exit(__func__, 0);
275 #if LINUX_POLICY_ROUTING
276 olsr_cnf->rtnl_s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
277 if (olsr_cnf->rtnl_s < 0) {
278 olsr_syslog(OLSR_LOG_ERR, "rtnetlink socket: %m");
279 olsr_exit(__func__, 0);
281 fcntl(olsr_cnf->rtnl_s, F_SETFL, O_NONBLOCK);
285 * create routing socket
287 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
288 olsr_cnf->rts = socket(PF_ROUTE, SOCK_RAW, 0);
289 if (olsr_cnf->rts < 0) {
290 olsr_syslog(OLSR_LOG_ERR, "routing socket: %m");
291 olsr_exit(__func__, 0);
295 /* Init empty TC timer */
296 set_empty_tc_timer(GET_TIMESTAMP(0));
299 *enable ip forwarding on host
301 enable_ip_forwarding(olsr_cnf->ip_version);
303 /* Initialize parser */
306 /* Initialize route-exporter */
307 olsr_init_export_route();
309 /* Initialize message sequencnumber */
312 /* Initialize dynamic willingness calculation */
313 olsr_init_willingness();
316 *Set up willingness/APM
318 if (olsr_cnf->willingness_auto) {
319 if (apm_init() < 0) {
320 OLSR_PRINTF(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
322 olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT);
324 olsr_cnf->willingness_auto = 0;
325 olsr_cnf->willingness = WILL_DEFAULT;
327 olsr_cnf->willingness = olsr_calculate_willingness();
329 OLSR_PRINTF(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, olsr_cnf->will_int);
336 #if LINUX_POLICY_ROUTING
337 /* Create rule for RtTable to resolve route insertion problems*/
338 if ( ( olsr_cnf->rttable < 253) & ( olsr_cnf->rttable > 0 ) ) {
339 olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_NEWRULE);
343 /* Initializing networkinterfaces */
345 if (olsr_cnf->allow_no_interfaces) {
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");
350 fprintf(stderr, "No interfaces detected!\nBailing out!\n");
351 olsr_exit(__func__, EXIT_FAILURE);
355 /* Print heartbeat to stdout */
358 if (olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO)) {
359 olsr_start_timer(STDOUT_PULSE_INT, 0, OLSR_TIMER_PERIODIC, &generate_stdout_pulse, NULL, 0);
363 /* Initialize the IPC socket */
365 if (olsr_cnf->ipc_connections > 0) {
368 /* Initialisation of different tables to be used. */
373 if (olsr_cnf->debug_level == 0 && !olsr_cnf->no_fork) {
374 printf("%s detaching from the current process...\n", olsrd_version);
375 if (daemon(0, 0) < 0) {
376 printf("daemon(3) failed: %s\n", strerror(errno));
385 OLSR_PRINTF(1, "Main address: %s\n\n", olsr_ip_to_string(&buf, &olsr_cnf->main_addr));
387 /* Start syslog entry */
388 olsr_syslog(OLSR_LOG_INFO, "%s successfully started", olsrd_version);
394 /* ctrl-C and friends */
397 SetConsoleCtrlHandler(SignalHandler, true);
400 signal(SIGHUP, olsr_reconfigure);
401 signal(SIGINT, olsr_shutdown);
402 signal(SIGQUIT, olsr_shutdown);
403 signal(SIGILL, olsr_shutdown);
404 signal(SIGABRT, olsr_shutdown);
405 // signal(SIGSEGV, olsr_shutdown);
406 signal(SIGTERM, olsr_shutdown);
407 signal(SIGPIPE, SIG_IGN);
410 link_changes = false;
412 /* Starting scheduler */
415 /* Like we're ever going to reach this ;-) */
420 * Reconfigure olsrd. Currently kind of a hack...
422 *@param signal the signal that triggered this callback
426 olsr_reconfigure(int signal __attribute__ ((unused)))
428 /* if we are started with -nofork, we do not weant to go into the
429 * background here. So we can simply stop on -HUP
431 olsr_syslog(OLSR_LOG_INFO, "sot: olsr_reconfigure()\n");
432 if (!olsr_cnf->no_fork) {
439 sigaddset(&sigs, SIGHUP);
440 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
441 for (i = sysconf(_SC_OPEN_MAX); --i > STDERR_FILENO; ) {
444 printf("Restarting %s\n", olsr_argv[0]);
445 olsr_syslog(OLSR_LOG_INFO, "Restarting %s\n", olsr_argv[0]);
446 execv(olsr_argv[0], olsr_argv);
447 olsr_syslog(OLSR_LOG_ERR, "execv(%s) fails: %s!\n", olsr_argv[0], strerror(errno));
450 olsr_syslog(OLSR_LOG_INFO, "RECONFIGURING!\n");
458 *Function called at shutdown. Signal handler
460 * @param signal the signal that triggered this call
464 SignalHandler(unsigned long signal)
467 olsr_shutdown(int signal __attribute__ ((unused)))
470 struct interface *ifn;
472 OLSR_PRINTF(1, "Received signal %d - shutting down\n", (int)signal);
475 OLSR_PRINTF(1, "Waiting for the scheduler to stop.\n");
477 olsr_win32_end_request = TRUE;
479 while (!olsr_win32_end_flag)
482 OLSR_PRINTF(1, "Scheduler stopped.\n");
485 olsr_delete_all_kernel_routes();
487 OLSR_PRINTF(1, "Closing sockets...\n");
489 /* front-end IPC socket */
490 if (olsr_cnf->ipc_connections > 0) {
495 for (ifn = ifnet; ifn; ifn = ifn->int_next)
496 close(ifn->olsr_socket);
498 /* Closing plug-ins */
499 olsr_close_plugins();
501 /* Reset network settings */
502 restore_settings(olsr_cnf->ip_version);
505 close(olsr_cnf->ioctl_s);
507 #if LINUX_POLICY_ROUTING
508 /* RtTable (linux only!!) */
509 if ( ( olsr_cnf->rttable < 253) & ( olsr_cnf->rttable > 0 ) ) {
510 olsr_netlink_rule(olsr_cnf->ip_version, olsr_cnf->rttable, RTM_DELRULE);
513 close(olsr_cnf->rtnl_s);
516 #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__
518 close(olsr_cnf->rts);
521 /* Free cookies and memory pools attached. */
522 olsr_delete_all_cookies();
524 olsr_syslog(OLSR_LOG_INFO, "%s stopped", olsrd_version);
526 OLSR_PRINTF(1, "\n <<<< %s - terminating >>>>\n http://www.olsr.org\n", olsrd_version);
528 exit(olsr_cnf->exit_value);
532 * Print the command line usage
539 "An error occured somwhere between your keyboard and your chair!\n"
540 "usage: olsrd [-f <configfile>] [ -i interface1 interface2 ... ]\n"
541 " [-d <debug_level>] [-ipv6] [-multi <IPv6 multicast address>]\n"
542 " [-lql <LQ level>] [-lqw <LQ winsize>] [-lqnt <nat threshold>]\n"
543 " [-bcast <broadcastaddr>] [-ipc] [-dispin] [-dispout] [-delgw]\n"
544 " [-hint <hello interval (secs)>] [-tcint <tc interval (secs)>]\n"
545 " [-midint <mid interval (secs)>] [-hnaint <hna interval (secs)>]\n"
546 " [-T <Polling Rate (secs)>] [-nofork] [-hemu <ip_address>]\n" " [-lql <LQ level>] [-lqa <LQ aging factor>]\n");
550 * Sets the provided configuration on all unconfigured
553 * @param ifs a linked list of interfaces to check and possible update
554 * @param cnf the default configuration to set on unconfigured interfaces
557 set_default_ifcnfs(struct olsr_if *ifs, struct if_config_options *cnf)
562 if (ifs->cnf == NULL) {
563 ifs->cnf = olsr_malloc(sizeof(struct if_config_options), "Set default config");
572 #define NEXT_ARG do { argv++;argc--; } while (0)
573 #define CHECK_ARGC do { if(!argc) { \
574 if((argc - 1) == 1){ \
575 fprintf(stderr, "Error parsing command line options!\n"); \
578 fprintf(stderr, "You must provide a parameter when using the %s switch!\n", *argv); \
580 olsr_exit(__func__, EXIT_FAILURE); \
584 * Process command line arguments passed to olsrd
588 olsr_process_arguments(int argc, char *argv[], struct olsrd_config *cnf, struct if_config_options *ifcnf)
596 if (strcmp(*argv, "-int") == 0) {
605 if (strcmp(*argv, "-f") == 0) {
606 fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n");
607 olsr_exit(__func__, EXIT_FAILURE);
613 if (strcmp(*argv, "-ipv6") == 0) {
614 cnf->ip_version = AF_INET6;
621 if (strcmp(*argv, "-bcast") == 0) {
626 if (inet_aton(*argv, &in) == 0) {
627 printf("Invalid broadcast address! %s\nSkipping it!\n", *argv);
630 memcpy(&ifcnf->ipv4_broadcast.v4, &in.s_addr, sizeof(uint32_t));
637 if (strcmp(*argv, "-lql") == 0) {
642 /* Sanity checking is done later */
643 sscanf(*argv, "%d", &tmp_lq_level);
644 olsr_cnf->lq_level = tmp_lq_level;
651 if (strcmp(*argv, "-lqa") == 0) {
656 sscanf(*argv, "%f", &tmp_lq_aging);
658 if (tmp_lq_aging < MIN_LQ_AGING || tmp_lq_aging > MAX_LQ_AGING) {
659 printf("LQ aging factor %f not allowed. Range [%f-%f]\n", tmp_lq_aging, MIN_LQ_AGING, MAX_LQ_AGING);
660 olsr_exit(__func__, EXIT_FAILURE);
662 olsr_cnf->lq_aging = tmp_lq_aging;
669 if (strcmp(*argv, "-lqnt") == 0) {
670 float tmp_lq_nat_thresh;
674 sscanf(*argv, "%f", &tmp_lq_nat_thresh);
676 if (tmp_lq_nat_thresh < 0.1 || tmp_lq_nat_thresh > 1.0) {
677 printf("NAT threshold %f not allowed. Range [%f-%f]\n", tmp_lq_nat_thresh, 0.1, 1.0);
678 olsr_exit(__func__, EXIT_FAILURE);
680 olsr_cnf->lq_nat_thresh = tmp_lq_nat_thresh;
685 * Enable additional debugging information to be logged.
687 if (strcmp(*argv, "-d") == 0) {
691 sscanf(*argv, "%d", &cnf->debug_level);
696 * Interfaces to be used by olsrd.
698 if (strcmp(*argv, "-i") == 0) {
702 if (*argv[0] == '-') {
703 fprintf(stderr, "You must provide an interface label!\n");
704 olsr_exit(__func__, EXIT_FAILURE);
706 printf("Queuing if %s\n", *argv);
707 queue_if(*argv, false);
709 while ((argc - 1) && (argv[1][0] != '-')) {
711 printf("Queuing if %s\n", *argv);
712 queue_if(*argv, false);
718 * Set the hello interval to be used by olsrd.
721 if (strcmp(*argv, "-hint") == 0) {
724 sscanf(*argv, "%f", &ifcnf->hello_params.emission_interval);
725 ifcnf->hello_params.validity_time = ifcnf->hello_params.emission_interval * 3;
730 * Set the HNA interval to be used by olsrd.
733 if (strcmp(*argv, "-hnaint") == 0) {
736 sscanf(*argv, "%f", &ifcnf->hna_params.emission_interval);
737 ifcnf->hna_params.validity_time = ifcnf->hna_params.emission_interval * 3;
742 * Set the MID interval to be used by olsrd.
745 if (strcmp(*argv, "-midint") == 0) {
748 sscanf(*argv, "%f", &ifcnf->mid_params.emission_interval);
749 ifcnf->mid_params.validity_time = ifcnf->mid_params.emission_interval * 3;
754 * Set the tc interval to be used by olsrd.
757 if (strcmp(*argv, "-tcint") == 0) {
760 sscanf(*argv, "%f", &ifcnf->tc_params.emission_interval);
761 ifcnf->tc_params.validity_time = ifcnf->tc_params.emission_interval * 3;
766 * Set the polling interval to be used by olsrd.
768 if (strcmp(*argv, "-T") == 0) {
771 sscanf(*argv, "%f", &cnf->pollrate);
776 * Should we display the contents of packages beeing sent?
778 if (strcmp(*argv, "-dispin") == 0) {
779 parser_set_disp_pack_in(true);
784 * Should we display the contents of incoming packages?
786 if (strcmp(*argv, "-dispout") == 0) {
787 net_set_disp_pack_out(true);
792 * Should we set up and send on a IPC socket for the front-end?
794 if (strcmp(*argv, "-ipc") == 0) {
795 cnf->ipc_connections = 1;
800 * IPv6 multicast addr
802 if (strcmp(*argv, "-multi") == 0) {
806 if (inet_pton(AF_INET6, *argv, &in6) <= 0) {
807 fprintf(stderr, "Failed converting IP address %s\n", *argv);
811 memcpy(&ifcnf->ipv6_multi_glbl, &in6, sizeof(struct in6_addr));
819 if (strcmp(*argv, "-hemu") == 0) {
825 if (inet_pton(AF_INET, *argv, &in) <= 0) {
826 fprintf(stderr, "Failed converting IP address %s\n", *argv);
829 /* Add hemu interface */
831 ifa = queue_if("hcif01", true);
836 ifa->cnf = get_default_if_config();
837 ifa->host_emul = true;
838 memcpy(&ifa->hemu_ip, &in, sizeof(union olsr_ip_addr));
839 cnf->host_emul = true;
845 * Delete possible default GWs
847 if (strcmp(*argv, "-delgw") == 0) {
848 olsr_cnf->del_gws = true;
852 if (strcmp(*argv, "-nofork") == 0) {
863 * A wrapper around times(2). Note, that this function has
864 * some portability problems, e.g. different operating systems
865 * and linux kernel versions may return values counted from
866 * an arbitrary point in time (mostly uptime, some count from
867 * the epoch. The linux man page therefore recommends not to
868 * use this function. On the other hand, this function has
869 * proved it's functions but some olsrd implementations does
870 * error handling in a clumsy way - thus inducing bugs...
876 clock_t t=times(&tms_buf);
877 if ( t >=0 ) return t;
879 const char *const err_msg = strerror(errno);
880 olsr_syslog(OLSR_LOG_ERR,"Time error: '%s' (%d)", err_msg, errno);
882 return -1; /* todo: only on 'unrecoverable' errors (like errno=14) */
884 /* todo: read syslog and learn error codes
885 * which we can safely "ignore" -> return 0; */
888 olsr_syslog(OLSR_LOG_ERR,"WARNING: times() reported negative result %i which olsr ignored (Did time went backwards ?)", t);
889 /* report time went backwards to syslog */
897 * indent-tabs-mode: nil