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