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