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/>.
21 * @file testbed/gnunet-service-testbed_peers.c
22 * @brief implementation of TESTBED service that deals with peer management
23 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 #include "gnunet-service-testbed.h"
27 #include "gnunet_arm_service.h"
32 * A list of peers we know about
34 struct Peer **GST_peer_list;
37 * The current number of peers running locally under this controller
39 unsigned int GST_num_local_peers;
43 * Context information to manage peers' services
45 struct ManageServiceContext
50 struct ManageServiceContext *next;
55 struct ManageServiceContext *prev;
58 * The ARM handle of the peer
60 struct GNUNET_ARM_Handle *ah;
63 * peer whose service has to be managed
68 * The client which requested to manage the peer's service
70 struct GNUNET_SERVICE_Client *client;
73 * Name of the service.
78 * The operation id of the associated request
83 * 1 if the service at the peer has to be started; 0 if it has to be stopped
88 * Is this context expired? Do not work on this context if it is set to
96 * Context information for peer re-configure operations
98 struct PeerReconfigureContext
101 * DLL next for inclusoin in peer reconfigure operations list
103 struct PeerReconfigureContext *next;
108 struct PeerReconfigureContext *prev;
111 * The client which gave this operation to us
113 struct GNUNET_SERVICE_Client *client;
116 * The configuration handle to use as the new template
118 struct GNUNET_CONFIGURATION_Handle *cfg;
121 * The id of the operation
126 * The id of the peer which has to be reconfigured
131 * The the peer stopped? Used while cleaning up this context to decide
132 * whether the asynchronous stop request through Testing/ARM API has to be
139 * The DLL head for the peer reconfigure list
141 static struct PeerReconfigureContext *prc_head;
144 * The DLL tail for the peer reconfigure list
146 static struct PeerReconfigureContext *prc_tail;
151 * DLL head for queue of manage service requests
153 static struct ManageServiceContext *mctx_head;
156 * DLL tail for queue of manage service requests
158 static struct ManageServiceContext *mctx_tail;
162 * Adds a peer to the peer array
164 * @param peer the peer to add
167 peer_list_add (struct Peer *peer)
169 if (peer->id >= GST_peer_list_size)
170 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
171 GNUNET_assert (NULL == GST_peer_list[peer->id]);
172 GST_peer_list[peer->id] = peer;
173 if (GNUNET_NO == peer->is_remote)
174 GST_num_local_peers++;
179 * Removes a the give peer from the peer array
181 * @param peer the peer to be removed
184 peer_list_remove (struct Peer *peer)
186 unsigned int orig_size;
189 if (GNUNET_NO == peer->is_remote)
190 GST_num_local_peers--;
191 GST_peer_list[peer->id] = NULL;
192 orig_size = GST_peer_list_size;
193 while (GST_peer_list_size >= LIST_GROW_STEP)
195 for (id = GST_peer_list_size - 1;
196 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
198 if (NULL != GST_peer_list[id])
200 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
202 GST_peer_list_size -= LIST_GROW_STEP;
204 if (orig_size == GST_peer_list_size)
207 GNUNET_realloc (GST_peer_list,
208 sizeof (struct Peer *) * GST_peer_list_size);
213 * The task to be executed if the forwarded peer create operation has been
216 * @param cls the FowardedOperationContext
219 peer_create_forward_timeout (void *cls)
221 struct ForwardedOperationContext *fopc = cls;
223 GNUNET_free (fopc->cls);
224 GST_forwarded_operation_timeout (fopc);
229 * Callback to be called when forwarded peer create operation is successfull. We
230 * have to relay the reply msg back to the client
232 * @param cls ForwardedOperationContext
233 * @param msg the peer create success message
236 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
238 struct ForwardedOperationContext *fopc = cls;
239 struct Peer *remote_peer;
241 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
243 GNUNET_assert (NULL != fopc->cls);
244 remote_peer = fopc->cls;
245 peer_list_add (remote_peer);
247 GST_forwarded_operation_reply_relay (fopc,
253 * Function to destroy a peer
255 * @param peer the peer structure to destroy
258 GST_destroy_peer (struct Peer *peer)
260 GNUNET_break (0 == peer->reference_cnt);
261 if (GNUNET_YES == peer->is_remote)
263 peer_list_remove (peer);
267 if (GNUNET_YES == peer->details.local.is_running)
269 GNUNET_TESTING_peer_stop (peer->details.local.peer);
270 peer->details.local.is_running = GNUNET_NO;
272 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
273 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
274 peer_list_remove (peer);
280 * Cleanup the context information created for managing a peer's service
282 * @param mctx the ManageServiceContext
285 cleanup_mctx (struct ManageServiceContext *mctx)
287 mctx->expired = GNUNET_YES;
288 GNUNET_CONTAINER_DLL_remove (mctx_head,
291 GNUNET_ARM_disconnect (mctx->ah);
292 GNUNET_assert (0 < mctx->peer->reference_cnt);
293 mctx->peer->reference_cnt--;
294 if ( (GNUNET_YES == mctx->peer->destroy_flag) &&
295 (0 == mctx->peer->reference_cnt) )
296 GST_destroy_peer (mctx->peer);
297 GNUNET_free (mctx->service);
305 * @param peer the peer to stop
306 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
309 stop_peer (struct Peer *peer)
311 GNUNET_assert (GNUNET_NO == peer->is_remote);
312 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
313 return GNUNET_SYSERR;
314 peer->details.local.is_running = GNUNET_NO;
320 * Cleans up the given PeerReconfigureContext
322 * @param prc the PeerReconfigureContext
325 cleanup_prc (struct PeerReconfigureContext *prc)
329 if (VALID_PEER_ID (prc->peer_id))
331 peer = GST_peer_list [prc->peer_id];
332 if (1 != prc->stopped)
334 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
335 stop_peer (peer); /* Stop the peer synchronously */
338 if (NULL != prc->cfg)
339 GNUNET_CONFIGURATION_destroy (prc->cfg);
340 GNUNET_CONTAINER_DLL_remove (prc_head,
348 * Notify peers subsystem that @a client disconnected.
350 * @param client the client that disconnected
353 GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
355 struct ForwardedOperationContext *fopc;
356 struct ForwardedOperationContext *fopcn;
357 struct ManageServiceContext *mctx;
358 struct ManageServiceContext *mctxn;
359 struct PeerReconfigureContext *prc;
360 struct PeerReconfigureContext *prcn;
362 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
365 if (client == fopc->client)
367 if (OP_PEER_CREATE == fopc->type)
368 GNUNET_free (fopc->cls);
369 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
370 GST_forwarded_operation_timeout (fopc);
373 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
376 if (client == mctx->client)
379 for (prc = prc_head; NULL != prc; prc = prcn)
382 if (client == prc->client)
389 * Callback to be called when forwarded peer destroy operation is successfull. We
390 * have to relay the reply msg back to the client
392 * @param cls ForwardedOperationContext
393 * @param msg the peer create success message
396 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
398 struct ForwardedOperationContext *fopc = cls;
399 struct Peer *remote_peer;
401 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
404 remote_peer = fopc->cls;
405 GNUNET_assert (NULL != remote_peer);
406 remote_peer->destroy_flag = GNUNET_YES;
407 if (0 == remote_peer->reference_cnt)
408 GST_destroy_peer (remote_peer);
410 GST_forwarded_operation_reply_relay (fopc,
416 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
418 * @param cls identification of the client
419 * @param msg the actual message
420 * @return #GNUNET_OK if @a msg is well-formed
423 check_peer_create (void *cls,
424 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
426 return GNUNET_OK; /* checked later */
431 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
433 * @param cls identification of the client
434 * @param msg the actual message
437 handle_peer_create (void *cls,
438 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
440 struct GNUNET_SERVICE_Client *client = cls;
441 struct GNUNET_MQ_Envelope *env;
442 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
443 struct GNUNET_CONFIGURATION_Handle *cfg;
444 struct ForwardedOperationContext *fo_ctxt;
451 host_id = ntohl (msg->host_id);
452 peer_id = ntohl (msg->peer_id);
453 if (VALID_PEER_ID (peer_id))
455 (void) GNUNET_asprintf (&emsg,
456 "Peer with ID %u already exists",
458 GST_send_operation_fail_msg (client,
459 GNUNET_ntohll (msg->operation_id),
462 GNUNET_SERVICE_client_continue (client);
465 if (UINT32_MAX == peer_id)
467 GST_send_operation_fail_msg (client,
468 GNUNET_ntohll (msg->operation_id),
469 "Cannot create peer with given ID");
470 GNUNET_SERVICE_client_continue (client);
473 if (host_id == GST_context->host_id)
475 /* We are responsible for this peer */
476 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
480 GNUNET_SERVICE_client_drop (client);
483 GNUNET_CONFIGURATION_set_value_number (cfg,
486 (unsigned long long) peer_id);
488 GNUNET_CONFIGURATION_set_value_number (cfg,
491 (unsigned long long) peer_id);
492 peer = GNUNET_new (struct Peer);
493 peer->is_remote = GNUNET_NO;
494 peer->details.local.cfg = cfg;
496 LOG_DEBUG ("Creating peer with id: %u\n",
497 (unsigned int) peer->id);
498 peer->details.local.peer =
499 GNUNET_TESTING_peer_configure (GST_context->system,
500 peer->details.local.cfg, peer->id,
503 if (NULL == peer->details.local.peer)
505 LOG (GNUNET_ERROR_TYPE_WARNING,
506 "Configuring peer failed: %s\n",
511 GNUNET_SERVICE_client_drop (client);
514 peer->details.local.is_running = GNUNET_NO;
515 peer_list_add (peer);
516 env = GNUNET_MQ_msg (reply,
517 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
518 reply->peer_id = msg->peer_id;
519 reply->operation_id = msg->operation_id;
520 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
522 GNUNET_SERVICE_client_continue (client);
526 /* Forward peer create request */
527 route = GST_find_dest_route (host_id);
531 GNUNET_SERVICE_client_continue (client); // ?
534 peer = GNUNET_new (struct Peer);
535 peer->is_remote = GNUNET_YES;
537 peer->details.remote.slave = GST_slave_list[route->dest];
538 peer->details.remote.remote_host_id = host_id;
539 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
540 fo_ctxt->client = client;
541 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
543 fo_ctxt->type = OP_PEER_CREATE;
545 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
546 [route->dest]->controller,
547 fo_ctxt->operation_id,
549 &peer_create_success_cb,
551 fo_ctxt->timeout_task =
552 GNUNET_SCHEDULER_add_delayed (GST_timeout,
553 &peer_create_forward_timeout,
555 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
558 GNUNET_SERVICE_client_continue (client);
563 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
565 * @param cls identification of the client
566 * @param msg the actual message
569 handle_peer_destroy (void *cls,
570 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
572 struct GNUNET_SERVICE_Client *client = cls;
573 struct ForwardedOperationContext *fopc;
577 peer_id = ntohl (msg->peer_id);
578 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %llu\n",
579 (unsigned int) peer_id,
580 (unsigned long long) GNUNET_ntohll (msg->operation_id));
581 if (!VALID_PEER_ID (peer_id))
583 LOG (GNUNET_ERROR_TYPE_ERROR,
584 "Asked to destroy a non existent peer with id: %u\n", peer_id);
585 GST_send_operation_fail_msg (client,
586 GNUNET_ntohll (msg->operation_id),
587 "Peer doesn't exist");
588 GNUNET_SERVICE_client_continue (client);
591 peer = GST_peer_list[peer_id];
592 if (GNUNET_YES == peer->is_remote)
594 /* Forward the destory message to sub controller */
595 fopc = GNUNET_new (struct ForwardedOperationContext);
596 fopc->client = client;
598 fopc->type = OP_PEER_DESTROY;
599 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
601 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
605 &peer_destroy_success_cb,
608 GNUNET_SCHEDULER_add_delayed (GST_timeout,
609 &GST_forwarded_operation_timeout,
611 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
614 GNUNET_SERVICE_client_continue (client);
617 peer->destroy_flag = GNUNET_YES;
618 if (0 == peer->reference_cnt)
619 GST_destroy_peer (peer);
621 LOG (GNUNET_ERROR_TYPE_DEBUG,
622 "Delaying peer destroy as peer is currently in use\n");
623 GST_send_operation_success_msg (client,
624 GNUNET_ntohll (msg->operation_id));
625 GNUNET_SERVICE_client_continue (client);
632 * @param peer the peer to start
633 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
636 start_peer (struct Peer *peer)
638 GNUNET_assert (GNUNET_NO == peer->is_remote);
639 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
640 return GNUNET_SYSERR;
641 peer->details.local.is_running = GNUNET_YES;
647 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
649 * @param cls identification of the client
650 * @param msg the actual message
653 handle_peer_start (void *cls,
654 const struct GNUNET_TESTBED_PeerStartMessage *msg)
656 struct GNUNET_SERVICE_Client *client = cls;
657 struct GNUNET_MQ_Envelope *env;
658 struct GNUNET_TESTBED_PeerEventMessage *reply;
659 struct ForwardedOperationContext *fopc;
663 peer_id = ntohl (msg->peer_id);
664 if (! VALID_PEER_ID (peer_id))
667 LOG (GNUNET_ERROR_TYPE_ERROR,
668 "Asked to start a non existent peer with id: %u\n",
670 GNUNET_SERVICE_client_continue (client);
673 peer = GST_peer_list[peer_id];
674 if (GNUNET_YES == peer->is_remote)
676 fopc = GNUNET_new (struct ForwardedOperationContext);
677 fopc->client = client;
678 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
679 fopc->type = OP_PEER_START;
681 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
683 fopc->operation_id, &msg->header,
684 &GST_forwarded_operation_reply_relay,
687 GNUNET_SCHEDULER_add_delayed (GST_timeout,
688 &GST_forwarded_operation_timeout,
690 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
693 GNUNET_SERVICE_client_continue (client);
696 if (GNUNET_OK != start_peer (peer))
698 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
700 GNUNET_SERVICE_client_continue (client);
703 env = GNUNET_MQ_msg (reply,
704 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
705 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
706 reply->host_id = htonl (GST_context->host_id);
707 reply->peer_id = msg->peer_id;
708 reply->operation_id = msg->operation_id;
709 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
711 GNUNET_SERVICE_client_continue (client);
716 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
718 * @param cls identification of the client
719 * @param msg the actual message
722 handle_peer_stop (void *cls,
723 const struct GNUNET_TESTBED_PeerStopMessage *msg)
725 struct GNUNET_SERVICE_Client *client = cls;
726 struct GNUNET_MQ_Envelope *env;
727 struct GNUNET_TESTBED_PeerEventMessage *reply;
728 struct ForwardedOperationContext *fopc;
732 peer_id = ntohl (msg->peer_id);
733 LOG (GNUNET_ERROR_TYPE_DEBUG,
734 "Received PEER_STOP for peer %u\n",
735 (unsigned int) peer_id);
736 if (! VALID_PEER_ID (peer_id))
738 GST_send_operation_fail_msg (client,
739 GNUNET_ntohll (msg->operation_id),
741 GNUNET_SERVICE_client_continue (client);
744 peer = GST_peer_list[peer_id];
745 if (GNUNET_YES == peer->is_remote)
747 LOG (GNUNET_ERROR_TYPE_DEBUG,
748 "Forwarding PEER_STOP for peer %u\n",
749 (unsigned int) peer_id);
750 fopc = GNUNET_new (struct ForwardedOperationContext);
751 fopc->client = client;
752 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
753 fopc->type = OP_PEER_STOP;
755 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
759 &GST_forwarded_operation_reply_relay,
762 GNUNET_SCHEDULER_add_delayed (GST_timeout,
763 &GST_forwarded_operation_timeout,
765 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
768 GNUNET_SERVICE_client_continue (client);
771 if (GNUNET_OK != stop_peer (peer))
773 LOG (GNUNET_ERROR_TYPE_WARNING,
774 "Stopping peer %u failed\n",
775 (unsigned int) peer_id);
776 GST_send_operation_fail_msg (client,
777 GNUNET_ntohll (msg->operation_id),
779 GNUNET_SERVICE_client_continue (client);
782 LOG (GNUNET_ERROR_TYPE_DEBUG,
783 "Peer %u successfully stopped\n",
784 (unsigned int) peer_id);
785 env = GNUNET_MQ_msg (reply,
786 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
787 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
788 reply->host_id = htonl (GST_context->host_id);
789 reply->peer_id = msg->peer_id;
790 reply->operation_id = msg->operation_id;
791 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
793 GNUNET_SERVICE_client_continue (client);
794 GNUNET_TESTING_peer_wait (peer->details.local.peer);
799 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
801 * @param cls identification of the client
802 * @param msg the actual message
805 handle_peer_get_config (void *cls,
806 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
808 struct GNUNET_SERVICE_Client *client = cls;
809 struct GNUNET_MQ_Envelope *env;
810 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
811 struct ForwardedOperationContext *fopc;
819 peer_id = ntohl (msg->peer_id);
820 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
821 (unsigned int) peer_id);
822 if (!VALID_PEER_ID (peer_id))
824 GST_send_operation_fail_msg (client,
825 GNUNET_ntohll (msg->operation_id),
827 GNUNET_SERVICE_client_continue (client);
830 peer = GST_peer_list[peer_id];
831 if (GNUNET_YES == peer->is_remote)
833 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
834 (unsigned int) peer_id);
835 fopc = GNUNET_new (struct ForwardedOperationContext);
836 fopc->client = client;
837 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
838 fopc->type = OP_PEER_INFO;
840 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
844 &GST_forwarded_operation_reply_relay,
847 GNUNET_SCHEDULER_add_delayed (GST_timeout,
848 &GST_forwarded_operation_timeout,
850 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
853 GNUNET_SERVICE_client_continue (client);
856 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
859 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
861 xc_size = GNUNET_TESTBED_compress_config_ (config,
864 GNUNET_free (config);
865 env = GNUNET_MQ_msg_extra (reply,
867 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
868 reply->peer_id = msg->peer_id;
869 reply->operation_id = msg->operation_id;
870 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
871 &reply->peer_identity);
872 reply->config_size = htons ((uint16_t) c_size);
873 GNUNET_memcpy (&reply[1],
876 GNUNET_free (xconfig);
877 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
879 GNUNET_SERVICE_client_continue (client);
884 * Cleans up the Peer reconfigure context list
889 while (NULL != prc_head)
890 cleanup_prc (prc_head);
895 * Update peer configuration
897 * @param peer the peer to update
898 * @param cfg the new configuration
899 * @return error message (freshly allocated); NULL upon success
902 update_peer_config (struct Peer *peer,
903 struct GNUNET_CONFIGURATION_Handle *cfg)
907 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
908 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
909 peer->details.local.cfg = cfg;
911 peer->details.local.peer
912 = GNUNET_TESTING_peer_configure (GST_context->system,
913 peer->details.local.cfg,
922 * Callback to inform whether the peer is running or stopped.
924 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
925 * @param p the respective peer whose status is being reported
926 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
930 prc_stop_cb (void *cls,
931 struct GNUNET_TESTING_Peer *p,
934 struct PeerReconfigureContext *prc = cls;
938 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
939 peer = GST_peer_list [prc->peer_id];
940 GNUNET_assert (GNUNET_NO == peer->is_remote);
941 emsg = update_peer_config (peer, prc->cfg);
946 GST_send_operation_fail_msg (prc->client,
951 if (GNUNET_OK != start_peer (peer))
953 GST_send_operation_fail_msg (prc->client,
955 "Failed to start reconfigured peer");
958 GST_send_operation_success_msg (prc->client,
968 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
970 * @param cls identification of the client
971 * @param msg the actual message
972 * @return #GNUNET_OK if @a msg is well-formed
975 check_peer_reconfigure (void *cls,
976 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
978 return GNUNET_OK; /* checked later */
983 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
984 * Should stop the peer asyncronously, destroy it and create it again with the
987 * @param cls identification of the client
988 * @param msg the actual message
991 handle_peer_reconfigure (void *cls,
992 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
994 struct GNUNET_SERVICE_Client *client = cls;
996 struct GNUNET_CONFIGURATION_Handle *cfg;
997 struct ForwardedOperationContext *fopc;
998 struct PeerReconfigureContext *prc;
1003 peer_id = ntohl (msg->peer_id);
1004 op_id = GNUNET_ntohll (msg->operation_id);
1005 if (! VALID_PEER_ID (peer_id))
1008 GST_send_operation_fail_msg (client,
1011 GNUNET_SERVICE_client_continue (client);
1014 peer = GST_peer_list[peer_id];
1015 if (GNUNET_YES == peer->is_remote)
1017 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1018 fopc = GNUNET_new (struct ForwardedOperationContext);
1019 fopc->client = client;
1020 fopc->operation_id = op_id;
1021 fopc->type = OP_PEER_RECONFIGURE;
1023 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1027 &GST_forwarded_operation_reply_relay,
1029 fopc->timeout_task =
1030 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1031 &GST_forwarded_operation_timeout,
1033 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1036 GNUNET_SERVICE_client_continue (client);
1039 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1040 (unsigned int) peer_id);
1041 if (0 < peer->reference_cnt)
1044 GST_send_operation_fail_msg (client,
1047 GNUNET_SERVICE_client_continue (client);
1050 if (GNUNET_YES == peer->destroy_flag)
1053 GST_send_operation_fail_msg (client,
1055 "Peer is being destroyed");
1056 GNUNET_SERVICE_client_continue (client);
1059 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1063 GST_send_operation_fail_msg (client,
1065 "Compression error");
1066 GNUNET_SERVICE_client_continue (client);
1069 if (GNUNET_NO == peer->details.local.is_running)
1071 emsg = update_peer_config (peer,
1074 GST_send_operation_fail_msg (client,
1077 GST_send_operation_success_msg (client,
1079 GNUNET_SERVICE_client_continue (client);
1080 GNUNET_free_non_null (emsg);
1083 prc = GNUNET_new (struct PeerReconfigureContext);
1085 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1089 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1090 "Error trying to stop peer %u asynchronously\n",
1092 LOG (GNUNET_ERROR_TYPE_ERROR,
1095 GST_send_operation_fail_msg (client,
1098 GNUNET_SERVICE_client_continue (client);
1104 prc->peer_id = peer_id;
1106 prc->client = client;
1107 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1110 GNUNET_SERVICE_client_continue (client);
1115 * Frees the ManageServiceContext queue
1120 while (NULL != mctx_head)
1121 cleanup_mctx (mctx_head);
1126 * Returns a string interpretation of @a rs.
1128 * @param rs the request status from ARM
1129 * @return a string interpretation of the request status
1132 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1136 case GNUNET_ARM_REQUEST_SENT_OK:
1137 return _("Message was sent successfully");
1138 case GNUNET_ARM_REQUEST_DISCONNECTED:
1139 return _("We disconnected from ARM before we could send a request");
1141 return _("Unknown request status");
1146 * Returns a string interpretation of the @a result.
1148 * @param result the arm result
1149 * @return a string interpretation
1152 arm_ret_string (enum GNUNET_ARM_Result result)
1156 case GNUNET_ARM_RESULT_STOPPED:
1157 return _("%s is stopped");
1158 case GNUNET_ARM_RESULT_STARTING:
1159 return _("%s is starting");
1160 case GNUNET_ARM_RESULT_STOPPING:
1161 return _("%s is stopping");
1162 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1163 return _("%s is starting already");
1164 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1165 return _("%s is stopping already");
1166 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1167 return _("%s is started already");
1168 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1169 return _("%s is stopped already");
1170 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1171 return _("%s service is not known to ARM");
1172 case GNUNET_ARM_RESULT_START_FAILED:
1173 return _("%s service failed to start");
1174 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1175 return _("%s service can't be started because ARM is shutting down");
1177 return _("%.s Unknown result code.");
1182 * Function called in response to a start/stop request.
1183 * Will be called when request was not sent successfully,
1184 * or when a reply comes. If the request was not sent successfully,
1185 * @a rs will indicate that, and @a result will be undefined.
1187 * @param cls ManageServiceContext
1188 * @param rs status of the request
1189 * @param result result of the operation
1192 service_manage_result_cb (void *cls,
1193 enum GNUNET_ARM_RequestStatus rs,
1194 enum GNUNET_ARM_Result result)
1196 struct ManageServiceContext *mctx = cls;
1200 if (GNUNET_YES == mctx->expired)
1202 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1204 GNUNET_asprintf (&emsg,
1205 "Error communicating with Peer %u's ARM: %s",
1207 arm_req_string (rs));
1210 if (1 == mctx->start)
1211 goto service_start_check;
1212 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1213 || (GNUNET_ARM_RESULT_STOPPING == result)
1214 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1215 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1217 /* stopping a service failed */
1218 GNUNET_asprintf (&emsg,
1219 arm_ret_string (result),
1223 /* service stopped successfully */
1226 service_start_check:
1227 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1228 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1229 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1231 /* starting a service failed */
1232 GNUNET_asprintf (&emsg,
1233 arm_ret_string (result),
1237 /* service started successfully */
1242 LOG_DEBUG ("%s\n", emsg);
1243 GST_send_operation_fail_msg (mctx->client,
1248 GST_send_operation_success_msg (mctx->client,
1250 GNUNET_free_non_null (emsg);
1251 cleanup_mctx (mctx);
1256 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1258 * @param cls identification of client
1259 * @param msg the actual message
1260 * @return #GNUNET_OK if @a msg is well-formed
1263 check_manage_peer_service (void *cls,
1264 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1267 const char* service;
1269 msize = ntohs (msg->header.size);
1270 service = (const char *) &msg[1];
1271 if ('\0' != service[msize - sizeof
1272 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1274 GNUNET_break_op (0);
1275 return GNUNET_SYSERR;
1279 GNUNET_break_op (0);
1280 return GNUNET_SYSERR;
1287 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
1289 * @param cls identification of client
1290 * @param msg the actual message
1293 handle_manage_peer_service (void *cls,
1294 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1296 struct GNUNET_SERVICE_Client *client = cls;
1297 const char* service;
1300 struct GNUNET_ARM_Handle *ah;
1301 struct ManageServiceContext *mctx;
1302 struct ForwardedOperationContext *fopc;
1306 service = (const char *) &msg[1];
1307 peer_id = ntohl (msg->peer_id);
1308 op_id = GNUNET_ntohll (msg->operation_id);
1309 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1310 service, (unsigned int) peer_id);
1311 if ((GST_peer_list_size <= peer_id)
1312 || (NULL == (peer = GST_peer_list[peer_id])))
1314 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1315 "with id: %u", peer_id);
1318 if (0 == strcasecmp ("arm", service))
1320 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1321 "Use peer start/stop for that");
1324 if (GNUNET_YES == peer->is_remote)
1326 /* Forward the destory message to sub controller */
1327 fopc = GNUNET_new (struct ForwardedOperationContext);
1328 fopc->client = client;
1330 fopc->type = OP_MANAGE_SERVICE;
1331 fopc->operation_id = op_id;
1333 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1337 &GST_forwarded_operation_reply_relay,
1339 fopc->timeout_task =
1340 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1341 &GST_forwarded_operation_timeout,
1343 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1346 GNUNET_SERVICE_client_continue (client);
1349 if (GNUNET_NO == peer->details.local.is_running)
1351 emsg = GNUNET_strdup ("Peer not running\n");
1354 if ((0 != peer->reference_cnt)
1355 && ( (0 == strcasecmp ("core", service))
1356 || (0 == strcasecmp ("transport", service)) ) )
1358 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1359 "since it is required by existing operations",
1363 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1366 GNUNET_asprintf (&emsg,
1367 "Cannot connect to ARM service of peer with id: %u",
1371 mctx = GNUNET_new (struct ManageServiceContext);
1373 peer->reference_cnt++;
1374 mctx->op_id = op_id;
1376 mctx->client = client;
1377 mctx->start = msg->start;
1378 mctx->service = GNUNET_strdup (service);
1379 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1382 if (1 == mctx->start)
1383 GNUNET_ARM_request_service_start (mctx->ah,
1385 GNUNET_OS_INHERIT_STD_ERR,
1386 &service_manage_result_cb,
1389 GNUNET_ARM_request_service_stop (mctx->ah, service,
1390 &service_manage_result_cb,
1392 GNUNET_SERVICE_client_continue (client);
1396 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1397 GST_send_operation_fail_msg (client, op_id, emsg);
1399 GNUNET_SERVICE_client_continue (client);
1404 * Stops and destroys all peers
1407 GST_destroy_peers ()
1412 if (NULL == GST_peer_list)
1414 for (id = 0; id < GST_peer_list_size; id++)
1416 peer = GST_peer_list[id];
1419 /* If destroy flag is set it means that this peer should have been
1420 * destroyed by a context which we destroy before */
1421 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1422 /* counter should be zero as we free all contexts before */
1423 GNUNET_break (0 == peer->reference_cnt);
1424 if ((GNUNET_NO == peer->is_remote) &&
1425 (GNUNET_YES == peer->details.local.is_running))
1426 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1428 for (id = 0; id < GST_peer_list_size; id++)
1430 peer = GST_peer_list[id];
1433 if (GNUNET_NO == peer->is_remote)
1435 if (GNUNET_YES == peer->details.local.is_running)
1436 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1437 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1438 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1442 GNUNET_free_non_null (GST_peer_list);
1443 GST_peer_list = NULL;
1444 GST_peer_list_size = 0;
1449 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1450 * success reply is received from all clients and then sends the success message
1453 * @param cls ForwardedOperationContext
1454 * @param msg the message to relay
1457 shutdown_peers_reply_cb (void *cls,
1458 const struct GNUNET_MessageHeader *msg)
1460 struct ForwardedOperationContext *fo_ctxt = cls;
1461 struct HandlerContext_ShutdownPeers *hc;
1464 GNUNET_assert (0 < hc->nslaves);
1466 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1468 hc->timeout = GNUNET_YES;
1469 if (0 == hc->nslaves)
1471 if (GNUNET_YES == hc->timeout)
1472 GST_send_operation_fail_msg (fo_ctxt->client,
1473 fo_ctxt->operation_id,
1474 "Timeout at a slave controller");
1476 GST_send_operation_success_msg (fo_ctxt->client,
1477 fo_ctxt->operation_id);
1481 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1484 GNUNET_free (fo_ctxt);
1489 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1491 * @param cls identification of the client
1492 * @param msg the actual message
1495 handle_shutdown_peers (void *cls,
1496 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1498 struct GNUNET_SERVICE_Client *client = cls;
1499 struct HandlerContext_ShutdownPeers *hc;
1500 struct Slave *slave;
1501 struct ForwardedOperationContext *fo_ctxt;
1505 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1506 /* Stop and destroy all peers */
1511 /* Forward to all slaves which we have started */
1512 op_id = GNUNET_ntohll (msg->operation_id);
1513 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1514 /* FIXME: have a better implementation where we track which slaves are
1515 started by this controller */
1516 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1518 slave = GST_slave_list[cnt];
1521 if (NULL == slave->controller_proc) /* We didn't start the slave */
1523 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1525 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1526 fo_ctxt->client = client;
1527 fo_ctxt->operation_id = op_id;
1529 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1531 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1532 fo_ctxt->operation_id,
1534 shutdown_peers_reply_cb,
1536 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1540 LOG_DEBUG ("Shutting down peers\n");
1541 GST_destroy_peers ();
1542 if (0 == hc->nslaves)
1544 GST_send_operation_success_msg (client,
1548 GNUNET_SERVICE_client_continue (client);