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