eliminate KX short cut
[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
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 3, or (at your
8   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   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18   Boston, MA 02110-1301, USA.
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 /**
92  * Wrapper around Barrier handle
93  */
94 struct 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  */
131 struct 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 /**
212  * Hashtable handle for storing initialised barriers
213  */
214 static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
215
216 /**
217  * Service context
218  */
219 static struct GNUNET_SERVICE_Handle *ctx;
220
221
222 /**
223  * Function to remove a barrier from the barrier map and cleanup resources
224  * occupied by a barrier
225  *
226  * @param barrier the barrier handle
227  */
228 static void
229 remove_barrier (struct Barrier *barrier)
230 {
231   struct ClientCtx *ctx;
232
233   GNUNET_assert (GNUNET_YES ==
234                  GNUNET_CONTAINER_multihashmap_remove (barrier_map,
235                                                        &barrier->hash,
236                                                        barrier));
237   while (NULL != (ctx = barrier->head))
238   {
239     GNUNET_CONTAINER_DLL_remove (barrier->head,
240                                  barrier->tail,
241                                  ctx);
242     ctx->barrier = NULL;
243   }
244   GNUNET_free (barrier->name);
245   GNUNET_free (barrier);
246 }
247
248
249 /**
250  * Cancels all subcontroller barrier handles
251  *
252  * @param barrier the local barrier
253  */
254 static void
255 cancel_wrappers (struct Barrier *barrier)
256 {
257   struct WBarrier *wrapper;
258
259   while (NULL != (wrapper = barrier->whead))
260   {
261     GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier);
262     GNUNET_CONTAINER_DLL_remove (barrier->whead,
263                                  barrier->wtail,
264                                  wrapper);
265     GNUNET_free (wrapper);
266   }
267 }
268
269
270 /**
271  * Send a status message about a barrier to the given client
272  *
273  * @param client the client to send the message to
274  * @param name the barrier name
275  * @param status the status of the barrier
276  * @param emsg the error message; should be non-NULL for
277  *   status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
278  */
279 static void
280 send_client_status_msg (struct GNUNET_SERVICE_Client *client,
281                         const char *name,
282                         enum GNUNET_TESTBED_BarrierStatus status,
283                         const char *emsg)
284 {
285   struct GNUNET_MQ_Envelope *env;
286   struct GNUNET_TESTBED_BarrierStatusMsg *msg;
287   size_t name_len;
288   size_t err_len;
289
290   GNUNET_assert ( (NULL == emsg) ||
291                   (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status) );
292   name_len = strlen (name) + 1;
293   err_len = ((NULL == emsg) ? 0 : (strlen (emsg) + 1));
294   env = GNUNET_MQ_msg_extra (msg,
295                              name_len + err_len,
296                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
297   msg->status = htons (status);
298   msg->name_len = htons ((uint16_t) name_len - 1);
299   GNUNET_memcpy (msg->data,
300                  name,
301                  name_len);
302   GNUNET_memcpy (msg->data + name_len,
303                  emsg,
304                  err_len);
305   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
306                   env);
307 }
308
309
310 /**
311  * Sends a barrier failed message
312  *
313  * @param barrier the corresponding barrier
314  * @param emsg the error message; should be non-NULL for
315  *   status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
316  */
317 static void
318 send_barrier_status_msg (struct Barrier *barrier,
319                          const char *emsg)
320 {
321   GNUNET_assert (0 != barrier->status);
322   send_client_status_msg (barrier->mc,
323                           barrier->name,
324                           barrier->status,
325                           emsg);
326 }
327
328
329 /**
330  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.
331  *
332  * @param cls identification of the client
333  * @param message the actual message
334  */
335 static int
336 check_barrier_wait (void *cls,
337                      const struct GNUNET_TESTBED_BarrierWait *msg)
338 {
339   return GNUNET_OK; /* always well-formed */
340 }
341
342
343 /**
344  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.  This
345  * message should come from peers or a shared helper service using the
346  * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
347  *
348  * This handler is queued in the main service and will handle the messages sent
349  * either from the testbed driver or from a high level controller
350  *
351  * @param cls identification of the client
352  * @param message the actual message
353  */
354 static void
355 handle_barrier_wait (void *cls,
356                      const struct GNUNET_TESTBED_BarrierWait *msg)
357 {
358   struct ClientCtx *client_ctx = cls;
359   struct Barrier *barrier;
360   char *name;
361   struct GNUNET_HashCode key;
362   size_t name_len;
363   uint16_t msize;
364
365   msize = ntohs (msg->header.size);
366   if (NULL == barrier_map)
367   {
368     GNUNET_break (0);
369     GNUNET_SERVICE_client_drop (client_ctx->client);
370     return;
371   }
372   name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierWait);
373   name = GNUNET_malloc (name_len + 1);
374   name[name_len] = '\0';
375   GNUNET_memcpy (name,
376                  msg->name,
377                  name_len);
378   LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n",
379              name);
380   GNUNET_CRYPTO_hash (name,
381                       name_len,
382                       &key);
383   GNUNET_free (name);
384   if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
385   {
386     GNUNET_break (0);
387     GNUNET_SERVICE_client_drop (client_ctx->client);
388     return;
389   }
390   if (NULL != client_ctx->barrier)
391   {
392     GNUNET_break (0);
393     GNUNET_SERVICE_client_drop (client_ctx->client);
394     return;
395   }
396   client_ctx->barrier = barrier;
397   GNUNET_CONTAINER_DLL_insert_tail (barrier->head,
398                                     barrier->tail,
399                                     client_ctx);
400   barrier->nreached++;
401   if ( (barrier->num_wbarriers_reached == barrier->num_wbarriers) &&
402        (LOCAL_QUORUM_REACHED (barrier)) )
403   {
404     barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
405     send_barrier_status_msg (barrier,
406                              NULL);
407   }
408   GNUNET_SERVICE_client_continue (client_ctx->client);
409 }
410
411
412 /**
413  * Function called when a client connects to the testbed-barrier service.
414  *
415  * @param cls NULL
416  * @param client the connecting client
417  * @param mq queue to talk to @a client
418  * @return our `struct ClientCtx`
419  */
420 static void *
421 connect_cb (void *cls,
422             struct GNUNET_SERVICE_Client *client,
423             struct GNUNET_MQ_Handle *mq)
424 {
425   struct ClientCtx *client_ctx;
426
427   LOG_DEBUG ("Client connected to testbed-barrier service\n");
428   client_ctx = GNUNET_new (struct ClientCtx);
429   client_ctx->client = client;
430   return client_ctx;
431 }
432
433
434 /**
435  * Functions with this signature are called whenever a client
436  * is disconnected on the network level.
437  *
438  * @param cls closure
439  * @param client identification of the client; NULL
440  *        for the last call when the server is destroyed
441  */
442 static void
443 disconnect_cb (void *cls,
444                struct GNUNET_SERVICE_Client *client,
445                void *app_ctx)
446 {
447   struct ClientCtx *client_ctx = app_ctx;
448   struct Barrier *barrier = client_ctx->barrier;
449
450   if (NULL != barrier)
451   {
452     GNUNET_CONTAINER_DLL_remove (barrier->head,
453                                  barrier->tail,
454                                  client_ctx);
455     client_ctx->barrier = NULL;
456   }
457   GNUNET_free (client_ctx);
458   LOG_DEBUG ("Client disconnected from testbed-barrier service\n");
459 }
460
461
462 /**
463  * Function to initialise barrriers component
464  *
465  * @param cfg the configuration to use for initialisation
466  */
467 void
468 GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
469 {
470   struct GNUNET_MQ_MessageHandler message_handlers[] = {
471     GNUNET_MQ_hd_var_size (barrier_wait,
472                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT,
473                            struct GNUNET_TESTBED_BarrierWait,
474                            NULL),
475     GNUNET_MQ_handler_end ()
476   };
477
478   LOG_DEBUG ("Launching testbed-barrier service\n");
479   barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
480                                                       GNUNET_YES);
481   ctx = GNUNET_SERVICE_start ("testbed-barrier",
482                               cfg,
483                               &connect_cb,
484                               &disconnect_cb,
485                               NULL,
486                               message_handlers);
487 }
488
489
490 /**
491  * Iterator over hash map entries.
492  *
493  * @param cls closure
494  * @param key current key code
495  * @param value value in the hash map
496  * @return #GNUNET_YES if we should continue to
497  *         iterate,
498  *         #GNUNET_NO if not.
499  */
500 static int
501 barrier_destroy_iterator (void *cls,
502                           const struct GNUNET_HashCode *key,
503                           void *value)
504 {
505   struct Barrier *barrier = value;
506
507   GNUNET_assert (NULL != barrier);
508   cancel_wrappers (barrier);
509   remove_barrier (barrier);
510   return GNUNET_YES;
511 }
512
513
514 /**
515  * Function to stop the barrier service
516  */
517 void
518 GST_barriers_destroy ()
519 {
520   GNUNET_assert (NULL != barrier_map);
521   GNUNET_assert (GNUNET_SYSERR !=
522                  GNUNET_CONTAINER_multihashmap_iterate (barrier_map,
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 messsage
543  */
544 static void
545 wbarrier_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   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   case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
583     if (0 != barrier->status)
584     {
585       GNUNET_break_op (0);
586       return;
587     }
588     barrier->num_wbarriers_inited++;
589     if (barrier->num_wbarriers_inited == barrier->num_wbarriers)
590     {
591       barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
592       send_barrier_status_msg (barrier, NULL);
593     }
594     return;
595   }
596 }
597
598
599 /**
600  * Function called upon timeout while waiting for a response from the
601  * subcontrollers to barrier init message
602  *
603  * @param cls barrier
604  */
605 static void
606 fwd_tout_barrier_init (void *cls)
607 {
608   struct Barrier *barrier = cls;
609
610   cancel_wrappers (barrier);
611   barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR;
612   send_barrier_status_msg (barrier,
613                            "Timedout while propagating barrier initialisation\n");
614   remove_barrier (barrier);
615 }
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  */
626 int
627 check_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  */
645 void
646 handle_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 ("Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n",
729                barrier->name);
730     send_barrier_status_msg (barrier, NULL);
731   }else
732     barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (30),
733                                                        &fwd_tout_barrier_init,
734                                                        barrier);
735 }
736
737
738 /**
739  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.
740  *
741  * @param cls identification of the client
742  * @param msg the actual message
743  * @return #GNUNET_OK if @a msg is well-formed
744  */
745 int
746 check_barrier_cancel (void *cls,
747                       const struct GNUNET_TESTBED_BarrierCancel *msg)
748 {
749   return GNUNET_OK; /* all are well-formed */
750 }
751
752
753 /**
754  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.  This
755  * message should always come from a parent controller or the testbed API if we
756  * are the root controller.
757  *
758  * This handler is queued in the main service and will handle the messages sent
759  * either from the testbed driver or from a high level controller
760  *
761  * @param cls identification of the client
762  * @param msg the actual message
763  */
764 void
765 handle_barrier_cancel (void *cls,
766                        const struct GNUNET_TESTBED_BarrierCancel *msg)
767 {
768   struct GNUNET_SERVICE_Client *client = cls;
769   char *name;
770   struct Barrier *barrier;
771   struct GNUNET_HashCode hash;
772   size_t name_len;
773   uint16_t msize;
774
775   if (NULL == GST_context)
776   {
777     GNUNET_break_op (0);
778     GNUNET_SERVICE_client_drop (client);
779     return;
780   }
781   if (client != GST_context->client)
782   {
783     GNUNET_break_op (0);
784     GNUNET_SERVICE_client_drop (client);
785     return;
786   }
787   msize = ntohs (msg->header.size);
788   name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierCancel);
789   name = GNUNET_malloc (name_len + 1);
790   GNUNET_memcpy (name,
791                  msg->name,
792                  name_len);
793   LOG_DEBUG ("Received BARRIER_CANCEL for barrier `%s'\n",
794              name);
795   GNUNET_CRYPTO_hash (name,
796                       name_len,
797                       &hash);
798   if (GNUNET_NO ==
799       GNUNET_CONTAINER_multihashmap_contains (barrier_map,
800                                               &hash))
801   {
802     GNUNET_break_op (0);
803     GNUNET_SERVICE_client_drop (client);
804     return;
805   }
806   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
807                                                &hash);
808   GNUNET_assert (NULL != barrier);
809   cancel_wrappers (barrier);
810   remove_barrier (barrier);
811   GNUNET_SERVICE_client_continue (client);
812 }
813
814
815 /**
816  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
817  *
818  * @param cls identification of the client
819  * @param msg the actual message
820  * @return #GNUNET_OK if @a msg is well-formed
821  */
822 int
823 check_barrier_status (void *cls,
824                       const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
825 {
826   uint16_t msize;
827   uint16_t name_len;
828   const char *name;
829   enum GNUNET_TESTBED_BarrierStatus status;
830
831   msize = ntohs (msg->header.size) - sizeof (*msg);
832   status = ntohs (msg->status);
833   if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status)
834   {
835     GNUNET_break_op (0);        /* current we only expect BARRIER_CROSSED
836                                    status message this way */
837     return GNUNET_SYSERR;
838   }
839   name = msg->data;
840   name_len = ntohs (msg->name_len);
841   if ((name_len + 1) != msize)
842   {
843     GNUNET_break_op (0);
844     return GNUNET_SYSERR;
845   }
846   if ('\0' != name[name_len])
847   {
848     GNUNET_break_op (0);
849     return GNUNET_SYSERR;
850   }
851   return GNUNET_OK;
852 }
853
854
855 /**
856  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
857  * This handler is queued in the main service and will handle the messages sent
858  * either from the testbed driver or from a high level controller
859  *
860  * @param cls identification of the client
861  * @param msg the actual message
862  */
863 void
864 handle_barrier_status (void *cls,
865                        const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
866 {
867   struct GNUNET_SERVICE_Client *client = cls;
868   struct Barrier *barrier;
869   struct ClientCtx *client_ctx;
870   struct WBarrier *wrapper;
871   const char *name;
872   struct GNUNET_HashCode key;
873   uint16_t name_len;
874   struct GNUNET_MQ_Envelope *env;
875
876   if (NULL == GST_context)
877   {
878     GNUNET_break_op (0);
879     GNUNET_SERVICE_client_drop (client);
880     return;
881   }
882   if (client != GST_context->client)
883   {
884     GNUNET_break_op (0);
885     GNUNET_SERVICE_client_drop (client);
886     return;
887   }
888   name = msg->data;
889   name_len = ntohs (msg->name_len);
890   LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n",
891              name);
892   GNUNET_CRYPTO_hash (name,
893                       name_len,
894                       &key);
895   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
896                                                &key);
897   if (NULL == barrier)
898   {
899     GNUNET_break_op (0);
900     GNUNET_SERVICE_client_drop (client);
901     return;
902   }
903   GNUNET_SERVICE_client_continue (client);
904   for(client_ctx = barrier->head; NULL != client_ctx; client_ctx = client_ctx->next) /* Notify peers */
905   {
906     env = GNUNET_MQ_msg_copy (&msg->header);
907     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client_ctx->client),
908                     env);
909   }
910   /**
911    * The wrapper barriers do not echo the barrier status, so we have to do it
912    * here
913    */
914   for (wrapper = barrier->whead; NULL != wrapper; wrapper = wrapper->next)
915   {
916     GNUNET_TESTBED_queue_message_ (wrapper->controller,
917                                    GNUNET_copy_message (&msg->header));
918   }
919 }
920
921 /* end of gnunet-service-testbed_barriers.c */