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