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