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