- use topology service instead of statistics as statistics may not terminate when...
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
1 /*
2   This file is part of GNUnet.
3   (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file testbed/gnunet-service-testbed.c
23  * @brief implementation of the TESTBED service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "gnunet-service-testbed.h"
28 #include "gnunet_arm_service.h"
29
30 #include <zlib.h>
31
32
33 /**
34  * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
35  */
36 struct HandlerContext_ShutdownPeers
37 {
38   /**
39    * The number of slave we expect to hear from since we forwarded the
40    * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
41    */
42   unsigned int nslaves;
43
44   /**
45    * Did we observe a timeout with respect to this operation at any of the
46    * slaves
47    */
48   int timeout;
49 };
50
51
52 /***********/
53 /* Globals */
54 /***********/
55
56 /**
57  * Our configuration
58  */
59 struct GNUNET_CONFIGURATION_Handle *our_config;
60
61 /**
62  * The master context; generated with the first INIT message
63  */
64 struct Context *GST_context;
65
66 /**
67  * A list of directly linked neighbours
68  */
69 struct Slave **GST_slave_list;
70
71 /**
72  * A list of peers we know about
73  */
74 struct Peer **GST_peer_list;
75
76 /**
77  * Array of hosts
78  */
79 struct GNUNET_TESTBED_Host **GST_host_list;
80
81 /**
82  * DLL head for forwarded operation contexts
83  */
84 struct ForwardedOperationContext *fopcq_head;
85
86 /**
87  * DLL tail for forwarded operation contexts
88  */
89 struct ForwardedOperationContext *fopcq_tail;
90
91 /**
92  * Operation queue for open file descriptors
93  */
94 struct OperationQueue *GST_opq_openfds;
95
96 /**
97  * Timeout for operations which may take some time
98  */
99 const struct GNUNET_TIME_Relative GST_timeout;
100
101 /**
102  * The size of the host list
103  */
104 unsigned int GST_host_list_size;
105
106 /**
107  * The size of directly linked neighbours list
108  */
109 unsigned int GST_slave_list_size;
110
111 /**
112  * The size of the peer list
113  */
114 unsigned int GST_peer_list_size;
115
116
117 /***********************************/
118 /* Local definitions and variables */
119 /***********************************/
120
121 /**
122  * The message queue for sending messages to clients
123  */
124 struct MessageQueue
125 {
126   /**
127    * The message to be sent
128    */
129   struct GNUNET_MessageHeader *msg;
130
131   /**
132    * The client to send the message to
133    */
134   struct GNUNET_SERVER_Client *client;
135
136   /**
137    * next pointer for DLL
138    */
139   struct MessageQueue *next;
140
141   /**
142    * prev pointer for DLL
143    */
144   struct MessageQueue *prev;
145 };
146
147 /**
148  * Our hostname; we give this to all the peers we start
149  */
150 static char *hostname;
151
152 /**
153  * Current Transmit Handle; NULL if no notify transmit exists currently
154  */
155 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
156
157 /**
158  * The head for the LCF queue
159  */
160 static struct LCFContextQueue *lcfq_head;
161
162 /**
163  * The tail for the LCF queue
164  */
165 static struct LCFContextQueue *lcfq_tail;
166
167 /**
168  * The message queue head
169  */
170 static struct MessageQueue *mq_head;
171
172 /**
173  * The message queue tail
174  */
175 static struct MessageQueue *mq_tail;
176
177 /**
178  * The hashmap of shared services
179  */
180 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
181
182 /**
183  * A list of routes
184  */
185 static struct Route **route_list;
186
187 /**
188  * The event mask for the events we listen from sub-controllers
189  */
190 static uint64_t event_mask;
191
192 /**
193  * The size of the route list
194  */
195 static unsigned int route_list_size;
196
197 /**
198  * The lcf_task handle
199  */
200 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
201
202 /**
203  * The shutdown task handle
204  */
205 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
206
207
208 /**
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.
212  *
213  * @param cls NULL
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
217  */
218 static size_t
219 transmit_ready_notify (void *cls, size_t size, void *buf)
220 {
221   struct MessageQueue *mq_entry;
222
223   transmit_handle = NULL;
224   mq_entry = mq_head;
225   GNUNET_assert (NULL != mq_entry);
226   if (0 == size)
227     return 0;
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);
235   mq_entry = mq_head;
236   if (NULL != mq_entry)
237     transmit_handle =
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);
242   return size;
243 }
244
245
246 /**
247  * Queues a message in send queue for sending to the service
248  *
249  * @param client the client to whom the queued message has to be sent
250  * @param msg the message to queue
251  */
252 void
253 GST_queue_message (struct GNUNET_SERVER_Client *client,
254                    struct GNUNET_MessageHeader *msg)
255 {
256   struct MessageQueue *mq_entry;
257   uint16_t type;
258   uint16_t size;
259
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));
265   mq_entry->msg = msg;
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,
269              ntohs (msg->size));
270   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
271   if (NULL == transmit_handle)
272     transmit_handle =
273         GNUNET_SERVER_notify_transmit_ready (client, size,
274                                              GNUNET_TIME_UNIT_FOREVER_REL,
275                                              &transmit_ready_notify, NULL);
276 }
277
278
279 /**
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
282  * of LIST_GROW_STEP.
283  *
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
288  *          accommodate_size
289  */
290 #define array_grow_large_enough(ptr, size, accommodate_size) \
291   do                                                                    \
292   {                                                                     \
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);                            \
300   } while (0)
301
302
303 /**
304  * Function to add a host to the current list of known hosts
305  *
306  * @param host the host to add
307  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
308  *           already in use
309  */
310 static int
311 host_list_add (struct GNUNET_TESTBED_Host *host)
312 {
313   uint32_t host_id;
314
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])
319   {
320     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
321     return GNUNET_SYSERR;
322   }
323   GST_host_list[host_id] = host;
324   return GNUNET_OK;
325 }
326
327
328 /**
329  * Adds a route to the route list
330  *
331  * @param route the route to add
332  */
333 static void
334 route_list_add (struct Route *route)
335 {
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;
340 }
341
342
343 /**
344  * Adds a slave to the slave array
345  *
346  * @param slave the slave controller to add
347  */
348 static void
349 slave_list_add (struct Slave *slave)
350 {
351   if (slave->host_id >= GST_slave_list_size)
352     array_grow_large_enough (GST_slave_list, GST_slave_list_size,
353                              slave->host_id);
354   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
355   GST_slave_list[slave->host_id] = slave;
356 }
357
358
359 /**
360  * Adds a peer to the peer array
361  *
362  * @param peer the peer to add
363  */
364 static void
365 peer_list_add (struct Peer *peer)
366 {
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;
371 }
372
373
374 /**
375  * Removes a the give peer from the peer array
376  *
377  * @param peer the peer to be removed
378  */
379 static void
380 peer_list_remove (struct Peer *peer)
381 {
382   unsigned int orig_size;
383   uint32_t id;
384
385   GST_peer_list[peer->id] = NULL;
386   orig_size = GST_peer_list_size;
387   while (GST_peer_list_size >= LIST_GROW_STEP)
388   {
389     for (id = GST_peer_list_size - 1;
390          (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
391          id--)
392       if (NULL != GST_peer_list[id])
393         break;
394     if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
395       break;
396     GST_peer_list_size -= LIST_GROW_STEP;
397   }
398   if (orig_size == GST_peer_list_size)
399     return;
400   GST_peer_list =
401       GNUNET_realloc (GST_peer_list,
402                       sizeof (struct Peer *) * GST_peer_list_size);
403 }
404
405
406 /**
407  * Finds the route with directly connected host as destination through which
408  * the destination host can be reached
409  *
410  * @param host_id the id of the destination host
411  * @return the route with directly connected destination host; NULL if no route
412  *           is found
413  */
414 struct Route *
415 GST_find_dest_route (uint32_t host_id)
416 {
417   struct Route *route;
418
419   if (route_list_size <= host_id)
420     return NULL;
421   while (NULL != (route = route_list[host_id]))
422   {
423     if (route->thru == GST_context->host_id)
424       break;
425     host_id = route->thru;
426   }
427   return route;
428 }
429
430
431 /**
432  * Routes message to a host given its host_id
433  *
434  * @param host_id the id of the destination host
435  * @param msg the message to be routed
436  */
437 static void
438 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
439 {
440   GNUNET_break (0);
441 }
442
443
444 /**
445  * Send operation failure message to client
446  *
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
450  */
451 void
452 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
453                              uint64_t operation_id, const char *emsg)
454 {
455   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
456   uint16_t msize;
457   uint16_t emsg_len;
458
459   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
460   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
461   msize += emsg_len;
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);
467   if (0 != emsg_len)
468     memcpy (&msg[1], emsg, emsg_len);
469   GST_queue_message (client, &msg->header);
470 }
471
472
473 /**
474  * Function to send generic operation success message to given client
475  *
476  * @param client the client to send the message to
477  * @param operation_id the id of the operation which was successful
478  */
479 static void
480 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
481                             uint64_t operation_id)
482 {
483   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
484   uint16_t msize;
485
486   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
487   msg = GNUNET_malloc (msize);
488   msg->header.size = htons (msize);
489   msg->header.type =
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);
494 }
495
496
497 /**
498  * Function to send a failure reponse for controller link operation
499  *
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
504  *          linked to.
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!
508  */
509 static void
510 send_controller_link_response (struct GNUNET_SERVER_Client *client,
511                                uint64_t operation_id,
512                                const struct GNUNET_CONFIGURATION_Handle
513                                *cfg,
514                                const char *emsg)
515 {
516   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
517   char *xconfig;
518   size_t config_size;
519   size_t xconfig_size;  
520   uint16_t msize;
521
522   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
523   xconfig = NULL;
524   xconfig_size = 0;
525   config_size = 0;
526   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
527   if (NULL != cfg)
528   {
529     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
530                                             &config_size,
531                                             &xconfig_size);
532     msize += xconfig_size;
533   }
534   if (NULL != emsg)
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);
540   if (NULL == emsg)
541     msg->success = htons (GNUNET_YES);
542   msg->operation_id = GNUNET_htonll (operation_id);
543   msg->config_size = htons ((uint16_t) config_size);
544   if (NULL != xconfig)
545     memcpy (&msg[1], xconfig, xconfig_size);
546   if (NULL != emsg)
547     memcpy (&msg[1], emsg, strlen (emsg));
548   GST_queue_message (client, &msg->header);
549 }
550
551 /**
552  * Callback which will be called after a host registration succeeded or failed
553  *
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
556  */
557 static void
558 hr_completion (void *cls, const char *emsg);
559
560
561 /**
562  * Attempts to register the next host in the host registration queue
563  *
564  * @param slave the slave controller whose host registration queue is checked
565  *          for host registrations
566  */
567 static void
568 register_next_host (struct Slave *slave)
569 {
570   struct HostRegistration *hr;
571
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]));
578   slave->rhandle =
579       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
580                                     slave);
581 }
582
583
584 /**
585  * Callback which will be called to after a host registration succeeded or failed
586  *
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
589  */
590 static void
591 hr_completion (void *cls, const char *emsg)
592 {
593   struct Slave *slave = cls;
594   struct HostRegistration *hr;
595
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);
603   if (NULL != hr->cb)
604     hr->cb (hr->cb_cls, emsg);
605   GNUNET_free (hr);
606   if (NULL != slave->hr_dll_head)
607     register_next_host (slave);
608 }
609
610
611 /**
612  * Adds a host registration's request to a slave's registration queue
613  *
614  * @param slave the slave controller at which the given host has to be
615  *          registered
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
619  */
620 void
621 GST_queue_host_registration (struct Slave *slave,
622                              GNUNET_TESTBED_HostRegistrationCompletion cb,
623                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
624 {
625   struct HostRegistration *hr;
626   int call_register;
627
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));
633   hr->cb = cb;
634   hr->cb_cls = cb_cls;
635   hr->host = host;
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);
640 }
641
642
643 /**
644  * The  Link Controller forwarding task
645  *
646  * @param cls the LCFContext
647  * @param tc the Task context from scheduler
648  */
649 static void
650 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
651
652
653 /**
654  * Completion callback for host registrations while forwarding Link Controller messages
655  *
656  * @param cls the LCFContext
657  * @param emsg the error message; NULL if host registration is successful
658  */
659 static void
660 lcf_proc_cc (void *cls, const char *emsg)
661 {
662   struct LCFContext *lcf = cls;
663
664   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
665   switch (lcf->state)
666   {
667   case INIT:
668     if (NULL != emsg)
669       goto registration_error;
670     lcf->state = DELEGATED_HOST_REGISTERED;
671     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
672     break;
673   case DELEGATED_HOST_REGISTERED:
674     if (NULL != emsg)
675       goto registration_error;
676     lcf->state = SLAVE_HOST_REGISTERED;
677     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
678     break;
679   default:
680     GNUNET_assert (0);          /* Shouldn't reach here */
681   }
682   return;
683
684 registration_error:
685   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
686        emsg);
687   lcf->state = FINISHED;
688   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
689 }
690
691
692 /**
693  * Callback to relay the reply msg of a forwarded operation back to the client
694  *
695  * @param cls ForwardedOperationContext
696  * @param msg the message to relay
697  */
698 void
699 GST_forwarded_operation_reply_relay (void *cls,
700                                      const struct GNUNET_MessageHeader *msg)
701 {
702   struct ForwardedOperationContext *fopc = cls;
703   struct GNUNET_MessageHeader *dup_msg;
704   uint16_t msize;
705
706   msize = ntohs (msg->size);
707   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
708              msize);
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);
714   GNUNET_free (fopc);
715 }
716
717
718 /**
719  * Task to free resources when forwarded operation has been timedout
720  *
721  * @param cls the ForwardedOperationContext
722  * @param tc the task context from scheduler
723  */
724 void
725 GST_forwarded_operation_timeout (void *cls,
726                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
727 {
728   struct ForwardedOperationContext *fopc = cls;
729
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);
736   GNUNET_free (fopc);
737 }
738
739
740 /**
741  * The  Link Controller forwarding task
742  *
743  * @param cls the LCFContext
744  * @param tc the Task context from scheduler
745  */
746 static void
747 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
748
749
750 /**
751  * Task to free resources when forwarded link controllers has been timedout
752  *
753  * @param cls the LCFContext
754  * @param tc the task context from scheduler
755  */
756 static void
757 lcf_forwarded_operation_timeout (void *cls,
758                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
759 {
760   struct LCFContext *lcf = cls;
761
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 "
768                                  "timed out\n");
769   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
770   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
771 }
772
773
774 /**
775  * The  Link Controller forwarding task
776  *
777  * @param cls the LCFContext
778  * @param tc the Task context from scheduler
779  */
780 static void
781 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
782 {
783   struct LCFContext *lcf = cls;
784   struct LCFContextQueue *lcfq;
785
786   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
787   switch (lcf->state)
788   {
789   case INIT:
790     if (GNUNET_NO ==
791         GNUNET_TESTBED_is_host_registered_ (GST_host_list
792                                             [lcf->delegated_host_id],
793                                             lcf->gateway->controller))
794     {
795       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
796                                    GST_host_list[lcf->delegated_host_id]);
797     }
798     else
799     {
800       lcf->state = DELEGATED_HOST_REGISTERED;
801       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
802     }
803     break;
804   case DELEGATED_HOST_REGISTERED:
805     if (GNUNET_NO ==
806         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
807                                             lcf->gateway->controller))
808     {
809       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
810                                    GST_host_list[lcf->slave_host_id]);
811     }
812     else
813     {
814       lcf->state = SLAVE_HOST_REGISTERED;
815       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
816     }
817     break;
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],
823                                               NULL,
824                                               lcf->is_subordinate);
825     lcf->timeout_task =
826         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
827                                       lcf);
828     lcf->state = FINISHED;
829     break;
830   case FINISHED:
831     lcfq = lcfq_head;
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);
837     GNUNET_free (lcf);
838     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
839     GNUNET_free (lcfq);
840     if (NULL != lcfq_head)
841       lcf_proc_task_id =
842           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
843   }
844 }
845
846
847 /**
848  * Callback for event from slave controllers
849  *
850  * @param cls struct Slave *
851  * @param event information about the event
852  */
853 static void
854 slave_event_callback (void *cls,
855                       const struct GNUNET_TESTBED_EventInformation *event)
856 {
857   struct RegisteredHostContext *rhc;
858   struct LCFContext *lcf;
859   struct GNUNET_CONFIGURATION_Handle *cfg;
860   struct GNUNET_TESTBED_Operation *old_op;
861
862   /* We currently only get here when working on RegisteredHostContexts and
863      LCFContexts */
864   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
865   rhc = event->op_cls;
866   if (CLOSURE_TYPE_RHC == rhc->type)
867   {
868     GNUNET_assert (rhc->sub_op == event->op);
869     switch (rhc->state)
870     {
871     case RHC_GET_CFG:
872       cfg = event->details.operation_finished.generic;
873       old_op = rhc->sub_op;
874       rhc->state = RHC_LINK;
875       rhc->sub_op =
876           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
877                                           rhc->reg_host, rhc->host, cfg,
878                                           GNUNET_NO);
879       GNUNET_TESTBED_operation_done (old_op);
880       break;
881     case RHC_LINK:
882       LOG_DEBUG ("OL: Linking controllers successfull\n");
883       GNUNET_TESTBED_operation_done (rhc->sub_op);
884       rhc->sub_op = NULL;
885       rhc->state = RHC_OL_CONNECT;
886       GST_process_next_focc (rhc);
887       break;
888     default:
889       GNUNET_assert (0);
890     }
891     return;
892   }
893   lcf = event->op_cls;
894   if (CLOSURE_TYPE_LCF == lcf->type)
895   {    
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]),
904                                      NULL);
905     else
906       send_controller_link_response (lcf->client, lcf->operation_id,
907                                      NULL,
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);
911     return;
912   }
913   GNUNET_assert (0);
914 }
915
916
917 /**
918  * Callback to signal successfull startup of the controller process
919  *
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
925  */
926 static void
927 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
928                        int status)
929 {
930   struct Slave *slave = cls;
931   struct LinkControllersContext *lcc;
932
933   lcc = slave->lcc;
934   if (GNUNET_SYSERR == status)
935   {
936     slave->controller_proc = NULL;
937     GST_slave_list[slave->host_id] = NULL;
938     GNUNET_free (slave);
939     slave = NULL;
940     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
941     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
942     goto clean_lcc;
943   }
944   slave->controller =
945       GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
946                                          event_mask, &slave_event_callback,
947                                          slave);
948   if (NULL != slave->controller)
949   {
950     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
951   }
952   else
953   {
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;
958     GNUNET_free (slave);
959     slave = NULL;
960   }
961
962 clean_lcc:
963   if (NULL != lcc)
964   {
965     if (NULL != lcc->client)
966     {
967       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
968       GNUNET_SERVER_client_drop (lcc->client);
969       lcc->client = NULL;
970     }
971     GNUNET_free (lcc);
972   }
973   if (NULL != slave)
974     slave->lcc = NULL;
975 }
976
977
978 /**
979  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
980  *
981  * @param cls NULL
982  * @param client identification of the client
983  * @param message the actual message
984  */
985 static void
986 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
987              const struct GNUNET_MessageHeader *message)
988 {
989   const struct GNUNET_TESTBED_InitMessage *msg;
990   struct GNUNET_TESTBED_Host *host;
991   const char *controller_hostname;
992   uint16_t msize;
993
994   if (NULL != GST_context)
995   {
996     LOG_DEBUG ("We are being connected to laterally\n");
997     GNUNET_SERVER_receive_done (client, GNUNET_OK);
998     return;
999   }
1000   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1001   msize = ntohs (message->size);
1002   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1003   {
1004     GNUNET_break (0);
1005     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1006     return;
1007   }
1008   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1009   controller_hostname = (const char *) &msg[1];
1010   if ('\0' != controller_hostname[msize - 1])
1011   {
1012     GNUNET_break (0);
1013     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1014     return;
1015   }
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,
1024                                     hostname);
1025   host =
1026       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
1027                                           GST_context->master_ip, NULL,
1028                                           our_config, 0);
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);
1032 }
1033
1034
1035 /**
1036  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1037  *
1038  * @param cls NULL
1039  * @param client identification of the client
1040  * @param message the actual message
1041  */
1042 static void
1043 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1044                  const struct GNUNET_MessageHeader *message)
1045 {
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;
1050   char *username;
1051   char *hostname;
1052   char *emsg;
1053   const void *ptr;
1054   uint32_t host_id;
1055   uint16_t username_length;
1056   uint16_t hostname_length;
1057   uint16_t reply_size;
1058   uint16_t msize;
1059
1060   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1061   msize = ntohs (msg->header.size);
1062   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
1063   {
1064     GNUNET_break_op (0);
1065     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1066     return;
1067   }
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) + 
1072                  username_length))
1073       || (0 == hostname_length))
1074   {
1075     GNUNET_break_op (0);
1076     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1077     return;
1078   }
1079   /* msg must contain configuration */
1080   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1081                 username_length + hostname_length))
1082   {
1083     GNUNET_break_op (0);
1084     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1085     return;
1086   }
1087   username = NULL;
1088   hostname = NULL;
1089   ptr = &msg[1];
1090   if (0 != username_length)
1091   {
1092     username = GNUNET_malloc (username_length + 1);
1093     strncpy (username, ptr, username_length);
1094     ptr += username_length;
1095   }
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)))
1100   {
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);
1105     return;
1106   }
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);
1113   else
1114     LOG_DEBUG ("-------username: <not given>\n");
1115   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1116   host =
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);
1122   if (NULL == host)
1123   {
1124     GNUNET_break_op (0);
1125     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1126     return;
1127   }
1128   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1129   if (GNUNET_OK != host_list_add (host))
1130   {
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);
1138   }
1139   else
1140   {
1141     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
1142     reply = GNUNET_malloc (reply_size);
1143   }
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);
1149 }
1150
1151
1152 /**
1153  * Iterator over hash map entries.
1154  *
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
1159  *         iterate,
1160  *         GNUNET_NO if not.
1161  */
1162 int
1163 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1164 {
1165   struct SharedService *queried_ss = cls;
1166   struct SharedService *ss = value;
1167
1168   if (0 == strcmp (ss->name, queried_ss->name))
1169     return GNUNET_NO;
1170   else
1171     return GNUNET_YES;
1172 }
1173
1174
1175 /**
1176  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1177  *
1178  * @param cls NULL
1179  * @param client identification of the client
1180  * @param message the actual message
1181  */
1182 static void
1183 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1184                                  const struct GNUNET_MessageHeader *message)
1185 {
1186   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1187   struct SharedService *ss;
1188   char *service_name;
1189   struct GNUNET_HashCode hash;
1190   uint16_t msg_size;
1191   uint16_t service_name_size;
1192
1193   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1194   msg_size = ntohs (message->size);
1195   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1196   {
1197     GNUNET_break (0);
1198     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1199     return;
1200   }
1201   service_name_size =
1202       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1203   service_name = (char *) &msg[1];
1204   if ('\0' != service_name[service_name_size - 1])
1205   {
1206     GNUNET_break (0);
1207     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1208     return;
1209   }
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)
1213   {
1214     route_message (ntohl (msg->host_id), message);
1215     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1216     return;
1217   }
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))
1226   {
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);
1231     GNUNET_free (ss);
1232     return;
1233   }
1234   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1235                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1236 }
1237
1238
1239 /**
1240  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1241  *
1242  * @param cls NULL
1243  * @param client identification of the client
1244  * @param message the actual message
1245  */
1246 static void
1247 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1248                          const struct GNUNET_MessageHeader *message)
1249 {
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;
1257   uint16_t msize;
1258
1259   if (NULL == GST_context)
1260   {
1261     GNUNET_break (0);
1262     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1263     return;
1264   }
1265   msize = ntohs (message->size);
1266   if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
1267   {
1268     GNUNET_break (0);
1269     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1270     return;
1271   }
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)
1275   {
1276     GNUNET_break (0);
1277     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1278     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1279     return;
1280   }
1281   if ((delegated_host_id >= GST_host_list_size) ||
1282       (NULL == GST_host_list[delegated_host_id]))
1283   {
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);
1287     return;
1288   }
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]))
1292   {
1293     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1294          slave_host_id);
1295     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1296     return;
1297   }
1298   if (slave_host_id == delegated_host_id)
1299   {
1300     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1301     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1302     return;
1303   }
1304   cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */
1305   if (NULL == cfg)
1306   {
1307     GNUNET_break (0);         /* Configuration parsing error */
1308     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1309     return;
1310   }
1311   if (slave_host_id == GST_context->host_id)    /* Link from us */
1312   {
1313     struct Slave *slave;
1314     struct LinkControllersContext *lcc;
1315
1316     if ((delegated_host_id < GST_slave_list_size) &&
1317         (NULL != GST_slave_list[delegated_host_id]))
1318     {
1319       GNUNET_break (0);
1320       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1321       return;
1322     }
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)
1328     {
1329       slave->controller =
1330           GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
1331                                              event_mask, &slave_event_callback,
1332                                              slave);
1333       if (NULL != slave->controller)
1334         send_controller_link_response (client,
1335                                        GNUNET_ntohll (msg->operation_id),
1336                                        NULL,
1337                                        NULL);
1338       else
1339         send_controller_link_response (client,
1340                                        GNUNET_ntohll (msg->operation_id),
1341                                        NULL,
1342                                        "Could not connect to delegated controller");
1343       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1344       return;
1345     }
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;
1350     slave->lcc = lcc;
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);
1360     return;
1361   }
1362
1363   /* Route the request */
1364   if (slave_host_id >= route_list_size)
1365   {
1366     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1367     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1368     return;
1369   }
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)
1387   {
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);
1391   }
1392   else
1393     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1394   /* FIXME: Adding a new route should happen after the controllers are linked
1395    * successfully */
1396   if (1 != msg->is_subordinate)
1397   {
1398     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1399     return;
1400   }
1401   if ((delegated_host_id < route_list_size) &&
1402       (NULL != route_list[delegated_host_id]))
1403   {
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);
1407     return;
1408   }
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);
1414 }
1415
1416
1417 /**
1418  * The task to be executed if the forwarded peer create operation has been
1419  * timed out
1420  *
1421  * @param cls the FowardedOperationContext
1422  * @param tc the TaskContext from the scheduler
1423  */
1424 static void
1425 peer_create_forward_timeout (void *cls,
1426                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1427 {
1428   struct ForwardedOperationContext *fopc = cls;
1429
1430   GNUNET_free (fopc->cls);
1431   GST_forwarded_operation_timeout (fopc, tc);
1432 }
1433
1434
1435 /**
1436  * Callback to be called when forwarded peer create operation is successfull. We
1437  * have to relay the reply msg back to the client
1438  *
1439  * @param cls ForwardedOperationContext
1440  * @param msg the peer create success message
1441  */
1442 static void
1443 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1444 {
1445   struct ForwardedOperationContext *fopc = cls;
1446   struct Peer *remote_peer;
1447
1448   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
1449   {
1450     GNUNET_assert (NULL != fopc->cls);
1451     remote_peer = fopc->cls;
1452     peer_list_add (remote_peer);
1453   }
1454   GST_forwarded_operation_reply_relay (fopc, msg);
1455 }
1456
1457
1458 /**
1459  * Function to destroy a peer
1460  *
1461  * @param peer the peer structure to destroy
1462  */
1463 void
1464 GST_destroy_peer (struct Peer *peer)
1465 {
1466   GNUNET_break (0 == peer->reference_cnt);
1467   if (GNUNET_YES == peer->is_remote)
1468   {
1469     peer_list_remove (peer);
1470     GNUNET_free (peer);
1471     return;
1472   }
1473   if (GNUNET_YES == peer->details.local.is_running)
1474   {
1475     GNUNET_TESTING_peer_stop (peer->details.local.peer);
1476     peer->details.local.is_running = GNUNET_NO;
1477   }
1478   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1479   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1480   peer_list_remove (peer);
1481   GNUNET_free (peer);
1482 }
1483
1484
1485 /**
1486  * Callback to be called when forwarded peer destroy operation is successfull. We
1487  * have to relay the reply msg back to the client
1488  *
1489  * @param cls ForwardedOperationContext
1490  * @param msg the peer create success message
1491  */
1492 static void
1493 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1494 {
1495   struct ForwardedOperationContext *fopc = cls;
1496   struct Peer *remote_peer;
1497
1498   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
1499       ntohs (msg->type))
1500   {
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);
1506   }
1507   GST_forwarded_operation_reply_relay (fopc, msg);
1508 }
1509
1510
1511
1512 /**
1513  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1514  *
1515  * @param cls NULL
1516  * @param client identification of the client
1517  * @param message the actual message
1518  */
1519 static void
1520 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1521                     const struct GNUNET_MessageHeader *message)
1522 {
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;
1528   struct Peer *peer;
1529   char *config;
1530   size_t dest_size;
1531   int ret;
1532   uint32_t config_size;
1533   uint32_t host_id;
1534   uint32_t peer_id;
1535   uint16_t msize;
1536
1537
1538   msize = ntohs (message->size);
1539   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1540   {
1541     GNUNET_break (0);           /* We need configuration */
1542     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1543     return;
1544   }
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)
1549   {
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);
1553     return;
1554   }
1555   if (host_id == GST_context->host_id)
1556   {
1557     char *emsg;
1558
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;
1564     if (Z_OK !=
1565         (ret =
1566          uncompress ((Bytef *) config, (uLongf *) & dest_size,
1567                      (const Bytef *) &msg[1], (uLong) msize)))
1568     {
1569       GNUNET_break (0);         /* uncompression error */
1570       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1571       return;
1572     }
1573     if (config_size != dest_size)
1574     {
1575       GNUNET_break (0);         /* Uncompressed config size mismatch */
1576       GNUNET_free (config);
1577       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1578       return;
1579     }
1580     cfg = GNUNET_CONFIGURATION_create ();
1581     if (GNUNET_OK !=
1582         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1583     {
1584       GNUNET_break (0);         /* Configuration parsing error */
1585       GNUNET_free (config);
1586       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1587       return;
1588     }
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;
1595     peer->id = peer_id;
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 */ ,
1601                                        &emsg);
1602     if (NULL == peer->details.local.peer)
1603     {
1604       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1605       GNUNET_free (emsg);
1606       GNUNET_free (peer);
1607       GNUNET_break (0);
1608       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1609       return;
1610     }
1611     peer->details.local.is_running = GNUNET_NO;
1612     peer_list_add (peer);
1613     reply =
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);
1624     return;
1625   }
1626
1627   /* Forward peer create request */
1628   route = GST_find_dest_route (host_id);
1629   if (NULL == route)
1630   {
1631     GNUNET_break (0);
1632     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1633     return;
1634   }
1635
1636   peer = GNUNET_malloc (sizeof (struct Peer));
1637   peer->is_remote = GNUNET_YES;
1638   peer->id = peer_id;
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;
1647   fo_ctxt->opc =
1648       GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
1649                                              [route->dest]->controller,
1650                                              fo_ctxt->operation_id,
1651                                              &msg->header,
1652                                              peer_create_success_cb, fo_ctxt);
1653   fo_ctxt->timeout_task =
1654       GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
1655                                     fo_ctxt);
1656   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1657   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1658 }
1659
1660
1661 /**
1662  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1663  *
1664  * @param cls NULL
1665  * @param client identification of the client
1666  * @param message the actual message
1667  */
1668 static void
1669 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1670                      const struct GNUNET_MessageHeader *message)
1671 {
1672   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1673   struct ForwardedOperationContext *fopc;
1674   struct Peer *peer;
1675   uint32_t peer_id;
1676
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]))
1682   {
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);
1688     return;
1689   }
1690   peer = GST_peer_list[peer_id];
1691   if (GNUNET_YES == peer->is_remote)
1692   {
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;
1697     fopc->cls = peer;
1698     fopc->type = OP_PEER_DESTROY;
1699     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1700     fopc->opc =
1701         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1702                                                slave->controller,
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,
1707                                       fopc);
1708     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1709     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1710     return;
1711   }
1712   peer->destroy_flag = GNUNET_YES;
1713   if (0 == peer->reference_cnt)
1714     GST_destroy_peer (peer);
1715   else
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);
1720 }
1721
1722
1723 /**
1724  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1725  *
1726  * @param cls NULL
1727  * @param client identification of the client
1728  * @param message the actual message
1729  */
1730 static void
1731 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1732                    const struct GNUNET_MessageHeader *message)
1733 {
1734   const struct GNUNET_TESTBED_PeerStartMessage *msg;
1735   struct GNUNET_TESTBED_PeerEventMessage *reply;
1736   struct ForwardedOperationContext *fopc;
1737   struct Peer *peer;
1738   uint32_t peer_id;
1739
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]))
1743   {
1744     GNUNET_break (0);
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);
1748     return;
1749   }
1750   peer = GST_peer_list[peer_id];
1751   if (GNUNET_YES == peer->is_remote)
1752   {
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;
1758     fopc->opc =
1759         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1760                                                slave->controller,
1761                                                fopc->operation_id, &msg->header,
1762                                                &GST_forwarded_operation_reply_relay,
1763                                                fopc);
1764     fopc->timeout_task =
1765         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1766                                       fopc);
1767     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1768     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1769     return;
1770   }
1771   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1772   {
1773     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1774                                  "Failed to start");
1775     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1776     return;
1777   }
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);
1788 }
1789
1790
1791 /**
1792  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1793  *
1794  * @param cls NULL
1795  * @param client identification of the client
1796  * @param message the actual message
1797  */
1798 static void
1799 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1800                   const struct GNUNET_MessageHeader *message)
1801 {
1802   const struct GNUNET_TESTBED_PeerStopMessage *msg;
1803   struct GNUNET_TESTBED_PeerEventMessage *reply;
1804   struct ForwardedOperationContext *fopc;
1805   struct Peer *peer;
1806   uint32_t peer_id;
1807
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]))
1812   {
1813     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1814                                  "Peer not found");
1815     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1816     return;
1817   }
1818   peer = GST_peer_list[peer_id];
1819   if (GNUNET_YES == peer->is_remote)
1820   {
1821     LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
1822          peer_id);
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;
1828     fopc->opc =
1829         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1830                                                slave->controller,
1831                                                fopc->operation_id, &msg->header,
1832                                                &GST_forwarded_operation_reply_relay,
1833                                                fopc);
1834     fopc->timeout_task =
1835         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1836                                       fopc);
1837     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1838     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1839     return;
1840   }
1841   if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
1842   {
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);
1847     return;
1848   }
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);
1861 }
1862
1863
1864 /**
1865  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1866  *
1867  * @param cls NULL
1868  * @param client identification of the client
1869  * @param message the actual message
1870  */
1871 static void
1872 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1873                         const struct GNUNET_MessageHeader *message)
1874 {
1875   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1876   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1877   struct Peer *peer;
1878   char *config;
1879   char *xconfig;
1880   size_t c_size;
1881   size_t xc_size;
1882   uint32_t peer_id;
1883   uint16_t msize;
1884
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]))
1888   {
1889     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1890                                  "Peer not found");
1891     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1892     return;
1893   }
1894   peer = GST_peer_list[peer_id];
1895   if (GNUNET_YES == peer->is_remote)
1896   {
1897     struct ForwardedOperationContext *fopc;
1898
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;
1905     fopc->opc =
1906         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1907                                                slave->controller,
1908                                                fopc->operation_id, &msg->header,
1909                                                &GST_forwarded_operation_reply_relay,
1910                                                fopc);
1911     fopc->timeout_task =
1912         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1913                                       fopc);
1914     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1915     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1916     return;
1917   }
1918   LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
1919   config =
1920       GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
1921                                       &c_size);
1922   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1923   GNUNET_free (config);
1924   msize =
1925       xc_size +
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);
1938 }
1939
1940
1941 /**
1942  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1943  *
1944  * @param cls NULL
1945  * @param client identification of the client
1946  * @param message the actual message
1947  */
1948 static void
1949 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1950                          const struct GNUNET_MessageHeader *message)
1951 {
1952   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1953   struct Slave *slave;
1954   struct GNUNET_TESTBED_SlaveConfiguration *reply;
1955   const struct GNUNET_CONFIGURATION_Handle *cfg;
1956   char *config;
1957   char *xconfig;
1958   size_t config_size;
1959   size_t xconfig_size;
1960   size_t reply_size;
1961   uint64_t op_id;
1962   uint32_t slave_id;
1963
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]))
1968   {
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);
1972     return;
1973   }
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);
1977   xconfig_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);
1992 }
1993
1994 struct ManageServiceContext
1995 {
1996
1997   struct ManageServiceContext *next;
1998
1999   struct ManageServiceContext *prev;
2000
2001   struct GNUNET_ARM_Handle *ah;
2002
2003   struct Peer *peer;
2004
2005   struct GNUNET_SERVER_Client *client;
2006   
2007   uint64_t op_id;
2008   
2009   uint8_t start;
2010
2011   uint8_t expired;
2012   
2013 };
2014
2015 static struct ManageServiceContext *mctx_head;
2016
2017 static struct ManageServiceContext *mctx_tail;
2018
2019 static void
2020 cleanup_mctx (struct ManageServiceContext *mctx)
2021 {
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);
2031   GNUNET_free (mctx);
2032 }
2033
2034 static void
2035 free_mctxq ()
2036 {
2037   while (NULL != mctx_head)
2038     cleanup_mctx (mctx_head);
2039 }
2040
2041 static const char *
2042 arm_req_string (enum GNUNET_ARM_RequestStatus rs)
2043 {
2044   switch (rs)
2045   {
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");
2058   }
2059   return _("Unknown request status");
2060 }
2061
2062 static const char *
2063 arm_ret_string (enum GNUNET_ARM_Result result)
2064 {
2065   switch (result)
2066   {
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");
2087   }
2088   return _("%.s Unknown result code.");
2089 }
2090
2091 static void
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)
2095 {
2096   struct ManageServiceContext *mctx = cls;
2097   char *emsg;
2098
2099   emsg = NULL;
2100   if (GNUNET_YES == mctx->expired)
2101     return;
2102   if (GNUNET_ARM_REQUEST_SENT_OK != rs)
2103   {
2104     GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
2105                      mctx->peer->id, arm_req_string (rs));
2106     goto ret;
2107   }
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)) )
2114   {
2115     /* stopping a service failed */
2116     GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2117     goto ret;
2118   }
2119   /* service stopped successfully */
2120   goto ret;
2121
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)) )
2126   {
2127     /* starting a service failed */
2128     GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2129     goto ret;
2130   }
2131   /* service started successfully */
2132   
2133  ret:
2134   if (NULL != emsg)
2135   {
2136     LOG_DEBUG ("%s\n", emsg);
2137     GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
2138   }
2139   else
2140     send_operation_success_msg (mctx->client, mctx->op_id);
2141   GNUNET_free_non_null (emsg);
2142   cleanup_mctx (mctx);
2143 }
2144
2145 static void
2146 handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
2147                             const struct GNUNET_MessageHeader *message)
2148 {
2149   const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
2150   const char* service;
2151   struct Peer *peer;
2152   char *emsg;
2153   struct GNUNET_ARM_Handle *ah;
2154   struct ManageServiceContext *mctx;
2155   struct ForwardedOperationContext *fopc;
2156   uint64_t op_id;
2157   uint32_t peer_id;
2158   uint16_t msize;
2159   
2160
2161   msize = ntohs (message->size);
2162   if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
2163   {
2164     GNUNET_break_op (0);  
2165     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2166     return;
2167   }
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])
2172   {
2173     GNUNET_break_op (0);
2174     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2175     return;
2176   }
2177   if (1 < msg->start)
2178   {
2179     GNUNET_break_op (0);
2180     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2181     return;    
2182   }
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])))
2189   {
2190     GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
2191                      "with id: %u", peer_id);
2192     goto err_ret;
2193   }
2194   if (0 == strcasecmp ("arm", service))
2195   {
2196     emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service.  "
2197                           "Use peer start/stop for that");
2198     goto err_ret;
2199   }
2200   if (GNUNET_YES == peer->is_remote)
2201   {
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;
2206     fopc->cls = peer;
2207     fopc->type = OP_MANAGE_SERVICE;
2208     fopc->operation_id = op_id;
2209     fopc->opc =
2210         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
2211                                                slave->controller,
2212                                                fopc->operation_id, &msg->header,
2213                                                &GST_forwarded_operation_reply_relay,
2214                                                fopc);
2215     fopc->timeout_task =
2216         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
2217                                       fopc);
2218     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2219     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2220     return;
2221   }
2222   if ((0 != peer->reference_cnt)
2223       && ( (0 == strcasecmp ("core", service))
2224            || (0 == strcasecmp ("transport", service)) )  )
2225   {
2226     GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
2227                      "since it is required by existing operations",
2228                      service, peer_id);
2229     goto err_ret;
2230   }
2231   ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
2232   if (NULL == ah)
2233   {
2234     GNUNET_asprintf (&emsg,
2235                      "Cannot connect to ARM service of peer with id: %u",
2236                      peer_id);
2237     goto err_ret;
2238   }
2239   mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
2240   mctx->peer = peer;
2241   peer->reference_cnt++;
2242   mctx->op_id = op_id;
2243   mctx->ah = ah;
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,
2251                                       GST_timeout,
2252                                       service_manage_result_cb,
2253                                       mctx);
2254   else
2255     GNUNET_ARM_request_service_stop (mctx->ah, service,
2256                                      GST_timeout,
2257                                      service_manage_result_cb,
2258                                      mctx);
2259   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2260   return;
2261
2262  err_ret:
2263   LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
2264   GST_send_operation_fail_msg (client, op_id, emsg);
2265   GNUNET_free (emsg);
2266   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2267 }
2268
2269 /**
2270  * Clears the forwarded operations queue
2271  */
2272 static void
2273 clear_fopcq ()
2274 {
2275   struct ForwardedOperationContext *fopc;
2276   
2277   while (NULL != (fopc = fopcq_head))
2278   {
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);
2284     switch (fopc->type)
2285     {
2286     case OP_PEER_CREATE:
2287       GNUNET_free (fopc->cls);
2288       break;
2289     case OP_SHUTDOWN_PEERS:
2290       {
2291         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
2292         
2293         GNUNET_assert (0 < hc->nslaves);
2294         hc->nslaves--;
2295         if (0 == hc->nslaves)
2296           GNUNET_free (hc);
2297       }
2298       break;
2299     case OP_PEER_START:
2300     case OP_PEER_STOP:
2301     case OP_PEER_DESTROY:
2302     case OP_PEER_INFO:
2303     case OP_OVERLAY_CONNECT:
2304     case OP_LINK_CONTROLLERS:
2305     case OP_GET_SLAVE_CONFIG:
2306     case OP_MANAGE_SERVICE:
2307       break;
2308     case OP_FORWARDED:
2309       GNUNET_assert (0);
2310     };
2311     GNUNET_free (fopc);
2312   }
2313 }
2314
2315
2316 /**
2317  * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
2318  *
2319  * @param cls the ForwardedOperationContext
2320  * @param tc the scheduler task context
2321  */
2322 static void
2323 shutdown_peers_timeout_cb (void *cls,
2324                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2325 {
2326   struct ForwardedOperationContext *fo_ctxt = cls;
2327   struct HandlerContext_ShutdownPeers *hc;
2328
2329   fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2330   hc = fo_ctxt->cls;
2331   hc->timeout = GNUNET_YES;
2332   GNUNET_assert (0 < hc->nslaves);
2333   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);
2341 }
2342
2343
2344 /**
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
2347  * to the client
2348  *
2349  * @param cls ForwardedOperationContext
2350  * @param msg the message to relay
2351  */
2352 static void
2353 shutdown_peers_reply_cb (void *cls,
2354                          const struct GNUNET_MessageHeader *msg)
2355 {
2356   struct ForwardedOperationContext *fo_ctxt = cls;
2357   struct HandlerContext_ShutdownPeers *hc;
2358   
2359   hc = fo_ctxt->cls;
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);
2364   hc->nslaves--;
2365   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != 
2366       ntohs (msg->type))
2367     hc->timeout = GNUNET_YES;
2368   if (0 == hc->nslaves)
2369   {
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");
2373     else
2374       send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
2375   }
2376   GNUNET_SERVER_client_drop (fo_ctxt->client);
2377   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2378   GNUNET_free (fo_ctxt);
2379 }
2380
2381
2382 /**
2383  * Stops and destroys all peers
2384  */
2385 static void
2386 destroy_peers ()
2387 {
2388   struct Peer *peer;
2389   unsigned int id;
2390
2391   if (NULL == GST_peer_list)
2392     return;
2393   for (id = 0; id < GST_peer_list_size; id++)
2394   {
2395     peer = GST_peer_list[id];
2396     if (NULL == peer)
2397       continue;
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);
2406   }
2407   for (id = 0; id < GST_peer_list_size; id++)
2408   {
2409     peer = GST_peer_list[id];
2410     if (NULL == peer)
2411       continue;    
2412     if (GNUNET_NO == peer->is_remote)
2413     {
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);
2418     }
2419     GNUNET_free (peer);
2420   }
2421   GNUNET_free_non_null (GST_peer_list);
2422   GST_peer_list = NULL;
2423   GST_peer_list_size = 0;
2424 }
2425
2426
2427 /**
2428  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
2429  *
2430  * @param cls NULL
2431  * @param client identification of the client
2432  * @param message the actual message
2433  */
2434 static void
2435 handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
2436                        const struct GNUNET_MessageHeader *message)
2437 {
2438   const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2439   struct HandlerContext_ShutdownPeers *hc;
2440   struct Slave *slave;
2441   struct ForwardedOperationContext *fo_ctxt;
2442   uint64_t op_id;
2443   unsigned int cnt;
2444
2445   msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
2446   LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
2447     /* Stop and destroy all peers */
2448   free_mctxq ();
2449   GST_free_occq ();
2450   GST_free_roccq ();
2451   clear_fopcq ();
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++)
2458   {
2459     slave = GST_slave_list[cnt];
2460     if (NULL == slave)
2461       continue;
2462     if (NULL == slave->controller_proc) /* We didn't start the slave */
2463       continue;
2464     LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
2465     hc->nslaves++;
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;
2470     fo_ctxt->cls = hc;
2471     fo_ctxt->type = OP_SHUTDOWN_PEERS;
2472     fo_ctxt->opc =
2473         GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
2474                                                fo_ctxt->operation_id,
2475                                                &msg->header,
2476                                                shutdown_peers_reply_cb,
2477                                                fo_ctxt);
2478     fo_ctxt->timeout_task =
2479         GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
2480                                       fo_ctxt);
2481     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2482   }
2483   LOG_DEBUG ("Shutting down peers\n");
2484   destroy_peers ();
2485   if (0 == hc->nslaves)
2486   {
2487     send_operation_success_msg (client, op_id);
2488     GNUNET_free (hc);
2489   }
2490   GNUNET_SERVER_receive_done (client, GNUNET_OK);  
2491 }
2492
2493
2494 /**
2495  * Iterator over hash map entries.
2496  *
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
2501  *         iterate,
2502  *         GNUNET_NO if not.
2503  */
2504 static int
2505 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2506 {
2507   struct SharedService *ss = value;
2508
2509   GNUNET_assert (GNUNET_YES ==
2510                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2511   GNUNET_free (ss->name);
2512   GNUNET_free (ss);
2513   return GNUNET_YES;
2514 }
2515
2516
2517 /**
2518  * Iterator for freeing hash map entries in a slave's reghost_map
2519  *
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
2524  *         iterate,
2525  *         GNUNET_NO if not.
2526  */
2527 static int
2528 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
2529                        void *value)
2530 {
2531   struct Slave *slave = cls;
2532   struct RegisteredHostContext *rhc = value;
2533   struct ForwardedOverlayConnectContext *focc;
2534
2535   GNUNET_assert (GNUNET_YES ==
2536                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
2537                                                        value));
2538   while (NULL != (focc = rhc->focc_dll_head))
2539   {
2540     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
2541     GST_cleanup_focc (focc);
2542   }
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);
2548   return GNUNET_YES;
2549 }
2550
2551
2552 /**
2553  * Task to clean up and shutdown nicely
2554  *
2555  * @param cls NULL
2556  * @param tc the TaskContext from scheduler
2557  */
2558 static void
2559 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2560 {
2561   struct LCFContextQueue *lcfq;
2562   struct MessageQueue *mq_entry;
2563   uint32_t id;
2564
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,
2568                                                 NULL);
2569   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2570   /* cleanup any remaining forwarded operations */
2571   clear_fopcq ();
2572   if (NULL != lcfq_head)
2573   {
2574     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2575     {
2576       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2577       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2578     }
2579   }
2580   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2581   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2582   {
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);
2588     GNUNET_free (lcfq);
2589   }
2590   free_mctxq ();
2591   GST_free_occq ();
2592   GST_free_roccq ();
2593   /* Clear peer list */
2594   destroy_peers ();
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])
2608     {
2609       struct HostRegistration *hr_entry;
2610
2611       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
2612       {
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);
2616       }
2617       if (NULL != GST_slave_list[id]->rhandle)
2618         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
2619       (void)
2620           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
2621                                                  [id]->reghost_map,
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]);
2630     }
2631   GNUNET_free_non_null (GST_slave_list);
2632   if (NULL != GST_context)
2633   {
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);
2639     GST_context = NULL;
2640   }
2641   if (NULL != transmit_handle)
2642     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
2643   while (NULL != (mq_entry = mq_head))
2644   {
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);
2649   }
2650   GNUNET_free_non_null (hostname);
2651   GNUNET_CONFIGURATION_destroy (our_config);
2652   /* Free hello cache */
2653   GST_cache_clear ();
2654   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
2655   GST_opq_openfds = NULL;
2656 }
2657
2658
2659 /**
2660  * Callback for client disconnect
2661  *
2662  * @param cls NULL
2663  * @param client the client which has disconnected
2664  */
2665 static void
2666 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2667 {
2668   if (NULL == GST_context)
2669     return;
2670   if (client == GST_context->client)
2671   {
2672     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2673     /* should not be needed as we're terminated by failure to read
2674      * from stdin, but if stdin fails for some reason, this shouldn't
2675      * hurt for now --- might need to revise this later if we ever
2676      * decide that master connections might be temporarily down
2677      * for some reason */
2678     //GNUNET_SCHEDULER_shutdown ();
2679   }
2680 }
2681
2682
2683 /**
2684  * Testbed setup
2685  *
2686  * @param cls closure
2687  * @param server the initialized server
2688  * @param cfg configuration to use
2689  */
2690 static void
2691 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2692              const struct GNUNET_CONFIGURATION_Handle *cfg)
2693 {
2694   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2695     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2696     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
2697     {&handle_configure_shared_service, NULL,
2698      GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
2699     {&handle_link_controllers, NULL,
2700      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
2701     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
2702     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
2703      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2704     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
2705      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2706     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
2707      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2708     {&handle_peer_get_config, NULL,
2709      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
2710      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2711     {&GST_handle_overlay_connect, NULL,
2712      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
2713      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2714     {&GST_handle_remote_overlay_connect, NULL,
2715      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
2716     {&handle_manage_peer_service, NULL,
2717      GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
2718     {&handle_slave_get_config, NULL,
2719      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
2720      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2721     {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
2722      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
2723     {NULL}
2724   };
2725   char *logfile;
2726   unsigned long long num;
2727
2728   if (GNUNET_OK ==
2729       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
2730                                                &logfile))
2731   {
2732     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
2733     GNUNET_free (logfile);
2734   }
2735   GNUNET_assert (GNUNET_OK ==
2736                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2737                                                         "CACHE_SIZE", &num));
2738   GST_cache_init ((unsigned int) num);
2739   GNUNET_assert (GNUNET_OK ==
2740                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2741                                                         "MAX_OPEN_FDS", &num));
2742   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
2743   GNUNET_assert (GNUNET_OK ==
2744                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
2745                                                       "OPERATION_TIMEOUT",
2746                                                       (struct
2747                                                        GNUNET_TIME_Relative *)
2748                                                       &GST_timeout));
2749   GNUNET_assert (GNUNET_OK ==
2750                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
2751                                                         "HOSTNAME", &hostname));  
2752   our_config = GNUNET_CONFIGURATION_dup (cfg);
2753   GNUNET_SERVER_add_handlers (server, message_handlers);
2754   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2755   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
2756   shutdown_task_id =
2757       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
2758                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
2759                                                   &shutdown_task, NULL);
2760   LOG_DEBUG ("Testbed startup complete\n");
2761   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
2762 }
2763
2764
2765 /**
2766  * The starting point of execution
2767  */
2768 int
2769 main (int argc, char *const *argv)
2770 {
2771   //sleep (15);                 /* Debugging */
2772   return (GNUNET_OK ==
2773           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2774                               &testbed_run, NULL)) ? 0 : 1;
2775 }
2776
2777 /* end of gnunet-service-testbed.c */