yapf format.
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_barriers.c
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  */
60 struct Barrier;
61
62
63 /**
64  * Context to be associated with each client
65  */
66 struct 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  */
93 struct 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  */
130 struct 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  */
212 static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
213
214 /**
215  * Service context
216  */
217 static 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  */
226 static void
227 remove_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  */
252 static void
253 cancel_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  */
277 static void
278 send_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  */
315 static void
316 send_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  */
333 static int
334 check_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  */
352 static void
353 handle_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  */
418 static void *
419 connect_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  */
440 static void
441 disconnect_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 barrriers component
462  *
463  * @param cfg the configuration to use for initialisation
464  */
465 void
466 GST_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  */
498 static int
499 barrier_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  */
515 void
516 GST_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 messsage
542  */
543 static void
544 wbarrier_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  */
606 static void
607 fwd_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 /**
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  */
627 int
628 check_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  */
646 void
647 handle_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  */
749 int
750 check_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  */
768 void
769 handle_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_SERVICE_client_drop (client);
808     return;
809   }
810   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
811                                                &hash);
812   GNUNET_assert (NULL != barrier);
813   cancel_wrappers (barrier);
814   remove_barrier (barrier);
815   GNUNET_SERVICE_client_continue (client);
816 }
817
818
819 /**
820  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
821  *
822  * @param cls identification of the client
823  * @param msg the actual message
824  * @return #GNUNET_OK if @a msg is well-formed
825  */
826 int
827 check_barrier_status (void *cls,
828                       const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
829 {
830   uint16_t msize;
831   uint16_t name_len;
832   const char *name;
833   enum GNUNET_TESTBED_BarrierStatus status;
834
835   msize = ntohs (msg->header.size) - sizeof(*msg);
836   status = ntohs (msg->status);
837   if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status)
838   {
839     GNUNET_break_op (0);        /* current we only expect BARRIER_CROSSED
840                                    status message this way */
841     return GNUNET_SYSERR;
842   }
843   name = msg->data;
844   name_len = ntohs (msg->name_len);
845   if ((name_len + 1) != msize)
846   {
847     GNUNET_break_op (0);
848     return GNUNET_SYSERR;
849   }
850   if ('\0' != name[name_len])
851   {
852     GNUNET_break_op (0);
853     return GNUNET_SYSERR;
854   }
855   return GNUNET_OK;
856 }
857
858
859 /**
860  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
861  * This handler is queued in the main service and will handle the messages sent
862  * either from the testbed driver or from a high level controller
863  *
864  * @param cls identification of the client
865  * @param msg the actual message
866  */
867 void
868 handle_barrier_status (void *cls,
869                        const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
870 {
871   struct GNUNET_SERVICE_Client *client = cls;
872   struct Barrier *barrier;
873   struct ClientCtx *client_ctx;
874   struct WBarrier *wrapper;
875   const char *name;
876   struct GNUNET_HashCode key;
877   uint16_t name_len;
878   struct GNUNET_MQ_Envelope *env;
879
880   if (NULL == GST_context)
881   {
882     GNUNET_break_op (0);
883     GNUNET_SERVICE_client_drop (client);
884     return;
885   }
886   if (client != GST_context->client)
887   {
888     GNUNET_break_op (0);
889     GNUNET_SERVICE_client_drop (client);
890     return;
891   }
892   name = msg->data;
893   name_len = ntohs (msg->name_len);
894   LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n",
895              name);
896   GNUNET_CRYPTO_hash (name,
897                       name_len,
898                       &key);
899   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
900                                                &key);
901   if (NULL == barrier)
902   {
903     GNUNET_break_op (0);
904     GNUNET_SERVICE_client_drop (client);
905     return;
906   }
907   GNUNET_SERVICE_client_continue (client);
908   for (client_ctx = barrier->head; NULL != client_ctx; client_ctx =
909          client_ctx->next)                                                            /* Notify peers */
910   {
911     env = GNUNET_MQ_msg_copy (&msg->header);
912     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client_ctx->client),
913                     env);
914   }
915   /**
916    * The wrapper barriers do not echo the barrier status, so we have to do it
917    * here
918    */
919   for (wrapper = barrier->whead; NULL != wrapper; wrapper = wrapper->next)
920   {
921     GNUNET_TESTBED_queue_message_ (wrapper->controller,
922                                    GNUNET_copy_message (&msg->header));
923   }
924 }
925
926 /* end of gnunet-service-testbed_barriers.c */