X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Ftestbed%2Ftestbed_api_services.c;h=1a94ecc0ffd1bc097f365afe5a7e40e84bb96d84;hb=f0a19819c13f90c7f6692fbefc68696d40c8769c;hp=89427bfd962291e34340688d40322c343258bde2;hpb=65f3c726359d3c60c760b3c116ec7c5ab97f5e5d;p=oweals%2Fgnunet.git diff --git a/src/testbed/testbed_api_services.c b/src/testbed/testbed_api_services.c index 89427bfd9..1a94ecc0f 100644 --- a/src/testbed/testbed_api_services.c +++ b/src/testbed/testbed_api_services.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2008--2012 Christian Grothoff (and other contributing authors) + Copyright (C) 2008--2013 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,17 +14,221 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** - * @file testing/testbed_api_services.c + * @file testbed/testbed_api_services.c * @brief convenience functions for accessing services * @author Christian Grothoff */ #include "platform.h" +#include "testbed_api.h" #include "testbed_api_peers.h" +#include "testbed_api_operations.h" + + +/** + * States for Service connect operations + */ +enum State +{ + /** + * Initial state + */ + INIT, + + /** + * The configuration request has been sent + */ + CFG_REQUEST_QUEUED, + + /** + * connected to service + */ + SERVICE_CONNECTED +}; + + +/** + * Data accessed during service connections + */ +struct ServiceConnectData +{ + /** + * helper function callback to establish the connection + */ + GNUNET_TESTBED_ConnectAdapter ca; + + /** + * helper function callback to close the connection + */ + GNUNET_TESTBED_DisconnectAdapter da; + + /** + * Closure to the above callbacks + */ + void *cada_cls; + + /** + * Service name + */ + char *service_name; + + /** + * Closure for operation event + */ + void *op_cls; + + /** + * The operation which created this structure + */ + struct GNUNET_TESTBED_Operation *operation; + + /** + * The operation context from GNUNET_TESTBED_forward_operation_msg_() + */ + struct OperationContext *opc; + + /** + * The peer handle + */ + struct GNUNET_TESTBED_Peer *peer; + + /** + * The acquired configuration of the peer + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * The op_result pointer from ConnectAdapter + */ + void *op_result; + + /** + * The operation completion callback + */ + GNUNET_TESTBED_ServiceConnectCompletionCallback cb; + + /** + * The closure for operation completion callback + */ + void *cb_cls; + + /** + * State information + */ + enum State state; + +}; + + +/** + * Type of a function to call when we receive a message + * from the service. + * + * @param cls ServiceConnectData + * @param msg message received, NULL on timeout or fatal error + */ +static void +configuration_receiver (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct ServiceConnectData *data = cls; + struct GNUNET_TESTBED_Controller *c; + const char *emsg; + struct GNUNET_TESTBED_EventInformation info; + uint16_t mtype; + + c = data->peer->controller; + mtype = ntohs (msg->type); + emsg = NULL; + info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED; + info.op = data->operation; + info.op_cls = data->op_cls; + if (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT == mtype) + { + emsg = + GNUNET_TESTBED_parse_error_string_ ((const struct + GNUNET_TESTBED_OperationFailureEventMessage + *) msg); + if (NULL == emsg) + emsg = "Unknown error"; + info.details.operation_finished.emsg = emsg; + info.details.operation_finished.generic = NULL; + goto call_cb; + } + data->cfg = GNUNET_TESTBED_extract_config_ (msg); + GNUNET_assert (NULL == data->op_result); + data->op_result = data->ca (data->cada_cls, data->cfg); + info.details.operation_finished.emsg = NULL; + info.details.operation_finished.generic = data->op_result; + data->state = SERVICE_CONNECTED; + +call_cb: + if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) && + (NULL != c->cc)) + c->cc (c->cc_cls, &info); + if (NULL != data->cb) + data->cb (data->cb_cls, data->operation, data->op_result, emsg); +} + + +/** + * Function called when a service connect operation is ready + * + * @param cls the closure from GNUNET_TESTBED_operation_create_() + */ +static void +opstart_service_connect (void *cls) +{ + struct ServiceConnectData *data = cls; + struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg; + struct GNUNET_TESTBED_Controller *c; + uint64_t op_id; + + GNUNET_assert (NULL != data); + GNUNET_assert (NULL != data->peer); + c = data->peer->controller; + op_id = GNUNET_TESTBED_get_next_op_id (c); + msg = + GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id, op_id); + data->opc = + GNUNET_TESTBED_forward_operation_msg_ (c, op_id, &msg->header, + &configuration_receiver, data); + GNUNET_free (msg); + data->state = CFG_REQUEST_QUEUED; +} + + +/** + * Callback which will be called when service connect type operation is + * released + * + * @param cls the closure from GNUNET_TESTBED_operation_create_() + */ +static void +oprelease_service_connect (void *cls) +{ + struct ServiceConnectData *data = cls; + + switch (data->state) + { + case INIT: + break; + case CFG_REQUEST_QUEUED: + GNUNET_assert (NULL != data->opc); + GNUNET_TESTBED_forward_operation_msg_cancel_ (data->opc); + break; + case SERVICE_CONNECTED: + GNUNET_assert (NULL != data->cfg); + GNUNET_CONFIGURATION_destroy (data->cfg); + if (NULL != data->da) + data->da (data->cada_cls, data->op_result); + break; + } + GNUNET_free (data); +} /** @@ -33,29 +237,52 @@ * maintain connections with other systems. The actual service * handle is then returned via the 'op_result' member in the event * callback. The 'ca' callback is used to create the connection - * when the time is right; the 'da' callback will be used to + * when the time is right; the 'da' callback will be used to * destroy the connection (upon 'GNUNET_TESTBED_operation_done'). - * 'GNUNET_TESTBED_operation_cancel' can be used to abort this + * 'GNUNET_TESTBED_operation_done' can be used to abort this * operation until the event callback has been called. * * @param op_cls closure to pass in operation event * @param peer peer that runs the service * @param service_name name of the service to connect to + * @param cb the callback to call when this operation finishes + * @param cb_cls closure for the above callback * @param ca helper function to establish the connection * @param da helper function to close the connection * @param cada_cls closure for ca and da * @return handle for the operation */ struct GNUNET_TESTBED_Operation * -GNUNET_TESTBED_service_connect (void *op_cls, - struct GNUNET_TESTBED_Peer *peer, - const char *service_name, - GNUNET_TESTBED_ConnectAdapter ca, - GNUNET_TESTBED_DisconnectAdapter da, - void *cada_cls) +GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer, + const char *service_name, + GNUNET_TESTBED_ServiceConnectCompletionCallback + cb, void *cb_cls, + GNUNET_TESTBED_ConnectAdapter ca, + GNUNET_TESTBED_DisconnectAdapter da, + void *cada_cls) { - GNUNET_break (0); - return NULL; + struct ServiceConnectData *data; + + data = GNUNET_new (struct ServiceConnectData); + data->ca = ca; + data->da = da; + data->cada_cls = cada_cls; + data->op_cls = op_cls; + data->peer = peer; + data->state = INIT; + data->cb = cb; + data->cb_cls = cb_cls; + data->operation = + GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect, + &oprelease_service_connect); + GNUNET_TESTBED_operation_queue_insert_ (peer-> + controller->opq_parallel_service_connections, + data->operation); + GNUNET_TESTBED_operation_queue_insert_ (peer-> + controller->opq_parallel_operations, + data->operation); + GNUNET_TESTBED_operation_begin_wait_ (data->operation); + return data->operation; } /* end of testbed_api_services.c */