/** * Run a standard GNUnet command startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param binaryName our expected name * @param binaryHelp help text for the program * @param options command line options * @param task main function to run * @param task_cls closure for task * @param run_without_scheduler GNUNET_NO start the scheduler, GNUNET_YES do not * start the scheduler just run the main task * @return GNUNET_SYSERR on error, GNUNET_OK on success */ int GNUNET_PROGRAM_run2 (int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls, int run_without_scheduler) { struct CommandContext cc; char *path; char *loglev; char *logfile; int ret; unsigned int cnt; unsigned long long skew_offset; unsigned long long skew_variance; long long clock_offset; struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_GETOPT_CommandLineOption defoptions[] = { GNUNET_GETOPT_OPTION_CFG_FILE (&cc.cfgfile), GNUNET_GETOPT_OPTION_HELP (binaryHelp), GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), GNUNET_GETOPT_OPTION_LOGFILE (&logfile), GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION) }; struct GNUNET_GETOPT_CommandLineOption *allopts; const char *gargs; char *lpfx; char *spc; logfile = NULL; gargs = getenv ("GNUNET_ARGS"); if (gargs != NULL) { char **gargv; unsigned int gargc; int i; char *tok; char *cargs; gargv = NULL; gargc = 0; for (i = 0; i < argc; i++) GNUNET_array_append (gargv, gargc, GNUNET_strdup (argv[i])); cargs = GNUNET_strdup (gargs); tok = strtok (cargs, " "); while (NULL != tok) { GNUNET_array_append (gargv, gargc, GNUNET_strdup (tok)); tok = strtok (NULL, " "); } GNUNET_free (cargs); GNUNET_array_append (gargv, gargc, NULL); argv = (char *const *) gargv; argc = gargc - 1; } memset (&cc, 0, sizeof (cc)); loglev = NULL; cc.task = task; cc.task_cls = task_cls; cc.cfg = cfg = GNUNET_CONFIGURATION_create (); /* prepare */ #if ENABLE_NLS setlocale (LC_ALL, ""); path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR); if (path != NULL) { BINDTEXTDOMAIN ("GNUnet", path); GNUNET_free (path); } textdomain ("GNUnet"); #endif cnt = 0; while (options[cnt].name != NULL) cnt++; allopts = GNUNET_malloc ((cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption) + sizeof (defoptions)); memcpy (allopts, defoptions, sizeof (defoptions)); memcpy (&allopts [sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption)], options, (cnt + 1) * sizeof (struct GNUNET_GETOPT_CommandLineOption)); cnt += sizeof (defoptions) / sizeof (struct GNUNET_GETOPT_CommandLineOption); qsort (allopts, cnt, sizeof (struct GNUNET_GETOPT_CommandLineOption), &cmd_sorter); loglev = NULL; cc.cfgfile = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); lpfx = GNUNET_strdup (binaryName); if (NULL != (spc = strstr (lpfx, " "))) *spc = '\0'; if ((-1 == (ret = GNUNET_GETOPT_run (binaryName, allopts, (unsigned int) argc, argv))) || (GNUNET_OK != GNUNET_log_setup (lpfx, loglev, logfile))) { GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free_non_null (cc.cfgfile); GNUNET_free_non_null (loglev); GNUNET_free_non_null (logfile); GNUNET_free (allopts); GNUNET_free (lpfx); return GNUNET_SYSERR; } (void) GNUNET_CONFIGURATION_load (cfg, cc.cfgfile); GNUNET_free (allopts); GNUNET_free (lpfx); if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_offset", &skew_offset) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cc.cfg, "testing", "skew_variance", &skew_variance))) { clock_offset = skew_offset - skew_variance; GNUNET_TIME_set_offset (clock_offset); } /* run */ cc.args = &argv[ret]; if (GNUNET_NO == run_without_scheduler) { GNUNET_SCHEDULER_run (&program_main, &cc); } else { GNUNET_RESOLVER_connect (cc.cfg); cc.task (cc.task_cls, cc.args, cc.cfgfile, cc.cfg); } /* clean up */ GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); GNUNET_free_non_null (cc.cfgfile); GNUNET_free_non_null (loglev); GNUNET_free_non_null (logfile); return GNUNET_OK; }
/** * Run a standard GNUnet service startup sequence (initialize loggers * and configuration, parse options). * * @param argc number of command line arguments * @param argv command line arguments * @param service_name our service name * @param options service options * @param task main task of the service * @param task_cls closure for @a task * @return #GNUNET_SYSERR on error, #GNUNET_OK * if we shutdown nicely */ int GNUNET_SERVICE_run (int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_Main task, void *task_cls) { #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) int err; int ret; char *cfg_fn; char *opt_cfg_fn; char *loglev; char *logfile; int do_daemonize; unsigned int i; unsigned long long skew_offset; unsigned long long skew_variance; long long clock_offset; struct GNUNET_SERVICE_Context sctx; struct GNUNET_CONFIGURATION_Handle *cfg; const char *xdg; struct GNUNET_GETOPT_CommandLineOption service_options[] = { GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn), {'d', "daemonize", NULL, gettext_noop ("do daemonize (detach from terminal)"), 0, GNUNET_GETOPT_set_one, &do_daemonize}, GNUNET_GETOPT_OPTION_HELP (NULL), GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), GNUNET_GETOPT_OPTION_LOGFILE (&logfile), GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), GNUNET_GETOPT_OPTION_END }; err = 1; do_daemonize = 0; logfile = NULL; loglev = NULL; opt_cfg_fn = NULL; xdg = getenv ("XDG_CONFIG_HOME"); if (NULL != xdg) GNUNET_asprintf (&cfg_fn, "%s%s%s", xdg, DIR_SEPARATOR_STR, "gnunet.conf"); else cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE); memset (&sctx, 0, sizeof (sctx)); sctx.options = options; sctx.ready_confirm_fd = -1; sctx.ret = GNUNET_OK; sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; sctx.task = task; sctx.task_cls = task_cls; sctx.service_name = service_name; sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); /* setup subsystems */ ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv); if (GNUNET_SYSERR == ret) goto shutdown; if (GNUNET_NO == ret) { err = 0; goto shutdown; } if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) HANDLE_ERROR; if (NULL == opt_cfg_fn) opt_cfg_fn = GNUNET_strdup (cfg_fn); if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn)) { if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Malformed configuration file `%s', exit ...\n"), opt_cfg_fn); goto shutdown; } } else { if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Malformed configuration, exit ...\n")); goto shutdown; } if (0 != strcmp (opt_cfg_fn, cfg_fn)) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not access configuration file `%s'\n"), opt_cfg_fn); } if (GNUNET_OK != setup_service (&sctx)) goto shutdown; if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) HANDLE_ERROR; if (GNUNET_OK != set_user_id (&sctx)) goto shutdown; LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' runs with configuration from `%s'\n", service_name, opt_cfg_fn); if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", "SKEW_OFFSET", &skew_offset)) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", "SKEW_VARIANCE", &skew_variance))) { clock_offset = skew_offset - skew_variance; GNUNET_TIME_set_offset (clock_offset); LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); } /* actually run service */ err = 0; GNUNET_SCHEDULER_run (&service_task, &sctx); /* shutdown */ if ((1 == do_daemonize) && (NULL != sctx.server)) pid_file_delete (&sctx); GNUNET_free_non_null (sctx.my_handlers); shutdown: if (-1 != sctx.ready_confirm_fd) { if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); } #if HAVE_MALLINFO { char *counter; if ( (GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name, "GAUGER_HEAP")) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name, "GAUGER_HEAP", &counter)) ) { struct mallinfo mi; mi = mallinfo (); GAUGER (service_name, counter, mi.usmblks, "blocks"); GNUNET_free (counter); } } #endif GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); i = 0; if (NULL != sctx.addrs) while (NULL != sctx.addrs[i]) GNUNET_free (sctx.addrs[i++]); GNUNET_free_non_null (sctx.addrs); GNUNET_free_non_null (sctx.addrlens); GNUNET_free_non_null (logfile); GNUNET_free_non_null (loglev); GNUNET_free (cfg_fn); GNUNET_free_non_null (opt_cfg_fn); GNUNET_free_non_null (sctx.v4_denied); GNUNET_free_non_null (sctx.v6_denied); GNUNET_free_non_null (sctx.v4_allowed); GNUNET_free_non_null (sctx.v6_allowed); return err ? GNUNET_SYSERR : sctx.ret; }