send configurations of newly started slave controllers as part of controller link...
[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 #include <zlib.h>
30
31
32 /***********/
33 /* Globals */
34 /***********/
35
36 /**
37  * Our configuration
38  */
39 struct GNUNET_CONFIGURATION_Handle *our_config;
40
41 /**
42  * The master context; generated with the first INIT message
43  */
44 struct Context *GST_context;
45
46 /**
47  * A list of directly linked neighbours
48  */
49 struct Slave **GST_slave_list;
50
51 /**
52  * A list of peers we know about
53  */
54 struct Peer **GST_peer_list;
55
56 /**
57  * Array of hosts
58  */
59 struct GNUNET_TESTBED_Host **GST_host_list;
60
61 /**
62  * DLL head for forwarded operation contexts
63  */
64 struct ForwardedOperationContext *fopcq_head;
65
66 /**
67  * DLL tail for forwarded operation contexts
68  */
69 struct ForwardedOperationContext *fopcq_tail;
70
71 /**
72  * Operation queue for open file descriptors
73  */
74 struct OperationQueue *GST_opq_openfds;
75
76 /**
77  * Timeout for operations which may take some time
78  */
79 const struct GNUNET_TIME_Relative GST_timeout;
80
81 /**
82  * The size of the host list
83  */
84 unsigned int GST_host_list_size;
85
86 /**
87  * The size of directly linked neighbours list
88  */
89 unsigned int GST_slave_list_size;
90
91 /**
92  * The size of the peer list
93  */
94 unsigned int GST_peer_list_size;
95
96
97 /***********************************/
98 /* Local definitions and variables */
99 /***********************************/
100
101 /**
102  * The message queue for sending messages to clients
103  */
104 struct MessageQueue
105 {
106   /**
107    * The message to be sent
108    */
109   struct GNUNET_MessageHeader *msg;
110
111   /**
112    * The client to send the message to
113    */
114   struct GNUNET_SERVER_Client *client;
115
116   /**
117    * next pointer for DLL
118    */
119   struct MessageQueue *next;
120
121   /**
122    * prev pointer for DLL
123    */
124   struct MessageQueue *prev;
125 };
126
127 /**
128  * Our hostname; we give this to all the peers we start
129  */
130 static char *hostname;
131
132 /**
133  * Current Transmit Handle; NULL if no notify transmit exists currently
134  */
135 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
136
137 /**
138  * The head for the LCF queue
139  */
140 static struct LCFContextQueue *lcfq_head;
141
142 /**
143  * The tail for the LCF queue
144  */
145 static struct LCFContextQueue *lcfq_tail;
146
147 /**
148  * The message queue head
149  */
150 static struct MessageQueue *mq_head;
151
152 /**
153  * The message queue tail
154  */
155 static struct MessageQueue *mq_tail;
156
157 /**
158  * The hashmap of shared services
159  */
160 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
161
162 /**
163  * A list of routes
164  */
165 static struct Route **route_list;
166
167 /**
168  * The event mask for the events we listen from sub-controllers
169  */
170 static uint64_t event_mask;
171
172 /**
173  * The size of the route list
174  */
175 static unsigned int route_list_size;
176
177 /**
178  * The lcf_task handle
179  */
180 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
181
182 /**
183  * The shutdown task handle
184  */
185 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
186
187
188 /**
189  * Function called to notify a client about the connection begin ready to queue
190  * more data.  "buf" will be NULL and "size" zero if the connection was closed
191  * for writing in the meantime.
192  *
193  * @param cls NULL
194  * @param size number of bytes available in buf
195  * @param buf where the callee should write the message
196  * @return number of bytes written to buf
197  */
198 static size_t
199 transmit_ready_notify (void *cls, size_t size, void *buf)
200 {
201   struct MessageQueue *mq_entry;
202
203   transmit_handle = NULL;
204   mq_entry = mq_head;
205   GNUNET_assert (NULL != mq_entry);
206   if (0 == size)
207     return 0;
208   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
209   size = ntohs (mq_entry->msg->size);
210   memcpy (buf, mq_entry->msg, size);
211   GNUNET_free (mq_entry->msg);
212   GNUNET_SERVER_client_drop (mq_entry->client);
213   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
214   GNUNET_free (mq_entry);
215   mq_entry = mq_head;
216   if (NULL != mq_entry)
217     transmit_handle =
218         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
219                                              ntohs (mq_entry->msg->size),
220                                              GNUNET_TIME_UNIT_FOREVER_REL,
221                                              &transmit_ready_notify, NULL);
222   return size;
223 }
224
225
226 /**
227  * Queues a message in send queue for sending to the service
228  *
229  * @param client the client to whom the queued message has to be sent
230  * @param msg the message to queue
231  */
232 void
233 GST_queue_message (struct GNUNET_SERVER_Client *client,
234                    struct GNUNET_MessageHeader *msg)
235 {
236   struct MessageQueue *mq_entry;
237   uint16_t type;
238   uint16_t size;
239
240   type = ntohs (msg->type);
241   size = ntohs (msg->size);
242   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
243                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
244   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
245   mq_entry->msg = msg;
246   mq_entry->client = client;
247   GNUNET_SERVER_client_keep (client);
248   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
249              ntohs (msg->size));
250   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
251   if (NULL == transmit_handle)
252     transmit_handle =
253         GNUNET_SERVER_notify_transmit_ready (client, size,
254                                              GNUNET_TIME_UNIT_FOREVER_REL,
255                                              &transmit_ready_notify, NULL);
256 }
257
258
259 /**
260  * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
261  * several times we call it only once. The array is also made to grow in steps
262  * of LIST_GROW_STEP.
263  *
264  * @param ptr the array pointer to grow
265  * @param size the size of array
266  * @param accommodate_size the size which the array has to accommdate; after
267  *          this call the array will be big enough to accommdate sizes upto
268  *          accommodate_size
269  */
270 #define array_grow_large_enough(ptr, size, accommodate_size) \
271   do                                                                    \
272   {                                                                     \
273     unsigned int growth_size;                                           \
274     GNUNET_assert (size <= accommodate_size);                            \
275     growth_size = size;                                                 \
276     while (growth_size <= accommodate_size)                             \
277       growth_size += LIST_GROW_STEP;                                    \
278     GNUNET_array_grow (ptr, size, growth_size);                         \
279     GNUNET_assert (size > accommodate_size);                            \
280   } while (0)
281
282
283 /**
284  * Function to add a host to the current list of known hosts
285  *
286  * @param host the host to add
287  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
288  *           already in use
289  */
290 static int
291 host_list_add (struct GNUNET_TESTBED_Host *host)
292 {
293   uint32_t host_id;
294
295   host_id = GNUNET_TESTBED_host_get_id_ (host);
296   if (GST_host_list_size <= host_id)
297     array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
298   if (NULL != GST_host_list[host_id])
299   {
300     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
301     return GNUNET_SYSERR;
302   }
303   GST_host_list[host_id] = host;
304   return GNUNET_OK;
305 }
306
307
308 /**
309  * Adds a route to the route list
310  *
311  * @param route the route to add
312  */
313 static void
314 route_list_add (struct Route *route)
315 {
316   if (route->dest >= route_list_size)
317     array_grow_large_enough (route_list, route_list_size, route->dest);
318   GNUNET_assert (NULL == route_list[route->dest]);
319   route_list[route->dest] = route;
320 }
321
322
323 /**
324  * Adds a slave to the slave array
325  *
326  * @param slave the slave controller to add
327  */
328 static void
329 slave_list_add (struct Slave *slave)
330 {
331   if (slave->host_id >= GST_slave_list_size)
332     array_grow_large_enough (GST_slave_list, GST_slave_list_size,
333                              slave->host_id);
334   GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
335   GST_slave_list[slave->host_id] = slave;
336 }
337
338
339 /**
340  * Adds a peer to the peer array
341  *
342  * @param peer the peer to add
343  */
344 static void
345 peer_list_add (struct Peer *peer)
346 {
347   if (peer->id >= GST_peer_list_size)
348     array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
349   GNUNET_assert (NULL == GST_peer_list[peer->id]);
350   GST_peer_list[peer->id] = peer;
351 }
352
353
354 /**
355  * Removes a the give peer from the peer array
356  *
357  * @param peer the peer to be removed
358  */
359 static void
360 peer_list_remove (struct Peer *peer)
361 {
362   unsigned int orig_size;
363   uint32_t id;
364
365   GST_peer_list[peer->id] = NULL;
366   orig_size = GST_peer_list_size;
367   while (GST_peer_list_size >= LIST_GROW_STEP)
368   {
369     for (id = GST_peer_list_size - 1;
370          (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
371          id--)
372       if (NULL != GST_peer_list[id])
373         break;
374     if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
375       break;
376     GST_peer_list_size -= LIST_GROW_STEP;
377   }
378   if (orig_size == GST_peer_list_size)
379     return;
380   GST_peer_list =
381       GNUNET_realloc (GST_peer_list,
382                       sizeof (struct Peer *) * GST_peer_list_size);
383 }
384
385
386 /**
387  * Finds the route with directly connected host as destination through which
388  * the destination host can be reached
389  *
390  * @param host_id the id of the destination host
391  * @return the route with directly connected destination host; NULL if no route
392  *           is found
393  */
394 struct Route *
395 GST_find_dest_route (uint32_t host_id)
396 {
397   struct Route *route;
398
399   if (route_list_size <= host_id)
400     return NULL;
401   while (NULL != (route = route_list[host_id]))
402   {
403     if (route->thru == GST_context->host_id)
404       break;
405     host_id = route->thru;
406   }
407   return route;
408 }
409
410
411 /**
412  * Routes message to a host given its host_id
413  *
414  * @param host_id the id of the destination host
415  * @param msg the message to be routed
416  */
417 static void
418 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
419 {
420   GNUNET_break (0);
421 }
422
423
424 /**
425  * Send operation failure message to client
426  *
427  * @param client the client to which the failure message has to be sent to
428  * @param operation_id the id of the failed operation
429  * @param emsg the error message; can be NULL
430  */
431 void
432 GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
433                              uint64_t operation_id, const char *emsg)
434 {
435   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
436   uint16_t msize;
437   uint16_t emsg_len;
438
439   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
440   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
441   msize += emsg_len;
442   msg = GNUNET_malloc (msize);
443   msg->header.size = htons (msize);
444   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
445   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
446   msg->operation_id = GNUNET_htonll (operation_id);
447   if (0 != emsg_len)
448     memcpy (&msg[1], emsg, emsg_len);
449   GST_queue_message (client, &msg->header);
450 }
451
452
453 /**
454  * Function to send generic operation success message to given client
455  *
456  * @param client the client to send the message to
457  * @param operation_id the id of the operation which was successful
458  */
459 static void
460 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
461                             uint64_t operation_id)
462 {
463   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
464   uint16_t msize;
465
466   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
467   msg = GNUNET_malloc (msize);
468   msg->header.size = htons (msize);
469   msg->header.type =
470       htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
471   msg->operation_id = GNUNET_htonll (operation_id);
472   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
473   GST_queue_message (client, &msg->header);
474 }
475
476
477 /**
478  * Function to send a failure reponse for controller link operation
479  *
480  * @param client the client to send the message to
481  * @param operation_id the operation ID of the controller link request
482  * @param cfg the configuration with which the delegated controller is started.
483  *          Can be NULL if the delegated controller is not started but just
484  *          linked to.
485  * @param emsg set to an error message explaining why the controller link
486  *          failed.  Setting this to NULL signifies success.  !This should be
487  *          NULL if cfg is set!
488  */
489 static void
490 send_controller_link_response (struct GNUNET_SERVER_Client *client,
491                                uint64_t operation_id,
492                                const struct GNUNET_CONFIGURATION_Handle
493                                *cfg,
494                                const char *emsg)
495 {
496   struct GNUNET_TESTBED_ControllerLinkResponse *msg;
497   char *xconfig;
498   size_t config_size;
499   size_t xconfig_size;  
500   uint16_t msize;
501
502   GNUNET_assert ((NULL == cfg) || (NULL == emsg));
503   xconfig = NULL;
504   xconfig_size = 0;
505   config_size = 0;
506   msize = sizeof (struct GNUNET_TESTBED_ControllerLinkResponse);
507   if (NULL != cfg)
508   {
509     xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
510                                             &config_size,
511                                             &xconfig_size);
512     msize += xconfig_size;
513   }
514   if (NULL != emsg)
515     msize += strlen (emsg);
516   msg = GNUNET_malloc (msize);
517   msg->header.type = htons
518       (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
519   msg->header.size = htons (msize);
520   if (NULL == emsg)
521     msg->success = htons (GNUNET_YES);
522   msg->operation_id = GNUNET_htonll (operation_id);
523   msg->config_size = htons ((uint16_t) config_size);
524   if (NULL != xconfig)
525     memcpy (&msg[1], xconfig, xconfig_size);
526   if (NULL != emsg)
527     memcpy (&msg[1], emsg, strlen (emsg));
528   GST_queue_message (client, &msg->header);
529 }
530
531 /**
532  * Callback which will be called after a host registration succeeded or failed
533  *
534  * @param cls the handle to the slave at which the registration is completed
535  * @param emsg the error message; NULL if host registration is successful
536  */
537 static void
538 hr_completion (void *cls, const char *emsg);
539
540
541 /**
542  * Attempts to register the next host in the host registration queue
543  *
544  * @param slave the slave controller whose host registration queue is checked
545  *          for host registrations
546  */
547 static void
548 register_next_host (struct Slave *slave)
549 {
550   struct HostRegistration *hr;
551
552   hr = slave->hr_dll_head;
553   GNUNET_assert (NULL != hr);
554   GNUNET_assert (NULL == slave->rhandle);
555   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
556        GNUNET_TESTBED_host_get_id_ (hr->host),
557        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
558   slave->rhandle =
559       GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
560                                     slave);
561 }
562
563
564 /**
565  * Callback which will be called to after a host registration succeeded or failed
566  *
567  * @param cls the handle to the slave at which the registration is completed
568  * @param emsg the error message; NULL if host registration is successful
569  */
570 static void
571 hr_completion (void *cls, const char *emsg)
572 {
573   struct Slave *slave = cls;
574   struct HostRegistration *hr;
575
576   slave->rhandle = NULL;
577   hr = slave->hr_dll_head;
578   GNUNET_assert (NULL != hr);
579   LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
580        GNUNET_TESTBED_host_get_id_ (hr->host),
581        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
582   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
583   if (NULL != hr->cb)
584     hr->cb (hr->cb_cls, emsg);
585   GNUNET_free (hr);
586   if (NULL != slave->hr_dll_head)
587     register_next_host (slave);
588 }
589
590
591 /**
592  * Adds a host registration's request to a slave's registration queue
593  *
594  * @param slave the slave controller at which the given host has to be
595  *          registered
596  * @param cb the host registration completion callback
597  * @param cb_cls the closure for the host registration completion callback
598  * @param host the host which has to be registered
599  */
600 void
601 GST_queue_host_registration (struct Slave *slave,
602                              GNUNET_TESTBED_HostRegistrationCompletion cb,
603                              void *cb_cls, struct GNUNET_TESTBED_Host *host)
604 {
605   struct HostRegistration *hr;
606   int call_register;
607
608   LOG (GNUNET_ERROR_TYPE_DEBUG,
609        "Queueing host registration for host %u at %u\n",
610        GNUNET_TESTBED_host_get_id_ (host),
611        GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
612   hr = GNUNET_malloc (sizeof (struct HostRegistration));
613   hr->cb = cb;
614   hr->cb_cls = cb_cls;
615   hr->host = host;
616   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
617   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
618   if (GNUNET_YES == call_register)
619     register_next_host (slave);
620 }
621
622
623 /**
624  * The  Link Controller forwarding task
625  *
626  * @param cls the LCFContext
627  * @param tc the Task context from scheduler
628  */
629 static void
630 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
631
632
633 /**
634  * Completion callback for host registrations while forwarding Link Controller messages
635  *
636  * @param cls the LCFContext
637  * @param emsg the error message; NULL if host registration is successful
638  */
639 static void
640 lcf_proc_cc (void *cls, const char *emsg)
641 {
642   struct LCFContext *lcf = cls;
643
644   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
645   switch (lcf->state)
646   {
647   case INIT:
648     if (NULL != emsg)
649       goto registration_error;
650     lcf->state = DELEGATED_HOST_REGISTERED;
651     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
652     break;
653   case DELEGATED_HOST_REGISTERED:
654     if (NULL != emsg)
655       goto registration_error;
656     lcf->state = SLAVE_HOST_REGISTERED;
657     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
658     break;
659   default:
660     GNUNET_assert (0);          /* Shouldn't reach here */
661   }
662   return;
663
664 registration_error:
665   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
666        emsg);
667   lcf->state = FINISHED;
668   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
669 }
670
671
672 /**
673  * Callback to relay the reply msg of a forwarded operation back to the client
674  *
675  * @param cls ForwardedOperationContext
676  * @param msg the message to relay
677  */
678 void
679 GST_forwarded_operation_reply_relay (void *cls,
680                                      const struct GNUNET_MessageHeader *msg)
681 {
682   struct ForwardedOperationContext *fopc = cls;
683   struct GNUNET_MessageHeader *dup_msg;
684   uint16_t msize;
685
686   msize = ntohs (msg->size);
687   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
688              msize);
689   dup_msg = GNUNET_copy_message (msg);
690   GST_queue_message (fopc->client, dup_msg);
691   GNUNET_SERVER_client_drop (fopc->client);
692   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
693   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
694   GNUNET_free (fopc);
695 }
696
697
698 /**
699  * Task to free resources when forwarded operation has been timedout
700  *
701  * @param cls the ForwardedOperationContext
702  * @param tc the task context from scheduler
703  */
704 void
705 GST_forwarded_operation_timeout (void *cls,
706                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
707 {
708   struct ForwardedOperationContext *fopc = cls;
709
710   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
711   LOG (GNUNET_ERROR_TYPE_WARNING, "A forwarded operation has timed out\n");
712   GST_send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
713   GNUNET_SERVER_client_drop (fopc->client);
714   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
715   GNUNET_free (fopc);
716 }
717
718
719 /**
720  * The  Link Controller forwarding task
721  *
722  * @param cls the LCFContext
723  * @param tc the Task context from scheduler
724  */
725 static void
726 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
727
728
729 /**
730  * Callback to be called when forwarded link controllers operation is
731  * successfull. We have to relay the reply msg back to the client
732  *
733  * @param cls the LCFContext
734  * @param msg the message to relay
735  */
736 static void
737 lcf_forwarded_operation_reply_relay (void *cls,
738                                      const struct GNUNET_MessageHeader *msg)
739 {
740   struct LCFContext *lcf = cls;
741
742   GNUNET_assert (NULL != lcf->fopc);
743   GST_forwarded_operation_reply_relay (lcf->fopc, msg);
744   lcf->fopc = NULL;
745   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
746   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
747 }
748
749
750 /**
751  * Task to free resources when forwarded link controllers has been timedout
752  *
753  * @param cls the LCFContext
754  * @param tc the task context from scheduler
755  */
756 static void
757 lcf_forwarded_operation_timeout (void *cls,
758                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
759 {
760   struct LCFContext *lcf = cls;
761   struct ForwardedOperationContext *fopc = lcf->fopc;
762
763   GNUNET_assert (NULL != lcf->fopc);
764   lcf->fopc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
765   //  GST_forwarded_operation_timeout (lcf->fopc, tc);
766   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
767   LOG (GNUNET_ERROR_TYPE_WARNING,
768        "A forwarded operation as part of controller linking has timed out\n");
769   send_controller_link_response (fopc->client, fopc->operation_id, NULL, "Timeout");
770   GNUNET_SERVER_client_drop (fopc->client);
771   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
772   GNUNET_free (fopc);
773   lcf->fopc = NULL;
774   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
775   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
776 }
777
778
779 /**
780  * The  Link Controller forwarding task
781  *
782  * @param cls the LCFContext
783  * @param tc the Task context from scheduler
784  */
785 static void
786 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
787 {
788   struct LCFContext *lcf = cls;
789   struct LCFContextQueue *lcfq;
790
791   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
792   switch (lcf->state)
793   {
794   case INIT:
795     if (GNUNET_NO ==
796         GNUNET_TESTBED_is_host_registered_ (GST_host_list
797                                             [lcf->delegated_host_id],
798                                             lcf->gateway->controller))
799     {
800       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
801                                    GST_host_list[lcf->delegated_host_id]);
802     }
803     else
804     {
805       lcf->state = DELEGATED_HOST_REGISTERED;
806       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
807     }
808     break;
809   case DELEGATED_HOST_REGISTERED:
810     if (GNUNET_NO ==
811         GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
812                                             lcf->gateway->controller))
813     {
814       GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
815                                    GST_host_list[lcf->slave_host_id]);
816     }
817     else
818     {
819       lcf->state = SLAVE_HOST_REGISTERED;
820       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
821     }
822     break;
823   case SLAVE_HOST_REGISTERED:
824     lcf->fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
825     lcf->fopc->client = lcf->client;
826     lcf->fopc->operation_id = lcf->operation_id;
827     lcf->fopc->type = OP_LINK_CONTROLLERS;
828     lcf->fopc->opc =
829         GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
830                                                lcf->operation_id,
831                                                &lcf->msg->header,
832                                                &lcf_forwarded_operation_reply_relay,
833                                                lcf);
834     lcf->fopc->timeout_task =
835         GNUNET_SCHEDULER_add_delayed (GST_timeout, &lcf_forwarded_operation_timeout,
836                                       lcf);
837     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, lcf->fopc);
838     lcf->state = FINISHED;
839     break;
840   case FINISHED:
841     lcfq = lcfq_head;
842     GNUNET_assert (lcfq->lcf == lcf);
843     GNUNET_free (lcf->msg);
844     GNUNET_free (lcf);
845     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
846     GNUNET_free (lcfq);
847     if (NULL != lcfq_head)
848       lcf_proc_task_id =
849           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
850   }
851 }
852
853
854 /**
855  * Callback for event from slave controllers
856  *
857  * @param cls struct Slave *
858  * @param event information about the event
859  */
860 static void
861 slave_event_callback (void *cls,
862                       const struct GNUNET_TESTBED_EventInformation *event)
863 {
864   struct RegisteredHostContext *rhc;
865   struct GNUNET_CONFIGURATION_Handle *cfg;
866   struct GNUNET_TESTBED_Operation *old_op;
867
868   /* We currently only get here when working on RegisteredHostContexts */
869   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
870   rhc = event->details.operation_finished.op_cls;
871   GNUNET_assert (rhc->sub_op == event->details.operation_finished.operation);
872   switch (rhc->state)
873   {
874   case RHC_GET_CFG:
875     cfg = event->details.operation_finished.generic;
876     old_op = rhc->sub_op;
877     rhc->state = RHC_LINK;
878     rhc->sub_op =
879         GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
880                                         rhc->reg_host, rhc->host, cfg,
881                                         GNUNET_NO);
882     GNUNET_TESTBED_operation_done (old_op);
883     break;
884   case RHC_LINK:
885     LOG_DEBUG ("OL: Linking controllers successfull\n");
886     GNUNET_TESTBED_operation_done (rhc->sub_op);
887     rhc->sub_op = NULL;
888     rhc->state = RHC_OL_CONNECT;
889     GST_process_next_focc (rhc);
890     break;
891   default:
892     GNUNET_assert (0);
893   }
894 }
895
896
897 /**
898  * Callback to signal successfull startup of the controller process
899  *
900  * @param cls the handle to the slave whose status is to be found here
901  * @param cfg the configuration with which the controller has been started;
902  *          NULL if status is not GNUNET_OK
903  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
904  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
905  */
906 static void
907 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
908                        int status)
909 {
910   struct Slave *slave = cls;
911   struct LinkControllersContext *lcc;
912
913   lcc = slave->lcc;
914   if (GNUNET_SYSERR == status)
915   {
916     slave->controller_proc = NULL;
917     GST_slave_list[slave->host_id] = NULL;
918     if (NULL != slave->cfg)
919       GNUNET_CONFIGURATION_destroy (slave->cfg);
920     GNUNET_free (slave);
921     slave = NULL;
922     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
923     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
924     goto clean_lcc;
925   }
926   slave->controller =
927       GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
928                                          event_mask, &slave_event_callback,
929                                          slave);
930   if (NULL != slave->controller)
931   {
932     send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
933     slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
934   }
935   else
936   {
937     send_controller_link_response (lcc->client, lcc->operation_id, NULL,
938                                    "Could not connect to delegated controller");
939     GNUNET_TESTBED_controller_stop (slave->controller_proc);
940     GST_slave_list[slave->host_id] = NULL;
941     GNUNET_free (slave);
942     slave = NULL;
943   }
944
945 clean_lcc:
946   if (NULL != lcc)
947   {
948     if (NULL != lcc->client)
949     {
950       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
951       GNUNET_SERVER_client_drop (lcc->client);
952       lcc->client = NULL;
953     }
954     GNUNET_free (lcc);
955   }
956   if (NULL != slave)
957     slave->lcc = NULL;
958 }
959
960
961 /**
962  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
963  *
964  * @param cls NULL
965  * @param client identification of the client
966  * @param message the actual message
967  */
968 static void
969 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
970              const struct GNUNET_MessageHeader *message)
971 {
972   const struct GNUNET_TESTBED_InitMessage *msg;
973   struct GNUNET_TESTBED_Host *host;
974   const char *controller_hostname;
975   uint16_t msize;
976
977   if (NULL != GST_context)
978   {
979     LOG_DEBUG ("We are being connected to laterally\n");
980     GNUNET_SERVER_receive_done (client, GNUNET_OK);
981     return;
982   }
983   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
984   msize = ntohs (message->size);
985   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
986   {
987     GNUNET_break (0);
988     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
989     return;
990   }
991   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
992   controller_hostname = (const char *) &msg[1];
993   if ('\0' != controller_hostname[msize - 1])
994   {
995     GNUNET_break (0);
996     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
997     return;
998   }
999   GST_context = GNUNET_malloc (sizeof (struct Context));
1000   GNUNET_SERVER_client_keep (client);
1001   GST_context->client = client;
1002   GST_context->host_id = ntohl (msg->host_id);
1003   GST_context->master_ip = GNUNET_strdup (controller_hostname);
1004   LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
1005   GST_context->system =
1006       GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
1007                                     hostname);
1008   host =
1009       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
1010                                           GST_context->master_ip, NULL,
1011                                           our_config, 0);
1012   host_list_add (host);
1013   LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
1014   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1015 }
1016
1017
1018 /**
1019  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1020  *
1021  * @param cls NULL
1022  * @param client identification of the client
1023  * @param message the actual message
1024  */
1025 static void
1026 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1027                  const struct GNUNET_MessageHeader *message)
1028 {
1029   struct GNUNET_TESTBED_Host *host;
1030   const struct GNUNET_TESTBED_AddHostMessage *msg;
1031   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1032   struct GNUNET_CONFIGURATION_Handle *host_cfg;
1033   char *username;
1034   char *hostname;
1035   char *emsg;
1036   const void *ptr;
1037   uint32_t host_id;
1038   uint16_t username_length;
1039   uint16_t hostname_length;
1040   uint16_t reply_size;
1041   uint16_t msize;
1042
1043   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1044   msize = ntohs (msg->header.size);
1045   if (msize <= sizeof (struct GNUNET_TESTBED_AddHostMessage))
1046   {
1047     GNUNET_break_op (0);
1048     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1049     return;
1050   }
1051   username_length = ntohs (msg->username_length);
1052   hostname_length = ntohs (msg->hostname_length);
1053   /* msg must contain hostname */
1054   if ((msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) + 
1055                  username_length))
1056       || (0 == hostname_length))
1057   {
1058     GNUNET_break_op (0);
1059     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1060     return;
1061   }
1062   /* msg must contain configuration */
1063   if (msize <= (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1064                 username_length + hostname_length))
1065   {
1066     GNUNET_break_op (0);
1067     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1068     return;
1069   }
1070   username = NULL;
1071   hostname = NULL;
1072   ptr = &msg[1];
1073   if (0 != username_length)
1074   {
1075     username = GNUNET_malloc (username_length + 1);
1076     strncpy (username, ptr, username_length);
1077     ptr += username_length;
1078   }
1079   hostname = GNUNET_malloc (hostname_length + 1);
1080   strncpy (hostname, ptr, hostname_length);
1081   ptr += hostname_length;
1082   if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (message)))
1083   {
1084     GNUNET_free_non_null (username);
1085     GNUNET_free_non_null (hostname);
1086     GNUNET_break_op (0);
1087     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1088     return;
1089   }
1090   host_id = ntohl (msg->host_id);
1091   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
1092   LOG_DEBUG ("-------host id: %u\n", host_id);
1093   LOG_DEBUG ("-------hostname: %s\n", hostname);
1094   if (NULL != username)
1095     LOG_DEBUG ("-------username: %s\n", username);
1096   else
1097     LOG_DEBUG ("-------username: <not given>\n");
1098   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1099   host =
1100       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1101                                           host_cfg, ntohs (msg->ssh_port));
1102   GNUNET_free_non_null (username);
1103   GNUNET_free (hostname);
1104   GNUNET_CONFIGURATION_destroy (host_cfg);
1105   if (NULL == host)
1106   {
1107     GNUNET_break_op (0);
1108     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1109     return;
1110   }
1111   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1112   if (GNUNET_OK != host_list_add (host))
1113   {
1114     /* We are unable to add a host */
1115     emsg = "A host exists with given host-id";
1116     LOG_DEBUG ("%s: %u", emsg, host_id);
1117     GNUNET_TESTBED_host_destroy (host);
1118     reply_size += strlen (emsg) + 1;
1119     reply = GNUNET_malloc (reply_size);
1120     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1121   }
1122   else
1123   {
1124     LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
1125     reply = GNUNET_malloc (reply_size);
1126   }
1127   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
1128   reply->header.size = htons (reply_size);
1129   reply->host_id = htonl (host_id);
1130   GST_queue_message (client, &reply->header);
1131   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1132 }
1133
1134
1135 /**
1136  * Iterator over hash map entries.
1137  *
1138  * @param cls closure
1139  * @param key current key code
1140  * @param value value in the hash map
1141  * @return GNUNET_YES if we should continue to
1142  *         iterate,
1143  *         GNUNET_NO if not.
1144  */
1145 int
1146 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1147 {
1148   struct SharedService *queried_ss = cls;
1149   struct SharedService *ss = value;
1150
1151   if (0 == strcmp (ss->name, queried_ss->name))
1152     return GNUNET_NO;
1153   else
1154     return GNUNET_YES;
1155 }
1156
1157
1158 /**
1159  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1160  *
1161  * @param cls NULL
1162  * @param client identification of the client
1163  * @param message the actual message
1164  */
1165 static void
1166 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1167                                  const struct GNUNET_MessageHeader *message)
1168 {
1169   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1170   struct SharedService *ss;
1171   char *service_name;
1172   struct GNUNET_HashCode hash;
1173   uint16_t msg_size;
1174   uint16_t service_name_size;
1175
1176   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1177   msg_size = ntohs (message->size);
1178   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1179   {
1180     GNUNET_break (0);
1181     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1182     return;
1183   }
1184   service_name_size =
1185       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1186   service_name = (char *) &msg[1];
1187   if ('\0' != service_name[service_name_size - 1])
1188   {
1189     GNUNET_break (0);
1190     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1191     return;
1192   }
1193   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1194              service_name, ntohl (msg->num_peers));
1195   if (ntohl (msg->host_id) != GST_context->host_id)
1196   {
1197     route_message (ntohl (msg->host_id), message);
1198     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1199     return;
1200   }
1201   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1202   ss = GNUNET_malloc (sizeof (struct SharedService));
1203   ss->name = strdup (service_name);
1204   ss->num_shared = ntohl (msg->num_peers);
1205   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1206   if (GNUNET_SYSERR ==
1207       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1208                                                   &ss_exists_iterator, ss))
1209   {
1210     LOG (GNUNET_ERROR_TYPE_WARNING,
1211          "Service %s already configured as a shared service. "
1212          "Ignoring service sharing request \n", ss->name);
1213     GNUNET_free (ss->name);
1214     GNUNET_free (ss);
1215     return;
1216   }
1217   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1218                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1219 }
1220
1221
1222 /**
1223  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1224  *
1225  * @param cls NULL
1226  * @param client identification of the client
1227  * @param message the actual message
1228  */
1229 static void
1230 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1231                          const struct GNUNET_MessageHeader *message)
1232 {
1233   const struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1234   struct GNUNET_CONFIGURATION_Handle *cfg;
1235   struct LCFContextQueue *lcfq;
1236   struct Route *route;
1237   struct Route *new_route;
1238   char *config;
1239   uLongf dest_size;
1240   size_t config_size;
1241   uint32_t delegated_host_id;
1242   uint32_t slave_host_id;
1243   uint16_t msize;
1244
1245   if (NULL == GST_context)
1246   {
1247     GNUNET_break (0);
1248     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1249     return;
1250   }
1251   msize = ntohs (message->size);
1252   if (sizeof (struct GNUNET_TESTBED_ControllerLinkRequest) >= msize)
1253   {
1254     GNUNET_break (0);
1255     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1256     return;
1257   }
1258   msg = (const struct GNUNET_TESTBED_ControllerLinkRequest *) message;
1259   delegated_host_id = ntohl (msg->delegated_host_id);
1260   if (delegated_host_id == GST_context->host_id)
1261   {
1262     GNUNET_break (0);
1263     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1264     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1265     return;
1266   }
1267   if ((delegated_host_id >= GST_host_list_size) ||
1268       (NULL == GST_host_list[delegated_host_id]))
1269   {
1270     LOG (GNUNET_ERROR_TYPE_WARNING,
1271          "Delegated host %u not registered with us\n", delegated_host_id);
1272     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1273     return;
1274   }
1275   slave_host_id = ntohl (msg->slave_host_id);
1276   if ((slave_host_id >= GST_host_list_size) ||
1277       (NULL == GST_host_list[slave_host_id]))
1278   {
1279     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
1280          slave_host_id);
1281     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1282     return;
1283   }
1284   if (slave_host_id == delegated_host_id)
1285   {
1286     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1287     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1288     return;
1289   }
1290
1291   if (slave_host_id == GST_context->host_id)    /* Link from us */
1292   {
1293     struct Slave *slave;
1294     struct LinkControllersContext *lcc;
1295
1296     msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkRequest);
1297     config_size = ntohs (msg->config_size);
1298     if ((delegated_host_id < GST_slave_list_size) && (NULL != GST_slave_list[delegated_host_id]))       /* We have already added */
1299     {
1300       LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
1301            delegated_host_id);
1302       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1303       return;
1304     }
1305     config = GNUNET_malloc (config_size);
1306     dest_size = (uLongf) config_size;
1307     if (Z_OK !=
1308         uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
1309                     (uLong) msize))
1310     {
1311       GNUNET_break (0);         /* Compression error */
1312       GNUNET_free (config);
1313       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1314       return;
1315     }
1316     if (config_size != dest_size)
1317     {
1318       LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
1319       GNUNET_free (config);
1320       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1321       return;
1322     }
1323     cfg = GNUNET_CONFIGURATION_create ();       /* Free here or in lcfcontext */
1324     if (GNUNET_OK !=
1325         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1326     {
1327       GNUNET_break (0);         /* Configuration parsing error */
1328       GNUNET_free (config);
1329       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1330       return;
1331     }
1332     GNUNET_free (config);
1333     if ((delegated_host_id < GST_slave_list_size) &&
1334         (NULL != GST_slave_list[delegated_host_id]))
1335     {
1336       GNUNET_break (0);         /* Configuration parsing error */
1337       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1338       return;
1339     }
1340     slave = GNUNET_malloc (sizeof (struct Slave));
1341     slave->host_id = delegated_host_id;
1342     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
1343     slave_list_add (slave);
1344     if (1 != msg->is_subordinate)
1345     {
1346       slave->controller =
1347           GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
1348                                              event_mask, &slave_event_callback,
1349                                              slave);
1350       slave->cfg = cfg;
1351       if (NULL != slave->controller)
1352         send_controller_link_response (client,
1353                                        GNUNET_ntohll (msg->operation_id),
1354                                        NULL,
1355                                        NULL);
1356       else
1357         send_controller_link_response (client,
1358                                        GNUNET_ntohll (msg->operation_id),
1359                                        NULL,
1360                                        "Could not connect to delegated controller");
1361       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1362       return;
1363     }
1364     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1365     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1366     GNUNET_SERVER_client_keep (client);
1367     lcc->client = client;
1368     slave->lcc = lcc;
1369     slave->controller_proc =
1370         GNUNET_TESTBED_controller_start (GST_context->master_ip,
1371                                          GST_host_list[slave->host_id], cfg,
1372                                          &slave_status_callback, slave);
1373     GNUNET_CONFIGURATION_destroy (cfg);
1374     new_route = GNUNET_malloc (sizeof (struct Route));
1375     new_route->dest = delegated_host_id;
1376     new_route->thru = GST_context->host_id;
1377     route_list_add (new_route);
1378     return;
1379   }
1380
1381   /* Route the request */
1382   if (slave_host_id >= route_list_size)
1383   {
1384     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1385     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1386     return;
1387   }
1388   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1389   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1390   lcfq->lcf->delegated_host_id = delegated_host_id;
1391   lcfq->lcf->slave_host_id = slave_host_id;
1392   route = GST_find_dest_route (slave_host_id);
1393   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1394   GNUNET_assert (route->dest < GST_slave_list_size);
1395   GNUNET_assert (NULL != GST_slave_list[route->dest]);
1396   lcfq->lcf->state = INIT;
1397   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1398   lcfq->lcf->gateway = GST_slave_list[route->dest];
1399   lcfq->lcf->msg = GNUNET_malloc (msize);
1400   (void) memcpy (lcfq->lcf->msg, msg, msize);
1401   GNUNET_SERVER_client_keep (client);
1402   lcfq->lcf->client = client;
1403   if (NULL == lcfq_head)
1404   {
1405     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1406     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1407     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1408   }
1409   else
1410     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1411   /* FIXME: Adding a new route should happen after the controllers are linked
1412    * successfully */
1413   if (1 != msg->is_subordinate)
1414   {
1415     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1416     return;
1417   }
1418   if ((delegated_host_id < route_list_size) &&
1419       (NULL != route_list[delegated_host_id]))
1420   {
1421     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1422                                  * with is subordinate flag set to GNUNET_YES? */
1423     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1424     return;
1425   }
1426   new_route = GNUNET_malloc (sizeof (struct Route));
1427   new_route->dest = delegated_host_id;
1428   new_route->thru = route->dest;
1429   route_list_add (new_route);
1430   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1431 }
1432
1433
1434 /**
1435  * The task to be executed if the forwarded peer create operation has been
1436  * timed out
1437  *
1438  * @param cls the FowardedOperationContext
1439  * @param tc the TaskContext from the scheduler
1440  */
1441 static void
1442 peer_create_forward_timeout (void *cls,
1443                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1444 {
1445   struct ForwardedOperationContext *fopc = cls;
1446
1447   GNUNET_free (fopc->cls);
1448   GST_forwarded_operation_timeout (fopc, tc);
1449 }
1450
1451
1452 /**
1453  * Callback to be called when forwarded peer create operation is successfull. We
1454  * have to relay the reply msg back to the client
1455  *
1456  * @param cls ForwardedOperationContext
1457  * @param msg the peer create success message
1458  */
1459 static void
1460 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1461 {
1462   struct ForwardedOperationContext *fopc = cls;
1463   struct Peer *remote_peer;
1464
1465   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
1466   {
1467     GNUNET_assert (NULL != fopc->cls);
1468     remote_peer = fopc->cls;
1469     peer_list_add (remote_peer);
1470   }
1471   GST_forwarded_operation_reply_relay (fopc, msg);
1472 }
1473
1474
1475 /**
1476  * Function to destroy a peer
1477  *
1478  * @param peer the peer structure to destroy
1479  */
1480 void
1481 GST_destroy_peer (struct Peer *peer)
1482 {
1483   GNUNET_break (0 == peer->reference_cnt);
1484   if (GNUNET_YES == peer->is_remote)
1485   {
1486     peer_list_remove (peer);
1487     GNUNET_free (peer);
1488     return;
1489   }
1490   if (GNUNET_YES == peer->details.local.is_running)
1491   {
1492     GNUNET_TESTING_peer_stop (peer->details.local.peer);
1493     peer->details.local.is_running = GNUNET_NO;
1494   }
1495   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1496   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1497   peer_list_remove (peer);
1498   GNUNET_free (peer);
1499 }
1500
1501
1502 /**
1503  * Callback to be called when forwarded peer destroy operation is successfull. We
1504  * have to relay the reply msg back to the client
1505  *
1506  * @param cls ForwardedOperationContext
1507  * @param msg the peer create success message
1508  */
1509 static void
1510 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1511 {
1512   struct ForwardedOperationContext *fopc = cls;
1513   struct Peer *remote_peer;
1514
1515   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
1516       ntohs (msg->type))
1517   {
1518     remote_peer = fopc->cls;
1519     GNUNET_assert (NULL != remote_peer);
1520     remote_peer->destroy_flag = GNUNET_YES;
1521     if (0 == remote_peer->reference_cnt)
1522       GST_destroy_peer (remote_peer);
1523   }
1524   GST_forwarded_operation_reply_relay (fopc, msg);
1525 }
1526
1527
1528
1529 /**
1530  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1531  *
1532  * @param cls NULL
1533  * @param client identification of the client
1534  * @param message the actual message
1535  */
1536 static void
1537 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1538                     const struct GNUNET_MessageHeader *message)
1539 {
1540   const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1541   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1542   struct GNUNET_CONFIGURATION_Handle *cfg;
1543   struct ForwardedOperationContext *fo_ctxt;
1544   struct Route *route;
1545   struct Peer *peer;
1546   char *config;
1547   size_t dest_size;
1548   int ret;
1549   uint32_t config_size;
1550   uint32_t host_id;
1551   uint32_t peer_id;
1552   uint16_t msize;
1553
1554
1555   msize = ntohs (message->size);
1556   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1557   {
1558     GNUNET_break (0);           /* We need configuration */
1559     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1560     return;
1561   }
1562   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1563   host_id = ntohl (msg->host_id);
1564   peer_id = ntohl (msg->peer_id);
1565   if (UINT32_MAX == peer_id)
1566   {
1567     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1568                                  "Cannot create peer with given ID");
1569     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1570     return;
1571   }
1572   if (host_id == GST_context->host_id)
1573   {
1574     char *emsg;
1575
1576     /* We are responsible for this peer */
1577     msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1578     config_size = ntohl (msg->config_size);
1579     config = GNUNET_malloc (config_size);
1580     dest_size = config_size;
1581     if (Z_OK !=
1582         (ret =
1583          uncompress ((Bytef *) config, (uLongf *) & dest_size,
1584                      (const Bytef *) &msg[1], (uLong) msize)))
1585     {
1586       GNUNET_break (0);         /* uncompression error */
1587       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1588       return;
1589     }
1590     if (config_size != dest_size)
1591     {
1592       GNUNET_break (0);         /* Uncompressed config size mismatch */
1593       GNUNET_free (config);
1594       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1595       return;
1596     }
1597     cfg = GNUNET_CONFIGURATION_create ();
1598     if (GNUNET_OK !=
1599         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1600     {
1601       GNUNET_break (0);         /* Configuration parsing error */
1602       GNUNET_free (config);
1603       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1604       return;
1605     }
1606     GNUNET_free (config);
1607     GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
1608                                            (unsigned long long) peer_id);
1609     peer = GNUNET_malloc (sizeof (struct Peer));
1610     peer->is_remote = GNUNET_NO;
1611     peer->details.local.cfg = cfg;
1612     peer->id = peer_id;
1613     LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
1614     peer->details.local.peer =
1615         GNUNET_TESTING_peer_configure (GST_context->system,
1616                                        peer->details.local.cfg, peer->id,
1617                                        NULL /* Peer id */ ,
1618                                        &emsg);
1619     if (NULL == peer->details.local.peer)
1620     {
1621       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1622       GNUNET_free (emsg);
1623       GNUNET_free (peer);
1624       GNUNET_break (0);
1625       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1626       return;
1627     }
1628     peer->details.local.is_running = GNUNET_NO;
1629     peer_list_add (peer);
1630     reply =
1631         GNUNET_malloc (sizeof
1632                        (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1633     reply->header.size =
1634         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1635     reply->header.type =
1636         htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
1637     reply->peer_id = msg->peer_id;
1638     reply->operation_id = msg->operation_id;
1639     GST_queue_message (client, &reply->header);
1640     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1641     return;
1642   }
1643
1644   /* Forward peer create request */
1645   route = GST_find_dest_route (host_id);
1646   if (NULL == route)
1647   {
1648     GNUNET_break (0);
1649     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1650     return;
1651   }
1652
1653   peer = GNUNET_malloc (sizeof (struct Peer));
1654   peer->is_remote = GNUNET_YES;
1655   peer->id = peer_id;
1656   peer->details.remote.slave = GST_slave_list[route->dest];
1657   peer->details.remote.remote_host_id = host_id;
1658   fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1659   GNUNET_SERVER_client_keep (client);
1660   fo_ctxt->client = client;
1661   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1662   fo_ctxt->cls = peer;          //GST_slave_list[route->dest]->controller;
1663   fo_ctxt->type = OP_PEER_CREATE;
1664   fo_ctxt->opc =
1665       GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
1666                                              [route->dest]->controller,
1667                                              fo_ctxt->operation_id,
1668                                              &msg->header,
1669                                              peer_create_success_cb, fo_ctxt);
1670   fo_ctxt->timeout_task =
1671       GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
1672                                     fo_ctxt);
1673   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1674   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1675 }
1676
1677
1678 /**
1679  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1680  *
1681  * @param cls NULL
1682  * @param client identification of the client
1683  * @param message the actual message
1684  */
1685 static void
1686 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1687                      const struct GNUNET_MessageHeader *message)
1688 {
1689   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1690   struct ForwardedOperationContext *fopc;
1691   struct Peer *peer;
1692   uint32_t peer_id;
1693
1694   msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1695   peer_id = ntohl (msg->peer_id);
1696   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1697              peer_id, GNUNET_ntohll (msg->operation_id));
1698   if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
1699   {
1700     LOG (GNUNET_ERROR_TYPE_ERROR,
1701          "Asked to destroy a non existent peer with id: %u\n", peer_id);
1702     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1703                                  "Peer doesn't exist");
1704     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1705     return;
1706   }
1707   peer = GST_peer_list[peer_id];
1708   if (GNUNET_YES == peer->is_remote)
1709   {
1710     /* Forward the destory message to sub controller */
1711     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1712     GNUNET_SERVER_client_keep (client);
1713     fopc->client = client;
1714     fopc->cls = peer;
1715     fopc->type = OP_PEER_DESTROY;
1716     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1717     fopc->opc =
1718         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1719                                                slave->controller,
1720                                                fopc->operation_id, &msg->header,
1721                                                &peer_destroy_success_cb, fopc);
1722     fopc->timeout_task =
1723         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1724                                       fopc);
1725     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1726     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1727     return;
1728   }
1729   peer->destroy_flag = GNUNET_YES;
1730   if (0 == peer->reference_cnt)
1731     GST_destroy_peer (peer);
1732   else
1733     LOG (GNUNET_ERROR_TYPE_DEBUG,
1734          "Delaying peer destroy as peer is currently in use\n");
1735   send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1736   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1737 }
1738
1739
1740 /**
1741  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1742  *
1743  * @param cls NULL
1744  * @param client identification of the client
1745  * @param message the actual message
1746  */
1747 static void
1748 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1749                    const struct GNUNET_MessageHeader *message)
1750 {
1751   const struct GNUNET_TESTBED_PeerStartMessage *msg;
1752   struct GNUNET_TESTBED_PeerEventMessage *reply;
1753   struct ForwardedOperationContext *fopc;
1754   struct Peer *peer;
1755   uint32_t peer_id;
1756
1757   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1758   peer_id = ntohl (msg->peer_id);
1759   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1760   {
1761     GNUNET_break (0);
1762     LOG (GNUNET_ERROR_TYPE_ERROR,
1763          "Asked to start a non existent peer with id: %u\n", peer_id);
1764     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1765     return;
1766   }
1767   peer = GST_peer_list[peer_id];
1768   if (GNUNET_YES == peer->is_remote)
1769   {
1770     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1771     GNUNET_SERVER_client_keep (client);
1772     fopc->client = client;
1773     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1774     fopc->type = OP_PEER_START;
1775     fopc->opc =
1776         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1777                                                slave->controller,
1778                                                fopc->operation_id, &msg->header,
1779                                                &GST_forwarded_operation_reply_relay,
1780                                                fopc);
1781     fopc->timeout_task =
1782         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1783                                       fopc);
1784     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1785     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1786     return;
1787   }
1788   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1789   {
1790     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1791                                  "Failed to start");
1792     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1793     return;
1794   }
1795   peer->details.local.is_running = GNUNET_YES;
1796   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1797   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1798   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1799   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1800   reply->host_id = htonl (GST_context->host_id);
1801   reply->peer_id = msg->peer_id;
1802   reply->operation_id = msg->operation_id;
1803   GST_queue_message (client, &reply->header);
1804   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1805 }
1806
1807
1808 /**
1809  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1810  *
1811  * @param cls NULL
1812  * @param client identification of the client
1813  * @param message the actual message
1814  */
1815 static void
1816 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1817                   const struct GNUNET_MessageHeader *message)
1818 {
1819   const struct GNUNET_TESTBED_PeerStopMessage *msg;
1820   struct GNUNET_TESTBED_PeerEventMessage *reply;
1821   struct ForwardedOperationContext *fopc;
1822   struct Peer *peer;
1823   uint32_t peer_id;
1824
1825   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1826   peer_id = ntohl (msg->peer_id);
1827   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
1828   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1829   {
1830     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1831                                  "Peer not found");
1832     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1833     return;
1834   }
1835   peer = GST_peer_list[peer_id];
1836   if (GNUNET_YES == peer->is_remote)
1837   {
1838     LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
1839          peer_id);
1840     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1841     GNUNET_SERVER_client_keep (client);
1842     fopc->client = client;
1843     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1844     fopc->type = OP_PEER_STOP;
1845     fopc->opc =
1846         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1847                                                slave->controller,
1848                                                fopc->operation_id, &msg->header,
1849                                                &GST_forwarded_operation_reply_relay,
1850                                                fopc);
1851     fopc->timeout_task =
1852         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1853                                       fopc);
1854     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1855     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1856     return;
1857   }
1858   if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
1859   {
1860     LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
1861     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1862                                  "Peer not running");
1863     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1864     return;
1865   }
1866   LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
1867   peer->details.local.is_running = GNUNET_NO;
1868   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1869   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1870   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1871   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
1872   reply->host_id = htonl (GST_context->host_id);
1873   reply->peer_id = msg->peer_id;
1874   reply->operation_id = msg->operation_id;
1875   GST_queue_message (client, &reply->header);
1876   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1877   GNUNET_TESTING_peer_wait (peer->details.local.peer);
1878 }
1879
1880
1881 /**
1882  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1883  *
1884  * @param cls NULL
1885  * @param client identification of the client
1886  * @param message the actual message
1887  */
1888 static void
1889 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1890                         const struct GNUNET_MessageHeader *message)
1891 {
1892   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1893   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1894   struct Peer *peer;
1895   char *config;
1896   char *xconfig;
1897   size_t c_size;
1898   size_t xc_size;
1899   uint32_t peer_id;
1900   uint16_t msize;
1901
1902   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
1903   peer_id = ntohl (msg->peer_id);
1904   if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1905   {
1906     GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1907                                  "Peer not found");
1908     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1909     return;
1910   }
1911   peer = GST_peer_list[peer_id];
1912   if (GNUNET_YES == peer->is_remote)
1913   {
1914     struct ForwardedOperationContext *fopc;
1915
1916     LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
1917     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1918     GNUNET_SERVER_client_keep (client);
1919     fopc->client = client;
1920     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1921     fopc->type = OP_PEER_INFO;
1922     fopc->opc =
1923         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1924                                                slave->controller,
1925                                                fopc->operation_id, &msg->header,
1926                                                &GST_forwarded_operation_reply_relay,
1927                                                fopc);
1928     fopc->timeout_task =
1929         GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1930                                       fopc);
1931     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1932     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1933     return;
1934   }
1935   LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
1936   config =
1937       GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
1938                                       &c_size);
1939   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1940   GNUNET_free (config);
1941   msize =
1942       xc_size +
1943       sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1944   reply = GNUNET_realloc (xconfig, msize);
1945   (void) memmove (&reply[1], reply, xc_size);
1946   reply->header.size = htons (msize);
1947   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
1948   reply->peer_id = msg->peer_id;
1949   reply->operation_id = msg->operation_id;
1950   GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
1951                                     &reply->peer_identity);
1952   reply->config_size = htons ((uint16_t) c_size);
1953   GST_queue_message (client, &reply->header);
1954   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1955 }
1956
1957
1958 /**
1959  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1960  *
1961  * @param cls NULL
1962  * @param client identification of the client
1963  * @param message the actual message
1964  */
1965 static void
1966 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1967                          const struct GNUNET_MessageHeader *message)
1968 {
1969   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1970   struct Slave *slave;
1971   struct GNUNET_TESTBED_SlaveConfiguration *reply;
1972   char *config;
1973   char *xconfig;
1974   size_t config_size;
1975   size_t xconfig_size;
1976   size_t reply_size;
1977   uint64_t op_id;
1978   uint32_t slave_id;
1979
1980   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
1981   slave_id = ntohl (msg->slave_id);
1982   op_id = GNUNET_ntohll (msg->operation_id);
1983   if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
1984   {
1985     /* FIXME: Add forwardings for this type of message here.. */
1986     GST_send_operation_fail_msg (client, op_id, "Slave not found");
1987     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1988     return;
1989   }
1990   slave = GST_slave_list[slave_id];
1991   if (NULL == slave->cfg)
1992   {
1993     GST_send_operation_fail_msg (client, op_id,
1994                                  "Configuration not found (slave not started by me)");
1995     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1996     return;
1997   }
1998   config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
1999   xconfig_size =
2000       GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
2001   GNUNET_free (config);
2002   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
2003   GNUNET_break (reply_size <= UINT16_MAX);
2004   GNUNET_break (config_size <= UINT16_MAX);
2005   reply = GNUNET_realloc (xconfig, reply_size);
2006   (void) memmove (&reply[1], reply, xconfig_size);
2007   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
2008   reply->header.size = htons ((uint16_t) reply_size);
2009   reply->slave_id = msg->slave_id;
2010   reply->operation_id = msg->operation_id;
2011   reply->config_size = htons ((uint16_t) config_size);
2012   GST_queue_message (client, &reply->header);
2013   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2014 }
2015
2016
2017 /**
2018  * Iterator over hash map entries.
2019  *
2020  * @param cls closure
2021  * @param key current key code
2022  * @param value value in the hash map
2023  * @return GNUNET_YES if we should continue to
2024  *         iterate,
2025  *         GNUNET_NO if not.
2026  */
2027 static int
2028 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2029 {
2030   struct SharedService *ss = value;
2031
2032   GNUNET_assert (GNUNET_YES ==
2033                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2034   GNUNET_free (ss->name);
2035   GNUNET_free (ss);
2036   return GNUNET_YES;
2037 }
2038
2039
2040 /**
2041  * Iterator for freeing hash map entries in a slave's reghost_map
2042  *
2043  * @param cls handle to the slave
2044  * @param key current key code
2045  * @param value value in the hash map
2046  * @return GNUNET_YES if we should continue to
2047  *         iterate,
2048  *         GNUNET_NO if not.
2049  */
2050 static int
2051 reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
2052                        void *value)
2053 {
2054   struct Slave *slave = cls;
2055   struct RegisteredHostContext *rhc = value;
2056   struct ForwardedOverlayConnectContext *focc;
2057
2058   GNUNET_assert (GNUNET_YES ==
2059                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
2060                                                        value));
2061   while (NULL != (focc = rhc->focc_dll_head))
2062   {
2063     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
2064     GST_cleanup_focc (focc);
2065   }
2066   if (NULL != rhc->sub_op)
2067     GNUNET_TESTBED_operation_done (rhc->sub_op);
2068   if (NULL != rhc->client)
2069     GNUNET_SERVER_client_drop (rhc->client);
2070   GNUNET_free (value);
2071   return GNUNET_YES;
2072 }
2073
2074
2075 /**
2076  * Task to clean up and shutdown nicely
2077  *
2078  * @param cls NULL
2079  * @param tc the TaskContext from scheduler
2080  */
2081 static void
2082 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2083 {
2084   struct LCFContextQueue *lcfq;
2085   struct ForwardedOperationContext *fopc;
2086   struct MessageQueue *mq_entry;
2087   uint32_t id;
2088
2089   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2090   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2091   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2092                                                 NULL);
2093   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2094   /* cleanup any remaining forwarded operations */
2095   while (NULL != (fopc = fopcq_head))
2096   {
2097     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
2098     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
2099     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
2100       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
2101     GNUNET_SERVER_client_drop (fopc->client);
2102     switch (fopc->type)
2103     {
2104     case OP_PEER_CREATE:
2105       GNUNET_free (fopc->cls);
2106       break;
2107     case OP_PEER_START:
2108     case OP_PEER_STOP:
2109     case OP_PEER_DESTROY:
2110     case OP_PEER_INFO:
2111     case OP_OVERLAY_CONNECT:
2112     case OP_LINK_CONTROLLERS:
2113     case OP_GET_SLAVE_CONFIG:
2114       break;
2115     case OP_FORWARDED:
2116       GNUNET_assert (0);
2117     };
2118     GNUNET_free (fopc);
2119   }
2120   if (NULL != lcfq_head)
2121   {
2122     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2123     {
2124       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2125       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2126     }
2127   }
2128   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2129   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2130   {
2131     GNUNET_free (lcfq->lcf->msg);
2132     GNUNET_free (lcfq->lcf);
2133     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2134     GNUNET_free (lcfq);
2135   }
2136   GST_free_occq ();
2137   GST_free_roccq ();
2138   /* Clear peer list */
2139   for (id = 0; id < GST_peer_list_size; id++)
2140     if (NULL != GST_peer_list[id])
2141     {
2142       /* If destroy flag is set it means that this peer should have been
2143        * destroyed by a context which we destroy before */
2144       GNUNET_break (GNUNET_NO == GST_peer_list[id]->destroy_flag);
2145       /* counter should be zero as we free all contexts before */
2146       GNUNET_break (0 == GST_peer_list[id]->reference_cnt);
2147       if ((GNUNET_NO == GST_peer_list[id]->is_remote) &&
2148           (GNUNET_YES == GST_peer_list[id]->details.local.is_running))
2149         GNUNET_TESTING_peer_kill (GST_peer_list[id]->details.local.peer);
2150     }
2151   for (id = 0; id < GST_peer_list_size; id++)
2152     if (NULL != GST_peer_list[id])
2153     {
2154       if (GNUNET_NO == GST_peer_list[id]->is_remote)
2155       {
2156         if (GNUNET_YES == GST_peer_list[id]->details.local.is_running)
2157           GNUNET_TESTING_peer_wait (GST_peer_list[id]->details.local.peer);
2158         GNUNET_TESTING_peer_destroy (GST_peer_list[id]->details.local.peer);
2159         GNUNET_CONFIGURATION_destroy (GST_peer_list[id]->details.local.cfg);
2160       }
2161       GNUNET_free (GST_peer_list[id]);
2162     }
2163   GNUNET_free_non_null (GST_peer_list);
2164   /* Clear host list */
2165   for (id = 0; id < GST_host_list_size; id++)
2166     if (NULL != GST_host_list[id])
2167       GNUNET_TESTBED_host_destroy (GST_host_list[id]);
2168   GNUNET_free_non_null (GST_host_list);
2169   /* Clear route list */
2170   for (id = 0; id < route_list_size; id++)
2171     if (NULL != route_list[id])
2172       GNUNET_free (route_list[id]);
2173   GNUNET_free_non_null (route_list);
2174   /* Clear GST_slave_list */
2175   for (id = 0; id < GST_slave_list_size; id++)
2176     if (NULL != GST_slave_list[id])
2177     {
2178       struct HostRegistration *hr_entry;
2179
2180       while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
2181       {
2182         GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
2183                                      GST_slave_list[id]->hr_dll_tail, hr_entry);
2184         GNUNET_free (hr_entry);
2185       }
2186       if (NULL != GST_slave_list[id]->rhandle)
2187         GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
2188       (void)
2189           GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
2190                                                  [id]->reghost_map,
2191                                                  reghost_free_iterator,
2192                                                  GST_slave_list[id]);
2193       GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
2194       if (NULL != GST_slave_list[id]->cfg)
2195         GNUNET_CONFIGURATION_destroy (GST_slave_list[id]->cfg);
2196       if (NULL != GST_slave_list[id]->controller)
2197         GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
2198       if (NULL != GST_slave_list[id]->controller_proc)
2199         GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
2200       GNUNET_free (GST_slave_list[id]);
2201     }
2202   GNUNET_free_non_null (GST_slave_list);
2203   if (NULL != GST_context)
2204   {
2205     GNUNET_free_non_null (GST_context->master_ip);
2206     if (NULL != GST_context->system)
2207       GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
2208     GNUNET_SERVER_client_drop (GST_context->client);
2209     GNUNET_free (GST_context);
2210     GST_context = NULL;
2211   }
2212   if (NULL != transmit_handle)
2213     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
2214   while (NULL != (mq_entry = mq_head))
2215   {
2216     GNUNET_free (mq_entry->msg);
2217     GNUNET_SERVER_client_drop (mq_entry->client);
2218     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
2219     GNUNET_free (mq_entry);
2220   }
2221   GNUNET_free_non_null (hostname);
2222   GNUNET_CONFIGURATION_destroy (our_config);
2223   /* Free hello cache */
2224   GST_cache_clear ();
2225   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
2226   GST_opq_openfds = NULL;
2227 }
2228
2229
2230 /**
2231  * Callback for client disconnect
2232  *
2233  * @param cls NULL
2234  * @param client the client which has disconnected
2235  */
2236 static void
2237 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2238 {
2239   if (NULL == GST_context)
2240     return;
2241   if (client == GST_context->client)
2242   {
2243     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2244     /* should not be needed as we're terminated by failure to read
2245      * from stdin, but if stdin fails for some reason, this shouldn't
2246      * hurt for now --- might need to revise this later if we ever
2247      * decide that master connections might be temporarily down
2248      * for some reason */
2249     //GNUNET_SCHEDULER_shutdown ();
2250   }
2251 }
2252
2253
2254 /**
2255  * Testbed setup
2256  *
2257  * @param cls closure
2258  * @param server the initialized server
2259  * @param cfg configuration to use
2260  */
2261 static void
2262 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2263              const struct GNUNET_CONFIGURATION_Handle *cfg)
2264 {
2265   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2266     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2267     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
2268     {&handle_configure_shared_service, NULL,
2269      GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
2270     {&handle_link_controllers, NULL,
2271      GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
2272     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
2273     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
2274      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2275     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
2276      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2277     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
2278      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2279     {&handle_peer_get_config, NULL,
2280      GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
2281      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2282     {&GST_handle_overlay_connect, NULL,
2283      GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
2284      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2285     {&GST_handle_remote_overlay_connect, NULL,
2286      GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
2287     {handle_slave_get_config, NULL,
2288      GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
2289      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2290     {NULL}
2291   };
2292   char *logfile;
2293   unsigned long long num;
2294
2295   if (GNUNET_OK ==
2296       GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
2297                                                &logfile))
2298   {
2299     GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
2300     GNUNET_free (logfile);
2301   }
2302   GNUNET_assert (GNUNET_OK ==
2303                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2304                                                         "CACHE_SIZE", &num));
2305   GST_cache_init ((unsigned int) num);
2306   GNUNET_assert (GNUNET_OK ==
2307                  GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
2308                                                         "MAX_OPEN_FDS", &num));
2309   GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
2310   GNUNET_assert (GNUNET_OK ==
2311                  GNUNET_CONFIGURATION_get_value_time (cfg, "TESTBED",
2312                                                       "OPERATION_TIMEOUT",
2313                                                       (struct
2314                                                        GNUNET_TIME_Relative *)
2315                                                       &GST_timeout));
2316   GNUNET_assert (GNUNET_OK ==
2317                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
2318                                                         "HOSTNAME", &hostname));  
2319   our_config = GNUNET_CONFIGURATION_dup (cfg);
2320   GNUNET_SERVER_add_handlers (server, message_handlers);
2321   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2322   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
2323   shutdown_task_id =
2324       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
2325                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
2326                                                   &shutdown_task, NULL);
2327   LOG_DEBUG ("Testbed startup complete\n");
2328   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
2329 }
2330
2331
2332 /**
2333  * The starting point of execution
2334  */
2335 int
2336 main (int argc, char *const *argv)
2337 {
2338   //sleep (15);                 /* Debugging */
2339   return (GNUNET_OK ==
2340           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2341                               &testbed_run, NULL)) ? 0 : 1;
2342 }
2343
2344 /* end of gnunet-service-testbed.c */