controller linking with host ids
[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  * Structure representing a connected(directly-linked) controller
164  */
165 struct Slave
166 {
167   /**
168    * The controller process handle if we had started the controller
169    */
170   struct GNUNET_TESTBED_ControllerProc *controller_proc;
171
172   /**
173    * The controller handle
174    */
175   struct GNUNET_TESTBED_Controller *controller;
176
177   /**
178    * The configuration of the slave. Cannot be NULL
179    */
180   struct GNUNET_CONFIGURATION_Handle *cfg;
181
182   /**
183    * handle to lcc which is associated with this slave startup. Should be set to
184    * NULL when the slave has successfully started up
185    */
186   struct LinkControllersContext *lcc;
187
188   /**
189    * The id of the host this controller is running on
190    */
191   uint32_t host_id;
192 };
193
194
195 /**
196  * States of LCFContext
197  */
198 enum LCFContextState
199 {
200   /**
201    * The Context has been initialized; Nothing has been done on it
202    */
203   INIT,
204
205   /**
206    * Delegated host has been registered at the forwarding controller
207    */
208   DELEGATED_HOST_REGISTERED,
209   
210   /**
211    * The slave host has been registred at the forwarding controller
212    */
213   SLAVE_HOST_REGISTERED,
214   
215   /**
216    * The context has been finished (may have error)
217    */
218   FINISHED
219 };
220
221
222 /**
223  * Link controllers request forwarding context
224  */
225 struct LCFContext
226 {
227   /**
228    * The gateway which will pass the link message to delegated host
229    */
230   struct Slave *gateway;
231
232   /**
233    * The controller link message that has to be forwarded to
234    */
235   struct GNUNET_TESTBED_ControllerLinkMessage *msg;
236
237   /**
238    * The client which has asked to perform this operation
239    */
240   struct GNUNET_SERVER_Client *client;
241
242   /**
243    * The host registration handle while registered hosts in this context
244    */
245   struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
246
247   /**
248    * The id of the operation which created this context
249    */
250   uint64_t operation_id;
251
252   /**
253    * The state of this context
254    */
255   enum LCFContextState state;
256
257   /**
258    * The delegated host
259    */
260   uint32_t delegated_host_id;
261
262   /**
263    * The slave host
264    */
265   uint32_t slave_host_id;
266
267 };
268
269
270 /**
271  * Structure of a queue entry in LCFContext request queue
272  */
273 struct LCFContextQueue
274 {
275   /**
276    * The LCFContext
277    */
278   struct LCFContext *lcf;
279
280   /**
281    * Head prt for DLL
282    */
283   struct LCFContextQueue *next;
284
285   /**
286    * Tail ptr for DLL
287    */
288   struct LCFContextQueue *prev;
289 };
290
291
292 /**
293  * A peer
294  */
295 struct Peer
296 {
297   union
298   {
299     struct
300     {
301       /**
302        * The peer handle from testing API
303        */
304       struct GNUNET_TESTING_Peer *peer;
305
306       /**
307        * The modified (by GNUNET_TESTING_peer_configure) configuration this
308        * peer is configured with
309        */
310       struct GNUNET_CONFIGURATION_Handle *cfg;
311       
312       /**
313        * Is the peer running
314        */
315       int is_running;
316
317     } local;
318
319     struct
320     {
321       /**
322        * The controller this peer is started through
323        */
324       struct GNUNET_TESTBED_Controller *controller;
325
326       /**
327        * The id of the remote host this peer is running on
328        */
329       uint32_t remote_host_id;
330
331     } remote;
332
333   } details;
334
335   /**
336    * Is this peer locally created?
337    */
338   int is_remote;
339
340   /**
341    * Our local reference id for this peer
342    */
343   uint32_t id;
344
345 };
346
347
348 /**
349  * Context information for connecting 2 peers in overlay
350  */
351 struct OverlayConnectContext
352 {
353   /**
354    * The client which has requested for overlay connection
355    */
356   struct GNUNET_SERVER_Client *client;
357
358   /**
359    * the peer which has to connect to the other peer
360    */
361   struct Peer *peer;
362
363   /**
364    * Transport handle of the first peer to get its HELLO
365    */
366   struct GNUNET_TRANSPORT_Handle *p1th;
367
368   /**
369    * Transport handle of other peer to offer first peer's HELLO
370    */
371   struct GNUNET_TRANSPORT_Handle *p2th;
372
373   /**
374    * Core handles of the first peer; used to notify when second peer connects to it
375    */
376   struct GNUNET_CORE_Handle *ch;
377
378   /**
379    * HELLO of the other peer
380    */
381   struct GNUNET_MessageHeader *hello;
382
383   /**
384    * Get hello handle to acquire HELLO of first peer
385    */
386   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
387
388   /**
389    * The error message we send if this overlay connect operation has timed out
390    */
391   char *emsg;
392
393   /**
394    * Operation context for suboperations
395    */
396   struct OperationContext *opc;
397
398   /**
399    * Controller of peer 2; NULL if the peer is local
400    */
401   struct GNUNET_TESTBED_Controller *peer2_controller;
402
403   /**
404    * The peer identity of the first peer
405    */
406   struct GNUNET_PeerIdentity peer_identity;
407
408   /**
409    * The peer identity of the other peer
410    */
411   struct GNUNET_PeerIdentity other_peer_identity;
412
413   /**
414    * The id of the operation responsible for creating this context
415    */
416   uint64_t op_id;
417
418   /**
419    * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
420    * connect to peer 2
421    */
422   GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
423
424   /**
425    * The id of the overlay connect timeout task
426    */
427   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
428
429   /**
430    * The id of peer A
431    */
432   uint32_t peer_id;
433
434   /**
435    * The id of peer B
436    */
437   uint32_t other_peer_id;
438
439   /**
440    * Number of times we tried to send hello; used to increase delay in offering
441    * hellos
442    */
443   uint16_t retries;
444 };
445
446
447 /**
448  * Context information for RequestOverlayConnect
449  * operations. RequestOverlayConnect is used when peers A, B reside on different
450  * hosts and the host controller for peer B is asked by the host controller of
451  * peer A to make peer B connect to peer A
452  */
453 struct RequestOverlayConnectContext
454 {
455   /**
456    * The transport handle of peer B
457    */
458   struct GNUNET_TRANSPORT_Handle *th;
459   
460   /**
461    * Peer A's HELLO
462    */
463   struct GNUNET_MessageHeader *hello;
464
465   /**
466    * The peer identity of peer A
467    */
468   struct GNUNET_PeerIdentity a_id;
469
470   /**
471    * Task for offering HELLO of A to B and doing try_connect
472    */
473   GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
474   
475   /**
476    * Task to timeout RequestOverlayConnect
477    */
478   GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
479   
480   /**
481    * Number of times we tried to send hello; used to increase delay in offering
482    * hellos
483    */
484   uint16_t retries;
485   
486 };
487
488
489 /**
490  * Context information for operations forwarded to subcontrollers
491  */
492 struct ForwardedOperationContext
493 {
494   /**
495    * The generated operation context
496    */
497   struct OperationContext *opc;
498
499   /**
500    * The client to which we have to reply
501    */
502   struct GNUNET_SERVER_Client *client;
503
504   /**
505    * Closure pointer
506    */
507   void *cls;
508
509   /**
510    * Task ID for the timeout task
511    */
512   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
513
514   /**
515    * The id of the operation that has been forwarded
516    */
517   uint64_t operation_id;
518
519 };
520
521
522 /**
523  * Context information used while linking controllers
524  */
525 struct LinkControllersContext
526 {
527   /**
528    * The client which initiated the link controller operation
529    */
530   struct GNUNET_SERVER_Client *client;
531
532   /**
533    * The ID of the operation
534    */
535   uint64_t operation_id;
536
537 };
538
539
540 /**
541  * Context information to used during operations which forward the overlay
542  * connect message
543  */
544 struct ForwardedOverlayConnectContext
545 {
546   /**
547    * The gateway controller to which this operation is forwarded to
548    */
549   struct GNUNET_TESTBED_Controller *gateway;
550
551   /**
552    * The gateway controller through which peer2's controller can be reached
553    */
554   struct GNUNET_TESTBED_Controller *gateway2;
555
556   /**
557    * Handle for sub-operations
558    */
559   struct GNUNET_TESTBED_Operation *sub_op;
560
561   /**
562    * Enumeration of states for this context
563    */
564   enum FOCCState {
565
566     /**
567      * The initial state
568      */
569     FOCC_INIT = 0,
570
571     /**
572      * State where we attempt to get peer2's controller configuration
573      */
574     FOCC_GET_CFG,
575
576     /**
577      * State where we attempt to link the controller of peer 1 to the controller
578      * of peer2
579      */
580     FOCC_LINK,
581
582     /**
583      * State where we attempt to do the overlay connection again
584      */
585     FOCC_OL_CONNECT
586     
587   } state;
588
589   /**
590    * the id of peer 1
591    */
592   uint32_t peer1;
593   
594   /**
595    * The id of peer 2
596    */
597   uint32_t peer2;
598   
599   /**
600    * Id of the host where peer2 is running
601    */
602   uint32_t peer2_host_id;
603 };
604
605
606
607 /**
608  * The master context; generated with the first INIT message
609  */
610 static struct Context *master_context;
611
612 /**
613  * Our hostname; we give this to all the peers we start
614  */
615 static char *hostname;
616
617 /***********/
618 /* Handles */
619 /***********/
620
621 /**
622  * Current Transmit Handle; NULL if no notify transmit exists currently
623  */
624 static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
625
626 /****************/
627 /* Lists & Maps */
628 /****************/
629
630 /**
631  * The head for the LCF queue
632  */
633 static struct LCFContextQueue *lcfq_head;
634
635 /**
636  * The tail for the LCF queue
637  */
638 static struct LCFContextQueue *lcfq_tail;
639
640 /**
641  * The message queue head
642  */
643 static struct MessageQueue *mq_head;
644
645 /**
646  * The message queue tail
647  */
648 static struct MessageQueue *mq_tail;
649
650 /**
651  * Array of host list
652  */
653 static struct GNUNET_TESTBED_Host **host_list;
654
655 /**
656  * A list of routes
657  */
658 static struct Route **route_list;
659
660 /**
661  * A list of directly linked neighbours
662  */
663 static struct Slave **slave_list;
664
665 /**
666  * A list of peers we know about
667  */
668 static struct Peer **peer_list;
669
670 /**
671  * The hashmap of shared services
672  */
673 static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
674
675 /**
676  * The event mask for the events we listen from sub-controllers
677  */
678 static uint64_t event_mask;
679
680 /**
681  * The size of the host list
682  */
683 static uint32_t host_list_size;
684
685 /**
686  * The size of the route list
687  */
688 static uint32_t route_list_size;
689
690 /**
691  * The size of directly linked neighbours list
692  */
693 static uint32_t slave_list_size;
694
695 /**
696  * The size of the peer list
697  */
698 static uint32_t peer_list_size;
699
700 /*********/
701 /* Tasks */
702 /*********/
703
704 /**
705  * The lcf_task handle
706  */
707 static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
708
709 /**
710  * The shutdown task handle
711  */
712 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
713
714
715 /**
716  * Function called to notify a client about the connection begin ready to queue
717  * more data.  "buf" will be NULL and "size" zero if the connection was closed
718  * for writing in the meantime.
719  *
720  * @param cls NULL
721  * @param size number of bytes available in buf
722  * @param buf where the callee should write the message
723  * @return number of bytes written to buf
724  */
725 static size_t
726 transmit_ready_notify (void *cls, size_t size, void *buf)
727 {
728   struct MessageQueue *mq_entry;
729
730   transmit_handle = NULL;
731   mq_entry = mq_head;
732   GNUNET_assert (NULL != mq_entry);
733   if (0 == size)
734     return 0;
735   GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
736   size = ntohs (mq_entry->msg->size);
737   memcpy (buf, mq_entry->msg, size);
738   GNUNET_free (mq_entry->msg);
739   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
740   GNUNET_free (mq_entry);
741   mq_entry = mq_head;
742   if (NULL != mq_entry)
743     transmit_handle =
744         GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
745                                              ntohs (mq_entry->msg->size),
746                                              GNUNET_TIME_UNIT_FOREVER_REL,
747                                              &transmit_ready_notify, NULL);
748   return size;
749 }
750
751
752 /**
753  * Queues a message in send queue for sending to the service
754  *
755  * @param client the client to whom the queued message has to be sent
756  * @param msg the message to queue
757  */
758 static void
759 queue_message (struct GNUNET_SERVER_Client *client,
760                struct GNUNET_MessageHeader *msg)
761 {
762   struct MessageQueue *mq_entry;
763   uint16_t type;
764   uint16_t size;
765
766   type = ntohs (msg->type);
767   size = ntohs (msg->size);
768   GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
769                  (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
770   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
771   mq_entry->msg = msg;
772   mq_entry->client = client;
773   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
774              ntohs (msg->size));
775   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
776   if (NULL == transmit_handle)
777     transmit_handle =
778         GNUNET_SERVER_notify_transmit_ready (client, size,
779                                              GNUNET_TIME_UNIT_FOREVER_REL,
780                                              &transmit_ready_notify, NULL);
781 }
782
783
784 /**
785  * Similar to GNUNET_realloc; however clears tail part of newly allocated memory
786  *
787  * @param ptr the memory block to realloc
788  * @param size the size of ptr
789  * @param new_size the size to which ptr has to be realloc'ed
790  * @return the newly reallocated memory block
791  */
792 static void *
793 TESTBED_realloc (void *ptr, size_t size, size_t new_size)
794 {
795   ptr = GNUNET_realloc (ptr, new_size);
796   if (new_size > size)
797     (void) memset (ptr + size, 0, new_size - size);
798   return ptr;
799 }
800
801
802 /**
803  * Function to add a host to the current list of known hosts
804  *
805  * @param host the host to add
806  * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
807  *           already in use
808  */
809 static int
810 host_list_add (struct GNUNET_TESTBED_Host *host)
811 {
812   uint32_t host_id;
813   uint32_t orig_size;
814
815   host_id = GNUNET_TESTBED_host_get_id_ (host);
816   orig_size = host_list_size;  
817   if (host_list_size <= host_id)
818   {
819     while (host_list_size <= host_id)
820       host_list_size += LIST_GROW_STEP;
821     host_list =
822         TESTBED_realloc (host_list,
823                          sizeof (struct GNUNET_TESTBED_Host *) * orig_size,
824                          sizeof (struct GNUNET_TESTBED_Host *)
825                          * host_list_size);
826   }
827   if (NULL != host_list[host_id])
828   {
829     LOG_DEBUG ("A host with id: %u already exists\n", host_id);
830     return GNUNET_SYSERR;
831   }
832   host_list[host_id] = host;
833   return GNUNET_OK;
834 }
835
836
837 /**
838  * Adds a route to the route list
839  *
840  * @param route the route to add
841  */
842 static void
843 route_list_add (struct Route *route)
844 {
845   uint32_t orig_size;
846
847   orig_size = route_list_size;  
848   if (route->dest >= route_list_size)
849   {
850     while (route->dest >= route_list_size)
851       route_list_size += LIST_GROW_STEP;
852     route_list =
853         TESTBED_realloc (route_list,
854                          sizeof (struct Route *) * orig_size,
855                          sizeof (struct Route *) * route_list_size);
856   }
857   GNUNET_assert (NULL == route_list[route->dest]);
858   route_list[route->dest] = route;
859 }
860
861
862 /**
863  * Adds a slave to the slave array
864  *
865  * @param slave the slave controller to add
866  */
867 static void
868 slave_list_add (struct Slave *slave)
869 {
870   if (slave->host_id >= slave_list_size)
871   {
872     slave_list =
873         TESTBED_realloc (slave_list, sizeof (struct Slave *) * slave_list_size,
874                          sizeof (struct Slave *) * (slave_list_size +
875                                                     LIST_GROW_STEP));
876     slave_list_size += LIST_GROW_STEP;
877   }
878   GNUNET_assert (NULL == slave_list[slave->host_id]);
879   slave_list[slave->host_id] = slave;
880 }
881
882
883 /**
884  * Adds a peer to the peer array
885  *
886  * @param peer the peer to add
887  */
888 static void
889 peer_list_add (struct Peer *peer)
890 {
891   uint32_t orig_size;
892
893   orig_size = peer_list_size;
894   if (peer->id >= peer_list_size)
895   {
896     while (peer->id >= peer_list_size)
897       peer_list_size += LIST_GROW_STEP;
898     peer_list =
899         TESTBED_realloc (peer_list, sizeof (struct Peer *) * orig_size,
900                          sizeof (struct Peer *) * peer_list_size);
901   }  
902   GNUNET_assert (NULL == peer_list[peer->id]);
903   peer_list[peer->id] = peer;
904 }
905
906
907 /**
908  * Removes a the give peer from the peer array
909  *
910  * @param peer the peer to be removed
911  */
912 static void
913 peer_list_remove (struct Peer *peer)
914 {
915   uint32_t id;
916   uint32_t orig_size;
917
918   peer_list[peer->id] = NULL;
919   orig_size = peer_list_size;
920   while (peer_list_size >= LIST_GROW_STEP)
921   {
922     for (id = peer_list_size - 1;
923          (id >= peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); id--)
924       if (NULL != peer_list[id])
925         break;
926     if (id != ((peer_list_size - LIST_GROW_STEP) - 1))
927       break;
928     peer_list_size -= LIST_GROW_STEP;
929   }
930   if (orig_size == peer_list_size)
931     return;
932   peer_list =
933       GNUNET_realloc (peer_list, sizeof (struct Peer *) * peer_list_size);
934 }
935
936
937 /**
938  * Finds the route with directly connected host as destination through which
939  * the destination host can be reached
940  *
941  * @param host_id the id of the destination host
942  * @return the route with directly connected destination host; NULL if no route
943  *           is found
944  */
945 static struct Route *
946 find_dest_route (uint32_t host_id)
947 {
948   struct Route *route;
949
950   if (route_list_size <= host_id)
951     return NULL;
952   while (NULL != (route = route_list[host_id]))
953   {
954     if (route->thru == master_context->host_id)
955       break;
956     host_id = route->thru;
957   }
958   return route;
959 }
960
961
962 /**
963  * Routes message to a host given its host_id
964  *
965  * @param host_id the id of the destination host
966  * @param msg the message to be routed
967  */
968 static void
969 route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
970 {
971   GNUNET_break (0);
972 }
973
974
975 /**
976  * Send operation failure message to client
977  *
978  * @param client the client to which the failure message has to be sent to
979  * @param operation_id the id of the failed operation
980  * @param emsg the error message; can be NULL
981  */
982 static void
983 send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
984                          uint64_t operation_id, const char *emsg)
985 {
986   struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
987   uint16_t msize;
988   uint16_t emsg_len;
989
990   msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
991   emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
992   msize += emsg_len;
993   msg = GNUNET_malloc (msize);
994   msg->header.size = htons (msize);
995   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT);
996   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
997   msg->operation_id = GNUNET_htonll (operation_id);
998   if (0 != emsg_len)
999     memcpy (&msg[1], emsg, emsg_len);
1000   queue_message (client, &msg->header);
1001 }
1002
1003
1004 /**
1005  * Function to send generic operation success message to given client
1006  *
1007  * @param client the client to send the message to
1008  * @param operation_id the id of the operation which was successful
1009  */
1010 static void
1011 send_operation_success_msg (struct GNUNET_SERVER_Client *client,
1012                             uint64_t operation_id)
1013 {
1014   struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
1015   uint16_t msize;
1016
1017   msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
1018   msg = GNUNET_malloc (msize);
1019   msg->header.size = htons (msize);
1020   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERICOPSUCCESS);
1021   msg->operation_id = GNUNET_htonll (operation_id);
1022   msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
1023   queue_message (client, &msg->header);
1024 }
1025
1026
1027 /**
1028  * The  Link Controller forwarding task
1029  *
1030  * @param cls the LCFContext
1031  * @param tc the Task context from scheduler
1032  */
1033 static void
1034 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1035
1036
1037 /**
1038  * Completion callback for host registrations while forwarding Link Controller messages
1039  *
1040  * @param cls the LCFContext
1041  * @param emsg the error message; NULL if host registration is successful
1042  */
1043 static void
1044 lcf_proc_cc (void *cls, const char *emsg)
1045 {
1046   struct LCFContext *lcf = cls;
1047
1048   lcf->rhandle = NULL;
1049   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1050   switch (lcf->state)
1051   {
1052   case INIT:
1053     if (NULL != emsg)
1054       goto registration_error;
1055     lcf->state = DELEGATED_HOST_REGISTERED;
1056     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1057     break;
1058   case DELEGATED_HOST_REGISTERED:
1059     if (NULL != emsg)
1060       goto registration_error;
1061     lcf->state = SLAVE_HOST_REGISTERED;
1062     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1063     break;
1064   default:
1065     GNUNET_assert (0);          /* Shouldn't reach here */
1066   }
1067   return;
1068
1069  registration_error:
1070   LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
1071        emsg);
1072   lcf->state = FINISHED;
1073   lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1074 }
1075
1076
1077 /**
1078  * Callback to be called when forwarded link controllers operation is
1079  * successfull. We have to relay the reply msg back to the client
1080  *
1081  * @param cls ForwardedOperationContext
1082  * @param msg the peer create success message
1083  */
1084 static void
1085 forwarded_operation_reply_relay (void *cls,
1086                                  const struct GNUNET_MessageHeader *msg)
1087 {
1088   struct ForwardedOperationContext *fopc = cls;
1089   struct GNUNET_MessageHeader *dup_msg;
1090   uint16_t msize;
1091
1092   msize = ntohs (msg->size);
1093   LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
1094              msize);
1095   dup_msg = GNUNET_malloc (msize);
1096   (void) memcpy (dup_msg, msg, msize);
1097   queue_message (fopc->client, dup_msg);
1098   GNUNET_SERVER_client_drop (fopc->client);
1099   GNUNET_SCHEDULER_cancel (fopc->timeout_task);
1100   GNUNET_free (fopc);
1101 }
1102
1103
1104 /**
1105  * Task to free resources when forwarded link controllers has been timedout
1106  *
1107  * @param cls the ForwardedOperationContext
1108  * @param tc the task context from scheduler
1109  */
1110 static void
1111 forwarded_operation_timeout (void *cls,
1112                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1113 {
1114   struct ForwardedOperationContext *fopc = cls;
1115
1116   GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
1117   send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
1118   GNUNET_SERVER_client_drop (fopc->client);
1119   GNUNET_free (fopc);
1120 }
1121
1122
1123 /**
1124  * The  Link Controller forwarding task
1125  *
1126  * @param cls the LCFContext
1127  * @param tc the Task context from scheduler
1128  */
1129 static void
1130 lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1131 {
1132   struct LCFContext *lcf = cls;
1133   struct LCFContextQueue *lcfq;
1134   struct ForwardedOperationContext *fopc;
1135
1136   lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
1137   switch (lcf->state)
1138   {
1139   case INIT:
1140     if (GNUNET_NO ==
1141         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
1142                                             lcf->gateway->controller))
1143     {
1144       lcf->rhandle =
1145           GNUNET_TESTBED_register_host (lcf->gateway->controller,
1146                                         host_list[lcf->delegated_host_id],
1147                                         lcf_proc_cc, lcf);
1148     }
1149     else
1150     {
1151       lcf->state = DELEGATED_HOST_REGISTERED;
1152       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1153     }
1154     break;
1155   case DELEGATED_HOST_REGISTERED:
1156     if (GNUNET_NO ==
1157         GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
1158                                             lcf->gateway->controller))
1159     {
1160       lcf->rhandle =
1161           GNUNET_TESTBED_register_host (lcf->gateway->controller,
1162                                         host_list[lcf->slave_host_id],
1163                                         lcf_proc_cc, lcf);
1164     }
1165     else
1166     {
1167       lcf->state = SLAVE_HOST_REGISTERED;
1168       lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1169     }
1170     break;
1171   case SLAVE_HOST_REGISTERED:
1172     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1173     fopc->client = lcf->client;
1174     fopc->operation_id = lcf->operation_id;
1175     fopc->opc =
1176         GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
1177                                                lcf->operation_id,
1178                                                &lcf->msg->header,
1179                                                &forwarded_operation_reply_relay,
1180                                                fopc);
1181     fopc->timeout_task =
1182         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1183                                       fopc);
1184     lcf->state = FINISHED;
1185     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
1186     break;
1187   case FINISHED:
1188     lcfq = lcfq_head;
1189     GNUNET_assert (lcfq->lcf == lcf);
1190     GNUNET_free (lcf->msg);
1191     GNUNET_free (lcf);
1192     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
1193     GNUNET_free (lcfq);
1194     if (NULL != lcfq_head)
1195       lcf_proc_task_id =
1196           GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
1197   }
1198 }
1199
1200
1201 /**
1202  * Callback for event from slave controllers
1203  *
1204  * @param cls struct Slave *
1205  * @param event information about the event
1206  */
1207 static void
1208 slave_event_callback (void *cls,
1209                       const struct GNUNET_TESTBED_EventInformation *event)
1210 {
1211   struct ForwardedOverlayConnectContext *focc;
1212   struct GNUNET_CONFIGURATION_Handle *slave_cfg;
1213
1214   /* We currently only get here when doing overlay connect operations and that
1215      too while trying out sub operations */
1216   if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
1217     return;
1218   focc = event->details.operation_finished.op_cls;
1219   switch (focc->state)
1220   {
1221   case FOCC_GET_CFG:
1222     slave_cfg = event->details.operation_finished.generic;
1223     GNUNET_break (0);           /* FIXME */
1224     GNUNET_CONFIGURATION_destroy (slave_cfg);
1225   default:  
1226     GNUNET_assert (0);
1227   }
1228 }
1229
1230
1231 /**
1232  * Callback to signal successfull startup of the controller process
1233  *
1234  * @param cls the handle to the slave whose status is to be found here
1235  * @param cfg the configuration with which the controller has been started;
1236  *          NULL if status is not GNUNET_OK
1237  * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
1238  *          GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1239  */
1240 static void
1241 slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1242                        int status)
1243 {
1244   struct Slave *slave = cls;
1245   struct LinkControllersContext *lcc;
1246
1247   lcc = slave->lcc;
1248   if (GNUNET_SYSERR == status)
1249   {
1250     slave->controller_proc = NULL;
1251     slave_list[slave->host_id] = NULL;
1252     if (NULL != slave->cfg)
1253       GNUNET_CONFIGURATION_destroy (slave->cfg);
1254     GNUNET_free (slave);
1255     slave = NULL;
1256     LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
1257     GNUNET_SCHEDULER_shutdown ();       /* We too shutdown */
1258     goto clean_lcc;
1259   }
1260   slave->controller =
1261       GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1262                                          event_mask,
1263                                          &slave_event_callback, slave);
1264   if (NULL != slave->controller)
1265   {
1266     send_operation_success_msg (lcc->client, lcc->operation_id);
1267     slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
1268   }
1269   else
1270   {
1271     send_operation_fail_msg (lcc->client, lcc->operation_id,
1272                              "Could not connect to delegated controller");
1273     GNUNET_TESTBED_controller_stop (slave->controller_proc);
1274     slave_list[slave->host_id] = NULL;
1275     GNUNET_free (slave);
1276     slave = NULL;
1277   }
1278
1279  clean_lcc:
1280   if (NULL != lcc)
1281   {
1282     if (NULL != lcc->client)
1283     {
1284       GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
1285       GNUNET_SERVER_client_drop (lcc->client);
1286       lcc->client = NULL;
1287     }
1288     GNUNET_free (lcc);
1289   }
1290   if (NULL != slave)
1291     slave->lcc = NULL;
1292 }
1293
1294
1295 /**
1296  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
1297  *
1298  * @param cls NULL
1299  * @param client identification of the client
1300  * @param message the actual message
1301  */
1302 static void
1303 handle_init (void *cls, struct GNUNET_SERVER_Client *client,
1304              const struct GNUNET_MessageHeader *message)
1305 {
1306   const struct GNUNET_TESTBED_InitMessage *msg;
1307   struct GNUNET_TESTBED_Host *host;
1308   const char *controller_hostname;
1309   uint16_t msize;
1310
1311   if (NULL != master_context)
1312   {
1313     LOG_DEBUG ("We are being connected to laterally\n");
1314     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1315     return;
1316   }
1317   msg = (const struct GNUNET_TESTBED_InitMessage *) message;
1318   msize = ntohs (message->size);
1319   if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
1320   {
1321     GNUNET_break (0);
1322     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1323     return;
1324   }
1325   msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
1326   controller_hostname = (const char *) &msg[1];
1327   if ('\0' != controller_hostname[msize - 1])
1328   {
1329     GNUNET_break (0);
1330     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1331     return;
1332   }
1333   master_context = GNUNET_malloc (sizeof (struct Context));
1334   master_context->client = client;
1335   master_context->host_id = ntohl (msg->host_id);
1336   master_context->master_ip = GNUNET_strdup (controller_hostname);
1337   LOG_DEBUG ("Master Controller IP: %s\n", master_context->master_ip);
1338   master_context->system =
1339       GNUNET_TESTING_system_create ("testbed", master_context->master_ip, hostname);
1340   host =
1341       GNUNET_TESTBED_host_create_with_id (master_context->host_id, NULL, NULL,
1342                                           0);
1343   host_list_add (host);
1344   GNUNET_SERVER_client_keep (client);
1345   LOG_DEBUG ("Created master context with host ID: %u\n",
1346              master_context->host_id);
1347   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1348 }
1349
1350
1351 /**
1352  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1353  *
1354  * @param cls NULL
1355  * @param client identification of the client
1356  * @param message the actual message
1357  */
1358 static void
1359 handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
1360                  const struct GNUNET_MessageHeader *message)
1361 {
1362   struct GNUNET_TESTBED_Host *host;
1363   const struct GNUNET_TESTBED_AddHostMessage *msg;
1364   struct GNUNET_TESTBED_HostConfirmedMessage *reply;
1365   char *username;
1366   char *hostname;
1367   char *emsg;
1368   uint32_t host_id;
1369   uint16_t username_length;
1370   uint16_t hostname_length;
1371   uint16_t reply_size;
1372   uint16_t msize;
1373
1374   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
1375   msize = ntohs (msg->header.size);
1376   username = (char *) &(msg[1]);
1377   username_length = ntohs (msg->user_name_length);
1378   GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length + 1));        /* msg must contain hostname */
1379   if (0 != username_length)
1380     GNUNET_assert ('\0' == username[username_length]);
1381   username_length = (0 == username_length) ? 0 : username_length + 1;
1382   hostname = username + username_length;
1383   hostname_length =
1384       msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
1385   GNUNET_assert ('\0' == hostname[hostname_length - 1]);
1386   GNUNET_assert (strlen (hostname) == hostname_length - 1);
1387   host_id = ntohl (msg->host_id);
1388   LOG_DEBUG ("Received ADDHOST message\n");
1389   LOG_DEBUG ("-------host id: %u\n", host_id);
1390   LOG_DEBUG ("-------hostname: %s\n", hostname);
1391   if (0 != username_length)
1392     LOG_DEBUG ("-------username: %s\n", username);
1393   else
1394   {
1395     LOG_DEBUG ("-------username: NULL\n");
1396     username = NULL;
1397   }
1398   LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
1399   host =
1400       GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
1401                                           ntohs (msg->ssh_port));
1402   GNUNET_assert (NULL != host);
1403   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1404   reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
1405   if (GNUNET_OK != host_list_add (host))
1406   {
1407     /* We are unable to add a host */
1408     emsg = "A host exists with given host-id";
1409     LOG_DEBUG ("%s: %u", emsg, host_id);
1410     GNUNET_TESTBED_host_destroy (host);
1411     reply_size += strlen (emsg) + 1;
1412     reply = GNUNET_malloc (reply_size);
1413     memcpy (&reply[1], emsg, strlen (emsg) + 1);
1414   }
1415   else
1416     reply = GNUNET_malloc (reply_size);
1417   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM);
1418   reply->header.size = htons (reply_size);
1419   reply->host_id = htonl (host_id);
1420   queue_message (client, &reply->header);
1421 }
1422
1423
1424 /**
1425  * Iterator over hash map entries.
1426  *
1427  * @param cls closure
1428  * @param key current key code
1429  * @param value value in the hash map
1430  * @return GNUNET_YES if we should continue to
1431  *         iterate,
1432  *         GNUNET_NO if not.
1433  */
1434 int
1435 ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
1436 {
1437   struct SharedService *queried_ss = cls;
1438   struct SharedService *ss = value;
1439
1440   if (0 == strcmp (ss->name, queried_ss->name))
1441     return GNUNET_NO;
1442   else
1443     return GNUNET_YES;
1444 }
1445
1446
1447 /**
1448  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
1449  *
1450  * @param cls NULL
1451  * @param client identification of the client
1452  * @param message the actual message
1453  */
1454 static void
1455 handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
1456                                  const struct GNUNET_MessageHeader *message)
1457 {
1458   const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
1459   struct SharedService *ss;
1460   char *service_name;
1461   struct GNUNET_HashCode hash;
1462   uint16_t msg_size;
1463   uint16_t service_name_size;
1464
1465   msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
1466   msg_size = ntohs (message->size);
1467   if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
1468   {
1469     GNUNET_break (0);
1470     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1471     return;
1472   }
1473   service_name_size =
1474       msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
1475   service_name = (char *) &msg[1];
1476   if ('\0' != service_name[service_name_size - 1])
1477   {
1478     GNUNET_break (0);
1479     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1480     return;
1481   }
1482   LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
1483              service_name, ntohl (msg->num_peers));
1484   if (ntohl (msg->host_id) != master_context->host_id)
1485   {
1486     route_message (ntohl (msg->host_id), message);
1487     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1488     return;
1489   }
1490   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1491   ss = GNUNET_malloc (sizeof (struct SharedService));
1492   ss->name = strdup (service_name);
1493   ss->num_shared = ntohl (msg->num_peers);
1494   GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
1495   if (GNUNET_SYSERR ==
1496       GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
1497                                                   &ss_exists_iterator, ss))
1498   {
1499     LOG (GNUNET_ERROR_TYPE_WARNING,
1500          "Service %s already configured as a shared service. "
1501          "Ignoring service sharing request \n", ss->name);
1502     GNUNET_free (ss->name);
1503     GNUNET_free (ss);
1504     return;
1505   }
1506   GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
1507                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1508 }
1509
1510
1511 /**
1512  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1513  *
1514  * @param cls NULL
1515  * @param client identification of the client
1516  * @param message the actual message
1517  */
1518 static void
1519 handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1520                          const struct GNUNET_MessageHeader *message)
1521 {
1522   const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
1523   struct GNUNET_CONFIGURATION_Handle *cfg;
1524   struct LCFContextQueue *lcfq;
1525   struct Route *route;
1526   struct Route *new_route;
1527   char *config;
1528   uLongf dest_size;
1529   size_t config_size;
1530   uint32_t delegated_host_id;
1531   uint32_t slave_host_id;
1532   uint16_t msize;
1533
1534   if (NULL == master_context)
1535   {
1536     GNUNET_break (0);
1537     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1538     return;
1539   }
1540   msize = ntohs (message->size);
1541   if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
1542   {
1543     GNUNET_break (0);
1544     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1545     return;
1546   }
1547   msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
1548   delegated_host_id = ntohl (msg->delegated_host_id);
1549   if (delegated_host_id == master_context->host_id)
1550   {
1551     GNUNET_break (0);
1552     LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
1553     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1554     return;
1555   }
1556   if ((delegated_host_id >= host_list_size) ||
1557       (NULL == host_list[delegated_host_id]))
1558   {
1559     LOG (GNUNET_ERROR_TYPE_WARNING,
1560          "Delegated host %u not registered with us\n", delegated_host_id);
1561     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1562     return;
1563   }
1564   slave_host_id = ntohl (msg->slave_host_id);
1565   if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
1566   {
1567     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
1568     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1569     return;
1570   }
1571   if (slave_host_id == delegated_host_id)
1572   {
1573     LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
1574     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1575     return;
1576   }
1577
1578   if (slave_host_id == master_context->host_id) /* Link from us */
1579   {
1580     struct Slave *slave;
1581     struct LinkControllersContext *lcc;
1582
1583     msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
1584     config_size = ntohs (msg->config_size);
1585     if ((delegated_host_id < slave_list_size) && (NULL != slave_list[delegated_host_id]))       /* We have already added */
1586     {
1587       LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
1588            delegated_host_id);
1589       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1590       return;
1591     }
1592     config = GNUNET_malloc (config_size);
1593     dest_size = (uLongf) config_size;
1594     if (Z_OK !=
1595         uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
1596                     (uLong) msize))
1597     {
1598       GNUNET_break (0);         /* Compression error */
1599       GNUNET_free (config);
1600       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1601       return;
1602     }
1603     if (config_size != dest_size)
1604     {
1605       LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
1606       GNUNET_free (config);
1607       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1608       return;
1609     }
1610     cfg = GNUNET_CONFIGURATION_create ();       /* Free here or in lcfcontext */
1611     if (GNUNET_OK !=
1612         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1613     {
1614       GNUNET_break (0);         /* Configuration parsing error */
1615       GNUNET_free (config);
1616       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1617       return;
1618     }
1619     GNUNET_free (config);
1620     if ((delegated_host_id < slave_list_size) &&
1621         (NULL != slave_list[delegated_host_id]))
1622     {
1623       GNUNET_break (0);         /* Configuration parsing error */
1624       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1625       return;
1626     }
1627     slave = GNUNET_malloc (sizeof (struct Slave));
1628     slave->host_id = delegated_host_id;
1629     slave_list_add (slave);
1630     if (1 != msg->is_subordinate)
1631     {
1632       slave->controller =
1633           GNUNET_TESTBED_controller_connect (cfg, host_list[slave->host_id],
1634                                              event_mask,
1635                                              &slave_event_callback, slave);
1636       slave->cfg = cfg;
1637       if (NULL != slave->controller)
1638         send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1639       else
1640         send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1641                                  "Could not connect to delegated controller");
1642       GNUNET_SERVER_receive_done (client, GNUNET_OK);
1643       return;
1644     }
1645     lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
1646     lcc->operation_id = GNUNET_ntohll (msg->operation_id);
1647     GNUNET_SERVER_client_keep (client);
1648     lcc->client = client;
1649     slave->lcc = lcc;
1650     slave->controller_proc =
1651         GNUNET_TESTBED_controller_start (master_context->master_ip,
1652                                          host_list[slave->host_id], cfg,
1653                                          &slave_status_callback, slave);
1654     GNUNET_CONFIGURATION_destroy (cfg);
1655     new_route = GNUNET_malloc (sizeof (struct Route));
1656     new_route->dest = delegated_host_id;
1657     new_route->thru = master_context->host_id;
1658     route_list_add (new_route);
1659     return;
1660   }
1661
1662   /* Route the request */
1663   if (slave_host_id >= route_list_size)
1664   {
1665     LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
1666     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1667     return;
1668   }
1669   lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
1670   lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
1671   lcfq->lcf->delegated_host_id = delegated_host_id;
1672   lcfq->lcf->slave_host_id = slave_host_id;
1673   route = find_dest_route (slave_host_id);
1674   GNUNET_assert (NULL != route);        /* because we add routes carefully */
1675   GNUNET_assert (route->dest < slave_list_size);
1676   GNUNET_assert (NULL != slave_list[route->dest]);
1677   lcfq->lcf->state = INIT;
1678   lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
1679   lcfq->lcf->gateway = slave_list[route->dest];
1680   lcfq->lcf->msg = GNUNET_malloc (msize);
1681   (void) memcpy (lcfq->lcf->msg, msg, msize);
1682   GNUNET_SERVER_client_keep (client);
1683   lcfq->lcf->client = client;
1684   if (NULL == lcfq_head)
1685   {
1686     GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
1687     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1688     lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
1689   }
1690   else
1691     GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
1692   /* FIXME: Adding a new route should happen after the controllers are linked
1693    * successfully */
1694   if (1 != msg->is_subordinate)
1695   {
1696     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1697     return;
1698   }
1699   if ((delegated_host_id < route_list_size)
1700       && (NULL != route_list[delegated_host_id]))
1701   {
1702     GNUNET_break_op (0);        /* Are you trying to link delegated host twice
1703                                    with is subordinate flag set to GNUNET_YES? */
1704     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1705     return;
1706   }
1707   new_route = GNUNET_malloc (sizeof (struct Route));
1708   new_route->dest = delegated_host_id;
1709   new_route->thru = route->dest;
1710   route_list_add (new_route);
1711   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1712 }
1713
1714
1715 /**
1716  * The task to be executed if the forwarded peer create operation has been
1717  * timed out
1718  *
1719  * @param cls the FowardedOperationContext
1720  * @param tc the TaskContext from the scheduler
1721  */
1722 static void
1723 peer_create_forward_timeout (void *cls,
1724                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1725 {
1726   struct ForwardedOperationContext *fo_ctxt = cls;
1727
1728   /* send error msg to client */
1729   GNUNET_free (fo_ctxt->cls);
1730   send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id, "Timedout");
1731   GNUNET_SERVER_client_drop (fo_ctxt->client);
1732   GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
1733   GNUNET_free (fo_ctxt);
1734 }
1735
1736
1737 /**
1738  * Callback to be called when forwarded peer create operation is
1739  * successfull. We have to relay the reply msg back to the client
1740  *
1741  * @param cls ForwardedOperationContext
1742  * @param msg the peer create success message
1743  */
1744 static void
1745 peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1746 {
1747   struct ForwardedOperationContext *fo_ctxt = cls;
1748   const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *success_msg;
1749   struct GNUNET_MessageHeader *dup_msg;
1750   struct Peer *remote_peer;
1751   uint16_t msize;
1752
1753   GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
1754   if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS)
1755   {
1756     success_msg =
1757         (const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *) msg;
1758     GNUNET_assert (NULL != fo_ctxt->cls);
1759     remote_peer = fo_ctxt->cls;
1760     GNUNET_assert (remote_peer->details.remote.remote_host_id
1761                    == ntohl (success_msg->peer_id));
1762     peer_list_add (remote_peer);
1763   }
1764   msize = ntohs (msg->size);
1765   dup_msg = GNUNET_malloc (msize);
1766   (void) memcpy (dup_msg, msg, msize);
1767   queue_message (fo_ctxt->client, dup_msg);
1768   GNUNET_SERVER_client_drop (fo_ctxt->client);
1769   GNUNET_free (fo_ctxt);
1770 }
1771
1772
1773
1774 /**
1775  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1776  *
1777  * @param cls NULL
1778  * @param client identification of the client
1779  * @param message the actual message
1780  */
1781 static void
1782 handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1783                     const struct GNUNET_MessageHeader *message)
1784 {
1785   const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1786   struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1787   struct GNUNET_CONFIGURATION_Handle *cfg;
1788   struct ForwardedOperationContext *fo_ctxt;
1789   struct Route *route;
1790   struct Peer *peer;
1791   char *config;
1792   size_t dest_size;
1793   int ret;
1794   uint32_t config_size;
1795   uint32_t host_id;
1796   uint32_t peer_id;
1797   uint16_t msize;
1798
1799
1800   msize = ntohs (message->size);
1801   if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1802   {
1803     GNUNET_break (0);           /* We need configuration */
1804     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1805     return;
1806   }
1807   msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1808   host_id = ntohl (msg->host_id);
1809   peer_id = ntohl (msg->peer_id);
1810   if (UINT32_MAX == peer_id)
1811   {
1812     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1813                              "Cannot create peer with given ID");
1814     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1815     return;
1816   }
1817   if (host_id == master_context->host_id)
1818   {
1819     char *emsg;
1820
1821     /* We are responsible for this peer */
1822     msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1823     config_size = ntohl (msg->config_size);
1824     config = GNUNET_malloc (config_size);
1825     dest_size = config_size;
1826     if (Z_OK !=
1827         (ret =
1828          uncompress ((Bytef *) config, (uLongf *) & dest_size,
1829                      (const Bytef *) &msg[1], (uLong) msize)))
1830     {
1831       GNUNET_break (0);         /* uncompression error */
1832       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1833       return;
1834     }
1835     if (config_size != dest_size)
1836     {
1837       GNUNET_break (0);         /* Uncompressed config size mismatch */
1838       GNUNET_free (config);
1839       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1840       return;
1841     }
1842     cfg = GNUNET_CONFIGURATION_create ();
1843     if (GNUNET_OK !=
1844         GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1845     {
1846       GNUNET_break (0);         /* Configuration parsing error */
1847       GNUNET_free (config);
1848       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1849       return;
1850     }
1851     GNUNET_free (config);
1852     peer = GNUNET_malloc (sizeof (struct Peer));
1853     peer->is_remote = GNUNET_NO;
1854     peer->details.local.cfg = cfg;
1855     peer->id = peer_id;
1856     LOG_DEBUG ("Creating peer with id: %u\n", peer->id);
1857     peer->details.local.peer =
1858         GNUNET_TESTING_peer_configure (master_context->system,
1859                                        peer->details.local.cfg, peer->id,
1860                                        NULL /* Peer id */ ,
1861                                        &emsg);
1862     if (NULL == peer->details.local.peer)
1863     {
1864       LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1865       GNUNET_free (emsg);
1866       GNUNET_free (peer);
1867       GNUNET_break (0);
1868       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1869       return;
1870     }
1871     peer->details.local.is_running = GNUNET_NO;
1872     peer_list_add (peer);
1873     reply =
1874         GNUNET_malloc (sizeof
1875                        (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1876     reply->header.size =
1877         htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1878     reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS);
1879     reply->peer_id = msg->peer_id;
1880     reply->operation_id = msg->operation_id;
1881     queue_message (client, &reply->header);
1882     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1883     return;
1884   }
1885
1886   /* Forward peer create request */
1887   route = find_dest_route (host_id);
1888   if (NULL == route)
1889   {
1890     GNUNET_break (0);
1891     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1892     return;
1893   }
1894
1895   peer = GNUNET_malloc (sizeof (struct Peer));
1896   peer->is_remote = GNUNET_YES;
1897   peer->id = peer_id;
1898   peer->details.remote.controller = slave_list[route->dest]->controller;
1899   peer->details.remote.remote_host_id = host_id;
1900   fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1901   GNUNET_SERVER_client_keep (client);
1902   fo_ctxt->client = client;
1903   fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1904   fo_ctxt->cls = peer; //slave_list[route->dest]->controller;
1905   fo_ctxt->opc =
1906       GNUNET_TESTBED_forward_operation_msg_ (slave_list [route->dest]->controller,
1907                                              fo_ctxt->operation_id,
1908                                              &msg->header,
1909                                              peer_create_success_cb, fo_ctxt);
1910   fo_ctxt->timeout_task =
1911       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
1912                                     fo_ctxt);
1913   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1914 }
1915
1916
1917 /**
1918  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1919  *
1920  * @param cls NULL
1921  * @param client identification of the client
1922  * @param message the actual message
1923  */
1924 static void
1925 handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1926                      const struct GNUNET_MessageHeader *message)
1927 {
1928   const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1929   struct ForwardedOperationContext *fopc;
1930   struct Peer *peer;
1931   uint32_t peer_id;
1932
1933   msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1934   peer_id = ntohl (msg->peer_id);
1935   LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1936              peer_id, GNUNET_ntohll (msg->operation_id));
1937   if ((peer_list_size <= peer_id) || (NULL == peer_list[peer_id]))
1938   {
1939     LOG (GNUNET_ERROR_TYPE_ERROR,
1940          "Asked to destroy a non existent peer with id: %u\n", peer_id);
1941     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1942                              "Peer doesn't exist");
1943     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1944     return;
1945   }
1946   peer = peer_list[peer_id];
1947   if (GNUNET_YES == peer->is_remote)
1948   {
1949     /* Forward the destory message to sub controller */
1950     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1951     GNUNET_SERVER_client_keep (client);
1952     fopc->client = client;
1953     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1954     fopc->opc =
1955         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
1956                                                fopc->operation_id, &msg->header,
1957                                                &forwarded_operation_reply_relay,
1958                                                fopc);
1959     fopc->timeout_task =
1960         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
1961                                       fopc);
1962     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1963     return;
1964   }
1965   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1966   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1967   peer_list_remove (peer);
1968   GNUNET_free (peer);
1969   send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1970   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1971 }
1972
1973
1974 /**
1975  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1976  *
1977  * @param cls NULL
1978  * @param client identification of the client
1979  * @param message the actual message
1980  */
1981 static void
1982 handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1983                    const struct GNUNET_MessageHeader *message)
1984 {
1985   const struct GNUNET_TESTBED_PeerStartMessage *msg;
1986   struct GNUNET_TESTBED_PeerEventMessage *reply;
1987   struct ForwardedOperationContext *fopc;
1988   struct Peer *peer;
1989   uint32_t peer_id;
1990
1991   msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1992   peer_id = ntohl (msg->peer_id);
1993   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
1994   {
1995     GNUNET_break (0);
1996     LOG (GNUNET_ERROR_TYPE_ERROR,
1997          "Asked to start a non existent peer with id: %u\n", peer_id);
1998     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1999     return;
2000   }
2001   peer = peer_list[peer_id];
2002   if (GNUNET_YES == peer->is_remote)
2003   {
2004     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2005     GNUNET_SERVER_client_keep (client);
2006     fopc->client = client;
2007     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2008     fopc->opc =
2009         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2010                                                fopc->operation_id, &msg->header,
2011                                                &forwarded_operation_reply_relay,
2012                                                fopc);
2013     fopc->timeout_task =
2014         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2015                                       fopc);
2016     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2017     return;
2018   }
2019   if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
2020   {
2021     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2022                              "Failed to start");
2023     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2024     return;
2025   }
2026   peer->details.local.is_running = GNUNET_YES;
2027   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2028   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2029   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2030   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
2031   reply->host_id = htonl (master_context->host_id);
2032   reply->peer_id = msg->peer_id;
2033   reply->operation_id = msg->operation_id;
2034   queue_message (client, &reply->header);
2035   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2036 }
2037
2038
2039 /**
2040  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
2041  *
2042  * @param cls NULL
2043  * @param client identification of the client
2044  * @param message the actual message
2045  */
2046 static void
2047 handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
2048                   const struct GNUNET_MessageHeader *message)
2049 {
2050   const struct GNUNET_TESTBED_PeerStopMessage *msg;
2051   struct GNUNET_TESTBED_PeerEventMessage *reply;
2052   struct ForwardedOperationContext *fopc;
2053   struct Peer *peer;
2054   uint32_t peer_id;
2055
2056   msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
2057   peer_id = ntohl (msg->peer_id);
2058   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2059   {
2060     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2061                              "Peer not found");
2062     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2063     return;
2064   }
2065   peer = peer_list[peer_id];
2066   if (GNUNET_YES == peer->is_remote)
2067   {
2068     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2069     GNUNET_SERVER_client_keep (client);
2070     fopc->client = client;
2071     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2072     fopc->opc =
2073         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2074                                                fopc->operation_id, &msg->header,
2075                                                &forwarded_operation_reply_relay,
2076                                                fopc);
2077     fopc->timeout_task =
2078         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2079                                       fopc);
2080     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2081     return;
2082   }
2083   if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
2084   {
2085     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2086                              "Peer not running");
2087     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2088     return;
2089   }
2090   peer->details.local.is_running = GNUNET_NO;
2091   reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2092   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT);
2093   reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
2094   reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
2095   reply->host_id = htonl (master_context->host_id);
2096   reply->peer_id = msg->peer_id;
2097   reply->operation_id = msg->operation_id;
2098   queue_message (client, &reply->header);
2099   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2100 }
2101
2102
2103 /**
2104  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
2105  *
2106  * @param cls NULL
2107  * @param client identification of the client
2108  * @param message the actual message
2109  */
2110 static void
2111 handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2112                         const struct GNUNET_MessageHeader *message)
2113 {
2114   const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
2115   struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
2116   struct Peer *peer;
2117   char *config;
2118   char *xconfig;
2119   size_t c_size;
2120   size_t xc_size;
2121   uint32_t peer_id;
2122   uint16_t msize;
2123
2124   msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
2125   peer_id = ntohl (msg->peer_id);
2126   if ((peer_id >= peer_list_size) || (NULL == peer_list[peer_id]))
2127   {
2128     send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
2129                              "Peer not found");
2130     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2131     return;
2132   }
2133   peer = peer_list[peer_id];
2134   if (GNUNET_YES == peer->is_remote)
2135   {
2136     struct ForwardedOperationContext *fopc;
2137     
2138     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2139     GNUNET_SERVER_client_keep (client);
2140     fopc->client = client;
2141     fopc->operation_id = GNUNET_ntohll (msg->operation_id);
2142     fopc->opc =
2143         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2144                                                fopc->operation_id, &msg->header,
2145                                                &forwarded_operation_reply_relay,
2146                                                fopc);
2147     fopc->timeout_task =
2148         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2149                                       fopc);    
2150     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2151     return;
2152   }
2153   config =
2154       GNUNET_CONFIGURATION_serialize (peer_list[peer_id]->details.local.cfg,
2155                                       &c_size);
2156   xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
2157   GNUNET_free (config);
2158   msize =
2159       xc_size +
2160       sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2161   reply = GNUNET_realloc (xconfig, msize);
2162   (void) memmove (&reply[1], reply, xc_size);
2163   reply->header.size = htons (msize);
2164   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG);
2165   reply->peer_id = msg->peer_id;
2166   reply->operation_id = msg->operation_id;
2167   GNUNET_TESTING_peer_get_identity (peer_list[peer_id]->details.local.peer,
2168                                     &reply->peer_identity);
2169   reply->config_size = htons ((uint16_t) c_size);
2170   queue_message (client, &reply->header);
2171   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2172 }
2173
2174
2175 /**
2176  * Task for cleaing up overlay connect context structure
2177  *
2178  * @param cls the overlay connect context
2179  * @param tc the task context
2180  */
2181 static void
2182 occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2183 {
2184   struct OverlayConnectContext *occ = cls;
2185
2186   LOG_DEBUG ("Cleaning up occ\n");
2187   GNUNET_free_non_null (occ->emsg);
2188   GNUNET_free_non_null (occ->hello);
2189   GNUNET_SERVER_client_drop (occ->client);
2190   if (NULL != occ->opc)
2191     GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
2192   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2193     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2194   if (NULL != occ->ch)
2195     GNUNET_CORE_disconnect (occ->ch);
2196   if (NULL != occ->ghh)
2197     GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2198   if (NULL != occ->p1th)
2199     GNUNET_TRANSPORT_disconnect (occ->p1th);
2200   if (NULL != occ->p2th)
2201     GNUNET_TRANSPORT_disconnect (occ->p2th);
2202   GNUNET_free (occ);
2203 }
2204
2205
2206 /**
2207  * Task which will be run when overlay connect request has been timed out
2208  *
2209  * @param cls the OverlayConnectContext
2210  * @param tc the TaskContext
2211  */
2212 static void
2213 timeout_overlay_connect (void *cls,
2214                          const struct GNUNET_SCHEDULER_TaskContext *tc)
2215 {
2216   struct OverlayConnectContext *occ = cls;
2217
2218   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2219   send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
2220   occ_cleanup (occ, tc);
2221 }
2222
2223
2224
2225 /**
2226  * Function called to notify transport users that another
2227  * peer connected to us.
2228  *
2229  * @param cls closure
2230  * @param new_peer the peer that connected
2231  * @param ats performance data
2232  * @param ats_count number of entries in ats (excluding 0-termination)
2233  */
2234 static void
2235 overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2236                         const struct GNUNET_ATS_Information *ats,
2237                         unsigned int ats_count)
2238 {
2239   struct OverlayConnectContext *occ = cls;
2240   struct GNUNET_TESTBED_ConnectionEventMessage *msg;
2241   char *new_peer_str;
2242   char *other_peer_str;
2243
2244   LOG_DEBUG ("Overlay connect notify\n");
2245   if (0 ==
2246       memcmp (new_peer, &occ->peer_identity,
2247               sizeof (struct GNUNET_PeerIdentity)))
2248     return;
2249   new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
2250   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2251   if (0 !=
2252       memcmp (new_peer, &occ->other_peer_identity,
2253               sizeof (struct GNUNET_PeerIdentity)))
2254   {
2255     LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n",
2256                new_peer_str, other_peer_str);
2257     GNUNET_free (new_peer_str);
2258     GNUNET_free (other_peer_str);
2259     return;
2260   }
2261   GNUNET_free (new_peer_str);
2262   LOG_DEBUG ("Peer %4s connected to peer %4s\n", other_peer_str, 
2263              GNUNET_i2s (&occ->peer_identity));
2264   GNUNET_free (other_peer_str);
2265   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
2266   {
2267     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
2268     occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2269   }
2270   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
2271   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2272   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2273   GNUNET_free_non_null (occ->emsg);
2274   occ->emsg = NULL;
2275   if (NULL != occ->p2th)
2276     GNUNET_TRANSPORT_disconnect (occ->p2th);
2277   occ->p2th = NULL;
2278   LOG_DEBUG ("Peers connected - Sending overlay connect success\n");
2279   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2280   msg->header.size =
2281       htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
2282   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT);
2283   msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
2284   msg->peer1 = htonl (occ->peer_id);
2285   msg->peer2 = htonl (occ->other_peer_id);
2286   msg->operation_id = GNUNET_htonll (occ->op_id);
2287   queue_message (occ->client, &msg->header);
2288   GNUNET_SCHEDULER_add_now (&occ_cleanup, occ);
2289 }
2290
2291
2292 /**
2293  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
2294  * peer 1.
2295  *
2296  * @param cls the OverlayConnectContext
2297  * @param tc the TaskContext from scheduler
2298  */
2299 static void
2300 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2301 {
2302   struct OverlayConnectContext *occ = cls;
2303   char *other_peer_str;
2304
2305   occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
2306   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2307     return;
2308   GNUNET_assert (NULL != occ->hello);
2309   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
2310   if (NULL != occ->peer2_controller)
2311   {
2312     struct GNUNET_TESTBED_RequestConnectMessage *msg;
2313     uint16_t msize;
2314     uint16_t hello_size;
2315
2316     LOG_DEBUG ("Offering HELLO of %s to %s via Remote Overlay Request\n", 
2317                GNUNET_i2s (&occ->peer_identity), other_peer_str);
2318     hello_size = ntohs (occ->hello->size);
2319     msize = sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hello_size;
2320     msg = GNUNET_malloc (msize);
2321     msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT);
2322     msg->header.size = htons (msize);
2323     msg->peer = htonl (occ->other_peer_id);
2324     msg->operation_id = GNUNET_htonll (occ->op_id);
2325     (void) memcpy (&msg->peer_identity, &occ->peer_identity,
2326                    sizeof (struct GNUNET_PeerIdentity));
2327     memcpy (msg->hello, occ->hello, hello_size);
2328     GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
2329   }
2330   else
2331   {
2332     LOG_DEBUG ("Offering HELLO of %s to %s\n", 
2333                GNUNET_i2s (&occ->peer_identity), other_peer_str);
2334     GNUNET_TRANSPORT_offer_hello (occ->p2th, occ->hello, NULL, NULL);
2335     GNUNET_TRANSPORT_try_connect (occ->p2th, &occ->peer_identity);
2336     occ->send_hello_task =
2337         GNUNET_SCHEDULER_add_delayed
2338         (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
2339                                         100 * (pow (2, occ->retries++))),
2340          &send_hello, occ);
2341   }
2342   GNUNET_free (other_peer_str);  
2343 }
2344
2345 /**
2346  * Test for checking whether HELLO message is empty
2347  *
2348  * @param cls empty flag to set
2349  * @param address the HELLO
2350  * @param expiration expiration of the HELLO
2351  * @return
2352  */
2353 static int
2354 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
2355               struct GNUNET_TIME_Absolute expiration)
2356 {
2357   int *empty = cls;
2358
2359   *empty = GNUNET_NO;
2360   return GNUNET_OK;
2361 }
2362
2363
2364 /**
2365  * Function called whenever there is an update to the HELLO of peers in the
2366  * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
2367  * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
2368  *
2369  * @param cls closure
2370  * @param hello our updated HELLO
2371  */
2372 static void
2373 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
2374 {
2375   struct OverlayConnectContext *occ = cls;
2376   int empty;
2377   uint16_t msize;
2378
2379   msize = ntohs (hello->size);
2380   empty = GNUNET_YES;
2381   (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
2382                                          hello, GNUNET_NO, &test_address,
2383                                          &empty);
2384   if (GNUNET_YES == empty)
2385   {
2386     LOG_DEBUG ("HELLO of %s is empty\n", GNUNET_i2s (&occ->peer_identity));
2387     return;
2388   }
2389   LOG_DEBUG ("Received HELLO of %s\n", GNUNET_i2s (&occ->peer_identity));
2390   occ->hello = GNUNET_malloc (msize);
2391   memcpy (occ->hello, hello, msize);
2392   GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
2393   occ->ghh = NULL;
2394   GNUNET_TRANSPORT_disconnect (occ->p1th);
2395   occ->p1th = NULL;
2396   GNUNET_free_non_null (occ->emsg);
2397   if (NULL == occ->peer2_controller)
2398   {   
2399     occ->p2th =
2400         GNUNET_TRANSPORT_connect (peer_list[occ->other_peer_id]->details.local.cfg,
2401                                   &occ->other_peer_identity, NULL, NULL, NULL,
2402                                   NULL);
2403     if (NULL == occ->p2th)
2404     {
2405       GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of %s\n",
2406                        GNUNET_i2s (&occ->other_peer_identity));
2407       GNUNET_SCHEDULER_cancel (occ->timeout_task);
2408       occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2409       return;
2410     }
2411   }
2412   occ->emsg = GNUNET_strdup ("Timeout while offering HELLO to other peer");
2413   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
2414 }
2415
2416
2417 /**
2418  * Function called after GNUNET_CORE_connect has succeeded (or failed
2419  * for good).  Note that the private key of the peer is intentionally
2420  * not exposed here; if you need it, your process should try to read
2421  * the private key file directly (which should work if you are
2422  * authorized...).
2423  *
2424  * @param cls closure
2425  * @param server handle to the server, NULL if we failed
2426  * @param my_identity ID of this peer, NULL if we failed
2427  */
2428 static void
2429 core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
2430                  const struct GNUNET_PeerIdentity *my_identity)
2431 {
2432   struct OverlayConnectContext *occ = cls;
2433
2434   GNUNET_free_non_null (occ->emsg);
2435   occ->emsg = GNUNET_strdup ("Failed to connect to CORE\n");
2436   if ((NULL == server) || (NULL == my_identity))
2437     goto error_return;
2438   GNUNET_free (occ->emsg);
2439   occ->ch = server;
2440   occ->emsg = NULL;
2441   memcpy (&occ->peer_identity, my_identity,
2442           sizeof (struct GNUNET_PeerIdentity));
2443   occ->p1th =
2444       GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
2445                                 &occ->peer_identity, NULL, NULL, NULL, NULL);
2446   if (NULL == occ->p1th)
2447   {
2448     GNUNET_asprintf (&occ->emsg, "Cannot connect to TRANSPORT of peers %4s",
2449                     GNUNET_i2s (&occ->peer_identity));
2450     goto error_return;
2451   }
2452   LOG_DEBUG ("Acquiring HELLO of peer %s\n", GNUNET_i2s (&occ->peer_identity));
2453   occ->emsg = GNUNET_strdup ("Timeout while acquiring HELLO message");
2454   occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
2455   return;
2456   
2457  error_return:
2458   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2459   occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2460   return;
2461 }
2462
2463
2464 /**
2465  * Callback to be called when forwarded get peer config operation as part of
2466  * overlay connect is successfull. Connection to Peer 1's core is made and is
2467  * checked for new connection from peer 2
2468  *
2469  * @param cls ForwardedOperationContext
2470  * @param msg the peer create success message
2471  */
2472 static void
2473 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
2474 {
2475   struct OverlayConnectContext *occ = cls;
2476   const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
2477   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2478     {NULL, 0, 0}
2479   };
2480
2481   occ->opc = NULL;
2482   if (GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG != ntohs (msg->type))
2483     goto error_return;
2484   cmsg = (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *)
2485       msg;
2486   memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
2487           sizeof (struct GNUNET_PeerIdentity));
2488   GNUNET_free_non_null (occ->emsg);
2489   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2490   occ->ch =
2491       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2492                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2493                            GNUNET_NO, no_handlers);
2494   if (NULL == occ->ch)
2495     goto error_return;
2496   return;
2497
2498  error_return:
2499   GNUNET_SCHEDULER_cancel (occ->timeout_task);
2500   occ->timeout_task = 
2501       GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2502 }
2503
2504
2505 /**
2506  * Callback to be called when forwarded overlay connection operation has a reply
2507  * from the sub-controller successfull. We have to relay the reply msg back to
2508  * the client
2509  *
2510  * @param cls ForwardedOperationContext
2511  * @param msg the peer create success message
2512  */
2513 static void
2514 forwarded_overlay_connect_listener (void *cls,
2515                                     const struct GNUNET_MessageHeader *msg)
2516 {
2517   struct ForwardedOperationContext *fopc = cls;
2518   struct ForwardedOverlayConnectContext *focc;
2519
2520   focc = fopc->cls;
2521   if (NULL == focc)
2522   {
2523     forwarded_operation_reply_relay (cls, msg);
2524     return;
2525   }
2526   switch (focc->state)
2527   {
2528   case FOCC_INIT:
2529     if (GNUNET_MESSAGE_TYPE_TESTBED_NEEDCONTROLLERCONFIG != ntohs (msg->type))
2530     {
2531       GNUNET_break (0);  /* Something failed; you may check output of sub-controllers */
2532       forwarded_operation_reply_relay (cls, msg);
2533       return;
2534     }
2535     GNUNET_assert (NULL == focc->sub_op);
2536     focc->state = FOCC_GET_CFG;
2537     focc->sub_op = GNUNET_TESTBED_get_slave_config_ (focc, focc->gateway2,
2538                                                      focc->peer2_host_id);
2539     /* FIXME */
2540     GNUNET_break (0);
2541     break;
2542     /* focc->op = GNUNET_TESTBED_controller_link (focc, */
2543     /*                                            focc->gateway, */
2544     /*                                            slave_list[peer2_host_id], */
2545     /*                                            slave_list[peer_list[focc->peer1]->remote_host_id], */
2546     /*                                            slave_list */
2547                                                
2548   default:
2549     GNUNET_assert (0);
2550   }
2551 }
2552
2553
2554 /**
2555  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
2556  *
2557  * @param cls NULL
2558  * @param client identification of the client
2559  * @param message the actual message
2560  */
2561 static void
2562 handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
2563                         const struct GNUNET_MessageHeader *message)
2564 {
2565   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
2566   struct OverlayConnectContext *occ;
2567   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
2568     {NULL, 0, 0}
2569   };
2570   struct Peer *peer;
2571   uint64_t operation_id;
2572   uint32_t p1;
2573   uint32_t p2; 
2574   uint32_t peer2_host_id;
2575
2576   
2577   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
2578   p1 = ntohl (msg->peer1);
2579   p2 = ntohl (msg->peer2);
2580   peer2_host_id = ntohl (msg->peer2_host_id);
2581   GNUNET_assert (p1 < peer_list_size);
2582   GNUNET_assert (NULL != peer_list[p1]);
2583   peer = peer_list[p1];
2584   operation_id = GNUNET_ntohll (msg->operation_id);  
2585   if (GNUNET_YES == peer->is_remote)
2586   {
2587     struct ForwardedOperationContext *fopc;
2588     struct Route *route_to_peer2_host;
2589     struct Route *route_to_peer1_host;
2590
2591     LOG_DEBUG ("Forwarding overlay connect\n");
2592     GNUNET_SERVER_client_keep (client);
2593     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2594     fopc->client = client;
2595     fopc->operation_id = operation_id;
2596     route_to_peer2_host = NULL;
2597     route_to_peer1_host = NULL;
2598     route_to_peer2_host = find_dest_route (peer2_host_id);
2599     if (NULL != route_to_peer2_host)
2600     {
2601       route_to_peer1_host = 
2602           find_dest_route (peer_list[p1]->details.remote.remote_host_id);
2603       GNUNET_assert (NULL != route_to_peer1_host);
2604       if (route_to_peer2_host->dest != route_to_peer1_host->dest)
2605       {
2606         struct ForwardedOverlayConnectContext *focc;
2607         
2608         focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
2609         focc->gateway = peer->details.remote.controller;
2610         focc->gateway2 = slave_list[route_to_peer2_host->dest]->controller;
2611         focc->peer1 = p1;
2612         focc->peer2 = p2;
2613         focc->peer2_host_id = peer2_host_id;
2614         focc->state = FOCC_INIT;
2615         fopc->cls = focc;
2616       }
2617     }
2618     fopc->opc = 
2619         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.controller,
2620                                                operation_id, message,
2621                                                &forwarded_overlay_connect_listener,
2622                                                fopc);
2623     fopc->timeout_task =
2624         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
2625                                       fopc);
2626     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2627     return;
2628   }
2629   occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
2630   GNUNET_SERVER_client_keep (client);
2631   occ->client = client;
2632   occ->peer_id = p1;
2633   occ->other_peer_id = p2;
2634   occ->peer = peer_list[p1];
2635   occ->op_id = GNUNET_ntohll (msg->operation_id);  
2636   if ((p2 >= peer_list_size) || (NULL == peer_list[p2]))
2637   {   
2638     if ((peer2_host_id >= slave_list_size)
2639         || (NULL ==slave_list[peer2_host_id]))
2640     {
2641       struct GNUNET_TESTBED_NeedControllerConfig *reply;
2642
2643       GNUNET_free (occ);
2644       reply = GNUNET_malloc (sizeof (struct
2645                                      GNUNET_TESTBED_NeedControllerConfig)); 
2646       reply->header.size = htons (sizeof (struct
2647                                           GNUNET_TESTBED_NeedControllerConfig));
2648       reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_NEEDCONTROLLERCONFIG);
2649       reply->controller_host_id = msg->peer2_host_id;
2650       reply->operation_id = msg->operation_id;
2651       queue_message (client, &reply->header);      
2652       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2653       return;
2654     }
2655     else
2656     {
2657       occ->peer2_controller = slave_list[peer2_host_id]->controller;
2658       if (NULL == occ->peer2_controller)
2659       {
2660         GNUNET_break (0);       /* What's going on? */
2661         GNUNET_SERVER_client_drop (client);
2662         GNUNET_free (occ);
2663         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2664         return;
2665       }
2666     }
2667   }
2668   else
2669   {
2670     if (GNUNET_YES == peer_list[occ->other_peer_id]->is_remote)
2671       occ->peer2_controller = peer_list[occ->other_peer_id]->details.remote.controller;
2672   }
2673   /* Get the identity of the second peer */
2674   if (NULL != occ->peer2_controller)
2675   {
2676     struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
2677
2678     cmsg.header.size = 
2679         htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
2680     cmsg.header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG);
2681     cmsg.peer_id = msg->peer2;
2682     cmsg.operation_id = msg->operation_id;
2683     occ->opc = 
2684         GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
2685                                                occ->op_id, &cmsg.header,
2686                                                &overlay_connect_get_config,
2687                                                occ);
2688     occ->emsg = 
2689         GNUNET_strdup ("Timeout while getting peer identity of peer B\n");
2690     occ->timeout_task =
2691         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2692                                       (GNUNET_TIME_UNIT_SECONDS, 30),
2693                                       &timeout_overlay_connect, occ);
2694     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2695     return;
2696   }
2697   GNUNET_TESTING_peer_get_identity (peer_list[occ->other_peer_id]->details.local.peer,
2698                                     &occ->other_peer_identity);
2699   /* Connect to the core of 1st peer and wait for the 2nd peer to connect */
2700   occ->emsg = GNUNET_strdup ("Timeout while connecting to CORE");
2701   occ->ch =
2702       GNUNET_CORE_connect (occ->peer->details.local.cfg, occ, &core_startup_cb,
2703                            &overlay_connect_notify, NULL, NULL, GNUNET_NO, NULL,
2704                            GNUNET_NO, no_handlers);
2705   if (NULL == occ->ch)
2706     occ->timeout_task = 
2707         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
2708   else
2709     occ->timeout_task =
2710         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2711                                       (GNUNET_TIME_UNIT_SECONDS, 30),
2712                                       &timeout_overlay_connect, occ);
2713   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2714 }
2715
2716
2717 /**
2718  * Function to cleanup RequestOverlayConnectContext and any associated tasks
2719  * with it
2720  *
2721  * @param rocc the RequestOverlayConnectContext
2722  */
2723 static void
2724 cleanup_rocc (struct RequestOverlayConnectContext *rocc)
2725 {
2726   if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
2727     GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
2728   if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
2729     GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
2730   GNUNET_TRANSPORT_disconnect (rocc->th);
2731   GNUNET_free_non_null (rocc->hello);
2732   GNUNET_free (rocc);
2733 }
2734
2735
2736 /**
2737  * Task to timeout rocc and cleanit up
2738  *
2739  * @param cls the RequestOverlayConnectContext
2740  * @param tc the TaskContext from scheduler
2741  */
2742 static void
2743 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2744 {
2745   struct RequestOverlayConnectContext *rocc = cls;
2746   
2747   rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
2748   cleanup_rocc (rocc);
2749 }
2750
2751
2752 /**
2753  * Function called to notify transport users that another
2754  * peer connected to us.
2755  *
2756  * @param cls closure
2757  * @param new_peer the peer that connected
2758  * @param ats performance data
2759  * @param ats_count number of entries in ats (excluding 0-termination)
2760  */
2761 static void 
2762 transport_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
2763                           const struct GNUNET_ATS_Information * ats,
2764                           uint32_t ats_count)
2765 {
2766   struct RequestOverlayConnectContext *rocc = cls;
2767
2768   LOG_DEBUG ("Request Overlay connect notify\n");
2769   if (0 != memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)))
2770     return;
2771   LOG_DEBUG ("Peer %4s connected\n", GNUNET_i2s (&rocc->a_id));
2772   cleanup_rocc (rocc);
2773 }
2774
2775
2776 /**
2777  * Task to offer the HELLO message to the peer and ask it to connect to the peer
2778  * whose identity is in RequestOverlayConnectContext
2779  *
2780  * @param cls the RequestOverlayConnectContext
2781  * @param tc the TaskContext from scheduler
2782  */
2783 static void
2784 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2785 {
2786   struct RequestOverlayConnectContext *rocc = cls;
2787
2788   rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
2789   GNUNET_TRANSPORT_offer_hello (rocc->th, rocc->hello, NULL, NULL);
2790   GNUNET_TRANSPORT_try_connect (rocc->th, &rocc->a_id);
2791   rocc->attempt_connect_task_id = 
2792       GNUNET_SCHEDULER_add_delayed 
2793       (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
2794                                       100 * (pow (2, rocc->retries++))),
2795        &attempt_connect_task, rocc);
2796 }
2797
2798
2799 /**
2800  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
2801  *
2802  * @param cls NULL
2803  * @param client identification of the client
2804  * @param message the actual message
2805  */
2806 static void
2807 handle_overlay_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
2808                                 const struct GNUNET_MessageHeader *message)
2809 {
2810   const struct GNUNET_TESTBED_RequestConnectMessage *msg;
2811   struct RequestOverlayConnectContext *rocc;
2812   struct Peer *peer;
2813   uint32_t peer_id;
2814   uint16_t msize;
2815   uint16_t hsize;
2816   
2817   msize = ntohs (message->size);
2818   if (sizeof (struct GNUNET_TESTBED_RequestConnectMessage) >= msize)
2819   {
2820     GNUNET_break (0);
2821     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2822     return;
2823   }  
2824   msg = (const struct GNUNET_TESTBED_RequestConnectMessage *) message;
2825   if ((NULL == msg->hello) || 
2826       (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
2827   {
2828     GNUNET_break (0);
2829     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2830     return;
2831   }
2832   hsize = ntohs (msg->hello->size);
2833   if ((sizeof (struct GNUNET_TESTBED_RequestConnectMessage) + hsize) != msize)
2834   {
2835     GNUNET_break (0);
2836     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2837     return;
2838   }
2839   peer_id = ntohl (msg->peer);
2840   if ((peer_id >= peer_list_size) || (NULL == (peer = peer_list[peer_id])))
2841   {
2842     GNUNET_break_op (0);
2843     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2844     return;
2845   }
2846   if (GNUNET_YES == peer->is_remote)
2847   {
2848     struct GNUNET_MessageHeader *msg2;
2849     
2850     msg2 = GNUNET_malloc (msize);
2851     (void) memcpy (msg2, message, msize);
2852     GNUNET_TESTBED_queue_message_ (peer->details.remote.controller, msg2);
2853     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2854     return;
2855   }
2856   rocc = GNUNET_malloc (sizeof (struct RequestOverlayConnectContext));
2857   rocc->th = GNUNET_TRANSPORT_connect (peer->details.local.cfg, NULL, rocc, 
2858                                        NULL, &transport_connect_notify, NULL);
2859   if (NULL == rocc->th)
2860   {
2861     GNUNET_break (0);
2862     GNUNET_free (rocc);
2863     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2864     return;
2865   }
2866   memcpy (&rocc->a_id, &msg->peer_identity,
2867           sizeof (struct GNUNET_PeerIdentity));
2868   rocc->hello = GNUNET_malloc (hsize);
2869   memcpy (rocc->hello, msg->hello, hsize);
2870   rocc->attempt_connect_task_id =
2871       GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
2872   rocc->timeout_rocc_task_id =
2873       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
2874   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2875 }
2876
2877
2878 /**
2879  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
2880  *
2881  * @param cls NULL
2882  * @param client identification of the client
2883  * @param message the actual message
2884  */
2885 static void
2886 handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
2887                          const struct GNUNET_MessageHeader *message)
2888 {
2889   struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
2890   struct Slave *slave;  
2891   struct GNUNET_TESTBED_SlaveConfiguration *reply;
2892   char *config;
2893   char *xconfig;
2894   size_t config_size;
2895   size_t xconfig_size;
2896   size_t reply_size;
2897   uint64_t op_id;
2898   uint32_t slave_id;
2899
2900   msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
2901   slave_id = ntohl (msg->slave_id);
2902   op_id = GNUNET_ntohll (msg->operation_id);
2903   if ((slave_list_size <= slave_id) || (NULL == slave_list[slave_id]))
2904   {
2905     send_operation_fail_msg (client, op_id, "Slave not found");
2906     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2907     return;
2908   }
2909   slave = slave_list[slave_id];
2910   if (NULL == slave->cfg)
2911   {
2912     send_operation_fail_msg (client, op_id,
2913                              "Configuration not found (slave not started by me)");
2914     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2915     return;
2916   }
2917   config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
2918   xconfig_size = GNUNET_TESTBED_compress_config_ (config, config_size, 
2919                                                   &xconfig);
2920   GNUNET_free (config);  
2921   reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
2922   GNUNET_break (reply_size <= UINT16_MAX);
2923   GNUNET_break (config_size <= UINT16_MAX);
2924   reply = GNUNET_realloc (xconfig, reply_size);
2925   (void) memmove (&reply[1], reply, xconfig_size);
2926   reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG);
2927   reply->header.size = htons ((uint16_t) reply_size);
2928   reply->slave_id = msg->slave_id;
2929   reply->operation_id = msg->operation_id;
2930   reply->config_size = htons ((uint16_t) config_size);
2931   queue_message (client, &reply->header);
2932   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2933 }
2934
2935
2936 /**
2937  * Iterator over hash map entries.
2938  *
2939  * @param cls closure
2940  * @param key current key code
2941  * @param value value in the hash map
2942  * @return GNUNET_YES if we should continue to
2943  *         iterate,
2944  *         GNUNET_NO if not.
2945  */
2946 static int
2947 ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
2948 {
2949   struct SharedService *ss = value;
2950
2951   GNUNET_assert (GNUNET_YES ==
2952                  GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
2953   GNUNET_free (ss->name);
2954   GNUNET_free (ss);
2955   return GNUNET_YES;
2956 }
2957
2958
2959 /**
2960  * Task to clean up and shutdown nicely
2961  *
2962  * @param cls NULL
2963  * @param tc the TaskContext from scheduler
2964  */
2965 static void
2966 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2967 {
2968   struct LCFContextQueue *lcfq;
2969   uint32_t id;
2970
2971   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
2972   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
2973   (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
2974                                                 NULL);
2975   GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2976   if (NULL != lcfq_head)
2977   {
2978     if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
2979     {
2980       GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
2981       lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
2982     }
2983     if (NULL != lcfq_head->lcf->rhandle)
2984       GNUNET_TESTBED_cancel_registration (lcfq_head->lcf->rhandle);
2985   }
2986   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
2987   for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
2988   {
2989     GNUNET_free (lcfq->lcf->msg);
2990     GNUNET_free (lcfq->lcf);
2991     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2992     GNUNET_free (lcfq);
2993   }
2994   /* Clear peer list */
2995   for (id = 0; id < peer_list_size; id++)
2996     if (NULL != peer_list[id])
2997     {
2998       if (GNUNET_NO == peer_list[id]->is_remote)
2999       {
3000         if (GNUNET_YES == peer_list[id]->details.local.is_running)
3001           GNUNET_TESTING_peer_stop (peer_list[id]->details.local.peer);
3002         GNUNET_TESTING_peer_destroy (peer_list[id]->details.local.peer);
3003         GNUNET_CONFIGURATION_destroy (peer_list[id]->details.local.cfg);
3004       }
3005       GNUNET_free (peer_list[id]);
3006     }
3007   GNUNET_free_non_null (peer_list);
3008   /* Clear host list */
3009   for (id = 0; id < host_list_size; id++)
3010     if (NULL != host_list[id])
3011       GNUNET_TESTBED_host_destroy (host_list[id]);
3012   GNUNET_free_non_null (host_list);
3013   /* Clear route list */
3014   for (id = 0; id < route_list_size; id++)
3015     if (NULL != route_list[id])
3016       GNUNET_free (route_list[id]);
3017   GNUNET_free_non_null (route_list);
3018   /* Clear slave_list */
3019   for (id = 0; id < slave_list_size; id++)
3020     if (NULL != slave_list[id])
3021     {
3022       if (NULL != slave_list[id]->cfg)
3023         GNUNET_CONFIGURATION_destroy (slave_list[id]->cfg);
3024       if (NULL != slave_list[id]->controller)
3025         GNUNET_TESTBED_controller_disconnect (slave_list[id]->controller);
3026       if (NULL != slave_list[id]->controller_proc)
3027         GNUNET_TESTBED_controller_stop (slave_list[id]->controller_proc);
3028       GNUNET_free (slave_list[id]);
3029     }
3030   GNUNET_free_non_null (slave_list);
3031   if (NULL != master_context)
3032   {
3033     GNUNET_free_non_null (master_context->master_ip);
3034     if (NULL != master_context->system)
3035       GNUNET_TESTING_system_destroy (master_context->system, GNUNET_YES);
3036     GNUNET_free (master_context);
3037     master_context = NULL;
3038   }
3039   GNUNET_free_non_null (hostname);
3040 }
3041
3042
3043 /**
3044  * Callback for client disconnect
3045  *
3046  * @param cls NULL
3047  * @param client the client which has disconnected
3048  */
3049 static void
3050 client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
3051 {
3052   if (NULL == master_context)
3053     return;
3054   if (client == master_context->client)
3055   {
3056     LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
3057     GNUNET_SERVER_client_drop (client);
3058     /* should not be needed as we're terminated by failure to read
3059      * from stdin, but if stdin fails for some reason, this shouldn't
3060      * hurt for now --- might need to revise this later if we ever
3061      * decide that master connections might be temporarily down
3062      * for some reason */
3063     //GNUNET_SCHEDULER_shutdown ();
3064   }
3065 }
3066
3067
3068 /**
3069  * Testbed setup
3070  *
3071  * @param cls closure
3072  * @param server the initialized server
3073  * @param cfg configuration to use
3074  */
3075 static void
3076 testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
3077              const struct GNUNET_CONFIGURATION_Handle *cfg)
3078 {
3079   static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
3080     {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
3081     {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST, 0},
3082     {&handle_configure_shared_service, NULL,
3083      GNUNET_MESSAGE_TYPE_TESTBED_SERVICESHARE, 0},
3084     {&handle_link_controllers, NULL,
3085      GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS, 0},
3086     {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER, 0},
3087     {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER,
3088      sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
3089     {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STARTPEER,
3090      sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
3091     {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOPPEER,
3092      sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
3093     {&handle_peer_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG,
3094      sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
3095     {&handle_overlay_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT,
3096      sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
3097     {&handle_overlay_request_connect, NULL, GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT,
3098      0},
3099     {handle_slave_get_config, NULL, GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG,
3100      sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
3101     {NULL}
3102   };
3103
3104   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string 
3105                  (cfg, "testbed", "HOSTNAME", &hostname));
3106   GNUNET_SERVER_add_handlers (server, message_handlers);
3107   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
3108   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
3109   shutdown_task_id =
3110       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
3111                                     &shutdown_task, NULL);
3112   LOG_DEBUG ("Testbed startup complete\n");
3113   event_mask = GNUNET_TESTBED_ET_OPERATION_FINISHED;
3114 }
3115
3116
3117 /**
3118  * The starting point of execution
3119  */
3120 int
3121 main (int argc, char *const *argv)
3122 {
3123   //sleep (15);                 /* Debugging */
3124   return (GNUNET_OK ==
3125           GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
3126                               &testbed_run, NULL)) ? 0 : 1;
3127 }
3128
3129 /* end of gnunet-service-testbed.c */