2 This file is part of GNUnet.
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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;
40 * Context information to manage peers' services
42 struct ManageServiceContext
47 struct ManageServiceContext *next;
52 struct ManageServiceContext *prev;
55 * The ARM handle of the peer
57 struct GNUNET_ARM_Handle *ah;
60 * peer whose service has to be managed
65 * The client which requested to manage the peer's service
67 struct GNUNET_SERVER_Client *client;
70 * The operation id of the associated request
75 * 1 if the service at the peer has to be started; 0 if it has to be stopped
80 * Is this context expired? Do not work on this context if it is set to
88 * Context information for peer re-configure operations
90 struct PeerReconfigureContext
93 * DLL next for inclusoin in peer reconfigure operations list
95 struct PeerReconfigureContext *next;
100 struct PeerReconfigureContext *prev;
103 * The client which gave this operation to us
105 struct GNUNET_SERVER_Client *client;
108 * The configuration handle to use as the new template
110 struct GNUNET_CONFIGURATION_Handle *cfg;
113 * The id of the operation
118 * The id of the peer which has to be reconfigured
123 * The the peer stopped? Used while cleaning up this context to decide
124 * whether the asynchronous stop request through Testing/ARM API has to be
131 * The DLL head for the peer reconfigure list
133 static struct PeerReconfigureContext *prc_head;
136 * The DLL tail for the peer reconfigure list
138 static struct PeerReconfigureContext *prc_tail;
143 * DLL head for queue of manage service requests
145 static struct ManageServiceContext *mctx_head;
148 * DLL tail for queue of manage service requests
150 static struct ManageServiceContext *mctx_tail;
154 * Adds a peer to the peer array
156 * @param peer the peer to add
159 peer_list_add (struct Peer *peer)
161 if (peer->id >= GST_peer_list_size)
162 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
163 GNUNET_assert (NULL == GST_peer_list[peer->id]);
164 GST_peer_list[peer->id] = peer;
169 * Removes a the give peer from the peer array
171 * @param peer the peer to be removed
174 peer_list_remove (struct Peer *peer)
176 unsigned int orig_size;
179 GST_peer_list[peer->id] = NULL;
180 orig_size = GST_peer_list_size;
181 while (GST_peer_list_size >= LIST_GROW_STEP)
183 for (id = GST_peer_list_size - 1;
184 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
186 if (NULL != GST_peer_list[id])
188 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
190 GST_peer_list_size -= LIST_GROW_STEP;
192 if (orig_size == GST_peer_list_size)
195 GNUNET_realloc (GST_peer_list,
196 sizeof (struct Peer *) * GST_peer_list_size);
201 * The task to be executed if the forwarded peer create operation has been
204 * @param cls the FowardedOperationContext
205 * @param tc the TaskContext from the scheduler
208 peer_create_forward_timeout (void *cls,
209 const struct GNUNET_SCHEDULER_TaskContext *tc)
211 struct ForwardedOperationContext *fopc = cls;
213 GNUNET_free (fopc->cls);
214 GST_forwarded_operation_timeout (fopc, tc);
219 * Callback to be called when forwarded peer create operation is successfull. We
220 * have to relay the reply msg back to the client
222 * @param cls ForwardedOperationContext
223 * @param msg the peer create success message
226 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
228 struct ForwardedOperationContext *fopc = cls;
229 struct Peer *remote_peer;
231 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
233 GNUNET_assert (NULL != fopc->cls);
234 remote_peer = fopc->cls;
235 peer_list_add (remote_peer);
237 GST_forwarded_operation_reply_relay (fopc, msg);
242 * Function to destroy a peer
244 * @param peer the peer structure to destroy
247 GST_destroy_peer (struct Peer *peer)
249 GNUNET_break (0 == peer->reference_cnt);
250 if (GNUNET_YES == peer->is_remote)
252 peer_list_remove (peer);
256 if (GNUNET_YES == peer->details.local.is_running)
258 GNUNET_TESTING_peer_stop (peer->details.local.peer);
259 peer->details.local.is_running = GNUNET_NO;
261 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
262 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
263 peer_list_remove (peer);
269 * Callback to be called when forwarded peer destroy operation is successfull. We
270 * have to relay the reply msg back to the client
272 * @param cls ForwardedOperationContext
273 * @param msg the peer create success message
276 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
278 struct ForwardedOperationContext *fopc = cls;
279 struct Peer *remote_peer;
281 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
284 remote_peer = fopc->cls;
285 GNUNET_assert (NULL != remote_peer);
286 remote_peer->destroy_flag = GNUNET_YES;
287 if (0 == remote_peer->reference_cnt)
288 GST_destroy_peer (remote_peer);
290 GST_forwarded_operation_reply_relay (fopc, msg);
295 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
298 * @param client identification of the client
299 * @param message the actual message
302 GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
303 const struct GNUNET_MessageHeader *message)
305 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
306 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
307 struct GNUNET_CONFIGURATION_Handle *cfg;
308 struct ForwardedOperationContext *fo_ctxt;
317 msize = ntohs (message->size);
318 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
320 GNUNET_break (0); /* We need configuration */
321 GNUNET_SERVER_receive_done (client, GNUNET_OK);
324 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
325 host_id = ntohl (msg->host_id);
326 peer_id = ntohl (msg->peer_id);
327 if (VALID_PEER_ID (peer_id))
329 (void) GNUNET_asprintf (&emsg, "Peer with ID %u already exists", peer_id);
330 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
333 GNUNET_SERVER_receive_done (client, GNUNET_OK);
336 if (UINT32_MAX == peer_id)
338 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
339 "Cannot create peer with given ID");
340 GNUNET_SERVER_receive_done (client, GNUNET_OK);
343 if (host_id == GST_context->host_id)
345 /* We are responsible for this peer */
346 cfg = GNUNET_TESTBED_extract_config_ (message);
350 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
353 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
354 (unsigned long long) peer_id);
355 peer = GNUNET_malloc (sizeof (struct Peer));
356 peer->is_remote = GNUNET_NO;
357 peer->details.local.cfg = cfg;
359 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
360 peer->details.local.peer =
361 GNUNET_TESTING_peer_configure (GST_context->system,
362 peer->details.local.cfg, peer->id,
365 if (NULL == peer->details.local.peer)
367 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
371 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
374 peer->details.local.is_running = GNUNET_NO;
375 peer_list_add (peer);
377 GNUNET_malloc (sizeof
378 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
380 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
382 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
383 reply->peer_id = msg->peer_id;
384 reply->operation_id = msg->operation_id;
385 GST_queue_message (client, &reply->header);
386 GNUNET_SERVER_receive_done (client, GNUNET_OK);
390 /* Forward peer create request */
391 route = GST_find_dest_route (host_id);
395 GNUNET_SERVER_receive_done (client, GNUNET_OK);
398 peer = GNUNET_malloc (sizeof (struct Peer));
399 peer->is_remote = GNUNET_YES;
401 peer->details.remote.slave = GST_slave_list[route->dest];
402 peer->details.remote.remote_host_id = host_id;
403 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
404 GNUNET_SERVER_client_keep (client);
405 fo_ctxt->client = client;
406 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
408 fo_ctxt->type = OP_PEER_CREATE;
410 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
411 [route->dest]->controller,
412 fo_ctxt->operation_id,
414 peer_create_success_cb, fo_ctxt);
415 fo_ctxt->timeout_task =
416 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
418 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
419 GNUNET_SERVER_receive_done (client, GNUNET_OK);
424 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
427 * @param client identification of the client
428 * @param message the actual message
431 GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
432 const struct GNUNET_MessageHeader *message)
434 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
435 struct ForwardedOperationContext *fopc;
439 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
440 peer_id = ntohl (msg->peer_id);
441 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
442 peer_id, GNUNET_ntohll (msg->operation_id));
443 if (!VALID_PEER_ID (peer_id))
445 LOG (GNUNET_ERROR_TYPE_ERROR,
446 "Asked to destroy a non existent peer with id: %u\n", peer_id);
447 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
448 "Peer doesn't exist");
449 GNUNET_SERVER_receive_done (client, GNUNET_OK);
452 peer = GST_peer_list[peer_id];
453 if (GNUNET_YES == peer->is_remote)
455 /* Forward the destory message to sub controller */
456 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
457 GNUNET_SERVER_client_keep (client);
458 fopc->client = client;
460 fopc->type = OP_PEER_DESTROY;
461 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
463 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
465 fopc->operation_id, &msg->header,
466 &peer_destroy_success_cb, fopc);
468 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
470 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
471 GNUNET_SERVER_receive_done (client, GNUNET_OK);
474 peer->destroy_flag = GNUNET_YES;
475 if (0 == peer->reference_cnt)
476 GST_destroy_peer (peer);
478 LOG (GNUNET_ERROR_TYPE_DEBUG,
479 "Delaying peer destroy as peer is currently in use\n");
480 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
481 GNUNET_SERVER_receive_done (client, GNUNET_OK);
488 * @param peer the peer to start
489 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
492 start_peer (struct Peer *peer)
494 GNUNET_assert (GNUNET_NO == peer->is_remote);
495 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
496 return GNUNET_SYSERR;
497 peer->details.local.is_running = GNUNET_YES;
505 * @param peer the peer to stop
506 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
509 stop_peer (struct Peer *peer)
511 GNUNET_assert (GNUNET_NO == peer->is_remote);
512 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
513 return GNUNET_SYSERR;
514 peer->details.local.is_running = GNUNET_NO;
520 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
523 * @param client identification of the client
524 * @param message the actual message
527 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
528 const struct GNUNET_MessageHeader *message)
530 const struct GNUNET_TESTBED_PeerStartMessage *msg;
531 struct GNUNET_TESTBED_PeerEventMessage *reply;
532 struct ForwardedOperationContext *fopc;
536 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
537 peer_id = ntohl (msg->peer_id);
538 if (!VALID_PEER_ID (peer_id))
541 LOG (GNUNET_ERROR_TYPE_ERROR,
542 "Asked to start a non existent peer with id: %u\n", peer_id);
543 GNUNET_SERVER_receive_done (client, GNUNET_OK);
546 peer = GST_peer_list[peer_id];
547 if (GNUNET_YES == peer->is_remote)
549 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
550 GNUNET_SERVER_client_keep (client);
551 fopc->client = client;
552 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
553 fopc->type = OP_PEER_START;
555 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
557 fopc->operation_id, &msg->header,
558 &GST_forwarded_operation_reply_relay,
561 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
563 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
564 GNUNET_SERVER_receive_done (client, GNUNET_OK);
567 if (GNUNET_OK != start_peer (peer))
569 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
571 GNUNET_SERVER_receive_done (client, GNUNET_OK);
574 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
575 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
576 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
577 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
578 reply->host_id = htonl (GST_context->host_id);
579 reply->peer_id = msg->peer_id;
580 reply->operation_id = msg->operation_id;
581 GST_queue_message (client, &reply->header);
582 GNUNET_SERVER_receive_done (client, GNUNET_OK);
587 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
590 * @param client identification of the client
591 * @param message the actual message
594 GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
595 const struct GNUNET_MessageHeader *message)
597 const struct GNUNET_TESTBED_PeerStopMessage *msg;
598 struct GNUNET_TESTBED_PeerEventMessage *reply;
599 struct ForwardedOperationContext *fopc;
603 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
604 peer_id = ntohl (msg->peer_id);
605 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
606 if (!VALID_PEER_ID (peer_id))
608 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
610 GNUNET_SERVER_receive_done (client, GNUNET_OK);
613 peer = GST_peer_list[peer_id];
614 if (GNUNET_YES == peer->is_remote)
616 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
618 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
619 GNUNET_SERVER_client_keep (client);
620 fopc->client = client;
621 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
622 fopc->type = OP_PEER_STOP;
624 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
626 fopc->operation_id, &msg->header,
627 &GST_forwarded_operation_reply_relay,
630 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
632 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
633 GNUNET_SERVER_receive_done (client, GNUNET_OK);
636 if (GNUNET_OK != stop_peer (peer))
638 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
639 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
641 GNUNET_SERVER_receive_done (client, GNUNET_OK);
644 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
645 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
646 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
647 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
648 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
649 reply->host_id = htonl (GST_context->host_id);
650 reply->peer_id = msg->peer_id;
651 reply->operation_id = msg->operation_id;
652 GST_queue_message (client, &reply->header);
653 GNUNET_SERVER_receive_done (client, GNUNET_OK);
654 GNUNET_TESTING_peer_wait (peer->details.local.peer);
659 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
662 * @param client identification of the client
663 * @param message the actual message
666 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
667 const struct GNUNET_MessageHeader *message)
669 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
670 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
671 struct ForwardedOperationContext *fopc;
680 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
681 peer_id = ntohl (msg->peer_id);
682 LOG_DEBUG ("Received GET_CONFIG for peer %u\n", peer_id);
683 if (!VALID_PEER_ID (peer_id))
685 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
687 GNUNET_SERVER_receive_done (client, GNUNET_OK);
690 peer = GST_peer_list[peer_id];
691 if (GNUNET_YES == peer->is_remote)
693 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
694 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
695 GNUNET_SERVER_client_keep (client);
696 fopc->client = client;
697 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
698 fopc->type = OP_PEER_INFO;
700 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
702 fopc->operation_id, &msg->header,
703 &GST_forwarded_operation_reply_relay,
706 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
708 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
709 GNUNET_SERVER_receive_done (client, GNUNET_OK);
712 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
714 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
716 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
717 GNUNET_free (config);
720 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
721 reply = GNUNET_realloc (xconfig, msize);
722 (void) memmove (&reply[1], reply, xc_size);
723 reply->header.size = htons (msize);
724 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
725 reply->peer_id = msg->peer_id;
726 reply->operation_id = msg->operation_id;
727 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
728 &reply->peer_identity);
729 reply->config_size = htons ((uint16_t) c_size);
730 GST_queue_message (client, &reply->header);
731 GNUNET_SERVER_receive_done (client, GNUNET_OK);
736 * Cleans up the given PeerReconfigureContext
738 * @param prc the PeerReconfigureContext
741 cleanup_prc (struct PeerReconfigureContext *prc)
745 if (VALID_PEER_ID (prc->peer_id))
747 peer = GST_peer_list [prc->peer_id];
748 if (1 != prc->stopped)
750 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
751 stop_peer (peer); /* Stop the peer synchronously */
754 if (NULL != prc->cfg)
755 GNUNET_CONFIGURATION_destroy (prc->cfg);
756 GNUNET_SERVER_client_drop (prc->client);
757 GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
763 * Cleans up the Peer reconfigure context list
768 while (NULL != prc_head)
769 cleanup_prc (prc_head);
774 * Callback to inform whether the peer is running or stopped.
776 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
777 * @param peer the respective peer whose status is being reported
778 * @param success GNUNET_YES if the peer is stopped; GNUNET_SYSERR upon any
782 prc_stop_cb (void *cls, struct GNUNET_TESTING_Peer *p, int success)
784 struct PeerReconfigureContext *prc = cls;
788 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
789 peer = GST_peer_list [prc->peer_id];
790 GNUNET_assert (GNUNET_NO == peer->is_remote);
791 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
792 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
793 peer->details.local.cfg = prc->cfg;
797 peer->details.local.peer
798 = GNUNET_TESTING_peer_configure (GST_context->system,
799 peer->details.local.cfg, peer->id,
802 if (NULL == peer->details.local.peer)
804 GST_send_operation_fail_msg (prc->client, prc->op_id, emsg);
807 if (GNUNET_OK != start_peer (peer))
810 GST_send_operation_fail_msg (prc->client, prc->op_id,
811 "Failed to start reconfigured peer");
814 GST_send_operation_success_msg (prc->client, prc->op_id);
823 * Handler for GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
824 * Should stop the peer asyncronously, destroy it and create it again with the
828 * @param client identification of the client
829 * @param message the actual message
832 GST_handle_peer_reconfigure (void *cls, struct GNUNET_SERVER_Client *client,
833 const struct GNUNET_MessageHeader *message)
835 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
837 struct GNUNET_CONFIGURATION_Handle *cfg;
838 struct ForwardedOperationContext *fopc;
839 struct PeerReconfigureContext *prc;
844 msize = ntohs (message->size);
845 if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
848 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
851 msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
852 peer_id = ntohl (msg->peer_id);
853 op_id = GNUNET_ntohll (msg->operation_id);
854 if (!VALID_PEER_ID (peer_id))
857 GST_send_operation_fail_msg (client, op_id, "Peer not found");
858 GNUNET_SERVER_receive_done (client, GNUNET_OK);
861 peer = GST_peer_list[peer_id];
862 if (GNUNET_YES == peer->is_remote)
864 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
865 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
866 GNUNET_SERVER_client_keep (client);
867 fopc->client = client;
868 fopc->operation_id = op_id;
869 fopc->type = OP_PEER_RECONFIGURE;
871 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
873 fopc->operation_id, &msg->header,
874 &GST_forwarded_operation_reply_relay,
877 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
879 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
880 GNUNET_SERVER_receive_done (client, GNUNET_OK);
883 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", peer_id);
884 if (0 < peer->reference_cnt)
887 GST_send_operation_fail_msg (client, op_id, "Peer in use");
888 GNUNET_SERVER_receive_done (client, GNUNET_OK);
891 if (GNUNET_YES == peer->destroy_flag)
894 GST_send_operation_fail_msg (client, op_id, "Peer is being destroyed");
895 GNUNET_SERVER_receive_done (client, GNUNET_OK);
898 cfg = GNUNET_TESTBED_extract_config_ (message);
902 GST_send_operation_fail_msg (client, op_id, "Compression error");
903 GNUNET_SERVER_receive_done (client, GNUNET_OK);
906 prc = GNUNET_malloc (sizeof (struct PeerReconfigureContext));
908 prc->peer_id = peer_id;
910 prc->client = client;
911 GNUNET_SERVER_client_keep (client);
912 GNUNET_CONTAINER_DLL_insert_tail (prc_head, prc_tail, prc);
913 GNUNET_TESTING_peer_stop_async (peer->details.local.peer, prc_stop_cb, prc);
914 GNUNET_SERVER_receive_done (client, GNUNET_OK);
919 * Cleanup the context information created for managing a peer's service
921 * @param mctx the ManageServiceContext
924 cleanup_mctx (struct ManageServiceContext *mctx)
926 mctx->expired = GNUNET_YES;
927 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
928 GNUNET_SERVER_client_drop (mctx->client);
929 GNUNET_ARM_disconnect_and_free (mctx->ah);
930 GNUNET_assert (0 < mctx->peer->reference_cnt);
931 mctx->peer->reference_cnt--;
932 if ( (GNUNET_YES == mctx->peer->destroy_flag)
933 && (0 == mctx->peer->reference_cnt) )
934 GST_destroy_peer (mctx->peer);
940 * Frees the ManageServiceContext queue
945 while (NULL != mctx_head)
946 cleanup_mctx (mctx_head);
951 * Returns a string interpretation of 'rs'
953 * @param rs the request status from ARM
954 * @return a string interpretation of the request status
957 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
961 case GNUNET_ARM_REQUEST_SENT_OK:
962 return _("Message was sent successfully");
963 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
964 return _("Misconfiguration (can't connect to the ARM service)");
965 case GNUNET_ARM_REQUEST_DISCONNECTED:
966 return _("We disconnected from ARM before we could send a request");
967 case GNUNET_ARM_REQUEST_BUSY:
968 return _("ARM API is busy");
969 case GNUNET_ARM_REQUEST_TOO_LONG:
970 return _("Request doesn't fit into a message");
971 case GNUNET_ARM_REQUEST_TIMEOUT:
972 return _("Request timed out");
974 return _("Unknown request status");
979 * Returns a string interpretation of the 'result'
981 * @param result the arm result
982 * @return a string interpretation
985 arm_ret_string (enum GNUNET_ARM_Result result)
989 case GNUNET_ARM_RESULT_STOPPED:
990 return _("%s is stopped");
991 case GNUNET_ARM_RESULT_STARTING:
992 return _("%s is starting");
993 case GNUNET_ARM_RESULT_STOPPING:
994 return _("%s is stopping");
995 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
996 return _("%s is starting already");
997 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
998 return _("%s is stopping already");
999 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1000 return _("%s is started already");
1001 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1002 return _("%s is stopped already");
1003 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1004 return _("%s service is not known to ARM");
1005 case GNUNET_ARM_RESULT_START_FAILED:
1006 return _("%s service failed to start");
1007 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1008 return _("%s service can't be started because ARM is shutting down");
1010 return _("%.s Unknown result code.");
1015 * Function called in response to a start/stop request.
1016 * Will be called when request was not sent successfully,
1017 * or when a reply comes. If the request was not sent successfully,
1018 * 'rs' will indicate that, and 'service' and 'result' will be undefined.
1020 * @param cls ManageServiceContext
1021 * @param rs status of the request
1022 * @param service service name
1023 * @param result result of the operation
1026 service_manage_result_cb (void *cls,
1027 enum GNUNET_ARM_RequestStatus rs,
1028 const char *service, enum GNUNET_ARM_Result result)
1030 struct ManageServiceContext *mctx = cls;
1034 if (GNUNET_YES == mctx->expired)
1036 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1038 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
1039 mctx->peer->id, arm_req_string (rs));
1042 if (1 == mctx->start)
1043 goto service_start_check;
1044 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1045 || (GNUNET_ARM_RESULT_STOPPING == result)
1046 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1047 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1049 /* stopping a service failed */
1050 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1053 /* service stopped successfully */
1056 service_start_check:
1057 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1058 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1059 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1061 /* starting a service failed */
1062 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1065 /* service started successfully */
1070 LOG_DEBUG ("%s\n", emsg);
1071 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
1074 GST_send_operation_success_msg (mctx->client, mctx->op_id);
1075 GNUNET_free_non_null (emsg);
1076 cleanup_mctx (mctx);
1081 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
1084 * @param client identification of client
1085 * @param message the actual message
1088 GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
1089 const struct GNUNET_MessageHeader *message)
1091 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
1092 const char* service;
1095 struct GNUNET_ARM_Handle *ah;
1096 struct ManageServiceContext *mctx;
1097 struct ForwardedOperationContext *fopc;
1103 msize = ntohs (message->size);
1104 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
1106 GNUNET_break_op (0);
1107 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1110 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
1111 service = (const char *) &msg[1];
1112 if ('\0' != service[msize - sizeof
1113 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1115 GNUNET_break_op (0);
1116 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1121 GNUNET_break_op (0);
1122 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1125 peer_id = ntohl (msg->peer_id);
1126 op_id = GNUNET_ntohll (msg->operation_id);
1127 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1128 service, (unsigned int) peer_id);
1129 if ((GST_peer_list_size <= peer_id)
1130 || (NULL == (peer = GST_peer_list[peer_id])))
1132 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1133 "with id: %u", peer_id);
1136 if (0 == strcasecmp ("arm", service))
1138 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1139 "Use peer start/stop for that");
1142 if (GNUNET_YES == peer->is_remote)
1144 /* Forward the destory message to sub controller */
1145 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1146 GNUNET_SERVER_client_keep (client);
1147 fopc->client = client;
1149 fopc->type = OP_MANAGE_SERVICE;
1150 fopc->operation_id = op_id;
1152 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1154 fopc->operation_id, &msg->header,
1155 &GST_forwarded_operation_reply_relay,
1157 fopc->timeout_task =
1158 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1160 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1161 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1164 if ((0 != peer->reference_cnt)
1165 && ( (0 == strcasecmp ("core", service))
1166 || (0 == strcasecmp ("transport", service)) ) )
1168 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1169 "since it is required by existing operations",
1173 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1176 GNUNET_asprintf (&emsg,
1177 "Cannot connect to ARM service of peer with id: %u",
1181 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
1183 peer->reference_cnt++;
1184 mctx->op_id = op_id;
1186 GNUNET_SERVER_client_keep (client);
1187 mctx->client = client;
1188 mctx->start = msg->start;
1189 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
1190 if (1 == mctx->start)
1191 GNUNET_ARM_request_service_start (mctx->ah, service,
1192 GNUNET_OS_INHERIT_STD_ERR,
1194 service_manage_result_cb,
1197 GNUNET_ARM_request_service_stop (mctx->ah, service,
1199 service_manage_result_cb,
1201 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1205 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1206 GST_send_operation_fail_msg (client, op_id, emsg);
1208 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1213 * Stops and destroys all peers
1216 GST_destroy_peers ()
1221 if (NULL == GST_peer_list)
1223 for (id = 0; id < GST_peer_list_size; id++)
1225 peer = GST_peer_list[id];
1228 /* If destroy flag is set it means that this peer should have been
1229 * destroyed by a context which we destroy before */
1230 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1231 /* counter should be zero as we free all contexts before */
1232 GNUNET_break (0 == peer->reference_cnt);
1233 if ((GNUNET_NO == peer->is_remote) &&
1234 (GNUNET_YES == peer->details.local.is_running))
1235 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1237 for (id = 0; id < GST_peer_list_size; id++)
1239 peer = GST_peer_list[id];
1242 if (GNUNET_NO == peer->is_remote)
1244 if (GNUNET_YES == peer->details.local.is_running)
1245 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1246 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1247 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1251 GNUNET_free_non_null (GST_peer_list);
1252 GST_peer_list = NULL;
1253 GST_peer_list_size = 0;
1258 * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
1260 * @param cls the ForwardedOperationContext
1261 * @param tc the scheduler task context
1264 shutdown_peers_timeout_cb (void *cls,
1265 const struct GNUNET_SCHEDULER_TaskContext *tc)
1267 struct ForwardedOperationContext *fo_ctxt = cls;
1268 struct HandlerContext_ShutdownPeers *hc;
1270 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1272 hc->timeout = GNUNET_YES;
1273 GNUNET_assert (0 < hc->nslaves);
1275 if (0 == hc->nslaves)
1276 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1277 "Timeout at a slave controller");
1278 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1279 GNUNET_SERVER_client_drop (fo_ctxt->client);
1280 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1281 GNUNET_free (fo_ctxt);
1286 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1287 * success reply is received from all clients and then sends the success message
1290 * @param cls ForwardedOperationContext
1291 * @param msg the message to relay
1294 shutdown_peers_reply_cb (void *cls,
1295 const struct GNUNET_MessageHeader *msg)
1297 struct ForwardedOperationContext *fo_ctxt = cls;
1298 struct HandlerContext_ShutdownPeers *hc;
1301 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
1302 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1303 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1304 GNUNET_assert (0 < hc->nslaves);
1306 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1308 hc->timeout = GNUNET_YES;
1309 if (0 == hc->nslaves)
1311 if (GNUNET_YES == hc->timeout)
1312 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1313 "Timeout at a slave controller");
1315 GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
1317 GNUNET_SERVER_client_drop (fo_ctxt->client);
1318 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1319 GNUNET_free (fo_ctxt);
1324 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1327 * @param client identification of the client
1328 * @param message the actual message
1331 GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
1332 const struct GNUNET_MessageHeader *message)
1334 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1335 struct HandlerContext_ShutdownPeers *hc;
1336 struct Slave *slave;
1337 struct ForwardedOperationContext *fo_ctxt;
1341 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1342 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1343 /* Stop and destroy all peers */
1348 /* Forward to all slaves which we have started */
1349 op_id = GNUNET_ntohll (msg->operation_id);
1350 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
1351 /* FIXME: have a better implementation where we track which slaves are
1352 started by this controller */
1353 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1355 slave = GST_slave_list[cnt];
1358 if (NULL == slave->controller_proc) /* We didn't start the slave */
1360 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1362 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1363 GNUNET_SERVER_client_keep (client);
1364 fo_ctxt->client = client;
1365 fo_ctxt->operation_id = op_id;
1367 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1369 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1370 fo_ctxt->operation_id,
1372 shutdown_peers_reply_cb,
1374 fo_ctxt->timeout_task =
1375 GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
1377 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1379 LOG_DEBUG ("Shutting down peers\n");
1380 GST_destroy_peers ();
1381 if (0 == hc->nslaves)
1383 GST_send_operation_success_msg (client, op_id);
1386 GNUNET_SERVER_receive_done (client, GNUNET_OK);