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