+/**
+ * Checks if the given host is registered at the given slave.
+ *
+ * @param slave the slave where registration has to be checked. The check is
+ * actually done through a locally maintained hashmap. No
+ * communication with the slave is involved.
+ * @param host the host to register
+ * @return If the given host is not registered already or the registration is
+ * pending, it returns the registration context. Any overlay connects
+ * to be forwarded should be queued in the context so that they can be
+ * executed when the registration is completed. If the given host is
+ * already registered, NULL is returned.
+ */
+static struct RegisteredHostContext *
+register_host (struct Slave *slave, struct GNUNET_TESTBED_Host *host)
+{
+ struct GNUNET_HashCode hash;
+ struct RegisteredHostContext *rhc;
+
+ rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
+ rhc->reg_host = host;
+ rhc->host = GST_host_list[slave->host_id];
+ GNUNET_assert (NULL != rhc->reg_host);
+ GNUNET_assert (NULL != rhc->host);
+ rhc->state = RHC_INIT;
+ hash = hash_hosts (rhc->reg_host, rhc->host);
+ if ((GNUNET_NO ==
+ GNUNET_CONTAINER_multihashmap_contains (slave->reghost_map, &hash)) ||
+ (GNUNET_SYSERR !=
+ GNUNET_CONTAINER_multihashmap_get_multiple (slave->reghost_map,
+ &hash,
+ reghost_match_iterator,
+ &rhc)))
+ {
+ /* create and add a new registerd host context */
+ /* add the focc to its queue */
+ GNUNET_CONTAINER_multihashmap_put (slave->reghost_map, &hash, rhc,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GST_queue_host_registration (slave, host_registration_comp,
+ rhc, rhc->reg_host);
+ }
+ else
+ {
+ /* rhc is now set to the existing one from the hash map by
+ * reghost_match_iterator() */
+ /* if queue is empty then ignore creating focc and proceed with normal
+ * forwarding */
+ if (RHC_DONE == rhc->state)
+ return NULL;
+ }
+ return rhc;
+}
+
+
+/**
+ * Forwards the overlay connect request to a slave controller. Before
+ * forwarding, any hosts which are needed to be known by the slave controller to
+ * execute the overlay connect request are registered at slave.
+ *
+ * @param msg the overlay connect request message to be forwarded
+ * @param client the client to which the status of the forwarded request has to
+ * be notified
+ */
+static void
+forward_overlay_connect (const struct GNUNET_TESTBED_OverlayConnectMessage *msg,
+ struct GNUNET_SERVER_Client *client)
+{
+ struct ForwardedOperationContext *fopc;
+ struct Route *route_to_peer2_host;
+ struct Route *route_to_peer1_host;
+ struct Peer *peer;
+ struct RegisteredHostContext *rhc;
+ struct ForwardedOverlayConnectContext *focc;
+ uint64_t op_id;
+ uint32_t peer2_host_id;
+ uint32_t p1;
+ uint32_t p2;
+
+ p1 = ntohl (msg->peer1);
+ p2 = ntohl (msg->peer2);
+ op_id = GNUNET_ntohll (msg->operation_id);
+ peer2_host_id = ntohl (msg->peer2_host_id);
+ GNUNET_assert (VALID_PEER_ID (p1));
+ GNUNET_assert (VALID_HOST_ID (peer2_host_id));
+ peer = GST_peer_list[p1];
+ GNUNET_assert (GNUNET_YES == peer->is_remote);
+ LOG_DEBUG ("0x%llx: Forwarding overlay connect\n", op_id);
+ route_to_peer2_host = GST_find_dest_route (peer2_host_id);
+ route_to_peer1_host = GST_find_dest_route
+ (peer->details.remote.remote_host_id);
+ GNUNET_assert (NULL != route_to_peer1_host);
+ if ((NULL != route_to_peer2_host) &&
+ (route_to_peer1_host->dest == route_to_peer2_host->dest))
+ goto forward;
+ /* Peer2 is either with us OR peer1 and peer2 can be reached through
+ different subtrees OR peer2 is on a subtree unknown to us */
+ if (NULL != (rhc = register_host (peer->details.remote.slave,
+ GST_host_list[peer2_host_id])))
+ {
+ LOG_DEBUG ("Queueing forwarding FOCC for connecting peers %u and %u\n", p1, p2);
+ focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
+ focc->peer1 = p1;
+ focc->peer2 = p2;
+ focc->peer2_host_id = peer2_host_id;
+ focc->orig_msg = GNUNET_copy_message (&msg->header);
+ focc->operation_id = op_id;
+ focc->client = client;
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head, rhc->focc_dll_tail,
+ focc);
+ return;
+ }
+
+ forward:
+ LOG_DEBUG ("Forwarding without FOCC for connecting peers %u and %u\n", p1, p2);
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->operation_id = op_id;
+ fopc->type = OP_OVERLAY_CONNECT;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller, op_id,
+ &msg->header,
+ &GST_forwarded_operation_reply_relay,
+ fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+}
+
+
+/**
+ * Callback called when a connection to the controller of peer2 has been
+ * established
+ *
+ * @param cls the overlay connect contexts
+ * @param c handle to the controller connection
+ */
+static void
+p2_controller_connect_cb (void *cls, struct GNUNET_TESTBED_Controller *c)
+{
+ struct OverlayConnectContext *occ = cls;
+ struct RemotePeer2Context *rp2c;
+ struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
+
+ GNUNET_assert (OCC_TYPE_LOCAL != occ->type);
+ rp2c = &occ->p2ctx.remote;
+ rp2c->ncn = NULL;
+ rp2c->p2c = c;
+ cmsg.header.size =
+ htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
+ cmsg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION);
+ cmsg.peer_id = htonl (occ->other_peer_id);
+ cmsg.operation_id = GNUNET_htonll (occ->op_id);
+ rp2c->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (rp2c->p2c,
+ occ->op_id, &cmsg.header,
+ &overlay_connect_get_config,
+ occ);
+ GNUNET_free_non_null (occ->emsg);
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while getting peer identity of peer "
+ "with id: %u", occ->op_id, occ->other_peer_id);
+}
+
+