2 This file is part of GNUnet.
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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>
28 #include "gnunet-service-testbed.h"
29 #include "gnunet_arm_service.h"
34 * A list of peers we know about
36 struct Peer **GST_peer_list;
39 * The current number of peers running locally under this controller
41 unsigned int GST_num_local_peers;
45 * Context information to manage peers' services
47 struct ManageServiceContext
52 struct ManageServiceContext *next;
57 struct ManageServiceContext *prev;
60 * The ARM handle of the peer
62 struct GNUNET_ARM_Handle *ah;
65 * peer whose service has to be managed
70 * The client which requested to manage the peer's service
72 struct GNUNET_SERVICE_Client *client;
75 * Name of the service.
80 * The operation id of the associated request
85 * 1 if the service at the peer has to be started; 0 if it has to be stopped
90 * Is this context expired? Do not work on this context if it is set to
98 * Context information for peer re-configure operations
100 struct PeerReconfigureContext
103 * DLL next for inclusoin in peer reconfigure operations list
105 struct PeerReconfigureContext *next;
110 struct PeerReconfigureContext *prev;
113 * The client which gave this operation to us
115 struct GNUNET_SERVICE_Client *client;
118 * The configuration handle to use as the new template
120 struct GNUNET_CONFIGURATION_Handle *cfg;
123 * The id of the operation
128 * The id of the peer which has to be reconfigured
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
141 * The DLL head for the peer reconfigure list
143 static struct PeerReconfigureContext *prc_head;
146 * The DLL tail for the peer reconfigure list
148 static struct PeerReconfigureContext *prc_tail;
153 * DLL head for queue of manage service requests
155 static struct ManageServiceContext *mctx_head;
158 * DLL tail for queue of manage service requests
160 static struct ManageServiceContext *mctx_tail;
164 * Adds a peer to the peer array
166 * @param peer the peer to add
169 peer_list_add (struct Peer *peer)
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++;
181 * Removes a the give peer from the peer array
183 * @param peer the peer to be removed
186 peer_list_remove (struct Peer *peer)
188 unsigned int orig_size;
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)
197 for (id = GST_peer_list_size - 1;
198 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
200 if (NULL != GST_peer_list[id])
202 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
204 GST_peer_list_size -= LIST_GROW_STEP;
206 if (orig_size == GST_peer_list_size)
209 GNUNET_realloc (GST_peer_list,
210 sizeof(struct Peer *) * GST_peer_list_size);
215 * The task to be executed if the forwarded peer create operation has been
218 * @param cls the FowardedOperationContext
221 peer_create_forward_timeout (void *cls)
223 struct ForwardedOperationContext *fopc = cls;
225 GNUNET_free (fopc->cls);
226 GST_forwarded_operation_timeout (fopc);
231 * Callback to be called when forwarded peer create operation is successfull. We
232 * have to relay the reply msg back to the client
234 * @param cls ForwardedOperationContext
235 * @param msg the peer create success message
238 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
240 struct ForwardedOperationContext *fopc = cls;
241 struct Peer *remote_peer;
243 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
245 GNUNET_assert (NULL != fopc->cls);
246 remote_peer = fopc->cls;
247 peer_list_add (remote_peer);
249 GST_forwarded_operation_reply_relay (fopc,
255 * Function to destroy a peer
257 * @param peer the peer structure to destroy
260 GST_destroy_peer (struct Peer *peer)
262 GNUNET_break (0 == peer->reference_cnt);
263 if (GNUNET_YES == peer->is_remote)
265 peer_list_remove (peer);
269 if (GNUNET_YES == peer->details.local.is_running)
271 GNUNET_TESTING_peer_stop (peer->details.local.peer);
272 peer->details.local.is_running = GNUNET_NO;
274 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
275 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
276 peer_list_remove (peer);
282 * Cleanup the context information created for managing a peer's service
284 * @param mctx the ManageServiceContext
287 cleanup_mctx (struct ManageServiceContext *mctx)
289 mctx->expired = GNUNET_YES;
290 GNUNET_CONTAINER_DLL_remove (mctx_head,
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);
307 * @param peer the peer to stop
308 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
311 stop_peer (struct Peer *peer)
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;
322 * Cleans up the given PeerReconfigureContext
324 * @param prc the PeerReconfigureContext
327 cleanup_prc (struct PeerReconfigureContext *prc)
331 if (VALID_PEER_ID (prc->peer_id))
333 peer = GST_peer_list [prc->peer_id];
334 if (1 != prc->stopped)
336 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
337 stop_peer (peer); /* Stop the peer synchronously */
340 if (NULL != prc->cfg)
341 GNUNET_CONFIGURATION_destroy (prc->cfg);
342 GNUNET_CONTAINER_DLL_remove (prc_head,
350 * Notify peers subsystem that @a client disconnected.
352 * @param client the client that disconnected
355 GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
357 struct ForwardedOperationContext *fopc;
358 struct ForwardedOperationContext *fopcn;
359 struct ManageServiceContext *mctx;
360 struct ManageServiceContext *mctxn;
361 struct PeerReconfigureContext *prc;
362 struct PeerReconfigureContext *prcn;
364 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
367 if (client == fopc->client)
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);
375 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
378 if (client == mctx->client)
381 for (prc = prc_head; NULL != prc; prc = prcn)
384 if (client == prc->client)
391 * Callback to be called when forwarded peer destroy operation is successfull. We
392 * have to relay the reply msg back to the client
394 * @param cls ForwardedOperationContext
395 * @param msg the peer create success message
398 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
400 struct ForwardedOperationContext *fopc = cls;
401 struct Peer *remote_peer;
403 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
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);
412 GST_forwarded_operation_reply_relay (fopc,
418 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
420 * @param cls identification of the client
421 * @param msg the actual message
422 * @return #GNUNET_OK if @a msg is well-formed
425 check_peer_create (void *cls,
426 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
428 return GNUNET_OK; /* checked later */
433 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
435 * @param cls identification of the client
436 * @param msg the actual message
439 handle_peer_create (void *cls,
440 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
442 struct GNUNET_SERVICE_Client *client = cls;
443 struct GNUNET_MQ_Envelope *env;
444 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
445 struct GNUNET_CONFIGURATION_Handle *cfg;
446 struct ForwardedOperationContext *fo_ctxt;
453 host_id = ntohl (msg->host_id);
454 peer_id = ntohl (msg->peer_id);
455 if (VALID_PEER_ID (peer_id))
457 (void) GNUNET_asprintf (&emsg,
458 "Peer with ID %u already exists",
460 GST_send_operation_fail_msg (client,
461 GNUNET_ntohll (msg->operation_id),
464 GNUNET_SERVICE_client_continue (client);
467 if (UINT32_MAX == peer_id)
469 GST_send_operation_fail_msg (client,
470 GNUNET_ntohll (msg->operation_id),
471 "Cannot create peer with given ID");
472 GNUNET_SERVICE_client_continue (client);
475 if (host_id == GST_context->host_id)
477 /* We are responsible for this peer */
478 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
482 GNUNET_SERVICE_client_drop (client);
485 GNUNET_CONFIGURATION_set_value_number (cfg,
488 (unsigned long long) peer_id);
490 GNUNET_CONFIGURATION_set_value_number (cfg,
493 (unsigned long long) peer_id);
494 peer = GNUNET_new (struct Peer);
495 peer->is_remote = GNUNET_NO;
496 peer->details.local.cfg = cfg;
498 LOG_DEBUG ("Creating peer with id: %u\n",
499 (unsigned int) peer->id);
500 peer->details.local.peer =
501 GNUNET_TESTING_peer_configure (GST_context->system,
502 peer->details.local.cfg, peer->id,
505 if (NULL == peer->details.local.peer)
507 LOG (GNUNET_ERROR_TYPE_WARNING,
508 "Configuring peer failed: %s\n",
513 GNUNET_SERVICE_client_drop (client);
516 peer->details.local.is_running = GNUNET_NO;
517 peer_list_add (peer);
518 env = GNUNET_MQ_msg (reply,
519 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
520 reply->peer_id = msg->peer_id;
521 reply->operation_id = msg->operation_id;
522 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
524 GNUNET_SERVICE_client_continue (client);
528 /* Forward peer create request */
529 route = GST_find_dest_route (host_id);
533 GNUNET_SERVICE_client_continue (client); // ?
536 peer = GNUNET_new (struct Peer);
537 peer->is_remote = GNUNET_YES;
539 peer->details.remote.slave = GST_slave_list[route->dest];
540 peer->details.remote.remote_host_id = host_id;
541 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
542 fo_ctxt->client = client;
543 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
545 fo_ctxt->type = OP_PEER_CREATE;
547 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
548 [route->dest]->controller,
549 fo_ctxt->operation_id,
551 &peer_create_success_cb,
553 fo_ctxt->timeout_task =
554 GNUNET_SCHEDULER_add_delayed (GST_timeout,
555 &peer_create_forward_timeout,
557 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
560 GNUNET_SERVICE_client_continue (client);
565 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
567 * @param cls identification of the client
568 * @param msg the actual message
571 handle_peer_destroy (void *cls,
572 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
574 struct GNUNET_SERVICE_Client *client = cls;
575 struct ForwardedOperationContext *fopc;
579 peer_id = ntohl (msg->peer_id);
580 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %llu\n",
581 (unsigned int) peer_id,
582 (unsigned long long) GNUNET_ntohll (msg->operation_id));
583 if (! VALID_PEER_ID (peer_id))
585 LOG (GNUNET_ERROR_TYPE_ERROR,
586 "Asked to destroy a non existent peer with id: %u\n", peer_id);
587 GST_send_operation_fail_msg (client,
588 GNUNET_ntohll (msg->operation_id),
589 "Peer doesn't exist");
590 GNUNET_SERVICE_client_continue (client);
593 peer = GST_peer_list[peer_id];
594 if (GNUNET_YES == peer->is_remote)
596 /* Forward the destory message to sub controller */
597 fopc = GNUNET_new (struct ForwardedOperationContext);
598 fopc->client = client;
600 fopc->type = OP_PEER_DESTROY;
601 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
603 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
607 &peer_destroy_success_cb,
610 GNUNET_SCHEDULER_add_delayed (GST_timeout,
611 &GST_forwarded_operation_timeout,
613 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
616 GNUNET_SERVICE_client_continue (client);
619 peer->destroy_flag = GNUNET_YES;
620 if (0 == peer->reference_cnt)
621 GST_destroy_peer (peer);
623 LOG (GNUNET_ERROR_TYPE_DEBUG,
624 "Delaying peer destroy as peer is currently in use\n");
625 GST_send_operation_success_msg (client,
626 GNUNET_ntohll (msg->operation_id));
627 GNUNET_SERVICE_client_continue (client);
634 * @param peer the peer to start
635 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
638 start_peer (struct Peer *peer)
640 GNUNET_assert (GNUNET_NO == peer->is_remote);
641 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
642 return GNUNET_SYSERR;
643 peer->details.local.is_running = GNUNET_YES;
649 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
651 * @param cls identification of the client
652 * @param msg the actual message
655 handle_peer_start (void *cls,
656 const struct GNUNET_TESTBED_PeerStartMessage *msg)
658 struct GNUNET_SERVICE_Client *client = cls;
659 struct GNUNET_MQ_Envelope *env;
660 struct GNUNET_TESTBED_PeerEventMessage *reply;
661 struct ForwardedOperationContext *fopc;
665 peer_id = ntohl (msg->peer_id);
666 if (! VALID_PEER_ID (peer_id))
669 LOG (GNUNET_ERROR_TYPE_ERROR,
670 "Asked to start a non existent peer with id: %u\n",
672 GNUNET_SERVICE_client_continue (client);
675 peer = GST_peer_list[peer_id];
676 if (GNUNET_YES == peer->is_remote)
678 fopc = GNUNET_new (struct ForwardedOperationContext);
679 fopc->client = client;
680 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
681 fopc->type = OP_PEER_START;
683 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
685 fopc->operation_id, &msg->header,
687 GST_forwarded_operation_reply_relay,
690 GNUNET_SCHEDULER_add_delayed (GST_timeout,
691 &GST_forwarded_operation_timeout,
693 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
696 GNUNET_SERVICE_client_continue (client);
699 if (GNUNET_OK != start_peer (peer))
701 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
703 GNUNET_SERVICE_client_continue (client);
706 env = GNUNET_MQ_msg (reply,
707 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
708 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
709 reply->host_id = htonl (GST_context->host_id);
710 reply->peer_id = msg->peer_id;
711 reply->operation_id = msg->operation_id;
712 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
714 GNUNET_SERVICE_client_continue (client);
719 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
721 * @param cls identification of the client
722 * @param msg the actual message
725 handle_peer_stop (void *cls,
726 const struct GNUNET_TESTBED_PeerStopMessage *msg)
728 struct GNUNET_SERVICE_Client *client = cls;
729 struct GNUNET_MQ_Envelope *env;
730 struct GNUNET_TESTBED_PeerEventMessage *reply;
731 struct ForwardedOperationContext *fopc;
735 peer_id = ntohl (msg->peer_id);
736 LOG (GNUNET_ERROR_TYPE_DEBUG,
737 "Received PEER_STOP for peer %u\n",
738 (unsigned int) peer_id);
739 if (! VALID_PEER_ID (peer_id))
741 GST_send_operation_fail_msg (client,
742 GNUNET_ntohll (msg->operation_id),
744 GNUNET_SERVICE_client_continue (client);
747 peer = GST_peer_list[peer_id];
748 if (GNUNET_YES == peer->is_remote)
750 LOG (GNUNET_ERROR_TYPE_DEBUG,
751 "Forwarding PEER_STOP for peer %u\n",
752 (unsigned int) peer_id);
753 fopc = GNUNET_new (struct ForwardedOperationContext);
754 fopc->client = client;
755 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
756 fopc->type = OP_PEER_STOP;
758 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
763 GST_forwarded_operation_reply_relay,
766 GNUNET_SCHEDULER_add_delayed (GST_timeout,
767 &GST_forwarded_operation_timeout,
769 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
772 GNUNET_SERVICE_client_continue (client);
775 if (GNUNET_OK != stop_peer (peer))
777 LOG (GNUNET_ERROR_TYPE_WARNING,
778 "Stopping peer %u failed\n",
779 (unsigned int) peer_id);
780 GST_send_operation_fail_msg (client,
781 GNUNET_ntohll (msg->operation_id),
783 GNUNET_SERVICE_client_continue (client);
786 LOG (GNUNET_ERROR_TYPE_DEBUG,
787 "Peer %u successfully stopped\n",
788 (unsigned int) peer_id);
789 env = GNUNET_MQ_msg (reply,
790 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
791 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
792 reply->host_id = htonl (GST_context->host_id);
793 reply->peer_id = msg->peer_id;
794 reply->operation_id = msg->operation_id;
795 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
797 GNUNET_SERVICE_client_continue (client);
798 GNUNET_TESTING_peer_wait (peer->details.local.peer);
803 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
805 * @param cls identification of the client
806 * @param msg the actual message
809 handle_peer_get_config (void *cls,
811 GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
813 struct GNUNET_SERVICE_Client *client = cls;
814 struct GNUNET_MQ_Envelope *env;
815 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
816 struct ForwardedOperationContext *fopc;
824 peer_id = ntohl (msg->peer_id);
825 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
826 (unsigned int) peer_id);
827 if (! VALID_PEER_ID (peer_id))
829 GST_send_operation_fail_msg (client,
830 GNUNET_ntohll (msg->operation_id),
832 GNUNET_SERVICE_client_continue (client);
835 peer = GST_peer_list[peer_id];
836 if (GNUNET_YES == peer->is_remote)
838 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
839 (unsigned int) peer_id);
840 fopc = GNUNET_new (struct ForwardedOperationContext);
841 fopc->client = client;
842 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
843 fopc->type = OP_PEER_INFO;
845 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
850 GST_forwarded_operation_reply_relay,
853 GNUNET_SCHEDULER_add_delayed (GST_timeout,
854 &GST_forwarded_operation_timeout,
856 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
859 GNUNET_SERVICE_client_continue (client);
862 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
865 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
867 xc_size = GNUNET_TESTBED_compress_config_ (config,
870 GNUNET_free (config);
871 env = GNUNET_MQ_msg_extra (reply,
873 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
874 reply->peer_id = msg->peer_id;
875 reply->operation_id = msg->operation_id;
876 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
877 &reply->peer_identity);
878 reply->config_size = htons ((uint16_t) c_size);
879 GNUNET_memcpy (&reply[1],
882 GNUNET_free (xconfig);
883 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
885 GNUNET_SERVICE_client_continue (client);
890 * Cleans up the Peer reconfigure context list
895 while (NULL != prc_head)
896 cleanup_prc (prc_head);
901 * Update peer configuration
903 * @param peer the peer to update
904 * @param cfg the new configuration
905 * @return error message (freshly allocated); NULL upon success
908 update_peer_config (struct Peer *peer,
909 struct GNUNET_CONFIGURATION_Handle *cfg)
913 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
914 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
915 peer->details.local.cfg = cfg;
917 peer->details.local.peer
918 = GNUNET_TESTING_peer_configure (GST_context->system,
919 peer->details.local.cfg,
928 * Callback to inform whether the peer is running or stopped.
930 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
931 * @param p the respective peer whose status is being reported
932 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
936 prc_stop_cb (void *cls,
937 struct GNUNET_TESTING_Peer *p,
940 struct PeerReconfigureContext *prc = cls;
944 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
945 peer = GST_peer_list [prc->peer_id];
946 GNUNET_assert (GNUNET_NO == peer->is_remote);
947 emsg = update_peer_config (peer, prc->cfg);
952 GST_send_operation_fail_msg (prc->client,
957 if (GNUNET_OK != start_peer (peer))
959 GST_send_operation_fail_msg (prc->client,
961 "Failed to start reconfigured peer");
964 GST_send_operation_success_msg (prc->client,
974 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
976 * @param cls identification of the client
977 * @param msg the actual message
978 * @return #GNUNET_OK if @a msg is well-formed
981 check_peer_reconfigure (void *cls,
982 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
984 return GNUNET_OK; /* checked later */
989 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
990 * Should stop the peer asyncronously, destroy it and create it again with the
993 * @param cls identification of the client
994 * @param msg the actual message
997 handle_peer_reconfigure (void *cls,
999 GNUNET_TESTBED_PeerReconfigureMessage *msg)
1001 struct GNUNET_SERVICE_Client *client = cls;
1003 struct GNUNET_CONFIGURATION_Handle *cfg;
1004 struct ForwardedOperationContext *fopc;
1005 struct PeerReconfigureContext *prc;
1010 peer_id = ntohl (msg->peer_id);
1011 op_id = GNUNET_ntohll (msg->operation_id);
1012 if (! VALID_PEER_ID (peer_id))
1015 GST_send_operation_fail_msg (client,
1018 GNUNET_SERVICE_client_continue (client);
1021 peer = GST_peer_list[peer_id];
1022 if (GNUNET_YES == peer->is_remote)
1024 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1025 fopc = GNUNET_new (struct ForwardedOperationContext);
1026 fopc->client = client;
1027 fopc->operation_id = op_id;
1028 fopc->type = OP_PEER_RECONFIGURE;
1030 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1035 GST_forwarded_operation_reply_relay,
1037 fopc->timeout_task =
1038 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1039 &GST_forwarded_operation_timeout,
1041 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1044 GNUNET_SERVICE_client_continue (client);
1047 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1048 (unsigned int) peer_id);
1049 if (0 < peer->reference_cnt)
1052 GST_send_operation_fail_msg (client,
1055 GNUNET_SERVICE_client_continue (client);
1058 if (GNUNET_YES == peer->destroy_flag)
1061 GST_send_operation_fail_msg (client,
1063 "Peer is being destroyed");
1064 GNUNET_SERVICE_client_continue (client);
1067 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1071 GST_send_operation_fail_msg (client,
1073 "Compression error");
1074 GNUNET_SERVICE_client_continue (client);
1077 if (GNUNET_NO == peer->details.local.is_running)
1079 emsg = update_peer_config (peer,
1082 GST_send_operation_fail_msg (client,
1085 GST_send_operation_success_msg (client,
1087 GNUNET_SERVICE_client_continue (client);
1088 GNUNET_free_non_null (emsg);
1091 prc = GNUNET_new (struct PeerReconfigureContext);
1093 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1097 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1098 "Error trying to stop peer %u asynchronously\n",
1100 LOG (GNUNET_ERROR_TYPE_ERROR,
1103 GST_send_operation_fail_msg (client,
1106 GNUNET_SERVICE_client_continue (client);
1112 prc->peer_id = peer_id;
1114 prc->client = client;
1115 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1118 GNUNET_SERVICE_client_continue (client);
1123 * Frees the ManageServiceContext queue
1128 while (NULL != mctx_head)
1129 cleanup_mctx (mctx_head);
1134 * Returns a string interpretation of @a rs.
1136 * @param rs the request status from ARM
1137 * @return a string interpretation of the request status
1140 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1144 case GNUNET_ARM_REQUEST_SENT_OK:
1145 return _ ("Message was sent successfully");
1147 case GNUNET_ARM_REQUEST_DISCONNECTED:
1148 return _ ("We disconnected from ARM before we could send a request");
1150 return _ ("Unknown request status");
1155 * Returns a string interpretation of the @a result.
1157 * @param result the arm result
1158 * @return a string interpretation
1161 arm_ret_string (enum GNUNET_ARM_Result result)
1165 case GNUNET_ARM_RESULT_STOPPED:
1166 return _ ("%s is stopped");
1168 case GNUNET_ARM_RESULT_STARTING:
1169 return _ ("%s is starting");
1171 case GNUNET_ARM_RESULT_STOPPING:
1172 return _ ("%s is stopping");
1174 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1175 return _ ("%s is starting already");
1177 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1178 return _ ("%s is stopping already");
1180 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1181 return _ ("%s is started already");
1183 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1184 return _ ("%s is stopped already");
1186 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1187 return _ ("%s service is not known to ARM");
1189 case GNUNET_ARM_RESULT_START_FAILED:
1190 return _ ("%s service failed to start");
1192 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1193 return _ ("%s service can't be started because ARM is shutting down");
1195 return _ ("%.s Unknown result code.");
1200 * Function called in response to a start/stop request.
1201 * Will be called when request was not sent successfully,
1202 * or when a reply comes. If the request was not sent successfully,
1203 * @a rs will indicate that, and @a result will be undefined.
1205 * @param cls ManageServiceContext
1206 * @param rs status of the request
1207 * @param result result of the operation
1210 service_manage_result_cb (void *cls,
1211 enum GNUNET_ARM_RequestStatus rs,
1212 enum GNUNET_ARM_Result result)
1214 struct ManageServiceContext *mctx = cls;
1218 if (GNUNET_YES == mctx->expired)
1220 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1222 GNUNET_asprintf (&emsg,
1223 "Error communicating with Peer %u's ARM: %s",
1225 arm_req_string (rs));
1228 if (1 == mctx->start)
1229 goto service_start_check;
1230 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1231 || (GNUNET_ARM_RESULT_STOPPING == result)
1232 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1233 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)))
1235 /* stopping a service failed */
1236 GNUNET_asprintf (&emsg,
1237 arm_ret_string (result),
1241 /* service stopped successfully */
1244 service_start_check:
1245 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1246 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1247 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)))
1249 /* starting a service failed */
1250 GNUNET_asprintf (&emsg,
1251 arm_ret_string (result),
1255 /* service started successfully */
1260 LOG_DEBUG ("%s\n", emsg);
1261 GST_send_operation_fail_msg (mctx->client,
1266 GST_send_operation_success_msg (mctx->client,
1268 GNUNET_free_non_null (emsg);
1269 cleanup_mctx (mctx);
1274 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1276 * @param cls identification of client
1277 * @param msg the actual message
1278 * @return #GNUNET_OK if @a msg is well-formed
1281 check_manage_peer_service (void *cls,
1283 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1288 msize = ntohs (msg->header.size);
1289 service = (const char *) &msg[1];
1290 if ('\0' != service[msize - sizeof
1291 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1293 GNUNET_break_op (0);
1294 return GNUNET_SYSERR;
1298 GNUNET_break_op (0);
1299 return GNUNET_SYSERR;
1306 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1308 * @param cls identification of client
1309 * @param msg the actual message
1312 handle_manage_peer_service (void *cls,
1314 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1316 struct GNUNET_SERVICE_Client *client = cls;
1320 struct GNUNET_ARM_Handle *ah;
1321 struct ManageServiceContext *mctx;
1322 struct ForwardedOperationContext *fopc;
1326 service = (const char *) &msg[1];
1327 peer_id = ntohl (msg->peer_id);
1328 op_id = GNUNET_ntohll (msg->operation_id);
1329 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1330 service, (unsigned int) peer_id);
1331 if ((GST_peer_list_size <= peer_id)
1332 || (NULL == (peer = GST_peer_list[peer_id])))
1334 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1335 "with id: %u", peer_id);
1338 if (0 == strcasecmp ("arm", service))
1340 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1341 "Use peer start/stop for that");
1344 if (GNUNET_YES == peer->is_remote)
1346 /* Forward the destory message to sub controller */
1347 fopc = GNUNET_new (struct ForwardedOperationContext);
1348 fopc->client = client;
1350 fopc->type = OP_MANAGE_SERVICE;
1351 fopc->operation_id = op_id;
1353 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1358 GST_forwarded_operation_reply_relay,
1360 fopc->timeout_task =
1361 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1362 &GST_forwarded_operation_timeout,
1364 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1367 GNUNET_SERVICE_client_continue (client);
1370 if (GNUNET_NO == peer->details.local.is_running)
1372 emsg = GNUNET_strdup ("Peer not running\n");
1375 if ((0 != peer->reference_cnt)
1376 && ((0 == strcasecmp ("core", service))
1377 || (0 == strcasecmp ("transport", service))))
1379 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1380 "since it is required by existing operations",
1384 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1387 GNUNET_asprintf (&emsg,
1388 "Cannot connect to ARM service of peer with id: %u",
1392 mctx = GNUNET_new (struct ManageServiceContext);
1394 peer->reference_cnt++;
1395 mctx->op_id = op_id;
1397 mctx->client = client;
1398 mctx->start = msg->start;
1399 mctx->service = GNUNET_strdup (service);
1400 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1403 if (1 == mctx->start)
1404 GNUNET_ARM_request_service_start (mctx->ah,
1406 GNUNET_OS_INHERIT_STD_ERR,
1407 &service_manage_result_cb,
1410 GNUNET_ARM_request_service_stop (mctx->ah, service,
1411 &service_manage_result_cb,
1413 GNUNET_SERVICE_client_continue (client);
1417 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1418 GST_send_operation_fail_msg (client, op_id, emsg);
1420 GNUNET_SERVICE_client_continue (client);
1425 * Stops and destroys all peers
1428 GST_destroy_peers ()
1433 if (NULL == GST_peer_list)
1435 for (id = 0; id < GST_peer_list_size; id++)
1437 peer = GST_peer_list[id];
1440 /* If destroy flag is set it means that this peer should have been
1441 * destroyed by a context which we destroy before */
1442 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1443 /* counter should be zero as we free all contexts before */
1444 GNUNET_break (0 == peer->reference_cnt);
1445 if ((GNUNET_NO == peer->is_remote) &&
1446 (GNUNET_YES == peer->details.local.is_running))
1447 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1449 for (id = 0; id < GST_peer_list_size; id++)
1451 peer = GST_peer_list[id];
1454 if (GNUNET_NO == peer->is_remote)
1456 if (GNUNET_YES == peer->details.local.is_running)
1457 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1458 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1459 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1463 GNUNET_free_non_null (GST_peer_list);
1464 GST_peer_list = NULL;
1465 GST_peer_list_size = 0;
1470 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1471 * success reply is received from all clients and then sends the success message
1474 * @param cls ForwardedOperationContext
1475 * @param msg the message to relay
1478 shutdown_peers_reply_cb (void *cls,
1479 const struct GNUNET_MessageHeader *msg)
1481 struct ForwardedOperationContext *fo_ctxt = cls;
1482 struct HandlerContext_ShutdownPeers *hc;
1485 GNUNET_assert (0 < hc->nslaves);
1487 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1489 hc->timeout = GNUNET_YES;
1490 if (0 == hc->nslaves)
1492 if (GNUNET_YES == hc->timeout)
1493 GST_send_operation_fail_msg (fo_ctxt->client,
1494 fo_ctxt->operation_id,
1495 "Timeout at a slave controller");
1497 GST_send_operation_success_msg (fo_ctxt->client,
1498 fo_ctxt->operation_id);
1502 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1505 GNUNET_free (fo_ctxt);
1510 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1512 * @param cls identification of the client
1513 * @param msg the actual message
1516 handle_shutdown_peers (void *cls,
1517 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1519 struct GNUNET_SERVICE_Client *client = cls;
1520 struct HandlerContext_ShutdownPeers *hc;
1521 struct Slave *slave;
1522 struct ForwardedOperationContext *fo_ctxt;
1526 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1527 /* Stop and destroy all peers */
1532 /* Forward to all slaves which we have started */
1533 op_id = GNUNET_ntohll (msg->operation_id);
1534 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1535 /* FIXME: have a better implementation where we track which slaves are
1536 started by this controller */
1537 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1539 slave = GST_slave_list[cnt];
1542 if (NULL == slave->controller_proc) /* We didn't start the slave */
1544 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1546 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1547 fo_ctxt->client = client;
1548 fo_ctxt->operation_id = op_id;
1550 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1552 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1553 fo_ctxt->operation_id,
1555 shutdown_peers_reply_cb,
1557 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1561 LOG_DEBUG ("Shutting down peers\n");
1562 GST_destroy_peers ();
1563 if (0 == hc->nslaves)
1565 GST_send_operation_success_msg (client,
1569 GNUNET_SERVICE_client_continue (client);