add $(GN_LIBINTL) to Makefile.am (fixes 0005902)
[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 it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
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 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
341 #define GROW_SS                                 \
342   do {                                          \
343     GNUNET_array_grow (slist, n, n + 1);                                  \
344     GNUNET_memcpy (&slist[n - 1], &ss,                                  \
345                    sizeof(struct GNUNET_TESTING_SharedService));       \
346   } while (0)
347
348   slist = NULL;
349   n = 0;
350   ss.cfg = cfg;
351   for (; NULL != (arg = strtok (ss_str, " ")); ss_str = NULL)
352   {
353     ss.service = NULL;
354     ss.share = 0;
355     if (2 != sscanf (arg, "%255[^:]:%u",
356                      service,
357                      &ss.share))
358     {
359       LOG (GNUNET_ERROR_TYPE_WARNING,
360            "Ignoring shared service spec: %s",
361            arg);
362       continue;
363     }
364     LOG_DEBUG ("Will be sharing %s service among %u peers\n",
365                service,
366                ss.share);
367     ss.service = GNUNET_strdup (service);
368     GROW_SS;
369   }
370   if (NULL != slist)
371   {
372     /* Add trailing NULL block */
373     (void) memset (&ss,
374                    0,
375                    sizeof(struct GNUNET_TESTING_SharedService));
376     GROW_SS;
377   }
378   return slist;
379 #undef GROW_SS
380 }
381
382
383 /**
384  * Check #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
385  *
386  * @param cls identification of the client
387  * @param message the actual message
388  * @return #GNUNET_OK if @a message is well-formed
389  */
390 static int
391 check_init (void *cls,
392             const struct GNUNET_TESTBED_InitMessage *msg)
393 {
394   const char *controller_hostname;
395   uint16_t msize;
396
397   msize = ntohs (msg->header.size) - sizeof(struct GNUNET_TESTBED_InitMessage);
398   controller_hostname = (const char *) &msg[1];
399   if ('\0' != controller_hostname[msize - 1])
400   {
401     GNUNET_break (0);
402     return GNUNET_SYSERR;
403   }
404   return GNUNET_OK;
405 }
406
407
408 /**
409  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
410  *
411  * @param cls identification of the client
412  * @param message the actual message
413  */
414 static void
415 handle_init (void *cls,
416              const struct GNUNET_TESTBED_InitMessage *msg)
417 {
418   struct GNUNET_SERVICE_Client *client = cls;
419   struct GNUNET_TESTBED_Host *host;
420   const char *controller_hostname;
421   char *ss_str;
422   struct GNUNET_TESTING_SharedService *ss;
423   unsigned int cnt;
424
425   if (NULL != GST_context)
426   {
427     LOG_DEBUG ("We are being connected to laterally\n");
428     GNUNET_SERVICE_client_continue (client);
429     return;
430   }
431   controller_hostname = (const char *) &msg[1];
432   ss_str = NULL;
433   ss = NULL;
434   if (GNUNET_OK ==
435       GNUNET_CONFIGURATION_get_value_string (GST_config,
436                                              "TESTBED",
437                                              "SHARED_SERVICES",
438                                              &ss_str))
439   {
440     ss = parse_shared_services (ss_str,
441                                 GST_config);
442     GNUNET_free (ss_str);
443     ss_str = NULL;
444   }
445   GST_context = GNUNET_new (struct Context);
446   GST_context->client = client;
447   GST_context->host_id = ntohl (msg->host_id);
448   GST_context->master_ip = GNUNET_strdup (controller_hostname);
449   LOG_DEBUG ("Our IP: %s\n",
450              GST_context->master_ip);
451   GST_context->system
452     = GNUNET_TESTING_system_create ("testbed",
453                                     GST_context->master_ip,
454                                     hostname,
455                                     ss);
456   if (NULL != ss)
457   {
458     for (cnt = 0; NULL != ss[cnt].service; cnt++)
459     {
460       ss_str = (char *) ss[cnt].service;
461       GNUNET_free (ss_str);
462     }
463     GNUNET_free (ss);
464     ss = NULL;
465   }
466   host =
467     GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
468                                         GST_context->master_ip,
469                                         NULL,
470                                         GST_config,
471                                         0);
472   host_list_add (host);
473   LOG_DEBUG ("Created master context with host ID: %u\n",
474              GST_context->host_id);
475   GNUNET_SERVICE_client_continue (client);
476 }
477
478
479 /**
480  * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
481  *
482  * @param cls identification of the client
483  * @param msg the actual message
484  * @return #GNUNET_OK if @a message is well-formed
485  */
486 static int
487 check_add_host (void *cls,
488                 const struct GNUNET_TESTBED_AddHostMessage *msg)
489 {
490   uint16_t username_length;
491   uint16_t hostname_length;
492   uint16_t msize;
493
494   msize = ntohs (msg->header.size) - sizeof(struct
495                                             GNUNET_TESTBED_AddHostMessage);
496   username_length = ntohs (msg->username_length);
497   hostname_length = ntohs (msg->hostname_length);
498   /* msg must contain hostname */
499   if ((msize <= username_length) ||
500       (0 == hostname_length))
501   {
502     GNUNET_break (0);
503     return GNUNET_SYSERR;
504   }
505   /* msg must contain configuration */
506   if (msize <= username_length + hostname_length)
507   {
508     GNUNET_break (0);
509     return GNUNET_SYSERR;
510   }
511   return GNUNET_OK;
512 }
513
514
515 /**
516  * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
517  *
518  * @param cls identification of the client
519  * @param msg the actual message
520  */
521 static void
522 handle_add_host (void *cls,
523                  const struct GNUNET_TESTBED_AddHostMessage *msg)
524 {
525   struct GNUNET_SERVICE_Client *client = cls;
526   struct GNUNET_TESTBED_Host *host;
527   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
528   struct GNUNET_CONFIGURATION_Handle *host_cfg;
529   char *username;
530   char *hostname;
531   char *emsg;
532   const void *ptr;
533   uint32_t host_id;
534   uint16_t username_length;
535   uint16_t hostname_length;
536   struct GNUNET_MQ_Envelope *env;
537
538   username_length = ntohs (msg->username_length);
539   hostname_length = ntohs (msg->hostname_length);
540   username = NULL;
541   hostname = NULL;
542   ptr = &msg[1];
543   if (0 != username_length)
544   {
545     username = GNUNET_malloc (username_length + 1);
546     GNUNET_strlcpy (username, ptr, username_length + 1);
547     ptr += username_length;
548   }
549   hostname = GNUNET_malloc (hostname_length + 1);
550   GNUNET_strlcpy (hostname, ptr, hostname_length + 1);
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
621                          GNUNET_TESTBED_SlaveGetConfigurationMessage *msg)
622 {
623   struct GNUNET_SERVICE_Client *client = cls;
624   struct Slave *slave;
625   struct GNUNET_TESTBED_SlaveConfiguration *reply;
626   const struct GNUNET_CONFIGURATION_Handle *cfg;
627   struct GNUNET_MQ_Envelope *env;
628   char *config;
629   char *xconfig;
630   size_t config_size;
631   size_t xconfig_size;
632   uint64_t op_id;
633   uint32_t slave_id;
634
635   slave_id = ntohl (msg->slave_id);
636   op_id = GNUNET_ntohll (msg->operation_id);
637   if ((GST_slave_list_size <= slave_id) ||
638       (NULL == GST_slave_list[slave_id]))
639   {
640     /* FIXME: Add forwardings for this type of message here.. */
641     GST_send_operation_fail_msg (client,
642                                  op_id,
643                                  "Slave not found");
644     GNUNET_SERVICE_client_continue (client);
645     return;
646   }
647   slave = GST_slave_list[slave_id];
648   GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (
649                             GST_host_list[slave->host_id])));
650   config = GNUNET_CONFIGURATION_serialize (cfg,
651                                            &config_size);
652   /* FIXME: maybe we want to transmit the delta to the default here? */
653   xconfig_size = GNUNET_TESTBED_compress_config_ (config,
654                                                   config_size,
655                                                   &xconfig);
656   GNUNET_free (config);
657   GNUNET_assert (xconfig_size + sizeof(struct
658                                        GNUNET_TESTBED_SlaveConfiguration) <=
659                  UINT16_MAX);
660   GNUNET_assert (xconfig_size <= UINT16_MAX);
661   env = GNUNET_MQ_msg_extra (reply,
662                              xconfig_size,
663                              GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
664   reply->slave_id = msg->slave_id;
665   reply->operation_id = msg->operation_id;
666   reply->config_size = htons ((uint16_t) config_size);
667   GNUNET_memcpy (&reply[1],
668                  xconfig,
669                  xconfig_size);
670   GNUNET_free (xconfig);
671   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
672                   env);
673   GNUNET_SERVICE_client_continue (client);
674 }
675
676
677 /**
678  * Clears the forwarded operations queue
679  */
680 void
681 GST_clear_fopcq ()
682 {
683   struct ForwardedOperationContext *fopc;
684
685   while (NULL != (fopc = fopcq_head))
686   {
687     GNUNET_CONTAINER_DLL_remove (fopcq_head,
688                                  fopcq_tail,
689                                  fopc);
690     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
691     if (NULL != fopc->timeout_task)
692       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
693     switch (fopc->type)
694     {
695     case OP_PEER_CREATE:
696       GNUNET_free (fopc->cls);
697       break;
698
699     case OP_SHUTDOWN_PEERS:
700       {
701         struct HandlerContext_ShutdownPeers *hc = fopc->cls;
702
703         GNUNET_assert (0 < hc->nslaves);
704         hc->nslaves--;
705         if (0 == hc->nslaves)
706           GNUNET_free (hc);
707       }
708       break;
709
710     case OP_PEER_START:
711     case OP_PEER_STOP:
712     case OP_PEER_DESTROY:
713     case OP_PEER_INFO:
714     case OP_OVERLAY_CONNECT:
715     case OP_LINK_CONTROLLERS:
716     case OP_GET_SLAVE_CONFIG:
717     case OP_MANAGE_SERVICE:
718     case OP_PEER_RECONFIGURE:
719       break;
720
721     case OP_FORWARDED:
722       GNUNET_assert (0);
723     }
724     ;
725     GNUNET_free (fopc);
726   }
727 }
728
729
730 /**
731  * Task to clean up and shutdown nicely
732  *
733  * @param cls NULL
734  */
735 static void
736 shutdown_task (void *cls)
737 {
738   uint32_t id;
739
740   LOG_DEBUG ("Shutting down testbed service\n");
741   /* cleanup any remaining forwarded operations */
742   GST_clear_fopcq ();
743   GST_free_lcf ();
744   GST_free_mctxq ();
745   GST_free_occq ();
746   GST_free_roccq ();
747   GST_free_nccq ();
748   GST_neighbour_list_clean ();
749   GST_free_prcq ();
750   /* Clear peer list */
751   GST_destroy_peers ();
752   /* Clear route list */
753   GST_route_list_clear ();
754   /* Clear GST_slave_list */
755   GST_slave_list_clear ();
756   /* Clear host list */
757   for (id = 0; id < GST_host_list_size; id++)
758     if (NULL != GST_host_list[id])
759       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
760   GNUNET_free_non_null (GST_host_list);
761   if (NULL != GST_context)
762   {
763     GNUNET_free_non_null (GST_context->master_ip);
764     if (NULL != GST_context->system)
765       GNUNET_TESTING_system_destroy (GST_context->system,
766                                      GNUNET_YES);
767     GNUNET_free (GST_context);
768     GST_context = NULL;
769   }
770   GNUNET_free_non_null (hostname);
771   /* Free hello cache */
772   GST_cache_clear ();
773   GST_connection_pool_destroy ();
774   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
775   GST_opq_openfds = NULL;
776   GST_stats_destroy ();
777   GST_barriers_destroy ();
778   GNUNET_CONFIGURATION_destroy (GST_config);
779 }
780
781
782 /**
783  * Callback for client connect
784  *
785  * @param cls NULL
786  * @param client the client which has disconnected
787  * @param mq queue for sending messages to @a client
788  * @return @a client
789  */
790 static void *
791 client_connect_cb (void *cls,
792                    struct GNUNET_SERVICE_Client *client,
793                    struct GNUNET_MQ_Handle *mq)
794 {
795   return client;
796 }
797
798
799 /**
800  * Callback for client disconnect
801  *
802  * @param cls NULL
803  * @param client the client which has disconnected
804  * @param app_ctx should match @a client
805  */
806 static void
807 client_disconnect_cb (void *cls,
808                       struct GNUNET_SERVICE_Client *client,
809                       void *app_ctx)
810 {
811   struct ForwardedOperationContext *fopc;
812   struct ForwardedOperationContext *fopcn;
813
814   GNUNET_assert (client == app_ctx);
815   GST_notify_client_disconnect_oc (client);
816   GST_link_notify_disconnect (client);
817   GST_notify_client_disconnect_peers (client);
818   for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
819   {
820     fopcn = fopc->next;
821     if (fopc->client == client)
822     {
823       /* handle as if it were a timeout */
824       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
825       GST_forwarded_operation_timeout (fopc);
826     }
827   }
828   if (NULL == GST_context)
829     return;
830   if (client == GST_context->client)
831   {
832     LOG (GNUNET_ERROR_TYPE_DEBUG,
833          "Master client disconnected\n");
834     GST_context->client = NULL;
835     /* should not be needed as we're terminated by failure to read
836      * from stdin, but if stdin fails for some reason, this shouldn't
837      * hurt for now --- might need to revise this later if we ever
838      * decide that master connections might be temporarily down
839      * for some reason */// GNUNET_SCHEDULER_shutdown ();
840   }
841 }
842
843
844 /**
845  * Testbed setup
846  *
847  * @param cls closure
848  * @param cfg configuration to use
849  * @param service the initialized server
850  */
851 static void
852 testbed_run (void *cls,
853              const struct GNUNET_CONFIGURATION_Handle *cfg,
854              struct GNUNET_SERVICE_Handle *service)
855 {
856   char *logfile;
857   unsigned long long num;
858
859   LOG_DEBUG ("Starting testbed\n");
860   if (GNUNET_OK ==
861       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
862                                                &logfile))
863   {
864     GNUNET_break (GNUNET_OK ==
865                   GNUNET_log_setup ("testbed",
866                                     "DEBUG",
867                                     logfile));
868     GNUNET_free (logfile);
869   }
870   GNUNET_assert (GNUNET_OK ==
871                  GNUNET_CONFIGURATION_get_value_number (cfg,
872                                                         "testbed",
873                                                         "CACHE_SIZE",
874                                                         &num));
875   GST_cache_init ((unsigned int) num);
876   GST_connection_pool_init ((unsigned int) num);
877   GNUNET_assert (GNUNET_OK ==
878                  GNUNET_CONFIGURATION_get_value_number (cfg,
879                                                         "testbed",
880                                                         "MAX_OPEN_FDS",
881                                                         &num));
882   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ (
883     OPERATION_QUEUE_TYPE_FIXED,
884     (unsigned int) num);
885   GNUNET_assert (GNUNET_OK ==
886                  GNUNET_CONFIGURATION_get_value_time (cfg,
887                                                       "testbed",
888                                                       "OPERATION_TIMEOUT",
889                                                       &GST_timeout));
890   GNUNET_assert (GNUNET_OK ==
891                  GNUNET_CONFIGURATION_get_value_string (cfg,
892                                                         "testbed",
893                                                         "HOSTNAME",
894                                                         &hostname));
895   GST_config = GNUNET_CONFIGURATION_dup (cfg);
896   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
897                                  NULL);
898   LOG_DEBUG ("Testbed startup complete\n");
899   GST_stats_init (GST_config);
900   GST_barriers_init (GST_config);
901 }
902
903
904 /**
905  * Define "main" method using service macro.
906  */
907 GNUNET_SERVICE_MAIN
908   ("testbed",
909   GNUNET_SERVICE_OPTION_NONE,
910   &testbed_run,
911   &client_connect_cb,
912   &client_disconnect_cb,
913   NULL,
914   GNUNET_MQ_hd_var_size (init,
915                          GNUNET_MESSAGE_TYPE_TESTBED_INIT,
916                          struct GNUNET_TESTBED_InitMessage,
917                          NULL),
918   GNUNET_MQ_hd_var_size (add_host,
919                          GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
920                          struct GNUNET_TESTBED_AddHostMessage,
921                          NULL),
922   GNUNET_MQ_hd_fixed_size (slave_get_config,
923                            GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
924                            struct GNUNET_TESTBED_SlaveGetConfigurationMessage,
925                            NULL),
926   GNUNET_MQ_hd_fixed_size (link_controllers,
927                            GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
928                            struct GNUNET_TESTBED_ControllerLinkRequest,
929                            NULL),
930   GNUNET_MQ_hd_var_size (remote_overlay_connect,
931                          GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT,
932                          struct GNUNET_TESTBED_RemoteOverlayConnectMessage,
933                          NULL),
934   GNUNET_MQ_hd_fixed_size (overlay_connect,
935                            GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
936                            struct GNUNET_TESTBED_OverlayConnectMessage,
937                            NULL),
938   GNUNET_MQ_hd_var_size (peer_create,
939                          GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER,
940                          struct GNUNET_TESTBED_PeerCreateMessage,
941                          NULL),
942   GNUNET_MQ_hd_fixed_size (peer_destroy,
943                            GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
944                            struct GNUNET_TESTBED_PeerDestroyMessage,
945                            NULL),
946   GNUNET_MQ_hd_fixed_size (peer_start,
947                            GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
948                            struct GNUNET_TESTBED_PeerStartMessage,
949                            NULL),
950   GNUNET_MQ_hd_fixed_size (peer_stop,
951                            GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
952                            struct GNUNET_TESTBED_PeerStopMessage,
953                            NULL),
954   GNUNET_MQ_hd_fixed_size (peer_get_config,
955                            GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION,
956                            struct GNUNET_TESTBED_PeerGetConfigurationMessage,
957                            NULL),
958   GNUNET_MQ_hd_var_size (manage_peer_service,
959                          GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE,
960                          struct GNUNET_TESTBED_ManagePeerServiceMessage,
961                          NULL),
962   GNUNET_MQ_hd_fixed_size (shutdown_peers,
963                            GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
964                            struct GNUNET_TESTBED_ShutdownPeersMessage,
965                            NULL),
966   GNUNET_MQ_hd_var_size (peer_reconfigure,
967                          GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER,
968                          struct GNUNET_TESTBED_PeerReconfigureMessage,
969                          NULL),
970   GNUNET_MQ_hd_var_size (barrier_init,
971                          GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT,
972                          struct GNUNET_TESTBED_BarrierInit,
973                          NULL),
974   GNUNET_MQ_hd_var_size (barrier_cancel,
975                          GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL,
976                          struct GNUNET_TESTBED_BarrierCancel,
977                          NULL),
978   GNUNET_MQ_hd_var_size (barrier_status,
979                          GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
980                          struct GNUNET_TESTBED_BarrierStatusMsg,
981                          NULL),
982   GNUNET_MQ_handler_end ());
983
984
985 /* end of gnunet-service-testbed.c */