2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 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 * 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_SERVER_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, msg);
249 * Function to destroy a peer
251 * @param peer the peer structure to destroy
254 GST_destroy_peer (struct Peer *peer)
256 GNUNET_break (0 == peer->reference_cnt);
257 if (GNUNET_YES == peer->is_remote)
259 peer_list_remove (peer);
263 if (GNUNET_YES == peer->details.local.is_running)
265 GNUNET_TESTING_peer_stop (peer->details.local.peer);
266 peer->details.local.is_running = GNUNET_NO;
268 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
269 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
270 peer_list_remove (peer);
276 * Callback to be called when forwarded peer destroy operation is successfull. We
277 * have to relay the reply msg back to the client
279 * @param cls ForwardedOperationContext
280 * @param msg the peer create success message
283 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
285 struct ForwardedOperationContext *fopc = cls;
286 struct Peer *remote_peer;
288 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
291 remote_peer = fopc->cls;
292 GNUNET_assert (NULL != remote_peer);
293 remote_peer->destroy_flag = GNUNET_YES;
294 if (0 == remote_peer->reference_cnt)
295 GST_destroy_peer (remote_peer);
297 GST_forwarded_operation_reply_relay (fopc, msg);
302 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
305 * @param client identification of the client
306 * @param message the actual message
309 GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
310 const struct GNUNET_MessageHeader *message)
312 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
313 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
314 struct GNUNET_CONFIGURATION_Handle *cfg;
315 struct ForwardedOperationContext *fo_ctxt;
324 msize = ntohs (message->size);
325 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
327 GNUNET_break (0); /* We need configuration */
328 GNUNET_SERVER_receive_done (client, GNUNET_OK);
331 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
332 host_id = ntohl (msg->host_id);
333 peer_id = ntohl (msg->peer_id);
334 if (VALID_PEER_ID (peer_id))
336 (void) GNUNET_asprintf (&emsg, "Peer with ID %u already exists", peer_id);
337 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
340 GNUNET_SERVER_receive_done (client, GNUNET_OK);
343 if (UINT32_MAX == peer_id)
345 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
346 "Cannot create peer with given ID");
347 GNUNET_SERVER_receive_done (client, GNUNET_OK);
350 if (host_id == GST_context->host_id)
352 /* We are responsible for this peer */
353 cfg = GNUNET_TESTBED_extract_config_ (message);
357 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
360 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
361 (unsigned long long) peer_id);
363 GNUNET_CONFIGURATION_set_value_number (cfg, "PATHS", "PEERID",
364 (unsigned long long) peer_id);
365 peer = GNUNET_new (struct Peer);
366 peer->is_remote = GNUNET_NO;
367 peer->details.local.cfg = cfg;
369 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
370 peer->details.local.peer =
371 GNUNET_TESTING_peer_configure (GST_context->system,
372 peer->details.local.cfg, peer->id,
375 if (NULL == peer->details.local.peer)
377 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
381 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
384 peer->details.local.is_running = GNUNET_NO;
385 peer_list_add (peer);
386 reply = GNUNET_new (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage);
388 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
390 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
391 reply->peer_id = msg->peer_id;
392 reply->operation_id = msg->operation_id;
393 GST_queue_message (client, &reply->header);
394 GNUNET_SERVER_receive_done (client, GNUNET_OK);
398 /* Forward peer create request */
399 route = GST_find_dest_route (host_id);
403 GNUNET_SERVER_receive_done (client, GNUNET_OK);
406 peer = GNUNET_new (struct Peer);
407 peer->is_remote = GNUNET_YES;
409 peer->details.remote.slave = GST_slave_list[route->dest];
410 peer->details.remote.remote_host_id = host_id;
411 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
412 GNUNET_SERVER_client_keep (client);
413 fo_ctxt->client = client;
414 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
416 fo_ctxt->type = OP_PEER_CREATE;
418 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
419 [route->dest]->controller,
420 fo_ctxt->operation_id,
422 peer_create_success_cb, fo_ctxt);
423 fo_ctxt->timeout_task =
424 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
426 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
427 GNUNET_SERVER_receive_done (client, GNUNET_OK);
432 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
435 * @param client identification of the client
436 * @param message the actual message
439 GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
440 const struct GNUNET_MessageHeader *message)
442 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
443 struct ForwardedOperationContext *fopc;
447 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
448 peer_id = ntohl (msg->peer_id);
449 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
450 peer_id, GNUNET_ntohll (msg->operation_id));
451 if (!VALID_PEER_ID (peer_id))
453 LOG (GNUNET_ERROR_TYPE_ERROR,
454 "Asked to destroy a non existent peer with id: %u\n", peer_id);
455 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
456 "Peer doesn't exist");
457 GNUNET_SERVER_receive_done (client, GNUNET_OK);
460 peer = GST_peer_list[peer_id];
461 if (GNUNET_YES == peer->is_remote)
463 /* Forward the destory message to sub controller */
464 fopc = GNUNET_new (struct ForwardedOperationContext);
465 GNUNET_SERVER_client_keep (client);
466 fopc->client = client;
468 fopc->type = OP_PEER_DESTROY;
469 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
471 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
473 fopc->operation_id, &msg->header,
474 &peer_destroy_success_cb, fopc);
476 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
478 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
479 GNUNET_SERVER_receive_done (client, GNUNET_OK);
482 peer->destroy_flag = GNUNET_YES;
483 if (0 == peer->reference_cnt)
484 GST_destroy_peer (peer);
486 LOG (GNUNET_ERROR_TYPE_DEBUG,
487 "Delaying peer destroy as peer is currently in use\n");
488 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
489 GNUNET_SERVER_receive_done (client, GNUNET_OK);
496 * @param peer the peer to start
497 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
500 start_peer (struct Peer *peer)
502 GNUNET_assert (GNUNET_NO == peer->is_remote);
503 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
504 return GNUNET_SYSERR;
505 peer->details.local.is_running = GNUNET_YES;
513 * @param peer the peer to stop
514 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
517 stop_peer (struct Peer *peer)
519 GNUNET_assert (GNUNET_NO == peer->is_remote);
520 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
521 return GNUNET_SYSERR;
522 peer->details.local.is_running = GNUNET_NO;
528 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
531 * @param client identification of the client
532 * @param message the actual message
535 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
536 const struct GNUNET_MessageHeader *message)
538 const struct GNUNET_TESTBED_PeerStartMessage *msg;
539 struct GNUNET_TESTBED_PeerEventMessage *reply;
540 struct ForwardedOperationContext *fopc;
544 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
545 peer_id = ntohl (msg->peer_id);
546 if (!VALID_PEER_ID (peer_id))
549 LOG (GNUNET_ERROR_TYPE_ERROR,
550 "Asked to start a non existent peer with id: %u\n", peer_id);
551 GNUNET_SERVER_receive_done (client, GNUNET_OK);
554 peer = GST_peer_list[peer_id];
555 if (GNUNET_YES == peer->is_remote)
557 fopc = GNUNET_new (struct ForwardedOperationContext);
558 GNUNET_SERVER_client_keep (client);
559 fopc->client = client;
560 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
561 fopc->type = OP_PEER_START;
563 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
565 fopc->operation_id, &msg->header,
566 &GST_forwarded_operation_reply_relay,
569 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
571 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
572 GNUNET_SERVER_receive_done (client, GNUNET_OK);
575 if (GNUNET_OK != start_peer (peer))
577 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
579 GNUNET_SERVER_receive_done (client, GNUNET_OK);
582 reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
583 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
584 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
585 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
586 reply->host_id = htonl (GST_context->host_id);
587 reply->peer_id = msg->peer_id;
588 reply->operation_id = msg->operation_id;
589 GST_queue_message (client, &reply->header);
590 GNUNET_SERVER_receive_done (client, GNUNET_OK);
595 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
598 * @param client identification of the client
599 * @param message the actual message
602 GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
603 const struct GNUNET_MessageHeader *message)
605 const struct GNUNET_TESTBED_PeerStopMessage *msg;
606 struct GNUNET_TESTBED_PeerEventMessage *reply;
607 struct ForwardedOperationContext *fopc;
611 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
612 peer_id = ntohl (msg->peer_id);
613 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
614 if (!VALID_PEER_ID (peer_id))
616 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
618 GNUNET_SERVER_receive_done (client, GNUNET_OK);
621 peer = GST_peer_list[peer_id];
622 if (GNUNET_YES == peer->is_remote)
624 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
626 fopc = GNUNET_new (struct ForwardedOperationContext);
627 GNUNET_SERVER_client_keep (client);
628 fopc->client = client;
629 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
630 fopc->type = OP_PEER_STOP;
632 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
634 fopc->operation_id, &msg->header,
635 &GST_forwarded_operation_reply_relay,
638 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
640 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
641 GNUNET_SERVER_receive_done (client, GNUNET_OK);
644 if (GNUNET_OK != stop_peer (peer))
646 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
647 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
649 GNUNET_SERVER_receive_done (client, GNUNET_OK);
652 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
653 reply = GNUNET_new (struct GNUNET_TESTBED_PeerEventMessage);
654 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
655 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
656 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
657 reply->host_id = htonl (GST_context->host_id);
658 reply->peer_id = msg->peer_id;
659 reply->operation_id = msg->operation_id;
660 GST_queue_message (client, &reply->header);
661 GNUNET_SERVER_receive_done (client, GNUNET_OK);
662 GNUNET_TESTING_peer_wait (peer->details.local.peer);
667 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
670 * @param client identification of the client
671 * @param message the actual message
674 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
675 const struct GNUNET_MessageHeader *message)
677 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
678 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
679 struct ForwardedOperationContext *fopc;
688 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
689 peer_id = ntohl (msg->peer_id);
690 LOG_DEBUG ("Received GET_CONFIG for peer %u\n", peer_id);
691 if (!VALID_PEER_ID (peer_id))
693 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
695 GNUNET_SERVER_receive_done (client, GNUNET_OK);
698 peer = GST_peer_list[peer_id];
699 if (GNUNET_YES == peer->is_remote)
701 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
702 fopc = GNUNET_new (struct ForwardedOperationContext);
703 GNUNET_SERVER_client_keep (client);
704 fopc->client = client;
705 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
706 fopc->type = OP_PEER_INFO;
708 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
710 fopc->operation_id, &msg->header,
711 &GST_forwarded_operation_reply_relay,
714 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
716 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
717 GNUNET_SERVER_receive_done (client, GNUNET_OK);
720 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
722 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
724 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
725 GNUNET_free (config);
728 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
729 reply = GNUNET_realloc (xconfig, msize);
730 (void) memmove (&reply[1], reply, xc_size);
731 reply->header.size = htons (msize);
732 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
733 reply->peer_id = msg->peer_id;
734 reply->operation_id = msg->operation_id;
735 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
736 &reply->peer_identity);
737 reply->config_size = htons ((uint16_t) c_size);
738 GST_queue_message (client, &reply->header);
739 GNUNET_SERVER_receive_done (client, GNUNET_OK);
744 * Cleans up the given PeerReconfigureContext
746 * @param prc the PeerReconfigureContext
749 cleanup_prc (struct PeerReconfigureContext *prc)
753 if (VALID_PEER_ID (prc->peer_id))
755 peer = GST_peer_list [prc->peer_id];
756 if (1 != prc->stopped)
758 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
759 stop_peer (peer); /* Stop the peer synchronously */
762 if (NULL != prc->cfg)
763 GNUNET_CONFIGURATION_destroy (prc->cfg);
764 GNUNET_SERVER_client_drop (prc->client);
765 GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
771 * Cleans up the Peer reconfigure context list
776 while (NULL != prc_head)
777 cleanup_prc (prc_head);
782 * Update peer configuration
784 * @param peer the peer to update
785 * @param cfg the new configuration
786 * @return error message (freshly allocated); NULL upon success
789 update_peer_config (struct Peer *peer,
790 struct GNUNET_CONFIGURATION_Handle *cfg)
794 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
795 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
796 peer->details.local.cfg = cfg;
798 peer->details.local.peer
799 = GNUNET_TESTING_peer_configure (GST_context->system,
800 peer->details.local.cfg, peer->id,
808 * Callback to inform whether the peer is running or stopped.
810 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
811 * @param p the respective peer whose status is being reported
812 * @param success GNUNET_YES if the peer is stopped; GNUNET_SYSERR upon any
816 prc_stop_cb (void *cls, struct GNUNET_TESTING_Peer *p, int success)
818 struct PeerReconfigureContext *prc = cls;
822 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
823 peer = GST_peer_list [prc->peer_id];
824 GNUNET_assert (GNUNET_NO == peer->is_remote);
825 emsg = update_peer_config (peer, prc->cfg);
830 GST_send_operation_fail_msg (prc->client, prc->op_id, emsg);
833 if (GNUNET_OK != start_peer (peer))
835 GST_send_operation_fail_msg (prc->client, prc->op_id,
836 "Failed to start reconfigured peer");
839 GST_send_operation_success_msg (prc->client, prc->op_id);
848 * Handler for GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
849 * Should stop the peer asyncronously, destroy it and create it again with the
853 * @param client identification of the client
854 * @param message the actual message
857 GST_handle_peer_reconfigure (void *cls, struct GNUNET_SERVER_Client *client,
858 const struct GNUNET_MessageHeader *message)
860 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
862 struct GNUNET_CONFIGURATION_Handle *cfg;
863 struct ForwardedOperationContext *fopc;
864 struct PeerReconfigureContext *prc;
870 msize = ntohs (message->size);
871 if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
874 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
877 msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
878 peer_id = ntohl (msg->peer_id);
879 op_id = GNUNET_ntohll (msg->operation_id);
880 if (!VALID_PEER_ID (peer_id))
883 GST_send_operation_fail_msg (client, op_id, "Peer not found");
884 GNUNET_SERVER_receive_done (client, GNUNET_OK);
887 peer = GST_peer_list[peer_id];
888 if (GNUNET_YES == peer->is_remote)
890 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
891 fopc = GNUNET_new (struct ForwardedOperationContext);
892 GNUNET_SERVER_client_keep (client);
893 fopc->client = client;
894 fopc->operation_id = op_id;
895 fopc->type = OP_PEER_RECONFIGURE;
897 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
899 fopc->operation_id, &msg->header,
900 &GST_forwarded_operation_reply_relay,
903 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
905 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
906 GNUNET_SERVER_receive_done (client, GNUNET_OK);
909 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", peer_id);
910 if (0 < peer->reference_cnt)
913 GST_send_operation_fail_msg (client, op_id, "Peer in use");
914 GNUNET_SERVER_receive_done (client, GNUNET_OK);
917 if (GNUNET_YES == peer->destroy_flag)
920 GST_send_operation_fail_msg (client, op_id, "Peer is being destroyed");
921 GNUNET_SERVER_receive_done (client, GNUNET_OK);
924 cfg = GNUNET_TESTBED_extract_config_ (message);
928 GST_send_operation_fail_msg (client, op_id, "Compression error");
929 GNUNET_SERVER_receive_done (client, GNUNET_OK);
932 if (GNUNET_NO == peer->details.local.is_running)
934 emsg = update_peer_config (peer, cfg);
936 GST_send_operation_fail_msg (client, op_id, emsg);
937 GST_send_operation_success_msg (client, op_id);
938 GNUNET_SERVER_receive_done (client, GNUNET_OK);
939 GNUNET_free_non_null (emsg);
942 prc = GNUNET_new (struct PeerReconfigureContext);
944 GNUNET_TESTING_peer_stop_async (peer->details.local.peer, &prc_stop_cb,
947 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
948 "Error trying to stop peer %u asynchronously\n",
950 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
951 GST_send_operation_fail_msg (client, op_id, emsg);
952 GNUNET_SERVER_receive_done (client, GNUNET_OK);
958 prc->peer_id = peer_id;
960 prc->client = client;
961 GNUNET_SERVER_client_keep (client);
962 GNUNET_CONTAINER_DLL_insert_tail (prc_head, prc_tail, prc);
963 GNUNET_SERVER_receive_done (client, GNUNET_OK);
968 * Cleanup the context information created for managing a peer's service
970 * @param mctx the ManageServiceContext
973 cleanup_mctx (struct ManageServiceContext *mctx)
975 mctx->expired = GNUNET_YES;
976 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
977 GNUNET_SERVER_client_drop (mctx->client);
978 GNUNET_ARM_disconnect_and_free (mctx->ah);
979 GNUNET_assert (0 < mctx->peer->reference_cnt);
980 mctx->peer->reference_cnt--;
981 if ( (GNUNET_YES == mctx->peer->destroy_flag)
982 && (0 == mctx->peer->reference_cnt) )
983 GST_destroy_peer (mctx->peer);
989 * Frees the ManageServiceContext queue
994 while (NULL != mctx_head)
995 cleanup_mctx (mctx_head);
1000 * Returns a string interpretation of 'rs'
1002 * @param rs the request status from ARM
1003 * @return a string interpretation of the request status
1006 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1010 case GNUNET_ARM_REQUEST_SENT_OK:
1011 return _("Message was sent successfully");
1012 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
1013 return _("Misconfiguration (can't connect to the ARM service)");
1014 case GNUNET_ARM_REQUEST_DISCONNECTED:
1015 return _("We disconnected from ARM before we could send a request");
1016 case GNUNET_ARM_REQUEST_BUSY:
1017 return _("ARM API is busy");
1018 case GNUNET_ARM_REQUEST_TOO_LONG:
1019 return _("Request doesn't fit into a message");
1020 case GNUNET_ARM_REQUEST_TIMEOUT:
1021 return _("Request timed out");
1023 return _("Unknown request status");
1028 * Returns a string interpretation of the 'result'
1030 * @param result the arm result
1031 * @return a string interpretation
1034 arm_ret_string (enum GNUNET_ARM_Result result)
1038 case GNUNET_ARM_RESULT_STOPPED:
1039 return _("%s is stopped");
1040 case GNUNET_ARM_RESULT_STARTING:
1041 return _("%s is starting");
1042 case GNUNET_ARM_RESULT_STOPPING:
1043 return _("%s is stopping");
1044 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1045 return _("%s is starting already");
1046 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1047 return _("%s is stopping already");
1048 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1049 return _("%s is started already");
1050 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1051 return _("%s is stopped already");
1052 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1053 return _("%s service is not known to ARM");
1054 case GNUNET_ARM_RESULT_START_FAILED:
1055 return _("%s service failed to start");
1056 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1057 return _("%s service can't be started because ARM is shutting down");
1059 return _("%.s Unknown result code.");
1064 * Function called in response to a start/stop request.
1065 * Will be called when request was not sent successfully,
1066 * or when a reply comes. If the request was not sent successfully,
1067 * 'rs' will indicate that, and 'service' and 'result' will be undefined.
1069 * @param cls ManageServiceContext
1070 * @param rs status of the request
1071 * @param service service name
1072 * @param result result of the operation
1075 service_manage_result_cb (void *cls,
1076 enum GNUNET_ARM_RequestStatus rs,
1077 const char *service, enum GNUNET_ARM_Result result)
1079 struct ManageServiceContext *mctx = cls;
1083 if (GNUNET_YES == mctx->expired)
1085 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1087 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
1088 mctx->peer->id, arm_req_string (rs));
1091 if (1 == mctx->start)
1092 goto service_start_check;
1093 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1094 || (GNUNET_ARM_RESULT_STOPPING == result)
1095 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1096 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1098 /* stopping a service failed */
1099 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1102 /* service stopped successfully */
1105 service_start_check:
1106 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1107 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1108 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1110 /* starting a service failed */
1111 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1114 /* service started successfully */
1119 LOG_DEBUG ("%s\n", emsg);
1120 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
1123 GST_send_operation_success_msg (mctx->client, mctx->op_id);
1124 GNUNET_free_non_null (emsg);
1125 cleanup_mctx (mctx);
1130 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
1133 * @param client identification of client
1134 * @param message the actual message
1137 GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
1138 const struct GNUNET_MessageHeader *message)
1140 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
1141 const char* service;
1144 struct GNUNET_ARM_Handle *ah;
1145 struct ManageServiceContext *mctx;
1146 struct ForwardedOperationContext *fopc;
1152 msize = ntohs (message->size);
1153 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
1155 GNUNET_break_op (0);
1156 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1159 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
1160 service = (const char *) &msg[1];
1161 if ('\0' != service[msize - sizeof
1162 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1164 GNUNET_break_op (0);
1165 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1170 GNUNET_break_op (0);
1171 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1174 peer_id = ntohl (msg->peer_id);
1175 op_id = GNUNET_ntohll (msg->operation_id);
1176 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1177 service, (unsigned int) peer_id);
1178 if ((GST_peer_list_size <= peer_id)
1179 || (NULL == (peer = GST_peer_list[peer_id])))
1181 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1182 "with id: %u", peer_id);
1185 if (0 == strcasecmp ("arm", service))
1187 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1188 "Use peer start/stop for that");
1191 if (GNUNET_YES == peer->is_remote)
1193 /* Forward the destory message to sub controller */
1194 fopc = GNUNET_new (struct ForwardedOperationContext);
1195 GNUNET_SERVER_client_keep (client);
1196 fopc->client = client;
1198 fopc->type = OP_MANAGE_SERVICE;
1199 fopc->operation_id = op_id;
1201 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1203 fopc->operation_id, &msg->header,
1204 &GST_forwarded_operation_reply_relay,
1206 fopc->timeout_task =
1207 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1209 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1210 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1213 if (GNUNET_NO == peer->details.local.is_running)
1215 emsg = GNUNET_strdup ("Peer not running\n");
1218 if ((0 != peer->reference_cnt)
1219 && ( (0 == strcasecmp ("core", service))
1220 || (0 == strcasecmp ("transport", service)) ) )
1222 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1223 "since it is required by existing operations",
1227 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1230 GNUNET_asprintf (&emsg,
1231 "Cannot connect to ARM service of peer with id: %u",
1235 mctx = GNUNET_new (struct ManageServiceContext);
1237 peer->reference_cnt++;
1238 mctx->op_id = op_id;
1240 GNUNET_SERVER_client_keep (client);
1241 mctx->client = client;
1242 mctx->start = msg->start;
1243 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
1244 if (1 == mctx->start)
1245 GNUNET_ARM_request_service_start (mctx->ah, service,
1246 GNUNET_OS_INHERIT_STD_ERR,
1248 service_manage_result_cb,
1251 GNUNET_ARM_request_service_stop (mctx->ah, service,
1253 service_manage_result_cb,
1255 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1259 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1260 GST_send_operation_fail_msg (client, op_id, emsg);
1262 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1267 * Stops and destroys all peers
1270 GST_destroy_peers ()
1275 if (NULL == GST_peer_list)
1277 for (id = 0; id < GST_peer_list_size; id++)
1279 peer = GST_peer_list[id];
1282 /* If destroy flag is set it means that this peer should have been
1283 * destroyed by a context which we destroy before */
1284 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1285 /* counter should be zero as we free all contexts before */
1286 GNUNET_break (0 == peer->reference_cnt);
1287 if ((GNUNET_NO == peer->is_remote) &&
1288 (GNUNET_YES == peer->details.local.is_running))
1289 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1291 for (id = 0; id < GST_peer_list_size; id++)
1293 peer = GST_peer_list[id];
1296 if (GNUNET_NO == peer->is_remote)
1298 if (GNUNET_YES == peer->details.local.is_running)
1299 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1300 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1301 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1305 GNUNET_free_non_null (GST_peer_list);
1306 GST_peer_list = NULL;
1307 GST_peer_list_size = 0;
1312 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1313 * success reply is received from all clients and then sends the success message
1316 * @param cls ForwardedOperationContext
1317 * @param msg the message to relay
1320 shutdown_peers_reply_cb (void *cls,
1321 const struct GNUNET_MessageHeader *msg)
1323 struct ForwardedOperationContext *fo_ctxt = cls;
1324 struct HandlerContext_ShutdownPeers *hc;
1327 GNUNET_assert (0 < hc->nslaves);
1329 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1331 hc->timeout = GNUNET_YES;
1332 if (0 == hc->nslaves)
1334 if (GNUNET_YES == hc->timeout)
1335 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1336 "Timeout at a slave controller");
1338 GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
1342 GNUNET_SERVER_client_drop (fo_ctxt->client);
1343 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1344 GNUNET_free (fo_ctxt);
1349 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1352 * @param client identification of the client
1353 * @param message the actual message
1356 GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
1357 const struct GNUNET_MessageHeader *message)
1359 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1360 struct HandlerContext_ShutdownPeers *hc;
1361 struct Slave *slave;
1362 struct ForwardedOperationContext *fo_ctxt;
1366 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1367 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1368 /* Stop and destroy all peers */
1373 /* Forward to all slaves which we have started */
1374 op_id = GNUNET_ntohll (msg->operation_id);
1375 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1376 /* FIXME: have a better implementation where we track which slaves are
1377 started by this controller */
1378 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1380 slave = GST_slave_list[cnt];
1383 if (NULL == slave->controller_proc) /* We didn't start the slave */
1385 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1387 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1388 GNUNET_SERVER_client_keep (client);
1389 fo_ctxt->client = client;
1390 fo_ctxt->operation_id = op_id;
1392 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1394 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1395 fo_ctxt->operation_id,
1397 shutdown_peers_reply_cb,
1399 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1401 LOG_DEBUG ("Shutting down peers\n");
1402 GST_destroy_peers ();
1403 if (0 == hc->nslaves)
1405 GST_send_operation_success_msg (client, op_id);
1408 GNUNET_SERVER_receive_done (client, GNUNET_OK);