Example #1
0
int main (int argc, char *argv[])
{
    char cfg_file[256];
    char app_name[256];
    char* p;

    p = strrchr(argv[0], '/');
    snprintf(app_name, sizeof(app_name), "%s", p+1);

    /* -- get the config filename -- */
    switch (sys_getopt(argc, argv, "c:", cfg_file, sizeof(cfg_file))) {
        case 'c':
#ifdef __DEBUG__
            fprintf(stdout, "config file = [%s]\n", cfg_file);
#endif
            if (0 != Config::load(cfg_file)) {
                fprintf(stderr, "%s: Unable to load config file [%s]!!!\n", app_name, cfg_file);
                exit(-1);
            }
            break;
        default:
            usage(argv[0]);
            exit(0);
    }

    /* -- check if already running -- */
    if (0 != sys_bind(Config::getLockPort())) {
        fprintf(stderr, "%s: Unable to continue, make sure there's no other instance running!!!\n", app_name);
        exit(-1);
    }

    /* -- initialize log -- */
    LOG_INIT(Config::getLogFile(), Config::getLogLevel());

    /* -- check if logger is successfully initialized -- */
    if (0 != LOG_GET_STATUS()) {
        fprintf(stderr, "%s: Unable to initialize logger!\n", app_name);
        exit(-1);
    }

    /* -- initialize libsqlora8 -- */
    if (OraDB::init_lib(true) < 0) {
        LOG_CRITICAL("%s: Unable to initialize libsqlora8!", app_name);
        exit(-1);
    }

    /* -- load system messages from db -- */
    if (0 != Sysmsg::load(Config::getOraAuth(), Config::getBrand())) {
        LOG_CRITICAL("%s: Unable to load system messages from db (%s).", app_name, Config::getOraAuth());
        exit(-1);
    }

    /* -- load services from db -- */
    if (0 != Global::loadRC(Config::getOraAuth(), Config::getLibraryPath(), Config::getBrand())) {
        LOG_CRITICAL("%s: Unable to load services from db (%s).", app_name, Config::getOraAuth());
        exit(-1);
    }

    /* -- initialize request queue -- */
    if (0 != c2q_init(Global::getRequestQ())) {
        LOG_CRITICAL("%s: Unable to initialize request queue!", app_name);
        exit(-1);
    }

    /* -- initialize transaction queue -- */
    if (0 != c2q_init(Global::getTransactionQ())) {
        LOG_CRITICAL("%s: Unable to initialize transaction queue!", app_name);
        exit(-1);
    }

    /* -- initialize response queue -- */
    if (0 != c2q_init(Global::getResponseQ())) {
        LOG_CRITICAL("%s: Unable to initialize response queue!", app_name);
        exit(-1);
    }

    /* -- initialize notification queue -- */
    if (0 != c2q_init(Global::getNotificationQ())) {
        LOG_CRITICAL("%s: Unable to initialize notification queue!", app_name);
        exit(-1);
    }

    /* -- initialize queue -- */
    int rc_size = Global::getRCSize();
    LOG_DEBUG("%s: rc_size: %d", app_name, rc_size);
    if (Global::initTransactionQ(rc_size) < 0) {
        LOG_CRITICAL("%s: Unable to initialize transaction queue!", app_name);
        exit(-1);
    }
    int tran_size = Global::getTransactionQSize();
    LOG_DEBUG("%s: tran_size: %d", app_name, tran_size);
    for (int i=0; i<tran_size; ++i) {
        if (0 != c2q_init(Global::getTransactionQ(i))) {
            LOG_CRITICAL("%s: Unable to initialize transaction queue: %d!", app_name, i);
            exit(-1);
        }
    }

    /* -- initialize geoprobe queue -- */
    if (0 != c2q_init(Global::getGeoProbeQ())) {
        LOG_CRITICAL("%s: Unable to initialize geoprobe queue!", app_name);
        exit(-1);
    }

    /* -- initialize ods queue -- */
    if (0 != c2q_init(Global::getODSQ())) {
        LOG_CRITICAL("%s: Unable to initialize ods queue!", app_name);
        exit(-1);
    }

    /* -- initialize ccb queue -- */
    if (0 != c2q_init(Global::getCCBQ())) {
        LOG_CRITICAL("%s: Unable to initialize ccb queue!", app_name);
        exit(-1);
    }

    /* -- initialize conditioner queue -- */
    if (0 != c2q_init(Global::getConditionerQ())) {
        LOG_CRITICAL("%s: Unable to initialize conditioner queue!", app_name);
        exit(-1);
    }

    /* -- initialize voyager queue -- */
    if (0 != c2q_init(Global::getVoyagerQ())) {
        LOG_CRITICAL("%s: Unable to initialize voyager queue!", app_name);
        exit(-1);
    }


    /* -- run in background -- */
    sys_daemon();

    /* -- block all signals -- */
    sys_sigblock();

    // Thread attributes
    pthread_attr_t pthread_attr_norm;
    pthread_attr_init(&pthread_attr_norm);
    pthread_attr_setstacksize(&pthread_attr_norm, Global::thr_stack_size);

    std::vector<pthread_t> thrs;

    // Signal handler
    pthread_t signal_thr;
    if (0 != pthread_create(&signal_thr, &pthread_attr_norm, signal_handler, NULL)) {
        LOG_CRITICAL("%s: Unable to create signal_handler thread!!!", app_name);
        exit(-1);
    }
    thrs.push_back(signal_thr);

    // Response handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t response_thr;
        if (0 != pthread_create(&response_thr, &pthread_attr_norm, response_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create response_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(response_thr);
    }

    // Notification handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t notification_thr;
        if (0 != pthread_create(&notification_thr, &pthread_attr_norm, notification_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create notification_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(notification_thr);
    }

    // Transaction fetcher
    int proc_id = 0;
    int step_no = 0;
    rc_t* rc;
    while ((rc = Global::getNextRC(step_no))) {
        rc_proc_t* rc_proc = new(rc_proc_t);
        rc_proc->rc = rc;
        rc_proc->proc_id = proc_id;
        rc_proc->parent_id = -1;
        rc_proc->ppid = getpid();
        pthread_t tran_fetcher_thr;
        if (0 != pthread_create(&tran_fetcher_thr, &pthread_attr_norm, transaction_fetcher, (void*) rc_proc)) {
            LOG_CRITICAL("%s: Unable to create transaction_fetcher thread (%d)!!!", app_name, proc_id);
            abort();
        }
        thrs.push_back(tran_fetcher_thr);
        step_no = rc->step_no;
        proc_id++;
    }

    // Request handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t request_thr;
        if (0 != pthread_create(&request_thr, &pthread_attr_norm, request_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create request_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(request_thr);
    }

    // Request fetcher
    pthread_t request_fetcher_thr;
    if (0 != pthread_create(&request_fetcher_thr, &pthread_attr_norm, request_fetcher, NULL)) {
        LOG_CRITICAL("%s: Unable to create request_fetcher thread!!!", app_name);
        abort();
    }
    thrs.push_back(request_fetcher_thr);

    // Raw handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t raw_thr;
        if (0 != pthread_create(&raw_thr, &pthread_attr_norm, raw_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create raw_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(raw_thr);
    }

    // Raw fetcher
    pthread_t raw_fetcher_thr;
    if (0 != pthread_create(&raw_fetcher_thr, &pthread_attr_norm, raw_fetcher, NULL)) {
        LOG_CRITICAL("%s: Unable to create raw_fetcher thread!!!", app_name);
        abort();
    }
    thrs.push_back(raw_fetcher_thr);

    // Geoprobe handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t geoprobe_thr;
        if (0 != pthread_create(&geoprobe_thr, &pthread_attr_norm, geoprobe_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create geoprobe_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(geoprobe_thr);
    }

    // Geoprobe fetcher
    pthread_t geoprobe_fetcher_thr;
    if (0 != pthread_create(&geoprobe_fetcher_thr, &pthread_attr_norm, geoprobe_fetcher, NULL)) {
        LOG_CRITICAL("%s: Unable to create geoprobe_fetcher thread!!!", app_name);
        abort();
    }
    thrs.push_back(geoprobe_fetcher_thr);

    // ODS handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t ods_thr;
        if (0 != pthread_create(&ods_thr, &pthread_attr_norm, ods_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create ods_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(ods_thr);
    }

    // ODS fetcher
    pthread_t ods_fetcher_thr;
    if (0 != pthread_create(&ods_fetcher_thr, &pthread_attr_norm, ods_fetcher, NULL)) {
        LOG_CRITICAL("%s: Unable to create ods_fetcher thread!!!", app_name);
        abort();
    }
    thrs.push_back(ods_fetcher_thr);

    // CCB handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t ccb_thr;
        if (0 != pthread_create(&ccb_thr, &pthread_attr_norm, ccb_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create ccb_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(ccb_thr);
    }

    if (! strncasecmp(Config::getBrand(), "PREPAID", 7)) {
        // conditioner fetcher
        pthread_t conditioner_fetcher_thr;
        if (0 != pthread_create(&conditioner_fetcher_thr, &pthread_attr_norm, conditioner_fetcher, NULL)) {
            LOG_CRITICAL("%s: Unable to create conditioner_fetcher thread!!!", app_name);
            abort();
        }
        thrs.push_back(conditioner_fetcher_thr);

        // conditioner handler
        for (int i=0; i<Config::getThreadCount(); ++i) {
            pthread_t conditioner_thr;
            if (0 != pthread_create(&conditioner_thr, &pthread_attr_norm, conditioner_handler, (void*)i)) {
                LOG_CRITICAL("%s: Unable to create conditioner_handler thread (%d)!!!", app_name, i);
                abort();
            }
            thrs.push_back(conditioner_thr);
        }

        // voyager fetcher
        pthread_t voyager_fetcher_thr;
        if (0 != pthread_create(&voyager_fetcher_thr, &pthread_attr_norm, voyager_fetcher, NULL)) {
            LOG_CRITICAL("%s: Unable to create voyager_fetcher thread!!!", app_name);
            abort();
        }
        thrs.push_back(voyager_fetcher_thr);

        // voyager handler
        for (int i=0; i<Config::getThreadCount(); ++i) {
            pthread_t voyager_thr;
            if (0 != pthread_create(&voyager_thr, &pthread_attr_norm, voyager_handler, (void*)i)) {
                LOG_CRITICAL("%s: Unable to create voyager_handler thread (%d)!!!", app_name, i);
                abort();
            }
            thrs.push_back(voyager_thr);
        }
    }

    LOG_INFO("%s: Started.", app_name);

    if (Config::bypassARDS()) {
        LOG_WARNING("%s: ARDS bypass is ENABLED!", app_name);
    }

    while (! IS_SHUTDOWN()) {
        sys_msleep(1000);
    }

#if 0
    for (int i=0; i<(int)thrs.size(); ++i) {
        pthread_join(thrs[i], NULL);
    }
#endif

    while (! thrs.empty()) {
        pthread_join(thrs.back(), NULL);
        thrs.pop_back();
    }

    LOG_INFO("%s: Terminated.", app_name);

    /* -- deinitialize queue -- */
    for (int i=0; i<Global::getTransactionQSize(); ++i) {
        c2q_deinit(Global::getTransactionQ(i));
    }
    Global::deinitTransactionQ();

    c2q_deinit(Global::getRequestQ());
    c2q_deinit(Global::getTransactionQ());
    c2q_deinit(Global::getResponseQ());
    c2q_deinit(Global::getGeoProbeQ());
    c2q_deinit(Global::getODSQ());
    c2q_deinit(Global::getCCBQ());
    c2q_deinit(Global::getConditionerQ());
    c2q_deinit(Global::getVoyagerQ());

    /* -- deinitialize log -- */
    LOG_DEINIT();

    return 0;
}
Example #2
0
int main(int argc, char *argv[])
{
	bool prefer_ipv6 = false, run_daemon = false, test = false;
	const char *ua_eprm = NULL;
	const char *exec = NULL;
	const char *modv[16];
	size_t modc = 0;
	int err;

	(void)re_fprintf(stderr, "baresip v%s"
			 " Copyright (C) 2010 - 2015"
			 " Alfred E. Heggestad et al.\n",
			 BARESIP_VERSION);

	(void)sys_coredump_set(true);

	err = libre_init();
	if (err)
		goto out;

#ifdef HAVE_GETOPT
	for (;;) {
		const int c = getopt(argc, argv, "6de:f:p:hu:vtm:");
		if (0 > c)
			break;

		switch (c) {

		case '?':
		case 'h':
			usage();
			return -2;

#if HAVE_INET6
		case '6':
			prefer_ipv6 = true;
			break;
#endif

		case 'd':
			run_daemon = true;
			break;

		case 'e':
			exec = optarg;
			break;

		case 'f':
			conf_path_set(optarg);
			break;

		case 'm':
			if (modc >= ARRAY_SIZE(modv)) {
				warning("max %zu modules\n",
					ARRAY_SIZE(modv));
				err = EINVAL;
				goto out;
			}
			modv[modc++] = optarg;
			break;

		case 'p':
			play_set_path(optarg);
			break;

		case 't':
			test = true;
			break;

		case 'u':
			ua_eprm = optarg;
			break;

		case 'v':
			log_enable_debug(true);
			break;

		default:
			break;
		}
	}
#else
	(void)argc;
	(void)argv;
#endif

	err = conf_configure();
	if (err) {
		warning("main: configure failed: %m\n", err);
		goto out;
	}

	/* NOTE: must be done after all arguments are processed */
	if (modc) {
		size_t i;

		info("pre-loading modules: %zu\n", modc);

		for (i=0; i<modc; i++) {

			err = module_preload(modv[i]);
			if (err) {
				re_fprintf(stderr,
					   "could not pre-load module"
					   " '%s' (%m)\n", modv[i], err);
			}
		}
	}

	/* Initialise User Agents */
	err = ua_init("baresip v" BARESIP_VERSION " (" ARCH "/" OS ")",
		      true, true, true, prefer_ipv6);
	if (err)
		goto out;

	if (ua_eprm) {
		err = uag_set_extra_params(ua_eprm);
		if (err)
			goto out;
	}

	if (test)
		goto out;

	/* Load modules */
	err = conf_modules();
	if (err)
		goto out;

	if (run_daemon) {
		err = sys_daemon();
		if (err)
			goto out;

		log_enable_stderr(false);
	}

	info("baresip is ready.\n");

	if (exec)
		ui_input_str(exec);

	/* Main loop */
	err = re_main(signal_handler);

 out:
	if (err)
		ua_stop_all(true);

	ua_close();
	conf_close();

	libre_close();

	/* Check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}
Example #3
0
int main (int argc, char *argv[])
{
    char cfg_file[256];
    char app_name[256];
    char* p;

    p = strrchr(argv[0], '/');
    snprintf(app_name, sizeof(app_name), "%s", p+1);

    /* -- get the config filename -- */
    switch (sys_getopt(argc, argv, "c:", cfg_file, sizeof(cfg_file))) {
        case 'c':
#ifdef __DEBUG__
            fprintf(stdout, "config file = [%s]\n", cfg_file);
#endif
            if (0 != Config::load(cfg_file)) {
                fprintf(stderr, "%s: Unable to load config file [%s]!!!\n", app_name, cfg_file);
                exit(-1);
            }
            break;
        default:
            usage(argv[0]);
            exit(0);
    }

    /* -- check if already running -- */
    if (0 != sys_bind(Config::getLockPort())) {
        fprintf(stderr, "%s: Unable to continue, make sure there's no other instance running!!!\n", app_name);
        exit(-1);
    }

    /* -- initialize log -- */
    LOG_INIT(Config::getLogFile(), Config::getLogLevel());

    /* -- check if logger is successfully initialized -- */
    if (0 != LOG_GET_STATUS()) {
        fprintf(stderr, "%s: Unable to initialize logger!\n", app_name);
        exit(-1);
    }

    /* -- initialize libsqlora8 -- */
    if (OraDB::init_lib(true) < 0) {
        LOG_CRITICAL("%s: Unable to initialize libsqlora8!", app_name);
        exit(-1);
    }

    /* -- initialize queue -- */
    if (0 != c2q_init(Global::getNotificationQ())) {
        LOG_CRITICAL("%s: Unable to initialize notification queue!", app_name);
        exit(-1);
    }

    /* -- run in background -- */
    sys_daemon();

    /* -- block all signals -- */
    sys_sigblock();

    // Thread attributes
    pthread_attr_t pthread_attr_norm;
    pthread_attr_init(&pthread_attr_norm);
    pthread_attr_setstacksize(&pthread_attr_norm, Global::thr_stack_size);

    std::vector<pthread_t> thrs;

    // Signal handler
    pthread_t signal_thr;
    if (0 != pthread_create(&signal_thr, &pthread_attr_norm, signal_handler, NULL)) {
        LOG_CRITICAL("%s: Unable to create signal_handler thread!!!", app_name);
        exit(-1);
    }
    thrs.push_back(signal_thr);

    // Notification handler
    for (int i=0; i<Config::getThreadCount(); ++i) {
        pthread_t notification_thr;
        if (0 != pthread_create(&notification_thr, &pthread_attr_norm, notification_handler, (void*)i)) {
            LOG_CRITICAL("%s: Unable to create notification_handler thread (%d)!!!", app_name, i);
            abort();
        }
        thrs.push_back(notification_thr);
    }

    // Notification fetcher
    pthread_t notification_fetcher_thr;
    if (0 != pthread_create(&notification_fetcher_thr, &pthread_attr_norm, notification_fetcher, NULL)) {
        LOG_CRITICAL("%s: Unable to create notification_fetcher thread (%d)!!!", app_name);
        abort();
    }
    thrs.push_back(notification_fetcher_thr);

    LOG_INFO("%s: Started.", app_name);

    while (! IS_SHUTDOWN()) {
        sys_msleep(1000);
    }

#if 0
    for (int i=0; i<(int)thrs.size(); ++i) {
        pthread_join(thrs[i], NULL);
    }
#endif

    while (! thrs.empty()) {
        pthread_join(thrs.back(), NULL);
        thrs.pop_back();
    }

    LOG_INFO("%s: Terminated.", app_name);

    /* -- deinitialize queue -- */
    c2q_deinit(Global::getNotificationQ());

    /* -- deinitialize log -- */
    LOG_DEINIT();

    return 0;
}
Example #4
0
int main(int argc, char *argv[])
{
	bool prefer_ipv6 = false, run_daemon = false, test = false;
	const char *exec = NULL;
	int err;

	(void)re_fprintf(stderr, "baresip v%s"
			 " Copyright (C) 2010 - 2015"
			 " Alfred E. Heggestad et al.\n",
			 BARESIP_VERSION);

	(void)sys_coredump_set(true);

	err = libre_init();
	if (err)
		goto out;

#ifdef HAVE_GETOPT
	for (;;) {
		const int c = getopt(argc, argv, "6de:f:p:hvtm:");
		if (0 > c)
			break;

		switch (c) {

		case '?':
		case 'h':
			usage();
			return -2;

#if HAVE_INET6
		case '6':
			prefer_ipv6 = true;
			break;
#endif

		case 'd':
			run_daemon = true;
			break;

		case 'e':
			exec = optarg;
			break;

		case 'f':
			conf_path_set(optarg);
			break;

		case 'm':
			err = module_preload(optarg);
			if (err) {
				re_fprintf(stderr,
					   "could not pre-load module"
					   " '%s' (%m)\n", optarg, err);
			}
			break;

		case 'p':
			play_set_path(optarg);
			break;

		case 't':
			test = true;
			break;

		case 'v':
			log_enable_debug(true);
			break;

		default:
			break;
		}
	}
#else
	(void)argc;
	(void)argv;
#endif

	err = conf_configure();
	if (err) {
		warning("main: configure failed: %m\n", err);
		goto out;
	}

	/* Initialise User Agents */
	err = ua_init("baresip v" BARESIP_VERSION " (" ARCH "/" OS ")",
		      true, true, true, prefer_ipv6);
	if (err)
		goto out;

	if (test)
		goto out;

	/* Load modules */
	err = conf_modules();
	if (err)
		goto out;

	if (run_daemon) {
		err = sys_daemon();
		if (err)
			goto out;

		log_enable_stderr(false);
	}

	info("baresip is ready.\n");

	if (exec)
		ui_input_str(exec);

	/* Main loop */
	err = re_main(signal_handler);

 out:
	if (err)
		ua_stop_all(true);

	ua_close();
	mod_close();

	libre_close();

	/* Check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}
Example #5
0
int main(int argc, char *argv[])
{
	bool prefer_ipv6 = false, run_daemon = false;
	const char *exec = NULL;
	int err;

	(void)re_fprintf(stderr, "baresip v%s"
			 " Copyright (C) 2010 - 2014"
			 " Alfred E. Heggestad et al.\n",
			 BARESIP_VERSION);

	(void)sys_coredump_set(true);

#ifdef HAVE_GETOPT
	for (;;) {
		const int c = getopt(argc, argv, "6de:f:hv");
		if (0 > c)
			break;

		switch (c) {

		case '?':
		case 'h':
			(void)re_fprintf(stderr,
					 "Usage: baresip [options]\n"
					 "options:\n"
#if HAVE_INET6
					 "\t-6               Prefer IPv6\n"
#endif
					 "\t-d               Daemon\n"
					 "\t-e <commands>    Exec commands\n"
					 "\t-f <path>        Config path\n"
					 "\t-h -?            Help\n"
					 "\t-v               Verbose debug\n"
					 );
			return -2;

#if HAVE_INET6
		case '6':
			prefer_ipv6 = true;
			break;
#endif

		case 'd':
			run_daemon = true;
			break;

		case 'e':
			exec = optarg;
			break;

		case 'f':
			conf_path_set(optarg);
			break;

		case 'v':
			log_enable_debug(true);
			break;

		default:
			break;
		}
	}
#else
	(void)argc;
	(void)argv;
#endif

	err = libre_init();
	if (err)
		goto out;

	err = conf_configure();
	if (err) {
		warning("main: configure failed: %m\n", err);
		goto out;
	}

	/* Initialise User Agents */
	err = ua_init("baresip v" BARESIP_VERSION " (" ARCH "/" OS ")",
		      true, true, true, prefer_ipv6);
	if (err)
		goto out;

	/* Load modules */
	err = conf_modules();
	if (err)
		goto out;

	if (run_daemon) {
		err = sys_daemon();
		if (err)
			goto out;

		log_enable_stderr(false);
	}

	info("baresip is ready.\n");

	if (exec)
		ui_input_str(exec);

	/* Main loop */
	err = re_main(signal_handler);

 out:
	if (err)
		ua_stop_all(true);

	ua_close();
	mod_close();

	libre_close();

	/* Check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}
Example #6
0
int main(int argc, char *argv[])
{
	bool daemon = true;
	int err = 0;
	struct pl opt;

	(void)sys_coredump_set(true);

#ifdef HAVE_GETOPT
	for (;;) {

		const int c = getopt(argc, argv, "dhnf:");
		if (0 > c)
			break;

		switch (c) {

		case 'd':
			force_debug = true;
			restund_log_enable_debug(true);
			break;

		case 'f':
			configfile = optarg;
			break;

		case 'n':
			daemon = false;
			break;

		case '?':
			err = EINVAL;
			/*@fallthrough@*/
		case 'h':
			usage();
			return err;
		}
	}
#else
	(void)argc;
	(void)argv;
#endif

	restund_cmd_subscribe(&cmd_reload);

	err = fd_setsize(4096);
	if (err) {
		restund_warning("fd_setsize error: %m\n", err);
		goto out;
	}

	err = libre_init();
	if (err) {
		restund_error("re init failed: %m\n", err);
		goto out;
	}

	/* configuration file */
	err = conf_alloc(&conf, configfile);
	if (err) {
		restund_error("error loading configuration: %s: %m\n",
			      configfile, err);
		goto out;
	}

	/* debug config */
	if (!conf_get(conf, "debug", &opt) && !pl_strcasecmp(&opt, "yes"))
		restund_log_enable_debug(true);

	/* udp */
	err = restund_udp_init();
	if (err)
		goto out;

	/* tcp */
	err = restund_tcp_init();
	if (err)
		goto out;

	/* daemon config */
	if (!conf_get(conf, "daemon", &opt) && !pl_strcasecmp(&opt, "no"))
		daemon = false;

	/* module config */
	if (conf_get(conf, "module_path", &opt))
		pl_set_str(&opt, ".");

	err = conf_apply(conf, "module", module_handler, &opt);
	if (err)
		goto out;

	/* daemon */
	if (daemon) {
		err = sys_daemon();
		if (err) {
			restund_error("daemon error: %m\n", err);
			goto out;
 		}

		restund_log_enable_stderr(false);
	}

	/* database */
	err = restund_db_init();
	if (err) {
		restund_warning("database error: %m\n", err);
		goto out;
	}

	restund_info("stun server ready\n");

	/* main loop */
	err = re_main(signal_handler);

 out:
	restund_db_close();
	mod_close();
	restund_udp_close();
	restund_tcp_close();
	conf = mem_deref(conf);

	libre_close();

	restund_cmd_unsubscribe(&cmd_reload);

	/* check for memory leaks */
	tmr_debug();
	mem_debug();

	return err;
}