- towards on-demand controller linking
[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  * The hashmap of shared services
132  */
133 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
134
135 /**
136  * The shutdown task handle
137  */
138 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
139
140
141 /**
142  * Function called to notify a client about the connection begin ready to queue
143  * more data.  "buf" will be NULL and "size" zero if the connection was closed
144  * for writing in the meantime.
145  *
146  * @param cls NULL
147  * @param size number of bytes available in buf
148  * @param buf where the callee should write the message
149  * @return number of bytes written to buf
150  */
151 static size_t
152 transmit_ready_notify (void *cls, size_t size, void *buf)
153 {
154   struct MessageQueue *mq_entry;
155
156   transmit_handle = NULL;
157   mq_entry = mq_head;
158   GNUNET_assert (NULL != mq_entry);
159   if (0 == size)
160     return 0;
161   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
162   size = ntohs (mq_entry->msg->size);
163   memcpy (buf, mq_entry->msg, size);
164   GNUNET_free (mq_entry->msg);
165   GNUNET_SERVER_client_drop (mq_entry->client);
166   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
167   GNUNET_free (mq_entry);
168   mq_entry = mq_head;
169   if (NULL != mq_entry)
170     transmit_handle =
171         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
172                                              ntohs (mq_entry->msg->size),
173                                              GNUNET_TIME_UNIT_FOREVER_REL,
174                                              &transmit_ready_notify, NULL);
175   return size;
176 }
177
178
179 /**
180  * Queues a message in send queue for sending to the service
181  *
182  * @param client the client to whom the queued message has to be sent
183  * @param msg the message to queue
184  */
185 void
186 GST_queue_message (struct GNUNET_SERVER_Client *client,
187                    struct GNUNET_MessageHeader *msg)
188 {
189   struct MessageQueue *mq_entry;
190   uint16_t type;
191   uint16_t size;
192
193   type = ntohs (msg->type);
194   size = ntohs (msg->size);
195   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
196                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
197   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
198   mq_entry->msg = msg;
199   mq_entry->client = client;
200   GNUNET_SERVER_client_keep (client);
201   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
202              ntohs (msg->size));
203   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
204   if (NULL == transmit_handle)
205     transmit_handle =
206         GNUNET_SERVER_notify_transmit_ready (client, size,
207                                              GNUNET_TIME_UNIT_FOREVER_REL,
208                                              &transmit_ready_notify, NULL);
209 }
210
211
212 /**
213  * Function to add a host to the current list of known hosts
214  *
215  * @param host the host to add
216  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
217  *           already in use
218  */
219 static int
220 host_list_add (struct GNUNET_TESTBED_Host *host)
221 {
222   uint32_t host_id;
223
224   host_id = GNUNET_TESTBED_host_get_id_ (host);
225   if (GST_host_list_size <= host_id)
226     GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
227   if (NULL != GST_host_list[host_id])
228   {
229     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
230     return GNUNET_SYSERR;
231   }
232   GST_host_list[host_id] = host;
233   return GNUNET_OK;
234 }
235
236
237 /**
238  * Routes message to a host given its host_id
239  *
240  * @param host_id the id of the destination host
241  * @param msg the message to be routed
242  */
243 static void
244 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
245 {
246   GNUNET_break (0);
247 }
248
249
250 /**
251  * Send operation failure message to client
252  *
253  * @param client the client to which the failure message has to be sent to
254  * @param operation_id the id of the failed operation
255  * @param emsg the error message; can be NULL
256  */
257 void
258 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
259                              uint64_t operation_id, const char *emsg)
260 {
261   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
262   uint16_t msize;
263   uint16_t emsg_len;
264
265   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
266   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
267   msize += emsg_len;
268   msg = GNUNET_malloc (msize);
269   msg->header.size = htons (msize);
270   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
271   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
272   msg->operation_id = GNUNET_htonll (operation_id);
273   if (0 != emsg_len)
274     memcpy (&msg[1], emsg, emsg_len);
275   GST_queue_message (client, &msg->header);
276 }
277
278
279 /**
280  * Function to send generic operation success message to given client
281  *
282  * @param client the client to send the message to
283  * @param operation_id the id of the operation which was successful
284  */
285 void
286 GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client,
287                                 uint64_t operation_id)
288 {
289   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
290   uint16_t msize;
291
292   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
293   msg = GNUNET_malloc (msize);
294   msg->header.size = htons (msize);
295   msg->header.type =
296       htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
297   msg->operation_id = GNUNET_htonll (operation_id);
298   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
299   GST_queue_message (client, &msg->header);
300 }
301
302 /**
303  * Callback which will be called after a host registration succeeded or failed
304  *
305  * @param cls the handle to the slave at which the registration is completed
306  * @param emsg the error message; NULL if host registration is successful
307  */
308 static void
309 hr_completion (void *cls, const char *emsg);
310
311
312 /**
313  * Attempts to register the next host in the host registration queue
314  *
315  * @param slave the slave controller whose host registration queue is checked
316  *          for host registrations
317  */
318 static void
319 register_next_host (struct Slave *slave)
320 {
321   struct HostRegistration *hr;
322
323   hr = slave->hr_dll_head;
324   GNUNET_assert (NULL != hr);
325   GNUNET_assert (NULL == slave->rhandle);
326   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
327        GNUNET_TESTBED_host_get_id_ (hr->host),
328        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
329   slave->rhandle =
330       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
331                                     slave);
332 }
333
334
335 /**
336  * Callback which will be called to after a host registration succeeded or failed
337  *
338  * @param cls the handle to the slave at which the registration is completed
339  * @param emsg the error message; NULL if host registration is successful
340  */
341 static void
342 hr_completion (void *cls, const char *emsg)
343 {
344   struct Slave *slave = cls;
345   struct HostRegistration *hr;
346
347   slave->rhandle = NULL;
348   hr = slave->hr_dll_head;
349   GNUNET_assert (NULL != hr);
350   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
351        GNUNET_TESTBED_host_get_id_ (hr->host),
352        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
353   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
354   if (NULL != hr->cb)
355     hr->cb (hr->cb_cls, emsg);
356   GNUNET_free (hr);
357   if (NULL != slave->hr_dll_head)
358     register_next_host (slave);
359 }
360
361
362 /**
363  * Adds a host registration's request to a slave's registration queue
364  *
365  * @param slave the slave controller at which the given host has to be
366  *          registered
367  * @param cb the host registration completion callback
368  * @param cb_cls the closure for the host registration completion callback
369  * @param host the host which has to be registered
370  */
371 void
372 GST_queue_host_registration (struct Slave *slave,
373                              GNUNET_TESTBED_HostRegistrationCompletion cb,
374                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
375 {
376   struct HostRegistration *hr;
377   int call_register;
378
379   LOG (GNUNET_ERROR_TYPE_DEBUG,
380        "Queueing host registration for host %u at %u\n",
381        GNUNET_TESTBED_host_get_id_ (host),
382        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
383   hr = GNUNET_malloc (sizeof (struct HostRegistration));
384   hr->cb = cb;
385   hr->cb_cls = cb_cls;
386   hr->host = host;
387   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
388   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
389   if (GNUNET_YES == call_register)
390     register_next_host (slave);
391 }
392
393
394 /**
395  * Callback to relay the reply msg of a forwarded operation back to the client
396  *
397  * @param cls ForwardedOperationContext
398  * @param msg the message to relay
399  */
400 void
401 GST_forwarded_operation_reply_relay (void *cls,
402                                      const struct GNUNET_MessageHeader *msg)
403 {
404   struct ForwardedOperationContext *fopc = cls;
405   struct GNUNET_MessageHeader *dup_msg;
406   uint16_t msize;
407
408   msize = ntohs (msg->size);
409   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
410              msize);
411   dup_msg = GNUNET_copy_message (msg);
412   GST_queue_message (fopc->client, dup_msg);
413   GNUNET_SERVER_client_drop (fopc->client);
414   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
415   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
416   GNUNET_free (fopc);
417 }
418
419
420 /**
421  * Task to free resources when forwarded operation has been timedout
422  *
423  * @param cls the ForwardedOperationContext
424  * @param tc the task context from scheduler
425  */
426 void
427 GST_forwarded_operation_timeout (void *cls,
428                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
429 {
430   struct ForwardedOperationContext *fopc = cls;
431
432   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
433   LOG (GNUNET_ERROR_TYPE_DEBUG, "A forwarded operation has timed out\n");
434   GST_send_operation_fail_msg (fopc->client, fopc->operation_id,
435                                "A forwarded operation has timed out");
436   GNUNET_SERVER_client_drop (fopc->client);
437   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
438   GNUNET_free (fopc);
439 }
440
441
442 /**
443  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
444  *
445  * @param cls NULL
446  * @param client identification of the client
447  * @param message the actual message
448  */
449 static void
450 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
451              const struct GNUNET_MessageHeader *message)
452 {
453   const struct GNUNET_TESTBED_InitMessage *msg;
454   struct GNUNET_TESTBED_Host *host;
455   const char *controller_hostname;
456   uint16_t msize;
457
458   if (NULL != GST_context)
459   {
460     LOG_DEBUG ("We are being connected to laterally\n");
461     GNUNET_SERVER_receive_done (client, GNUNET_OK);
462     return;
463   }
464   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
465   msize = ntohs (message->size);
466   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
467   {
468     GNUNET_break (0);
469     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
470     return;
471   }
472   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
473   controller_hostname = (const char *) &msg[1];
474   if ('\0' != controller_hostname[msize - 1])
475   {
476     GNUNET_break (0);
477     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
478     return;
479   }
480   GST_context = GNUNET_malloc (sizeof (struct Context));
481   GNUNET_SERVER_client_keep (client);
482   GST_context->client = client;
483   GST_context->host_id = ntohl (msg->host_id);
484   GST_context->master_ip = GNUNET_strdup (controller_hostname);
485   LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
486   GST_context->system =
487       GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
488                                     hostname);
489   host =
490       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
491                                           GST_context->master_ip, NULL,
492                                           our_config, 0);
493   host_list_add (host);
494   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
495   GNUNET_SERVER_receive_done (client, GNUNET_OK);
496 }
497
498
499 /**
500  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
501  *
502  * @param cls NULL
503  * @param client identification of the client
504  * @param message the actual message
505  */
506 static void
507 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
508                  const struct GNUNET_MessageHeader *message)
509 {
510   struct GNUNET_TESTBED_Host *host;
511   const struct GNUNET_TESTBED_AddHostMessage *msg;
512   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
513   struct GNUNET_CONFIGURATION_Handle *host_cfg;
514   char *username;
515   char *hostname;
516   char *emsg;
517   const void *ptr;
518   uint32_t host_id;
519   uint16_t username_length;
520   uint16_t hostname_length;
521   uint16_t reply_size;
522   uint16_t msize;
523
524   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
525   msize = ntohs (msg->header.size);
526   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
527   {
528     GNUNET_break_op (0);
529     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
530     return;
531   }
532   username_length = ntohs (msg->username_length);
533   hostname_length = ntohs (msg->hostname_length);
534   /* msg must contain hostname */
535   if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
536                  username_length))
537       || (0 == hostname_length))
538   {
539     GNUNET_break_op (0);
540     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
541     return;
542   }
543   /* msg must contain configuration */
544   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
545                 username_length + hostname_length))
546   {
547     GNUNET_break_op (0);
548     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
549     return;
550   }
551   username = NULL;
552   hostname = NULL;
553   ptr = &msg[1];
554   if (0 != username_length)
555   {
556     username = GNUNET_malloc (username_length + 1);
557     strncpy (username, ptr, username_length);
558     ptr += username_length;
559   }
560   hostname = GNUNET_malloc (hostname_length + 1);
561   strncpy (hostname, ptr, hostname_length);
562   ptr += hostname_length;
563   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
564   {
565     GNUNET_free_non_null (username);
566     GNUNET_free_non_null (hostname);
567     GNUNET_break_op (0);
568     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
569     return;
570   }
571   host_id = ntohl (msg->host_id);
572   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
573   LOG_DEBUG ("-------host id: %u\n", host_id);
574   LOG_DEBUG ("-------hostname: %s\n", hostname);
575   if (NULL != username)
576     LOG_DEBUG ("-------username: %s\n", username);
577   else
578     LOG_DEBUG ("-------username: <not given>\n");
579   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
580   host =
581       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
582                                           host_cfg, ntohs (msg->ssh_port));
583   GNUNET_free_non_null (username);
584   GNUNET_free (hostname);
585   GNUNET_CONFIGURATION_destroy (host_cfg);
586   if (NULL == host)
587   {
588     GNUNET_break_op (0);
589     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
590     return;
591   }
592   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
593   if (GNUNET_OK != host_list_add (host))
594   {
595     /* We are unable to add a host */
596     emsg = "A host exists with given host-id";
597     LOG_DEBUG ("%s: %u", emsg, host_id);
598     GNUNET_TESTBED_host_destroy (host);
599     reply_size += strlen (emsg) + 1;
600     reply = GNUNET_malloc (reply_size);
601     memcpy (&reply[1], emsg, strlen (emsg) + 1);
602   }
603   else
604   {
605     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
606     reply = GNUNET_malloc (reply_size);
607   }
608   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
609   reply->header.size = htons (reply_size);
610   reply->host_id = htonl (host_id);
611   GST_queue_message (client, &reply->header);
612   GNUNET_SERVER_receive_done (client, GNUNET_OK);
613 }
614
615
616 /**
617  * Iterator over hash map entries.
618  *
619  * @param cls closure
620  * @param key current key code
621  * @param value value in the hash map
622  * @return GNUNET_YES if we should continue to
623  *         iterate,
624  *         GNUNET_NO if not.
625  */
626 int
627 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
628 {
629   struct SharedService *queried_ss = cls;
630   struct SharedService *ss = value;
631
632   if (0 == strcmp (ss->name, queried_ss->name))
633     return GNUNET_NO;
634   else
635     return GNUNET_YES;
636 }
637
638
639 /**
640  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
641  *
642  * @param cls NULL
643  * @param client identification of the client
644  * @param message the actual message
645  */
646 static void
647 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
648                                  const struct GNUNET_MessageHeader *message)
649 {
650   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
651   struct SharedService *ss;
652   char *service_name;
653   struct GNUNET_HashCode hash;
654   uint16_t msg_size;
655   uint16_t service_name_size;
656
657   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
658   msg_size = ntohs (message->size);
659   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
660   {
661     GNUNET_break (0);
662     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
663     return;
664   }
665   service_name_size =
666       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
667   service_name = (char *) &msg[1];
668   if ('\0' != service_name[service_name_size - 1])
669   {
670     GNUNET_break (0);
671     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
672     return;
673   }
674   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
675              service_name, ntohl (msg->num_peers));
676   if (ntohl (msg->host_id) != GST_context->host_id)
677   {
678     route_message (ntohl (msg->host_id), message);
679     GNUNET_SERVER_receive_done (client, GNUNET_OK);
680     return;
681   }
682   GNUNET_SERVER_receive_done (client, GNUNET_OK);
683   ss = GNUNET_malloc (sizeof (struct SharedService));
684   ss->name = strdup (service_name);
685   ss->num_shared = ntohl (msg->num_peers);
686   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
687   if (GNUNET_SYSERR ==
688       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
689                                                   &ss_exists_iterator, ss))
690   {
691     LOG (GNUNET_ERROR_TYPE_WARNING,
692          "Service %s already configured as a shared service. "
693          "Ignoring service sharing request \n", ss->name);
694     GNUNET_free (ss->name);
695     GNUNET_free (ss);
696     return;
697   }
698   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
699                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
700 }
701
702
703 /**
704  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
705  *
706  * @param cls NULL
707  * @param client identification of the client
708  * @param message the actual message
709  */
710 static void
711 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
712                          const struct GNUNET_MessageHeader *message)
713 {
714   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
715   struct Slave *slave;
716   struct GNUNET_TESTBED_SlaveConfiguration *reply;
717   const struct GNUNET_CONFIGURATION_Handle *cfg;
718   char *config;
719   char *xconfig;
720   size_t config_size;
721   size_t xconfig_size;
722   size_t reply_size;
723   uint64_t op_id;
724   uint32_t slave_id;
725
726   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
727   slave_id = ntohl (msg->slave_id);
728   op_id = GNUNET_ntohll (msg->operation_id);
729   if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
730   {
731     /* FIXME: Add forwardings for this type of message here.. */
732     GST_send_operation_fail_msg (client, op_id, "Slave not found");
733     GNUNET_SERVER_receive_done (client, GNUNET_OK);
734     return;
735   }
736   slave = GST_slave_list[slave_id];
737   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
738   config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
739   xconfig_size =
740       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
741   GNUNET_free (config);
742   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
743   GNUNET_break (reply_size <= UINT16_MAX);
744   GNUNET_break (config_size <= UINT16_MAX);
745   reply = GNUNET_realloc (xconfig, reply_size);
746   (void) memmove (&reply[1], reply, xconfig_size);
747   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
748   reply->header.size = htons ((uint16_t) reply_size);
749   reply->slave_id = msg->slave_id;
750   reply->operation_id = msg->operation_id;
751   reply->config_size = htons ((uint16_t) config_size);
752   GST_queue_message (client, &reply->header);
753   GNUNET_SERVER_receive_done (client, GNUNET_OK);
754 }
755
756
757 /**
758  * Clears the forwarded operations queue
759  */
760 void
761 GST_clear_fopcq ()
762 {
763   struct ForwardedOperationContext *fopc;
764   
765   while (NULL != (fopc = fopcq_head))
766   {
767     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
768     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
769     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
770       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
771     GNUNET_SERVER_client_drop (fopc->client);
772     switch (fopc->type)
773     {
774     case OP_PEER_CREATE:
775       GNUNET_free (fopc->cls);
776       break;
777     case OP_SHUTDOWN_PEERS:
778       {
779         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
780         
781         GNUNET_assert (0 < hc->nslaves);
782         hc->nslaves--;
783         if (0 == hc->nslaves)
784           GNUNET_free (hc);
785       }
786       break;
787     case OP_PEER_START:
788     case OP_PEER_STOP:
789     case OP_PEER_DESTROY:
790     case OP_PEER_INFO:
791     case OP_OVERLAY_CONNECT:
792     case OP_LINK_CONTROLLERS:
793     case OP_GET_SLAVE_CONFIG:
794     case OP_MANAGE_SERVICE:
795       break;
796     case OP_FORWARDED:
797       GNUNET_assert (0);
798     };
799     GNUNET_free (fopc);
800   }
801 }
802
803
804 /**
805  * Iterator over hash map entries.
806  *
807  * @param cls closure
808  * @param key current key code
809  * @param value value in the hash map
810  * @return GNUNET_YES if we should continue to
811  *         iterate,
812  *         GNUNET_NO if not.
813  */
814 static int
815 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
816 {
817   struct SharedService *ss = value;
818
819   GNUNET_assert (GNUNET_YES ==
820                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
821   GNUNET_free (ss->name);
822   GNUNET_free (ss);
823   return GNUNET_YES;
824 }
825
826
827 /**
828  * Task to clean up and shutdown nicely
829  *
830  * @param cls NULL
831  * @param tc the TaskContext from scheduler
832  */
833 static void
834 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
835 {
836   struct MessageQueue *mq_entry;
837   uint32_t id;
838
839   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
840   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
841   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
842                                                 NULL);
843   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
844   /* cleanup any remaining forwarded operations */
845   GST_clear_fopcq ();
846   GST_free_lcfq ();
847   GST_free_mctxq ();
848   GST_free_occq ();
849   GST_free_roccq ();
850   GST_free_nccq ();
851   GST_neighbour_list_clean();
852   /* Clear peer list */
853   GST_destroy_peers ();
854   /* Clear host list */
855   for (id = 0; id < GST_host_list_size; id++)
856     if (NULL != GST_host_list[id])
857       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
858   GNUNET_free_non_null (GST_host_list);
859   /* Clear route list */
860   GST_route_list_clear ();
861   /* Clear GST_slave_list */
862   GST_slave_list_clear ();
863   if (NULL != GST_context)
864   {
865     GNUNET_free_non_null (GST_context->master_ip);
866     if (NULL != GST_context->system)
867       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
868     GNUNET_SERVER_client_drop (GST_context->client);
869     GNUNET_free (GST_context);
870     GST_context = NULL;
871   }
872   if (NULL != transmit_handle)
873     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
874   while (NULL != (mq_entry = mq_head))
875   {
876     GNUNET_free (mq_entry->msg);
877     GNUNET_SERVER_client_drop (mq_entry->client);
878     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
879     GNUNET_free (mq_entry);
880   }
881   GNUNET_free_non_null (hostname);
882   GNUNET_CONFIGURATION_destroy (our_config);
883   /* Free hello cache */
884   GST_cache_clear ();
885   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
886   GST_opq_openfds = NULL;
887   GST_stats_destroy ();
888 }
889
890
891 /**
892  * Callback for client disconnect
893  *
894  * @param cls NULL
895  * @param client the client which has disconnected
896  */
897 static void
898 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
899 {
900   if (NULL == GST_context)
901     return;
902   if (client == GST_context->client)
903   {
904     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
905     /* should not be needed as we're terminated by failure to read
906      * from stdin, but if stdin fails for some reason, this shouldn't
907      * hurt for now --- might need to revise this later if we ever
908      * decide that master connections might be temporarily down
909      * for some reason */
910     //GNUNET_SCHEDULER_shutdown ();
911   }
912 }
913
914
915 /**
916  * Testbed setup
917  *
918  * @param cls closure
919  * @param server the initialized server
920  * @param cfg configuration to use
921  */
922 static void
923 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
924              const struct GNUNET_CONFIGURATION_Handle *cfg)
925 {
926   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
927     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
928     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
929     {&handle_configure_shared_service, NULL,
930      GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
931     {&GST_handle_link_controllers, NULL,
932      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
933     {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
934     {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
935      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
936     {&GST_handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
937      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
938     {&GST_handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
939      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
940     {&GST_handle_peer_get_config, NULL,
941      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
942      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
943     {&GST_handle_overlay_connect, NULL,
944      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
945      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
946     {&GST_handle_remote_overlay_connect, NULL,
947      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
948     {&GST_handle_manage_peer_service, NULL,
949      GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
950     {&handle_slave_get_config, NULL,
951      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
952      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
953     {&GST_handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
954      sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
955     {NULL}
956   };
957   char *logfile;
958   unsigned long long num;
959
960   if (GNUNET_OK ==
961       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
962                                                &logfile))
963   {
964     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
965     GNUNET_free (logfile);
966   }
967   GNUNET_assert (GNUNET_OK ==
968                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
969                                                         "CACHE_SIZE", &num));
970   GST_cache_init ((unsigned int) num);
971   GNUNET_assert (GNUNET_OK ==
972                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
973                                                         "MAX_OPEN_FDS", &num));
974   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
975   GNUNET_assert (GNUNET_OK ==
976                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
977                                                       "OPERATION_TIMEOUT",
978                                                       (struct
979                                                        GNUNET_TIME_Relative *)
980                                                       &GST_timeout));
981   GNUNET_assert (GNUNET_OK ==
982                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
983                                                         "HOSTNAME", &hostname));
984   our_config = GNUNET_CONFIGURATION_dup (cfg);
985   GNUNET_SERVER_add_handlers (server, message_handlers);
986   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
987   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
988   shutdown_task_id =
989       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
990                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
991                                                   &shutdown_task, NULL);
992   LOG_DEBUG ("Testbed startup complete\n");
993   GST_stats_init (our_config);
994 }
995
996
997 /**
998  * The starting point of execution
999  */
1000 int
1001 main (int argc, char *const *argv)
1002 {
1003   //sleep (15);                 /* Debugging */
1004   return (GNUNET_OK ==
1005           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
1006                               &testbed_run, NULL)) ? 0 : 1;
1007 }
1008
1009 /* end of gnunet-service-testbed.c */