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