-fix channel data range to make -1 legal value
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_peers.c
index 00bfe479eb93bcc1a21c8d407666c783b5f16a2c..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
 
   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
   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
 /**
  * @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"
  */
 
 #include "gnunet-service-testbed.h"
  */
 struct Peer **GST_peer_list;
 
  */
 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
 
 /**
  * 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 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;
   /**
    * 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
    */
   /**
    * 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
    */
    * 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
 
 /**
  * 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;
     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;
 
   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)
   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;
   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;
   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);
   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),
   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)
   {
   }
   if (host_id == GST_context->host_id)
   {
-    char *emsg;
-
     /* We are responsible for this peer */
     /* 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_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-    GNUNET_free (config);
     GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
                                            (unsigned long long) peer_id);
     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;
     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);
     }
     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 =
     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;
   }
     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;
   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);
   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
   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));
   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);
   {
     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 */
   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;
     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
  *
 /**
  * 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);
 
   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,
   {
     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)
   {
   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);
     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;
   }
     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;
   }
   {
     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);
   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);
   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");
   {
     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);
   {
     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);
     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;
   }
     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),
   {
     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);
     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);
   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;
 {
   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
+  struct ForwardedOperationContext *fopc;
   struct Peer *peer;
   char *config;
   char *xconfig;
   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);
 
   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");
   {
     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)
   {
   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);
     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);
     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 = 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,
   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
  *
 /**
  * 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
  * '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
  * @param rs status of the request
  * @param service service name
  * @param result result of the operation
  */
 static void
-service_manage_result_cb (void *cls, 
-                          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;
                           const char *service, enum GNUNET_ARM_Result result)
 {
   struct ManageServiceContext *mctx = cls;
@@ -814,7 +1114,7 @@ service_manage_result_cb (void *cls,
     goto ret;
   }
   /* service started successfully */
     goto ret;
   }
   /* service started successfully */
-  
+
  ret:
   if (NULL != emsg)
   {
  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;
   uint64_t op_id;
   uint32_t peer_id;
   uint16_t msize;
-  
+
 
   msize = ntohs (message->size);
   if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
   {
 
   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;
     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])
   {
   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);
   {
     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);
   }
   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 */
   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;
     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;
   }
     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)) )  )
   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;
   }
                      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;
   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)
   {
     peer = GST_peer_list[id];
     if (NULL == peer)
-      continue;    
+      continue;
     if (GNUNET_NO == peer->is_remote)
     {
       if (GNUNET_YES == peer->details.local.is_running)
     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
 /**
  * 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;
 {
   struct ForwardedOperationContext *fo_ctxt = cls;
   struct HandlerContext_ShutdownPeers *hc;
-  
+
   hc = fo_ctxt->cls;
   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--;
   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)
       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);
                                    "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);
   }
   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);
   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++)
   /* 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++;
       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;
     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);
                                                &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");
     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);
   }
     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);
 }
 }