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 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.
18 * @file testbed/gnunet-service-testbed_peers.c
19 * @brief implementation of TESTBED service that deals with peer management
20 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
23 #include "gnunet-service-testbed.h"
24 #include "gnunet_arm_service.h"
29 * A list of peers we know about
31 struct Peer **GST_peer_list;
34 * The current number of peers running locally under this controller
36 unsigned int GST_num_local_peers;
40 * Context information to manage peers' services
42 struct ManageServiceContext
47 struct ManageServiceContext *next;
52 struct ManageServiceContext *prev;
55 * The ARM handle of the peer
57 struct GNUNET_ARM_Handle *ah;
60 * peer whose service has to be managed
65 * The client which requested to manage the peer's service
67 struct GNUNET_SERVICE_Client *client;
70 * Name of the service.
75 * The operation id of the associated request
80 * 1 if the service at the peer has to be started; 0 if it has to be stopped
85 * Is this context expired? Do not work on this context if it is set to
93 * Context information for peer re-configure operations
95 struct PeerReconfigureContext
98 * DLL next for inclusoin in peer reconfigure operations list
100 struct PeerReconfigureContext *next;
105 struct PeerReconfigureContext *prev;
108 * The client which gave this operation to us
110 struct GNUNET_SERVICE_Client *client;
113 * The configuration handle to use as the new template
115 struct GNUNET_CONFIGURATION_Handle *cfg;
118 * The id of the operation
123 * The id of the peer which has to be reconfigured
128 * The the peer stopped? Used while cleaning up this context to decide
129 * whether the asynchronous stop request through Testing/ARM API has to be
136 * The DLL head for the peer reconfigure list
138 static struct PeerReconfigureContext *prc_head;
141 * The DLL tail for the peer reconfigure list
143 static struct PeerReconfigureContext *prc_tail;
148 * DLL head for queue of manage service requests
150 static struct ManageServiceContext *mctx_head;
153 * DLL tail for queue of manage service requests
155 static struct ManageServiceContext *mctx_tail;
159 * Adds a peer to the peer array
161 * @param peer the peer to add
164 peer_list_add (struct Peer *peer)
166 if (peer->id >= GST_peer_list_size)
167 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
168 GNUNET_assert (NULL == GST_peer_list[peer->id]);
169 GST_peer_list[peer->id] = peer;
170 if (GNUNET_NO == peer->is_remote)
171 GST_num_local_peers++;
176 * Removes a the give peer from the peer array
178 * @param peer the peer to be removed
181 peer_list_remove (struct Peer *peer)
183 unsigned int orig_size;
186 if (GNUNET_NO == peer->is_remote)
187 GST_num_local_peers--;
188 GST_peer_list[peer->id] = NULL;
189 orig_size = GST_peer_list_size;
190 while (GST_peer_list_size >= LIST_GROW_STEP)
192 for (id = GST_peer_list_size - 1;
193 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
195 if (NULL != GST_peer_list[id])
197 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
199 GST_peer_list_size -= LIST_GROW_STEP;
201 if (orig_size == GST_peer_list_size)
204 GNUNET_realloc (GST_peer_list,
205 sizeof (struct Peer *) * GST_peer_list_size);
210 * The task to be executed if the forwarded peer create operation has been
213 * @param cls the FowardedOperationContext
216 peer_create_forward_timeout (void *cls)
218 struct ForwardedOperationContext *fopc = cls;
220 GNUNET_free (fopc->cls);
221 GST_forwarded_operation_timeout (fopc);
226 * Callback to be called when forwarded peer create operation is successfull. We
227 * have to relay the reply msg back to the client
229 * @param cls ForwardedOperationContext
230 * @param msg the peer create success message
233 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
235 struct ForwardedOperationContext *fopc = cls;
236 struct Peer *remote_peer;
238 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
240 GNUNET_assert (NULL != fopc->cls);
241 remote_peer = fopc->cls;
242 peer_list_add (remote_peer);
244 GST_forwarded_operation_reply_relay (fopc,
250 * Function to destroy a peer
252 * @param peer the peer structure to destroy
255 GST_destroy_peer (struct Peer *peer)
257 GNUNET_break (0 == peer->reference_cnt);
258 if (GNUNET_YES == peer->is_remote)
260 peer_list_remove (peer);
264 if (GNUNET_YES == peer->details.local.is_running)
266 GNUNET_TESTING_peer_stop (peer->details.local.peer);
267 peer->details.local.is_running = GNUNET_NO;
269 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
270 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
271 peer_list_remove (peer);
277 * Cleanup the context information created for managing a peer's service
279 * @param mctx the ManageServiceContext
282 cleanup_mctx (struct ManageServiceContext *mctx)
284 mctx->expired = GNUNET_YES;
285 GNUNET_CONTAINER_DLL_remove (mctx_head,
288 GNUNET_ARM_disconnect (mctx->ah);
289 GNUNET_assert (0 < mctx->peer->reference_cnt);
290 mctx->peer->reference_cnt--;
291 if ( (GNUNET_YES == mctx->peer->destroy_flag) &&
292 (0 == mctx->peer->reference_cnt) )
293 GST_destroy_peer (mctx->peer);
294 GNUNET_free (mctx->service);
302 * @param peer the peer to stop
303 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
306 stop_peer (struct Peer *peer)
308 GNUNET_assert (GNUNET_NO == peer->is_remote);
309 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
310 return GNUNET_SYSERR;
311 peer->details.local.is_running = GNUNET_NO;
317 * Cleans up the given PeerReconfigureContext
319 * @param prc the PeerReconfigureContext
322 cleanup_prc (struct PeerReconfigureContext *prc)
326 if (VALID_PEER_ID (prc->peer_id))
328 peer = GST_peer_list [prc->peer_id];
329 if (1 != prc->stopped)
331 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
332 stop_peer (peer); /* Stop the peer synchronously */
335 if (NULL != prc->cfg)
336 GNUNET_CONFIGURATION_destroy (prc->cfg);
337 GNUNET_CONTAINER_DLL_remove (prc_head,
345 * Notify peers subsystem that @a client disconnected.
347 * @param client the client that disconnected
350 GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
352 struct ForwardedOperationContext *fopc;
353 struct ForwardedOperationContext *fopcn;
354 struct ManageServiceContext *mctx;
355 struct ManageServiceContext *mctxn;
356 struct PeerReconfigureContext *prc;
357 struct PeerReconfigureContext *prcn;
359 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
362 if (client == fopc->client)
364 if (OP_PEER_CREATE == fopc->type)
365 GNUNET_free (fopc->cls);
366 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
367 GST_forwarded_operation_timeout (fopc);
370 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
373 if (client == mctx->client)
376 for (prc = prc_head; NULL != prc; prc = prcn)
379 if (client == prc->client)
386 * Callback to be called when forwarded peer destroy operation is successfull. We
387 * have to relay the reply msg back to the client
389 * @param cls ForwardedOperationContext
390 * @param msg the peer create success message
393 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
395 struct ForwardedOperationContext *fopc = cls;
396 struct Peer *remote_peer;
398 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
401 remote_peer = fopc->cls;
402 GNUNET_assert (NULL != remote_peer);
403 remote_peer->destroy_flag = GNUNET_YES;
404 if (0 == remote_peer->reference_cnt)
405 GST_destroy_peer (remote_peer);
407 GST_forwarded_operation_reply_relay (fopc,
413 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
415 * @param cls identification of the client
416 * @param msg the actual message
417 * @return #GNUNET_OK if @a msg is well-formed
420 check_peer_create (void *cls,
421 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
423 return GNUNET_OK; /* checked later */
428 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
430 * @param cls identification of the client
431 * @param msg the actual message
434 handle_peer_create (void *cls,
435 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
437 struct GNUNET_SERVICE_Client *client = cls;
438 struct GNUNET_MQ_Envelope *env;
439 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
440 struct GNUNET_CONFIGURATION_Handle *cfg;
441 struct ForwardedOperationContext *fo_ctxt;
448 host_id = ntohl (msg->host_id);
449 peer_id = ntohl (msg->peer_id);
450 if (VALID_PEER_ID (peer_id))
452 (void) GNUNET_asprintf (&emsg,
453 "Peer with ID %u already exists",
455 GST_send_operation_fail_msg (client,
456 GNUNET_ntohll (msg->operation_id),
459 GNUNET_SERVICE_client_continue (client);
462 if (UINT32_MAX == peer_id)
464 GST_send_operation_fail_msg (client,
465 GNUNET_ntohll (msg->operation_id),
466 "Cannot create peer with given ID");
467 GNUNET_SERVICE_client_continue (client);
470 if (host_id == GST_context->host_id)
472 /* We are responsible for this peer */
473 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
477 GNUNET_SERVICE_client_drop (client);
480 GNUNET_CONFIGURATION_set_value_number (cfg,
483 (unsigned long long) peer_id);
485 GNUNET_CONFIGURATION_set_value_number (cfg,
488 (unsigned long long) peer_id);
489 peer = GNUNET_new (struct Peer);
490 peer->is_remote = GNUNET_NO;
491 peer->details.local.cfg = cfg;
493 LOG_DEBUG ("Creating peer with id: %u\n",
494 (unsigned int) peer->id);
495 peer->details.local.peer =
496 GNUNET_TESTING_peer_configure (GST_context->system,
497 peer->details.local.cfg, peer->id,
500 if (NULL == peer->details.local.peer)
502 LOG (GNUNET_ERROR_TYPE_WARNING,
503 "Configuring peer failed: %s\n",
508 GNUNET_SERVICE_client_drop (client);
511 peer->details.local.is_running = GNUNET_NO;
512 peer_list_add (peer);
513 env = GNUNET_MQ_msg (reply,
514 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
515 reply->peer_id = msg->peer_id;
516 reply->operation_id = msg->operation_id;
517 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
519 GNUNET_SERVICE_client_continue (client);
523 /* Forward peer create request */
524 route = GST_find_dest_route (host_id);
528 GNUNET_SERVICE_client_continue (client); // ?
531 peer = GNUNET_new (struct Peer);
532 peer->is_remote = GNUNET_YES;
534 peer->details.remote.slave = GST_slave_list[route->dest];
535 peer->details.remote.remote_host_id = host_id;
536 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
537 fo_ctxt->client = client;
538 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
540 fo_ctxt->type = OP_PEER_CREATE;
542 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
543 [route->dest]->controller,
544 fo_ctxt->operation_id,
546 &peer_create_success_cb,
548 fo_ctxt->timeout_task =
549 GNUNET_SCHEDULER_add_delayed (GST_timeout,
550 &peer_create_forward_timeout,
552 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
555 GNUNET_SERVICE_client_continue (client);
560 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
562 * @param cls identification of the client
563 * @param msg the actual message
566 handle_peer_destroy (void *cls,
567 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
569 struct GNUNET_SERVICE_Client *client = cls;
570 struct ForwardedOperationContext *fopc;
574 peer_id = ntohl (msg->peer_id);
575 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %llu\n",
576 (unsigned int) peer_id,
577 (unsigned long long) GNUNET_ntohll (msg->operation_id));
578 if (!VALID_PEER_ID (peer_id))
580 LOG (GNUNET_ERROR_TYPE_ERROR,
581 "Asked to destroy a non existent peer with id: %u\n", peer_id);
582 GST_send_operation_fail_msg (client,
583 GNUNET_ntohll (msg->operation_id),
584 "Peer doesn't exist");
585 GNUNET_SERVICE_client_continue (client);
588 peer = GST_peer_list[peer_id];
589 if (GNUNET_YES == peer->is_remote)
591 /* Forward the destory message to sub controller */
592 fopc = GNUNET_new (struct ForwardedOperationContext);
593 fopc->client = client;
595 fopc->type = OP_PEER_DESTROY;
596 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
598 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
602 &peer_destroy_success_cb,
605 GNUNET_SCHEDULER_add_delayed (GST_timeout,
606 &GST_forwarded_operation_timeout,
608 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
611 GNUNET_SERVICE_client_continue (client);
614 peer->destroy_flag = GNUNET_YES;
615 if (0 == peer->reference_cnt)
616 GST_destroy_peer (peer);
618 LOG (GNUNET_ERROR_TYPE_DEBUG,
619 "Delaying peer destroy as peer is currently in use\n");
620 GST_send_operation_success_msg (client,
621 GNUNET_ntohll (msg->operation_id));
622 GNUNET_SERVICE_client_continue (client);
629 * @param peer the peer to start
630 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
633 start_peer (struct Peer *peer)
635 GNUNET_assert (GNUNET_NO == peer->is_remote);
636 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
637 return GNUNET_SYSERR;
638 peer->details.local.is_running = GNUNET_YES;
644 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
646 * @param cls identification of the client
647 * @param msg the actual message
650 handle_peer_start (void *cls,
651 const struct GNUNET_TESTBED_PeerStartMessage *msg)
653 struct GNUNET_SERVICE_Client *client = cls;
654 struct GNUNET_MQ_Envelope *env;
655 struct GNUNET_TESTBED_PeerEventMessage *reply;
656 struct ForwardedOperationContext *fopc;
660 peer_id = ntohl (msg->peer_id);
661 if (! VALID_PEER_ID (peer_id))
664 LOG (GNUNET_ERROR_TYPE_ERROR,
665 "Asked to start a non existent peer with id: %u\n",
667 GNUNET_SERVICE_client_continue (client);
670 peer = GST_peer_list[peer_id];
671 if (GNUNET_YES == peer->is_remote)
673 fopc = GNUNET_new (struct ForwardedOperationContext);
674 fopc->client = client;
675 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
676 fopc->type = OP_PEER_START;
678 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
680 fopc->operation_id, &msg->header,
681 &GST_forwarded_operation_reply_relay,
684 GNUNET_SCHEDULER_add_delayed (GST_timeout,
685 &GST_forwarded_operation_timeout,
687 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
690 GNUNET_SERVICE_client_continue (client);
693 if (GNUNET_OK != start_peer (peer))
695 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
697 GNUNET_SERVICE_client_continue (client);
700 env = GNUNET_MQ_msg (reply,
701 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
702 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
703 reply->host_id = htonl (GST_context->host_id);
704 reply->peer_id = msg->peer_id;
705 reply->operation_id = msg->operation_id;
706 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
708 GNUNET_SERVICE_client_continue (client);
713 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
715 * @param cls identification of the client
716 * @param msg the actual message
719 handle_peer_stop (void *cls,
720 const struct GNUNET_TESTBED_PeerStopMessage *msg)
722 struct GNUNET_SERVICE_Client *client = cls;
723 struct GNUNET_MQ_Envelope *env;
724 struct GNUNET_TESTBED_PeerEventMessage *reply;
725 struct ForwardedOperationContext *fopc;
729 peer_id = ntohl (msg->peer_id);
730 LOG (GNUNET_ERROR_TYPE_DEBUG,
731 "Received PEER_STOP for peer %u\n",
732 (unsigned int) peer_id);
733 if (! VALID_PEER_ID (peer_id))
735 GST_send_operation_fail_msg (client,
736 GNUNET_ntohll (msg->operation_id),
738 GNUNET_SERVICE_client_continue (client);
741 peer = GST_peer_list[peer_id];
742 if (GNUNET_YES == peer->is_remote)
744 LOG (GNUNET_ERROR_TYPE_DEBUG,
745 "Forwarding PEER_STOP for peer %u\n",
746 (unsigned int) peer_id);
747 fopc = GNUNET_new (struct ForwardedOperationContext);
748 fopc->client = client;
749 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
750 fopc->type = OP_PEER_STOP;
752 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
756 &GST_forwarded_operation_reply_relay,
759 GNUNET_SCHEDULER_add_delayed (GST_timeout,
760 &GST_forwarded_operation_timeout,
762 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
765 GNUNET_SERVICE_client_continue (client);
768 if (GNUNET_OK != stop_peer (peer))
770 LOG (GNUNET_ERROR_TYPE_WARNING,
771 "Stopping peer %u failed\n",
772 (unsigned int) peer_id);
773 GST_send_operation_fail_msg (client,
774 GNUNET_ntohll (msg->operation_id),
776 GNUNET_SERVICE_client_continue (client);
779 LOG (GNUNET_ERROR_TYPE_DEBUG,
780 "Peer %u successfully stopped\n",
781 (unsigned int) peer_id);
782 env = GNUNET_MQ_msg (reply,
783 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
784 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
785 reply->host_id = htonl (GST_context->host_id);
786 reply->peer_id = msg->peer_id;
787 reply->operation_id = msg->operation_id;
788 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
790 GNUNET_SERVICE_client_continue (client);
791 GNUNET_TESTING_peer_wait (peer->details.local.peer);
796 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
798 * @param cls identification of the client
799 * @param msg the actual message
802 handle_peer_get_config (void *cls,
803 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
805 struct GNUNET_SERVICE_Client *client = cls;
806 struct GNUNET_MQ_Envelope *env;
807 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
808 struct ForwardedOperationContext *fopc;
816 peer_id = ntohl (msg->peer_id);
817 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
818 (unsigned int) peer_id);
819 if (!VALID_PEER_ID (peer_id))
821 GST_send_operation_fail_msg (client,
822 GNUNET_ntohll (msg->operation_id),
824 GNUNET_SERVICE_client_continue (client);
827 peer = GST_peer_list[peer_id];
828 if (GNUNET_YES == peer->is_remote)
830 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
831 (unsigned int) peer_id);
832 fopc = GNUNET_new (struct ForwardedOperationContext);
833 fopc->client = client;
834 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
835 fopc->type = OP_PEER_INFO;
837 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
841 &GST_forwarded_operation_reply_relay,
844 GNUNET_SCHEDULER_add_delayed (GST_timeout,
845 &GST_forwarded_operation_timeout,
847 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
850 GNUNET_SERVICE_client_continue (client);
853 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
856 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
858 xc_size = GNUNET_TESTBED_compress_config_ (config,
861 GNUNET_free (config);
862 env = GNUNET_MQ_msg_extra (reply,
864 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
865 reply->peer_id = msg->peer_id;
866 reply->operation_id = msg->operation_id;
867 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
868 &reply->peer_identity);
869 reply->config_size = htons ((uint16_t) c_size);
870 GNUNET_memcpy (&reply[1],
873 GNUNET_free (xconfig);
874 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
876 GNUNET_SERVICE_client_continue (client);
881 * Cleans up the Peer reconfigure context list
886 while (NULL != prc_head)
887 cleanup_prc (prc_head);
892 * Update peer configuration
894 * @param peer the peer to update
895 * @param cfg the new configuration
896 * @return error message (freshly allocated); NULL upon success
899 update_peer_config (struct Peer *peer,
900 struct GNUNET_CONFIGURATION_Handle *cfg)
904 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
905 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
906 peer->details.local.cfg = cfg;
908 peer->details.local.peer
909 = GNUNET_TESTING_peer_configure (GST_context->system,
910 peer->details.local.cfg,
919 * Callback to inform whether the peer is running or stopped.
921 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
922 * @param p the respective peer whose status is being reported
923 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
927 prc_stop_cb (void *cls,
928 struct GNUNET_TESTING_Peer *p,
931 struct PeerReconfigureContext *prc = cls;
935 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
936 peer = GST_peer_list [prc->peer_id];
937 GNUNET_assert (GNUNET_NO == peer->is_remote);
938 emsg = update_peer_config (peer, prc->cfg);
943 GST_send_operation_fail_msg (prc->client,
948 if (GNUNET_OK != start_peer (peer))
950 GST_send_operation_fail_msg (prc->client,
952 "Failed to start reconfigured peer");
955 GST_send_operation_success_msg (prc->client,
965 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
967 * @param cls identification of the client
968 * @param msg the actual message
969 * @return #GNUNET_OK if @a msg is well-formed
972 check_peer_reconfigure (void *cls,
973 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
975 return GNUNET_OK; /* checked later */
980 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
981 * Should stop the peer asyncronously, destroy it and create it again with the
984 * @param cls identification of the client
985 * @param msg the actual message
988 handle_peer_reconfigure (void *cls,
989 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
991 struct GNUNET_SERVICE_Client *client = cls;
993 struct GNUNET_CONFIGURATION_Handle *cfg;
994 struct ForwardedOperationContext *fopc;
995 struct PeerReconfigureContext *prc;
1000 peer_id = ntohl (msg->peer_id);
1001 op_id = GNUNET_ntohll (msg->operation_id);
1002 if (! VALID_PEER_ID (peer_id))
1005 GST_send_operation_fail_msg (client,
1008 GNUNET_SERVICE_client_continue (client);
1011 peer = GST_peer_list[peer_id];
1012 if (GNUNET_YES == peer->is_remote)
1014 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1015 fopc = GNUNET_new (struct ForwardedOperationContext);
1016 fopc->client = client;
1017 fopc->operation_id = op_id;
1018 fopc->type = OP_PEER_RECONFIGURE;
1020 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1024 &GST_forwarded_operation_reply_relay,
1026 fopc->timeout_task =
1027 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1028 &GST_forwarded_operation_timeout,
1030 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1033 GNUNET_SERVICE_client_continue (client);
1036 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1037 (unsigned int) peer_id);
1038 if (0 < peer->reference_cnt)
1041 GST_send_operation_fail_msg (client,
1044 GNUNET_SERVICE_client_continue (client);
1047 if (GNUNET_YES == peer->destroy_flag)
1050 GST_send_operation_fail_msg (client,
1052 "Peer is being destroyed");
1053 GNUNET_SERVICE_client_continue (client);
1056 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1060 GST_send_operation_fail_msg (client,
1062 "Compression error");
1063 GNUNET_SERVICE_client_continue (client);
1066 if (GNUNET_NO == peer->details.local.is_running)
1068 emsg = update_peer_config (peer,
1071 GST_send_operation_fail_msg (client,
1074 GST_send_operation_success_msg (client,
1076 GNUNET_SERVICE_client_continue (client);
1077 GNUNET_free_non_null (emsg);
1080 prc = GNUNET_new (struct PeerReconfigureContext);
1082 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1086 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1087 "Error trying to stop peer %u asynchronously\n",
1089 LOG (GNUNET_ERROR_TYPE_ERROR,
1092 GST_send_operation_fail_msg (client,
1095 GNUNET_SERVICE_client_continue (client);
1101 prc->peer_id = peer_id;
1103 prc->client = client;
1104 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1107 GNUNET_SERVICE_client_continue (client);
1112 * Frees the ManageServiceContext queue
1117 while (NULL != mctx_head)
1118 cleanup_mctx (mctx_head);
1123 * Returns a string interpretation of @a rs.
1125 * @param rs the request status from ARM
1126 * @return a string interpretation of the request status
1129 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1133 case GNUNET_ARM_REQUEST_SENT_OK:
1134 return _("Message was sent successfully");
1135 case GNUNET_ARM_REQUEST_DISCONNECTED:
1136 return _("We disconnected from ARM before we could send a request");
1138 return _("Unknown request status");
1143 * Returns a string interpretation of the @a result.
1145 * @param result the arm result
1146 * @return a string interpretation
1149 arm_ret_string (enum GNUNET_ARM_Result result)
1153 case GNUNET_ARM_RESULT_STOPPED:
1154 return _("%s is stopped");
1155 case GNUNET_ARM_RESULT_STARTING:
1156 return _("%s is starting");
1157 case GNUNET_ARM_RESULT_STOPPING:
1158 return _("%s is stopping");
1159 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1160 return _("%s is starting already");
1161 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1162 return _("%s is stopping already");
1163 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1164 return _("%s is started already");
1165 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1166 return _("%s is stopped already");
1167 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1168 return _("%s service is not known to ARM");
1169 case GNUNET_ARM_RESULT_START_FAILED:
1170 return _("%s service failed to start");
1171 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1172 return _("%s service can't be started because ARM is shutting down");
1174 return _("%.s Unknown result code.");
1179 * Function called in response to a start/stop request.
1180 * Will be called when request was not sent successfully,
1181 * or when a reply comes. If the request was not sent successfully,
1182 * @a rs will indicate that, and @a result will be undefined.
1184 * @param cls ManageServiceContext
1185 * @param rs status of the request
1186 * @param result result of the operation
1189 service_manage_result_cb (void *cls,
1190 enum GNUNET_ARM_RequestStatus rs,
1191 enum GNUNET_ARM_Result result)
1193 struct ManageServiceContext *mctx = cls;
1197 if (GNUNET_YES == mctx->expired)
1199 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1201 GNUNET_asprintf (&emsg,
1202 "Error communicating with Peer %u's ARM: %s",
1204 arm_req_string (rs));
1207 if (1 == mctx->start)
1208 goto service_start_check;
1209 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1210 || (GNUNET_ARM_RESULT_STOPPING == result)
1211 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1212 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1214 /* stopping a service failed */
1215 GNUNET_asprintf (&emsg,
1216 arm_ret_string (result),
1220 /* service stopped successfully */
1223 service_start_check:
1224 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1225 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1226 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1228 /* starting a service failed */
1229 GNUNET_asprintf (&emsg,
1230 arm_ret_string (result),
1234 /* service started successfully */
1239 LOG_DEBUG ("%s\n", emsg);
1240 GST_send_operation_fail_msg (mctx->client,
1245 GST_send_operation_success_msg (mctx->client,
1247 GNUNET_free_non_null (emsg);
1248 cleanup_mctx (mctx);
1253 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1255 * @param cls identification of client
1256 * @param msg the actual message
1257 * @return #GNUNET_OK if @a msg is well-formed
1260 check_manage_peer_service (void *cls,
1261 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1264 const char* service;
1266 msize = ntohs (msg->header.size);
1267 service = (const char *) &msg[1];
1268 if ('\0' != service[msize - sizeof
1269 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1271 GNUNET_break_op (0);
1272 return GNUNET_SYSERR;
1276 GNUNET_break_op (0);
1277 return GNUNET_SYSERR;
1284 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1286 * @param cls identification of client
1287 * @param msg the actual message
1290 handle_manage_peer_service (void *cls,
1291 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1293 struct GNUNET_SERVICE_Client *client = cls;
1294 const char* service;
1297 struct GNUNET_ARM_Handle *ah;
1298 struct ManageServiceContext *mctx;
1299 struct ForwardedOperationContext *fopc;
1303 service = (const char *) &msg[1];
1304 peer_id = ntohl (msg->peer_id);
1305 op_id = GNUNET_ntohll (msg->operation_id);
1306 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1307 service, (unsigned int) peer_id);
1308 if ((GST_peer_list_size <= peer_id)
1309 || (NULL == (peer = GST_peer_list[peer_id])))
1311 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1312 "with id: %u", peer_id);
1315 if (0 == strcasecmp ("arm", service))
1317 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1318 "Use peer start/stop for that");
1321 if (GNUNET_YES == peer->is_remote)
1323 /* Forward the destory message to sub controller */
1324 fopc = GNUNET_new (struct ForwardedOperationContext);
1325 fopc->client = client;
1327 fopc->type = OP_MANAGE_SERVICE;
1328 fopc->operation_id = op_id;
1330 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1334 &GST_forwarded_operation_reply_relay,
1336 fopc->timeout_task =
1337 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1338 &GST_forwarded_operation_timeout,
1340 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1343 GNUNET_SERVICE_client_continue (client);
1346 if (GNUNET_NO == peer->details.local.is_running)
1348 emsg = GNUNET_strdup ("Peer not running\n");
1351 if ((0 != peer->reference_cnt)
1352 && ( (0 == strcasecmp ("core", service))
1353 || (0 == strcasecmp ("transport", service)) ) )
1355 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1356 "since it is required by existing operations",
1360 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1363 GNUNET_asprintf (&emsg,
1364 "Cannot connect to ARM service of peer with id: %u",
1368 mctx = GNUNET_new (struct ManageServiceContext);
1370 peer->reference_cnt++;
1371 mctx->op_id = op_id;
1373 mctx->client = client;
1374 mctx->start = msg->start;
1375 mctx->service = GNUNET_strdup (service);
1376 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1379 if (1 == mctx->start)
1380 GNUNET_ARM_request_service_start (mctx->ah,
1382 GNUNET_OS_INHERIT_STD_ERR,
1383 &service_manage_result_cb,
1386 GNUNET_ARM_request_service_stop (mctx->ah, service,
1387 &service_manage_result_cb,
1389 GNUNET_SERVICE_client_continue (client);
1393 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1394 GST_send_operation_fail_msg (client, op_id, emsg);
1396 GNUNET_SERVICE_client_continue (client);
1401 * Stops and destroys all peers
1404 GST_destroy_peers ()
1409 if (NULL == GST_peer_list)
1411 for (id = 0; id < GST_peer_list_size; id++)
1413 peer = GST_peer_list[id];
1416 /* If destroy flag is set it means that this peer should have been
1417 * destroyed by a context which we destroy before */
1418 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1419 /* counter should be zero as we free all contexts before */
1420 GNUNET_break (0 == peer->reference_cnt);
1421 if ((GNUNET_NO == peer->is_remote) &&
1422 (GNUNET_YES == peer->details.local.is_running))
1423 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1425 for (id = 0; id < GST_peer_list_size; id++)
1427 peer = GST_peer_list[id];
1430 if (GNUNET_NO == peer->is_remote)
1432 if (GNUNET_YES == peer->details.local.is_running)
1433 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1434 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1435 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1439 GNUNET_free_non_null (GST_peer_list);
1440 GST_peer_list = NULL;
1441 GST_peer_list_size = 0;
1446 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1447 * success reply is received from all clients and then sends the success message
1450 * @param cls ForwardedOperationContext
1451 * @param msg the message to relay
1454 shutdown_peers_reply_cb (void *cls,
1455 const struct GNUNET_MessageHeader *msg)
1457 struct ForwardedOperationContext *fo_ctxt = cls;
1458 struct HandlerContext_ShutdownPeers *hc;
1461 GNUNET_assert (0 < hc->nslaves);
1463 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1465 hc->timeout = GNUNET_YES;
1466 if (0 == hc->nslaves)
1468 if (GNUNET_YES == hc->timeout)
1469 GST_send_operation_fail_msg (fo_ctxt->client,
1470 fo_ctxt->operation_id,
1471 "Timeout at a slave controller");
1473 GST_send_operation_success_msg (fo_ctxt->client,
1474 fo_ctxt->operation_id);
1478 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1481 GNUNET_free (fo_ctxt);
1486 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1488 * @param cls identification of the client
1489 * @param msg the actual message
1492 handle_shutdown_peers (void *cls,
1493 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1495 struct GNUNET_SERVICE_Client *client = cls;
1496 struct HandlerContext_ShutdownPeers *hc;
1497 struct Slave *slave;
1498 struct ForwardedOperationContext *fo_ctxt;
1502 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1503 /* Stop and destroy all peers */
1508 /* Forward to all slaves which we have started */
1509 op_id = GNUNET_ntohll (msg->operation_id);
1510 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1511 /* FIXME: have a better implementation where we track which slaves are
1512 started by this controller */
1513 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1515 slave = GST_slave_list[cnt];
1518 if (NULL == slave->controller_proc) /* We didn't start the slave */
1520 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1522 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1523 fo_ctxt->client = client;
1524 fo_ctxt->operation_id = op_id;
1526 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1528 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1529 fo_ctxt->operation_id,
1531 shutdown_peers_reply_cb,
1533 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1537 LOG_DEBUG ("Shutting down peers\n");
1538 GST_destroy_peers ();
1539 if (0 == hc->nslaves)
1541 GST_send_operation_success_msg (client,
1545 GNUNET_SERVICE_client_continue (client);