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