+ GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
+ &oprelease_overlay_connect);
+ GNUNET_TESTBED_host_queue_oc_ (p1->host, opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
+}
+
+
+/**
+ * Function called when a peer manage service operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_manage_service (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct ManageServiceData *data = opc->data;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
+ size_t xlen;
+
+ GNUNET_assert (NULL != data);
+ xlen = data->msize - sizeof(struct GNUNET_TESTBED_ManagePeerServiceMessage);
+ env = GNUNET_MQ_msg_extra (msg,
+ xlen,
+ GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE);
+ msg->peer_id = htonl (data->peer->unique_id);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ msg->start = (uint8_t) data->start;
+ GNUNET_memcpy (&msg[1],
+ data->service_name,
+ xlen);
+ GNUNET_free (data->service_name);
+ data->service_name = NULL;
+ opc->state = OPC_STATE_STARTED;
+ GNUNET_TESTBED_insert_opc_ (opc->c, opc);
+ GNUNET_MQ_send (opc->c->mq,
+ env);
+}
+
+
+/**
+ * Callback which will be called when peer manage server operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_manage_service (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct ManageServiceData *data;
+
+ data = opc->data;
+ switch (opc->state)
+ {
+ case OPC_STATE_STARTED:
+ GNUNET_TESTBED_remove_opc_ (opc->c, opc);
+ break;
+
+ case OPC_STATE_INIT:
+ GNUNET_assert (NULL != data);
+ GNUNET_free (data->service_name);
+ break;
+
+ case OPC_STATE_FINISHED:
+ break;
+ }
+ GNUNET_free_non_null (data);
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Start or stop given service at a peer. This should not be called to
+ * start/stop the peer's ARM service. Use GNUNET_TESTBED_peer_start(),
+ * GNUNET_TESTBED_peer_stop() for starting/stopping peer's ARM service. Success
+ * or failure of the generated operation is signalled through the controller
+ * event callback and/or operation completion callback.
+ *
+ * @param op_cls the closure for the operation
+ * @param peer the peer whose service is to be started/stopped
+ * @param service_name the name of the service
+ * @param cb the operation completion callback
+ * @param cb_cls the closure for the operation completion callback
+ * @param start 1 to start the service; 0 to stop the service
+ * @return an operation handle; NULL upon error (peer not running)
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_peer_manage_service (void *op_cls,
+ struct GNUNET_TESTBED_Peer *peer,
+ const char *service_name,
+ GNUNET_TESTBED_OperationCompletionCallback
+ cb,
+ void *cb_cls,
+ unsigned int start)
+{
+ struct ManageServiceData *data;
+ struct OperationContext *opc;
+ size_t msize;
+
+ GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */
+ msize = strlen (service_name) + 1;
+ msize += sizeof(struct GNUNET_TESTBED_ManagePeerServiceMessage);
+ if (GNUNET_MAX_MESSAGE_SIZE < msize)
+ return NULL;
+ data = GNUNET_new (struct ManageServiceData);
+ data->cb = cb;
+ data->cb_cls = cb_cls;
+ data->peer = peer;
+ data->service_name = GNUNET_strdup (service_name);
+ data->start = start;
+ data->msize = (uint16_t) msize;
+ opc = GNUNET_new (struct OperationContext);
+ opc->data = data;
+ opc->c = peer->controller;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->type = OP_MANAGE_SERVICE;
+ opc->op_cls = op_cls;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_manage_service,
+ &oprelease_manage_service);