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