/** * Return a newly allocated individual path to reach a peer from the local peer, * according to the path tree of some tunnel. * * @param t Tunnel from which to read the path tree. * @param peer Short ID of the destination peer to whom we want a path. * * @return A newly allocated individual path to reach the destination peer. * Path must be destroyed afterwards. */ struct MeshPeerPath * tree_get_path_to_peer (struct MeshTunnelTree *t, GNUNET_PEER_Id peer) { struct MeshTunnelTreeNode *n; struct MeshPeerPath *p; n = tree_find_peer (t, peer); if (NULL == n) { GNUNET_break (0); return NULL; } p = path_new (0); /* Building the path (inverted!) */ while (n->peer != 1) { GNUNET_array_append (p->peers, p->length, n->peer); GNUNET_PEER_change_rc (n->peer, 1); n = n->parent; if (NULL == n) { GNUNET_break (0); path_destroy (p); return NULL; } } GNUNET_array_append (p->peers, p->length, 1); GNUNET_PEER_change_rc (1, 1); path_invert (p); return p; }
/** * Changes the state of the operation while moving its associated queue entries * in the operation's operation queues * * @param op the operation whose state has to be changed * @param state the state the operation should have. It cannot be OP_STATE_INIT */ static void change_state (struct GNUNET_TESTBED_Operation *op, enum OperationState state) { struct QueueEntry *entry; struct OperationQueue *opq; unsigned int cnt; unsigned int s; GNUNET_assert (OP_STATE_INIT != state); GNUNET_assert (NULL != op->queues); GNUNET_assert (NULL != op->nres); GNUNET_assert ((OP_STATE_INIT == op->state) || (NULL != op->qentries)); GNUNET_assert (op->state != state); for (cnt = 0; cnt < op->nqueues; cnt++) { if (OP_STATE_INIT == op->state) { entry = GNUNET_new (struct QueueEntry); entry->op = op; entry->nres = op->nres[cnt]; s = cnt; GNUNET_array_append (op->qentries, s, entry); } else {
/** * @brief Schedule a operation on given peer * * Avoids scheduling an operation twice. * * @param peer the peer we want to schedule the operation for once it gets live * * @return #GNUNET_YES if the operation was scheduled * #GNUNET_NO otherwise */ int Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer, const PeerOp peer_op) { struct PeerPendingOp pending_op; struct PeerContext *peer_ctx; if (0 == GNUNET_CRYPTO_cmp_peer_identity (peer, own_identity)) { return GNUNET_NO; } GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer)); //TODO if LIVE/ONLINE execute immediately if (GNUNET_NO == check_operation_scheduled (peer, peer_op)) { peer_ctx = get_peer_ctx (peer); pending_op.op = peer_op; pending_op.op_cls = NULL; GNUNET_array_append (peer_ctx->pending_ops, peer_ctx->num_pending_ops, pending_op); return GNUNET_YES; } return GNUNET_NO; }
/** * Check if some client is monitoring GET messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the GET path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param key Key of the requested data. */ void GDS_CLIENTS_process_get (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, const struct GNUNET_HashCode * key) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorGetMessage *mmsg; struct GNUNET_PeerIdentity *msg_path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = path_length * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorGetMessage); msize += sizeof (struct PendingMessage); pm = GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorGetMessage *) &pm[1]; pm->msg = &mmsg->header; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET); mmsg->options = htonl(options); mmsg->type = htonl(type); mmsg->hop_count = htonl(hop_count); mmsg->desired_replication_level = htonl(desired_replication_level); mmsg->get_path_length = htonl(path_length); memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode)); msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (path_length > 0) memcpy (msg_path, path, path_length * sizeof (struct GNUNET_PeerIdentity)); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); }
/** * Check if some client is monitoring GET RESP messages and notify * them in that case. * * @param type The type of data in the result. * @param get_path Peers on GET path (or NULL if not recorded). * @param get_path_length number of entries in get_path. * @param put_path peers on the PUT path (or NULL if not recorded). * @param put_path_length number of entries in get_path. * @param exp Expiration time of the data. * @param key Key of the data. * @param data Pointer to the result data. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_get_resp (enum GNUNET_BLOCK_Type type, const struct GNUNET_PeerIdentity *get_path, unsigned int get_path_length, const struct GNUNET_PeerIdentity *put_path, unsigned int put_path_length, struct GNUNET_TIME_Absolute exp, const struct GNUNET_HashCode * key, const void *data, size_t size) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorGetRespMessage *mmsg; struct GNUNET_PeerIdentity *path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = size; msize += (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorGetRespMessage); msize += sizeof (struct PendingMessage); pm = GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorGetRespMessage *) &pm[1]; pm->msg = (struct GNUNET_MessageHeader *) mmsg; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_GET_RESP); mmsg->type = htonl(type); mmsg->put_path_length = htonl(put_path_length); mmsg->get_path_length = htonl(get_path_length); path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (put_path_length > 0) { memcpy (path, put_path, put_path_length * sizeof (struct GNUNET_PeerIdentity)); path = &path[put_path_length]; } if (get_path_length > 0) memcpy (path, get_path, get_path_length * sizeof (struct GNUNET_PeerIdentity)); mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp); memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode)); if (size > 0) memcpy (&path[get_path_length], data, size); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); }
/** * Iterator over hash map entries that send a given reply to * each of the matching clients. With some tricky recycling * of the buffer. * * @param cls the 'struct ForwardReplyContext' * @param key current key * @param value value in the hash map, a ClientQueryRecord * @return GNUNET_YES (we should continue to iterate), * if the result is mal-formed, GNUNET_NO */ static int forward_reply (void *cls, const struct GNUNET_HashCode * key, void *value) { struct ForwardReplyContext *frc = cls; struct ClientQueryRecord *record = value; struct PendingMessage *pm; struct GNUNET_DHT_ClientResultMessage *reply; enum GNUNET_BLOCK_EvaluationResult eval; int do_free; struct GNUNET_HashCode ch; unsigned int i; LOG_TRAFFIC (GNUNET_ERROR_TYPE_DEBUG, "XDHT CLIENT-RESULT %s\n", GNUNET_h2s (key)); if ((record->type != GNUNET_BLOCK_TYPE_ANY) && (record->type != frc->type)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Record type missmatch, not passing request for key %s to local client\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Key match, type mismatches in REPLY to CLIENT"), 1, GNUNET_NO); return GNUNET_YES; /* type mismatch */ } GNUNET_CRYPTO_hash (frc->data, frc->data_size, &ch); for (i = 0; i < record->seen_replies_count; i++) if (0 == memcmp (&record->seen_replies[i], &ch, sizeof (struct GNUNET_HashCode))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Duplicate reply, not passing request for key %s to local client\n", GNUNET_h2s (key)); GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# Duplicate REPLIES to CLIENT request dropped"), 1, GNUNET_NO); return GNUNET_YES; /* duplicate */ } eval = GNUNET_BLOCK_evaluate (GDS_block_context, record->type, key, NULL, 0, record->xquery, record->xquery_size, frc->data, frc->data_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Evaluation result is %d for key %s for local client's query\n", (int) eval, GNUNET_h2s (key)); switch (eval) { case GNUNET_BLOCK_EVALUATION_OK_LAST: do_free = GNUNET_YES; break; case GNUNET_BLOCK_EVALUATION_OK_MORE: GNUNET_array_append (record->seen_replies, record->seen_replies_count, ch); do_free = GNUNET_NO; break; case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE: /* should be impossible to encounter here */ GNUNET_break (0); return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_RESULT_INVALID: GNUNET_break_op (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_REQUEST_VALID: GNUNET_break (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID: GNUNET_break (0); return GNUNET_NO; case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT: return GNUNET_YES; case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unsupported block type (%u) in request!\n"), record->type); return GNUNET_NO; default: GNUNET_break (0); return GNUNET_NO; } if (GNUNET_NO == frc->do_copy) { /* first time, we can use the original data */ pm = frc->pm; frc->do_copy = GNUNET_YES; } else { /* two clients waiting for same reply, must copy for queueing */ pm = GNUNET_malloc (sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); memcpy (pm, frc->pm, sizeof (struct PendingMessage) + ntohs (frc->pm->msg->size)); pm->next = pm->prev = NULL; pm->msg = (struct GNUNET_MessageHeader *) &pm[1]; } GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# RESULTS queued for clients"), 1, GNUNET_NO); reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; reply->unique_id = record->unique_id; LOG (GNUNET_ERROR_TYPE_DEBUG, "Queueing reply to query %s for client %p\n", GNUNET_h2s (key), record->client->client_handle); add_pending_message (record->client, pm); if (GNUNET_YES == do_free) remove_client_records (record->client, key, record); return GNUNET_YES; }
/** * Actually start the process for the given service. * * @param sl identifies service to start */ static void start_process (struct ServiceList *sl) { char *loprefix; char *options; char *optpos; char *optend; const char *next; int use_debug; char b; char *val; struct ServiceListeningInfo *sli; SOCKTYPE *lsocks; unsigned int ls; /* calculate listen socket list */ lsocks = NULL; ls = 0; for (sli = sl->listen_head; NULL != sli; sli = sli->next) { GNUNET_array_append (lsocks, ls, GNUNET_NETWORK_get_fd (sli->listen_socket)); if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_NO_TASK; } } #if WINDOWS GNUNET_array_append (lsocks, ls, INVALID_SOCKET); #else GNUNET_array_append (lsocks, ls, -1); #endif /* obtain configuration */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "PREFIX", &loprefix)) loprefix = GNUNET_strdup (prefix_command); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, sl->name, "OPTIONS", &options)) { options = GNUNET_strdup (final_option); if (NULL == strstr (options, "%")) { /* replace '{}' with service name */ while (NULL != (optpos = strstr (options, "{}"))) { optpos[0] = '%'; optpos[1] = 's'; GNUNET_asprintf (&optpos, options, sl->name); GNUNET_free (options); options = optpos; } /* replace '$PATH' with value associated with "PATH" */ while (NULL != (optpos = strstr (options, "$"))) { optend = optpos + 1; while (isupper ((unsigned char) *optend)) optend++; b = *optend; if ('\0' == b) next = ""; else next = optend + 1; *optend = '\0'; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", optpos + 1, &val)) val = GNUNET_strdup (""); *optpos = '\0'; GNUNET_asprintf (&optpos, "%s%s%c%s", options, val, b, next); GNUNET_free (options); GNUNET_free (val); options = optpos; } } } use_debug = GNUNET_CONFIGURATION_get_value_yesno (cfg, sl->name, "DEBUG"); /* actually start process */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting service `%s' using binary `%s' and configuration `%s'\n", sl->name, sl->binary, sl->config); GNUNET_assert (NULL == sl->proc); if (GNUNET_YES == use_debug) sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, "-L", "DEBUG", options, NULL); else sl->proc = do_start_process (sl->pipe_control, lsocks, loprefix, sl->binary, "-c", sl->config, options, NULL); if (sl->proc == NULL) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), sl->name); else GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), sl->name); /* clean up */ GNUNET_free (loprefix); GNUNET_free (options); GNUNET_array_grow (lsocks, ls, 0); }
/** * Search for a peer offering a regex matching certain string in the DHT. * The search runs until #REGEX_INTERNAL_search_cancel() is called, even if results * are returned. * * @param dht An existing and valid DHT service handle. * @param string String to match against the regexes in the DHT. * @param callback Callback for found peers. * @param callback_cls Closure for @c callback. * @param stats Optional statistics handle to report usage. Can be NULL. * @return Handle to stop search and free resources. * Must be freed by calling #REGEX_INTERNAL_search_cancel(). */ struct REGEX_INTERNAL_Search * REGEX_INTERNAL_search (struct GNUNET_DHT_Handle *dht, const char *string, REGEX_INTERNAL_Found callback, void *callback_cls, struct GNUNET_STATISTICS_Handle *stats) { struct REGEX_INTERNAL_Search *h; struct GNUNET_DHT_GetHandle *get_h; struct RegexSearchContext *ctx; struct GNUNET_HashCode key; size_t size; size_t len; /* Initialize handle */ GNUNET_assert (NULL != dht); GNUNET_assert (NULL != callback); h = GNUNET_new (struct REGEX_INTERNAL_Search); h->dht = dht; h->description = GNUNET_strdup (string); h->callback = callback; h->callback_cls = callback_cls; h->stats = stats; h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); /* Initialize context */ len = strlen (string); size = REGEX_INTERNAL_get_first_key (string, len, &key); LOG (GNUNET_ERROR_TYPE_INFO, "Initial key for `%s' is %s (based on `%.*s')\n", string, GNUNET_h2s (&key), size, string); ctx = GNUNET_new (struct RegexSearchContext); ctx->position = size; ctx->info = h; GNUNET_array_append (h->contexts, h->n_contexts, ctx); /* Start search in DHT */ get_h = GNUNET_DHT_get_start (h->dht, /* handle */ GNUNET_BLOCK_TYPE_REGEX, /* type */ &key, /* key to search */ DHT_REPLICATION, /* replication level */ DHT_OPT, &h->description[size], /* xquery */ // FIXME add BLOOMFILTER to exclude filtered peers len + 1 - size, /* xquery bits */ // FIXME add BLOOMFILTER SIZE &dht_get_string_handler, ctx); GNUNET_break ( GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (h->dht_get_handles, &key, get_h, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST) ); return h; }
/** * Jump to the next edge, with the longest matching token. * * @param block Block found in the DHT. * @param size Size of the block. * @param ctx Context of the search. */ static void regex_next_edge (const struct RegexBlock *block, size_t size, struct RegexSearchContext *ctx) { struct RegexSearchContext *new_ctx; struct REGEX_INTERNAL_Search *info = ctx->info; struct GNUNET_DHT_GetHandle *get_h; struct GNUNET_HashCode *hash; const char *rest; int result; LOG (GNUNET_ERROR_TYPE_DEBUG, "Next edge\n"); /* Find the longest match for the current string position, * among tokens in the given block */ ctx->longest_match = 0; result = REGEX_BLOCK_iterate (block, size, ®ex_edge_iterator, ctx); GNUNET_break (GNUNET_OK == result); /* Did anything match? */ if (0 == ctx->longest_match) { LOG (GNUNET_ERROR_TYPE_DEBUG, "no match in block\n"); return; } hash = &ctx->hash; new_ctx = GNUNET_new (struct RegexSearchContext); new_ctx->info = info; new_ctx->position = ctx->position + ctx->longest_match; GNUNET_array_append (info->contexts, info->n_contexts, new_ctx); /* Check whether we already have a DHT GET running for it */ if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (info->dht_get_handles, hash)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "GET for %s running, END\n", GNUNET_h2s (hash)); GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results, hash, ®ex_result_iterator, new_ctx); return; /* We are already looking for it */ } GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed", 1, GNUNET_NO); LOG (GNUNET_ERROR_TYPE_DEBUG, "Following edges at %s for offset %u in `%s'\n", GNUNET_h2s (hash), (unsigned int) ctx->position, info->description); rest = &new_ctx->info->description[new_ctx->position]; get_h = GNUNET_DHT_get_start (info->dht, /* handle */ GNUNET_BLOCK_TYPE_REGEX, /* type */ hash, /* key to search */ DHT_REPLICATION, /* replication level */ DHT_OPT, rest, /* xquery */ strlen (rest) + 1, /* xquery bits */ &dht_get_string_handler, new_ctx); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles, hash, get_h, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) { GNUNET_break (0); return; } }
/** * 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; }