diff options
Diffstat (limited to 'src/testbed/gnunet-service-testbed_barriers.c')
-rw-r--r-- | src/testbed/gnunet-service-testbed_barriers.c | 929 |
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 | */ | ||
61 | struct Barrier; | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Context to be associated with each client | ||
66 | */ | ||
67 | struct 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 | */ | ||
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 | * Hashtable handle for storing initialised barriers | ||
212 | */ | ||
213 | static struct GNUNET_CONTAINER_MultiHashMap *barrier_map; | ||
214 | |||
215 | /** | ||
216 | * Service context | ||
217 | */ | ||
218 | static 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 | */ | ||
227 | static void | ||
228 | remove_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 | */ | ||
253 | static void | ||
254 | cancel_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 | */ | ||
278 | static void | ||
279 | send_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 | */ | ||
316 | static void | ||
317 | send_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 | */ | ||
334 | static int | ||
335 | check_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 | */ | ||
353 | static void | ||
354 | handle_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 | */ | ||
419 | static void * | ||
420 | connect_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 | */ | ||
441 | static void | ||
442 | disconnect_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 | */ | ||
466 | void | ||
467 | GST_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 | */ | ||
499 | static int | ||
500 | barrier_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 | */ | ||
516 | void | ||
517 | GST_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 | */ | ||
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 | |||
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 | */ | ||
607 | static void | ||
608 | fwd_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 | */ | ||
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_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 | */ | ||
828 | int | ||
829 | check_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 | */ | ||
869 | void | ||
870 | handle_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 */ | ||