-/**
- * Function to find a suitable GSTCacheGetHandle which is waiting for one of the
- * handles in given entry to be available.
- *
- * @param entry the cache entry whose GSTCacheGetHandle list has to be searched
- * @param head the starting list element in the GSTCacheGetHandle where the
- * search has to be begin
- * @return a suitable GSTCacheGetHandle whose handle ready notify callback
- * hasn't been called yet. NULL if no such suitable GSTCacheGetHandle
- * is found
- */
-static struct GSTCacheGetHandle *
-search_suitable_cgh (const struct CacheEntry *entry,
- const struct GSTCacheGetHandle *head)
-{
- const struct GSTCacheGetHandle *cgh;
-
- for (cgh = head; NULL != cgh; cgh = cgh->next)
- {
- if (GNUNET_YES == cgh->notify_called)
- return NULL;
- switch (cgh->type)
- {
- case CGT_TRANSPORT_HANDLE:
- if (NULL == entry->transport_handle)
- continue;
- break;
- case CGT_CORE_HANDLE:
- if (NULL == entry->core_handle)
- continue;
- if (NULL == entry->peer_identity) /* Our CORE connection isn't ready yet */
- continue;
- break;
- }
- break;
- }
- return (struct GSTCacheGetHandle *) cgh;
-}
-
-
-/**
- * Task to call the handle ready notify callback of a queued GSTCacheGetHandle
- * of an entry when one or all of its handles are available.
- *
- * @param cls the cache entry
- * @param tc the task context from scheduler
- */
-static void
-call_cgh_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CacheEntry *entry = cls;
- struct GSTCacheGetHandle *cgh;
- const struct GSTCacheGetHandle *cgh2;
-
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->notify_task);
- entry->notify_task = GNUNET_SCHEDULER_NO_TASK;
- cgh = search_suitable_cgh (entry, entry->cgh_qhead);
- GNUNET_assert (NULL != cgh);
- cgh2 = NULL;
- if (NULL != cgh->next)
- cgh2 = search_suitable_cgh (entry, cgh->next);
- GNUNET_CONTAINER_DLL_remove (entry->cgh_qhead, entry->cgh_qtail, cgh);
- cgh->notify_called = GNUNET_YES;
- GNUNET_CONTAINER_DLL_insert_tail (entry->cgh_qhead, entry->cgh_qtail, cgh);
- if (NULL != cgh2)
- entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
- if (NULL != cgh->nctxt)
- { /* Register the peer connect notify callback */
- GNUNET_CONTAINER_DLL_insert_tail (entry->nctxt_qhead, entry->nctxt_qtail,
- cgh->nctxt);
- }
- LOG_DEBUG ("Calling notify for handle type %u\n", cgh->type);
- GNUNET_break ((NULL == entry->core_handle) || (NULL != entry->peer_identity));
- cgh->cb (cgh->cb_cls, entry->core_handle, entry->transport_handle,
- entry->peer_identity);
-}
-
-
-/**
- * Function called from peer connect notify callbacks from CORE and TRANSPORT
- * connections. This function calls the pendning peer connect notify callbacks
- * which are queued in an entry.
- *
- * @param cls the cache entry
- * @param peer the peer that connected
- * @param type the type of the handle this notification corresponds to
- */
-static void
-peer_connect_notify_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
- const enum CacheGetType type)
-{
- struct CacheEntry *entry = cls;
- struct ConnectNotifyContext *ctxt;
- struct ConnectNotifyContext *ctxt2;
- GST_cache_peer_connect_notify cb;
- void *cb_cls;
-
-
- for (ctxt = entry->nctxt_qhead; NULL != ctxt;)
- {
- GNUNET_assert (NULL != ctxt->cgh);
- if (type != ctxt->cgh->type)
- {
- ctxt = ctxt->next;
- continue;
- }
- if (0 != memcmp (ctxt->target, peer, sizeof (struct GNUNET_PeerIdentity)))
- {
- ctxt = ctxt->next;
- continue;
- }
- cb = ctxt->cb;
- cb_cls = ctxt->cb_cls;
- ctxt->cgh->nctxt = NULL;
- ctxt2 = ctxt->next;
- GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, ctxt);
- GNUNET_free (ctxt);
- ctxt = ctxt2;
- cb (cb_cls, peer);
- }
- if (NULL == ctxt)
- return;
-
-}
-
-
-/**
- * Function called to notify transport users that another
- * peer connected to us.
- *
- * @param cls closure
- * @param peer the peer that connected
- * @param ats performance data
- * @param ats_count number of entries in ats (excluding 0-termination)
- */
-static void
-transport_peer_connect_notify_cb (void *cls,
- const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_ATS_Information *ats,
- uint32_t ats_count)
-{
- peer_connect_notify_cb (cls, peer, CGT_TRANSPORT_HANDLE);
-}
-
-
-/**
- * Function called when resources for opening a connection to TRANSPORT are
- * available.
- *
- * @param cls the cache entry
- */
-static void
-opstart_get_handle_transport (void *cls)
-{
- struct CacheEntry *entry = cls;
-
- GNUNET_assert (NULL != entry);
- LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->peer_id);
- entry->transport_handle =
- GNUNET_TRANSPORT_connect (entry->cfg, NULL, entry, NULL,
- &transport_peer_connect_notify_cb, NULL);
- if (NULL == entry->transport_handle)
- {
- GNUNET_break (0);
- return;
- }
- if (0 == entry->demand)
- return;
- if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
- return;
- if (NULL != search_suitable_cgh (entry, entry->cgh_qhead))
- entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
-}
-
-
-/**
- * Function called when the operation responsible for opening a TRANSPORT
- * connection is marked as done.
- *
- * @param cls the cache entry
- */
-static void
-oprelease_get_handle_transport (void *cls)
-{
- struct CacheEntry *entry = cls;
-
- if (NULL == entry->transport_handle)
- return;
- GNUNET_TRANSPORT_disconnect (entry->transport_handle);
- entry->transport_handle = NULL;
-}
-
-
-/**
- * Function called after GNUNET_CORE_connect has succeeded (or failed
- * for good). Note that the private key of the peer is intentionally
- * not exposed here; if you need it, your process should try to read
- * the private key file directly (which should work if you are
- * authorized...). Implementations of this function must not call
- * GNUNET_CORE_disconnect (other than by scheduling a new task to
- * do this later).
- *
- * @param cls closure
- * @param server handle to the server, NULL if we failed
- * @param my_identity ID of this peer, NULL if we failed
- */
-static void
-core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
- const struct GNUNET_PeerIdentity *my_identity)
-{
- struct CacheEntry *entry = cls;
-
- if (NULL == my_identity)
- {
- GNUNET_break (0);
- return;
- }
- GNUNET_assert (NULL == entry->peer_identity);
- GNUNET_break (NULL != server);
- entry->core_handle = server;
- entry->peer_identity = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
- memcpy (entry->peer_identity, my_identity,
- sizeof (struct GNUNET_PeerIdentity));
- if (0 == entry->demand)
- return;
- if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
- return;
- if (NULL != search_suitable_cgh (entry, entry->cgh_qhead))
- entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
-}
-
-
-/**
- * Method called whenever a given peer connects at CORE level
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- * @param atsi performance data for the connection
- * @param atsi_count number of records in 'atsi'
- */
-static void
-core_peer_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_ATS_Information *atsi,
- unsigned int atsi_count)
-{
- peer_connect_notify_cb (cls, peer, CGT_CORE_HANDLE);
-}
-
-
-/**
- * Function called when resources for opening a connection to CORE are
- * available.
- *
- * @param cls the cache entry
- */
-static void
-opstart_get_handle_core (void *cls)
-{
- struct CacheEntry *entry = cls;
-
- const struct GNUNET_CORE_MessageHandler no_handlers[] = {
- {NULL, 0, 0}
- };
-
- GNUNET_assert (NULL != entry);
- LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->peer_id);
- entry->core_handle =
- GNUNET_CORE_connect (entry->cfg, entry, /* closure */
- &core_startup_cb, /* core startup notify */
- &core_peer_connect_cb, /* peer connect notify */
- NULL, /* peer disconnect notify */
- NULL, /* inbound notify */
- GNUNET_NO, /* inbound header only? */
- NULL, /* outbound notify */
- GNUNET_NO, /* outbound header only? */
- no_handlers);
-}
-
-
-/**
- * Function called when the operation responsible for opening a TRANSPORT
- * connection is marked as done.
- *
- * @param cls the cache entry
- */
-static void
-oprelease_get_handle_core (void *cls)
-{
- struct CacheEntry *entry = cls;
-
- if (NULL == entry->core_handle)
- return;
- GNUNET_CORE_disconnect (entry->core_handle);
- entry->core_handle = NULL;
- GNUNET_free_non_null (entry->peer_identity);
- entry->peer_identity = NULL;
-}
-
-
-/**
- * Function to get a handle with given configuration. The type of the handle is
- * implicitly provided in the GSTCacheGetHandle. If the handle is already cached
- * before, it will be retured in the given callback; the peer_id is used to
- * lookup in the cache; if not, a new operation is started to open the transport
- * handle and will be given in the callback when it is available.
- *
- * @param cls the cache entry
- */
-static struct GSTCacheGetHandle *
-cache_get_handle (unsigned int peer_id, struct GSTCacheGetHandle *cgh,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const struct GNUNET_PeerIdentity *target,
- GST_cache_peer_connect_notify connect_notify_cb,
- void *connect_notify_cb_cls)
-{
- struct GNUNET_HashCode key;
- void *handle;
- struct CacheEntry *entry;
- struct ConnectNotifyContext *ctxt;
- struct GNUNET_TESTBED_Operation *op;
-
- GNUNET_assert (0 != cgh->type);
- GNUNET_CRYPTO_hash (&peer_id, sizeof (peer_id), &key);
- handle = NULL;
- entry = cache_lookup (&key);
- if (NULL != entry)
- {
- if (GNUNET_YES == entry->in_lru)
- {
- GNUNET_assert (0 == entry->demand);
- GNUNET_assert (0 < lru_cache_size);
- if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
- {
- GNUNET_SCHEDULER_cancel (entry->expire_task);
- entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
- }
- GNUNET_CONTAINER_DLL_remove (lru_cache_head, lru_cache_tail, entry);
- lru_cache_size--;
- entry->in_lru = GNUNET_NO;
- }
- switch (cgh->type)
- {
- case CGT_TRANSPORT_HANDLE:
- handle = entry->transport_handle;
- if (NULL != handle)
- LOG_DEBUG ("Found TRANSPORT handle in cache for peer %u\n",
- entry->peer_id);
- break;
- case CGT_CORE_HANDLE:
- handle = entry->core_handle;
- if (NULL != handle)
- LOG_DEBUG ("Found CORE handle in cache for peer %u\n", entry->peer_id);
- break;
- }
- }
- if (NULL == entry)
- entry = add_entry (&key, peer_id);
- if (NULL == entry->cfg)
- entry->cfg = GNUNET_CONFIGURATION_dup (cfg);
- entry->demand++;
- cgh->entry = entry;
- GNUNET_CONTAINER_DLL_insert (entry->cgh_qhead, entry->cgh_qtail, cgh);
- if ((NULL != target) && (NULL != connect_notify_cb))
- {
- ctxt = GNUNET_malloc (sizeof (struct ConnectNotifyContext));
- ctxt->target = target;
- ctxt->cb = connect_notify_cb;
- ctxt->cb_cls = connect_notify_cb_cls;
- GNUNET_assert (NULL == cgh->nctxt);
- cgh->nctxt = ctxt;
- ctxt->cgh = cgh;
- }
- if (NULL != handle)
- {
- if (GNUNET_SCHEDULER_NO_TASK == entry->notify_task)
- {
- if (NULL != search_suitable_cgh (entry, entry->cgh->qhead))
- entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
- }
- return cgh;
- }
- switch (cgh->type)
- {
- case CGT_TRANSPORT_HANDLE:
- if (NULL != entry->transport_op)
- return cgh;
- op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_transport,
- &oprelease_get_handle_transport);
- entry->transport_op = op;
- break;
- case CGT_CORE_HANDLE:
- if (NULL != entry->core_op)
- return cgh;
- op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_core,
- &oprelease_get_handle_core);
- entry->core_op = op;
- break;
- }
- GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, op);
- GNUNET_TESTBED_operation_begin_wait_ (op);
- return cgh;
-}
-
-