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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
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_SERVER_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_SERVER_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, msg);
254 * Function to destroy a peer
256 * @param peer the peer structure to destroy
259 GST_destroy_peer (struct Peer *peer)
261 GNUNET_break (0 == peer->reference_cnt);
262 if (GNUNET_YES == peer->is_remote)
264 peer_list_remove (peer);
268 if (GNUNET_YES == peer->details.local.is_running)
270 GNUNET_TESTING_peer_stop (peer->details.local.peer);
271 peer->details.local.is_running = GNUNET_NO;
273 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
274 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
275 peer_list_remove (peer);
281 * Callback to be called when forwarded peer destroy operation is successfull. We
282 * have to relay the reply msg back to the client
284 * @param cls ForwardedOperationContext
285 * @param msg the peer create success message
288 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
290 struct ForwardedOperationContext *fopc = cls;
291 struct Peer *remote_peer;
293 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
296 remote_peer = fopc->cls;
297 GNUNET_assert (NULL != remote_peer);
298 remote_peer->destroy_flag = GNUNET_YES;
299 if (0 == remote_peer->reference_cnt)
300 GST_destroy_peer (remote_peer);
302 GST_forwarded_operation_reply_relay (fopc, msg);
307 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
310 * @param client identification of the client
311 * @param message the actual message
314 GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
315 const struct GNUNET_MessageHeader *message)
317 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
318 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
319 struct GNUNET_CONFIGURATION_Handle *cfg;
320 struct ForwardedOperationContext *fo_ctxt;
329 msize = ntohs (message->size);
330 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
332 GNUNET_break (0); /* We need configuration */
333 GNUNET_SERVER_receive_done (client, GNUNET_OK);
336 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
337 host_id = ntohl (msg->host_id);
338 peer_id = ntohl (msg->peer_id);
339 if (VALID_PEER_ID (peer_id))
341 (void) GNUNET_asprintf (&emsg, "Peer with ID %u already exists", peer_id);
342 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
345 GNUNET_SERVER_receive_done (client, GNUNET_OK);
348 if (UINT32_MAX == peer_id)
350 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
351 "Cannot create peer with given ID");
352 GNUNET_SERVER_receive_done (client, GNUNET_OK);
355 if (host_id == GST_context->host_id)
357 /* We are responsible for this peer */
358 cfg = GNUNET_TESTBED_extract_config_ (message);
362 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
365 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
366 (unsigned long long) peer_id);
368 GNUNET_CONFIGURATION_set_value_number (cfg, "PATHS", "PEERID",
369 (unsigned long long) peer_id);
370 peer = GNUNET_new (struct Peer);
371 peer->is_remote = GNUNET_NO;
372 peer->details.local.cfg = cfg;
374 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
375 peer->details.local.peer =
376 GNUNET_TESTING_peer_configure (GST_context->system,
377 peer->details.local.cfg, peer->id,
380 if (NULL == peer->details.local.peer)
382 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
386 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
389 peer->details.local.is_running = GNUNET_NO;
390 peer_list_add (peer);
391 reply = GNUNET_new (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage);
393 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
395 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
396 reply->peer_id = msg->peer_id;
397 reply->operation_id = msg->operation_id;
398 GST_queue_message (client, &reply->header);
399 GNUNET_SERVER_receive_done (client, GNUNET_OK);
403 /* Forward peer create request */
404 route = GST_find_dest_route (host_id);
408 GNUNET_SERVER_receive_done (client, GNUNET_OK);
411 peer = GNUNET_new (struct Peer);
412 peer->is_remote = GNUNET_YES;
414 peer->details.remote.slave = GST_slave_list[route->dest];
415 peer->details.remote.remote_host_id = host_id;
416 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
417 GNUNET_SERVER_client_keep (client);
418 fo_ctxt->client = client;
419 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
421 fo_ctxt->type = OP_PEER_CREATE;
423 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
424 [route->dest]->controller,
425 fo_ctxt->operation_id,
427 peer_create_success_cb, fo_ctxt);
428 fo_ctxt->timeout_task =
429 GNUNET_SCHEDULER_add_delayed (GST_timeout,
430 &peer_create_forward_timeout,
432 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
433 GNUNET_SERVER_receive_done (client, GNUNET_OK);
438 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
441 * @param client identification of the client
442 * @param message the actual message
445 GST_handle_peer_destroy (void *cls,
446 struct GNUNET_SERVER_Client *client,
447 const struct GNUNET_MessageHeader *message)
449 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
450 struct ForwardedOperationContext *fopc;
454 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
455 peer_id = ntohl (msg->peer_id);
456 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %llu\n",
457 (unsigned int) peer_id,
458 (unsigned long long) GNUNET_ntohll (msg->operation_id));
459 if (!VALID_PEER_ID (peer_id))
461 LOG (GNUNET_ERROR_TYPE_ERROR,
462 "Asked to destroy a non existent peer with id: %u\n", peer_id);
463 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
464 "Peer doesn't exist");
465 GNUNET_SERVER_receive_done (client, GNUNET_OK);
468 peer = GST_peer_list[peer_id];
469 if (GNUNET_YES == peer->is_remote)
471 /* Forward the destory message to sub controller */
472 fopc = GNUNET_new (struct ForwardedOperationContext);
473 GNUNET_SERVER_client_keep (client);
474 fopc->client = client;
476 fopc->type = OP_PEER_DESTROY;
477 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
479 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
481 fopc->operation_id, &msg->header,
482 &peer_destroy_success_cb, fopc);
484 GNUNET_SCHEDULER_add_delayed (GST_timeout,
485 &GST_forwarded_operation_timeout,
487 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
488 GNUNET_SERVER_receive_done (client, GNUNET_OK);
491 peer->destroy_flag = GNUNET_YES;
492 if (0 == peer->reference_cnt)
493 GST_destroy_peer (peer);
495 LOG (GNUNET_ERROR_TYPE_DEBUG,
496 "Delaying peer destroy as peer is currently in use\n");
497 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
498 GNUNET_SERVER_receive_done (client, GNUNET_OK);
505 * @param peer the peer to start
506 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
509 start_peer (struct Peer *peer)
511 GNUNET_assert (GNUNET_NO == peer->is_remote);
512 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
513 return GNUNET_SYSERR;
514 peer->details.local.is_running = GNUNET_YES;
522 * @param peer the peer to stop
523 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
526 stop_peer (struct Peer *peer)
528 GNUNET_assert (GNUNET_NO == peer->is_remote);
529 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
530 return GNUNET_SYSERR;
531 peer->details.local.is_running = GNUNET_NO;
537 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
540 * @param client identification of the client
541 * @param message the actual message
544 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
545 const struct GNUNET_MessageHeader *message)
547 const struct GNUNET_TESTBED_PeerStartMessage *msg;
548 struct GNUNET_TESTBED_PeerEventMessage *reply;
549 struct ForwardedOperationContext *fopc;
553 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
554 peer_id = ntohl (msg->peer_id);
555 if (!VALID_PEER_ID (peer_id))
558 LOG (GNUNET_ERROR_TYPE_ERROR,
559 "Asked to start a non existent peer with id: %u\n", peer_id);
560 GNUNET_SERVER_receive_done (client, GNUNET_OK);
563 peer = GST_peer_list[peer_id];
564 if (GNUNET_YES == peer->is_remote)
566 fopc = GNUNET_new (struct ForwardedOperationContext);
567 GNUNET_SERVER_client_keep (client);
568 fopc->client = client;
569 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
570 fopc->type = OP_PEER_START;
572 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
574 fopc->operation_id, &msg->header,
575 &GST_forwarded_operation_reply_relay,
578 GNUNET_SCHEDULER_add_delayed (GST_timeout,
579 &GST_forwarded_operation_timeout,
581 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
582 GNUNET_SERVER_receive_done (client, GNUNET_OK);
585 if (GNUNET_OK != start_peer (peer))
587 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
589 GNUNET_SERVER_receive_done (client, GNUNET_OK);
592 reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
593 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
594 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
595 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
596 reply->host_id = htonl (GST_context->host_id);
597 reply->peer_id = msg->peer_id;
598 reply->operation_id = msg->operation_id;
599 GST_queue_message (client, &reply->header);
600 GNUNET_SERVER_receive_done (client, GNUNET_OK);
605 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
608 * @param client identification of the client
609 * @param message the actual message
612 GST_handle_peer_stop (void *cls,
613 struct GNUNET_SERVER_Client *client,
614 const struct GNUNET_MessageHeader *message)
616 const struct GNUNET_TESTBED_PeerStopMessage *msg;
617 struct GNUNET_TESTBED_PeerEventMessage *reply;
618 struct ForwardedOperationContext *fopc;
622 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
623 peer_id = ntohl (msg->peer_id);
624 LOG (GNUNET_ERROR_TYPE_DEBUG,
625 "Received PEER_STOP for peer %u\n",
626 (unsigned int) peer_id);
627 if (!VALID_PEER_ID (peer_id))
629 GST_send_operation_fail_msg (client,
630 GNUNET_ntohll (msg->operation_id),
632 GNUNET_SERVER_receive_done (client, GNUNET_OK);
635 peer = GST_peer_list[peer_id];
636 if (GNUNET_YES == peer->is_remote)
638 LOG (GNUNET_ERROR_TYPE_DEBUG,
639 "Forwarding PEER_STOP for peer %u\n",
640 (unsigned int) peer_id);
641 fopc = GNUNET_new (struct ForwardedOperationContext);
642 GNUNET_SERVER_client_keep (client);
643 fopc->client = client;
644 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
645 fopc->type = OP_PEER_STOP;
647 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
651 &GST_forwarded_operation_reply_relay,
654 GNUNET_SCHEDULER_add_delayed (GST_timeout,
655 &GST_forwarded_operation_timeout,
657 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
660 GNUNET_SERVER_receive_done (client, GNUNET_OK);
663 if (GNUNET_OK != stop_peer (peer))
665 LOG (GNUNET_ERROR_TYPE_WARNING,
666 "Stopping peer %u failed\n",
667 (unsigned int) peer_id);
668 GST_send_operation_fail_msg (client,
669 GNUNET_ntohll (msg->operation_id),
671 GNUNET_SERVER_receive_done (client,
675 LOG (GNUNET_ERROR_TYPE_DEBUG,
676 "Peer %u successfully stopped\n",
677 (unsigned int) peer_id);
678 reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
679 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
680 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
681 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
682 reply->host_id = htonl (GST_context->host_id);
683 reply->peer_id = msg->peer_id;
684 reply->operation_id = msg->operation_id;
685 GST_queue_message (client, &reply->header);
686 GNUNET_SERVER_receive_done (client, GNUNET_OK);
687 GNUNET_TESTING_peer_wait (peer->details.local.peer);
692 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
695 * @param client identification of the client
696 * @param message the actual message
699 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
700 const struct GNUNET_MessageHeader *message)
702 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
703 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
704 struct ForwardedOperationContext *fopc;
713 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
714 peer_id = ntohl (msg->peer_id);
715 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
716 (unsigned int) peer_id);
717 if (!VALID_PEER_ID (peer_id))
719 GST_send_operation_fail_msg (client,
720 GNUNET_ntohll (msg->operation_id),
722 GNUNET_SERVER_receive_done (client, GNUNET_OK);
725 peer = GST_peer_list[peer_id];
726 if (GNUNET_YES == peer->is_remote)
728 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
729 (unsigned int) peer_id);
730 fopc = GNUNET_new (struct ForwardedOperationContext);
731 GNUNET_SERVER_client_keep (client);
732 fopc->client = client;
733 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
734 fopc->type = OP_PEER_INFO;
736 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
740 &GST_forwarded_operation_reply_relay,
743 GNUNET_SCHEDULER_add_delayed (GST_timeout,
744 &GST_forwarded_operation_timeout,
746 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
749 GNUNET_SERVER_receive_done (client, GNUNET_OK);
752 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
755 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
757 xc_size = GNUNET_TESTBED_compress_config_ (config,
760 GNUNET_free (config);
763 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
764 reply = GNUNET_realloc (xconfig, msize);
765 (void) memmove (&reply[1], reply, xc_size);
766 reply->header.size = htons (msize);
767 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
768 reply->peer_id = msg->peer_id;
769 reply->operation_id = msg->operation_id;
770 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
771 &reply->peer_identity);
772 reply->config_size = htons ((uint16_t) c_size);
773 GST_queue_message (client, &reply->header);
774 GNUNET_SERVER_receive_done (client, GNUNET_OK);
779 * Cleans up the given PeerReconfigureContext
781 * @param prc the PeerReconfigureContext
784 cleanup_prc (struct PeerReconfigureContext *prc)
788 if (VALID_PEER_ID (prc->peer_id))
790 peer = GST_peer_list [prc->peer_id];
791 if (1 != prc->stopped)
793 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
794 stop_peer (peer); /* Stop the peer synchronously */
797 if (NULL != prc->cfg)
798 GNUNET_CONFIGURATION_destroy (prc->cfg);
799 GNUNET_SERVER_client_drop (prc->client);
800 GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
806 * Cleans up the Peer reconfigure context list
811 while (NULL != prc_head)
812 cleanup_prc (prc_head);
817 * Update peer configuration
819 * @param peer the peer to update
820 * @param cfg the new configuration
821 * @return error message (freshly allocated); NULL upon success
824 update_peer_config (struct Peer *peer,
825 struct GNUNET_CONFIGURATION_Handle *cfg)
829 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
830 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
831 peer->details.local.cfg = cfg;
833 peer->details.local.peer
834 = GNUNET_TESTING_peer_configure (GST_context->system,
835 peer->details.local.cfg,
844 * Callback to inform whether the peer is running or stopped.
846 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
847 * @param p the respective peer whose status is being reported
848 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
852 prc_stop_cb (void *cls,
853 struct GNUNET_TESTING_Peer *p,
856 struct PeerReconfigureContext *prc = cls;
860 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
861 peer = GST_peer_list [prc->peer_id];
862 GNUNET_assert (GNUNET_NO == peer->is_remote);
863 emsg = update_peer_config (peer, prc->cfg);
868 GST_send_operation_fail_msg (prc->client,
873 if (GNUNET_OK != start_peer (peer))
875 GST_send_operation_fail_msg (prc->client,
877 "Failed to start reconfigured peer");
880 GST_send_operation_success_msg (prc->client,
890 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
891 * Should stop the peer asyncronously, destroy it and create it again with the
895 * @param client identification of the client
896 * @param message the actual message
899 GST_handle_peer_reconfigure (void *cls,
900 struct GNUNET_SERVER_Client *client,
901 const struct GNUNET_MessageHeader *message)
903 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
905 struct GNUNET_CONFIGURATION_Handle *cfg;
906 struct ForwardedOperationContext *fopc;
907 struct PeerReconfigureContext *prc;
913 msize = ntohs (message->size);
914 if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
917 GNUNET_SERVER_receive_done (client,
921 msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
922 peer_id = ntohl (msg->peer_id);
923 op_id = GNUNET_ntohll (msg->operation_id);
924 if (!VALID_PEER_ID (peer_id))
927 GST_send_operation_fail_msg (client,
930 GNUNET_SERVER_receive_done (client,
934 peer = GST_peer_list[peer_id];
935 if (GNUNET_YES == peer->is_remote)
937 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
938 fopc = GNUNET_new (struct ForwardedOperationContext);
939 GNUNET_SERVER_client_keep (client);
940 fopc->client = client;
941 fopc->operation_id = op_id;
942 fopc->type = OP_PEER_RECONFIGURE;
944 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
948 &GST_forwarded_operation_reply_relay,
951 GNUNET_SCHEDULER_add_delayed (GST_timeout,
952 &GST_forwarded_operation_timeout,
954 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
957 GNUNET_SERVER_receive_done (client, GNUNET_OK);
960 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
961 (unsigned int) peer_id);
962 if (0 < peer->reference_cnt)
965 GST_send_operation_fail_msg (client,
968 GNUNET_SERVER_receive_done (client,
972 if (GNUNET_YES == peer->destroy_flag)
975 GST_send_operation_fail_msg (client,
977 "Peer is being destroyed");
978 GNUNET_SERVER_receive_done (client,
982 cfg = GNUNET_TESTBED_extract_config_ (message);
986 GST_send_operation_fail_msg (client,
988 "Compression error");
989 GNUNET_SERVER_receive_done (client,
993 if (GNUNET_NO == peer->details.local.is_running)
995 emsg = update_peer_config (peer,
998 GST_send_operation_fail_msg (client,
1001 GST_send_operation_success_msg (client,
1003 GNUNET_SERVER_receive_done (client,
1005 GNUNET_free_non_null (emsg);
1008 prc = GNUNET_new (struct PeerReconfigureContext);
1010 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1014 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1015 "Error trying to stop peer %u asynchronously\n",
1017 LOG (GNUNET_ERROR_TYPE_ERROR,
1020 GST_send_operation_fail_msg (client,
1023 GNUNET_SERVER_receive_done (client,
1030 prc->peer_id = peer_id;
1032 prc->client = client;
1033 GNUNET_SERVER_client_keep (client);
1034 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1037 GNUNET_SERVER_receive_done (client,
1043 * Cleanup the context information created for managing a peer's service
1045 * @param mctx the ManageServiceContext
1048 cleanup_mctx (struct ManageServiceContext *mctx)
1050 mctx->expired = GNUNET_YES;
1051 GNUNET_CONTAINER_DLL_remove (mctx_head,
1054 GNUNET_SERVER_client_drop (mctx->client);
1055 GNUNET_ARM_disconnect (mctx->ah);
1056 GNUNET_assert (0 < mctx->peer->reference_cnt);
1057 mctx->peer->reference_cnt--;
1058 if ( (GNUNET_YES == mctx->peer->destroy_flag)
1059 && (0 == mctx->peer->reference_cnt) )
1060 GST_destroy_peer (mctx->peer);
1061 GNUNET_free (mctx->service);
1067 * Frees the ManageServiceContext queue
1072 while (NULL != mctx_head)
1073 cleanup_mctx (mctx_head);
1078 * Returns a string interpretation of @a rs.
1080 * @param rs the request status from ARM
1081 * @return a string interpretation of the request status
1084 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1088 case GNUNET_ARM_REQUEST_SENT_OK:
1089 return _("Message was sent successfully");
1090 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
1091 return _("Misconfiguration (can't connect to the ARM service)");
1092 case GNUNET_ARM_REQUEST_DISCONNECTED:
1093 return _("We disconnected from ARM before we could send a request");
1094 case GNUNET_ARM_REQUEST_BUSY:
1095 return _("ARM API is busy");
1096 case GNUNET_ARM_REQUEST_TIMEOUT:
1097 return _("Request timed out");
1099 return _("Unknown request status");
1104 * Returns a string interpretation of the @a result.
1106 * @param result the arm result
1107 * @return a string interpretation
1110 arm_ret_string (enum GNUNET_ARM_Result result)
1114 case GNUNET_ARM_RESULT_STOPPED:
1115 return _("%s is stopped");
1116 case GNUNET_ARM_RESULT_STARTING:
1117 return _("%s is starting");
1118 case GNUNET_ARM_RESULT_STOPPING:
1119 return _("%s is stopping");
1120 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1121 return _("%s is starting already");
1122 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1123 return _("%s is stopping already");
1124 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1125 return _("%s is started already");
1126 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1127 return _("%s is stopped already");
1128 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1129 return _("%s service is not known to ARM");
1130 case GNUNET_ARM_RESULT_START_FAILED:
1131 return _("%s service failed to start");
1132 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1133 return _("%s service can't be started because ARM is shutting down");
1135 return _("%.s Unknown result code.");
1140 * Function called in response to a start/stop request.
1141 * Will be called when request was not sent successfully,
1142 * or when a reply comes. If the request was not sent successfully,
1143 * @a rs will indicate that, and @a result will be undefined.
1145 * @param cls ManageServiceContext
1146 * @param rs status of the request
1147 * @param result result of the operation
1150 service_manage_result_cb (void *cls,
1151 enum GNUNET_ARM_RequestStatus rs,
1152 enum GNUNET_ARM_Result result)
1154 struct ManageServiceContext *mctx = cls;
1158 if (GNUNET_YES == mctx->expired)
1160 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1162 GNUNET_asprintf (&emsg,
1163 "Error communicating with Peer %u's ARM: %s",
1165 arm_req_string (rs));
1168 if (1 == mctx->start)
1169 goto service_start_check;
1170 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1171 || (GNUNET_ARM_RESULT_STOPPING == result)
1172 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1173 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1175 /* stopping a service failed */
1176 GNUNET_asprintf (&emsg,
1177 arm_ret_string (result),
1181 /* service stopped successfully */
1184 service_start_check:
1185 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1186 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1187 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1189 /* starting a service failed */
1190 GNUNET_asprintf (&emsg,
1191 arm_ret_string (result),
1195 /* service started successfully */
1200 LOG_DEBUG ("%s\n", emsg);
1201 GST_send_operation_fail_msg (mctx->client,
1206 GST_send_operation_success_msg (mctx->client,
1208 GNUNET_free_non_null (emsg);
1209 cleanup_mctx (mctx);
1214 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
1217 * @param client identification of client
1218 * @param message the actual message
1221 GST_handle_manage_peer_service (void *cls,
1222 struct GNUNET_SERVER_Client *client,
1223 const struct GNUNET_MessageHeader *message)
1225 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
1226 const char* service;
1229 struct GNUNET_ARM_Handle *ah;
1230 struct ManageServiceContext *mctx;
1231 struct ForwardedOperationContext *fopc;
1237 msize = ntohs (message->size);
1238 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
1240 GNUNET_break_op (0);
1241 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1244 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
1245 service = (const char *) &msg[1];
1246 if ('\0' != service[msize - sizeof
1247 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1249 GNUNET_break_op (0);
1250 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1255 GNUNET_break_op (0);
1256 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1259 peer_id = ntohl (msg->peer_id);
1260 op_id = GNUNET_ntohll (msg->operation_id);
1261 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1262 service, (unsigned int) peer_id);
1263 if ((GST_peer_list_size <= peer_id)
1264 || (NULL == (peer = GST_peer_list[peer_id])))
1266 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1267 "with id: %u", peer_id);
1270 if (0 == strcasecmp ("arm", service))
1272 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1273 "Use peer start/stop for that");
1276 if (GNUNET_YES == peer->is_remote)
1278 /* Forward the destory message to sub controller */
1279 fopc = GNUNET_new (struct ForwardedOperationContext);
1280 GNUNET_SERVER_client_keep (client);
1281 fopc->client = client;
1283 fopc->type = OP_MANAGE_SERVICE;
1284 fopc->operation_id = op_id;
1286 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1290 &GST_forwarded_operation_reply_relay,
1292 fopc->timeout_task =
1293 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1294 &GST_forwarded_operation_timeout,
1296 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1299 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1302 if (GNUNET_NO == peer->details.local.is_running)
1304 emsg = GNUNET_strdup ("Peer not running\n");
1307 if ((0 != peer->reference_cnt)
1308 && ( (0 == strcasecmp ("core", service))
1309 || (0 == strcasecmp ("transport", service)) ) )
1311 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1312 "since it is required by existing operations",
1316 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1319 GNUNET_asprintf (&emsg,
1320 "Cannot connect to ARM service of peer with id: %u",
1324 mctx = GNUNET_new (struct ManageServiceContext);
1326 peer->reference_cnt++;
1327 mctx->op_id = op_id;
1329 GNUNET_SERVER_client_keep (client);
1330 mctx->client = client;
1331 mctx->start = msg->start;
1332 mctx->service = GNUNET_strdup (service);
1333 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1336 if (1 == mctx->start)
1337 GNUNET_ARM_request_service_start (mctx->ah,
1339 GNUNET_OS_INHERIT_STD_ERR,
1340 &service_manage_result_cb,
1343 GNUNET_ARM_request_service_stop (mctx->ah, service,
1344 &service_manage_result_cb,
1346 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1350 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1351 GST_send_operation_fail_msg (client, op_id, emsg);
1353 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1358 * Stops and destroys all peers
1361 GST_destroy_peers ()
1366 if (NULL == GST_peer_list)
1368 for (id = 0; id < GST_peer_list_size; id++)
1370 peer = GST_peer_list[id];
1373 /* If destroy flag is set it means that this peer should have been
1374 * destroyed by a context which we destroy before */
1375 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1376 /* counter should be zero as we free all contexts before */
1377 GNUNET_break (0 == peer->reference_cnt);
1378 if ((GNUNET_NO == peer->is_remote) &&
1379 (GNUNET_YES == peer->details.local.is_running))
1380 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1382 for (id = 0; id < GST_peer_list_size; id++)
1384 peer = GST_peer_list[id];
1387 if (GNUNET_NO == peer->is_remote)
1389 if (GNUNET_YES == peer->details.local.is_running)
1390 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1391 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1392 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1396 GNUNET_free_non_null (GST_peer_list);
1397 GST_peer_list = NULL;
1398 GST_peer_list_size = 0;
1403 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1404 * success reply is received from all clients and then sends the success message
1407 * @param cls ForwardedOperationContext
1408 * @param msg the message to relay
1411 shutdown_peers_reply_cb (void *cls,
1412 const struct GNUNET_MessageHeader *msg)
1414 struct ForwardedOperationContext *fo_ctxt = cls;
1415 struct HandlerContext_ShutdownPeers *hc;
1418 GNUNET_assert (0 < hc->nslaves);
1420 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1422 hc->timeout = GNUNET_YES;
1423 if (0 == hc->nslaves)
1425 if (GNUNET_YES == hc->timeout)
1426 GST_send_operation_fail_msg (fo_ctxt->client,
1427 fo_ctxt->operation_id,
1428 "Timeout at a slave controller");
1430 GST_send_operation_success_msg (fo_ctxt->client,
1431 fo_ctxt->operation_id);
1435 GNUNET_SERVER_client_drop (fo_ctxt->client);
1436 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1439 GNUNET_free (fo_ctxt);
1444 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1447 * @param client identification of the client
1448 * @param message the actual message
1451 GST_handle_shutdown_peers (void *cls,
1452 struct GNUNET_SERVER_Client *client,
1453 const struct GNUNET_MessageHeader *message)
1455 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1456 struct HandlerContext_ShutdownPeers *hc;
1457 struct Slave *slave;
1458 struct ForwardedOperationContext *fo_ctxt;
1462 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1463 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1464 /* Stop and destroy all peers */
1469 /* Forward to all slaves which we have started */
1470 op_id = GNUNET_ntohll (msg->operation_id);
1471 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1472 /* FIXME: have a better implementation where we track which slaves are
1473 started by this controller */
1474 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1476 slave = GST_slave_list[cnt];
1479 if (NULL == slave->controller_proc) /* We didn't start the slave */
1481 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1483 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1484 GNUNET_SERVER_client_keep (client);
1485 fo_ctxt->client = client;
1486 fo_ctxt->operation_id = op_id;
1488 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1490 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1491 fo_ctxt->operation_id,
1493 shutdown_peers_reply_cb,
1495 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1499 LOG_DEBUG ("Shutting down peers\n");
1500 GST_destroy_peers ();
1501 if (0 == hc->nslaves)
1503 GST_send_operation_success_msg (client,
1507 GNUNET_SERVER_receive_done (client,