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);
364 peer = GNUNET_malloc (sizeof (struct Peer));
365 peer->is_remote = GNUNET_NO;
366 peer->details.local.cfg = cfg;
368 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
369 peer->details.local.peer =
370 GNUNET_TESTING_peer_configure (GST_context->system,
371 peer->details.local.cfg, peer->id,
374 if (NULL == peer->details.local.peer)
376 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
380 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
383 peer->details.local.is_running = GNUNET_NO;
384 peer_list_add (peer);
386 GNUNET_malloc (sizeof
387 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
389 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
391 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
392 reply->peer_id = msg->peer_id;
393 reply->operation_id = msg->operation_id;
394 GST_queue_message (client, &reply->header);
395 GNUNET_SERVER_receive_done (client, GNUNET_OK);
399 /* Forward peer create request */
400 route = GST_find_dest_route (host_id);
404 GNUNET_SERVER_receive_done (client, GNUNET_OK);
407 peer = GNUNET_malloc (sizeof (struct Peer));
408 peer->is_remote = GNUNET_YES;
410 peer->details.remote.slave = GST_slave_list[route->dest];
411 peer->details.remote.remote_host_id = host_id;
412 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
413 GNUNET_SERVER_client_keep (client);
414 fo_ctxt->client = client;
415 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
417 fo_ctxt->type = OP_PEER_CREATE;
419 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
420 [route->dest]->controller,
421 fo_ctxt->operation_id,
423 peer_create_success_cb, fo_ctxt);
424 fo_ctxt->timeout_task =
425 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
427 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
428 GNUNET_SERVER_receive_done (client, GNUNET_OK);
433 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
436 * @param client identification of the client
437 * @param message the actual message
440 GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
441 const struct GNUNET_MessageHeader *message)
443 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
444 struct ForwardedOperationContext *fopc;
448 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
449 peer_id = ntohl (msg->peer_id);
450 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
451 peer_id, GNUNET_ntohll (msg->operation_id));
452 if (!VALID_PEER_ID (peer_id))
454 LOG (GNUNET_ERROR_TYPE_ERROR,
455 "Asked to destroy a non existent peer with id: %u\n", peer_id);
456 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
457 "Peer doesn't exist");
458 GNUNET_SERVER_receive_done (client, GNUNET_OK);
461 peer = GST_peer_list[peer_id];
462 if (GNUNET_YES == peer->is_remote)
464 /* Forward the destory message to sub controller */
465 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
466 GNUNET_SERVER_client_keep (client);
467 fopc->client = client;
469 fopc->type = OP_PEER_DESTROY;
470 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
472 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
474 fopc->operation_id, &msg->header,
475 &peer_destroy_success_cb, fopc);
477 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
479 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
480 GNUNET_SERVER_receive_done (client, GNUNET_OK);
483 peer->destroy_flag = GNUNET_YES;
484 if (0 == peer->reference_cnt)
485 GST_destroy_peer (peer);
487 LOG (GNUNET_ERROR_TYPE_DEBUG,
488 "Delaying peer destroy as peer is currently in use\n");
489 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
490 GNUNET_SERVER_receive_done (client, GNUNET_OK);
497 * @param peer the peer to start
498 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
501 start_peer (struct Peer *peer)
503 GNUNET_assert (GNUNET_NO == peer->is_remote);
504 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
505 return GNUNET_SYSERR;
506 peer->details.local.is_running = GNUNET_YES;
514 * @param peer the peer to stop
515 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
518 stop_peer (struct Peer *peer)
520 GNUNET_assert (GNUNET_NO == peer->is_remote);
521 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
522 return GNUNET_SYSERR;
523 peer->details.local.is_running = GNUNET_NO;
529 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
532 * @param client identification of the client
533 * @param message the actual message
536 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
537 const struct GNUNET_MessageHeader *message)
539 const struct GNUNET_TESTBED_PeerStartMessage *msg;
540 struct GNUNET_TESTBED_PeerEventMessage *reply;
541 struct ForwardedOperationContext *fopc;
545 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
546 peer_id = ntohl (msg->peer_id);
547 if (!VALID_PEER_ID (peer_id))
550 LOG (GNUNET_ERROR_TYPE_ERROR,
551 "Asked to start a non existent peer with id: %u\n", peer_id);
552 GNUNET_SERVER_receive_done (client, GNUNET_OK);
555 peer = GST_peer_list[peer_id];
556 if (GNUNET_YES == peer->is_remote)
558 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
559 GNUNET_SERVER_client_keep (client);
560 fopc->client = client;
561 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
562 fopc->type = OP_PEER_START;
564 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
566 fopc->operation_id, &msg->header,
567 &GST_forwarded_operation_reply_relay,
570 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
572 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
576 if (GNUNET_OK != start_peer (peer))
578 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
580 GNUNET_SERVER_receive_done (client, GNUNET_OK);
583 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
584 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
585 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
586 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
587 reply->host_id = htonl (GST_context->host_id);
588 reply->peer_id = msg->peer_id;
589 reply->operation_id = msg->operation_id;
590 GST_queue_message (client, &reply->header);
591 GNUNET_SERVER_receive_done (client, GNUNET_OK);
596 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
599 * @param client identification of the client
600 * @param message the actual message
603 GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
604 const struct GNUNET_MessageHeader *message)
606 const struct GNUNET_TESTBED_PeerStopMessage *msg;
607 struct GNUNET_TESTBED_PeerEventMessage *reply;
608 struct ForwardedOperationContext *fopc;
612 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
613 peer_id = ntohl (msg->peer_id);
614 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
615 if (!VALID_PEER_ID (peer_id))
617 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
619 GNUNET_SERVER_receive_done (client, GNUNET_OK);
622 peer = GST_peer_list[peer_id];
623 if (GNUNET_YES == peer->is_remote)
625 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
627 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
628 GNUNET_SERVER_client_keep (client);
629 fopc->client = client;
630 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
631 fopc->type = OP_PEER_STOP;
633 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
635 fopc->operation_id, &msg->header,
636 &GST_forwarded_operation_reply_relay,
639 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
641 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
642 GNUNET_SERVER_receive_done (client, GNUNET_OK);
645 if (GNUNET_OK != stop_peer (peer))
647 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
648 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
650 GNUNET_SERVER_receive_done (client, GNUNET_OK);
653 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
654 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
655 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
656 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
657 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
658 reply->host_id = htonl (GST_context->host_id);
659 reply->peer_id = msg->peer_id;
660 reply->operation_id = msg->operation_id;
661 GST_queue_message (client, &reply->header);
662 GNUNET_SERVER_receive_done (client, GNUNET_OK);
663 GNUNET_TESTING_peer_wait (peer->details.local.peer);
668 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
671 * @param client identification of the client
672 * @param message the actual message
675 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
676 const struct GNUNET_MessageHeader *message)
678 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
679 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
680 struct ForwardedOperationContext *fopc;
689 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
690 peer_id = ntohl (msg->peer_id);
691 LOG_DEBUG ("Received GET_CONFIG for peer %u\n", peer_id);
692 if (!VALID_PEER_ID (peer_id))
694 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
696 GNUNET_SERVER_receive_done (client, GNUNET_OK);
699 peer = GST_peer_list[peer_id];
700 if (GNUNET_YES == peer->is_remote)
702 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
703 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
704 GNUNET_SERVER_client_keep (client);
705 fopc->client = client;
706 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
707 fopc->type = OP_PEER_INFO;
709 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
711 fopc->operation_id, &msg->header,
712 &GST_forwarded_operation_reply_relay,
715 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
717 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
718 GNUNET_SERVER_receive_done (client, GNUNET_OK);
721 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
723 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
725 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
726 GNUNET_free (config);
729 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
730 reply = GNUNET_realloc (xconfig, msize);
731 (void) memmove (&reply[1], reply, xc_size);
732 reply->header.size = htons (msize);
733 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
734 reply->peer_id = msg->peer_id;
735 reply->operation_id = msg->operation_id;
736 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
737 &reply->peer_identity);
738 reply->config_size = htons ((uint16_t) c_size);
739 GST_queue_message (client, &reply->header);
740 GNUNET_SERVER_receive_done (client, GNUNET_OK);
745 * Cleans up the given PeerReconfigureContext
747 * @param prc the PeerReconfigureContext
750 cleanup_prc (struct PeerReconfigureContext *prc)
754 if (VALID_PEER_ID (prc->peer_id))
756 peer = GST_peer_list [prc->peer_id];
757 if (1 != prc->stopped)
759 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
760 stop_peer (peer); /* Stop the peer synchronously */
763 if (NULL != prc->cfg)
764 GNUNET_CONFIGURATION_destroy (prc->cfg);
765 GNUNET_SERVER_client_drop (prc->client);
766 GNUNET_CONTAINER_DLL_remove (prc_head, prc_tail, prc);
772 * Cleans up the Peer reconfigure context list
777 while (NULL != prc_head)
778 cleanup_prc (prc_head);
783 * Update peer configuration
785 * @param peer the peer to update
786 * @param cfg the new configuration
787 * @return error message (freshly allocated); NULL upon success
790 update_peer_config (struct Peer *peer,
791 struct GNUNET_CONFIGURATION_Handle *cfg)
795 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
796 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
797 peer->details.local.cfg = cfg;
799 peer->details.local.peer
800 = GNUNET_TESTING_peer_configure (GST_context->system,
801 peer->details.local.cfg, peer->id,
809 * Callback to inform whether the peer is running or stopped.
811 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
812 * @param p the respective peer whose status is being reported
813 * @param success GNUNET_YES if the peer is stopped; GNUNET_SYSERR upon any
817 prc_stop_cb (void *cls, struct GNUNET_TESTING_Peer *p, int success)
819 struct PeerReconfigureContext *prc = cls;
823 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
824 peer = GST_peer_list [prc->peer_id];
825 GNUNET_assert (GNUNET_NO == peer->is_remote);
826 emsg = update_peer_config (peer, prc->cfg);
831 GST_send_operation_fail_msg (prc->client, prc->op_id, emsg);
834 if (GNUNET_OK != start_peer (peer))
836 GST_send_operation_fail_msg (prc->client, prc->op_id,
837 "Failed to start reconfigured peer");
840 GST_send_operation_success_msg (prc->client, prc->op_id);
849 * Handler for GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
850 * Should stop the peer asyncronously, destroy it and create it again with the
854 * @param client identification of the client
855 * @param message the actual message
858 GST_handle_peer_reconfigure (void *cls, struct GNUNET_SERVER_Client *client,
859 const struct GNUNET_MessageHeader *message)
861 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
863 struct GNUNET_CONFIGURATION_Handle *cfg;
864 struct ForwardedOperationContext *fopc;
865 struct PeerReconfigureContext *prc;
871 msize = ntohs (message->size);
872 if (msize <= sizeof (struct GNUNET_TESTBED_PeerReconfigureMessage))
875 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
878 msg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) message;
879 peer_id = ntohl (msg->peer_id);
880 op_id = GNUNET_ntohll (msg->operation_id);
881 if (!VALID_PEER_ID (peer_id))
884 GST_send_operation_fail_msg (client, op_id, "Peer not found");
885 GNUNET_SERVER_receive_done (client, GNUNET_OK);
888 peer = GST_peer_list[peer_id];
889 if (GNUNET_YES == peer->is_remote)
891 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
892 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
893 GNUNET_SERVER_client_keep (client);
894 fopc->client = client;
895 fopc->operation_id = op_id;
896 fopc->type = OP_PEER_RECONFIGURE;
898 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
900 fopc->operation_id, &msg->header,
901 &GST_forwarded_operation_reply_relay,
904 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
906 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
907 GNUNET_SERVER_receive_done (client, GNUNET_OK);
910 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", peer_id);
911 if (0 < peer->reference_cnt)
914 GST_send_operation_fail_msg (client, op_id, "Peer in use");
915 GNUNET_SERVER_receive_done (client, GNUNET_OK);
918 if (GNUNET_YES == peer->destroy_flag)
921 GST_send_operation_fail_msg (client, op_id, "Peer is being destroyed");
922 GNUNET_SERVER_receive_done (client, GNUNET_OK);
925 cfg = GNUNET_TESTBED_extract_config_ (message);
929 GST_send_operation_fail_msg (client, op_id, "Compression error");
930 GNUNET_SERVER_receive_done (client, GNUNET_OK);
933 if (GNUNET_NO == peer->details.local.is_running)
935 emsg = update_peer_config (peer, cfg);
937 GST_send_operation_fail_msg (client, op_id, emsg);
938 GST_send_operation_success_msg (client, op_id);
939 GNUNET_SERVER_receive_done (client, GNUNET_OK);
942 prc = GNUNET_malloc (sizeof (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);
957 prc->peer_id = peer_id;
959 prc->client = client;
960 GNUNET_SERVER_client_keep (client);
961 GNUNET_CONTAINER_DLL_insert_tail (prc_head, prc_tail, prc);
962 GNUNET_SERVER_receive_done (client, GNUNET_OK);
967 * Cleanup the context information created for managing a peer's service
969 * @param mctx the ManageServiceContext
972 cleanup_mctx (struct ManageServiceContext *mctx)
974 mctx->expired = GNUNET_YES;
975 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
976 GNUNET_SERVER_client_drop (mctx->client);
977 GNUNET_ARM_disconnect_and_free (mctx->ah);
978 GNUNET_assert (0 < mctx->peer->reference_cnt);
979 mctx->peer->reference_cnt--;
980 if ( (GNUNET_YES == mctx->peer->destroy_flag)
981 && (0 == mctx->peer->reference_cnt) )
982 GST_destroy_peer (mctx->peer);
988 * Frees the ManageServiceContext queue
993 while (NULL != mctx_head)
994 cleanup_mctx (mctx_head);
999 * Returns a string interpretation of 'rs'
1001 * @param rs the request status from ARM
1002 * @return a string interpretation of the request status
1005 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1009 case GNUNET_ARM_REQUEST_SENT_OK:
1010 return _("Message was sent successfully");
1011 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
1012 return _("Misconfiguration (can't connect to the ARM service)");
1013 case GNUNET_ARM_REQUEST_DISCONNECTED:
1014 return _("We disconnected from ARM before we could send a request");
1015 case GNUNET_ARM_REQUEST_BUSY:
1016 return _("ARM API is busy");
1017 case GNUNET_ARM_REQUEST_TOO_LONG:
1018 return _("Request doesn't fit into a message");
1019 case GNUNET_ARM_REQUEST_TIMEOUT:
1020 return _("Request timed out");
1022 return _("Unknown request status");
1027 * Returns a string interpretation of the 'result'
1029 * @param result the arm result
1030 * @return a string interpretation
1033 arm_ret_string (enum GNUNET_ARM_Result result)
1037 case GNUNET_ARM_RESULT_STOPPED:
1038 return _("%s is stopped");
1039 case GNUNET_ARM_RESULT_STARTING:
1040 return _("%s is starting");
1041 case GNUNET_ARM_RESULT_STOPPING:
1042 return _("%s is stopping");
1043 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1044 return _("%s is starting already");
1045 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1046 return _("%s is stopping already");
1047 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1048 return _("%s is started already");
1049 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1050 return _("%s is stopped already");
1051 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1052 return _("%s service is not known to ARM");
1053 case GNUNET_ARM_RESULT_START_FAILED:
1054 return _("%s service failed to start");
1055 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1056 return _("%s service can't be started because ARM is shutting down");
1058 return _("%.s Unknown result code.");
1063 * Function called in response to a start/stop request.
1064 * Will be called when request was not sent successfully,
1065 * or when a reply comes. If the request was not sent successfully,
1066 * 'rs' will indicate that, and 'service' and 'result' will be undefined.
1068 * @param cls ManageServiceContext
1069 * @param rs status of the request
1070 * @param service service name
1071 * @param result result of the operation
1074 service_manage_result_cb (void *cls,
1075 enum GNUNET_ARM_RequestStatus rs,
1076 const char *service, enum GNUNET_ARM_Result result)
1078 struct ManageServiceContext *mctx = cls;
1082 if (GNUNET_YES == mctx->expired)
1084 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1086 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
1087 mctx->peer->id, arm_req_string (rs));
1090 if (1 == mctx->start)
1091 goto service_start_check;
1092 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1093 || (GNUNET_ARM_RESULT_STOPPING == result)
1094 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1095 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
1097 /* stopping a service failed */
1098 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1101 /* service stopped successfully */
1104 service_start_check:
1105 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1106 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1107 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
1109 /* starting a service failed */
1110 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
1113 /* service started successfully */
1118 LOG_DEBUG ("%s\n", emsg);
1119 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
1122 GST_send_operation_success_msg (mctx->client, mctx->op_id);
1123 GNUNET_free_non_null (emsg);
1124 cleanup_mctx (mctx);
1129 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
1132 * @param client identification of client
1133 * @param message the actual message
1136 GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
1137 const struct GNUNET_MessageHeader *message)
1139 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
1140 const char* service;
1143 struct GNUNET_ARM_Handle *ah;
1144 struct ManageServiceContext *mctx;
1145 struct ForwardedOperationContext *fopc;
1151 msize = ntohs (message->size);
1152 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
1154 GNUNET_break_op (0);
1155 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1158 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
1159 service = (const char *) &msg[1];
1160 if ('\0' != service[msize - sizeof
1161 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1163 GNUNET_break_op (0);
1164 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1169 GNUNET_break_op (0);
1170 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1173 peer_id = ntohl (msg->peer_id);
1174 op_id = GNUNET_ntohll (msg->operation_id);
1175 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1176 service, (unsigned int) peer_id);
1177 if ((GST_peer_list_size <= peer_id)
1178 || (NULL == (peer = GST_peer_list[peer_id])))
1180 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1181 "with id: %u", peer_id);
1184 if (0 == strcasecmp ("arm", service))
1186 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1187 "Use peer start/stop for that");
1190 if (GNUNET_YES == peer->is_remote)
1192 /* Forward the destory message to sub controller */
1193 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1194 GNUNET_SERVER_client_keep (client);
1195 fopc->client = client;
1197 fopc->type = OP_MANAGE_SERVICE;
1198 fopc->operation_id = op_id;
1200 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1202 fopc->operation_id, &msg->header,
1203 &GST_forwarded_operation_reply_relay,
1205 fopc->timeout_task =
1206 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1208 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1209 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1212 if (GNUNET_NO == peer->details.local.is_running)
1214 emsg = GNUNET_strdup ("Peer not running\n");
1217 if ((0 != peer->reference_cnt)
1218 && ( (0 == strcasecmp ("core", service))
1219 || (0 == strcasecmp ("transport", service)) ) )
1221 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1222 "since it is required by existing operations",
1226 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1229 GNUNET_asprintf (&emsg,
1230 "Cannot connect to ARM service of peer with id: %u",
1234 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
1236 peer->reference_cnt++;
1237 mctx->op_id = op_id;
1239 GNUNET_SERVER_client_keep (client);
1240 mctx->client = client;
1241 mctx->start = msg->start;
1242 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
1243 if (1 == mctx->start)
1244 GNUNET_ARM_request_service_start (mctx->ah, service,
1245 GNUNET_OS_INHERIT_STD_ERR,
1247 service_manage_result_cb,
1250 GNUNET_ARM_request_service_stop (mctx->ah, service,
1252 service_manage_result_cb,
1254 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1258 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1259 GST_send_operation_fail_msg (client, op_id, emsg);
1261 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1266 * Stops and destroys all peers
1269 GST_destroy_peers ()
1274 if (NULL == GST_peer_list)
1276 for (id = 0; id < GST_peer_list_size; id++)
1278 peer = GST_peer_list[id];
1281 /* If destroy flag is set it means that this peer should have been
1282 * destroyed by a context which we destroy before */
1283 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1284 /* counter should be zero as we free all contexts before */
1285 GNUNET_break (0 == peer->reference_cnt);
1286 if ((GNUNET_NO == peer->is_remote) &&
1287 (GNUNET_YES == peer->details.local.is_running))
1288 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1290 for (id = 0; id < GST_peer_list_size; id++)
1292 peer = GST_peer_list[id];
1295 if (GNUNET_NO == peer->is_remote)
1297 if (GNUNET_YES == peer->details.local.is_running)
1298 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1299 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1300 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1304 GNUNET_free_non_null (GST_peer_list);
1305 GST_peer_list = NULL;
1306 GST_peer_list_size = 0;
1311 * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
1313 * @param cls the ForwardedOperationContext
1314 * @param tc the scheduler task context
1317 shutdown_peers_timeout_cb (void *cls,
1318 const struct GNUNET_SCHEDULER_TaskContext *tc)
1320 struct ForwardedOperationContext *fo_ctxt = cls;
1321 struct HandlerContext_ShutdownPeers *hc;
1323 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1325 hc->timeout = GNUNET_YES;
1326 GNUNET_assert (0 < hc->nslaves);
1328 if (0 == hc->nslaves)
1330 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1331 "Timeout at a slave controller");
1335 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1336 GNUNET_SERVER_client_drop (fo_ctxt->client);
1337 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1338 GNUNET_free (fo_ctxt);
1343 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1344 * success reply is received from all clients and then sends the success message
1347 * @param cls ForwardedOperationContext
1348 * @param msg the message to relay
1351 shutdown_peers_reply_cb (void *cls,
1352 const struct GNUNET_MessageHeader *msg)
1354 struct ForwardedOperationContext *fo_ctxt = cls;
1355 struct HandlerContext_ShutdownPeers *hc;
1358 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
1359 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1360 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1361 GNUNET_assert (0 < hc->nslaves);
1363 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1365 hc->timeout = GNUNET_YES;
1366 if (0 == hc->nslaves)
1368 if (GNUNET_YES == hc->timeout)
1369 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1370 "Timeout at a slave controller");
1372 GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
1376 GNUNET_SERVER_client_drop (fo_ctxt->client);
1377 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1378 GNUNET_free (fo_ctxt);
1383 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1386 * @param client identification of the client
1387 * @param message the actual message
1390 GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
1391 const struct GNUNET_MessageHeader *message)
1393 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1394 struct HandlerContext_ShutdownPeers *hc;
1395 struct Slave *slave;
1396 struct ForwardedOperationContext *fo_ctxt;
1400 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1401 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1402 /* Stop and destroy all peers */
1407 /* Forward to all slaves which we have started */
1408 op_id = GNUNET_ntohll (msg->operation_id);
1409 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
1410 /* FIXME: have a better implementation where we track which slaves are
1411 started by this controller */
1412 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1414 slave = GST_slave_list[cnt];
1417 if (NULL == slave->controller_proc) /* We didn't start the slave */
1419 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1421 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1422 GNUNET_SERVER_client_keep (client);
1423 fo_ctxt->client = client;
1424 fo_ctxt->operation_id = op_id;
1426 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1428 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1429 fo_ctxt->operation_id,
1431 shutdown_peers_reply_cb,
1433 fo_ctxt->timeout_task =
1434 GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
1436 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1438 LOG_DEBUG ("Shutting down peers\n");
1439 GST_destroy_peers ();
1440 if (0 == hc->nslaves)
1442 GST_send_operation_success_msg (client, op_id);
1445 GNUNET_SERVER_receive_done (client, GNUNET_OK);