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