}
+/**
+ * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
+ */
+struct HandlerContext_ShutdownPeers
+{
+ /**
+ * The number of slave we expect to hear from since we forwarded the
+ * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
+ */
+ unsigned int nslaves;
+
+ /**
+ * Did we observe a timeout with respect to this operation at any of the
+ * slaves
+ */
+ int timeout;
+};
+
+
+/**
+ * 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;
+
+ 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
+ * to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the message to relay
+ */
+static void
+shutdown_peers_reply_cb (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationContext *fo_ctxt = cls;
+ struct HandlerContext_ShutdownPeers *hc;
+
+ hc = fo_ctxt->cls;
+ GNUNET_assert (0 < hc->nslaves);
+ hc->nslaves--;
+ if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
+ ntohs (msg->type))
+ hc->timeout = GNUNET_YES;
+ if (0 == hc->nslaves)
+ {
+ if (GNUNET_YES == hc->timeout)
+ GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
+ "Timeout at a slave controller");
+ else
+ send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
+ }
+ GNUNET_SERVER_client_drop (fo_ctxt->client);
+ GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
+ GNUNET_free (fo_ctxt);
+}
+
+
+/**
+ * Stops and destroys all peers
+ */
+static void
+destroy_peers ()
+{
+ struct Peer *peer;
+ unsigned int id;
+
+ if (NULL == GST_peer_list)
+ return;
+ for (id = 0; id < GST_peer_list_size; id++)
+ {
+ peer = GST_peer_list[id];
+ if (NULL == peer)
+ continue;
+ /* If destroy flag is set it means that this peer should have been
+ * destroyed by a context which we destroy before */
+ GNUNET_break (GNUNET_NO == peer->destroy_flag);
+ /* counter should be zero as we free all contexts before */
+ GNUNET_break (0 == peer->reference_cnt);
+ if ((GNUNET_NO == peer->is_remote) &&
+ (GNUNET_YES == peer->details.local.is_running))
+ GNUNET_TESTING_peer_kill (peer->details.local.peer);
+ }
+ for (id = 0; id < GST_peer_list_size; id++)
+ {
+ peer = GST_peer_list[id];
+ if (NULL == peer)
+ continue;
+ if (GNUNET_NO == peer->is_remote)
+ {
+ if (GNUNET_YES == peer->details.local.is_running)
+ GNUNET_TESTING_peer_wait (peer->details.local.peer);
+ GNUNET_TESTING_peer_destroy (peer->details.local.peer);
+ GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
+ }
+ GNUNET_free (peer);
+ }
+ GNUNET_free_non_null (GST_peer_list);
+ GST_peer_list = NULL;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
+ struct HandlerContext_ShutdownPeers *hc;
+ struct Slave *slave;
+ struct ForwardedOperationContext *fo_ctxt;
+ uint64_t op_id;
+ unsigned int cnt;
+
+ msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
+ LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
+ /* Forward to all slaves which we have started */
+ op_id = GNUNET_ntohll (msg->operation_id);
+ hc = GNUNET_malloc (sizeof (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++)
+ {
+ slave = GST_slave_list[cnt];
+ if (NULL == slave)
+ continue;
+ if (NULL == slave->controller_proc) /* We didn't start the slave */
+ continue;
+ LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
+ hc->nslaves++;
+ fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fo_ctxt->client = client;
+ fo_ctxt->operation_id = op_id;
+ fo_ctxt->cls = hc;
+ fo_ctxt->type = OP_SHUTDOWN_PEERS;
+ fo_ctxt->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
+ fo_ctxt->operation_id,
+ &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");
+ /* Stop and destroy all peers */
+ destroy_peers ();
+ if (0 == hc->nslaves)
+ {
+ send_operation_success_msg (client, op_id);
+ GNUNET_free (hc);
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
/**
* Iterator over hash map entries.
*
case OP_PEER_CREATE:
GNUNET_free (fopc->cls);
break;
+ case OP_SHUTDOWN_PEERS:
+ {
+ struct HandlerContext_ShutdownPeers *hc = fopc->cls;
+
+ GNUNET_assert (0 < hc->nslaves);
+ hc->nslaves--;
+ if (0 == hc->nslaves)
+ GNUNET_free (hc);
+ }
+ break;
case OP_PEER_START:
case OP_PEER_STOP:
case OP_PEER_DESTROY:
GST_free_occq ();
GST_free_roccq ();
/* Clear peer list */
- for (id = 0; id < GST_peer_list_size; id++)
- if (NULL != GST_peer_list[id])
- {
- /* If destroy flag is set it means that this peer should have been
- * destroyed by a context which we destroy before */
- GNUNET_break (GNUNET_NO == GST_peer_list[id]->destroy_flag);
- /* counter should be zero as we free all contexts before */
- GNUNET_break (0 == GST_peer_list[id]->reference_cnt);
- if ((GNUNET_NO == GST_peer_list[id]->is_remote) &&
- (GNUNET_YES == GST_peer_list[id]->details.local.is_running))
- GNUNET_TESTING_peer_kill (GST_peer_list[id]->details.local.peer);
- }
- for (id = 0; id < GST_peer_list_size; id++)
- if (NULL != GST_peer_list[id])
- {
- if (GNUNET_NO == GST_peer_list[id]->is_remote)
- {
- if (GNUNET_YES == GST_peer_list[id]->details.local.is_running)
- GNUNET_TESTING_peer_wait (GST_peer_list[id]->details.local.peer);
- GNUNET_TESTING_peer_destroy (GST_peer_list[id]->details.local.peer);
- GNUNET_CONFIGURATION_destroy (GST_peer_list[id]->details.local.cfg);
- }
- GNUNET_free (GST_peer_list[id]);
- }
- GNUNET_free_non_null (GST_peer_list);
+ destroy_peers ();
/* Clear host list */
for (id = 0; id < GST_host_list_size; id++)
if (NULL != GST_host_list[id])
sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
{&GST_handle_remote_overlay_connect, NULL,
GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
- {handle_slave_get_config, NULL,
+ {&handle_slave_get_config, NULL,
GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
+ {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
+ sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
{NULL}
};
char *logfile;
*/
RC_READY,
- /**
- * Peers are stopped
- */
- RC_PEERS_STOPPED,
+ /* /\** */
+ /* * Peers are stopped */
+ /* *\/ */
+ /* RC_PEERS_STOPPED, */
+
+ /* /\** */
+ /* * Peers are destroyed */
+ /* *\/ */
+ /* RC_PEERS_DESTROYED */
/**
- * Peers are destroyed
+ * All peers shutdown (stopped and destroyed)
*/
- RC_PEERS_DESTROYED
+ RC_PEERS_SHUTDOWN
};
GNUNET_assert (NULL == rc->reg_handle);
GNUNET_assert (NULL == rc->peers);
GNUNET_assert (NULL == rc->hc_handles);
- GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
+ GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
if (NULL != rc->dll_op_head)
{ /* cancel our pending operations */
while (NULL != (dll_op = rc->dll_op_head))
{
struct RunContext *rc = cls;
struct DLLOperation *dll_op;
- int all_peers_destroyed;
- unsigned int peer;
unsigned int nhost;
GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
}
if (RC_INIT == rc->state)
rc->state = RC_READY; /* Even though we haven't called the master callback */
- rc->peer_count = 0;
- /* Check if some peers are stopped */
- for (peer = 0; peer < rc->num_peers; peer++)
- {
- if (NULL == rc->peers[peer])
- continue;
- if (PS_STOPPED != rc->peers[peer]->state)
- break;
- }
- if (peer == rc->num_peers)
- {
- /* All peers are stopped */
- rc->state = RC_PEERS_STOPPED;
- all_peers_destroyed = GNUNET_YES;
- for (peer = 0; peer < rc->num_peers; peer++)
- {
- if (NULL == rc->peers[peer])
- continue;
- all_peers_destroyed = GNUNET_NO;
- dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
- dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
- GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
- dll_op);
- }
- if (all_peers_destroyed == GNUNET_NO)
- {
- DEBUG ("Destroying peers\n");
- rc->pstart_time = GNUNET_TIME_absolute_get ();
- return;
- }
- }
- /* Some peers are stopped */
- DEBUG ("Stopping peers\n");
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->op = GNUNET_TESTBED_shutdown_peers (rc->c, dll_op, NULL, NULL);
+ DEBUG ("Shutting down peers\n");
rc->pstart_time = GNUNET_TIME_absolute_get ();
- for (peer = 0; peer < rc->num_peers; peer++)
- {
- if ((NULL == rc->peers[peer]) || (PS_STARTED != rc->peers[peer]->state))
- {
- rc->peer_count++;
- continue;
- }
- dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
- dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
- dll_op->cls = rc->peers[peer];
- GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
- dll_op);
- }
- if (rc->peer_count != rc->num_peers)
- return;
- GNUNET_free (rc->peers);
- rc->peers = NULL;
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+ dll_op);
+ return;
}
}
- rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
- * state where all peers are destroyed */
+ rc->state = RC_PEERS_SHUTDOWN; /* No peers are present so we consider the
+ * state where all peers are SHUTDOWN */
GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
}
{
struct RunContext *rc = cls;
struct DLLOperation *dll_op;
- unsigned int peer_id;
if (RC_INIT == rc->state)
{
if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
(event->details.operation_finished.operation == dll_op->op))
break;
- if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
- (event->details.peer_stop.peer == dll_op->cls))
- break;
}
if (NULL == dll_op)
goto call_cc;
GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
GNUNET_TESTBED_operation_done (dll_op->op);
GNUNET_free (dll_op);
- rc->peer_count++;
- if (rc->peer_count < rc->num_peers)
- return;
switch (rc->state)
{
case RC_PEERS_CREATED:
case RC_READY:
- rc->state = RC_PEERS_STOPPED;
- DEBUG ("Peers stopped in %s\n", prof_time (rc));
- DEBUG ("Destroying peers\n");
- rc->pstart_time = GNUNET_TIME_absolute_get ();
- rc->peer_count = 0;
- for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
- {
- dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
- dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
- GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
- dll_op);
- }
- break;
- case RC_PEERS_STOPPED:
- rc->state = RC_PEERS_DESTROYED;
+ rc->state = RC_PEERS_SHUTDOWN;
GNUNET_free (rc->peers);
rc->peers = NULL;
- DEBUG ("Peers destroyed in %s\n", prof_time (rc));
+ DEBUG ("Peers shut down in %s\n", prof_time (rc));
GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
break;
default:
GNUNET_CONFIGURATION_destroy (rc->cfg);
rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
event_mask = rc->event_mask;
- event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)