- adapt mesh to strided regex implementation
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
1 /*
2   This file is part of GNUnet.
3   (C) 2012 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 "platform.h"
28 #include "gnunet_service_lib.h"
29 #include "gnunet_server_lib.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_hello_lib.h"
33 #include <zlib.h>
34
35 #include "gnunet_testbed_service.h"
36 #include "testbed.h"
37 #include "testbed_api.h"
38 #include "testbed_api_hosts.h"
39 #include "gnunet_testing_lib-new.h"
40
41 /**
42  * Generic logging
43  */
44 #define LOG(kind,...)                           \
45   GNUNET_log (kind, __VA_ARGS__)
46
47 /**
48  * Debug logging
49  */
50 #define LOG_DEBUG(...)                          \
51   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
52
53 /**
54  * By how much should the arrays lists grow
55  */
56 #define LIST_GROW_STEP 10
57
58 /**
59  * Default timeout for operations which may take some time
60  */
61 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
62
63 /**
64  * Timeout of Transport try_connect requests
65  */
66 #define TRANSPORT_TRY_CONNECT_TIMEOUT                                   \
67   GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100)
68
69 /**
70  * The main context information associated with the client which started us
71  */
72 struct Context
73 {
74   /**
75    * The client handle associated with this context
76    */
77   struct GNUNET_SERVER_Client *client;
78
79   /**
80    * The network address of the master controller
81    */
82   char *master_ip;
83
84   /**
85    * The TESTING system handle for starting peers locally
86    */
87   struct GNUNET_TESTING_System *system;
88
89   /**
90    * Event mask of event to be responded in this context
91    */
92   uint64_t event_mask;
93
94   /**
95    * Our host id according to this context
96    */
97   uint32_t host_id;
98 };
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 /**
129  * The structure for identifying a shared service
130  */
131 struct SharedService
132 {
133   /**
134    * The name of the shared service
135    */
136   char *name;
137
138   /**
139    * Number of shared peers per instance of the shared service
140    */
141   uint32_t num_shared;
142
143   /**
144    * Number of peers currently sharing the service
145    */
146   uint32_t num_sharing;
147 };
148
149
150 /**
151  * A routing entry
152  */
153 struct Route
154 {
155   /**
156    * destination host
157    */
158   uint32_t dest;
159
160   /**
161    * The host destination is reachable thru
162    */
163   uint32_t thru;
164 };
165
166
167 /**
168  * Structure representing a connected(directly-linked) controller
169  */
170 struct Slave
171 {
172   /**
173    * The controller process handle if we had started the controller
174    */
175   struct GNUNET_TESTBED_ControllerProc *controller_proc;
176
177   /**
178    * The controller handle
179    */
180   struct GNUNET_TESTBED_Controller *controller;
181
182   /**
183    * The id of the host this controller is running on
184    */
185   uint32_t host_id;
186 };
187
188
189 /**
190  * States of LCFContext
191  */
192 enum LCFContextState
193 {
194   /**
195    * The Context has been initialized; Nothing has been done on it
196    */
197   INIT,
198
199   /**
200    * Delegated host has been registered at the forwarding controller
201    */
202   DELEGATED_HOST_REGISTERED,
203   
204   /**
205    * The slave host has been registred at the forwarding controller
206    */
207   SLAVE_HOST_REGISTERED,
208   
209   /**
210    * The context has been finished (may have error)
211    */
212   FINISHED
213 };
214
215
216 /**
217  * Link controllers request forwarding context
218  */
219 struct LCFContext
220 {
221   /**
222    * The gateway which will pass the link message to delegated host
223    */
224   struct Slave *gateway;
225
226   /**
227    * The controller link message that has to be forwarded to
228    */
229   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
230
231   /**
232    * The client which has asked to perform this operation
233    */
234   struct GNUNET_SERVER_Client *client;
235
236   /**
237    * The host registration handle while registered hosts in this context
238    */
239   struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
240
241   /**
242    * The id of the operation which created this context
243    */
244   uint64_t operation_id;
245
246   /**
247    * The state of this context
248    */
249   enum LCFContextState state;
250
251   /**
252    * The delegated host
253    */
254   uint32_t delegated_host_id;
255
256   /**
257    * The slave host
258    */
259   uint32_t slave_host_id;
260
261 };
262
263
264 /**
265  * Structure of a queue entry in LCFContext request queue
266  */
267 struct LCFContextQueue
268 {
269   /**
270    * The LCFContext
271    */
272   struct LCFContext *lcf;
273
274   /**
275    * Head prt for DLL
276    */
277   struct LCFContextQueue *next;
278
279   /**
280    * Tail ptr for DLL
281    */
282   struct LCFContextQueue *prev;
283 };
284
285
286 /**
287  * A locally started peer
288  */
289 struct Peer
290 {
291   union
292   {
293     struct
294     {
295       /**
296        * The peer handle from testing API
297        */
298       struct GNUNET_TESTING_Peer *peer;
299
300       /**
301        * The modified (by GNUNET_TESTING_peer_configure) configuration this
302        * peer is configured with
303        */
304       struct GNUNET_CONFIGURATION_Handle *cfg;
305       
306       /**
307        * Is the peer running
308        */
309       int is_running;
310
311     } local;
312
313     struct
314     {
315       /**
316        * The controller this peer is started through
317        */
318       struct GNUNET_TESTBED_Controller *controller;
319
320     } remote;
321
322   } details;
323
324   /**
325    * Is this peer locally created?
326    */
327   int is_remote;
328
329   /**
330    * Our local reference id for this peer
331    */
332   uint32_t id;
333
334 };
335
336
337 /**
338  * Context information for connecting 2 peers in overlay
339  */
340 struct OverlayConnectContext
341 {
342   /**
343    * The client which has requested for overlay connection
344    */
345   struct GNUNET_SERVER_Client *client;
346
347   /**
348    * the peer which has to connect to the other peer
349    */
350   struct Peer *peer;
351
352   /**
353    * The other peer
354    */
355   struct Peer *other_peer;
356
357   /**
358    * Transport handle of the first peer to get its HELLO
359    */
360   struct GNUNET_TRANSPORT_Handle *p1th;
361
362   /**
363    * Transport handle of other peer to offer first peer's HELLO
364    */
365   struct GNUNET_TRANSPORT_Handle *p2th;
366
367   /**
368    * Core handles of the first peer; used to notify when second peer connects to it
369    */
370   struct GNUNET_CORE_Handle *ch;
371
372   /**
373    * HELLO of the other peer
374    */
375   struct GNUNET_MessageHeader *hello;
376
377   /**
378    * Get hello handle to acquire HELLO of first peer
379    */
380   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
381
382   /**
383    * The error message we send if this overlay connect operation has timed out
384    */
385   char *emsg;
386
387   /**
388    * Operation context for suboperations
389    */
390   struct OperationContext *opc;
391
392   /**
393    * The peer identity of the first peer
394    */
395   struct GNUNET_PeerIdentity peer_identity;
396
397   /**
398    * The peer identity of the other peer
399    */
400   struct GNUNET_PeerIdentity other_peer_identity;
401
402   /**
403    * The id of the operation responsible for creating this context
404    */
405   uint64_t op_id;
406
407   /**
408    * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
409    * connect to peer 2
410    */
411   GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
412
413   /**
414    * The id of the overlay connect timeout task
415    */
416   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
417
418 };
419
420
421 /**
422  * Context information for RequestOverlayConnect
423  * operations. RequestOverlayConnect is used when peers A, B reside on different
424  * hosts and the host controller for peer B is asked by the host controller of
425  * peer A to make peer B connect to peer A
426  */
427 struct RequestOverlayConnectContext
428 {
429   /**
430    * The transport handle of peer B
431    */
432   struct GNUNET_TRANSPORT_Handle *th;
433   
434   /**
435    * Peer A's HELLO
436    */
437   struct GNUNET_MessageHeader *hello;
438
439   /**
440    * The peer identity of peer A
441    */
442   struct GNUNET_PeerIdentity a_id;
443
444   /**
445    * Task for offering HELLO of A to B and doing try_connect
446    */
447   GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
448   
449   /**
450    * Task to timeout RequestOverlayConnect
451    */
452   GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
453   
454 };
455
456
457 /**
458  * Context information for operations forwarded to subcontrollers
459  */
460 struct ForwardedOperationContext
461 {
462   /**
463    * The generated operation context
464    */
465   struct OperationContext *opc;
466
467   /**
468    * The client to which we have to reply
469    */
470   struct GNUNET_SERVER_Client *client;
471
472   /**
473    * Closure pointer
474    */
475   void *cls;
476
477   /**
478    * Task ID for the timeout task
479    */
480   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
481
482   /**
483    * The id of the operation that has been forwarded
484    */
485   uint64_t operation_id;
486
487 };
488
489
490 /**
491  * Context information used while linking controllers
492  */
493 struct LinkControllersContext
494 {
495   /**
496    * The client which initiated the link controller operation
497    */
498   struct GNUNET_SERVER_Client *client;
499
500   /**
501    * The ID of the operation
502    */
503   uint64_t operation_id;
504
505   /**
506    * Pointer to the slave handle if we are directly starting/connecting to the controller
507    */
508   struct Slave *slave;
509 };
510
511
512
513 /**
514  * The master context; generated with the first INIT message
515  */
516 static struct Context *master_context;
517
518 /***********/
519 /* Handles */
520 /***********/
521
522 /**
523  * Current Transmit Handle; NULL if no notify transmit exists currently
524  */
525 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
526
527 /****************/
528 /* Lists & Maps */
529 /****************/
530
531 /**
532  * The head for the LCF queue
533  */
534 static struct LCFContextQueue *lcfq_head;
535
536 /**
537  * The tail for the LCF queue
538  */
539 static struct LCFContextQueue *lcfq_tail;
540
541 /**
542  * The message queue head
543  */
544 static struct MessageQueue *mq_head;
545
546 /**
547  * The message queue tail
548  */
549 static struct MessageQueue *mq_tail;
550
551 /**
552  * Array of host list
553  */
554 static struct GNUNET_TESTBED_Host **host_list;
555
556 /**
557  * A list of routes
558  */
559 static struct Route **route_list;
560
561 /**
562  * A list of directly linked neighbours
563  */
564 static struct Slave **slave_list;
565
566 /**
567  * A list of peers we own locally
568  */
569 static struct Peer **peer_list;
570
571 /**
572  * The hashmap of shared services
573  */
574 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
575
576 /**
577  * The size of the host list
578  */
579 static uint32_t host_list_size;
580
581 /**
582  * The size of the route list
583  */
584 static uint32_t route_list_size;
585
586 /**
587  * The size of directly linked neighbours list
588  */
589 static uint32_t slave_list_size;
590
591 /**
592  * The size of the peer list
593  */
594 static uint32_t peer_list_size;
595
596 /*********/
597 /* Tasks */
598 /*********/
599
600 /**
601  * The lcf_task handle
602  */
603 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
604
605 /**
606  * The shutdown task handle
607  */
608 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
609
610
611 /**
612  * Function called to notify a client about the connection begin ready to queue
613  * more data.  "buf" will be NULL and "size" zero if the connection was closed
614  * for writing in the meantime.
615  *
616  * @param cls NULL
617  * @param size number of bytes available in buf
618  * @param buf where the callee should write the message
619  * @return number of bytes written to buf
620  */
621 static size_t
622 transmit_ready_notify (void *cls, size_t size, void *buf)
623 {
624   struct MessageQueue *mq_entry;
625
626   transmit_handle = NULL;
627   mq_entry = mq_head;
628   GNUNET_assert (NULL != mq_entry);
629   if (0 == size)
630     return 0;
631   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
632   size = ntohs (mq_entry->msg->size);
633   memcpy (buf, mq_entry->msg, size);
634   GNUNET_free (mq_entry->msg);
635   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
636   GNUNET_free (mq_entry);
637   mq_entry = mq_head;
638   if (NULL != mq_entry)
639     transmit_handle =
640         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
641                                              ntohs (mq_entry->msg->size),
642                                              GNUNET_TIME_UNIT_FOREVER_REL,
643                                              &transmit_ready_notify, NULL);
644   return size;
645 }
646
647
648 /**
649  * Queues a message in send queue for sending to the service
650  *
651  * @param client the client to whom the queued message has to be sent
652  * @param msg the message to queue
653  */
654 static void
655 queue_message (struct GNUNET_SERVER_Client *client,
656                struct GNUNET_MessageHeader *msg)
657 {
658   struct MessageQueue *mq_entry;
659   uint16_t type;
660   uint16_t size;
661
662   type = ntohs (msg->type);
663   size = ntohs (msg->size);
664   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
665                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
666   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
667   mq_entry->msg = msg;
668   mq_entry->client = client;
669   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
670              ntohs (msg->size));
671   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
672   if (NULL == transmit_handle)
673     transmit_handle =
674         GNUNET_SERVER_notify_transmit_ready (client, size,
675                                              GNUNET_TIME_UNIT_FOREVER_REL,
676                                              &transmit_ready_notify, NULL);
677 }
678
679
680 /**
681  * Similar to GNUNET_realloc; however clears tail part of newly allocated memory
682  *
683  * @param ptr the memory block to realloc
684  * @param size the size of ptr
685  * @param new_size the size to which ptr has to be realloc'ed
686  * @return the newly reallocated memory block
687  */
688 static void *
689 TESTBED_realloc (void *ptr, size_t size, size_t new_size)
690 {
691   ptr = GNUNET_realloc (ptr, new_size);
692   if (new_size > size)
693     ptr = memset (ptr + size, 0, new_size - size);
694   return ptr;
695 }
696
697
698 /**
699  * Function to add a host to the current list of known hosts
700  *
701  * @param host the host to add
702  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
703  *           already in use
704  */
705 static int
706 host_list_add (struct GNUNET_TESTBED_Host *host)
707 {
708   uint32_t host_id;
709
710   host_id = GNUNET_TESTBED_host_get_id_ (host);
711   if (host_list_size <= host_id)
712   {
713     host_list =
714         TESTBED_realloc (host_list,
715                          sizeof (struct GNUNET_TESTBED_Host *) * host_list_size,
716                          sizeof (struct GNUNET_TESTBED_Host *) *
717                          (host_list_size + LIST_GROW_STEP));
718     host_list_size += LIST_GROW_STEP;
719   }
720   if (NULL != host_list[host_id])
721   {
722     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
723     return GNUNET_SYSERR;
724   }
725   host_list[host_id] = host;
726   return GNUNET_OK;
727 }
728
729
730 /**
731  * Adds a route to the route list
732  *
733  * @param route the route to add
734  */
735 static void
736 route_list_add (struct Route *route)
737 {
738   if (route->dest >= route_list_size)
739   {
740     route_list =
741         TESTBED_realloc (route_list, sizeof (struct Route *) * route_list_size,
742                          sizeof (struct Route *) * (route_list_size +
743                                                     LIST_GROW_STEP));
744     route_list_size += LIST_GROW_STEP;
745   }
746   GNUNET_assert (NULL == route_list[route->dest]);
747   route_list[route->dest] = route;
748 }
749
750
751 /**
752  * Adds a slave to the slave array
753  *
754  * @param slave the slave controller to add
755  */
756 static void
757 slave_list_add (struct Slave *slave)
758 {
759   if (slave->host_id >= slave_list_size)
760   {
761     slave_list =
762         TESTBED_realloc (slave_list, sizeof (struct Slave *) * slave_list_size,
763                          sizeof (struct Slave *) * (slave_list_size +
764                                                     LIST_GROW_STEP));
765     slave_list_size += LIST_GROW_STEP;
766   }
767   GNUNET_assert (NULL == slave_list[slave->host_id]);
768   slave_list[slave->host_id] = slave;
769 }
770
771
772 /**
773  * Adds a peer to the peer array
774  *
775  * @param peer the peer to add
776  */
777 static void
778 peer_list_add (struct Peer *peer)
779 {
780   uint32_t orig_size;
781
782   orig_size = peer_list_size;
783   if (peer->id >= peer_list_size)
784   {
785     while (peer->id >= peer_list_size)
786       peer_list_size += LIST_GROW_STEP;
787     peer_list =
788         TESTBED_realloc (peer_list, sizeof (struct Peer *) * orig_size,
789                          sizeof (struct Peer *) * peer_list_size);
790   }
791   GNUNET_assert (NULL == peer_list[peer->id]);
792   peer_list[peer->id] = peer;
793 }
794
795
796 /**
797  * Removes a the give peer from the peer array
798  *
799  * @param peer the peer to be removed
800  */
801 static void
802 peer_list_remove (struct Peer *peer)
803 {
804   uint32_t id;
805   uint32_t orig_size;
806
807   peer_list[peer->id] = NULL;
808   orig_size = peer_list_size;
809   while (peer_list_size >= LIST_GROW_STEP)
810   {
811     for (id = peer_list_size - 1;
812          (id >= peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--)
813       if (NULL != peer_list[id])
814         break;
815     if (id != ((peer_list_size - LIST_GROW_STEP) - 1))
816       break;
817     peer_list_size -= LIST_GROW_STEP;
818   }
819   if (orig_size == peer_list_size)
820     return;
821   peer_list =
822       GNUNET_realloc (peer_list, sizeof (struct Peer *) * peer_list_size);
823 }
824
825
826 /**
827  * Finds the route with directly connected host as destination through which
828  * the destination host can be reached
829  *
830  * @param host_id the id of the destination host
831  * @return the route with directly connected destination host; NULL if no route
832  *           is found
833  */
834 static struct Route *
835 find_dest_route (uint32_t host_id)
836 {
837   struct Route *route;
838
839   while (NULL != (route = route_list[host_id]))
840   {
841     if (route->thru == master_context->host_id)
842       break;
843     host_id = route->thru;
844   }
845   return route;
846 }
847
848
849 /**
850  * Routes message to a host given its host_id
851  *
852  * @param host_id the id of the destination host
853  * @param msg the message to be routed
854  */
855 static void
856 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
857 {
858   GNUNET_break (0);
859 }
860
861
862 /**
863  * Send operation failure message to client
864  *
865  * @param client the client to which the failure message has to be sent to
866  * @param operation_id the id of the failed operation
867  * @param emsg the error message; can be NULL
868  */
869 static void
870 send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
871                          uint64_t operation_id, const char *emsg)
872 {
873   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
874   uint16_t msize;
875   uint16_t emsg_len;
876
877   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
878   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
879   msize += emsg_len;
880   msg = GNUNET_malloc (msize);
881   msg->header.size = htons (msize);
882   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT);
883   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
884   msg->operation_id = GNUNET_htonll (operation_id);
885   if (0 != emsg_len)
886     memcpy (&msg[1], emsg, emsg_len);
887   queue_message (client, &msg->header);
888 }
889
890
891 /**
892  * Function to send generic operation success message to given client
893  *
894  * @param client the client to send the message to
895  * @param operation_id the id of the operation which was successful
896  */
897 static void
898 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
899                             uint64_t operation_id)
900 {
901   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
902   uint16_t msize;
903
904   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
905   msg = GNUNET_malloc (msize);
906   msg->header.size = htons (msize);
907   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS);
908   msg->operation_id = GNUNET_htonll (operation_id);
909   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
910   queue_message (client, &msg->header);
911 }
912
913
914 /**
915  * The  Link Controller forwarding task
916  *
917  * @param cls the LCFContext
918  * @param tc the Task context from scheduler
919  */
920 static void
921 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
922
923
924 /**
925  * Completion callback for host registrations while forwarding Link Controller messages
926  *
927  * @param cls the LCFContext
928  * @param emsg the error message; NULL if host registration is successful
929  */
930 static void
931 lcf_proc_cc (void *cls, const char *emsg)
932 {
933   struct LCFContext *lcf = cls;
934
935   lcf->rhandle = NULL;
936   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
937   switch (lcf->state)
938   {
939   case INIT:
940     if (NULL != emsg)
941       goto registration_error;
942     lcf->state = DELEGATED_HOST_REGISTERED;
943     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
944     break;
945   case DELEGATED_HOST_REGISTERED:
946     if (NULL != emsg)
947       goto registration_error;
948     lcf->state = SLAVE_HOST_REGISTERED;
949     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
950     break;
951   default:
952     GNUNET_assert (0);          /* Shouldn't reach here */
953   }
954   return;
955
956  registration_error:
957   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
958        emsg);
959   lcf->state = FINISHED;
960   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
961 }
962
963
964 /**
965  * Callback to be called when forwarded link controllers operation is
966  * successfull. We have to relay the reply msg back to the client
967  *
968  * @param cls ForwardedOperationContext
969  * @param msg the peer create success message
970  */
971 static void
972 forwarded_operation_reply_relay (void *cls,
973                                  const struct GNUNET_MessageHeader *msg)
974 {
975   struct ForwardedOperationContext *fopc = cls;
976   struct GNUNET_MessageHeader *dup_msg;
977   uint16_t msize;
978
979   msize = ntohs (msg->size);
980   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
981              msize);
982   dup_msg = GNUNET_malloc (msize);
983   (void) memcpy (dup_msg, msg, msize);
984   queue_message (fopc->client, dup_msg);
985   GNUNET_SERVER_client_drop (fopc->client);
986   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
987   GNUNET_free (fopc);
988 }
989
990
991 /**
992  * Task to free resources when forwarded link controllers has been timedout
993  *
994  * @param cls the ForwardedOperationContext
995  * @param tc the task context from scheduler
996  */
997 static void
998 forwarded_operation_timeout (void *cls,
999                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1000 {
1001   struct ForwardedOperationContext *fopc = cls;
1002
1003   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1004   send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
1005   GNUNET_SERVER_client_drop (fopc->client);
1006   GNUNET_free (fopc);
1007 }
1008
1009
1010 /**
1011  * The  Link Controller forwarding task
1012  *
1013  * @param cls the LCFContext
1014  * @param tc the Task context from scheduler
1015  */
1016 static void
1017 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1018 {
1019   struct LCFContext *lcf = cls;
1020   struct LCFContextQueue *lcfq;
1021   struct ForwardedOperationContext *fopc;
1022
1023   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1024   switch (lcf->state)
1025   {
1026   case INIT:
1027     if (GNUNET_NO ==
1028         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
1029                                             lcf->gateway->controller))
1030     {
1031       lcf->rhandle =
1032           GNUNET_TESTBED_register_host (lcf->gateway->controller,
1033                                         host_list[lcf->delegated_host_id],
1034                                         lcf_proc_cc, lcf);
1035     }
1036     else
1037     {
1038       lcf->state = DELEGATED_HOST_REGISTERED;
1039       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1040     }
1041     break;
1042   case DELEGATED_HOST_REGISTERED:
1043     if (GNUNET_NO ==
1044         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
1045                                             lcf->gateway->controller))
1046     {
1047       lcf->rhandle =
1048           GNUNET_TESTBED_register_host (lcf->gateway->controller,
1049                                         host_list[lcf->slave_host_id],
1050                                         lcf_proc_cc, lcf);
1051     }
1052     else
1053     {
1054       lcf->state = SLAVE_HOST_REGISTERED;
1055       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1056     }
1057     break;
1058   case SLAVE_HOST_REGISTERED:
1059     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1060     fopc->client = lcf->client;
1061     fopc->operation_id = lcf->operation_id;
1062     fopc->opc =
1063         GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
1064                                                lcf->operation_id,
1065                                                &lcf->msg->header,
1066                                                &forwarded_operation_reply_relay,
1067                                                fopc);
1068     fopc->timeout_task =
1069         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1070                                       fopc);
1071     lcf->state = FINISHED;
1072     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1073     break;
1074   case FINISHED:
1075     lcfq = lcfq_head;
1076     GNUNET_assert (lcfq->lcf == lcf);
1077     GNUNET_free (lcf->msg);
1078     GNUNET_free (lcf);
1079     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1080     GNUNET_free (lcfq);
1081     if (NULL != lcfq_head)
1082       lcf_proc_task_id =
1083           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
1084   }
1085 }
1086
1087
1088 /**
1089  * Callback for event from slave controllers
1090  *
1091  * @param cls struct Slave *
1092  * @param event information about the event
1093  */
1094 static void
1095 slave_event_callback (void *cls,
1096                       const struct GNUNET_TESTBED_EventInformation *event)
1097 {
1098   GNUNET_break (0);
1099 }
1100
1101
1102 /**
1103  * Callback to signal successfull startup of the controller process
1104  *
1105  * @param cls the closure from GNUNET_TESTBED_controller_start()
1106  * @param cfg the configuration with which the controller has been started;
1107  *          NULL if status is not GNUNET_OK
1108  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1109  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1110  */
1111 static void
1112 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1113                        int status)
1114 {
1115   struct LinkControllersContext *lcc = cls;
1116
1117   if (GNUNET_SYSERR == status)
1118   {
1119     lcc->slave->controller_proc = NULL;
1120     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
1121     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
1122     return;
1123   }
1124   lcc->slave->controller =
1125       GNUNET_TESTBED_controller_connect (cfg, host_list[lcc->slave->host_id],
1126                                          master_context->event_mask,
1127                                          &slave_event_callback, lcc->slave);
1128   if (NULL != lcc->slave->controller)
1129     send_operation_success_msg (lcc->client, lcc->operation_id);
1130   else
1131     send_operation_fail_msg (lcc->client, lcc->operation_id,
1132                              "Could not connect to delegated controller");
1133   GNUNET_SERVER_client_drop (lcc->client);
1134   GNUNET_free (lcc);
1135 }
1136
1137
1138 /**
1139  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
1140  *
1141  * @param cls NULL
1142  * @param client identification of the client
1143  * @param message the actual message
1144  */
1145 static void
1146 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
1147              const struct GNUNET_MessageHeader *message)
1148 {
1149   const struct GNUNET_TESTBED_InitMessage *msg;
1150   struct GNUNET_TESTBED_Host *host;
1151   const char *controller_hostname;
1152   uint16_t msize;
1153
1154   if (NULL != master_context)
1155   {
1156     GNUNET_break (0);
1157     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1158     return;
1159   }
1160   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1161   msize = ntohs (message->size);
1162   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1163   {
1164     GNUNET_break (0);
1165     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1166     return;
1167   }
1168   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1169   controller_hostname = (const char *) &msg[1];
1170   if ('\0' != controller_hostname[msize - 1])
1171   {
1172     GNUNET_break (0);
1173     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1174     return;
1175   }
1176   master_context = GNUNET_malloc (sizeof (struct Context));
1177   master_context->client = client;
1178   master_context->host_id = ntohl (msg->host_id);
1179   master_context->master_ip = GNUNET_strdup (controller_hostname);
1180   LOG_DEBUG ("Master Controller IP: %s\n", master_context->master_ip);
1181   master_context->system =
1182       GNUNET_TESTING_system_create ("testbed", master_context->master_ip);
1183   host =
1184       GNUNET_TESTBED_host_create_with_id (master_context->host_id, NULL, NULL,
1185                                           0);
1186   host_list_add (host);
1187   master_context->event_mask = GNUNET_ntohll (msg->event_mask);
1188   GNUNET_SERVER_client_keep (client);
1189   LOG_DEBUG ("Created master context with host ID: %u\n",
1190              master_context->host_id);
1191   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1192 }
1193
1194
1195 /**
1196  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1197  *
1198  * @param cls NULL
1199  * @param client identification of the client
1200  * @param message the actual message
1201  */
1202 static void
1203 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1204                  const struct GNUNET_MessageHeader *message)
1205 {
1206   struct GNUNET_TESTBED_Host *host;
1207   const struct GNUNET_TESTBED_AddHostMessage *msg;
1208   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1209   char *username;
1210   char *hostname;
1211   char *emsg;
1212   uint32_t host_id;
1213   uint16_t username_length;
1214   uint16_t hostname_length;
1215   uint16_t reply_size;
1216   uint16_t msize;
1217
1218   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1219   msize = ntohs (msg->header.size);
1220   username = (char *) &(msg[1]);
1221   username_length = ntohs (msg->user_name_length);
1222   GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length + 1));        /* msg must contain hostname */
1223   if (0 != username_length)
1224     GNUNET_assert ('\0' == username[username_length]);
1225   username_length = (0 == username_length) ? 0 : username_length + 1;
1226   hostname = username + username_length;
1227   hostname_length =
1228       msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
1229   GNUNET_assert ('\0' == hostname[hostname_length - 1]);
1230   GNUNET_assert (strlen (hostname) == hostname_length - 1);
1231   host_id = ntohl (msg->host_id);
1232   LOG_DEBUG ("Received ADDHOST message\n");
1233   LOG_DEBUG ("-------host id: %u\n", host_id);
1234   LOG_DEBUG ("-------hostname: %s\n", hostname);
1235   if (0 != username_length)
1236     LOG_DEBUG ("-------username: %s\n", username);
1237   else
1238   {
1239     LOG_DEBUG ("-------username: NULL\n");
1240     username = NULL;
1241   }
1242   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1243   host =
1244       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1245                                           ntohs (msg->ssh_port));
1246   GNUNET_assert (NULL != host);
1247   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1248   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1249   if (GNUNET_OK != host_list_add (host))
1250   {
1251     /* We are unable to add a host */
1252     emsg = "A host exists with given host-id";
1253     LOG_DEBUG ("%s: %u", emsg, host_id);
1254     GNUNET_TESTBED_host_destroy (host);
1255     reply_size += strlen (emsg) + 1;
1256     reply = GNUNET_malloc (reply_size);
1257     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1258   }
1259   else
1260     reply = GNUNET_malloc (reply_size);
1261   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
1262   reply->header.size = htons (reply_size);
1263   reply->host_id = htonl (host_id);
1264   queue_message (client, &reply->header);
1265 }
1266
1267
1268 /**
1269  * Iterator over hash map entries.
1270  *
1271  * @param cls closure
1272  * @param key current key code
1273  * @param value value in the hash map
1274  * @return GNUNET_YES if we should continue to
1275  *         iterate,
1276  *         GNUNET_NO if not.
1277  */
1278 int
1279 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1280 {
1281   struct SharedService *queried_ss = cls;
1282   struct SharedService *ss = value;
1283
1284   if (0 == strcmp (ss->name, queried_ss->name))
1285     return GNUNET_NO;
1286   else
1287     return GNUNET_YES;
1288 }
1289
1290
1291 /**
1292  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1293  *
1294  * @param cls NULL
1295  * @param client identification of the client
1296  * @param message the actual message
1297  */
1298 static void
1299 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1300                                  const struct GNUNET_MessageHeader *message)
1301 {
1302   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1303   struct SharedService *ss;
1304   char *service_name;
1305   struct GNUNET_HashCode hash;
1306   uint16_t msg_size;
1307   uint16_t service_name_size;
1308
1309   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1310   msg_size = ntohs (message->size);
1311   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1312   {
1313     GNUNET_break (0);
1314     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1315     return;
1316   }
1317   service_name_size =
1318       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1319   service_name = (char *) &msg[1];
1320   if ('\0' != service_name[service_name_size - 1])
1321   {
1322     GNUNET_break (0);
1323     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1324     return;
1325   }
1326   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1327              service_name, ntohl (msg->num_peers));
1328   if (ntohl (msg->host_id) != master_context->host_id)
1329   {
1330     route_message (ntohl (msg->host_id), message);
1331     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1332     return;
1333   }
1334   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1335   ss = GNUNET_malloc (sizeof (struct SharedService));
1336   ss->name = strdup (service_name);
1337   ss->num_shared = ntohl (msg->num_peers);
1338   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1339   if (GNUNET_SYSERR ==
1340       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1341                                                   &ss_exists_iterator, ss))
1342   {
1343     LOG (GNUNET_ERROR_TYPE_WARNING,
1344          "Service %s already configured as a shared service. "
1345          "Ignoring service sharing request \n", ss->name);
1346     GNUNET_free (ss->name);
1347     GNUNET_free (ss);
1348     return;
1349   }
1350   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1351                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1352 }
1353
1354
1355 /**
1356  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1357  *
1358  * @param cls NULL
1359  * @param client identification of the client
1360  * @param message the actual message
1361  */
1362 static void
1363 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1364                          const struct GNUNET_MessageHeader *message)
1365 {
1366   const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1367   struct GNUNET_CONFIGURATION_Handle *cfg;
1368   struct LCFContextQueue *lcfq;
1369   struct Route *route;
1370   struct Route *new_route;
1371   char *config;
1372   uLongf dest_size;
1373   size_t config_size;
1374   uint32_t delegated_host_id;
1375   uint32_t slave_host_id;
1376   uint16_t msize;
1377
1378   if (NULL == master_context)
1379   {
1380     GNUNET_break (0);
1381     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1382     return;
1383   }
1384   msize = ntohs (message->size);
1385   if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
1386   {
1387     GNUNET_break (0);
1388     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1389     return;
1390   }
1391   msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
1392   delegated_host_id = ntohl (msg->delegated_host_id);
1393   if (delegated_host_id == master_context->host_id)
1394   {
1395     GNUNET_break (0);
1396     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1397     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1398     return;
1399   }
1400   if ((delegated_host_id >= host_list_size) ||
1401       (NULL == host_list[delegated_host_id]))
1402   {
1403     LOG (GNUNET_ERROR_TYPE_WARNING, "Delegated host not registered with us\n");
1404     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1405     return;
1406   }
1407   slave_host_id = ntohl (msg->slave_host_id);
1408   if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
1409   {
1410     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
1411     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1412     return;
1413   }
1414   if (slave_host_id == delegated_host_id)
1415   {
1416     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1417     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1418     return;
1419   }
1420
1421   if (slave_host_id == master_context->host_id) /* Link from us */
1422   {
1423     struct Slave *slave;
1424     struct LinkControllersContext *lcc;
1425
1426     msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1427     config_size = ntohs (msg->config_size);
1428     if ((delegated_host_id < slave_list_size) && (NULL != slave_list[delegated_host_id]))       /* We have already added */
1429     {
1430       LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
1431            delegated_host_id);
1432       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1433       return;
1434     }
1435     config = GNUNET_malloc (config_size);
1436     dest_size = (uLongf) config_size;
1437     if (Z_OK !=
1438         uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
1439                     (uLong) msize))
1440     {
1441       GNUNET_break (0);         /* Compression error */
1442       GNUNET_free (config);
1443       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1444       return;
1445     }
1446     if (config_size != dest_size)
1447     {
1448       LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
1449       GNUNET_free (config);
1450       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1451       return;
1452     }
1453     cfg = GNUNET_CONFIGURATION_create ();       /* Free here or in lcfcontext */
1454     if (GNUNET_OK !=
1455         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1456     {
1457       GNUNET_break (0);         /* Configuration parsing error */
1458       GNUNET_free (config);
1459       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1460       return;
1461     }
1462     GNUNET_free (config);
1463     if ((delegated_host_id < slave_list_size) &&
1464         (NULL != slave_list[delegated_host_id]))
1465     {
1466       GNUNET_break (0);         /* Configuration parsing error */
1467       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1468       return;
1469     }
1470     slave = GNUNET_malloc (sizeof (struct Slave));
1471     slave->host_id = delegated_host_id;
1472     slave_list_add (slave);
1473     if (1 != msg->is_subordinate)
1474     {
1475       slave->controller =
1476           GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1477                                              master_context->event_mask,
1478                                              &slave_event_callback, slave);
1479       GNUNET_CONFIGURATION_destroy (cfg);
1480       if (NULL != slave->controller)
1481         send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1482       else
1483         send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1484                                  "Could not connect to delegated controller");
1485       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1486       return;
1487     }
1488     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1489     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1490     GNUNET_SERVER_client_keep (client);
1491     lcc->client = client;
1492     lcc->slave = slave;
1493     slave->controller_proc =
1494         GNUNET_TESTBED_controller_start (master_context->master_ip,
1495                                          host_list[slave->host_id], cfg,
1496                                          &slave_status_callback, lcc);
1497     GNUNET_CONFIGURATION_destroy (cfg);
1498     new_route = GNUNET_malloc (sizeof (struct Route));
1499     new_route->dest = delegated_host_id;
1500     new_route->thru = master_context->host_id;
1501     route_list_add (new_route);
1502     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1503     return;
1504   }
1505
1506   /* Route the request */
1507   if (slave_host_id >= route_list_size)
1508   {
1509     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1510     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1511     return;
1512   }
1513   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1514   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1515   lcfq->lcf->delegated_host_id = delegated_host_id;
1516   lcfq->lcf->slave_host_id = slave_host_id;
1517   route = find_dest_route (slave_host_id);
1518   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1519   GNUNET_assert (route->dest < slave_list_size);
1520   GNUNET_assert (NULL != slave_list[route->dest]);
1521   lcfq->lcf->state = INIT;
1522   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1523   lcfq->lcf->gateway = slave_list[route->dest];
1524   lcfq->lcf->msg = GNUNET_malloc (msize);
1525   (void) memcpy (lcfq->lcf->msg, msg, msize);
1526   GNUNET_SERVER_client_keep (client);
1527   lcfq->lcf->client = client;
1528   if (NULL == lcfq_head)
1529   {
1530     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1531     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1532     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1533   }
1534   else
1535     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1536   /* FIXME: Adding a new route should happen after the controllers are linked
1537    * successfully */
1538   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1539   new_route = GNUNET_malloc (sizeof (struct Route));
1540   new_route->dest = delegated_host_id;
1541   new_route->thru = route->dest;
1542   route_list_add (new_route);
1543 }
1544
1545
1546 /**
1547  * The task to be executed if the forwarded peer create operation has been
1548  * timed out
1549  *
1550  * @param cls the FowardedOperationContext
1551  * @param tc the TaskContext from the scheduler
1552  */
1553 static void
1554 peer_create_forward_timeout (void *cls,
1555                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1556 {
1557   struct ForwardedOperationContext *fo_ctxt = cls;
1558
1559   /* send error msg to client */
1560   send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id, "Timedout");
1561   GNUNET_SERVER_client_drop (fo_ctxt->client);
1562   GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1563   GNUNET_free (fo_ctxt);
1564 }
1565
1566
1567 /**
1568  * Callback to be called when forwarded peer create operation is
1569  * successfull. We have to relay the reply msg back to the client
1570  *
1571  * @param cls ForwardedOperationContext
1572  * @param msg the peer create success message
1573  */
1574 static void
1575 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1576 {
1577   struct ForwardedOperationContext *fo_ctxt = cls;
1578   const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *success_msg;
1579   struct GNUNET_MessageHeader *dup_msg;
1580   struct Peer *peer;
1581   uint16_t msize;
1582
1583   GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1584   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS)
1585   {
1586     success_msg =
1587         (const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *) msg;
1588     peer = GNUNET_malloc (sizeof (struct Peer));
1589     peer->is_remote = GNUNET_YES;
1590     peer->id = ntohl (success_msg->peer_id);
1591     GNUNET_assert (NULL != fo_ctxt->cls);
1592     peer->details.remote.controller = fo_ctxt->cls;
1593     peer_list_add (peer);
1594   }
1595   msize = ntohs (msg->size);
1596   dup_msg = GNUNET_malloc (msize);
1597   (void) memcpy (dup_msg, msg, msize);
1598   queue_message (fo_ctxt->client, dup_msg);
1599   GNUNET_SERVER_client_drop (fo_ctxt->client);
1600   GNUNET_free (fo_ctxt);
1601 }
1602
1603
1604
1605 /**
1606  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1607  *
1608  * @param cls NULL
1609  * @param client identification of the client
1610  * @param message the actual message
1611  */
1612 static void
1613 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1614                     const struct GNUNET_MessageHeader *message)
1615 {
1616   const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1617   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1618   struct GNUNET_CONFIGURATION_Handle *cfg;
1619   struct ForwardedOperationContext *fo_ctxt;
1620   struct Route *route;
1621   struct Peer *peer;
1622   char *config;
1623   size_t dest_size;
1624   int ret;
1625   uint32_t config_size;
1626   uint32_t host_id;
1627   uint32_t peer_id;
1628   uint16_t msize;
1629
1630
1631   msize = ntohs (message->size);
1632   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1633   {
1634     GNUNET_break (0);           /* We need configuration */
1635     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1636     return;
1637   }
1638   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1639   host_id = ntohl (msg->host_id);
1640   peer_id = ntohl (msg->peer_id);
1641   if (UINT32_MAX == peer_id)
1642   {
1643     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1644                              "Cannot create peer with given ID");
1645     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1646     return;
1647   }
1648   if (host_id == master_context->host_id)
1649   {
1650     char *emsg;
1651
1652     /* We are responsible for this peer */
1653     msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1654     config_size = ntohl (msg->config_size);
1655     config = GNUNET_malloc (config_size);
1656     dest_size = config_size;
1657     if (Z_OK !=
1658         (ret =
1659          uncompress ((Bytef *) config, (uLongf *) & dest_size,
1660                      (const Bytef *) &msg[1], (uLong) msize)))
1661     {
1662       GNUNET_break (0);         /* uncompression error */
1663       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1664       return;
1665     }
1666     if (config_size != dest_size)
1667     {
1668       GNUNET_break (0);         /* Uncompressed config size mismatch */
1669       GNUNET_free (config);
1670       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1671       return;
1672     }
1673     cfg = GNUNET_CONFIGURATION_create ();
1674     if (GNUNET_OK !=
1675         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1676     {
1677       GNUNET_break (0);         /* Configuration parsing error */
1678       GNUNET_free (config);
1679       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1680       return;
1681     }
1682     GNUNET_free (config);
1683     peer = GNUNET_malloc (sizeof (struct Peer));
1684     peer->is_remote = GNUNET_NO;
1685     peer->details.local.cfg = cfg;
1686     peer->id = peer_id;
1687     LOG_DEBUG ("Creating peer with id: %u\n", peer->id);
1688     peer->details.local.peer =
1689         GNUNET_TESTING_peer_configure (master_context->system,
1690                                        peer->details.local.cfg, peer->id,
1691                                        NULL /* Peer id */ ,
1692                                        &emsg);
1693     if (NULL == peer->details.local.peer)
1694     {
1695       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1696       GNUNET_free (emsg);
1697       GNUNET_free (peer);
1698       GNUNET_break (0);
1699       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1700       return;
1701     }
1702     peer->details.local.is_running = GNUNET_NO;
1703     peer_list_add (peer);
1704     reply =
1705         GNUNET_malloc (sizeof
1706                        (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1707     reply->header.size =
1708         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1709     reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS);
1710     reply->peer_id = msg->peer_id;
1711     reply->operation_id = msg->operation_id;
1712     queue_message (client, &reply->header);
1713     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1714     return;
1715   }
1716
1717   /* Forward peer create request */
1718   route = find_dest_route (host_id);
1719   if (NULL == route)
1720   {
1721     GNUNET_break (0);
1722     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1723     return;
1724   }
1725   fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1726   GNUNET_SERVER_client_keep (client);
1727   fo_ctxt->client = client;
1728   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1729   fo_ctxt->cls = slave_list[route->dest]->controller;
1730   fo_ctxt->opc =
1731       GNUNET_TESTBED_forward_operation_msg_ (slave_list
1732                                              [route->dest]->controller,
1733                                              fo_ctxt->operation_id,
1734                                              &msg->header,
1735                                              peer_create_success_cb, fo_ctxt);
1736   fo_ctxt->timeout_task =
1737       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
1738                                     fo_ctxt);
1739
1740   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1741 }
1742
1743
1744 /**
1745  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1746  *
1747  * @param cls NULL
1748  * @param client identification of the client
1749  * @param message the actual message
1750  */
1751 static void
1752 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1753                      const struct GNUNET_MessageHeader *message)
1754 {
1755   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1756   struct ForwardedOperationContext *fopc;
1757   struct Peer *peer;
1758   uint32_t peer_id;
1759
1760   msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1761   peer_id = ntohl (msg->peer_id);
1762   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1763              peer_id, GNUNET_ntohll (msg->operation_id));
1764   if ((peer_list_size <= peer_id) || (NULL == peer_list[peer_id]))
1765   {
1766     LOG (GNUNET_ERROR_TYPE_ERROR,
1767          "Asked to destroy a non existent peer with id: %u\n", peer_id);
1768     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1769                              "Peer doesn't exist");
1770     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1771     return;
1772   }
1773   peer = peer_list[peer_id];
1774   if (GNUNET_YES == peer->is_remote)
1775   {
1776     /* Forward the destory message to sub controller */
1777     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1778     GNUNET_SERVER_client_keep (client);
1779     fopc->client = client;
1780     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1781     fopc->opc =
1782         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1783                                                fopc->operation_id, &msg->header,
1784                                                &forwarded_operation_reply_relay,
1785                                                fopc);
1786     fopc->timeout_task =
1787         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1788                                       fopc);
1789     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1790     return;
1791   }
1792   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1793   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1794   peer_list_remove (peer);
1795   GNUNET_free (peer);
1796   send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1797   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1798 }
1799
1800
1801 /**
1802  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1803  *
1804  * @param cls NULL
1805  * @param client identification of the client
1806  * @param message the actual message
1807  */
1808 static void
1809 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1810                    const struct GNUNET_MessageHeader *message)
1811 {
1812   const struct GNUNET_TESTBED_PeerStartMessage *msg;
1813   struct GNUNET_TESTBED_PeerEventMessage *reply;
1814   struct ForwardedOperationContext *fopc;
1815   struct Peer *peer;
1816   uint32_t peer_id;
1817
1818   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1819   peer_id = ntohl (msg->peer_id);
1820   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1821   {
1822     GNUNET_break (0);
1823     LOG (GNUNET_ERROR_TYPE_ERROR,
1824          "Asked to start a non existent peer with id: %u\n", peer_id);
1825     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1826     return;
1827   }
1828   peer = peer_list[peer_id];
1829   if (GNUNET_YES == peer->is_remote)
1830   {
1831     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1832     GNUNET_SERVER_client_keep (client);
1833     fopc->client = client;
1834     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1835     fopc->opc =
1836         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1837                                                fopc->operation_id, &msg->header,
1838                                                &forwarded_operation_reply_relay,
1839                                                fopc);
1840     fopc->timeout_task =
1841         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1842                                       fopc);
1843     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1844     return;
1845   }
1846   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1847   {
1848     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1849                              "Failed to start");
1850     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1851     return;
1852   }
1853   peer->details.local.is_running = GNUNET_YES;
1854   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1855   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
1856   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1857   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1858   reply->host_id = htonl (master_context->host_id);
1859   reply->peer_id = msg->peer_id;
1860   reply->operation_id = msg->operation_id;
1861   queue_message (client, &reply->header);
1862   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1863 }
1864
1865
1866 /**
1867  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1868  *
1869  * @param cls NULL
1870  * @param client identification of the client
1871  * @param message the actual message
1872  */
1873 static void
1874 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1875                   const struct GNUNET_MessageHeader *message)
1876 {
1877   const struct GNUNET_TESTBED_PeerStopMessage *msg;
1878   struct GNUNET_TESTBED_PeerEventMessage *reply;
1879   struct ForwardedOperationContext *fopc;
1880   struct Peer *peer;
1881   uint32_t peer_id;
1882
1883   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1884   peer_id = ntohl (msg->peer_id);
1885   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1886   {
1887     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1888                              "Peer not found");
1889     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1890     return;
1891   }
1892   peer = peer_list[peer_id];
1893   if (GNUNET_YES == peer->is_remote)
1894   {
1895     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1896     GNUNET_SERVER_client_keep (client);
1897     fopc->client = client;
1898     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1899     fopc->opc =
1900         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1901                                                fopc->operation_id, &msg->header,
1902                                                &forwarded_operation_reply_relay,
1903                                                fopc);
1904     fopc->timeout_task =
1905         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1906                                       fopc);
1907     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1908     return;
1909   }
1910   if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
1911   {
1912     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1913                              "Peer not running");
1914     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1915     return;
1916   }
1917   peer->details.local.is_running = GNUNET_NO;
1918   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1919   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
1920   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1921   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
1922   reply->host_id = htonl (master_context->host_id);
1923   reply->peer_id = msg->peer_id;
1924   reply->operation_id = msg->operation_id;
1925   queue_message (client, &reply->header);
1926   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1927 }
1928
1929
1930 /**
1931  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1932  *
1933  * @param cls NULL
1934  * @param client identification of the client
1935  * @param message the actual message
1936  */
1937 static void
1938 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1939                         const struct GNUNET_MessageHeader *message)
1940 {
1941   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1942   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1943   struct Peer *peer;
1944   char *config;
1945   char *xconfig;
1946   size_t c_size;
1947   size_t xc_size;
1948   uint32_t peer_id;
1949   uint16_t msize;
1950
1951   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
1952   peer_id = ntohl (msg->peer_id);
1953   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1954   {
1955     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1956                              "Peer not found");
1957     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1958     return;
1959   }
1960   peer = peer_list[peer_id];
1961   if (GNUNET_YES == peer->is_remote)
1962   {
1963     /* FIXME: forward to sub controller */
1964     GNUNET_break (0);
1965     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1966     return;
1967   }
1968   config =
1969       GNUNET_CONFIGURATION_serialize (peer_list[peer_id]->details.local.cfg,
1970                                       &c_size);
1971   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1972   GNUNET_free (config);
1973   msize =
1974       xc_size +
1975       sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1976   reply = GNUNET_realloc (xconfig, msize);
1977   (void) memmove (&reply[1], reply, xc_size);
1978   reply->header.size = htons (msize);
1979   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG);
1980   reply->peer_id = msg->peer_id;
1981   reply->operation_id = msg->operation_id;
1982   GNUNET_TESTING_peer_get_identity (peer_list[peer_id]->details.local.peer,
1983                                     &reply->peer_identity);
1984   reply->config_size = htons ((uint16_t) c_size);
1985   queue_message (client, &reply->header);
1986   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1987 }
1988
1989
1990 /**
1991  * Task for cleaing up overlay connect context structure
1992  *
1993  * @param cls the overlay connect context
1994  * @param tc the task context
1995  */
1996 static void
1997 occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1998 {
1999   struct OverlayConnectContext *occ = cls;
2000
2001   LOG_DEBUG ("Cleaning up occ\n");
2002   GNUNET_free_non_null (occ->emsg);
2003   GNUNET_free_non_null (occ->hello);
2004   if (NULL != occ->opc)
2005     GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
2006   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2007     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2008   if (NULL != occ->ch)
2009     GNUNET_CORE_disconnect (occ->ch);
2010   if (NULL != occ->ghh)
2011     GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2012   if (NULL != occ->p1th)
2013     GNUNET_TRANSPORT_disconnect (occ->p1th);
2014   if (NULL != occ->p2th)
2015     GNUNET_TRANSPORT_disconnect (occ->p2th);
2016   GNUNET_free (occ);
2017 }
2018
2019
2020 /**
2021  * Task which will be run when overlay connect request has been timed out
2022  *
2023  * @param cls the OverlayConnectContext
2024  * @param tc the TaskContext
2025  */
2026 static void
2027 timeout_overlay_connect (void *cls,
2028                          const struct GNUNET_SCHEDULER_TaskContext *tc)
2029 {
2030   struct OverlayConnectContext *occ = cls;
2031
2032   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2033   send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
2034   GNUNET_SERVER_client_drop (occ->client);
2035   occ_cleanup (occ, tc);
2036 }
2037
2038
2039
2040 /**
2041  * Function called to notify transport users that another
2042  * peer connected to us.
2043  *
2044  * @param cls closure
2045  * @param new_peer the peer that connected
2046  * @param ats performance data
2047  * @param ats_count number of entries in ats (excluding 0-termination)
2048  */
2049 static void
2050 overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2051                         const struct GNUNET_ATS_Information *ats,
2052                         unsigned int ats_count)
2053 {
2054   struct OverlayConnectContext *occ = cls;
2055   struct GNUNET_TESTBED_ConnectionEventMessage *msg;
2056   char *new_peer_str;
2057   char *other_peer_str;
2058
2059   LOG_DEBUG ("Overlay connect notify\n");
2060   if (0 ==
2061       memcmp (new_peer, &occ->peer_identity,
2062               sizeof (struct GNUNET_PeerIdentity)))
2063     return;
2064   new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
2065   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2066   if (0 !=
2067       memcmp (new_peer, &occ->other_peer_identity,
2068               sizeof (struct GNUNET_PeerIdentity)))
2069   {
2070     LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n",
2071                new_peer_str, other_peer_str);
2072     GNUNET_free (new_peer_str);
2073     GNUNET_free (other_peer_str);
2074     return;
2075   }
2076   GNUNET_free (new_peer_str);
2077   LOG_DEBUG ("Peer %4s connected to peer %4s\n", other_peer_str, 
2078              GNUNET_i2s (&occ->peer_identity));
2079   GNUNET_free (other_peer_str);
2080   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2081   {
2082     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2083     occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2084   }
2085   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
2086   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2087   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2088   GNUNET_free_non_null (occ->emsg);
2089   occ->emsg = NULL;
2090   if (NULL != occ->p2th)
2091     GNUNET_TRANSPORT_disconnect (occ->p2th);
2092   occ->p2th = NULL;
2093   LOG_DEBUG ("Peers connected - Sending overlay connect success\n");
2094   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2095   msg->header.size =
2096       htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2097   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT);
2098   msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
2099   msg->peer1 = htonl (occ->peer->id);
2100   msg->peer2 = htonl (occ->other_peer->id);
2101   msg->operation_id = GNUNET_htonll (occ->op_id);
2102   queue_message (occ->client, &msg->header);
2103   GNUNET_SERVER_client_drop (occ->client);
2104   GNUNET_SCHEDULER_add_now (&occ_cleanup, occ);
2105 }
2106
2107
2108 /**
2109  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
2110  * peer 1.
2111  *
2112  * @param cls the OverlayConnectContext
2113  * @param tc the TaskContext from scheduler
2114  */
2115 static void
2116 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2117 {
2118   struct OverlayConnectContext *occ = cls;
2119   char *other_peer_str;
2120
2121   occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2122   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2123     return;
2124   GNUNET_assert (NULL != occ->hello);
2125   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2126   if (GNUNET_YES == occ->other_peer->is_remote)
2127   {
2128     struct GNUNET_TESTBED_RequestConnectMessage *msg;
2129     uint16_t msize;
2130     uint16_t hello_size;
2131
2132     LOG_DEBUG ("Offering HELLO of %s to %s via Remote Overlay Request\n", 
2133                GNUNET_i2s (&occ->peer_identity), other_peer_str);
2134     hello_size = ntohs (occ->hello->size);
2135     msize = sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hello_size;
2136     msg = GNUNET_malloc (msize);
2137     msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT);
2138     msg->header.size = htons (msize);
2139     msg->peer = htonl (occ->other_peer->id);
2140     msg->operation_id = GNUNET_htonll (occ->op_id);
2141     (void) memcpy (&msg->peer_identity, &occ->peer_identity,
2142                    sizeof (struct GNUNET_PeerIdentity));
2143     memcpy (msg->hello, occ->hello, hello_size);
2144     GNUNET_TESTBED_queue_message_ (occ->other_peer->details.remote.controller,
2145                                    &msg->header);
2146   }
2147   else
2148   {
2149     LOG_DEBUG ("Offering HELLO of %s to %s\n", 
2150                GNUNET_i2s (&occ->peer_identity), other_peer_str);
2151     GNUNET_TRANSPORT_offer_hello (occ->p2th, occ->hello, NULL, NULL);
2152     GNUNET_TRANSPORT_try_connect (occ->p2th, &occ->peer_identity);
2153     occ->send_hello_task =
2154         GNUNET_SCHEDULER_add_delayed (TRANSPORT_TRY_CONNECT_TIMEOUT,
2155                                       &send_hello, occ);
2156   }
2157   GNUNET_free (other_peer_str);  
2158 }
2159
2160 /**
2161  * Test for checking whether HELLO message is empty
2162  *
2163  * @param cls empty flag to set
2164  * @param address the HELLO
2165  * @param expiration expiration of the HELLO
2166  * @return
2167  */
2168 static int
2169 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
2170               struct GNUNET_TIME_Absolute expiration)
2171 {
2172   int *empty = cls;
2173
2174   *empty = GNUNET_NO;
2175   return GNUNET_OK;
2176 }
2177
2178
2179 /**
2180  * Function called whenever there is an update to the HELLO of peers in the
2181  * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
2182  * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
2183  *
2184  * @param cls closure
2185  * @param hello our updated HELLO
2186  */
2187 static void
2188 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
2189 {
2190   struct OverlayConnectContext *occ = cls;
2191   int empty;
2192   uint16_t msize;
2193
2194   msize = ntohs (hello->size);
2195   empty = GNUNET_YES;
2196   (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
2197                                          hello, GNUNET_NO, &test_address,
2198                                          &empty);
2199   if (GNUNET_YES == empty)
2200   {
2201     LOG_DEBUG ("HELLO of %s is empty\n", GNUNET_i2s (&occ->peer_identity));
2202     return;
2203   }
2204   LOG_DEBUG ("Received HELLO of %s\n", GNUNET_i2s (&occ->peer_identity));
2205   occ->hello = GNUNET_malloc (msize);
2206   memcpy (occ->hello, hello, msize);
2207   GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2208   occ->ghh = NULL;
2209   GNUNET_TRANSPORT_disconnect (occ->p1th);
2210   occ->p1th = NULL;
2211   GNUNET_free_non_null (occ->emsg);
2212   if (GNUNET_NO == occ->other_peer->is_remote)
2213   {   
2214     occ->p2th =
2215         GNUNET_TRANSPORT_connect (occ->other_peer->details.local.cfg,
2216                                   &occ->other_peer_identity, NULL, NULL, NULL,
2217                                   NULL);
2218     if (NULL == occ->p2th)
2219     {
2220       GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of %s\n",
2221                        GNUNET_i2s (&occ->other_peer_identity));
2222       GNUNET_SCHEDULER_cancel (occ->timeout_task);
2223       occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2224       return;
2225     }
2226   }
2227   occ->emsg = GNUNET_strdup ("Timeout while offering HELLO to other peer");
2228   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
2229 }
2230
2231
2232 /**
2233  * Function called after GNUNET_CORE_connect has succeeded (or failed
2234  * for good).  Note that the private key of the peer is intentionally
2235  * not exposed here; if you need it, your process should try to read
2236  * the private key file directly (which should work if you are
2237  * authorized...).
2238  *
2239  * @param cls closure
2240  * @param server handle to the server, NULL if we failed
2241  * @param my_identity ID of this peer, NULL if we failed
2242  */
2243 static void
2244 core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
2245                  const struct GNUNET_PeerIdentity *my_identity)
2246 {
2247   struct OverlayConnectContext *occ = cls;
2248
2249   GNUNET_free_non_null (occ->emsg);
2250   occ->emsg = GNUNET_strdup ("Failed to connect to CORE\n");
2251   if ((NULL == server) || (NULL == my_identity))
2252     goto error_return;
2253   GNUNET_free (occ->emsg);
2254   occ->ch = server;
2255   occ->emsg = NULL;
2256   memcpy (&occ->peer_identity, my_identity,
2257           sizeof (struct GNUNET_PeerIdentity));
2258   occ->p1th =
2259       GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
2260                                 &occ->peer_identity, NULL, NULL, NULL, NULL);
2261   if (NULL == occ->p1th)
2262   {
2263     GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of peers %4s",
2264                     GNUNET_i2s (&occ->peer_identity));
2265     goto error_return;
2266   }
2267   LOG_DEBUG ("Acquiring HELLO of peer %s\n", GNUNET_i2s (&occ->peer_identity));
2268   occ->emsg = GNUNET_strdup ("Timeout while acquiring HELLO message");
2269   occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
2270   return;
2271   
2272  error_return:
2273   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2274   occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2275   return;
2276 }
2277
2278
2279 /**
2280  * Callback to be called when forwarded get peer config operation as part of
2281  * overlay connect is successfull. Connection to Peer 1's core is made and is
2282  * checked for new connection from peer 2
2283  *
2284  * @param cls ForwardedOperationContext
2285  * @param msg the peer create success message
2286  */
2287 static void
2288 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
2289 {
2290   struct OverlayConnectContext *occ = cls;
2291   const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
2292   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2293     {NULL, 0, 0}
2294   };
2295
2296   occ->opc = NULL;
2297   if (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG != ntohs (msg->type))
2298     goto error_return;
2299   cmsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
2300       msg;
2301   memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
2302           sizeof (struct GNUNET_PeerIdentity));
2303   GNUNET_free_non_null (occ->emsg);
2304   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2305   occ->ch =
2306       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2307                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2308                            GNUNET_NO, no_handlers);
2309   if (NULL == occ->ch)
2310     goto error_return;
2311   return;
2312
2313  error_return:
2314   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2315   occ->timeout_task = 
2316       GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2317 }
2318
2319
2320 /**
2321  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
2322  *
2323  * @param cls NULL
2324  * @param client identification of the client
2325  * @param message the actual message
2326  */
2327 static void
2328 handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
2329                         const struct GNUNET_MessageHeader *message)
2330 {
2331   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
2332   struct OverlayConnectContext *occ;
2333   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2334     {NULL, 0, 0}
2335   };
2336   uint32_t p1;
2337   uint32_t p2;
2338
2339   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
2340   p1 = ntohl (msg->peer1);
2341   p2 = ntohl (msg->peer2);
2342   GNUNET_assert (p1 < peer_list_size);
2343   GNUNET_assert (NULL != peer_list[p1]);
2344   GNUNET_assert (p2 < peer_list_size);
2345   GNUNET_assert (NULL != peer_list[p2]);
2346   /* FIXME: Add cases where we have to forward overlay connect message to sub
2347    * controllers */
2348   GNUNET_assert (GNUNET_NO == peer_list[p1]->is_remote);
2349   occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
2350   GNUNET_SERVER_client_keep (client);
2351   occ->client = client;
2352   occ->peer = peer_list[p1];
2353   occ->other_peer = peer_list[p2];
2354   occ->op_id = GNUNET_ntohll (msg->operation_id);
2355   /* Get the identity of the second peer */
2356   if (GNUNET_YES == occ->other_peer->is_remote)
2357   {
2358     struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
2359
2360     cmsg.header.size = 
2361         htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
2362     cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG);
2363     cmsg.peer_id = msg->peer2;
2364     cmsg.operation_id = msg->operation_id;
2365     occ->opc = 
2366         GNUNET_TESTBED_forward_operation_msg_ (occ->other_peer->details.remote.controller,
2367                                                occ->op_id, &cmsg.header,
2368                                                &overlay_connect_get_config,
2369                                                occ);
2370     occ->emsg = 
2371         GNUNET_strdup ("Timeout while getting peer identity of peer B\n");
2372     occ->timeout_task =
2373         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2374                                       (GNUNET_TIME_UNIT_SECONDS, 30),
2375                                       &timeout_overlay_connect, occ);
2376     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2377     return;
2378   }
2379   GNUNET_TESTING_peer_get_identity (occ->other_peer->details.local.peer,
2380                                     &occ->other_peer_identity);
2381   /* Connect to the core of 1st peer and wait for the 2nd peer to connect */
2382   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2383   occ->ch =
2384       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2385                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2386                            GNUNET_NO, no_handlers);
2387   if (NULL == occ->ch)
2388     occ->timeout_task = 
2389         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2390   else
2391     occ->timeout_task =
2392         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2393                                       (GNUNET_TIME_UNIT_SECONDS, 30),
2394                                       &timeout_overlay_connect, occ);
2395   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2396 }
2397
2398
2399 /**
2400  * Function to cleanup RequestOverlayConnectContext and any associated tasks
2401  * with it
2402  *
2403  * @param rocc the RequestOverlayConnectContext
2404  */
2405 static void
2406 cleanup_rocc (struct RequestOverlayConnectContext *rocc)
2407 {
2408   if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
2409     GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
2410   if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
2411     GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
2412   GNUNET_TRANSPORT_disconnect (rocc->th);
2413   GNUNET_free_non_null (rocc->hello);
2414   GNUNET_free (rocc);
2415 }
2416
2417
2418 /**
2419  * Task to timeout rocc and cleanit up
2420  *
2421  * @param cls the RequestOverlayConnectContext
2422  * @param tc the TaskContext from scheduler
2423  */
2424 static void
2425 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2426 {
2427   struct RequestOverlayConnectContext *rocc = cls;
2428   
2429   rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
2430   cleanup_rocc (rocc);
2431 }
2432
2433
2434 /**
2435  * Function called to notify transport users that another
2436  * peer connected to us.
2437  *
2438  * @param cls closure
2439  * @param new_peer the peer that connected
2440  * @param ats performance data
2441  * @param ats_count number of entries in ats (excluding 0-termination)
2442  */
2443 static void 
2444 transport_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2445                           const struct GNUNET_ATS_Information * ats,
2446                           uint32_t ats_count)
2447 {
2448   struct RequestOverlayConnectContext *rocc = cls;
2449
2450   LOG_DEBUG ("Request Overlay connect notify\n");
2451   if (0 != memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)))
2452   {
2453     return;
2454   }
2455   LOG_DEBUG ("Peer %4s connected\n", GNUNET_i2s (&rocc->a_id));
2456   cleanup_rocc (rocc);
2457 }
2458
2459
2460 /**
2461  * Task to offer the HELLO message to the peer and ask it to connect to the peer
2462  * whose identity is in RequestOverlayConnectContext
2463  *
2464  * @param cls the RequestOverlayConnectContext
2465  * @param tc the TaskContext from scheduler
2466  */
2467 static void
2468 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2469 {
2470   struct RequestOverlayConnectContext *rocc = cls;
2471
2472   rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
2473   GNUNET_TRANSPORT_offer_hello (rocc->th, rocc->hello, NULL, NULL);
2474   GNUNET_TRANSPORT_try_connect (rocc->th, &rocc->a_id);
2475   rocc->attempt_connect_task_id = 
2476       GNUNET_SCHEDULER_add_delayed (TRANSPORT_TRY_CONNECT_TIMEOUT,
2477                                     &attempt_connect_task, rocc);
2478 }
2479
2480
2481 /**
2482  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
2483  *
2484  * @param cls NULL
2485  * @param client identification of the client
2486  * @param message the actual message
2487  */
2488 static void
2489 handle_overlay_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
2490                                 const struct GNUNET_MessageHeader *message)
2491 {
2492   const struct GNUNET_TESTBED_RequestConnectMessage *msg;
2493   struct RequestOverlayConnectContext *rocc;
2494   struct Peer *peer;
2495   uint32_t peer_id;
2496   uint16_t msize;
2497   uint16_t hsize;
2498   
2499   msize = ntohs (message->size);
2500   if (sizeof (struct GNUNET_TESTBED_RequestConnectMessage) >= msize)
2501   {
2502     GNUNET_break (0);
2503     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2504     return;
2505   }  
2506   msg = (const struct GNUNET_TESTBED_RequestConnectMessage *) message;
2507   if ((NULL == msg->hello) || 
2508       (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
2509   {
2510     GNUNET_break (0);
2511     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2512     return;
2513   }
2514   hsize = ntohs (msg->hello->size);
2515   if ((sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hsize) != msize)
2516   {
2517     GNUNET_break (0);
2518     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2519     return;
2520   }
2521   peer_id = ntohl (msg->peer);
2522   if ((peer_id >= peer_list_size) || (NULL == (peer = peer_list[peer_id])))
2523   {
2524     GNUNET_break_op (0);
2525     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2526     return;
2527   }
2528   if (GNUNET_NO != peer->is_remote)
2529   {
2530     GNUNET_break (0);
2531     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2532     return;
2533   }
2534   rocc = GNUNET_malloc (sizeof (struct RequestOverlayConnectContext));
2535   rocc->th = GNUNET_TRANSPORT_connect (peer->details.local.cfg, NULL, rocc, 
2536                                        NULL, &transport_connect_notify, NULL);
2537   if (NULL == rocc->th)
2538   {
2539     GNUNET_break (0);
2540     GNUNET_free (rocc);
2541     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2542     return;
2543   }
2544   memcpy (&rocc->a_id, &msg->peer_identity,
2545           sizeof (struct GNUNET_PeerIdentity));
2546   rocc->hello = GNUNET_malloc (hsize);
2547   memcpy (rocc->hello, msg->hello, hsize);
2548   /* GNUNET_TRANSPORT_offer_hello (th, msg->hello, NULL, NULL); */
2549   /* GNUNET_TRANSPORT_try_connect (th, &msg->peer_identity); */
2550   rocc->attempt_connect_task_id =
2551       GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
2552   rocc->timeout_rocc_task_id =
2553       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
2554   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2555 }
2556
2557
2558 /**
2559  * Iterator over hash map entries.
2560  *
2561  * @param cls closure
2562  * @param key current key code
2563  * @param value value in the hash map
2564  * @return GNUNET_YES if we should continue to
2565  *         iterate,
2566  *         GNUNET_NO if not.
2567  */
2568 static int
2569 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2570 {
2571   struct SharedService *ss = value;
2572
2573   GNUNET_assert (GNUNET_YES ==
2574                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2575   GNUNET_free (ss->name);
2576   GNUNET_free (ss);
2577   return GNUNET_YES;
2578 }
2579
2580
2581 /**
2582  * Task to clean up and shutdown nicely
2583  *
2584  * @param cls NULL
2585  * @param tc the TaskContext from scheduler
2586  */
2587 static void
2588 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2589 {
2590   struct LCFContextQueue *lcfq;
2591   uint32_t id;
2592
2593   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2594   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2595   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2596                                                 NULL);
2597   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2598   if (NULL != lcfq_head)
2599   {
2600     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2601     {
2602       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2603       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2604     }
2605     if (NULL != lcfq_head->lcf->rhandle)
2606       GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
2607   }
2608   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2609   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2610   {
2611     GNUNET_free (lcfq->lcf->msg);
2612     GNUNET_free (lcfq->lcf);
2613     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2614     GNUNET_free (lcfq);
2615   }
2616   /* Clear peer list */
2617   for (id = 0; id < peer_list_size; id++)
2618     if (NULL != peer_list[id])
2619     {
2620       if (GNUNET_NO == peer_list[id]->is_remote)
2621       {
2622         if (GNUNET_YES == peer_list[id]->details.local.is_running)
2623           GNUNET_TESTING_peer_stop (peer_list[id]->details.local.peer);
2624         GNUNET_TESTING_peer_destroy (peer_list[id]->details.local.peer);
2625         GNUNET_CONFIGURATION_destroy (peer_list[id]->details.local.cfg);
2626       }
2627       GNUNET_free (peer_list[id]);
2628     }
2629   GNUNET_free_non_null (peer_list);
2630   /* Clear host list */
2631   for (id = 0; id < host_list_size; id++)
2632     if (NULL != host_list[id])
2633       GNUNET_TESTBED_host_destroy (host_list[id]);
2634   GNUNET_free_non_null (host_list);
2635   /* Clear route list */
2636   for (id = 0; id < route_list_size; id++)
2637     if (NULL != route_list[id])
2638       GNUNET_free (route_list[id]);
2639   GNUNET_free_non_null (route_list);
2640   /* Clear slave_list */
2641   for (id = 0; id < slave_list_size; id++)
2642     if (NULL != slave_list[id])
2643     {
2644       if (NULL != slave_list[id]->controller)
2645         GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
2646       if (NULL != slave_list[id]->controller_proc)
2647         GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
2648     }
2649   if (NULL != master_context)
2650   {
2651     GNUNET_free_non_null (master_context->master_ip);
2652     if (NULL != master_context->system)
2653       GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
2654     GNUNET_free (master_context);
2655     master_context = NULL;
2656   }
2657 }
2658
2659
2660 /**
2661  * Callback for client disconnect
2662  *
2663  * @param cls NULL
2664  * @param client the client which has disconnected
2665  */
2666 static void
2667 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
2668 {
2669   if (NULL == master_context)
2670     return;
2671   if (client == master_context->client)
2672   {
2673     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
2674     GNUNET_SERVER_client_drop (client);
2675     /* should not be needed as we're terminated by failure to read
2676      * from stdin, but if stdin fails for some reason, this shouldn't
2677      * hurt for now --- might need to revise this later if we ever
2678      * decide that master connections might be temporarily down
2679      * for some reason */
2680     //GNUNET_SCHEDULER_shutdown ();
2681   }
2682 }
2683
2684
2685 /**
2686  * Testbed setup
2687  *
2688  * @param cls closure
2689  * @param server the initialized server
2690  * @param cfg configuration to use
2691  */
2692 static void
2693 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2694              const struct GNUNET_CONFIGURATION_Handle *cfg)
2695 {
2696   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
2697     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
2698     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
2699     {&handle_configure_shared_service, NULL,
2700      GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
2701     {&handle_link_controllers, NULL,
2702      GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
2703     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER, 0},
2704     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER,
2705      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2706     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STARTPEER,
2707      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2708     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOPPEER,
2709      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2710     {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG,
2711      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2712     {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT,
2713      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2714     {&handle_overlay_request_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT,
2715      0},
2716     {NULL}
2717   };
2718
2719   GNUNET_SERVER_add_handlers (server, message_handlers);
2720   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
2721   ss_map = GNUNET_CONTAINER_multihashmap_create (5);
2722   shutdown_task_id =
2723       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2724                                     &shutdown_task, NULL);
2725   LOG_DEBUG ("Testbed startup complete\n");
2726 }
2727
2728
2729 /**
2730  * The starting point of execution
2731  */
2732 int
2733 main (int argc, char *const *argv)
2734 {
2735   //sleep (15);                 /* Debugging */
2736   return (GNUNET_OK ==
2737           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
2738                               &testbed_run, NULL)) ? 0 : 1;
2739 }
2740
2741 /* end of gnunet-service-testbed.c */