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