- struct CadetPeer *p = value;
- struct GNUNET_TIME_Absolute *abs = cls;
-
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "peer %s timeout\n", GNUNET_i2s (key));
-
- if (p->last_contact.abs_value_us == abs->abs_value_us &&
- GNUNET_NO == peer_is_used (p))
- {
- peer_destroy (p);
- return GNUNET_NO;
- }
- return GNUNET_YES;
-}
-
-
-/**
- * Delete oldest unused peer.
- */
-static void
-peer_delete_oldest (void)
-{
- struct GNUNET_TIME_Absolute abs;
-
- abs = GNUNET_TIME_UNIT_FOREVER_ABS;
-
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &peer_get_oldest,
- &abs);
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &peer_timeout,
- &abs);
-}
-
-
-/**
- * Choose the best (yet unused) path towards a peer,
- * considering the tunnel properties.
- *
- * @param peer The destination peer.
- * @return Best current known path towards the peer, if any.
- */
-static struct CadetPeerPath *
-peer_get_best_path (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *best_p;
- struct CadetPeerPath *p;
- unsigned int best_cost;
- unsigned int cost;
-
- best_cost = UINT_MAX;
- best_p = NULL;
- for (p = peer->path_head; NULL != p; p = p->next)
- {
- if (GNUNET_NO == path_is_valid (p))
- continue; /* Don't use invalid paths. */
- if (GNUNET_YES == GCT_is_path_used (peer->tunnel, p))
- continue; /* If path is already in use, skip it. */
-
- if ((cost = GCT_get_path_cost (peer->tunnel, p)) < best_cost)
- {
- best_cost = cost;
- best_p = p;
- }
- }
- return best_p;
-}
-
-
-/**
- * Is this queue element sendable?
- *
- * - All management traffic is always sendable.
- * - For payload traffic, check the connection flow control.
- *
- * @param q Queue element to inspect.
- * @return #GNUNET_YES if it is sendable, #GNUNET_NO otherwise.
- */
-static int
-queue_is_sendable (struct CadetPeerQueue *q)
-{
- /* Is PID-independent? */
- switch (q->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- return GNUNET_YES;
-
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- case GNUNET_MESSAGE_TYPE_CADET_AX:
- break;
-
- default:
- GNUNET_break (0);
- }
-
- return GCC_is_sendable (q->c, q->fwd);
-}
-
-
-/**
- * Get first sendable message.
- *
- * @param peer The destination peer.
- *
- * @return First transmittable message, if any. Otherwise, NULL.
- */
-static struct CadetPeerQueue *
-peer_get_first_message (const struct CadetPeer *peer)
-{
- struct CadetPeerQueue *q;
-
- for (q = peer->queue_head; NULL != q; q = q->next)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking q:%p on c:%s\n", q, GCC_2s (q->c));
- if (queue_is_sendable (q))
- return q;
- }
-
- return NULL;
-}
-
-
-/**
- * Function to process paths received for a new peer addition. The recorded
- * paths form the initial tunnel, which can be optimized later.
- * Called on each result obtained for the DHT search.
- *
- * @param cls closure
- * @param path
- */
-static void
-search_handler (void *cls, const struct CadetPeerPath *path)
-{
- struct CadetPeer *peer = cls;
- unsigned int connection_count;
-
- GCC_check_connections ();
- GCP_add_path_to_all (path, GNUNET_NO);
-
- /* Count connections */
- connection_count = GCT_count_connections (peer->tunnel);
-
- /* If we already have our minimum (or more) connections, it's enough */
- if (CONNECTIONS_PER_TUNNEL <= connection_count)
- {
- GCC_check_connections ();
- return;
- }
-
- if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
- GCP_connect (peer);
- }
- GCC_check_connections ();
-}
-
-
-/**
- * Adjust core requested size to accomodate an ACK.
- *
- * @param message_size Requested size.
- *
- * @return Size enough to fit @c message_size and an ACK.
- */
-static size_t
-get_core_size (size_t message_size)
-{
- return message_size + sizeof (struct GNUNET_CADET_ACK);
-}
-
-
-/**
- * Fill a core buffer with the appropriate data for the queued message.
- *
- * @param queue Queue element for the message.
- * @param buf Core buffer to fill.
- * @param size Size remaining in @c buf.
- * @param[out] pid In case its an encrypted payload, set payload.
- *
- * @return Bytes written to @c buf.
- */
-static size_t
-fill_buf (struct CadetPeerQueue *queue, void *buf, size_t size, uint32_t *pid)
-{
- struct CadetConnection *c = queue->c;
- size_t msg_size;
-
- switch (queue->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- *pid = GCC_get_pid (queue->c, queue->fwd);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " otr payload ID %u\n", *pid);
- msg_size = send_core_data_raw (queue->cls, size, buf);
- ((struct GNUNET_CADET_Encrypted *) buf)->pid = htonl (*pid);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_AX:
- *pid = GCC_get_pid (queue->c, queue->fwd);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ax payload ID %u\n", *pid);
- msg_size = send_core_data_raw (queue->cls, size, buf);
- ((struct GNUNET_CADET_AX *) buf)->pid = htonl (*pid);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " raw %s\n", GC_m2s (queue->type));
- msg_size = send_core_data_raw (queue->cls, size, buf);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path create\n");
- if (GCC_is_origin (c, GNUNET_YES))
- msg_size = send_core_connection_create (c, size, buf);
- else
- msg_size = send_core_data_raw (queue->cls, size, buf);
- break;
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path ack\n");
- if (GCC_is_origin (c, GNUNET_NO) ||
- GCC_is_origin (c, GNUNET_YES))
- {
- msg_size = send_core_connection_ack (c, size, buf);
- }
- else
- {
- msg_size = send_core_data_raw (queue->cls, size, buf);
- }
- break;
- case GNUNET_MESSAGE_TYPE_CADET_DATA:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
- /* This should be encapsulted */
- msg_size = 0;
- GNUNET_assert (0);
- break;
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_WARNING, " type unknown: %u\n", queue->type);
- msg_size = 0;
- }
-
- GNUNET_assert (size >= msg_size);
-
- return msg_size;
-}
-
-
-/**
- * Core callback to write a queued packet to core buffer
- *
- * @param cls Closure (peer info).
- * @param size Number of bytes available in buf.
- * @param buf Where the to write the message.
- *
- * @return number of bytes written to buf
- */
-static size_t
-queue_send (void *cls, size_t size, void *buf)
-{
- struct CadetPeer *peer = cls;
- struct CadetConnection *c;
- struct CadetPeerQueue *queue;
- struct GNUNET_TIME_Relative core_wait_time;
- const struct GNUNET_PeerIdentity *dst_id;
- size_t msg_size;
- size_t total_size;
- size_t rest;
- char *dst;
- uint32_t pid;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue send towards %s (max %u)\n",
- GCP_2s (peer), size);
-
- /* Sanity checking */
- if (NULL == buf || 0 == size)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not allowed/\n");
- if (GNUNET_NO == in_shutdown)
- {
- queue = peer_get_first_message (peer);
- dst_id = GNUNET_PEER_resolve2 (peer->id);
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (queue),
- GNUNET_TIME_UNIT_FOREVER_REL,
- dst_id,
- get_core_size (queue->size),
- &queue_send,
- peer);
- peer->tmt_time = GNUNET_TIME_absolute_get ();
- }
- else
- {
- peer->core_transmit = NULL;
- peer->tmt_time.abs_value_us = 0;
- }
- GCC_check_connections ();
- return 0;
- }
-
- /* Init */
- rest = size;
- total_size = 0;
- dst = (char *) buf;
- pid = 0;
- peer->core_transmit = NULL;
- queue = peer_get_first_message (peer);
- if (NULL == queue)
- {
- GNUNET_break (0); /* Core tmt_rdy should've been canceled */
- peer->tmt_time.abs_value_us = 0;
- return 0;
- }
- core_wait_time = GNUNET_TIME_absolute_get_duration (peer->tmt_time);
- if (core_wait_time.rel_value_us >= 1000000)
- {
- LOG (GNUNET_ERROR_TYPE_ERROR, " core wait time %s > 1 second\n",
- GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " core wait time %s\n",
- GNUNET_STRINGS_relative_time_to_string (core_wait_time, GNUNET_NO));
- }
- peer->tmt_time.abs_value_us = 0;
-
- /* Copy all possible messages to the core buffer */
- while (NULL != queue && rest >= queue->size)
- {
- c = queue->c;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s %s\n",
- GCC_2s (c), GC_f2s(queue->fwd));
- LOG (GNUNET_ERROR_TYPE_DEBUG, " size %u ok (%u/%u)\n",
- queue->size, total_size, size);
-
- msg_size = fill_buf (queue, (void *) dst, size, &pid);
-
- if (0 < drop_percent &&
- GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "DD %s (%s %u) on connection %s %s\n",
- GC_m2s (queue->type), GC_m2s (queue->payload_type),
- queue->payload_id, GCC_2s (c), GC_f2s (queue->fwd));
- msg_size = 0;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_INFO,
- "snd %s (%s %4u) on connection %s (%p) %s (size %u)\n",
- GC_m2s (queue->type), GC_m2s (queue->payload_type),
- queue->payload_id, GCC_2s (c), c, GC_f2s (queue->fwd), msg_size);
- }
- total_size += msg_size;
- rest -= msg_size;
- dst = &dst[msg_size];
- msg_size = 0;
-
- /* Free queue, but cls was freed by send_core_* in fill_buf. */
- (void) GCP_queue_destroy (queue, GNUNET_NO, GNUNET_YES, pid);
-
- /* Next! */
- queue = peer_get_first_message (peer);
- }
-
- /* If more data in queue, send next */
- if (NULL != queue)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " more data! (%u)\n", queue->size);
- if (NULL == peer->core_transmit)
- {
- dst_id = GNUNET_PEER_resolve2 (peer->id);
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (queue),
- GNUNET_TIME_UNIT_FOREVER_REL,
- dst_id,
- get_core_size (queue->size),
- &queue_send,
- peer);
- peer->tmt_time = GNUNET_TIME_absolute_get ();
- queue->start_waiting = GNUNET_TIME_absolute_get ();
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "* tmt rdy called somewhere else\n");
- }
-// GCC_start_poll (); FIXME needed?
- }
- else
- {
-// GCC_stop_poll(); FIXME needed?
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, " return %d\n", total_size);
- queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
- GCC_check_connections ();
- return total_size;
-}
-
-
-/******************************************************************************/
-/******************************** API ***********************************/
-/******************************************************************************/
-
-
-/**
- * Free a transmission that was already queued with all resources
- * associated to the request.
- *
- * If connection was marked to be destroyed, and this was the last queued
- * message on it, the connection will be free'd as a result.
- *
- * @param queue Queue handler to cancel.
- * @param clear_cls Is it necessary to free associated cls?
- * @param sent Was it really sent? (Could have been canceled)
- * @param pid PID, if relevant (was sent and was a payload message).
- *
- * @return #GNUNET_YES if connection was destroyed as a result,
- * #GNUNET_NO otherwise.
- */
-int
-GCP_queue_destroy (struct CadetPeerQueue *queue,
- int clear_cls,
- int sent,
- uint32_t pid)
-{
- struct CadetPeer *peer;
- int connection_destroyed;
-
- GCC_check_connections ();
- peer = queue->peer;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "queue destroy %s\n", GC_m2s (queue->type));
- if (GNUNET_YES == clear_cls)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " free cls\n");
- switch (queue->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- LOG (GNUNET_ERROR_TYPE_INFO, "destroying a DESTROY message\n");
- /* fall through */
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- case GNUNET_MESSAGE_TYPE_CADET_AX:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- GNUNET_free_non_null (queue->cls);
- break;
-
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_ERROR, " type %s unknown!\n",
- GC_m2s (queue->type));
- }
- }
- GNUNET_CONTAINER_DLL_remove (peer->queue_head, peer->queue_tail, queue);
-
- if (queue->type != GNUNET_MESSAGE_TYPE_CADET_ACK &&
- queue->type != GNUNET_MESSAGE_TYPE_CADET_POLL)
- {
- peer->queue_n--;
- }
-
- if (NULL != queue->cont)
- {
- struct GNUNET_TIME_Relative wait_time;
-
- wait_time = GNUNET_TIME_absolute_get_duration (queue->start_waiting);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " calling callback, time elapsed %s\n",
- GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
- connection_destroyed = queue->cont (queue->cont_cls,
- queue->c, sent, queue->type, pid,
- queue->fwd, queue->size, wait_time);
- }
- else
- {
- connection_destroyed = GNUNET_NO;
- }
-
- if (NULL == peer_get_first_message (peer) && NULL != peer->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
- peer->core_transmit = NULL;
- peer->tmt_time.abs_value_us = 0;
- }
-
- GNUNET_free (queue);
- GCC_check_connections ();
- return connection_destroyed;
-}
-
-
-/**
- * @brief Queue and pass message to core when possible.
- *
- * @param peer Peer towards which to queue the message.
- * @param cls Closure (@c type dependant). It will be used by queue_send to
- * build the message to be sent if not already prebuilt.
- * @param type Type of the message, 0 for a raw message.
- * @param size Size of the message.
- * @param c Connection this message belongs to (can be NULL).
- * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
- * @param cont Continuation to be called once CORE has taken the message.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it is sent. Once cont is called
- * message has been sent and therefore the handle is no longer valid.
- */
-struct CadetPeerQueue *
-GCP_queue_add (struct CadetPeer *peer, void *cls, uint16_t type,
- uint16_t payload_type, uint32_t payload_id, size_t size,
- struct CadetConnection *c, int fwd,
- GCP_sent cont, void *cont_cls)
-{
- struct CadetPeerQueue *q;
- int error_level;
- int priority;
- int call_core;
-
- GCC_check_connections ();
- if (NULL == c && GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN != type)
- error_level = GNUNET_ERROR_TYPE_ERROR;
- else
- error_level = GNUNET_ERROR_TYPE_INFO;
- LOG (error_level,
- "que %s (%s %4u) on connection %s (%p) %s towards %s (size %u)\n",
- GC_m2s (type), GC_m2s (payload_type), payload_id,
- GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
-
- if (error_level == GNUNET_ERROR_TYPE_ERROR)
- GNUNET_assert (0);
- if (NULL == peer->connections)
- {
- /* We are not connected to this peer, ignore request. */
- LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
- GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
- GNUNET_NO);
- return NULL;
- }
-
- priority = 0;
-
- if (GNUNET_MESSAGE_TYPE_CADET_POLL == type ||
- GNUNET_MESSAGE_TYPE_CADET_ACK == type)
- {
- priority = 100;
- }
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "priority %d\n", priority);
-
- call_core = (NULL == c || type == GNUNET_MESSAGE_TYPE_CADET_KX) ?
- GNUNET_YES : GCC_is_sendable (c, fwd);
- q = GNUNET_new (struct CadetPeerQueue);
- q->cls = cls;
- q->type = type;
- q->payload_type = payload_type;
- q->payload_id = payload_id;
- q->size = size;
- q->peer = peer;
- q->c = c;
- q->fwd = fwd;
- q->cont = cont;
- q->cont_cls = cont_cls;
- if (100 > priority)
- {
- GNUNET_CONTAINER_DLL_insert_tail (peer->queue_head, peer->queue_tail, q);
- peer->queue_n++;
- }
- else
- {
- GNUNET_CONTAINER_DLL_insert (peer->queue_head, peer->queue_tail, q);
- call_core = GNUNET_YES;
- }
-
- q->start_waiting = GNUNET_TIME_absolute_get ();
- if (NULL == peer->core_transmit && GNUNET_YES == call_core)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "calling core tmt rdy towards %s for %u bytes\n",
- GCP_2s (peer), size);
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (q),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_PEER_resolve2 (peer->id),
- get_core_size (size),
- &queue_send, peer);
- peer->tmt_time = GNUNET_TIME_absolute_get ();
- }
- else if (GNUNET_NO == call_core)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s not needed\n",
- GCP_2s (peer));
-
- }
- else
- {
- struct GNUNET_TIME_Relative elapsed;
- elapsed = GNUNET_TIME_absolute_get_duration (peer->tmt_time);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "core tmt rdy towards %s already called %s\n",
- GCP_2s (peer),
- GNUNET_STRINGS_relative_time_to_string (elapsed, GNUNET_NO));
-
- }
- queue_debug (peer, GNUNET_ERROR_TYPE_DEBUG);
- GCC_check_connections ();
- return q;
-}
-
-
-/**
- * Cancel all queued messages to a peer that belong to a certain connection.
- *
- * @param peer Peer towards whom to cancel.
- * @param c Connection whose queued messages to cancel. Might be destroyed by
- * the sent continuation call.
- */
-void
-GCP_queue_cancel (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
- struct CadetPeerQueue *next;
- struct CadetPeerQueue *prev;
- int connection_destroyed;
-
- GCC_check_connections ();
- connection_destroyed = GNUNET_NO;
- for (q = peer->queue_head; NULL != q; q = next)
- {
- prev = q->prev;
- if (q->c == c)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, "GMP queue cancel %s\n", GC_m2s (q->type));
- GNUNET_break (GNUNET_NO == connection_destroyed);
- if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY == q->type)
- {
- q->c = NULL;
- }
- else
- {
- connection_destroyed = GCP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
- }
-
- /* Get next from prev, q->next might be already freed:
- * queue destroy -> callback -> GCC_destroy -> cancel_queues -> here
- */
- if (NULL == prev)
- next = peer->queue_head;
- else
- next = prev->next;
- }
- else
- {
- next = q->next;
- }
- }
-
- if (NULL == peer->queue_head && NULL != peer->core_transmit)
- {
- GNUNET_CORE_notify_transmit_ready_cancel (peer->core_transmit);
- peer->core_transmit = NULL;
- peer->tmt_time.abs_value_us = 0;
- }
- GCC_check_connections ();
-}
-
-
-/**
- * Get the first transmittable message for a connection.
- *
- * @param peer Neighboring peer.
- * @param c Connection.
- *
- * @return First transmittable message.
- */
-static struct CadetPeerQueue *
-connection_get_first_message (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
-
- for (q = peer->queue_head; NULL != q; q = q->next)
- {
- if (q->c != c)
- continue;
- if (queue_is_sendable (q))
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable!!\n");
- return q;
- }
- LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
- }
-
- return NULL;
-}
-
-
-/**
- * Get the first message for a connection and unqueue it.
- *
- * Only tunnel (or higher) level messages are unqueued. Connection specific
- * messages are silently destroyed upon encounter.
- *
- * @param peer Neighboring peer.
- * @param c Connection.
- * @param destroyed[in/out] Was the connection destroyed (prev/as a result)?.
- * Can NOT be NULL.
- *
- * @return First message for this connection.
- */
-struct GNUNET_MessageHeader *
-GCP_connection_pop (struct CadetPeer *peer,
- struct CadetConnection *c,
- int *destroyed)
-{
- struct CadetPeerQueue *q;
- struct CadetPeerQueue *next;
- struct GNUNET_MessageHeader *msg;
- int dest;
-
- GCC_check_connections ();
- GNUNET_assert (NULL != destroyed);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "connection_pop on connection %p\n", c);
- for (q = peer->queue_head; NULL != q; q = next)
- {
- next = q->next;
- if (q->c != c)
- continue;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " - queued: %s (%s %u), cont: %p\n",
- GC_m2s (q->type), GC_m2s (q->payload_type), q->payload_id,
- q->cont);
- switch (q->type)
- {
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
- case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
- case GNUNET_MESSAGE_TYPE_CADET_ACK:
- case GNUNET_MESSAGE_TYPE_CADET_POLL:
- dest = GCP_queue_destroy (q, GNUNET_YES, GNUNET_NO, 0);
- if (GNUNET_YES == dest)
- {
- GNUNET_break (GNUNET_NO == *destroyed);
- *destroyed = GNUNET_YES;
- }
- continue;
-
- case GNUNET_MESSAGE_TYPE_CADET_KX:
- case GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED:
- case GNUNET_MESSAGE_TYPE_CADET_AX:
- case GNUNET_MESSAGE_TYPE_CADET_AX_KX:
- msg = (struct GNUNET_MessageHeader *) q->cls;
- dest = GCP_queue_destroy (q, GNUNET_NO, GNUNET_NO, 0);
- if (GNUNET_YES == dest)
- {
- GNUNET_break (GNUNET_NO == *destroyed);
- *destroyed = GNUNET_YES;
- }
- return msg;
-
- default:
- GNUNET_break (0);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Unknown message %s\n", GC_m2s (q->type));
- }
- }
- GCC_check_connections ();
- return NULL;
-}
-
-
-/**
- * Unlock a possibly locked queue for a connection.
- *
- * If there is a message that can be sent on this connection, call core for it.
- * Otherwise (if core transmit is already called or there is no sendable
- * message) do nothing.
- *
- * @param peer Peer who keeps the queue.
- * @param c Connection whose messages to unlock.
- */
-void
-GCP_queue_unlock (struct CadetPeer *peer, struct CadetConnection *c)
-{
- struct CadetPeerQueue *q;
- size_t size;
-
- GCC_check_connections ();
- if (NULL != peer->core_transmit)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " already unlocked!\n");
- return; /* Already unlocked */
- }
-
- q = connection_get_first_message (peer, c);
- if (NULL == q)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " queue empty!\n");
- return; /* Nothing to transmit */
- }
-
- size = q->size;
- peer->core_transmit =
- GNUNET_CORE_notify_transmit_ready (core_handle,
- GNUNET_NO, get_priority (q),
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_PEER_resolve2 (peer->id),
- get_core_size (size),
- &queue_send,
- peer);
- peer->tmt_time = GNUNET_TIME_absolute_get ();
- GCC_check_connections ();
-}
-
-
-/**
- * Initialize the peer subsystem.
- *
- * @param c Configuration.
- */
-void
-GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "GCP_init\n");
- in_shutdown = GNUNET_NO;
- peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
- &max_peers))
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- "CADET", "MAX_PEERS", "USING DEFAULT");
- max_peers = 1000;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT",
- &drop_percent))
- {
- drop_percent = 0;
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
- }
-
- core_handle = GNUNET_CORE_connect (c, /* Main configuration */
- NULL, /* Closure passed to CADET functions */
- &core_init, /* Call core_init once connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on disconnects */
- NULL, /* Don't notify about all incoming messages */
- GNUNET_NO, /* For header only in notification */
- NULL, /* Don't notify about all outbound messages */
- GNUNET_NO, /* For header-only out notification */
- core_handlers); /* Register these handlers */
- if (GNUNET_YES !=
- GNUNET_CONFIGURATION_get_value_yesno (c, "CADET", "DISABLE_TRY_CONNECT"))
- {
- transport_handle = GNUNET_TRANSPORT_connect (c, &my_full_id, NULL, /* cls */
- /* Notify callbacks */
- NULL, NULL, NULL);
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "* DISABLE TRYING CONNECT in config *\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "* Use this only for test purposes. *\n");
- LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
- transport_handle = NULL;
- }
-
-
-
- if (NULL == core_handle)
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
-}
-
-
-/**
- * Shut down the peer subsystem.
- */
-void
-GCP_shutdown (void)
-{
- in_shutdown = GNUNET_YES;
- GNUNET_CONTAINER_multipeermap_iterate (peers,
- &shutdown_peer,
- NULL);
- if (NULL != core_handle)
- {
- GNUNET_CORE_disconnect (core_handle);
- core_handle = NULL;
- }
- if (NULL != transport_handle)
- {
- GNUNET_TRANSPORT_disconnect (transport_handle);
- transport_handle = NULL;
- }
- GNUNET_PEER_change_rc (myid, -1);
- GNUNET_CONTAINER_multipeermap_destroy (peers);
- peers = NULL;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id)
-{
- struct CadetPeer *peer;
-
- peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
- if (NULL == peer)
- {
- peer = GNUNET_new (struct CadetPeer);
- if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
- {
- peer_delete_oldest ();
- }
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multipeermap_put (peers,
- peer_id,
- peer,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- peer->id = GNUNET_PEER_intern (peer_id);
- }
- peer->last_contact = GNUNET_TIME_absolute_get ();
-
- return peer;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer, create one
- * and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- *
- * @return Existing or newly created peer structure.
- */
-struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer)
-{
- return GCP_get (GNUNET_PEER_resolve2 (peer));
-}
-
-
-/**
- * Try to connect to a peer on transport level.
- *
- * @param cls Closure (peer).
- * @param tc TaskContext.
- */
-static void
-try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct CadetPeer *peer = cls;
-
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- return;
-
- GNUNET_TRANSPORT_try_connect (transport_handle,
- GNUNET_PEER_resolve2 (peer->id), NULL, NULL);
-}
-
-
-/**
- * Try to establish a new connection to this peer (in its tunnel).
- * If the peer doesn't have any path to it yet, try to get one.
- * If the peer already has some path, send a CREATE CONNECTION towards it.
- *
- * @param peer Peer to connect to.
- */
-void
-GCP_connect (struct CadetPeer *peer)
-{
- struct CadetTunnel *t;
- struct CadetPeerPath *p;
- struct CadetConnection *c;
- int rerun_search;
-
- GCC_check_connections ();
- LOG (GNUNET_ERROR_TYPE_DEBUG, "peer_connect towards %s\n", GCP_2s (peer));
-
- /* If we have a current hello, try to connect using it. */
- GCP_try_connect (peer);
-
- t = peer->tunnel;
- c = NULL;
- rerun_search = GNUNET_NO;
-
- if (NULL != peer->path_head)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " some path exists\n");
- p = peer_get_best_path (peer);
- if (NULL != p)
- {
- char *s;
-
- s = path_2s (p);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " path to use: %s\n", s);
- GNUNET_free (s);
-
- c = GCT_use_path (t, p);
- if (NULL == c)
- {
- /* This case can happen when the path includes a first hop that is
- * not yet known to be connected.
- *
- * This happens quite often during testing when running cadet
- * under valgrind: core connect notifications come very late
- * and the DHT result has already come and created a valid
- * path. In this case, the peer->connections_{pred,succ}
- * hashmaps will be NULL and tunnel_use_path will not be able
- * to create a connection from that path.
- *
- * Re-running the DHT GET should give core time to callback.
- *
- * GCT_use_path -> GCC_new -> register_neighbors takes care of
- * updating statistics about this issue.
- */
- rerun_search = GNUNET_YES;
- }
- else
- {
- GCC_send_create (c);
- return;
- }
- }
- else
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " but is NULL, all paths are in use\n");
- }
- }
-
- if (GNUNET_YES == rerun_search)
- {
- struct GNUNET_TIME_Relative delay;
-
- GCP_stop_search (peer);
- delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
- peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay,
- &delayed_search,
- peer);
- GCC_check_connections ();
- return;
- }
-
- if (GNUNET_NO == is_searching (peer))
- GCP_start_search (peer);
- GCC_check_connections ();
-}
-
-
-/**
- * Chech whether there is a direct (core level) connection to peer.
- *
- * @param peer Peer to check.
- *
- * @return #GNUNET_YES if there is a direct connection.
- */
-int
-GCP_is_neighbor (const struct CadetPeer *peer)
-{
- struct CadetPeerPath *path;
-
- if (NULL == peer->connections)
- return GNUNET_NO;
-
- for (path = peer->path_head; NULL != path; path = path->next)