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