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