diff options
Diffstat (limited to 'src/testbed/testbed_api.c')
-rw-r--r-- | src/testbed/testbed_api.c | 2474 |
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 | */ | ||
70 | struct 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 | */ | ||
87 | struct 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 | */ | ||
99 | struct 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 | */ | ||
116 | struct 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 | */ | ||
133 | struct 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 | */ | ||
155 | static struct ExpireOperationEntry *exop_head; | ||
156 | |||
157 | /** | ||
158 | * DLL tail for list of operation marked for expiry | ||
159 | */ | ||
160 | static 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 | */ | ||
168 | static void | ||
169 | exop_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 | */ | ||
190 | static int | ||
191 | exop_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 | */ | ||
225 | struct 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 | */ | ||
248 | static int | ||
249 | opc_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 | */ | ||
271 | static struct OperationContext * | ||
272 | find_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 | */ | ||
297 | void | ||
298 | GNUNET_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 | */ | ||
318 | void | ||
319 | GNUNET_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 | */ | ||
340 | static int | ||
341 | check_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 | */ | ||
368 | static void | ||
369 | handle_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 | */ | ||
414 | static void | ||
415 | handle_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 | */ | ||
438 | static void | ||
439 | handle_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 | */ | ||
542 | static void | ||
543 | handle_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 | */ | ||
600 | static void | ||
601 | handle_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 | */ | ||
681 | static void | ||
682 | handle_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 | */ | ||
757 | static int | ||
758 | check_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 | */ | ||
774 | static void | ||
775 | handle_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 | */ | ||
847 | static int | ||
848 | check_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 | */ | ||
864 | static void | ||
865 | handle_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 | */ | ||
1003 | static struct GNUNET_TESTBED_SlaveGetConfigurationMessage * | ||
1004 | GNUNET_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 | */ | ||
1027 | static int | ||
1028 | check_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 | */ | ||
1043 | static void | ||
1044 | handle_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 | */ | ||
1088 | static int | ||
1089 | check_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 | */ | ||
1105 | static void | ||
1106 | handle_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 | */ | ||
1195 | static int | ||
1196 | check_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 | */ | ||
1241 | static void | ||
1242 | handle_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 | |||
1317 | cleanup: | ||
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 | */ | ||
1335 | void | ||
1336 | GNUNET_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 | */ | ||
1369 | struct OperationContext * | ||
1370 | GNUNET_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 | */ | ||
1406 | void | ||
1407 | GNUNET_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 | */ | ||
1421 | static void | ||
1422 | opstart_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 | */ | ||
1443 | static void | ||
1444 | oprelease_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 | */ | ||
1473 | static void | ||
1474 | opstart_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 | */ | ||
1496 | static void | ||
1497 | oprelease_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 | */ | ||
1528 | static void | ||
1529 | mq_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 | */ | ||
1554 | struct GNUNET_TESTBED_Controller * | ||
1555 | GNUNET_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 | */ | ||
1698 | static int | ||
1699 | opc_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 | */ | ||
1720 | void | ||
1721 | GNUNET_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 | */ | ||
1757 | size_t | ||
1758 | GNUNET_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 | */ | ||
1784 | char * | ||
1785 | GNUNET_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 | */ | ||
1831 | struct GNUNET_TESTBED_Operation * | ||
1832 | GNUNET_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 | */ | ||
1893 | struct GNUNET_TESTBED_Operation * | ||
1894 | GNUNET_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 | */ | ||
1935 | struct GNUNET_TESTBED_Operation * | ||
1936 | GNUNET_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 | */ | ||
1958 | void | ||
1959 | GNUNET_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 | */ | ||
1980 | struct GNUNET_TESTBED_HelperInit * | ||
1981 | GNUNET_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 | */ | ||
2044 | void | ||
2045 | GNUNET_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 | */ | ||
2066 | struct GNUNET_CONFIGURATION_Handle * | ||
2067 | GNUNET_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 | */ | ||
2180 | const char * | ||
2181 | GNUNET_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 | */ | ||
2208 | uint64_t | ||
2209 | GNUNET_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 | */ | ||
2225 | static void | ||
2226 | opstart_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 | */ | ||
2245 | static void | ||
2246 | oprelease_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 | */ | ||
2282 | struct GNUNET_TESTBED_Operation * | ||
2283 | GNUNET_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 | */ | ||
2321 | uint32_t | ||
2322 | GNUNET_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 | */ | ||
2334 | void | ||
2335 | GNUNET_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 | */ | ||
2370 | struct GNUNET_TESTBED_Barrier * | ||
2371 | GNUNET_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 | */ | ||
2437 | struct GNUNET_TESTBED_Barrier * | ||
2438 | GNUNET_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 | */ | ||
2458 | void | ||
2459 | GNUNET_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 */ | ||