diff options
Diffstat (limited to 'src/testbed/gnunet-service-testbed_barriers.c')
-rw-r--r-- | src/testbed/gnunet-service-testbed_barriers.c | 926 |
1 files changed, 0 insertions, 926 deletions
diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c deleted file mode 100644 index be33bd131..000000000 --- a/src/testbed/gnunet-service-testbed_barriers.c +++ /dev/null | |||
@@ -1,926 +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 "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 barriers 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 message | ||
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 | * 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 ( | ||
729 | "Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n", | ||
730 | barrier->name); | ||
731 | send_barrier_status_msg (barrier, NULL); | ||
732 | } | ||
733 | else | ||
734 | barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT ( | ||
735 | 30), | ||
736 | &fwd_tout_barrier_init, | ||
737 | barrier); | ||
738 | } | ||
739 | |||
740 | |||
741 | /** | ||
742 | * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. | ||
743 | * | ||
744 | * @param cls identification of the client | ||
745 | * @param msg the actual message | ||
746 | * @return #GNUNET_OK if @a msg is well-formed | ||
747 | */ | ||
748 | int | ||
749 | check_barrier_cancel (void *cls, | ||
750 | const struct GNUNET_TESTBED_BarrierCancel *msg) | ||
751 | { | ||
752 | return GNUNET_OK; /* all are well-formed */ | ||
753 | } | ||
754 | |||
755 | |||
756 | /** | ||
757 | * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. This | ||
758 | * message should always come from a parent controller or the testbed API if we | ||
759 | * are the root controller. | ||
760 | * | ||
761 | * This handler is queued in the main service and will handle the messages sent | ||
762 | * either from the testbed driver or from a high level controller | ||
763 | * | ||
764 | * @param cls identification of the client | ||
765 | * @param msg the actual message | ||
766 | */ | ||
767 | void | ||
768 | handle_barrier_cancel (void *cls, | ||
769 | const struct GNUNET_TESTBED_BarrierCancel *msg) | ||
770 | { | ||
771 | struct GNUNET_SERVICE_Client *client = cls; | ||
772 | char *name; | ||
773 | struct Barrier *barrier; | ||
774 | struct GNUNET_HashCode hash; | ||
775 | size_t name_len; | ||
776 | uint16_t msize; | ||
777 | |||
778 | if (NULL == GST_context) | ||
779 | { | ||
780 | GNUNET_break_op (0); | ||
781 | GNUNET_SERVICE_client_drop (client); | ||
782 | return; | ||
783 | } | ||
784 | if (client != GST_context->client) | ||
785 | { | ||
786 | GNUNET_break_op (0); | ||
787 | GNUNET_SERVICE_client_drop (client); | ||
788 | return; | ||
789 | } | ||
790 | msize = ntohs (msg->header.size); | ||
791 | name_len = msize - sizeof(struct GNUNET_TESTBED_BarrierCancel); | ||
792 | name = GNUNET_malloc (name_len + 1); | ||
793 | GNUNET_memcpy (name, | ||
794 | msg->name, | ||
795 | name_len); | ||
796 | LOG_DEBUG ("Received BARRIER_CANCEL for barrier `%s'\n", | ||
797 | name); | ||
798 | GNUNET_CRYPTO_hash (name, | ||
799 | name_len, | ||
800 | &hash); | ||
801 | if (GNUNET_NO == | ||
802 | GNUNET_CONTAINER_multihashmap_contains (barrier_map, | ||
803 | &hash)) | ||
804 | { | ||
805 | GNUNET_break_op (0); | ||
806 | GNUNET_SERVICE_client_drop (client); | ||
807 | return; | ||
808 | } | ||
809 | barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, | ||
810 | &hash); | ||
811 | GNUNET_assert (NULL != barrier); | ||
812 | cancel_wrappers (barrier); | ||
813 | remove_barrier (barrier); | ||
814 | GNUNET_SERVICE_client_continue (client); | ||
815 | } | ||
816 | |||
817 | |||
818 | /** | ||
819 | * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. | ||
820 | * | ||
821 | * @param cls identification of the client | ||
822 | * @param msg the actual message | ||
823 | * @return #GNUNET_OK if @a msg is well-formed | ||
824 | */ | ||
825 | int | ||
826 | check_barrier_status (void *cls, | ||
827 | const struct GNUNET_TESTBED_BarrierStatusMsg *msg) | ||
828 | { | ||
829 | uint16_t msize; | ||
830 | uint16_t name_len; | ||
831 | const char *name; | ||
832 | enum GNUNET_TESTBED_BarrierStatus status; | ||
833 | |||
834 | msize = ntohs (msg->header.size) - sizeof(*msg); | ||
835 | status = ntohs (msg->status); | ||
836 | if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status) | ||
837 | { | ||
838 | GNUNET_break_op (0); /* current we only expect BARRIER_CROSSED | ||
839 | status message this way */ | ||
840 | return GNUNET_SYSERR; | ||
841 | } | ||
842 | name = msg->data; | ||
843 | name_len = ntohs (msg->name_len); | ||
844 | if ((name_len + 1) != msize) | ||
845 | { | ||
846 | GNUNET_break_op (0); | ||
847 | return GNUNET_SYSERR; | ||
848 | } | ||
849 | if ('\0' != name[name_len]) | ||
850 | { | ||
851 | GNUNET_break_op (0); | ||
852 | return GNUNET_SYSERR; | ||
853 | } | ||
854 | return GNUNET_OK; | ||
855 | } | ||
856 | |||
857 | |||
858 | /** | ||
859 | * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. | ||
860 | * This handler is queued in the main service and will handle the messages sent | ||
861 | * either from the testbed driver or from a high level controller | ||
862 | * | ||
863 | * @param cls identification of the client | ||
864 | * @param msg the actual message | ||
865 | */ | ||
866 | void | ||
867 | handle_barrier_status (void *cls, | ||
868 | const struct GNUNET_TESTBED_BarrierStatusMsg *msg) | ||
869 | { | ||
870 | struct GNUNET_SERVICE_Client *client = cls; | ||
871 | struct Barrier *barrier; | ||
872 | struct ClientCtx *client_ctx; | ||
873 | struct WBarrier *wrapper; | ||
874 | const char *name; | ||
875 | struct GNUNET_HashCode key; | ||
876 | uint16_t name_len; | ||
877 | struct GNUNET_MQ_Envelope *env; | ||
878 | |||
879 | if (NULL == GST_context) | ||
880 | { | ||
881 | GNUNET_break_op (0); | ||
882 | GNUNET_SERVICE_client_drop (client); | ||
883 | return; | ||
884 | } | ||
885 | if (client != GST_context->client) | ||
886 | { | ||
887 | GNUNET_break_op (0); | ||
888 | GNUNET_SERVICE_client_drop (client); | ||
889 | return; | ||
890 | } | ||
891 | name = msg->data; | ||
892 | name_len = ntohs (msg->name_len); | ||
893 | LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n", | ||
894 | name); | ||
895 | GNUNET_CRYPTO_hash (name, | ||
896 | name_len, | ||
897 | &key); | ||
898 | barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, | ||
899 | &key); | ||
900 | if (NULL == barrier) | ||
901 | { | ||
902 | GNUNET_break_op (0); | ||
903 | GNUNET_SERVICE_client_drop (client); | ||
904 | return; | ||
905 | } | ||
906 | GNUNET_SERVICE_client_continue (client); | ||
907 | for (client_ctx = barrier->head; NULL != client_ctx; client_ctx = | ||
908 | client_ctx->next) /* Notify peers */ | ||
909 | { | ||
910 | env = GNUNET_MQ_msg_copy (&msg->header); | ||
911 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client_ctx->client), | ||
912 | env); | ||
913 | } | ||
914 | /** | ||
915 | * The wrapper barriers do not echo the barrier status, so we have to do it | ||
916 | * here | ||
917 | */ | ||
918 | for (wrapper = barrier->whead; NULL != wrapper; wrapper = wrapper->next) | ||
919 | { | ||
920 | GNUNET_TESTBED_queue_message_ (wrapper->controller, | ||
921 | GNUNET_copy_message (&msg->header)); | ||
922 | } | ||
923 | } | ||
924 | |||
925 | |||
926 | /* end of gnunet-service-testbed_barriers.c */ | ||