- adopting to new transport API in rocc
[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  * The main context information associated with the client which started us
65  */
66 struct Context
67 {
68   /**
69    * The client handle associated with this context
70    */
71   struct GNUNET_SERVER_Client *client;
72
73   /**
74    * The network address of the master controller
75    */
76   char *master_ip;
77
78   /**
79    * The TESTING system handle for starting peers locally
80    */
81   struct GNUNET_TESTING_System *system;
82   
83   /**
84    * Our host id according to this context
85    */
86   uint32_t host_id;
87 };
88
89
90 /**
91  * The message queue for sending messages to clients
92  */
93 struct MessageQueue
94 {
95   /**
96    * The message to be sent
97    */
98   struct GNUNET_MessageHeader *msg;
99
100   /**
101    * The client to send the message to
102    */
103   struct GNUNET_SERVER_Client *client;
104
105   /**
106    * next pointer for DLL
107    */
108   struct MessageQueue *next;
109
110   /**
111    * prev pointer for DLL
112    */
113   struct MessageQueue *prev;
114 };
115
116
117 /**
118  * The structure for identifying a shared service
119  */
120 struct SharedService
121 {
122   /**
123    * The name of the shared service
124    */
125   char *name;
126
127   /**
128    * Number of shared peers per instance of the shared service
129    */
130   uint32_t num_shared;
131
132   /**
133    * Number of peers currently sharing the service
134    */
135   uint32_t num_sharing;
136 };
137
138
139 /**
140  * A routing entry
141  */
142 struct Route
143 {
144   /**
145    * destination host
146    */
147   uint32_t dest;
148
149   /**
150    * The destination host is reachable thru
151    */
152   uint32_t thru;
153 };
154
155
156 /**
157  * Context information used while linking controllers
158  */
159 struct LinkControllersContext;
160
161
162 /**
163  * A DLL of host registrations to be made
164  */
165 struct HostRegistration
166 {
167   /**
168    * next registration in the DLL
169    */
170   struct HostRegistration *next;
171
172   /**
173    * previous registration in the DLL
174    */
175   struct HostRegistration *prev;
176
177   /**
178    * The callback to call after this registration's status is available
179    */
180   GNUNET_TESTBED_HostRegistrationCompletion cb;
181
182   /**
183    * The closure for the above callback
184    */
185   void *cb_cls;
186
187   /**
188    * The host that has to be registered
189    */
190   struct GNUNET_TESTBED_Host *host;
191 };
192
193
194 /**
195  * This context information will be created for each host that is registered at
196  * slave controllers during overlay connects.
197  */
198 struct RegisteredHostContext
199 {
200   /**
201    * The host which is being registered
202    */
203   struct GNUNET_TESTBED_Host *reg_host;
204
205   /**
206    * The host of the controller which has to connect to the above rhost
207    */
208   struct GNUNET_TESTBED_Host *host;
209
210   /**
211    * The gateway to which this operation is forwarded to
212    */
213   struct Slave *gateway;
214
215   /**
216    * The gateway through which peer2's controller can be reached
217    */
218   struct Slave *gateway2;
219
220   /**
221    * Handle for sub-operations
222    */
223   struct GNUNET_TESTBED_Operation *sub_op;
224
225   /**
226    * The client which initiated the link controller operation
227    */
228   struct GNUNET_SERVER_Client *client;
229
230   /**
231    * Head of the ForwardedOverlayConnectContext DLL
232    */
233   struct ForwardedOverlayConnectContext *focc_dll_head;
234
235   /**
236    * Tail of the ForwardedOverlayConnectContext DLL
237    */
238   struct ForwardedOverlayConnectContext *focc_dll_tail;
239   
240   /**
241    * Enumeration of states for this context
242    */
243   enum RHCState {
244
245     /**
246      * The initial state
247      */
248     RHC_INIT = 0,
249
250     /**
251      * State where we attempt to get peer2's controller configuration
252      */
253     RHC_GET_CFG,
254
255     /**
256      * State where we attempt to link the controller of peer 1 to the controller
257      * of peer2
258      */
259     RHC_LINK,
260
261     /**
262      * State where we attempt to do the overlay connection again
263      */
264     RHC_OL_CONNECT
265     
266   } state;
267
268 };
269
270
271 /**
272  * Structure representing a connected(directly-linked) controller
273  */
274 struct Slave
275 {
276   /**
277    * The controller process handle if we had started the controller
278    */
279   struct GNUNET_TESTBED_ControllerProc *controller_proc;
280
281   /**
282    * The controller handle
283    */
284   struct GNUNET_TESTBED_Controller *controller;
285
286   /**
287    * The configuration of the slave. Cannot be NULL
288    */
289   struct GNUNET_CONFIGURATION_Handle *cfg;
290
291   /**
292    * handle to lcc which is associated with this slave startup. Should be set to
293    * NULL when the slave has successfully started up
294    */
295   struct LinkControllersContext *lcc;
296
297   /**
298    * Head of the host registration DLL
299    */
300   struct HostRegistration *hr_dll_head;
301
302   /**
303    * Tail of the host registration DLL
304    */
305   struct HostRegistration *hr_dll_tail;
306
307   /**
308    * The current host registration handle
309    */
310   struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
311
312   /**
313    * Hashmap to hold Registered host contexts
314    */
315   struct GNUNET_CONTAINER_MultiHashMap *reghost_map;
316
317   /**
318    * The id of the host this controller is running on
319    */
320   uint32_t host_id;
321
322 };
323
324
325 /**
326  * States of LCFContext
327  */
328 enum LCFContextState
329 {
330   /**
331    * The Context has been initialized; Nothing has been done on it
332    */
333   INIT,
334
335   /**
336    * Delegated host has been registered at the forwarding controller
337    */
338   DELEGATED_HOST_REGISTERED,
339   
340   /**
341    * The slave host has been registred at the forwarding controller
342    */
343   SLAVE_HOST_REGISTERED,
344   
345   /**
346    * The context has been finished (may have error)
347    */
348   FINISHED
349 };
350
351
352 /**
353  * Link controllers request forwarding context
354  */
355 struct LCFContext
356 {
357   /**
358    * The gateway which will pass the link message to delegated host
359    */
360   struct Slave *gateway;
361
362   /**
363    * The controller link message that has to be forwarded to
364    */
365   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
366
367   /**
368    * The client which has asked to perform this operation
369    */
370   struct GNUNET_SERVER_Client *client;
371
372   /**
373    * Handle for operations which are forwarded while linking controllers
374    */
375   struct ForwardedOperationContext *fopc;
376
377   /**
378    * The id of the operation which created this context
379    */
380   uint64_t operation_id;
381
382   /**
383    * The state of this context
384    */
385   enum LCFContextState state;
386
387   /**
388    * The delegated host
389    */
390   uint32_t delegated_host_id;
391
392   /**
393    * The slave host
394    */
395   uint32_t slave_host_id;
396
397 };
398
399
400 /**
401  * Structure of a queue entry in LCFContext request queue
402  */
403 struct LCFContextQueue
404 {
405   /**
406    * The LCFContext
407    */
408   struct LCFContext *lcf;
409
410   /**
411    * Head prt for DLL
412    */
413   struct LCFContextQueue *next;
414
415   /**
416    * Tail ptr for DLL
417    */
418   struct LCFContextQueue *prev;
419 };
420
421
422 /**
423  * A peer
424  */
425 struct Peer
426 {
427   
428   union
429   {
430     struct
431     {
432       /**
433        * The peer handle from testing API
434        */
435       struct GNUNET_TESTING_Peer *peer;
436
437       /**
438        * The modified (by GNUNET_TESTING_peer_configure) configuration this
439        * peer is configured with
440        */
441       struct GNUNET_CONFIGURATION_Handle *cfg;
442       
443       /**
444        * Is the peer running
445        */
446       int is_running;
447
448     } local;
449
450     struct
451     {
452       /**
453        * The slave this peer is started through
454        */
455       struct Slave *slave;
456
457       /**
458        * The id of the remote host this peer is running on
459        */
460       uint32_t remote_host_id;
461
462     } remote;
463
464   } details;
465
466   /**
467    * Is this peer locally created?
468    */
469   int is_remote;
470
471   /**
472    * Our local reference id for this peer
473    */
474   uint32_t id;
475
476   /**
477    * References to peers are using in forwarded overlay contexts and remote
478    * overlay connect contexts. A peer can only be destroyed after all such
479    * contexts are destroyed. For this, we maintain a reference counter. When we
480    * use a peer in any such context, we increment this counter. We decrement it
481    * when we are destroying these contexts
482    */
483   uint32_t reference_cnt;
484
485   /**
486    * While destroying a peer, due to the fact that there could be references to
487    * this peer, we delay the peer destroy to a further time. We do this by using
488    * this flag to destroy the peer while destroying a context in which this peer
489    * has been used. When the flag is set to 1 and reference_cnt = 0 we destroy
490    * the peer
491    */
492   uint32_t destroy_flag;
493
494 };
495
496
497 /**
498  * Context information for connecting 2 peers in overlay
499  */
500 struct OverlayConnectContext
501 {
502   /**
503    * The next pointer for maintaining a DLL
504    */
505   struct OverlayConnectContext *next;
506
507   /**
508    * The prev pointer for maintaining a DLL
509    */
510   struct OverlayConnectContext *prev;
511   
512   /**
513    * The client which has requested for overlay connection
514    */
515   struct GNUNET_SERVER_Client *client;
516
517   /**
518    * the peer which has to connect to the other peer
519    */
520   struct Peer *peer;
521
522   /**
523    * Transport handle of the first peer to get its HELLO
524    */
525   struct GNUNET_TRANSPORT_Handle *p1th;
526
527   /**
528    * Transport handle of other peer to offer first peer's HELLO
529    */
530   struct GNUNET_TRANSPORT_Handle *p2th;
531
532   /**
533    * Core handles of the first peer; used to notify when second peer connects to it
534    */
535   struct GNUNET_CORE_Handle *ch;
536
537   /**
538    * HELLO of the other peer
539    */
540   struct GNUNET_MessageHeader *hello;
541
542   /**
543    * Get hello handle to acquire HELLO of first peer
544    */
545   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
546
547   /**
548    * The handle for offering HELLO
549    */
550   struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
551
552   /**
553    * The handle for transport try connect
554    */
555   struct GNUNET_TRANSPORT_TryConnectHandle *tch;
556
557   /**
558    * The error message we send if this overlay connect operation has timed out
559    */
560   char *emsg;
561
562   /**
563    * Operation context for suboperations
564    */
565   struct OperationContext *opc;
566
567   /**
568    * Controller of peer 2; NULL if the peer is local
569    */
570   struct GNUNET_TESTBED_Controller *peer2_controller;
571
572   /**
573    * The peer identity of the first peer
574    */
575   struct GNUNET_PeerIdentity peer_identity;
576
577   /**
578    * The peer identity of the other peer
579    */
580   struct GNUNET_PeerIdentity other_peer_identity;
581
582   /**
583    * The id of the operation responsible for creating this context
584    */
585   uint64_t op_id;
586
587   /**
588    * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
589    * connect to peer 2
590    */
591   GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
592
593   /**
594    * The id of the overlay connect timeout task
595    */
596   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
597
598   /**
599    * The id of the cleanup task
600    */
601   GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
602
603   /**
604    * The id of peer A
605    */
606   uint32_t peer_id;
607
608   /**
609    * The id of peer B
610    */
611   uint32_t other_peer_id;
612
613 };
614
615
616 /**
617  * Context information for RequestOverlayConnect
618  * operations. RequestOverlayConnect is used when peers A, B reside on different
619  * hosts and the host controller for peer B is asked by the host controller of
620  * peer A to make peer B connect to peer A
621  */
622 struct RequestOverlayConnectContext
623 {
624   /**
625    * the next pointer for DLL
626    */
627   struct RequestOverlayConnectContext *next;
628
629   /**
630    * the prev pointer for DLL
631    */
632   struct RequestOverlayConnectContext *prev;
633
634   /**
635    * The transport handle of peer B
636    */
637   struct GNUNET_TRANSPORT_Handle *th;
638   
639   /**
640    * Peer A's HELLO
641    */
642   struct GNUNET_MessageHeader *hello;
643
644   /**
645    * The handle for offering HELLO
646    */
647   struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
648
649   /**
650    * The handle for transport try connect
651    */
652   struct GNUNET_TRANSPORT_TryConnectHandle *tch;
653
654   /**
655    * The peer identity of peer A
656    */
657   struct GNUNET_PeerIdentity a_id;
658
659   /**
660    * Task for offering HELLO of A to B and doing try_connect
661    */
662   GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
663   
664   /**
665    * Task to timeout RequestOverlayConnect
666    */
667   GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
668   
669 };
670
671
672 /**
673  * Context information for operations forwarded to subcontrollers
674  */
675 struct ForwardedOperationContext
676 {
677   /**
678    * The next pointer for DLL
679    */
680   struct ForwardedOperationContext *next;
681
682   /**
683    * The prev pointer for DLL
684    */
685   struct ForwardedOperationContext *prev;
686   
687   /**
688    * The generated operation context
689    */
690   struct OperationContext *opc;
691
692   /**
693    * The client to which we have to reply
694    */
695   struct GNUNET_SERVER_Client *client;
696
697   /**
698    * Closure pointer
699    */
700   void *cls;
701
702   /**
703    * Task ID for the timeout task
704    */
705   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
706
707   /**
708    * The id of the operation that has been forwarded
709    */
710   uint64_t operation_id;
711
712   /**
713    * The type of the operation which is forwarded
714    */
715   enum OperationType type;
716
717 };
718
719
720 /**
721  * Context information used while linking controllers
722  */
723 struct LinkControllersContext
724 {
725   /**
726    * The client which initiated the link controller operation
727    */
728   struct GNUNET_SERVER_Client *client;
729
730   /**
731    * The ID of the operation
732    */
733   uint64_t operation_id;
734
735 };
736
737
738 /**
739  * Context information to used during operations which forward the overlay
740  * connect message
741  */
742 struct ForwardedOverlayConnectContext
743 {
744   /**
745    * next ForwardedOverlayConnectContext in the DLL
746    */
747   struct ForwardedOverlayConnectContext *next;
748
749   /**
750    * previous ForwardedOverlayConnectContext in the DLL
751    */
752   struct ForwardedOverlayConnectContext *prev;
753
754   /**
755    * A copy of the original overlay connect message
756    */
757   struct GNUNET_MessageHeader *orig_msg;
758
759   /**
760    * The id of the operation which created this context information
761    */
762   uint64_t operation_id;
763
764   /**
765    * the id of peer 1
766    */
767   uint32_t peer1;
768   
769   /**
770    * The id of peer 2
771    */
772   uint32_t peer2;
773   
774   /**
775    * Id of the host where peer2 is running
776    */
777   uint32_t peer2_host_id;
778 };
779
780
781
782 /**
783  * The master context; generated with the first INIT message
784  */
785 static struct Context *master_context;
786
787 /**
788  * Our hostname; we give this to all the peers we start
789  */
790 static char *hostname;
791
792
793 /***********/
794 /* Handles */
795 /***********/
796
797 /**
798  * Our configuration
799  */
800 static struct GNUNET_CONFIGURATION_Handle *our_config;
801
802 /**
803  * Current Transmit Handle; NULL if no notify transmit exists currently
804  */
805 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
806
807 /****************/
808 /* Lists & Maps */
809 /****************/
810
811 /**
812  * The head for the LCF queue
813  */
814 static struct LCFContextQueue *lcfq_head;
815
816 /**
817  * The tail for the LCF queue
818  */
819 static struct LCFContextQueue *lcfq_tail;
820
821 /**
822  * The message queue head
823  */
824 static struct MessageQueue *mq_head;
825
826 /**
827  * The message queue tail
828  */
829 static struct MessageQueue *mq_tail;
830
831 /**
832  * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
833  */
834 static struct OverlayConnectContext *occq_head;
835
836 /**
837  * DLL tail for OverlayConnectContext DLL
838  */
839 static struct OverlayConnectContext *occq_tail;
840
841 /**
842  * DLL head for RequectOverlayConnectContext DLL - to be used to clean up during
843  * shutdown
844  */
845 static struct RequestOverlayConnectContext *roccq_head;
846
847 /**
848  * DLL tail for RequectOverlayConnectContext DLL
849  */
850 static struct RequestOverlayConnectContext *roccq_tail;
851
852 /**
853  * DLL head for forwarded operation contexts
854  */
855 static struct ForwardedOperationContext *fopcq_head;
856
857 /**
858  * DLL tail for forwarded operation contexts
859  */
860 static struct ForwardedOperationContext *fopcq_tail;
861
862 /**
863  * Array of hosts
864  */
865 static struct GNUNET_TESTBED_Host **host_list;
866
867 /**
868  * A list of routes
869  */
870 static struct Route **route_list;
871
872 /**
873  * A list of directly linked neighbours
874  */
875 static struct Slave **slave_list;
876
877 /**
878  * A list of peers we know about
879  */
880 static struct Peer **peer_list;
881
882 /**
883  * The hashmap of shared services
884  */
885 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
886
887 /**
888  * The event mask for the events we listen from sub-controllers
889  */
890 static uint64_t event_mask;
891
892 /**
893  * The size of the host list
894  */
895 static uint32_t host_list_size;
896
897 /**
898  * The size of the route list
899  */
900 static uint32_t route_list_size;
901
902 /**
903  * The size of directly linked neighbours list
904  */
905 static uint32_t slave_list_size;
906
907 /**
908  * The size of the peer list
909  */
910 static uint32_t peer_list_size;
911
912 /*********/
913 /* Tasks */
914 /*********/
915
916 /**
917  * The lcf_task handle
918  */
919 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
920
921 /**
922  * The shutdown task handle
923  */
924 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
925
926
927 /**
928  * Function called to notify a client about the connection begin ready to queue
929  * more data.  "buf" will be NULL and "size" zero if the connection was closed
930  * for writing in the meantime.
931  *
932  * @param cls NULL
933  * @param size number of bytes available in buf
934  * @param buf where the callee should write the message
935  * @return number of bytes written to buf
936  */
937 static size_t
938 transmit_ready_notify (void *cls, size_t size, void *buf)
939 {
940   struct MessageQueue *mq_entry;
941
942   transmit_handle = NULL;
943   mq_entry = mq_head;
944   GNUNET_assert (NULL != mq_entry);
945   if (0 == size)
946     return 0;
947   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
948   size = ntohs (mq_entry->msg->size);
949   memcpy (buf, mq_entry->msg, size);
950   GNUNET_free (mq_entry->msg);
951   GNUNET_SERVER_client_drop (mq_entry->client);
952   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
953   GNUNET_free (mq_entry);
954   mq_entry = mq_head;
955   if (NULL != mq_entry)
956     transmit_handle =
957         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
958                                              ntohs (mq_entry->msg->size),
959                                              GNUNET_TIME_UNIT_FOREVER_REL,
960                                              &transmit_ready_notify, NULL);
961   return size;
962 }
963
964
965 /**
966  * Queues a message in send queue for sending to the service
967  *
968  * @param client the client to whom the queued message has to be sent
969  * @param msg the message to queue
970  */
971 static void
972 queue_message (struct GNUNET_SERVER_Client *client,
973                struct GNUNET_MessageHeader *msg)
974 {
975   struct MessageQueue *mq_entry;
976   uint16_t type;
977   uint16_t size;
978
979   type = ntohs (msg->type);
980   size = ntohs (msg->size);
981   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
982                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
983   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
984   mq_entry->msg = msg;
985   mq_entry->client = client;
986   GNUNET_SERVER_client_keep (client);
987   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
988              ntohs (msg->size));
989   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
990   if (NULL == transmit_handle)
991     transmit_handle =
992         GNUNET_SERVER_notify_transmit_ready (client, size,
993                                              GNUNET_TIME_UNIT_FOREVER_REL,
994                                              &transmit_ready_notify, NULL);
995 }
996
997
998 /**
999  * Similar to GNUNET_realloc; however clears tail part of newly allocated memory
1000  *
1001  * @param ptr the memory block to realloc
1002  * @param size the size of ptr
1003  * @param new_size the size to which ptr has to be realloc'ed
1004  * @return the newly reallocated memory block
1005  */
1006 static void *
1007 TESTBED_realloc (void *ptr, size_t size, size_t new_size)
1008 {
1009   ptr = GNUNET_realloc (ptr, new_size);
1010   if (new_size > size)
1011     (void) memset (ptr + size, 0, new_size - size);
1012   return ptr;
1013 }
1014
1015
1016 /**
1017  * Function to add a host to the current list of known hosts
1018  *
1019  * @param host the host to add
1020  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
1021  *           already in use
1022  */
1023 static int
1024 host_list_add (struct GNUNET_TESTBED_Host *host)
1025 {
1026   uint32_t host_id;
1027   uint32_t orig_size;
1028
1029   host_id = GNUNET_TESTBED_host_get_id_ (host);
1030   orig_size = host_list_size;  
1031   if (host_list_size <= host_id)
1032   {
1033     while (host_list_size <= host_id)
1034       host_list_size += LIST_GROW_STEP;
1035     host_list =
1036         TESTBED_realloc (host_list,
1037                          sizeof (struct GNUNET_TESTBED_Host *) * orig_size,
1038                          sizeof (struct GNUNET_TESTBED_Host *)
1039                          * host_list_size);
1040   }
1041   if (NULL != host_list[host_id])
1042   {
1043     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
1044     return GNUNET_SYSERR;
1045   }
1046   host_list[host_id] = host;
1047   return GNUNET_OK;
1048 }
1049
1050
1051 /**
1052  * Adds a route to the route list
1053  *
1054  * @param route the route to add
1055  */
1056 static void
1057 route_list_add (struct Route *route)
1058 {
1059   uint32_t orig_size;
1060
1061   orig_size = route_list_size;  
1062   if (route->dest >= route_list_size)
1063   {
1064     while (route->dest >= route_list_size)
1065       route_list_size += LIST_GROW_STEP;
1066     route_list =
1067         TESTBED_realloc (route_list,
1068                          sizeof (struct Route *) * orig_size,
1069                          sizeof (struct Route *) * route_list_size);
1070   }
1071   GNUNET_assert (NULL == route_list[route->dest]);
1072   route_list[route->dest] = route;
1073 }
1074
1075
1076 /**
1077  * Adds a slave to the slave array
1078  *
1079  * @param slave the slave controller to add
1080  */
1081 static void
1082 slave_list_add (struct Slave *slave)
1083 {
1084   uint32_t orig_size;
1085
1086   orig_size = slave_list_size;  
1087   if (slave->host_id >= slave_list_size)
1088   {
1089     while (slave->host_id >= slave_list_size)
1090       slave_list_size += LIST_GROW_STEP;
1091     slave_list =
1092         TESTBED_realloc (slave_list, sizeof (struct Slave *) * orig_size,
1093                          sizeof (struct Slave *) * slave_list_size);
1094   }
1095   GNUNET_assert (NULL == slave_list[slave->host_id]);
1096   slave_list[slave->host_id] = slave;
1097 }
1098
1099
1100 /**
1101  * Adds a peer to the peer array
1102  *
1103  * @param peer the peer to add
1104  */
1105 static void
1106 peer_list_add (struct Peer *peer)
1107 {
1108   uint32_t orig_size;
1109
1110   orig_size = peer_list_size;
1111   if (peer->id >= peer_list_size)
1112   {
1113     while (peer->id >= peer_list_size)
1114       peer_list_size += LIST_GROW_STEP;
1115     peer_list =
1116         TESTBED_realloc (peer_list, sizeof (struct Peer *) * orig_size,
1117                          sizeof (struct Peer *) * peer_list_size);
1118   }  
1119   GNUNET_assert (NULL == peer_list[peer->id]);
1120   peer_list[peer->id] = peer;
1121 }
1122
1123
1124 /**
1125  * Removes a the give peer from the peer array
1126  *
1127  * @param peer the peer to be removed
1128  */
1129 static void
1130 peer_list_remove (struct Peer *peer)
1131 {
1132   uint32_t id;
1133   uint32_t orig_size;
1134
1135   peer_list[peer->id] = NULL;
1136   orig_size = peer_list_size;
1137   while (peer_list_size >= LIST_GROW_STEP)
1138   {
1139     for (id = peer_list_size - 1;
1140          (id >= peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--)
1141       if (NULL != peer_list[id])
1142         break;
1143     if (id != ((peer_list_size - LIST_GROW_STEP) - 1))
1144       break;
1145     peer_list_size -= LIST_GROW_STEP;
1146   }
1147   if (orig_size == peer_list_size)
1148     return;
1149   peer_list =
1150       GNUNET_realloc (peer_list, sizeof (struct Peer *) * peer_list_size);
1151 }
1152
1153
1154 /**
1155  * Finds the route with directly connected host as destination through which
1156  * the destination host can be reached
1157  *
1158  * @param host_id the id of the destination host
1159  * @return the route with directly connected destination host; NULL if no route
1160  *           is found
1161  */
1162 static struct Route *
1163 find_dest_route (uint32_t host_id)
1164 {
1165   struct Route *route;
1166
1167   if (route_list_size <= host_id)
1168     return NULL;
1169   while (NULL != (route = route_list[host_id]))
1170   {
1171     if (route->thru == master_context->host_id)
1172       break;
1173     host_id = route->thru;
1174   }
1175   return route;
1176 }
1177
1178
1179 /**
1180  * Routes message to a host given its host_id
1181  *
1182  * @param host_id the id of the destination host
1183  * @param msg the message to be routed
1184  */
1185 static void
1186 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
1187 {
1188   GNUNET_break (0);
1189 }
1190
1191
1192 /**
1193  * Send operation failure message to client
1194  *
1195  * @param client the client to which the failure message has to be sent to
1196  * @param operation_id the id of the failed operation
1197  * @param emsg the error message; can be NULL
1198  */
1199 static void
1200 send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
1201                          uint64_t operation_id, const char *emsg)
1202 {
1203   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
1204   uint16_t msize;
1205   uint16_t emsg_len;
1206
1207   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
1208   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
1209   msize += emsg_len;
1210   msg = GNUNET_malloc (msize);
1211   msg->header.size = htons (msize);
1212   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT);
1213   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
1214   msg->operation_id = GNUNET_htonll (operation_id);
1215   if (0 != emsg_len)
1216     memcpy (&msg[1], emsg, emsg_len);
1217   queue_message (client, &msg->header);
1218 }
1219
1220
1221 /**
1222  * Function to send generic operation success message to given client
1223  *
1224  * @param client the client to send the message to
1225  * @param operation_id the id of the operation which was successful
1226  */
1227 static void
1228 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
1229                             uint64_t operation_id)
1230 {
1231   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
1232   uint16_t msize;
1233
1234   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
1235   msg = GNUNET_malloc (msize);
1236   msg->header.size = htons (msize);
1237   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS);
1238   msg->operation_id = GNUNET_htonll (operation_id);
1239   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
1240   queue_message (client, &msg->header);
1241 }
1242
1243
1244 /**
1245  * Callback which will be called to after a host registration succeeded or failed
1246  *
1247  * @param cls the handle to the slave at which the registration is completed
1248  * @param emsg the error message; NULL if host registration is successful
1249  */
1250 static void 
1251 hr_completion (void *cls, const char *emsg);
1252
1253
1254 /**
1255  * Attempts to register the next host in the host registration queue
1256  *
1257  * @param slave the slave controller whose host registration queue is checked
1258  *          for host registrations
1259  */
1260 static void
1261 register_next_host (struct Slave *slave)
1262 {
1263   struct HostRegistration *hr;
1264   
1265   hr = slave->hr_dll_head;
1266   GNUNET_assert (NULL != hr);
1267   GNUNET_assert (NULL == slave->rhandle);
1268   LOG (GNUNET_ERROR_TYPE_DEBUG,
1269        "Registering host %u at %u\n",
1270        GNUNET_TESTBED_host_get_id_ (hr->host),
1271        GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1272   slave->rhandle = GNUNET_TESTBED_register_host (slave->controller,
1273                                                  hr->host,
1274                                                  hr_completion,
1275                                                  slave);
1276 }
1277
1278
1279 /**
1280  * Callback which will be called to after a host registration succeeded or failed
1281  *
1282  * @param cls the handle to the slave at which the registration is completed
1283  * @param emsg the error message; NULL if host registration is successful
1284  */
1285 static void 
1286 hr_completion (void *cls, const char *emsg)
1287 {
1288   struct Slave *slave = cls;
1289   struct HostRegistration *hr;
1290
1291   slave->rhandle = NULL;
1292   hr = slave->hr_dll_head;
1293   GNUNET_assert (NULL != hr);
1294   LOG (GNUNET_ERROR_TYPE_DEBUG,
1295        "Registering host %u at %u successful\n",
1296        GNUNET_TESTBED_host_get_id_ (hr->host),
1297        GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1298   GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head,
1299                                slave->hr_dll_tail,
1300                                hr);
1301   if (NULL != hr->cb)
1302     hr->cb (hr->cb_cls, emsg);
1303   GNUNET_free (hr);
1304   if (NULL != slave->hr_dll_head)
1305     register_next_host (slave);
1306 }
1307
1308
1309 /**
1310  * Adds a host registration's request to a slave's registration queue
1311  *
1312  * @param slave the slave controller at which the given host has to be
1313  *          registered 
1314  * @param cb the host registration completion callback
1315  * @param cb_cls the closure for the host registration completion callback
1316  * @param host the host which has to be registered
1317  */
1318 static void
1319 queue_host_registration (struct Slave *slave,
1320                          GNUNET_TESTBED_HostRegistrationCompletion cb,
1321                          void *cb_cls,
1322                          struct GNUNET_TESTBED_Host *host)
1323 {
1324   struct HostRegistration *hr;
1325   int call_register;
1326
1327   LOG (GNUNET_ERROR_TYPE_DEBUG,
1328        "Queueing host registration for host %u at %u\n",
1329        GNUNET_TESTBED_host_get_id_ (host),
1330        GNUNET_TESTBED_host_get_id_ (host_list[slave->host_id]));
1331   hr = GNUNET_malloc (sizeof (struct HostRegistration));
1332   hr->cb = cb;
1333   hr->cb_cls = cb_cls;
1334   hr->host = host;
1335   call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
1336   GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head,
1337                                     slave->hr_dll_tail,
1338                                     hr);
1339   if (GNUNET_YES == call_register)
1340     register_next_host (slave);
1341 }
1342
1343
1344 /**
1345  * The  Link Controller forwarding task
1346  *
1347  * @param cls the LCFContext
1348  * @param tc the Task context from scheduler
1349  */
1350 static void
1351 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1352
1353
1354 /**
1355  * Completion callback for host registrations while forwarding Link Controller messages
1356  *
1357  * @param cls the LCFContext
1358  * @param emsg the error message; NULL if host registration is successful
1359  */
1360 static void
1361 lcf_proc_cc (void *cls, const char *emsg)
1362 {
1363   struct LCFContext *lcf = cls;
1364
1365   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1366   switch (lcf->state)
1367   {
1368   case INIT:
1369     if (NULL != emsg)
1370       goto registration_error;
1371     lcf->state = DELEGATED_HOST_REGISTERED;
1372     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1373     break;
1374   case DELEGATED_HOST_REGISTERED:
1375     if (NULL != emsg)
1376       goto registration_error;
1377     lcf->state = SLAVE_HOST_REGISTERED;
1378     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1379     break;
1380   default:
1381     GNUNET_assert (0);          /* Shouldn't reach here */
1382   }
1383   return;
1384
1385  registration_error:
1386   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
1387        emsg);
1388   lcf->state = FINISHED;
1389   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1390 }
1391
1392
1393 /**
1394  * Callback to relay the reply msg of a forwarded operation back to the client
1395  *
1396  * @param cls ForwardedOperationContext
1397  * @param msg the message to relay
1398  */
1399 static void
1400 forwarded_operation_reply_relay (void *cls,
1401                                  const struct GNUNET_MessageHeader *msg)
1402 {
1403   struct ForwardedOperationContext *fopc = cls;
1404   struct GNUNET_MessageHeader *dup_msg;
1405   uint16_t msize;
1406
1407   msize = ntohs (msg->size);
1408   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
1409              msize);
1410   dup_msg = GNUNET_copy_message (msg);
1411   queue_message (fopc->client, dup_msg);
1412   GNUNET_SERVER_client_drop (fopc->client);
1413   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
1414   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
1415   GNUNET_free (fopc);
1416 }
1417
1418
1419 /**
1420  * Task to free resources when forwarded operation has been timedout
1421  *
1422  * @param cls the ForwardedOperationContext
1423  * @param tc the task context from scheduler
1424  */
1425 static void
1426 forwarded_operation_timeout (void *cls,
1427                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1428 {
1429   struct ForwardedOperationContext *fopc = cls;
1430
1431   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1432   LOG (GNUNET_ERROR_TYPE_WARNING, "A forwarded operation has timed out\n");
1433   send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
1434   GNUNET_SERVER_client_drop (fopc->client);
1435   GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
1436   GNUNET_free (fopc);
1437 }
1438
1439
1440 /**
1441  * The  Link Controller forwarding task
1442  *
1443  * @param cls the LCFContext
1444  * @param tc the Task context from scheduler
1445  */
1446 static void
1447 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1448
1449
1450 /**
1451  * Callback to be called when forwarded link controllers operation is
1452  * successfull. We have to relay the reply msg back to the client
1453  *
1454  * @param cls the LCFContext
1455  * @param msg the message to relay
1456  */
1457 static void
1458 lcf_forwarded_operation_reply_relay (void *cls,
1459                                      const struct GNUNET_MessageHeader *msg)
1460 {
1461   struct LCFContext *lcf = cls;
1462
1463   GNUNET_assert (NULL != lcf->fopc);
1464   forwarded_operation_reply_relay (lcf->fopc, msg);
1465   lcf->fopc = NULL;
1466   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1467   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1468 }
1469
1470
1471 /**
1472  * Task to free resources when forwarded link controllers has been timedout
1473  *
1474  * @param cls the LCFContext
1475  * @param tc the task context from scheduler
1476  */
1477 static void
1478 lcf_forwarded_operation_timeout (void *cls,
1479                                  const struct GNUNET_SCHEDULER_TaskContext *tc)
1480 {
1481   struct LCFContext *lcf = cls;
1482
1483   GNUNET_assert (NULL != lcf->fopc);
1484   lcf->fopc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1485   forwarded_operation_timeout (lcf->fopc, tc);
1486   lcf->fopc = NULL;
1487   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1488   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1489 }
1490
1491
1492 /**
1493  * The  Link Controller forwarding task
1494  *
1495  * @param cls the LCFContext
1496  * @param tc the Task context from scheduler
1497  */
1498 static void
1499 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1500 {
1501   struct LCFContext *lcf = cls;
1502   struct LCFContextQueue *lcfq;
1503
1504   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1505   switch (lcf->state)
1506   {
1507   case INIT:
1508     if (GNUNET_NO ==
1509         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
1510                                             lcf->gateway->controller))
1511     {
1512       queue_host_registration (lcf->gateway,
1513                                lcf_proc_cc, lcf,
1514                                host_list[lcf->delegated_host_id]);
1515     }
1516     else
1517     {
1518       lcf->state = DELEGATED_HOST_REGISTERED;
1519       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1520     }
1521     break;
1522   case DELEGATED_HOST_REGISTERED:
1523     if (GNUNET_NO ==
1524         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
1525                                             lcf->gateway->controller))
1526     {
1527       queue_host_registration (lcf->gateway,
1528                                lcf_proc_cc, lcf,
1529                                host_list[lcf->slave_host_id]);
1530     }
1531     else
1532     {
1533       lcf->state = SLAVE_HOST_REGISTERED;
1534       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1535     }
1536     break;
1537   case SLAVE_HOST_REGISTERED:
1538     lcf->fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1539     lcf->fopc->client = lcf->client;
1540     lcf->fopc->operation_id = lcf->operation_id;
1541     lcf->fopc->type = OP_LINK_CONTROLLERS;
1542     lcf->fopc->opc =
1543         GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
1544                                                lcf->operation_id,
1545                                                &lcf->msg->header,
1546                                                &lcf_forwarded_operation_reply_relay,
1547                                                lcf);
1548     lcf->fopc->timeout_task =
1549         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &lcf_forwarded_operation_timeout,
1550                                       lcf);
1551     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, lcf->fopc);
1552     lcf->state = FINISHED;
1553     break;
1554   case FINISHED:
1555     lcfq = lcfq_head;
1556     GNUNET_assert (lcfq->lcf == lcf);
1557     GNUNET_free (lcf->msg);
1558     GNUNET_free (lcf);
1559     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1560     GNUNET_free (lcfq);
1561     if (NULL != lcfq_head)
1562       lcf_proc_task_id =
1563           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
1564   }
1565 }
1566
1567
1568 /**
1569  * Cleans up ForwardedOverlayConnectContext
1570  *
1571  * @param focc the ForwardedOverlayConnectContext to cleanup
1572  */
1573 static void
1574 cleanup_focc (struct ForwardedOverlayConnectContext *focc)
1575 {
1576   GNUNET_free_non_null (focc->orig_msg);
1577   GNUNET_free (focc);
1578 }
1579
1580
1581 /**
1582  * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
1583  *
1584  * @param rhc the RegisteredHostContext
1585  */
1586 static void
1587 process_next_focc (struct RegisteredHostContext *rhc);
1588
1589
1590 /**
1591  * Timeout task for cancelling a forwarded overlay connect connect
1592  *
1593  * @param cls the ForwardedOverlayConnectContext
1594  * @param tc the task context from the scheduler
1595  */
1596 static void
1597 forwarded_overlay_connect_timeout (void *cls,
1598                                    const struct GNUNET_SCHEDULER_TaskContext
1599                                    *tc)
1600 {
1601   struct ForwardedOperationContext *fopc = cls;
1602   struct RegisteredHostContext *rhc;
1603   struct ForwardedOverlayConnectContext *focc;
1604   
1605   rhc = fopc->cls;
1606   focc = rhc->focc_dll_head;
1607   GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
1608   cleanup_focc (focc);
1609   LOG_DEBUG ("Overlay linking between peers %u and %u failed\n",
1610              focc->peer1, focc->peer2);
1611   forwarded_operation_timeout (cls, tc);
1612   if (NULL != rhc->focc_dll_head)
1613     process_next_focc (rhc);
1614 }
1615
1616
1617 /**
1618  * Callback to be called when forwarded overlay connection operation has a reply
1619  * from the sub-controller successfull. We have to relay the reply msg back to
1620  * the client
1621  *
1622  * @param cls ForwardedOperationContext
1623  * @param msg the peer create success message
1624  */
1625 static void
1626 forwarded_overlay_connect_listener (void *cls,
1627                                     const struct GNUNET_MessageHeader *msg)
1628 {
1629   struct ForwardedOperationContext *fopc = cls;
1630   struct RegisteredHostContext *rhc;
1631   struct ForwardedOverlayConnectContext *focc;
1632   
1633   rhc = fopc->cls;
1634   forwarded_operation_reply_relay (cls, msg);
1635   focc = rhc->focc_dll_head;
1636   GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
1637   cleanup_focc (focc);
1638   if (NULL != rhc->focc_dll_head)
1639     process_next_focc (rhc);
1640 }
1641
1642
1643 /**
1644  * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
1645  *
1646  * @param rhc the RegisteredHostContext
1647  */
1648 static void
1649 process_next_focc (struct RegisteredHostContext *rhc)
1650 {
1651   struct ForwardedOperationContext *fopc;
1652   struct ForwardedOverlayConnectContext *focc;
1653
1654   focc = rhc->focc_dll_head;
1655   GNUNET_assert (NULL != focc);
1656   GNUNET_assert (RHC_OL_CONNECT == rhc->state);
1657   fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1658   GNUNET_SERVER_client_keep (rhc->client);
1659   fopc->client = rhc->client;  
1660   fopc->operation_id = focc->operation_id;
1661   fopc->cls = rhc;
1662   fopc->type = OP_OVERLAY_CONNECT;
1663   fopc->opc =
1664         GNUNET_TESTBED_forward_operation_msg_ (rhc->gateway->controller,
1665                                                focc->operation_id, focc->orig_msg,
1666                                                &forwarded_overlay_connect_listener,
1667                                                fopc);
1668   GNUNET_free (focc->orig_msg);
1669   focc->orig_msg = NULL;
1670   fopc->timeout_task =
1671       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_overlay_connect_timeout,
1672                                     fopc);
1673   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1674 }
1675
1676
1677 /**
1678  * Callback for event from slave controllers
1679  *
1680  * @param cls struct Slave *
1681  * @param event information about the event
1682  */
1683 static void
1684 slave_event_callback (void *cls,
1685                       const struct GNUNET_TESTBED_EventInformation *event)
1686 {
1687   struct RegisteredHostContext *rhc;
1688   struct GNUNET_CONFIGURATION_Handle *cfg;
1689   struct GNUNET_TESTBED_Operation *old_op;
1690   
1691   /* We currently only get here when working on RegisteredHostContexts */
1692   GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
1693   rhc = event->details.operation_finished.op_cls;
1694   GNUNET_assert (rhc->sub_op == event->details.operation_finished.operation);
1695   switch (rhc->state)
1696   {
1697   case RHC_GET_CFG:
1698     cfg = event->details.operation_finished.generic;
1699     old_op = rhc->sub_op;
1700     rhc->state = RHC_LINK;
1701     rhc->sub_op =
1702         GNUNET_TESTBED_controller_link (rhc,
1703                                         rhc->gateway->controller,
1704                                         rhc->reg_host,
1705                                         rhc->host,
1706                                         cfg,
1707                                         GNUNET_NO);
1708     GNUNET_TESTBED_operation_done (old_op);
1709     break;
1710   case RHC_LINK:
1711     LOG_DEBUG ("OL: Linking controllers successfull\n");
1712     GNUNET_TESTBED_operation_done (rhc->sub_op);
1713     rhc->sub_op = NULL;
1714     rhc->state = RHC_OL_CONNECT;
1715     process_next_focc (rhc);
1716     break;
1717   default:
1718     GNUNET_assert (0);
1719   }
1720 }
1721
1722
1723 /**
1724  * Callback to signal successfull startup of the controller process
1725  *
1726  * @param cls the handle to the slave whose status is to be found here
1727  * @param cfg the configuration with which the controller has been started;
1728  *          NULL if status is not GNUNET_OK
1729  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1730  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1731  */
1732 static void
1733 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1734                        int status)
1735 {
1736   struct Slave *slave = cls;
1737   struct LinkControllersContext *lcc;
1738
1739   lcc = slave->lcc;
1740   if (GNUNET_SYSERR == status)
1741   {
1742     slave->controller_proc = NULL;
1743     slave_list[slave->host_id] = NULL;
1744     if (NULL != slave->cfg)
1745       GNUNET_CONFIGURATION_destroy (slave->cfg);
1746     GNUNET_free (slave);
1747     slave = NULL;
1748     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
1749     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
1750     goto clean_lcc;
1751   }
1752   slave->controller =
1753       GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1754                                          event_mask,
1755                                          &slave_event_callback, slave);
1756   if (NULL != slave->controller)
1757   {
1758     send_operation_success_msg (lcc->client, lcc->operation_id);
1759     slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
1760   }
1761   else
1762   {
1763     send_operation_fail_msg (lcc->client, lcc->operation_id,
1764                              "Could not connect to delegated controller");
1765     GNUNET_TESTBED_controller_stop (slave->controller_proc);
1766     slave_list[slave->host_id] = NULL;
1767     GNUNET_free (slave);
1768     slave = NULL;
1769   }
1770
1771  clean_lcc:
1772   if (NULL != lcc)
1773   {
1774     if (NULL != lcc->client)
1775     {
1776       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
1777       GNUNET_SERVER_client_drop (lcc->client);
1778       lcc->client = NULL;
1779     }
1780     GNUNET_free (lcc);
1781   }
1782   if (NULL != slave)
1783     slave->lcc = NULL;
1784 }
1785
1786
1787 /**
1788  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
1789  *
1790  * @param cls NULL
1791  * @param client identification of the client
1792  * @param message the actual message
1793  */
1794 static void
1795 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
1796              const struct GNUNET_MessageHeader *message)
1797 {
1798   const struct GNUNET_TESTBED_InitMessage *msg;
1799   struct GNUNET_TESTBED_Host *host;
1800   const char *controller_hostname;
1801   uint16_t msize;
1802
1803   if (NULL != master_context)
1804   {
1805     LOG_DEBUG ("We are being connected to laterally\n");
1806     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1807     return;
1808   }
1809   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1810   msize = ntohs (message->size);
1811   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1812   {
1813     GNUNET_break (0);
1814     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1815     return;
1816   }
1817   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1818   controller_hostname = (const char *) &msg[1];
1819   if ('\0' != controller_hostname[msize - 1])
1820   {
1821     GNUNET_break (0);
1822     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1823     return;
1824   }
1825   master_context = GNUNET_malloc (sizeof (struct Context));
1826   GNUNET_SERVER_client_keep (client);
1827   master_context->client = client;
1828   master_context->host_id = ntohl (msg->host_id);
1829   master_context->master_ip = GNUNET_strdup (controller_hostname);
1830   LOG_DEBUG ("Our IP: %s\n", master_context->master_ip);
1831   master_context->system =
1832       GNUNET_TESTING_system_create ("testbed", master_context->master_ip, hostname);
1833   host =
1834       GNUNET_TESTBED_host_create_with_id (master_context->host_id,
1835                                           master_context->master_ip,
1836                                           NULL,
1837                                           0);
1838   host_list_add (host);
1839   LOG_DEBUG ("Created master context with host ID: %u\n",
1840              master_context->host_id);
1841   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1842 }
1843
1844
1845 /**
1846  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1847  *
1848  * @param cls NULL
1849  * @param client identification of the client
1850  * @param message the actual message
1851  */
1852 static void
1853 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1854                  const struct GNUNET_MessageHeader *message)
1855 {
1856   struct GNUNET_TESTBED_Host *host;
1857   const struct GNUNET_TESTBED_AddHostMessage *msg;
1858   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1859   char *username;
1860   char *hostname;
1861   char *emsg;
1862   uint32_t host_id;
1863   uint16_t username_length;
1864   uint16_t hostname_length;
1865   uint16_t reply_size;
1866   uint16_t msize;
1867
1868   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1869   msize = ntohs (msg->header.size);
1870   username = (char *) &msg[1];
1871   username_length = ntohs (msg->user_name_length);
1872   if (0 != username_length)
1873     username_length++;
1874   /* msg must contain hostname */
1875   GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
1876                           username_length + 1));
1877   if (0 != username_length)
1878     GNUNET_assert ('\0' == username[username_length - 1]);
1879   hostname = username + username_length;
1880   hostname_length =
1881       msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
1882   GNUNET_assert ('\0' == hostname[hostname_length - 1]);
1883   GNUNET_assert (strlen (hostname) == hostname_length - 1);
1884   host_id = ntohl (msg->host_id);
1885   LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
1886   LOG_DEBUG ("-------host id: %u\n", host_id);
1887   LOG_DEBUG ("-------hostname: %s\n", hostname);
1888   if (0 != username_length)
1889     LOG_DEBUG ("-------username: %s\n", username);
1890   else
1891   {
1892     LOG_DEBUG ("-------username: NULL\n");
1893     username = NULL;
1894   }
1895   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1896   host =
1897       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1898                                           ntohs (msg->ssh_port));
1899   GNUNET_assert (NULL != host);
1900   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1901   if (GNUNET_OK != host_list_add (host))
1902   {
1903     /* We are unable to add a host */
1904     emsg = "A host exists with given host-id";
1905     LOG_DEBUG ("%s: %u", emsg, host_id);
1906     GNUNET_TESTBED_host_destroy (host);
1907     reply_size += strlen (emsg) + 1;
1908     reply = GNUNET_malloc (reply_size);
1909     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1910   }
1911   else
1912   {
1913     LOG_DEBUG ("Added host %u at %u\n",
1914                host_id, master_context->host_id);
1915     reply = GNUNET_malloc (reply_size);
1916   }
1917   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
1918   reply->header.size = htons (reply_size);
1919   reply->host_id = htonl (host_id);
1920   queue_message (client, &reply->header);
1921   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1922 }
1923
1924
1925 /**
1926  * Iterator over hash map entries.
1927  *
1928  * @param cls closure
1929  * @param key current key code
1930  * @param value value in the hash map
1931  * @return GNUNET_YES if we should continue to
1932  *         iterate,
1933  *         GNUNET_NO if not.
1934  */
1935 int
1936 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1937 {
1938   struct SharedService *queried_ss = cls;
1939   struct SharedService *ss = value;
1940
1941   if (0 == strcmp (ss->name, queried_ss->name))
1942     return GNUNET_NO;
1943   else
1944     return GNUNET_YES;
1945 }
1946
1947
1948 /**
1949  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1950  *
1951  * @param cls NULL
1952  * @param client identification of the client
1953  * @param message the actual message
1954  */
1955 static void
1956 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1957                                  const struct GNUNET_MessageHeader *message)
1958 {
1959   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1960   struct SharedService *ss;
1961   char *service_name;
1962   struct GNUNET_HashCode hash;
1963   uint16_t msg_size;
1964   uint16_t service_name_size;
1965
1966   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1967   msg_size = ntohs (message->size);
1968   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1969   {
1970     GNUNET_break (0);
1971     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1972     return;
1973   }
1974   service_name_size =
1975       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1976   service_name = (char *) &msg[1];
1977   if ('\0' != service_name[service_name_size - 1])
1978   {
1979     GNUNET_break (0);
1980     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1981     return;
1982   }
1983   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1984              service_name, ntohl (msg->num_peers));
1985   if (ntohl (msg->host_id) != master_context->host_id)
1986   {
1987     route_message (ntohl (msg->host_id), message);
1988     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1989     return;
1990   }
1991   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1992   ss = GNUNET_malloc (sizeof (struct SharedService));
1993   ss->name = strdup (service_name);
1994   ss->num_shared = ntohl (msg->num_peers);
1995   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1996   if (GNUNET_SYSERR ==
1997       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1998                                                   &ss_exists_iterator, ss))
1999   {
2000     LOG (GNUNET_ERROR_TYPE_WARNING,
2001          "Service %s already configured as a shared service. "
2002          "Ignoring service sharing request \n", ss->name);
2003     GNUNET_free (ss->name);
2004     GNUNET_free (ss);
2005     return;
2006   }
2007   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
2008                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2009 }
2010
2011
2012 /**
2013  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
2014  *
2015  * @param cls NULL
2016  * @param client identification of the client
2017  * @param message the actual message
2018  */
2019 static void
2020 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
2021                          const struct GNUNET_MessageHeader *message)
2022 {
2023   const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
2024   struct GNUNET_CONFIGURATION_Handle *cfg;
2025   struct LCFContextQueue *lcfq;
2026   struct Route *route;
2027   struct Route *new_route;
2028   char *config;
2029   uLongf dest_size;
2030   size_t config_size;
2031   uint32_t delegated_host_id;
2032   uint32_t slave_host_id;
2033   uint16_t msize;
2034
2035   if (NULL == master_context)
2036   {
2037     GNUNET_break (0);
2038     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2039     return;
2040   }
2041   msize = ntohs (message->size);
2042   if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
2043   {
2044     GNUNET_break (0);
2045     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2046     return;
2047   }
2048   msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
2049   delegated_host_id = ntohl (msg->delegated_host_id);
2050   if (delegated_host_id == master_context->host_id)
2051   {
2052     GNUNET_break (0);
2053     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
2054     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2055     return;
2056   }
2057   if ((delegated_host_id >= host_list_size) ||
2058       (NULL == host_list[delegated_host_id]))
2059   {
2060     LOG (GNUNET_ERROR_TYPE_WARNING,
2061          "Delegated host %u not registered with us\n", delegated_host_id);
2062     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2063     return;
2064   }
2065   slave_host_id = ntohl (msg->slave_host_id);
2066   if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
2067   {
2068     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
2069          slave_host_id);
2070     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2071     return;
2072   }
2073   if (slave_host_id == delegated_host_id)
2074   {
2075     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
2076     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2077     return;
2078   }
2079
2080   if (slave_host_id == master_context->host_id) /* Link from us */
2081   {
2082     struct Slave *slave;
2083     struct LinkControllersContext *lcc;
2084
2085     msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
2086     config_size = ntohs (msg->config_size);
2087     if ((delegated_host_id < slave_list_size) && (NULL != slave_list[delegated_host_id]))       /* We have already added */
2088     {
2089       LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
2090            delegated_host_id);
2091       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2092       return;
2093     }
2094     config = GNUNET_malloc (config_size);
2095     dest_size = (uLongf) config_size;
2096     if (Z_OK !=
2097         uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
2098                     (uLong) msize))
2099     {
2100       GNUNET_break (0);         /* Compression error */
2101       GNUNET_free (config);
2102       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2103       return;
2104     }
2105     if (config_size != dest_size)
2106     {
2107       LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
2108       GNUNET_free (config);
2109       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2110       return;
2111     }
2112     cfg = GNUNET_CONFIGURATION_create ();       /* Free here or in lcfcontext */
2113     if (GNUNET_OK !=
2114         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
2115     {
2116       GNUNET_break (0);         /* Configuration parsing error */
2117       GNUNET_free (config);
2118       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2119       return;
2120     }
2121     GNUNET_free (config);
2122     if ((delegated_host_id < slave_list_size) &&
2123         (NULL != slave_list[delegated_host_id]))
2124     {
2125       GNUNET_break (0);         /* Configuration parsing error */
2126       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2127       return;
2128     }
2129     slave = GNUNET_malloc (sizeof (struct Slave));
2130     slave->host_id = delegated_host_id;
2131     slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
2132     slave_list_add (slave);
2133     if (1 != msg->is_subordinate)
2134     {
2135       slave->controller =
2136           GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
2137                                              event_mask,
2138                                              &slave_event_callback, slave);
2139       slave->cfg = cfg;
2140       if (NULL != slave->controller)
2141         send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
2142       else
2143         send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2144                                  "Could not connect to delegated controller");
2145       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2146       return;
2147     }
2148     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
2149     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
2150     GNUNET_SERVER_client_keep (client);
2151     lcc->client = client;
2152     slave->lcc = lcc;
2153     slave->controller_proc =
2154         GNUNET_TESTBED_controller_start (master_context->master_ip,
2155                                          host_list[slave->host_id], cfg,
2156                                          &slave_status_callback, slave);
2157     GNUNET_CONFIGURATION_destroy (cfg);
2158     new_route = GNUNET_malloc (sizeof (struct Route));
2159     new_route->dest = delegated_host_id;
2160     new_route->thru = master_context->host_id;
2161     route_list_add (new_route);
2162     return;
2163   }
2164
2165   /* Route the request */
2166   if (slave_host_id >= route_list_size)
2167   {
2168     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
2169     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2170     return;
2171   }
2172   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
2173   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
2174   lcfq->lcf->delegated_host_id = delegated_host_id;
2175   lcfq->lcf->slave_host_id = slave_host_id;
2176   route = find_dest_route (slave_host_id);
2177   GNUNET_assert (NULL != route);        /* because we add routes carefully */
2178   GNUNET_assert (route->dest < slave_list_size);
2179   GNUNET_assert (NULL != slave_list[route->dest]);
2180   lcfq->lcf->state = INIT;
2181   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
2182   lcfq->lcf->gateway = slave_list[route->dest];
2183   lcfq->lcf->msg = GNUNET_malloc (msize);
2184   (void) memcpy (lcfq->lcf->msg, msg, msize);
2185   GNUNET_SERVER_client_keep (client);
2186   lcfq->lcf->client = client;
2187   if (NULL == lcfq_head)
2188   {
2189     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2190     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
2191     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
2192   }
2193   else
2194     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
2195   /* FIXME: Adding a new route should happen after the controllers are linked
2196    * successfully */
2197   if (1 != msg->is_subordinate)
2198   {
2199     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2200     return;
2201   }
2202   if ((delegated_host_id < route_list_size)
2203       && (NULL != route_list[delegated_host_id]))
2204   {
2205     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
2206                                    with is subordinate flag set to GNUNET_YES? */
2207     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2208     return;
2209   }
2210   new_route = GNUNET_malloc (sizeof (struct Route));
2211   new_route->dest = delegated_host_id;
2212   new_route->thru = route->dest;
2213   route_list_add (new_route);
2214   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2215 }
2216
2217
2218 /**
2219  * The task to be executed if the forwarded peer create operation has been
2220  * timed out
2221  *
2222  * @param cls the FowardedOperationContext
2223  * @param tc the TaskContext from the scheduler
2224  */
2225 static void
2226 peer_create_forward_timeout (void *cls,
2227                              const struct GNUNET_SCHEDULER_TaskContext *tc)
2228 {
2229   struct ForwardedOperationContext *fopc = cls;
2230
2231   GNUNET_free (fopc->cls);
2232   forwarded_operation_timeout (fopc, tc);
2233 }
2234
2235
2236 /**
2237  * Callback to be called when forwarded peer create operation is successfull. We
2238  * have to relay the reply msg back to the client
2239  *
2240  * @param cls ForwardedOperationContext
2241  * @param msg the peer create success message
2242  */
2243 static void
2244 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
2245 {
2246   struct ForwardedOperationContext *fopc = cls;
2247   struct Peer *remote_peer;
2248
2249   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS)
2250   {
2251     GNUNET_assert (NULL != fopc->cls);
2252     remote_peer = fopc->cls;
2253     peer_list_add (remote_peer);
2254   }
2255   forwarded_operation_reply_relay (fopc, msg);
2256 }
2257
2258
2259 /**
2260  * Function to destroy a peer
2261  *
2262  * @param peer the peer structure to destroy
2263  */
2264 static void
2265 destroy_peer (struct Peer *peer)
2266 {
2267   GNUNET_break (0 == peer->reference_cnt);
2268   if (GNUNET_YES == peer->is_remote)
2269   {
2270     peer_list_remove (peer);
2271     GNUNET_free (peer);
2272     return;
2273   }
2274   if (GNUNET_YES == peer->details.local.is_running)
2275   {
2276     GNUNET_TESTING_peer_stop (peer->details.local.peer);
2277     peer->details.local.is_running = GNUNET_NO;
2278   }
2279   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
2280   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
2281   peer_list_remove (peer);
2282   GNUNET_free (peer);
2283 }
2284
2285
2286 /**
2287  * Callback to be called when forwarded peer destroy operation is successfull. We
2288  * have to relay the reply msg back to the client
2289  *
2290  * @param cls ForwardedOperationContext
2291  * @param msg the peer create success message
2292  */
2293 static void
2294 peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
2295 {
2296   struct ForwardedOperationContext *fopc = cls;
2297   struct Peer *remote_peer;
2298
2299   if (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS == ntohs (msg->type))
2300   {
2301     remote_peer = fopc->cls;
2302     GNUNET_assert (NULL != remote_peer);
2303     remote_peer->destroy_flag = GNUNET_YES;
2304     if (0 == remote_peer->reference_cnt)
2305       destroy_peer (remote_peer);
2306   }
2307   forwarded_operation_reply_relay (fopc, msg);
2308 }
2309
2310
2311
2312 /**
2313  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
2314  *
2315  * @param cls NULL
2316  * @param client identification of the client
2317  * @param message the actual message
2318  */
2319 static void
2320 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
2321                     const struct GNUNET_MessageHeader *message)
2322 {
2323   const struct GNUNET_TESTBED_PeerCreateMessage *msg;
2324   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
2325   struct GNUNET_CONFIGURATION_Handle *cfg;
2326   struct ForwardedOperationContext *fo_ctxt;
2327   struct Route *route;
2328   struct Peer *peer;
2329   char *config;
2330   size_t dest_size;
2331   int ret;
2332   uint32_t config_size;
2333   uint32_t host_id;
2334   uint32_t peer_id;
2335   uint16_t msize;
2336
2337
2338   msize = ntohs (message->size);
2339   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
2340   {
2341     GNUNET_break (0);           /* We need configuration */
2342     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2343     return;
2344   }
2345   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
2346   host_id = ntohl (msg->host_id);
2347   peer_id = ntohl (msg->peer_id);
2348   if (UINT32_MAX == peer_id)
2349   {
2350     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2351                              "Cannot create peer with given ID");
2352     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2353     return;
2354   }
2355   if (host_id == master_context->host_id)
2356   {
2357     char *emsg;
2358
2359     /* We are responsible for this peer */
2360     msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
2361     config_size = ntohl (msg->config_size);
2362     config = GNUNET_malloc (config_size);
2363     dest_size = config_size;
2364     if (Z_OK !=
2365         (ret =
2366          uncompress ((Bytef *) config, (uLongf *) & dest_size,
2367                      (const Bytef *) &msg[1], (uLong) msize)))
2368     {
2369       GNUNET_break (0);         /* uncompression error */
2370       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2371       return;
2372     }
2373     if (config_size != dest_size)
2374     {
2375       GNUNET_break (0);         /* Uncompressed config size mismatch */
2376       GNUNET_free (config);
2377       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2378       return;
2379     }
2380     cfg = GNUNET_CONFIGURATION_create ();
2381     if (GNUNET_OK !=
2382         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
2383     {
2384       GNUNET_break (0);         /* Configuration parsing error */
2385       GNUNET_free (config);
2386       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2387       return;
2388     }
2389     GNUNET_free (config);
2390     peer = GNUNET_malloc (sizeof (struct Peer));
2391     peer->is_remote = GNUNET_NO;
2392     peer->details.local.cfg = cfg;
2393     peer->id = peer_id;
2394     LOG_DEBUG ("Creating peer with id: %u\n", peer->id);
2395     peer->details.local.peer =
2396         GNUNET_TESTING_peer_configure (master_context->system,
2397                                        peer->details.local.cfg, peer->id,
2398                                        NULL /* Peer id */ ,
2399                                        &emsg);
2400     if (NULL == peer->details.local.peer)
2401     {
2402       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
2403       GNUNET_free (emsg);
2404       GNUNET_free (peer);
2405       GNUNET_break (0);
2406       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2407       return;
2408     }
2409     peer->details.local.is_running = GNUNET_NO;
2410     peer_list_add (peer);
2411     reply =
2412         GNUNET_malloc (sizeof
2413                        (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
2414     reply->header.size =
2415         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
2416     reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS);
2417     reply->peer_id = msg->peer_id;
2418     reply->operation_id = msg->operation_id;
2419     queue_message (client, &reply->header);
2420     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2421     return;
2422   }
2423
2424   /* Forward peer create request */
2425   route = find_dest_route (host_id);
2426   if (NULL == route)
2427   {
2428     GNUNET_break (0);
2429     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2430     return;
2431   }
2432
2433   peer = GNUNET_malloc (sizeof (struct Peer));
2434   peer->is_remote = GNUNET_YES;
2435   peer->id = peer_id;
2436   peer->details.remote.slave = slave_list[route->dest];
2437   peer->details.remote.remote_host_id = host_id;
2438   fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2439   GNUNET_SERVER_client_keep (client);
2440   fo_ctxt->client = client;
2441   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
2442   fo_ctxt->cls = peer; //slave_list[route->dest]->controller;
2443   fo_ctxt->type = OP_PEER_CREATE;
2444   fo_ctxt->opc =
2445       GNUNET_TESTBED_forward_operation_msg_ (slave_list [route->dest]->controller,
2446                                              fo_ctxt->operation_id,
2447                                              &msg->header,
2448                                              peer_create_success_cb, fo_ctxt);
2449   fo_ctxt->timeout_task =
2450       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
2451                                     fo_ctxt);
2452   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2453   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2454 }
2455
2456
2457 /**
2458  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2459  *
2460  * @param cls NULL
2461  * @param client identification of the client
2462  * @param message the actual message
2463  */
2464 static void
2465 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
2466                      const struct GNUNET_MessageHeader *message)
2467 {
2468   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
2469   struct ForwardedOperationContext *fopc;
2470   struct Peer *peer;
2471   uint32_t peer_id;
2472
2473   msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
2474   peer_id = ntohl (msg->peer_id);
2475   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
2476              peer_id, GNUNET_ntohll (msg->operation_id));
2477   if ((peer_list_size <= peer_id) || (NULL == peer_list[peer_id]))
2478   {
2479     LOG (GNUNET_ERROR_TYPE_ERROR,
2480          "Asked to destroy a non existent peer with id: %u\n", peer_id);
2481     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2482                              "Peer doesn't exist");
2483     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2484     return;
2485   }
2486   peer = peer_list[peer_id];
2487   if (GNUNET_YES == peer->is_remote)
2488   {
2489     /* Forward the destory message to sub controller */
2490     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2491     GNUNET_SERVER_client_keep (client);
2492     fopc->client = client;
2493     fopc->cls = peer;
2494     fopc->type = OP_PEER_DESTROY;
2495     fopc->operation_id = GNUNET_ntohll (msg->operation_id);    
2496     fopc->opc = 
2497         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2498                                                fopc->operation_id, &msg->header,
2499                                                &peer_destroy_success_cb,
2500                                                fopc);
2501     fopc->timeout_task =
2502         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2503                                       fopc);
2504     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2505     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2506     return;
2507   }
2508   peer->destroy_flag = GNUNET_YES;
2509   if (0 == peer->reference_cnt)
2510     destroy_peer (peer);
2511   else
2512     LOG (GNUNET_ERROR_TYPE_WARNING,
2513          "Delaying peer destroy as peer is currently in use\n");
2514   send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
2515   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2516 }
2517
2518
2519 /**
2520  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2521  *
2522  * @param cls NULL
2523  * @param client identification of the client
2524  * @param message the actual message
2525  */
2526 static void
2527 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
2528                    const struct GNUNET_MessageHeader *message)
2529 {
2530   const struct GNUNET_TESTBED_PeerStartMessage *msg;
2531   struct GNUNET_TESTBED_PeerEventMessage *reply;
2532   struct ForwardedOperationContext *fopc;
2533   struct Peer *peer;
2534   uint32_t peer_id;
2535
2536   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
2537   peer_id = ntohl (msg->peer_id);
2538   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2539   {
2540     GNUNET_break (0);
2541     LOG (GNUNET_ERROR_TYPE_ERROR,
2542          "Asked to start a non existent peer with id: %u\n", peer_id);
2543     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2544     return;
2545   }
2546   peer = peer_list[peer_id];
2547   if (GNUNET_YES == peer->is_remote)
2548   {
2549     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2550     GNUNET_SERVER_client_keep (client);
2551     fopc->client = client;
2552     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2553     fopc->type = OP_PEER_START;
2554     fopc->opc =
2555         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2556                                                fopc->operation_id, &msg->header,
2557                                                &forwarded_operation_reply_relay,
2558                                                fopc);
2559     fopc->timeout_task =
2560         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2561                                       fopc);
2562     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2563     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2564     return;
2565   }
2566   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
2567   {
2568     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2569                              "Failed to start");
2570     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2571     return;
2572   }
2573   peer->details.local.is_running = GNUNET_YES;
2574   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2575   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2576   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2577   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
2578   reply->host_id = htonl (master_context->host_id);
2579   reply->peer_id = msg->peer_id;
2580   reply->operation_id = msg->operation_id;
2581   queue_message (client, &reply->header);
2582   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2583 }
2584
2585
2586 /**
2587  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2588  *
2589  * @param cls NULL
2590  * @param client identification of the client
2591  * @param message the actual message
2592  */
2593 static void
2594 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
2595                   const struct GNUNET_MessageHeader *message)
2596 {
2597   const struct GNUNET_TESTBED_PeerStopMessage *msg;
2598   struct GNUNET_TESTBED_PeerEventMessage *reply;
2599   struct ForwardedOperationContext *fopc;
2600   struct Peer *peer;
2601   uint32_t peer_id;
2602
2603   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
2604   peer_id = ntohl (msg->peer_id);
2605   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2606   {
2607     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2608                              "Peer not found");
2609     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2610     return;
2611   }
2612   peer = peer_list[peer_id];
2613   if (GNUNET_YES == peer->is_remote)
2614   {
2615     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2616     GNUNET_SERVER_client_keep (client);
2617     fopc->client = client;
2618     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2619     fopc->type = OP_PEER_STOP;
2620     fopc->opc =
2621         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2622                                                fopc->operation_id, &msg->header,
2623                                                &forwarded_operation_reply_relay,
2624                                                fopc);
2625     fopc->timeout_task =
2626         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2627                                       fopc);
2628     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2629     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2630     return;
2631   }
2632   if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
2633   {
2634     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2635                              "Peer not running");
2636     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2637     return;
2638   }
2639   peer->details.local.is_running = GNUNET_NO;
2640   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2641   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2642   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2643   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
2644   reply->host_id = htonl (master_context->host_id);
2645   reply->peer_id = msg->peer_id;
2646   reply->operation_id = msg->operation_id;
2647   queue_message (client, &reply->header);
2648   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2649 }
2650
2651
2652 /**
2653  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
2654  *
2655  * @param cls NULL
2656  * @param client identification of the client
2657  * @param message the actual message
2658  */
2659 static void
2660 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2661                         const struct GNUNET_MessageHeader *message)
2662 {
2663   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
2664   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
2665   struct Peer *peer;
2666   char *config;
2667   char *xconfig;
2668   size_t c_size;
2669   size_t xc_size;
2670   uint32_t peer_id;
2671   uint16_t msize;
2672
2673   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
2674   peer_id = ntohl (msg->peer_id);
2675   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2676   {
2677     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2678                              "Peer not found");
2679     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2680     return;
2681   }
2682   peer = peer_list[peer_id];
2683   if (GNUNET_YES == peer->is_remote)
2684   {
2685     struct ForwardedOperationContext *fopc;
2686     
2687     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2688     GNUNET_SERVER_client_keep (client);
2689     fopc->client = client;
2690     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2691     fopc->type = OP_PEER_INFO;
2692     fopc->opc =
2693         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
2694                                                fopc->operation_id, &msg->header,
2695                                                &forwarded_operation_reply_relay,
2696                                                fopc);
2697     fopc->timeout_task =
2698         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2699                                       fopc);
2700     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); 
2701     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2702     return;
2703   }
2704   config =
2705       GNUNET_CONFIGURATION_serialize (peer_list[peer_id]->details.local.cfg,
2706                                       &c_size);
2707   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
2708   GNUNET_free (config);
2709   msize =
2710       xc_size +
2711       sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2712   reply = GNUNET_realloc (xconfig, msize);
2713   (void) memmove (&reply[1], reply, xc_size);
2714   reply->header.size = htons (msize);
2715   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG);
2716   reply->peer_id = msg->peer_id;
2717   reply->operation_id = msg->operation_id;
2718   GNUNET_TESTING_peer_get_identity (peer_list[peer_id]->details.local.peer,
2719                                     &reply->peer_identity);
2720   reply->config_size = htons ((uint16_t) c_size);
2721   queue_message (client, &reply->header);
2722   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2723 }
2724
2725
2726 /**
2727  * Cleanup overlay connect context structure
2728  *
2729  * @param occ the overlay connect context
2730  */
2731 static void
2732 cleanup_occ (struct OverlayConnectContext *occ)
2733 {
2734   LOG_DEBUG ("Cleaning up occ\n");
2735   GNUNET_free_non_null (occ->emsg);
2736   GNUNET_free_non_null (occ->hello);
2737   GNUNET_SERVER_client_drop (occ->client);
2738   if (NULL != occ->opc)
2739     GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
2740   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2741     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2742   if (GNUNET_SCHEDULER_NO_TASK != occ->cleanup_task)
2743     GNUNET_SCHEDULER_cancel (occ->cleanup_task);
2744   if (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task)
2745     GNUNET_SCHEDULER_cancel (occ->timeout_task);
2746   if (NULL != occ->ch)
2747   {
2748     GNUNET_CORE_disconnect (occ->ch);
2749     occ->peer->reference_cnt--;
2750   }
2751   if (NULL != occ->ghh)
2752     GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2753   if (NULL != occ->ohh)
2754     GNUNET_TRANSPORT_offer_hello_cancel (occ->ohh);
2755   if (NULL != occ->tch)
2756     GNUNET_TRANSPORT_try_connect_cancel (occ->tch);
2757   if (NULL != occ->p1th)
2758   {
2759     GNUNET_TRANSPORT_disconnect (occ->p1th);
2760     occ->peer->reference_cnt--;
2761   }
2762   if (NULL != occ->p2th)
2763   {
2764     GNUNET_TRANSPORT_disconnect (occ->p2th);
2765     peer_list[occ->other_peer_id]->reference_cnt--;
2766   }
2767   if ((GNUNET_YES == occ->peer->destroy_flag)
2768       && (0 == occ->peer->reference_cnt))
2769     destroy_peer (occ->peer);
2770   if ((NULL == occ->peer2_controller)
2771       && (GNUNET_YES == peer_list[occ->other_peer_id]->destroy_flag)
2772         && (0 == peer_list[occ->other_peer_id]->reference_cnt))
2773       destroy_peer (peer_list[occ->other_peer_id]);  
2774   GNUNET_CONTAINER_DLL_remove (occq_head, occq_tail, occ);
2775   GNUNET_free (occ);
2776 }
2777
2778
2779 /**
2780  * Task for cleaing up overlay connect context structure
2781  *
2782  * @param cls the overlay connect context
2783  * @param tc the task context
2784  */
2785 static void
2786 do_cleanup_occ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2787 {
2788   struct OverlayConnectContext *occ = cls;
2789   
2790   occ->cleanup_task = GNUNET_SCHEDULER_NO_TASK;
2791   cleanup_occ (occ);
2792 }
2793
2794
2795 /**
2796  * Task which will be run when overlay connect request has been timed out
2797  *
2798  * @param cls the OverlayConnectContext
2799  * @param tc the TaskContext
2800  */
2801 static void
2802 timeout_overlay_connect (void *cls,
2803                          const struct GNUNET_SCHEDULER_TaskContext *tc)
2804 {
2805   struct OverlayConnectContext *occ = cls;
2806
2807   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2808   LOG (GNUNET_ERROR_TYPE_WARNING,
2809        "Timeout while connecting peers %u and %u\n",
2810        occ->peer_id, occ->other_peer_id);
2811   send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
2812   cleanup_occ (occ);
2813 }
2814
2815
2816
2817 /**
2818  * Function called to notify transport users that another
2819  * peer connected to us.
2820  *
2821  * @param cls closure
2822  * @param new_peer the peer that connected
2823  * @param ats performance data
2824  * @param ats_count number of entries in ats (excluding 0-termination)
2825  */
2826 static void
2827 overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2828                         const struct GNUNET_ATS_Information *ats,
2829                         unsigned int ats_count)
2830 {
2831   struct OverlayConnectContext *occ = cls;
2832   struct GNUNET_TESTBED_ConnectionEventMessage *msg;
2833   char *new_peer_str;
2834   char *other_peer_str;
2835
2836   LOG_DEBUG ("Overlay connect notify\n");
2837   if (0 ==
2838       memcmp (new_peer, &occ->peer_identity,
2839               sizeof (struct GNUNET_PeerIdentity)))
2840     return;
2841   new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
2842   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2843   if (0 !=
2844       memcmp (new_peer, &occ->other_peer_identity,
2845               sizeof (struct GNUNET_PeerIdentity)))
2846   {
2847     LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n",
2848                new_peer_str, other_peer_str);
2849     GNUNET_free (new_peer_str);
2850     GNUNET_free (other_peer_str);
2851     return;
2852   }
2853   GNUNET_free (new_peer_str);
2854   LOG_DEBUG ("Peer %4s connected to peer %4s\n", other_peer_str, 
2855              GNUNET_i2s (&occ->peer_identity));
2856   GNUNET_free (other_peer_str);
2857   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2858   {
2859     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2860     occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2861   }
2862   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
2863   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2864   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2865   GNUNET_free_non_null (occ->emsg);
2866   occ->emsg = NULL;
2867   if (NULL != occ->p2th)
2868   {
2869     GNUNET_TRANSPORT_disconnect (occ->p2th);
2870     peer_list[occ->other_peer_id]->reference_cnt--;
2871   }
2872   occ->p2th = NULL;
2873   LOG_DEBUG ("Peers connected - Sending overlay connect success\n");
2874   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2875   msg->header.size =
2876       htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2877   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT);
2878   msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
2879   msg->peer1 = htonl (occ->peer_id);
2880   msg->peer2 = htonl (occ->other_peer_id);
2881   msg->operation_id = GNUNET_htonll (occ->op_id);
2882   queue_message (occ->client, &msg->header);
2883   occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
2884   //cleanup_occ (occ);
2885 }
2886
2887
2888 /**
2889  * Callback to be called with result of the try connect request.
2890  *
2891  * @param cls the overlay connect context
2892  * @param result GNUNET_OK if message was transmitted to transport service
2893  *               GNUNET_SYSERR if message was not transmitted to transport service
2894  */
2895 static void 
2896 try_connect_cb (void *cls, const int result)
2897 {
2898   struct OverlayConnectContext *occ = cls;
2899   
2900   occ->tch = NULL;
2901   if (GNUNET_OK == result)
2902   {
2903     GNUNET_free_non_null (occ->emsg);
2904     occ->emsg = GNUNET_strdup ("Waiting for transport to connect");
2905     //return; FIXME: should return here
2906   }
2907   //  GNUNET_break (0);
2908   occ->tch = GNUNET_TRANSPORT_try_connect (occ->p2th, &occ->peer_identity,
2909                                            &try_connect_cb, occ);
2910 }
2911
2912
2913 /**
2914  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
2915  * peer 1.
2916  *
2917  * @param cls the OverlayConnectContext
2918  * @param tc the TaskContext from scheduler
2919  */
2920 static void
2921 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
2922
2923
2924 /**
2925  * Task that is run when hello has been sent
2926  *
2927  * @param cls the overlay connect context
2928  * @param tc the scheduler task context; if tc->reason =
2929  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
2930  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
2931  */
2932 static void
2933 occ_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2934 {
2935   struct OverlayConnectContext *occ = cls;
2936
2937   occ->ohh = NULL;
2938   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->send_hello_task);
2939   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
2940   {
2941     //GNUNET_break (0);
2942     goto schedule_send_hello;
2943   }
2944   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
2945     return;
2946   GNUNET_free_non_null (occ->emsg);
2947   occ->emsg = GNUNET_strdup ("Timeout while try connect\n");
2948   occ->tch = GNUNET_TRANSPORT_try_connect (occ->p2th, &occ->peer_identity,
2949                                            &try_connect_cb, occ);
2950   if (NULL != occ->tch)
2951     return;
2952   GNUNET_break (0);
2953
2954  schedule_send_hello:
2955   GNUNET_free_non_null (occ->emsg);
2956   occ->emsg = GNUNET_strdup ("Timeout while offering HELLO to other peer");
2957   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
2958 }
2959
2960
2961 /**
2962  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
2963  * peer 1.
2964  *
2965  * @param cls the OverlayConnectContext
2966  * @param tc the TaskContext from scheduler
2967  */
2968 static void
2969 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2970 {
2971   struct OverlayConnectContext *occ = cls;
2972   char *other_peer_str;
2973
2974   occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2975   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2976     return;
2977   GNUNET_assert (NULL != occ->hello);
2978   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2979   if (NULL != occ->peer2_controller)
2980   {
2981     struct GNUNET_TESTBED_RequestConnectMessage *msg;
2982     uint16_t msize;
2983     uint16_t hello_size;
2984
2985     LOG_DEBUG ("Offering HELLO of %s to %s via Remote Overlay Request\n", 
2986                GNUNET_i2s (&occ->peer_identity), other_peer_str);
2987     hello_size = ntohs (occ->hello->size);
2988     msize = sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hello_size;
2989     msg = GNUNET_malloc (msize);
2990     msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT);
2991     msg->header.size = htons (msize);
2992     msg->peer = htonl (occ->other_peer_id);
2993     msg->operation_id = GNUNET_htonll (occ->op_id);
2994     (void) memcpy (&msg->peer_identity, &occ->peer_identity,
2995                    sizeof (struct GNUNET_PeerIdentity));
2996     memcpy (msg->hello, occ->hello, hello_size);
2997     GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
2998   }
2999   else
3000   {
3001     LOG_DEBUG ("Offering HELLO of %s to %s\n", 
3002                GNUNET_i2s (&occ->peer_identity), other_peer_str);
3003     occ->ohh = GNUNET_TRANSPORT_offer_hello (occ->p2th,
3004                                              occ->hello,
3005                                              occ_hello_sent_cb,
3006                                              occ);
3007     if (NULL == occ->ohh)
3008     {
3009       GNUNET_break (0);
3010       occ->send_hello_task =
3011           GNUNET_SCHEDULER_add_delayed
3012           (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
3013                                           100 + GNUNET_CRYPTO_random_u32
3014                                           (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
3015            &send_hello, occ);
3016     }
3017   }
3018   GNUNET_free (other_peer_str);  
3019 }
3020
3021 /**
3022  * Test for checking whether HELLO message is empty
3023  *
3024  * @param cls empty flag to set
3025  * @param address the HELLO
3026  * @param expiration expiration of the HELLO
3027  * @return
3028  */
3029 static int
3030 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
3031               struct GNUNET_TIME_Absolute expiration)
3032 {
3033   int *empty = cls;
3034
3035   *empty = GNUNET_NO;
3036   return GNUNET_OK;
3037 }
3038
3039
3040 /**
3041  * Function called whenever there is an update to the HELLO of peers in the
3042  * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
3043  * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
3044  *
3045  * @param cls closure
3046  * @param hello our updated HELLO
3047  */
3048 static void
3049 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
3050 {
3051   struct OverlayConnectContext *occ = cls;
3052   int empty;
3053   uint16_t msize;
3054
3055   msize = ntohs (hello->size);
3056   empty = GNUNET_YES;
3057   (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
3058                                          hello, GNUNET_NO, &test_address,
3059                                          &empty);
3060   if (GNUNET_YES == empty)
3061   {
3062     LOG_DEBUG ("HELLO of %s is empty\n", GNUNET_i2s (&occ->peer_identity));
3063     return;
3064   }
3065   LOG_DEBUG ("Received HELLO of %s\n", GNUNET_i2s (&occ->peer_identity));
3066   occ->hello = GNUNET_malloc (msize);
3067   memcpy (occ->hello, hello, msize);
3068   GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
3069   occ->ghh = NULL;
3070   GNUNET_TRANSPORT_disconnect (occ->p1th);
3071   occ->p1th = NULL;
3072   occ->peer->reference_cnt--;
3073   GNUNET_free_non_null (occ->emsg);
3074   if (NULL == occ->peer2_controller)
3075   {
3076     peer_list[occ->other_peer_id]->reference_cnt++;
3077     occ->p2th =
3078         GNUNET_TRANSPORT_connect (peer_list[occ->other_peer_id]->details.local.cfg,
3079                                   &occ->other_peer_identity, NULL, NULL, NULL,
3080                                   NULL);
3081     if (NULL == occ->p2th)
3082     {
3083       GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of %s\n",
3084                        GNUNET_i2s (&occ->other_peer_identity));
3085       GNUNET_SCHEDULER_cancel (occ->timeout_task);
3086       occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3087       return;
3088     }
3089   }
3090   occ->emsg = GNUNET_strdup ("Timeout while offering HELLO to other peer");
3091   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
3092 }
3093
3094
3095 /**
3096  * Function called after GNUNET_CORE_connect has succeeded (or failed
3097  * for good).  Note that the private key of the peer is intentionally
3098  * not exposed here; if you need it, your process should try to read
3099  * the private key file directly (which should work if you are
3100  * authorized...).
3101  *
3102  * @param cls closure
3103  * @param server handle to the server, NULL if we failed
3104  * @param my_identity ID of this peer, NULL if we failed
3105  */
3106 static void
3107 core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
3108                  const struct GNUNET_PeerIdentity *my_identity)
3109 {
3110   struct OverlayConnectContext *occ = cls;
3111
3112   GNUNET_free_non_null (occ->emsg);
3113   occ->emsg = GNUNET_strdup ("Failed to connect to CORE\n");
3114   if ((NULL == server) || (NULL == my_identity))
3115     goto error_return;
3116   GNUNET_free (occ->emsg);
3117   occ->ch = server;
3118   occ->emsg = NULL;
3119   memcpy (&occ->peer_identity, my_identity,
3120           sizeof (struct GNUNET_PeerIdentity));
3121   occ->peer->reference_cnt++;
3122   occ->p1th =
3123       GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
3124                                 &occ->peer_identity, NULL, NULL, NULL, NULL);
3125   if (NULL == occ->p1th)
3126   {
3127     GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of peers %4s",
3128                     GNUNET_i2s (&occ->peer_identity));
3129     goto error_return;
3130   }
3131   LOG_DEBUG ("Acquiring HELLO of peer %s\n", GNUNET_i2s (&occ->peer_identity));
3132   occ->emsg = GNUNET_strdup ("Timeout while acquiring HELLO message");
3133   occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
3134   return;
3135   
3136  error_return:
3137   GNUNET_SCHEDULER_cancel (occ->timeout_task);
3138   occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3139   return;
3140 }
3141
3142
3143 /**
3144  * Callback to be called when forwarded get peer config operation as part of
3145  * overlay connect is successfull. Connection to Peer 1's core is made and is
3146  * checked for new connection from peer 2
3147  *
3148  * @param cls ForwardedOperationContext
3149  * @param msg the peer create success message
3150  */
3151 static void
3152 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
3153 {
3154   struct OverlayConnectContext *occ = cls;
3155   const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
3156   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
3157     {NULL, 0, 0}
3158   };
3159
3160   occ->opc = NULL;
3161   if (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG != ntohs (msg->type))
3162     goto error_return;
3163   cmsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
3164       msg;
3165   memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
3166           sizeof (struct GNUNET_PeerIdentity));
3167   GNUNET_free_non_null (occ->emsg);
3168   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
3169   occ->peer->reference_cnt++;
3170   occ->ch =
3171       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
3172                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
3173                            GNUNET_NO, no_handlers);
3174   if (NULL == occ->ch)
3175     goto error_return;
3176   return;
3177
3178  error_return:
3179   GNUNET_SCHEDULER_cancel (occ->timeout_task);
3180   occ->timeout_task = 
3181       GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3182 }
3183
3184
3185 /**
3186  * Callback which will be called to after a host registration succeeded or failed
3187  *
3188  * @param cls the RegisteredHostContext
3189  * @param emsg the error message; NULL if host registration is successful
3190  */
3191 static void 
3192 registeredhost_registration_completion (void *cls, const char *emsg)
3193 {
3194   struct RegisteredHostContext *rhc = cls;
3195   struct GNUNET_CONFIGURATION_Handle *cfg;
3196   uint32_t peer2_host_id;
3197
3198   /* if (NULL != rhc->focc_dll_head) */
3199   /*   process_next_focc (rhc); */
3200   peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
3201   GNUNET_assert (RHC_INIT == rhc->state);
3202   GNUNET_assert (NULL == rhc->sub_op);
3203   if ((NULL == rhc->gateway2)
3204       || ((peer2_host_id < slave_list_size) /* Check if we have the needed config */
3205           && (NULL != slave_list[peer2_host_id])))
3206   {
3207     rhc->state = RHC_LINK;
3208     cfg = (NULL == rhc->gateway2) ? our_config : slave_list[peer2_host_id]->cfg;
3209     rhc->sub_op =
3210         GNUNET_TESTBED_controller_link (rhc,
3211                                         rhc->gateway->controller,
3212                                         rhc->reg_host,
3213                                         rhc->host,
3214                                         cfg,
3215                                         GNUNET_NO);
3216     return;
3217   }
3218   rhc->state = RHC_GET_CFG;
3219   rhc->sub_op =  GNUNET_TESTBED_get_slave_config (rhc,
3220                                                   rhc->gateway2->controller,
3221                                                   rhc->reg_host);
3222 }
3223
3224
3225 /**
3226  * Iterator to match a registered host context
3227  *
3228  * @param cls pointer 2 pointer of RegisteredHostContext
3229  * @param key current key code
3230  * @param value value in the hash map
3231  * @return GNUNET_YES if we should continue to
3232  *         iterate,
3233  *         GNUNET_NO if not.
3234  */
3235 static int 
3236 reghost_match_iterator (void *cls,
3237                         const struct GNUNET_HashCode * key,
3238                         void *value)
3239 {
3240   struct RegisteredHostContext **rh = cls;
3241   struct RegisteredHostContext *rh_val = value;
3242
3243   if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
3244   {
3245     GNUNET_free (*rh);
3246     *rh = rh_val;
3247     return GNUNET_NO;
3248   }
3249   return GNUNET_YES;
3250 }
3251
3252
3253 /**
3254  * Function to generate the hashcode corresponding to a RegisteredHostContext
3255  *
3256  * @param reg_host the host which is being registered in RegisteredHostContext
3257  * @param host the host of the controller which has to connect to the above rhost
3258  * @return the hashcode
3259  */
3260 static struct GNUNET_HashCode
3261 hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
3262             struct GNUNET_TESTBED_Host *host)
3263 {
3264   struct GNUNET_HashCode hash;
3265   uint32_t host_ids[2];
3266
3267   host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
3268   host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
3269   GNUNET_CRYPTO_hash (host_ids, sizeof (host_ids), &hash);
3270   return hash;
3271 }
3272
3273
3274 /**
3275  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
3276  *
3277  * @param cls NULL
3278  * @param client identification of the client
3279  * @param message the actual message
3280  */
3281 static void
3282 handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
3283                         const struct GNUNET_MessageHeader *message)
3284 {
3285   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
3286   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
3287     {NULL, 0, 0}
3288   };
3289   struct Peer *peer;
3290   struct OverlayConnectContext *occ;
3291   struct GNUNET_TESTBED_Controller *peer2_controller;
3292   uint64_t operation_id;
3293   uint32_t p1;
3294   uint32_t p2; 
3295   uint32_t peer2_host_id;
3296
3297   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
3298   p1 = ntohl (msg->peer1);
3299   p2 = ntohl (msg->peer2);
3300   peer2_host_id = ntohl (msg->peer2_host_id);
3301   GNUNET_assert (p1 < peer_list_size);
3302   GNUNET_assert (NULL != peer_list[p1]);
3303   peer = peer_list[p1];
3304   operation_id = GNUNET_ntohll (msg->operation_id);  
3305   LOG_DEBUG ("Received overlay connect for peers %u and %u with op id: 0x%lx\n",
3306              p1, p2, operation_id);
3307   if (GNUNET_YES == peer->is_remote)
3308   {
3309     struct ForwardedOperationContext *fopc;
3310     struct Route *route_to_peer2_host;
3311     struct Route *route_to_peer1_host;
3312
3313     LOG_DEBUG ("Forwarding overlay connect\n");
3314     route_to_peer2_host = NULL;
3315     route_to_peer1_host = NULL;
3316     route_to_peer2_host = find_dest_route (peer2_host_id);
3317     if ((NULL != route_to_peer2_host) 
3318         || (peer2_host_id == master_context->host_id))
3319     {
3320       /* Peer 2 either below us OR with us */
3321       route_to_peer1_host = 
3322           find_dest_route (peer_list[p1]->details.remote.remote_host_id);
3323       /* Because we get this message only if we know where peer 1 is */
3324       GNUNET_assert (NULL != route_to_peer1_host);
3325       if ((peer2_host_id == master_context->host_id) 
3326           || (route_to_peer2_host->dest != route_to_peer1_host->dest))
3327       {
3328         /* Peer2 is either with us OR peer1 and peer2 can be reached through
3329            different gateways */
3330         struct GNUNET_HashCode hash;
3331         struct RegisteredHostContext *rhc;
3332         int skip_focc;
3333
3334         rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
3335         if (NULL != route_to_peer2_host)
3336           rhc->reg_host = host_list[route_to_peer2_host->dest];
3337         else
3338           rhc->reg_host = host_list[master_context->host_id];
3339         rhc->host = host_list[route_to_peer1_host->dest];
3340         GNUNET_assert (NULL != rhc->reg_host);
3341         GNUNET_assert (NULL != rhc->host);
3342         rhc->gateway = peer->details.remote.slave;
3343         rhc->gateway2 = (NULL == route_to_peer2_host) ? NULL :
3344             slave_list[route_to_peer2_host->dest];
3345         rhc->state = RHC_INIT;
3346         GNUNET_SERVER_client_keep (client);
3347         rhc->client = client;
3348         hash = hash_hosts (rhc->reg_host, rhc->host);
3349         skip_focc = GNUNET_NO;
3350         if ((GNUNET_NO == 
3351              GNUNET_CONTAINER_multihashmap_contains
3352              (peer->details.remote.slave->reghost_map, &hash))
3353             || (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple
3354                 (peer->details.remote.slave->reghost_map, &hash,
3355                  reghost_match_iterator, &rhc)))
3356         {
3357           /* create and add a new registerd host context */
3358           /* add the focc to its queue */
3359           GNUNET_CONTAINER_multihashmap_put
3360               (peer->details.remote.slave->reghost_map,
3361                &hash, rhc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3362           GNUNET_assert (NULL != host_list[peer2_host_id]);
3363           queue_host_registration (peer->details.remote.slave,
3364                                    registeredhost_registration_completion, rhc,
3365                                    host_list[peer2_host_id]);
3366         }
3367         else {
3368           /* rhc is now set to the existing one from the hash map by
3369              reghost_match_iterator() */
3370           /* if queue is empty then ignore creating focc and proceed with
3371              normal forwarding */                 
3372           if (RHC_OL_CONNECT == rhc->state)
3373             skip_focc = GNUNET_YES;
3374         }
3375         if (GNUNET_NO == skip_focc)
3376         {
3377           struct ForwardedOverlayConnectContext *focc;
3378
3379           focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
3380           focc->peer1 = p1;
3381           focc->peer2 = p2;
3382           focc->peer2_host_id = peer2_host_id;
3383           focc->orig_msg = GNUNET_copy_message (message);
3384           focc->operation_id = operation_id;
3385           GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
3386                                             rhc->focc_dll_tail,
3387                                             focc);
3388           GNUNET_SERVER_receive_done (client, GNUNET_OK);
3389           return;
3390         }
3391       }
3392     }
3393     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
3394     GNUNET_SERVER_client_keep (client);
3395     fopc->client = client;
3396     fopc->operation_id = operation_id;
3397     fopc->type = OP_OVERLAY_CONNECT;
3398     fopc->opc = 
3399         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.slave->controller,
3400                                                operation_id, message,
3401                                                &forwarded_operation_reply_relay,
3402                                                fopc);
3403     fopc->timeout_task =
3404         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
3405                                       fopc);
3406     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
3407     GNUNET_SERVER_receive_done (client, GNUNET_OK);
3408     return;
3409   }
3410
3411   peer2_controller = NULL;
3412   if ((p2 >= peer_list_size) || (NULL == peer_list[p2]))
3413   {   
3414     if ((peer2_host_id >= slave_list_size)
3415         || (NULL ==slave_list[peer2_host_id]))
3416     {
3417       LOG (GNUNET_ERROR_TYPE_WARNING,
3418            "Configuration of peer2's controller missing for connecting peers"
3419            "%u and %u\n", p1, p2);      
3420       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3421       return;
3422     }
3423     peer2_controller = slave_list[peer2_host_id]->controller;
3424     if (NULL == peer2_controller)
3425     {
3426       GNUNET_break (0);       /* What's going on? */
3427       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3428       return;
3429     }
3430   }
3431   else
3432   {
3433     if (GNUNET_YES == peer_list[p2]->is_remote)
3434       peer2_controller = peer_list[p2]->details.remote.slave->controller;
3435   }
3436   occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
3437   GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
3438   GNUNET_SERVER_client_keep (client);
3439   occ->client = client;
3440   occ->peer_id = p1;
3441   occ->other_peer_id = p2;
3442   occ->peer = peer_list[p1];
3443   occ->op_id = GNUNET_ntohll (msg->operation_id);
3444   occ->peer2_controller = peer2_controller;
3445   /* Get the identity of the second peer */
3446   if (NULL != occ->peer2_controller)
3447   {
3448     struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
3449
3450     cmsg.header.size = 
3451         htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
3452     cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG);
3453     cmsg.peer_id = msg->peer2;
3454     cmsg.operation_id = msg->operation_id;
3455     occ->opc = 
3456         GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
3457                                                occ->op_id, &cmsg.header,
3458                                                &overlay_connect_get_config,
3459                                                occ);
3460     occ->emsg = 
3461         GNUNET_strdup ("Timeout while getting peer identity of peer B\n");
3462     occ->timeout_task =
3463         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3464                                       (GNUNET_TIME_UNIT_SECONDS, 30),
3465                                       &timeout_overlay_connect, occ);
3466     GNUNET_SERVER_receive_done (client, GNUNET_OK);
3467     return;
3468   }
3469   GNUNET_TESTING_peer_get_identity (peer_list[occ->other_peer_id]->details.local.peer,
3470                                     &occ->other_peer_identity);
3471   /* Connect to the core of 1st peer and wait for the 2nd peer to connect */
3472   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
3473   occ->peer->reference_cnt++;
3474   occ->ch =
3475       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
3476                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
3477                            GNUNET_NO, no_handlers);
3478   if (NULL == occ->ch)
3479     occ->timeout_task = 
3480         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
3481   else
3482     occ->timeout_task =
3483         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3484                                       (GNUNET_TIME_UNIT_SECONDS, 30),
3485                                       &timeout_overlay_connect, occ);
3486   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3487 }
3488
3489
3490 /**
3491  * Function to cleanup RequestOverlayConnectContext and any associated tasks
3492  * with it
3493  *
3494  * @param rocc the RequestOverlayConnectContext
3495  */
3496 static void
3497 cleanup_rocc (struct RequestOverlayConnectContext *rocc)
3498 {
3499   if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
3500     GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
3501   if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
3502     GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
3503   GNUNET_TRANSPORT_disconnect (rocc->th);
3504   if (NULL != rocc->tch)
3505     GNUNET_TRANSPORT_try_connect_cancel (rocc->tch);
3506   if (NULL != rocc->ohh)
3507     GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
3508   GNUNET_free_non_null (rocc->hello);
3509   GNUNET_CONTAINER_DLL_remove (roccq_head, roccq_tail, rocc);
3510   GNUNET_free (rocc);
3511 }
3512
3513
3514 /**
3515  * Task to timeout rocc and cleanit up
3516  *
3517  * @param cls the RequestOverlayConnectContext
3518  * @param tc the TaskContext from scheduler
3519  */
3520 static void
3521 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3522 {
3523   struct RequestOverlayConnectContext *rocc = cls;
3524   
3525   rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
3526   cleanup_rocc (rocc);
3527 }
3528
3529
3530 /**
3531  * Function called to notify transport users that another
3532  * peer connected to us.
3533  *
3534  * @param cls closure
3535  * @param new_peer the peer that connected
3536  * @param ats performance data
3537  * @param ats_count number of entries in ats (excluding 0-termination)
3538  */
3539 static void 
3540 transport_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
3541                           const struct GNUNET_ATS_Information * ats,
3542                           uint32_t ats_count)
3543 {
3544   struct RequestOverlayConnectContext *rocc = cls;
3545
3546   LOG_DEBUG ("Request Overlay connect notify\n");
3547   if (0 != memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)))
3548     return;
3549   LOG_DEBUG ("Peer %4s connected\n", GNUNET_i2s (&rocc->a_id));
3550   cleanup_rocc (rocc);
3551 }
3552
3553
3554 /**
3555  * Callback to be called with result of the try connect request.
3556  *
3557  * @param cls the overlay connect context
3558  * @param result GNUNET_OK if message was transmitted to transport service
3559  *               GNUNET_SYSERR if message was not transmitted to transport service
3560  */
3561 static void 
3562 rocc_try_connect_cb (void *cls, const int result)
3563 {
3564   struct RequestOverlayConnectContext *rocc = cls;
3565   
3566   rocc->tch = NULL;
3567   rocc->tch = GNUNET_TRANSPORT_try_connect (rocc->th, &rocc->a_id,
3568                                             &rocc_try_connect_cb, rocc);
3569 }
3570
3571
3572 /**
3573  * Task to offer the HELLO message to the peer and ask it to connect to the peer
3574  * whose identity is in RequestOverlayConnectContext
3575  *
3576  * @param cls the RequestOverlayConnectContext
3577  * @param tc the TaskContext from scheduler
3578  */
3579 static void
3580 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
3581
3582
3583 /**
3584  * Task that is run when hello has been sent
3585  *
3586  * @param cls the overlay connect context
3587  * @param tc the scheduler task context; if tc->reason =
3588  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
3589  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
3590  */
3591 static void
3592 rocc_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3593 {
3594   struct RequestOverlayConnectContext *rocc = cls;
3595   
3596   rocc->ohh = NULL;
3597   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rocc->attempt_connect_task_id);
3598   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
3599     goto schedule_attempt_connect;
3600   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
3601     return;
3602   rocc->tch = GNUNET_TRANSPORT_try_connect (rocc->th, &rocc->a_id,
3603                                             &rocc_try_connect_cb, rocc);
3604   if (NULL != rocc->tch)
3605     return;
3606    GNUNET_break (0);
3607    
3608  schedule_attempt_connect:
3609    rocc->attempt_connect_task_id =
3610        GNUNET_SCHEDULER_add_now (&attempt_connect_task,
3611                                  rocc);
3612 }
3613
3614
3615 /**
3616  * Task to offer the HELLO message to the peer and ask it to connect to the peer
3617  * whose identity is in RequestOverlayConnectContext
3618  *
3619  * @param cls the RequestOverlayConnectContext
3620  * @param tc the TaskContext from scheduler
3621  */
3622 static void
3623 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3624 {
3625   struct RequestOverlayConnectContext *rocc = cls;
3626
3627   rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
3628   rocc->ohh = GNUNET_TRANSPORT_offer_hello (rocc->th, rocc->hello,
3629                                             rocc_hello_sent_cb, rocc);
3630   if (NULL == rocc->ohh)
3631     rocc->attempt_connect_task_id = 
3632         GNUNET_SCHEDULER_add_delayed 
3633         (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
3634                                         100 + GNUNET_CRYPTO_random_u32
3635                                         (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
3636          &attempt_connect_task, rocc);
3637 }
3638
3639
3640 /**
3641  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
3642  *
3643  * @param cls NULL
3644  * @param client identification of the client
3645  * @param message the actual message
3646  */
3647 static void
3648 handle_overlay_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
3649                                 const struct GNUNET_MessageHeader *message)
3650 {
3651   const struct GNUNET_TESTBED_RequestConnectMessage *msg;
3652   struct RequestOverlayConnectContext *rocc;
3653   struct Peer *peer;
3654   uint32_t peer_id;
3655   uint16_t msize;
3656   uint16_t hsize;
3657   
3658   msize = ntohs (message->size);
3659   if (sizeof (struct GNUNET_TESTBED_RequestConnectMessage) >= msize)
3660   {
3661     GNUNET_break (0);
3662     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3663     return;
3664   }  
3665   msg = (const struct GNUNET_TESTBED_RequestConnectMessage *) message;
3666   if ((NULL == msg->hello) || 
3667       (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
3668   {
3669     GNUNET_break (0);
3670     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3671     return;
3672   }
3673   hsize = ntohs (msg->hello->size);
3674   if ((sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hsize) != msize)
3675   {
3676     GNUNET_break (0);
3677     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3678     return;
3679   }
3680   peer_id = ntohl (msg->peer);
3681   if ((peer_id >= peer_list_size) || (NULL == (peer = peer_list[peer_id])))
3682   {
3683     GNUNET_break_op (0);
3684     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3685     return;
3686   }
3687   if (GNUNET_YES == peer->is_remote)
3688   {
3689     struct GNUNET_MessageHeader *msg2;
3690     
3691     msg2 = GNUNET_copy_message (message);
3692     GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller, msg2);
3693     GNUNET_SERVER_receive_done (client, GNUNET_OK);
3694     return;
3695   }
3696   rocc = GNUNET_malloc (sizeof (struct RequestOverlayConnectContext));
3697   GNUNET_CONTAINER_DLL_insert_tail (roccq_head, roccq_tail, rocc);
3698   rocc->th = GNUNET_TRANSPORT_connect (peer->details.local.cfg, NULL, rocc, 
3699                                        NULL, &transport_connect_notify, NULL);
3700   if (NULL == rocc->th)
3701   {
3702     GNUNET_break (0);
3703     GNUNET_free (rocc);
3704     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3705     return;
3706   }
3707   memcpy (&rocc->a_id, &msg->peer_identity,
3708           sizeof (struct GNUNET_PeerIdentity));
3709   rocc->hello = GNUNET_malloc (hsize);
3710   memcpy (rocc->hello, msg->hello, hsize);
3711   rocc->attempt_connect_task_id =
3712       GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
3713   rocc->timeout_rocc_task_id =
3714       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
3715   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3716 }
3717
3718
3719 /**
3720  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
3721  *
3722  * @param cls NULL
3723  * @param client identification of the client
3724  * @param message the actual message
3725  */
3726 static void
3727 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
3728                          const struct GNUNET_MessageHeader *message)
3729 {
3730   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
3731   struct Slave *slave;  
3732   struct GNUNET_TESTBED_SlaveConfiguration *reply;
3733   char *config;
3734   char *xconfig;
3735   size_t config_size;
3736   size_t xconfig_size;
3737   size_t reply_size;
3738   uint64_t op_id;
3739   uint32_t slave_id;
3740
3741   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
3742   slave_id = ntohl (msg->slave_id);
3743   op_id = GNUNET_ntohll (msg->operation_id);
3744   if ((slave_list_size <= slave_id) || (NULL == slave_list[slave_id]))
3745   {
3746     /* FIXME: Add forwardings for this type of message here.. */
3747     send_operation_fail_msg (client, op_id, "Slave not found");
3748     GNUNET_SERVER_receive_done (client, GNUNET_OK);
3749     return;
3750   }
3751   slave = slave_list[slave_id];
3752   if (NULL == slave->cfg)
3753   {
3754     send_operation_fail_msg (client, op_id,
3755                              "Configuration not found (slave not started by me)");
3756     GNUNET_SERVER_receive_done (client, GNUNET_OK);
3757     return;
3758   }
3759   config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
3760   xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size, 
3761                                                   &xconfig);
3762   GNUNET_free (config);  
3763   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
3764   GNUNET_break (reply_size <= UINT16_MAX);
3765   GNUNET_break (config_size <= UINT16_MAX);
3766   reply = GNUNET_realloc (xconfig, reply_size);
3767   (void) memmove (&reply[1], reply, xconfig_size);
3768   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG);
3769   reply->header.size = htons ((uint16_t) reply_size);
3770   reply->slave_id = msg->slave_id;
3771   reply->operation_id = msg->operation_id;
3772   reply->config_size = htons ((uint16_t) config_size);
3773   queue_message (client, &reply->header);
3774   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3775 }
3776
3777
3778 /**
3779  * Iterator over hash map entries.
3780  *
3781  * @param cls closure
3782  * @param key current key code
3783  * @param value value in the hash map
3784  * @return GNUNET_YES if we should continue to
3785  *         iterate,
3786  *         GNUNET_NO if not.
3787  */
3788 static int
3789 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
3790 {
3791   struct SharedService *ss = value;
3792
3793   GNUNET_assert (GNUNET_YES ==
3794                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
3795   GNUNET_free (ss->name);
3796   GNUNET_free (ss);
3797   return GNUNET_YES;
3798 }
3799
3800
3801 /**
3802  * Iterator for freeing hash map entries in a slave's reghost_map
3803  *
3804  * @param cls handle to the slave
3805  * @param key current key code
3806  * @param value value in the hash map
3807  * @return GNUNET_YES if we should continue to
3808  *         iterate,
3809  *         GNUNET_NO if not.
3810  */
3811 static int 
3812 reghost_free_iterator (void *cls,
3813                        const struct GNUNET_HashCode * key,
3814                        void *value)
3815 {
3816   struct Slave *slave = cls;
3817   struct RegisteredHostContext *rhc = value;
3818   struct ForwardedOverlayConnectContext *focc;
3819
3820   GNUNET_assert (GNUNET_YES ==
3821                  GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map,
3822                                                        key, value));
3823   while (NULL != (focc = rhc->focc_dll_head))
3824   {
3825     GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head,
3826                                  rhc->focc_dll_tail,
3827                                  focc);
3828     cleanup_focc (focc);
3829   }
3830   if (NULL != rhc->sub_op)
3831     GNUNET_TESTBED_operation_done (rhc->sub_op);
3832   if (NULL != rhc->client)
3833   GNUNET_SERVER_client_drop (rhc->client);
3834   GNUNET_free (value);
3835   return GNUNET_YES;
3836 }
3837
3838
3839 /**
3840  * Task to clean up and shutdown nicely
3841  *
3842  * @param cls NULL
3843  * @param tc the TaskContext from scheduler
3844  */
3845 static void
3846 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3847 {
3848   struct LCFContextQueue *lcfq;
3849   struct OverlayConnectContext *occ;
3850   struct RequestOverlayConnectContext *rocc;
3851   struct ForwardedOperationContext *fopc;
3852   struct MessageQueue *mq_entry;
3853   uint32_t id;
3854
3855   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
3856   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
3857   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
3858                                                 NULL);
3859   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
3860   /* cleanup any remaining forwarded operations */
3861   while (NULL != (fopc = fopcq_head))
3862   {
3863     GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
3864     GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
3865     if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
3866       GNUNET_SCHEDULER_cancel (fopc->timeout_task);
3867     GNUNET_SERVER_client_drop (fopc->client);
3868     switch (fopc->type)
3869     {
3870     case OP_PEER_CREATE:
3871       GNUNET_free (fopc->cls);
3872       break;
3873     case OP_PEER_START:
3874     case OP_PEER_STOP:
3875     case OP_PEER_DESTROY:
3876     case OP_PEER_INFO:
3877     case OP_OVERLAY_CONNECT:
3878     case OP_LINK_CONTROLLERS:
3879     case OP_GET_SLAVE_CONFIG:
3880       break;
3881     case OP_FORWARDED:
3882       GNUNET_assert (0);
3883     };
3884     GNUNET_free (fopc);
3885   }
3886   if (NULL != lcfq_head)
3887   {
3888     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
3889     {
3890       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
3891       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
3892     }
3893   }
3894   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
3895   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
3896   {
3897     GNUNET_free (lcfq->lcf->msg);
3898     GNUNET_free (lcfq->lcf);
3899     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
3900     GNUNET_free (lcfq);
3901   }
3902   while (NULL != (occ = occq_head))
3903     cleanup_occ (occ);
3904   while (NULL != (rocc = roccq_head))
3905     cleanup_rocc (rocc);
3906   /* Clear peer list */
3907   for (id = 0; id < peer_list_size; id++)
3908     if (NULL != peer_list[id])
3909     {
3910       /* If destroy flag is set it means that this peer should have been
3911          destroyed by a context which we destroy before */
3912       GNUNET_break (GNUNET_NO == peer_list[id]->destroy_flag);
3913       /* counter should be zero as we free all contexts before */
3914       GNUNET_break (0 == peer_list[id]->reference_cnt);
3915       if (GNUNET_NO == peer_list[id]->is_remote)
3916       {
3917         if (GNUNET_YES == peer_list[id]->details.local.is_running)
3918           GNUNET_TESTING_peer_stop (peer_list[id]->details.local.peer);
3919         GNUNET_TESTING_peer_destroy (peer_list[id]->details.local.peer);
3920         GNUNET_CONFIGURATION_destroy (peer_list[id]->details.local.cfg);
3921       }
3922       GNUNET_free (peer_list[id]);
3923     }
3924   GNUNET_free_non_null (peer_list);
3925   /* Clear host list */
3926   for (id = 0; id < host_list_size; id++)
3927     if (NULL != host_list[id])
3928       GNUNET_TESTBED_host_destroy (host_list[id]);
3929   GNUNET_free_non_null (host_list);
3930   /* Clear route list */
3931   for (id = 0; id < route_list_size; id++)
3932     if (NULL != route_list[id])
3933       GNUNET_free (route_list[id]);
3934   GNUNET_free_non_null (route_list);
3935   /* Clear slave_list */
3936   for (id = 0; id < slave_list_size; id++)
3937     if (NULL != slave_list[id])
3938     {
3939       struct HostRegistration *hr_entry;
3940       
3941       while (NULL != (hr_entry = slave_list[id]->hr_dll_head))
3942       {
3943         GNUNET_CONTAINER_DLL_remove (slave_list[id]->hr_dll_head,
3944                                      slave_list[id]->hr_dll_tail,
3945                                      hr_entry);
3946         GNUNET_free (hr_entry);
3947       }
3948       if (NULL != slave_list[id]->rhandle)
3949         GNUNET_TESTBED_cancel_registration (slave_list[id]->rhandle);
3950       (void) GNUNET_CONTAINER_multihashmap_iterate (slave_list[id]->reghost_map,
3951                                                     reghost_free_iterator,
3952                                                     slave_list[id]);
3953       GNUNET_CONTAINER_multihashmap_destroy (slave_list[id]->reghost_map);
3954       if (NULL != slave_list[id]->cfg)
3955         GNUNET_CONFIGURATION_destroy (slave_list[id]->cfg);
3956       if (NULL != slave_list[id]->controller)
3957         GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
3958       if (NULL != slave_list[id]->controller_proc)
3959         GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
3960       GNUNET_free (slave_list[id]);
3961     }
3962   GNUNET_free_non_null (slave_list);
3963   if (NULL != master_context)
3964   {
3965     GNUNET_free_non_null (master_context->master_ip);
3966     if (NULL != master_context->system)
3967       GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
3968     GNUNET_SERVER_client_drop (master_context->client);
3969     GNUNET_free (master_context);
3970     master_context = NULL;
3971   }
3972   if (NULL != transmit_handle)
3973     GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);  
3974   while (NULL != (mq_entry = mq_head))
3975   {
3976     GNUNET_free (mq_entry->msg);
3977     GNUNET_SERVER_client_drop (mq_entry->client);
3978     GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);    
3979     GNUNET_free (mq_entry);
3980   }
3981   GNUNET_free_non_null (hostname);
3982   GNUNET_CONFIGURATION_destroy (our_config);
3983 }
3984
3985
3986 /**
3987  * Callback for client disconnect
3988  *
3989  * @param cls NULL
3990  * @param client the client which has disconnected
3991  */
3992 static void
3993 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
3994 {
3995   if (NULL == master_context)
3996     return;
3997   if (client == master_context->client)
3998   {
3999     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
4000     /* should not be needed as we're terminated by failure to read
4001      * from stdin, but if stdin fails for some reason, this shouldn't
4002      * hurt for now --- might need to revise this later if we ever
4003      * decide that master connections might be temporarily down
4004      * for some reason */
4005     //GNUNET_SCHEDULER_shutdown ();
4006   }
4007 }
4008
4009
4010 /**
4011  * Testbed setup
4012  *
4013  * @param cls closure
4014  * @param server the initialized server
4015  * @param cfg configuration to use
4016  */
4017 static void
4018 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
4019              const struct GNUNET_CONFIGURATION_Handle *cfg)
4020 {
4021   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
4022     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
4023     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
4024     {&handle_configure_shared_service, NULL,
4025      GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
4026     {&handle_link_controllers, NULL,
4027      GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
4028     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER, 0},
4029     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER,
4030      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
4031     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STARTPEER,
4032      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
4033     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOPPEER,
4034      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
4035     {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG,
4036      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
4037     {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT,
4038      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
4039     {&handle_overlay_request_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT,
4040      0},
4041     {handle_slave_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG,
4042      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
4043     {NULL}
4044   };
4045
4046   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string 
4047                  (cfg, "testbed", "HOSTNAME", &hostname));
4048   our_config = GNUNET_CONFIGURATION_dup (cfg);
4049   GNUNET_SERVER_add_handlers (server, message_handlers);
4050   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
4051   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
4052   shutdown_task_id =
4053       GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
4054                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
4055                                                   &shutdown_task, NULL);
4056   LOG_DEBUG ("Testbed startup complete\n");
4057   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
4058 }
4059
4060
4061 /**
4062  * The starting point of execution
4063  */
4064 int
4065 main (int argc, char *const *argv)
4066 {
4067   //sleep (15);                 /* Debugging */
4068   return (GNUNET_OK ==
4069           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
4070                               &testbed_run, NULL)) ? 0 : 1;
4071 }
4072
4073 /* end of gnunet-service-testbed.c */