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