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