- restructure
[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
30 /***********/
31 /* Globals */
32 /***********/
33
34 /**
35  * Our configuration
36  */
37 struct GNUNET_CONFIGURATION_Handle *our_config;
38
39 /**
40  * The master context; generated with the first INIT message
41  */
42 struct Context *GST_context;
43
44 /**
45  * A list of directly linked neighbours
46  */
47 struct Slave **GST_slave_list;
48
49 /**
50  * Array of hosts
51  */
52 struct GNUNET_TESTBED_Host **GST_host_list;
53
54 /**
55  * DLL head for forwarded operation contexts
56  */
57 struct ForwardedOperationContext *fopcq_head;
58
59 /**
60  * DLL tail for forwarded operation contexts
61  */
62 struct ForwardedOperationContext *fopcq_tail;
63
64 /**
65  * Operation queue for open file descriptors
66  */
67 struct OperationQueue *GST_opq_openfds;
68
69 /**
70  * Timeout for operations which may take some time
71  */
72 const struct GNUNET_TIME_Relative GST_timeout;
73
74 /**
75  * The size of the host list
76  */
77 unsigned int GST_host_list_size;
78
79 /**
80  * The size of directly linked neighbours list
81  */
82 unsigned int GST_slave_list_size;
83
84 /**
85  * The size of the peer list
86  */
87 unsigned int GST_peer_list_size;
88
89
90 /***********************************/
91 /* Local definitions and variables */
92 /***********************************/
93
94 /**
95  * The message queue for sending messages to clients
96  */
97 struct MessageQueue
98 {
99   /**
100    * The message to be sent
101    */
102   struct GNUNET_MessageHeader *msg;
103
104   /**
105    * The client to send the message to
106    */
107   struct GNUNET_SERVER_Client *client;
108
109   /**
110    * next pointer for DLL
111    */
112   struct MessageQueue *next;
113
114   /**
115    * prev pointer for DLL
116    */
117   struct MessageQueue *prev;
118 };
119
120 /**
121  * Our hostname; we give this to all the peers we start
122  */
123 static char *hostname;
124
125 /**
126  * Current Transmit Handle; NULL if no notify transmit exists currently
127  */
128 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
129
130 /**
131  * The head for the LCF queue
132  */
133 static struct LCFContextQueue *lcfq_head;
134
135 /**
136  * The tail for the LCF queue
137  */
138 static struct LCFContextQueue *lcfq_tail;
139
140 /**
141  * The message queue head
142  */
143 static struct MessageQueue *mq_head;
144
145 /**
146  * The message queue tail
147  */
148 static struct MessageQueue *mq_tail;
149
150 /**
151  * The hashmap of shared services
152  */
153 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
154
155 /**
156  * A list of routes
157  */
158 static struct Route **route_list;
159
160 /**
161  * The event mask for the events we listen from sub-controllers
162  */
163 static uint64_t event_mask;
164
165 /**
166  * The size of the route list
167  */
168 static unsigned int route_list_size;
169
170 /**
171  * The lcf_task handle
172  */
173 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
174
175 /**
176  * The shutdown task handle
177  */
178 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
179
180
181 /**
182  * Function called to notify a client about the connection begin ready to queue
183  * more data.  "buf" will be NULL and "size" zero if the connection was closed
184  * for writing in the meantime.
185  *
186  * @param cls NULL
187  * @param size number of bytes available in buf
188  * @param buf where the callee should write the message
189  * @return number of bytes written to buf
190  */
191 static size_t
192 transmit_ready_notify (void *cls, size_t size, void *buf)
193 {
194   struct MessageQueue *mq_entry;
195
196   transmit_handle = NULL;
197   mq_entry = mq_head;
198   GNUNET_assert (NULL != mq_entry);
199   if (0 == size)
200     return 0;
201   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
202   size = ntohs (mq_entry->msg->size);
203   memcpy (buf, mq_entry->msg, size);
204   GNUNET_free (mq_entry->msg);
205   GNUNET_SERVER_client_drop (mq_entry->client);
206   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
207   GNUNET_free (mq_entry);
208   mq_entry = mq_head;
209   if (NULL != mq_entry)
210     transmit_handle =
211         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
212                                              ntohs (mq_entry->msg->size),
213                                              GNUNET_TIME_UNIT_FOREVER_REL,
214                                              &transmit_ready_notify, NULL);
215   return size;
216 }
217
218
219 /**
220  * Queues a message in send queue for sending to the service
221  *
222  * @param client the client to whom the queued message has to be sent
223  * @param msg the message to queue
224  */
225 void
226 GST_queue_message (struct GNUNET_SERVER_Client *client,
227                    struct GNUNET_MessageHeader *msg)
228 {
229   struct MessageQueue *mq_entry;
230   uint16_t type;
231   uint16_t size;
232
233   type = ntohs (msg->type);
234   size = ntohs (msg->size);
235   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
236                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
237   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
238   mq_entry->msg = msg;
239   mq_entry->client = client;
240   GNUNET_SERVER_client_keep (client);
241   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
242              ntohs (msg->size));
243   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
244   if (NULL == transmit_handle)
245     transmit_handle =
246         GNUNET_SERVER_notify_transmit_ready (client, size,
247                                              GNUNET_TIME_UNIT_FOREVER_REL,
248                                              &transmit_ready_notify, NULL);
249 }
250
251
252 /**
253  * Function to add a host to the current list of known hosts
254  *
255  * @param host the host to add
256  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
257  *           already in use
258  */
259 static int
260 host_list_add (struct GNUNET_TESTBED_Host *host)
261 {
262   uint32_t host_id;
263
264   host_id = GNUNET_TESTBED_host_get_id_ (host);
265   if (GST_host_list_size <= host_id)
266     GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
267   if (NULL != GST_host_list[host_id])
268   {
269     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
270     return GNUNET_SYSERR;
271   }
272   GST_host_list[host_id] = host;
273   return GNUNET_OK;
274 }
275
276
277 /**
278  * Adds a route to the route list
279  *
280  * @param route the route to add
281  */
282 static void
283 route_list_add (struct Route *route)
284 {
285   if (route->dest >= route_list_size)
286     GST_array_grow_large_enough (route_list, route_list_size, route->dest);
287   GNUNET_assert (NULL == route_list[route->dest]);
288   route_list[route->dest] = route;
289 }
290
291
292 /**
293  * Adds a slave to the slave array
294  *
295  * @param slave the slave controller to add
296  */
297 static void
298 slave_list_add (struct Slave *slave)
299 {
300   if (slave->host_id >= GST_slave_list_size)
301     GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
302                                  slave->host_id);
303   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
304   GST_slave_list[slave->host_id] = slave;
305 }
306
307
308 /**
309  * Finds the route with directly connected host as destination through which
310  * the destination host can be reached
311  *
312  * @param host_id the id of the destination host
313  * @return the route with directly connected destination host; NULL if no route
314  *           is found
315  */
316 struct Route *
317 GST_find_dest_route (uint32_t host_id)
318 {
319   struct Route *route;
320
321   if (route_list_size <= host_id)
322     return NULL;
323   while (NULL != (route = route_list[host_id]))
324   {
325     if (route->thru == GST_context->host_id)
326       break;
327     host_id = route->thru;
328   }
329   return route;
330 }
331
332
333 /**
334  * Routes message to a host given its host_id
335  *
336  * @param host_id the id of the destination host
337  * @param msg the message to be routed
338  */
339 static void
340 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
341 {
342   GNUNET_break (0);
343 }
344
345
346 /**
347  * Send operation failure message to client
348  *
349  * @param client the client to which the failure message has to be sent to
350  * @param operation_id the id of the failed operation
351  * @param emsg the error message; can be NULL
352  */
353 void
354 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
355                              uint64_t operation_id, const char *emsg)
356 {
357   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
358   uint16_t msize;
359   uint16_t emsg_len;
360
361   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
362   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
363   msize += emsg_len;
364   msg = GNUNET_malloc (msize);
365   msg->header.size = htons (msize);
366   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
367   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
368   msg->operation_id = GNUNET_htonll (operation_id);
369   if (0 != emsg_len)
370     memcpy (&msg[1], emsg, emsg_len);
371   GST_queue_message (client, &msg->header);
372 }
373
374
375 /**
376  * Function to send generic operation success message to given client
377  *
378  * @param client the client to send the message to
379  * @param operation_id the id of the operation which was successful
380  */
381 void
382 GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client,
383                                 uint64_t operation_id)
384 {
385   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
386   uint16_t msize;
387
388   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
389   msg = GNUNET_malloc (msize);
390   msg->header.size = htons (msize);
391   msg->header.type =
392       htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
393   msg->operation_id = GNUNET_htonll (operation_id);
394   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
395   GST_queue_message (client, &msg->header);
396 }
397
398
399 /**
400  * Function to send a failure reponse for controller link operation
401  *
402  * @param client the client to send the message to
403  * @param operation_id the operation ID of the controller link request
404  * @param cfg the configuration with which the delegated controller is started.
405  *          Can be NULL if the delegated controller is not started but just
406  *          linked to.
407  * @param emsg set to an error message explaining why the controller link
408  *          failed.  Setting this to NULL signifies success.  !This should be
409  *          NULL if cfg is set!
410  */
411 static void
412 send_controller_link_response (struct GNUNET_SERVER_Client *client,
413                                uint64_t operation_id,
414                                const struct GNUNET_CONFIGURATION_Handle
415                                *cfg,
416                                const char *emsg)
417 {
418   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
419   char *xconfig;
420   size_t config_size;
421   size_t xconfig_size;  
422   uint16_t msize;
423
424   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
425   xconfig = NULL;
426   xconfig_size = 0;
427   config_size = 0;
428   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
429   if (NULL != cfg)
430   {
431     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
432                                             &config_size,
433                                             &xconfig_size);
434     msize += xconfig_size;
435   }
436   if (NULL != emsg)
437     msize += strlen (emsg);
438   msg = GNUNET_malloc (msize);
439   msg->header.type = htons
440       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
441   msg->header.size = htons (msize);
442   if (NULL == emsg)
443     msg->success = htons (GNUNET_YES);
444   msg->operation_id = GNUNET_htonll (operation_id);
445   msg->config_size = htons ((uint16_t) config_size);
446   if (NULL != xconfig)
447     memcpy (&msg[1], xconfig, xconfig_size);
448   if (NULL != emsg)
449     memcpy (&msg[1], emsg, strlen (emsg));
450   GST_queue_message (client, &msg->header);
451 }
452
453 /**
454  * Callback which will be called after a host registration succeeded or failed
455  *
456  * @param cls the handle to the slave at which the registration is completed
457  * @param emsg the error message; NULL if host registration is successful
458  */
459 static void
460 hr_completion (void *cls, const char *emsg);
461
462
463 /**
464  * Attempts to register the next host in the host registration queue
465  *
466  * @param slave the slave controller whose host registration queue is checked
467  *          for host registrations
468  */
469 static void
470 register_next_host (struct Slave *slave)
471 {
472   struct HostRegistration *hr;
473
474   hr = slave->hr_dll_head;
475   GNUNET_assert (NULL != hr);
476   GNUNET_assert (NULL == slave->rhandle);
477   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
478        GNUNET_TESTBED_host_get_id_ (hr->host),
479        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
480   slave->rhandle =
481       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
482                                     slave);
483 }
484
485
486 /**
487  * Callback which will be called to after a host registration succeeded or failed
488  *
489  * @param cls the handle to the slave at which the registration is completed
490  * @param emsg the error message; NULL if host registration is successful
491  */
492 static void
493 hr_completion (void *cls, const char *emsg)
494 {
495   struct Slave *slave = cls;
496   struct HostRegistration *hr;
497
498   slave->rhandle = NULL;
499   hr = slave->hr_dll_head;
500   GNUNET_assert (NULL != hr);
501   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
502        GNUNET_TESTBED_host_get_id_ (hr->host),
503        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
504   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
505   if (NULL != hr->cb)
506     hr->cb (hr->cb_cls, emsg);
507   GNUNET_free (hr);
508   if (NULL != slave->hr_dll_head)
509     register_next_host (slave);
510 }
511
512
513 /**
514  * Adds a host registration's request to a slave's registration queue
515  *
516  * @param slave the slave controller at which the given host has to be
517  *          registered
518  * @param cb the host registration completion callback
519  * @param cb_cls the closure for the host registration completion callback
520  * @param host the host which has to be registered
521  */
522 void
523 GST_queue_host_registration (struct Slave *slave,
524                              GNUNET_TESTBED_HostRegistrationCompletion cb,
525                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
526 {
527   struct HostRegistration *hr;
528   int call_register;
529
530   LOG (GNUNET_ERROR_TYPE_DEBUG,
531        "Queueing host registration for host %u at %u\n",
532        GNUNET_TESTBED_host_get_id_ (host),
533        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
534   hr = GNUNET_malloc (sizeof (struct HostRegistration));
535   hr->cb = cb;
536   hr->cb_cls = cb_cls;
537   hr->host = host;
538   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
539   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
540   if (GNUNET_YES == call_register)
541     register_next_host (slave);
542 }
543
544
545 /**
546  * The  Link Controller forwarding task
547  *
548  * @param cls the LCFContext
549  * @param tc the Task context from scheduler
550  */
551 static void
552 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
553
554
555 /**
556  * Completion callback for host registrations while forwarding Link Controller messages
557  *
558  * @param cls the LCFContext
559  * @param emsg the error message; NULL if host registration is successful
560  */
561 static void
562 lcf_proc_cc (void *cls, const char *emsg)
563 {
564   struct LCFContext *lcf = cls;
565
566   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
567   switch (lcf->state)
568   {
569   case INIT:
570     if (NULL != emsg)
571       goto registration_error;
572     lcf->state = DELEGATED_HOST_REGISTERED;
573     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
574     break;
575   case DELEGATED_HOST_REGISTERED:
576     if (NULL != emsg)
577       goto registration_error;
578     lcf->state = SLAVE_HOST_REGISTERED;
579     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
580     break;
581   default:
582     GNUNET_assert (0);          /* Shouldn't reach here */
583   }
584   return;
585
586 registration_error:
587   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
588        emsg);
589   lcf->state = FINISHED;
590   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
591 }
592
593
594 /**
595  * Callback to relay the reply msg of a forwarded operation back to the client
596  *
597  * @param cls ForwardedOperationContext
598  * @param msg the message to relay
599  */
600 void
601 GST_forwarded_operation_reply_relay (void *cls,
602                                      const struct GNUNET_MessageHeader *msg)
603 {
604   struct ForwardedOperationContext *fopc = cls;
605   struct GNUNET_MessageHeader *dup_msg;
606   uint16_t msize;
607
608   msize = ntohs (msg->size);
609   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
610              msize);
611   dup_msg = GNUNET_copy_message (msg);
612   GST_queue_message (fopc->client, dup_msg);
613   GNUNET_SERVER_client_drop (fopc->client);
614   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
615   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
616   GNUNET_free (fopc);
617 }
618
619
620 /**
621  * Task to free resources when forwarded operation has been timedout
622  *
623  * @param cls the ForwardedOperationContext
624  * @param tc the task context from scheduler
625  */
626 void
627 GST_forwarded_operation_timeout (void *cls,
628                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
629 {
630   struct ForwardedOperationContext *fopc = cls;
631
632   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
633   LOG (GNUNET_ERROR_TYPE_DEBUG, "A forwarded operation has timed out\n");
634   GST_send_operation_fail_msg (fopc->client, fopc->operation_id,
635                                "A forwarded operation has timed out");
636   GNUNET_SERVER_client_drop (fopc->client);
637   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
638   GNUNET_free (fopc);
639 }
640
641
642 /**
643  * The  Link Controller forwarding task
644  *
645  * @param cls the LCFContext
646  * @param tc the Task context from scheduler
647  */
648 static void
649 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
650
651
652 /**
653  * Task to free resources when forwarded link controllers has been timedout
654  *
655  * @param cls the LCFContext
656  * @param tc the task context from scheduler
657  */
658 static void
659 lcf_forwarded_operation_timeout (void *cls,
660                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
661 {
662   struct LCFContext *lcf = cls;
663
664   lcf->timeout_task = GNUNET_SCHEDULER_NO_TASK;
665   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
666   LOG (GNUNET_ERROR_TYPE_WARNING,
667        "A forwarded controller link operation has timed out\n");
668   send_controller_link_response (lcf->client, lcf->operation_id, NULL,
669                                  "A forwarded controller link operation has "
670                                  "timed out\n");
671   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
672   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
673 }
674
675
676 /**
677  * The  Link Controller forwarding task
678  *
679  * @param cls the LCFContext
680  * @param tc the Task context from scheduler
681  */
682 static void
683 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
684 {
685   struct LCFContext *lcf = cls;
686   struct LCFContextQueue *lcfq;
687
688   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
689   switch (lcf->state)
690   {
691   case INIT:
692     if (GNUNET_NO ==
693         GNUNET_TESTBED_is_host_registered_ (GST_host_list
694                                             [lcf->delegated_host_id],
695                                             lcf->gateway->controller))
696     {
697       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
698                                    GST_host_list[lcf->delegated_host_id]);
699     }
700     else
701     {
702       lcf->state = DELEGATED_HOST_REGISTERED;
703       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
704     }
705     break;
706   case DELEGATED_HOST_REGISTERED:
707     if (GNUNET_NO ==
708         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
709                                             lcf->gateway->controller))
710     {
711       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
712                                    GST_host_list[lcf->slave_host_id]);
713     }
714     else
715     {
716       lcf->state = SLAVE_HOST_REGISTERED;
717       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
718     }
719     break;
720   case SLAVE_HOST_REGISTERED:
721     lcf->op = GNUNET_TESTBED_controller_link (lcf,
722                                               lcf->gateway->controller,
723                                               GST_host_list[lcf->delegated_host_id],
724                                               GST_host_list[lcf->slave_host_id],
725                                               NULL,
726                                               lcf->is_subordinate);
727     lcf->timeout_task =
728         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
729                                       lcf);
730     lcf->state = FINISHED;
731     break;
732   case FINISHED:
733     lcfq = lcfq_head;
734     GNUNET_assert (lcfq->lcf == lcf);
735     GNUNET_assert (NULL != lcf->cfg);
736     GNUNET_CONFIGURATION_destroy (lcf->cfg);
737     GNUNET_SERVER_client_drop (lcf->client);
738     GNUNET_TESTBED_operation_done (lcf->op);
739     GNUNET_free (lcf);
740     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
741     GNUNET_free (lcfq);
742     if (NULL != lcfq_head)
743       lcf_proc_task_id =
744           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
745   }
746 }
747
748
749 /**
750  * Callback for event from slave controllers
751  *
752  * @param cls struct Slave *
753  * @param event information about the event
754  */
755 static void
756 slave_event_callback (void *cls,
757                       const struct GNUNET_TESTBED_EventInformation *event)
758 {
759   struct RegisteredHostContext *rhc;
760   struct LCFContext *lcf;
761   struct GNUNET_CONFIGURATION_Handle *cfg;
762   struct GNUNET_TESTBED_Operation *old_op;
763
764   /* We currently only get here when working on RegisteredHostContexts and
765      LCFContexts */
766   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
767   rhc = event->op_cls;
768   if (CLOSURE_TYPE_RHC == rhc->type)
769   {
770     GNUNET_assert (rhc->sub_op == event->op);
771     switch (rhc->state)
772     {
773     case RHC_GET_CFG:
774       cfg = event->details.operation_finished.generic;
775       old_op = rhc->sub_op;
776       rhc->state = RHC_LINK;
777       rhc->sub_op =
778           GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
779                                           rhc->reg_host, rhc->host, cfg,
780                                           GNUNET_NO);
781       GNUNET_TESTBED_operation_done (old_op);
782       break;
783     case RHC_LINK:
784       LOG_DEBUG ("OL: Linking controllers successfull\n");
785       GNUNET_TESTBED_operation_done (rhc->sub_op);
786       rhc->sub_op = NULL;
787       rhc->state = RHC_OL_CONNECT;
788       GST_process_next_focc (rhc);
789       break;
790     default:
791       GNUNET_assert (0);
792     }
793     return;
794   }
795   lcf = event->op_cls;
796   if (CLOSURE_TYPE_LCF == lcf->type)
797   {    
798     GNUNET_assert (lcf->op == event->op);
799     GNUNET_assert (FINISHED == lcf->state);
800     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != lcf->timeout_task);
801     GNUNET_SCHEDULER_cancel (lcf->timeout_task);
802     if (NULL == event->details.operation_finished.emsg)
803       send_controller_link_response (lcf->client, lcf->operation_id,
804                                      GNUNET_TESTBED_host_get_cfg_ 
805                                      (GST_host_list[lcf->delegated_host_id]),
806                                      NULL);
807     else
808       send_controller_link_response (lcf->client, lcf->operation_id,
809                                      NULL,
810                                      event->details.operation_finished.emsg);
811     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
812     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
813     return;
814   }
815   GNUNET_assert (0);
816 }
817
818
819 /**
820  * Callback to signal successfull startup of the controller process
821  *
822  * @param cls the handle to the slave whose status is to be found here
823  * @param cfg the configuration with which the controller has been started;
824  *          NULL if status is not GNUNET_OK
825  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
826  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
827  */
828 static void
829 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
830                        int status)
831 {
832   struct Slave *slave = cls;
833   struct LinkControllersContext *lcc;
834
835   lcc = slave->lcc;
836   if (GNUNET_SYSERR == status)
837   {
838     slave->controller_proc = NULL;
839     GST_slave_list[slave->host_id] = NULL;
840     GNUNET_free (slave);
841     slave = NULL;
842     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
843     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
844     goto clean_lcc;
845   }
846   slave->controller =
847       GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
848                                          event_mask, &slave_event_callback,
849                                          slave);
850   if (NULL != slave->controller)
851   {
852     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
853   }
854   else
855   {
856     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
857                                    "Could not connect to delegated controller");
858     GNUNET_TESTBED_controller_stop (slave->controller_proc);
859     GST_slave_list[slave->host_id] = NULL;
860     GNUNET_free (slave);
861     slave = NULL;
862   }
863
864 clean_lcc:
865   if (NULL != lcc)
866   {
867     if (NULL != lcc->client)
868     {
869       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
870       GNUNET_SERVER_client_drop (lcc->client);
871       lcc->client = NULL;
872     }
873     GNUNET_free (lcc);
874   }
875   if (NULL != slave)
876     slave->lcc = NULL;
877 }
878
879
880 /**
881  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
882  *
883  * @param cls NULL
884  * @param client identification of the client
885  * @param message the actual message
886  */
887 static void
888 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
889              const struct GNUNET_MessageHeader *message)
890 {
891   const struct GNUNET_TESTBED_InitMessage *msg;
892   struct GNUNET_TESTBED_Host *host;
893   const char *controller_hostname;
894   uint16_t msize;
895
896   if (NULL != GST_context)
897   {
898     LOG_DEBUG ("We are being connected to laterally\n");
899     GNUNET_SERVER_receive_done (client, GNUNET_OK);
900     return;
901   }
902   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
903   msize = ntohs (message->size);
904   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
905   {
906     GNUNET_break (0);
907     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
908     return;
909   }
910   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
911   controller_hostname = (const char *) &msg[1];
912   if ('\0' != controller_hostname[msize - 1])
913   {
914     GNUNET_break (0);
915     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
916     return;
917   }
918   GST_context = GNUNET_malloc (sizeof (struct Context));
919   GNUNET_SERVER_client_keep (client);
920   GST_context->client = client;
921   GST_context->host_id = ntohl (msg->host_id);
922   GST_context->master_ip = GNUNET_strdup (controller_hostname);
923   LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
924   GST_context->system =
925       GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
926                                     hostname);
927   host =
928       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
929                                           GST_context->master_ip, NULL,
930                                           our_config, 0);
931   host_list_add (host);
932   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
933   GNUNET_SERVER_receive_done (client, GNUNET_OK);
934 }
935
936
937 /**
938  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
939  *
940  * @param cls NULL
941  * @param client identification of the client
942  * @param message the actual message
943  */
944 static void
945 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
946                  const struct GNUNET_MessageHeader *message)
947 {
948   struct GNUNET_TESTBED_Host *host;
949   const struct GNUNET_TESTBED_AddHostMessage *msg;
950   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
951   struct GNUNET_CONFIGURATION_Handle *host_cfg;
952   char *username;
953   char *hostname;
954   char *emsg;
955   const void *ptr;
956   uint32_t host_id;
957   uint16_t username_length;
958   uint16_t hostname_length;
959   uint16_t reply_size;
960   uint16_t msize;
961
962   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
963   msize = ntohs (msg->header.size);
964   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
965   {
966     GNUNET_break_op (0);
967     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
968     return;
969   }
970   username_length = ntohs (msg->username_length);
971   hostname_length = ntohs (msg->hostname_length);
972   /* msg must contain hostname */
973   if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
974                  username_length))
975       || (0 == hostname_length))
976   {
977     GNUNET_break_op (0);
978     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
979     return;
980   }
981   /* msg must contain configuration */
982   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
983                 username_length + hostname_length))
984   {
985     GNUNET_break_op (0);
986     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
987     return;
988   }
989   username = NULL;
990   hostname = NULL;
991   ptr = &msg[1];
992   if (0 != username_length)
993   {
994     username = GNUNET_malloc (username_length + 1);
995     strncpy (username, ptr, username_length);
996     ptr += username_length;
997   }
998   hostname = GNUNET_malloc (hostname_length + 1);
999   strncpy (hostname, ptr, hostname_length);
1000   ptr += hostname_length;
1001   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
1002   {
1003     GNUNET_free_non_null (username);
1004     GNUNET_free_non_null (hostname);
1005     GNUNET_break_op (0);
1006     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1007     return;
1008   }
1009   host_id = ntohl (msg->host_id);
1010   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
1011   LOG_DEBUG ("-------host id: %u\n", host_id);
1012   LOG_DEBUG ("-------hostname: %s\n", hostname);
1013   if (NULL != username)
1014     LOG_DEBUG ("-------username: %s\n", username);
1015   else
1016     LOG_DEBUG ("-------username: <not given>\n");
1017   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1018   host =
1019       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1020                                           host_cfg, ntohs (msg->ssh_port));
1021   GNUNET_free_non_null (username);
1022   GNUNET_free (hostname);
1023   GNUNET_CONFIGURATION_destroy (host_cfg);
1024   if (NULL == host)
1025   {
1026     GNUNET_break_op (0);
1027     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1028     return;
1029   }
1030   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1031   if (GNUNET_OK != host_list_add (host))
1032   {
1033     /* We are unable to add a host */
1034     emsg = "A host exists with given host-id";
1035     LOG_DEBUG ("%s: %u", emsg, host_id);
1036     GNUNET_TESTBED_host_destroy (host);
1037     reply_size += strlen (emsg) + 1;
1038     reply = GNUNET_malloc (reply_size);
1039     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1040   }
1041   else
1042   {
1043     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
1044     reply = GNUNET_malloc (reply_size);
1045   }
1046   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
1047   reply->header.size = htons (reply_size);
1048   reply->host_id = htonl (host_id);
1049   GST_queue_message (client, &reply->header);
1050   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1051 }
1052
1053
1054 /**
1055  * Iterator over hash map entries.
1056  *
1057  * @param cls closure
1058  * @param key current key code
1059  * @param value value in the hash map
1060  * @return GNUNET_YES if we should continue to
1061  *         iterate,
1062  *         GNUNET_NO if not.
1063  */
1064 int
1065 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1066 {
1067   struct SharedService *queried_ss = cls;
1068   struct SharedService *ss = value;
1069
1070   if (0 == strcmp (ss->name, queried_ss->name))
1071     return GNUNET_NO;
1072   else
1073     return GNUNET_YES;
1074 }
1075
1076
1077 /**
1078  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1079  *
1080  * @param cls NULL
1081  * @param client identification of the client
1082  * @param message the actual message
1083  */
1084 static void
1085 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1086                                  const struct GNUNET_MessageHeader *message)
1087 {
1088   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1089   struct SharedService *ss;
1090   char *service_name;
1091   struct GNUNET_HashCode hash;
1092   uint16_t msg_size;
1093   uint16_t service_name_size;
1094
1095   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1096   msg_size = ntohs (message->size);
1097   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1098   {
1099     GNUNET_break (0);
1100     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1101     return;
1102   }
1103   service_name_size =
1104       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1105   service_name = (char *) &msg[1];
1106   if ('\0' != service_name[service_name_size - 1])
1107   {
1108     GNUNET_break (0);
1109     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1110     return;
1111   }
1112   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1113              service_name, ntohl (msg->num_peers));
1114   if (ntohl (msg->host_id) != GST_context->host_id)
1115   {
1116     route_message (ntohl (msg->host_id), message);
1117     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1118     return;
1119   }
1120   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1121   ss = GNUNET_malloc (sizeof (struct SharedService));
1122   ss->name = strdup (service_name);
1123   ss->num_shared = ntohl (msg->num_peers);
1124   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1125   if (GNUNET_SYSERR ==
1126       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1127                                                   &ss_exists_iterator, ss))
1128   {
1129     LOG (GNUNET_ERROR_TYPE_WARNING,
1130          "Service %s already configured as a shared service. "
1131          "Ignoring service sharing request \n", ss->name);
1132     GNUNET_free (ss->name);
1133     GNUNET_free (ss);
1134     return;
1135   }
1136   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1137                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1138 }
1139
1140
1141 /**
1142  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1143  *
1144  * @param cls NULL
1145  * @param client identification of the client
1146  * @param message the actual message
1147  */
1148 static void
1149 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1150                          const struct GNUNET_MessageHeader *message)
1151 {
1152   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1153   struct GNUNET_CONFIGURATION_Handle *cfg;
1154   struct LCFContextQueue *lcfq;
1155   struct Route *route;
1156   struct Route *new_route;
1157   uint32_t delegated_host_id;
1158   uint32_t slave_host_id;
1159   uint16_t msize;
1160
1161   if (NULL == GST_context)
1162   {
1163     GNUNET_break (0);
1164     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1165     return;
1166   }
1167   msize = ntohs (message->size);
1168   if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
1169   {
1170     GNUNET_break (0);
1171     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1172     return;
1173   }
1174   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1175   delegated_host_id = ntohl (msg->delegated_host_id);
1176   if (delegated_host_id == GST_context->host_id)
1177   {
1178     GNUNET_break (0);
1179     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1180     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1181     return;
1182   }
1183   if ((delegated_host_id >= GST_host_list_size) ||
1184       (NULL == GST_host_list[delegated_host_id]))
1185   {
1186     LOG (GNUNET_ERROR_TYPE_WARNING,
1187          "Delegated host %u not registered with us\n", delegated_host_id);
1188     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1189     return;
1190   }
1191   slave_host_id = ntohl (msg->slave_host_id);
1192   if ((slave_host_id >= GST_host_list_size) ||
1193       (NULL == GST_host_list[slave_host_id]))
1194   {
1195     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1196          slave_host_id);
1197     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1198     return;
1199   }
1200   if (slave_host_id == delegated_host_id)
1201   {
1202     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1203     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1204     return;
1205   }
1206   cfg = GNUNET_TESTBED_extract_config_ (message); /* destroy cfg here or in lcfcontext */
1207   if (NULL == cfg)
1208   {
1209     GNUNET_break (0);         /* Configuration parsing error */
1210     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1211     return;
1212   }
1213   if (slave_host_id == GST_context->host_id)    /* Link from us */
1214   {
1215     struct Slave *slave;
1216     struct LinkControllersContext *lcc;
1217
1218     if ((delegated_host_id < GST_slave_list_size) &&
1219         (NULL != GST_slave_list[delegated_host_id]))
1220     {
1221       GNUNET_break (0);
1222       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1223       return;
1224     }
1225     slave = GNUNET_malloc (sizeof (struct Slave));
1226     slave->host_id = delegated_host_id;
1227     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1228     slave_list_add (slave);
1229     if (1 != msg->is_subordinate)
1230     {
1231       slave->controller =
1232           GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
1233                                              event_mask, &slave_event_callback,
1234                                              slave);
1235       if (NULL != slave->controller)
1236         send_controller_link_response (client,
1237                                        GNUNET_ntohll (msg->operation_id),
1238                                        NULL,
1239                                        NULL);
1240       else
1241         send_controller_link_response (client,
1242                                        GNUNET_ntohll (msg->operation_id),
1243                                        NULL,
1244                                        "Could not connect to delegated controller");
1245       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1246       return;
1247     }
1248     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1249     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1250     GNUNET_SERVER_client_keep (client);
1251     lcc->client = client;
1252     slave->lcc = lcc;
1253     slave->controller_proc =
1254         GNUNET_TESTBED_controller_start (GST_context->master_ip,
1255                                          GST_host_list[slave->host_id], cfg,
1256                                          &slave_status_callback, slave);
1257     GNUNET_CONFIGURATION_destroy (cfg);
1258     new_route = GNUNET_malloc (sizeof (struct Route));
1259     new_route->dest = delegated_host_id;
1260     new_route->thru = GST_context->host_id;
1261     route_list_add (new_route);
1262     return;
1263   }
1264
1265   /* Route the request */
1266   if (slave_host_id >= route_list_size)
1267   {
1268     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1269     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1270     return;
1271   }
1272   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1273   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1274   lcfq->lcf->type = CLOSURE_TYPE_LCF;
1275   lcfq->lcf->delegated_host_id = delegated_host_id;
1276   lcfq->lcf->slave_host_id = slave_host_id;
1277   route = GST_find_dest_route (slave_host_id);
1278   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1279   GNUNET_assert (route->dest < GST_slave_list_size);
1280   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1281   lcfq->lcf->cfg = cfg;
1282   lcfq->lcf->is_subordinate = msg->is_subordinate;
1283   lcfq->lcf->state = INIT;
1284   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1285   lcfq->lcf->gateway = GST_slave_list[route->dest];
1286   GNUNET_SERVER_client_keep (client);
1287   lcfq->lcf->client = client;
1288   if (NULL == lcfq_head)
1289   {
1290     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1291     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1292     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1293   }
1294   else
1295     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1296   /* FIXME: Adding a new route should happen after the controllers are linked
1297    * successfully */
1298   if (1 != msg->is_subordinate)
1299   {
1300     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1301     return;
1302   }
1303   if ((delegated_host_id < route_list_size) &&
1304       (NULL != route_list[delegated_host_id]))
1305   {
1306     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1307                                  * with is subordinate flag set to GNUNET_YES? */
1308     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1309     return;
1310   }
1311   new_route = GNUNET_malloc (sizeof (struct Route));
1312   new_route->dest = delegated_host_id;
1313   new_route->thru = route->dest;
1314   route_list_add (new_route);
1315   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1316 }
1317
1318
1319 /**
1320  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1321  *
1322  * @param cls NULL
1323  * @param client identification of the client
1324  * @param message the actual message
1325  */
1326 static void
1327 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1328                          const struct GNUNET_MessageHeader *message)
1329 {
1330   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1331   struct Slave *slave;
1332   struct GNUNET_TESTBED_SlaveConfiguration *reply;
1333   const struct GNUNET_CONFIGURATION_Handle *cfg;
1334   char *config;
1335   char *xconfig;
1336   size_t config_size;
1337   size_t xconfig_size;
1338   size_t reply_size;
1339   uint64_t op_id;
1340   uint32_t slave_id;
1341
1342   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
1343   slave_id = ntohl (msg->slave_id);
1344   op_id = GNUNET_ntohll (msg->operation_id);
1345   if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
1346   {
1347     /* FIXME: Add forwardings for this type of message here.. */
1348     GST_send_operation_fail_msg (client, op_id, "Slave not found");
1349     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1350     return;
1351   }
1352   slave = GST_slave_list[slave_id];
1353   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
1354   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1355   xconfig_size =
1356       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1357   GNUNET_free (config);
1358   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
1359   GNUNET_break (reply_size <= UINT16_MAX);
1360   GNUNET_break (config_size <= UINT16_MAX);
1361   reply = GNUNET_realloc (xconfig, reply_size);
1362   (void) memmove (&reply[1], reply, xconfig_size);
1363   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
1364   reply->header.size = htons ((uint16_t) reply_size);
1365   reply->slave_id = msg->slave_id;
1366   reply->operation_id = msg->operation_id;
1367   reply->config_size = htons ((uint16_t) config_size);
1368   GST_queue_message (client, &reply->header);
1369   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1370 }
1371
1372
1373 /**
1374  * Clears the forwarded operations queue
1375  */
1376 void
1377 GST_clear_fopcq ()
1378 {
1379   struct ForwardedOperationContext *fopc;
1380   
1381   while (NULL != (fopc = fopcq_head))
1382   {
1383     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
1384     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1385     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
1386       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
1387     GNUNET_SERVER_client_drop (fopc->client);
1388     switch (fopc->type)
1389     {
1390     case OP_PEER_CREATE:
1391       GNUNET_free (fopc->cls);
1392       break;
1393     case OP_SHUTDOWN_PEERS:
1394       {
1395         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
1396         
1397         GNUNET_assert (0 < hc->nslaves);
1398         hc->nslaves--;
1399         if (0 == hc->nslaves)
1400           GNUNET_free (hc);
1401       }
1402       break;
1403     case OP_PEER_START:
1404     case OP_PEER_STOP:
1405     case OP_PEER_DESTROY:
1406     case OP_PEER_INFO:
1407     case OP_OVERLAY_CONNECT:
1408     case OP_LINK_CONTROLLERS:
1409     case OP_GET_SLAVE_CONFIG:
1410     case OP_MANAGE_SERVICE:
1411       break;
1412     case OP_FORWARDED:
1413       GNUNET_assert (0);
1414     };
1415     GNUNET_free (fopc);
1416   }
1417 }
1418
1419
1420 /**
1421  * Iterator over hash map entries.
1422  *
1423  * @param cls closure
1424  * @param key current key code
1425  * @param value value in the hash map
1426  * @return GNUNET_YES if we should continue to
1427  *         iterate,
1428  *         GNUNET_NO if not.
1429  */
1430 static int
1431 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1432 {
1433   struct SharedService *ss = value;
1434
1435   GNUNET_assert (GNUNET_YES ==
1436                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
1437   GNUNET_free (ss->name);
1438   GNUNET_free (ss);
1439   return GNUNET_YES;
1440 }
1441
1442
1443 /**
1444  * Iterator for freeing hash map entries in a slave's reghost_map
1445  *
1446  * @param cls handle to the slave
1447  * @param key current key code
1448  * @param value value in the hash map
1449  * @return GNUNET_YES if we should continue to
1450  *         iterate,
1451  *         GNUNET_NO if not.
1452  */
1453 static int
1454 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
1455                        void *value)
1456 {
1457   struct Slave *slave = cls;
1458   struct RegisteredHostContext *rhc = value;
1459   struct ForwardedOverlayConnectContext *focc;
1460
1461   GNUNET_assert (GNUNET_YES ==
1462                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
1463                                                        value));
1464   while (NULL != (focc = rhc->focc_dll_head))
1465   {
1466     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
1467     GST_cleanup_focc (focc);
1468   }
1469   if (NULL != rhc->sub_op)
1470     GNUNET_TESTBED_operation_done (rhc->sub_op);
1471   if (NULL != rhc->client)
1472     GNUNET_SERVER_client_drop (rhc->client);
1473   GNUNET_free (value);
1474   return GNUNET_YES;
1475 }
1476
1477
1478 /**
1479  * Task to clean up and shutdown nicely
1480  *
1481  * @param cls NULL
1482  * @param tc the TaskContext from scheduler
1483  */
1484 static void
1485 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1486 {
1487   struct LCFContextQueue *lcfq;
1488   struct MessageQueue *mq_entry;
1489   uint32_t id;
1490
1491   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
1492   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
1493   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
1494                                                 NULL);
1495   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
1496   /* cleanup any remaining forwarded operations */
1497   GST_clear_fopcq ();
1498   if (NULL != lcfq_head)
1499   {
1500     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
1501     {
1502       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1503       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1504     }
1505   }
1506   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1507   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
1508   {
1509     GNUNET_SERVER_client_drop (lcfq->lcf->client);
1510     GNUNET_assert (NULL != lcfq->lcf->cfg);
1511     GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
1512     GNUNET_free (lcfq->lcf);
1513     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1514     GNUNET_free (lcfq);
1515   }
1516   GST_free_mctxq ();
1517   GST_free_occq ();
1518   GST_free_roccq ();
1519   /* Clear peer list */
1520   GST_destroy_peers ();
1521   /* Clear host list */
1522   for (id = 0; id < GST_host_list_size; id++)
1523     if (NULL != GST_host_list[id])
1524       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
1525   GNUNET_free_non_null (GST_host_list);
1526   /* Clear route list */
1527   for (id = 0; id < route_list_size; id++)
1528     if (NULL != route_list[id])
1529       GNUNET_free (route_list[id]);
1530   GNUNET_free_non_null (route_list);
1531   /* Clear GST_slave_list */
1532   for (id = 0; id < GST_slave_list_size; id++)
1533     if (NULL != GST_slave_list[id])
1534     {
1535       struct HostRegistration *hr_entry;
1536
1537       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
1538       {
1539         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
1540                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
1541         GNUNET_free (hr_entry);
1542       }
1543       if (NULL != GST_slave_list[id]->rhandle)
1544         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
1545       (void)
1546           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
1547                                                  [id]->reghost_map,
1548                                                  reghost_free_iterator,
1549                                                  GST_slave_list[id]);
1550       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
1551       if (NULL != GST_slave_list[id]->controller)
1552         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
1553       if (NULL != GST_slave_list[id]->controller_proc)
1554         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
1555       GNUNET_free (GST_slave_list[id]);
1556     }
1557   GNUNET_free_non_null (GST_slave_list);
1558   if (NULL != GST_context)
1559   {
1560     GNUNET_free_non_null (GST_context->master_ip);
1561     if (NULL != GST_context->system)
1562       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
1563     GNUNET_SERVER_client_drop (GST_context->client);
1564     GNUNET_free (GST_context);
1565     GST_context = NULL;
1566   }
1567   if (NULL != transmit_handle)
1568     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
1569   while (NULL != (mq_entry = mq_head))
1570   {
1571     GNUNET_free (mq_entry->msg);
1572     GNUNET_SERVER_client_drop (mq_entry->client);
1573     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
1574     GNUNET_free (mq_entry);
1575   }
1576   GNUNET_free_non_null (hostname);
1577   GNUNET_CONFIGURATION_destroy (our_config);
1578   /* Free hello cache */
1579   GST_cache_clear ();
1580   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
1581   GST_opq_openfds = NULL;
1582   GST_stats_destroy ();
1583 }
1584
1585
1586 /**
1587  * Callback for client disconnect
1588  *
1589  * @param cls NULL
1590  * @param client the client which has disconnected
1591  */
1592 static void
1593 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
1594 {
1595   if (NULL == GST_context)
1596     return;
1597   if (client == GST_context->client)
1598   {
1599     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
1600     /* should not be needed as we're terminated by failure to read
1601      * from stdin, but if stdin fails for some reason, this shouldn't
1602      * hurt for now --- might need to revise this later if we ever
1603      * decide that master connections might be temporarily down
1604      * for some reason */
1605     //GNUNET_SCHEDULER_shutdown ();
1606   }
1607 }
1608
1609
1610 /**
1611  * Testbed setup
1612  *
1613  * @param cls closure
1614  * @param server the initialized server
1615  * @param cfg configuration to use
1616  */
1617 static void
1618 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
1619              const struct GNUNET_CONFIGURATION_Handle *cfg)
1620 {
1621   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
1622     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
1623     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
1624     {&handle_configure_shared_service, NULL,
1625      GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
1626     {&handle_link_controllers, NULL,
1627      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
1628     {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
1629     {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
1630      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
1631     {&GST_handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
1632      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
1633     {&GST_handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
1634      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
1635     {&GST_handle_peer_get_config, NULL,
1636      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
1637      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
1638     {&GST_handle_overlay_connect, NULL,
1639      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
1640      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
1641     {&GST_handle_remote_overlay_connect, NULL,
1642      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
1643     {&GST_handle_manage_peer_service, NULL,
1644      GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
1645     {&handle_slave_get_config, NULL,
1646      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
1647      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
1648     {&GST_handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
1649      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
1650     {NULL}
1651   };
1652   char *logfile;
1653   unsigned long long num;
1654
1655   if (GNUNET_OK ==
1656       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
1657                                                &logfile))
1658   {
1659     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
1660     GNUNET_free (logfile);
1661   }
1662   GNUNET_assert (GNUNET_OK ==
1663                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
1664                                                         "CACHE_SIZE", &num));
1665   GST_cache_init ((unsigned int) num);
1666   GNUNET_assert (GNUNET_OK ==
1667                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
1668                                                         "MAX_OPEN_FDS", &num));
1669   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
1670   GNUNET_assert (GNUNET_OK ==
1671                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
1672                                                       "OPERATION_TIMEOUT",
1673                                                       (struct
1674                                                        GNUNET_TIME_Relative *)
1675                                                       &GST_timeout));
1676   GNUNET_assert (GNUNET_OK ==
1677                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
1678                                                         "HOSTNAME", &hostname));
1679   our_config = GNUNET_CONFIGURATION_dup (cfg);
1680   GNUNET_SERVER_add_handlers (server, message_handlers);
1681   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
1682   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
1683   shutdown_task_id =
1684       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
1685                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1686                                                   &shutdown_task, NULL);
1687   LOG_DEBUG ("Testbed startup complete\n");
1688   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
1689   GST_stats_init (our_config);
1690 }
1691
1692
1693 /**
1694  * The starting point of execution
1695  */
1696 int
1697 main (int argc, char *const *argv)
1698 {
1699   //sleep (15);                 /* Debugging */
1700   return (GNUNET_OK ==
1701           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
1702                               &testbed_run, NULL)) ? 0 : 1;
1703 }
1704
1705 /* end of gnunet-service-testbed.c */