- use faster hash for tunnel hashmaps
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
1 /*
2   This file is part of GNUnet.
3   (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 2, or (at your
8   option) any later version.
9
10   GNUnet is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file testbed/gnunet-service-testbed.c
23  * @brief implementation of the TESTBED service
24  * @author Sree Harsha Totakura
25  */
26
27 #include "gnunet-service-testbed.h"
28
29
30 /***********/
31 /* Globals */
32 /***********/
33
34 /**
35  * Our configuration
36  */
37 struct GNUNET_CONFIGURATION_Handle *our_config;
38
39 /**
40  * The master context; generated with the first INIT message
41  */
42 struct Context *GST_context;
43
44 /**
45  * Array of hosts
46  */
47 struct GNUNET_TESTBED_Host **GST_host_list;
48
49 /**
50  * DLL head for forwarded operation contexts
51  */
52 struct ForwardedOperationContext *fopcq_head;
53
54 /**
55  * DLL tail for forwarded operation contexts
56  */
57 struct ForwardedOperationContext *fopcq_tail;
58
59 /**
60  * Operation queue for open file descriptors
61  */
62 struct OperationQueue *GST_opq_openfds;
63
64 /**
65  * Timeout for operations which may take some time
66  */
67 const struct GNUNET_TIME_Relative GST_timeout;
68
69 /**
70  * The size of the host list
71  */
72 unsigned int GST_host_list_size;
73
74 /**
75  * The size of the peer list
76  */
77 unsigned int GST_peer_list_size;
78
79
80 /***********************************/
81 /* Local definitions and variables */
82 /***********************************/
83
84 /**
85  * The message queue for sending messages to clients
86  */
87 struct MessageQueue
88 {
89   /**
90    * The message to be sent
91    */
92   struct GNUNET_MessageHeader *msg;
93
94   /**
95    * The client to send the message to
96    */
97   struct GNUNET_SERVER_Client *client;
98
99   /**
100    * next pointer for DLL
101    */
102   struct MessageQueue *next;
103
104   /**
105    * prev pointer for DLL
106    */
107   struct MessageQueue *prev;
108 };
109
110 /**
111  * Our hostname; we give this to all the peers we start
112  */
113 static char *hostname;
114
115 /**
116  * Current Transmit Handle; NULL if no notify transmit exists currently
117  */
118 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
119
120 /**
121  * The message queue head
122  */
123 static struct MessageQueue *mq_head;
124
125 /**
126  * The message queue tail
127  */
128 static struct MessageQueue *mq_tail;
129
130
131 /**
132  * The shutdown task handle
133  */
134 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
135
136
137 /**
138  * Function called to notify a client about the connection begin ready to queue
139  * more data.  "buf" will be NULL and "size" zero if the connection was closed
140  * for writing in the meantime.
141  *
142  * @param cls NULL
143  * @param size number of bytes available in buf
144  * @param buf where the callee should write the message
145  * @return number of bytes written to buf
146  */
147 static size_t
148 transmit_ready_notify (void *cls, size_t size, void *buf)
149 {
150   struct MessageQueue *mq_entry;
151
152   transmit_handle = NULL;
153   mq_entry = mq_head;
154   GNUNET_assert (NULL != mq_entry);
155   if (0 == size)
156     return 0;
157   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
158   size = ntohs (mq_entry->msg->size);
159   memcpy (buf, mq_entry->msg, size);
160   GNUNET_free (mq_entry->msg);
161   GNUNET_SERVER_client_drop (mq_entry->client);
162   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
163   GNUNET_free (mq_entry);
164   mq_entry = mq_head;
165   if (NULL != mq_entry)
166     transmit_handle =
167         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
168                                              ntohs (mq_entry->msg->size),
169                                              GNUNET_TIME_UNIT_FOREVER_REL,
170                                              &transmit_ready_notify, NULL);
171   return size;
172 }
173
174
175 /**
176  * Queues a message in send queue for sending to the service
177  *
178  * @param client the client to whom the queued message has to be sent
179  * @param msg the message to queue
180  */
181 void
182 GST_queue_message (struct GNUNET_SERVER_Client *client,
183                    struct GNUNET_MessageHeader *msg)
184 {
185   struct MessageQueue *mq_entry;
186   uint16_t type;
187   uint16_t size;
188
189   type = ntohs (msg->type);
190   size = ntohs (msg->size);
191   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
192                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
193   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
194   mq_entry->msg = msg;
195   mq_entry->client = client;
196   GNUNET_SERVER_client_keep (client);
197   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
198              ntohs (msg->size));
199   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
200   if (NULL == transmit_handle)
201     transmit_handle =
202         GNUNET_SERVER_notify_transmit_ready (client, size,
203                                              GNUNET_TIME_UNIT_FOREVER_REL,
204                                              &transmit_ready_notify, NULL);
205 }
206
207
208 /**
209  * Function to add a host to the current list of known hosts
210  *
211  * @param host the host to add
212  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
213  *           already in use
214  */
215 static int
216 host_list_add (struct GNUNET_TESTBED_Host *host)
217 {
218   uint32_t host_id;
219
220   host_id = GNUNET_TESTBED_host_get_id_ (host);
221   if (GST_host_list_size <= host_id)
222     GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
223   if (NULL != GST_host_list[host_id])
224   {
225     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
226     return GNUNET_SYSERR;
227   }
228   GST_host_list[host_id] = host;
229   return GNUNET_OK;
230 }
231
232
233 /**
234  * Send operation failure message to client
235  *
236  * @param client the client to which the failure message has to be sent to
237  * @param operation_id the id of the failed operation
238  * @param emsg the error message; can be NULL
239  */
240 void
241 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
242                              uint64_t operation_id, const char *emsg)
243 {
244   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
245   uint16_t msize;
246   uint16_t emsg_len;
247
248   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
249   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
250   msize += emsg_len;
251   msg = GNUNET_malloc (msize);
252   msg->header.size = htons (msize);
253   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
254   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
255   msg->operation_id = GNUNET_htonll (operation_id);
256   if (0 != emsg_len)
257     memcpy (&msg[1], emsg, emsg_len);
258   GST_queue_message (client, &msg->header);
259 }
260
261
262 /**
263  * Function to send generic operation success message to given client
264  *
265  * @param client the client to send the message to
266  * @param operation_id the id of the operation which was successful
267  */
268 void
269 GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client,
270                                 uint64_t operation_id)
271 {
272   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
273   uint16_t msize;
274
275   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
276   msg = GNUNET_malloc (msize);
277   msg->header.size = htons (msize);
278   msg->header.type =
279       htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
280   msg->operation_id = GNUNET_htonll (operation_id);
281   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
282   GST_queue_message (client, &msg->header);
283 }
284
285 /**
286  * Callback which will be called after a host registration succeeded or failed
287  *
288  * @param cls the handle to the slave at which the registration is completed
289  * @param emsg the error message; NULL if host registration is successful
290  */
291 static void
292 hr_completion (void *cls, const char *emsg);
293
294
295 /**
296  * Attempts to register the next host in the host registration queue
297  *
298  * @param slave the slave controller whose host registration queue is checked
299  *          for host registrations
300  */
301 static void
302 register_next_host (struct Slave *slave)
303 {
304   struct HostRegistration *hr;
305
306   hr = slave->hr_dll_head;
307   GNUNET_assert (NULL != hr);
308   GNUNET_assert (NULL == slave->rhandle);
309   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
310        GNUNET_TESTBED_host_get_id_ (hr->host),
311        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
312   slave->rhandle =
313       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
314                                     slave);
315 }
316
317
318 /**
319  * Callback which will be called to after a host registration succeeded or failed
320  *
321  * @param cls the handle to the slave at which the registration is completed
322  * @param emsg the error message; NULL if host registration is successful
323  */
324 static void
325 hr_completion (void *cls, const char *emsg)
326 {
327   struct Slave *slave = cls;
328   struct HostRegistration *hr;
329
330   slave->rhandle = NULL;
331   hr = slave->hr_dll_head;
332   GNUNET_assert (NULL != hr);
333   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
334        GNUNET_TESTBED_host_get_id_ (hr->host),
335        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
336   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
337   if (NULL != hr->cb)
338     hr->cb (hr->cb_cls, emsg);
339   GNUNET_free (hr);
340   if (NULL != slave->hr_dll_head)
341     register_next_host (slave);
342 }
343
344
345 /**
346  * Adds a host registration's request to a slave's registration queue
347  *
348  * @param slave the slave controller at which the given host has to be
349  *          registered
350  * @param cb the host registration completion callback
351  * @param cb_cls the closure for the host registration completion callback
352  * @param host the host which has to be registered
353  */
354 void
355 GST_queue_host_registration (struct Slave *slave,
356                              GNUNET_TESTBED_HostRegistrationCompletion cb,
357                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
358 {
359   struct HostRegistration *hr;
360   int call_register;
361
362   LOG (GNUNET_ERROR_TYPE_DEBUG,
363        "Queueing host registration for host %u at %u\n",
364        GNUNET_TESTBED_host_get_id_ (host),
365        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
366   hr = GNUNET_malloc (sizeof (struct HostRegistration));
367   hr->cb = cb;
368   hr->cb_cls = cb_cls;
369   hr->host = host;
370   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
371   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
372   if (GNUNET_YES == call_register)
373     register_next_host (slave);
374 }
375
376
377 /**
378  * Callback to relay the reply msg of a forwarded operation back to the client
379  *
380  * @param cls ForwardedOperationContext
381  * @param msg the message to relay
382  */
383 void
384 GST_forwarded_operation_reply_relay (void *cls,
385                                      const struct GNUNET_MessageHeader *msg)
386 {
387   struct ForwardedOperationContext *fopc = cls;
388   struct GNUNET_MessageHeader *dup_msg;
389   uint16_t msize;
390
391   msize = ntohs (msg->size);
392   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
393              msize);
394   dup_msg = GNUNET_copy_message (msg);
395   GST_queue_message (fopc->client, dup_msg);
396   GNUNET_SERVER_client_drop (fopc->client);
397   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
398   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
399   GNUNET_free (fopc);
400 }
401
402
403 /**
404  * Task to free resources when forwarded operation has been timedout
405  *
406  * @param cls the ForwardedOperationContext
407  * @param tc the task context from scheduler
408  */
409 void
410 GST_forwarded_operation_timeout (void *cls,
411                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
412 {
413   struct ForwardedOperationContext *fopc = cls;
414
415   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
416   LOG (GNUNET_ERROR_TYPE_DEBUG, "A forwarded operation has timed out\n");
417   GST_send_operation_fail_msg (fopc->client, fopc->operation_id,
418                                "A forwarded operation has timed out");
419   GNUNET_SERVER_client_drop (fopc->client);
420   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
421   GNUNET_free (fopc);
422 }
423
424
425 /**
426  * Parse service sharing specification line.
427  * Format is "[<service:share>] [<service:share>] ..."
428  *
429  * @param ss_str the spec string to be parsed
430  * @param cfg the configuration to use for shared services
431  * @return an array suitable to pass to GNUNET_TESTING_system_create().  NULL
432  *           upon empty service sharing specification.
433  */
434 static struct GNUNET_TESTING_SharedService *
435 parse_shared_services (char *ss_str, struct GNUNET_CONFIGURATION_Handle *cfg)
436 {
437   struct GNUNET_TESTING_SharedService ss;
438   struct GNUNET_TESTING_SharedService *slist;
439   char service[256];
440   char *arg;
441   unsigned int n;
442 #define GROW_SS                                 \
443   do {                                          \
444     GNUNET_array_grow (slist, n, n+1);                                  \
445     (void) memcpy (&slist[n - 1], &ss,                                  \
446                    sizeof (struct GNUNET_TESTING_SharedService));       \
447   } while (0)
448   
449   slist = NULL;
450   n = 0;
451   ss.cfg = cfg;
452   for (; NULL != (arg = strtok (ss_str, " ")); ss_str = NULL)
453   {
454     ss.service = NULL;
455     ss.share = 0;
456     if (2 != sscanf (arg, "%255[^:]:%u", service, &ss.share))
457     {
458       LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring shared service spec: %s", arg);
459       continue;
460     }
461     LOG_DEBUG ("Will be sharing %s service among %u peers\n", service, ss.share);
462     ss.service = GNUNET_strdup (service);
463     GROW_SS;
464   }
465   if (NULL != slist)
466   {
467     /* Add trailing NULL block */
468     (void) memset (&ss, 0, sizeof (struct GNUNET_TESTING_SharedService));
469     GROW_SS;
470   }
471   return slist;
472 #undef GROW_SS
473 }
474
475
476 /**
477  * Callback function invoked for each interface found.
478  *
479  * @param cls NULL
480  * @param name name of the interface (can be NULL for unknown)
481  * @param isDefault is this presumably the default interface
482  * @param addr address of this interface (can be NULL for unknown or unassigned)
483  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
484  * @param netmask the network mask (can be NULL for unknown or unassigned))
485  * @param addrlen length of the address
486  * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
487  */
488 static int 
489 addr_proc (void *cls, const char *name, int isDefault,
490            const struct sockaddr *addr,
491            const struct sockaddr *broadcast_addr,
492            const struct sockaddr *netmask, socklen_t addrlen)
493 {
494   struct Context *ctx = cls;
495   const struct sockaddr_in *in_addr;
496   char *ipaddr;
497   char *tmp;  
498
499   if (sizeof (struct sockaddr_in) != addrlen)
500     return GNUNET_OK;
501   in_addr = (const struct sockaddr_in *) addr;
502   if (NULL == (ipaddr = inet_ntoa (in_addr->sin_addr)))
503     return GNUNET_OK;
504   if (NULL == ctx->master_ips)
505   {
506     ctx->master_ips = GNUNET_strdup (ipaddr);
507     return GNUNET_OK;
508   }
509   tmp = NULL;
510   (void) GNUNET_asprintf (&tmp, "%s; %s", ctx->master_ips, ipaddr);
511   GNUNET_free (ctx->master_ips);
512   ctx->master_ips = tmp;
513   return GNUNET_OK;
514 }
515
516
517
518 /**
519  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
520  *
521  * @param cls NULL
522  * @param client identification of the client
523  * @param message the actual message
524  */
525 static void
526 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
527              const struct GNUNET_MessageHeader *message)
528 {
529   const struct GNUNET_TESTBED_InitMessage *msg;
530   struct GNUNET_TESTBED_Host *host;
531   char *ss_str;
532   struct GNUNET_TESTING_SharedService *ss;
533   char *hostname;
534   unsigned int cnt;
535   unsigned int len;
536
537   if (NULL != GST_context)
538   {
539     LOG_DEBUG ("We are being connected to laterally\n");
540     GNUNET_SERVER_receive_done (client, GNUNET_OK);
541     return;
542   }
543   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
544   len = GNUNET_OS_get_hostname_max_length ();
545   hostname = GNUNET_malloc (len);
546   if (0 != gethostname (hostname, len))
547   {
548     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
549     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
550     return;
551   }
552   ss_str = NULL;
553   ss = NULL;
554   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (our_config, "TESTBED",
555                                                           "SHARED_SERVICES",
556                                                           &ss_str))
557   {
558     ss = parse_shared_services (ss_str, our_config);
559     GNUNET_free (ss_str);
560     ss_str = NULL;
561   }
562   GST_context = GNUNET_malloc (sizeof (struct Context));
563   GNUNET_SERVER_client_keep (client);
564   GST_context->client = client;
565   GST_context->host_id = ntohl (msg->host_id);
566   GNUNET_OS_network_interfaces_list (&addr_proc, GST_context);
567   if (NULL == GST_context->master_ips)
568   {
569     LOG (GNUNET_ERROR_TYPE_ERROR, 
570          "Testbed needs networking, but no network interfaces are found on this host.  Exiting\n");
571     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
572     GNUNET_SCHEDULER_shutdown ();
573     return;
574   }
575   LOG_DEBUG ("Our IP addresses: %s\n", GST_context->master_ips);
576   GST_context->system =
577       GNUNET_TESTING_system_create ("testbed", GST_context->master_ips,
578                                     hostname, ss);
579   if (NULL != ss)
580   {
581     for (cnt = 0; NULL != ss[cnt].service; cnt++)
582     {
583       ss_str = (char *) ss[cnt].service;
584       GNUNET_free (ss_str);
585     }
586     GNUNET_free (ss);
587     ss = NULL;
588   }
589
590   host = GNUNET_TESTBED_host_create_with_id (GST_context->host_id, hostname,
591                                              NULL, our_config, 0);
592   host_list_add (host);
593   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
594   GNUNET_SERVER_receive_done (client, GNUNET_OK);
595 }
596
597
598 /**
599  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
600  *
601  * @param cls NULL
602  * @param client identification of the client
603  * @param message the actual message
604  */
605 static void
606 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
607                  const struct GNUNET_MessageHeader *message)
608 {
609   struct GNUNET_TESTBED_Host *host;
610   const struct GNUNET_TESTBED_AddHostMessage *msg;
611   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
612   struct GNUNET_CONFIGURATION_Handle *host_cfg;
613   char *username;
614   char *hostname;
615   char *emsg;
616   const void *ptr;
617   uint32_t host_id;
618   uint16_t username_length;
619   uint16_t hostname_length;
620   uint16_t reply_size;
621   uint16_t msize;
622
623   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
624   msize = ntohs (msg->header.size);
625   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
626   {
627     GNUNET_break_op (0);
628     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
629     return;
630   }
631   username_length = ntohs (msg->username_length);
632   hostname_length = ntohs (msg->hostname_length);
633   /* msg must contain hostname */
634   if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
635                  username_length))
636       || (0 == hostname_length))
637   {
638     GNUNET_break_op (0);
639     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
640     return;
641   }
642   /* msg must contain configuration */
643   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
644                 username_length + hostname_length))
645   {
646     GNUNET_break_op (0);
647     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
648     return;
649   }
650   username = NULL;
651   hostname = NULL;
652   ptr = &msg[1];
653   if (0 != username_length)
654   {
655     username = GNUNET_malloc (username_length + 1);
656     strncpy (username, ptr, username_length);
657     ptr += username_length;
658   }
659   hostname = GNUNET_malloc (hostname_length + 1);
660   strncpy (hostname, ptr, hostname_length);
661   ptr += hostname_length;
662   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
663   {
664     GNUNET_free_non_null (username);
665     GNUNET_free_non_null (hostname);
666     GNUNET_break_op (0);
667     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
668     return;
669   }
670   host_id = ntohl (msg->host_id);
671   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
672   LOG_DEBUG ("-------host id: %u\n", host_id);
673   LOG_DEBUG ("-------hostname: %s\n", hostname);
674   if (NULL != username)
675     LOG_DEBUG ("-------username: %s\n", username);
676   else
677     LOG_DEBUG ("-------username: <not given>\n");
678   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
679   host =
680       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
681                                           host_cfg, ntohs (msg->ssh_port));
682   GNUNET_free_non_null (username);
683   GNUNET_free (hostname);
684   GNUNET_CONFIGURATION_destroy (host_cfg);
685   if (NULL == host)
686   {
687     GNUNET_break_op (0);
688     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
689     return;
690   }
691   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
692   if (GNUNET_OK != host_list_add (host))
693   {
694     /* We are unable to add a host */
695     emsg = "A host exists with given host-id";
696     LOG_DEBUG ("%s: %u", emsg, host_id);
697     GNUNET_TESTBED_host_destroy (host);
698     reply_size += strlen (emsg) + 1;
699     reply = GNUNET_malloc (reply_size);
700     memcpy (&reply[1], emsg, strlen (emsg) + 1);
701   }
702   else
703   {
704     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
705     reply = GNUNET_malloc (reply_size);
706   }
707   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
708   reply->header.size = htons (reply_size);
709   reply->host_id = htonl (host_id);
710   GST_queue_message (client, &reply->header);
711   GNUNET_SERVER_receive_done (client, GNUNET_OK);
712 }
713
714
715 /**
716  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
717  *
718  * @param cls NULL
719  * @param client identification of the client
720  * @param message the actual message
721  */
722 static void
723 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
724                          const struct GNUNET_MessageHeader *message)
725 {
726   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
727   struct Slave *slave;
728   struct GNUNET_TESTBED_SlaveConfiguration *reply;
729   const struct GNUNET_CONFIGURATION_Handle *cfg;
730   char *config;
731   char *xconfig;
732   size_t config_size;
733   size_t xconfig_size;
734   size_t reply_size;
735   uint64_t op_id;
736   uint32_t slave_id;
737
738   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
739   slave_id = ntohl (msg->slave_id);
740   op_id = GNUNET_ntohll (msg->operation_id);
741   if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
742   {
743     /* FIXME: Add forwardings for this type of message here.. */
744     GST_send_operation_fail_msg (client, op_id, "Slave not found");
745     GNUNET_SERVER_receive_done (client, GNUNET_OK);
746     return;
747   }
748   slave = GST_slave_list[slave_id];
749   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
750   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
751   xconfig_size =
752       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
753   GNUNET_free (config);
754   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
755   GNUNET_break (reply_size <= UINT16_MAX);
756   GNUNET_break (config_size <= UINT16_MAX);
757   reply = GNUNET_realloc (xconfig, reply_size);
758   (void) memmove (&reply[1], reply, xconfig_size);
759   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
760   reply->header.size = htons ((uint16_t) reply_size);
761   reply->slave_id = msg->slave_id;
762   reply->operation_id = msg->operation_id;
763   reply->config_size = htons ((uint16_t) config_size);
764   GST_queue_message (client, &reply->header);
765   GNUNET_SERVER_receive_done (client, GNUNET_OK);
766 }
767
768
769 /**
770  * Clears the forwarded operations queue
771  */
772 void
773 GST_clear_fopcq ()
774 {
775   struct ForwardedOperationContext *fopc;
776   
777   while (NULL != (fopc = fopcq_head))
778   {
779     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
780     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
781     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
782       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
783     GNUNET_SERVER_client_drop (fopc->client);
784     switch (fopc->type)
785     {
786     case OP_PEER_CREATE:
787       GNUNET_free (fopc->cls);
788       break;
789     case OP_SHUTDOWN_PEERS:
790       {
791         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
792         
793         GNUNET_assert (0 < hc->nslaves);
794         hc->nslaves--;
795         if (0 == hc->nslaves)
796           GNUNET_free (hc);
797       }
798       break;
799     case OP_PEER_START:
800     case OP_PEER_STOP:
801     case OP_PEER_DESTROY:
802     case OP_PEER_INFO:
803     case OP_OVERLAY_CONNECT:
804     case OP_LINK_CONTROLLERS:
805     case OP_GET_SLAVE_CONFIG:
806     case OP_MANAGE_SERVICE:
807     case OP_PEER_RECONFIGURE:
808       break;
809     case OP_FORWARDED:
810       GNUNET_assert (0);
811     };
812     GNUNET_free (fopc);
813   }
814 }
815
816
817 /**
818  * Task to clean up and shutdown nicely
819  *
820  * @param cls NULL
821  * @param tc the TaskContext from scheduler
822  */
823 static void
824 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
825 {
826   struct MessageQueue *mq_entry;
827   uint32_t id;
828
829   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
830   LOG_DEBUG ("Shutting down testbed service\n");
831   /* cleanup any remaining forwarded operations */
832   GST_clear_fopcq ();
833   GST_free_lcfq ();
834   GST_free_mctxq ();
835   GST_free_occq ();
836   GST_free_roccq ();
837   GST_free_nccq ();
838   GST_neighbour_list_clean();
839   GST_free_prcq ();
840   /* Clear peer list */
841   GST_destroy_peers ();
842   /* Clear route list */
843   GST_route_list_clear ();
844   /* Clear GST_slave_list */
845   GST_slave_list_clear ();
846   /* Clear host list */
847   for (id = 0; id < GST_host_list_size; id++)
848     if (NULL != GST_host_list[id])
849       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
850   GNUNET_free_non_null (GST_host_list);
851   if (NULL != GST_context)
852   {
853     GNUNET_free_non_null (GST_context->master_ips);
854     if (NULL != GST_context->system)
855       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
856     GNUNET_SERVER_client_drop (GST_context->client);
857     GNUNET_free (GST_context);
858     GST_context = NULL;
859   }
860   if (NULL != transmit_handle)
861     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
862   while (NULL != (mq_entry = mq_head))
863   {
864     GNUNET_free (mq_entry->msg);
865     GNUNET_SERVER_client_drop (mq_entry->client);
866     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
867     GNUNET_free (mq_entry);
868   }
869   GNUNET_free_non_null (hostname);
870   GNUNET_CONFIGURATION_destroy (our_config);
871   /* Free hello cache */
872   GST_cache_clear ();
873   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
874   GST_opq_openfds = NULL;
875   GST_stats_destroy ();
876 }
877
878
879 /**
880  * Callback for client disconnect
881  *
882  * @param cls NULL
883  * @param client the client which has disconnected
884  */
885 static void
886 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
887 {
888   if (NULL == GST_context)
889     return;
890   if (client == GST_context->client)
891   {
892     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
893     /* should not be needed as we're terminated by failure to read
894      * from stdin, but if stdin fails for some reason, this shouldn't
895      * hurt for now --- might need to revise this later if we ever
896      * decide that master connections might be temporarily down
897      * for some reason */
898     //GNUNET_SCHEDULER_shutdown ();
899   }
900 }
901
902
903 /**
904  * Testbed setup
905  *
906  * @param cls closure
907  * @param server the initialized server
908  * @param cfg configuration to use
909  */
910 static void
911 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
912              const struct GNUNET_CONFIGURATION_Handle *cfg)
913 {
914   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
915     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT,
916      sizeof (struct GNUNET_TESTBED_InitMessage)},
917     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
918     {&GST_handle_link_controllers, NULL,
919      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
920      sizeof (struct GNUNET_TESTBED_ControllerLinkRequest)},
921     {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
922     {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
923      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
924     {&GST_handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
925      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
926     {&GST_handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
927      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
928     {&GST_handle_peer_get_config, NULL,
929      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
930      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
931     {&GST_handle_overlay_connect, NULL,
932      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
933      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
934     {&GST_handle_remote_overlay_connect, NULL,
935      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
936     {&GST_handle_manage_peer_service, NULL,
937      GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
938     {&handle_slave_get_config, NULL,
939      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
940      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
941     {&GST_handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
942      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
943     {&GST_handle_peer_reconfigure, NULL, 
944      GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER, 0},
945     {NULL, NULL, 0, 0}
946   };
947   char *logfile;
948   unsigned long long num;
949
950   LOG_DEBUG ("Starting testbed\n");
951   if (GNUNET_OK ==
952       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
953                                                &logfile))
954   {
955     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
956     GNUNET_free (logfile);
957   }
958   GNUNET_assert (GNUNET_OK ==
959                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
960                                                         "CACHE_SIZE", &num));
961   GST_cache_init ((unsigned int) num);
962   GNUNET_assert (GNUNET_OK ==
963                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
964                                                         "MAX_OPEN_FDS", &num));
965   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
966   GNUNET_assert (GNUNET_OK ==
967                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
968                                                       "OPERATION_TIMEOUT",
969                                                       (struct
970                                                        GNUNET_TIME_Relative *)
971                                                       &GST_timeout));
972   GNUNET_assert (GNUNET_OK ==
973                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
974                                                         "HOSTNAME", &hostname));
975   our_config = GNUNET_CONFIGURATION_dup (cfg);
976   GNUNET_SERVER_add_handlers (server, message_handlers);
977   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
978   shutdown_task_id =
979       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
980                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
981                                                   &shutdown_task, NULL);
982   LOG_DEBUG ("Testbed startup complete\n");
983   GST_stats_init (our_config);
984 }
985
986
987 /**
988  * The starting point of execution
989  */
990 int
991 main (int argc, char *const *argv)
992 {
993   //sleep (15);                 /* Debugging */
994   return (GNUNET_OK ==
995           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
996                               &testbed_run, NULL)) ? 0 : 1;
997 }
998
999 /* end of gnunet-service-testbed.c */