- fixes
[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
29 #include <zlib.h>
30
31
32 /***********/
33 /* Globals */
34 /***********/
35
36 /**
37  * Our configuration
38  */
39 struct GNUNET_CONFIGURATION_Handle *our_config;
40
41 /**
42  * The master context; generated with the first INIT message
43  */
44 struct Context *GST_context;
45
46 /**
47  * A list of directly linked neighbours
48  */
49 struct Slave **GST_slave_list;
50
51 /**
52  * A list of peers we know about
53  */
54 struct Peer **GST_peer_list;
55
56 /**
57  * Array of hosts
58  */
59 struct GNUNET_TESTBED_Host **GST_host_list;
60
61 /**
62  * DLL head for forwarded operation contexts
63  */
64 struct ForwardedOperationContext *fopcq_head;
65
66 /**
67  * DLL tail for forwarded operation contexts
68  */
69 struct ForwardedOperationContext *fopcq_tail;
70
71 /**
72  * Operation queue for open file descriptors
73  */
74 struct OperationQueue *GST_opq_openfds;
75
76 /**
77  * Timeout for operations which may take some time
78  */
79 const struct GNUNET_TIME_Relative GST_timeout;
80
81 /**
82  * The size of the host list
83  */
84 unsigned int GST_host_list_size;
85
86 /**
87  * The size of directly linked neighbours list
88  */
89 unsigned int GST_slave_list_size;
90
91 /**
92  * The size of the peer list
93  */
94 unsigned int GST_peer_list_size;
95
96
97 /***********************************/
98 /* Local definitions and variables */
99 /***********************************/
100
101 /**
102  * The message queue for sending messages to clients
103  */
104 struct MessageQueue
105 {
106   /**
107    * The message to be sent
108    */
109   struct GNUNET_MessageHeader *msg;
110
111   /**
112    * The client to send the message to
113    */
114   struct GNUNET_SERVER_Client *client;
115
116   /**
117    * next pointer for DLL
118    */
119   struct MessageQueue *next;
120
121   /**
122    * prev pointer for DLL
123    */
124   struct MessageQueue *prev;
125 };
126
127 /**
128  * Our hostname; we give this to all the peers we start
129  */
130 static char *hostname;
131
132 /**
133  * Current Transmit Handle; NULL if no notify transmit exists currently
134  */
135 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
136
137 /**
138  * The head for the LCF queue
139  */
140 static struct LCFContextQueue *lcfq_head;
141
142 /**
143  * The tail for the LCF queue
144  */
145 static struct LCFContextQueue *lcfq_tail;
146
147 /**
148  * The message queue head
149  */
150 static struct MessageQueue *mq_head;
151
152 /**
153  * The message queue tail
154  */
155 static struct MessageQueue *mq_tail;
156
157 /**
158  * The hashmap of shared services
159  */
160 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
161
162 /**
163  * A list of routes
164  */
165 static struct Route **route_list;
166
167 /**
168  * The event mask for the events we listen from sub-controllers
169  */
170 static uint64_t event_mask;
171
172 /**
173  * The size of the route list
174  */
175 static unsigned int route_list_size;
176
177 /**
178  * The lcf_task handle
179  */
180 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
181
182 /**
183  * The shutdown task handle
184  */
185 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
186
187
188 /**
189  * Function called to notify a client about the connection begin ready to queue
190  * more data.  "buf" will be NULL and "size" zero if the connection was closed
191  * for writing in the meantime.
192  *
193  * @param cls NULL
194  * @param size number of bytes available in buf
195  * @param buf where the callee should write the message
196  * @return number of bytes written to buf
197  */
198 static size_t
199 transmit_ready_notify (void *cls, size_t size, void *buf)
200 {
201   struct MessageQueue *mq_entry;
202
203   transmit_handle = NULL;
204   mq_entry = mq_head;
205   GNUNET_assert (NULL != mq_entry);
206   if (0 == size)
207     return 0;
208   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
209   size = ntohs (mq_entry->msg->size);
210   memcpy (buf, mq_entry->msg, size);
211   GNUNET_free (mq_entry->msg);
212   GNUNET_SERVER_client_drop (mq_entry->client);
213   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
214   GNUNET_free (mq_entry);
215   mq_entry = mq_head;
216   if (NULL != mq_entry)
217     transmit_handle =
218         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
219                                              ntohs (mq_entry->msg->size),
220                                              GNUNET_TIME_UNIT_FOREVER_REL,
221                                              &transmit_ready_notify, NULL);
222   return size;
223 }
224
225
226 /**
227  * Queues a message in send queue for sending to the service
228  *
229  * @param client the client to whom the queued message has to be sent
230  * @param msg the message to queue
231  */
232 void
233 GST_queue_message (struct GNUNET_SERVER_Client *client,
234                    struct GNUNET_MessageHeader *msg)
235 {
236   struct MessageQueue *mq_entry;
237   uint16_t type;
238   uint16_t size;
239
240   type = ntohs (msg->type);
241   size = ntohs (msg->size);
242   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
243                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
244   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
245   mq_entry->msg = msg;
246   mq_entry->client = client;
247   GNUNET_SERVER_client_keep (client);
248   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
249              ntohs (msg->size));
250   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
251   if (NULL == transmit_handle)
252     transmit_handle =
253         GNUNET_SERVER_notify_transmit_ready (client, size,
254                                              GNUNET_TIME_UNIT_FOREVER_REL,
255                                              &transmit_ready_notify, NULL);
256 }
257
258
259 /**
260  * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
261  * several times we call it only once. The array is also made to grow in steps
262  * of LIST_GROW_STEP.
263  *
264  * @param ptr the array pointer to grow
265  * @param size the size of array
266  * @param accommodate_size the size which the array has to accommdate; after
267  *          this call the array will be big enough to accommdate sizes upto
268  *          accommodate_size
269  */
270 #define array_grow_large_enough(ptr, size, accommodate_size) \
271   do                                                                    \
272   {                                                                     \
273     unsigned int growth_size;                                           \
274     GNUNET_assert (size <= accommodate_size);                            \
275     growth_size = size;                                                 \
276     while (growth_size <= accommodate_size)                             \
277       growth_size += LIST_GROW_STEP;                                    \
278     GNUNET_array_grow (ptr, size, growth_size);                         \
279     GNUNET_assert (size > accommodate_size);                            \
280   } while (0)
281
282
283 /**
284  * Function to add a host to the current list of known hosts
285  *
286  * @param host the host to add
287  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
288  *           already in use
289  */
290 static int
291 host_list_add (struct GNUNET_TESTBED_Host *host)
292 {
293   uint32_t host_id;
294
295   host_id = GNUNET_TESTBED_host_get_id_ (host);
296   if (GST_host_list_size <= host_id)
297     array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
298   if (NULL != GST_host_list[host_id])
299   {
300     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
301     return GNUNET_SYSERR;
302   }
303   GST_host_list[host_id] = host;
304   return GNUNET_OK;
305 }
306
307
308 /**
309  * Adds a route to the route list
310  *
311  * @param route the route to add
312  */
313 static void
314 route_list_add (struct Route *route)
315 {
316   if (route->dest >= route_list_size)
317     array_grow_large_enough (route_list, route_list_size, route->dest);
318   GNUNET_assert (NULL == route_list[route->dest]);
319   route_list[route->dest] = route;
320 }
321
322
323 /**
324  * Adds a slave to the slave array
325  *
326  * @param slave the slave controller to add
327  */
328 static void
329 slave_list_add (struct Slave *slave)
330 {
331   if (slave->host_id >= GST_slave_list_size)
332     array_grow_large_enough (GST_slave_list, GST_slave_list_size,
333                              slave->host_id);
334   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
335   GST_slave_list[slave->host_id] = slave;
336 }
337
338
339 /**
340  * Adds a peer to the peer array
341  *
342  * @param peer the peer to add
343  */
344 static void
345 peer_list_add (struct Peer *peer)
346 {
347   if (peer->id >= GST_peer_list_size)
348     array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
349   GNUNET_assert (NULL == GST_peer_list[peer->id]);
350   GST_peer_list[peer->id] = peer;
351 }
352
353
354 /**
355  * Removes a the give peer from the peer array
356  *
357  * @param peer the peer to be removed
358  */
359 static void
360 peer_list_remove (struct Peer *peer)
361 {
362   unsigned int orig_size;
363   uint32_t id;
364
365   GST_peer_list[peer->id] = NULL;
366   orig_size = GST_peer_list_size;
367   while (GST_peer_list_size >= LIST_GROW_STEP)
368   {
369     for (id = GST_peer_list_size - 1;
370          (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
371          id--)
372       if (NULL != GST_peer_list[id])
373         break;
374     if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
375       break;
376     GST_peer_list_size -= LIST_GROW_STEP;
377   }
378   if (orig_size == GST_peer_list_size)
379     return;
380   GST_peer_list =
381       GNUNET_realloc (GST_peer_list,
382                       sizeof (struct Peer *) * GST_peer_list_size);
383 }
384
385
386 /**
387  * Finds the route with directly connected host as destination through which
388  * the destination host can be reached
389  *
390  * @param host_id the id of the destination host
391  * @return the route with directly connected destination host; NULL if no route
392  *           is found
393  */
394 struct Route *
395 GST_find_dest_route (uint32_t host_id)
396 {
397   struct Route *route;
398
399   if (route_list_size <= host_id)
400     return NULL;
401   while (NULL != (route = route_list[host_id]))
402   {
403     if (route->thru == GST_context->host_id)
404       break;
405     host_id = route->thru;
406   }
407   return route;
408 }
409
410
411 /**
412  * Routes message to a host given its host_id
413  *
414  * @param host_id the id of the destination host
415  * @param msg the message to be routed
416  */
417 static void
418 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
419 {
420   GNUNET_break (0);
421 }
422
423
424 /**
425  * Send operation failure message to client
426  *
427  * @param client the client to which the failure message has to be sent to
428  * @param operation_id the id of the failed operation
429  * @param emsg the error message; can be NULL
430  */
431 void
432 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
433                              uint64_t operation_id, const char *emsg)
434 {
435   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
436   uint16_t msize;
437   uint16_t emsg_len;
438
439   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
440   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
441   msize += emsg_len;
442   msg = GNUNET_malloc (msize);
443   msg->header.size = htons (msize);
444   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
445   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
446   msg->operation_id = GNUNET_htonll (operation_id);
447   if (0 != emsg_len)
448     memcpy (&msg[1], emsg, emsg_len);
449   GST_queue_message (client, &msg->header);
450 }
451
452
453 /**
454  * Function to send generic operation success message to given client
455  *
456  * @param client the client to send the message to
457  * @param operation_id the id of the operation which was successful
458  */
459 static void
460 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
461                             uint64_t operation_id)
462 {
463   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
464   uint16_t msize;
465
466   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
467   msg = GNUNET_malloc (msize);
468   msg->header.size = htons (msize);
469   msg->header.type =
470       htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
471   msg->operation_id = GNUNET_htonll (operation_id);
472   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
473   GST_queue_message (client, &msg->header);
474 }
475
476
477 /**
478  * Function to send a failure reponse for controller link operation
479  *
480  * @param client the client to send the message to
481  * @param operation_id the operation ID of the controller link request
482  * @param cfg the configuration with which the delegated controller is started.
483  *          Can be NULL if the delegated controller is not started but just
484  *          linked to.
485  * @param emsg set to an error message explaining why the controller link
486  *          failed.  Setting this to NULL signifies success.  !This should be
487  *          NULL if cfg is set!
488  */
489 static void
490 send_controller_link_response (struct GNUNET_SERVER_Client *client,
491                                uint64_t operation_id,
492                                const struct GNUNET_CONFIGURATION_Handle
493                                *cfg,
494                                const char *emsg)
495 {
496   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
497   char *xconfig;
498   size_t config_size;
499   size_t xconfig_size;  
500   uint16_t msize;
501
502   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
503   xconfig = NULL;
504   xconfig_size = 0;
505   config_size = 0;
506   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
507   if (NULL != cfg)
508   {
509     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
510                                             &config_size,
511                                             &xconfig_size);
512     msize += xconfig_size;
513   }
514   if (NULL != emsg)
515     msize += strlen (emsg);
516   msg = GNUNET_malloc (msize);
517   msg->header.type = htons
518       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
519   msg->header.size = htons (msize);
520   if (NULL == emsg)
521     msg->success = htons (GNUNET_YES);
522   msg->operation_id = GNUNET_htonll (operation_id);
523   msg->config_size = htons ((uint16_t) config_size);
524   if (NULL != xconfig)
525     memcpy (&msg[1], xconfig, xconfig_size);
526   if (NULL != emsg)
527     memcpy (&msg[1], emsg, strlen (emsg));
528   GST_queue_message (client, &msg->header);
529 }
530
531 /**
532  * Callback which will be called after a host registration succeeded or failed
533  *
534  * @param cls the handle to the slave at which the registration is completed
535  * @param emsg the error message; NULL if host registration is successful
536  */
537 static void
538 hr_completion (void *cls, const char *emsg);
539
540
541 /**
542  * Attempts to register the next host in the host registration queue
543  *
544  * @param slave the slave controller whose host registration queue is checked
545  *          for host registrations
546  */
547 static void
548 register_next_host (struct Slave *slave)
549 {
550   struct HostRegistration *hr;
551
552   hr = slave->hr_dll_head;
553   GNUNET_assert (NULL != hr);
554   GNUNET_assert (NULL == slave->rhandle);
555   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
556        GNUNET_TESTBED_host_get_id_ (hr->host),
557        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
558   slave->rhandle =
559       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
560                                     slave);
561 }
562
563
564 /**
565  * Callback which will be called to after a host registration succeeded or failed
566  *
567  * @param cls the handle to the slave at which the registration is completed
568  * @param emsg the error message; NULL if host registration is successful
569  */
570 static void
571 hr_completion (void *cls, const char *emsg)
572 {
573   struct Slave *slave = cls;
574   struct HostRegistration *hr;
575
576   slave->rhandle = NULL;
577   hr = slave->hr_dll_head;
578   GNUNET_assert (NULL != hr);
579   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
580        GNUNET_TESTBED_host_get_id_ (hr->host),
581        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
582   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
583   if (NULL != hr->cb)
584     hr->cb (hr->cb_cls, emsg);
585   GNUNET_free (hr);
586   if (NULL != slave->hr_dll_head)
587     register_next_host (slave);
588 }
589
590
591 /**
592  * Adds a host registration's request to a slave's registration queue
593  *
594  * @param slave the slave controller at which the given host has to be
595  *          registered
596  * @param cb the host registration completion callback
597  * @param cb_cls the closure for the host registration completion callback
598  * @param host the host which has to be registered
599  */
600 void
601 GST_queue_host_registration (struct Slave *slave,
602                              GNUNET_TESTBED_HostRegistrationCompletion cb,
603                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
604 {
605   struct HostRegistration *hr;
606   int call_register;
607
608   LOG (GNUNET_ERROR_TYPE_DEBUG,
609        "Queueing host registration for host %u at %u\n",
610        GNUNET_TESTBED_host_get_id_ (host),
611        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
612   hr = GNUNET_malloc (sizeof (struct HostRegistration));
613   hr->cb = cb;
614   hr->cb_cls = cb_cls;
615   hr->host = host;
616   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
617   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
618   if (GNUNET_YES == call_register)
619     register_next_host (slave);
620 }
621
622
623 /**
624  * The  Link Controller forwarding task
625  *
626  * @param cls the LCFContext
627  * @param tc the Task context from scheduler
628  */
629 static void
630 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
631
632
633 /**
634  * Completion callback for host registrations while forwarding Link Controller messages
635  *
636  * @param cls the LCFContext
637  * @param emsg the error message; NULL if host registration is successful
638  */
639 static void
640 lcf_proc_cc (void *cls, const char *emsg)
641 {
642   struct LCFContext *lcf = cls;
643
644   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
645   switch (lcf->state)
646   {
647   case INIT:
648     if (NULL != emsg)
649       goto registration_error;
650     lcf->state = DELEGATED_HOST_REGISTERED;
651     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
652     break;
653   case DELEGATED_HOST_REGISTERED:
654     if (NULL != emsg)
655       goto registration_error;
656     lcf->state = SLAVE_HOST_REGISTERED;
657     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
658     break;
659   default:
660     GNUNET_assert (0);          /* Shouldn't reach here */
661   }
662   return;
663
664 registration_error:
665   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
666        emsg);
667   lcf->state = FINISHED;
668   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
669 }
670
671
672 /**
673  * Callback to relay the reply msg of a forwarded operation back to the client
674  *
675  * @param cls ForwardedOperationContext
676  * @param msg the message to relay
677  */
678 void
679 GST_forwarded_operation_reply_relay (void *cls,
680                                      const struct GNUNET_MessageHeader *msg)
681 {
682   struct ForwardedOperationContext *fopc = cls;
683   struct GNUNET_MessageHeader *dup_msg;
684   uint16_t msize;
685
686   msize = ntohs (msg->size);
687   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
688              msize);
689   dup_msg = GNUNET_copy_message (msg);
690   GST_queue_message (fopc->client, dup_msg);
691   GNUNET_SERVER_client_drop (fopc->client);
692   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
693   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
694   GNUNET_free (fopc);
695 }
696
697
698 /**
699  * Task to free resources when forwarded operation has been timedout
700  *
701  * @param cls the ForwardedOperationContext
702  * @param tc the task context from scheduler
703  */
704 void
705 GST_forwarded_operation_timeout (void *cls,
706                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
707 {
708   struct ForwardedOperationContext *fopc = cls;
709
710   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
711   LOG (GNUNET_ERROR_TYPE_DEBUG, "A forwarded operation has timed out\n");
712   GST_send_operation_fail_msg (fopc->client, fopc->operation_id,
713                                "A forwarded operation has timed out");
714   GNUNET_SERVER_client_drop (fopc->client);
715   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
716   GNUNET_free (fopc);
717 }
718
719
720 /**
721  * The  Link Controller forwarding task
722  *
723  * @param cls the LCFContext
724  * @param tc the Task context from scheduler
725  */
726 static void
727 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
728
729
730 /**
731  * Task to free resources when forwarded link controllers has been timedout
732  *
733  * @param cls the LCFContext
734  * @param tc the task context from scheduler
735  */
736 static void
737 lcf_forwarded_operation_timeout (void *cls,
738                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
739 {
740   struct LCFContext *lcf = cls;
741
742   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
743   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
744   LOG (GNUNET_ERROR_TYPE_WARNING,
745        "A forwarded controller link operation has timed out\n");
746   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
747                                  "A forwarded controller link operation has "
748                                  "timed out\n");
749   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
750   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
751 }
752
753
754 /**
755  * The  Link Controller forwarding task
756  *
757  * @param cls the LCFContext
758  * @param tc the Task context from scheduler
759  */
760 static void
761 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
762 {
763   struct LCFContext *lcf = cls;
764   struct LCFContextQueue *lcfq;
765
766   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
767   switch (lcf->state)
768   {
769   case INIT:
770     if (GNUNET_NO ==
771         GNUNET_TESTBED_is_host_registered_ (GST_host_list
772                                             [lcf->delegated_host_id],
773                                             lcf->gateway->controller))
774     {
775       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
776                                    GST_host_list[lcf->delegated_host_id]);
777     }
778     else
779     {
780       lcf->state = DELEGATED_HOST_REGISTERED;
781       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
782     }
783     break;
784   case DELEGATED_HOST_REGISTERED:
785     if (GNUNET_NO ==
786         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
787                                             lcf->gateway->controller))
788     {
789       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
790                                    GST_host_list[lcf->slave_host_id]);
791     }
792     else
793     {
794       lcf->state = SLAVE_HOST_REGISTERED;
795       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
796     }
797     break;
798   case SLAVE_HOST_REGISTERED:
799     lcf->op = GNUNET_TESTBED_controller_link (lcf,
800                                               lcf->gateway->controller,
801                                               GST_host_list[lcf->delegated_host_id],
802                                               GST_host_list[lcf->slave_host_id],
803                                               NULL,
804                                               lcf->is_subordinate);
805     lcf->timeout_task =
806         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
807                                       lcf);
808     lcf->state = FINISHED;
809     break;
810   case FINISHED:
811     lcfq = lcfq_head;
812     GNUNET_assert (lcfq->lcf == lcf);
813     GNUNET_assert (NULL != lcf->cfg);
814     GNUNET_CONFIGURATION_destroy (lcf->cfg);
815     GNUNET_SERVER_client_drop (lcf->client);
816     GNUNET_TESTBED_operation_done (lcf->op);
817     GNUNET_free (lcf);
818     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
819     GNUNET_free (lcfq);
820     if (NULL != lcfq_head)
821       lcf_proc_task_id =
822           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
823   }
824 }
825
826
827 /**
828  * Callback for event from slave controllers
829  *
830  * @param cls struct Slave *
831  * @param event information about the event
832  */
833 static void
834 slave_event_callback (void *cls,
835                       const struct GNUNET_TESTBED_EventInformation *event)
836 {
837   struct RegisteredHostContext *rhc;
838   struct LCFContext *lcf;
839   struct GNUNET_CONFIGURATION_Handle *cfg;
840   struct GNUNET_TESTBED_Operation *old_op;
841
842   /* We currently only get here when working on RegisteredHostContexts and
843      LCFContexts */
844   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
845   rhc = event->details.operation_finished.op_cls;
846   if (CLOSURE_TYPE_RHC == rhc->type)
847   {
848     GNUNET_assert (rhc->sub_op == event->details.operation_finished.operation);
849     switch (rhc->state)
850     {
851     case RHC_GET_CFG:
852       cfg = event->details.operation_finished.generic;
853       old_op = rhc->sub_op;
854       rhc->state = RHC_LINK;
855       rhc->sub_op =
856           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
857                                           rhc->reg_host, rhc->host, cfg,
858                                           GNUNET_NO);
859       GNUNET_TESTBED_operation_done (old_op);
860       break;
861     case RHC_LINK:
862       LOG_DEBUG ("OL: Linking controllers successfull\n");
863       GNUNET_TESTBED_operation_done (rhc->sub_op);
864       rhc->sub_op = NULL;
865       rhc->state = RHC_OL_CONNECT;
866       GST_process_next_focc (rhc);
867       break;
868     default:
869       GNUNET_assert (0);
870     }
871     return;
872   }
873   lcf = event->details.operation_finished.op_cls;
874   if (CLOSURE_TYPE_LCF == lcf->type)
875   {    
876     GNUNET_assert (lcf->op == event->details.operation_finished.operation);
877     GNUNET_assert (FINISHED == lcf->state);
878     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
879     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
880     if (NULL == event->details.operation_finished.emsg)
881       send_controller_link_response (lcf->client, lcf->operation_id,
882                                      GNUNET_TESTBED_host_get_cfg_ 
883                                      (GST_host_list[lcf->delegated_host_id]),
884                                      NULL);
885     else
886       send_controller_link_response (lcf->client, lcf->operation_id,
887                                      NULL,
888                                      event->details.operation_finished.emsg);
889     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
890     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
891     return;
892   }
893   GNUNET_assert (0);
894 }
895
896
897 /**
898  * Callback to signal successfull startup of the controller process
899  *
900  * @param cls the handle to the slave whose status is to be found here
901  * @param cfg the configuration with which the controller has been started;
902  *          NULL if status is not GNUNET_OK
903  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
904  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
905  */
906 static void
907 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
908                        int status)
909 {
910   struct Slave *slave = cls;
911   struct LinkControllersContext *lcc;
912
913   lcc = slave->lcc;
914   if (GNUNET_SYSERR == status)
915   {
916     slave->controller_proc = NULL;
917     GST_slave_list[slave->host_id] = NULL;
918     GNUNET_free (slave);
919     slave = NULL;
920     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
921     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
922     goto clean_lcc;
923   }
924   slave->controller =
925       GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
926                                          event_mask, &slave_event_callback,
927                                          slave);
928   if (NULL != slave->controller)
929   {
930     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
931   }
932   else
933   {
934     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
935                                    "Could not connect to delegated controller");
936     GNUNET_TESTBED_controller_stop (slave->controller_proc);
937     GST_slave_list[slave->host_id] = NULL;
938     GNUNET_free (slave);
939     slave = NULL;
940   }
941
942 clean_lcc:
943   if (NULL != lcc)
944   {
945     if (NULL != lcc->client)
946     {
947       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
948       GNUNET_SERVER_client_drop (lcc->client);
949       lcc->client = NULL;
950     }
951     GNUNET_free (lcc);
952   }
953   if (NULL != slave)
954     slave->lcc = NULL;
955 }
956
957
958 /**
959  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
960  *
961  * @param cls NULL
962  * @param client identification of the client
963  * @param message the actual message
964  */
965 static void
966 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
967              const struct GNUNET_MessageHeader *message)
968 {
969   const struct GNUNET_TESTBED_InitMessage *msg;
970   struct GNUNET_TESTBED_Host *host;
971   const char *controller_hostname;
972   uint16_t msize;
973
974   if (NULL != GST_context)
975   {
976     LOG_DEBUG ("We are being connected to laterally\n");
977     GNUNET_SERVER_receive_done (client, GNUNET_OK);
978     return;
979   }
980   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
981   msize = ntohs (message->size);
982   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
983   {
984     GNUNET_break (0);
985     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
986     return;
987   }
988   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
989   controller_hostname = (const char *) &msg[1];
990   if ('\0' != controller_hostname[msize - 1])
991   {
992     GNUNET_break (0);
993     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
994     return;
995   }
996   GST_context = GNUNET_malloc (sizeof (struct Context));
997   GNUNET_SERVER_client_keep (client);
998   GST_context->client = client;
999   GST_context->host_id = ntohl (msg->host_id);
1000   GST_context->master_ip = GNUNET_strdup (controller_hostname);
1001   LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
1002   GST_context->system =
1003       GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
1004                                     hostname);
1005   host =
1006       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
1007                                           GST_context->master_ip, NULL,
1008                                           our_config, 0);
1009   host_list_add (host);
1010   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
1011   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1012 }
1013
1014
1015 /**
1016  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1017  *
1018  * @param cls NULL
1019  * @param client identification of the client
1020  * @param message the actual message
1021  */
1022 static void
1023 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1024                  const struct GNUNET_MessageHeader *message)
1025 {
1026   struct GNUNET_TESTBED_Host *host;
1027   const struct GNUNET_TESTBED_AddHostMessage *msg;
1028   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1029   struct GNUNET_CONFIGURATION_Handle *host_cfg;
1030   char *username;
1031   char *hostname;
1032   char *emsg;
1033   const void *ptr;
1034   uint32_t host_id;
1035   uint16_t username_length;
1036   uint16_t hostname_length;
1037   uint16_t reply_size;
1038   uint16_t msize;
1039
1040   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1041   msize = ntohs (msg->header.size);
1042   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
1043   {
1044     GNUNET_break_op (0);
1045     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1046     return;
1047   }
1048   username_length = ntohs (msg->username_length);
1049   hostname_length = ntohs (msg->hostname_length);
1050   /* msg must contain hostname */
1051   if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
1052                  username_length))
1053       || (0 == hostname_length))
1054   {
1055     GNUNET_break_op (0);
1056     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1057     return;
1058   }
1059   /* msg must contain configuration */
1060   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1061                 username_length + hostname_length))
1062   {
1063     GNUNET_break_op (0);
1064     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1065     return;
1066   }
1067   username = NULL;
1068   hostname = NULL;
1069   ptr = &msg[1];
1070   if (0 != username_length)
1071   {
1072     username = GNUNET_malloc (username_length + 1);
1073     strncpy (username, ptr, username_length);
1074     ptr += username_length;
1075   }
1076   hostname = GNUNET_malloc (hostname_length + 1);
1077   strncpy (hostname, ptr, hostname_length);
1078   ptr += hostname_length;
1079   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
1080   {
1081     GNUNET_free_non_null (username);
1082     GNUNET_free_non_null (hostname);
1083     GNUNET_break_op (0);
1084     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1085     return;
1086   }
1087   host_id = ntohl (msg->host_id);
1088   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
1089   LOG_DEBUG ("-------host id: %u\n", host_id);
1090   LOG_DEBUG ("-------hostname: %s\n", hostname);
1091   if (NULL != username)
1092     LOG_DEBUG ("-------username: %s\n", username);
1093   else
1094     LOG_DEBUG ("-------username: <not given>\n");
1095   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1096   host =
1097       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1098                                           host_cfg, ntohs (msg->ssh_port));
1099   GNUNET_free_non_null (username);
1100   GNUNET_free (hostname);
1101   GNUNET_CONFIGURATION_destroy (host_cfg);
1102   if (NULL == host)
1103   {
1104     GNUNET_break_op (0);
1105     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1106     return;
1107   }
1108   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1109   if (GNUNET_OK != host_list_add (host))
1110   {
1111     /* We are unable to add a host */
1112     emsg = "A host exists with given host-id";
1113     LOG_DEBUG ("%s: %u", emsg, host_id);
1114     GNUNET_TESTBED_host_destroy (host);
1115     reply_size += strlen (emsg) + 1;
1116     reply = GNUNET_malloc (reply_size);
1117     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1118   }
1119   else
1120   {
1121     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
1122     reply = GNUNET_malloc (reply_size);
1123   }
1124   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
1125   reply->header.size = htons (reply_size);
1126   reply->host_id = htonl (host_id);
1127   GST_queue_message (client, &reply->header);
1128   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1129 }
1130
1131
1132 /**
1133  * Iterator over hash map entries.
1134  *
1135  * @param cls closure
1136  * @param key current key code
1137  * @param value value in the hash map
1138  * @return GNUNET_YES if we should continue to
1139  *         iterate,
1140  *         GNUNET_NO if not.
1141  */
1142 int
1143 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1144 {
1145   struct SharedService *queried_ss = cls;
1146   struct SharedService *ss = value;
1147
1148   if (0 == strcmp (ss->name, queried_ss->name))
1149     return GNUNET_NO;
1150   else
1151     return GNUNET_YES;
1152 }
1153
1154
1155 /**
1156  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1157  *
1158  * @param cls NULL
1159  * @param client identification of the client
1160  * @param message the actual message
1161  */
1162 static void
1163 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1164                                  const struct GNUNET_MessageHeader *message)
1165 {
1166   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1167   struct SharedService *ss;
1168   char *service_name;
1169   struct GNUNET_HashCode hash;
1170   uint16_t msg_size;
1171   uint16_t service_name_size;
1172
1173   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1174   msg_size = ntohs (message->size);
1175   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1176   {
1177     GNUNET_break (0);
1178     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1179     return;
1180   }
1181   service_name_size =
1182       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1183   service_name = (char *) &msg[1];
1184   if ('\0' != service_name[service_name_size - 1])
1185   {
1186     GNUNET_break (0);
1187     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1188     return;
1189   }
1190   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1191              service_name, ntohl (msg->num_peers));
1192   if (ntohl (msg->host_id) != GST_context->host_id)
1193   {
1194     route_message (ntohl (msg->host_id), message);
1195     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1196     return;
1197   }
1198   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1199   ss = GNUNET_malloc (sizeof (struct SharedService));
1200   ss->name = strdup (service_name);
1201   ss->num_shared = ntohl (msg->num_peers);
1202   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1203   if (GNUNET_SYSERR ==
1204       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1205                                                   &ss_exists_iterator, ss))
1206   {
1207     LOG (GNUNET_ERROR_TYPE_WARNING,
1208          "Service %s already configured as a shared service. "
1209          "Ignoring service sharing request \n", ss->name);
1210     GNUNET_free (ss->name);
1211     GNUNET_free (ss);
1212     return;
1213   }
1214   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1215                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1216 }
1217
1218
1219 /**
1220  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1221  *
1222  * @param cls NULL
1223  * @param client identification of the client
1224  * @param message the actual message
1225  */
1226 static void
1227 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1228                          const struct GNUNET_MessageHeader *message)
1229 {
1230   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1231   struct GNUNET_CONFIGURATION_Handle *cfg;
1232   struct LCFContextQueue *lcfq;
1233   struct Route *route;
1234   struct Route *new_route;
1235   uint32_t delegated_host_id;
1236   uint32_t slave_host_id;
1237   uint16_t msize;
1238
1239   if (NULL == GST_context)
1240   {
1241     GNUNET_break (0);
1242     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1243     return;
1244   }
1245   msize = ntohs (message->size);
1246   if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
1247   {
1248     GNUNET_break (0);
1249     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1250     return;
1251   }
1252   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1253   delegated_host_id = ntohl (msg->delegated_host_id);
1254   if (delegated_host_id == GST_context->host_id)
1255   {
1256     GNUNET_break (0);
1257     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1258     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1259     return;
1260   }
1261   if ((delegated_host_id >= GST_host_list_size) ||
1262       (NULL == GST_host_list[delegated_host_id]))
1263   {
1264     LOG (GNUNET_ERROR_TYPE_WARNING,
1265          "Delegated host %u not registered with us\n", delegated_host_id);
1266     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1267     return;
1268   }
1269   slave_host_id = ntohl (msg->slave_host_id);
1270   if ((slave_host_id >= GST_host_list_size) ||
1271       (NULL == GST_host_list[slave_host_id]))
1272   {
1273     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1274          slave_host_id);
1275     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1276     return;
1277   }
1278   if (slave_host_id == delegated_host_id)
1279   {
1280     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1281     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1282     return;
1283   }
1284   cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */
1285   if (NULL == cfg)
1286   {
1287     GNUNET_break (0);         /* Configuration parsing error */
1288     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1289     return;
1290   }
1291   if (slave_host_id == GST_context->host_id)    /* Link from us */
1292   {
1293     struct Slave *slave;
1294     struct LinkControllersContext *lcc;
1295
1296     if ((delegated_host_id < GST_slave_list_size) &&
1297         (NULL != GST_slave_list[delegated_host_id]))
1298     {
1299       GNUNET_break (0);
1300       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1301       return;
1302     }
1303     slave = GNUNET_malloc (sizeof (struct Slave));
1304     slave->host_id = delegated_host_id;
1305     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1306     slave_list_add (slave);
1307     if (1 != msg->is_subordinate)
1308     {
1309       slave->controller =
1310           GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
1311                                              event_mask, &slave_event_callback,
1312                                              slave);
1313       if (NULL != slave->controller)
1314         send_controller_link_response (client,
1315                                        GNUNET_ntohll (msg->operation_id),
1316                                        NULL,
1317                                        NULL);
1318       else
1319         send_controller_link_response (client,
1320                                        GNUNET_ntohll (msg->operation_id),
1321                                        NULL,
1322                                        "Could not connect to delegated controller");
1323       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1324       return;
1325     }
1326     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1327     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1328     GNUNET_SERVER_client_keep (client);
1329     lcc->client = client;
1330     slave->lcc = lcc;
1331     slave->controller_proc =
1332         GNUNET_TESTBED_controller_start (GST_context->master_ip,
1333                                          GST_host_list[slave->host_id], cfg,
1334                                          &slave_status_callback, slave);
1335     GNUNET_CONFIGURATION_destroy (cfg);
1336     new_route = GNUNET_malloc (sizeof (struct Route));
1337     new_route->dest = delegated_host_id;
1338     new_route->thru = GST_context->host_id;
1339     route_list_add (new_route);
1340     return;
1341   }
1342
1343   /* Route the request */
1344   if (slave_host_id >= route_list_size)
1345   {
1346     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1347     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1348     return;
1349   }
1350   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1351   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1352   lcfq->lcf->type = CLOSURE_TYPE_LCF;
1353   lcfq->lcf->delegated_host_id = delegated_host_id;
1354   lcfq->lcf->slave_host_id = slave_host_id;
1355   route = GST_find_dest_route (slave_host_id);
1356   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1357   GNUNET_assert (route->dest < GST_slave_list_size);
1358   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1359   lcfq->lcf->cfg = cfg;
1360   lcfq->lcf->is_subordinate = msg->is_subordinate;
1361   lcfq->lcf->state = INIT;
1362   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1363   lcfq->lcf->gateway = GST_slave_list[route->dest];
1364   GNUNET_SERVER_client_keep (client);
1365   lcfq->lcf->client = client;
1366   if (NULL == lcfq_head)
1367   {
1368     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1369     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1370     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1371   }
1372   else
1373     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1374   /* FIXME: Adding a new route should happen after the controllers are linked
1375    * successfully */
1376   if (1 != msg->is_subordinate)
1377   {
1378     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1379     return;
1380   }
1381   if ((delegated_host_id < route_list_size) &&
1382       (NULL != route_list[delegated_host_id]))
1383   {
1384     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1385                                  * with is subordinate flag set to GNUNET_YES? */
1386     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1387     return;
1388   }
1389   new_route = GNUNET_malloc (sizeof (struct Route));
1390   new_route->dest = delegated_host_id;
1391   new_route->thru = route->dest;
1392   route_list_add (new_route);
1393   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1394 }
1395
1396
1397 /**
1398  * The task to be executed if the forwarded peer create operation has been
1399  * timed out
1400  *
1401  * @param cls the FowardedOperationContext
1402  * @param tc the TaskContext from the scheduler
1403  */
1404 static void
1405 peer_create_forward_timeout (void *cls,
1406                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1407 {
1408   struct ForwardedOperationContext *fopc = cls;
1409
1410   GNUNET_free (fopc->cls);
1411   GST_forwarded_operation_timeout (fopc, tc);
1412 }
1413
1414
1415 /**
1416  * Callback to be called when forwarded peer create operation is successfull. We
1417  * have to relay the reply msg back to the client
1418  *
1419  * @param cls ForwardedOperationContext
1420  * @param msg the peer create success message
1421  */
1422 static void
1423 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1424 {
1425   struct ForwardedOperationContext *fopc = cls;
1426   struct Peer *remote_peer;
1427
1428   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
1429   {
1430     GNUNET_assert (NULL != fopc->cls);
1431     remote_peer = fopc->cls;
1432     peer_list_add (remote_peer);
1433   }
1434   GST_forwarded_operation_reply_relay (fopc, msg);
1435 }
1436
1437
1438 /**
1439  * Function to destroy a peer
1440  *
1441  * @param peer the peer structure to destroy
1442  */
1443 void
1444 GST_destroy_peer (struct Peer *peer)
1445 {
1446   GNUNET_break (0 == peer->reference_cnt);
1447   if (GNUNET_YES == peer->is_remote)
1448   {
1449     peer_list_remove (peer);
1450     GNUNET_free (peer);
1451     return;
1452   }
1453   if (GNUNET_YES == peer->details.local.is_running)
1454   {
1455     GNUNET_TESTING_peer_stop (peer->details.local.peer);
1456     peer->details.local.is_running = GNUNET_NO;
1457   }
1458   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1459   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1460   peer_list_remove (peer);
1461   GNUNET_free (peer);
1462 }
1463
1464
1465 /**
1466  * Callback to be called when forwarded peer destroy operation is successfull. We
1467  * have to relay the reply msg back to the client
1468  *
1469  * @param cls ForwardedOperationContext
1470  * @param msg the peer create success message
1471  */
1472 static void
1473 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1474 {
1475   struct ForwardedOperationContext *fopc = cls;
1476   struct Peer *remote_peer;
1477
1478   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
1479       ntohs (msg->type))
1480   {
1481     remote_peer = fopc->cls;
1482     GNUNET_assert (NULL != remote_peer);
1483     remote_peer->destroy_flag = GNUNET_YES;
1484     if (0 == remote_peer->reference_cnt)
1485       GST_destroy_peer (remote_peer);
1486   }
1487   GST_forwarded_operation_reply_relay (fopc, msg);
1488 }
1489
1490
1491
1492 /**
1493  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1494  *
1495  * @param cls NULL
1496  * @param client identification of the client
1497  * @param message the actual message
1498  */
1499 static void
1500 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1501                     const struct GNUNET_MessageHeader *message)
1502 {
1503   const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1504   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1505   struct GNUNET_CONFIGURATION_Handle *cfg;
1506   struct ForwardedOperationContext *fo_ctxt;
1507   struct Route *route;
1508   struct Peer *peer;
1509   char *config;
1510   size_t dest_size;
1511   int ret;
1512   uint32_t config_size;
1513   uint32_t host_id;
1514   uint32_t peer_id;
1515   uint16_t msize;
1516
1517
1518   msize = ntohs (message->size);
1519   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1520   {
1521     GNUNET_break (0);           /* We need configuration */
1522     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1523     return;
1524   }
1525   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1526   host_id = ntohl (msg->host_id);
1527   peer_id = ntohl (msg->peer_id);
1528   if (UINT32_MAX == peer_id)
1529   {
1530     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1531                                  "Cannot create peer with given ID");
1532     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1533     return;
1534   }
1535   if (host_id == GST_context->host_id)
1536   {
1537     char *emsg;
1538
1539     /* We are responsible for this peer */
1540     msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1541     config_size = ntohl (msg->config_size);
1542     config = GNUNET_malloc (config_size);
1543     dest_size = config_size;
1544     if (Z_OK !=
1545         (ret =
1546          uncompress ((Bytef *) config, (uLongf *) & dest_size,
1547                      (const Bytef *) &msg[1], (uLong) msize)))
1548     {
1549       GNUNET_break (0);         /* uncompression error */
1550       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1551       return;
1552     }
1553     if (config_size != dest_size)
1554     {
1555       GNUNET_break (0);         /* Uncompressed config size mismatch */
1556       GNUNET_free (config);
1557       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1558       return;
1559     }
1560     cfg = GNUNET_CONFIGURATION_create ();
1561     if (GNUNET_OK !=
1562         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1563     {
1564       GNUNET_break (0);         /* Configuration parsing error */
1565       GNUNET_free (config);
1566       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1567       return;
1568     }
1569     GNUNET_free (config);
1570     GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
1571                                            (unsigned long long) peer_id);
1572     peer = GNUNET_malloc (sizeof (struct Peer));
1573     peer->is_remote = GNUNET_NO;
1574     peer->details.local.cfg = cfg;
1575     peer->id = peer_id;
1576     LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
1577     peer->details.local.peer =
1578         GNUNET_TESTING_peer_configure (GST_context->system,
1579                                        peer->details.local.cfg, peer->id,
1580                                        NULL /* Peer id */ ,
1581                                        &emsg);
1582     if (NULL == peer->details.local.peer)
1583     {
1584       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1585       GNUNET_free (emsg);
1586       GNUNET_free (peer);
1587       GNUNET_break (0);
1588       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1589       return;
1590     }
1591     peer->details.local.is_running = GNUNET_NO;
1592     peer_list_add (peer);
1593     reply =
1594         GNUNET_malloc (sizeof
1595                        (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1596     reply->header.size =
1597         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1598     reply->header.type =
1599         htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
1600     reply->peer_id = msg->peer_id;
1601     reply->operation_id = msg->operation_id;
1602     GST_queue_message (client, &reply->header);
1603     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1604     return;
1605   }
1606
1607   /* Forward peer create request */
1608   route = GST_find_dest_route (host_id);
1609   if (NULL == route)
1610   {
1611     GNUNET_break (0);
1612     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1613     return;
1614   }
1615
1616   peer = GNUNET_malloc (sizeof (struct Peer));
1617   peer->is_remote = GNUNET_YES;
1618   peer->id = peer_id;
1619   peer->details.remote.slave = GST_slave_list[route->dest];
1620   peer->details.remote.remote_host_id = host_id;
1621   fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1622   GNUNET_SERVER_client_keep (client);
1623   fo_ctxt->client = client;
1624   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1625   fo_ctxt->cls = peer;          //GST_slave_list[route->dest]->controller;
1626   fo_ctxt->type = OP_PEER_CREATE;
1627   fo_ctxt->opc =
1628       GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
1629                                              [route->dest]->controller,
1630                                              fo_ctxt->operation_id,
1631                                              &msg->header,
1632                                              peer_create_success_cb, fo_ctxt);
1633   fo_ctxt->timeout_task =
1634       GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
1635                                     fo_ctxt);
1636   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1637   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1638 }
1639
1640
1641 /**
1642  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1643  *
1644  * @param cls NULL
1645  * @param client identification of the client
1646  * @param message the actual message
1647  */
1648 static void
1649 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1650                      const struct GNUNET_MessageHeader *message)
1651 {
1652   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1653   struct ForwardedOperationContext *fopc;
1654   struct Peer *peer;
1655   uint32_t peer_id;
1656
1657   msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1658   peer_id = ntohl (msg->peer_id);
1659   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1660              peer_id, GNUNET_ntohll (msg->operation_id));
1661   if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
1662   {
1663     LOG (GNUNET_ERROR_TYPE_ERROR,
1664          "Asked to destroy a non existent peer with id: %u\n", peer_id);
1665     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1666                                  "Peer doesn't exist");
1667     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1668     return;
1669   }
1670   peer = GST_peer_list[peer_id];
1671   if (GNUNET_YES == peer->is_remote)
1672   {
1673     /* Forward the destory message to sub controller */
1674     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1675     GNUNET_SERVER_client_keep (client);
1676     fopc->client = client;
1677     fopc->cls = peer;
1678     fopc->type = OP_PEER_DESTROY;
1679     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1680     fopc->opc =
1681         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1682                                                slave->controller,
1683                                                fopc->operation_id, &msg->header,
1684                                                &peer_destroy_success_cb, fopc);
1685     fopc->timeout_task =
1686         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1687                                       fopc);
1688     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1689     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1690     return;
1691   }
1692   peer->destroy_flag = GNUNET_YES;
1693   if (0 == peer->reference_cnt)
1694     GST_destroy_peer (peer);
1695   else
1696     LOG (GNUNET_ERROR_TYPE_DEBUG,
1697          "Delaying peer destroy as peer is currently in use\n");
1698   send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1699   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1700 }
1701
1702
1703 /**
1704  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1705  *
1706  * @param cls NULL
1707  * @param client identification of the client
1708  * @param message the actual message
1709  */
1710 static void
1711 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1712                    const struct GNUNET_MessageHeader *message)
1713 {
1714   const struct GNUNET_TESTBED_PeerStartMessage *msg;
1715   struct GNUNET_TESTBED_PeerEventMessage *reply;
1716   struct ForwardedOperationContext *fopc;
1717   struct Peer *peer;
1718   uint32_t peer_id;
1719
1720   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1721   peer_id = ntohl (msg->peer_id);
1722   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1723   {
1724     GNUNET_break (0);
1725     LOG (GNUNET_ERROR_TYPE_ERROR,
1726          "Asked to start a non existent peer with id: %u\n", peer_id);
1727     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1728     return;
1729   }
1730   peer = GST_peer_list[peer_id];
1731   if (GNUNET_YES == peer->is_remote)
1732   {
1733     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1734     GNUNET_SERVER_client_keep (client);
1735     fopc->client = client;
1736     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1737     fopc->type = OP_PEER_START;
1738     fopc->opc =
1739         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1740                                                slave->controller,
1741                                                fopc->operation_id, &msg->header,
1742                                                &GST_forwarded_operation_reply_relay,
1743                                                fopc);
1744     fopc->timeout_task =
1745         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1746                                       fopc);
1747     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1748     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1749     return;
1750   }
1751   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1752   {
1753     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1754                                  "Failed to start");
1755     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1756     return;
1757   }
1758   peer->details.local.is_running = GNUNET_YES;
1759   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1760   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1761   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1762   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1763   reply->host_id = htonl (GST_context->host_id);
1764   reply->peer_id = msg->peer_id;
1765   reply->operation_id = msg->operation_id;
1766   GST_queue_message (client, &reply->header);
1767   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1768 }
1769
1770
1771 /**
1772  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1773  *
1774  * @param cls NULL
1775  * @param client identification of the client
1776  * @param message the actual message
1777  */
1778 static void
1779 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1780                   const struct GNUNET_MessageHeader *message)
1781 {
1782   const struct GNUNET_TESTBED_PeerStopMessage *msg;
1783   struct GNUNET_TESTBED_PeerEventMessage *reply;
1784   struct ForwardedOperationContext *fopc;
1785   struct Peer *peer;
1786   uint32_t peer_id;
1787
1788   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1789   peer_id = ntohl (msg->peer_id);
1790   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
1791   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1792   {
1793     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1794                                  "Peer not found");
1795     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1796     return;
1797   }
1798   peer = GST_peer_list[peer_id];
1799   if (GNUNET_YES == peer->is_remote)
1800   {
1801     LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
1802          peer_id);
1803     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1804     GNUNET_SERVER_client_keep (client);
1805     fopc->client = client;
1806     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1807     fopc->type = OP_PEER_STOP;
1808     fopc->opc =
1809         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1810                                                slave->controller,
1811                                                fopc->operation_id, &msg->header,
1812                                                &GST_forwarded_operation_reply_relay,
1813                                                fopc);
1814     fopc->timeout_task =
1815         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1816                                       fopc);
1817     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1818     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1819     return;
1820   }
1821   if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
1822   {
1823     LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
1824     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1825                                  "Peer not running");
1826     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1827     return;
1828   }
1829   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
1830   peer->details.local.is_running = GNUNET_NO;
1831   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1832   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1833   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1834   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
1835   reply->host_id = htonl (GST_context->host_id);
1836   reply->peer_id = msg->peer_id;
1837   reply->operation_id = msg->operation_id;
1838   GST_queue_message (client, &reply->header);
1839   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1840   GNUNET_TESTING_peer_wait (peer->details.local.peer);
1841 }
1842
1843
1844 /**
1845  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1846  *
1847  * @param cls NULL
1848  * @param client identification of the client
1849  * @param message the actual message
1850  */
1851 static void
1852 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1853                         const struct GNUNET_MessageHeader *message)
1854 {
1855   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1856   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1857   struct Peer *peer;
1858   char *config;
1859   char *xconfig;
1860   size_t c_size;
1861   size_t xc_size;
1862   uint32_t peer_id;
1863   uint16_t msize;
1864
1865   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
1866   peer_id = ntohl (msg->peer_id);
1867   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1868   {
1869     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1870                                  "Peer not found");
1871     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1872     return;
1873   }
1874   peer = GST_peer_list[peer_id];
1875   if (GNUNET_YES == peer->is_remote)
1876   {
1877     struct ForwardedOperationContext *fopc;
1878
1879     LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
1880     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1881     GNUNET_SERVER_client_keep (client);
1882     fopc->client = client;
1883     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1884     fopc->type = OP_PEER_INFO;
1885     fopc->opc =
1886         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1887                                                slave->controller,
1888                                                fopc->operation_id, &msg->header,
1889                                                &GST_forwarded_operation_reply_relay,
1890                                                fopc);
1891     fopc->timeout_task =
1892         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1893                                       fopc);
1894     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1895     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1896     return;
1897   }
1898   LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
1899   config =
1900       GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
1901                                       &c_size);
1902   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1903   GNUNET_free (config);
1904   msize =
1905       xc_size +
1906       sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1907   reply = GNUNET_realloc (xconfig, msize);
1908   (void) memmove (&reply[1], reply, xc_size);
1909   reply->header.size = htons (msize);
1910   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
1911   reply->peer_id = msg->peer_id;
1912   reply->operation_id = msg->operation_id;
1913   GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
1914                                     &reply->peer_identity);
1915   reply->config_size = htons ((uint16_t) c_size);
1916   GST_queue_message (client, &reply->header);
1917   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1918 }
1919
1920
1921 /**
1922  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1923  *
1924  * @param cls NULL
1925  * @param client identification of the client
1926  * @param message the actual message
1927  */
1928 static void
1929 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1930                          const struct GNUNET_MessageHeader *message)
1931 {
1932   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1933   struct Slave *slave;
1934   struct GNUNET_TESTBED_SlaveConfiguration *reply;
1935   const struct GNUNET_CONFIGURATION_Handle *cfg;
1936   char *config;
1937   char *xconfig;
1938   size_t config_size;
1939   size_t xconfig_size;
1940   size_t reply_size;
1941   uint64_t op_id;
1942   uint32_t slave_id;
1943
1944   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
1945   slave_id = ntohl (msg->slave_id);
1946   op_id = GNUNET_ntohll (msg->operation_id);
1947   if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
1948   {
1949     /* FIXME: Add forwardings for this type of message here.. */
1950     GST_send_operation_fail_msg (client, op_id, "Slave not found");
1951     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1952     return;
1953   }
1954   slave = GST_slave_list[slave_id];
1955   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
1956   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1957   xconfig_size =
1958       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1959   GNUNET_free (config);
1960   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
1961   GNUNET_break (reply_size <= UINT16_MAX);
1962   GNUNET_break (config_size <= UINT16_MAX);
1963   reply = GNUNET_realloc (xconfig, reply_size);
1964   (void) memmove (&reply[1], reply, xconfig_size);
1965   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
1966   reply->header.size = htons ((uint16_t) reply_size);
1967   reply->slave_id = msg->slave_id;
1968   reply->operation_id = msg->operation_id;
1969   reply->config_size = htons ((uint16_t) config_size);
1970   GST_queue_message (client, &reply->header);
1971   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1972 }
1973
1974
1975 /**
1976  * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
1977  */
1978 struct HandlerContext_ShutdownPeers
1979 {
1980   /**
1981    * The number of slave we expect to hear from since we forwarded the
1982    * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
1983    */
1984   unsigned int nslaves;
1985
1986   /**
1987    * Did we observe a timeout with respect to this operation at any of the
1988    * slaves
1989    */
1990   int timeout;
1991 };
1992
1993
1994 /**
1995  * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
1996  *
1997  * @param cls the ForwardedOperationContext
1998  * @param tc the scheduler task context
1999  */
2000 static void
2001 shutdown_peers_timeout_cb (void *cls,
2002                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2003 {
2004   struct ForwardedOperationContext *fo_ctxt = cls;
2005   struct HandlerContext_ShutdownPeers *hc;
2006
2007   hc = fo_ctxt->cls;
2008   hc->timeout = GNUNET_YES;
2009   GNUNET_assert (0 < hc->nslaves);
2010   hc->nslaves--;
2011   if (0 == hc->nslaves)
2012     GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2013                                  "Timeout at a slave controller");
2014   GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);  
2015   GNUNET_SERVER_client_drop (fo_ctxt->client);
2016   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2017   GNUNET_free (fo_ctxt);
2018 }
2019
2020
2021 /**
2022  * The reply msg handler forwarded SHUTDOWN_PEERS operation.  Checks if a
2023  * success reply is received from all clients and then sends the success message
2024  * to the client
2025  *
2026  * @param cls ForwardedOperationContext
2027  * @param msg the message to relay
2028  */
2029 static void
2030 shutdown_peers_reply_cb (void *cls,
2031                          const struct GNUNET_MessageHeader *msg)
2032 {
2033   struct ForwardedOperationContext *fo_ctxt = cls;
2034   struct HandlerContext_ShutdownPeers *hc;
2035   
2036   hc = fo_ctxt->cls;
2037   GNUNET_assert (0 < hc->nslaves);
2038   hc->nslaves--;
2039   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != 
2040       ntohs (msg->type))
2041     hc->timeout = GNUNET_YES;
2042   if (0 == hc->nslaves)
2043   {
2044     if (GNUNET_YES == hc->timeout)
2045       GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2046                                    "Timeout at a slave controller");
2047     else
2048       send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
2049   }
2050   GNUNET_SERVER_client_drop (fo_ctxt->client);
2051   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2052   GNUNET_free (fo_ctxt);
2053 }
2054
2055
2056 /**
2057  * Stops and destroys all peers
2058  */
2059 static void
2060 destroy_peers ()
2061 {
2062   struct Peer *peer;
2063   unsigned int id;
2064
2065   if (NULL == GST_peer_list)
2066     return;
2067   for (id = 0; id < GST_peer_list_size; id++)
2068   {
2069     peer = GST_peer_list[id];
2070     if (NULL == peer)
2071       continue;
2072     /* If destroy flag is set it means that this peer should have been
2073      * destroyed by a context which we destroy before */
2074     GNUNET_break (GNUNET_NO == peer->destroy_flag);
2075     /* counter should be zero as we free all contexts before */
2076     GNUNET_break (0 == peer->reference_cnt);
2077     if ((GNUNET_NO == peer->is_remote) &&
2078         (GNUNET_YES == peer->details.local.is_running))
2079       GNUNET_TESTING_peer_kill (peer->details.local.peer);
2080   }
2081   for (id = 0; id < GST_peer_list_size; id++)
2082   {
2083     peer = GST_peer_list[id];
2084     if (NULL == peer)
2085       continue;    
2086     if (GNUNET_NO == peer->is_remote)
2087     {
2088       if (GNUNET_YES == peer->details.local.is_running)
2089         GNUNET_TESTING_peer_wait (peer->details.local.peer);
2090       GNUNET_TESTING_peer_destroy (peer->details.local.peer);
2091       GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
2092     }
2093     GNUNET_free (peer);
2094   }
2095   GNUNET_free_non_null (GST_peer_list);
2096   GST_peer_list = NULL;
2097 }
2098
2099
2100 /**
2101  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
2102  *
2103  * @param cls NULL
2104  * @param client identification of the client
2105  * @param message the actual message
2106  */
2107 static void
2108 handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
2109                        const struct GNUNET_MessageHeader *message)
2110 {
2111   const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2112   struct HandlerContext_ShutdownPeers *hc;
2113   struct Slave *slave;
2114   struct ForwardedOperationContext *fo_ctxt;
2115   uint64_t op_id;
2116   unsigned int cnt;
2117
2118   msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
2119   LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
2120   /* Forward to all slaves which we have started */
2121   op_id = GNUNET_ntohll (msg->operation_id);
2122   hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
2123   /* FIXME: have a better implementation where we track which slaves are
2124      started by this controller */
2125   for (cnt = 0; cnt < GST_slave_list_size; cnt++)
2126   {
2127     slave = GST_slave_list[cnt];
2128     if (NULL == slave)
2129       continue;
2130     if (NULL == slave->controller_proc) /* We didn't start the slave */
2131       continue;
2132     LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
2133     hc->nslaves++;
2134     fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2135     GNUNET_SERVER_client_keep (client);
2136     fo_ctxt->client = client;
2137     fo_ctxt->operation_id = op_id;
2138     fo_ctxt->cls = hc;
2139     fo_ctxt->type = OP_SHUTDOWN_PEERS;
2140     fo_ctxt->opc =
2141         GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
2142                                                fo_ctxt->operation_id,
2143                                                &msg->header,
2144                                                shutdown_peers_reply_cb,
2145                                                fo_ctxt);
2146     fo_ctxt->timeout_task =
2147         GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
2148                                       fo_ctxt);
2149     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2150   }
2151   LOG_DEBUG ("Shutting down peers\n");
2152   /* Stop and destroy all peers */
2153   GST_free_occq ();
2154   GST_free_roccq ();
2155   destroy_peers ();
2156   if (0 == hc->nslaves)
2157   {
2158     send_operation_success_msg (client, op_id);
2159     GNUNET_free (hc);
2160   }
2161   GNUNET_SERVER_receive_done (client, GNUNET_OK);  
2162 }
2163
2164
2165 /**
2166  * Iterator over hash map entries.
2167  *
2168  * @param cls closure
2169  * @param key current key code
2170  * @param value value in the hash map
2171  * @return GNUNET_YES if we should continue to
2172  *         iterate,
2173  *         GNUNET_NO if not.
2174  */
2175 static int
2176 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2177 {
2178   struct SharedService *ss = value;
2179
2180   GNUNET_assert (GNUNET_YES ==
2181                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2182   GNUNET_free (ss->name);
2183   GNUNET_free (ss);
2184   return GNUNET_YES;
2185 }
2186
2187
2188 /**
2189  * Iterator for freeing hash map entries in a slave's reghost_map
2190  *
2191  * @param cls handle to the slave
2192  * @param key current key code
2193  * @param value value in the hash map
2194  * @return GNUNET_YES if we should continue to
2195  *         iterate,
2196  *         GNUNET_NO if not.
2197  */
2198 static int
2199 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
2200                        void *value)
2201 {
2202   struct Slave *slave = cls;
2203   struct RegisteredHostContext *rhc = value;
2204   struct ForwardedOverlayConnectContext *focc;
2205
2206   GNUNET_assert (GNUNET_YES ==
2207                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
2208                                                        value));
2209   while (NULL != (focc = rhc->focc_dll_head))
2210   {
2211     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
2212     GST_cleanup_focc (focc);
2213   }
2214   if (NULL != rhc->sub_op)
2215     GNUNET_TESTBED_operation_done (rhc->sub_op);
2216   if (NULL != rhc->client)
2217     GNUNET_SERVER_client_drop (rhc->client);
2218   GNUNET_free (value);
2219   return GNUNET_YES;
2220 }
2221
2222
2223 /**
2224  * Task to clean up and shutdown nicely
2225  *
2226  * @param cls NULL
2227  * @param tc the TaskContext from scheduler
2228  */
2229 static void
2230 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2231 {
2232   struct LCFContextQueue *lcfq;
2233   struct ForwardedOperationContext *fopc;
2234   struct MessageQueue *mq_entry;
2235   uint32_t id;
2236
2237   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2238   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2239   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2240                                                 NULL);
2241   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2242   /* cleanup any remaining forwarded operations */
2243   while (NULL != (fopc = fopcq_head))
2244   {
2245     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
2246     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
2247     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
2248       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
2249     GNUNET_SERVER_client_drop (fopc->client);
2250     switch (fopc->type)
2251     {
2252     case OP_PEER_CREATE:
2253       GNUNET_free (fopc->cls);
2254       break;
2255     case OP_SHUTDOWN_PEERS:
2256       {
2257         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
2258         
2259         GNUNET_assert (0 < hc->nslaves);
2260         hc->nslaves--;
2261         if (0 == hc->nslaves)
2262           GNUNET_free (hc);
2263       }
2264       break;
2265     case OP_PEER_START:
2266     case OP_PEER_STOP:
2267     case OP_PEER_DESTROY:
2268     case OP_PEER_INFO:
2269     case OP_OVERLAY_CONNECT:
2270     case OP_LINK_CONTROLLERS:
2271     case OP_GET_SLAVE_CONFIG:
2272       break;
2273     case OP_FORWARDED:
2274       GNUNET_assert (0);
2275     };
2276     GNUNET_free (fopc);
2277   }
2278   if (NULL != lcfq_head)
2279   {
2280     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2281     {
2282       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2283       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2284     }
2285   }
2286   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2287   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2288   {
2289     GNUNET_SERVER_client_drop (lcfq->lcf->client);
2290     GNUNET_assert (NULL != lcfq->lcf->cfg);
2291     GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
2292     GNUNET_free (lcfq->lcf);
2293     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2294     GNUNET_free (lcfq);
2295   }
2296   GST_free_occq ();
2297   GST_free_roccq ();
2298   /* Clear peer list */
2299   destroy_peers ();
2300   /* Clear host list */
2301   for (id = 0; id < GST_host_list_size; id++)
2302     if (NULL != GST_host_list[id])
2303       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
2304   GNUNET_free_non_null (GST_host_list);
2305   /* Clear route list */
2306   for (id = 0; id < route_list_size; id++)
2307     if (NULL != route_list[id])
2308       GNUNET_free (route_list[id]);
2309   GNUNET_free_non_null (route_list);
2310   /* Clear GST_slave_list */
2311   for (id = 0; id < GST_slave_list_size; id++)
2312     if (NULL != GST_slave_list[id])
2313     {
2314       struct HostRegistration *hr_entry;
2315
2316       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
2317       {
2318         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
2319                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
2320         GNUNET_free (hr_entry);
2321       }
2322       if (NULL != GST_slave_list[id]->rhandle)
2323         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
2324       (void)
2325           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
2326                                                  [id]->reghost_map,
2327                                                  reghost_free_iterator,
2328                                                  GST_slave_list[id]);
2329       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
2330       if (NULL != GST_slave_list[id]->controller)
2331         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
2332       if (NULL != GST_slave_list[id]->controller_proc)
2333         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
2334       GNUNET_free (GST_slave_list[id]);
2335     }
2336   GNUNET_free_non_null (GST_slave_list);
2337   if (NULL != GST_context)
2338   {
2339     GNUNET_free_non_null (GST_context->master_ip);
2340     if (NULL != GST_context->system)
2341       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
2342     GNUNET_SERVER_client_drop (GST_context->client);
2343     GNUNET_free (GST_context);
2344     GST_context = NULL;
2345   }
2346   if (NULL != transmit_handle)
2347     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
2348   while (NULL != (mq_entry = mq_head))
2349   {
2350     GNUNET_free (mq_entry->msg);
2351     GNUNET_SERVER_client_drop (mq_entry->client);
2352     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
2353     GNUNET_free (mq_entry);
2354   }
2355   GNUNET_free_non_null (hostname);
2356   GNUNET_CONFIGURATION_destroy (our_config);
2357   /* Free hello cache */
2358   GST_cache_clear ();
2359   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
2360   GST_opq_openfds = NULL;
2361 }
2362
2363
2364 /**
2365  * Callback for client disconnect
2366  *
2367  * @param cls NULL
2368  * @param client the client which has disconnected
2369  */
2370 static void
2371 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2372 {
2373   if (NULL == GST_context)
2374     return;
2375   if (client == GST_context->client)
2376   {
2377     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2378     /* should not be needed as we're terminated by failure to read
2379      * from stdin, but if stdin fails for some reason, this shouldn't
2380      * hurt for now --- might need to revise this later if we ever
2381      * decide that master connections might be temporarily down
2382      * for some reason */
2383     //GNUNET_SCHEDULER_shutdown ();
2384   }
2385 }
2386
2387
2388 /**
2389  * Testbed setup
2390  *
2391  * @param cls closure
2392  * @param server the initialized server
2393  * @param cfg configuration to use
2394  */
2395 static void
2396 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2397              const struct GNUNET_CONFIGURATION_Handle *cfg)
2398 {
2399   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2400     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2401     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
2402     {&handle_configure_shared_service, NULL,
2403      GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
2404     {&handle_link_controllers, NULL,
2405      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
2406     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
2407     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
2408      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2409     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
2410      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2411     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
2412      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2413     {&handle_peer_get_config, NULL,
2414      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
2415      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2416     {&GST_handle_overlay_connect, NULL,
2417      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
2418      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2419     {&GST_handle_remote_overlay_connect, NULL,
2420      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
2421     {&handle_slave_get_config, NULL,
2422      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
2423      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2424     {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
2425      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
2426     {NULL}
2427   };
2428   char *logfile;
2429   unsigned long long num;
2430
2431   if (GNUNET_OK ==
2432       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
2433                                                &logfile))
2434   {
2435     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
2436     GNUNET_free (logfile);
2437   }
2438   GNUNET_assert (GNUNET_OK ==
2439                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2440                                                         "CACHE_SIZE", &num));
2441   GST_cache_init ((unsigned int) num);
2442   GNUNET_assert (GNUNET_OK ==
2443                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2444                                                         "MAX_OPEN_FDS", &num));
2445   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
2446   GNUNET_assert (GNUNET_OK ==
2447                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
2448                                                       "OPERATION_TIMEOUT",
2449                                                       (struct
2450                                                        GNUNET_TIME_Relative *)
2451                                                       &GST_timeout));
2452   GNUNET_assert (GNUNET_OK ==
2453                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
2454                                                         "HOSTNAME", &hostname));  
2455   our_config = GNUNET_CONFIGURATION_dup (cfg);
2456   GNUNET_SERVER_add_handlers (server, message_handlers);
2457   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2458   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
2459   shutdown_task_id =
2460       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
2461                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
2462                                                   &shutdown_task, NULL);
2463   LOG_DEBUG ("Testbed startup complete\n");
2464   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
2465 }
2466
2467
2468 /**
2469  * The starting point of execution
2470  */
2471 int
2472 main (int argc, char *const *argv)
2473 {
2474   //sleep (15);                 /* Debugging */
2475   return (GNUNET_OK ==
2476           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2477                               &testbed_run, NULL)) ? 0 : 1;
2478 }
2479
2480 /* end of gnunet-service-testbed.c */