aboutsummaryrefslogtreecommitdiff
path: root/src/testbed/testbed_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed/testbed_api.c')
-rw-r--r--src/testbed/testbed_api.c2474
1 files changed, 0 insertions, 2474 deletions
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
deleted file mode 100644
index 18bb0c3f6..000000000
--- a/src/testbed/testbed_api.c
+++ /dev/null
@@ -1,2474 +0,0 @@
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 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/testbed_api.c
23 * @brief API for accessing the GNUnet testing service.
24 * This library is supposed to make it easier to write
25 * testcases and script large-scale benchmarks.
26 * @author Christian Grothoff
27 * @author Sree Harsha Totakura
28 */
29#include "platform.h"
30#include "gnunet_testbed_service.h"
31#include "gnunet_core_service.h"
32#include "gnunet_constants.h"
33#include "gnunet_transport_service.h"
34#include "gnunet_hello_lib.h"
35#include <zlib.h>
36
37#include "testbed.h"
38#include "testbed_api.h"
39#include "testbed_api_hosts.h"
40#include "testbed_api_peers.h"
41#include "testbed_api_operations.h"
42#include "testbed_api_sd.h"
43
44/**
45 * Generic logging shorthand
46 */
47#define LOG(kind, ...) GNUNET_log_from (kind, "testbed-api", __VA_ARGS__)
48
49/**
50 * Debug logging
51 */
52#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
53
54/**
55 * Relative time seconds shorthand
56 */
57#define TIME_REL_SECS(sec) \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
59
60
61/**
62 * Default server message sending retry timeout
63 */
64#define TIMEOUT_REL TIME_REL_SECS (1)
65
66
67/**
68 * Context data for forwarded Operation
69 */
70struct ForwardedOperationData
71{
72 /**
73 * The callback to call when reply is available
74 */
75 GNUNET_MQ_MessageCallback cc;
76
77 /**
78 * The closure for the above callback
79 */
80 void *cc_cls;
81};
82
83
84/**
85 * Context data for get slave config operations
86 */
87struct GetSlaveConfigData
88{
89 /**
90 * The id of the slave controller
91 */
92 uint32_t slave_id;
93};
94
95
96/**
97 * Context data for controller link operations
98 */
99struct ControllerLinkData
100{
101 /**
102 * The controller link message
103 */
104 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
105
106 /**
107 * The id of the host which is hosting the controller to be linked
108 */
109 uint32_t host_id;
110};
111
112
113/**
114 * Date context for OP_SHUTDOWN_PEERS operations
115 */
116struct ShutdownPeersData
117{
118 /**
119 * The operation completion callback to call
120 */
121 GNUNET_TESTBED_OperationCompletionCallback cb;
122
123 /**
124 * The closure for the above callback
125 */
126 void *cb_cls;
127};
128
129
130/**
131 * An entry in the stack for keeping operations which are about to expire
132 */
133struct ExpireOperationEntry
134{
135 /**
136 * DLL head; new entries are to be inserted here
137 */
138 struct ExpireOperationEntry *next;
139
140 /**
141 * DLL tail; entries are deleted from here
142 */
143 struct ExpireOperationEntry *prev;
144
145 /**
146 * The operation. This will be a dangling pointer when the operation is freed
147 */
148 const struct GNUNET_TESTBED_Operation *op;
149};
150
151
152/**
153 * DLL head for list of operations marked for expiry
154 */
155static struct ExpireOperationEntry *exop_head;
156
157/**
158 * DLL tail for list of operation marked for expiry
159 */
160static struct ExpireOperationEntry *exop_tail;
161
162
163/**
164 * Inserts an operation into the list of operations marked for expiry
165 *
166 * @param op the operation to insert
167 */
168static void
169exop_insert (struct GNUNET_TESTBED_Operation *op)
170{
171 struct ExpireOperationEntry *entry;
172
173 entry = GNUNET_new (struct ExpireOperationEntry);
174 entry->op = op;
175 GNUNET_CONTAINER_DLL_insert_tail (exop_head, exop_tail, entry);
176}
177
178
179/**
180 * Checks if an operation is present in the list of operations marked for
181 * expiry. If the operation is found, it and the tail of operations after it
182 * are removed from the list.
183 *
184 * @param op the operation to check
185 * @return GNUNET_NO if the operation is not present in the list; GNUNET_YES if
186 * the operation is found in the list (the operation is then removed
187 * from the list -- calling this function again with the same
188 * paramenter will return GNUNET_NO)
189 */
190static int
191exop_check (const struct GNUNET_TESTBED_Operation *const op)
192{
193 struct ExpireOperationEntry *entry;
194 struct ExpireOperationEntry *entry2;
195 int found;
196
197 found = GNUNET_NO;
198 entry = exop_head;
199 while (NULL != entry)
200 {
201 if (op == entry->op)
202 {
203 found = GNUNET_YES;
204 break;
205 }
206 entry = entry->next;
207 }
208 if (GNUNET_NO == found)
209 return GNUNET_NO;
210 /* Truncate the tail */
211 while (NULL != entry)
212 {
213 entry2 = entry->next;
214 GNUNET_CONTAINER_DLL_remove (exop_head, exop_tail, entry);
215 GNUNET_free (entry);
216 entry = entry2;
217 }
218 return GNUNET_YES;
219}
220
221
222/**
223 * Context information to be used while searching for operation contexts
224 */
225struct SearchContext
226{
227 /**
228 * The result of the search
229 */
230 struct OperationContext *opc;
231
232 /**
233 * The id of the operation context we are searching for
234 */
235 uint64_t id;
236};
237
238
239/**
240 * Search iterator for searching an operation context
241 *
242 * @param cls the search context
243 * @param key current key code
244 * @param value value in the hash map
245 * @return #GNUNET_YES if we should continue to iterate,
246 * #GNUNET_NO if not.
247 */
248static int
249opc_search_iterator (void *cls, uint32_t key, void *value)
250{
251 struct SearchContext *sc = cls;
252 struct OperationContext *opc = value;
253
254 GNUNET_assert (NULL != opc);
255 GNUNET_assert (NULL == sc->opc);
256 if (opc->id != sc->id)
257 return GNUNET_YES;
258 sc->opc = opc;
259 return GNUNET_NO;
260}
261
262
263/**
264 * Returns the operation context with the given id if found in the Operation
265 * context queues of the controller
266 *
267 * @param c the controller whose operation context map is searched
268 * @param id the id which has to be checked
269 * @return the matching operation context; NULL if no match found
270 */
271static struct OperationContext *
272find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
273{
274 struct SearchContext sc;
275
276 sc.id = id;
277 sc.opc = NULL;
278 GNUNET_assert (NULL != c->opc_map);
279 if (GNUNET_SYSERR !=
280 GNUNET_CONTAINER_multihashmap32_get_multiple (c->opc_map,
281 (uint32_t) id,
282 &opc_search_iterator,
283 &sc))
284 return NULL;
285 return sc.opc;
286}
287
288
289/**
290 * Inserts the given operation context into the operation context map of the
291 * given controller. Creates the operation context map if one does not exist
292 * for the controller
293 *
294 * @param c the controller
295 * @param opc the operation context to be inserted
296 */
297void
298GNUNET_TESTBED_insert_opc_ (struct GNUNET_TESTBED_Controller *c,
299 struct OperationContext *opc)
300{
301 if (NULL == c->opc_map)
302 c->opc_map = GNUNET_CONTAINER_multihashmap32_create (256);
303 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap32_put (
304 c->opc_map,
305 (uint32_t) opc->id,
306 opc,
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
308}
309
310
311/**
312 * Removes the given operation context from the operation context map of the
313 * given controller
314 *
315 * @param c the controller
316 * @param opc the operation context to remove
317 */
318void
319GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
320 struct OperationContext *opc)
321{
322 GNUNET_assert (NULL != c->opc_map);
323 GNUNET_assert (GNUNET_YES ==
324 GNUNET_CONTAINER_multihashmap32_remove (c->opc_map,
325 (uint32_t) opc->id,
326 opc));
327 if ((0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map)) &&
328 (NULL != c->opcq_empty_cb))
329 c->opcq_empty_cb (c->opcq_empty_cls);
330}
331
332
333/**
334 * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message is well-formed.
335 *
336 * @param cls the controller handler
337 * @param msg message received
338 * @return #GNUNET_OK if message is well-formed
339 */
340static int
341check_add_host_confirm (void *cls,
342 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
343{
344 const char *emsg;
345 uint16_t msg_size;
346
347 msg_size = ntohs (msg->header.size) - sizeof(*msg);
348 if (0 == msg_size)
349 return GNUNET_OK;
350 /* We have an error message */
351 emsg = (const char *) &msg[1];
352 if ('\0' != emsg[msg_size - 1])
353 {
354 GNUNET_break (0);
355 return GNUNET_SYSERR;
356 }
357 return GNUNET_OK;
358}
359
360
361/**
362 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
363 * controller (testbed service)
364 *
365 * @param cls the controller handler
366 * @param msg message received
367 */
368static void
369handle_add_host_confirm (void *cls,
370 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
371{
372 struct GNUNET_TESTBED_Controller *c = cls;
373 struct GNUNET_TESTBED_HostRegistrationHandle *rh = c->rh;
374 const char *emsg;
375 uint16_t msg_size;
376
377 if (NULL == rh)
378 return;
379 if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
380 {
381 LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
382 GNUNET_TESTBED_host_get_id_ (rh->host),
383 ntohl (msg->host_id));
384 return;
385 }
386 c->rh = NULL;
387 msg_size = ntohs (msg->header.size) - sizeof(*msg);
388 if (0 == msg_size)
389 {
390 LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
391 GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
392 rh->cc (rh->cc_cls, NULL);
393 GNUNET_free (rh);
394 return;
395 }
396 /* We have an error message */
397 emsg = (const char *) &msg[1];
398 LOG (GNUNET_ERROR_TYPE_ERROR,
399 _ ("Adding host %u failed with error: %s\n"),
400 ntohl (msg->host_id),
401 emsg);
402 rh->cc (rh->cc_cls, emsg);
403 GNUNET_free (rh);
404}
405
406
407/**
408 * Handler for forwarded operations
409 *
410 * @param c the controller handle
411 * @param opc the operation context
412 * @param msg the message
413 */
414static void
415handle_forwarded_operation_msg (void *cls,
416 struct OperationContext *opc,
417 const struct GNUNET_MessageHeader *msg)
418{
419 struct GNUNET_TESTBED_Controller *c = cls;
420 struct ForwardedOperationData *fo_data;
421
422 fo_data = opc->data;
423 if (NULL != fo_data->cc)
424 fo_data->cc (fo_data->cc_cls, msg);
425 GNUNET_TESTBED_remove_opc_ (c, opc);
426 GNUNET_free (fo_data);
427 GNUNET_free (opc);
428}
429
430
431/**
432 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS message from
433 * controller (testbed service)
434 *
435 * @param c the controller handler
436 * @param msg message received
437 */
438static void
439handle_opsuccess (
440 void *cls,
441 const struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
442{
443 struct GNUNET_TESTBED_Controller *c = cls;
444 struct OperationContext *opc;
445 GNUNET_TESTBED_OperationCompletionCallback op_comp_cb;
446 void *op_comp_cb_cls;
447 struct GNUNET_TESTBED_EventInformation event;
448 uint64_t op_id;
449
450 op_id = GNUNET_ntohll (msg->operation_id);
451 LOG_DEBUG ("Operation %llu successful\n",
452 (unsigned long long) op_id);
453 if (NULL == (opc = find_opc (c, op_id)))
454 {
455 LOG_DEBUG ("Operation not found\n");
456 return;
457 }
458 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
459 event.op = opc->op;
460 event.op_cls = opc->op_cls;
461 event.details.operation_finished.emsg = NULL;
462 event.details.operation_finished.generic = NULL;
463 op_comp_cb = NULL;
464 op_comp_cb_cls = NULL;
465 switch (opc->type)
466 {
467 case OP_FORWARDED: {
468 handle_forwarded_operation_msg (c,
469 opc,
470 (const struct
471 GNUNET_MessageHeader *) msg);
472 return;
473 }
474 break;
475
476 case OP_PEER_DESTROY: {
477 struct GNUNET_TESTBED_Peer *peer;
478
479 peer = opc->data;
480 GNUNET_TESTBED_peer_deregister_ (peer);
481 GNUNET_free (peer);
482 opc->data = NULL;
483 // PEERDESTROYDATA
484 }
485 break;
486
487 case OP_SHUTDOWN_PEERS: {
488 struct ShutdownPeersData *data;
489
490 data = opc->data;
491 op_comp_cb = data->cb;
492 op_comp_cb_cls = data->cb_cls;
493 GNUNET_free (data);
494 opc->data = NULL;
495 GNUNET_TESTBED_cleanup_peers_ ();
496 }
497 break;
498
499 case OP_MANAGE_SERVICE: {
500 struct ManageServiceData *data;
501
502 GNUNET_assert (NULL != (data = opc->data));
503 op_comp_cb = data->cb;
504 op_comp_cb_cls = data->cb_cls;
505 GNUNET_free (data);
506 opc->data = NULL;
507 }
508 break;
509
510 case OP_PEER_RECONFIGURE:
511 break;
512
513 default:
514 GNUNET_assert (0);
515 }
516 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
517 opc->state = OPC_STATE_FINISHED;
518 exop_insert (event.op);
519 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
520 {
521 if (NULL != c->cc)
522 c->cc (c->cc_cls, &event);
523 if (GNUNET_NO == exop_check (event.op))
524 return;
525 }
526 else
527 LOG_DEBUG ("Not calling callback\n");
528 if (NULL != op_comp_cb)
529 op_comp_cb (op_comp_cb_cls, event.op, NULL);
530 /* You could have marked the operation as done by now */
531 GNUNET_break (GNUNET_NO == exop_check (event.op));
532}
533
534
535/**
536 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS message from
537 * controller (testbed service)
538 *
539 * @param c the controller handle
540 * @param msg message received
541 */
542static void
543handle_peer_create_success (
544 void *cls,
545 const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
546{
547 struct GNUNET_TESTBED_Controller *c = cls;
548 struct OperationContext *opc;
549 struct PeerCreateData *data;
550 struct GNUNET_TESTBED_Peer *peer;
551 struct GNUNET_TESTBED_Operation *op;
552 GNUNET_TESTBED_PeerCreateCallback cb;
553 void *cb_cls;
554 uint64_t op_id;
555
556 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
557 ntohs (msg->header.size));
558 op_id = GNUNET_ntohll (msg->operation_id);
559 if (NULL == (opc = find_opc (c, op_id)))
560 {
561 LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
562 return;
563 }
564 if (OP_FORWARDED == opc->type)
565 {
566 handle_forwarded_operation_msg (c,
567 opc,
568 (const struct GNUNET_MessageHeader *) msg);
569 return;
570 }
571 GNUNET_assert (OP_PEER_CREATE == opc->type);
572 GNUNET_assert (NULL != opc->data);
573 data = opc->data;
574 GNUNET_assert (NULL != data->peer);
575 peer = data->peer;
576 GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
577 peer->state = TESTBED_PS_CREATED;
578 GNUNET_TESTBED_peer_register_ (peer);
579 cb = data->cb;
580 cb_cls = data->cls;
581 op = opc->op;
582 GNUNET_free (opc->data);
583 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
584 opc->state = OPC_STATE_FINISHED;
585 exop_insert (op);
586 if (NULL != cb)
587 cb (cb_cls, peer, NULL);
588 /* You could have marked the operation as done by now */
589 GNUNET_break (GNUNET_NO == exop_check (op));
590}
591
592
593/**
594 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT message from
595 * controller (testbed service)
596 *
597 * @param c the controller handler
598 * @param msg message received
599 */
600static void
601handle_peer_event (void *cls, const struct GNUNET_TESTBED_PeerEventMessage *msg)
602{
603 struct GNUNET_TESTBED_Controller *c = cls;
604 struct OperationContext *opc;
605 struct GNUNET_TESTBED_Peer *peer;
606 struct PeerEventData *data;
607 GNUNET_TESTBED_PeerChurnCallback pcc;
608 void *pcc_cls;
609 struct GNUNET_TESTBED_EventInformation event;
610 uint64_t op_id;
611 uint64_t mask;
612
613 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerEventMessage) ==
614 ntohs (msg->header.size));
615 op_id = GNUNET_ntohll (msg->operation_id);
616 if (NULL == (opc = find_opc (c, op_id)))
617 {
618 LOG_DEBUG ("Operation not found\n");
619 return;
620 }
621 if (OP_FORWARDED == opc->type)
622 {
623 handle_forwarded_operation_msg (c,
624 opc,
625 (const struct GNUNET_MessageHeader *) msg);
626 return;
627 }
628 GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
629 data = opc->data;
630 GNUNET_assert (NULL != data);
631 peer = data->peer;
632 GNUNET_assert (NULL != peer);
633 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
634 event.op = opc->op;
635 event.op_cls = opc->op_cls;
636 switch (event.type)
637 {
638 case GNUNET_TESTBED_ET_PEER_START:
639 peer->state = TESTBED_PS_STARTED;
640 event.details.peer_start.host = peer->host;
641 event.details.peer_start.peer = peer;
642 break;
643
644 case GNUNET_TESTBED_ET_PEER_STOP:
645 peer->state = TESTBED_PS_STOPPED;
646 event.details.peer_stop.peer = peer;
647 break;
648
649 default:
650 GNUNET_assert (0); /* We should never reach this state */
651 }
652 pcc = data->pcc;
653 pcc_cls = data->pcc_cls;
654 GNUNET_free (data);
655 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
656 opc->state = OPC_STATE_FINISHED;
657 exop_insert (event.op);
658 mask = 1LL << GNUNET_TESTBED_ET_PEER_START;
659 mask |= 1LL << GNUNET_TESTBED_ET_PEER_STOP;
660 if (0 != (mask & c->event_mask))
661 {
662 if (NULL != c->cc)
663 c->cc (c->cc_cls, &event);
664 if (GNUNET_NO == exop_check (event.op))
665 return;
666 }
667 if (NULL != pcc)
668 pcc (pcc_cls, NULL);
669 /* You could have marked the operation as done by now */
670 GNUNET_break (GNUNET_NO == exop_check (event.op));
671}
672
673
674/**
675 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT message from
676 * controller (testbed service)
677 *
678 * @param c the controller handler
679 * @param msg message received
680 */
681static void
682handle_peer_conevent (void *cls,
683 const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
684{
685 struct GNUNET_TESTBED_Controller *c = cls;
686 struct OperationContext *opc;
687 struct OverlayConnectData *data;
688 GNUNET_TESTBED_OperationCompletionCallback cb;
689 void *cb_cls;
690 struct GNUNET_TESTBED_EventInformation event;
691 uint64_t op_id;
692 uint64_t mask;
693
694 op_id = GNUNET_ntohll (msg->operation_id);
695 if (NULL == (opc = find_opc (c, op_id)))
696 {
697 LOG_DEBUG ("Operation not found\n");
698 return;
699 }
700 if (OP_FORWARDED == opc->type)
701 {
702 handle_forwarded_operation_msg (c,
703 opc,
704 (const struct GNUNET_MessageHeader *) msg);
705 return;
706 }
707 GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
708 GNUNET_assert (NULL != (data = opc->data));
709 GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
710 (ntohl (msg->peer2) == data->p2->unique_id));
711 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
712 event.op = opc->op;
713 event.op_cls = opc->op_cls;
714 switch (event.type)
715 {
716 case GNUNET_TESTBED_ET_CONNECT:
717 event.details.peer_connect.peer1 = data->p1;
718 event.details.peer_connect.peer2 = data->p2;
719 break;
720
721 case GNUNET_TESTBED_ET_DISCONNECT:
722 GNUNET_assert (0); /* FIXME: implement */
723 break;
724
725 default:
726 GNUNET_assert (0); /* Should never reach here */
727 break;
728 }
729 cb = data->cb;
730 cb_cls = data->cb_cls;
731 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
732 opc->state = OPC_STATE_FINISHED;
733 exop_insert (event.op);
734 mask = 1LL << GNUNET_TESTBED_ET_CONNECT;
735 mask |= 1LL << GNUNET_TESTBED_ET_DISCONNECT;
736 if (0 != (mask & c->event_mask))
737 {
738 if (NULL != c->cc)
739 c->cc (c->cc_cls, &event);
740 if (GNUNET_NO == exop_check (event.op))
741 return;
742 }
743 if (NULL != cb)
744 cb (cb_cls, opc->op, NULL);
745 /* You could have marked the operation as done by now */
746 GNUNET_break (GNUNET_NO == exop_check (event.op));
747}
748
749
750/**
751 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
752 * controller (testbed service)
753 *
754 * @param c the controller handler
755 * @param msg message received
756 */
757static int
758check_peer_config (
759 void *cls,
760 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
761{
762 /* anything goes? */
763 return GNUNET_OK;
764}
765
766
767/**
768 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
769 * controller (testbed service)
770 *
771 * @param c the controller handler
772 * @param msg message received
773 */
774static void
775handle_peer_config (
776 void *cls,
777 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
778{
779 struct GNUNET_TESTBED_Controller *c = cls;
780 struct OperationContext *opc;
781 struct GNUNET_TESTBED_Peer *peer;
782 struct PeerInfoData *data;
783 struct GNUNET_TESTBED_PeerInformation *pinfo;
784 GNUNET_TESTBED_PeerInfoCallback cb;
785 void *cb_cls;
786 uint64_t op_id;
787
788 op_id = GNUNET_ntohll (msg->operation_id);
789 if (NULL == (opc = find_opc (c, op_id)))
790 {
791 LOG_DEBUG ("Operation not found\n");
792 return;
793 }
794 if (OP_FORWARDED == opc->type)
795 {
796 handle_forwarded_operation_msg (c, opc, &msg->header);
797 return;
798 }
799 data = opc->data;
800 GNUNET_assert (NULL != data);
801 peer = data->peer;
802 GNUNET_assert (NULL != peer);
803 GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
804 pinfo = GNUNET_new (struct GNUNET_TESTBED_PeerInformation);
805 pinfo->pit = data->pit;
806 cb = data->cb;
807 cb_cls = data->cb_cls;
808 GNUNET_assert (NULL != cb);
809 GNUNET_free (data);
810 opc->data = NULL;
811 switch (pinfo->pit)
812 {
813 case GNUNET_TESTBED_PIT_IDENTITY:
814 pinfo->result.id = GNUNET_new (struct GNUNET_PeerIdentity);
815 GNUNET_memcpy (pinfo->result.id,
816 &msg->peer_identity,
817 sizeof(struct GNUNET_PeerIdentity));
818 break;
819
820 case GNUNET_TESTBED_PIT_CONFIGURATION:
821 pinfo->result.cfg = /* Freed in oprelease_peer_getinfo */
822 GNUNET_TESTBED_extract_config_ (&msg->header);
823 break;
824
825 case GNUNET_TESTBED_PIT_GENERIC:
826 GNUNET_assert (0); /* never reach here */
827 break;
828 }
829 opc->data = pinfo;
830 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
831 opc->state = OPC_STATE_FINISHED;
832 cb (cb_cls, opc->op, pinfo, NULL);
833 /* We dont check whether the operation is marked as done here as the
834 operation contains data (cfg/identify) which will be freed at a later point
835 */
836}
837
838
839/**
840 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
841 * controller (testbed service)
842 *
843 * @param c the controller handler
844 * @param msg message received
845 * @return #GNUNET_OK if message is well-formed
846 */
847static int
848check_op_fail_event (
849 void *cls,
850 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
851{
852 /* we accept anything as a valid error message */
853 return GNUNET_OK;
854}
855
856
857/**
858 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
859 * controller (testbed service)
860 *
861 * @param c the controller handler
862 * @param msg message received
863 */
864static void
865handle_op_fail_event (
866 void *cls,
867 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
868{
869 struct GNUNET_TESTBED_Controller *c = cls;
870 struct OperationContext *opc;
871 const char *emsg;
872 uint64_t op_id;
873 uint64_t mask;
874 struct GNUNET_TESTBED_EventInformation event;
875
876 op_id = GNUNET_ntohll (msg->operation_id);
877 if (NULL == (opc = find_opc (c, op_id)))
878 {
879 LOG_DEBUG ("Operation not found\n");
880 return;
881 }
882 if (OP_FORWARDED == opc->type)
883 {
884 handle_forwarded_operation_msg (c,
885 opc,
886 (const struct GNUNET_MessageHeader *) msg);
887 return;
888 }
889 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
890 opc->state = OPC_STATE_FINISHED;
891 emsg = GNUNET_TESTBED_parse_error_string_ (msg);
892 if (NULL == emsg)
893 emsg = "Unknown error";
894 if (OP_PEER_INFO == opc->type)
895 {
896 struct PeerInfoData *data;
897
898 data = opc->data;
899 if (NULL != data->cb)
900 data->cb (data->cb_cls, opc->op, NULL, emsg);
901 GNUNET_free (data);
902 return; /* We do not call controller callback for peer info */
903 }
904 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
905 event.op = opc->op;
906 event.op_cls = opc->op_cls;
907 event.details.operation_finished.emsg = emsg;
908 event.details.operation_finished.generic = NULL;
909 mask = (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
910 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
911 {
912 exop_insert (event.op);
913 c->cc (c->cc_cls, &event);
914 if (GNUNET_NO == exop_check (event.op))
915 return;
916 }
917 switch (opc->type)
918 {
919 case OP_PEER_CREATE: {
920 struct PeerCreateData *data;
921
922 data = opc->data;
923 GNUNET_free (data->peer);
924 if (NULL != data->cb)
925 data->cb (data->cls, NULL, emsg);
926 GNUNET_free (data);
927 }
928 break;
929
930 case OP_PEER_START:
931 case OP_PEER_STOP: {
932 struct PeerEventData *data;
933
934 data = opc->data;
935 if (NULL != data->pcc)
936 data->pcc (data->pcc_cls, emsg);
937 GNUNET_free (data);
938 }
939 break;
940
941 case OP_PEER_DESTROY:
942 break;
943
944 case OP_PEER_INFO:
945 GNUNET_assert (0);
946
947 case OP_OVERLAY_CONNECT: {
948 struct OverlayConnectData *data;
949
950 data = opc->data;
951 GNUNET_TESTBED_operation_mark_failed (opc->op);
952 if (NULL != data->cb)
953 data->cb (data->cb_cls, opc->op, emsg);
954 }
955 break;
956
957 case OP_FORWARDED:
958 GNUNET_assert (0);
959
960 case OP_LINK_CONTROLLERS: /* No secondary callback */
961 break;
962
963 case OP_SHUTDOWN_PEERS: {
964 struct ShutdownPeersData *data;
965
966 data = opc->data;
967 GNUNET_free (data); /* FIXME: Decide whether we call data->op_cb */
968 opc->data = NULL;
969 }
970 break;
971
972 case OP_MANAGE_SERVICE: {
973 struct ManageServiceData *data = opc->data;
974 GNUNET_TESTBED_OperationCompletionCallback cb;
975 void *cb_cls;
976
977 GNUNET_assert (NULL != data);
978 cb = data->cb;
979 cb_cls = data->cb_cls;
980 GNUNET_free (data);
981 opc->data = NULL;
982 exop_insert (event.op);
983 if (NULL != cb)
984 cb (cb_cls, opc->op, emsg);
985 /* You could have marked the operation as done by now */
986 GNUNET_break (GNUNET_NO == exop_check (event.op));
987 }
988 break;
989
990 default:
991 GNUNET_break (0);
992 }
993}
994
995
996/**
997 * Function to build GET_SLAVE_CONFIG message
998 *
999 * @param op_id the id this message should contain in its operation id field
1000 * @param slave_id the id this message should contain in its slave id field
1001 * @return newly allocated SlaveGetConfigurationMessage
1002 */
1003static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
1004GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
1005{
1006 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1007 uint16_t msize;
1008
1009 msize = sizeof(struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
1010 msg = GNUNET_malloc (msize);
1011 msg->header.size = htons (msize);
1012 msg->header.type =
1013 htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
1014 msg->operation_id = GNUNET_htonll (op_id);
1015 msg->slave_id = htonl (slave_id);
1016 return msg;
1017}
1018
1019
1020/**
1021 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_INFORMATION message from
1022 * controller (testbed service)
1023 *
1024 * @param c the controller handler
1025 * @param msg message received
1026 */
1027static int
1028check_slave_config (void *cls,
1029 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1030{
1031 /* anything goes? */
1032 return GNUNET_OK;
1033}
1034
1035
1036/**
1037 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION message from controller
1038 * (testbed service)
1039 *
1040 * @param c the controller handler
1041 * @param msg message received
1042 */
1043static void
1044handle_slave_config (void *cls,
1045 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1046{
1047 struct GNUNET_TESTBED_Controller *c = cls;
1048 struct OperationContext *opc;
1049 uint64_t op_id;
1050 uint64_t mask;
1051 struct GNUNET_TESTBED_EventInformation event;
1052
1053 op_id = GNUNET_ntohll (msg->operation_id);
1054 if (NULL == (opc = find_opc (c, op_id)))
1055 {
1056 LOG_DEBUG ("Operation not found\n");
1057 return;
1058 }
1059 if (OP_GET_SLAVE_CONFIG != opc->type)
1060 {
1061 GNUNET_break (0);
1062 return;
1063 }
1064 opc->state = OPC_STATE_FINISHED;
1065 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1066 mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
1067 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
1068 {
1069 opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
1070 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1071 event.op = opc->op;
1072 event.op_cls = opc->op_cls;
1073 event.details.operation_finished.generic = opc->data;
1074 event.details.operation_finished.emsg = NULL;
1075 c->cc (c->cc_cls, &event);
1076 }
1077}
1078
1079
1080/**
1081 * Check #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1082 * (testbed service)
1083 *
1084 * @param c the controller handler
1085 * @param msg message received
1086 * @return #GNUNET_OK if @a msg is well-formed
1087 */
1088static int
1089check_link_controllers_result (
1090 void *cls,
1091 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1092{
1093 /* actual check to be implemented */
1094 return GNUNET_OK;
1095}
1096
1097
1098/**
1099 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1100 * (testbed service)
1101 *
1102 * @param c the controller handler
1103 * @param msg message received
1104 */
1105static void
1106handle_link_controllers_result (
1107 void *cls,
1108 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1109{
1110 struct GNUNET_TESTBED_Controller *c = cls;
1111 struct OperationContext *opc;
1112 struct ControllerLinkData *data;
1113 struct GNUNET_CONFIGURATION_Handle *cfg;
1114 struct GNUNET_TESTBED_Host *host;
1115 char *emsg;
1116 uint64_t op_id;
1117 struct GNUNET_TESTBED_EventInformation event;
1118
1119 op_id = GNUNET_ntohll (msg->operation_id);
1120 if (NULL == (opc = find_opc (c, op_id)))
1121 {
1122 LOG_DEBUG ("Operation not found\n");
1123 return;
1124 }
1125 if (OP_FORWARDED == opc->type)
1126 {
1127 handle_forwarded_operation_msg (c,
1128 opc,
1129 (const struct GNUNET_MessageHeader *) msg);
1130 return;
1131 }
1132 if (OP_LINK_CONTROLLERS != opc->type)
1133 {
1134 GNUNET_break (0);
1135 return;
1136 }
1137 GNUNET_assert (NULL != (data = opc->data));
1138 host = GNUNET_TESTBED_host_lookup_by_id_ (data->host_id);
1139 GNUNET_assert (NULL != host);
1140 GNUNET_free (data);
1141 opc->data = NULL;
1142 opc->state = OPC_STATE_FINISHED;
1143 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1144 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1145 event.op = opc->op;
1146 event.op_cls = opc->op_cls;
1147 event.details.operation_finished.emsg = NULL;
1148 event.details.operation_finished.generic = NULL;
1149 emsg = NULL;
1150 cfg = NULL;
1151 if (GNUNET_NO == ntohs (msg->success))
1152 {
1153 emsg =
1154 GNUNET_malloc (ntohs (msg->header.size)
1155 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse)
1156 + 1);
1157 GNUNET_memcpy (emsg,
1158 &msg[1],
1159 ntohs (msg->header.size)
1160 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse));
1161 event.details.operation_finished.emsg = emsg;
1162 }
1163 else
1164 {
1165 if (0 != ntohs (msg->config_size))
1166 {
1167 cfg = GNUNET_TESTBED_extract_config_ (
1168 (const struct GNUNET_MessageHeader *) msg);
1169 GNUNET_assert (NULL != cfg);
1170 GNUNET_TESTBED_host_replace_cfg_ (host, cfg);
1171 }
1172 }
1173 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
1174 {
1175 if (NULL != c->cc)
1176 c->cc (c->cc_cls, &event);
1177 }
1178 else
1179 LOG_DEBUG ("Not calling callback\n");
1180 if (NULL != cfg)
1181 GNUNET_CONFIGURATION_destroy (cfg);
1182 GNUNET_free (emsg);
1183}
1184
1185
1186/**
1187 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS message.
1188 *
1189 * @param cls the controller handle to determine the connection this message
1190 * belongs to
1191 * @param msg the barrier status message
1192 * @return #GNUNET_OK if the message is valid; #GNUNET_SYSERR to tear it
1193 * down signalling an error (message malformed)
1194 */
1195static int
1196check_barrier_status (void *cls,
1197 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1198{
1199 uint16_t msize;
1200 uint16_t name_len;
1201 int status;
1202 const char *name;
1203 size_t emsg_len;
1204
1205 msize = ntohs (msg->header.size);
1206 name = msg->data;
1207 name_len = ntohs (msg->name_len);
1208
1209 if (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
1210 {
1211 GNUNET_break_op (0);
1212 return GNUNET_SYSERR;
1213 }
1214 if ('\0' != name[name_len])
1215 {
1216 GNUNET_break_op (0);
1217 return GNUNET_SYSERR;
1218 }
1219 status = ntohs (msg->status);
1220 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1221 {
1222 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1223 + name_len + 1); /* +1!? */
1224 if (0 == emsg_len)
1225 {
1226 GNUNET_break_op (0);
1227 return GNUNET_SYSERR;
1228 }
1229 }
1230 return GNUNET_OK;
1231}
1232
1233
1234/**
1235 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
1236 *
1237 * @param cls the controller handle to determine the connection this message
1238 * belongs to
1239 * @param msg the barrier status message
1240 */
1241static void
1242handle_barrier_status (void *cls,
1243 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1244{
1245 struct GNUNET_TESTBED_Controller *c = cls;
1246 struct GNUNET_TESTBED_Barrier *barrier;
1247 char *emsg;
1248 const char *name;
1249 struct GNUNET_HashCode key;
1250 size_t emsg_len;
1251 int status;
1252 uint16_t msize;
1253 uint16_t name_len;
1254
1255 emsg = NULL;
1256 barrier = NULL;
1257 msize = ntohs (msg->header.size);
1258 if (msize <= sizeof(struct GNUNET_TESTBED_BarrierStatusMsg))
1259 {
1260 GNUNET_break_op (0);
1261 goto cleanup;
1262 }
1263 name = msg->data;
1264 name_len = ntohs (msg->name_len);
1265 if (name_len >= // name_len is strlen(barrier_name)
1266 (msize - ((sizeof msg->header) + sizeof(msg->status))))
1267 {
1268 GNUNET_break_op (0);
1269 goto cleanup;
1270 }
1271 if ('\0' != name[name_len])
1272 {
1273 GNUNET_break_op (0);
1274 goto cleanup;
1275 }
1276 LOG_DEBUG ("Received BARRIER_STATUS msg\n");
1277 status = ntohs (msg->status);
1278 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1279 {
1280 status = -1;
1281 // unlike name_len, emsg_len includes the trailing zero
1282 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1283 + (name_len + 1));
1284 if (0 == emsg_len)
1285 {
1286 GNUNET_break_op (0);
1287 goto cleanup;
1288 }
1289 if ('\0' != (msg->data[(name_len + 1) + (emsg_len - 1)]))
1290 {
1291 GNUNET_break_op (0);
1292 goto cleanup;
1293 }
1294 emsg = GNUNET_malloc (emsg_len);
1295 GNUNET_memcpy (emsg, msg->data + name_len + 1, emsg_len);
1296 }
1297 if (NULL == c->barrier_map)
1298 {
1299 GNUNET_break_op (0);
1300 goto cleanup;
1301 }
1302 GNUNET_CRYPTO_hash (name, name_len, &key);
1303 barrier = GNUNET_CONTAINER_multihashmap_get (c->barrier_map, &key);
1304 if (NULL == barrier)
1305 {
1306 GNUNET_break_op (0);
1307 goto cleanup;
1308 }
1309 GNUNET_assert (NULL != barrier->cb);
1310 if ((GNUNET_YES == barrier->echo) &&
1311 (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status))
1312 GNUNET_TESTBED_queue_message_ (c, GNUNET_copy_message (&msg->header));
1313 barrier->cb (barrier->cls, name, barrier, status, emsg);
1314 if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED == status)
1315 return; /* just initialised; skip cleanup */
1316
1317cleanup:
1318 GNUNET_free (emsg);
1319 /**
1320 * Do not remove the barrier if we did not echo the status back; this is
1321 * required at the chained testbed controller setup to ensure the only the
1322 * test-driver echos the status and the controller hierarchy properly
1323 * propagates the status.
1324 */if ((NULL != barrier) && (GNUNET_YES == barrier->echo))
1325 GNUNET_TESTBED_barrier_remove_ (barrier);
1326}
1327
1328
1329/**
1330 * Queues a message in send queue for sending to the service
1331 *
1332 * @param controller the handle to the controller
1333 * @param msg the message to queue
1334 */
1335void
1336GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1337 struct GNUNET_MessageHeader *msg)
1338{
1339 struct GNUNET_MQ_Envelope *env;
1340 struct GNUNET_MessageHeader *m2;
1341 uint16_t type;
1342 uint16_t size;
1343
1344 type = ntohs (msg->type);
1345 size = ntohs (msg->size);
1346 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1347 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1348 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1349 GNUNET_memcpy (m2, msg, size);
1350 GNUNET_free (msg);
1351 GNUNET_MQ_send (controller->mq, env);
1352}
1353
1354
1355/**
1356 * Sends the given message as an operation. The given callback is called when a
1357 * reply for the operation is available. Call
1358 * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1359 * operation context if the cc hasn't been called
1360 *
1361 * @param controller the controller to which the message has to be sent
1362 * @param operation_id the operation id of the message
1363 * @param msg the message to send
1364 * @param cc the callback to call when reply is available
1365 * @param cc_cls the closure for the above callback
1366 * @return the operation context which can be used to cancel the forwarded
1367 * operation
1368 */
1369struct OperationContext *
1370GNUNET_TESTBED_forward_operation_msg_ (
1371 struct GNUNET_TESTBED_Controller *controller,
1372 uint64_t operation_id,
1373 const struct GNUNET_MessageHeader *msg,
1374 GNUNET_MQ_MessageCallback cc,
1375 void *cc_cls)
1376{
1377 struct OperationContext *opc;
1378 struct ForwardedOperationData *data;
1379 struct GNUNET_MQ_Envelope *env;
1380 struct GNUNET_MessageHeader *m2;
1381 uint16_t type = ntohs (msg->type);
1382 uint16_t size = ntohs (msg->size);
1383
1384 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1385 GNUNET_memcpy (m2, msg, size);
1386 GNUNET_MQ_send (controller->mq, env);
1387 data = GNUNET_new (struct ForwardedOperationData);
1388 data->cc = cc;
1389 data->cc_cls = cc_cls;
1390 opc = GNUNET_new (struct OperationContext);
1391 opc->c = controller;
1392 opc->type = OP_FORWARDED;
1393 opc->data = data;
1394 opc->id = operation_id;
1395 GNUNET_TESTBED_insert_opc_ (controller, opc);
1396 return opc;
1397}
1398
1399
1400/**
1401 * Function to cancel an operation created by simply forwarding an operation
1402 * message.
1403 *
1404 * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1405 */
1406void
1407GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1408{
1409 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1410 GNUNET_free (opc->data);
1411 GNUNET_free (opc);
1412}
1413
1414
1415/**
1416 * Function to call to start a link-controllers type operation once all queues
1417 * the operation is part of declare that the operation can be activated.
1418 *
1419 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1420 */
1421static void
1422opstart_link_controllers (void *cls)
1423{
1424 struct OperationContext *opc = cls;
1425 struct ControllerLinkData *data;
1426 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1427
1428 GNUNET_assert (NULL != opc->data);
1429 data = opc->data;
1430 msg = data->msg;
1431 data->msg = NULL;
1432 opc->state = OPC_STATE_STARTED;
1433 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1434 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1435}
1436
1437
1438/**
1439 * Callback which will be called when link-controllers type operation is released
1440 *
1441 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1442 */
1443static void
1444oprelease_link_controllers (void *cls)
1445{
1446 struct OperationContext *opc = cls;
1447 struct ControllerLinkData *data;
1448
1449 data = opc->data;
1450 switch (opc->state)
1451 {
1452 case OPC_STATE_INIT:
1453 GNUNET_free (data->msg);
1454 break;
1455
1456 case OPC_STATE_STARTED:
1457 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1458 break;
1459
1460 case OPC_STATE_FINISHED:
1461 break;
1462 }
1463 GNUNET_free (data);
1464 GNUNET_free (opc);
1465}
1466
1467
1468/**
1469 * Function to be called when get slave config operation is ready
1470 *
1471 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1472 */
1473static void
1474opstart_get_slave_config (void *cls)
1475{
1476 struct OperationContext *opc = cls;
1477 struct GetSlaveConfigData *data = opc->data;
1478 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1479
1480 GNUNET_assert (NULL != data);
1481 msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1482 GNUNET_free (opc->data);
1483 data = NULL;
1484 opc->data = NULL;
1485 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1486 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1487 opc->state = OPC_STATE_STARTED;
1488}
1489
1490
1491/**
1492 * Function to be called when get slave config operation is cancelled or finished
1493 *
1494 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1495 */
1496static void
1497oprelease_get_slave_config (void *cls)
1498{
1499 struct OperationContext *opc = cls;
1500
1501 switch (opc->state)
1502 {
1503 case OPC_STATE_INIT:
1504 GNUNET_free (opc->data);
1505 break;
1506
1507 case OPC_STATE_STARTED:
1508 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1509 break;
1510
1511 case OPC_STATE_FINISHED:
1512 if (NULL != opc->data)
1513 GNUNET_CONFIGURATION_destroy (opc->data);
1514 break;
1515 }
1516 GNUNET_free (opc);
1517}
1518
1519
1520/**
1521 * Generic error handler, called with the appropriate error code and
1522 * the same closure specified at the creation of the message queue.
1523 * Not every message queue implementation supports an error handler.
1524 *
1525 * @param cls closure, a `struct GNUNET_TESTBED_Controller *`
1526 * @param error error code
1527 */
1528static void
1529mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
1530{
1531 /* struct GNUNET_TESTBED_Controller *c = cls; */
1532
1533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encountered MQ error: %d\n", error);
1534 /* now what? */
1535 GNUNET_SCHEDULER_shutdown (); /* seems most reasonable */
1536}
1537
1538
1539/**
1540 * Start a controller process using the given configuration at the
1541 * given host.
1542 *
1543 * @param host host to run the controller on; This should be the same host if
1544 * the controller was previously started with
1545 * GNUNET_TESTBED_controller_start()
1546 * @param event_mask bit mask with set of events to call 'cc' for;
1547 * or-ed values of "1LL" shifted by the
1548 * respective 'enum GNUNET_TESTBED_EventType'
1549 * (e.g. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1550 * @param cc controller callback to invoke on events
1551 * @param cc_cls closure for cc
1552 * @return handle to the controller
1553 */
1554struct GNUNET_TESTBED_Controller *
1555GNUNET_TESTBED_controller_connect (struct GNUNET_TESTBED_Host *host,
1556 uint64_t event_mask,
1557 GNUNET_TESTBED_ControllerCallback cc,
1558 void *cc_cls)
1559{
1560 struct GNUNET_TESTBED_Controller *controller =
1561 GNUNET_new (struct GNUNET_TESTBED_Controller);
1562 struct GNUNET_MQ_MessageHandler handlers[] =
1563 { GNUNET_MQ_hd_var_size (add_host_confirm,
1564 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS,
1565 struct GNUNET_TESTBED_HostConfirmedMessage,
1566 controller),
1567 GNUNET_MQ_hd_fixed_size (peer_conevent,
1568 GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT,
1569 struct GNUNET_TESTBED_ConnectionEventMessage,
1570 controller),
1571 GNUNET_MQ_hd_fixed_size (opsuccess,
1572 GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS,
1573 struct
1574 GNUNET_TESTBED_GenericOperationSuccessEventMessage,
1575 controller),
1576 GNUNET_MQ_hd_var_size (op_fail_event,
1577 GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT,
1578 struct GNUNET_TESTBED_OperationFailureEventMessage,
1579 controller),
1580 GNUNET_MQ_hd_fixed_size (peer_create_success,
1581 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS,
1582 struct
1583 GNUNET_TESTBED_PeerCreateSuccessEventMessage,
1584 controller),
1585 GNUNET_MQ_hd_fixed_size (peer_event,
1586 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT,
1587 struct GNUNET_TESTBED_PeerEventMessage,
1588 controller),
1589 GNUNET_MQ_hd_var_size (peer_config,
1590 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
1591 struct
1592 GNUNET_TESTBED_PeerConfigurationInformationMessage,
1593 controller),
1594 GNUNET_MQ_hd_var_size (slave_config,
1595 GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
1596 struct GNUNET_TESTBED_SlaveConfiguration,
1597 controller),
1598 GNUNET_MQ_hd_var_size (link_controllers_result,
1599 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
1600 struct GNUNET_TESTBED_ControllerLinkResponse,
1601 controller),
1602 GNUNET_MQ_hd_var_size (barrier_status,
1603 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
1604 struct GNUNET_TESTBED_BarrierStatusMsg,
1605 controller),
1606 GNUNET_MQ_handler_end () };
1607 struct GNUNET_TESTBED_InitMessage *msg;
1608 struct GNUNET_MQ_Envelope *env;
1609 const struct GNUNET_CONFIGURATION_Handle *cfg;
1610 const char *controller_hostname;
1611 unsigned long long max_parallel_operations;
1612 unsigned long long max_parallel_service_connections;
1613 unsigned long long max_parallel_topology_config_operations;
1614 size_t slen;
1615
1616 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1617 if (GNUNET_OK !=
1618 GNUNET_CONFIGURATION_get_value_number (cfg,
1619 "testbed",
1620 "MAX_PARALLEL_OPERATIONS",
1621 &max_parallel_operations))
1622 {
1623 GNUNET_break (0);
1624 GNUNET_free (controller);
1625 return NULL;
1626 }
1627 if (GNUNET_OK !=
1628 GNUNET_CONFIGURATION_get_value_number (cfg,
1629 "testbed",
1630 "MAX_PARALLEL_SERVICE_CONNECTIONS",
1631 &max_parallel_service_connections))
1632 {
1633 GNUNET_break (0);
1634 GNUNET_free (controller);
1635 return NULL;
1636 }
1637 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (
1638 cfg,
1639 "testbed",
1640 "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1641 &max_parallel_topology_config_operations))
1642 {
1643 GNUNET_break (0);
1644 GNUNET_free (controller);
1645 return NULL;
1646 }
1647 controller->cc = cc;
1648 controller->cc_cls = cc_cls;
1649 controller->event_mask = event_mask;
1650 controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1651 controller->mq = GNUNET_CLIENT_connect (controller->cfg,
1652 "testbed",
1653 handlers,
1654 &mq_error_handler,
1655 controller);
1656 if (NULL == controller->mq)
1657 {
1658 GNUNET_break (0);
1659 GNUNET_TESTBED_controller_disconnect (controller);
1660 return NULL;
1661 }
1662 GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1663 controller->host = host;
1664 controller->opq_parallel_operations =
1665 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1666 (unsigned int)
1667 max_parallel_operations);
1668 controller->opq_parallel_service_connections =
1669 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1670 (unsigned int)
1671 max_parallel_service_connections);
1672 controller->opq_parallel_topology_config_operations =
1673 GNUNET_TESTBED_operation_queue_create_ (
1674 OPERATION_QUEUE_TYPE_FIXED,
1675 (unsigned int) max_parallel_topology_config_operations);
1676 controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1677 if (NULL == controller_hostname)
1678 controller_hostname = "127.0.0.1";
1679 slen = strlen (controller_hostname) + 1;
1680 env = GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1681 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1682 msg->event_mask = GNUNET_htonll (controller->event_mask);
1683 GNUNET_memcpy (&msg[1], controller_hostname, slen);
1684 GNUNET_MQ_send (controller->mq, env);
1685 return controller;
1686}
1687
1688
1689/**
1690 * Iterator to free opc map entries
1691 *
1692 * @param cls closure
1693 * @param key current key code
1694 * @param value value in the hash map
1695 * @return #GNUNET_YES if we should continue to iterate,
1696 * #GNUNET_NO if not.
1697 */
1698static int
1699opc_free_iterator (void *cls, uint32_t key, void *value)
1700{
1701 struct GNUNET_CONTAINER_MultiHashMap32 *map = cls;
1702 struct OperationContext *opc = value;
1703
1704 GNUNET_assert (NULL != opc);
1705 GNUNET_break (0);
1706 GNUNET_assert (GNUNET_YES ==
1707 GNUNET_CONTAINER_multihashmap32_remove (map, key, value));
1708 GNUNET_free (opc);
1709 return GNUNET_YES;
1710}
1711
1712
1713/**
1714 * Stop the given controller (also will terminate all peers and
1715 * controllers dependent on this controller). This function
1716 * blocks until the testbed has been fully terminated (!).
1717 *
1718 * @param c handle to controller to stop
1719 */
1720void
1721GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *c)
1722{
1723 if (NULL != c->mq)
1724 {
1725 GNUNET_MQ_destroy (c->mq);
1726 c->mq = NULL;
1727 }
1728 if (NULL != c->host)
1729 GNUNET_TESTBED_deregister_host_at_ (c->host, c);
1730 GNUNET_CONFIGURATION_destroy (c->cfg);
1731 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_operations);
1732 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_service_connections);
1733 GNUNET_TESTBED_operation_queue_destroy_ (
1734 c->opq_parallel_topology_config_operations);
1735 if (NULL != c->opc_map)
1736 {
1737 GNUNET_assert (GNUNET_SYSERR !=
1738 GNUNET_CONTAINER_multihashmap32_iterate (c->opc_map,
1739 &opc_free_iterator,
1740 c->opc_map));
1741 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map));
1742 GNUNET_CONTAINER_multihashmap32_destroy (c->opc_map);
1743 }
1744 GNUNET_free (c);
1745}
1746
1747
1748/**
1749 * Compresses given configuration using zlib compress
1750 *
1751 * @param config the serialized configuration
1752 * @param size the size of config
1753 * @param xconfig will be set to the compressed configuration (memory is fresly
1754 * allocated)
1755 * @return the size of the xconfig
1756 */
1757size_t
1758GNUNET_TESTBED_compress_config_ (const char *config,
1759 size_t size,
1760 char **xconfig)
1761{
1762 size_t xsize;
1763
1764 xsize = compressBound ((uLong) size);
1765 *xconfig = GNUNET_malloc (xsize);
1766 GNUNET_assert (Z_OK == compress2 ((Bytef *) *xconfig,
1767 (uLongf *) &xsize,
1768 (const Bytef *) config,
1769 (uLongf) size,
1770 Z_BEST_SPEED));
1771 return xsize;
1772}
1773
1774
1775/**
1776 * Function to serialize and compress using zlib a configuration through a
1777 * configuration handle
1778 *
1779 * @param cfg the configuration
1780 * @param size the size of configuration when serialize. Will be set on success.
1781 * @param xsize the sizeo of the compressed configuration. Will be set on success.
1782 * @return the serialized and compressed configuration
1783 */
1784char *
1785GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
1786 size_t *size,
1787 size_t *xsize)
1788{
1789 char *config;
1790 char *xconfig;
1791 size_t size_;
1792 size_t xsize_;
1793
1794 config = GNUNET_CONFIGURATION_serialize (cfg, &size_);
1795 xsize_ = GNUNET_TESTBED_compress_config_ (config, size_, &xconfig);
1796 GNUNET_free (config);
1797 *size = size_;
1798 *xsize = xsize_;
1799 return xconfig;
1800}
1801
1802
1803/**
1804 * Create a link from slave controller to delegated controller. Whenever the
1805 * master controller is asked to start a peer at the delegated controller the
1806 * request will be routed towards slave controller (if a route exists). The
1807 * slave controller will then route it to the delegated controller. The
1808 * configuration of the delegated controller is given and is used to either
1809 * create the delegated controller or to connect to an existing controller. Note
1810 * that while starting the delegated controller the configuration will be
1811 * modified to accommodate available free ports. the 'is_subordinate' specifies
1812 * if the given delegated controller should be started and managed by the slave
1813 * controller, or if the delegated controller already has a master and the slave
1814 * controller connects to it as a non master controller. The success or failure
1815 * of this operation will be signalled through the
1816 * GNUNET_TESTBED_ControllerCallback() with an event of type
1817 * GNUNET_TESTBED_ET_OPERATION_FINISHED
1818 *
1819 * @param op_cls the operation closure for the event which is generated to
1820 * signal success or failure of this operation
1821 * @param master handle to the master controller who creates the association
1822 * @param delegated_host requests to which host should be delegated; cannot be NULL
1823 * @param slave_host which host is used to run the slave controller; use NULL to
1824 * make the master controller connect to the delegated host
1825 * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1826 * be started by the slave controller; GNUNET_NO if the slave
1827 * controller has to connect to the already started delegated
1828 * controller via TCP/IP
1829 * @return the operation handle
1830 */
1831struct GNUNET_TESTBED_Operation *
1832GNUNET_TESTBED_controller_link (void *op_cls,
1833 struct GNUNET_TESTBED_Controller *master,
1834 struct GNUNET_TESTBED_Host *delegated_host,
1835 struct GNUNET_TESTBED_Host *slave_host,
1836 int is_subordinate)
1837{
1838 struct OperationContext *opc;
1839 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1840 struct ControllerLinkData *data;
1841 uint32_t slave_host_id;
1842 uint32_t delegated_host_id;
1843 uint16_t msg_size;
1844
1845 GNUNET_assert (GNUNET_YES ==
1846 GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1847 slave_host_id = GNUNET_TESTBED_host_get_id_ (
1848 (NULL != slave_host) ? slave_host : master->host);
1849 delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
1850 if ((NULL != slave_host) && (0 != slave_host_id))
1851 GNUNET_assert (GNUNET_YES ==
1852 GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1853 msg_size = sizeof(struct GNUNET_TESTBED_ControllerLinkRequest);
1854 msg = GNUNET_malloc (msg_size);
1855 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
1856 msg->header.size = htons (msg_size);
1857 msg->delegated_host_id = htonl (delegated_host_id);
1858 msg->slave_host_id = htonl (slave_host_id);
1859 msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1860 data = GNUNET_new (struct ControllerLinkData);
1861 data->msg = msg;
1862 data->host_id = delegated_host_id;
1863 opc = GNUNET_new (struct OperationContext);
1864 opc->c = master;
1865 opc->data = data;
1866 opc->type = OP_LINK_CONTROLLERS;
1867 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1868 opc->state = OPC_STATE_INIT;
1869 opc->op_cls = op_cls;
1870 msg->operation_id = GNUNET_htonll (opc->id);
1871 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1872 &opstart_link_controllers,
1873 &oprelease_link_controllers);
1874 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1875 opc->op);
1876 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1877 return opc->op;
1878}
1879
1880
1881/**
1882 * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
1883 * check. Another difference is that this function takes the id of the slave
1884 * host.
1885 *
1886 * @param op_cls the closure for the operation
1887 * @param master the handle to master controller
1888 * @param slave_host_id id of the host where the slave controller is running to
1889 * the slave_host should remain valid until this operation is cancelled
1890 * or marked as finished
1891 * @return the operation handle;
1892 */
1893struct GNUNET_TESTBED_Operation *
1894GNUNET_TESTBED_get_slave_config_ (void *op_cls,
1895 struct GNUNET_TESTBED_Controller *master,
1896 uint32_t slave_host_id)
1897{
1898 struct OperationContext *opc;
1899 struct GetSlaveConfigData *data;
1900
1901 data = GNUNET_new (struct GetSlaveConfigData);
1902 data->slave_id = slave_host_id;
1903 opc = GNUNET_new (struct OperationContext);
1904 opc->state = OPC_STATE_INIT;
1905 opc->c = master;
1906 opc->id = GNUNET_TESTBED_get_next_op_id (master);
1907 opc->type = OP_GET_SLAVE_CONFIG;
1908 opc->data = data;
1909 opc->op_cls = op_cls;
1910 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1911 &opstart_get_slave_config,
1912 &oprelease_get_slave_config);
1913 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1914 opc->op);
1915 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1916 return opc->op;
1917}
1918
1919
1920/**
1921 * Function to acquire the configuration of a running slave controller. The
1922 * completion of the operation is signalled through the controller_cb from
1923 * GNUNET_TESTBED_controller_connect(). If the operation is successful the
1924 * handle to the configuration is available in the generic pointer of
1925 * operation_finished field of struct GNUNET_TESTBED_EventInformation.
1926 *
1927 * @param op_cls the closure for the operation
1928 * @param master the handle to master controller
1929 * @param slave_host the host where the slave controller is running; the handle
1930 * to the slave_host should remain valid until this operation is
1931 * cancelled or marked as finished
1932 * @return the operation handle; NULL if the slave_host is not registered at
1933 * master
1934 */
1935struct GNUNET_TESTBED_Operation *
1936GNUNET_TESTBED_get_slave_config (void *op_cls,
1937 struct GNUNET_TESTBED_Controller *master,
1938 struct GNUNET_TESTBED_Host *slave_host)
1939{
1940 if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
1941 return NULL;
1942 return GNUNET_TESTBED_get_slave_config_ (op_cls,
1943 master,
1944 GNUNET_TESTBED_host_get_id_ (
1945 slave_host));
1946}
1947
1948
1949/**
1950 * Ask the testbed controller to write the current overlay topology to
1951 * a file. Naturally, the file will only contain a snapshot as the
1952 * topology may evolve all the time.
1953 *
1954 * @param controller overlay controller to inspect
1955 * @param filename name of the file the topology should
1956 * be written to.
1957 */
1958void
1959GNUNET_TESTBED_overlay_write_topology_to_file (
1960 struct GNUNET_TESTBED_Controller *controller,
1961 const char *filename)
1962{
1963 GNUNET_break (0);
1964}
1965
1966
1967/**
1968 * Creates a helper initialization message. This function is here because we
1969 * want to use this in testing
1970 *
1971 * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1972 * HOST(all connections form this ip are permitted by the testbed) when
1973 * starting testbed controller at host. This can either be a single ip
1974 * address or a network address in CIDR notation.
1975 * @param hostname the hostname of the destination this message is intended for
1976 * @param cfg the configuration that has to used to start the testbed service
1977 * thru helper
1978 * @return the initialization message
1979 */
1980struct GNUNET_TESTBED_HelperInit *
1981GNUNET_TESTBED_create_helper_init_msg_ (
1982 const char *trusted_ip,
1983 const char *hostname,
1984 const struct GNUNET_CONFIGURATION_Handle *cfg)
1985{
1986 struct GNUNET_TESTBED_HelperInit *msg;
1987 char *config;
1988 char *xconfig;
1989 size_t config_size;
1990 size_t xconfig_size;
1991 uint16_t trusted_ip_len;
1992 uint16_t hostname_len;
1993 uint16_t msg_size;
1994
1995 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1996 GNUNET_assert (NULL != config);
1997 xconfig_size =
1998 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1999 GNUNET_free (config);
2000 trusted_ip_len = strlen (trusted_ip);
2001 hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
2002 msg_size = xconfig_size + trusted_ip_len + 1
2003 + sizeof(struct GNUNET_TESTBED_HelperInit);
2004 msg_size += hostname_len;
2005 msg = GNUNET_realloc (xconfig, msg_size);
2006 (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len,
2007 msg,
2008 xconfig_size);
2009 msg->header.size = htons (msg_size);
2010 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
2011 msg->trusted_ip_size = htons (trusted_ip_len);
2012 msg->hostname_size = htons (hostname_len);
2013 msg->config_size = htons (config_size);
2014 (void) strcpy ((char *) &msg[1], trusted_ip);
2015 if (0 != hostname_len)
2016 GNUNET_memcpy ((char *) &msg[1] + trusted_ip_len + 1,
2017 hostname,
2018 hostname_len);
2019 return msg;
2020}
2021
2022
2023/**
2024 * This function is used to signal that the event information (struct
2025 * GNUNET_TESTBED_EventInformation) from an operation has been fully processed
2026 * i.e. if the event callback is ever called for this operation. If the event
2027 * callback for this operation has not yet been called, calling this function
2028 * cancels the operation, frees its resources and ensures the no event is
2029 * generated with respect to this operation. Note that however cancelling an
2030 * operation does NOT guarantee that the operation will be fully undone (or that
2031 * nothing ever happened).
2032 *
2033 * This function MUST be called for every operation to fully remove the
2034 * operation from the operation queue. After calling this function, if
2035 * operation is completed and its event information is of type
2036 * GNUNET_TESTBED_ET_OPERATION_FINISHED, the 'op_result' becomes invalid (!).
2037
2038 * If the operation is generated from GNUNET_TESTBED_service_connect() then
2039 * calling this function on such as operation calls the disconnect adapter if
2040 * the connect adapter was ever called.
2041 *
2042 * @param operation operation to signal completion or cancellation
2043 */
2044void
2045GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
2046{
2047 (void) exop_check (operation);
2048 GNUNET_TESTBED_operation_release_ (operation);
2049}
2050
2051
2052/**
2053 * Generates configuration by uncompressing configuration in given message. The
2054 * given message should be of the following types:
2055 * #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
2056 * #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
2057 * #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
2058 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
2059 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
2060 *
2061 * FIXME: This API is incredibly ugly.
2062 *
2063 * @param msg the message containing compressed configuration
2064 * @return handle to the parsed configuration; NULL upon error while parsing the message
2065 */
2066struct GNUNET_CONFIGURATION_Handle *
2067GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
2068{
2069 struct GNUNET_CONFIGURATION_Handle *cfg;
2070 Bytef *data;
2071 const Bytef *xdata;
2072 uLong data_len;
2073 uLong xdata_len;
2074 int ret;
2075
2076 switch (ntohs (msg->type))
2077 {
2078 case GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION: {
2079 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
2080
2081 imsg =
2082 (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
2083 data_len = (uLong) ntohs (imsg->config_size);
2084 xdata_len =
2085 ntohs (imsg->header.size)
2086 - sizeof(struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2087 xdata = (const Bytef *) &imsg[1];
2088 }
2089 break;
2090
2091 case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION: {
2092 const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
2093
2094 imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
2095 data_len = (uLong) ntohs (imsg->config_size);
2096 xdata_len = ntohs (imsg->header.size)
2097 - sizeof(struct GNUNET_TESTBED_SlaveConfiguration);
2098 xdata = (const Bytef *) &imsg[1];
2099 }
2100 break;
2101
2102 case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST: {
2103 const struct GNUNET_TESTBED_AddHostMessage *imsg;
2104 uint16_t osize;
2105
2106 imsg = (const struct GNUNET_TESTBED_AddHostMessage *) msg;
2107 data_len = (uLong) ntohs (imsg->config_size);
2108 osize = sizeof(struct GNUNET_TESTBED_AddHostMessage)
2109 + ntohs (imsg->username_length) + ntohs (imsg->hostname_length);
2110 xdata_len = ntohs (imsg->header.size) - osize;
2111 xdata = (const Bytef *) ((const void *) imsg + osize);
2112 }
2113 break;
2114
2115 case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT: {
2116 const struct GNUNET_TESTBED_ControllerLinkResponse *imsg;
2117
2118 imsg = (const struct GNUNET_TESTBED_ControllerLinkResponse *) msg;
2119 data_len = ntohs (imsg->config_size);
2120 xdata_len = ntohs (imsg->header.size)
2121 - sizeof(const struct GNUNET_TESTBED_ControllerLinkResponse);
2122 xdata = (const Bytef *) &imsg[1];
2123 }
2124 break;
2125
2126 case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER: {
2127 const struct GNUNET_TESTBED_PeerCreateMessage *imsg;
2128
2129 imsg = (const struct GNUNET_TESTBED_PeerCreateMessage *) msg;
2130 data_len = ntohs (imsg->config_size);
2131 xdata_len = ntohs (imsg->header.size)
2132 - sizeof(struct GNUNET_TESTBED_PeerCreateMessage);
2133 xdata = (const Bytef *) &imsg[1];
2134 }
2135 break;
2136
2137 case GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER: {
2138 const struct GNUNET_TESTBED_PeerReconfigureMessage *imsg;
2139
2140 imsg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) msg;
2141 data_len = ntohs (imsg->config_size);
2142 xdata_len = ntohs (imsg->header.size)
2143 - sizeof(struct GNUNET_TESTBED_PeerReconfigureMessage);
2144 xdata = (const Bytef *) &imsg[1];
2145 }
2146 break;
2147
2148 default:
2149 GNUNET_assert (0);
2150 }
2151 data = GNUNET_malloc (data_len);
2152 if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
2153 {
2154 GNUNET_free (data);
2155 GNUNET_break_op (0); /* Un-compression failure */
2156 return NULL;
2157 }
2158 cfg = GNUNET_CONFIGURATION_create ();
2159 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg,
2160 (const char *) data,
2161 (size_t) data_len,
2162 NULL))
2163 {
2164 GNUNET_free (data);
2165 GNUNET_break_op (0); /* De-serialization failure */
2166 return NULL;
2167 }
2168 GNUNET_free (data);
2169 return cfg;
2170}
2171
2172
2173/**
2174 * Checks the integrity of the OperationFailureEventMessage and if good returns
2175 * the error message it contains.
2176 *
2177 * @param msg the OperationFailureEventMessage
2178 * @return the error message
2179 */
2180const char *
2181GNUNET_TESTBED_parse_error_string_ (
2182 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
2183{
2184 uint16_t msize;
2185 const char *emsg;
2186
2187 msize = ntohs (msg->header.size);
2188 if (sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
2189 return NULL;
2190 msize -= sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage);
2191 emsg = (const char *) &msg[1];
2192 if ('\0' != emsg[msize - 1])
2193 {
2194 GNUNET_break (0);
2195 return NULL;
2196 }
2197 return emsg;
2198}
2199
2200
2201/**
2202 * Function to return the operation id for a controller. The operation id is
2203 * created from the controllers host id and its internal operation counter.
2204 *
2205 * @param controller the handle to the controller whose operation id has to be incremented
2206 * @return the incremented operation id.
2207 */
2208uint64_t
2209GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller)
2210{
2211 uint64_t op_id;
2212
2213 op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
2214 op_id = op_id << 32;
2215 op_id |= (uint64_t) controller->operation_counter++;
2216 return op_id;
2217}
2218
2219
2220/**
2221 * Function called when a shutdown peers operation is ready
2222 *
2223 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2224 */
2225static void
2226opstart_shutdown_peers (void *cls)
2227{
2228 struct OperationContext *opc = cls;
2229 struct GNUNET_MQ_Envelope *env;
2230 struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2231
2232 opc->state = OPC_STATE_STARTED;
2233 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS);
2234 msg->operation_id = GNUNET_htonll (opc->id);
2235 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
2236 GNUNET_MQ_send (opc->c->mq, env);
2237}
2238
2239
2240/**
2241 * Callback which will be called when shutdown peers operation is released
2242 *
2243 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2244 */
2245static void
2246oprelease_shutdown_peers (void *cls)
2247{
2248 struct OperationContext *opc = cls;
2249
2250 switch (opc->state)
2251 {
2252 case OPC_STATE_STARTED:
2253 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
2254
2255 /* no break; continue */
2256 case OPC_STATE_INIT:
2257 GNUNET_free (opc->data);
2258 break;
2259
2260 case OPC_STATE_FINISHED:
2261 break;
2262 }
2263 GNUNET_free (opc);
2264}
2265
2266
2267/**
2268 * Stops and destroys all peers. Is equivalent of calling
2269 * GNUNET_TESTBED_peer_stop() and GNUNET_TESTBED_peer_destroy() on all peers,
2270 * except that the peer stop event and operation finished event corresponding to
2271 * the respective functions are not generated. This function should be called
2272 * when there are no other pending operations. If there are pending operations,
2273 * it will return NULL
2274 *
2275 * @param c the controller to send this message to
2276 * @param op_cls closure for the operation
2277 * @param cb the callback to call when all peers are stopped and destroyed
2278 * @param cb_cls the closure for the callback
2279 * @return operation handle on success; NULL if any pending operations are
2280 * present
2281 */
2282struct GNUNET_TESTBED_Operation *
2283GNUNET_TESTBED_shutdown_peers (struct GNUNET_TESTBED_Controller *c,
2284 void *op_cls,
2285 GNUNET_TESTBED_OperationCompletionCallback cb,
2286 void *cb_cls)
2287{
2288 struct OperationContext *opc;
2289 struct ShutdownPeersData *data;
2290
2291 if (0 != GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
2292 return NULL;
2293 data = GNUNET_new (struct ShutdownPeersData);
2294 data->cb = cb;
2295 data->cb_cls = cb_cls;
2296 opc = GNUNET_new (struct OperationContext);
2297 opc->c = c;
2298 opc->op_cls = op_cls;
2299 opc->data = data;
2300 opc->id = GNUNET_TESTBED_get_next_op_id (c);
2301 opc->type = OP_SHUTDOWN_PEERS;
2302 opc->state = OPC_STATE_INIT;
2303 opc->op = GNUNET_TESTBED_operation_create_ (opc,
2304 &opstart_shutdown_peers,
2305 &oprelease_shutdown_peers);
2306 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
2307 opc->op);
2308 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2309 return opc->op;
2310}
2311
2312
2313/**
2314 * Return the index of the peer inside of the total peer array,
2315 * aka. the peer's "unique ID".
2316 *
2317 * @param peer Peer handle.
2318 *
2319 * @return The peer's unique ID.
2320 */
2321uint32_t
2322GNUNET_TESTBED_get_index (const struct GNUNET_TESTBED_Peer *peer)
2323{
2324 return peer->unique_id;
2325}
2326
2327
2328/**
2329 * Remove a barrier and it was the last one in the barrier hash map, destroy the
2330 * hash map
2331 *
2332 * @param barrier the barrier to remove
2333 */
2334void
2335GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier)
2336{
2337 struct GNUNET_TESTBED_Controller *c = barrier->c;
2338
2339 GNUNET_assert (NULL != c->barrier_map); /* No barriers present */
2340 GNUNET_assert (GNUNET_OK ==
2341 GNUNET_CONTAINER_multihashmap_remove (c->barrier_map,
2342 &barrier->key,
2343 barrier));
2344 GNUNET_free (barrier->name);
2345 GNUNET_free (barrier);
2346 if (0 == GNUNET_CONTAINER_multihashmap_size (c->barrier_map))
2347 {
2348 GNUNET_CONTAINER_multihashmap_destroy (c->barrier_map);
2349 c->barrier_map = NULL;
2350 }
2351}
2352
2353
2354/**
2355 * Initialise a barrier and call the given callback when the required percentage
2356 * of peers (quorum) reach the barrier OR upon error.
2357 *
2358 * @param controller the handle to the controller
2359 * @param name identification name of the barrier
2360 * @param quorum the percentage of peers that is required to reach the barrier.
2361 * Peers signal reaching a barrier by calling
2362 * GNUNET_TESTBED_barrier_reached().
2363 * @param cb the callback to call when the barrier is reached or upon error.
2364 * Cannot be NULL.
2365 * @param cls closure for the above callback
2366 * @param echo GNUNET_YES to echo the barrier crossed status message back to the
2367 * controller
2368 * @return barrier handle; NULL upon error
2369 */
2370struct GNUNET_TESTBED_Barrier *
2371GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
2372 const char *name,
2373 unsigned int quorum,
2374 GNUNET_TESTBED_barrier_status_cb cb,
2375 void *cls,
2376 int echo)
2377{
2378 struct GNUNET_TESTBED_BarrierInit *msg;
2379 struct GNUNET_MQ_Envelope *env;
2380 struct GNUNET_TESTBED_Barrier *barrier;
2381 struct GNUNET_HashCode key;
2382 size_t name_len;
2383
2384 GNUNET_assert (quorum <= 100);
2385 GNUNET_assert (NULL != cb);
2386 name_len = strlen (name);
2387 GNUNET_assert (0 < name_len);
2388 GNUNET_CRYPTO_hash (name, name_len, &key);
2389 if (NULL == controller->barrier_map)
2390 controller->barrier_map =
2391 GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
2392 if (GNUNET_YES ==
2393 GNUNET_CONTAINER_multihashmap_contains (controller->barrier_map, &key))
2394 {
2395 GNUNET_break (0);
2396 return NULL;
2397 }
2398 LOG_DEBUG ("Initialising barrier `%s'\n", name);
2399 barrier = GNUNET_new (struct GNUNET_TESTBED_Barrier);
2400 barrier->c = controller;
2401 barrier->name = GNUNET_strdup (name);
2402 barrier->cb = cb;
2403 barrier->cls = cls;
2404 barrier->echo = echo;
2405 GNUNET_memcpy (&barrier->key, &key, sizeof(struct GNUNET_HashCode));
2406 GNUNET_assert (GNUNET_OK ==
2407 GNUNET_CONTAINER_multihashmap_put (
2408 controller->barrier_map,
2409 &barrier->key,
2410 barrier,
2411 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
2412
2413 env = GNUNET_MQ_msg_extra (msg,
2414 name_len,
2415 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT);
2416 msg->quorum = (uint8_t) quorum;
2417 GNUNET_memcpy (msg->name, barrier->name, name_len);
2418 GNUNET_MQ_send (barrier->c->mq, env);
2419 return barrier;
2420}
2421
2422
2423/**
2424 * Initialise a barrier and call the given callback when the required percentage
2425 * of peers (quorum) reach the barrier OR upon error.
2426 *
2427 * @param controller the handle to the controller
2428 * @param name identification name of the barrier
2429 * @param quorum the percentage of peers that is required to reach the barrier.
2430 * Peers signal reaching a barrier by calling
2431 * GNUNET_TESTBED_barrier_reached().
2432 * @param cb the callback to call when the barrier is reached or upon error.
2433 * Cannot be NULL.
2434 * @param cls closure for the above callback
2435 * @return barrier handle; NULL upon error
2436 */
2437struct GNUNET_TESTBED_Barrier *
2438GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
2439 const char *name,
2440 unsigned int quorum,
2441 GNUNET_TESTBED_barrier_status_cb cb,
2442 void *cls)
2443{
2444 return GNUNET_TESTBED_barrier_init_ (controller,
2445 name,
2446 quorum,
2447 cb,
2448 cls,
2449 GNUNET_YES);
2450}
2451
2452
2453/**
2454 * Cancel a barrier.
2455 *
2456 * @param barrier the barrier handle
2457 */
2458void
2459GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
2460{
2461 struct GNUNET_MQ_Envelope *env;
2462 struct GNUNET_TESTBED_BarrierCancel *msg;
2463 size_t slen;
2464
2465 slen = strlen (barrier->name);
2466 env =
2467 GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL);
2468 GNUNET_memcpy (msg->name, barrier->name, slen);
2469 GNUNET_MQ_send (barrier->c->mq, env);
2470 GNUNET_TESTBED_barrier_remove_ (barrier);
2471}
2472
2473
2474/* end of testbed_api.c */