- fixes and implements caching core handles
[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 GetCacheHandle for the p1th transport handle
114    */
115   struct GSTGetCacheHandle *gch_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->p1th)
422   {
423     GNUNET_TRANSPORT_disconnect (occ->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   GST_cache_get_handle_done (occ->cgh_ch);
550   occ->peer->reference_cnt--;
551   occ->cgh_ch = NULL;
552   GNUNET_free_non_null (occ->emsg);
553   occ->emsg = NULL;
554   send_overlay_connect_success_msg (occ);
555   occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
556   //cleanup_occ (occ);
557 }
558
559
560 /**
561  * Task to ask transport of a peer to connect to another peer
562  *
563  * @param cls the TryConnectContext
564  * @param tc the scheduler task context
565  */
566 static void
567 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
568
569
570 /**
571  * Callback to be called with result of the try connect request.
572  *
573  * @param cls the overlay connect context
574  * @param result GNUNET_OK if message was transmitted to transport service
575  *               GNUNET_SYSERR if message was not transmitted to transport service
576  */
577 static void
578 try_connect_cb (void *cls, const int result)
579 {
580   struct TryConnectContext *tcc = cls;
581
582   tcc->tch = NULL;
583   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == tcc->task);
584   tcc->task =
585       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
586                                     (GNUNET_TIME_UNIT_MILLISECONDS,
587                                      500 + pow (2, ++tcc->retries)),
588                                     &try_connect_task, tcc);
589 }
590
591
592 /**
593  * Task to ask transport of a peer to connect to another peer
594  *
595  * @param cls the TryConnectContext
596  * @param tc the scheduler task context
597  */
598 static void
599 try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
600 {
601   struct TryConnectContext *tcc = cls;
602
603   tcc->task = GNUNET_SCHEDULER_NO_TASK;
604   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
605     return;
606   GNUNET_assert (NULL == tcc->tch);
607   GNUNET_assert (NULL != tcc->pid);
608   GNUNET_assert (NULL != tcc->th_);
609   GNUNET_assert (NULL != tcc->cgh_th);
610   LOG_DEBUG ("0x%llx: Trail %u to connect to peer %s\n", tcc->op_id,
611              tcc->retries, GNUNET_i2s (tcc->pid));
612   tcc->tch =
613       GNUNET_TRANSPORT_try_connect (tcc->th_, tcc->pid, &try_connect_cb, tcc);
614 }
615
616
617 /**
618  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
619  * peer 1.
620  *
621  * @param cls the OverlayConnectContext
622  * @param tc the TaskContext from scheduler
623  */
624 static void
625 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
626
627
628 /**
629  * Task that is run when hello has been sent
630  *
631  * @param cls the overlay connect context
632  * @param tc the scheduler task context; if tc->reason =
633  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
634  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
635  */
636 static void
637 occ_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
638 {
639   struct OverlayConnectContext *occ = cls;
640
641   occ->ohh = NULL;
642   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->send_hello_task);
643   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
644   {
645     GNUNET_free_non_null (occ->emsg);
646     GNUNET_asprintf (&occ->emsg,
647                      "0x%llx: Timeout while offering HELLO to other peer",
648                      occ->op_id);
649     occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
650     return;
651   }
652   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
653     return;
654   GNUNET_free_non_null (occ->emsg);
655   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while try connect", occ->op_id);
656   occ->tcc.pid = &occ->peer_identity;
657   occ->tcc.op_id = occ->op_id;
658   occ->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &occ->tcc);
659 }
660
661
662 /**
663  * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
664  * peer 1.
665  *
666  * @param cls the OverlayConnectContext
667  * @param tc the TaskContext from scheduler
668  */
669 static void
670 send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
671 {
672   struct OverlayConnectContext *occ = cls;
673   char *other_peer_str;
674
675   occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
676   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
677     return;
678   GNUNET_assert (NULL != occ->hello);
679   other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
680   if (NULL != occ->peer2_controller)
681   {
682     struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
683     uint16_t msize;
684     uint16_t hello_size;
685
686     LOG_DEBUG ("0x%llx: Offering HELLO of %s (size: %u) to %s via Remote "
687                "Overlay Request\n", occ->op_id,
688                GNUNET_i2s (&occ->peer_identity), ntohs (occ->hello->size),
689                other_peer_str);
690     hello_size = ntohs (occ->hello->size);
691     msize =
692         sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hello_size;
693     msg = GNUNET_malloc (msize);
694     msg->header.type =
695         htons (GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT);
696     msg->header.size = htons (msize);
697     msg->peer = htonl (occ->other_peer_id);
698     msg->operation_id = GNUNET_htonll (occ->op_id);
699     (void) memcpy (&msg->peer_identity, &occ->peer_identity,
700                    sizeof (struct GNUNET_PeerIdentity));
701     memcpy (msg->hello, occ->hello, hello_size);
702     GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
703   }
704   else
705   {
706     LOG_DEBUG ("0x%llx: Offering HELLO of %s to %s\n", occ->op_id,
707                GNUNET_i2s (&occ->peer_identity), other_peer_str);
708     occ->ohh =
709         GNUNET_TRANSPORT_offer_hello (occ->tcc.th_, occ->hello,
710                                       occ_hello_sent_cb, occ);
711     if (NULL == occ->ohh)
712     {
713       GNUNET_break (0);
714       occ->send_hello_task =
715           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
716                                         (GNUNET_TIME_UNIT_MILLISECONDS,
717                                          100 +
718                                          GNUNET_CRYPTO_random_u32
719                                          (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
720                                         &send_hello, occ);
721     }
722   }
723   GNUNET_free (other_peer_str);
724 }
725
726
727 /**
728  * Callback from cache with needed handles set
729  *
730  * @param cls the closure passed to GST_cache_get_handle_transport()
731  * @param ch the handle to CORE. Can be NULL if it is not requested
732  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
733  * @param ignore_ peer identity which is ignored in this callback
734  */
735 static void 
736 p2_transport_connect_cache_callback (void *cls, struct GNUNET_CORE_Handle *ch, 
737                                      struct GNUNET_TRANSPORT_Handle *th,
738                                      const struct GNUNET_PeerIdentity *ignore_)
739 {
740   struct OverlayConnectContext *occ = cls;
741
742   if (NULL == th)
743   {
744     GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
745                      occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
746     GNUNET_SCHEDULER_cancel (occ->timeout_task);
747     occ->timeout_task =
748         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
749     return;
750   }
751   occ->tcc.th_ = th;
752   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
753                    occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
754   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
755 }
756
757
758 /**
759  * Connects to the transport of the other peer if it is a local peer and
760  * schedules the send hello task
761  *
762  * @param occ the overlay connect context
763  */
764 static void
765 p2_transport_connect (struct OverlayConnectContext *occ)
766 {
767   GNUNET_assert (NULL == occ->emsg);
768   GNUNET_assert (NULL != occ->hello);
769   GNUNET_assert (NULL == occ->ghh);
770   GNUNET_assert (NULL == occ->p1th);
771   if (NULL == occ->peer2_controller)
772   {
773     GST_peer_list[occ->other_peer_id]->reference_cnt++;
774     occ->tcc.cgh_th = 
775         GST_cache_get_handle_transport (occ->other_peer_id,
776                                         GST_peer_list[occ->other_peer_id]->
777                                         details.local.cfg,
778                                         &p2_transport_connect_cache_callback,
779                                         occ,
780                                         NULL, NULL, NULL);
781     return;
782   }
783   GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
784                    occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
785   occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
786 }
787
788
789 /**
790  * Test for checking whether HELLO message is empty
791  *
792  * @param cls empty flag to set
793  * @param address the HELLO
794  * @param expiration expiration of the HELLO
795  * @return
796  */
797 static int
798 test_address (void *cls, const struct GNUNET_HELLO_Address *address,
799               struct GNUNET_TIME_Absolute expiration)
800 {
801   int *empty = cls;
802
803   *empty = GNUNET_NO;
804   return GNUNET_OK;
805 }
806
807
808 /**
809  * Function called whenever there is an update to the HELLO of peers in the
810  * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
811  * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
812  *
813  * @param cls closure
814  * @param hello our updated HELLO
815  */
816 static void
817 hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
818 {
819   struct OverlayConnectContext *occ = cls;
820   int empty;
821   uint16_t msize;
822
823   msize = ntohs (hello->size);
824   empty = GNUNET_YES;
825   (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
826                                          hello, GNUNET_NO, &test_address,
827                                          &empty);
828   if (GNUNET_YES == empty)
829   {
830     LOG_DEBUG ("0x%llx: HELLO of %s is empty\n", occ->op_id,
831                GNUNET_i2s (&occ->peer_identity));
832     return;
833   }
834   LOG_DEBUG ("0x%llx: Received HELLO of %s\n", occ->op_id,
835              GNUNET_i2s (&occ->peer_identity));
836   occ->hello = GNUNET_malloc (msize);
837   GST_cache_add_hello (occ->peer_id, hello);
838   memcpy (occ->hello, hello, msize);
839   GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
840   occ->ghh = NULL;
841   GNUNET_TRANSPORT_disconnect (occ->p1th);
842   occ->p1th = NULL;
843   occ->peer->reference_cnt--;
844   GNUNET_free_non_null (occ->emsg);
845   occ->emsg = NULL;
846   p2_transport_connect (occ);
847 }
848
849
850 /**
851  * Callback from cache with needed handles set
852  *
853  * @param cls the closure passed to GST_cache_get_handle_transport()
854  * @param ch the handle to CORE. Can be NULL if it is not requested
855  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
856  * @param my_identity the identity of our peer
857  */
858 static void 
859 occ_cache_get_handle_core_cb (void *cls, struct GNUNET_CORE_Handle *ch, 
860                               struct GNUNET_TRANSPORT_Handle *th,
861                               const struct GNUNET_PeerIdentity *my_identity)
862 {
863   struct OverlayConnectContext *occ = cls;
864   const struct GNUNET_MessageHeader *hello;
865
866   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
867   GNUNET_free_non_null (occ->emsg);
868   (void) GNUNET_asprintf (&occ->emsg,
869                           "0x%llx: Failed to connect to CORE of peer with"
870                           "id: %u", occ->op_id, occ->peer_id);
871   if ((NULL == ch) || (NULL == my_identity))
872     goto error_return;
873   GNUNET_free (occ->emsg);
874   //occ->ch_ = ch;
875   occ->emsg = NULL;
876   if (GNUNET_YES == 
877       GNUNET_CORE_is_peer_connected_sync (ch, &occ->other_peer_identity))
878   {
879     LOG_DEBUG ("0x%llx: Target peer already connected\n", occ->op_id);
880     GNUNET_SCHEDULER_cancel (occ->timeout_task);
881     occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
882     send_overlay_connect_success_msg (occ);
883     occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
884     return;
885   }  
886   memcpy (&occ->peer_identity, my_identity,
887           sizeof (struct GNUNET_PeerIdentity));
888   LOG_DEBUG ("0x%llx: Acquiring HELLO of peer %s\n", occ->op_id,
889              GNUNET_i2s (&occ->peer_identity));
890   /* Lookup for HELLO in hello cache */
891   if (NULL != (hello = GST_cache_lookup_hello (occ->peer_id)))
892   {
893     LOG_DEBUG ("0x%llx: HELLO of peer %s found in cache\n", occ->op_id,
894                GNUNET_i2s (&occ->peer_identity));
895     occ->hello = GNUNET_copy_message (hello);
896     p2_transport_connect (occ);
897     return;
898   }
899   occ->peer->reference_cnt++;
900   occ->p1th =
901       GNUNET_TRANSPORT_connect (occ->peer->details.local.cfg,
902                                 &occ->peer_identity, NULL, NULL, NULL, NULL);
903   if (NULL == occ->p1th)
904   {
905     GNUNET_asprintf (&occ->emsg,
906                      "0x%llx: Cannot connect to TRANSPORT of peer %4s",
907                      occ->op_id, GNUNET_i2s (&occ->peer_identity));
908     goto error_return;
909   }
910   GNUNET_asprintf (&occ->emsg,
911                    "0x%llx: Timeout while acquiring HELLO of peer %4s",
912                    occ->op_id, GNUNET_i2s (&occ->peer_identity));
913   occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th, &hello_update_cb, occ);
914   return;
915
916 error_return:
917   GNUNET_SCHEDULER_cancel (occ->timeout_task);
918   occ->timeout_task = GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
919   return;
920 }
921
922
923 /**
924  * Callback to be called when forwarded get peer config operation as part of
925  * overlay connect is successfull. Connection to Peer 1's core is made and is
926  * checked for new connection from peer 2
927  *
928  * @param cls ForwardedOperationContext
929  * @param msg the peer create success message
930  */
931 static void
932 overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
933 {
934   struct OverlayConnectContext *occ = cls;
935   const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
936
937   occ->opc = NULL;
938   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
939   if (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION != ntohs (msg->type))
940   {
941     GNUNET_SCHEDULER_cancel (occ->timeout_task);
942     occ->timeout_task =
943         GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
944   }
945   cmsg =
946       (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
947   memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
948           sizeof (struct GNUNET_PeerIdentity));
949   GNUNET_free_non_null (occ->emsg);
950   GNUNET_asprintf (&occ->emsg,
951                    "0x%llx: Timeout while connecting to CORE of peer with "
952                    "id: %u", occ->op_id, occ->peer_id);
953   occ->peer->reference_cnt++;
954   occ->cgh_ch = GST_cache_get_handle_core (occ->peer_id,
955                                            occ->peer->details.local.cfg,
956                                            occ_cache_get_handle_core_cb,
957                                            occ,
958                                            &occ->other_peer_identity,
959                                            &overlay_connect_notify,
960                                            occ);
961   return;
962 }
963
964
965 /**
966  * Callback which will be called to after a host registration succeeded or failed
967  *
968  * @param cls the RegisteredHostContext
969  * @param emsg the error message; NULL if host registration is successful
970  */
971 static void
972 registeredhost_registration_completion (void *cls, const char *emsg)
973 {
974   struct RegisteredHostContext *rhc = cls;
975   struct GNUNET_CONFIGURATION_Handle *cfg;
976   uint32_t peer2_host_id;
977
978   /* if (NULL != rhc->focc_dll_head) */
979   /*   TESTBED_process_next_focc (rhc); */
980   peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
981   GNUNET_assert (RHC_INIT == rhc->state);
982   GNUNET_assert (NULL == rhc->sub_op);
983   if ((NULL == rhc->gateway2) || ((peer2_host_id < GST_slave_list_size) /* Check if we have the needed config */
984                                   && (NULL != GST_slave_list[peer2_host_id])))
985   {
986     rhc->state = RHC_LINK;
987     cfg =
988         (NULL ==
989          rhc->gateway2) ? our_config : GST_slave_list[peer2_host_id]->cfg;
990     rhc->sub_op =
991         GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
992                                         rhc->reg_host, rhc->host, cfg,
993                                         GNUNET_NO);
994     return;
995   }
996   rhc->state = RHC_GET_CFG;
997   rhc->sub_op =
998       GNUNET_TESTBED_get_slave_config (rhc, rhc->gateway2->controller,
999                                        rhc->reg_host);
1000 }
1001
1002
1003 /**
1004  * Iterator to match a registered host context
1005  *
1006  * @param cls pointer 2 pointer of RegisteredHostContext
1007  * @param key current key code
1008  * @param value value in the hash map
1009  * @return GNUNET_YES if we should continue to
1010  *         iterate,
1011  *         GNUNET_NO if not.
1012  */
1013 static int
1014 reghost_match_iterator (void *cls, const struct GNUNET_HashCode *key,
1015                         void *value)
1016 {
1017   struct RegisteredHostContext **rh = cls;
1018   struct RegisteredHostContext *rh_val = value;
1019
1020   if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
1021   {
1022     GNUNET_free (*rh);
1023     *rh = rh_val;
1024     return GNUNET_NO;
1025   }
1026   return GNUNET_YES;
1027 }
1028
1029
1030 /**
1031  * Function to generate the hashcode corresponding to a RegisteredHostContext
1032  *
1033  * @param reg_host the host which is being registered in RegisteredHostContext
1034  * @param host the host of the controller which has to connect to the above rhost
1035  * @return the hashcode
1036  */
1037 static struct GNUNET_HashCode
1038 hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
1039             struct GNUNET_TESTBED_Host *host)
1040 {
1041   struct GNUNET_HashCode hash;
1042   uint32_t host_ids[2];
1043
1044   host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
1045   host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
1046   GNUNET_CRYPTO_hash (host_ids, sizeof (host_ids), &hash);
1047   return hash;
1048 }
1049
1050
1051 /**
1052  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
1053  *
1054  * @param cls NULL
1055  * @param client identification of the client
1056  * @param message the actual message
1057  */
1058 void
1059 GST_handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
1060                             const struct GNUNET_MessageHeader *message)
1061 {
1062   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
1063   struct Peer *peer;
1064   struct OverlayConnectContext *occ;
1065   struct GNUNET_TESTBED_Controller *peer2_controller;
1066   uint64_t operation_id;
1067   uint32_t p1;
1068   uint32_t p2;
1069   uint32_t peer2_host_id;
1070
1071   if (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage) !=
1072       ntohs (message->size))
1073   {
1074     GNUNET_break (0);
1075     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1076     return;
1077   }
1078   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
1079   p1 = ntohl (msg->peer1);
1080   p2 = ntohl (msg->peer2);
1081   if ((p1 >= GST_peer_list_size) || (NULL == GST_peer_list[p1]))
1082   {
1083     GNUNET_break (0);
1084     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1085     return;
1086   }
1087   peer = GST_peer_list[p1];
1088   peer2_host_id = ntohl (msg->peer2_host_id);
1089   operation_id = GNUNET_ntohll (msg->operation_id);
1090   LOG_DEBUG
1091       ("Received overlay connect for peers %u and %u with op id: 0x%llx\n", p1,
1092        p2, operation_id);
1093   if (GNUNET_YES == peer->is_remote)
1094   {
1095     struct ForwardedOperationContext *fopc;
1096     struct Route *route_to_peer2_host;
1097     struct Route *route_to_peer1_host;
1098
1099     LOG_DEBUG ("0x%llx: Forwarding overlay connect\n", operation_id);
1100     route_to_peer2_host = NULL;
1101     route_to_peer1_host = NULL;
1102     route_to_peer2_host = GST_find_dest_route (peer2_host_id);
1103     if ((NULL != route_to_peer2_host) ||
1104         (peer2_host_id == GST_context->host_id))
1105     {
1106       /* Peer 2 either below us OR with us */
1107       route_to_peer1_host =
1108           GST_find_dest_route (GST_peer_list[p1]->details.
1109                                remote.remote_host_id);
1110       /* Because we get this message only if we know where peer 1 is */
1111       GNUNET_assert (NULL != route_to_peer1_host);
1112       if ((peer2_host_id == GST_context->host_id) ||
1113           (route_to_peer2_host->dest != route_to_peer1_host->dest))
1114       {
1115         /* Peer2 is either with us OR peer1 and peer2 can be reached through
1116          * different gateways */
1117         struct GNUNET_HashCode hash;
1118         struct RegisteredHostContext *rhc;
1119         int skip_focc;
1120
1121         rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
1122         if (NULL != route_to_peer2_host)
1123           rhc->reg_host = GST_host_list[route_to_peer2_host->dest];
1124         else
1125           rhc->reg_host = GST_host_list[GST_context->host_id];
1126         rhc->host = GST_host_list[route_to_peer1_host->dest];
1127         GNUNET_assert (NULL != rhc->reg_host);
1128         GNUNET_assert (NULL != rhc->host);
1129         rhc->gateway = peer->details.remote.slave;
1130         rhc->gateway2 =
1131             (NULL ==
1132              route_to_peer2_host) ? NULL :
1133             GST_slave_list[route_to_peer2_host->dest];
1134         rhc->state = RHC_INIT;
1135         GNUNET_SERVER_client_keep (client);
1136         rhc->client = client;
1137         hash = hash_hosts (rhc->reg_host, rhc->host);
1138         skip_focc = GNUNET_NO;
1139         if ((GNUNET_NO ==
1140              GNUNET_CONTAINER_multihashmap_contains (peer->details.
1141                                                      remote.slave->reghost_map,
1142                                                      &hash)) ||
1143             (GNUNET_SYSERR !=
1144              GNUNET_CONTAINER_multihashmap_get_multiple (peer->details.remote.
1145                                                          slave->reghost_map,
1146                                                          &hash,
1147                                                          reghost_match_iterator,
1148                                                          &rhc)))
1149         {
1150           /* create and add a new registerd host context */
1151           /* add the focc to its queue */
1152           GNUNET_CONTAINER_multihashmap_put (peer->details.remote.
1153                                              slave->reghost_map, &hash, rhc,
1154                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1155           GNUNET_assert (NULL != GST_host_list[peer2_host_id]);
1156           GST_queue_host_registration (peer->details.remote.slave,
1157                                        registeredhost_registration_completion,
1158                                        rhc, GST_host_list[peer2_host_id]);
1159         }
1160         else
1161         {
1162           /* rhc is now set to the existing one from the hash map by
1163            * reghost_match_iterator() */
1164           /* if queue is empty then ignore creating focc and proceed with
1165            * normal forwarding */
1166           if (RHC_OL_CONNECT == rhc->state)
1167             skip_focc = GNUNET_YES;
1168         }
1169         if (GNUNET_NO == skip_focc)
1170         {
1171           struct ForwardedOverlayConnectContext *focc;
1172
1173           focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
1174           focc->peer1 = p1;
1175           focc->peer2 = p2;
1176           focc->peer2_host_id = peer2_host_id;
1177           focc->orig_msg = GNUNET_copy_message (message);
1178           focc->operation_id = operation_id;
1179           GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
1180                                             rhc->focc_dll_tail, focc);
1181           GNUNET_SERVER_receive_done (client, GNUNET_OK);
1182           return;
1183         }
1184       }
1185     }
1186     fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1187     GNUNET_SERVER_client_keep (client);
1188     fopc->client = client;
1189     fopc->operation_id = operation_id;
1190     fopc->type = OP_OVERLAY_CONNECT;
1191     fopc->opc =
1192         GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1193                                                slave->controller, operation_id,
1194                                                message,
1195                                                &GST_forwarded_operation_reply_relay,
1196                                                fopc);
1197     fopc->timeout_task =
1198         GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
1199                                       fopc);
1200     GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1201     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1202     return;
1203   }
1204
1205   peer2_controller = NULL;
1206   if ((p2 >= GST_peer_list_size) || (NULL == GST_peer_list[p2]))
1207   {
1208     if ((peer2_host_id >= GST_slave_list_size) ||
1209         (NULL == GST_slave_list[peer2_host_id]))
1210     {
1211       LOG (GNUNET_ERROR_TYPE_WARNING,
1212            "0x%llx: Configuration of peer2's controller missing for connecting peers"
1213            "%u and %u\n", operation_id, p1, p2);
1214       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1215       return;
1216     }
1217     peer2_controller = GST_slave_list[peer2_host_id]->controller;
1218     if (NULL == peer2_controller)
1219     {
1220       GNUNET_break (0);         /* What's going on? */
1221       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1222       return;
1223     }
1224   }
1225   else
1226   {
1227     if (GNUNET_YES == GST_peer_list[p2]->is_remote)
1228       peer2_controller = GST_peer_list[p2]->details.remote.slave->controller;
1229   }
1230   occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
1231   GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
1232   GNUNET_SERVER_client_keep (client);
1233   occ->client = client;
1234   occ->peer_id = p1;
1235   occ->other_peer_id = p2;
1236   occ->peer = GST_peer_list[p1];
1237   occ->op_id = GNUNET_ntohll (msg->operation_id);
1238   occ->peer2_controller = peer2_controller;
1239   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->timeout_task);
1240   occ->timeout_task =
1241       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_overlay_connect, occ);
1242   /* Get the identity of the second peer */
1243   if (NULL != occ->peer2_controller)
1244   {
1245     struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
1246
1247     cmsg.header.size =
1248         htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
1249     cmsg.header.type =
1250         htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
1251     cmsg.peer_id = msg->peer2;
1252     cmsg.operation_id = msg->operation_id;
1253     occ->opc =
1254         GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
1255                                                occ->op_id, &cmsg.header,
1256                                                &overlay_connect_get_config,
1257                                                occ);
1258     GNUNET_asprintf (&occ->emsg,
1259                      "0x%llx: Timeout while getting peer identity of peer "
1260                      "with id: %u", occ->op_id, occ->other_peer_id);
1261     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1262     return;
1263   }
1264   GNUNET_TESTING_peer_get_identity (GST_peer_list[occ->other_peer_id]->
1265                                     details.local.peer,
1266                                     &occ->other_peer_identity);
1267   GNUNET_asprintf (&occ->emsg,
1268                    "0x%llx: Timeout while connecting to CORE of peer with "
1269                    "id: %u", occ->op_id, occ->peer_id);
1270   occ->peer->reference_cnt++;
1271   occ->cgh_ch = GST_cache_get_handle_core (occ->peer_id,
1272                                            occ->peer->details.local.cfg,
1273                                            occ_cache_get_handle_core_cb,
1274                                            occ,
1275                                            &occ->other_peer_identity,
1276                                            &overlay_connect_notify,
1277                                            occ);
1278   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1279 }
1280
1281
1282 /**
1283  * Function to cleanup RemoteOverlayConnectCtx and any associated tasks
1284  * with it
1285  *
1286  * @param rocc the RemoteOverlayConnectCtx
1287  */
1288 static void
1289 cleanup_rocc (struct RemoteOverlayConnectCtx *rocc)
1290 {
1291   LOG_DEBUG ("0x%llx: Cleaning up rocc\n", rocc->op_id);
1292   if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
1293     GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
1294   if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
1295     GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
1296   if (NULL != rocc->ohh)
1297     GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
1298   if (NULL != rocc->tcc.tch)
1299     GNUNET_TRANSPORT_try_connect_cancel (rocc->tcc.tch);
1300   if (GNUNET_SCHEDULER_NO_TASK != rocc->tcc.task)
1301     GNUNET_SCHEDULER_cancel (rocc->tcc.task);
1302   //GNUNET_TRANSPORT_disconnect (rocc->tcc.th_);
1303   GST_cache_get_handle_done (rocc->tcc.cgh_th);
1304   rocc->peer->reference_cnt--;
1305   if ((GNUNET_YES == rocc->peer->destroy_flag) &&
1306       (0 == rocc->peer->reference_cnt))
1307     GST_destroy_peer (rocc->peer);
1308   GNUNET_free_non_null (rocc->hello);
1309   GNUNET_CONTAINER_DLL_remove (roccq_head, roccq_tail, rocc);
1310   GNUNET_free (rocc);
1311 }
1312
1313
1314 /**
1315  * Task to timeout rocc and cleanit up
1316  *
1317  * @param cls the RemoteOverlayConnectCtx
1318  * @param tc the TaskContext from scheduler
1319  */
1320 static void
1321 timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1322 {
1323   struct RemoteOverlayConnectCtx *rocc = cls;
1324
1325   GNUNET_assert (rocc->timeout_rocc_task_id != GNUNET_SCHEDULER_NO_TASK);
1326   rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
1327   LOG_DEBUG ("0x%llx: rocc timed out\n", rocc->op_id);
1328   cleanup_rocc (rocc);
1329 }
1330
1331
1332 /**
1333  * Function called to notify transport users that another
1334  * peer connected to us.
1335  *
1336  * @param cls closure
1337  * @param new_peer the peer that connected
1338  * @param ats performance data
1339  * @param ats_count number of entries in ats (excluding 0-termination)
1340  */
1341 static void
1342 cache_transport_peer_connect_notify (void *cls, 
1343                                      const struct GNUNET_PeerIdentity *new_peer)
1344 {
1345   struct RemoteOverlayConnectCtx *rocc = cls;
1346
1347   LOG_DEBUG ("0x%llx: Request Overlay connect notify\n", rocc->op_id);
1348   GNUNET_assert (0 == memcmp (new_peer, &rocc->a_id, sizeof (struct GNUNET_PeerIdentity)));
1349   LOG_DEBUG ("0x%llx: Peer %4s connected\n", rocc->op_id,
1350              GNUNET_i2s (&rocc->a_id));
1351   cleanup_rocc (rocc);
1352 }
1353
1354
1355 /**
1356  * Task to offer the HELLO message to the peer and ask it to connect to the peer
1357  * whose identity is in RemoteOverlayConnectCtx
1358  *
1359  * @param cls the RemoteOverlayConnectCtx
1360  * @param tc the TaskContext from scheduler
1361  */
1362 static void
1363 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1364
1365
1366 /**
1367  * Task that is run when hello has been sent
1368  *
1369  * @param cls the overlay connect context
1370  * @param tc the scheduler task context; if tc->reason =
1371  *          GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
1372  *          GNUNET_SCHEDULER_REASON_READ_READY is succeeded
1373  */
1374 static void
1375 rocc_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1376 {
1377   struct RemoteOverlayConnectCtx *rocc = cls;
1378
1379   rocc->ohh = NULL;
1380   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rocc->attempt_connect_task_id);
1381   LOG_DEBUG ("0x%llx: HELLO of peer %4s sent to local peer with id: %u\n",
1382              rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1383   if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
1384   {
1385     GNUNET_break (0);
1386     rocc->attempt_connect_task_id =
1387         GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
1388     return;
1389   }
1390   if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
1391     return;
1392   rocc->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &rocc->tcc);
1393 }
1394
1395
1396 /**
1397  * Task to offer the HELLO message to the peer and ask it to connect to the peer
1398  * whose identity is in RemoteOverlayConnectCtx
1399  *
1400  * @param cls the RemoteOverlayConnectCtx
1401  * @param tc the TaskContext from scheduler
1402  */
1403 static void
1404 attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1405 {
1406   struct RemoteOverlayConnectCtx *rocc = cls;
1407
1408   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id);
1409   rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
1410   LOG_DEBUG ("0x%llx: Offering HELLO of peer %4s to local peer with id: %u\n",
1411              rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1412   rocc->ohh =
1413       GNUNET_TRANSPORT_offer_hello (rocc->tcc.th_, rocc->hello,
1414                                     rocc_hello_sent_cb, rocc);
1415   if (NULL == rocc->ohh)
1416     rocc->attempt_connect_task_id =
1417         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1418                                       (GNUNET_TIME_UNIT_MILLISECONDS,
1419                                        100 +
1420                                        GNUNET_CRYPTO_random_u32
1421                                        (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
1422                                       &attempt_connect_task, rocc);
1423 }
1424
1425
1426 /**
1427  * Callback from cache with needed handles set
1428  *
1429  * @param cls the closure passed to GST_cache_get_handle_transport()
1430  * @param ch the handle to CORE. Can be NULL if it is not requested
1431  * @param th the handle to TRANSPORT. Can be NULL if it is not requested
1432  * @param ignore_ peer identity which is ignored in this callback
1433  */
1434 static void 
1435 rocc_cache_get_handle_transport_cb (void *cls, struct GNUNET_CORE_Handle *ch, 
1436                                     struct GNUNET_TRANSPORT_Handle *th,
1437                                     const struct GNUNET_PeerIdentity *ignore_)
1438 {
1439   struct RemoteOverlayConnectCtx *rocc = cls;
1440   
1441   if (NULL == th)
1442   {
1443     rocc->timeout_rocc_task_id =
1444         GNUNET_SCHEDULER_add_now (&timeout_rocc_task, rocc);
1445     return;
1446   }
1447   rocc->tcc.th_ = th;
1448   rocc->tcc.pid = &rocc->a_id;
1449   if (GNUNET_YES == GNUNET_TRANSPORT_check_neighbour_connected (rocc->tcc.th_,
1450                                                                 rocc->tcc.pid))
1451   {
1452     LOG_DEBUG ("0x%llx: Target peer %4s already connected to local peer: %u\n",
1453                rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
1454     cleanup_rocc (rocc);
1455     return;
1456   }
1457   rocc->attempt_connect_task_id =
1458       GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);  
1459 }
1460
1461
1462 /**
1463  * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
1464  *
1465  * @param cls NULL
1466  * @param client identification of the client
1467  * @param message the actual message
1468  */
1469 void
1470 GST_handle_remote_overlay_connect (void *cls,
1471                                    struct GNUNET_SERVER_Client *client,
1472                                    const struct GNUNET_MessageHeader *message)
1473 {
1474   const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
1475   struct RemoteOverlayConnectCtx *rocc;
1476   struct Peer *peer;
1477   uint32_t peer_id;
1478   uint16_t msize;
1479   uint16_t hsize;
1480
1481   msize = ntohs (message->size);
1482   if (sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) >= msize)
1483   {
1484     GNUNET_break (0);
1485     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1486     return;
1487   }
1488   msg = (const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *) message;
1489   if ((NULL == msg->hello) ||
1490       (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
1491   {
1492     GNUNET_break (0);
1493     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1494     return;
1495   }
1496   hsize = ntohs (msg->hello->size);
1497   if ((sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hsize) !=
1498       msize)
1499   {
1500     GNUNET_break (0);
1501     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1502     return;
1503   }
1504   peer_id = ntohl (msg->peer);
1505   if ((peer_id >= GST_peer_list_size) ||
1506       (NULL == (peer = GST_peer_list[peer_id])))
1507   {
1508     GNUNET_break_op (0);
1509     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1510     return;
1511   }
1512   if (GNUNET_YES == peer->is_remote)
1513   {
1514     struct GNUNET_MessageHeader *msg2;
1515
1516     msg2 = GNUNET_copy_message (message);
1517     GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller,
1518                                    msg2);
1519     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1520     return;
1521   }
1522   rocc = GNUNET_malloc (sizeof (struct RemoteOverlayConnectCtx));
1523   rocc->op_id = GNUNET_ntohll (msg->operation_id);
1524   GNUNET_CONTAINER_DLL_insert_tail (roccq_head, roccq_tail, rocc);
1525   memcpy (&rocc->a_id, &msg->peer_identity,
1526           sizeof (struct GNUNET_PeerIdentity));
1527   LOG_DEBUG ("Received request for overlay connection with op_id: 0x%llx "
1528              "from local peer %u to peer %4s with hello size: %u\n",
1529              rocc->op_id, peer_id, GNUNET_i2s (&rocc->a_id), hsize);
1530   rocc->peer = peer;
1531   rocc->peer->reference_cnt++;
1532   rocc->hello = GNUNET_malloc (hsize);
1533   memcpy (rocc->hello, msg->hello, hsize);
1534   rocc->tcc.cgh_th = 
1535       GST_cache_get_handle_transport (peer_id,
1536                                       rocc->peer->details.local.cfg,
1537                                       &rocc_cache_get_handle_transport_cb,
1538                                       rocc, 
1539                                       &rocc->a_id,
1540                                       &cache_transport_peer_connect_notify,
1541                                       rocc);
1542   rocc->timeout_rocc_task_id =
1543       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
1544   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1545 }
1546
1547
1548 /**
1549  * Clears all pending overlay connect contexts in queue
1550  */
1551 void
1552 GST_free_occq ()
1553 {
1554   struct OverlayConnectContext *occ;
1555
1556   while (NULL != (occ = occq_head))
1557     cleanup_occ (occ);
1558 }
1559
1560
1561 /**
1562  * Clears all pending remote overlay connect contexts in queue
1563  */
1564 void
1565 GST_free_roccq ()
1566 {
1567   struct RemoteOverlayConnectCtx *rocc;
1568
1569   while (NULL != (rocc = roccq_head))
1570     cleanup_rocc (rocc);
1571 }