コード例 #1
0
/**
 * 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;
}
コード例 #2
0
ファイル: testbed_api_operations.c プロジェクト: tg-x/gnunet
/**
 * 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
    {
コード例 #3
0
/**
 * @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;
}
コード例 #4
0
/**
 * 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);
}
コード例 #5
0
/**
 * 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);
}
コード例 #6
0
/**
 * 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;
}
コード例 #7
0
/**
 * 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);
}
コード例 #8
0
ファイル: regex_internal_dht.c プロジェクト: GNUnet/gnunet
/**
 * 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;
}
コード例 #9
0
ファイル: regex_internal_dht.c プロジェクト: GNUnet/gnunet
/**
 * 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,
                                &regex_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,
                                                &regex_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;
  }
}
コード例 #10
0
ファイル: program.c プロジェクト: h4ck3rm1k3/gnunet-debian
/**
 * 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;
}