/**
* Session with another peer.
*/
-struct Session
+struct GNUNET_ATS_Session
{
/**
* Which peer is this session for?
struct GNUNET_TIME_Relative flow_delay_for_other_peer;
/**
- * Desired delay for next sending we received from other peer
+ * Desired delay for transmissions we received from other peer.
+ * Adjusted to be per fragment (UDP_MTU), even though on the
+ * wire it was for "full messages".
*/
- struct GNUNET_TIME_Absolute flow_delay_from_other_peer;
+ struct GNUNET_TIME_Relative flow_delay_from_other_peer;
/**
* Session timeout task
*/
struct GNUNET_TIME_Absolute timeout;
+ /**
+ * What time did we last transmit?
+ */
+ struct GNUNET_TIME_Absolute last_transmit_time;
+
/**
* expected delay for ACKs
*/
/**
* The session this fragmentation context belongs to
*/
- struct Session *session;
+ struct GNUNET_ATS_Session *session;
/**
* Function to call upon completion of the transmission.
*/
void *cont_cls;
+ /**
+ * Start time.
+ */
+ struct GNUNET_TIME_Absolute start_time;
+
+ /**
+ * Transmission time for the next fragment. Incremented by
+ * the "flow_delay_from_other_peer" for each fragment when
+ * we setup the fragments.
+ */
+ struct GNUNET_TIME_Absolute next_frag_time;
+
/**
* Message timeout
*/
/**
* Session this message belongs to
*/
- struct Session *session;
+ struct GNUNET_ATS_Session *session;
/**
* DLL of messages, previous element
*/
struct UDP_FragmentationContext *frag_ctx;
+ /**
+ * Message enqueue time.
+ */
+ struct GNUNET_TIME_Absolute start_time;
+
+ /**
+ * Desired transmission time for this message, based on the
+ * flow limiting information we got from the other peer.
+ */
+ struct GNUNET_TIME_Absolute transmission_time;
+
/**
* Message timeout.
*/
*/
static void
notify_session_monitor (struct Plugin *plugin,
- struct Session *session,
+ struct GNUNET_ATS_Session *session,
enum GNUNET_TRANSPORT_SessionState state)
{
struct GNUNET_TRANSPORT_SessionInfo info;
*
* @param cls the `struct Plugin` with the monitor callback (`sic`)
* @param peer peer we send information about
- * @param value our `struct Session` to send information about
+ * @param value our `struct GNUNET_ATS_Session` to send information about
* @return #GNUNET_OK (continue to iterate)
*/
static int
void *value)
{
struct Plugin *plugin = cls;
- struct Session *session = value;
+ struct GNUNET_ATS_Session *session = value;
notify_session_monitor (plugin,
session,
* @param s session to free
*/
static void
-free_session (struct Session *s)
+free_session (struct GNUNET_ATS_Session *s)
{
if (NULL != s->address)
{
*/
static enum GNUNET_ATS_Network_Type
udp_plugin_get_network (void *cls,
- struct Session *session)
+ struct GNUNET_ATS_Session *session)
{
return session->scope;
}
min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
for (udpw = plugin->ipv4_queue_head; NULL != udpw; udpw = udpw->next)
min_delay = GNUNET_TIME_relative_min (min_delay,
- GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer));
+ GNUNET_TIME_absolute_get_remaining (udpw->transmission_time));
if (NULL != plugin->select_task_v4)
GNUNET_SCHEDULER_cancel (plugin->select_task_v4);
+ if (NULL != plugin->ipv4_queue_head)
+ {
+ if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Calculated flow delay for UDPv4 at %s\n",
+ GNUNET_STRINGS_relative_time_to_string (min_delay,
+ GNUNET_YES));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Calculated flow delay for UDPv4 at %s\n",
+ GNUNET_STRINGS_relative_time_to_string (min_delay,
+ GNUNET_YES));
+ }
+ }
plugin->select_task_v4
= GNUNET_SCHEDULER_add_read_net (min_delay,
plugin->sockv4,
min_delay = GNUNET_TIME_UNIT_FOREVER_REL;
for (udpw = plugin->ipv6_queue_head; NULL != udpw; udpw = udpw->next)
min_delay = GNUNET_TIME_relative_min (min_delay,
- GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer));
+ GNUNET_TIME_absolute_get_remaining (udpw->transmission_time));
if (NULL != plugin->select_task_v6)
GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
+ if (NULL != plugin->ipv6_queue_head)
+ {
+ if (min_delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Calculated flow delay for UDPv6 at %s\n",
+ GNUNET_STRINGS_relative_time_to_string (min_delay,
+ GNUNET_YES));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Calculated flow delay for UDPv6 at %s\n",
+ GNUNET_STRINGS_relative_time_to_string (min_delay,
+ GNUNET_YES));
+ }
+ }
plugin->select_task_v6
= GNUNET_SCHEDULER_add_read_net (min_delay,
plugin->sockv6,
/**
* Closure for #session_cmp_it().
*/
-struct SessionCompareContext
+struct GNUNET_ATS_SessionCompareContext
{
/**
* Set to session matching the address.
*/
- struct Session *res;
+ struct GNUNET_ATS_Session *res;
/**
* Address we are looking for.
/**
* Find a session with a matching address.
*
- * @param cls the `struct SessionCompareContext *`
+ * @param cls the `struct GNUNET_ATS_SessionCompareContext *`
* @param key peer identity (unused)
- * @param value the `struct Session *`
+ * @param value the `struct GNUNET_ATS_Session *`
* @return #GNUNET_NO if we found the session, #GNUNET_OK if not
*/
static int
const struct GNUNET_PeerIdentity *key,
void *value)
{
- struct SessionCompareContext *cctx = cls;
- struct Session *s = value;
+ struct GNUNET_ATS_SessionCompareContext *cctx = cls;
+ struct GNUNET_ATS_Session *s = value;
if (0 == GNUNET_HELLO_address_cmp (s->address,
cctx->address))
* @param address the address we should locate the session by
* @return the session if it exists, or NULL if it is not found
*/
-static struct Session *
+static struct GNUNET_ATS_Session *
udp_plugin_lookup_session (void *cls,
const struct GNUNET_HELLO_Address *address)
{
struct Plugin *plugin = cls;
const struct IPv6UdpAddress *udp_a6;
const struct IPv4UdpAddress *udp_a4;
- struct SessionCompareContext cctx;
+ struct GNUNET_ATS_SessionCompareContext cctx;
if (NULL == address->address)
{
* @param s session to reschedule timeout activity for
*/
static void
-reschedule_session_timeout (struct Session *s)
+reschedule_session_timeout (struct GNUNET_ATS_Session *s)
{
if (GNUNET_YES == s->in_destroy)
return;
static void
udp_plugin_update_session_timeout (void *cls,
const struct GNUNET_PeerIdentity *peer,
- struct Session *session)
+ struct GNUNET_ATS_Session *session)
{
struct Plugin *plugin = cls;
dequeue (struct Plugin *plugin,
struct UDP_MessageWrapper *udpw)
{
- struct Session *session = udpw->session;
+ struct GNUNET_ATS_Session *session = udpw->session;
if (plugin->bytes_in_buffer < udpw->msg_size)
{
enqueue (struct Plugin *plugin,
struct UDP_MessageWrapper *udpw)
{
- struct Session *session = udpw->session;
+ struct GNUNET_ATS_Session *session = udpw->session;
if (GNUNET_YES == session->in_destroy)
{
int result)
{
struct Plugin *plugin = frag_ctx->plugin;
- struct Session *s = frag_ctx->session;
+ struct GNUNET_ATS_Session *s = frag_ctx->session;
struct UDP_MessageWrapper *udpw;
struct UDP_MessageWrapper *tmp;
size_t overhead;
+ struct GNUNET_TIME_Relative delay;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"%p: Fragmented message removed with result %s\n",
overhead = frag_ctx->on_wire_size - frag_ctx->payload_size;
else
overhead = frag_ctx->on_wire_size;
+ delay = GNUNET_TIME_absolute_get_duration (frag_ctx->start_time);
+ if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Fragmented message acknowledged after %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Fragmented message acknowledged after %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES));
+ }
+
if (NULL != frag_ctx->cont)
frag_ctx->cont (frag_ctx->cont_cls,
&s->target,
struct UDP_FragmentationContext *frag_ctx = cls;
struct Plugin *plugin = frag_ctx->plugin;
struct UDP_MessageWrapper *udpw;
- struct Session *session = frag_ctx->session;
+ struct GNUNET_ATS_Session *session = frag_ctx->session;
size_t msg_len = ntohs (msg->size);
LOG (GNUNET_ERROR_TYPE_DEBUG,
udpw->msg_size = msg_len;
udpw->payload_size = msg_len; /* FIXME: minus fragment overhead */
udpw->timeout = frag_ctx->timeout;
+ udpw->start_time = frag_ctx->start_time;
+ udpw->transmission_time = frag_ctx->next_frag_time;
+ frag_ctx->next_frag_time
+ = GNUNET_TIME_absolute_add (frag_ctx->next_frag_time,
+ session->flow_delay_from_other_peer);
udpw->frag_ctx = frag_ctx;
udpw->qc = &qc_fragment_sent;
udpw->qc_cls = plugin;
{
struct Plugin *plugin = cls;
size_t overhead;
+ struct GNUNET_TIME_Relative delay;
if (udpw->msg_size >= udpw->payload_size)
overhead = udpw->msg_size - udpw->payload_size;
overhead = udpw->msg_size;
if (NULL != udpw->cont)
+ {
+ delay = GNUNET_TIME_absolute_get_duration (udpw->start_time);
+ if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Message sent via UDP with delay of %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Message sent via UDP with delay of %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay,
+ GNUNET_YES));
+ }
udpw->cont (udpw->cont_cls,
&udpw->session->target,
result,
udpw->payload_size,
overhead);
+ }
if (GNUNET_OK == result)
{
GNUNET_STATISTICS_update (plugin->env->stats,
*/
static ssize_t
udp_plugin_send (void *cls,
- struct Session *s,
+ struct GNUNET_ATS_Session *s,
const char *msgbuf,
size_t msgbuf_size,
unsigned int priority,
udpw->msg_buf = (char *) &udpw[1];
udpw->msg_size = udpmlen; /* message size with UDP overhead */
udpw->payload_size = msgbuf_size; /* message size without UDP overhead */
+ udpw->start_time = GNUNET_TIME_absolute_get ();
udpw->timeout = GNUNET_TIME_relative_to_absolute (to);
+ udpw->transmission_time = s->last_transmit_time;
+ s->last_transmit_time
+ = GNUNET_TIME_absolute_add (s->last_transmit_time,
+ s->flow_delay_from_other_peer);
udpw->cont = cont;
udpw->cont_cls = cont_cls;
udpw->frag_ctx = NULL;
frag_ctx->session = s;
frag_ctx->cont = cont;
frag_ctx->cont_cls = cont_cls;
+ frag_ctx->start_time = GNUNET_TIME_absolute_get ();
+ frag_ctx->next_frag_time = s->last_transmit_time;
frag_ctx->timeout = GNUNET_TIME_relative_to_absolute (to);
frag_ctx->payload_size = msgbuf_size; /* unfragmented message size without UDP overhead */
frag_ctx->on_wire_size = 0; /* bytes with UDP and fragmentation overhead */
&enqueue_fragment,
frag_ctx);
s->frag_ctx = frag_ctx;
+ s->last_transmit_time = frag_ctx->next_frag_time;
GNUNET_STATISTICS_update (plugin->env->stats,
"# UDP, fragmented messages active",
1,
const struct GNUNET_MessageHeader *ack;
const struct UDP_ACK_Message *udp_ack;
struct GNUNET_HELLO_Address *address;
- struct Session *s;
+ struct GNUNET_ATS_Session *s;
struct GNUNET_TIME_Relative flow_delay;
if (ntohs (msg->size)
GNUNET_STRINGS_relative_time_to_string (flow_delay,
GNUNET_YES),
GNUNET_i2s (&udp_ack->sender));
- s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute (flow_delay);
+ /* Flow delay is for the reassembled packet, however, our delay
+ is per packet, so we need to adjust: */
+ flow_delay = GNUNET_TIME_relative_divide (flow_delay,
+ 1 + (s->frag_ctx->payload_size /
+ UDP_MTU));
+ s->flow_delay_from_other_peer = flow_delay;
if (GNUNET_OK !=
/**
* Session associated with this context.
*/
- struct Session *session;
+ struct GNUNET_ATS_Session *session;
/**
* Address to find.
* to the service.
*
* @param cls the `struct Plugin *`
- * @param client the `struct Session *`
+ * @param client the `struct GNUNET_ATS_Session *`
* @param hdr the actual message
* @return #GNUNET_OK (always)
*/
const struct GNUNET_MessageHeader *hdr)
{
struct Plugin *plugin = cls;
- struct Session *session = client;
+ struct GNUNET_ATS_Session *session = client;
if (GNUNET_YES == session->in_destroy)
return GNUNET_OK;
*/
static int
udp_disconnect_session (void *cls,
- struct Session *s)
+ struct GNUNET_ATS_Session *s)
{
struct Plugin *plugin = cls;
struct UDP_MessageWrapper *udpw;
/**
* Session was idle, so disconnect it.
*
- * @param cls the `struct Session` to time out
+ * @param cls the `struct GNUNET_ATS_Session` to time out
* @param tc scheduler context
*/
static void
session_timeout (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct Session *s = cls;
+ struct GNUNET_ATS_Session *s = cls;
struct Plugin *plugin = s->plugin;
struct GNUNET_TIME_Relative left;
* @param network_type network type the address belongs to
* @return NULL on error, otherwise session handle
*/
-static struct Session *
+static struct GNUNET_ATS_Session *
udp_plugin_create_session (void *cls,
const struct GNUNET_HELLO_Address *address,
enum GNUNET_ATS_Network_Type network_type)
{
struct Plugin *plugin = cls;
- struct Session *s;
+ struct GNUNET_ATS_Session *s;
- s = GNUNET_new (struct Session);
+ s = GNUNET_new (struct GNUNET_ATS_Session);
s->plugin = plugin;
s->address = GNUNET_HELLO_address_copy (address);
s->target = address->peer;
+ s->last_transmit_time = GNUNET_TIME_absolute_get ();
s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
250);
s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
- s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
+ s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO;
s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
s->timeout = GNUNET_TIME_relative_to_absolute (UDP_SESSION_TIME_OUT);
s->timeout_task = GNUNET_SCHEDULER_add_delayed (UDP_SESSION_TIME_OUT,
* @param address the address
* @return the session or NULL of max connections exceeded
*/
-static struct Session *
+static struct GNUNET_ATS_Session *
udp_plugin_get_session (void *cls,
const struct GNUNET_HELLO_Address *address)
{
struct Plugin *plugin = cls;
- struct Session *s;
+ struct GNUNET_ATS_Session *s;
enum GNUNET_ATS_Network_Type network_type = GNUNET_ATS_NET_UNSPECIFIED;
const struct IPv4UdpAddress *udp_v4;
const struct IPv6UdpAddress *udp_v6;
size_t udp_addr_len,
enum GNUNET_ATS_Network_Type network_type)
{
- struct Session *s;
+ struct GNUNET_ATS_Session *s;
struct GNUNET_HELLO_Address *address;
GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != network_type);
struct UDP_ACK_Message *udp_ack;
uint32_t delay;
struct UDP_MessageWrapper *udpw;
- struct Session *s;
+ struct GNUNET_ATS_Session *s;
struct GNUNET_HELLO_Address *address;
if (GNUNET_NO == rc->have_sender)
udpw->msg_size = msize;
udpw->payload_size = 0;
udpw->session = s;
+ udpw->start_time = GNUNET_TIME_absolute_get ();
udpw->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
udpw->msg_buf = (char *) &udpw[1];
udpw->qc = &ack_message_sent;
{
struct UDP_MessageWrapper *udpw;
struct GNUNET_TIME_Relative remaining;
- struct Session *session;
+ struct GNUNET_ATS_Session *session;
int removed;
removed = GNUNET_NO;
}
else
{
- /* Message did not time out, check flow delay */
- remaining = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer);
+ /* Message did not time out, check transmission time */
+ remaining = GNUNET_TIME_absolute_get_remaining (udpw->transmission_time);
if (0 == remaining.rel_value_us)
{
/* this message is not delayed */
udpw->msg_size,
a,
slen);
+ udpw->session->last_transmit_time
+ = GNUNET_TIME_absolute_max (GNUNET_TIME_absolute_get (),
+ udpw->session->last_transmit_time);
dequeue (plugin,
udpw);
if (GNUNET_SYSERR == sent)