aboutsummaryrefslogtreecommitdiff
path: root/src/testbed/gnunet-service-testbed_peers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed/gnunet-service-testbed_peers.c')
-rw-r--r--src/testbed/gnunet-service-testbed_peers.c1552
1 files changed, 0 insertions, 1552 deletions
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c
deleted file mode 100644
index 05410c26a..000000000
--- a/src/testbed/gnunet-service-testbed_peers.c
+++ /dev/null
@@ -1,1552 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21
22/**
23 * @file testbed/gnunet-service-testbed_peers.c
24 * @brief implementation of TESTBED service that deals with peer management
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet-service-testbed.h"
30#include "gnunet_arm_service.h"
31#include <zlib.h>
32
33
34/**
35 * A list of peers we know about
36 */
37struct Peer **GST_peer_list;
38
39/**
40 * The current number of peers running locally under this controller
41 */
42unsigned int GST_num_local_peers;
43
44
45/**
46 * Context information to manage peers' services
47 */
48struct ManageServiceContext
49{
50 /**
51 * DLL next ptr
52 */
53 struct ManageServiceContext *next;
54
55 /**
56 * DLL prev ptr
57 */
58 struct ManageServiceContext *prev;
59
60 /**
61 * The ARM handle of the peer
62 */
63 struct GNUNET_ARM_Handle *ah;
64
65 /**
66 * peer whose service has to be managed
67 */
68 struct Peer *peer;
69
70 /**
71 * The client which requested to manage the peer's service
72 */
73 struct GNUNET_SERVICE_Client *client;
74
75 /**
76 * Name of the service.
77 */
78 char *service;
79
80 /**
81 * The operation id of the associated request
82 */
83 uint64_t op_id;
84
85 /**
86 * 1 if the service at the peer has to be started; 0 if it has to be stopped
87 */
88 uint8_t start;
89
90 /**
91 * Is this context expired? Do not work on this context if it is set to
92 * GNUNET_YES
93 */
94 uint8_t expired;
95};
96
97
98/**
99 * Context information for peer re-configure operations
100 */
101struct PeerReconfigureContext
102{
103 /**
104 * DLL next for inclusoin in peer reconfigure operations list
105 */
106 struct PeerReconfigureContext *next;
107
108 /**
109 * DLL prev
110 */
111 struct PeerReconfigureContext *prev;
112
113 /**
114 * The client which gave this operation to us
115 */
116 struct GNUNET_SERVICE_Client *client;
117
118 /**
119 * The configuration handle to use as the new template
120 */
121 struct GNUNET_CONFIGURATION_Handle *cfg;
122
123 /**
124 * The id of the operation
125 */
126 uint64_t op_id;
127
128 /**
129 * The id of the peer which has to be reconfigured
130 */
131 uint32_t peer_id;
132
133 /**
134 * The the peer stopped? Used while cleaning up this context to decide
135 * whether the asynchronous stop request through Testing/ARM API has to be
136 * cancelled
137 */
138 uint8_t stopped;
139};
140
141/**
142 * The DLL head for the peer reconfigure list
143 */
144static struct PeerReconfigureContext *prc_head;
145
146/**
147 * The DLL tail for the peer reconfigure list
148 */
149static struct PeerReconfigureContext *prc_tail;
150
151
152/**
153 * DLL head for queue of manage service requests
154 */
155static struct ManageServiceContext *mctx_head;
156
157/**
158 * DLL tail for queue of manage service requests
159 */
160static struct ManageServiceContext *mctx_tail;
161
162
163/**
164 * Adds a peer to the peer array
165 *
166 * @param peer the peer to add
167 */
168static void
169peer_list_add (struct Peer *peer)
170{
171 if (peer->id >= GST_peer_list_size)
172 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
173 GNUNET_assert (NULL == GST_peer_list[peer->id]);
174 GST_peer_list[peer->id] = peer;
175 if (GNUNET_NO == peer->is_remote)
176 GST_num_local_peers++;
177}
178
179
180/**
181 * Removes a the give peer from the peer array
182 *
183 * @param peer the peer to be removed
184 */
185static void
186peer_list_remove (struct Peer *peer)
187{
188 unsigned int orig_size;
189 uint32_t id;
190
191 if (GNUNET_NO == peer->is_remote)
192 GST_num_local_peers--;
193 GST_peer_list[peer->id] = NULL;
194 orig_size = GST_peer_list_size;
195 while (GST_peer_list_size >= LIST_GROW_STEP)
196 {
197 for (id = GST_peer_list_size - 1;
198 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
199 id--)
200 if (NULL != GST_peer_list[id])
201 break;
202 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
203 break;
204 GST_peer_list_size -= LIST_GROW_STEP;
205 }
206 if (orig_size == GST_peer_list_size)
207 return;
208 GST_peer_list =
209 GNUNET_realloc (GST_peer_list,
210 sizeof(struct Peer *) * GST_peer_list_size);
211}
212
213
214/**
215 * The task to be executed if the forwarded peer create operation has been
216 * timed out
217 *
218 * @param cls the FowardedOperationContext
219 */
220static void
221peer_create_forward_timeout (void *cls)
222{
223 struct ForwardedOperationContext *fopc = cls;
224
225 GNUNET_free (fopc->cls);
226 GST_forwarded_operation_timeout (fopc);
227}
228
229
230/**
231 * Callback to be called when forwarded peer create operation is successful. We
232 * have to relay the reply msg back to the client
233 *
234 * @param cls ForwardedOperationContext
235 * @param msg the peer create success message
236 */
237static void
238peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
239{
240 struct ForwardedOperationContext *fopc = cls;
241 struct Peer *remote_peer;
242
243 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
244 {
245 GNUNET_assert (NULL != fopc->cls);
246 remote_peer = fopc->cls;
247 peer_list_add (remote_peer);
248 }
249 GST_forwarded_operation_reply_relay (fopc,
250 msg);
251}
252
253
254/**
255 * Function to destroy a peer
256 *
257 * @param peer the peer structure to destroy
258 */
259void
260GST_destroy_peer (struct Peer *peer)
261{
262 GNUNET_break (0 == peer->reference_cnt);
263 if (GNUNET_YES == peer->is_remote)
264 {
265 peer_list_remove (peer);
266 GNUNET_free (peer);
267 return;
268 }
269 if (GNUNET_YES == peer->details.local.is_running)
270 {
271 GNUNET_TESTING_peer_stop (peer->details.local.peer);
272 peer->details.local.is_running = GNUNET_NO;
273 }
274 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
275 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
276 peer_list_remove (peer);
277 GNUNET_free (peer);
278}
279
280
281/**
282 * Cleanup the context information created for managing a peer's service
283 *
284 * @param mctx the ManageServiceContext
285 */
286static void
287cleanup_mctx (struct ManageServiceContext *mctx)
288{
289 mctx->expired = GNUNET_YES;
290 GNUNET_CONTAINER_DLL_remove (mctx_head,
291 mctx_tail,
292 mctx);
293 GNUNET_ARM_disconnect (mctx->ah);
294 GNUNET_assert (0 < mctx->peer->reference_cnt);
295 mctx->peer->reference_cnt--;
296 if ((GNUNET_YES == mctx->peer->destroy_flag) &&
297 (0 == mctx->peer->reference_cnt))
298 GST_destroy_peer (mctx->peer);
299 GNUNET_free (mctx->service);
300 GNUNET_free (mctx);
301}
302
303
304/**
305 * Stops a peer
306 *
307 * @param peer the peer to stop
308 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
309 */
310static int
311stop_peer (struct Peer *peer)
312{
313 GNUNET_assert (GNUNET_NO == peer->is_remote);
314 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
315 return GNUNET_SYSERR;
316 peer->details.local.is_running = GNUNET_NO;
317 return GNUNET_OK;
318}
319
320
321/**
322 * Cleans up the given PeerReconfigureContext
323 *
324 * @param prc the PeerReconfigureContext
325 */
326static void
327cleanup_prc (struct PeerReconfigureContext *prc)
328{
329 struct Peer *peer;
330
331 if (VALID_PEER_ID (prc->peer_id))
332 {
333 peer = GST_peer_list [prc->peer_id];
334 if (1 != prc->stopped)
335 {
336 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
337 stop_peer (peer); /* Stop the peer synchronously */
338 }
339 }
340 if (NULL != prc->cfg)
341 GNUNET_CONFIGURATION_destroy (prc->cfg);
342 GNUNET_CONTAINER_DLL_remove (prc_head,
343 prc_tail,
344 prc);
345 GNUNET_free (prc);
346}
347
348
349/**
350 * Notify peers subsystem that @a client disconnected.
351 *
352 * @param client the client that disconnected
353 */
354void
355GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
356{
357 struct ForwardedOperationContext *fopc;
358 struct ForwardedOperationContext *fopcn;
359 struct ManageServiceContext *mctx;
360 struct ManageServiceContext *mctxn;
361 struct PeerReconfigureContext *prc;
362 struct PeerReconfigureContext *prcn;
363
364 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
365 {
366 fopcn = fopc->next;
367 if (client == fopc->client)
368 {
369 if (OP_PEER_CREATE == fopc->type)
370 GNUNET_free (fopc->cls);
371 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
372 GST_forwarded_operation_timeout (fopc);
373 }
374 }
375 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
376 {
377 mctxn = mctx->next;
378 if (client == mctx->client)
379 cleanup_mctx (mctx);
380 }
381 for (prc = prc_head; NULL != prc; prc = prcn)
382 {
383 prcn = prc->next;
384 if (client == prc->client)
385 cleanup_prc (prc);
386 }
387}
388
389
390/**
391 * Callback to be called when forwarded peer destroy operation is successful. We
392 * have to relay the reply msg back to the client
393 *
394 * @param cls ForwardedOperationContext
395 * @param msg the peer create success message
396 */
397static void
398peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
399{
400 struct ForwardedOperationContext *fopc = cls;
401 struct Peer *remote_peer;
402
403 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
404 ntohs (msg->type))
405 {
406 remote_peer = fopc->cls;
407 GNUNET_assert (NULL != remote_peer);
408 remote_peer->destroy_flag = GNUNET_YES;
409 if (0 == remote_peer->reference_cnt)
410 GST_destroy_peer (remote_peer);
411 }
412 GST_forwarded_operation_reply_relay (fopc,
413 msg);
414}
415
416
417/**
418 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
419 *
420 * @param cls identification of the client
421 * @param msg the actual message
422 * @return #GNUNET_OK if @a msg is well-formed
423 */
424int
425check_peer_create (void *cls,
426 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
427{
428 return GNUNET_OK; /* checked later */
429}
430
431
432void
433handle_peer_create (void *cls,
434 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
435{
436 struct GNUNET_SERVICE_Client *client = cls;
437 struct GNUNET_MQ_Envelope *env;
438 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
439 struct GNUNET_CONFIGURATION_Handle *cfg;
440 struct ForwardedOperationContext *fo_ctxt;
441 struct Route *route;
442 struct Peer *peer;
443 char *emsg;
444 uint32_t host_id;
445 uint32_t peer_id;
446
447 host_id = ntohl (msg->host_id);
448 peer_id = ntohl (msg->peer_id);
449 if (VALID_PEER_ID (peer_id))
450 {
451 (void) GNUNET_asprintf (&emsg,
452 "Peer with ID %u already exists",
453 peer_id);
454 GST_send_operation_fail_msg (client,
455 GNUNET_ntohll (msg->operation_id),
456 emsg);
457 GNUNET_free (emsg);
458 GNUNET_SERVICE_client_continue (client);
459 return;
460 }
461 if (UINT32_MAX == peer_id)
462 {
463 GST_send_operation_fail_msg (client,
464 GNUNET_ntohll (msg->operation_id),
465 "Cannot create peer with given ID");
466 GNUNET_SERVICE_client_continue (client);
467 return;
468 }
469 if (host_id == GST_context->host_id)
470 {
471 /* We are responsible for this peer */
472 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
473 if (NULL == cfg)
474 {
475 GNUNET_break (0);
476 GNUNET_SERVICE_client_drop (client);
477 return;
478 }
479 GNUNET_CONFIGURATION_set_value_number (cfg,
480 "TESTBED",
481 "PEERID",
482 (unsigned long long) peer_id);
483
484 GNUNET_CONFIGURATION_set_value_number (cfg,
485 "PATHS",
486 "PEERID",
487 (unsigned long long) peer_id);
488 peer = GNUNET_new (struct Peer);
489 peer->is_remote = GNUNET_NO;
490 peer->details.local.cfg = cfg;
491 peer->id = peer_id;
492 LOG_DEBUG ("Creating peer with id: %u\n",
493 (unsigned int) peer->id);
494 peer->details.local.peer =
495 GNUNET_TESTING_peer_configure (GST_context->system,
496 peer->details.local.cfg, peer->id,
497 NULL /* Peer id */,
498 &emsg);
499 if (NULL == peer->details.local.peer)
500 {
501 LOG (GNUNET_ERROR_TYPE_WARNING,
502 "Configuring peer failed: %s\n",
503 emsg);
504 GNUNET_free (emsg);
505 GNUNET_free (peer);
506 GNUNET_break (0);
507 GNUNET_SERVICE_client_drop (client);
508 return;
509 }
510 peer->details.local.is_running = GNUNET_NO;
511 peer_list_add (peer);
512 env = GNUNET_MQ_msg (reply,
513 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
514 reply->peer_id = msg->peer_id;
515 reply->operation_id = msg->operation_id;
516 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
517 env);
518 GNUNET_SERVICE_client_continue (client);
519 return;
520 }
521
522 /* Forward peer create request */
523 route = GST_find_dest_route (host_id);
524 if (NULL == route)
525 {
526 GNUNET_break (0);
527 GNUNET_SERVICE_client_continue (client); // ?
528 return;
529 }
530 peer = GNUNET_new (struct Peer);
531 peer->is_remote = GNUNET_YES;
532 peer->id = peer_id;
533 peer->details.remote.slave = GST_slave_list[route->dest];
534 peer->details.remote.remote_host_id = host_id;
535 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
536 fo_ctxt->client = client;
537 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
538 fo_ctxt->cls = peer;
539 fo_ctxt->type = OP_PEER_CREATE;
540 fo_ctxt->opc =
541 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
542 [route->dest]->controller,
543 fo_ctxt->operation_id,
544 &msg->header,
545 &peer_create_success_cb,
546 fo_ctxt);
547 fo_ctxt->timeout_task =
548 GNUNET_SCHEDULER_add_delayed (GST_timeout,
549 &peer_create_forward_timeout,
550 fo_ctxt);
551 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
552 fopcq_tail,
553 fo_ctxt);
554 GNUNET_SERVICE_client_continue (client);
555}
556
557
558/**
559 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
560 *
561 * @param cls identification of the client
562 * @param msg the actual message
563 */
564void
565handle_peer_destroy (void *cls,
566 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
567{
568 struct GNUNET_SERVICE_Client *client = cls;
569 struct ForwardedOperationContext *fopc;
570 struct Peer *peer;
571 uint32_t peer_id;
572
573 peer_id = ntohl (msg->peer_id);
574 LOG_DEBUG ("Received peer destroy on peer: %u and operation id: %llu\n",
575 (unsigned int) peer_id,
576 (unsigned long long) GNUNET_ntohll (msg->operation_id));
577 if (! VALID_PEER_ID (peer_id))
578 {
579 LOG (GNUNET_ERROR_TYPE_ERROR,
580 "Asked to destroy a non existent peer with id: %u\n", peer_id);
581 GST_send_operation_fail_msg (client,
582 GNUNET_ntohll (msg->operation_id),
583 "Peer doesn't exist");
584 GNUNET_SERVICE_client_continue (client);
585 return;
586 }
587 peer = GST_peer_list[peer_id];
588 if (GNUNET_YES == peer->is_remote)
589 {
590 /* Forward the destroy message to sub controller */
591 fopc = GNUNET_new (struct ForwardedOperationContext);
592 fopc->client = client;
593 fopc->cls = peer;
594 fopc->type = OP_PEER_DESTROY;
595 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
596 fopc->opc =
597 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
598 slave->controller,
599 fopc->operation_id,
600 &msg->header,
601 &peer_destroy_success_cb,
602 fopc);
603 fopc->timeout_task =
604 GNUNET_SCHEDULER_add_delayed (GST_timeout,
605 &GST_forwarded_operation_timeout,
606 fopc);
607 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
608 fopcq_tail,
609 fopc);
610 GNUNET_SERVICE_client_continue (client);
611 return;
612 }
613 peer->destroy_flag = GNUNET_YES;
614 if (0 == peer->reference_cnt)
615 GST_destroy_peer (peer);
616 else
617 LOG (GNUNET_ERROR_TYPE_DEBUG,
618 "Delaying peer destroy as peer is currently in use\n");
619 GST_send_operation_success_msg (client,
620 GNUNET_ntohll (msg->operation_id));
621 GNUNET_SERVICE_client_continue (client);
622}
623
624
625/**
626 * Stats a peer
627 *
628 * @param peer the peer to start
629 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
630 */
631static int
632start_peer (struct Peer *peer)
633{
634 GNUNET_assert (GNUNET_NO == peer->is_remote);
635 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
636 return GNUNET_SYSERR;
637 peer->details.local.is_running = GNUNET_YES;
638 return GNUNET_OK;
639}
640
641
642void
643handle_peer_start (void *cls,
644 const struct GNUNET_TESTBED_PeerStartMessage *msg)
645{
646 struct GNUNET_SERVICE_Client *client = cls;
647 struct GNUNET_MQ_Envelope *env;
648 struct GNUNET_TESTBED_PeerEventMessage *reply;
649 struct ForwardedOperationContext *fopc;
650 struct Peer *peer;
651 uint32_t peer_id;
652
653 peer_id = ntohl (msg->peer_id);
654 if (! VALID_PEER_ID (peer_id))
655 {
656 GNUNET_break (0);
657 LOG (GNUNET_ERROR_TYPE_ERROR,
658 "Asked to start a non existent peer with id: %u\n",
659 peer_id);
660 GNUNET_SERVICE_client_continue (client);
661 return;
662 }
663 peer = GST_peer_list[peer_id];
664 if (GNUNET_YES == peer->is_remote)
665 {
666 fopc = GNUNET_new (struct ForwardedOperationContext);
667 fopc->client = client;
668 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
669 fopc->type = OP_PEER_START;
670 fopc->opc =
671 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
672 slave->controller,
673 fopc->operation_id, &msg->header,
674 &
675 GST_forwarded_operation_reply_relay,
676 fopc);
677 fopc->timeout_task =
678 GNUNET_SCHEDULER_add_delayed (GST_timeout,
679 &GST_forwarded_operation_timeout,
680 fopc);
681 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
682 fopcq_tail,
683 fopc);
684 GNUNET_SERVICE_client_continue (client);
685 return;
686 }
687 if (GNUNET_OK != start_peer (peer))
688 {
689 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
690 "Failed to start");
691 GNUNET_SERVICE_client_continue (client);
692 return;
693 }
694 env = GNUNET_MQ_msg (reply,
695 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
696 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
697 reply->host_id = htonl (GST_context->host_id);
698 reply->peer_id = msg->peer_id;
699 reply->operation_id = msg->operation_id;
700 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
701 env);
702 GNUNET_SERVICE_client_continue (client);
703}
704
705
706/**
707 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
708 *
709 * @param cls identification of the client
710 * @param msg the actual message
711 */
712void
713handle_peer_stop (void *cls,
714 const struct GNUNET_TESTBED_PeerStopMessage *msg)
715{
716 struct GNUNET_SERVICE_Client *client = cls;
717 struct GNUNET_MQ_Envelope *env;
718 struct GNUNET_TESTBED_PeerEventMessage *reply;
719 struct ForwardedOperationContext *fopc;
720 struct Peer *peer;
721 uint32_t peer_id;
722
723 peer_id = ntohl (msg->peer_id);
724 LOG (GNUNET_ERROR_TYPE_DEBUG,
725 "Received PEER_STOP for peer %u\n",
726 (unsigned int) peer_id);
727 if (! VALID_PEER_ID (peer_id))
728 {
729 GST_send_operation_fail_msg (client,
730 GNUNET_ntohll (msg->operation_id),
731 "Peer not found");
732 GNUNET_SERVICE_client_continue (client);
733 return;
734 }
735 peer = GST_peer_list[peer_id];
736 if (GNUNET_YES == peer->is_remote)
737 {
738 LOG (GNUNET_ERROR_TYPE_DEBUG,
739 "Forwarding PEER_STOP for peer %u\n",
740 (unsigned int) peer_id);
741 fopc = GNUNET_new (struct ForwardedOperationContext);
742 fopc->client = client;
743 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
744 fopc->type = OP_PEER_STOP;
745 fopc->opc =
746 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
747 slave->controller,
748 fopc->operation_id,
749 &msg->header,
750 &
751 GST_forwarded_operation_reply_relay,
752 fopc);
753 fopc->timeout_task =
754 GNUNET_SCHEDULER_add_delayed (GST_timeout,
755 &GST_forwarded_operation_timeout,
756 fopc);
757 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
758 fopcq_tail,
759 fopc);
760 GNUNET_SERVICE_client_continue (client);
761 return;
762 }
763 if (GNUNET_OK != stop_peer (peer))
764 {
765 LOG (GNUNET_ERROR_TYPE_WARNING,
766 "Stopping peer %u failed\n",
767 (unsigned int) peer_id);
768 GST_send_operation_fail_msg (client,
769 GNUNET_ntohll (msg->operation_id),
770 "Peer not running");
771 GNUNET_SERVICE_client_continue (client);
772 return;
773 }
774 LOG (GNUNET_ERROR_TYPE_DEBUG,
775 "Peer %u successfully stopped\n",
776 (unsigned int) peer_id);
777 env = GNUNET_MQ_msg (reply,
778 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
779 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
780 reply->host_id = htonl (GST_context->host_id);
781 reply->peer_id = msg->peer_id;
782 reply->operation_id = msg->operation_id;
783 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
784 env);
785 GNUNET_SERVICE_client_continue (client);
786 GNUNET_TESTING_peer_wait (peer->details.local.peer);
787}
788
789
790/**
791 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
792 *
793 * @param cls identification of the client
794 * @param msg the actual message
795 */
796void
797handle_peer_get_config (void *cls,
798 const struct
799 GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
800{
801 struct GNUNET_SERVICE_Client *client = cls;
802 struct GNUNET_MQ_Envelope *env;
803 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
804 struct ForwardedOperationContext *fopc;
805 struct Peer *peer;
806 char *config;
807 char *xconfig;
808 size_t c_size;
809 size_t xc_size;
810 uint32_t peer_id;
811
812 peer_id = ntohl (msg->peer_id);
813 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
814 (unsigned int) peer_id);
815 if (! VALID_PEER_ID (peer_id))
816 {
817 GST_send_operation_fail_msg (client,
818 GNUNET_ntohll (msg->operation_id),
819 "Peer not found");
820 GNUNET_SERVICE_client_continue (client);
821 return;
822 }
823 peer = GST_peer_list[peer_id];
824 if (GNUNET_YES == peer->is_remote)
825 {
826 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
827 (unsigned int) peer_id);
828 fopc = GNUNET_new (struct ForwardedOperationContext);
829 fopc->client = client;
830 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
831 fopc->type = OP_PEER_INFO;
832 fopc->opc =
833 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
834 slave->controller,
835 fopc->operation_id,
836 &msg->header,
837 &
838 GST_forwarded_operation_reply_relay,
839 fopc);
840 fopc->timeout_task =
841 GNUNET_SCHEDULER_add_delayed (GST_timeout,
842 &GST_forwarded_operation_timeout,
843 fopc);
844 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
845 fopcq_tail,
846 fopc);
847 GNUNET_SERVICE_client_continue (client);
848 return;
849 }
850 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
851 peer_id);
852 config =
853 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
854 &c_size);
855 xc_size = GNUNET_TESTBED_compress_config_ (config,
856 c_size,
857 &xconfig);
858 GNUNET_free (config);
859 env = GNUNET_MQ_msg_extra (reply,
860 xc_size,
861 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
862 reply->peer_id = msg->peer_id;
863 reply->operation_id = msg->operation_id;
864 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
865 &reply->peer_identity);
866 reply->config_size = htons ((uint16_t) c_size);
867 GNUNET_memcpy (&reply[1],
868 xconfig,
869 xc_size);
870 GNUNET_free (xconfig);
871 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
872 env);
873 GNUNET_SERVICE_client_continue (client);
874}
875
876
877/**
878 * Cleans up the Peer reconfigure context list
879 */
880void
881GST_free_prcq ()
882{
883 while (NULL != prc_head)
884 cleanup_prc (prc_head);
885}
886
887
888/**
889 * Update peer configuration
890 *
891 * @param peer the peer to update
892 * @param cfg the new configuration
893 * @return error message (freshly allocated); NULL upon success
894 */
895static char *
896update_peer_config (struct Peer *peer,
897 struct GNUNET_CONFIGURATION_Handle *cfg)
898{
899 char *emsg;
900
901 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
902 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
903 peer->details.local.cfg = cfg;
904 emsg = NULL;
905 peer->details.local.peer
906 = GNUNET_TESTING_peer_configure (GST_context->system,
907 peer->details.local.cfg,
908 peer->id,
909 NULL /* Peer id */,
910 &emsg);
911 return emsg;
912}
913
914
915/**
916 * Callback to inform whether the peer is running or stopped.
917 *
918 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
919 * @param p the respective peer whose status is being reported
920 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
921 * error
922 */
923static void
924prc_stop_cb (void *cls,
925 struct GNUNET_TESTING_Peer *p,
926 int success)
927{
928 struct PeerReconfigureContext *prc = cls;
929 struct Peer *peer;
930 char *emsg;
931
932 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
933 peer = GST_peer_list [prc->peer_id];
934 GNUNET_assert (GNUNET_NO == peer->is_remote);
935 emsg = update_peer_config (peer, prc->cfg);
936 prc->cfg = NULL;
937 prc->stopped = 1;
938 if (NULL != emsg)
939 {
940 GST_send_operation_fail_msg (prc->client,
941 prc->op_id,
942 emsg);
943 goto cleanup;
944 }
945 if (GNUNET_OK != start_peer (peer))
946 {
947 GST_send_operation_fail_msg (prc->client,
948 prc->op_id,
949 "Failed to start reconfigured peer");
950 goto cleanup;
951 }
952 GST_send_operation_success_msg (prc->client,
953 prc->op_id);
954
955cleanup:
956 cleanup_prc (prc);
957 return;
958}
959
960
961/**
962 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
963 *
964 * @param cls identification of the client
965 * @param msg the actual message
966 * @return #GNUNET_OK if @a msg is well-formed
967 */
968int
969check_peer_reconfigure (void *cls,
970 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
971{
972 return GNUNET_OK; /* checked later */
973}
974
975
976/**
977 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
978 * Should stop the peer asynchronously, destroy it and create it again with the
979 * new configuration.
980 *
981 * @param cls identification of the client
982 * @param msg the actual message
983 */
984void
985handle_peer_reconfigure (void *cls,
986 const struct
987 GNUNET_TESTBED_PeerReconfigureMessage *msg)
988{
989 struct GNUNET_SERVICE_Client *client = cls;
990 struct Peer *peer;
991 struct GNUNET_CONFIGURATION_Handle *cfg;
992 struct ForwardedOperationContext *fopc;
993 struct PeerReconfigureContext *prc;
994 char *emsg;
995 uint64_t op_id;
996 uint32_t peer_id;
997
998 peer_id = ntohl (msg->peer_id);
999 op_id = GNUNET_ntohll (msg->operation_id);
1000 if (! VALID_PEER_ID (peer_id))
1001 {
1002 GNUNET_break (0);
1003 GST_send_operation_fail_msg (client,
1004 op_id,
1005 "Peer not found");
1006 GNUNET_SERVICE_client_continue (client);
1007 return;
1008 }
1009 peer = GST_peer_list[peer_id];
1010 if (GNUNET_YES == peer->is_remote)
1011 {
1012 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1013 fopc = GNUNET_new (struct ForwardedOperationContext);
1014 fopc->client = client;
1015 fopc->operation_id = op_id;
1016 fopc->type = OP_PEER_RECONFIGURE;
1017 fopc->opc =
1018 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1019 slave->controller,
1020 fopc->operation_id,
1021 &msg->header,
1022 &
1023 GST_forwarded_operation_reply_relay,
1024 fopc);
1025 fopc->timeout_task =
1026 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1027 &GST_forwarded_operation_timeout,
1028 fopc);
1029 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1030 fopcq_tail,
1031 fopc);
1032 GNUNET_SERVICE_client_continue (client);
1033 return;
1034 }
1035 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1036 (unsigned int) peer_id);
1037 if (0 < peer->reference_cnt)
1038 {
1039 GNUNET_break (0);
1040 GST_send_operation_fail_msg (client,
1041 op_id,
1042 "Peer in use");
1043 GNUNET_SERVICE_client_continue (client);
1044 return;
1045 }
1046 if (GNUNET_YES == peer->destroy_flag)
1047 {
1048 GNUNET_break (0);
1049 GST_send_operation_fail_msg (client,
1050 op_id,
1051 "Peer is being destroyed");
1052 GNUNET_SERVICE_client_continue (client);
1053 return;
1054 }
1055 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1056 if (NULL == cfg)
1057 {
1058 GNUNET_break (0);
1059 GST_send_operation_fail_msg (client,
1060 op_id,
1061 "Compression error");
1062 GNUNET_SERVICE_client_continue (client);
1063 return;
1064 }
1065 if (GNUNET_NO == peer->details.local.is_running)
1066 {
1067 emsg = update_peer_config (peer,
1068 cfg);
1069 if (NULL != emsg)
1070 GST_send_operation_fail_msg (client,
1071 op_id,
1072 emsg);
1073 GST_send_operation_success_msg (client,
1074 op_id);
1075 GNUNET_SERVICE_client_continue (client);
1076 GNUNET_free (emsg);
1077 return;
1078 }
1079 prc = GNUNET_new (struct PeerReconfigureContext);
1080 if (GNUNET_OK !=
1081 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1082 &prc_stop_cb,
1083 prc))
1084 {
1085 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1086 "Error trying to stop peer %u asynchronously\n",
1087 peer_id));
1088 LOG (GNUNET_ERROR_TYPE_ERROR,
1089 "%s\n",
1090 emsg);
1091 GST_send_operation_fail_msg (client,
1092 op_id,
1093 emsg);
1094 GNUNET_SERVICE_client_continue (client);
1095 GNUNET_free (prc);
1096 GNUNET_free (emsg);
1097 return;
1098 }
1099 prc->cfg = cfg;
1100 prc->peer_id = peer_id;
1101 prc->op_id = op_id;
1102 prc->client = client;
1103 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1104 prc_tail,
1105 prc);
1106 GNUNET_SERVICE_client_continue (client);
1107}
1108
1109
1110/**
1111 * Frees the ManageServiceContext queue
1112 */
1113void
1114GST_free_mctxq ()
1115{
1116 while (NULL != mctx_head)
1117 cleanup_mctx (mctx_head);
1118}
1119
1120
1121/**
1122 * Returns a string interpretation of @a rs.
1123 *
1124 * @param rs the request status from ARM
1125 * @return a string interpretation of the request status
1126 */
1127static const char *
1128arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1129{
1130 switch (rs)
1131 {
1132 case GNUNET_ARM_REQUEST_SENT_OK:
1133 return _ ("Message was sent successfully");
1134
1135 case GNUNET_ARM_REQUEST_DISCONNECTED:
1136 return _ ("We disconnected from ARM before we could send a request");
1137 }
1138 return _ ("Unknown request status");
1139}
1140
1141
1142/**
1143 * Returns a string interpretation of the @a result.
1144 *
1145 * @param result the arm result
1146 * @return a string interpretation
1147 */
1148static const char *
1149arm_ret_string (enum GNUNET_ARM_Result result)
1150{
1151 switch (result)
1152 {
1153 case GNUNET_ARM_RESULT_STOPPED:
1154 return _ ("%s is stopped");
1155
1156 case GNUNET_ARM_RESULT_STARTING:
1157 return _ ("%s is starting");
1158
1159 case GNUNET_ARM_RESULT_STOPPING:
1160 return _ ("%s is stopping");
1161
1162 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1163 return _ ("%s is starting already");
1164
1165 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1166 return _ ("%s is stopping already");
1167
1168 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1169 return _ ("%s is started already");
1170
1171 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1172 return _ ("%s is stopped already");
1173
1174 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1175 return _ ("%s service is not known to ARM");
1176
1177 case GNUNET_ARM_RESULT_START_FAILED:
1178 return _ ("%s service failed to start");
1179
1180 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1181 return _ ("%s service can't be started because ARM is shutting down");
1182 }
1183 return _ ("%.s Unknown result code.");
1184}
1185
1186
1187/**
1188 * Function called in response to a start/stop request.
1189 * Will be called when request was not sent successfully,
1190 * or when a reply comes. If the request was not sent successfully,
1191 * @a rs will indicate that, and @a result will be undefined.
1192 *
1193 * @param cls ManageServiceContext
1194 * @param rs status of the request
1195 * @param result result of the operation
1196 */
1197static void
1198service_manage_result_cb (void *cls,
1199 enum GNUNET_ARM_RequestStatus rs,
1200 enum GNUNET_ARM_Result result)
1201{
1202 struct ManageServiceContext *mctx = cls;
1203 char *emsg;
1204
1205 emsg = NULL;
1206 if (GNUNET_YES == mctx->expired)
1207 return;
1208 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1209 {
1210 GNUNET_asprintf (&emsg,
1211 "Error communicating with Peer %u's ARM: %s",
1212 mctx->peer->id,
1213 arm_req_string (rs));
1214 goto ret;
1215 }
1216 if (1 == mctx->start)
1217 goto service_start_check;
1218 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1219 || (GNUNET_ARM_RESULT_STOPPING == result)
1220 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1221 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)))
1222 {
1223 /* stopping a service failed */
1224 GNUNET_asprintf (&emsg,
1225 arm_ret_string (result),
1226 mctx->service);
1227 goto ret;
1228 }
1229 /* service stopped successfully */
1230 goto ret;
1231
1232service_start_check:
1233 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1234 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1235 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)))
1236 {
1237 /* starting a service failed */
1238 GNUNET_asprintf (&emsg,
1239 arm_ret_string (result),
1240 mctx->service);
1241 goto ret;
1242 }
1243 /* service started successfully */
1244
1245ret:
1246 if (NULL != emsg)
1247 {
1248 LOG_DEBUG ("%s\n", emsg);
1249 GST_send_operation_fail_msg (mctx->client,
1250 mctx->op_id,
1251 emsg);
1252 }
1253 else
1254 GST_send_operation_success_msg (mctx->client,
1255 mctx->op_id);
1256 GNUNET_free (emsg);
1257 cleanup_mctx (mctx);
1258}
1259
1260
1261/**
1262 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1263 *
1264 * @param cls identification of client
1265 * @param msg the actual message
1266 * @return #GNUNET_OK if @a msg is well-formed
1267 */
1268int
1269check_manage_peer_service (void *cls,
1270 const struct
1271 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1272{
1273 uint16_t msize;
1274 const char*service;
1275
1276 msize = ntohs (msg->header.size);
1277 service = (const char *) &msg[1];
1278 if ('\0' != service[msize - sizeof
1279 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1280 {
1281 GNUNET_break_op (0);
1282 return GNUNET_SYSERR;
1283 }
1284 if (1 < msg->start)
1285 {
1286 GNUNET_break_op (0);
1287 return GNUNET_SYSERR;
1288 }
1289 return GNUNET_OK;
1290}
1291
1292
1293void
1294handle_manage_peer_service (void *cls,
1295 const struct
1296 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1297{
1298 struct GNUNET_SERVICE_Client *client = cls;
1299 const char*service;
1300 struct Peer *peer;
1301 char *emsg;
1302 struct GNUNET_ARM_Handle *ah;
1303 struct ManageServiceContext *mctx;
1304 struct ForwardedOperationContext *fopc;
1305 uint64_t op_id;
1306 uint32_t peer_id;
1307
1308 service = (const char *) &msg[1];
1309 peer_id = ntohl (msg->peer_id);
1310 op_id = GNUNET_ntohll (msg->operation_id);
1311 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1312 service, (unsigned int) peer_id);
1313 if ((GST_peer_list_size <= peer_id)
1314 || (NULL == (peer = GST_peer_list[peer_id])))
1315 {
1316 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1317 "with id: %u", peer_id);
1318 goto err_ret;
1319 }
1320 if (0 == strcasecmp ("arm", service))
1321 {
1322 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1323 "Use peer start/stop for that");
1324 goto err_ret;
1325 }
1326 if (GNUNET_YES == peer->is_remote)
1327 {
1328 /* Forward the destroy message to sub controller */
1329 fopc = GNUNET_new (struct ForwardedOperationContext);
1330 fopc->client = client;
1331 fopc->cls = peer;
1332 fopc->type = OP_MANAGE_SERVICE;
1333 fopc->operation_id = op_id;
1334 fopc->opc =
1335 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1336 slave->controller,
1337 fopc->operation_id,
1338 &msg->header,
1339 &
1340 GST_forwarded_operation_reply_relay,
1341 fopc);
1342 fopc->timeout_task =
1343 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1344 &GST_forwarded_operation_timeout,
1345 fopc);
1346 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1347 fopcq_tail,
1348 fopc);
1349 GNUNET_SERVICE_client_continue (client);
1350 return;
1351 }
1352 if (GNUNET_NO == peer->details.local.is_running)
1353 {
1354 emsg = GNUNET_strdup ("Peer not running\n");
1355 goto err_ret;
1356 }
1357 if ((0 != peer->reference_cnt)
1358 && ((0 == strcasecmp ("core", service))
1359 || (0 == strcasecmp ("transport", service))))
1360 {
1361 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1362 "since it is required by existing operations",
1363 service, peer_id);
1364 goto err_ret;
1365 }
1366 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1367 if (NULL == ah)
1368 {
1369 GNUNET_asprintf (&emsg,
1370 "Cannot connect to ARM service of peer with id: %u",
1371 peer_id);
1372 goto err_ret;
1373 }
1374 mctx = GNUNET_new (struct ManageServiceContext);
1375 mctx->peer = peer;
1376 peer->reference_cnt++;
1377 mctx->op_id = op_id;
1378 mctx->ah = ah;
1379 mctx->client = client;
1380 mctx->start = msg->start;
1381 mctx->service = GNUNET_strdup (service);
1382 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1383 mctx_tail,
1384 mctx);
1385 if (1 == mctx->start)
1386 GNUNET_ARM_request_service_start (mctx->ah,
1387 service,
1388 GNUNET_OS_INHERIT_STD_ERR,
1389 &service_manage_result_cb,
1390 mctx);
1391 else
1392 GNUNET_ARM_request_service_stop (mctx->ah, service,
1393 &service_manage_result_cb,
1394 mctx);
1395 GNUNET_SERVICE_client_continue (client);
1396 return;
1397
1398err_ret:
1399 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1400 GST_send_operation_fail_msg (client, op_id, emsg);
1401 GNUNET_free (emsg);
1402 GNUNET_SERVICE_client_continue (client);
1403}
1404
1405
1406/**
1407 * Stops and destroys all peers
1408 */
1409void
1410GST_destroy_peers ()
1411{
1412 struct Peer *peer;
1413 unsigned int id;
1414
1415 if (NULL == GST_peer_list)
1416 return;
1417 for (id = 0; id < GST_peer_list_size; id++)
1418 {
1419 peer = GST_peer_list[id];
1420 if (NULL == peer)
1421 continue;
1422 /* If destroy flag is set it means that this peer should have been
1423 * destroyed by a context which we destroy before */
1424 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1425 /* counter should be zero as we free all contexts before */
1426 GNUNET_break (0 == peer->reference_cnt);
1427 if ((GNUNET_NO == peer->is_remote) &&
1428 (GNUNET_YES == peer->details.local.is_running))
1429 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1430 }
1431 for (id = 0; id < GST_peer_list_size; id++)
1432 {
1433 peer = GST_peer_list[id];
1434 if (NULL == peer)
1435 continue;
1436 if (GNUNET_NO == peer->is_remote)
1437 {
1438 if (GNUNET_YES == peer->details.local.is_running)
1439 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1440 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1441 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1442 }
1443 GNUNET_free (peer);
1444 }
1445 GNUNET_free (GST_peer_list);
1446 GST_peer_list = NULL;
1447 GST_peer_list_size = 0;
1448}
1449
1450
1451/**
1452 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1453 * success reply is received from all clients and then sends the success message
1454 * to the client
1455 *
1456 * @param cls ForwardedOperationContext
1457 * @param msg the message to relay
1458 */
1459static void
1460shutdown_peers_reply_cb (void *cls,
1461 const struct GNUNET_MessageHeader *msg)
1462{
1463 struct ForwardedOperationContext *fo_ctxt = cls;
1464 struct HandlerContext_ShutdownPeers *hc;
1465
1466 hc = fo_ctxt->cls;
1467 GNUNET_assert (0 < hc->nslaves);
1468 hc->nslaves--;
1469 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1470 ntohs (msg->type))
1471 hc->timeout = GNUNET_YES;
1472 if (0 == hc->nslaves)
1473 {
1474 if (GNUNET_YES == hc->timeout)
1475 GST_send_operation_fail_msg (fo_ctxt->client,
1476 fo_ctxt->operation_id,
1477 "Timeout at a slave controller");
1478 else
1479 GST_send_operation_success_msg (fo_ctxt->client,
1480 fo_ctxt->operation_id);
1481 GNUNET_free (hc);
1482 hc = NULL;
1483 }
1484 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1485 fopcq_tail,
1486 fo_ctxt);
1487 GNUNET_free (fo_ctxt);
1488}
1489
1490
1491/**
1492 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1493 *
1494 * @param cls identification of the client
1495 * @param msg the actual message
1496 */
1497void
1498handle_shutdown_peers (void *cls,
1499 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1500{
1501 struct GNUNET_SERVICE_Client *client = cls;
1502 struct HandlerContext_ShutdownPeers *hc;
1503 struct Slave *slave;
1504 struct ForwardedOperationContext *fo_ctxt;
1505 uint64_t op_id;
1506 unsigned int cnt;
1507
1508 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1509 /* Stop and destroy all peers */
1510 GST_free_mctxq ();
1511 GST_free_occq ();
1512 GST_free_roccq ();
1513 GST_clear_fopcq ();
1514 /* Forward to all slaves which we have started */
1515 op_id = GNUNET_ntohll (msg->operation_id);
1516 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1517 /* FIXME: have a better implementation where we track which slaves are
1518 started by this controller */
1519 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1520 {
1521 slave = GST_slave_list[cnt];
1522 if (NULL == slave)
1523 continue;
1524 if (NULL == slave->controller_proc) /* We didn't start the slave */
1525 continue;
1526 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1527 hc->nslaves++;
1528 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1529 fo_ctxt->client = client;
1530 fo_ctxt->operation_id = op_id;
1531 fo_ctxt->cls = hc;
1532 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1533 fo_ctxt->opc =
1534 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1535 fo_ctxt->operation_id,
1536 &msg->header,
1537 shutdown_peers_reply_cb,
1538 fo_ctxt);
1539 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1540 fopcq_tail,
1541 fo_ctxt);
1542 }
1543 LOG_DEBUG ("Shutting down peers\n");
1544 GST_destroy_peers ();
1545 if (0 == hc->nslaves)
1546 {
1547 GST_send_operation_success_msg (client,
1548 op_id);
1549 GNUNET_free (hc);
1550 }
1551 GNUNET_SERVICE_client_continue (client);
1552}