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