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