/* * The olsr.org Optimized Link-State Routing daemon(olsrd) * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of olsr.org, olsrd nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Visit http://www.olsr.org for more information. * * If you find this software useful feel free to make a donation * to the project. For more information see the website or contact * the copyright holders. * * $Id: main.c,v 1.100 2007/09/17 22:24:22 bernd67 Exp $ */ #include #include #include #include "defs.h" #include "olsr.h" #include "log.h" #include "scheduler.h" #include "parser.h" #include "generate_msg.h" #include "plugin_loader.h" #include "socket_parser.h" #include "apm.h" #include "net_os.h" #include "build_msg.h" #if LINUX_POLICY_ROUTING #include #include #include #endif /* Global stuff externed in defs.h */ FILE *debug_handle; /* Where to send debug(defaults to stdout) */ struct olsrd_config *olsr_cnf; /* The global configuration */ #ifdef WIN32 #define close(x) closesocket(x) int __stdcall SignalHandler(unsigned long signal) __attribute__((noreturn)); void ListInterfaces(void); void DisableIcmpRedirects(void); olsr_bool olsr_win32_end_request = OLSR_FALSE; olsr_bool olsr_win32_end_flag = OLSR_FALSE; #else static void olsr_shutdown(int) __attribute__((noreturn)); #endif /* * Local function prototypes */ void olsr_reconfigure(int) __attribute__((noreturn)); static void print_usage(void); static int set_default_ifcnfs(struct olsr_if *, struct if_config_options *); static int olsr_process_arguments(int, char *[], struct olsrd_config *, struct if_config_options *); static char **olsr_argv; static char copyright_string[] = "The olsr.org Optimized Link-State Routing daemon(olsrd) Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org) All rights reserved."; /** * Main entrypoint */ int main(int argc, char *argv[]) { struct if_config_options *default_ifcnf; char conf_file_name[FILENAME_MAX]; struct tms tms_buf; #ifdef WIN32 WSADATA WsaData; int len; #endif /* Stop the compiler from complaining */ (void)copyright_string; debug_handle = stdout; olsr_argv = argv; setbuf(stdout, NULL); setbuf(stderr, NULL); #ifndef WIN32 /* Check if user is root */ if(geteuid()) { fprintf(stderr, "You must be root(uid = 0) to run olsrd!\nExiting\n\n"); exit(EXIT_FAILURE); } #else DisableIcmpRedirects(); if (WSAStartup(0x0202, &WsaData)) { fprintf(stderr, "Could not initialize WinSock.\n"); olsr_exit(__func__, EXIT_FAILURE); } #endif /* Grab initial timestamp */ now_times = times(&tms_buf); /* Open syslog */ olsr_openlog("olsrd"); /* Get initial timestep */ nowtm = NULL; while (nowtm == NULL) { nowtm = localtime((time_t *)&now.tv_sec); } printf("\n *** %s ***\n Build date: %s on %s\n http://www.olsr.org\n\n", olsrd_version, build_date, build_host); /* Using PID as random seed */ srandom(getpid()); /* * Set configfile name and * check if a configfile name was given as parameter */ #ifdef WIN32 #ifndef WINCE GetWindowsDirectory(conf_file_name, FILENAME_MAX - 11); #else conf_file_name[0] = 0; #endif len = strlen(conf_file_name); if (len == 0 || conf_file_name[len - 1] != '\\') conf_file_name[len++] = '\\'; strcpy(conf_file_name + len, "olsrd.conf"); #else strncpy(conf_file_name, OLSRD_GLOBAL_CONF_FILE, FILENAME_MAX); #endif if ((argc > 1) && (strcmp(argv[1], "-f") == 0)) { struct stat statbuf; argv++; argc--; if(argc == 1) { fprintf(stderr, "You must provide a filename when using the -f switch!\n"); exit(EXIT_FAILURE); } if (stat(argv[1], &statbuf) < 0) { fprintf(stderr, "Could not find specified config file %s!\n%s\n\n", argv[1], strerror(errno)); exit(EXIT_FAILURE); } strncpy(conf_file_name, argv[1], FILENAME_MAX); argv++; argc--; } /* * set up configuration prior to processing commandline options */ if((olsr_cnf = olsrd_parse_cnf(conf_file_name)) == NULL) { printf("Using default config values(no configfile)\n"); olsr_cnf = olsrd_get_default_cnf(); } if((default_ifcnf = get_default_if_config()) == NULL) { fprintf(stderr, "No default ifconfig found!\n"); exit(EXIT_FAILURE); } /* Initialize tick resolution */ #ifndef WIN32 olsr_cnf->system_tick_divider = 1000/sysconf(_SC_CLK_TCK); #else olsr_cnf->system_tick_divider = 1; #endif /* * Process olsrd options. */ if(olsr_process_arguments(argc, argv, olsr_cnf, default_ifcnf) < 0) { print_usage(); olsr_exit(__func__, EXIT_FAILURE); } /* * Set configuration for command-line specified interfaces */ set_default_ifcnfs(olsr_cnf->interfaces, default_ifcnf); /* free the default ifcnf */ free(default_ifcnf); /* Sanity check configuration */ if(olsrd_sanity_check_cnf(olsr_cnf) < 0) { fprintf(stderr, "Bad configuration!\n"); olsr_exit(__func__, EXIT_FAILURE); } /* * Print configuration */ if(olsr_cnf->debug_level > 1) olsrd_print_cnf(olsr_cnf); #ifndef WIN32 /* Disable redirects globally */ disable_redirects_global(olsr_cnf->ip_version); #endif /* *socket for icotl calls */ if ((olsr_cnf->ioctl_s = socket(olsr_cnf->ip_version, SOCK_DGRAM, 0)) < 0) { olsr_syslog(OLSR_LOG_ERR, "ioctl socket: %m"); olsr_exit(__func__, 0); } #if LINUX_POLICY_ROUTING if ((olsr_cnf->rtnl_s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { olsr_syslog(OLSR_LOG_ERR, "rtnetlink socket: %m"); olsr_exit(__func__, 0); } fcntl(olsr_cnf->rtnl_s, F_SETFL, O_NONBLOCK); #endif #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__ if ((olsr_cnf->rts = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { olsr_syslog(OLSR_LOG_ERR, "routing socket: %m"); olsr_exit(__func__, 0); } #endif /* Init empty TC timer */ set_empty_tc_timer(GET_TIMESTAMP(0)); /* *enable ip forwarding on host */ enable_ip_forwarding(olsr_cnf->ip_version); /* Initialize parser */ olsr_init_parser(); /* Initialize route-exporter */ olsr_init_export_route(); /* Initialize message sequencnumber */ init_msg_seqno(); /* Initialize dynamic willingness calculation */ olsr_init_willingness(); /* *Set up willingness/APM */ if(olsr_cnf->willingness_auto) { if(apm_init() < 0) { OLSR_PRINTF(1, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT); olsr_syslog(OLSR_LOG_ERR, "Could not read APM info - setting default willingness(%d)\n", WILL_DEFAULT); olsr_cnf->willingness_auto = 0; olsr_cnf->willingness = WILL_DEFAULT; } else { olsr_cnf->willingness = olsr_calculate_willingness(); OLSR_PRINTF(1, "Willingness set to %d - next update in %.1f secs\n", olsr_cnf->willingness, olsr_cnf->will_int); } } /* Set ipsize */ if(olsr_cnf->ip_version == AF_INET6) { OLSR_PRINTF(1, "Using IP version %d\n", 6); olsr_cnf->ipsize = sizeof(struct in6_addr); olsr_cnf->maxplen = 128; } else { OLSR_PRINTF(1, "Using IP version %d\n", 4); olsr_cnf->ipsize = sizeof(struct in_addr); olsr_cnf->maxplen = 32; } /* Initialize net */ init_net(); /* Initializing networkinterfaces */ if(!ifinit()) { if(olsr_cnf->allow_no_interfaces) { fprintf(stderr, "No interfaces detected! This might be intentional, but it also might mean that your configuration is fubar.\nI will continue after 5 seconds...\n"); sleep(5); } else { fprintf(stderr, "No interfaces detected!\nBailing out!\n"); olsr_exit(__func__, EXIT_FAILURE); } } /* Print heartbeat to stdout */ #if !defined WINCE if(olsr_cnf->debug_level > 0 && isatty(STDOUT_FILENO)) olsr_register_scheduler_event(&generate_stdout_pulse, NULL, STDOUT_PULSE_INT, 0, NULL); #endif gettimeofday(&now, NULL); /* Initialize the IPC socket */ if(olsr_cnf->open_ipc) ipc_init(); /* Initialisation of different tables to be used.*/ olsr_init_tables(); /* daemon mode */ #ifndef WIN32 if((olsr_cnf->debug_level == 0) && (!olsr_cnf->no_fork)) { printf("%s detaching from the current process...\n", olsrd_version); if(daemon(0, 0) < 0) { printf("daemon(3) failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } #endif /* Load plugins */ olsr_load_plugins(); OLSR_PRINTF(1, "Main address: %s\n\n", olsr_ip_to_string(&olsr_cnf->main_addr)); /* Start syslog entry */ olsr_syslog(OLSR_LOG_INFO, "%s successfully started", olsrd_version); /* *signal-handlers */ /* ctrl-C and friends */ #ifdef WIN32 #ifndef WINCE SetConsoleCtrlHandler(SignalHandler, OLSR_TRUE); #endif #else signal(SIGHUP, olsr_reconfigure); signal(SIGINT, olsr_shutdown); signal(SIGTERM, olsr_shutdown); signal(SIGPIPE, SIG_IGN); #endif /* Register socket poll event */ olsr_register_timeout_function(&poll_sockets, OLSR_FALSE); /* Starting scheduler */ scheduler(); /* Stop the compiler from complaining */ (void)copyright_string; /* Like we're ever going to reach this ;-) */ return 1; } /* main */ /** * Reconfigure olsrd. Currently kind of a hack... * *@param signal the signal that triggered this callback */ #ifndef WIN32 void olsr_reconfigure(int signal __attribute__((unused))) { if(!fork()) { /* New process */ sleep(3); printf("Restarting %s\n", olsr_argv[0]); execv(olsr_argv[0], olsr_argv); } olsr_shutdown(0); printf("RECONFIGURING!\n"); } #endif /** *Function called at shutdown. Signal handler * * @param signal the signal that triggered this call */ #ifdef WIN32 int __stdcall SignalHandler(unsigned long signal) #else static void olsr_shutdown(int signal) #endif { struct interface *ifn; OLSR_PRINTF(1, "Received signal %d - shutting down\n", (int)signal); #ifdef WIN32 OLSR_PRINTF(1, "Waiting for the scheduler to stop.\n"); olsr_win32_end_request = TRUE; while (!olsr_win32_end_flag) Sleep(100); OLSR_PRINTF(1, "Scheduler stopped.\n"); #endif olsr_delete_all_kernel_routes(); OLSR_PRINTF(1, "Closing sockets...\n"); /* front-end IPC socket */ if(olsr_cnf->open_ipc) shutdown_ipc(); /* OLSR sockets */ for (ifn = ifnet; ifn; ifn = ifn->int_next) close(ifn->olsr_socket); /* Closing plug-ins */ olsr_close_plugins(); /* Reset network settings */ restore_settings(olsr_cnf->ip_version); /* ioctl socket */ close(olsr_cnf->ioctl_s); #if LINUX_POLICY_ROUTING close(olsr_cnf->rtnl_s); #endif #if defined __FreeBSD__ || defined __MacOSX__ || defined __NetBSD__ || defined __OpenBSD__ /* routing socket */ close(olsr_cnf->rts); #endif olsr_syslog(OLSR_LOG_INFO, "%s stopped", olsrd_version); OLSR_PRINTF(1, "\n <<<< %s - terminating >>>>\n http://www.olsr.org\n", olsrd_version); exit(olsr_cnf->exit_value); } /** * Print the command line usage */ static void print_usage(void) { fprintf(stderr, "An error occured somwhere between your keyboard and your chair!\n" "usage: olsrd [-f ] [ -i interface1 interface2 ... ]\n" " [-d ] [-ipv6] [-multi ]\n" " [-lql ] [-lqw ]\n" " [-bcast ] [-ipc] [-dispin] [-dispout] [-delgw]\n" " [-hint ] [-tcint ]\n" " [-midint ] [-hnaint ]\n" " [-T ] [-nofork] [-hemu ]\n" " [-lql ] [-lqw ]\n"); } /** * Sets the provided configuration on all unconfigured * interfaces * * @param ifs a linked list of interfaces to check and possible update * @param cnf the default configuration to set on unconfigured interfaces */ int set_default_ifcnfs(struct olsr_if *ifs, struct if_config_options *cnf) { int changes = 0; while(ifs) { if(ifs->cnf == NULL) { ifs->cnf = olsr_malloc(sizeof(struct if_config_options), "Set default config"); *ifs->cnf = *cnf; changes++; } ifs = ifs->next; } return changes; } #define NEXT_ARG argv++;argc-- #define CHECK_ARGC if(!argc) { \ if((argc - 1) == 1){ \ fprintf(stderr, "Error parsing command line options!\n"); \ olsr_exit(__func__, EXIT_FAILURE); \ } else { \ argv--; \ fprintf(stderr, "You must provide a parameter when using the %s switch!\n", *argv); \ olsr_exit(__func__, EXIT_FAILURE); \ } \ } /** * Process command line arguments passed to olsrd * */ static int olsr_process_arguments(int argc, char *argv[], struct olsrd_config *cnf, struct if_config_options *ifcnf) { while (argc > 1) { NEXT_ARG; #ifdef WIN32 /* *Interface list */ if (strcmp(*argv, "-int") == 0) { ListInterfaces(); exit(0); } #endif /* *Configfilename */ if(strcmp(*argv, "-f") == 0) { fprintf(stderr, "Configfilename must ALWAYS be first argument!\n\n"); olsr_exit(__func__, EXIT_FAILURE); } /* *Use IP version 6 */ if(strcmp(*argv, "-ipv6") == 0) { cnf->ip_version = AF_INET6; continue; } /* *Broadcast address */ if(strcmp(*argv, "-bcast") == 0) { struct in_addr in; NEXT_ARG; CHECK_ARGC; if (inet_aton(*argv, &in) == 0) { printf("Invalid broadcast address! %s\nSkipping it!\n", *argv); continue; } memcpy(&ifcnf->ipv4_broadcast.v4, &in.s_addr, sizeof(olsr_u32_t)); continue; } /* * Set LQ level */ if (strcmp(*argv, "-lql") == 0) { int tmp_lq_level; NEXT_ARG; CHECK_ARGC; /* Sanity checking is done later */ sscanf(*argv, "%d", &tmp_lq_level); olsr_cnf->lq_level = tmp_lq_level; continue; } /* * Set LQ winsize */ if (strcmp(*argv, "-lqw") == 0) { int tmp_lq_wsize; NEXT_ARG; CHECK_ARGC; sscanf(*argv, "%d", &tmp_lq_wsize); if(tmp_lq_wsize < MIN_LQ_WSIZE || tmp_lq_wsize > MAX_LQ_WSIZE) { printf("LQ winsize %d not allowed. Range [%d-%d]\n", tmp_lq_wsize, MIN_LQ_WSIZE, MAX_LQ_WSIZE); olsr_exit(__func__, EXIT_FAILURE); } olsr_cnf->lq_wsize = tmp_lq_wsize; continue; } /* * Enable additional debugging information to be logged. */ if (strcmp(*argv, "-d") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%d", &cnf->debug_level); continue; } /* * Interfaces to be used by olsrd. */ if (strcmp(*argv, "-i") == 0) { NEXT_ARG; CHECK_ARGC; if(*argv[0] == '-') { fprintf(stderr, "You must provide an interface label!\n"); olsr_exit(__func__, EXIT_FAILURE); } printf("Queuing if %s\n", *argv); queue_if(*argv, OLSR_FALSE); while((argc - 1) && (argv[1][0] != '-')) { NEXT_ARG; printf("Queuing if %s\n", *argv); queue_if(*argv, OLSR_FALSE); } continue; } /* * Set the hello interval to be used by olsrd. * */ if (strcmp(*argv, "-hint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%f", &ifcnf->hello_params.emission_interval); ifcnf->hello_params.validity_time = ifcnf->hello_params.emission_interval * 3; continue; } /* * Set the HNA interval to be used by olsrd. * */ if (strcmp(*argv, "-hnaint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%f", &ifcnf->hna_params.emission_interval); ifcnf->hna_params.validity_time = ifcnf->hna_params.emission_interval * 3; continue; } /* * Set the MID interval to be used by olsrd. * */ if (strcmp(*argv, "-midint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%f", &ifcnf->mid_params.emission_interval); ifcnf->mid_params.validity_time = ifcnf->mid_params.emission_interval * 3; continue; } /* * Set the tc interval to be used by olsrd. * */ if (strcmp(*argv, "-tcint") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%f", &ifcnf->tc_params.emission_interval); ifcnf->tc_params.validity_time = ifcnf->tc_params.emission_interval * 3; continue; } /* * Set the polling interval to be used by olsrd. */ if (strcmp(*argv, "-T") == 0) { NEXT_ARG; CHECK_ARGC; sscanf(*argv,"%f",&cnf->pollrate); continue; } /* * Should we display the contents of packages beeing sent? */ if (strcmp(*argv, "-dispin") == 0) { parser_set_disp_pack_in(OLSR_TRUE); continue; } /* * Should we display the contents of incoming packages? */ if (strcmp(*argv, "-dispout") == 0) { net_set_disp_pack_out(OLSR_TRUE); continue; } /* * Should we set up and send on a IPC socket for the front-end? */ if (strcmp(*argv, "-ipc") == 0) { cnf->ipc_connections = 1; cnf->open_ipc = OLSR_TRUE; continue; } /* * IPv6 multicast addr */ if (strcmp(*argv, "-multi") == 0) { struct in6_addr in6; NEXT_ARG; CHECK_ARGC; if(inet_pton(AF_INET6, *argv, &in6) <= 0) { fprintf(stderr, "Failed converting IP address %s\n", *argv); exit(EXIT_FAILURE); } memcpy(&ifcnf->ipv6_multi_glbl, &in6, sizeof(struct in6_addr)); continue; } /* * Host emulation */ if (strcmp(*argv, "-hemu") == 0) { struct in_addr in; struct olsr_if *ifa; NEXT_ARG; CHECK_ARGC; if(inet_pton(AF_INET, *argv, &in) <= 0) { fprintf(stderr, "Failed converting IP address %s\n", *argv); exit(EXIT_FAILURE); } /* Add hemu interface */ ifa = queue_if("hcif01", OLSR_TRUE); if(!ifa) continue; ifa->cnf = get_default_if_config(); ifa->host_emul = OLSR_TRUE; memcpy(&ifa->hemu_ip, &in, sizeof(union olsr_ip_addr)); cnf->host_emul = OLSR_TRUE; continue; } /* * Delete possible default GWs */ if (strcmp(*argv, "-delgw") == 0) { olsr_cnf->del_gws = OLSR_TRUE; continue; } if (strcmp(*argv, "-nofork") == 0) { cnf->no_fork = OLSR_TRUE; continue; } return -1; } return 0; }