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;
152 * DLL head for queue of manage service requests
154 static struct ManageServiceContext *mctx_head;
157 * DLL tail for queue of manage service requests
159 static struct ManageServiceContext *mctx_tail;
163 * Adds a peer to the peer array
165 * @param peer the peer to add
168 peer_list_add (struct Peer *peer)
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++;
180 * Removes a the give peer from the peer array
182 * @param peer the peer to be removed
185 peer_list_remove (struct Peer *peer)
187 unsigned int orig_size;
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)
196 for (id = GST_peer_list_size - 1;
197 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
199 if (NULL != GST_peer_list[id])
201 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
203 GST_peer_list_size -= LIST_GROW_STEP;
205 if (orig_size == GST_peer_list_size)
208 GNUNET_realloc (GST_peer_list,
209 sizeof(struct Peer *) * GST_peer_list_size);
214 * The task to be executed if the forwarded peer create operation has been
217 * @param cls the FowardedOperationContext
220 peer_create_forward_timeout (void *cls)
222 struct ForwardedOperationContext *fopc = cls;
224 GNUNET_free (fopc->cls);
225 GST_forwarded_operation_timeout (fopc);
230 * Callback to be called when forwarded peer create operation is successfull. We
231 * have to relay the reply msg back to the client
233 * @param cls ForwardedOperationContext
234 * @param msg the peer create success message
237 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
239 struct ForwardedOperationContext *fopc = cls;
240 struct Peer *remote_peer;
242 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
244 GNUNET_assert (NULL != fopc->cls);
245 remote_peer = fopc->cls;
246 peer_list_add (remote_peer);
248 GST_forwarded_operation_reply_relay (fopc,
254 * Function to destroy a peer
256 * @param peer the peer structure to destroy
259 GST_destroy_peer (struct Peer *peer)
261 GNUNET_break (0 == peer->reference_cnt);
262 if (GNUNET_YES == peer->is_remote)
264 peer_list_remove (peer);
268 if (GNUNET_YES == peer->details.local.is_running)
270 GNUNET_TESTING_peer_stop (peer->details.local.peer);
271 peer->details.local.is_running = GNUNET_NO;
273 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
274 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
275 peer_list_remove (peer);
281 * Cleanup the context information created for managing a peer's service
283 * @param mctx the ManageServiceContext
286 cleanup_mctx (struct ManageServiceContext *mctx)
288 mctx->expired = GNUNET_YES;
289 GNUNET_CONTAINER_DLL_remove (mctx_head,
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);
306 * @param peer the peer to stop
307 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
310 stop_peer (struct Peer *peer)
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;
321 * Cleans up the given PeerReconfigureContext
323 * @param prc the PeerReconfigureContext
326 cleanup_prc (struct PeerReconfigureContext *prc)
330 if (VALID_PEER_ID (prc->peer_id))
332 peer = GST_peer_list [prc->peer_id];
333 if (1 != prc->stopped)
335 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
336 stop_peer (peer); /* Stop the peer synchronously */
339 if (NULL != prc->cfg)
340 GNUNET_CONFIGURATION_destroy (prc->cfg);
341 GNUNET_CONTAINER_DLL_remove (prc_head,
349 * Notify peers subsystem that @a client disconnected.
351 * @param client the client that disconnected
354 GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
356 struct ForwardedOperationContext *fopc;
357 struct ForwardedOperationContext *fopcn;
358 struct ManageServiceContext *mctx;
359 struct ManageServiceContext *mctxn;
360 struct PeerReconfigureContext *prc;
361 struct PeerReconfigureContext *prcn;
363 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
366 if (client == fopc->client)
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);
374 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
377 if (client == mctx->client)
380 for (prc = prc_head; NULL != prc; prc = prcn)
383 if (client == prc->client)
390 * Callback to be called when forwarded peer destroy operation is successfull. We
391 * have to relay the reply msg back to the client
393 * @param cls ForwardedOperationContext
394 * @param msg the peer create success message
397 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
399 struct ForwardedOperationContext *fopc = cls;
400 struct Peer *remote_peer;
402 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
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);
411 GST_forwarded_operation_reply_relay (fopc,
417 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
419 * @param cls identification of the client
420 * @param msg the actual message
421 * @return #GNUNET_OK if @a msg is well-formed
424 check_peer_create (void *cls,
425 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
427 return GNUNET_OK; /* checked later */
432 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
434 * @param cls identification of the client
435 * @param msg the actual message
438 handle_peer_create (void *cls,
439 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
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;
452 host_id = ntohl (msg->host_id);
453 peer_id = ntohl (msg->peer_id);
454 if (VALID_PEER_ID (peer_id))
456 (void) GNUNET_asprintf (&emsg,
457 "Peer with ID %u already exists",
459 GST_send_operation_fail_msg (client,
460 GNUNET_ntohll (msg->operation_id),
463 GNUNET_SERVICE_client_continue (client);
466 if (UINT32_MAX == peer_id)
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);
474 if (host_id == GST_context->host_id)
476 /* We are responsible for this peer */
477 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
481 GNUNET_SERVICE_client_drop (client);
484 GNUNET_CONFIGURATION_set_value_number (cfg,
487 (unsigned long long) peer_id);
489 GNUNET_CONFIGURATION_set_value_number (cfg,
492 (unsigned long long) peer_id);
493 peer = GNUNET_new (struct Peer);
494 peer->is_remote = GNUNET_NO;
495 peer->details.local.cfg = cfg;
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,
504 if (NULL == peer->details.local.peer)
506 LOG (GNUNET_ERROR_TYPE_WARNING,
507 "Configuring peer failed: %s\n",
512 GNUNET_SERVICE_client_drop (client);
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),
523 GNUNET_SERVICE_client_continue (client);
527 /* Forward peer create request */
528 route = GST_find_dest_route (host_id);
532 GNUNET_SERVICE_client_continue (client); // ?
535 peer = GNUNET_new (struct Peer);
536 peer->is_remote = GNUNET_YES;
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);
544 fo_ctxt->type = OP_PEER_CREATE;
546 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
547 [route->dest]->controller,
548 fo_ctxt->operation_id,
550 &peer_create_success_cb,
552 fo_ctxt->timeout_task =
553 GNUNET_SCHEDULER_add_delayed (GST_timeout,
554 &peer_create_forward_timeout,
556 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
559 GNUNET_SERVICE_client_continue (client);
564 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
566 * @param cls identification of the client
567 * @param msg the actual message
570 handle_peer_destroy (void *cls,
571 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
573 struct GNUNET_SERVICE_Client *client = cls;
574 struct ForwardedOperationContext *fopc;
578 peer_id = ntohl (msg->peer_id);
579 LOG_DEBUG ("Received peer destory 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))
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);
592 peer = GST_peer_list[peer_id];
593 if (GNUNET_YES == peer->is_remote)
595 /* Forward the destory message to sub controller */
596 fopc = GNUNET_new (struct ForwardedOperationContext);
597 fopc->client = client;
599 fopc->type = OP_PEER_DESTROY;
600 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
602 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
606 &peer_destroy_success_cb,
609 GNUNET_SCHEDULER_add_delayed (GST_timeout,
610 &GST_forwarded_operation_timeout,
612 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
615 GNUNET_SERVICE_client_continue (client);
618 peer->destroy_flag = GNUNET_YES;
619 if (0 == peer->reference_cnt)
620 GST_destroy_peer (peer);
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);
633 * @param peer the peer to start
634 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
637 start_peer (struct Peer *peer)
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;
648 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
650 * @param cls identification of the client
651 * @param msg the actual message
654 handle_peer_start (void *cls,
655 const struct GNUNET_TESTBED_PeerStartMessage *msg)
657 struct GNUNET_SERVICE_Client *client = cls;
658 struct GNUNET_MQ_Envelope *env;
659 struct GNUNET_TESTBED_PeerEventMessage *reply;
660 struct ForwardedOperationContext *fopc;
664 peer_id = ntohl (msg->peer_id);
665 if (! VALID_PEER_ID (peer_id))
668 LOG (GNUNET_ERROR_TYPE_ERROR,
669 "Asked to start a non existent peer with id: %u\n",
671 GNUNET_SERVICE_client_continue (client);
674 peer = GST_peer_list[peer_id];
675 if (GNUNET_YES == peer->is_remote)
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;
682 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
684 fopc->operation_id, &msg->header,
686 GST_forwarded_operation_reply_relay,
689 GNUNET_SCHEDULER_add_delayed (GST_timeout,
690 &GST_forwarded_operation_timeout,
692 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
695 GNUNET_SERVICE_client_continue (client);
698 if (GNUNET_OK != start_peer (peer))
700 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
702 GNUNET_SERVICE_client_continue (client);
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),
713 GNUNET_SERVICE_client_continue (client);
718 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
720 * @param cls identification of the client
721 * @param msg the actual message
724 handle_peer_stop (void *cls,
725 const struct GNUNET_TESTBED_PeerStopMessage *msg)
727 struct GNUNET_SERVICE_Client *client = cls;
728 struct GNUNET_MQ_Envelope *env;
729 struct GNUNET_TESTBED_PeerEventMessage *reply;
730 struct ForwardedOperationContext *fopc;
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))
740 GST_send_operation_fail_msg (client,
741 GNUNET_ntohll (msg->operation_id),
743 GNUNET_SERVICE_client_continue (client);
746 peer = GST_peer_list[peer_id];
747 if (GNUNET_YES == peer->is_remote)
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;
757 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
762 GST_forwarded_operation_reply_relay,
765 GNUNET_SCHEDULER_add_delayed (GST_timeout,
766 &GST_forwarded_operation_timeout,
768 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
771 GNUNET_SERVICE_client_continue (client);
774 if (GNUNET_OK != stop_peer (peer))
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),
782 GNUNET_SERVICE_client_continue (client);
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),
796 GNUNET_SERVICE_client_continue (client);
797 GNUNET_TESTING_peer_wait (peer->details.local.peer);
802 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
804 * @param cls identification of the client
805 * @param msg the actual message
808 handle_peer_get_config (void *cls,
810 GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
812 struct GNUNET_SERVICE_Client *client = cls;
813 struct GNUNET_MQ_Envelope *env;
814 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
815 struct ForwardedOperationContext *fopc;
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))
828 GST_send_operation_fail_msg (client,
829 GNUNET_ntohll (msg->operation_id),
831 GNUNET_SERVICE_client_continue (client);
834 peer = GST_peer_list[peer_id];
835 if (GNUNET_YES == peer->is_remote)
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;
844 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
849 GST_forwarded_operation_reply_relay,
852 GNUNET_SCHEDULER_add_delayed (GST_timeout,
853 &GST_forwarded_operation_timeout,
855 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
858 GNUNET_SERVICE_client_continue (client);
861 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
864 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
866 xc_size = GNUNET_TESTBED_compress_config_ (config,
869 GNUNET_free (config);
870 env = GNUNET_MQ_msg_extra (reply,
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],
881 GNUNET_free (xconfig);
882 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
884 GNUNET_SERVICE_client_continue (client);
889 * Cleans up the Peer reconfigure context list
894 while (NULL != prc_head)
895 cleanup_prc (prc_head);
900 * Update peer configuration
902 * @param peer the peer to update
903 * @param cfg the new configuration
904 * @return error message (freshly allocated); NULL upon success
907 update_peer_config (struct Peer *peer,
908 struct GNUNET_CONFIGURATION_Handle *cfg)
912 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
913 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
914 peer->details.local.cfg = cfg;
916 peer->details.local.peer
917 = GNUNET_TESTING_peer_configure (GST_context->system,
918 peer->details.local.cfg,
927 * Callback to inform whether the peer is running or stopped.
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
935 prc_stop_cb (void *cls,
936 struct GNUNET_TESTING_Peer *p,
939 struct PeerReconfigureContext *prc = cls;
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);
951 GST_send_operation_fail_msg (prc->client,
956 if (GNUNET_OK != start_peer (peer))
958 GST_send_operation_fail_msg (prc->client,
960 "Failed to start reconfigured peer");
963 GST_send_operation_success_msg (prc->client,
973 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
975 * @param cls identification of the client
976 * @param msg the actual message
977 * @return #GNUNET_OK if @a msg is well-formed
980 check_peer_reconfigure (void *cls,
981 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
983 return GNUNET_OK; /* checked later */
988 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
989 * Should stop the peer asyncronously, destroy it and create it again with the
992 * @param cls identification of the client
993 * @param msg the actual message
996 handle_peer_reconfigure (void *cls,
998 GNUNET_TESTBED_PeerReconfigureMessage *msg)
1000 struct GNUNET_SERVICE_Client *client = cls;
1002 struct GNUNET_CONFIGURATION_Handle *cfg;
1003 struct ForwardedOperationContext *fopc;
1004 struct PeerReconfigureContext *prc;
1009 peer_id = ntohl (msg->peer_id);
1010 op_id = GNUNET_ntohll (msg->operation_id);
1011 if (! VALID_PEER_ID (peer_id))
1014 GST_send_operation_fail_msg (client,
1017 GNUNET_SERVICE_client_continue (client);
1020 peer = GST_peer_list[peer_id];
1021 if (GNUNET_YES == peer->is_remote)
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;
1029 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1034 GST_forwarded_operation_reply_relay,
1036 fopc->timeout_task =
1037 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1038 &GST_forwarded_operation_timeout,
1040 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1043 GNUNET_SERVICE_client_continue (client);
1046 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1047 (unsigned int) peer_id);
1048 if (0 < peer->reference_cnt)
1051 GST_send_operation_fail_msg (client,
1054 GNUNET_SERVICE_client_continue (client);
1057 if (GNUNET_YES == peer->destroy_flag)
1060 GST_send_operation_fail_msg (client,
1062 "Peer is being destroyed");
1063 GNUNET_SERVICE_client_continue (client);
1066 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1070 GST_send_operation_fail_msg (client,
1072 "Compression error");
1073 GNUNET_SERVICE_client_continue (client);
1076 if (GNUNET_NO == peer->details.local.is_running)
1078 emsg = update_peer_config (peer,
1081 GST_send_operation_fail_msg (client,
1084 GST_send_operation_success_msg (client,
1086 GNUNET_SERVICE_client_continue (client);
1087 GNUNET_free_non_null (emsg);
1090 prc = GNUNET_new (struct PeerReconfigureContext);
1092 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1096 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1097 "Error trying to stop peer %u asynchronously\n",
1099 LOG (GNUNET_ERROR_TYPE_ERROR,
1102 GST_send_operation_fail_msg (client,
1105 GNUNET_SERVICE_client_continue (client);
1111 prc->peer_id = peer_id;
1113 prc->client = client;
1114 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1117 GNUNET_SERVICE_client_continue (client);
1122 * Frees the ManageServiceContext queue
1127 while (NULL != mctx_head)
1128 cleanup_mctx (mctx_head);
1133 * Returns a string interpretation of @a rs.
1135 * @param rs the request status from ARM
1136 * @return a string interpretation of the request status
1139 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1143 case GNUNET_ARM_REQUEST_SENT_OK:
1144 return _ ("Message was sent successfully");
1146 case GNUNET_ARM_REQUEST_DISCONNECTED:
1147 return _ ("We disconnected from ARM before we could send a request");
1149 return _ ("Unknown request status");
1154 * Returns a string interpretation of the @a result.
1156 * @param result the arm result
1157 * @return a string interpretation
1160 arm_ret_string (enum GNUNET_ARM_Result result)
1164 case GNUNET_ARM_RESULT_STOPPED:
1165 return _ ("%s is stopped");
1167 case GNUNET_ARM_RESULT_STARTING:
1168 return _ ("%s is starting");
1170 case GNUNET_ARM_RESULT_STOPPING:
1171 return _ ("%s is stopping");
1173 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1174 return _ ("%s is starting already");
1176 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1177 return _ ("%s is stopping already");
1179 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1180 return _ ("%s is started already");
1182 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1183 return _ ("%s is stopped already");
1185 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1186 return _ ("%s service is not known to ARM");
1188 case GNUNET_ARM_RESULT_START_FAILED:
1189 return _ ("%s service failed to start");
1191 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1192 return _ ("%s service can't be started because ARM is shutting down");
1194 return _ ("%.s Unknown result code.");
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.
1204 * @param cls ManageServiceContext
1205 * @param rs status of the request
1206 * @param result result of the operation
1209 service_manage_result_cb (void *cls,
1210 enum GNUNET_ARM_RequestStatus rs,
1211 enum GNUNET_ARM_Result result)
1213 struct ManageServiceContext *mctx = cls;
1217 if (GNUNET_YES == mctx->expired)
1219 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1221 GNUNET_asprintf (&emsg,
1222 "Error communicating with Peer %u's ARM: %s",
1224 arm_req_string (rs));
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)))
1234 /* stopping a service failed */
1235 GNUNET_asprintf (&emsg,
1236 arm_ret_string (result),
1240 /* service stopped successfully */
1243 service_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)))
1248 /* starting a service failed */
1249 GNUNET_asprintf (&emsg,
1250 arm_ret_string (result),
1254 /* service started successfully */
1259 LOG_DEBUG ("%s\n", emsg);
1260 GST_send_operation_fail_msg (mctx->client,
1265 GST_send_operation_success_msg (mctx->client,
1267 GNUNET_free_non_null (emsg);
1268 cleanup_mctx (mctx);
1273 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1275 * @param cls identification of client
1276 * @param msg the actual message
1277 * @return #GNUNET_OK if @a msg is well-formed
1280 check_manage_peer_service (void *cls,
1282 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1287 msize = ntohs (msg->header.size);
1288 service = (const char *) &msg[1];
1289 if ('\0' != service[msize - sizeof
1290 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1292 GNUNET_break_op (0);
1293 return GNUNET_SYSERR;
1297 GNUNET_break_op (0);
1298 return GNUNET_SYSERR;
1305 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1307 * @param cls identification of client
1308 * @param msg the actual message
1311 handle_manage_peer_service (void *cls,
1313 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1315 struct GNUNET_SERVICE_Client *client = cls;
1319 struct GNUNET_ARM_Handle *ah;
1320 struct ManageServiceContext *mctx;
1321 struct ForwardedOperationContext *fopc;
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])))
1333 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1334 "with id: %u", peer_id);
1337 if (0 == strcasecmp ("arm", service))
1339 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1340 "Use peer start/stop for that");
1343 if (GNUNET_YES == peer->is_remote)
1345 /* Forward the destory message to sub controller */
1346 fopc = GNUNET_new (struct ForwardedOperationContext);
1347 fopc->client = client;
1349 fopc->type = OP_MANAGE_SERVICE;
1350 fopc->operation_id = op_id;
1352 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1357 GST_forwarded_operation_reply_relay,
1359 fopc->timeout_task =
1360 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1361 &GST_forwarded_operation_timeout,
1363 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1366 GNUNET_SERVICE_client_continue (client);
1369 if (GNUNET_NO == peer->details.local.is_running)
1371 emsg = GNUNET_strdup ("Peer not running\n");
1374 if ((0 != peer->reference_cnt)
1375 && ((0 == strcasecmp ("core", service))
1376 || (0 == strcasecmp ("transport", service))))
1378 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1379 "since it is required by existing operations",
1383 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1386 GNUNET_asprintf (&emsg,
1387 "Cannot connect to ARM service of peer with id: %u",
1391 mctx = GNUNET_new (struct ManageServiceContext);
1393 peer->reference_cnt++;
1394 mctx->op_id = op_id;
1396 mctx->client = client;
1397 mctx->start = msg->start;
1398 mctx->service = GNUNET_strdup (service);
1399 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1402 if (1 == mctx->start)
1403 GNUNET_ARM_request_service_start (mctx->ah,
1405 GNUNET_OS_INHERIT_STD_ERR,
1406 &service_manage_result_cb,
1409 GNUNET_ARM_request_service_stop (mctx->ah, service,
1410 &service_manage_result_cb,
1412 GNUNET_SERVICE_client_continue (client);
1416 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1417 GST_send_operation_fail_msg (client, op_id, emsg);
1419 GNUNET_SERVICE_client_continue (client);
1424 * Stops and destroys all peers
1427 GST_destroy_peers ()
1432 if (NULL == GST_peer_list)
1434 for (id = 0; id < GST_peer_list_size; id++)
1436 peer = GST_peer_list[id];
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);
1448 for (id = 0; id < GST_peer_list_size; id++)
1450 peer = GST_peer_list[id];
1453 if (GNUNET_NO == peer->is_remote)
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);
1462 GNUNET_free_non_null (GST_peer_list);
1463 GST_peer_list = NULL;
1464 GST_peer_list_size = 0;
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
1473 * @param cls ForwardedOperationContext
1474 * @param msg the message to relay
1477 shutdown_peers_reply_cb (void *cls,
1478 const struct GNUNET_MessageHeader *msg)
1480 struct ForwardedOperationContext *fo_ctxt = cls;
1481 struct HandlerContext_ShutdownPeers *hc;
1484 GNUNET_assert (0 < hc->nslaves);
1486 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1488 hc->timeout = GNUNET_YES;
1489 if (0 == hc->nslaves)
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");
1496 GST_send_operation_success_msg (fo_ctxt->client,
1497 fo_ctxt->operation_id);
1501 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1504 GNUNET_free (fo_ctxt);
1509 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1511 * @param cls identification of the client
1512 * @param msg the actual message
1515 handle_shutdown_peers (void *cls,
1516 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1518 struct GNUNET_SERVICE_Client *client = cls;
1519 struct HandlerContext_ShutdownPeers *hc;
1520 struct Slave *slave;
1521 struct ForwardedOperationContext *fo_ctxt;
1525 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1526 /* Stop and destroy all peers */
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++)
1538 slave = GST_slave_list[cnt];
1541 if (NULL == slave->controller_proc) /* We didn't start the slave */
1543 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1545 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1546 fo_ctxt->client = client;
1547 fo_ctxt->operation_id = op_id;
1549 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1551 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1552 fo_ctxt->operation_id,
1554 shutdown_peers_reply_cb,
1556 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1560 LOG_DEBUG ("Shutting down peers\n");
1561 GST_destroy_peers ();
1562 if (0 == hc->nslaves)
1564 GST_send_operation_success_msg (client,
1568 GNUNET_SERVICE_client_continue (client);