X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftestbed%2Fgnunet-service-testbed_barriers.c;h=4450ddf777c2d59afd01f22e993fdda364be51af;hb=dd1927b960c7cea13733e061a11142274652ba27;hp=c12075d66df23dd0aa447155e4624919a6ffd0ae;hpb=6c684b3367b9f21ea46b0565b6e4aac8daf85f51;p=oweals%2Fgnunet.git diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c index c12075d66..4450ddf77 100644 --- a/src/testbed/gnunet-service-testbed_barriers.c +++ b/src/testbed/gnunet-service-testbed_barriers.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2008--2013 Christian Grothoff (and other contributing authors) + Copyright (C) 2008--2013 Christian Grothoff (and other contributing authors) 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,20 @@ 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 testbed/gnunet-service-testbed_barriers.c * @brief barrier handling at the testbed controller - * @author Sree Harsha Totakura + * @author Sree Harsha Totakura */ #include "gnunet-service-testbed.h" +#include "gnunet-service-testbed_barriers.h" +#include "testbed_api_barriers.h" + /** * timeout for outgoing message transmissions in seconds @@ -40,6 +43,17 @@ ((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100)) +#ifdef LOG +#undef LOG +#endif + +/** + * Logging shorthand + */ +#define LOG(kind,...) \ + GNUNET_log_from (kind, "testbed-barriers", __VA_ARGS__) + + /** * Barrier */ @@ -152,6 +166,11 @@ struct Barrier */ struct GNUNET_HashCode hash; + /** + * The client handle to the master controller + */ + struct GNUNET_SERVER_Client *mc; + /** * The name of the barrier */ @@ -177,6 +196,16 @@ struct Barrier */ struct WBarrier *wtail; + /** + * Identifier for the timeout task + */ + struct GNUNET_SCHEDULER_Task * tout_task; + + /** + * The status of this barrier + */ + enum GNUNET_TESTBED_BarrierStatus status; + /** * Number of barriers wrapped in the above DLL */ @@ -187,6 +216,11 @@ struct Barrier */ unsigned int num_wbarriers_reached; + /** + * Number of wrapped barrier initialised so far + */ + unsigned int num_wbarriers_inited; + /** * Number of peers which have reached this barrier */ @@ -201,11 +235,7 @@ struct Barrier * Quorum percentage to be reached */ uint8_t quorum; - - /** - * Was there a timeout while propagating initialisation - */ - uint8_t timedout; + }; @@ -231,7 +261,7 @@ static struct GNUNET_SERVICE_Context *ctx; * @param buf where the callee should write the message * @return number of bytes written to buf */ -static size_t +static size_t transmit_ready_cb (void *cls, size_t size, void *buf) { struct ClientCtx *ctx = cls; @@ -241,12 +271,11 @@ transmit_ready_cb (void *cls, size_t size, void *buf) size_t wrote; ctx->tx = NULL; - wrote = 0; if ((0 == size) || (NULL == buf)) { GNUNET_assert (NULL != ctx->client); GNUNET_SERVER_client_drop (ctx->client); - ctx->client = NULL; + ctx->client = NULL; return 0; } mq = ctx->mq_head; @@ -276,9 +305,11 @@ queue_message (struct ClientCtx *ctx, struct GNUNET_MessageHeader *msg) { struct MessageQueue *mq; struct GNUNET_SERVER_Client *client = ctx->client; - - mq = GNUNET_malloc (sizeof (struct MessageQueue)); + + mq = GNUNET_new (struct MessageQueue); mq->msg = msg; + LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", + ntohs (msg->type), ntohs (msg->size)); GNUNET_CONTAINER_DLL_insert_tail (ctx->mq_head, ctx->mq_tail, mq); if (NULL == ctx->tx) ctx->tx = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size), @@ -287,7 +318,33 @@ queue_message (struct ClientCtx *ctx, struct GNUNET_MessageHeader *msg) } -#if 0 +/** + * Function to cleanup client context data structure + * + * @param ctx the client context data structure + */ +static void +cleanup_clientctx (struct ClientCtx *ctx) +{ + struct MessageQueue *mq; + + if (NULL != ctx->client) + { + GNUNET_SERVER_client_set_user_context_ (ctx->client, NULL, 0); + GNUNET_SERVER_client_drop (ctx->client); + } + if (NULL != ctx->tx) + GNUNET_SERVER_notify_transmit_ready_cancel (ctx->tx); + if (NULL != (mq = ctx->mq_head)) + { + GNUNET_CONTAINER_DLL_remove (ctx->mq_head, ctx->mq_tail, mq); + GNUNET_free (mq->msg); + GNUNET_free (mq); + } + GNUNET_free (ctx); +} + + /** * Function to remove a barrier from the barrier map and cleanup resources * occupied by a barrier @@ -297,71 +354,89 @@ queue_message (struct ClientCtx *ctx, struct GNUNET_MessageHeader *msg) static void remove_barrier (struct Barrier *barrier) { + struct ClientCtx *ctx; + GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (barrier_map, &barrier->hash, barrier)); + while (NULL != (ctx = barrier->head)) + { + GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, ctx); + cleanup_clientctx (ctx); + } GNUNET_free (barrier->name); + GNUNET_SERVER_client_drop (barrier->mc); GNUNET_free (barrier); } /** - * Function called upon timeout while waiting for a response from the - * subcontrollers to barrier init message + * Cancels all subcontroller barrier handles * - * @param - * @return + * @param barrier the local barrier */ static void -fwd_tout_barrier_init (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +cancel_wrappers (struct Barrier *barrier) { - struct ForwardedOperationContext *foctx = cls; - struct Barrier *barrier = foctx->cls; - - barrier->nslaves--; - barrier->timedout = GNUNET_YES; - if (0 == barrier->nslaves) + struct WBarrier *wrapper; + + while (NULL != (wrapper = barrier->whead)) { - GST_send_operation_fail_msg (foctx->client, foctx->operation_id, - "Timeout while contacting a slave controller"); - remove_barrier (barrier); + GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier); + GNUNET_CONTAINER_DLL_remove (barrier->whead, barrier->wtail, wrapper); + GNUNET_free (wrapper); } } -#endif + /** - * Task for sending barrier crossed notifications to waiting client + * Send a status message about a barrier to the given client * - * @param cls the barrier which is crossed - * @param tc scheduler task context + * @param client the client to send the message to + * @param name the barrier name + * @param status the status of the barrier + * @param emsg the error message; should be non-NULL for + * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR */ static void -notify_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +send_client_status_msg (struct GNUNET_SERVER_Client *client, + const char *name, + enum GNUNET_TESTBED_BarrierStatus status, + const char *emsg) { - struct Barrier *barrier = cls; - struct ClientCtx *client_ctx; - struct GNUNET_TESTBED_BarrierStatus *msg; - struct GNUNET_MessageHeader *dup_msg; - uint16_t name_len; + struct GNUNET_TESTBED_BarrierStatusMsg *msg; + size_t name_len; uint16_t msize; - name_len = strlen (barrier->name) + 1; - msize = sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len; + GNUNET_assert ((NULL == emsg) || (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)); + name_len = strlen (name); + msize = sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + + (name_len + 1) + + ((NULL == emsg) ? 0 : (strlen (emsg) + 1)); msg = GNUNET_malloc (msize); msg->header.size = htons (msize); msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS); - msg->status = 0; - msg->name_len = htons (name_len); - (void) memcpy (msg->data, barrier->name, name_len); - msg->data[name_len] = '\0'; - while (NULL != (client_ctx = barrier->head)) - { - dup_msg = GNUNET_copy_message (&msg->header); - queue_message (client_ctx, dup_msg); - GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx); - GNUNET_SERVER_client_set_user_context_ (client_ctx->client, NULL, 0); - GNUNET_free (client_ctx); - } + msg->status = htons (status); + msg->name_len = htons ((uint16_t) name_len); + (void) memcpy (msg->data, name, name_len); + if (NULL != emsg) + (void) memcpy (msg->data + name_len + 1, emsg, strlen (emsg)); + GST_queue_message (client, &msg->header); +} + + +/** + * Sends a barrier failed message + * + * @param barrier the corresponding barrier + * @param emsg the error message; should be non-NULL for + * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR + */ +static void +send_barrier_status_msg (struct Barrier *barrier, const char *emsg) +{ + GNUNET_assert (0 != barrier->status); + send_client_status_msg (barrier->mc, barrier->name, barrier->status, emsg); } @@ -388,7 +463,7 @@ handle_barrier_wait (void *cls, struct GNUNET_SERVER_Client *client, struct GNUNET_HashCode key; size_t name_len; uint16_t msize; - + msize = ntohs (message->size); if (msize <= sizeof (struct GNUNET_TESTBED_BarrierWait)) { @@ -407,25 +482,31 @@ handle_barrier_wait (void *cls, struct GNUNET_SERVER_Client *client, name = GNUNET_malloc (name_len + 1); name[name_len] = '\0'; (void) memcpy (name, msg->name, name_len); - GNUNET_CRYPTO_hash (name, name_len - 1, &key); + LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n", name); + GNUNET_CRYPTO_hash (name, name_len, &key); + GNUNET_free (name); if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - GNUNET_free (name); return; } client_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientCtx); if (NULL == client_ctx) { - client_ctx = GNUNET_malloc (sizeof (struct ClientCtx)); + client_ctx = GNUNET_new (struct ClientCtx); client_ctx->client = client; GNUNET_SERVER_client_keep (client); client_ctx->barrier = barrier; GNUNET_CONTAINER_DLL_insert_tail (barrier->head, barrier->tail, client_ctx); - barrier->nreached++; - if (LOCAL_QUORUM_REACHED (barrier)) - notify_task_cb (barrier, NULL); + GNUNET_SERVER_client_set_user_context (client, client_ctx); + } + barrier->nreached++; + if ((barrier->num_wbarriers_reached == barrier->num_wbarriers) + && (LOCAL_QUORUM_REACHED (barrier))) + { + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED; + send_barrier_status_msg (barrier, NULL); } GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -443,21 +524,20 @@ static void disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client) { struct ClientCtx *client_ctx; - struct Barrier *barrier; - + + if (NULL == client) + return; client_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientCtx); if (NULL == client_ctx) return; - barrier = client_ctx->barrier; - GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx); - if (NULL != client_ctx->tx) - GNUNET_SERVER_notify_transmit_ready_cancel (client_ctx->tx); - + cleanup_clientctx (client_ctx); } /** * Function to initialise barrriers component + * + * @param cfg the configuration to use for initialisation */ void GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg) @@ -473,7 +553,31 @@ GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg) GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN); srv = GNUNET_SERVICE_get_server (ctx); GNUNET_SERVER_add_handlers (srv, message_handlers); - GNUNET_SERVER_disconnect_notify (srv, &disconnect_cb, NULL); + GNUNET_SERVER_disconnect_notify (srv, &disconnect_cb, NULL); +} + + +/** + * Iterator over hash map entries. + * + * @param cls closure + * @param key current key code + * @param value value in the hash map + * @return #GNUNET_YES if we should continue to + * iterate, + * #GNUNET_NO if not. + */ +static int +barrier_destroy_iterator (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct Barrier *barrier = value; + + GNUNET_assert (NULL != barrier); + cancel_wrappers (barrier); + remove_barrier (barrier); + return GNUNET_YES; } @@ -481,9 +585,13 @@ GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg) * Function to stop the barrier service */ void -GST_barriers_stop () +GST_barriers_destroy () { GNUNET_assert (NULL != barrier_map); + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_iterate (barrier_map, + &barrier_destroy_iterator, + NULL)); GNUNET_CONTAINER_multihashmap_destroy (barrier_map); GNUNET_assert (NULL != ctx); GNUNET_SERVICE_stop (ctx); @@ -497,16 +605,17 @@ GST_barriers_stop () * * @param cls the closure given to GNUNET_TESTBED_barrier_init() * @param name the name of the barrier - * @param barrier the barrier handle + * @param b_ the barrier handle * @param status status of the barrier; GNUNET_OK if the barrier is crossed; * GNUNET_SYSERR upon error * @param emsg if the status were to be GNUNET_SYSERR, this parameter has the * error messsage */ -static void +static void wbarrier_status_cb (void *cls, const char *name, - struct GNUNET_TESTBED_Barrier *b_, - int status, const char *emsg) + struct GNUNET_TESTBED_Barrier *b_, + enum GNUNET_TESTBED_BarrierStatus status, + const char *emsg) { struct WBarrier *wrapper = cls; struct Barrier *barrier = wrapper->barrier; @@ -515,28 +624,66 @@ wbarrier_status_cb (void *cls, const char *name, wrapper->hbarrier = NULL; GNUNET_CONTAINER_DLL_remove (barrier->whead, barrier->wtail, wrapper); GNUNET_free (wrapper); - if (GNUNET_SYSERR == status) + switch (status) { + case GNUNET_TESTBED_BARRIERSTATUS_ERROR: LOG (GNUNET_ERROR_TYPE_ERROR, - "Initialising barrier (%s) failed at a sub-controller: %s\n", + "Initialising barrier `%s' failed at a sub-controller: %s\n", barrier->name, (NULL != emsg) ? emsg : "NULL"); - while (NULL != (wrapper = barrier->whead)) + cancel_wrappers (barrier); + if (NULL == emsg) + emsg = "Initialisation failed at a sub-controller"; + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR; + send_barrier_status_msg (barrier, emsg); + return; + case GNUNET_TESTBED_BARRIERSTATUS_CROSSED: + if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED != barrier->status) { - GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier); - GNUNET_CONTAINER_DLL_remove (barrier->whead, barrier->wtail, wrapper); - GNUNET_free (wrapper); + GNUNET_break_op (0); + return; } - /* Send parent controller failure message */ - GNUNET_break (0); - } - barrier->num_wbarriers_reached++; - if ((barrier->num_wbarriers_reached == barrier->num_wbarriers) - && (LOCAL_QUORUM_REACHED (barrier))) - { - /* Send parent controller success status message */ - GNUNET_break (0); + barrier->num_wbarriers_reached++; + if ((barrier->num_wbarriers_reached == barrier->num_wbarriers) + && (LOCAL_QUORUM_REACHED (barrier))) + { + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED; + send_barrier_status_msg (barrier, NULL); + } + return; + case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED: + if (0 != barrier->status) + { + GNUNET_break_op (0); + return; + } + barrier->num_wbarriers_inited++; + if (barrier->num_wbarriers_inited == barrier->num_wbarriers) + { + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED; + send_barrier_status_msg (barrier, NULL); + } + return; } - return; +} + + +/** + * Function called upon timeout while waiting for a response from the + * subcontrollers to barrier init message + * + * @param cls barrier + * @param tc scheduler task context + */ +static void +fwd_tout_barrier_init (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct Barrier *barrier = cls; + + cancel_wrappers (barrier); + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR; + send_barrier_status_msg (barrier, + "Timedout while propagating barrier initialisation\n"); + remove_barrier (barrier); } @@ -557,16 +704,15 @@ GST_handle_barrier_init (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct GNUNET_TESTBED_BarrierInit *msg; - const char *name; + char *name; struct Barrier *barrier; struct Slave *slave; struct WBarrier *wrapper; struct GNUNET_HashCode hash; size_t name_len; - uint64_t op_id; unsigned int cnt; uint16_t msize; - + if (NULL == GST_context) { GNUNET_break_op (0); @@ -587,22 +733,26 @@ GST_handle_barrier_init (void *cls, struct GNUNET_SERVER_Client *client, return; } msg = (const struct GNUNET_TESTBED_BarrierInit *) message; - op_id = GNUNET_ntohll (msg->op_id); - name = msg->name; name_len = (size_t) msize - sizeof (struct GNUNET_TESTBED_BarrierInit); + name = GNUNET_malloc (name_len + 1); + (void) memcpy (name, msg->name, name_len); GNUNET_CRYPTO_hash (name, name_len, &hash); + LOG_DEBUG ("Received BARRIER_INIT for barrier `%s'\n", name); if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (barrier_map, &hash)) { - GST_send_operation_fail_msg (client, op_id, "Barrier already initialised"); + + send_client_status_msg (client, name, GNUNET_TESTBED_BARRIERSTATUS_ERROR, + "A barrier with the same name already exists"); + GNUNET_free (name); GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } - barrier = GNUNET_malloc (sizeof (struct Barrier)); + barrier = GNUNET_new (struct Barrier); (void) memcpy (&barrier->hash, &hash, sizeof (struct GNUNET_HashCode)); barrier->quorum = msg->quorum; - barrier->name = GNUNET_malloc (name_len + 1); - barrier->name[name_len] = '\0'; - (void) memcpy (barrier->name, name, name_len); + barrier->name = name; + barrier->mc = client; + GNUNET_SERVER_client_keep (client); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (barrier_map, &barrier->hash, @@ -618,13 +768,169 @@ GST_handle_barrier_init (void *cls, struct GNUNET_SERVER_Client *client, { GNUNET_break (0);/* May happen when we are connecting to the controller */ continue; - } - wrapper = GNUNET_malloc (sizeof (struct WBarrier)); + } + wrapper = GNUNET_new (struct WBarrier); wrapper->barrier = barrier; - wrapper->hbarrier = GNUNET_TESTBED_barrier_init (slave->controller, - barrier->name, - barrier->quorum, - &wbarrier_status_cb, - wrapper); + GNUNET_CONTAINER_DLL_insert_tail (barrier->whead, barrier->wtail, wrapper); + wrapper->hbarrier = GNUNET_TESTBED_barrier_init_ (slave->controller, + barrier->name, + barrier->quorum, + &wbarrier_status_cb, + wrapper, + GNUNET_NO); + } + if (NULL == barrier->whead) /* No further propagation */ + { + barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED; + LOG_DEBUG ("Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n", + barrier->name); + send_barrier_status_msg (barrier, NULL); + }else + barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (30), + &fwd_tout_barrier_init, + barrier); +} + + +/** + * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. This + * message should always come from a parent controller or the testbed API if we + * are the root controller. + * + * This handler is queued in the main service and will handle the messages sent + * either from the testbed driver or from a high level controller + * + * @param cls NULL + * @param client identification of the client + * @param message the actual message + */ +void +GST_handle_barrier_cancel (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TESTBED_BarrierCancel *msg; + char *name; + struct Barrier *barrier; + struct GNUNET_HashCode hash; + size_t name_len; + uint16_t msize; + + if (NULL == GST_context) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (client != GST_context->client) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msize = ntohs (message->size); + if (msize <= sizeof (struct GNUNET_TESTBED_BarrierCancel)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct GNUNET_TESTBED_BarrierCancel *) message; + name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierCancel); + name = GNUNET_malloc (name_len + 1); + (void) memcpy (name, msg->name, name_len); + GNUNET_CRYPTO_hash (name, name_len, &hash); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (barrier_map, &hash)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &hash); + GNUNET_assert (NULL != barrier); + cancel_wrappers (barrier); + remove_barrier (barrier); + GNUNET_SERVER_receive_done (client, GNUNET_OK); +} + + +/** + * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. + * This handler is queued in the main service and will handle the messages sent + * either from the testbed driver or from a high level controller + * + * @param cls NULL + * @param client identification of the client + * @param message the actual message + */ +void +GST_handle_barrier_status (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + const struct GNUNET_TESTBED_BarrierStatusMsg *msg; + struct Barrier *barrier; + struct ClientCtx *client_ctx; + const char *name; + struct GNUNET_HashCode key; + enum GNUNET_TESTBED_BarrierStatus status; + uint16_t msize; + uint16_t name_len; + + if (NULL == GST_context) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (client != GST_context->client) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msize = ntohs (message->size); + if (msize <= sizeof (struct GNUNET_TESTBED_BarrierStatusMsg)) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (const struct GNUNET_TESTBED_BarrierStatusMsg *) message; + status = ntohs (msg->status); + if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status) + { + GNUNET_break_op (0); /* current we only expect BARRIER_CROSSED + status message this way */ + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + name = msg->data; + name_len = ntohs (msg->name_len); + if ((sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1) != msize) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if ('\0' != name[name_len]) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_CRYPTO_hash (name, name_len, &key); + barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key); + if (NULL == barrier) + { + GNUNET_break_op (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_receive_done (client, GNUNET_OK); + while (NULL != (client_ctx = barrier->head)) /* Notify peers */ + { + queue_message (client_ctx, GNUNET_copy_message (message)); + GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx); } } + +/* end of gnunet-service-testbed_barriers.c */