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 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., 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;
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
214 * @param tc the TaskContext from the scheduler
217 peer_create_forward_timeout (void *cls,
218 const struct GNUNET_SCHEDULER_TaskContext *tc)
220 struct ForwardedOperationContext *fopc = cls;
222 GNUNET_free (fopc->cls);
223 GST_forwarded_operation_timeout (fopc, tc);
228 * Callback to be called when forwarded peer create operation is successfull. We
229 * have to relay the reply msg back to the client
231 * @param cls ForwardedOperationContext
232 * @param msg the peer create success message
235 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
237 struct ForwardedOperationContext *fopc = cls;
238 struct Peer *remote_peer;
240 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
242 GNUNET_assert (NULL != fopc->cls);
243 remote_peer = fopc->cls;
244 peer_list_add (remote_peer);
246 GST_forwarded_operation_reply_relay (fopc, msg);
251 * Function to destroy a peer
253 * @param peer the peer structure to destroy
256 GST_destroy_peer (struct Peer *peer)
258 GNUNET_break (0 == peer->reference_cnt);
259 if (GNUNET_YES == peer->is_remote)
261 peer_list_remove (peer);
265 if (GNUNET_YES == peer->details.local.is_running)
267 GNUNET_TESTING_peer_stop (peer->details.local.peer);
268 peer->details.local.is_running = GNUNET_NO;
270 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
271 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
272 peer_list_remove (peer);
278 * Callback to be called when forwarded peer destroy operation is successfull. We
279 * have to relay the reply msg back to the client
281 * @param cls ForwardedOperationContext
282 * @param msg the peer create success message
285 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
287 struct ForwardedOperationContext *fopc = cls;
288 struct Peer *remote_peer;
290 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
293 remote_peer = fopc->cls;
294 GNUNET_assert (NULL != remote_peer);
295 remote_peer->destroy_flag = GNUNET_YES;
296 if (0 == remote_peer->reference_cnt)
297 GST_destroy_peer (remote_peer);
299 GST_forwarded_operation_reply_relay (fopc, msg);
304 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
307 * @param client identification of the client
308 * @param message the actual message
311 GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
312 const struct GNUNET_MessageHeader *message)
314 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
315 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
316 struct GNUNET_CONFIGURATION_Handle *cfg;
317 struct ForwardedOperationContext *fo_ctxt;
326 msize = ntohs (message->size);
327 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
329 GNUNET_break (0); /* We need configuration */
330 GNUNET_SERVER_receive_done (client, GNUNET_OK);
333 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
334 host_id = ntohl (msg->host_id);
335 peer_id = ntohl (msg->peer_id);
336 if (VALID_PEER_ID (peer_id))
338 (void) GNUNET_asprintf (&emsg, "Peer with ID %u already exists", peer_id);
339 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
342 GNUNET_SERVER_receive_done (client, GNUNET_OK);
345 if (UINT32_MAX == peer_id)
347 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
348 "Cannot create peer with given ID");
349 GNUNET_SERVER_receive_done (client, GNUNET_OK);
352 if (host_id == GST_context->host_id)
354 /* We are responsible for this peer */
355 cfg = GNUNET_TESTBED_extract_config_ (message);
359 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
362 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
363 (unsigned long long) peer_id);
365 GNUNET_CONFIGURATION_set_value_number (cfg, "PATHS", "PEERID",
366 (unsigned long long) peer_id);
367 peer = GNUNET_malloc (sizeof (struct Peer));
368 peer->is_remote = GNUNET_NO;
369 peer->details.local.cfg = cfg;
371 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
372 peer->details.local.peer =
373 GNUNET_TESTING_peer_configure (GST_context->system,
374 peer->details.local.cfg, peer->id,
377 if (NULL == peer->details.local.peer)
379 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
383 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
386 peer->details.local.is_running = GNUNET_NO;
387 peer_list_add (peer);
389 GNUNET_malloc (sizeof
390 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
392 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
394 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
395 reply->peer_id = msg->peer_id;
396 reply->operation_id = msg->operation_id;
397 GST_queue_message (client, &reply->header);
398 GNUNET_SERVER_receive_done (client, GNUNET_OK);
402 /* Forward peer create request */
403 route = GST_find_dest_route (host_id);
407 GNUNET_SERVER_receive_done (client, GNUNET_OK);
410 peer = GNUNET_malloc (sizeof (struct Peer));
411 peer->is_remote = GNUNET_YES;
413 peer->details.remote.slave = GST_slave_list[route->dest];
414 peer->details.remote.remote_host_id = host_id;
415 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
416 GNUNET_SERVER_client_keep (client);
417 fo_ctxt->client = client;
418 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
420 fo_ctxt->type = OP_PEER_CREATE;
422 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
423 [route->dest]->controller,
424 fo_ctxt->operation_id,
426 peer_create_success_cb, fo_ctxt);
427 fo_ctxt->timeout_task =
428 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
430 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
431 GNUNET_SERVER_receive_done (client, GNUNET_OK);
436 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
439 * @param client identification of the client
440 * @param message the actual message
443 GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
444 const struct GNUNET_MessageHeader *message)
446 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
447 struct ForwardedOperationContext *fopc;
451 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
452 peer_id = ntohl (msg->peer_id);
453 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
454 peer_id, GNUNET_ntohll (msg->operation_id));
455 if (!VALID_PEER_ID (peer_id))
457 LOG (GNUNET_ERROR_TYPE_ERROR,
458 "Asked to destroy a non existent peer with id: %u\n", peer_id);
459 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
460 "Peer doesn't exist");
461 GNUNET_SERVER_receive_done (client, GNUNET_OK);
464 peer = GST_peer_list[peer_id];
465 if (GNUNET_YES == peer->is_remote)
467 /* Forward the destory message to sub controller */
468 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
469 GNUNET_SERVER_client_keep (client);
470 fopc->client = client;
472 fopc->type = OP_PEER_DESTROY;
473 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
475 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
477 fopc->operation_id, &msg->header,
478 &peer_destroy_success_cb, fopc);
480 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
482 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
483 GNUNET_SERVER_receive_done (client, GNUNET_OK);
486 peer->destroy_flag = GNUNET_YES;
487 if (0 == peer->reference_cnt)
488 GST_destroy_peer (peer);
490 LOG (GNUNET_ERROR_TYPE_DEBUG,
491 "Delaying peer destroy as peer is currently in use\n");
492 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
493 GNUNET_SERVER_receive_done (client, GNUNET_OK);
500 * @param peer the peer to start
501 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
504 start_peer (struct Peer *peer)
506 GNUNET_assert (GNUNET_NO == peer->is_remote);
507 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
508 return GNUNET_SYSERR;
509 peer->details.local.is_running = GNUNET_YES;
517 * @param peer the peer to stop
518 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
521 stop_peer (struct Peer *peer)
523 GNUNET_assert (GNUNET_NO == peer->is_remote);
524 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
525 return GNUNET_SYSERR;
526 peer->details.local.is_running = GNUNET_NO;
532 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
535 * @param client identification of the client
536 * @param message the actual message
539 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
540 const struct GNUNET_MessageHeader *message)
542 const struct GNUNET_TESTBED_PeerStartMessage *msg;
543 struct GNUNET_TESTBED_PeerEventMessage *reply;
544 struct ForwardedOperationContext *fopc;
548 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
549 peer_id = ntohl (msg->peer_id);
550 if (!VALID_PEER_ID (peer_id))
553 LOG (GNUNET_ERROR_TYPE_ERROR,
554 "Asked to start a non existent peer with id: %u\n", peer_id);
555 GNUNET_SERVER_receive_done (client, GNUNET_OK);
558 peer = GST_peer_list[peer_id];
559 if (GNUNET_YES == peer->is_remote)
561 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
562 GNUNET_SERVER_client_keep (client);
563 fopc->client = client;
564 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
565 fopc->type = OP_PEER_START;
567 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
569 fopc->operation_id, &msg->header,
570 &GST_forwarded_operation_reply_relay,
573 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
575 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
576 GNUNET_SERVER_receive_done (client, GNUNET_OK);
579 if (GNUNET_OK != start_peer (peer))
581 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
583 GNUNET_SERVER_receive_done (client, GNUNET_OK);
586 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
587 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
588 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
589 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
590 reply->host_id = htonl (GST_context->host_id);
591 reply->peer_id = msg->peer_id;
592 reply->operation_id = msg->operation_id;
593 GST_queue_message (client, &reply->header);
594 GNUNET_SERVER_receive_done (client, GNUNET_OK);
599 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
602 * @param client identification of the client
603 * @param message the actual message
606 GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
607 const struct GNUNET_MessageHeader *message)
609 const struct GNUNET_TESTBED_PeerStopMessage *msg;
610 struct GNUNET_TESTBED_PeerEventMessage *reply;
611 struct ForwardedOperationContext *fopc;
615 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
616 peer_id = ntohl (msg->peer_id);
617 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
618 if (!VALID_PEER_ID (peer_id))
620 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
622 GNUNET_SERVER_receive_done (client, GNUNET_OK);
625 peer = GST_peer_list[peer_id];
626 if (GNUNET_YES == peer->is_remote)
628 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
630 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
631 GNUNET_SERVER_client_keep (client);
632 fopc->client = client;
633 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
634 fopc->type = OP_PEER_STOP;
636 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
638 fopc->operation_id, &msg->header,
639 &GST_forwarded_operation_reply_relay,
642 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
644 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
645 GNUNET_SERVER_receive_done (client, GNUNET_OK);
648 if (GNUNET_OK != stop_peer (peer))
650 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
651 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
653 GNUNET_SERVER_receive_done (client, GNUNET_OK);
656 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
657 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
658 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
659 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
660 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
661 reply->host_id = htonl (GST_context->host_id);
662 reply->peer_id = msg->peer_id;
663 reply->operation_id = msg->operation_id;
664 GST_queue_message (client, &reply->header);
665 GNUNET_SERVER_receive_done (client, GNUNET_OK);
666 GNUNET_TESTING_peer_wait (peer->details.local.peer);
671 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
674 * @param client identification of the client
675 * @param message the actual message
678 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
679 const struct GNUNET_MessageHeader *message)
681 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
682 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
683 struct ForwardedOperationContext *fopc;
692 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
693 peer_id = ntohl (msg->peer_id);
694 LOG_DEBUG ("Received GET_CONFIG for peer %u\n", peer_id);
695 if (!VALID_PEER_ID (peer_id))
697 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
699 GNUNET_SERVER_receive_done (client, GNUNET_OK);
702 peer = GST_peer_list[peer_id];
703 if (GNUNET_YES == peer->is_remote)
705 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
706 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
707 GNUNET_SERVER_client_keep (client);
708 fopc->client = client;
709 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
710 fopc->type = OP_PEER_INFO;
712 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
714 fopc->operation_id, &msg->header,
715 &GST_forwarded_operation_reply_relay,
718 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
720 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
721 GNUNET_SERVER_receive_done (client, GNUNET_OK);
724 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
726 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
728 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
729 GNUNET_free (config);
732 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
733 reply = GNUNET_realloc (xconfig, msize);
734 (void) memmove (&reply[1], reply, xc_size);
735 reply->header.size = htons (msize);
736 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
737 reply->peer_id = msg->peer_id;
738 reply->operation_id = msg->operation_id;
739 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
740 &reply->peer_identity);
741 reply->config_size = htons ((uint16_t) c_size);
742 GST_queue_message (client, &reply->header);
743 GNUNET_SERVER_receive_done (client, GNUNET_OK);
748 * Cleans up the given PeerReconfigureContext
750 * @param prc the PeerReconfigureContext
753 cleanup_prc (struct PeerReconfigureContext *prc)
757 if (VALID_PEER_ID (prc->peer_id))
759 peer = GST_peer_list [prc->peer_id];
760 if (1 != prc->stopped)
762 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
763 stop_peer (peer); /* Stop the peer synchronously */
766 if (NULL != prc->cfg)
767 GNUNET_CONFIGURATION_destroy (prc->cfg);
768 GNUNET_SERVER_client_drop (prc->client);
769 GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
775 * Cleans up the Peer reconfigure context list
780 while (NULL != prc_head)
781 cleanup_prc (prc_head);
786 * Update peer configuration
788 * @param peer the peer to update
789 * @param cfg the new configuration
790 * @return error message (freshly allocated); NULL upon success
793 update_peer_config (struct Peer *peer,
794 struct GNUNET_CONFIGURATION_Handle *cfg)
798 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
799 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
800 peer->details.local.cfg = cfg;
802 peer->details.local.peer
803 = GNUNET_TESTING_peer_configure (GST_context->system,
804 peer->details.local.cfg, peer->id,
812 * Callback to inform whether the peer is running or stopped.
814 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
815 * @param p the respective peer whose status is being reported
816 * @param success GNUNET_YES if the peer is stopped; GNUNET_SYSERR upon any
820 prc_stop_cb (void *cls, struct GNUNET_TESTING_Peer *p, int success)
822 struct PeerReconfigureContext *prc = cls;
826 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
827 peer = GST_peer_list [prc->peer_id];
828 GNUNET_assert (GNUNET_NO == peer->is_remote);
829 emsg = update_peer_config (peer, prc->cfg);
834 GST_send_operation_fail_msg (prc->client, prc->op_id, emsg);
837 if (GNUNET_OK != start_peer (peer))
839 GST_send_operation_fail_msg (prc->client, prc->op_id,
840 "Failed to start reconfigured peer");
843 GST_send_operation_success_msg (prc->client, prc->op_id);
852 * Handler for GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
853 * Should stop the peer asyncronously, destroy it and create it again with the
857 * @param client identification of the client
858 * @param message the actual message
861 GST_handle_peer_reconfigure (void *cls, struct GNUNET_SERVER_Client *client,
862 const struct GNUNET_MessageHeader *message)
864 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
866 struct GNUNET_CONFIGURATION_Handle *cfg;
867 struct ForwardedOperationContext *fopc;
868 struct PeerReconfigureContext *prc;
874 msize = ntohs (message->size);
875 if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
878 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
881 msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
882 peer_id = ntohl (msg->peer_id);
883 op_id = GNUNET_ntohll (msg->operation_id);
884 if (!VALID_PEER_ID (peer_id))
887 GST_send_operation_fail_msg (client, op_id, "Peer not found");
888 GNUNET_SERVER_receive_done (client, GNUNET_OK);
891 peer = GST_peer_list[peer_id];
892 if (GNUNET_YES == peer->is_remote)
894 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
895 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
896 GNUNET_SERVER_client_keep (client);
897 fopc->client = client;
898 fopc->operation_id = op_id;
899 fopc->type = OP_PEER_RECONFIGURE;
901 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
903 fopc->operation_id, &msg->header,
904 &GST_forwarded_operation_reply_relay,
907 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
909 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
910 GNUNET_SERVER_receive_done (client, GNUNET_OK);
913 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", peer_id);
914 if (0 < peer->reference_cnt)
917 GST_send_operation_fail_msg (client, op_id, "Peer in use");
918 GNUNET_SERVER_receive_done (client, GNUNET_OK);
921 if (GNUNET_YES == peer->destroy_flag)
924 GST_send_operation_fail_msg (client, op_id, "Peer is being destroyed");
925 GNUNET_SERVER_receive_done (client, GNUNET_OK);
928 cfg = GNUNET_TESTBED_extract_config_ (message);
932 GST_send_operation_fail_msg (client, op_id, "Compression error");
933 GNUNET_SERVER_receive_done (client, GNUNET_OK);
936 if (GNUNET_NO == peer->details.local.is_running)
938 emsg = update_peer_config (peer, cfg);
940 GST_send_operation_fail_msg (client, op_id, emsg);
941 GST_send_operation_success_msg (client, op_id);
942 GNUNET_SERVER_receive_done (client, GNUNET_OK);
945 prc = GNUNET_malloc (sizeof (struct PeerReconfigureContext));
947 GNUNET_TESTING_peer_stop_async (peer->details.local.peer, &prc_stop_cb,
950 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
951 "Error trying to stop peer %u asynchronously\n",
953 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
954 GST_send_operation_fail_msg (client, op_id, emsg);
955 GNUNET_SERVER_receive_done (client, GNUNET_OK);
961 prc->peer_id = peer_id;
963 prc->client = client;
964 GNUNET_SERVER_client_keep (client);
965 GNUNET_CONTAINER_DLL_insert_tail (prc_head, prc_tail, prc);
966 GNUNET_SERVER_receive_done (client, GNUNET_OK);
971 * Cleanup the context information created for managing a peer's service
973 * @param mctx the ManageServiceContext
976 cleanup_mctx (struct ManageServiceContext *mctx)
978 mctx->expired = GNUNET_YES;
979 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
980 GNUNET_SERVER_client_drop (mctx->client);
981 GNUNET_ARM_disconnect_and_free (mctx->ah);
982 GNUNET_assert (0 < mctx->peer->reference_cnt);
983 mctx->peer->reference_cnt--;
984 if ( (GNUNET_YES == mctx->peer->destroy_flag)
985 && (0 == mctx->peer->reference_cnt) )
986 GST_destroy_peer (mctx->peer);
992 * Frees the ManageServiceContext queue
997 while (NULL != mctx_head)
998 cleanup_mctx (mctx_head);
1003 * Returns a string interpretation of 'rs'
1005 * @param rs the request status from ARM
1006 * @return a string interpretation of the request status
1009 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1013 case GNUNET_ARM_REQUEST_SENT_OK:
1014 return _("Message was sent successfully");
1015 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
1016 return _("Misconfiguration (can't connect to the ARM service)");
1017 case GNUNET_ARM_REQUEST_DISCONNECTED:
1018 return _("We disconnected from ARM before we could send a request");
1019 case GNUNET_ARM_REQUEST_BUSY:
1020 return _("ARM API is busy");
1021 case GNUNET_ARM_REQUEST_TOO_LONG:
1022 return _("Request doesn't fit into a message");
1023 case GNUNET_ARM_REQUEST_TIMEOUT:
1024 return _("Request timed out");
1026 return _("Unknown request status");
1031 * Returns a string interpretation of the 'result'
1033 * @param result the arm result
1034 * @return a string interpretation
1037 arm_ret_string (enum GNUNET_ARM_Result result)
1041 case GNUNET_ARM_RESULT_STOPPED:
1042 return _("%s is stopped");
1043 case GNUNET_ARM_RESULT_STARTING:
1044 return _("%s is starting");
1045 case GNUNET_ARM_RESULT_STOPPING:
1046 return _("%s is stopping");
1047 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1048 return _("%s is starting already");
1049 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1050 return _("%s is stopping already");
1051 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1052 return _("%s is started already");
1053 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1054 return _("%s is stopped already");
1055 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1056 return _("%s service is not known to ARM");
1057 case GNUNET_ARM_RESULT_START_FAILED:
1058 return _("%s service failed to start");
1059 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1060 return _("%s service can't be started because ARM is shutting down");
1062 return _("%.s Unknown result code.");
1067 * Function called in response to a start/stop request.
1068 * Will be called when request was not sent successfully,
1069 * or when a reply comes. If the request was not sent successfully,
1070 * 'rs' will indicate that, and 'service' and 'result' will be undefined.
1072 * @param cls ManageServiceContext
1073 * @param rs status of the request
1074 * @param service service name
1075 * @param result result of the operation
1078 service_manage_result_cb (void *cls,
1079 enum GNUNET_ARM_RequestStatus rs,
1080 const char *service, enum GNUNET_ARM_Result result)
1082 struct ManageServiceContext *mctx = cls;
1086 if (GNUNET_YES == mctx->expired)
1088 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1090 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
1091 mctx->peer->id, arm_req_string (rs));
1094 if (1 == mctx->start)
1095 goto service_start_check;
1096 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1097 || (GNUNET_ARM_RESULT_STOPPING == result)
1098 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1099 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1101 /* stopping a service failed */
1102 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1105 /* service stopped successfully */
1108 service_start_check:
1109 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1110 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1111 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1113 /* starting a service failed */
1114 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1117 /* service started successfully */
1122 LOG_DEBUG ("%s\n", emsg);
1123 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
1126 GST_send_operation_success_msg (mctx->client, mctx->op_id);
1127 GNUNET_free_non_null (emsg);
1128 cleanup_mctx (mctx);
1133 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
1136 * @param client identification of client
1137 * @param message the actual message
1140 GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
1141 const struct GNUNET_MessageHeader *message)
1143 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
1144 const char* service;
1147 struct GNUNET_ARM_Handle *ah;
1148 struct ManageServiceContext *mctx;
1149 struct ForwardedOperationContext *fopc;
1155 msize = ntohs (message->size);
1156 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
1158 GNUNET_break_op (0);
1159 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1162 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
1163 service = (const char *) &msg[1];
1164 if ('\0' != service[msize - sizeof
1165 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1167 GNUNET_break_op (0);
1168 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1173 GNUNET_break_op (0);
1174 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1177 peer_id = ntohl (msg->peer_id);
1178 op_id = GNUNET_ntohll (msg->operation_id);
1179 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1180 service, (unsigned int) peer_id);
1181 if ((GST_peer_list_size <= peer_id)
1182 || (NULL == (peer = GST_peer_list[peer_id])))
1184 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1185 "with id: %u", peer_id);
1188 if (0 == strcasecmp ("arm", service))
1190 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1191 "Use peer start/stop for that");
1194 if (GNUNET_YES == peer->is_remote)
1196 /* Forward the destory message to sub controller */
1197 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1198 GNUNET_SERVER_client_keep (client);
1199 fopc->client = client;
1201 fopc->type = OP_MANAGE_SERVICE;
1202 fopc->operation_id = op_id;
1204 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1206 fopc->operation_id, &msg->header,
1207 &GST_forwarded_operation_reply_relay,
1209 fopc->timeout_task =
1210 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1212 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1213 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1216 if (GNUNET_NO == peer->details.local.is_running)
1218 emsg = GNUNET_strdup ("Peer not running\n");
1221 if ((0 != peer->reference_cnt)
1222 && ( (0 == strcasecmp ("core", service))
1223 || (0 == strcasecmp ("transport", service)) ) )
1225 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1226 "since it is required by existing operations",
1230 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1233 GNUNET_asprintf (&emsg,
1234 "Cannot connect to ARM service of peer with id: %u",
1238 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
1240 peer->reference_cnt++;
1241 mctx->op_id = op_id;
1243 GNUNET_SERVER_client_keep (client);
1244 mctx->client = client;
1245 mctx->start = msg->start;
1246 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
1247 if (1 == mctx->start)
1248 GNUNET_ARM_request_service_start (mctx->ah, service,
1249 GNUNET_OS_INHERIT_STD_ERR,
1251 service_manage_result_cb,
1254 GNUNET_ARM_request_service_stop (mctx->ah, service,
1256 service_manage_result_cb,
1258 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1262 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1263 GST_send_operation_fail_msg (client, op_id, emsg);
1265 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1270 * Stops and destroys all peers
1273 GST_destroy_peers ()
1278 if (NULL == GST_peer_list)
1280 for (id = 0; id < GST_peer_list_size; id++)
1282 peer = GST_peer_list[id];
1285 /* If destroy flag is set it means that this peer should have been
1286 * destroyed by a context which we destroy before */
1287 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1288 /* counter should be zero as we free all contexts before */
1289 GNUNET_break (0 == peer->reference_cnt);
1290 if ((GNUNET_NO == peer->is_remote) &&
1291 (GNUNET_YES == peer->details.local.is_running))
1292 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1294 for (id = 0; id < GST_peer_list_size; id++)
1296 peer = GST_peer_list[id];
1299 if (GNUNET_NO == peer->is_remote)
1301 if (GNUNET_YES == peer->details.local.is_running)
1302 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1303 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1304 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1308 GNUNET_free_non_null (GST_peer_list);
1309 GST_peer_list = NULL;
1310 GST_peer_list_size = 0;
1315 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1316 * success reply is received from all clients and then sends the success message
1319 * @param cls ForwardedOperationContext
1320 * @param msg the message to relay
1323 shutdown_peers_reply_cb (void *cls,
1324 const struct GNUNET_MessageHeader *msg)
1326 struct ForwardedOperationContext *fo_ctxt = cls;
1327 struct HandlerContext_ShutdownPeers *hc;
1330 GNUNET_assert (0 < hc->nslaves);
1332 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1334 hc->timeout = GNUNET_YES;
1335 if (0 == hc->nslaves)
1337 if (GNUNET_YES == hc->timeout)
1338 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1339 "Timeout at a slave controller");
1341 GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
1345 GNUNET_SERVER_client_drop (fo_ctxt->client);
1346 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1347 GNUNET_free (fo_ctxt);
1352 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1355 * @param client identification of the client
1356 * @param message the actual message
1359 GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
1360 const struct GNUNET_MessageHeader *message)
1362 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1363 struct HandlerContext_ShutdownPeers *hc;
1364 struct Slave *slave;
1365 struct ForwardedOperationContext *fo_ctxt;
1369 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1370 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1371 /* Stop and destroy all peers */
1376 /* Forward to all slaves which we have started */
1377 op_id = GNUNET_ntohll (msg->operation_id);
1378 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
1379 /* FIXME: have a better implementation where we track which slaves are
1380 started by this controller */
1381 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1383 slave = GST_slave_list[cnt];
1386 if (NULL == slave->controller_proc) /* We didn't start the slave */
1388 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1390 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1391 GNUNET_SERVER_client_keep (client);
1392 fo_ctxt->client = client;
1393 fo_ctxt->operation_id = op_id;
1395 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1397 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1398 fo_ctxt->operation_id,
1400 shutdown_peers_reply_cb,
1402 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1404 LOG_DEBUG ("Shutting down peers\n");
1405 GST_destroy_peers ();
1406 if (0 == hc->nslaves)
1408 GST_send_operation_success_msg (client, op_id);
1411 GNUNET_SERVER_receive_done (client, GNUNET_OK);