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,
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.
761 &GST_forwarded_operation_reply_relay,
764 GNUNET_SCHEDULER_add_delayed (GST_timeout,
765 &GST_forwarded_operation_timeout,
767 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
770 GNUNET_SERVICE_client_continue (client);
773 if (GNUNET_OK != stop_peer (peer))
775 LOG (GNUNET_ERROR_TYPE_WARNING,
776 "Stopping peer %u failed\n",
777 (unsigned int) peer_id);
778 GST_send_operation_fail_msg (client,
779 GNUNET_ntohll (msg->operation_id),
781 GNUNET_SERVICE_client_continue (client);
784 LOG (GNUNET_ERROR_TYPE_DEBUG,
785 "Peer %u successfully stopped\n",
786 (unsigned int) peer_id);
787 env = GNUNET_MQ_msg (reply,
788 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
789 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
790 reply->host_id = htonl (GST_context->host_id);
791 reply->peer_id = msg->peer_id;
792 reply->operation_id = msg->operation_id;
793 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
795 GNUNET_SERVICE_client_continue (client);
796 GNUNET_TESTING_peer_wait (peer->details.local.peer);
801 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
803 * @param cls identification of the client
804 * @param msg the actual message
807 handle_peer_get_config (void *cls,
808 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
810 struct GNUNET_SERVICE_Client *client = cls;
811 struct GNUNET_MQ_Envelope *env;
812 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
813 struct ForwardedOperationContext *fopc;
821 peer_id = ntohl (msg->peer_id);
822 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
823 (unsigned int) peer_id);
824 if (!VALID_PEER_ID (peer_id))
826 GST_send_operation_fail_msg (client,
827 GNUNET_ntohll (msg->operation_id),
829 GNUNET_SERVICE_client_continue (client);
832 peer = GST_peer_list[peer_id];
833 if (GNUNET_YES == peer->is_remote)
835 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
836 (unsigned int) peer_id);
837 fopc = GNUNET_new (struct ForwardedOperationContext);
838 fopc->client = client;
839 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
840 fopc->type = OP_PEER_INFO;
842 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
846 &GST_forwarded_operation_reply_relay,
849 GNUNET_SCHEDULER_add_delayed (GST_timeout,
850 &GST_forwarded_operation_timeout,
852 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
855 GNUNET_SERVICE_client_continue (client);
858 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
861 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
863 xc_size = GNUNET_TESTBED_compress_config_ (config,
866 GNUNET_free (config);
867 env = GNUNET_MQ_msg_extra (reply,
869 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
870 reply->peer_id = msg->peer_id;
871 reply->operation_id = msg->operation_id;
872 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
873 &reply->peer_identity);
874 reply->config_size = htons ((uint16_t) c_size);
875 GNUNET_memcpy (&reply[1],
878 GNUNET_free (xconfig);
879 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
881 GNUNET_SERVICE_client_continue (client);
886 * Cleans up the Peer reconfigure context list
891 while (NULL != prc_head)
892 cleanup_prc (prc_head);
897 * Update peer configuration
899 * @param peer the peer to update
900 * @param cfg the new configuration
901 * @return error message (freshly allocated); NULL upon success
904 update_peer_config (struct Peer *peer,
905 struct GNUNET_CONFIGURATION_Handle *cfg)
909 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
910 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
911 peer->details.local.cfg = cfg;
913 peer->details.local.peer
914 = GNUNET_TESTING_peer_configure (GST_context->system,
915 peer->details.local.cfg,
924 * Callback to inform whether the peer is running or stopped.
926 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
927 * @param p the respective peer whose status is being reported
928 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
932 prc_stop_cb (void *cls,
933 struct GNUNET_TESTING_Peer *p,
936 struct PeerReconfigureContext *prc = cls;
940 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
941 peer = GST_peer_list [prc->peer_id];
942 GNUNET_assert (GNUNET_NO == peer->is_remote);
943 emsg = update_peer_config (peer, prc->cfg);
948 GST_send_operation_fail_msg (prc->client,
953 if (GNUNET_OK != start_peer (peer))
955 GST_send_operation_fail_msg (prc->client,
957 "Failed to start reconfigured peer");
960 GST_send_operation_success_msg (prc->client,
970 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
972 * @param cls identification of the client
973 * @param msg the actual message
974 * @return #GNUNET_OK if @a msg is well-formed
977 check_peer_reconfigure (void *cls,
978 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
980 return GNUNET_OK; /* checked later */
985 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
986 * Should stop the peer asyncronously, destroy it and create it again with the
989 * @param cls identification of the client
990 * @param msg the actual message
993 handle_peer_reconfigure (void *cls,
994 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
996 struct GNUNET_SERVICE_Client *client = cls;
998 struct GNUNET_CONFIGURATION_Handle *cfg;
999 struct ForwardedOperationContext *fopc;
1000 struct PeerReconfigureContext *prc;
1005 peer_id = ntohl (msg->peer_id);
1006 op_id = GNUNET_ntohll (msg->operation_id);
1007 if (! VALID_PEER_ID (peer_id))
1010 GST_send_operation_fail_msg (client,
1013 GNUNET_SERVICE_client_continue (client);
1016 peer = GST_peer_list[peer_id];
1017 if (GNUNET_YES == peer->is_remote)
1019 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1020 fopc = GNUNET_new (struct ForwardedOperationContext);
1021 fopc->client = client;
1022 fopc->operation_id = op_id;
1023 fopc->type = OP_PEER_RECONFIGURE;
1025 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1029 &GST_forwarded_operation_reply_relay,
1031 fopc->timeout_task =
1032 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1033 &GST_forwarded_operation_timeout,
1035 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1038 GNUNET_SERVICE_client_continue (client);
1041 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1042 (unsigned int) peer_id);
1043 if (0 < peer->reference_cnt)
1046 GST_send_operation_fail_msg (client,
1049 GNUNET_SERVICE_client_continue (client);
1052 if (GNUNET_YES == peer->destroy_flag)
1055 GST_send_operation_fail_msg (client,
1057 "Peer is being destroyed");
1058 GNUNET_SERVICE_client_continue (client);
1061 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1065 GST_send_operation_fail_msg (client,
1067 "Compression error");
1068 GNUNET_SERVICE_client_continue (client);
1071 if (GNUNET_NO == peer->details.local.is_running)
1073 emsg = update_peer_config (peer,
1076 GST_send_operation_fail_msg (client,
1079 GST_send_operation_success_msg (client,
1081 GNUNET_SERVICE_client_continue (client);
1082 GNUNET_free_non_null (emsg);
1085 prc = GNUNET_new (struct PeerReconfigureContext);
1087 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1091 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1092 "Error trying to stop peer %u asynchronously\n",
1094 LOG (GNUNET_ERROR_TYPE_ERROR,
1097 GST_send_operation_fail_msg (client,
1100 GNUNET_SERVICE_client_continue (client);
1106 prc->peer_id = peer_id;
1108 prc->client = client;
1109 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1112 GNUNET_SERVICE_client_continue (client);
1117 * Frees the ManageServiceContext queue
1122 while (NULL != mctx_head)
1123 cleanup_mctx (mctx_head);
1128 * Returns a string interpretation of @a rs.
1130 * @param rs the request status from ARM
1131 * @return a string interpretation of the request status
1134 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1138 case GNUNET_ARM_REQUEST_SENT_OK:
1139 return _("Message was sent successfully");
1140 case GNUNET_ARM_REQUEST_DISCONNECTED:
1141 return _("We disconnected from ARM before we could send a request");
1143 return _("Unknown request status");
1148 * Returns a string interpretation of the @a result.
1150 * @param result the arm result
1151 * @return a string interpretation
1154 arm_ret_string (enum GNUNET_ARM_Result result)
1158 case GNUNET_ARM_RESULT_STOPPED:
1159 return _("%s is stopped");
1160 case GNUNET_ARM_RESULT_STARTING:
1161 return _("%s is starting");
1162 case GNUNET_ARM_RESULT_STOPPING:
1163 return _("%s is stopping");
1164 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1165 return _("%s is starting already");
1166 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1167 return _("%s is stopping already");
1168 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1169 return _("%s is started already");
1170 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1171 return _("%s is stopped already");
1172 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1173 return _("%s service is not known to ARM");
1174 case GNUNET_ARM_RESULT_START_FAILED:
1175 return _("%s service failed to start");
1176 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1177 return _("%s service can't be started because ARM is shutting down");
1179 return _("%.s Unknown result code.");
1184 * Function called in response to a start/stop request.
1185 * Will be called when request was not sent successfully,
1186 * or when a reply comes. If the request was not sent successfully,
1187 * @a rs will indicate that, and @a result will be undefined.
1189 * @param cls ManageServiceContext
1190 * @param rs status of the request
1191 * @param result result of the operation
1194 service_manage_result_cb (void *cls,
1195 enum GNUNET_ARM_RequestStatus rs,
1196 enum GNUNET_ARM_Result result)
1198 struct ManageServiceContext *mctx = cls;
1202 if (GNUNET_YES == mctx->expired)
1204 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1206 GNUNET_asprintf (&emsg,
1207 "Error communicating with Peer %u's ARM: %s",
1209 arm_req_string (rs));
1212 if (1 == mctx->start)
1213 goto service_start_check;
1214 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1215 || (GNUNET_ARM_RESULT_STOPPING == result)
1216 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1217 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1219 /* stopping a service failed */
1220 GNUNET_asprintf (&emsg,
1221 arm_ret_string (result),
1225 /* service stopped successfully */
1228 service_start_check:
1229 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1230 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1231 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1233 /* starting a service failed */
1234 GNUNET_asprintf (&emsg,
1235 arm_ret_string (result),
1239 /* service started successfully */
1244 LOG_DEBUG ("%s\n", emsg);
1245 GST_send_operation_fail_msg (mctx->client,
1250 GST_send_operation_success_msg (mctx->client,
1252 GNUNET_free_non_null (emsg);
1253 cleanup_mctx (mctx);
1258 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1260 * @param cls identification of client
1261 * @param msg the actual message
1262 * @return #GNUNET_OK if @a msg is well-formed
1265 check_manage_peer_service (void *cls,
1266 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1269 const char* service;
1271 msize = ntohs (msg->header.size);
1272 service = (const char *) &msg[1];
1273 if ('\0' != service[msize - sizeof
1274 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1276 GNUNET_break_op (0);
1277 return GNUNET_SYSERR;
1281 GNUNET_break_op (0);
1282 return GNUNET_SYSERR;
1289 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1291 * @param cls identification of client
1292 * @param msg the actual message
1295 handle_manage_peer_service (void *cls,
1296 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1298 struct GNUNET_SERVICE_Client *client = cls;
1299 const char* service;
1302 struct GNUNET_ARM_Handle *ah;
1303 struct ManageServiceContext *mctx;
1304 struct ForwardedOperationContext *fopc;
1308 service = (const char *) &msg[1];
1309 peer_id = ntohl (msg->peer_id);
1310 op_id = GNUNET_ntohll (msg->operation_id);
1311 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1312 service, (unsigned int) peer_id);
1313 if ((GST_peer_list_size <= peer_id)
1314 || (NULL == (peer = GST_peer_list[peer_id])))
1316 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1317 "with id: %u", peer_id);
1320 if (0 == strcasecmp ("arm", service))
1322 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1323 "Use peer start/stop for that");
1326 if (GNUNET_YES == peer->is_remote)
1328 /* Forward the destory message to sub controller */
1329 fopc = GNUNET_new (struct ForwardedOperationContext);
1330 fopc->client = client;
1332 fopc->type = OP_MANAGE_SERVICE;
1333 fopc->operation_id = op_id;
1335 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1339 &GST_forwarded_operation_reply_relay,
1341 fopc->timeout_task =
1342 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1343 &GST_forwarded_operation_timeout,
1345 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1348 GNUNET_SERVICE_client_continue (client);
1351 if (GNUNET_NO == peer->details.local.is_running)
1353 emsg = GNUNET_strdup ("Peer not running\n");
1356 if ((0 != peer->reference_cnt)
1357 && ( (0 == strcasecmp ("core", service))
1358 || (0 == strcasecmp ("transport", service)) ) )
1360 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1361 "since it is required by existing operations",
1365 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1368 GNUNET_asprintf (&emsg,
1369 "Cannot connect to ARM service of peer with id: %u",
1373 mctx = GNUNET_new (struct ManageServiceContext);
1375 peer->reference_cnt++;
1376 mctx->op_id = op_id;
1378 mctx->client = client;
1379 mctx->start = msg->start;
1380 mctx->service = GNUNET_strdup (service);
1381 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1384 if (1 == mctx->start)
1385 GNUNET_ARM_request_service_start (mctx->ah,
1387 GNUNET_OS_INHERIT_STD_ERR,
1388 &service_manage_result_cb,
1391 GNUNET_ARM_request_service_stop (mctx->ah, service,
1392 &service_manage_result_cb,
1394 GNUNET_SERVICE_client_continue (client);
1398 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1399 GST_send_operation_fail_msg (client, op_id, emsg);
1401 GNUNET_SERVICE_client_continue (client);
1406 * Stops and destroys all peers
1409 GST_destroy_peers ()
1414 if (NULL == GST_peer_list)
1416 for (id = 0; id < GST_peer_list_size; id++)
1418 peer = GST_peer_list[id];
1421 /* If destroy flag is set it means that this peer should have been
1422 * destroyed by a context which we destroy before */
1423 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1424 /* counter should be zero as we free all contexts before */
1425 GNUNET_break (0 == peer->reference_cnt);
1426 if ((GNUNET_NO == peer->is_remote) &&
1427 (GNUNET_YES == peer->details.local.is_running))
1428 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1430 for (id = 0; id < GST_peer_list_size; id++)
1432 peer = GST_peer_list[id];
1435 if (GNUNET_NO == peer->is_remote)
1437 if (GNUNET_YES == peer->details.local.is_running)
1438 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1439 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1440 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1444 GNUNET_free_non_null (GST_peer_list);
1445 GST_peer_list = NULL;
1446 GST_peer_list_size = 0;
1451 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1452 * success reply is received from all clients and then sends the success message
1455 * @param cls ForwardedOperationContext
1456 * @param msg the message to relay
1459 shutdown_peers_reply_cb (void *cls,
1460 const struct GNUNET_MessageHeader *msg)
1462 struct ForwardedOperationContext *fo_ctxt = cls;
1463 struct HandlerContext_ShutdownPeers *hc;
1466 GNUNET_assert (0 < hc->nslaves);
1468 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1470 hc->timeout = GNUNET_YES;
1471 if (0 == hc->nslaves)
1473 if (GNUNET_YES == hc->timeout)
1474 GST_send_operation_fail_msg (fo_ctxt->client,
1475 fo_ctxt->operation_id,
1476 "Timeout at a slave controller");
1478 GST_send_operation_success_msg (fo_ctxt->client,
1479 fo_ctxt->operation_id);
1483 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1486 GNUNET_free (fo_ctxt);
1491 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1493 * @param cls identification of the client
1494 * @param msg the actual message
1497 handle_shutdown_peers (void *cls,
1498 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1500 struct GNUNET_SERVICE_Client *client = cls;
1501 struct HandlerContext_ShutdownPeers *hc;
1502 struct Slave *slave;
1503 struct ForwardedOperationContext *fo_ctxt;
1507 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1508 /* Stop and destroy all peers */
1513 /* Forward to all slaves which we have started */
1514 op_id = GNUNET_ntohll (msg->operation_id);
1515 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1516 /* FIXME: have a better implementation where we track which slaves are
1517 started by this controller */
1518 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1520 slave = GST_slave_list[cnt];
1523 if (NULL == slave->controller_proc) /* We didn't start the slave */
1525 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1527 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1528 fo_ctxt->client = client;
1529 fo_ctxt->operation_id = op_id;
1531 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1533 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1534 fo_ctxt->operation_id,
1536 shutdown_peers_reply_cb,
1538 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1542 LOG_DEBUG ("Shutting down peers\n");
1543 GST_destroy_peers ();
1544 if (0 == hc->nslaves)
1546 GST_send_operation_success_msg (client,
1550 GNUNET_SERVICE_client_continue (client);