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.
22 * @file testbed/gnunet-service-testbed.c
23 * @brief implementation of the TESTBED service
24 * @author Sree Harsha Totakura
27 #include "gnunet-service-testbed.h"
28 #include "gnunet_arm_service.h"
34 * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
36 struct HandlerContext_ShutdownPeers
39 * The number of slave we expect to hear from since we forwarded the
40 * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
45 * Did we observe a timeout with respect to this operation at any of the
59 struct GNUNET_CONFIGURATION_Handle *our_config;
62 * The master context; generated with the first INIT message
64 struct Context *GST_context;
67 * A list of directly linked neighbours
69 struct Slave **GST_slave_list;
72 * A list of peers we know about
74 struct Peer **GST_peer_list;
79 struct GNUNET_TESTBED_Host **GST_host_list;
82 * DLL head for forwarded operation contexts
84 struct ForwardedOperationContext *fopcq_head;
87 * DLL tail for forwarded operation contexts
89 struct ForwardedOperationContext *fopcq_tail;
92 * Operation queue for open file descriptors
94 struct OperationQueue *GST_opq_openfds;
97 * Timeout for operations which may take some time
99 const struct GNUNET_TIME_Relative GST_timeout;
102 * The size of the host list
104 unsigned int GST_host_list_size;
107 * The size of directly linked neighbours list
109 unsigned int GST_slave_list_size;
112 * The size of the peer list
114 unsigned int GST_peer_list_size;
117 /***********************************/
118 /* Local definitions and variables */
119 /***********************************/
122 * The message queue for sending messages to clients
127 * The message to be sent
129 struct GNUNET_MessageHeader *msg;
132 * The client to send the message to
134 struct GNUNET_SERVER_Client *client;
137 * next pointer for DLL
139 struct MessageQueue *next;
142 * prev pointer for DLL
144 struct MessageQueue *prev;
148 * Our hostname; we give this to all the peers we start
150 static char *hostname;
153 * Current Transmit Handle; NULL if no notify transmit exists currently
155 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
158 * The head for the LCF queue
160 static struct LCFContextQueue *lcfq_head;
163 * The tail for the LCF queue
165 static struct LCFContextQueue *lcfq_tail;
168 * The message queue head
170 static struct MessageQueue *mq_head;
173 * The message queue tail
175 static struct MessageQueue *mq_tail;
178 * The hashmap of shared services
180 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
185 static struct Route **route_list;
188 * The event mask for the events we listen from sub-controllers
190 static uint64_t event_mask;
193 * The size of the route list
195 static unsigned int route_list_size;
198 * The lcf_task handle
200 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
203 * The shutdown task handle
205 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
209 * Function called to notify a client about the connection begin ready to queue
210 * more data. "buf" will be NULL and "size" zero if the connection was closed
211 * for writing in the meantime.
214 * @param size number of bytes available in buf
215 * @param buf where the callee should write the message
216 * @return number of bytes written to buf
219 transmit_ready_notify (void *cls, size_t size, void *buf)
221 struct MessageQueue *mq_entry;
223 transmit_handle = NULL;
225 GNUNET_assert (NULL != mq_entry);
228 GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
229 size = ntohs (mq_entry->msg->size);
230 memcpy (buf, mq_entry->msg, size);
231 GNUNET_free (mq_entry->msg);
232 GNUNET_SERVER_client_drop (mq_entry->client);
233 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
234 GNUNET_free (mq_entry);
236 if (NULL != mq_entry)
238 GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
239 ntohs (mq_entry->msg->size),
240 GNUNET_TIME_UNIT_FOREVER_REL,
241 &transmit_ready_notify, NULL);
247 * Queues a message in send queue for sending to the service
249 * @param client the client to whom the queued message has to be sent
250 * @param msg the message to queue
253 GST_queue_message (struct GNUNET_SERVER_Client *client,
254 struct GNUNET_MessageHeader *msg)
256 struct MessageQueue *mq_entry;
260 type = ntohs (msg->type);
261 size = ntohs (msg->size);
262 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
263 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
264 mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
266 mq_entry->client = client;
267 GNUNET_SERVER_client_keep (client);
268 LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
270 GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
271 if (NULL == transmit_handle)
273 GNUNET_SERVER_notify_transmit_ready (client, size,
274 GNUNET_TIME_UNIT_FOREVER_REL,
275 &transmit_ready_notify, NULL);
280 * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
281 * several times we call it only once. The array is also made to grow in steps
284 * @param ptr the array pointer to grow
285 * @param size the size of array
286 * @param accommodate_size the size which the array has to accommdate; after
287 * this call the array will be big enough to accommdate sizes upto
290 #define array_grow_large_enough(ptr, size, accommodate_size) \
293 unsigned int growth_size; \
294 GNUNET_assert (size <= accommodate_size); \
295 growth_size = size; \
296 while (growth_size <= accommodate_size) \
297 growth_size += LIST_GROW_STEP; \
298 GNUNET_array_grow (ptr, size, growth_size); \
299 GNUNET_assert (size > accommodate_size); \
304 * Function to add a host to the current list of known hosts
306 * @param host the host to add
307 * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
311 host_list_add (struct GNUNET_TESTBED_Host *host)
315 host_id = GNUNET_TESTBED_host_get_id_ (host);
316 if (GST_host_list_size <= host_id)
317 array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
318 if (NULL != GST_host_list[host_id])
320 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
321 return GNUNET_SYSERR;
323 GST_host_list[host_id] = host;
329 * Adds a route to the route list
331 * @param route the route to add
334 route_list_add (struct Route *route)
336 if (route->dest >= route_list_size)
337 array_grow_large_enough (route_list, route_list_size, route->dest);
338 GNUNET_assert (NULL == route_list[route->dest]);
339 route_list[route->dest] = route;
344 * Adds a slave to the slave array
346 * @param slave the slave controller to add
349 slave_list_add (struct Slave *slave)
351 if (slave->host_id >= GST_slave_list_size)
352 array_grow_large_enough (GST_slave_list, GST_slave_list_size,
354 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
355 GST_slave_list[slave->host_id] = slave;
360 * Adds a peer to the peer array
362 * @param peer the peer to add
365 peer_list_add (struct Peer *peer)
367 if (peer->id >= GST_peer_list_size)
368 array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
369 GNUNET_assert (NULL == GST_peer_list[peer->id]);
370 GST_peer_list[peer->id] = peer;
375 * Removes a the give peer from the peer array
377 * @param peer the peer to be removed
380 peer_list_remove (struct Peer *peer)
382 unsigned int orig_size;
385 GST_peer_list[peer->id] = NULL;
386 orig_size = GST_peer_list_size;
387 while (GST_peer_list_size >= LIST_GROW_STEP)
389 for (id = GST_peer_list_size - 1;
390 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
392 if (NULL != GST_peer_list[id])
394 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
396 GST_peer_list_size -= LIST_GROW_STEP;
398 if (orig_size == GST_peer_list_size)
401 GNUNET_realloc (GST_peer_list,
402 sizeof (struct Peer *) * GST_peer_list_size);
407 * Finds the route with directly connected host as destination through which
408 * the destination host can be reached
410 * @param host_id the id of the destination host
411 * @return the route with directly connected destination host; NULL if no route
415 GST_find_dest_route (uint32_t host_id)
419 if (route_list_size <= host_id)
421 while (NULL != (route = route_list[host_id]))
423 if (route->thru == GST_context->host_id)
425 host_id = route->thru;
432 * Routes message to a host given its host_id
434 * @param host_id the id of the destination host
435 * @param msg the message to be routed
438 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
445 * Send operation failure message to client
447 * @param client the client to which the failure message has to be sent to
448 * @param operation_id the id of the failed operation
449 * @param emsg the error message; can be NULL
452 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
453 uint64_t operation_id, const char *emsg)
455 struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
459 msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
460 emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
462 msg = GNUNET_malloc (msize);
463 msg->header.size = htons (msize);
464 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
465 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
466 msg->operation_id = GNUNET_htonll (operation_id);
468 memcpy (&msg[1], emsg, emsg_len);
469 GST_queue_message (client, &msg->header);
474 * Function to send generic operation success message to given client
476 * @param client the client to send the message to
477 * @param operation_id the id of the operation which was successful
480 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
481 uint64_t operation_id)
483 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
486 msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
487 msg = GNUNET_malloc (msize);
488 msg->header.size = htons (msize);
490 htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
491 msg->operation_id = GNUNET_htonll (operation_id);
492 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
493 GST_queue_message (client, &msg->header);
498 * Function to send a failure reponse for controller link operation
500 * @param client the client to send the message to
501 * @param operation_id the operation ID of the controller link request
502 * @param cfg the configuration with which the delegated controller is started.
503 * Can be NULL if the delegated controller is not started but just
505 * @param emsg set to an error message explaining why the controller link
506 * failed. Setting this to NULL signifies success. !This should be
507 * NULL if cfg is set!
510 send_controller_link_response (struct GNUNET_SERVER_Client *client,
511 uint64_t operation_id,
512 const struct GNUNET_CONFIGURATION_Handle
516 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
522 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
526 msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
529 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
532 msize += xconfig_size;
535 msize += strlen (emsg);
536 msg = GNUNET_malloc (msize);
537 msg->header.type = htons
538 (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
539 msg->header.size = htons (msize);
541 msg->success = htons (GNUNET_YES);
542 msg->operation_id = GNUNET_htonll (operation_id);
543 msg->config_size = htons ((uint16_t) config_size);
545 memcpy (&msg[1], xconfig, xconfig_size);
547 memcpy (&msg[1], emsg, strlen (emsg));
548 GST_queue_message (client, &msg->header);
552 * Callback which will be called after a host registration succeeded or failed
554 * @param cls the handle to the slave at which the registration is completed
555 * @param emsg the error message; NULL if host registration is successful
558 hr_completion (void *cls, const char *emsg);
562 * Attempts to register the next host in the host registration queue
564 * @param slave the slave controller whose host registration queue is checked
565 * for host registrations
568 register_next_host (struct Slave *slave)
570 struct HostRegistration *hr;
572 hr = slave->hr_dll_head;
573 GNUNET_assert (NULL != hr);
574 GNUNET_assert (NULL == slave->rhandle);
575 LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
576 GNUNET_TESTBED_host_get_id_ (hr->host),
577 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
579 GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
585 * Callback which will be called to after a host registration succeeded or failed
587 * @param cls the handle to the slave at which the registration is completed
588 * @param emsg the error message; NULL if host registration is successful
591 hr_completion (void *cls, const char *emsg)
593 struct Slave *slave = cls;
594 struct HostRegistration *hr;
596 slave->rhandle = NULL;
597 hr = slave->hr_dll_head;
598 GNUNET_assert (NULL != hr);
599 LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
600 GNUNET_TESTBED_host_get_id_ (hr->host),
601 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
602 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
604 hr->cb (hr->cb_cls, emsg);
606 if (NULL != slave->hr_dll_head)
607 register_next_host (slave);
612 * Adds a host registration's request to a slave's registration queue
614 * @param slave the slave controller at which the given host has to be
616 * @param cb the host registration completion callback
617 * @param cb_cls the closure for the host registration completion callback
618 * @param host the host which has to be registered
621 GST_queue_host_registration (struct Slave *slave,
622 GNUNET_TESTBED_HostRegistrationCompletion cb,
623 void *cb_cls, struct GNUNET_TESTBED_Host *host)
625 struct HostRegistration *hr;
628 LOG (GNUNET_ERROR_TYPE_DEBUG,
629 "Queueing host registration for host %u at %u\n",
630 GNUNET_TESTBED_host_get_id_ (host),
631 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
632 hr = GNUNET_malloc (sizeof (struct HostRegistration));
636 call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
637 GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
638 if (GNUNET_YES == call_register)
639 register_next_host (slave);
644 * The Link Controller forwarding task
646 * @param cls the LCFContext
647 * @param tc the Task context from scheduler
650 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
654 * Completion callback for host registrations while forwarding Link Controller messages
656 * @param cls the LCFContext
657 * @param emsg the error message; NULL if host registration is successful
660 lcf_proc_cc (void *cls, const char *emsg)
662 struct LCFContext *lcf = cls;
664 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
669 goto registration_error;
670 lcf->state = DELEGATED_HOST_REGISTERED;
671 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
673 case DELEGATED_HOST_REGISTERED:
675 goto registration_error;
676 lcf->state = SLAVE_HOST_REGISTERED;
677 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
680 GNUNET_assert (0); /* Shouldn't reach here */
685 LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
687 lcf->state = FINISHED;
688 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
693 * Callback to relay the reply msg of a forwarded operation back to the client
695 * @param cls ForwardedOperationContext
696 * @param msg the message to relay
699 GST_forwarded_operation_reply_relay (void *cls,
700 const struct GNUNET_MessageHeader *msg)
702 struct ForwardedOperationContext *fopc = cls;
703 struct GNUNET_MessageHeader *dup_msg;
706 msize = ntohs (msg->size);
707 LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
709 dup_msg = GNUNET_copy_message (msg);
710 GST_queue_message (fopc->client, dup_msg);
711 GNUNET_SERVER_client_drop (fopc->client);
712 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
713 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
719 * Task to free resources when forwarded operation has been timedout
721 * @param cls the ForwardedOperationContext
722 * @param tc the task context from scheduler
725 GST_forwarded_operation_timeout (void *cls,
726 const struct GNUNET_SCHEDULER_TaskContext *tc)
728 struct ForwardedOperationContext *fopc = cls;
730 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
731 LOG (GNUNET_ERROR_TYPE_DEBUG, "A forwarded operation has timed out\n");
732 GST_send_operation_fail_msg (fopc->client, fopc->operation_id,
733 "A forwarded operation has timed out");
734 GNUNET_SERVER_client_drop (fopc->client);
735 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
741 * The Link Controller forwarding task
743 * @param cls the LCFContext
744 * @param tc the Task context from scheduler
747 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
751 * Task to free resources when forwarded link controllers has been timedout
753 * @param cls the LCFContext
754 * @param tc the task context from scheduler
757 lcf_forwarded_operation_timeout (void *cls,
758 const struct GNUNET_SCHEDULER_TaskContext *tc)
760 struct LCFContext *lcf = cls;
762 lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
763 // GST_forwarded_operation_timeout (lcf->fopc, tc);
764 LOG (GNUNET_ERROR_TYPE_WARNING,
765 "A forwarded controller link operation has timed out\n");
766 send_controller_link_response (lcf->client, lcf->operation_id, NULL,
767 "A forwarded controller link operation has "
769 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
770 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
775 * The Link Controller forwarding task
777 * @param cls the LCFContext
778 * @param tc the Task context from scheduler
781 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
783 struct LCFContext *lcf = cls;
784 struct LCFContextQueue *lcfq;
786 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
791 GNUNET_TESTBED_is_host_registered_ (GST_host_list
792 [lcf->delegated_host_id],
793 lcf->gateway->controller))
795 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
796 GST_host_list[lcf->delegated_host_id]);
800 lcf->state = DELEGATED_HOST_REGISTERED;
801 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
804 case DELEGATED_HOST_REGISTERED:
806 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
807 lcf->gateway->controller))
809 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
810 GST_host_list[lcf->slave_host_id]);
814 lcf->state = SLAVE_HOST_REGISTERED;
815 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
818 case SLAVE_HOST_REGISTERED:
819 lcf->op = GNUNET_TESTBED_controller_link (lcf,
820 lcf->gateway->controller,
821 GST_host_list[lcf->delegated_host_id],
822 GST_host_list[lcf->slave_host_id],
824 lcf->is_subordinate);
826 GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
828 lcf->state = FINISHED;
832 GNUNET_assert (lcfq->lcf == lcf);
833 GNUNET_assert (NULL != lcf->cfg);
834 GNUNET_CONFIGURATION_destroy (lcf->cfg);
835 GNUNET_SERVER_client_drop (lcf->client);
836 GNUNET_TESTBED_operation_done (lcf->op);
838 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
840 if (NULL != lcfq_head)
842 GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
848 * Callback for event from slave controllers
850 * @param cls struct Slave *
851 * @param event information about the event
854 slave_event_callback (void *cls,
855 const struct GNUNET_TESTBED_EventInformation *event)
857 struct RegisteredHostContext *rhc;
858 struct LCFContext *lcf;
859 struct GNUNET_CONFIGURATION_Handle *cfg;
860 struct GNUNET_TESTBED_Operation *old_op;
862 /* We currently only get here when working on RegisteredHostContexts and
864 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
866 if (CLOSURE_TYPE_RHC == rhc->type)
868 GNUNET_assert (rhc->sub_op == event->op);
872 cfg = event->details.operation_finished.generic;
873 old_op = rhc->sub_op;
874 rhc->state = RHC_LINK;
876 GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
877 rhc->reg_host, rhc->host, cfg,
879 GNUNET_TESTBED_operation_done (old_op);
882 LOG_DEBUG ("OL: Linking controllers successfull\n");
883 GNUNET_TESTBED_operation_done (rhc->sub_op);
885 rhc->state = RHC_OL_CONNECT;
886 GST_process_next_focc (rhc);
894 if (CLOSURE_TYPE_LCF == lcf->type)
896 GNUNET_assert (lcf->op == event->op);
897 GNUNET_assert (FINISHED == lcf->state);
898 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
899 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
900 if (NULL == event->details.operation_finished.emsg)
901 send_controller_link_response (lcf->client, lcf->operation_id,
902 GNUNET_TESTBED_host_get_cfg_
903 (GST_host_list[lcf->delegated_host_id]),
906 send_controller_link_response (lcf->client, lcf->operation_id,
908 event->details.operation_finished.emsg);
909 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
910 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
918 * Callback to signal successfull startup of the controller process
920 * @param cls the handle to the slave whose status is to be found here
921 * @param cfg the configuration with which the controller has been started;
922 * NULL if status is not GNUNET_OK
923 * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
924 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
927 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
930 struct Slave *slave = cls;
931 struct LinkControllersContext *lcc;
934 if (GNUNET_SYSERR == status)
936 slave->controller_proc = NULL;
937 GST_slave_list[slave->host_id] = NULL;
940 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
941 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
945 GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
946 event_mask, &slave_event_callback,
948 if (NULL != slave->controller)
950 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
954 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
955 "Could not connect to delegated controller");
956 GNUNET_TESTBED_controller_stop (slave->controller_proc);
957 GST_slave_list[slave->host_id] = NULL;
965 if (NULL != lcc->client)
967 GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
968 GNUNET_SERVER_client_drop (lcc->client);
979 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
982 * @param client identification of the client
983 * @param message the actual message
986 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
987 const struct GNUNET_MessageHeader *message)
989 const struct GNUNET_TESTBED_InitMessage *msg;
990 struct GNUNET_TESTBED_Host *host;
991 const char *controller_hostname;
994 if (NULL != GST_context)
996 LOG_DEBUG ("We are being connected to laterally\n");
997 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1000 msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1001 msize = ntohs (message->size);
1002 if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1005 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1008 msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1009 controller_hostname = (const char *) &msg[1];
1010 if ('\0' != controller_hostname[msize - 1])
1013 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1016 GST_context = GNUNET_malloc (sizeof (struct Context));
1017 GNUNET_SERVER_client_keep (client);
1018 GST_context->client = client;
1019 GST_context->host_id = ntohl (msg->host_id);
1020 GST_context->master_ip = GNUNET_strdup (controller_hostname);
1021 LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
1022 GST_context->system =
1023 GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
1026 GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
1027 GST_context->master_ip, NULL,
1029 host_list_add (host);
1030 LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
1031 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1036 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1039 * @param client identification of the client
1040 * @param message the actual message
1043 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1044 const struct GNUNET_MessageHeader *message)
1046 struct GNUNET_TESTBED_Host *host;
1047 const struct GNUNET_TESTBED_AddHostMessage *msg;
1048 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1049 struct GNUNET_CONFIGURATION_Handle *host_cfg;
1055 uint16_t username_length;
1056 uint16_t hostname_length;
1057 uint16_t reply_size;
1060 msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1061 msize = ntohs (msg->header.size);
1062 if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
1064 GNUNET_break_op (0);
1065 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1068 username_length = ntohs (msg->username_length);
1069 hostname_length = ntohs (msg->hostname_length);
1070 /* msg must contain hostname */
1071 if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1073 || (0 == hostname_length))
1075 GNUNET_break_op (0);
1076 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1079 /* msg must contain configuration */
1080 if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1081 username_length + hostname_length))
1083 GNUNET_break_op (0);
1084 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1090 if (0 != username_length)
1092 username = GNUNET_malloc (username_length + 1);
1093 strncpy (username, ptr, username_length);
1094 ptr += username_length;
1096 hostname = GNUNET_malloc (hostname_length + 1);
1097 strncpy (hostname, ptr, hostname_length);
1098 ptr += hostname_length;
1099 if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
1101 GNUNET_free_non_null (username);
1102 GNUNET_free_non_null (hostname);
1103 GNUNET_break_op (0);
1104 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1107 host_id = ntohl (msg->host_id);
1108 LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
1109 LOG_DEBUG ("-------host id: %u\n", host_id);
1110 LOG_DEBUG ("-------hostname: %s\n", hostname);
1111 if (NULL != username)
1112 LOG_DEBUG ("-------username: %s\n", username);
1114 LOG_DEBUG ("-------username: <not given>\n");
1115 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1117 GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1118 host_cfg, ntohs (msg->ssh_port));
1119 GNUNET_free_non_null (username);
1120 GNUNET_free (hostname);
1121 GNUNET_CONFIGURATION_destroy (host_cfg);
1124 GNUNET_break_op (0);
1125 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1128 reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1129 if (GNUNET_OK != host_list_add (host))
1131 /* We are unable to add a host */
1132 emsg = "A host exists with given host-id";
1133 LOG_DEBUG ("%s: %u", emsg, host_id);
1134 GNUNET_TESTBED_host_destroy (host);
1135 reply_size += strlen (emsg) + 1;
1136 reply = GNUNET_malloc (reply_size);
1137 memcpy (&reply[1], emsg, strlen (emsg) + 1);
1141 LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
1142 reply = GNUNET_malloc (reply_size);
1144 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
1145 reply->header.size = htons (reply_size);
1146 reply->host_id = htonl (host_id);
1147 GST_queue_message (client, &reply->header);
1148 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1153 * Iterator over hash map entries.
1155 * @param cls closure
1156 * @param key current key code
1157 * @param value value in the hash map
1158 * @return GNUNET_YES if we should continue to
1163 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1165 struct SharedService *queried_ss = cls;
1166 struct SharedService *ss = value;
1168 if (0 == strcmp (ss->name, queried_ss->name))
1176 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1179 * @param client identification of the client
1180 * @param message the actual message
1183 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1184 const struct GNUNET_MessageHeader *message)
1186 const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1187 struct SharedService *ss;
1189 struct GNUNET_HashCode hash;
1191 uint16_t service_name_size;
1193 msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1194 msg_size = ntohs (message->size);
1195 if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1198 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1202 msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1203 service_name = (char *) &msg[1];
1204 if ('\0' != service_name[service_name_size - 1])
1207 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1210 LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1211 service_name, ntohl (msg->num_peers));
1212 if (ntohl (msg->host_id) != GST_context->host_id)
1214 route_message (ntohl (msg->host_id), message);
1215 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1218 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1219 ss = GNUNET_malloc (sizeof (struct SharedService));
1220 ss->name = strdup (service_name);
1221 ss->num_shared = ntohl (msg->num_peers);
1222 GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1223 if (GNUNET_SYSERR ==
1224 GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1225 &ss_exists_iterator, ss))
1227 LOG (GNUNET_ERROR_TYPE_WARNING,
1228 "Service %s already configured as a shared service. "
1229 "Ignoring service sharing request \n", ss->name);
1230 GNUNET_free (ss->name);
1234 GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1235 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1240 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1243 * @param client identification of the client
1244 * @param message the actual message
1247 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1248 const struct GNUNET_MessageHeader *message)
1250 const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1251 struct GNUNET_CONFIGURATION_Handle *cfg;
1252 struct LCFContextQueue *lcfq;
1253 struct Route *route;
1254 struct Route *new_route;
1255 uint32_t delegated_host_id;
1256 uint32_t slave_host_id;
1259 if (NULL == GST_context)
1262 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1265 msize = ntohs (message->size);
1266 if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
1269 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1272 msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1273 delegated_host_id = ntohl (msg->delegated_host_id);
1274 if (delegated_host_id == GST_context->host_id)
1277 LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1281 if ((delegated_host_id >= GST_host_list_size) ||
1282 (NULL == GST_host_list[delegated_host_id]))
1284 LOG (GNUNET_ERROR_TYPE_WARNING,
1285 "Delegated host %u not registered with us\n", delegated_host_id);
1286 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1289 slave_host_id = ntohl (msg->slave_host_id);
1290 if ((slave_host_id >= GST_host_list_size) ||
1291 (NULL == GST_host_list[slave_host_id]))
1293 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1295 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1298 if (slave_host_id == delegated_host_id)
1300 LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1301 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1304 cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */
1307 GNUNET_break (0); /* Configuration parsing error */
1308 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1311 if (slave_host_id == GST_context->host_id) /* Link from us */
1313 struct Slave *slave;
1314 struct LinkControllersContext *lcc;
1316 if ((delegated_host_id < GST_slave_list_size) &&
1317 (NULL != GST_slave_list[delegated_host_id]))
1320 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1323 slave = GNUNET_malloc (sizeof (struct Slave));
1324 slave->host_id = delegated_host_id;
1325 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1326 slave_list_add (slave);
1327 if (1 != msg->is_subordinate)
1330 GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
1331 event_mask, &slave_event_callback,
1333 if (NULL != slave->controller)
1334 send_controller_link_response (client,
1335 GNUNET_ntohll (msg->operation_id),
1339 send_controller_link_response (client,
1340 GNUNET_ntohll (msg->operation_id),
1342 "Could not connect to delegated controller");
1343 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1346 lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1347 lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1348 GNUNET_SERVER_client_keep (client);
1349 lcc->client = client;
1351 slave->controller_proc =
1352 GNUNET_TESTBED_controller_start (GST_context->master_ip,
1353 GST_host_list[slave->host_id], cfg,
1354 &slave_status_callback, slave);
1355 GNUNET_CONFIGURATION_destroy (cfg);
1356 new_route = GNUNET_malloc (sizeof (struct Route));
1357 new_route->dest = delegated_host_id;
1358 new_route->thru = GST_context->host_id;
1359 route_list_add (new_route);
1363 /* Route the request */
1364 if (slave_host_id >= route_list_size)
1366 LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1367 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1370 lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1371 lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1372 lcfq->lcf->type = CLOSURE_TYPE_LCF;
1373 lcfq->lcf->delegated_host_id = delegated_host_id;
1374 lcfq->lcf->slave_host_id = slave_host_id;
1375 route = GST_find_dest_route (slave_host_id);
1376 GNUNET_assert (NULL != route); /* because we add routes carefully */
1377 GNUNET_assert (route->dest < GST_slave_list_size);
1378 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1379 lcfq->lcf->cfg = cfg;
1380 lcfq->lcf->is_subordinate = msg->is_subordinate;
1381 lcfq->lcf->state = INIT;
1382 lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1383 lcfq->lcf->gateway = GST_slave_list[route->dest];
1384 GNUNET_SERVER_client_keep (client);
1385 lcfq->lcf->client = client;
1386 if (NULL == lcfq_head)
1388 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1389 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1390 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1393 GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1394 /* FIXME: Adding a new route should happen after the controllers are linked
1396 if (1 != msg->is_subordinate)
1398 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1401 if ((delegated_host_id < route_list_size) &&
1402 (NULL != route_list[delegated_host_id]))
1404 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1405 * with is subordinate flag set to GNUNET_YES? */
1406 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1409 new_route = GNUNET_malloc (sizeof (struct Route));
1410 new_route->dest = delegated_host_id;
1411 new_route->thru = route->dest;
1412 route_list_add (new_route);
1413 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1418 * The task to be executed if the forwarded peer create operation has been
1421 * @param cls the FowardedOperationContext
1422 * @param tc the TaskContext from the scheduler
1425 peer_create_forward_timeout (void *cls,
1426 const struct GNUNET_SCHEDULER_TaskContext *tc)
1428 struct ForwardedOperationContext *fopc = cls;
1430 GNUNET_free (fopc->cls);
1431 GST_forwarded_operation_timeout (fopc, tc);
1436 * Callback to be called when forwarded peer create operation is successfull. We
1437 * have to relay the reply msg back to the client
1439 * @param cls ForwardedOperationContext
1440 * @param msg the peer create success message
1443 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1445 struct ForwardedOperationContext *fopc = cls;
1446 struct Peer *remote_peer;
1448 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
1450 GNUNET_assert (NULL != fopc->cls);
1451 remote_peer = fopc->cls;
1452 peer_list_add (remote_peer);
1454 GST_forwarded_operation_reply_relay (fopc, msg);
1459 * Function to destroy a peer
1461 * @param peer the peer structure to destroy
1464 GST_destroy_peer (struct Peer *peer)
1466 GNUNET_break (0 == peer->reference_cnt);
1467 if (GNUNET_YES == peer->is_remote)
1469 peer_list_remove (peer);
1473 if (GNUNET_YES == peer->details.local.is_running)
1475 GNUNET_TESTING_peer_stop (peer->details.local.peer);
1476 peer->details.local.is_running = GNUNET_NO;
1478 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1479 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1480 peer_list_remove (peer);
1486 * Callback to be called when forwarded peer destroy operation is successfull. We
1487 * have to relay the reply msg back to the client
1489 * @param cls ForwardedOperationContext
1490 * @param msg the peer create success message
1493 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1495 struct ForwardedOperationContext *fopc = cls;
1496 struct Peer *remote_peer;
1498 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
1501 remote_peer = fopc->cls;
1502 GNUNET_assert (NULL != remote_peer);
1503 remote_peer->destroy_flag = GNUNET_YES;
1504 if (0 == remote_peer->reference_cnt)
1505 GST_destroy_peer (remote_peer);
1507 GST_forwarded_operation_reply_relay (fopc, msg);
1513 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1516 * @param client identification of the client
1517 * @param message the actual message
1520 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1521 const struct GNUNET_MessageHeader *message)
1523 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1524 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1525 struct GNUNET_CONFIGURATION_Handle *cfg;
1526 struct ForwardedOperationContext *fo_ctxt;
1527 struct Route *route;
1532 uint32_t config_size;
1538 msize = ntohs (message->size);
1539 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1541 GNUNET_break (0); /* We need configuration */
1542 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1545 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1546 host_id = ntohl (msg->host_id);
1547 peer_id = ntohl (msg->peer_id);
1548 if (UINT32_MAX == peer_id)
1550 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1551 "Cannot create peer with given ID");
1552 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1555 if (host_id == GST_context->host_id)
1559 /* We are responsible for this peer */
1560 msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1561 config_size = ntohl (msg->config_size);
1562 config = GNUNET_malloc (config_size);
1563 dest_size = config_size;
1566 uncompress ((Bytef *) config, (uLongf *) & dest_size,
1567 (const Bytef *) &msg[1], (uLong) msize)))
1569 GNUNET_break (0); /* uncompression error */
1570 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1573 if (config_size != dest_size)
1575 GNUNET_break (0); /* Uncompressed config size mismatch */
1576 GNUNET_free (config);
1577 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1580 cfg = GNUNET_CONFIGURATION_create ();
1582 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1584 GNUNET_break (0); /* Configuration parsing error */
1585 GNUNET_free (config);
1586 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1589 GNUNET_free (config);
1590 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
1591 (unsigned long long) peer_id);
1592 peer = GNUNET_malloc (sizeof (struct Peer));
1593 peer->is_remote = GNUNET_NO;
1594 peer->details.local.cfg = cfg;
1596 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
1597 peer->details.local.peer =
1598 GNUNET_TESTING_peer_configure (GST_context->system,
1599 peer->details.local.cfg, peer->id,
1600 NULL /* Peer id */ ,
1602 if (NULL == peer->details.local.peer)
1604 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1608 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1611 peer->details.local.is_running = GNUNET_NO;
1612 peer_list_add (peer);
1614 GNUNET_malloc (sizeof
1615 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1616 reply->header.size =
1617 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1618 reply->header.type =
1619 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
1620 reply->peer_id = msg->peer_id;
1621 reply->operation_id = msg->operation_id;
1622 GST_queue_message (client, &reply->header);
1623 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1627 /* Forward peer create request */
1628 route = GST_find_dest_route (host_id);
1632 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1636 peer = GNUNET_malloc (sizeof (struct Peer));
1637 peer->is_remote = GNUNET_YES;
1639 peer->details.remote.slave = GST_slave_list[route->dest];
1640 peer->details.remote.remote_host_id = host_id;
1641 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1642 GNUNET_SERVER_client_keep (client);
1643 fo_ctxt->client = client;
1644 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1645 fo_ctxt->cls = peer; //GST_slave_list[route->dest]->controller;
1646 fo_ctxt->type = OP_PEER_CREATE;
1648 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
1649 [route->dest]->controller,
1650 fo_ctxt->operation_id,
1652 peer_create_success_cb, fo_ctxt);
1653 fo_ctxt->timeout_task =
1654 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
1656 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1657 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1662 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1665 * @param client identification of the client
1666 * @param message the actual message
1669 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1670 const struct GNUNET_MessageHeader *message)
1672 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1673 struct ForwardedOperationContext *fopc;
1677 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1678 peer_id = ntohl (msg->peer_id);
1679 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1680 peer_id, GNUNET_ntohll (msg->operation_id));
1681 if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
1683 LOG (GNUNET_ERROR_TYPE_ERROR,
1684 "Asked to destroy a non existent peer with id: %u\n", peer_id);
1685 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1686 "Peer doesn't exist");
1687 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1690 peer = GST_peer_list[peer_id];
1691 if (GNUNET_YES == peer->is_remote)
1693 /* Forward the destory message to sub controller */
1694 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1695 GNUNET_SERVER_client_keep (client);
1696 fopc->client = client;
1698 fopc->type = OP_PEER_DESTROY;
1699 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1701 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1703 fopc->operation_id, &msg->header,
1704 &peer_destroy_success_cb, fopc);
1705 fopc->timeout_task =
1706 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1708 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1709 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1712 peer->destroy_flag = GNUNET_YES;
1713 if (0 == peer->reference_cnt)
1714 GST_destroy_peer (peer);
1716 LOG (GNUNET_ERROR_TYPE_DEBUG,
1717 "Delaying peer destroy as peer is currently in use\n");
1718 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1719 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1724 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1727 * @param client identification of the client
1728 * @param message the actual message
1731 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1732 const struct GNUNET_MessageHeader *message)
1734 const struct GNUNET_TESTBED_PeerStartMessage *msg;
1735 struct GNUNET_TESTBED_PeerEventMessage *reply;
1736 struct ForwardedOperationContext *fopc;
1740 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1741 peer_id = ntohl (msg->peer_id);
1742 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1745 LOG (GNUNET_ERROR_TYPE_ERROR,
1746 "Asked to start a non existent peer with id: %u\n", peer_id);
1747 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1750 peer = GST_peer_list[peer_id];
1751 if (GNUNET_YES == peer->is_remote)
1753 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1754 GNUNET_SERVER_client_keep (client);
1755 fopc->client = client;
1756 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1757 fopc->type = OP_PEER_START;
1759 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1761 fopc->operation_id, &msg->header,
1762 &GST_forwarded_operation_reply_relay,
1764 fopc->timeout_task =
1765 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1767 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1768 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1771 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1773 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1775 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1778 peer->details.local.is_running = GNUNET_YES;
1779 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1780 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1781 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1782 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1783 reply->host_id = htonl (GST_context->host_id);
1784 reply->peer_id = msg->peer_id;
1785 reply->operation_id = msg->operation_id;
1786 GST_queue_message (client, &reply->header);
1787 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1792 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1795 * @param client identification of the client
1796 * @param message the actual message
1799 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1800 const struct GNUNET_MessageHeader *message)
1802 const struct GNUNET_TESTBED_PeerStopMessage *msg;
1803 struct GNUNET_TESTBED_PeerEventMessage *reply;
1804 struct ForwardedOperationContext *fopc;
1808 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1809 peer_id = ntohl (msg->peer_id);
1810 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
1811 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1813 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1815 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1818 peer = GST_peer_list[peer_id];
1819 if (GNUNET_YES == peer->is_remote)
1821 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
1823 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1824 GNUNET_SERVER_client_keep (client);
1825 fopc->client = client;
1826 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1827 fopc->type = OP_PEER_STOP;
1829 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1831 fopc->operation_id, &msg->header,
1832 &GST_forwarded_operation_reply_relay,
1834 fopc->timeout_task =
1835 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1837 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1838 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1841 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
1843 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
1844 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1845 "Peer not running");
1846 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1849 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
1850 peer->details.local.is_running = GNUNET_NO;
1851 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1852 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1853 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1854 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
1855 reply->host_id = htonl (GST_context->host_id);
1856 reply->peer_id = msg->peer_id;
1857 reply->operation_id = msg->operation_id;
1858 GST_queue_message (client, &reply->header);
1859 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1860 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1865 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1868 * @param client identification of the client
1869 * @param message the actual message
1872 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1873 const struct GNUNET_MessageHeader *message)
1875 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1876 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1885 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
1886 peer_id = ntohl (msg->peer_id);
1887 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1889 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1891 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1894 peer = GST_peer_list[peer_id];
1895 if (GNUNET_YES == peer->is_remote)
1897 struct ForwardedOperationContext *fopc;
1899 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
1900 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1901 GNUNET_SERVER_client_keep (client);
1902 fopc->client = client;
1903 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1904 fopc->type = OP_PEER_INFO;
1906 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1908 fopc->operation_id, &msg->header,
1909 &GST_forwarded_operation_reply_relay,
1911 fopc->timeout_task =
1912 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1914 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1915 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1918 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
1920 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
1922 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1923 GNUNET_free (config);
1926 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1927 reply = GNUNET_realloc (xconfig, msize);
1928 (void) memmove (&reply[1], reply, xc_size);
1929 reply->header.size = htons (msize);
1930 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
1931 reply->peer_id = msg->peer_id;
1932 reply->operation_id = msg->operation_id;
1933 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
1934 &reply->peer_identity);
1935 reply->config_size = htons ((uint16_t) c_size);
1936 GST_queue_message (client, &reply->header);
1937 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1942 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1945 * @param client identification of the client
1946 * @param message the actual message
1949 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1950 const struct GNUNET_MessageHeader *message)
1952 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1953 struct Slave *slave;
1954 struct GNUNET_TESTBED_SlaveConfiguration *reply;
1955 const struct GNUNET_CONFIGURATION_Handle *cfg;
1959 size_t xconfig_size;
1964 msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
1965 slave_id = ntohl (msg->slave_id);
1966 op_id = GNUNET_ntohll (msg->operation_id);
1967 if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
1969 /* FIXME: Add forwardings for this type of message here.. */
1970 GST_send_operation_fail_msg (client, op_id, "Slave not found");
1971 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1974 slave = GST_slave_list[slave_id];
1975 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
1976 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1978 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1979 GNUNET_free (config);
1980 reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
1981 GNUNET_break (reply_size <= UINT16_MAX);
1982 GNUNET_break (config_size <= UINT16_MAX);
1983 reply = GNUNET_realloc (xconfig, reply_size);
1984 (void) memmove (&reply[1], reply, xconfig_size);
1985 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
1986 reply->header.size = htons ((uint16_t) reply_size);
1987 reply->slave_id = msg->slave_id;
1988 reply->operation_id = msg->operation_id;
1989 reply->config_size = htons ((uint16_t) config_size);
1990 GST_queue_message (client, &reply->header);
1991 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1994 struct ManageServiceContext
1997 struct ManageServiceContext *next;
1999 struct ManageServiceContext *prev;
2001 struct GNUNET_ARM_Handle *ah;
2005 struct GNUNET_SERVER_Client *client;
2015 static struct ManageServiceContext *mctx_head;
2017 static struct ManageServiceContext *mctx_tail;
2020 cleanup_mctx (struct ManageServiceContext *mctx)
2022 mctx->expired = GNUNET_YES;
2023 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
2024 GNUNET_SERVER_client_drop (mctx->client);
2025 GNUNET_ARM_disconnect_and_free (mctx->ah);
2026 GNUNET_assert (0 < mctx->peer->reference_cnt);
2027 mctx->peer->reference_cnt--;
2028 if ( (GNUNET_YES == mctx->peer->destroy_flag)
2029 && (0 == mctx->peer->reference_cnt) )
2030 GST_destroy_peer (mctx->peer);
2037 while (NULL != mctx_head)
2038 cleanup_mctx (mctx_head);
2042 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
2046 case GNUNET_ARM_REQUEST_SENT_OK:
2047 return _("Message was sent successfully");
2048 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
2049 return _("Misconfiguration (can't connect to the ARM service)");
2050 case GNUNET_ARM_REQUEST_DISCONNECTED:
2051 return _("We disconnected from ARM before we could send a request");
2052 case GNUNET_ARM_REQUEST_BUSY:
2053 return _("ARM API is busy");
2054 case GNUNET_ARM_REQUEST_TOO_LONG:
2055 return _("Request doesn't fit into a message");
2056 case GNUNET_ARM_REQUEST_TIMEOUT:
2057 return _("Request timed out");
2059 return _("Unknown request status");
2063 arm_ret_string (enum GNUNET_ARM_Result result)
2067 case GNUNET_ARM_RESULT_STOPPED:
2068 return _("%s is stopped");
2069 case GNUNET_ARM_RESULT_STARTING:
2070 return _("%s is starting");
2071 case GNUNET_ARM_RESULT_STOPPING:
2072 return _("%s is stopping");
2073 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
2074 return _("%s is starting already");
2075 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
2076 return _("%s is stopping already");
2077 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
2078 return _("%s is started already");
2079 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
2080 return _("%s is stopped already");
2081 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
2082 return _("%s service is not known to ARM");
2083 case GNUNET_ARM_RESULT_START_FAILED:
2084 return _("%s service failed to start");
2085 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
2086 return _("%s service can't be started because ARM is shutting down");
2088 return _("%.s Unknown result code.");
2092 service_manage_result_cb (void *cls, struct GNUNET_ARM_Handle *arm,
2093 enum GNUNET_ARM_RequestStatus rs,
2094 const char *service, enum GNUNET_ARM_Result result)
2096 struct ManageServiceContext *mctx = cls;
2100 if (GNUNET_YES == mctx->expired)
2102 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
2104 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
2105 mctx->peer->id, arm_req_string (rs));
2108 if (1 == mctx->start)
2109 goto service_start_check;
2110 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
2111 || (GNUNET_ARM_RESULT_STOPPING == result)
2112 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
2113 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
2115 /* stopping a service failed */
2116 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2119 /* service stopped successfully */
2122 service_start_check:
2123 if (! ((GNUNET_ARM_RESULT_STARTING == result)
2124 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
2125 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
2127 /* starting a service failed */
2128 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2131 /* service started successfully */
2136 LOG_DEBUG ("%s\n", emsg);
2137 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
2140 send_operation_success_msg (mctx->client, mctx->op_id);
2141 GNUNET_free_non_null (emsg);
2142 cleanup_mctx (mctx);
2146 handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
2147 const struct GNUNET_MessageHeader *message)
2149 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
2150 const char* service;
2153 struct GNUNET_ARM_Handle *ah;
2154 struct ManageServiceContext *mctx;
2155 struct ForwardedOperationContext *fopc;
2161 msize = ntohs (message->size);
2162 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
2164 GNUNET_break_op (0);
2165 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2168 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
2169 service = (const char *) &msg[1];
2170 if ('\0' != service[msize - sizeof
2171 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
2173 GNUNET_break_op (0);
2174 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2179 GNUNET_break_op (0);
2180 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2183 peer_id = ntohl (msg->peer_id);
2184 op_id = GNUNET_ntohll (msg->operation_id);
2185 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
2186 service, (unsigned int) peer_id);
2187 if ((GST_peer_list_size <= peer_id)
2188 || (NULL == (peer = GST_peer_list[peer_id])))
2190 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
2191 "with id: %u", peer_id);
2194 if (0 == strcasecmp ("arm", service))
2196 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
2197 "Use peer start/stop for that");
2200 if (GNUNET_YES == peer->is_remote)
2202 /* Forward the destory message to sub controller */
2203 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2204 GNUNET_SERVER_client_keep (client);
2205 fopc->client = client;
2207 fopc->type = OP_MANAGE_SERVICE;
2208 fopc->operation_id = op_id;
2210 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
2212 fopc->operation_id, &msg->header,
2213 &GST_forwarded_operation_reply_relay,
2215 fopc->timeout_task =
2216 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
2218 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2219 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2222 if ((0 != peer->reference_cnt)
2223 && ( (0 == strcasecmp ("core", service))
2224 || (0 == strcasecmp ("transport", service)) ) )
2226 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
2227 "since it is required by existing operations",
2231 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
2234 GNUNET_asprintf (&emsg,
2235 "Cannot connect to ARM service of peer with id: %u",
2239 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
2241 peer->reference_cnt++;
2242 mctx->op_id = op_id;
2244 GNUNET_SERVER_client_keep (client);
2245 mctx->client = client;
2246 mctx->start = msg->start;
2247 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
2248 if (1 == mctx->start)
2249 GNUNET_ARM_request_service_start (mctx->ah, service,
2250 GNUNET_OS_INHERIT_STD_ERR,
2252 service_manage_result_cb,
2255 GNUNET_ARM_request_service_stop (mctx->ah, service,
2257 service_manage_result_cb,
2259 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2263 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
2264 GST_send_operation_fail_msg (client, op_id, emsg);
2266 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2270 * Clears the forwarded operations queue
2275 struct ForwardedOperationContext *fopc;
2277 while (NULL != (fopc = fopcq_head))
2279 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
2280 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
2281 if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
2282 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
2283 GNUNET_SERVER_client_drop (fopc->client);
2286 case OP_PEER_CREATE:
2287 GNUNET_free (fopc->cls);
2289 case OP_SHUTDOWN_PEERS:
2291 struct HandlerContext_ShutdownPeers *hc = fopc->cls;
2293 GNUNET_assert (0 < hc->nslaves);
2295 if (0 == hc->nslaves)
2301 case OP_PEER_DESTROY:
2303 case OP_OVERLAY_CONNECT:
2304 case OP_LINK_CONTROLLERS:
2305 case OP_GET_SLAVE_CONFIG:
2306 case OP_MANAGE_SERVICE:
2317 * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
2319 * @param cls the ForwardedOperationContext
2320 * @param tc the scheduler task context
2323 shutdown_peers_timeout_cb (void *cls,
2324 const struct GNUNET_SCHEDULER_TaskContext *tc)
2326 struct ForwardedOperationContext *fo_ctxt = cls;
2327 struct HandlerContext_ShutdownPeers *hc;
2329 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2331 hc->timeout = GNUNET_YES;
2332 GNUNET_assert (0 < hc->nslaves);
2334 if (0 == hc->nslaves)
2335 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2336 "Timeout at a slave controller");
2337 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
2338 GNUNET_SERVER_client_drop (fo_ctxt->client);
2339 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2340 GNUNET_free (fo_ctxt);
2345 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
2346 * success reply is received from all clients and then sends the success message
2349 * @param cls ForwardedOperationContext
2350 * @param msg the message to relay
2353 shutdown_peers_reply_cb (void *cls,
2354 const struct GNUNET_MessageHeader *msg)
2356 struct ForwardedOperationContext *fo_ctxt = cls;
2357 struct HandlerContext_ShutdownPeers *hc;
2360 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
2361 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
2362 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2363 GNUNET_assert (0 < hc->nslaves);
2365 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
2367 hc->timeout = GNUNET_YES;
2368 if (0 == hc->nslaves)
2370 if (GNUNET_YES == hc->timeout)
2371 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2372 "Timeout at a slave controller");
2374 send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
2376 GNUNET_SERVER_client_drop (fo_ctxt->client);
2377 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2378 GNUNET_free (fo_ctxt);
2383 * Stops and destroys all peers
2391 if (NULL == GST_peer_list)
2393 for (id = 0; id < GST_peer_list_size; id++)
2395 peer = GST_peer_list[id];
2398 /* If destroy flag is set it means that this peer should have been
2399 * destroyed by a context which we destroy before */
2400 GNUNET_break (GNUNET_NO == peer->destroy_flag);
2401 /* counter should be zero as we free all contexts before */
2402 GNUNET_break (0 == peer->reference_cnt);
2403 if ((GNUNET_NO == peer->is_remote) &&
2404 (GNUNET_YES == peer->details.local.is_running))
2405 GNUNET_TESTING_peer_kill (peer->details.local.peer);
2407 for (id = 0; id < GST_peer_list_size; id++)
2409 peer = GST_peer_list[id];
2412 if (GNUNET_NO == peer->is_remote)
2414 if (GNUNET_YES == peer->details.local.is_running)
2415 GNUNET_TESTING_peer_wait (peer->details.local.peer);
2416 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
2417 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
2421 GNUNET_free_non_null (GST_peer_list);
2422 GST_peer_list = NULL;
2423 GST_peer_list_size = 0;
2428 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
2431 * @param client identification of the client
2432 * @param message the actual message
2435 handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
2436 const struct GNUNET_MessageHeader *message)
2438 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2439 struct HandlerContext_ShutdownPeers *hc;
2440 struct Slave *slave;
2441 struct ForwardedOperationContext *fo_ctxt;
2445 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
2446 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
2447 /* Stop and destroy all peers */
2452 /* Forward to all slaves which we have started */
2453 op_id = GNUNET_ntohll (msg->operation_id);
2454 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
2455 /* FIXME: have a better implementation where we track which slaves are
2456 started by this controller */
2457 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
2459 slave = GST_slave_list[cnt];
2462 if (NULL == slave->controller_proc) /* We didn't start the slave */
2464 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
2466 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2467 GNUNET_SERVER_client_keep (client);
2468 fo_ctxt->client = client;
2469 fo_ctxt->operation_id = op_id;
2471 fo_ctxt->type = OP_SHUTDOWN_PEERS;
2473 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
2474 fo_ctxt->operation_id,
2476 shutdown_peers_reply_cb,
2478 fo_ctxt->timeout_task =
2479 GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
2481 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2483 LOG_DEBUG ("Shutting down peers\n");
2485 if (0 == hc->nslaves)
2487 send_operation_success_msg (client, op_id);
2490 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2495 * Iterator over hash map entries.
2497 * @param cls closure
2498 * @param key current key code
2499 * @param value value in the hash map
2500 * @return GNUNET_YES if we should continue to
2505 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2507 struct SharedService *ss = value;
2509 GNUNET_assert (GNUNET_YES ==
2510 GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2511 GNUNET_free (ss->name);
2518 * Iterator for freeing hash map entries in a slave's reghost_map
2520 * @param cls handle to the slave
2521 * @param key current key code
2522 * @param value value in the hash map
2523 * @return GNUNET_YES if we should continue to
2528 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
2531 struct Slave *slave = cls;
2532 struct RegisteredHostContext *rhc = value;
2533 struct ForwardedOverlayConnectContext *focc;
2535 GNUNET_assert (GNUNET_YES ==
2536 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
2538 while (NULL != (focc = rhc->focc_dll_head))
2540 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
2541 GST_cleanup_focc (focc);
2543 if (NULL != rhc->sub_op)
2544 GNUNET_TESTBED_operation_done (rhc->sub_op);
2545 if (NULL != rhc->client)
2546 GNUNET_SERVER_client_drop (rhc->client);
2547 GNUNET_free (value);
2553 * Task to clean up and shutdown nicely
2556 * @param tc the TaskContext from scheduler
2559 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2561 struct LCFContextQueue *lcfq;
2562 struct MessageQueue *mq_entry;
2565 shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2566 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2567 (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2569 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2570 /* cleanup any remaining forwarded operations */
2572 if (NULL != lcfq_head)
2574 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2576 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2577 lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2580 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2581 for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2583 GNUNET_SERVER_client_drop (lcfq->lcf->client);
2584 GNUNET_assert (NULL != lcfq->lcf->cfg);
2585 GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
2586 GNUNET_free (lcfq->lcf);
2587 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2593 /* Clear peer list */
2595 /* Clear host list */
2596 for (id = 0; id < GST_host_list_size; id++)
2597 if (NULL != GST_host_list[id])
2598 GNUNET_TESTBED_host_destroy (GST_host_list[id]);
2599 GNUNET_free_non_null (GST_host_list);
2600 /* Clear route list */
2601 for (id = 0; id < route_list_size; id++)
2602 if (NULL != route_list[id])
2603 GNUNET_free (route_list[id]);
2604 GNUNET_free_non_null (route_list);
2605 /* Clear GST_slave_list */
2606 for (id = 0; id < GST_slave_list_size; id++)
2607 if (NULL != GST_slave_list[id])
2609 struct HostRegistration *hr_entry;
2611 while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
2613 GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
2614 GST_slave_list[id]->hr_dll_tail, hr_entry);
2615 GNUNET_free (hr_entry);
2617 if (NULL != GST_slave_list[id]->rhandle)
2618 GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
2620 GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
2622 reghost_free_iterator,
2623 GST_slave_list[id]);
2624 GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
2625 if (NULL != GST_slave_list[id]->controller)
2626 GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
2627 if (NULL != GST_slave_list[id]->controller_proc)
2628 GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
2629 GNUNET_free (GST_slave_list[id]);
2631 GNUNET_free_non_null (GST_slave_list);
2632 if (NULL != GST_context)
2634 GNUNET_free_non_null (GST_context->master_ip);
2635 if (NULL != GST_context->system)
2636 GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
2637 GNUNET_SERVER_client_drop (GST_context->client);
2638 GNUNET_free (GST_context);
2641 if (NULL != transmit_handle)
2642 GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
2643 while (NULL != (mq_entry = mq_head))
2645 GNUNET_free (mq_entry->msg);
2646 GNUNET_SERVER_client_drop (mq_entry->client);
2647 GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
2648 GNUNET_free (mq_entry);
2650 GNUNET_free_non_null (hostname);
2651 GNUNET_CONFIGURATION_destroy (our_config);
2652 /* Free hello cache */
2654 GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
2655 GST_opq_openfds = NULL;
2656 GST_stats_destroy ();
2661 * Callback for client disconnect
2664 * @param client the client which has disconnected
2667 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2669 if (NULL == GST_context)
2671 if (client == GST_context->client)
2673 LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2674 /* should not be needed as we're terminated by failure to read
2675 * from stdin, but if stdin fails for some reason, this shouldn't
2676 * hurt for now --- might need to revise this later if we ever
2677 * decide that master connections might be temporarily down
2678 * for some reason */
2679 //GNUNET_SCHEDULER_shutdown ();
2687 * @param cls closure
2688 * @param server the initialized server
2689 * @param cfg configuration to use
2692 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2693 const struct GNUNET_CONFIGURATION_Handle *cfg)
2695 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2696 {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2697 {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
2698 {&handle_configure_shared_service, NULL,
2699 GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
2700 {&handle_link_controllers, NULL,
2701 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
2702 {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
2703 {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
2704 sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2705 {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
2706 sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2707 {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
2708 sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2709 {&handle_peer_get_config, NULL,
2710 GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
2711 sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2712 {&GST_handle_overlay_connect, NULL,
2713 GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
2714 sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2715 {&GST_handle_remote_overlay_connect, NULL,
2716 GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
2717 {&handle_manage_peer_service, NULL,
2718 GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
2719 {&handle_slave_get_config, NULL,
2720 GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
2721 sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2722 {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
2723 sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
2727 unsigned long long num;
2730 GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
2733 GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
2734 GNUNET_free (logfile);
2736 GNUNET_assert (GNUNET_OK ==
2737 GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2738 "CACHE_SIZE", &num));
2739 GST_cache_init ((unsigned int) num);
2740 GNUNET_assert (GNUNET_OK ==
2741 GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2742 "MAX_OPEN_FDS", &num));
2743 GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
2744 GNUNET_assert (GNUNET_OK ==
2745 GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
2746 "OPERATION_TIMEOUT",
2748 GNUNET_TIME_Relative *)
2750 GNUNET_assert (GNUNET_OK ==
2751 GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
2752 "HOSTNAME", &hostname));
2753 our_config = GNUNET_CONFIGURATION_dup (cfg);
2754 GNUNET_SERVER_add_handlers (server, message_handlers);
2755 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2756 ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
2758 GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
2759 GNUNET_SCHEDULER_PRIORITY_IDLE,
2760 &shutdown_task, NULL);
2761 LOG_DEBUG ("Testbed startup complete\n");
2762 event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
2763 GST_stats_init (our_config);
2768 * The starting point of execution
2771 main (int argc, char *const *argv)
2773 //sleep (15); /* Debugging */
2774 return (GNUNET_OK ==
2775 GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2776 &testbed_run, NULL)) ? 0 : 1;
2779 /* end of gnunet-service-testbed.c */