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