-clearing LCFContext queue on shutdown
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
1 /*
2   This file is part of GNUnet.
3   (C) 2012 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 "platform.h"
28 #include "gnunet_service_lib.h"
29 #include "gnunet_server_lib.h"
30 #include <zlib.h>
31
32 #include "testbed.h"
33 #include "gnunet_testbed_service.h"
34 #include "testbed_api_hosts.h"
35
36 /**
37  * Generic logging
38  */
39 #define LOG(kind,...)                           \
40   GNUNET_log (kind, __VA_ARGS__)
41
42 /**
43  * Debug logging
44  */
45 #define LOG_DEBUG(...)                          \
46   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
47
48 struct Context
49 {
50   /**
51    * The client handle associated with this context
52    */
53   struct GNUNET_SERVER_Client *client;
54   
55   /**
56    * Event mask of event to be responded in this context
57    */
58   uint64_t event_mask;
59
60   /**
61    * Our host id according to this context
62    */
63   uint32_t host_id;
64 };
65
66
67 /**
68  * The message queue for sending messages to clients
69  */
70 struct MessageQueue
71 {
72   /**
73    * The message to be sent
74    */
75   struct GNUNET_MessageHeader *msg;
76
77   /**
78    * The client to send the message to
79    */
80   struct GNUNET_SERVER_Client *client;
81   
82   /**
83    * next pointer for DLL
84    */
85   struct MessageQueue *next;
86   
87   /**
88    * prev pointer for DLL
89    */
90   struct MessageQueue *prev;
91 };
92
93
94 /**
95  * The structure for identifying a shared service
96  */
97 struct SharedService
98 {
99   /**
100    * The name of the shared service
101    */
102   char *name;
103
104   /**
105    * Number of shared peers per instance of the shared service
106    */
107   uint32_t num_shared;
108
109   /**
110    * Number of peers currently sharing the service
111    */
112   uint32_t num_sharing;
113 };
114
115
116 /**
117  * A routing entry
118  */
119 struct Route
120 {
121   /**
122    * The forwarding (next hop) host id
123    */
124   uint32_t next_hop;
125
126   /**
127    * The controller handle if we have started the controller at the next hop
128    * host 
129    */
130   struct GNUNET_TESTBED_Controller *fcontroller;
131 };
132
133
134 /**
135  * States of LCFContext
136  */
137 enum LCFContextState
138   {
139     /**
140      * The Context has been initialized; Nothing has been done on it
141      */
142     INIT,
143
144     /**
145      * Delegated host has been registered at the forwarding controller
146      */
147     DELEGATED_HOST_REGISTERED,
148     
149     /**
150      * The slave host has been registred at the forwarding controller
151      */
152     SLAVE_HOST_REGISTERED,
153
154     /**
155      * The context has been finished (may have error)
156      */
157     FINISHED
158
159   };
160
161
162 /**
163  * Link controllers request forwarding context
164  */
165 struct LCFContext
166 {
167   /**
168    * The configuration
169    */
170   struct GNUNET_CONFIGURATION_Handle *cfg;
171
172   /**
173    * The handle of the controller this request has to be forwarded to
174    */
175   struct GNUNET_TESTBED_Controller *fcontroller;
176
177   /**
178    * The host registration handle while registered hosts in this context
179    */
180   struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
181
182   /**
183    * Should the delegated host be started by the slave host?
184    */
185   int is_subordinate;
186
187   /**
188    * The state of this context
189    */
190   enum LCFContextState state;
191
192   /**
193    * The delegated host
194    */
195   uint32_t delegated_host_id;
196
197   /**
198    * The slave host
199    */
200   uint32_t slave_host_id;
201
202 };
203
204
205 /**
206  * Structure of a queue entry in LCFContext request queue
207  */
208 struct LCFContextQueue
209 {
210   /**
211    * The LCFContext
212    */
213   struct LCFContext *lcf;
214
215   /**
216    * Head prt for DLL
217    */
218   struct LCFContextQueue *next;
219
220   /**
221    * Tail ptr for DLL
222    */
223   struct LCFContextQueue *prev;
224 };
225
226
227 /**
228  * The master context; generated with the first INIT message
229  */
230 static struct Context *master_context;
231
232 /***********/
233 /* Handles */
234 /***********/
235
236 /**
237  * Wrapped stdin.
238  */
239 static struct GNUNET_DISK_FileHandle *fh;
240
241 /**
242  * Current Transmit Handle; NULL if no notify transmit exists currently
243  */
244 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
245
246 /****************/
247 /* Lists & Maps */
248 /****************/
249
250 /**
251  * The head for the LCF queue
252  */
253 static struct LCFContextQueue *lcfq_head;
254
255 /**
256  * The tail for the LCF queue
257  */
258 static struct LCFContextQueue *lcfq_tail;
259
260 /**
261  * The message queue head
262  */
263 static struct MessageQueue *mq_head;
264
265 /**
266  * The message queue tail
267  */
268 static struct MessageQueue *mq_tail;
269
270 /**
271  * Array of host list
272  */
273 static struct GNUNET_TESTBED_Host **host_list;
274
275 /**
276  * A list of routes
277  */
278 static struct Route **route_list;
279
280 /**
281  * The hashmap of shared services
282  */
283 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
284
285 /**
286  * The size of the host list
287  */
288 static uint32_t host_list_size;
289
290 /**
291  * The size of the route list
292  */
293 static uint32_t route_list_size;
294
295 /*********/
296 /* Tasks */
297 /*********/
298
299 /**
300  * The lcf_task handle
301  */
302 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
303
304 /**
305  * The shutdown task handle
306  */
307 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
308
309
310 /**
311  * Function called to notify a client about the connection begin ready to queue
312  * more data.  "buf" will be NULL and "size" zero if the connection was closed
313  * for writing in the meantime.
314  *
315  * @param cls NULL
316  * @param size number of bytes available in buf
317  * @param buf where the callee should write the message
318  * @return number of bytes written to buf
319  */
320 static size_t
321 transmit_ready_notify (void *cls, size_t size, void *buf)
322 {
323   struct MessageQueue *mq_entry;
324
325   transmit_handle = NULL;
326   mq_entry = mq_head;
327   GNUNET_assert (NULL != mq_entry);
328   if (0 == size)
329     return 0;
330   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
331   size = ntohs (mq_entry->msg->size);
332   memcpy (buf, mq_entry->msg, size);
333   GNUNET_free (mq_entry->msg);
334   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
335   GNUNET_free (mq_entry);
336   mq_entry = mq_head;
337   if (NULL != mq_entry)
338     transmit_handle = 
339       GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
340                                            ntohs (mq_entry->msg->size),
341                                            GNUNET_TIME_UNIT_FOREVER_REL,
342                                            &transmit_ready_notify, NULL);
343   return size;
344 }
345
346
347 /**
348  * Queues a message in send queue for sending to the service
349  *
350  * @param client the client to whom the queued message has to be sent
351  * @param msg the message to queue
352  */
353 static void
354 queue_message (struct GNUNET_SERVER_Client *client,
355                struct GNUNET_MessageHeader *msg)
356 {
357   struct MessageQueue *mq_entry;
358   uint16_t type;
359   uint16_t size;
360
361   type = ntohs (msg->type);
362   size = ntohs (msg->size);
363   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
364                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
365   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
366   mq_entry->msg = msg;
367   mq_entry->client = client;
368   LOG_DEBUG ( "Queueing message of type %u, size %u for sending\n", type,
369               ntohs (msg->size));
370   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
371   if (NULL == transmit_handle)
372     transmit_handle = 
373       GNUNET_SERVER_notify_transmit_ready (client, size,
374                                            GNUNET_TIME_UNIT_FOREVER_REL,
375                                            &transmit_ready_notify, NULL);
376 }
377
378
379 /**
380  * Function to add a host to the current list of known hosts
381  *
382  * @param host the host to add 
383  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
384  *           already in use
385  */
386 static int
387 host_list_add (struct GNUNET_TESTBED_Host *host)
388 {
389   uint32_t host_id;
390   
391   host_id = GNUNET_TESTBED_host_get_id_ (host);
392   if (host_list_size <= host_id)
393   {
394     host_list = GNUNET_realloc (host_list, 
395                                 sizeof (struct GNUNET_TESTBED_Host *)
396                                 * (host_id + 10));
397     host_list_size += (host_id + 10);
398   }
399   if (NULL != host_list[host_id])
400   {
401     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
402     return GNUNET_SYSERR;
403   }
404   host_list[host_id] = host;
405   return GNUNET_OK;
406 }
407
408
409 /**
410  * Routes message to a host given its host_id
411  *
412  * @param host_id the id of the destination host
413  * @param msg the message to be routed
414  */
415 static void
416 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
417 {
418   GNUNET_break (0);
419 }
420
421
422 /**
423  * The  Link Controller forwarding task
424  *
425  * @param cls the LCFContext
426  * @param tc the Task context from scheduler
427  */
428 static void
429 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
430
431
432 /**
433  * Completion callback for host registrations while forwarding Link Controller messages
434  *
435  * @param cls the LCFContext
436  * @param emsg the error message; NULL if host registration is successful
437  */
438 static void
439 lcf_proc_cc (void *cls, const char *emsg)
440 {
441   struct LCFContext *lcf = cls;
442
443   lcf->rhandle = NULL;
444   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
445   switch (lcf->state)
446   {
447   case INIT:
448     if (NULL != emsg)
449       goto registration_error;
450     lcf->state = DELEGATED_HOST_REGISTERED;
451     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
452     break;
453   case DELEGATED_HOST_REGISTERED:
454      if (NULL != emsg)
455       goto registration_error;
456      lcf->state = SLAVE_HOST_REGISTERED;
457      lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
458      break;
459   default:
460     GNUNET_assert (0);          /* Shouldn't reach here */
461   }  
462   return;
463
464  registration_error:
465   LOG (GNUNET_ERROR_TYPE_WARNING, 
466        "Host registration failed with message: %s\n", emsg);
467   lcf->state = FINISHED;
468   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
469 }
470
471
472 /**
473  * The  Link Controller forwarding task
474  *
475  * @param cls the LCFContext
476  * @param tc the Task context from scheduler
477  */
478 static void
479 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
480 {
481   struct LCFContext *lcf = cls;
482   struct LCFContextQueue *lcfq;
483
484   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
485   switch (lcf->state)
486   {
487   case INIT:
488     if (GNUNET_NO ==
489         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
490                                             lcf->fcontroller))
491     {
492       lcf->rhandle =
493         GNUNET_TESTBED_register_host (lcf->fcontroller,
494                                       host_list[lcf->delegated_host_id],
495                                       lcf_proc_cc, lcf);                                                   
496     }
497     else
498     {
499       lcf->state = DELEGATED_HOST_REGISTERED;
500       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
501     }
502     break;
503   case DELEGATED_HOST_REGISTERED:
504     if (GNUNET_NO ==
505         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
506                                             lcf->fcontroller))
507     {
508       lcf->rhandle =
509         GNUNET_TESTBED_register_host (lcf->fcontroller,
510                                       host_list[lcf->slave_host_id],
511                                       lcf_proc_cc, lcf);                                                   
512     }
513     else
514     {
515       lcf->state = SLAVE_HOST_REGISTERED;
516       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
517     }
518     break;
519   case SLAVE_HOST_REGISTERED:
520     GNUNET_TESTBED_controller_link (lcf->fcontroller,
521                                     host_list[lcf->delegated_host_id],
522                                     host_list[lcf->slave_host_id],
523                                     lcf->cfg, lcf->is_subordinate);
524     lcf->state = FINISHED;
525     break;
526   case FINISHED:
527     lcfq = lcfq_head;
528     GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
529     GNUNET_free (lcfq->lcf);
530     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
531     GNUNET_free (lcfq);
532     if (NULL != lcfq_head)
533       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
534   }
535 }
536
537
538 /**
539  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
540  *
541  * @param cls NULL
542  * @param client identification of the client
543  * @param message the actual message
544  */
545 static void 
546 handle_init (void *cls,
547              struct GNUNET_SERVER_Client *client,
548              const struct GNUNET_MessageHeader *message)
549 {
550   const struct GNUNET_TESTBED_InitMessage *msg;
551   struct GNUNET_TESTBED_Host *host;
552
553   if (NULL != master_context)
554   {
555     GNUNET_break (0);
556     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
557     return;
558   }
559   msg = (const struct GNUNET_TESTBED_InitMessage *) message;  
560   master_context = GNUNET_malloc (sizeof (struct Context));
561   master_context->client = client;
562   master_context->host_id = ntohl (msg->host_id);
563   host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
564                                              NULL, NULL, 0);
565   host_list_add (host);
566   master_context->event_mask = GNUNET_ntohll (msg->event_mask);
567   GNUNET_SERVER_client_keep (client);
568   LOG_DEBUG ("Created master context with host ID: %u\n",
569              master_context->host_id);
570   GNUNET_SERVER_receive_done (client, GNUNET_OK);
571 }
572
573
574 /**
575  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
576  *
577  * @param cls NULL
578  * @param client identification of the client
579  * @param message the actual message
580  */
581 static void 
582 handle_add_host (void *cls,
583                  struct GNUNET_SERVER_Client *client,
584                  const struct GNUNET_MessageHeader *message)
585 {
586   struct GNUNET_TESTBED_Host *host;
587   const struct GNUNET_TESTBED_AddHostMessage *msg;
588   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
589   char *username;
590   char *hostname;
591   char *emsg;
592   uint32_t host_id;
593   uint16_t username_length;
594   uint16_t hostname_length;
595   uint16_t reply_size;
596   
597   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
598   username_length = ntohs (msg->user_name_length);
599   username_length = (0 == username_length) ? 0 : username_length + 1;
600   username = (char *) &(msg[1]);
601   hostname = username + username_length;
602   if (ntohs (message->size) <=
603       (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length))
604   {
605     GNUNET_break (0);
606     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
607     return;
608   }
609   hostname_length = ntohs (message->size)
610     - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
611   if (strlen (hostname) != hostname_length)
612   {
613     GNUNET_break (0);
614     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
615     return;
616   }
617   host_id = ntohl (msg->host_id);
618   LOG_DEBUG ("Received ADDHOST message\n");
619   LOG_DEBUG ("-------host id: %u\n", host_id);
620   if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
621   if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
622   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
623   host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
624                                              ntohs (msg->ssh_port));
625   GNUNET_SERVER_receive_done (client, GNUNET_OK);
626   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
627   if (GNUNET_OK != host_list_add (host))
628   {    
629     /* We are unable to add a host */  
630     emsg = "A host exists with given host-id";
631     LOG_DEBUG ("%s: %u", emsg, host_id);
632     GNUNET_TESTBED_host_destroy (host);
633     reply_size += strlen (emsg) + 1;
634     reply = GNUNET_malloc (reply_size);
635     memcpy (&reply[1], emsg, strlen (emsg) + 1);
636   }
637   else
638     reply = GNUNET_malloc (reply_size);  
639   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
640   reply->header.size = htons (reply_size);
641   reply->host_id = htonl (host_id);  
642   queue_message (client, (struct GNUNET_MessageHeader *) reply);
643 }
644
645
646 /**
647  * Iterator over hash map entries.
648  *
649  * @param cls closure
650  * @param key current key code
651  * @param value value in the hash map
652  * @return GNUNET_YES if we should continue to
653  *         iterate,
654  *         GNUNET_NO if not.
655  */
656 int ss_exists_iterator (void *cls,
657                         const struct GNUNET_HashCode * key,
658                         void *value)
659 {
660   struct SharedService *queried_ss = cls;
661   struct SharedService *ss = value;
662
663   if (0 == strcmp (ss->name, queried_ss->name))
664     return GNUNET_NO;
665   else
666     return GNUNET_YES;
667 }
668
669 /**
670  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
671  *
672  * @param cls NULL
673  * @param client identification of the client
674  * @param message the actual message
675  */
676 static void 
677 handle_configure_shared_service (void *cls,
678                                  struct GNUNET_SERVER_Client *client,
679                                  const struct GNUNET_MessageHeader *message)
680 {
681   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
682   struct SharedService *ss;
683   char *service_name;
684   struct GNUNET_HashCode hash;
685   uint16_t msg_size;
686   uint16_t service_name_size;
687     
688   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
689   msg_size = ntohs (message->size);
690   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
691   {
692     GNUNET_break (0);
693     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
694     return;
695   }
696   service_name_size = msg_size - 
697     sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
698   service_name = (char *) &msg[1];
699   if ('\0' != service_name[service_name_size - 1])
700   {
701     GNUNET_break (0);
702     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
703     return;
704   }
705   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
706              service_name, ntohl (msg->num_peers));
707   if (ntohl (msg->host_id) != master_context->host_id)
708   {
709     route_message (ntohl (msg->host_id), message);
710     GNUNET_SERVER_receive_done (client, GNUNET_OK);
711     return;
712   }
713   GNUNET_SERVER_receive_done (client, GNUNET_OK);
714   ss = GNUNET_malloc (sizeof (struct SharedService));
715   ss->name = strdup (service_name);
716   ss->num_shared = ntohl (msg->num_peers);
717   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
718   if (GNUNET_SYSERR == 
719       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
720                                                   &ss_exists_iterator, ss))
721   {
722     LOG (GNUNET_ERROR_TYPE_WARNING,
723          "Service %s already configured as a shared service. "
724          "Ignoring service sharing request \n", ss->name);
725     GNUNET_free (ss->name);
726     GNUNET_free (ss);
727     return;
728   }
729   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
730                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);  
731 }
732
733
734 /**
735  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
736  *
737  * @param cls NULL
738  * @param client identification of the client
739  * @param message the actual message
740  */
741 static void 
742 handle_link_controllers (void *cls,
743                          struct GNUNET_SERVER_Client *client,
744                          const struct GNUNET_MessageHeader *message)
745 {
746   const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
747   struct GNUNET_CONFIGURATION_Handle *cfg;
748   struct LCFContextQueue *lcfq;
749   struct Route *route;
750   char *config;  
751   uLongf dest_size;
752   size_t config_size;
753   uint32_t delegated_host_id;
754   uint32_t slave_host_id;
755   uint16_t msize;
756    
757   msize = ntohs (message->size);
758   if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
759   {
760     GNUNET_break (0);
761     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
762     return;
763   }
764   msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
765   delegated_host_id = ntohl (msg->delegated_host_id);
766   if (delegated_host_id == master_context->host_id)
767   {
768     GNUNET_break (0);
769     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
770     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
771     return;
772   }
773   if ((delegated_host_id >= host_list_size) || 
774       (NULL == host_list[delegated_host_id]))
775   {
776     LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
777     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
778     return;
779   }
780   slave_host_id = ntohl (msg->slave_host_id);
781   if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
782   {
783     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
784     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
785     return;
786   }
787
788   config_size = ntohs (msg->config_size);
789   config = GNUNET_malloc (config_size);
790   dest_size = (uLongf) config_size;
791   msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
792   if (Z_OK != uncompress ((Bytef *) config, &dest_size,
793                           (const Bytef *) &msg[1], (uLong) msize))
794   {
795     GNUNET_break (0);           /* Compression error */
796     GNUNET_free (config);
797     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
798     return;
799   }
800   GNUNET_assert (config_size == dest_size);
801   cfg = GNUNET_CONFIGURATION_create ();
802   if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg, config, config_size,
803                                                      GNUNET_NO))
804   {
805     GNUNET_break (0);           /* Configuration parsing error */
806     GNUNET_break (config);
807     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
808     return;
809   }
810   GNUNET_free (config);
811
812   /* If delegated host and slave host are not same we have to forward
813      towards delegated host */
814   if (slave_host_id != delegated_host_id)
815   {
816     if ((slave_host_id >= route_list_size) ||
817         (NULL == (route = route_list[slave_host_id])) ||
818         (NULL == route->fcontroller))
819     {
820       LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
821       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
822       return;
823     }
824     if (slave_host_id == route->next_hop) /* Slave directly connected */
825     {
826       /* Then make slave host and delegated host same so that slave
827          will startup directly link to the delegated host */
828       slave_host_id = delegated_host_id;
829     }
830     lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
831     lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
832     lcfq->lcf->delegated_host_id = delegated_host_id;
833     lcfq->lcf->slave_host_id = slave_host_id;
834     lcfq->lcf->is_subordinate =
835       (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
836     lcfq->lcf->state = INIT;
837     lcfq->lcf->fcontroller = route->fcontroller;
838     lcfq->lcf->cfg = cfg;    
839     if (NULL == lcfq_head)
840     {
841       GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
842       GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
843       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
844     }
845     else
846       GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
847     GNUNET_SERVER_receive_done (client, GNUNET_OK);
848     return;
849   }
850   GNUNET_SERVER_receive_done (client, GNUNET_OK);
851   /* If we are not the slave controller then we have to route the request
852      towards the slave controller */
853   if (1 == msg->is_subordinate)
854   {
855     GNUNET_break (0);           /* FIXME: Implement the slave controller
856                                    startup */ 
857   }  
858   GNUNET_CONFIGURATION_destroy (cfg);
859 }
860
861
862 /**
863  * Iterator over hash map entries.
864  *
865  * @param cls closure
866  * @param key current key code
867  * @param value value in the hash map
868  * @return GNUNET_YES if we should continue to
869  *         iterate,
870  *         GNUNET_NO if not.
871  */
872 static int 
873 ss_map_free_iterator (void *cls,
874                       const struct GNUNET_HashCode * key, void *value)
875 {
876   struct SharedService *ss = value;
877
878   GNUNET_assert (GNUNET_YES ==
879                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
880   GNUNET_free (ss->name);
881   GNUNET_free (ss);
882   return GNUNET_YES;
883 }
884
885
886 /**
887  * Task to clean up and shutdown nicely
888  *
889  * @param cls NULL
890  * @param tc the TaskContext from scheduler
891  */
892 static void
893 shutdown_task (void *cls,
894                const struct GNUNET_SCHEDULER_TaskContext *tc)
895 {
896   struct LCFContextQueue *lcfq;
897   uint32_t host_id;
898   uint32_t route_id;
899
900   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
901   GNUNET_SCHEDULER_shutdown ();
902   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
903   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
904                                                 NULL);
905   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
906   if (NULL != fh)
907   {
908     GNUNET_DISK_file_close (fh);
909     fh = NULL;
910   }
911   if (NULL != lcfq_head)
912   {
913     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
914     {
915       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
916       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
917     }
918     if (NULL != lcfq_head->lcf->rhandle)
919       GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
920   }
921   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
922   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
923   {
924     GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
925     GNUNET_free (lcfq->lcf);
926     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
927     GNUNET_free (lcfq);
928   }
929   /* Clear host list */
930   for (host_id = 0; host_id < host_list_size; host_id++)
931     if (NULL != host_list[host_id])
932       GNUNET_TESTBED_host_destroy (host_list[host_id]);
933   GNUNET_free_non_null (host_list);
934   /* Clear route list */
935   for (route_id = 0; route_id < route_list_size; route_id++)
936     if (NULL != route_list[route_id])
937     {
938       if (NULL != route_list[route_id]->fcontroller)
939         GNUNET_TESTBED_controller_stop (route_list[route_id]->fcontroller);
940       GNUNET_free (route_list[route_id]);
941     }
942   GNUNET_free_non_null (route_list);
943   GNUNET_free_non_null (master_context);
944 }
945
946
947 /**
948  * Callback for client disconnect
949  *
950  * @param cls NULL
951  * @param client the client which has disconnected
952  */
953 static void
954 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
955 {
956   if (NULL == master_context)
957     return;
958   if (client == master_context->client)
959   {
960     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
961     GNUNET_SERVER_client_drop (client);
962     /* should not be needed as we're terminated by failure to read
963        from stdin, but if stdin fails for some reason, this shouldn't 
964        hurt for now --- might need to revise this later if we ever
965        decide that master connections might be temporarily down 
966        for some reason */
967     GNUNET_SCHEDULER_shutdown ();
968   }
969 }
970
971
972 /**
973  * Testbed setup
974  *
975  * @param cls closure
976  * @param server the initialized server
977  * @param cfg configuration to use
978  */
979 static void 
980 testbed_run (void *cls,
981              struct GNUNET_SERVER_Handle *server,
982              const struct GNUNET_CONFIGURATION_Handle *cfg)
983 {
984   static const struct GNUNET_SERVER_MessageHandler message_handlers[] =
985     {
986       {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
987        sizeof (struct GNUNET_TESTBED_InitMessage)},
988       {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
989       {&handle_configure_shared_service, NULL,
990        GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
991       {&handle_link_controllers, NULL,
992        GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
993       {NULL}
994     };
995
996   GNUNET_SERVER_add_handlers (server,
997                               message_handlers);
998   GNUNET_SERVER_disconnect_notify (server,
999                                    &client_disconnect_cb,
1000                                    NULL);
1001   ss_map = GNUNET_CONTAINER_multihashmap_create (5);
1002   fh = GNUNET_DISK_get_handle_from_native (stdin);
1003   if (NULL == fh)
1004     shutdown_task_id = 
1005       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,                                  
1006                                     &shutdown_task,
1007                                     NULL);
1008   else
1009     shutdown_task_id = 
1010       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
1011                                       fh,
1012                                       &shutdown_task,
1013                                       NULL);
1014 }
1015
1016
1017 /**
1018  * The starting point of execution
1019  */
1020 int main (int argc, char *const *argv)
1021 {
1022   return
1023     (GNUNET_OK ==
1024      GNUNET_SERVICE_run (argc,
1025                          argv,
1026                          "testbed",
1027                          GNUNET_SERVICE_OPTION_NONE,
1028                          &testbed_run,
1029                          NULL)) ? 0 : 1;
1030 }