aboutsummaryrefslogtreecommitdiff
path: root/src/testbed/gnunet-service-testbed_barriers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed/gnunet-service-testbed_barriers.c')
-rw-r--r--src/testbed/gnunet-service-testbed_barriers.c926
1 files changed, 0 insertions, 926 deletions
diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c
deleted file mode 100644
index be33bd131..000000000
--- a/src/testbed/gnunet-service-testbed_barriers.c
+++ /dev/null
@@ -1,926 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_barriers.c
23 * @brief barrier handling at the testbed controller
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "gnunet-service-testbed.h"
28#include "gnunet-service-testbed_barriers.h"
29#include "testbed_api.h"
30
31
32/**
33 * timeout for outgoing message transmissions in seconds
34 */
35#define MESSAGE_SEND_TIMEOUT(s) \
36 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
37
38
39/**
40 * Test to see if local peers have reached the required quorum of a barrier
41 */
42#define LOCAL_QUORUM_REACHED(barrier) \
43 ((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100))
44
45
46#ifdef LOG
47#undef LOG
48#endif
49
50/**
51 * Logging shorthand
52 */
53#define LOG(kind, ...) \
54 GNUNET_log_from (kind, "testbed-barriers", __VA_ARGS__)
55
56
57/**
58 * Barrier
59 */
60struct Barrier;
61
62
63/**
64 * Context to be associated with each client
65 */
66struct ClientCtx
67{
68 /**
69 * The barrier this client is waiting for
70 */
71 struct Barrier *barrier;
72
73 /**
74 * DLL next ptr
75 */
76 struct ClientCtx *next;
77
78 /**
79 * DLL prev ptr
80 */
81 struct ClientCtx *prev;
82
83 /**
84 * The client handle
85 */
86 struct GNUNET_SERVICE_Client *client;
87};
88
89
90/**
91 * Wrapper around Barrier handle
92 */
93struct WBarrier
94{
95 /**
96 * DLL next pointer
97 */
98 struct WBarrier *next;
99
100 /**
101 * DLL prev pointer
102 */
103 struct WBarrier *prev;
104
105 /**
106 * The local barrier associated with the creation of this wrapper
107 */
108 struct Barrier *barrier;
109
110 /**
111 * Handle to the slave controller where this wrapper creates a barrier
112 */
113 struct GNUNET_TESTBED_Controller *controller;
114
115 /**
116 * The barrier handle from API
117 */
118 struct GNUNET_TESTBED_Barrier *hbarrier;
119
120 /**
121 * Has this barrier been crossed?
122 */
123 uint8_t reached;
124};
125
126
127/**
128 * Barrier
129 */
130struct Barrier
131{
132 /**
133 * The hashcode of the barrier name
134 */
135 struct GNUNET_HashCode hash;
136
137 /**
138 * The client handle to the master controller
139 */
140 struct GNUNET_SERVICE_Client *mc;
141
142 /**
143 * The name of the barrier
144 */
145 char *name;
146
147 /**
148 * DLL head for the list of clients waiting for this barrier
149 */
150 struct ClientCtx *head;
151
152 /**
153 * DLL tail for the list of clients waiting for this barrier
154 */
155 struct ClientCtx *tail;
156
157 /**
158 * DLL head for the list of barrier handles
159 */
160 struct WBarrier *whead;
161
162 /**
163 * DLL tail for the list of barrier handles
164 */
165 struct WBarrier *wtail;
166
167 /**
168 * Identifier for the timeout task
169 */
170 struct GNUNET_SCHEDULER_Task *tout_task;
171
172 /**
173 * The status of this barrier
174 */
175 enum GNUNET_TESTBED_BarrierStatus status;
176
177 /**
178 * Number of barriers wrapped in the above DLL
179 */
180 unsigned int num_wbarriers;
181
182 /**
183 * Number of wrapped barriers reached so far
184 */
185 unsigned int num_wbarriers_reached;
186
187 /**
188 * Number of wrapped barrier initialised so far
189 */
190 unsigned int num_wbarriers_inited;
191
192 /**
193 * Number of peers which have reached this barrier
194 */
195 unsigned int nreached;
196
197 /**
198 * Number of slaves we have initialised this barrier
199 */
200 unsigned int nslaves;
201
202 /**
203 * Quorum percentage to be reached
204 */
205 uint8_t quorum;
206};
207
208
209/**
210 * Hashtable handle for storing initialised barriers
211 */
212static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
213
214/**
215 * Service context
216 */
217static struct GNUNET_SERVICE_Handle *ctx;
218
219
220/**
221 * Function to remove a barrier from the barrier map and cleanup resources
222 * occupied by a barrier
223 *
224 * @param barrier the barrier handle
225 */
226static void
227remove_barrier (struct Barrier *barrier)
228{
229 struct ClientCtx *ctx;
230
231 GNUNET_assert (GNUNET_YES ==
232 GNUNET_CONTAINER_multihashmap_remove (barrier_map,
233 &barrier->hash,
234 barrier));
235 while (NULL != (ctx = barrier->head))
236 {
237 GNUNET_CONTAINER_DLL_remove (barrier->head,
238 barrier->tail,
239 ctx);
240 ctx->barrier = NULL;
241 }
242 GNUNET_free (barrier->name);
243 GNUNET_free (barrier);
244}
245
246
247/**
248 * Cancels all subcontroller barrier handles
249 *
250 * @param barrier the local barrier
251 */
252static void
253cancel_wrappers (struct Barrier *barrier)
254{
255 struct WBarrier *wrapper;
256
257 while (NULL != (wrapper = barrier->whead))
258 {
259 GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier);
260 GNUNET_CONTAINER_DLL_remove (barrier->whead,
261 barrier->wtail,
262 wrapper);
263 GNUNET_free (wrapper);
264 }
265}
266
267
268/**
269 * Send a status message about a barrier to the given client
270 *
271 * @param client the client to send the message to
272 * @param name the barrier name
273 * @param status the status of the barrier
274 * @param emsg the error message; should be non-NULL for
275 * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
276 */
277static void
278send_client_status_msg (struct GNUNET_SERVICE_Client *client,
279 const char *name,
280 enum GNUNET_TESTBED_BarrierStatus status,
281 const char *emsg)
282{
283 struct GNUNET_MQ_Envelope *env;
284 struct GNUNET_TESTBED_BarrierStatusMsg *msg;
285 size_t name_len;
286 size_t err_len;
287
288 GNUNET_assert ((NULL == emsg) ||
289 (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status));
290 name_len = strlen (name) + 1;
291 err_len = ((NULL == emsg) ? 0 : (strlen (emsg) + 1));
292 env = GNUNET_MQ_msg_extra (msg,
293 name_len + err_len,
294 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
295 msg->status = htons (status);
296 msg->name_len = htons ((uint16_t) name_len - 1);
297 GNUNET_memcpy (msg->data,
298 name,
299 name_len);
300 GNUNET_memcpy (msg->data + name_len,
301 emsg,
302 err_len);
303 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
304 env);
305}
306
307
308/**
309 * Sends a barrier failed message
310 *
311 * @param barrier the corresponding barrier
312 * @param emsg the error message; should be non-NULL for
313 * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
314 */
315static void
316send_barrier_status_msg (struct Barrier *barrier,
317 const char *emsg)
318{
319 GNUNET_assert (0 != barrier->status);
320 send_client_status_msg (barrier->mc,
321 barrier->name,
322 barrier->status,
323 emsg);
324}
325
326
327/**
328 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.
329 *
330 * @param cls identification of the client
331 * @param message the actual message
332 */
333static int
334check_barrier_wait (void *cls,
335 const struct GNUNET_TESTBED_BarrierWait *msg)
336{
337 return GNUNET_OK; /* always well-formed */
338}
339
340
341/**
342 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages. This
343 * message should come from peers or a shared helper service using the
344 * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
345 *
346 * This handler is queued in the main service and will handle the messages sent
347 * either from the testbed driver or from a high level controller
348 *
349 * @param cls identification of the client
350 * @param message the actual message
351 */
352static void
353handle_barrier_wait (void *cls,
354 const struct GNUNET_TESTBED_BarrierWait *msg)
355{
356 struct ClientCtx *client_ctx = cls;
357 struct Barrier *barrier;
358 char *name;
359 struct GNUNET_HashCode key;
360 size_t name_len;
361 uint16_t msize;
362
363 msize = ntohs (msg->header.size);
364 if (NULL == barrier_map)
365 {
366 GNUNET_break (0);
367 GNUNET_SERVICE_client_drop (client_ctx->client);
368 return;
369 }
370 name_len = msize - sizeof(struct GNUNET_TESTBED_BarrierWait);
371 name = GNUNET_malloc (name_len + 1);
372 name[name_len] = '\0';
373 GNUNET_memcpy (name,
374 msg->name,
375 name_len);
376 LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n",
377 name);
378 GNUNET_CRYPTO_hash (name,
379 name_len,
380 &key);
381 GNUNET_free (name);
382 if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
383 {
384 GNUNET_break (0);
385 GNUNET_SERVICE_client_drop (client_ctx->client);
386 return;
387 }
388 if (NULL != client_ctx->barrier)
389 {
390 GNUNET_break (0);
391 GNUNET_SERVICE_client_drop (client_ctx->client);
392 return;
393 }
394 client_ctx->barrier = barrier;
395 GNUNET_CONTAINER_DLL_insert_tail (barrier->head,
396 barrier->tail,
397 client_ctx);
398 barrier->nreached++;
399 if ((barrier->num_wbarriers_reached == barrier->num_wbarriers) &&
400 (LOCAL_QUORUM_REACHED (barrier)))
401 {
402 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
403 send_barrier_status_msg (barrier,
404 NULL);
405 }
406 GNUNET_SERVICE_client_continue (client_ctx->client);
407}
408
409
410/**
411 * Function called when a client connects to the testbed-barrier service.
412 *
413 * @param cls NULL
414 * @param client the connecting client
415 * @param mq queue to talk to @a client
416 * @return our `struct ClientCtx`
417 */
418static void *
419connect_cb (void *cls,
420 struct GNUNET_SERVICE_Client *client,
421 struct GNUNET_MQ_Handle *mq)
422{
423 struct ClientCtx *client_ctx;
424
425 LOG_DEBUG ("Client connected to testbed-barrier service\n");
426 client_ctx = GNUNET_new (struct ClientCtx);
427 client_ctx->client = client;
428 return client_ctx;
429}
430
431
432/**
433 * Functions with this signature are called whenever a client
434 * is disconnected on the network level.
435 *
436 * @param cls closure
437 * @param client identification of the client; NULL
438 * for the last call when the server is destroyed
439 */
440static void
441disconnect_cb (void *cls,
442 struct GNUNET_SERVICE_Client *client,
443 void *app_ctx)
444{
445 struct ClientCtx *client_ctx = app_ctx;
446 struct Barrier *barrier = client_ctx->barrier;
447
448 if (NULL != barrier)
449 {
450 GNUNET_CONTAINER_DLL_remove (barrier->head,
451 barrier->tail,
452 client_ctx);
453 client_ctx->barrier = NULL;
454 }
455 GNUNET_free (client_ctx);
456 LOG_DEBUG ("Client disconnected from testbed-barrier service\n");
457}
458
459
460/**
461 * Function to initialise barriers component
462 *
463 * @param cfg the configuration to use for initialisation
464 */
465void
466GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
467{
468 struct GNUNET_MQ_MessageHandler message_handlers[] = {
469 GNUNET_MQ_hd_var_size (barrier_wait,
470 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT,
471 struct GNUNET_TESTBED_BarrierWait,
472 NULL),
473 GNUNET_MQ_handler_end ()
474 };
475
476 LOG_DEBUG ("Launching testbed-barrier service\n");
477 barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
478 GNUNET_YES);
479 ctx = GNUNET_SERVICE_start ("testbed-barrier",
480 cfg,
481 &connect_cb,
482 &disconnect_cb,
483 NULL,
484 message_handlers);
485}
486
487
488/**
489 * Iterator over hash map entries.
490 *
491 * @param cls closure
492 * @param key current key code
493 * @param value value in the hash map
494 * @return #GNUNET_YES if we should continue to
495 * iterate,
496 * #GNUNET_NO if not.
497 */
498static int
499barrier_destroy_iterator (void *cls,
500 const struct GNUNET_HashCode *key,
501 void *value)
502{
503 struct Barrier *barrier = value;
504
505 GNUNET_assert (NULL != barrier);
506 cancel_wrappers (barrier);
507 remove_barrier (barrier);
508 return GNUNET_YES;
509}
510
511
512/**
513 * Function to stop the barrier service
514 */
515void
516GST_barriers_destroy ()
517{
518 GNUNET_assert (NULL != barrier_map);
519 GNUNET_assert (GNUNET_SYSERR !=
520 GNUNET_CONTAINER_multihashmap_iterate (barrier_map,
521 &
522 barrier_destroy_iterator,
523 NULL));
524 GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
525 GNUNET_assert (NULL != ctx);
526 GNUNET_SERVICE_stop (ctx);
527}
528
529
530/**
531 * Functions of this type are to be given as callback argument to
532 * GNUNET_TESTBED_barrier_init(). The callback will be called when status
533 * information is available for the barrier.
534 *
535 * @param cls the closure given to GNUNET_TESTBED_barrier_init()
536 * @param name the name of the barrier
537 * @param b_ the barrier handle
538 * @param status status of the barrier; #GNUNET_OK if the barrier is crossed;
539 * #GNUNET_SYSERR upon error
540 * @param emsg if the status were to be #GNUNET_SYSERR, this parameter has the
541 * error message
542 */
543static void
544wbarrier_status_cb (void *cls,
545 const char *name,
546 struct GNUNET_TESTBED_Barrier *b_,
547 enum GNUNET_TESTBED_BarrierStatus status,
548 const char *emsg)
549{
550 struct WBarrier *wrapper = cls;
551 struct Barrier *barrier = wrapper->barrier;
552
553 GNUNET_assert (b_ == wrapper->hbarrier);
554 switch (status)
555 {
556 case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
557 LOG (GNUNET_ERROR_TYPE_ERROR,
558 "Initialising barrier `%s' failed at a sub-controller: %s\n",
559 barrier->name,
560 (NULL != emsg) ? emsg : "NULL");
561 cancel_wrappers (barrier);
562 if (NULL == emsg)
563 emsg = "Initialisation failed at a sub-controller";
564 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR;
565 send_barrier_status_msg (barrier, emsg);
566 return;
567
568 case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
569 if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED != barrier->status)
570 {
571 GNUNET_break_op (0);
572 return;
573 }
574 barrier->num_wbarriers_reached++;
575 if ((barrier->num_wbarriers_reached == barrier->num_wbarriers)
576 && (LOCAL_QUORUM_REACHED (barrier)))
577 {
578 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
579 send_barrier_status_msg (barrier, NULL);
580 }
581 return;
582
583 case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
584 if (0 != barrier->status)
585 {
586 GNUNET_break_op (0);
587 return;
588 }
589 barrier->num_wbarriers_inited++;
590 if (barrier->num_wbarriers_inited == barrier->num_wbarriers)
591 {
592 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
593 send_barrier_status_msg (barrier, NULL);
594 }
595 return;
596 }
597}
598
599
600/**
601 * Function called upon timeout while waiting for a response from the
602 * subcontrollers to barrier init message
603 *
604 * @param cls barrier
605 */
606static void
607fwd_tout_barrier_init (void *cls)
608{
609 struct Barrier *barrier = cls;
610
611 cancel_wrappers (barrier);
612 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR;
613 send_barrier_status_msg (barrier,
614 "Timedout while propagating barrier initialisation\n");
615 remove_barrier (barrier);
616}
617
618
619/**
620 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages.
621 *
622 * @param cls identification of the client
623 * @param msg the actual message
624 * @return #GNUNET_OK if @a msg is well-formed
625 */
626int
627check_barrier_init (void *cls,
628 const struct GNUNET_TESTBED_BarrierInit *msg)
629{
630 return GNUNET_OK; /* always well-formed */
631}
632
633
634/**
635 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages. This
636 * message should always come from a parent controller or the testbed API if we
637 * are the root controller.
638 *
639 * This handler is queued in the main service and will handle the messages sent
640 * either from the testbed driver or from a high level controller
641 *
642 * @param cls identification of the client
643 * @param msg the actual message
644 */
645void
646handle_barrier_init (void *cls,
647 const struct GNUNET_TESTBED_BarrierInit *msg)
648{
649 struct GNUNET_SERVICE_Client *client = cls;
650 char *name;
651 struct Barrier *barrier;
652 struct Slave *slave;
653 struct WBarrier *wrapper;
654 struct GNUNET_HashCode hash;
655 size_t name_len;
656 unsigned int cnt;
657 uint16_t msize;
658
659 if (NULL == GST_context)
660 {
661 GNUNET_break_op (0);
662 GNUNET_SERVICE_client_drop (client);
663 return;
664 }
665 if (client != GST_context->client)
666 {
667 GNUNET_break_op (0);
668 GNUNET_SERVICE_client_drop (client);
669 return;
670 }
671 msize = ntohs (msg->header.size);
672 name_len = (size_t) msize - sizeof(struct GNUNET_TESTBED_BarrierInit);
673 name = GNUNET_malloc (name_len + 1);
674 GNUNET_memcpy (name, msg->name, name_len);
675 GNUNET_CRYPTO_hash (name, name_len, &hash);
676 LOG_DEBUG ("Received BARRIER_INIT for barrier `%s'\n",
677 name);
678 if (GNUNET_YES ==
679 GNUNET_CONTAINER_multihashmap_contains (barrier_map,
680 &hash))
681 {
682 send_client_status_msg (client,
683 name,
684 GNUNET_TESTBED_BARRIERSTATUS_ERROR,
685 "A barrier with the same name already exists");
686 GNUNET_free (name);
687 GNUNET_SERVICE_client_continue (client);
688 return;
689 }
690 barrier = GNUNET_new (struct Barrier);
691 barrier->hash = hash;
692 barrier->quorum = msg->quorum;
693 barrier->name = name;
694 barrier->mc = client;
695 GNUNET_assert (GNUNET_OK ==
696 GNUNET_CONTAINER_multihashmap_put (barrier_map,
697 &barrier->hash,
698 barrier,
699 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
700 GNUNET_SERVICE_client_continue (client);
701 /* Propagate barrier init to subcontrollers */
702 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
703 {
704 if (NULL == (slave = GST_slave_list[cnt]))
705 continue;
706 if (NULL == slave->controller)
707 {
708 GNUNET_break (0); /* May happen when we are connecting to the controller */
709 continue;
710 }
711 wrapper = GNUNET_new (struct WBarrier);
712 wrapper->barrier = barrier;
713 wrapper->controller = slave->controller;
714 GNUNET_CONTAINER_DLL_insert_tail (barrier->whead,
715 barrier->wtail,
716 wrapper);
717 barrier->num_wbarriers++;
718 wrapper->hbarrier = GNUNET_TESTBED_barrier_init_ (wrapper->controller,
719 barrier->name,
720 barrier->quorum,
721 &wbarrier_status_cb,
722 wrapper,
723 GNUNET_NO);
724 }
725 if (NULL == barrier->whead) /* No further propagation */
726 {
727 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
728 LOG_DEBUG (
729 "Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n",
730 barrier->name);
731 send_barrier_status_msg (barrier, NULL);
732 }
733 else
734 barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (
735 30),
736 &fwd_tout_barrier_init,
737 barrier);
738}
739
740
741/**
742 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.
743 *
744 * @param cls identification of the client
745 * @param msg the actual message
746 * @return #GNUNET_OK if @a msg is well-formed
747 */
748int
749check_barrier_cancel (void *cls,
750 const struct GNUNET_TESTBED_BarrierCancel *msg)
751{
752 return GNUNET_OK; /* all are well-formed */
753}
754
755
756/**
757 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. This
758 * message should always come from a parent controller or the testbed API if we
759 * are the root controller.
760 *
761 * This handler is queued in the main service and will handle the messages sent
762 * either from the testbed driver or from a high level controller
763 *
764 * @param cls identification of the client
765 * @param msg the actual message
766 */
767void
768handle_barrier_cancel (void *cls,
769 const struct GNUNET_TESTBED_BarrierCancel *msg)
770{
771 struct GNUNET_SERVICE_Client *client = cls;
772 char *name;
773 struct Barrier *barrier;
774 struct GNUNET_HashCode hash;
775 size_t name_len;
776 uint16_t msize;
777
778 if (NULL == GST_context)
779 {
780 GNUNET_break_op (0);
781 GNUNET_SERVICE_client_drop (client);
782 return;
783 }
784 if (client != GST_context->client)
785 {
786 GNUNET_break_op (0);
787 GNUNET_SERVICE_client_drop (client);
788 return;
789 }
790 msize = ntohs (msg->header.size);
791 name_len = msize - sizeof(struct GNUNET_TESTBED_BarrierCancel);
792 name = GNUNET_malloc (name_len + 1);
793 GNUNET_memcpy (name,
794 msg->name,
795 name_len);
796 LOG_DEBUG ("Received BARRIER_CANCEL for barrier `%s'\n",
797 name);
798 GNUNET_CRYPTO_hash (name,
799 name_len,
800 &hash);
801 if (GNUNET_NO ==
802 GNUNET_CONTAINER_multihashmap_contains (barrier_map,
803 &hash))
804 {
805 GNUNET_break_op (0);
806 GNUNET_SERVICE_client_drop (client);
807 return;
808 }
809 barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
810 &hash);
811 GNUNET_assert (NULL != barrier);
812 cancel_wrappers (barrier);
813 remove_barrier (barrier);
814 GNUNET_SERVICE_client_continue (client);
815}
816
817
818/**
819 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
820 *
821 * @param cls identification of the client
822 * @param msg the actual message
823 * @return #GNUNET_OK if @a msg is well-formed
824 */
825int
826check_barrier_status (void *cls,
827 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
828{
829 uint16_t msize;
830 uint16_t name_len;
831 const char *name;
832 enum GNUNET_TESTBED_BarrierStatus status;
833
834 msize = ntohs (msg->header.size) - sizeof(*msg);
835 status = ntohs (msg->status);
836 if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status)
837 {
838 GNUNET_break_op (0); /* current we only expect BARRIER_CROSSED
839 status message this way */
840 return GNUNET_SYSERR;
841 }
842 name = msg->data;
843 name_len = ntohs (msg->name_len);
844 if ((name_len + 1) != msize)
845 {
846 GNUNET_break_op (0);
847 return GNUNET_SYSERR;
848 }
849 if ('\0' != name[name_len])
850 {
851 GNUNET_break_op (0);
852 return GNUNET_SYSERR;
853 }
854 return GNUNET_OK;
855}
856
857
858/**
859 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
860 * This handler is queued in the main service and will handle the messages sent
861 * either from the testbed driver or from a high level controller
862 *
863 * @param cls identification of the client
864 * @param msg the actual message
865 */
866void
867handle_barrier_status (void *cls,
868 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
869{
870 struct GNUNET_SERVICE_Client *client = cls;
871 struct Barrier *barrier;
872 struct ClientCtx *client_ctx;
873 struct WBarrier *wrapper;
874 const char *name;
875 struct GNUNET_HashCode key;
876 uint16_t name_len;
877 struct GNUNET_MQ_Envelope *env;
878
879 if (NULL == GST_context)
880 {
881 GNUNET_break_op (0);
882 GNUNET_SERVICE_client_drop (client);
883 return;
884 }
885 if (client != GST_context->client)
886 {
887 GNUNET_break_op (0);
888 GNUNET_SERVICE_client_drop (client);
889 return;
890 }
891 name = msg->data;
892 name_len = ntohs (msg->name_len);
893 LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n",
894 name);
895 GNUNET_CRYPTO_hash (name,
896 name_len,
897 &key);
898 barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
899 &key);
900 if (NULL == barrier)
901 {
902 GNUNET_break_op (0);
903 GNUNET_SERVICE_client_drop (client);
904 return;
905 }
906 GNUNET_SERVICE_client_continue (client);
907 for (client_ctx = barrier->head; NULL != client_ctx; client_ctx =
908 client_ctx->next) /* Notify peers */
909 {
910 env = GNUNET_MQ_msg_copy (&msg->header);
911 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client_ctx->client),
912 env);
913 }
914 /**
915 * The wrapper barriers do not echo the barrier status, so we have to do it
916 * here
917 */
918 for (wrapper = barrier->whead; NULL != wrapper; wrapper = wrapper->next)
919 {
920 GNUNET_TESTBED_queue_message_ (wrapper->controller,
921 GNUNET_copy_message (&msg->header));
922 }
923}
924
925
926/* end of gnunet-service-testbed_barriers.c */