Release 1.17.6

- Add failsafe: resume sending packets after some time

  The change puts a 1-second limit on the amount of time the engine
  will not send packets after some packets are delayed.  This makes
  the library robust in case the user does not unblock the engine
  explicitly using lsquic_engine_send_unsent_packets() call.

- [BUGFIX] Handle corner cases in send controller when packets are
  a) delayed or b) dropped during repackaging.

- [BUGFIX] Memory leak: destroy buffered packets during controller
  cleanup.
This commit is contained in:
Dmitri Tikhonov 2018-11-29 15:26:49 -05:00
parent bf2c703721
commit 8252b0b935
5 changed files with 72 additions and 9 deletions

View File

@ -1,3 +1,17 @@
2018-11-29
- 1.17.6
- Add failsafe: resume sending packets after some time
The change puts a 1-second limit on the amount of time the engine
will not send packets after some packets are delayed. This makes
the library robust in case the user does not unblock the engine
explicitly using lsquic_engine_send_unsent_packets() call.
- [BUGFIX] Handle corner cases in send controller when packets are
a) delayed or b) dropped during repackaging.
- [BUGFIX] Memory leak: destroy buffered packets during controller
cleanup.
2018-11-16
- 1.17.3
- [BUGFIX] Do not send STOP_WAITING frames when using Q044

View File

@ -25,7 +25,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 1
#define LSQUIC_MINOR_VERSION 17
#define LSQUIC_PATCH_VERSION 3
#define LSQUIC_PATCH_VERSION 6
/**
* Engine flags:

View File

@ -61,6 +61,8 @@
#define LSQUIC_LOGGER_MODULE LSQLM_ENGINE
#include "lsquic_logger.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/* The batch of outgoing packets grows and shrinks dynamically */
#define MAX_OUT_BATCH_SIZE 1024
@ -168,6 +170,7 @@ struct lsquic_engine
lsquic_time_t last_sent;
unsigned n_conns;
lsquic_time_t deadline;
lsquic_time_t resume_sending_at;
struct out_batch out_batch;
};
@ -1025,6 +1028,7 @@ send_batch (lsquic_engine_t *engine, struct conns_out_iter *conns_iter,
if (n_sent < (int) n_to_send)
{
engine->pub.enp_flags &= ~ENPUB_CAN_SEND;
engine->resume_sending_at = now + 1000000;
LSQ_DEBUG("cannot send packets");
EV_LOG_GENERIC_EVENT("cannot send packets");
}
@ -1272,6 +1276,15 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
TAILQ_INIT(&ticked_conns);
reset_deadline(engine, now);
if (!(engine->pub.enp_flags & ENPUB_CAN_SEND)
&& now > engine->resume_sending_at)
{
LSQ_NOTICE("failsafe activated: resume sending packets again after "
"timeout");
EV_LOG_GENERIC_EVENT("resume sending packets again after timeout");
engine->pub.enp_flags |= ENPUB_CAN_SEND;
}
i = 0;
while ((conn = next_conn(engine))
)
@ -1412,8 +1425,8 @@ lsquic_engine_quic_versions (const lsquic_engine_t *engine)
int
lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
{
const lsquic_time_t *next_time;
lsquic_time_t now;
const lsquic_time_t *next_attq_time;
lsquic_time_t now, next_time;
if (((engine->flags & ENG_PAST_DEADLINE)
&& lsquic_mh_count(&engine->conns_out))
@ -1423,12 +1436,24 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff)
return 1;
}
next_time = attq_next_time(engine->attq);
if (!next_time)
return 0;
next_attq_time = attq_next_time(engine->attq);
if (engine->pub.enp_flags & ENPUB_CAN_SEND)
{
if (next_attq_time)
next_time = *next_attq_time;
else
return 0;
}
else
{
if (next_attq_time)
next_time = MIN(*next_attq_time, engine->resume_sending_at);
else
next_time = engine->resume_sending_at;
}
now = lsquic_time_now();
*diff = (int) ((int64_t) *next_time - (int64_t) now);
*diff = (int) ((int64_t) next_time - (int64_t) now);
return 1;
}

View File

@ -94,6 +94,7 @@ typedef struct lsquic_packet_out
PO_IPv6 = (1 <<20), /* Set if pmi_allocate was passed is_ipv6=1,
* otherwise unset.
*/
PO_LIMITED = (1 <<21), /* Used to credit sc_next_limit if needed. */
} po_flags;
enum quic_ft_bit po_frame_types:16; /* Bitmask of QUIC_FRAME_* */
unsigned short po_data_sz; /* Number of usable bytes in data */

View File

@ -858,7 +858,8 @@ send_ctl_next_packno (lsquic_send_ctl_t *ctl)
void
lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
{
lsquic_packet_out_t *packet_out;
lsquic_packet_out_t *packet_out, *next;
unsigned n;
lsquic_senhist_cleanup(&ctl->sc_senhist);
while ((packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets)))
{
@ -881,6 +882,16 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
TAILQ_REMOVE(&ctl->sc_lost_packets, packet_out, po_next);
send_ctl_destroy_packet(ctl, packet_out);
}
for (n = 0; n < sizeof(ctl->sc_buffered_packets) /
sizeof(ctl->sc_buffered_packets[0]); ++n)
{
for (packet_out = TAILQ_FIRST(&ctl->sc_buffered_packets[n].bpq_packets);
packet_out; packet_out = next)
{
next = TAILQ_NEXT(packet_out, po_next);
send_ctl_destroy_packet(ctl, packet_out);
}
}
pacer_cleanup(&ctl->sc_pacer);
#if LSQUIC_SEND_STATS
LSQ_NOTICE("stats: n_total_sent: %u; n_resent: %u; n_delayed: %u",
@ -1083,6 +1094,7 @@ lsquic_packet_out_t *
lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
{
lsquic_packet_out_t *packet_out;
int dec_limit;
get_packet:
packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets);
@ -1093,10 +1105,12 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
!(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK)))
{
if (ctl->sc_next_limit)
--ctl->sc_next_limit;
dec_limit = 1;
else
return NULL;
}
else
dec_limit = 0;
send_ctl_sched_remove(ctl, packet_out);
if (packet_out->po_flags & PO_REPACKNO)
@ -1116,6 +1130,13 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
}
ctl->sc_bytes_out += packet_out_total_sz(packet_out);
if (dec_limit)
{
--ctl->sc_next_limit;
packet_out->po_flags |= PO_LIMITED;
}
else
packet_out->po_flags &= ~PO_LIMITED;
return packet_out;
}
@ -1126,6 +1147,8 @@ lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
{
send_ctl_sched_prepend(ctl, packet_out);
ctl->sc_bytes_out -= packet_out_total_sz(packet_out);
if (packet_out->po_flags & PO_LIMITED)
++ctl->sc_next_limit;
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
#if LSQUIC_SEND_STATS
++ctl->sc_stats.n_delayed;