43841b461d413180df00451819b1ec744a31b438
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_oc.c
1 /*
2   This file is part of GNUnet.
3   (C) 2012 Christian Grothoff (and other contributing authors)
4
5   GNUnet is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 2, or (at your
8   option) any later version.
9
10   GNUnet is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file testbed/gnunet-service-testbed_oc.c
23  * @brief code for handling overlay connect operations
24  * @author Sree Harsha Totakura
25  */
26
27 #include "gnunet-service-testbed.h"
28
29 /**
30  * Redefine LOG with a changed log component string
31  */
32 #ifdef LOG
33 #undef LOG
34 #endif
35 #define LOG(kind,...)                                   \
36   GNUNET_log_from (kind, "testbed-OC", __VA_ARGS__)
37
38
39 /**
40  * Context information for transport try connect
41  */
42 struct TryConnectContext
43 {
44   /**
45    * The identity of the peer to which the transport has to attempt a connection
46    */
47   struct GNUNET_PeerIdentity *pid;
48
49   /**
50    * The transport handle
51    */
52   struct GNUNET_TRANSPORT_Handle *th_;
53
54   /**
55    * The GetCacheHandle for the p1th transport handle
56    */
57   struct GSTCacheGetHandle *cgh_th;
58
59   /**
60    * the try connect handle
61    */
62   struct GNUNET_TRANSPORT_TryConnectHandle *tch;
63
64   /**
65    * The task handle
66    */
67   GNUNET_SCHEDULER_TaskIdentifier task;
68
69   /**
70    * The id of the operation which is resposible for this context
71    */
72   uint64_t op_id;
73
74   /**
75    * The number of times we attempted to connect
76    */
77   unsigned int retries;
78
79 };
80
81
82 /**
83  * Context information for connecting 2 peers in overlay
84  */
85 struct OverlayConnectContext
86 {
87   /**
88    * The next pointer for maintaining a DLL
89    */
90   struct OverlayConnectContext *next;
91
92   /**
93    * The prev pointer for maintaining a DLL
94    */
95   struct OverlayConnectContext *prev;
96
97   /**
98    * The client which has requested for overlay connection
99    */
100   struct GNUNET_SERVER_Client *client;
101
102   /**
103    * the peer which has to connect to the other peer
104    */
105   struct Peer *peer;
106
107   /**
108    * Transport handle of the first peer to get its HELLO
109    */
110   struct GNUNET_TRANSPORT_Handle *p1th_;
111
112   /**
113    * The CacheGetHandle for the p1th transport handle
114    */
115   struct GSTCacheGetHandle *cgh_p1th;
116
117   /**
118    * Core handles of the first peer; used to notify when second peer connects to it
119    */
120   //struct GNUNET_CORE_Handle *ch_;
121
122   /**
123    * The GetCacheHandle for the p1th transport handle
124    */
125   struct GSTCacheGetHandle *cgh_ch;
126
127   /**
128    * HELLO of the other peer
129    */
130   struct GNUNET_MessageHeader *hello;
131
132   /**
133    * Get hello handle to acquire HELLO of first peer
134    */
135   struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
136
137   /**
138    * The handle for offering HELLO
139    */
140   struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
141
142   /**
143    * The error message we send if this overlay connect operation has timed out
144    */
145   char *emsg;
146
147   /**
148    * Operation context for suboperations
149    */
150   struct OperationContext *opc;
151
152   /**
153    * Controller of peer 2; NULL if the peer is local
154    */
155   struct GNUNET_TESTBED_Controller *peer2_controller;
156
157   /**
158    * The transport try connect context
159    */
160   struct TryConnectContext tcc;
161
162   /**
163    * The peer identity of the first peer
164    */
165   struct GNUNET_PeerIdentity peer_identity;
166
167   /**
168    * The peer identity of the other peer
169    */
170   struct GNUNET_PeerIdentity other_peer_identity;
171
172   /**
173    * The id of the operation responsible for creating this context
174    */
175   uint64_t op_id;
176
177   /**
178    * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
179    * connect to peer 2
180    */
181   GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
182
183   /**
184    * The id of the overlay connect timeout task
185    */
186   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
187
188   /**
189    * The id of the cleanup task
190    */
191   GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
192
193   /**
194    * The id of peer A
195    */
196   uint32_t peer_id;
197
198   /**
199    * The id of peer B
200    */
201   uint32_t other_peer_id;
202
203 };
204
205
206 /**
207  * Context information for RequestOverlayConnect
208  * operations. RequestOverlayConnect is used when peers A, B reside on different
209  * hosts and the host controller for peer B is asked by the host controller of
210  * peer A to make peer B connect to peer A
211  */
212 struct RemoteOverlayConnectCtx
213 {
214   /**
215    * the next pointer for DLL
216    */
217   struct RemoteOverlayConnectCtx *next;
218
219   /**
220    * the prev pointer for DLL
221    */
222   struct RemoteOverlayConnectCtx *prev;
223
224   /**
225    * The peer handle of peer B
226    */
227   struct Peer *peer;
228
229   /**
230    * Peer A's HELLO
231    */
232   struct GNUNET_MessageHeader *hello;
233
234   /**
235    * The handle for offering HELLO
236    */
237   struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
238
239   /**
240    * The transport try connect context
241    */
242   struct TryConnectContext tcc;
243
244   /**
245    * The peer identity of peer A
246    */
247   struct GNUNET_PeerIdentity a_id;
248
249   /**
250    * Task for offering HELLO of A to B and doing try_connect
251    */
252   GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
253
254   /**
255    * Task to timeout RequestOverlayConnect
256    */
257   GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
258
259   /**
260    * The id of the operation responsible for creating this context
261    */
262   uint64_t op_id;
263 };
264
265
266 /**
267  * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
268  */
269 static struct OverlayConnectContext *occq_head;
270
271 /**
272  * DLL tail for OverlayConnectContext DLL
273  */
274 static struct OverlayConnectContext *occq_tail;
275
276 /**
277  * DLL head for RequectOverlayConnectContext DLL - to be used to clean up during
278  * shutdown
279  */
280 static struct RemoteOverlayConnectCtx *roccq_head;
281
282 /**
283  * DLL tail for RequectOverlayConnectContext DLL
284  */
285 static struct RemoteOverlayConnectCtx *roccq_tail;
286
287
288 /**
289  * Cleans up ForwardedOverlayConnectContext
290  *
291  * @param focc the ForwardedOverlayConnectContext to cleanup
292  */
293 void
294 GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc)
295 {
296   GNUNET_free_non_null (focc->orig_msg);
297   GNUNET_free (focc);
298 }
299
300
301 /**
302  * Timeout task for cancelling a forwarded overlay connect connect
303  *
304  * @param cls the ForwardedOverlayConnectContext
305  * @param tc the task context from the scheduler
306  */
307 static void
308 forwarded_overlay_connect_timeout (void *cls,
309                                    const struct GNUNET_SCHEDULER_TaskContext
310                                    *tc)
311 {
312   struct ForwardedOperationContext *fopc = cls;
313   struct RegisteredHostContext *rhc;
314   struct ForwardedOverlayConnectContext *focc;
315
316   rhc = fopc->cls;
317   focc = rhc->focc_dll_head;
318   GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
319   GST_cleanup_focc (focc);
320   LOG_DEBUG ("Overlay linking between peers %u and %u failed\n", focc->peer1,
321              focc->peer2);
322   GST_forwarded_operation_timeout (cls, tc);
323   if (NULL != rhc->focc_dll_head)
324     GST_process_next_focc (rhc);
325 }
326
327
328 /**
329  * Callback to be called when forwarded overlay connection operation has a reply
330  * from the sub-controller successfull. We have to relay the reply msg back to
331  * the client
332  *
333  * @param cls ForwardedOperationContext
334  * @param msg the peer create success message
335  */
336 static void
337 forwarded_overlay_connect_listener (void *cls,
338                                     const struct GNUNET_MessageHeader *msg)
339 {
340   struct ForwardedOperationContext *fopc = cls;
341   struct RegisteredHostContext *rhc;
342   struct ForwardedOverlayConnectContext *focc;
343
344   rhc = fopc->cls;
345   GST_forwarded_operation_reply_relay (cls, msg);
346   focc = rhc->focc_dll_head;
347   GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
348   GST_cleanup_focc (focc);
349   if (NULL != rhc->focc_dll_head)
350     GST_process_next_focc (rhc);
351 }
352
353
354 /**
355  * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
356  *
357  * @param rhc the RegisteredHostContext
358  */
359 void
360 GST_process_next_focc (struct RegisteredHostContext *rhc)
361 {
362   struct ForwardedOperationContext *fopc;
363   struct ForwardedOverlayConnectContext *focc;
364
365   focc = rhc->focc_dll_head;
366   GNUNET_assert (NULL != focc);
367   GNUNET_assert (RHC_OL_CONNECT == rhc->state);
368   fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
369   GNUNET_SERVER_client_keep (rhc->client);
370   fopc->client = rhc->client;
371   fopc->operation_id = focc->operation_id;
372   fopc->cls = rhc;
373   fopc->type = OP_OVERLAY_CONNECT;
374   fopc->opc =
375       GNUNET_TESTBED_forward_operation_msg_ (rhc->gateway->controller,
376                                              focc->operation_id, focc->orig_msg,
377                                              &forwarded_overlay_connect_listener,
378                                              fopc);
379   GNUNET_free (focc->orig_msg);
380   focc->orig_msg = NULL;
381   fopc->timeout_task =
382       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_overlay_connect_timeout,
383                                     fopc);
384   GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
385 }
386
387
388 /**
389  * Cleanup overlay connect context structure
390  *
391  * @param occ the overlay connect context
392  */
393 static void
394 cleanup_occ (struct OverlayConnectContext *occ)
395 {
396   LOG_DEBUG ("0x%llx: Cleaning up occ\n", occ->op_id);
397   GNUNET_free_non_null (occ->emsg);
398   GNUNET_free_non_null (occ->hello);
399   GNUNET_SERVER_client_drop (occ->client);
400   if (NULL != occ->opc)
401     GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
402   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
403     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
404   if (GNUNET_SCHEDULER_NO_TASK != occ->cleanup_task)
405     GNUNET_SCHEDULER_cancel (occ->cleanup_task);
406   if (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task)
407     GNUNET_SCHEDULER_cancel (occ->timeout_task);
408   if (NULL != occ->cgh_ch)
409   {
410     GST_cache_get_handle_done (occ->cgh_ch);
411     occ->peer->reference_cnt--;
412   }
413   if (NULL != occ->ghh)
414     GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
415   if (NULL != occ->ohh)
416     GNUNET_TRANSPORT_offer_hello_cancel (occ->ohh);
417   if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
418     GNUNET_SCHEDULER_cancel (occ->tcc.task);
419   if (NULL != occ->tcc.tch)
420     GNUNET_TRANSPORT_try_connect_cancel (occ->tcc.tch);
421   if (NULL != occ->cgh_p1th)
422   {
423     GST_cache_get_handle_done (occ->cgh_p1th);
424     occ->peer->reference_cnt--;
425   }
426   if (NULL != occ->tcc.cgh_th)
427   {
428     GST_cache_get_handle_done (occ->tcc.cgh_th);
429     GST_peer_list[occ->other_peer_id]->reference_cnt--;
430   }
431   if ((GNUNET_YES == occ->peer->destroy_flag) &&
432       (0 == occ->peer->reference_cnt))
433     GST_destroy_peer (occ->peer);
434   if ((NULL == occ->peer2_controller) &&
435       (GNUNET_YES == GST_peer_list[occ->other_peer_id]->destroy_flag) &&
436       (0 == GST_peer_list[occ->other_peer_id]->reference_cnt))
437     GST_destroy_peer (GST_peer_list[occ->other_peer_id]);
438   GNUNET_CONTAINER_DLL_remove (occq_head, occq_tail, occ);
439   GNUNET_free (occ);
440 }
441
442
443 /**
444  * Task for cleaing up overlay connect context structure
445  *
446  * @param cls the overlay connect context
447  * @param tc the task context
448  */
449 static void
450 do_cleanup_occ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
451 {
452   struct OverlayConnectContext *occ = cls;
453
454   occ->cleanup_task = GNUNET_SCHEDULER_NO_TASK;
455   cleanup_occ (occ);
456 }
457
458
459 /**
460  * Task which will be run when overlay connect request has been timed out
461  *
462  * @param cls the OverlayConnectContext
463  * @param tc the TaskContext
464  */
465 static void
466 timeout_overlay_connect (void *cls,
467                          const struct GNUNET_SCHEDULER_TaskContext *tc)
468 {
469   struct OverlayConnectContext *occ = cls;
470
471   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
472   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
473   LOG (GNUNET_ERROR_TYPE_WARNING,
474        "0x%llx: Timeout while connecting peers %u and %u\n", occ->op_id,
475        occ->peer_id, occ->other_peer_id);
476   GST_send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
477   cleanup_occ (occ);
478 }
479
480
481 static void
482 send_overlay_connect_success_msg (struct OverlayConnectContext *occ)
483 {
484   struct GNUNET_TESTBED_ConnectionEventMessage *msg;
485
486   LOG_DEBUG ("0x%llx: Peers connected - Sending overlay connect success\n",
487              occ->op_id);
488   msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
489   msg->header.size =
490       htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
491   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT);
492   msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
493   msg->peer1 = htonl (occ->peer_id);
494   msg->peer2 = htonl (occ->other_peer_id);
495   msg->operation_id = GNUNET_htonll (occ->op_id);
496   GST_queue_message (occ->client, &msg->header);
497 }
498
499
500 /**
501  * Function called to notify transport users that another
502  * peer connected to us.
503  *
504  * @param cls closure
505  * @param new_peer the peer that connected
506  */
507 static void
508 overlay_connect_notify (void *cls,
509                         const struct GNUNET_PeerIdentity *new_peer)
510 {
511   struct OverlayConnectContext *occ = cls;
512   char *new_peer_str;
513   char *other_peer_str;
514
515   //LOG_DEBUG ("Overlay connect notify\n");
516   if (0 ==
517       memcmp (new_peer, &occ->peer_identity,
518               sizeof (struct GNUNET_PeerIdentity)))
519     return;
520   new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
521   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
522   if (0 !=
523       memcmp (new_peer, &occ->other_peer_identity,
524               sizeof (struct GNUNET_PeerIdentity)))
525   {
526     /* LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n", */
527     /*         new_peer_str, other_peer_str); */
528     GNUNET_free (new_peer_str);
529     GNUNET_free (other_peer_str);
530     return;
531   }
532   GNUNET_free (new_peer_str);
533   LOG_DEBUG ("0x%llx: Peer %4s connected to peer %4s\n", occ->op_id,
534              other_peer_str, GNUNET_i2s (&occ->peer_identity));
535   GNUNET_free (other_peer_str);
536   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
537   {
538     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
539     occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
540   }
541   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
542   GNUNET_SCHEDULER_cancel (occ->timeout_task);
543   occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
544   if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
545   {
546     GNUNET_SCHEDULER_cancel (occ->tcc.task);
547     occ->tcc.task = GNUNET_SCHEDULER_NO_TASK;
548   }
549   GNUNET_free_non_null (occ->emsg);
550   occ->emsg = NULL;
551   send_overlay_connect_success_msg (occ);
552   occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
553   //cleanup_occ (occ);
554 }
555
556
557 /**
558  * Task to ask transport of a peer to connect to another peer
559  *
560  * @param cls the TryConnectContext
561  * @param tc the scheduler task context
562  */
563 static void
564 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
565
566
567 /**
568  * Callback to be called with result of the try connect request.
569  *
570  * @param cls the overlay connect context
571  * @param result GNUNET_OK if message was transmitted to transport service
572  *               GNUNET_SYSERR if message was not transmitted to transport service
573  */
574 static void
575 try_connect_cb (void *cls, const int result)
576 {
577   struct TryConnectContext *tcc = cls;
578
579   tcc->tch = NULL;
580   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == tcc->task);
581   tcc->task =
582       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
583                                     (GNUNET_TIME_UNIT_MILLISECONDS,
584                                      500 + pow (2, ++tcc->retries)),
585                                     &try_connect_task, tcc);
586 }
587
588
589 /**
590  * Task to ask transport of a peer to connect to another peer
591  *
592  * @param cls the TryConnectContext
593  * @param tc the scheduler task context
594  */
595 static void
596 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
597 {
598   struct TryConnectContext *tcc = cls;
599
600   tcc->task = GNUNET_SCHEDULER_NO_TASK;
601   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
602     return;
603   GNUNET_assert (NULL == tcc->tch);
604   GNUNET_assert (NULL != tcc->pid);
605   GNUNET_assert (NULL != tcc->th_);
606   GNUNET_assert (NULL != tcc->cgh_th);
607   LOG_DEBUG ("0x%llx: Trail %u to connect to peer %s\n", tcc->op_id,
608              tcc->retries, GNUNET_i2s (tcc->pid));
609   tcc->tch =
610       GNUNET_TRANSPORT_try_connect (tcc->th_, tcc->pid, &try_connect_cb, tcc);
611 }
612
613
614 /**
615  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
616  * peer 1.
617  *
618  * @param cls the OverlayConnectContext
619  * @param tc the TaskContext from scheduler
620  */
621 static void
622 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
623
624
625 /**
626  * Task that is run when hello has been sent
627  *
628  * @param cls the overlay connect context
629  * @param tc the scheduler task context; if tc->reason =
630  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
631  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
632  */
633 static void
634 occ_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
635 {
636   struct OverlayConnectContext *occ = cls;
637
638   occ->ohh = NULL;
639   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->send_hello_task);
640   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
641   {
642     GNUNET_free_non_null (occ->emsg);
643     GNUNET_asprintf (&occ->emsg,
644                      "0x%llx: Timeout while offering HELLO to other peer",
645                      occ->op_id);
646     occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
647     return;
648   }
649   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
650     return;
651   GNUNET_free_non_null (occ->emsg);
652   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while try connect", occ->op_id);
653   occ->tcc.pid = &occ->peer_identity;
654   occ->tcc.op_id = occ->op_id;
655   occ->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &occ->tcc);
656 }
657
658
659 /**
660  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
661  * peer 1.
662  *
663  * @param cls the OverlayConnectContext
664  * @param tc the TaskContext from scheduler
665  */
666 static void
667 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
668 {
669   struct OverlayConnectContext *occ = cls;
670   char *other_peer_str;
671
672   occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
673   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
674     return;
675   GNUNET_assert (NULL != occ->hello);
676   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
677   if (NULL != occ->peer2_controller)
678   {
679     struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
680     uint16_t msize;
681     uint16_t hello_size;
682
683     LOG_DEBUG ("0x%llx: Offering HELLO of %s (size: %u) to %s via Remote "
684                "Overlay Request\n", occ->op_id,
685                GNUNET_i2s (&occ->peer_identity), ntohs (occ->hello->size),
686                other_peer_str);
687     hello_size = ntohs (occ->hello->size);
688     msize =
689         sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hello_size;
690     msg = GNUNET_malloc (msize);
691     msg->header.type =
692         htons (GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT);
693     msg->header.size = htons (msize);
694     msg->peer = htonl (occ->other_peer_id);
695     msg->operation_id = GNUNET_htonll (occ->op_id);
696     (void) memcpy (&msg->peer_identity, &occ->peer_identity,
697                    sizeof (struct GNUNET_PeerIdentity));
698     memcpy (msg->hello, occ->hello, hello_size);
699     GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
700   }
701   else
702   {
703     LOG_DEBUG ("0x%llx: Offering HELLO of %s to %s\n", occ->op_id,
704                GNUNET_i2s (&occ->peer_identity), other_peer_str);
705     occ->ohh =
706         GNUNET_TRANSPORT_offer_hello (occ->tcc.th_, occ->hello,
707                                       occ_hello_sent_cb, occ);
708     if (NULL == occ->ohh)
709     {
710       GNUNET_break (0);
711       occ->send_hello_task =
712           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
713                                         (GNUNET_TIME_UNIT_MILLISECONDS,
714                                          100 +
715                                          GNUNET_CRYPTO_random_u32
716                                          (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
717                                         &send_hello, occ);
718     }
719   }
720   GNUNET_free (other_peer_str);
721 }
722
723
724 /**
725  * Callback from cache with needed handles set
726  *
727  * @param cls the closure passed to GST_cache_get_handle_transport()
728  * @param ch the handle to CORE. Can be NULL if it is not requested
729  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
730  * @param ignore_ peer identity which is ignored in this callback
731  */
732 static void 
733 p2_transport_connect_cache_callback (void *cls, struct GNUNET_CORE_Handle *ch, 
734                                      struct GNUNET_TRANSPORT_Handle *th,
735                                      const struct GNUNET_PeerIdentity *ignore_)
736 {
737   struct OverlayConnectContext *occ = cls;
738
739   if (NULL == th)
740   {
741     GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
742                      occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
743     GNUNET_SCHEDULER_cancel (occ->timeout_task);
744     occ->timeout_task =
745         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
746     return;
747   }
748   occ->tcc.th_ = th;
749   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
750                    occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
751   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
752 }
753
754
755 /**
756  * Connects to the transport of the other peer if it is a local peer and
757  * schedules the send hello task
758  *
759  * @param occ the overlay connect context
760  */
761 static void
762 p2_transport_connect (struct OverlayConnectContext *occ)
763 {
764   GNUNET_assert (NULL == occ->emsg);
765   GNUNET_assert (NULL != occ->hello);
766   GNUNET_assert (NULL == occ->ghh);
767   GNUNET_assert (NULL == occ->p1th_);
768   GNUNET_assert (NULL == occ->cgh_p1th);
769   if (NULL == occ->peer2_controller)
770   {
771     GST_peer_list[occ->other_peer_id]->reference_cnt++;
772     occ->tcc.cgh_th = 
773         GST_cache_get_handle_transport (occ->other_peer_id,
774                                         GST_peer_list[occ->other_peer_id]->
775                                         details.local.cfg,
776                                         &p2_transport_connect_cache_callback,
777                                         occ,
778                                         NULL, NULL, NULL);
779     return;
780   }
781   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
782                    occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
783   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
784 }
785
786
787 /**
788  * Test for checking whether HELLO message is empty
789  *
790  * @param cls empty flag to set
791  * @param address the HELLO
792  * @param expiration expiration of the HELLO
793  * @return
794  */
795 static int
796 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
797               struct GNUNET_TIME_Absolute expiration)
798 {
799   int *empty = cls;
800
801   *empty = GNUNET_NO;
802   return GNUNET_OK;
803 }
804
805
806 /**
807  * Function called whenever there is an update to the HELLO of peers in the
808  * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
809  * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
810  *
811  * @param cls closure
812  * @param hello our updated HELLO
813  */
814 static void
815 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
816 {
817   struct OverlayConnectContext *occ = cls;
818   int empty;
819   uint16_t msize;
820
821   msize = ntohs (hello->size);
822   empty = GNUNET_YES;
823   (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
824                                          hello, GNUNET_NO, &test_address,
825                                          &empty);
826   if (GNUNET_YES == empty)
827   {
828     LOG_DEBUG ("0x%llx: HELLO of %s is empty\n", occ->op_id,
829                GNUNET_i2s (&occ->peer_identity));
830     return;
831   }
832   LOG_DEBUG ("0x%llx: Received HELLO of %s\n", occ->op_id,
833              GNUNET_i2s (&occ->peer_identity));
834   occ->hello = GNUNET_malloc (msize);
835   GST_cache_add_hello (occ->peer_id, hello);
836   memcpy (occ->hello, hello, msize);
837   GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
838   occ->ghh = NULL;
839   GST_cache_get_handle_done (occ->cgh_p1th);
840   occ->peer->reference_cnt--;
841   occ->cgh_p1th = NULL;
842   occ->p1th_ = NULL;
843   GNUNET_free_non_null (occ->emsg);
844   occ->emsg = NULL;
845   p2_transport_connect (occ);
846 }
847
848
849 /**
850  * Callback from cache with needed handles set
851  *
852  * @param cls the closure passed to GST_cache_get_handle_transport()
853  * @param ch the handle to CORE. Can be NULL if it is not requested
854  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
855  * @param ignore_ peer identity which is ignored in this callback
856  */
857 static void 
858 p1_transport_connect_cache_callback (void *cls, struct GNUNET_CORE_Handle *ch, 
859                                      struct GNUNET_TRANSPORT_Handle *th,
860                                      const struct GNUNET_PeerIdentity *ignore_)
861 {
862   struct OverlayConnectContext *occ = cls;
863
864   GNUNET_free_non_null (occ->emsg);
865   occ->emsg = NULL;
866   if (NULL == th)
867   {
868     GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
869                      occ->op_id, GNUNET_i2s (&occ->peer_identity));
870     GNUNET_SCHEDULER_cancel (occ->timeout_task);
871     occ->timeout_task =
872         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
873     return;
874   }
875   GNUNET_assert (NULL == occ->p1th_);
876   GNUNET_assert (NULL != occ->cgh_p1th);
877   occ->p1th_ = th;
878   GNUNET_asprintf (&occ->emsg,
879                    "0x%llx: Timeout while acquiring HELLO of peer %4s",
880                    occ->op_id, GNUNET_i2s (&occ->peer_identity));
881   occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th_, &hello_update_cb, occ);
882 }
883
884
885 /**
886  * Callback from cache with needed handles set
887  *
888  * @param cls the closure passed to GST_cache_get_handle_transport()
889  * @param ch the handle to CORE. Can be NULL if it is not requested
890  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
891  * @param my_identity the identity of our peer
892  */
893 static void 
894 occ_cache_get_handle_core_cb (void *cls, struct GNUNET_CORE_Handle *ch, 
895                               struct GNUNET_TRANSPORT_Handle *th,
896                               const struct GNUNET_PeerIdentity *my_identity)
897 {
898   struct OverlayConnectContext *occ = cls;
899   const struct GNUNET_MessageHeader *hello;
900
901   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
902   GNUNET_free_non_null (occ->emsg);
903   if ((NULL == ch) || (NULL == my_identity))
904   {
905     (void) GNUNET_asprintf (&occ->emsg,
906                             "0x%llx: Failed to connect to CORE of peer with"
907                             "id: %u", occ->op_id, occ->peer_id);
908     GNUNET_SCHEDULER_cancel (occ->timeout_task);
909     occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
910     return;
911   }
912   //occ->ch_ = ch;
913   occ->emsg = NULL;
914   if (GNUNET_YES == 
915       GNUNET_CORE_is_peer_connected_sync (ch, &occ->other_peer_identity))
916   {
917     LOG_DEBUG ("0x%llx: Target peer already connected\n", occ->op_id);
918     GNUNET_SCHEDULER_cancel (occ->timeout_task);
919     occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
920     send_overlay_connect_success_msg (occ);
921     occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
922     return;
923   }  
924   memcpy (&occ->peer_identity, my_identity,
925           sizeof (struct GNUNET_PeerIdentity));
926   LOG_DEBUG ("0x%llx: Acquiring HELLO of peer %s\n", occ->op_id,
927              GNUNET_i2s (&occ->peer_identity));
928   /* Lookup for HELLO in hello cache */
929   if (NULL != (hello = GST_cache_lookup_hello (occ->peer_id)))
930   {
931     LOG_DEBUG ("0x%llx: HELLO of peer %s found in cache\n", occ->op_id,
932                GNUNET_i2s (&occ->peer_identity));
933     occ->hello = GNUNET_copy_message (hello);
934     p2_transport_connect (occ);
935     return;
936   }
937   GNUNET_asprintf (&occ->emsg,
938                    "0x%llx: Timeout while acquiring TRANSPORT of %s from cache",
939                    occ->op_id, GNUNET_i2s (&occ->peer_identity));
940   occ->peer->reference_cnt++;
941   occ->cgh_p1th = 
942       GST_cache_get_handle_transport (occ->peer_id,
943                                       occ->peer->details.local.cfg,
944                                       p1_transport_connect_cache_callback,
945                                       occ,
946                                       NULL, NULL, NULL);
947   return;
948 }
949
950
951 /**
952  * Callback to be called when forwarded get peer config operation as part of
953  * overlay connect is successfull. Connection to Peer 1's core is made and is
954  * checked for new connection from peer 2
955  *
956  * @param cls ForwardedOperationContext
957  * @param msg the peer create success message
958  */
959 static void
960 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
961 {
962   struct OverlayConnectContext *occ = cls;
963   const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
964
965   occ->opc = NULL;
966   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
967   if (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION != ntohs (msg->type))
968   {
969     GNUNET_SCHEDULER_cancel (occ->timeout_task);
970     occ->timeout_task =
971         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
972   }
973   cmsg =
974       (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
975   memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
976           sizeof (struct GNUNET_PeerIdentity));
977   GNUNET_free_non_null (occ->emsg);
978   GNUNET_asprintf (&occ->emsg,
979                    "0x%llx: Timeout while connecting to CORE of peer with "
980                    "id: %u", occ->op_id, occ->peer_id);
981   occ->peer->reference_cnt++;
982   occ->cgh_ch = GST_cache_get_handle_core (occ->peer_id,
983                                            occ->peer->details.local.cfg,
984                                            occ_cache_get_handle_core_cb,
985                                            occ,
986                                            &occ->other_peer_identity,
987                                            &overlay_connect_notify,
988                                            occ);
989   return;
990 }
991
992
993 /**
994  * Callback which will be called to after a host registration succeeded or failed
995  *
996  * @param cls the RegisteredHostContext
997  * @param emsg the error message; NULL if host registration is successful
998  */
999 static void
1000 registeredhost_registration_completion (void *cls, const char *emsg)
1001 {
1002   struct RegisteredHostContext *rhc = cls;
1003   struct GNUNET_CONFIGURATION_Handle *cfg;
1004   uint32_t peer2_host_id;
1005
1006   /* if (NULL != rhc->focc_dll_head) */
1007   /*   TESTBED_process_next_focc (rhc); */
1008   peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
1009   GNUNET_assert (RHC_INIT == rhc->state);
1010   GNUNET_assert (NULL == rhc->sub_op);
1011   if ((NULL == rhc->gateway2) || ((peer2_host_id < GST_slave_list_size) /* Check if we have the needed config */
1012                                   && (NULL != GST_slave_list[peer2_host_id])))
1013   {
1014     rhc->state = RHC_LINK;
1015     cfg =
1016         (NULL ==
1017          rhc->gateway2) ? our_config : GST_slave_list[peer2_host_id]->cfg;
1018     rhc->sub_op =
1019         GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
1020                                         rhc->reg_host, rhc->host, cfg,
1021                                         GNUNET_NO);
1022     return;
1023   }
1024   rhc->state = RHC_GET_CFG;
1025   rhc->sub_op =
1026       GNUNET_TESTBED_get_slave_config (rhc, rhc->gateway2->controller,
1027                                        rhc->reg_host);
1028 }
1029
1030
1031 /**
1032  * Iterator to match a registered host context
1033  *
1034  * @param cls pointer 2 pointer of RegisteredHostContext
1035  * @param key current key code
1036  * @param value value in the hash map
1037  * @return GNUNET_YES if we should continue to
1038  *         iterate,
1039  *         GNUNET_NO if not.
1040  */
1041 static int
1042 reghost_match_iterator (void *cls, const struct GNUNET_HashCode *key,
1043                         void *value)
1044 {
1045   struct RegisteredHostContext **rh = cls;
1046   struct RegisteredHostContext *rh_val = value;
1047
1048   if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
1049   {
1050     GNUNET_free (*rh);
1051     *rh = rh_val;
1052     return GNUNET_NO;
1053   }
1054   return GNUNET_YES;
1055 }
1056
1057
1058 /**
1059  * Function to generate the hashcode corresponding to a RegisteredHostContext
1060  *
1061  * @param reg_host the host which is being registered in RegisteredHostContext
1062  * @param host the host of the controller which has to connect to the above rhost
1063  * @return the hashcode
1064  */
1065 static struct GNUNET_HashCode
1066 hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
1067             struct GNUNET_TESTBED_Host *host)
1068 {
1069   struct GNUNET_HashCode hash;
1070   uint32_t host_ids[2];
1071
1072   host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
1073   host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
1074   GNUNET_CRYPTO_hash (host_ids, sizeof (host_ids), &hash);
1075   return hash;
1076 }
1077
1078
1079 /**
1080  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
1081  *
1082  * @param cls NULL
1083  * @param client identification of the client
1084  * @param message the actual message
1085  */
1086 void
1087 GST_handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
1088                             const struct GNUNET_MessageHeader *message)
1089 {
1090   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
1091   struct Peer *peer;
1092   struct OverlayConnectContext *occ;
1093   struct GNUNET_TESTBED_Controller *peer2_controller;
1094   uint64_t operation_id;
1095   uint32_t p1;
1096   uint32_t p2;
1097   uint32_t peer2_host_id;
1098
1099   if (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage) !=
1100       ntohs (message->size))
1101   {
1102     GNUNET_break (0);
1103     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1104     return;
1105   }
1106   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
1107   p1 = ntohl (msg->peer1);
1108   p2 = ntohl (msg->peer2);
1109   if ((p1 >= GST_peer_list_size) || (NULL == GST_peer_list[p1]))
1110   {
1111     GNUNET_break (0);
1112     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1113     return;
1114   }
1115   peer = GST_peer_list[p1];
1116   peer2_host_id = ntohl (msg->peer2_host_id);
1117   operation_id = GNUNET_ntohll (msg->operation_id);
1118   LOG_DEBUG
1119       ("Received overlay connect for peers %u and %u with op id: 0x%llx\n", p1,
1120        p2, operation_id);
1121   if (GNUNET_YES == peer->is_remote)
1122   {
1123     struct ForwardedOperationContext *fopc;
1124     struct Route *route_to_peer2_host;
1125     struct Route *route_to_peer1_host;
1126
1127     LOG_DEBUG ("0x%llx: Forwarding overlay connect\n", operation_id);
1128     route_to_peer2_host = NULL;
1129     route_to_peer1_host = NULL;
1130     route_to_peer2_host = GST_find_dest_route (peer2_host_id);
1131     if ((NULL != route_to_peer2_host) ||
1132         (peer2_host_id == GST_context->host_id))
1133     {
1134       /* Peer 2 either below us OR with us */
1135       route_to_peer1_host =
1136           GST_find_dest_route (GST_peer_list[p1]->details.
1137                                remote.remote_host_id);
1138       /* Because we get this message only if we know where peer 1 is */
1139       GNUNET_assert (NULL != route_to_peer1_host);
1140       if ((peer2_host_id == GST_context->host_id) ||
1141           (route_to_peer2_host->dest != route_to_peer1_host->dest))
1142       {
1143         /* Peer2 is either with us OR peer1 and peer2 can be reached through
1144          * different gateways */
1145         struct GNUNET_HashCode hash;
1146         struct RegisteredHostContext *rhc;
1147         int skip_focc;
1148
1149         rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
1150         if (NULL != route_to_peer2_host)
1151           rhc->reg_host = GST_host_list[route_to_peer2_host->dest];
1152         else
1153           rhc->reg_host = GST_host_list[GST_context->host_id];
1154         rhc->host = GST_host_list[route_to_peer1_host->dest];
1155         GNUNET_assert (NULL != rhc->reg_host);
1156         GNUNET_assert (NULL != rhc->host);
1157         rhc->gateway = peer->details.remote.slave;
1158         rhc->gateway2 =
1159             (NULL ==
1160              route_to_peer2_host) ? NULL :
1161             GST_slave_list[route_to_peer2_host->dest];
1162         rhc->state = RHC_INIT;
1163         GNUNET_SERVER_client_keep (client);
1164         rhc->client = client;
1165         hash = hash_hosts (rhc->reg_host, rhc->host);
1166         skip_focc = GNUNET_NO;
1167         if ((GNUNET_NO ==
1168              GNUNET_CONTAINER_multihashmap_contains (peer->details.
1169                                                      remote.slave->reghost_map,
1170                                                      &hash)) ||
1171             (GNUNET_SYSERR !=
1172              GNUNET_CONTAINER_multihashmap_get_multiple (peer->details.remote.
1173                                                          slave->reghost_map,
1174                                                          &hash,
1175                                                          reghost_match_iterator,
1176                                                          &rhc)))
1177         {
1178           /* create and add a new registerd host context */
1179           /* add the focc to its queue */
1180           GNUNET_CONTAINER_multihashmap_put (peer->details.remote.
1181                                              slave->reghost_map, &hash, rhc,
1182                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1183           GNUNET_assert (NULL != GST_host_list[peer2_host_id]);
1184           GST_queue_host_registration (peer->details.remote.slave,
1185                                        registeredhost_registration_completion,
1186                                        rhc, GST_host_list[peer2_host_id]);
1187         }
1188         else
1189         {
1190           /* rhc is now set to the existing one from the hash map by
1191            * reghost_match_iterator() */
1192           /* if queue is empty then ignore creating focc and proceed with
1193            * normal forwarding */
1194           if (RHC_OL_CONNECT == rhc->state)
1195             skip_focc = GNUNET_YES;
1196         }
1197         if (GNUNET_NO == skip_focc)
1198         {
1199           struct ForwardedOverlayConnectContext *focc;
1200
1201           focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
1202           focc->peer1 = p1;
1203           focc->peer2 = p2;
1204           focc->peer2_host_id = peer2_host_id;
1205           focc->orig_msg = GNUNET_copy_message (message);
1206           focc->operation_id = operation_id;
1207           GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
1208                                             rhc->focc_dll_tail, focc);
1209           GNUNET_SERVER_receive_done (client, GNUNET_OK);
1210           return;
1211         }
1212       }
1213     }
1214     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1215     GNUNET_SERVER_client_keep (client);
1216     fopc->client = client;
1217     fopc->operation_id = operation_id;
1218     fopc->type = OP_OVERLAY_CONNECT;
1219     fopc->opc =
1220         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1221                                                slave->controller, operation_id,
1222                                                message,
1223                                                &GST_forwarded_operation_reply_relay,
1224                                                fopc);
1225     fopc->timeout_task =
1226         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
1227                                       fopc);
1228     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1229     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1230     return;
1231   }
1232
1233   peer2_controller = NULL;
1234   if ((p2 >= GST_peer_list_size) || (NULL == GST_peer_list[p2]))
1235   {
1236     if ((peer2_host_id >= GST_slave_list_size) ||
1237         (NULL == GST_slave_list[peer2_host_id]))
1238     {
1239       LOG (GNUNET_ERROR_TYPE_WARNING,
1240            "0x%llx: Configuration of peer2's controller missing for connecting peers"
1241            "%u and %u\n", operation_id, p1, p2);
1242       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1243       return;
1244     }
1245     peer2_controller = GST_slave_list[peer2_host_id]->controller;
1246     if (NULL == peer2_controller)
1247     {
1248       GNUNET_break (0);         /* What's going on? */
1249       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1250       return;
1251     }
1252   }
1253   else
1254   {
1255     if (GNUNET_YES == GST_peer_list[p2]->is_remote)
1256       peer2_controller = GST_peer_list[p2]->details.remote.slave->controller;
1257   }
1258   occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
1259   GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
1260   GNUNET_SERVER_client_keep (client);
1261   occ->client = client;
1262   occ->peer_id = p1;
1263   occ->other_peer_id = p2;
1264   occ->peer = GST_peer_list[p1];
1265   occ->op_id = GNUNET_ntohll (msg->operation_id);
1266   occ->peer2_controller = peer2_controller;
1267   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->timeout_task);
1268   occ->timeout_task =
1269       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_overlay_connect, occ);
1270   /* Get the identity of the second peer */
1271   if (NULL != occ->peer2_controller)
1272   {
1273     struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
1274
1275     cmsg.header.size =
1276         htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
1277     cmsg.header.type =
1278         htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
1279     cmsg.peer_id = msg->peer2;
1280     cmsg.operation_id = msg->operation_id;
1281     occ->opc =
1282         GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
1283                                                occ->op_id, &cmsg.header,
1284                                                &overlay_connect_get_config,
1285                                                occ);
1286     GNUNET_asprintf (&occ->emsg,
1287                      "0x%llx: Timeout while getting peer identity of peer "
1288                      "with id: %u", occ->op_id, occ->other_peer_id);
1289     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1290     return;
1291   }
1292   GNUNET_TESTING_peer_get_identity (GST_peer_list[occ->other_peer_id]->
1293                                     details.local.peer,
1294                                     &occ->other_peer_identity);
1295   GNUNET_asprintf (&occ->emsg,
1296                    "0x%llx: Timeout while connecting to CORE of peer with "
1297                    "id: %u", occ->op_id, occ->peer_id);
1298   occ->peer->reference_cnt++;
1299   occ->cgh_ch = GST_cache_get_handle_core (occ->peer_id,
1300                                            occ->peer->details.local.cfg,
1301                                            occ_cache_get_handle_core_cb,
1302                                            occ,
1303                                            &occ->other_peer_identity,
1304                                            &overlay_connect_notify,
1305                                            occ);
1306   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1307 }
1308
1309
1310 /**
1311  * Function to cleanup RemoteOverlayConnectCtx and any associated tasks
1312  * with it
1313  *
1314  * @param rocc the RemoteOverlayConnectCtx
1315  */
1316 static void
1317 cleanup_rocc (struct RemoteOverlayConnectCtx *rocc)
1318 {
1319   LOG_DEBUG ("0x%llx: Cleaning up rocc\n", rocc->op_id);
1320   if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
1321     GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
1322   if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
1323     GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
1324   if (NULL != rocc->ohh)
1325     GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
1326   if (NULL != rocc->tcc.tch)
1327     GNUNET_TRANSPORT_try_connect_cancel (rocc->tcc.tch);
1328   if (GNUNET_SCHEDULER_NO_TASK != rocc->tcc.task)
1329     GNUNET_SCHEDULER_cancel (rocc->tcc.task);
1330   //GNUNET_TRANSPORT_disconnect (rocc->tcc.th_);
1331   GST_cache_get_handle_done (rocc->tcc.cgh_th);
1332   rocc->peer->reference_cnt--;
1333   if ((GNUNET_YES == rocc->peer->destroy_flag) &&
1334       (0 == rocc->peer->reference_cnt))
1335     GST_destroy_peer (rocc->peer);
1336   GNUNET_free_non_null (rocc->hello);
1337   GNUNET_CONTAINER_DLL_remove (roccq_head, roccq_tail, rocc);
1338   GNUNET_free (rocc);
1339 }
1340
1341
1342 /**
1343  * Task to timeout rocc and cleanit up
1344  *
1345  * @param cls the RemoteOverlayConnectCtx
1346  * @param tc the TaskContext from scheduler
1347  */
1348 static void
1349 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1350 {
1351   struct RemoteOverlayConnectCtx *rocc = cls;
1352
1353   GNUNET_assert (rocc->timeout_rocc_task_id != GNUNET_SCHEDULER_NO_TASK);
1354   rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
1355   LOG_DEBUG ("0x%llx: rocc timed out\n", rocc->op_id);
1356   cleanup_rocc (rocc);
1357 }
1358
1359
1360 /**
1361  * Function called to notify transport users that another
1362  * peer connected to us.
1363  *
1364  * @param cls closure
1365  * @param new_peer the peer that connected
1366  * @param ats performance data
1367  * @param ats_count number of entries in ats (excluding 0-termination)
1368  */
1369 static void
1370 cache_transport_peer_connect_notify (void *cls, 
1371                                      const struct GNUNET_PeerIdentity *new_peer)
1372 {
1373   struct RemoteOverlayConnectCtx *rocc = cls;
1374
1375   LOG_DEBUG ("0x%llx: Request Overlay connect notify\n", rocc->op_id);
1376   GNUNET_assert (0 == memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)));
1377   LOG_DEBUG ("0x%llx: Peer %4s connected\n", rocc->op_id,
1378              GNUNET_i2s (&rocc->a_id));
1379   cleanup_rocc (rocc);
1380 }
1381
1382
1383 /**
1384  * Task to offer the HELLO message to the peer and ask it to connect to the peer
1385  * whose identity is in RemoteOverlayConnectCtx
1386  *
1387  * @param cls the RemoteOverlayConnectCtx
1388  * @param tc the TaskContext from scheduler
1389  */
1390 static void
1391 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1392
1393
1394 /**
1395  * Task that is run when hello has been sent
1396  *
1397  * @param cls the overlay connect context
1398  * @param tc the scheduler task context; if tc->reason =
1399  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
1400  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
1401  */
1402 static void
1403 rocc_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1404 {
1405   struct RemoteOverlayConnectCtx *rocc = cls;
1406
1407   rocc->ohh = NULL;
1408   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rocc->attempt_connect_task_id);
1409   LOG_DEBUG ("0x%llx: HELLO of peer %4s sent to local peer with id: %u\n",
1410              rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1411   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
1412   {
1413     GNUNET_break (0);
1414     rocc->attempt_connect_task_id =
1415         GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
1416     return;
1417   }
1418   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
1419     return;
1420   rocc->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &rocc->tcc);
1421 }
1422
1423
1424 /**
1425  * Task to offer the HELLO message to the peer and ask it to connect to the peer
1426  * whose identity is in RemoteOverlayConnectCtx
1427  *
1428  * @param cls the RemoteOverlayConnectCtx
1429  * @param tc the TaskContext from scheduler
1430  */
1431 static void
1432 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1433 {
1434   struct RemoteOverlayConnectCtx *rocc = cls;
1435
1436   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id);
1437   rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
1438   LOG_DEBUG ("0x%llx: Offering HELLO of peer %4s to local peer with id: %u\n",
1439              rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1440   rocc->ohh =
1441       GNUNET_TRANSPORT_offer_hello (rocc->tcc.th_, rocc->hello,
1442                                     rocc_hello_sent_cb, rocc);
1443   if (NULL == rocc->ohh)
1444     rocc->attempt_connect_task_id =
1445         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1446                                       (GNUNET_TIME_UNIT_MILLISECONDS,
1447                                        100 +
1448                                        GNUNET_CRYPTO_random_u32
1449                                        (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
1450                                       &attempt_connect_task, rocc);
1451 }
1452
1453
1454 /**
1455  * Callback from cache with needed handles set
1456  *
1457  * @param cls the closure passed to GST_cache_get_handle_transport()
1458  * @param ch the handle to CORE. Can be NULL if it is not requested
1459  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
1460  * @param ignore_ peer identity which is ignored in this callback
1461  */
1462 static void 
1463 rocc_cache_get_handle_transport_cb (void *cls, struct GNUNET_CORE_Handle *ch, 
1464                                     struct GNUNET_TRANSPORT_Handle *th,
1465                                     const struct GNUNET_PeerIdentity *ignore_)
1466 {
1467   struct RemoteOverlayConnectCtx *rocc = cls;
1468   
1469   if (NULL == th)
1470   {
1471     rocc->timeout_rocc_task_id =
1472         GNUNET_SCHEDULER_add_now (&timeout_rocc_task, rocc);
1473     return;
1474   }
1475   rocc->tcc.th_ = th;
1476   rocc->tcc.pid = &rocc->a_id;
1477   if (GNUNET_YES == GNUNET_TRANSPORT_check_neighbour_connected (rocc->tcc.th_,
1478                                                                 rocc->tcc.pid))
1479   {
1480     LOG_DEBUG ("0x%llx: Target peer %4s already connected to local peer: %u\n",
1481                rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1482     cleanup_rocc (rocc);
1483     return;
1484   }
1485   rocc->attempt_connect_task_id =
1486       GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);  
1487 }
1488
1489
1490 /**
1491  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
1492  *
1493  * @param cls NULL
1494  * @param client identification of the client
1495  * @param message the actual message
1496  */
1497 void
1498 GST_handle_remote_overlay_connect (void *cls,
1499                                    struct GNUNET_SERVER_Client *client,
1500                                    const struct GNUNET_MessageHeader *message)
1501 {
1502   const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
1503   struct RemoteOverlayConnectCtx *rocc;
1504   struct Peer *peer;
1505   uint32_t peer_id;
1506   uint16_t msize;
1507   uint16_t hsize;
1508
1509   msize = ntohs (message->size);
1510   if (sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) >= msize)
1511   {
1512     GNUNET_break (0);
1513     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1514     return;
1515   }
1516   msg = (const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *) message;
1517   if ((NULL == msg->hello) ||
1518       (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
1519   {
1520     GNUNET_break (0);
1521     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1522     return;
1523   }
1524   hsize = ntohs (msg->hello->size);
1525   if ((sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hsize) !=
1526       msize)
1527   {
1528     GNUNET_break (0);
1529     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1530     return;
1531   }
1532   peer_id = ntohl (msg->peer);
1533   if ((peer_id >= GST_peer_list_size) ||
1534       (NULL == (peer = GST_peer_list[peer_id])))
1535   {
1536     GNUNET_break_op (0);
1537     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1538     return;
1539   }
1540   if (GNUNET_YES == peer->is_remote)
1541   {
1542     struct GNUNET_MessageHeader *msg2;
1543
1544     msg2 = GNUNET_copy_message (message);
1545     GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller,
1546                                    msg2);
1547     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1548     return;
1549   }
1550   rocc = GNUNET_malloc (sizeof (struct RemoteOverlayConnectCtx));
1551   rocc->op_id = GNUNET_ntohll (msg->operation_id);
1552   GNUNET_CONTAINER_DLL_insert_tail (roccq_head, roccq_tail, rocc);
1553   memcpy (&rocc->a_id, &msg->peer_identity,
1554           sizeof (struct GNUNET_PeerIdentity));
1555   LOG_DEBUG ("Received request for overlay connection with op_id: 0x%llx "
1556              "from local peer %u to peer %4s with hello size: %u\n",
1557              rocc->op_id, peer_id, GNUNET_i2s (&rocc->a_id), hsize);
1558   rocc->peer = peer;
1559   rocc->peer->reference_cnt++;
1560   rocc->hello = GNUNET_malloc (hsize);
1561   memcpy (rocc->hello, msg->hello, hsize);
1562   rocc->tcc.cgh_th = 
1563       GST_cache_get_handle_transport (peer_id,
1564                                       rocc->peer->details.local.cfg,
1565                                       &rocc_cache_get_handle_transport_cb,
1566                                       rocc, 
1567                                       &rocc->a_id,
1568                                       &cache_transport_peer_connect_notify,
1569                                       rocc);
1570   rocc->timeout_rocc_task_id =
1571       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
1572   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1573 }
1574
1575
1576 /**
1577  * Clears all pending overlay connect contexts in queue
1578  */
1579 void
1580 GST_free_occq ()
1581 {
1582   struct OverlayConnectContext *occ;
1583
1584   while (NULL != (occ = occq_head))
1585     cleanup_occ (occ);
1586 }
1587
1588
1589 /**
1590  * Clears all pending remote overlay connect contexts in queue
1591  */
1592 void
1593 GST_free_roccq ()
1594 {
1595   struct RemoteOverlayConnectCtx *rocc;
1596
1597   while (NULL != (rocc = roccq_head))
1598     cleanup_rocc (rocc);
1599 }