/**
* Restart the given peer
* @param tth testing handle
* @param p the peer
* @param cfgname the cfg file used to restart
* @param restart_cb callback to call when restarted
* @param cb_cls callback closure
* @return GNUNET_OK in success otherwise GNUNET_SYSERR
*/
int
GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
                                       *tth, struct PeerContext *p,
                                       const char *cfgname,
                                       GNUNET_TRANSPORT_TESTING_start_cb
                                       restart_cb, void *cb_cls)
{
  GNUNET_assert (tth != NULL);
  GNUNET_assert (p != NULL);
  GNUNET_assert (NULL != p->peer);

  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
                   "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));

  /* shutdown */
  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
                   "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
  if (NULL != p->ghh)
    GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
  p->ghh = NULL;

  if (NULL != p->th)
    GNUNET_TRANSPORT_disconnect (p->th);

  if (GNUNET_SYSERR == GNUNET_TESTING_peer_stop(p->peer))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Failed to stop peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
    return GNUNET_SYSERR;
  }

  sleep (5);

  /* restart */
  if (GNUNET_SYSERR == GNUNET_TESTING_peer_start(p->peer))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Failed to restart peer %u (`%s')\n",
                     p->no, GNUNET_i2s (&p->id));
    return GNUNET_SYSERR;
  }

  GNUNET_assert (p->th != NULL);
  GNUNET_assert (p->start_cb == NULL);
  p->start_cb = restart_cb;
  p->cb_cls = cb_cls;

  p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
                                    &notify_receive,
                                    &notify_connect,
                                    &notify_disconnect);
  GNUNET_assert (NULL != p->th);

  p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
  GNUNET_assert (p->ghh != NULL);
  return GNUNET_OK;
}
static void
setup_peer (struct PeerContext *p, const char *cfgname)
{
  p->cfg = GNUNET_CONFIGURATION_create ();
#if START_ARM
  p->arm_proc =
      GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-arm",
                               "gnunet-service-arm",
#if VERBOSE
                               "-L", "DEBUG",
#endif
                               "-c", cfgname, NULL);
#endif
  GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
  p->th =
      GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, &notify_connect, NULL);
  GNUNET_assert (p->th != NULL);
  p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
}
static void
setup_peer (struct PeerContext *p, const char *cfgname)
{
    char *binary;

    binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
    p->cfg = GNUNET_CONFIGURATION_create ();
    p->arm_proc =
        GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
                                 NULL, NULL,
                                 binary,
                                 "gnunet-service-arm",
                                 "-c", cfgname, NULL);
    GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
    p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL);
    GNUNET_assert (p->th != NULL);
    p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
    GNUNET_free (binary);
}
/**
 * Start a peer with the given configuration
 * @param tth the testing handle
 * @param cfgname configuration file
 * @param peer_id a unique number to identify the peer
 * @param rec receive callback
 * @param nc connect callback
 * @param nd disconnect callback
 * @param start_cb start callback
 * @param cb_cls closure for callback
 * @return the peer context
 */
struct PeerContext *
GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
                                     const char *cfgname, int peer_id,
                                     GNUNET_TRANSPORT_ReceiveCallback rec,
                                     GNUNET_TRANSPORT_NotifyConnect nc,
                                     GNUNET_TRANSPORT_NotifyDisconnect nd,
                                     GNUNET_TRANSPORT_TESTING_start_cb start_cb,
                                     void *cb_cls)
{
  char *emsg = NULL;
  struct GNUNET_PeerIdentity *dummy;

  GNUNET_assert (NULL != tth);
  GNUNET_assert (NULL != tth->tl_system);

  if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "File not found: `%s' \n", cfgname);
    return NULL;
  }

  struct PeerContext *p = GNUNET_new (struct PeerContext);
  GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p);

  /* Create configuration and call testing lib to modify it */
  p->cfg = GNUNET_CONFIGURATION_create ();
  GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));

  if (GNUNET_SYSERR == GNUNET_TESTING_configuration_create (tth->tl_system, p->cfg))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Testing library failed to create unique configuration based on `%s'\n",
                     cfgname);
    GNUNET_free (p);
    return NULL;
  }

  p->no = peer_id;
  /* Configure peer with configuration */
  p->peer = GNUNET_TESTING_peer_configure (tth->tl_system, p->cfg, p->no, NULL, &emsg);
  if (NULL == p->peer)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Testing library failed to create unique configuration based on `%s': `%s'\n",
                     cfgname, emsg);
    GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
    GNUNET_free_non_null (emsg);
    return NULL;
  }
  GNUNET_free_non_null (emsg);
  if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Testing library failed to create unique configuration based on `%s'\n",
                     cfgname);
    GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
    return NULL;
  }

  memset(&dummy, '\0', sizeof (dummy));
  GNUNET_TESTING_peer_get_identity (p->peer, &p->id);
  if (0 == memcmp (&dummy, &p->id, sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Testing library failed to obtain peer identity for peer %u\n",
                     p->no);
    GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
    return NULL;
  }
  else
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
                     "Peer %u configured with identity `%s'\n",
                     p->no,
                     GNUNET_i2s_full (&p->id));
  }

  p->tth = tth;
  p->nc = nc;
  p->nd = nd;
  p->rec = rec;
  p->start_cb = start_cb;
  if (cb_cls != NULL)
    p->cb_cls = cb_cls;
  else
    p->cb_cls = p;

  p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p,
                                    &notify_receive,
                                    &notify_connect, &notify_disconnect);
  if (NULL == p->th)
  {
    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
                     "Failed to connect to transport service for peer  `%s': `%s'\n",
                     cfgname, emsg);
    GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
    return NULL;
  }

  p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
  GNUNET_assert (p->ghh != NULL);

  return p;
}