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 * DLL head for queue of manage service requests
90 static struct ManageServiceContext *mctx_head;
93 * DLL tail for queue of manage service requests
95 static struct ManageServiceContext *mctx_tail;
99 * Adds a peer to the peer array
101 * @param peer the peer to add
104 peer_list_add (struct Peer *peer)
106 if (peer->id >= GST_peer_list_size)
107 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
108 GNUNET_assert (NULL == GST_peer_list[peer->id]);
109 GST_peer_list[peer->id] = peer;
114 * Removes a the give peer from the peer array
116 * @param peer the peer to be removed
119 peer_list_remove (struct Peer *peer)
121 unsigned int orig_size;
124 GST_peer_list[peer->id] = NULL;
125 orig_size = GST_peer_list_size;
126 while (GST_peer_list_size >= LIST_GROW_STEP)
128 for (id = GST_peer_list_size - 1;
129 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
131 if (NULL != GST_peer_list[id])
133 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
135 GST_peer_list_size -= LIST_GROW_STEP;
137 if (orig_size == GST_peer_list_size)
140 GNUNET_realloc (GST_peer_list,
141 sizeof (struct Peer *) * GST_peer_list_size);
146 * The task to be executed if the forwarded peer create operation has been
149 * @param cls the FowardedOperationContext
150 * @param tc the TaskContext from the scheduler
153 peer_create_forward_timeout (void *cls,
154 const struct GNUNET_SCHEDULER_TaskContext *tc)
156 struct ForwardedOperationContext *fopc = cls;
158 GNUNET_free (fopc->cls);
159 GST_forwarded_operation_timeout (fopc, tc);
164 * Callback to be called when forwarded peer create operation is successfull. We
165 * have to relay the reply msg back to the client
167 * @param cls ForwardedOperationContext
168 * @param msg the peer create success message
171 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
173 struct ForwardedOperationContext *fopc = cls;
174 struct Peer *remote_peer;
176 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
178 GNUNET_assert (NULL != fopc->cls);
179 remote_peer = fopc->cls;
180 peer_list_add (remote_peer);
182 GST_forwarded_operation_reply_relay (fopc, msg);
187 * Function to destroy a peer
189 * @param peer the peer structure to destroy
192 GST_destroy_peer (struct Peer *peer)
194 GNUNET_break (0 == peer->reference_cnt);
195 if (GNUNET_YES == peer->is_remote)
197 peer_list_remove (peer);
201 if (GNUNET_YES == peer->details.local.is_running)
203 GNUNET_TESTING_peer_stop (peer->details.local.peer);
204 peer->details.local.is_running = GNUNET_NO;
206 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
207 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
208 peer_list_remove (peer);
214 * Callback to be called when forwarded peer destroy operation is successfull. We
215 * have to relay the reply msg back to the client
217 * @param cls ForwardedOperationContext
218 * @param msg the peer create success message
221 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
223 struct ForwardedOperationContext *fopc = cls;
224 struct Peer *remote_peer;
226 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
229 remote_peer = fopc->cls;
230 GNUNET_assert (NULL != remote_peer);
231 remote_peer->destroy_flag = GNUNET_YES;
232 if (0 == remote_peer->reference_cnt)
233 GST_destroy_peer (remote_peer);
235 GST_forwarded_operation_reply_relay (fopc, msg);
240 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
243 * @param client identification of the client
244 * @param message the actual message
247 GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
248 const struct GNUNET_MessageHeader *message)
250 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
251 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
252 struct GNUNET_CONFIGURATION_Handle *cfg;
253 struct ForwardedOperationContext *fo_ctxt;
259 uint32_t config_size;
265 msize = ntohs (message->size);
266 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
268 GNUNET_break (0); /* We need configuration */
269 GNUNET_SERVER_receive_done (client, GNUNET_OK);
272 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
273 host_id = ntohl (msg->host_id);
274 peer_id = ntohl (msg->peer_id);
275 if (UINT32_MAX == peer_id)
277 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
278 "Cannot create peer with given ID");
279 GNUNET_SERVER_receive_done (client, GNUNET_OK);
282 if (host_id == GST_context->host_id)
286 /* We are responsible for this peer */
287 msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
288 config_size = ntohl (msg->config_size);
289 config = GNUNET_malloc (config_size);
290 dest_size = config_size;
293 uncompress ((Bytef *) config, (uLongf *) & dest_size,
294 (const Bytef *) &msg[1], (uLong) msize)))
296 GNUNET_break (0); /* uncompression error */
297 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
300 if (config_size != dest_size)
302 GNUNET_break (0); /* Uncompressed config size mismatch */
303 GNUNET_free (config);
304 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
307 cfg = GNUNET_CONFIGURATION_create ();
309 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
311 GNUNET_break (0); /* Configuration parsing error */
312 GNUNET_free (config);
313 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
316 GNUNET_free (config);
317 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
318 (unsigned long long) peer_id);
319 peer = GNUNET_malloc (sizeof (struct Peer));
320 peer->is_remote = GNUNET_NO;
321 peer->details.local.cfg = cfg;
323 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
324 peer->details.local.peer =
325 GNUNET_TESTING_peer_configure (GST_context->system,
326 peer->details.local.cfg, peer->id,
329 if (NULL == peer->details.local.peer)
331 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
335 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
338 peer->details.local.is_running = GNUNET_NO;
339 peer_list_add (peer);
341 GNUNET_malloc (sizeof
342 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
344 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
346 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
347 reply->peer_id = msg->peer_id;
348 reply->operation_id = msg->operation_id;
349 GST_queue_message (client, &reply->header);
350 GNUNET_SERVER_receive_done (client, GNUNET_OK);
354 /* Forward peer create request */
355 route = GST_find_dest_route (host_id);
359 GNUNET_SERVER_receive_done (client, GNUNET_OK);
363 peer = GNUNET_malloc (sizeof (struct Peer));
364 peer->is_remote = GNUNET_YES;
366 peer->details.remote.slave = GST_slave_list[route->dest];
367 peer->details.remote.remote_host_id = host_id;
368 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
369 GNUNET_SERVER_client_keep (client);
370 fo_ctxt->client = client;
371 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
372 fo_ctxt->cls = peer; //GST_slave_list[route->dest]->controller;
373 fo_ctxt->type = OP_PEER_CREATE;
375 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
376 [route->dest]->controller,
377 fo_ctxt->operation_id,
379 peer_create_success_cb, fo_ctxt);
380 fo_ctxt->timeout_task =
381 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
383 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
384 GNUNET_SERVER_receive_done (client, GNUNET_OK);
389 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
392 * @param client identification of the client
393 * @param message the actual message
396 GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
397 const struct GNUNET_MessageHeader *message)
399 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
400 struct ForwardedOperationContext *fopc;
404 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
405 peer_id = ntohl (msg->peer_id);
406 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
407 peer_id, GNUNET_ntohll (msg->operation_id));
408 if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
410 LOG (GNUNET_ERROR_TYPE_ERROR,
411 "Asked to destroy a non existent peer with id: %u\n", peer_id);
412 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
413 "Peer doesn't exist");
414 GNUNET_SERVER_receive_done (client, GNUNET_OK);
417 peer = GST_peer_list[peer_id];
418 if (GNUNET_YES == peer->is_remote)
420 /* Forward the destory message to sub controller */
421 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
422 GNUNET_SERVER_client_keep (client);
423 fopc->client = client;
425 fopc->type = OP_PEER_DESTROY;
426 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
428 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
430 fopc->operation_id, &msg->header,
431 &peer_destroy_success_cb, fopc);
433 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
435 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
436 GNUNET_SERVER_receive_done (client, GNUNET_OK);
439 peer->destroy_flag = GNUNET_YES;
440 if (0 == peer->reference_cnt)
441 GST_destroy_peer (peer);
443 LOG (GNUNET_ERROR_TYPE_DEBUG,
444 "Delaying peer destroy as peer is currently in use\n");
445 GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
446 GNUNET_SERVER_receive_done (client, GNUNET_OK);
451 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
454 * @param client identification of the client
455 * @param message the actual message
458 GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
459 const struct GNUNET_MessageHeader *message)
461 const struct GNUNET_TESTBED_PeerStartMessage *msg;
462 struct GNUNET_TESTBED_PeerEventMessage *reply;
463 struct ForwardedOperationContext *fopc;
467 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
468 peer_id = ntohl (msg->peer_id);
469 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
472 LOG (GNUNET_ERROR_TYPE_ERROR,
473 "Asked to start a non existent peer with id: %u\n", peer_id);
474 GNUNET_SERVER_receive_done (client, GNUNET_OK);
477 peer = GST_peer_list[peer_id];
478 if (GNUNET_YES == peer->is_remote)
480 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
481 GNUNET_SERVER_client_keep (client);
482 fopc->client = client;
483 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
484 fopc->type = OP_PEER_START;
486 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
488 fopc->operation_id, &msg->header,
489 &GST_forwarded_operation_reply_relay,
492 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
494 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
495 GNUNET_SERVER_receive_done (client, GNUNET_OK);
498 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
500 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
502 GNUNET_SERVER_receive_done (client, GNUNET_OK);
505 peer->details.local.is_running = GNUNET_YES;
506 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
507 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
508 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
509 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
510 reply->host_id = htonl (GST_context->host_id);
511 reply->peer_id = msg->peer_id;
512 reply->operation_id = msg->operation_id;
513 GST_queue_message (client, &reply->header);
514 GNUNET_SERVER_receive_done (client, GNUNET_OK);
519 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
522 * @param client identification of the client
523 * @param message the actual message
526 GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
527 const struct GNUNET_MessageHeader *message)
529 const struct GNUNET_TESTBED_PeerStopMessage *msg;
530 struct GNUNET_TESTBED_PeerEventMessage *reply;
531 struct ForwardedOperationContext *fopc;
535 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
536 peer_id = ntohl (msg->peer_id);
537 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
538 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
540 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
542 GNUNET_SERVER_receive_done (client, GNUNET_OK);
545 peer = GST_peer_list[peer_id];
546 if (GNUNET_YES == peer->is_remote)
548 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
550 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
551 GNUNET_SERVER_client_keep (client);
552 fopc->client = client;
553 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
554 fopc->type = OP_PEER_STOP;
556 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
558 fopc->operation_id, &msg->header,
559 &GST_forwarded_operation_reply_relay,
562 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
564 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
565 GNUNET_SERVER_receive_done (client, GNUNET_OK);
568 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
570 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
571 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
576 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
577 peer->details.local.is_running = GNUNET_NO;
578 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
579 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
580 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
581 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
582 reply->host_id = htonl (GST_context->host_id);
583 reply->peer_id = msg->peer_id;
584 reply->operation_id = msg->operation_id;
585 GST_queue_message (client, &reply->header);
586 GNUNET_SERVER_receive_done (client, GNUNET_OK);
587 GNUNET_TESTING_peer_wait (peer->details.local.peer);
592 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
595 * @param client identification of the client
596 * @param message the actual message
599 GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
600 const struct GNUNET_MessageHeader *message)
602 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
603 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
612 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
613 peer_id = ntohl (msg->peer_id);
614 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
616 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
618 GNUNET_SERVER_receive_done (client, GNUNET_OK);
621 peer = GST_peer_list[peer_id];
622 if (GNUNET_YES == peer->is_remote)
624 struct ForwardedOperationContext *fopc;
626 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
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_INFO;
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 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
647 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
649 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
650 GNUNET_free (config);
653 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
654 reply = GNUNET_realloc (xconfig, msize);
655 (void) memmove (&reply[1], reply, xc_size);
656 reply->header.size = htons (msize);
657 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
658 reply->peer_id = msg->peer_id;
659 reply->operation_id = msg->operation_id;
660 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
661 &reply->peer_identity);
662 reply->config_size = htons ((uint16_t) c_size);
663 GST_queue_message (client, &reply->header);
664 GNUNET_SERVER_receive_done (client, GNUNET_OK);
669 * Cleanup the context information created for managing a peer's service
671 * @param mctx the ManageServiceContext
674 cleanup_mctx (struct ManageServiceContext *mctx)
676 mctx->expired = GNUNET_YES;
677 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
678 GNUNET_SERVER_client_drop (mctx->client);
679 GNUNET_ARM_disconnect_and_free (mctx->ah);
680 GNUNET_assert (0 < mctx->peer->reference_cnt);
681 mctx->peer->reference_cnt--;
682 if ( (GNUNET_YES == mctx->peer->destroy_flag)
683 && (0 == mctx->peer->reference_cnt) )
684 GST_destroy_peer (mctx->peer);
690 * Frees the ManageServiceContext queue
695 while (NULL != mctx_head)
696 cleanup_mctx (mctx_head);
701 * Returns a string interpretation of 'rs'
703 * @param rs the request status from ARM
704 * @return a string interpretation of the request status
707 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
711 case GNUNET_ARM_REQUEST_SENT_OK:
712 return _("Message was sent successfully");
713 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
714 return _("Misconfiguration (can't connect to the ARM service)");
715 case GNUNET_ARM_REQUEST_DISCONNECTED:
716 return _("We disconnected from ARM before we could send a request");
717 case GNUNET_ARM_REQUEST_BUSY:
718 return _("ARM API is busy");
719 case GNUNET_ARM_REQUEST_TOO_LONG:
720 return _("Request doesn't fit into a message");
721 case GNUNET_ARM_REQUEST_TIMEOUT:
722 return _("Request timed out");
724 return _("Unknown request status");
729 * Returns a string interpretation of the 'result'
731 * @param result the arm result
732 * @return a string interpretation
735 arm_ret_string (enum GNUNET_ARM_Result result)
739 case GNUNET_ARM_RESULT_STOPPED:
740 return _("%s is stopped");
741 case GNUNET_ARM_RESULT_STARTING:
742 return _("%s is starting");
743 case GNUNET_ARM_RESULT_STOPPING:
744 return _("%s is stopping");
745 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
746 return _("%s is starting already");
747 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
748 return _("%s is stopping already");
749 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
750 return _("%s is started already");
751 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
752 return _("%s is stopped already");
753 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
754 return _("%s service is not known to ARM");
755 case GNUNET_ARM_RESULT_START_FAILED:
756 return _("%s service failed to start");
757 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
758 return _("%s service can't be started because ARM is shutting down");
760 return _("%.s Unknown result code.");
765 * Function called in response to a start/stop request.
766 * Will be called when request was not sent successfully,
767 * or when a reply comes. If the request was not sent successfully,
768 * 'rs' will indicate that, and 'service' and 'result' will be undefined.
770 * @param cls ManageServiceContext
771 * @param arm handle to the arm connection
772 * @param rs status of the request
773 * @param service service name
774 * @param result result of the operation
777 service_manage_result_cb (void *cls,
778 enum GNUNET_ARM_RequestStatus rs,
779 const char *service, enum GNUNET_ARM_Result result)
781 struct ManageServiceContext *mctx = cls;
785 if (GNUNET_YES == mctx->expired)
787 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
789 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
790 mctx->peer->id, arm_req_string (rs));
793 if (1 == mctx->start)
794 goto service_start_check;
795 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
796 || (GNUNET_ARM_RESULT_STOPPING == result)
797 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
798 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
800 /* stopping a service failed */
801 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
804 /* service stopped successfully */
808 if (! ((GNUNET_ARM_RESULT_STARTING == result)
809 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
810 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
812 /* starting a service failed */
813 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
816 /* service started successfully */
821 LOG_DEBUG ("%s\n", emsg);
822 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
825 GST_send_operation_success_msg (mctx->client, mctx->op_id);
826 GNUNET_free_non_null (emsg);
832 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
835 * @param client identification of client
836 * @param message the actual message
839 GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
840 const struct GNUNET_MessageHeader *message)
842 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
846 struct GNUNET_ARM_Handle *ah;
847 struct ManageServiceContext *mctx;
848 struct ForwardedOperationContext *fopc;
854 msize = ntohs (message->size);
855 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
858 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
861 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
862 service = (const char *) &msg[1];
863 if ('\0' != service[msize - sizeof
864 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
867 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
873 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
876 peer_id = ntohl (msg->peer_id);
877 op_id = GNUNET_ntohll (msg->operation_id);
878 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
879 service, (unsigned int) peer_id);
880 if ((GST_peer_list_size <= peer_id)
881 || (NULL == (peer = GST_peer_list[peer_id])))
883 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
884 "with id: %u", peer_id);
887 if (0 == strcasecmp ("arm", service))
889 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
890 "Use peer start/stop for that");
893 if (GNUNET_YES == peer->is_remote)
895 /* Forward the destory message to sub controller */
896 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
897 GNUNET_SERVER_client_keep (client);
898 fopc->client = client;
900 fopc->type = OP_MANAGE_SERVICE;
901 fopc->operation_id = op_id;
903 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
905 fopc->operation_id, &msg->header,
906 &GST_forwarded_operation_reply_relay,
909 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
911 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
912 GNUNET_SERVER_receive_done (client, GNUNET_OK);
915 if ((0 != peer->reference_cnt)
916 && ( (0 == strcasecmp ("core", service))
917 || (0 == strcasecmp ("transport", service)) ) )
919 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
920 "since it is required by existing operations",
924 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
927 GNUNET_asprintf (&emsg,
928 "Cannot connect to ARM service of peer with id: %u",
932 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
934 peer->reference_cnt++;
937 GNUNET_SERVER_client_keep (client);
938 mctx->client = client;
939 mctx->start = msg->start;
940 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
941 if (1 == mctx->start)
942 GNUNET_ARM_request_service_start (mctx->ah, service,
943 GNUNET_OS_INHERIT_STD_ERR,
945 service_manage_result_cb,
948 GNUNET_ARM_request_service_stop (mctx->ah, service,
950 service_manage_result_cb,
952 GNUNET_SERVER_receive_done (client, GNUNET_OK);
956 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
957 GST_send_operation_fail_msg (client, op_id, emsg);
959 GNUNET_SERVER_receive_done (client, GNUNET_OK);
964 * Stops and destroys all peers
972 if (NULL == GST_peer_list)
974 for (id = 0; id < GST_peer_list_size; id++)
976 peer = GST_peer_list[id];
979 /* If destroy flag is set it means that this peer should have been
980 * destroyed by a context which we destroy before */
981 GNUNET_break (GNUNET_NO == peer->destroy_flag);
982 /* counter should be zero as we free all contexts before */
983 GNUNET_break (0 == peer->reference_cnt);
984 if ((GNUNET_NO == peer->is_remote) &&
985 (GNUNET_YES == peer->details.local.is_running))
986 GNUNET_TESTING_peer_kill (peer->details.local.peer);
988 for (id = 0; id < GST_peer_list_size; id++)
990 peer = GST_peer_list[id];
993 if (GNUNET_NO == peer->is_remote)
995 if (GNUNET_YES == peer->details.local.is_running)
996 GNUNET_TESTING_peer_wait (peer->details.local.peer);
997 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
998 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1002 GNUNET_free_non_null (GST_peer_list);
1003 GST_peer_list = NULL;
1004 GST_peer_list_size = 0;
1009 * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
1011 * @param cls the ForwardedOperationContext
1012 * @param tc the scheduler task context
1015 shutdown_peers_timeout_cb (void *cls,
1016 const struct GNUNET_SCHEDULER_TaskContext *tc)
1018 struct ForwardedOperationContext *fo_ctxt = cls;
1019 struct HandlerContext_ShutdownPeers *hc;
1021 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1023 hc->timeout = GNUNET_YES;
1024 GNUNET_assert (0 < hc->nslaves);
1026 if (0 == hc->nslaves)
1027 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1028 "Timeout at a slave controller");
1029 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1030 GNUNET_SERVER_client_drop (fo_ctxt->client);
1031 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1032 GNUNET_free (fo_ctxt);
1037 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1038 * success reply is received from all clients and then sends the success message
1041 * @param cls ForwardedOperationContext
1042 * @param msg the message to relay
1045 shutdown_peers_reply_cb (void *cls,
1046 const struct GNUNET_MessageHeader *msg)
1048 struct ForwardedOperationContext *fo_ctxt = cls;
1049 struct HandlerContext_ShutdownPeers *hc;
1052 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
1053 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1054 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1055 GNUNET_assert (0 < hc->nslaves);
1057 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1059 hc->timeout = GNUNET_YES;
1060 if (0 == hc->nslaves)
1062 if (GNUNET_YES == hc->timeout)
1063 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
1064 "Timeout at a slave controller");
1066 GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
1068 GNUNET_SERVER_client_drop (fo_ctxt->client);
1069 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
1070 GNUNET_free (fo_ctxt);
1075 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1078 * @param client identification of the client
1079 * @param message the actual message
1082 GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
1083 const struct GNUNET_MessageHeader *message)
1085 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
1086 struct HandlerContext_ShutdownPeers *hc;
1087 struct Slave *slave;
1088 struct ForwardedOperationContext *fo_ctxt;
1092 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
1093 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1094 /* Stop and destroy all peers */
1099 /* Forward to all slaves which we have started */
1100 op_id = GNUNET_ntohll (msg->operation_id);
1101 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
1102 /* FIXME: have a better implementation where we track which slaves are
1103 started by this controller */
1104 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1106 slave = GST_slave_list[cnt];
1109 if (NULL == slave->controller_proc) /* We didn't start the slave */
1111 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1113 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1114 GNUNET_SERVER_client_keep (client);
1115 fo_ctxt->client = client;
1116 fo_ctxt->operation_id = op_id;
1118 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1120 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1121 fo_ctxt->operation_id,
1123 shutdown_peers_reply_cb,
1125 fo_ctxt->timeout_task =
1126 GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
1128 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1130 LOG_DEBUG ("Shutting down peers\n");
1131 GST_destroy_peers ();
1132 if (0 == hc->nslaves)
1134 GST_send_operation_success_msg (client, op_id);
1137 GNUNET_SERVER_receive_done (client, GNUNET_OK);