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