-fix channel data range to make -1 legal value
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_peers.c
index 65cfe342c8079bdb1e76f21b102c4f24b7b6cba8..f1359003d44fc8953b71c8543176e261bdd872e5 100644 (file)
@@ -4,7 +4,7 @@
 
   GNUnet is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
-  by the Free Software Foundation; either version 2, or (at your
+  by the Free Software Foundation; either version 3, or (at your
   option) any later version.
 
   GNUnet is distributed in the hope that it will be useful, but
@@ -22,7 +22,7 @@
 /**
  * @file testbed/gnunet-service-testbed_peers.c
  * @brief implementation of TESTBED service that deals with peer management
- * @author Sree Harsha Totakura <sreeharsha@totakura.in> 
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
  */
 
 #include "gnunet-service-testbed.h"
  */
 struct Peer **GST_peer_list;
 
+/**
+ * The current number of peers running locally under this controller
+ */
+unsigned int GST_num_local_peers;
+
 
 /**
  * Context information to manage peers' services
@@ -65,12 +70,12 @@ struct ManageServiceContext
    * The client which requested to manage the peer's service
    */
   struct GNUNET_SERVER_Client *client;
-  
+
   /**
    * The operation id of the associated request
    */
   uint64_t op_id;
-  
+
   /**
    * 1 if the service at the peer has to be started; 0 if it has to be stopped
    */
@@ -80,9 +85,64 @@ struct ManageServiceContext
    * Is this context expired?  Do not work on this context if it is set to
    * GNUNET_YES
    */
-  uint8_t expired;  
+  uint8_t expired;
+};
+
+
+/**
+ * Context information for peer re-configure operations
+ */
+struct PeerReconfigureContext
+{
+  /**
+   * DLL next for inclusoin in peer reconfigure operations list
+   */
+  struct PeerReconfigureContext *next;
+
+  /**
+   * DLL prev
+   */
+  struct PeerReconfigureContext *prev;
+
+  /**
+   * The client which gave this operation to us
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * The configuration handle to use as the new template
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * The id of the operation
+   */
+  uint64_t op_id;
+
+  /**
+   * The id of the peer which has to be reconfigured
+   */
+  uint32_t peer_id;
+
+  /**
+   * The the peer stopped?  Used while cleaning up this context to decide
+   * whether the asynchronous stop request through Testing/ARM API has to be
+   * cancelled
+   */
+  uint8_t stopped;
 };
 
+/**
+ * The DLL head for the peer reconfigure list
+ */
+static struct PeerReconfigureContext *prc_head;
+
+/**
+ * The DLL tail for the peer reconfigure list
+ */
+static struct PeerReconfigureContext *prc_tail;
+
+
 
 /**
  * DLL head for queue of manage service requests
@@ -107,6 +167,8 @@ peer_list_add (struct Peer *peer)
     GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
   GNUNET_assert (NULL == GST_peer_list[peer->id]);
   GST_peer_list[peer->id] = peer;
+  if (GNUNET_NO == peer->is_remote)
+    GST_num_local_peers++;
 }
 
 
@@ -121,6 +183,8 @@ peer_list_remove (struct Peer *peer)
   unsigned int orig_size;
   uint32_t id;
 
+  if (GNUNET_NO == peer->is_remote)
+    GST_num_local_peers--;
   GST_peer_list[peer->id] = NULL;
   orig_size = GST_peer_list_size;
   while (GST_peer_list_size >= LIST_GROW_STEP)
@@ -253,10 +317,7 @@ GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
   struct ForwardedOperationContext *fo_ctxt;
   struct Route *route;
   struct Peer *peer;
-  char *config;
-  size_t dest_size;
-  int ret;
-  uint32_t config_size;
+  char *emsg;
   uint32_t host_id;
   uint32_t peer_id;
   uint16_t msize;
@@ -272,6 +333,15 @@ GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
   host_id = ntohl (msg->host_id);
   peer_id = ntohl (msg->peer_id);
+  if (VALID_PEER_ID (peer_id))
+  {
+    (void) GNUNET_asprintf (&emsg, "Peer with ID %u already exists", peer_id);
+    GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+                                 emsg);
+    GNUNET_free (emsg);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
   if (UINT32_MAX == peer_id)
   {
     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
@@ -281,42 +351,20 @@ GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
   }
   if (host_id == GST_context->host_id)
   {
-    char *emsg;
-
     /* We are responsible for this peer */
-    msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
-    config_size = ntohl (msg->config_size);
-    config = GNUNET_malloc (config_size);
-    dest_size = config_size;
-    if (Z_OK !=
-        (ret =
-         uncompress ((Bytef *) config, (uLongf *) & dest_size,
-                     (const Bytef *) &msg[1], (uLong) msize)))
-    {
-      GNUNET_break (0);         /* uncompression error */
-      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-      return;
-    }
-    if (config_size != dest_size)
+    cfg = GNUNET_TESTBED_extract_config_ (message);
+    if (NULL == cfg)
     {
-      GNUNET_break (0);         /* Uncompressed config size mismatch */
-      GNUNET_free (config);
-      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-      return;
-    }
-    cfg = GNUNET_CONFIGURATION_create ();
-    if (GNUNET_OK !=
-        GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
-    {
-      GNUNET_break (0);         /* Configuration parsing error */
-      GNUNET_free (config);
+      GNUNET_break (0);
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-    GNUNET_free (config);
     GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
                                            (unsigned long long) peer_id);
-    peer = GNUNET_malloc (sizeof (struct Peer));
+
+    GNUNET_CONFIGURATION_set_value_number (cfg, "PATHS", "PEERID",
+                                           (unsigned long long) peer_id);
+    peer = GNUNET_new (struct Peer);
     peer->is_remote = GNUNET_NO;
     peer->details.local.cfg = cfg;
     peer->id = peer_id;
@@ -337,9 +385,7 @@ GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
     }
     peer->details.local.is_running = GNUNET_NO;
     peer_list_add (peer);
-    reply =
-        GNUNET_malloc (sizeof
-                       (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
+    reply = GNUNET_new (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage);
     reply->header.size =
         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
     reply->header.type =
@@ -359,17 +405,16 @@ GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
-
-  peer = GNUNET_malloc (sizeof (struct Peer));
+  peer = GNUNET_new (struct Peer);
   peer->is_remote = GNUNET_YES;
   peer->id = peer_id;
   peer->details.remote.slave = GST_slave_list[route->dest];
   peer->details.remote.remote_host_id = host_id;
-  fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+  fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
   GNUNET_SERVER_client_keep (client);
   fo_ctxt->client = client;
   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
-  fo_ctxt->cls = peer;          //GST_slave_list[route->dest]->controller;
+  fo_ctxt->cls = peer;
   fo_ctxt->type = OP_PEER_CREATE;
   fo_ctxt->opc =
       GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
@@ -405,7 +450,7 @@ GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
   peer_id = ntohl (msg->peer_id);
   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
              peer_id, GNUNET_ntohll (msg->operation_id));
-  if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
+  if (!VALID_PEER_ID (peer_id))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
          "Asked to destroy a non existent peer with id: %u\n", peer_id);
@@ -418,7 +463,7 @@ GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
   if (GNUNET_YES == peer->is_remote)
   {
     /* Forward the destory message to sub controller */
-    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fopc->client = client;
     fopc->cls = peer;
@@ -447,6 +492,40 @@ GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
 }
 
 
+/**
+ * Stats a peer
+ *
+ * @param peer the peer to start
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+static int
+start_peer (struct Peer *peer)
+{
+  GNUNET_assert (GNUNET_NO == peer->is_remote);
+  if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
+    return GNUNET_SYSERR;
+  peer->details.local.is_running = GNUNET_YES;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Stops a peer
+ *
+ * @param peer the peer to stop
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+static int
+stop_peer (struct Peer *peer)
+{
+  GNUNET_assert (GNUNET_NO == peer->is_remote);
+  if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
+    return GNUNET_SYSERR;
+  peer->details.local.is_running = GNUNET_NO;
+  return GNUNET_OK;
+}
+
+
 /**
  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
  *
@@ -466,7 +545,7 @@ GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
 
   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
   peer_id = ntohl (msg->peer_id);
-  if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+  if (!VALID_PEER_ID (peer_id))
   {
     GNUNET_break (0);
     LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -477,7 +556,7 @@ GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
   peer = GST_peer_list[peer_id];
   if (GNUNET_YES == peer->is_remote)
   {
-    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fopc->client = client;
     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
@@ -495,15 +574,14 @@ GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
-  if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
+  if (GNUNET_OK != start_peer (peer))
   {
     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
                                  "Failed to start");
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
-  peer->details.local.is_running = GNUNET_YES;
-  reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+  reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
@@ -535,7 +613,7 @@ GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
   peer_id = ntohl (msg->peer_id);
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
-  if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+  if (!VALID_PEER_ID (peer_id))
   {
     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
                                  "Peer not found");
@@ -547,7 +625,7 @@ GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
          peer_id);
-    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fopc->client = client;
     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
@@ -565,7 +643,7 @@ GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
-  if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
+  if (GNUNET_OK != stop_peer (peer))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
@@ -574,8 +652,7 @@ GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
-  peer->details.local.is_running = GNUNET_NO;
-  reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+  reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
@@ -601,6 +678,7 @@ GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
 {
   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
+  struct ForwardedOperationContext *fopc;
   struct Peer *peer;
   char *config;
   char *xconfig;
@@ -611,7 +689,8 @@ GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
 
   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
   peer_id = ntohl (msg->peer_id);
-  if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+  LOG_DEBUG ("Received GET_CONFIG for peer %u\n", peer_id);
+  if (!VALID_PEER_ID (peer_id))
   {
     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
                                  "Peer not found");
@@ -621,10 +700,8 @@ GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
   peer = GST_peer_list[peer_id];
   if (GNUNET_YES == peer->is_remote)
   {
-    struct ForwardedOperationContext *fopc;
-
     LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
-    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fopc->client = client;
     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
@@ -654,7 +731,7 @@ GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
   reply = GNUNET_realloc (xconfig, msize);
   (void) memmove (&reply[1], reply, xc_size);
   reply->header.size = htons (msize);
-  reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
+  reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
   reply->peer_id = msg->peer_id;
   reply->operation_id = msg->operation_id;
   GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
@@ -665,6 +742,230 @@ GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
 }
 
 
+/**
+ * Cleans up the given PeerReconfigureContext
+ *
+ * @param prc the PeerReconfigureContext
+ */
+static void
+cleanup_prc (struct PeerReconfigureContext *prc)
+{
+  struct Peer *peer;
+
+  if (VALID_PEER_ID (prc->peer_id))
+  {
+    peer = GST_peer_list [prc->peer_id];
+    if (1 != prc->stopped)
+    {
+      GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
+      stop_peer (peer);         /* Stop the peer synchronously */
+    }
+  }
+  if (NULL != prc->cfg)
+    GNUNET_CONFIGURATION_destroy (prc->cfg);
+  GNUNET_SERVER_client_drop (prc->client);
+  GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
+  GNUNET_free (prc);
+}
+
+
+/**
+ * Cleans up the Peer reconfigure context list
+ */
+void
+GST_free_prcq ()
+{
+  while (NULL != prc_head)
+    cleanup_prc (prc_head);
+}
+
+
+/**
+ * Update peer configuration
+ *
+ * @param peer the peer to update
+ * @param cfg the new configuration
+ * @return error message (freshly allocated); NULL upon success
+ */
+static char *
+update_peer_config (struct Peer *peer,
+                    struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  char *emsg;
+
+  GNUNET_TESTING_peer_destroy (peer->details.local.peer);
+  GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
+  peer->details.local.cfg = cfg;
+  emsg = NULL;
+  peer->details.local.peer
+      = GNUNET_TESTING_peer_configure (GST_context->system,
+                                       peer->details.local.cfg, peer->id,
+                                       NULL /* Peer id */ ,
+                                       &emsg);
+  return emsg;
+}
+
+
+/**
+ * Callback to inform whether the peer is running or stopped.
+ *
+ * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
+ * @param p the respective peer whose status is being reported
+ * @param success GNUNET_YES if the peer is stopped; GNUNET_SYSERR upon any
+ *          error
+ */
+static void
+prc_stop_cb (void *cls, struct GNUNET_TESTING_Peer *p, int success)
+{
+  struct PeerReconfigureContext *prc = cls;
+  struct Peer *peer;
+  char *emsg;
+
+  GNUNET_assert (VALID_PEER_ID (prc->peer_id));
+  peer = GST_peer_list [prc->peer_id];
+  GNUNET_assert (GNUNET_NO == peer->is_remote);
+  emsg = update_peer_config (peer, prc->cfg);
+  prc->cfg = NULL;
+  prc->stopped = 1;
+  if (NULL != emsg)
+  {
+    GST_send_operation_fail_msg (prc->client, prc->op_id, emsg);
+    goto cleanup;
+  }
+  if (GNUNET_OK != start_peer (peer))
+  {
+    GST_send_operation_fail_msg (prc->client, prc->op_id,
+                                 "Failed to start reconfigured peer");
+    goto cleanup;
+  }
+  GST_send_operation_success_msg (prc->client, prc->op_id);
+
+ cleanup:
+  cleanup_prc (prc);
+  return;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
+ * Should stop the peer asyncronously, destroy it and create it again with the
+ * new configuration.
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_peer_reconfigure (void *cls, struct GNUNET_SERVER_Client *client,
+                             const struct GNUNET_MessageHeader *message)
+{
+  const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
+  struct Peer *peer;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct ForwardedOperationContext *fopc;
+  struct PeerReconfigureContext *prc;
+  char *emsg;
+  uint64_t op_id;
+  uint32_t peer_id;
+  uint16_t msize;
+
+  msize = ntohs (message->size);
+  if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
+  {
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
+  peer_id = ntohl (msg->peer_id);
+  op_id = GNUNET_ntohll (msg->operation_id);
+  if (!VALID_PEER_ID (peer_id))
+  {
+    GNUNET_break (0);
+    GST_send_operation_fail_msg (client, op_id, "Peer not found");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  peer = GST_peer_list[peer_id];
+  if (GNUNET_YES == peer->is_remote)
+  {
+    LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
+    fopc = GNUNET_new (struct ForwardedOperationContext);
+    GNUNET_SERVER_client_keep (client);
+    fopc->client = client;
+    fopc->operation_id = op_id;
+    fopc->type = OP_PEER_RECONFIGURE;
+    fopc->opc =
+        GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+                                               slave->controller,
+                                               fopc->operation_id, &msg->header,
+                                               &GST_forwarded_operation_reply_relay,
+                                               fopc);
+    fopc->timeout_task =
+        GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
+                                      fopc);
+    GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", peer_id);
+  if (0 < peer->reference_cnt)
+  {
+    GNUNET_break (0);
+    GST_send_operation_fail_msg (client, op_id, "Peer in use");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (GNUNET_YES == peer->destroy_flag)
+  {
+    GNUNET_break (0);
+    GST_send_operation_fail_msg (client, op_id, "Peer is being destroyed");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  cfg = GNUNET_TESTBED_extract_config_ (message);
+  if (NULL == cfg)
+  {
+    GNUNET_break (0);
+    GST_send_operation_fail_msg (client, op_id, "Compression error");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  if (GNUNET_NO == peer->details.local.is_running)
+  {
+    emsg = update_peer_config (peer, cfg);
+    if (NULL != emsg)
+      GST_send_operation_fail_msg (client, op_id, emsg);
+    GST_send_operation_success_msg (client, op_id);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_free_non_null (emsg);
+    return;
+  }
+  prc = GNUNET_new (struct PeerReconfigureContext);
+  if (GNUNET_OK !=
+      GNUNET_TESTING_peer_stop_async (peer->details.local.peer, &prc_stop_cb,
+                                      prc))
+  {
+    GNUNET_assert (0 < GNUNET_asprintf (&emsg,
+                                        "Error trying to stop peer %u asynchronously\n",
+                                        peer_id));
+    LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
+    GST_send_operation_fail_msg (client, op_id, emsg);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_free (prc);
+    GNUNET_free (emsg);
+    return;
+  }
+  prc->cfg = cfg;
+  prc->peer_id = peer_id;
+  prc->op_id = op_id;
+  prc->client = client;
+  GNUNET_SERVER_client_keep (client);
+  GNUNET_CONTAINER_DLL_insert_tail (prc_head, prc_tail, prc);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
 /**
  * Cleanup the context information created for managing a peer's service
  *
@@ -768,14 +1069,13 @@ arm_ret_string (enum GNUNET_ARM_Result result)
  * 'rs' will indicate that, and 'service' and 'result' will be undefined.
  *
  * @param cls ManageServiceContext
- * @param arm handle to the arm connection
  * @param rs status of the request
  * @param service service name
  * @param result result of the operation
  */
 static void
-service_manage_result_cb (void *cls, struct GNUNET_ARM_Handle *arm,
-                          enum GNUNET_ARM_RequestStatus rs, 
+service_manage_result_cb (void *cls,
+                          enum GNUNET_ARM_RequestStatus rs,
                           const char *service, enum GNUNET_ARM_Result result)
 {
   struct ManageServiceContext *mctx = cls;
@@ -814,7 +1114,7 @@ service_manage_result_cb (void *cls, struct GNUNET_ARM_Handle *arm,
     goto ret;
   }
   /* service started successfully */
-  
+
  ret:
   if (NULL != emsg)
   {
@@ -849,17 +1149,17 @@ GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
   uint64_t op_id;
   uint32_t peer_id;
   uint16_t msize;
-  
+
 
   msize = ntohs (message->size);
   if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
   {
-    GNUNET_break_op (0);  
+    GNUNET_break_op (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
   msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
-  service = (const char *) &msg[1];  
+  service = (const char *) &msg[1];
   if ('\0' != service[msize - sizeof
                       (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
   {
@@ -871,7 +1171,7 @@ GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
   {
     GNUNET_break_op (0);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;    
+    return;
   }
   peer_id = ntohl (msg->peer_id);
   op_id = GNUNET_ntohll (msg->operation_id);
@@ -893,7 +1193,7 @@ GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
   if (GNUNET_YES == peer->is_remote)
   {
     /* Forward the destory message to sub controller */
-    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fopc->client = client;
     fopc->cls = peer;
@@ -912,6 +1212,11 @@ GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
+  if (GNUNET_NO == peer->details.local.is_running)
+  {
+    emsg = GNUNET_strdup ("Peer not running\n");
+    goto err_ret;
+  }
   if ((0 != peer->reference_cnt)
       && ( (0 == strcasecmp ("core", service))
            || (0 == strcasecmp ("transport", service)) )  )
@@ -929,7 +1234,7 @@ GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
                      peer_id);
     goto err_ret;
   }
-  mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
+  mctx = GNUNET_new (struct ManageServiceContext);
   mctx->peer = peer;
   peer->reference_cnt++;
   mctx->op_id = op_id;
@@ -989,7 +1294,7 @@ GST_destroy_peers ()
   {
     peer = GST_peer_list[id];
     if (NULL == peer)
-      continue;    
+      continue;
     if (GNUNET_NO == peer->is_remote)
     {
       if (GNUNET_YES == peer->details.local.is_running)
@@ -1005,34 +1310,6 @@ GST_destroy_peers ()
 }
 
 
-/**
- * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
- *
- * @param cls the ForwardedOperationContext
- * @param tc the scheduler task context
- */
-static void
-shutdown_peers_timeout_cb (void *cls,
-                           const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct ForwardedOperationContext *fo_ctxt = cls;
-  struct HandlerContext_ShutdownPeers *hc;
-
-  fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-  hc = fo_ctxt->cls;
-  hc->timeout = GNUNET_YES;
-  GNUNET_assert (0 < hc->nslaves);
-  hc->nslaves--;
-  if (0 == hc->nslaves)
-    GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
-                                 "Timeout at a slave controller");
-  GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);  
-  GNUNET_SERVER_client_drop (fo_ctxt->client);
-  GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
-  GNUNET_free (fo_ctxt);
-}
-
-
 /**
  * The reply msg handler forwarded SHUTDOWN_PEERS operation.  Checks if a
  * success reply is received from all clients and then sends the success message
@@ -1047,14 +1324,11 @@ shutdown_peers_reply_cb (void *cls,
 {
   struct ForwardedOperationContext *fo_ctxt = cls;
   struct HandlerContext_ShutdownPeers *hc;
-  
+
   hc = fo_ctxt->cls;
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
-  GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
-  fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (0 < hc->nslaves);
   hc->nslaves--;
-  if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != 
+  if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
       ntohs (msg->type))
     hc->timeout = GNUNET_YES;
   if (0 == hc->nslaves)
@@ -1064,6 +1338,8 @@ shutdown_peers_reply_cb (void *cls,
                                    "Timeout at a slave controller");
     else
       GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
+    GNUNET_free (hc);
+    hc = NULL;
   }
   GNUNET_SERVER_client_drop (fo_ctxt->client);
   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
@@ -1098,7 +1374,7 @@ GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
   GST_clear_fopcq ();
   /* Forward to all slaves which we have started */
   op_id = GNUNET_ntohll (msg->operation_id);
-  hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
+  hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
   /* FIXME: have a better implementation where we track which slaves are
      started by this controller */
   for (cnt = 0; cnt < GST_slave_list_size; cnt++)
@@ -1110,7 +1386,7 @@ GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
       continue;
     LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
     hc->nslaves++;
-    fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
     GNUNET_SERVER_client_keep (client);
     fo_ctxt->client = client;
     fo_ctxt->operation_id = op_id;
@@ -1122,9 +1398,6 @@ GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
                                                &msg->header,
                                                shutdown_peers_reply_cb,
                                                fo_ctxt);
-    fo_ctxt->timeout_task =
-        GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
-                                      fo_ctxt);
     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
   }
   LOG_DEBUG ("Shutting down peers\n");
@@ -1134,5 +1407,5 @@ GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
     GST_send_operation_success_msg (client, op_id);
     GNUNET_free (hc);
   }
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);  
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }