- minor changes, TODO, debug message
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_barriers.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2008--2013 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    * The barrier handle from API
113    */
114   struct GNUNET_TESTBED_Barrier *hbarrier;
115
116   /**
117    * Has this barrier been crossed?
118    */
119   uint8_t reached;
120 };
121
122
123 /**
124  * Barrier
125  */
126 struct Barrier
127 {
128   /**
129    * The hashcode of the barrier name
130    */
131   struct GNUNET_HashCode hash;
132
133   /**
134    * The client handle to the master controller
135    */
136   struct GNUNET_SERVICE_Client *mc;
137
138   /**
139    * The name of the barrier
140    */
141   char *name;
142
143   /**
144    * DLL head for the list of clients waiting for this barrier
145    */
146   struct ClientCtx *head;
147
148   /**
149    * DLL tail for the list of clients waiting for this barrier
150    */
151   struct ClientCtx *tail;
152
153   /**
154    * DLL head for the list of barrier handles
155    */
156   struct WBarrier *whead;
157
158   /**
159    * DLL tail for the list of barrier handles
160    */
161   struct WBarrier *wtail;
162
163   /**
164    * Identifier for the timeout task
165    */
166   struct GNUNET_SCHEDULER_Task *tout_task;
167
168   /**
169    * The status of this barrier
170    */
171   enum GNUNET_TESTBED_BarrierStatus status;
172
173   /**
174    * Number of barriers wrapped in the above DLL
175    */
176   unsigned int num_wbarriers;
177
178   /**
179    * Number of wrapped barriers reached so far
180    */
181   unsigned int num_wbarriers_reached;
182
183   /**
184    * Number of wrapped barrier initialised so far
185    */
186   unsigned int num_wbarriers_inited;
187
188   /**
189    * Number of peers which have reached this barrier
190    */
191   unsigned int nreached;
192
193   /**
194    * Number of slaves we have initialised this barrier
195    */
196   unsigned int nslaves;
197
198   /**
199    * Quorum percentage to be reached
200    */
201   uint8_t quorum;
202
203 };
204
205
206 /**
207  * Hashtable handle for storing initialised barriers
208  */
209 static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
210
211 /**
212  * Service context
213  */
214 static struct GNUNET_SERVICE_Handle *ctx;
215
216
217 /**
218  * Function to remove a barrier from the barrier map and cleanup resources
219  * occupied by a barrier
220  *
221  * @param barrier the barrier handle
222  */
223 static void
224 remove_barrier (struct Barrier *barrier)
225 {
226   struct ClientCtx *ctx;
227
228   GNUNET_assert (GNUNET_YES ==
229                  GNUNET_CONTAINER_multihashmap_remove (barrier_map,
230                                                        &barrier->hash,
231                                                        barrier));
232   while (NULL != (ctx = barrier->head))
233   {
234     GNUNET_CONTAINER_DLL_remove (barrier->head,
235                                  barrier->tail,
236                                  ctx);
237     GNUNET_free (ctx);
238   }
239   GNUNET_free (barrier->name);
240   GNUNET_free (barrier);
241 }
242
243
244 /**
245  * Cancels all subcontroller barrier handles
246  *
247  * @param barrier the local barrier
248  */
249 static void
250 cancel_wrappers (struct Barrier *barrier)
251 {
252   struct WBarrier *wrapper;
253
254   while (NULL != (wrapper = barrier->whead))
255   {
256     GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier);
257     GNUNET_CONTAINER_DLL_remove (barrier->whead,
258                                  barrier->wtail,
259                                  wrapper);
260     GNUNET_free (wrapper);
261   }
262 }
263
264
265 /**
266  * Send a status message about a barrier to the given client
267  *
268  * @param client the client to send the message to
269  * @param name the barrier name
270  * @param status the status of the barrier
271  * @param emsg the error message; should be non-NULL for
272  *   status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
273  */
274 static void
275 send_client_status_msg (struct GNUNET_SERVICE_Client *client,
276                         const char *name,
277                         enum GNUNET_TESTBED_BarrierStatus status,
278                         const char *emsg)
279 {
280   struct GNUNET_MQ_Envelope *env;
281   struct GNUNET_TESTBED_BarrierStatusMsg *msg;
282   size_t name_len;
283   size_t err_len;
284
285   GNUNET_assert ( (NULL == emsg) ||
286                   (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status) );
287   name_len = strlen (name) + 1;
288   err_len = ((NULL == emsg) ? 0 : (strlen (emsg) + 1));
289   env = GNUNET_MQ_msg_extra (msg,
290                              name_len + err_len,
291                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
292   msg->status = htons (status);
293   msg->name_len = htons ((uint16_t) name_len - 1);
294   GNUNET_memcpy (msg->data,
295                  name,
296                  name_len);
297   GNUNET_memcpy (msg->data + name_len,
298                  emsg,
299                  err_len);
300   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
301                   env);
302 }
303
304
305 /**
306  * Sends a barrier failed message
307  *
308  * @param barrier the corresponding barrier
309  * @param emsg the error message; should be non-NULL for
310  *   status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
311  */
312 static void
313 send_barrier_status_msg (struct Barrier *barrier,
314                          const char *emsg)
315 {
316   GNUNET_assert (0 != barrier->status);
317   send_client_status_msg (barrier->mc,
318                           barrier->name,
319                           barrier->status,
320                           emsg);
321 }
322
323
324 /**
325  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.
326  *
327  * @param cls identification of the client
328  * @param message the actual message
329  */
330 static int
331 check_barrier_wait (void *cls,
332                      const struct GNUNET_TESTBED_BarrierWait *msg)
333 {
334   return GNUNET_OK; /* always well-formed */
335 }
336
337
338 /**
339  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.  This
340  * message should come from peers or a shared helper service using the
341  * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
342  *
343  * This handler is queued in the main service and will handle the messages sent
344  * either from the testbed driver or from a high level controller
345  *
346  * @param cls identification of the client
347  * @param message the actual message
348  */
349 static void
350 handle_barrier_wait (void *cls,
351                      const struct GNUNET_TESTBED_BarrierWait *msg)
352 {
353   struct ClientCtx *client_ctx = cls;
354   struct Barrier *barrier;
355   char *name;
356   struct GNUNET_HashCode key;
357   size_t name_len;
358   uint16_t msize;
359
360   msize = ntohs (msg->header.size);
361   if (NULL == barrier_map)
362   {
363     GNUNET_break (0);
364     GNUNET_SERVICE_client_drop (client_ctx->client);
365     return;
366   }
367   name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierWait);
368   name = GNUNET_malloc (name_len + 1);
369   name[name_len] = '\0';
370   GNUNET_memcpy (name,
371                  msg->name,
372                  name_len);
373   LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n",
374              name);
375   GNUNET_CRYPTO_hash (name,
376                       name_len,
377                       &key);
378   GNUNET_free (name);
379   if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
380   {
381     GNUNET_break (0);
382     GNUNET_SERVICE_client_drop (client_ctx->client);
383     return;
384   }
385   if (NULL != client_ctx->barrier)
386   {
387     GNUNET_break (0);
388     GNUNET_SERVICE_client_drop (client_ctx->client);
389     return;
390   }
391   client_ctx->barrier = barrier;
392   GNUNET_CONTAINER_DLL_insert_tail (barrier->head,
393                                     barrier->tail,
394                                     client_ctx);
395   barrier->nreached++;
396   if ( (barrier->num_wbarriers_reached == barrier->num_wbarriers) &&
397        (LOCAL_QUORUM_REACHED (barrier)) )
398   {
399     barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
400     send_barrier_status_msg (barrier,
401                              NULL);
402   }
403   GNUNET_SERVICE_client_continue (client_ctx->client);
404 }
405
406
407 /**
408  * Function called when a client connects to the testbed-barrier service.
409  *
410  * @param cls NULL
411  * @param client the connecting client
412  * @param mq queue to talk to @a client
413  * @return our `struct ClientCtx`
414  */
415 static void *
416 connect_cb (void *cls,
417             struct GNUNET_SERVICE_Client *client,
418             struct GNUNET_MQ_Handle *mq)
419 {
420   struct ClientCtx *client_ctx;
421
422   LOG_DEBUG ("Client connected to testbed-barrier service\n");
423   client_ctx = GNUNET_new (struct ClientCtx);
424   client_ctx->client = client;
425   return client_ctx;
426 }
427
428
429 /**
430  * Functions with this signature are called whenever a client
431  * is disconnected on the network level.
432  *
433  * @param cls closure
434  * @param client identification of the client; NULL
435  *        for the last call when the server is destroyed
436  */
437 static void
438 disconnect_cb (void *cls,
439                struct GNUNET_SERVICE_Client *client,
440                void *app_ctx)
441 {
442   struct ClientCtx *client_ctx = app_ctx;
443   struct Barrier *barrier = client_ctx->barrier;
444
445   if (NULL != barrier)
446   {
447     GNUNET_CONTAINER_DLL_remove (barrier->head,
448                                  barrier->tail,
449                                  client_ctx);
450     client_ctx->barrier = NULL;
451   }
452   GNUNET_free (client_ctx);
453   LOG_DEBUG ("Client disconnected from testbed-barrier service\n");
454 }
455
456
457 /**
458  * Function to initialise barrriers component
459  *
460  * @param cfg the configuration to use for initialisation
461  */
462 void
463 GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
464 {
465   struct GNUNET_MQ_MessageHandler message_handlers[] = {
466     GNUNET_MQ_hd_var_size (barrier_wait,
467                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT,
468                            struct GNUNET_TESTBED_BarrierWait,
469                            NULL),
470     GNUNET_MQ_handler_end ()
471   };
472
473   LOG_DEBUG ("Launching testbed-barrier service\n");
474   barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
475                                                       GNUNET_YES);
476   ctx = GNUNET_SERVICE_starT ("testbed-barrier",
477                               cfg,
478                               &connect_cb,
479                               &disconnect_cb,
480                               NULL,
481                               message_handlers);
482 }
483
484
485 /**
486  * Iterator over hash map entries.
487  *
488  * @param cls closure
489  * @param key current key code
490  * @param value value in the hash map
491  * @return #GNUNET_YES if we should continue to
492  *         iterate,
493  *         #GNUNET_NO if not.
494  */
495 static int
496 barrier_destroy_iterator (void *cls,
497                           const struct GNUNET_HashCode *key,
498                           void *value)
499 {
500   struct Barrier *barrier = value;
501
502   GNUNET_assert (NULL != barrier);
503   cancel_wrappers (barrier);
504   remove_barrier (barrier);
505   return GNUNET_YES;
506 }
507
508
509 /**
510  * Function to stop the barrier service
511  */
512 void
513 GST_barriers_destroy ()
514 {
515   GNUNET_assert (NULL != barrier_map);
516   GNUNET_assert (GNUNET_SYSERR !=
517                  GNUNET_CONTAINER_multihashmap_iterate (barrier_map,
518                                                         &barrier_destroy_iterator,
519                                                         NULL));
520   GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
521   GNUNET_assert (NULL != ctx);
522   GNUNET_SERVICE_stoP (ctx);
523 }
524
525
526 /**
527  * Functions of this type are to be given as callback argument to
528  * GNUNET_TESTBED_barrier_init().  The callback will be called when status
529  * information is available for the barrier.
530  *
531  * @param cls the closure given to GNUNET_TESTBED_barrier_init()
532  * @param name the name of the barrier
533  * @param b_ the barrier handle
534  * @param status status of the barrier; #GNUNET_OK if the barrier is crossed;
535  *   #GNUNET_SYSERR upon error
536  * @param emsg if the status were to be #GNUNET_SYSERR, this parameter has the
537  *   error messsage
538  */
539 static void
540 wbarrier_status_cb (void *cls,
541                     const char *name,
542                     struct GNUNET_TESTBED_Barrier *b_,
543                     enum GNUNET_TESTBED_BarrierStatus status,
544                     const char *emsg)
545 {
546   struct WBarrier *wrapper = cls;
547   struct Barrier *barrier = wrapper->barrier;
548
549   GNUNET_assert (b_ == wrapper->hbarrier);
550   wrapper->hbarrier = NULL;
551   GNUNET_CONTAINER_DLL_remove (barrier->whead,
552                                barrier->wtail,
553                                wrapper);
554   GNUNET_free (wrapper);
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     GNUNET_CONTAINER_DLL_insert_tail (barrier->whead,
714                                       barrier->wtail,
715                                       wrapper);
716     wrapper->hbarrier = GNUNET_TESTBED_barrier_init_ (slave->controller,
717                                                       barrier->name,
718                                                       barrier->quorum,
719                                                       &wbarrier_status_cb,
720                                                       wrapper,
721                                                       GNUNET_NO);
722   }
723   if (NULL == barrier->whead)   /* No further propagation */
724   {
725     barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
726     LOG_DEBUG ("Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n",
727                barrier->name);
728     send_barrier_status_msg (barrier, NULL);
729   }else
730     barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (30),
731                                                        &fwd_tout_barrier_init,
732                                                        barrier);
733 }
734
735
736 /**
737  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.
738  *
739  * @param cls identification of the client
740  * @param msg the actual message
741  * @return #GNUNET_OK if @a msg is well-formed
742  */
743 int
744 check_barrier_cancel (void *cls,
745                       const struct GNUNET_TESTBED_BarrierCancel *msg)
746 {
747   return GNUNET_OK; /* all are well-formed */
748 }
749
750
751 /**
752  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.  This
753  * message should always come from a parent controller or the testbed API if we
754  * are the root controller.
755  *
756  * This handler is queued in the main service and will handle the messages sent
757  * either from the testbed driver or from a high level controller
758  *
759  * @param cls identification of the client
760  * @param msg the actual message
761  */
762 void
763 handle_barrier_cancel (void *cls,
764                        const struct GNUNET_TESTBED_BarrierCancel *msg)
765 {
766   struct GNUNET_SERVICE_Client *client = cls;
767   char *name;
768   struct Barrier *barrier;
769   struct GNUNET_HashCode hash;
770   size_t name_len;
771   uint16_t msize;
772
773   if (NULL == GST_context)
774   {
775     GNUNET_break_op (0);
776     GNUNET_SERVICE_client_drop (client);
777     return;
778   }
779   if (client != GST_context->client)
780   {
781     GNUNET_break_op (0);
782     GNUNET_SERVICE_client_drop (client);
783     return;
784   }
785   msize = ntohs (msg->header.size);
786   name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierCancel);
787   name = GNUNET_malloc (name_len + 1);
788   GNUNET_memcpy (name,
789                  msg->name,
790                  name_len);
791   LOG_DEBUG ("Received BARRIER_CANCEL for barrier `%s'\n",
792              name);
793   GNUNET_CRYPTO_hash (name,
794                       name_len,
795                       &hash);
796   if (GNUNET_NO ==
797       GNUNET_CONTAINER_multihashmap_contains (barrier_map,
798                                               &hash))
799   {
800     GNUNET_break_op (0);
801     GNUNET_SERVICE_client_drop (client);
802     return;
803   }
804   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
805                                                &hash);
806   GNUNET_assert (NULL != barrier);
807   cancel_wrappers (barrier);
808   remove_barrier (barrier);
809   GNUNET_SERVICE_client_continue (client);
810 }
811
812
813 /**
814  * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
815  *
816  * @param cls identification of the client
817  * @param msg the actual message
818  * @return #GNUNET_OK if @a msg is well-formed
819  */
820 int
821 check_barrier_status (void *cls,
822                       const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
823 {
824   uint16_t msize;
825   uint16_t name_len;
826   const char *name;
827   enum GNUNET_TESTBED_BarrierStatus status;
828
829   msize = ntohs (msg->header.size) - sizeof (*msg);
830   status = ntohs (msg->status);
831   if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status)
832   {
833     GNUNET_break_op (0);        /* current we only expect BARRIER_CROSSED
834                                    status message this way */
835     return GNUNET_SYSERR;
836   }
837   name = msg->data;
838   name_len = ntohs (msg->name_len);
839   if ((name_len + 1) != msize)
840   {
841     GNUNET_break_op (0);
842     return GNUNET_SYSERR;
843   }
844   if ('\0' != name[name_len])
845   {
846     GNUNET_break_op (0);
847     return GNUNET_SYSERR;
848   }
849   return GNUNET_OK;
850 }
851
852
853 /**
854  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
855  * This handler is queued in the main service and will handle the messages sent
856  * either from the testbed driver or from a high level controller
857  *
858  * @param cls identification of the client
859  * @param msg the actual message
860  */
861 void
862 handle_barrier_status (void *cls,
863                        const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
864 {
865   struct GNUNET_SERVICE_Client *client = cls;
866   struct Barrier *barrier;
867   struct ClientCtx *client_ctx;
868   const char *name;
869   struct GNUNET_HashCode key;
870   uint16_t name_len;
871   struct GNUNET_MQ_Envelope *env;
872
873   if (NULL == GST_context)
874   {
875     GNUNET_break_op (0);
876     GNUNET_SERVICE_client_drop (client);
877     return;
878   }
879   if (client != GST_context->client)
880   {
881     GNUNET_break_op (0);
882     GNUNET_SERVICE_client_drop (client);
883     return;
884   }
885   name = msg->data;
886   name_len = ntohs (msg->name_len);
887   LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n",
888              name);
889   GNUNET_CRYPTO_hash (name,
890                       name_len,
891                       &key);
892   barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
893                                                &key);
894   if (NULL == barrier)
895   {
896     GNUNET_break_op (0);
897     GNUNET_SERVICE_client_drop (client);
898     return;
899   }
900   GNUNET_SERVICE_client_continue (client);
901   while (NULL != (client_ctx = barrier->head)) /* Notify peers */
902   {
903     env = GNUNET_MQ_msg_copy (&msg->header);
904     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
905                     env);
906     GNUNET_CONTAINER_DLL_remove (barrier->head,
907                                  barrier->tail,
908                                  client_ctx);
909     client_ctx->barrier = NULL;
910   }
911 }
912
913 /* end of gnunet-service-testbed_barriers.c */