*
* FIXME:
* - proper connection evaluation during connection management:
- * + when managing connections, distinguish those that
- * have (recently) had traffic from those that were
- * never ready (or not recently)
- * + consider quality of current connection set when deciding
- * how often to do maintenance
+ * + consider quality (or quality spread?) of current connection set
+ * when deciding how often to do maintenance
* + interact with PEER to drive DHT GET/PUT operations based
* on how much we like our connections
*/
/**
* Continuation to call once sent (on the channel layer).
*/
- GNUNET_SCHEDULER_TaskCallback cont;
+ GCT_SendContinuation cont;
/**
* Closure for @c cont.
*/
struct CadetTunnelQueueEntry *tq_tail;
+ /**
+ * Identification of the connection from which we are currently processing
+ * a message. Only valid (non-NULL) during #handle_decrypted() and the
+ * handle-*()-functions called from our @e mq during that function.
+ */
+ struct CadetTConnection *current_ct;
+
/**
* How long do we wait until we retry the KX?
*/
sizeof (kx_auth)))
{
/* This KX_AUTH is not using the latest KX/KX_AUTH data
- we transmitted to the sender, refuse it! */
+ we transmitted to the sender, refuse it, try KX again. */
GNUNET_break_op (0);
+ send_kx (t,
+ NULL,
+ &t->ax);
return;
}
/* Yep, we're good. */
while (NULL != (tq = t->tq_head))
{
if (NULL != tq->cont)
- tq->cont (tq->cont_cls);
+ tq->cont (tq->cont_cls,
+ NULL);
GCT_send_cancel (tq);
}
GCP_drop_tunnel (t->destination,
GNUNET_free (t->unverified_ax);
}
cleanup_ax (&t->ax);
+ GNUNET_assert (NULL == t->destroy_task);
GNUNET_free (t);
}
GNUNET_CONTAINER_multihashmap32_remove (t->channels,
ntohl (ctn.cn),
ch));
- if (0 ==
- GCT_count_channels (t))
+ if ( (0 ==
+ GCT_count_channels (t)) &&
+ (NULL == t->destroy_task) )
{
- t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
- &destroy_tunnel,
- t);
+ t->destroy_task
+ = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+ &destroy_tunnel,
+ t);
}
}
{
struct CadetChannel *ch = value;
- GCCH_handle_remote_destroy (ch);
+ GCCH_handle_remote_destroy (ch,
+ NULL);
return GNUNET_OK;
}
GCC_transmit (ct->cc,
tq->env);
if (NULL != tq->cont)
- tq->cont (tq->cont_cls);
+ tq->cont (tq->cont_cls,
+ GCC_get_id (ct->cc));
GNUNET_free (tq);
}
struct EvaluationSummary *es = cls;
struct CadetConnection *cc = ct->cc;
struct CadetPeerPath *ps = GCC_get_path (cc);
+ const struct CadetConnectionMetrics *metrics;
GNUNET_CONTAINER_HeapCostType ct_desirability;
+ struct GNUNET_TIME_Relative uptime;
+ struct GNUNET_TIME_Relative last_use;
uint32_t ct_length;
double score;
+ double success_rate;
if (ps == es->path)
{
}
ct_desirability = GCPP_get_desirability (ps);
ct_length = GCPP_get_length (ps);
-
- /* FIXME: calculate score on more than path,
- include connection performance metrics like
- last successful transmission, uptime, etc. */
- score = ct_desirability + ct_length; /* FIXME: weigh these as well! */
+ metrics = GCC_get_metrics (cc);
+ uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
+ last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
+ /* We add 1.0 here to avoid division by zero. */
+ success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
+ score
+ = ct_desirability
+ + 100.0 / (1.0 + ct_length) /* longer paths = better */
+ + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
+ - last_use.rel_value_us / 1000L; /* longer idle = worse */
+ score *= success_rate; /* weigh overall by success rate */
if ( (NULL == es->worst) ||
(score < es->worst_score) )
ct->t = t;
ct->cc = GCC_create (t->destination,
path,
+ GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
ct,
&connection_ready_cb,
ct);
return;
}
GCCH_handle_channel_plaintext_data (ch,
+ GCC_get_id (t->current_ct->cc),
msg);
}
return;
}
GCCH_handle_channel_plaintext_data_ack (ch,
+ GCC_get_id (t->current_ct->cc),
ack);
}
GNUNET_h2s (&copen->port),
GCT_2s (t),
GCCH_2s (ch));
- GCCH_handle_duplicate_open (ch);
+ GCCH_handle_duplicate_open (ch,
+ GCC_get_id (t->current_ct->cc));
return;
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Received channel OPEN_ACK on channel %s from %s\n",
GCCH_2s (ch),
GCT_2s (t));
- GCCH_handle_channel_open_ack (ch);
+ GCCH_handle_channel_open_ack (ch,
+ GCC_get_id (t->current_ct->cc));
}
"Receicved channel DESTROY on %s from %s\n",
GCCH_2s (ch),
GCT_2s (t));
- GCCH_handle_remote_destroy (ch);
+ GCCH_handle_remote_destroy (ch,
+ GCC_get_id (t->current_ct->cc));
}
{
struct CadetTunnel *t = cls;
+ GNUNET_assert (NULL != t->current_ct);
GNUNET_MQ_inject_message (t->mq,
msg);
return GNUNET_OK;
*
* @param t a tunnel
* @param cid connection identifer to use for the connection
+ * @param options options for the connection
* @param path path to use for the connection
* @return #GNUNET_OK on success,
* #GNUNET_SYSERR on failure (duplicate connection)
int
GCT_add_inbound_connection (struct CadetTunnel *t,
const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+ enum GNUNET_CADET_ChannelOption options,
struct CadetPeerPath *path)
{
struct CadetTConnection *ct;
ct->t = t;
ct->cc = GCC_create_inbound (t->destination,
path,
+ options,
ct,
cid,
&connection_ready_cb,
}
/* The MST will ultimately call #handle_decrypted() on each message. */
+ t->current_ct = ct;
GNUNET_break_op (GNUNET_OK ==
GNUNET_MST_from_buffer (t->mst,
cbuf,
decrypted_size,
GNUNET_YES,
GNUNET_NO));
+ t->current_ct = NULL;
}
struct CadetTunnelQueueEntry *
GCT_send (struct CadetTunnel *t,
const struct GNUNET_MessageHeader *message,
- GNUNET_SCHEDULER_TaskCallback cont,
+ GCT_SendContinuation cont,
void *cont_cls)
{
struct CadetTunnelQueueEntry *tq;