mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
[FEATURE] Add support for Q042
This commit is contained in:
parent
4b332c36d1
commit
be4cfad023
11 changed files with 412 additions and 79 deletions
|
@ -1,5 +1,6 @@
|
||||||
2018-05-04
|
2018-05-04
|
||||||
|
|
||||||
|
- [FEATURE] Add support for Q042.
|
||||||
- Remove comment: MSPC is obsolete (no code changes)
|
- Remove comment: MSPC is obsolete (no code changes)
|
||||||
- Prog: use lsquic_str2ver() when processing -o version flag
|
- Prog: use lsquic_str2ver() when processing -o version flag
|
||||||
- Remove unused CTIM and SRBF transport parameters
|
- Remove unused CTIM and SRBF transport parameters
|
||||||
|
|
|
@ -76,19 +76,26 @@ enum lsquic_version
|
||||||
*/
|
*/
|
||||||
LSQVER_041,
|
LSQVER_041,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Q042. Receiving overlapping stream data is allowed.
|
||||||
|
*/
|
||||||
|
LSQVER_042,
|
||||||
|
|
||||||
N_LSQVER
|
N_LSQVER
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We currently support versions 35, 37, 38, 39, and 41.
|
* We currently support versions 35, 37, 38, 39, 41, and 42.
|
||||||
* @see lsquic_version
|
* @see lsquic_version
|
||||||
*/
|
*/
|
||||||
#define LSQUIC_SUPPORTED_VERSIONS ((1 << LSQVER_035) | (1 << LSQVER_037) | \
|
#define LSQUIC_SUPPORTED_VERSIONS ((1 << LSQVER_035) | (1 << LSQVER_037) | \
|
||||||
(1 << LSQVER_038) | (1 << LSQVER_039) | (1 << LSQVER_041))
|
(1 << LSQVER_038) | (1 << LSQVER_039) | (1 << LSQVER_041) | \
|
||||||
|
(1 << LSQVER_042))
|
||||||
|
|
||||||
#define LSQUIC_EXPERIMENTAL_VERSIONS ((1 << LSQVER_041))
|
#define LSQUIC_EXPERIMENTAL_VERSIONS ((1 << LSQVER_041))
|
||||||
|
|
||||||
#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_037) | (1 << LSQVER_038))
|
#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_037) | (1 << LSQVER_038) | \
|
||||||
|
(1 << LSQVER_042))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct lsquic_stream_if
|
* @struct lsquic_stream_if
|
||||||
|
|
|
@ -18,6 +18,7 @@ enum ins_frame
|
||||||
INS_FRAME_OK,
|
INS_FRAME_OK,
|
||||||
INS_FRAME_ERR,
|
INS_FRAME_ERR,
|
||||||
INS_FRAME_DUP,
|
INS_FRAME_DUP,
|
||||||
|
INS_FRAME_OVERLAP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,8 +30,14 @@ struct data_in_iface
|
||||||
int
|
int
|
||||||
(*di_empty) (struct data_in *);
|
(*di_empty) (struct data_in *);
|
||||||
|
|
||||||
/* The caller releases control of stream frame. Do not reference it
|
/* When INS_FRAME_OK, INS_FRAME_ERR, or INS_FRAME_DUP is returned, the
|
||||||
* after the call.
|
* caller releases control of stream frame. Do not reference it after
|
||||||
|
* the call.
|
||||||
|
*
|
||||||
|
* When INS_FRAME_OVERLAP is returned the caller has a choice to switch
|
||||||
|
* to implementation that supports overlaps and try to insert the frame
|
||||||
|
* again or to treat this as an error. Either way, the caller retains
|
||||||
|
* control of the frame.
|
||||||
*/
|
*/
|
||||||
enum ins_frame
|
enum ins_frame
|
||||||
(*di_insert_frame) (struct data_in *, struct stream_frame *,
|
(*di_insert_frame) (struct data_in *, struct stream_frame *,
|
||||||
|
@ -67,9 +74,15 @@ struct data_in
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* This implementation does not support overlapping frame and may return
|
||||||
|
* INS_FRAME_OVERLAP.
|
||||||
|
*/
|
||||||
struct data_in *
|
struct data_in *
|
||||||
data_in_nocopy_new (struct lsquic_conn_public *, uint32_t stream_id);
|
data_in_nocopy_new (struct lsquic_conn_public *, uint32_t stream_id);
|
||||||
|
|
||||||
|
/* This implementation supports overlapping frames and will never return
|
||||||
|
* INS_FRAME_OVERLAP.
|
||||||
|
*/
|
||||||
struct data_in *
|
struct data_in *
|
||||||
data_in_hash_new (struct lsquic_conn_public *, uint32_t stream_id,
|
data_in_hash_new (struct lsquic_conn_public *, uint32_t stream_id,
|
||||||
uint64_t byteage);
|
uint64_t byteage);
|
||||||
|
|
|
@ -355,7 +355,12 @@ data_in_hash_insert_data_frame (struct data_in *data_in,
|
||||||
unsigned size, nw;
|
unsigned size, nw;
|
||||||
|
|
||||||
if (data_frame->df_offset + data_frame->df_size < read_offset)
|
if (data_frame->df_offset + data_frame->df_size < read_offset)
|
||||||
return INS_FRAME_DUP;
|
{
|
||||||
|
if (data_frame->df_fin)
|
||||||
|
return INS_FRAME_ERR;
|
||||||
|
else
|
||||||
|
return INS_FRAME_DUP;
|
||||||
|
}
|
||||||
|
|
||||||
if ((hdi->hdi_flags & HDI_FIN) &&
|
if ((hdi->hdi_flags & HDI_FIN) &&
|
||||||
(
|
(
|
||||||
|
@ -427,6 +432,7 @@ hash_di_insert_frame (struct data_in *data_in,
|
||||||
enum ins_frame ins;
|
enum ins_frame ins;
|
||||||
|
|
||||||
ins = data_in_hash_insert_data_frame(data_in, data_frame, read_offset);
|
ins = data_in_hash_insert_data_frame(data_in, data_frame, read_offset);
|
||||||
|
assert(ins != INS_FRAME_OVERLAP);
|
||||||
lsquic_packet_in_put(hdi->hdi_conn_pub->mm, new_frame->packet_in);
|
lsquic_packet_in_put(hdi->hdi_conn_pub->mm, new_frame->packet_in);
|
||||||
lsquic_malo_put(new_frame);
|
lsquic_malo_put(new_frame);
|
||||||
return ins;
|
return ins;
|
||||||
|
|
|
@ -155,54 +155,110 @@ nocopy_di_destroy (struct data_in *data_in)
|
||||||
free(ncdi);
|
free(ncdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DF_OFF(frame) (frame)->data_frame.df_offset
|
||||||
|
#define DF_FIN(frame) (frame)->data_frame.df_fin
|
||||||
|
#define DF_SIZE(frame) (frame)->data_frame.df_size
|
||||||
|
#define DF_END(frame) (DF_OFF(frame) + DF_SIZE(frame))
|
||||||
|
|
||||||
#if 1
|
|
||||||
#define CHECK_ORDER(ncdi)
|
#if LSQUIC_EXTRA_CHECKS
|
||||||
#else
|
|
||||||
static int
|
static int
|
||||||
ordered (const struct nocopy_data_in *ncdi)
|
frame_list_is_sane (const struct nocopy_data_in *ncdi)
|
||||||
{
|
{
|
||||||
const stream_frame_t *frame;
|
const stream_frame_t *frame;
|
||||||
uint64_t off = 0;
|
uint64_t prev_off = 0, prev_end = 0;
|
||||||
int ordered = 1;
|
int ordered = 1, overlaps = 0;
|
||||||
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
||||||
{
|
{
|
||||||
ordered &= off <= frame->data_frame.df_offset;
|
ordered &= prev_off <= DF_OFF(frame);
|
||||||
off = frame->data_frame.df_offset;
|
overlaps |= prev_end > DF_OFF(frame);
|
||||||
|
prev_off = DF_OFF(frame);
|
||||||
|
prev_end = DF_END(frame);
|
||||||
}
|
}
|
||||||
return ordered;
|
return ordered && !overlaps;
|
||||||
}
|
}
|
||||||
#define CHECK_ORDER(ncdi) assert(ordered(ncdi))
|
#define CHECK_ORDER(ncdi) assert(frame_list_is_sane(ncdi))
|
||||||
|
#else
|
||||||
|
#define CHECK_ORDER(ncdi)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* To reduce the number of conditionals, logical operators have been replaced
|
/* When inserting a new frame into the frame list, there are four cases to
|
||||||
* with arithmetic operators. Return value is an integer in range [0, 3].
|
* consider:
|
||||||
* Bit 0 is set due to FIN in previous frame. If bit 1 is set, it means that
|
*
|
||||||
* it's a dup.
|
* I. New frame is the only frame in the list;
|
||||||
|
* II. New frame only has a neighbor to its left (previous frame);
|
||||||
|
* III. New frame only has a neighbor to its right (next frame); and
|
||||||
|
* IV. New frame has both left and right neighbors.
|
||||||
|
*
|
||||||
|
* I. New frame is the only frame in the list.
|
||||||
|
*
|
||||||
|
* A) If the read offset is larger than the end of the new frame and
|
||||||
|
* the new frame has a FIN, it is an ERROR.
|
||||||
|
*
|
||||||
|
* B) If the read offset is larger than the end of the new frame and
|
||||||
|
* the new frame does not have a FIN, it is a DUP.
|
||||||
|
*
|
||||||
|
* C) If the read offset is equal to the end of the new frame and
|
||||||
|
* the new frame has a FIN, it is an OVERLAP.
|
||||||
|
*
|
||||||
|
* D) If the read offset is equal to the end of the new frame and
|
||||||
|
* the new frame does not have a FIN, it is a DUP.
|
||||||
|
*
|
||||||
|
* II. New frame only has a neighbor to its left.
|
||||||
|
*
|
||||||
|
* - (A) and (B) apply.
|
||||||
|
*
|
||||||
|
* E) New frame could be the same as the previous frame: DUP.
|
||||||
|
*
|
||||||
|
* F) New frame has the same offset and size as previous frame, but
|
||||||
|
* previous frame has FIN and the new frame does not: DUP.
|
||||||
|
*
|
||||||
|
* G) New frame has the same offset and size as previous frame, but
|
||||||
|
* previous frame does not have a FIN and the new one does: OVERLAP.
|
||||||
|
*
|
||||||
|
* H) New frame could start inside previous frame: OVERLAP.
|
||||||
|
*
|
||||||
|
* III. New frame only has a neighbor to its right.
|
||||||
|
*
|
||||||
|
* - (A) and (B) apply.
|
||||||
|
*
|
||||||
|
* I) Right neighbor could start inside new frame: OVERLAP.
|
||||||
|
*
|
||||||
|
* IV. New frame has both left and right neighbors.
|
||||||
|
*
|
||||||
|
* - (A), (B), (E), (F), (G), (H), and (I) apply.
|
||||||
*/
|
*/
|
||||||
static int
|
|
||||||
|
|
||||||
|
static enum ins_frame
|
||||||
insert_frame (struct nocopy_data_in *ncdi, struct stream_frame *new_frame,
|
insert_frame (struct nocopy_data_in *ncdi, struct stream_frame *new_frame,
|
||||||
uint64_t read_offset, unsigned *p_n_frames)
|
uint64_t read_offset, unsigned *p_n_frames)
|
||||||
{
|
{
|
||||||
int ins;
|
|
||||||
unsigned count;
|
|
||||||
stream_frame_t *prev_frame, *next_frame;
|
stream_frame_t *prev_frame, *next_frame;
|
||||||
|
unsigned count;
|
||||||
|
|
||||||
|
if (read_offset > DF_END(new_frame))
|
||||||
|
{
|
||||||
|
if (DF_FIN(new_frame))
|
||||||
|
return INS_FRAME_ERR; /* Case (A) */
|
||||||
|
else
|
||||||
|
return INS_FRAME_DUP; /* Case (B) */
|
||||||
|
}
|
||||||
|
|
||||||
/* Find position in the list, going backwards. We go backwards because
|
/* Find position in the list, going backwards. We go backwards because
|
||||||
* that is the most likely scenario.
|
* that is the most likely scenario.
|
||||||
*/
|
*/
|
||||||
next_frame = TAILQ_LAST(&ncdi->ncdi_frames_in, stream_frames_tailq);
|
next_frame = TAILQ_LAST(&ncdi->ncdi_frames_in, stream_frames_tailq);
|
||||||
if (next_frame && new_frame->data_frame.df_offset < next_frame->data_frame.df_offset)
|
if (next_frame && DF_OFF(new_frame) < DF_OFF(next_frame))
|
||||||
{
|
{
|
||||||
count = 1;
|
count = 1;
|
||||||
prev_frame = TAILQ_PREV(next_frame, stream_frames_tailq, next_frame);
|
prev_frame = TAILQ_PREV(next_frame, stream_frames_tailq, next_frame);
|
||||||
for ( ; prev_frame &&
|
for ( ; prev_frame && DF_OFF(new_frame) < DF_OFF(next_frame);
|
||||||
new_frame->data_frame.df_offset < next_frame->data_frame.df_offset;
|
|
||||||
next_frame = prev_frame,
|
next_frame = prev_frame,
|
||||||
prev_frame = TAILQ_PREV(prev_frame, stream_frames_tailq, next_frame))
|
prev_frame = TAILQ_PREV(prev_frame, stream_frames_tailq, next_frame))
|
||||||
{
|
{
|
||||||
if (new_frame->data_frame.df_offset >= prev_frame->data_frame.df_offset)
|
if (DF_OFF(new_frame) >= DF_OFF(prev_frame))
|
||||||
break;
|
break;
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
@ -213,69 +269,74 @@ insert_frame (struct nocopy_data_in *ncdi, struct stream_frame *new_frame,
|
||||||
prev_frame = NULL;
|
prev_frame = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prev_frame && next_frame && new_frame->data_frame.df_offset >=
|
if (!prev_frame && next_frame && DF_OFF(new_frame) >= DF_OFF(next_frame))
|
||||||
next_frame->data_frame.df_offset)
|
|
||||||
{
|
{
|
||||||
prev_frame = next_frame;
|
prev_frame = next_frame;
|
||||||
next_frame = TAILQ_NEXT(next_frame, next_frame);
|
next_frame = TAILQ_NEXT(next_frame, next_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform checks */
|
const int select = !!prev_frame << 1 | !!next_frame;
|
||||||
if (prev_frame)
|
switch (select)
|
||||||
ins =
|
{
|
||||||
(((prev_frame->data_frame.df_offset == new_frame->data_frame.df_offset) &
|
default: /* No neighbors */
|
||||||
(prev_frame->data_frame.df_size == new_frame->data_frame.df_size) &
|
if (read_offset == DF_END(new_frame) && DF_SIZE(new_frame))
|
||||||
(prev_frame->data_frame.df_fin == new_frame->data_frame.df_fin)) << 1) /* Duplicate */
|
{
|
||||||
| prev_frame->data_frame.df_fin /* FIN in the middle or dup */
|
if (DF_FIN(new_frame))
|
||||||
| (prev_frame->data_frame.df_offset + prev_frame->data_frame.df_size
|
return INS_FRAME_OVERLAP; /* Case (C) */
|
||||||
> new_frame->data_frame.df_offset) /* Overlap */
|
else
|
||||||
;
|
return INS_FRAME_DUP; /* Case (D) */
|
||||||
else
|
}
|
||||||
ins = 0;
|
goto list_was_empty;
|
||||||
|
case 3: /* Both left and right neighbors */
|
||||||
if (next_frame)
|
case 2: /* Only left neighbor (prev_frame) */
|
||||||
ins |=
|
if (DF_OFF(prev_frame) == DF_OFF(new_frame)
|
||||||
(((next_frame->data_frame.df_offset == new_frame->data_frame.df_offset) &
|
&& DF_SIZE(prev_frame) == DF_SIZE(new_frame))
|
||||||
(next_frame->data_frame.df_size == new_frame->data_frame.df_size) &
|
{
|
||||||
(next_frame->data_frame.df_fin == new_frame->data_frame.df_fin)) << 1) /* Duplicate */
|
if (!DF_FIN(prev_frame) && DF_FIN(new_frame))
|
||||||
| (new_frame->data_frame.df_offset < read_offset) << 1 /* Duplicate */
|
return INS_FRAME_OVERLAP; /* Case (G) */
|
||||||
| new_frame->data_frame.df_fin /* FIN in the middle or dup */
|
else
|
||||||
| (new_frame->data_frame.df_offset + new_frame->data_frame.df_size
|
return INS_FRAME_DUP; /* Cases (E) and (F) */
|
||||||
> next_frame->data_frame.df_offset) /* Overlap */
|
}
|
||||||
;
|
if (DF_END(prev_frame) > DF_OFF(new_frame))
|
||||||
else
|
return INS_FRAME_OVERLAP; /* Case (H) */
|
||||||
ins |=
|
if (select == 2)
|
||||||
(new_frame->data_frame.df_offset < read_offset) << 1 /* Duplicate */
|
{
|
||||||
;
|
if (DF_FIN(prev_frame))
|
||||||
|
return INS_FRAME_ERR;
|
||||||
if (ins)
|
goto have_prev;
|
||||||
return ins;
|
}
|
||||||
|
/* Fall-through */
|
||||||
|
case 1: /* Only right neighbor (next_frame) */
|
||||||
|
if (DF_END(new_frame) > DF_OFF(next_frame))
|
||||||
|
return INS_FRAME_OVERLAP; /* Case (I) */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (prev_frame)
|
if (prev_frame)
|
||||||
{
|
{
|
||||||
|
have_prev:
|
||||||
TAILQ_INSERT_AFTER(&ncdi->ncdi_frames_in, prev_frame, new_frame, next_frame);
|
TAILQ_INSERT_AFTER(&ncdi->ncdi_frames_in, prev_frame, new_frame, next_frame);
|
||||||
ncdi->ncdi_n_holes += prev_frame->data_frame.df_offset +
|
ncdi->ncdi_n_holes += DF_END(prev_frame) != DF_OFF(new_frame);
|
||||||
prev_frame->data_frame.df_size != new_frame->data_frame.df_offset;
|
|
||||||
if (next_frame)
|
if (next_frame)
|
||||||
{
|
{
|
||||||
ncdi->ncdi_n_holes += new_frame->data_frame.df_offset +
|
ncdi->ncdi_n_holes += DF_END(new_frame) != DF_OFF(next_frame);
|
||||||
new_frame->data_frame.df_size != next_frame->data_frame.df_offset;
|
|
||||||
--ncdi->ncdi_n_holes;
|
--ncdi->ncdi_n_holes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ncdi->ncdi_n_holes += next_frame && new_frame->data_frame.df_offset +
|
ncdi->ncdi_n_holes += next_frame
|
||||||
new_frame->data_frame.df_size != next_frame->data_frame.df_offset;
|
&& DF_END(new_frame) != DF_OFF(next_frame);
|
||||||
|
list_was_empty:
|
||||||
TAILQ_INSERT_HEAD(&ncdi->ncdi_frames_in, new_frame, next_frame);
|
TAILQ_INSERT_HEAD(&ncdi->ncdi_frames_in, new_frame, next_frame);
|
||||||
}
|
}
|
||||||
CHECK_ORDER(ncdi);
|
CHECK_ORDER(ncdi);
|
||||||
|
|
||||||
++ncdi->ncdi_n_frames;
|
++ncdi->ncdi_n_frames;
|
||||||
ncdi->ncdi_byteage += new_frame->data_frame.df_size;
|
ncdi->ncdi_byteage += DF_SIZE(new_frame);
|
||||||
*p_n_frames = count;
|
*p_n_frames = count;
|
||||||
|
|
||||||
return 0;
|
return INS_FRAME_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,27 +382,26 @@ nocopy_di_insert_frame (struct data_in *data_in,
|
||||||
{
|
{
|
||||||
struct nocopy_data_in *const ncdi = NCDI_PTR(data_in);
|
struct nocopy_data_in *const ncdi = NCDI_PTR(data_in);
|
||||||
unsigned count;
|
unsigned count;
|
||||||
int ins;
|
enum ins_frame ins;
|
||||||
|
|
||||||
assert(0 == (new_frame->data_frame.df_fin & ~1));
|
assert(0 == (new_frame->data_frame.df_fin & ~1));
|
||||||
ins = insert_frame(ncdi, new_frame, read_offset, &count);
|
ins = insert_frame(ncdi, new_frame, read_offset, &count);
|
||||||
switch (ins)
|
switch (ins)
|
||||||
{
|
{
|
||||||
case 0:
|
case INS_FRAME_OK:
|
||||||
if (check_efficiency(ncdi, count))
|
if (check_efficiency(ncdi, count))
|
||||||
set_eff_alert(ncdi);
|
set_eff_alert(ncdi);
|
||||||
return INS_FRAME_OK;
|
break;
|
||||||
case 2:
|
case INS_FRAME_DUP:
|
||||||
case 3:
|
case INS_FRAME_ERR:
|
||||||
lsquic_packet_in_put(ncdi->ncdi_conn_pub->mm, new_frame->packet_in);
|
lsquic_packet_in_put(ncdi->ncdi_conn_pub->mm, new_frame->packet_in);
|
||||||
lsquic_malo_put(new_frame);
|
lsquic_malo_put(new_frame);
|
||||||
return INS_FRAME_DUP;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(1 == ins);
|
break;
|
||||||
lsquic_packet_in_put(ncdi->ncdi_conn_pub->mm, new_frame->packet_in);
|
|
||||||
lsquic_malo_put(new_frame);
|
|
||||||
return INS_FRAME_ERR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -866,7 +866,12 @@ static lsquic_stream_t *
|
||||||
new_stream_ext (struct full_conn *conn, uint32_t stream_id, int if_idx,
|
new_stream_ext (struct full_conn *conn, uint32_t stream_id, int if_idx,
|
||||||
enum stream_ctor_flags stream_ctor_flags)
|
enum stream_ctor_flags stream_ctor_flags)
|
||||||
{
|
{
|
||||||
lsquic_stream_t *stream = lsquic_stream_new_ext(stream_id, &conn->fc_pub,
|
struct lsquic_stream *stream;
|
||||||
|
|
||||||
|
if (conn->fc_conn.cn_version >= LSQVER_042)
|
||||||
|
stream_ctor_flags |= SCF_ALLOW_OVERLAP;
|
||||||
|
|
||||||
|
stream = lsquic_stream_new_ext(stream_id, &conn->fc_pub,
|
||||||
conn->fc_stream_ifs[if_idx].stream_if,
|
conn->fc_stream_ifs[if_idx].stream_if,
|
||||||
conn->fc_stream_ifs[if_idx].stream_if_ctx, conn->fc_settings->es_sfcw,
|
conn->fc_stream_ifs[if_idx].stream_if_ctx, conn->fc_settings->es_sfcw,
|
||||||
conn->fc_cfg.max_stream_send, stream_ctor_flags);
|
conn->fc_cfg.max_stream_send, stream_ctor_flags);
|
||||||
|
|
|
@ -167,7 +167,7 @@ extern const struct parse_funcs lsquic_parse_funcs_gquic_Q041;
|
||||||
((1 << (ver)) & ((1 << LSQVER_035) | \
|
((1 << (ver)) & ((1 << LSQVER_035) | \
|
||||||
(1 << LSQVER_037) | (1 << LSQVER_038))) \
|
(1 << LSQVER_037) | (1 << LSQVER_038))) \
|
||||||
? &lsquic_parse_funcs_gquic_le : \
|
? &lsquic_parse_funcs_gquic_le : \
|
||||||
((1 << (ver)) & (1 << LSQVER_039)) \
|
((1 << (ver)) & ((1 << LSQVER_039) | (1 << LSQVER_042))) \
|
||||||
? &lsquic_parse_funcs_gquic_Q039 \
|
? &lsquic_parse_funcs_gquic_Q039 \
|
||||||
: &lsquic_parse_funcs_gquic_Q041)
|
: &lsquic_parse_funcs_gquic_Q041)
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,8 @@ lsquic_stream_new_ext (uint32_t id, struct lsquic_conn_public *conn_pub,
|
||||||
lsquic_stream_call_on_new(stream);
|
lsquic_stream_call_on_new(stream);
|
||||||
if (ctor_flags & SCF_DISP_RW_ONCE)
|
if (ctor_flags & SCF_DISP_RW_ONCE)
|
||||||
stream->stream_flags |= STREAM_RW_ONCE;
|
stream->stream_flags |= STREAM_RW_ONCE;
|
||||||
|
if (ctor_flags & SCF_ALLOW_OVERLAP)
|
||||||
|
stream->stream_flags |= STREAM_ALLOW_OVERLAP;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,6 +500,7 @@ lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
got_next_offset = frame->data_frame.df_offset == stream->read_offset;
|
got_next_offset = frame->data_frame.df_offset == stream->read_offset;
|
||||||
|
insert_frame:
|
||||||
ins_frame = stream->data_in->di_if->di_insert_frame(stream->data_in, frame, stream->read_offset);
|
ins_frame = stream->data_in->di_if->di_insert_frame(stream->data_in, frame, stream->read_offset);
|
||||||
if (INS_FRAME_OK == ins_frame)
|
if (INS_FRAME_OK == ins_frame)
|
||||||
{
|
{
|
||||||
|
@ -533,6 +536,23 @@ lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (INS_FRAME_OVERLAP == ins_frame)
|
||||||
|
{
|
||||||
|
if (stream->stream_flags & STREAM_ALLOW_OVERLAP)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("overlap: switching DATA IN implementation");
|
||||||
|
stream->data_in = stream->data_in->di_if->di_switch_impl(
|
||||||
|
stream->data_in, stream->read_offset);
|
||||||
|
if (stream->data_in)
|
||||||
|
goto insert_frame;
|
||||||
|
stream->data_in = data_in_error_new();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LSQ_DEBUG("overlap not supported");
|
||||||
|
lsquic_packet_in_put(stream->conn_pub->mm, frame->packet_in);
|
||||||
|
lsquic_malo_put(frame);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(INS_FRAME_ERR == ins_frame);
|
assert(INS_FRAME_ERR == ins_frame);
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct lsquic_stream
|
||||||
STREAM_ONNEW_DONE = (1 <<26), /* on_new_stream has been called */
|
STREAM_ONNEW_DONE = (1 <<26), /* on_new_stream has been called */
|
||||||
STREAM_AUTOSWITCH = (1 <<27),
|
STREAM_AUTOSWITCH = (1 <<27),
|
||||||
STREAM_RW_ONCE = (1 <<28), /* When set, read/write events are dispatched once per call */
|
STREAM_RW_ONCE = (1 <<28), /* When set, read/write events are dispatched once per call */
|
||||||
|
STREAM_ALLOW_OVERLAP= (1 <<29),
|
||||||
} stream_flags;
|
} stream_flags;
|
||||||
|
|
||||||
/* There are more than one reason that a stream may be put onto
|
/* There are more than one reason that a stream may be put onto
|
||||||
|
@ -144,6 +145,7 @@ enum stream_ctor_flags
|
||||||
* performance.
|
* performance.
|
||||||
*/
|
*/
|
||||||
SCF_DISP_RW_ONCE = (1 << 3),
|
SCF_DISP_RW_ONCE = (1 << 3),
|
||||||
|
SCF_ALLOW_OVERLAP = (1 << 4), /* Allow STREAM frames to overlap */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
|
||||||
[LSQVER_038] = { 'Q', '0', '3', '8', },
|
[LSQVER_038] = { 'Q', '0', '3', '8', },
|
||||||
[LSQVER_039] = { 'Q', '0', '3', '9', },
|
[LSQVER_039] = { 'Q', '0', '3', '9', },
|
||||||
[LSQVER_041] = { 'Q', '0', '4', '1', },
|
[LSQVER_041] = { 'Q', '0', '4', '1', },
|
||||||
|
[LSQVER_042] = { 'Q', '0', '4', '2', },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
|
||||||
[LSQVER_038] = "Q038",
|
[LSQVER_038] = "Q038",
|
||||||
[LSQVER_039] = "Q039",
|
[LSQVER_039] = "Q039",
|
||||||
[LSQVER_041] = "Q041",
|
[LSQVER_041] = "Q041",
|
||||||
|
[LSQVER_042] = "Q042",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1407,6 +1407,221 @@ test_reading_from_stream2 (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This tests stream overlap support */
|
||||||
|
static void
|
||||||
|
test_overlaps (void)
|
||||||
|
{
|
||||||
|
struct test_objs tobjs;
|
||||||
|
char buf[0x1000];
|
||||||
|
lsquic_stream_t *stream;
|
||||||
|
stream_frame_t *frame;
|
||||||
|
int s;
|
||||||
|
const char data[] = "1234567890";
|
||||||
|
|
||||||
|
struct frame_spec
|
||||||
|
{
|
||||||
|
unsigned off;
|
||||||
|
unsigned len;
|
||||||
|
signed char fin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frame_step
|
||||||
|
{
|
||||||
|
struct frame_spec frame_spec;
|
||||||
|
int insert_res; /* Expected result */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct overlap_test
|
||||||
|
{
|
||||||
|
int line; /* Test identifier */
|
||||||
|
struct frame_step steps[10]; /* Sequence of steps */
|
||||||
|
unsigned n_steps;
|
||||||
|
const unsigned char buf[20]; /* Expected result of read */
|
||||||
|
ssize_t sz; /* Expected size of first read */
|
||||||
|
ssize_t second_read; /* Expected size of second read:
|
||||||
|
* 0 means EOS (FIN).
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct overlap_test tests[] =
|
||||||
|
{
|
||||||
|
|
||||||
|
{
|
||||||
|
.line = __LINE__,
|
||||||
|
.steps =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 0, .len = 10, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.n_steps = 1,
|
||||||
|
.buf = "0123456789",
|
||||||
|
.sz = 10,
|
||||||
|
.second_read = -1,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.line = __LINE__,
|
||||||
|
.steps =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 0, .len = 5, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 0, .len = 10, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.n_steps = 2,
|
||||||
|
.buf = "0123456789",
|
||||||
|
.sz = 10,
|
||||||
|
.second_read = -1,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.line = __LINE__,
|
||||||
|
.steps =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 1, .len = 9, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 1, .len = 9, .fin = 1, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 0, .len = 2, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 2, .len = 6, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.n_steps = 4,
|
||||||
|
.buf = "0123456789",
|
||||||
|
.sz = 10,
|
||||||
|
.second_read = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.line = __LINE__,
|
||||||
|
.steps =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 1, .len = 9, .fin = 1, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.frame_spec = { .off = 0, .len = 2, .fin = 0, },
|
||||||
|
.insert_res = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.n_steps = 2,
|
||||||
|
.buf = "0123456789",
|
||||||
|
.sz = 10,
|
||||||
|
.second_read = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.line = __LINE__,
|
||||||
|
.steps =
|
||||||
|
{
|
||||||
|
{ .frame_spec = { .off = 1, .len = 6, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 2, .len = 1, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 8, .len = 2, .fin = 1, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 3, .len = 2, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 4, .len = 1, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 5, .len = 2, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 6, .len = 1, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 7, .len = 3, .fin = 0, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 9, .len = 1, .fin = 1, }, .insert_res = 0, },
|
||||||
|
{ .frame_spec = { .off = 0, .len = 2, .fin = 0, }, .insert_res = 0, },
|
||||||
|
},
|
||||||
|
.n_steps = 10,
|
||||||
|
.buf = "0123456789",
|
||||||
|
.sz = 10,
|
||||||
|
.second_read = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
init_test_objs(&tobjs, 0x4000, 0x4000);
|
||||||
|
assert(!(tobjs.ctor_flags & SCF_ALLOW_OVERLAP)); /* Self-check */
|
||||||
|
tobjs.ctor_flags |= SCF_ALLOW_OVERLAP;
|
||||||
|
|
||||||
|
const struct overlap_test *test;
|
||||||
|
for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
|
||||||
|
{
|
||||||
|
LSQ_NOTICE("executing stream overlap test, line %d", test->line);
|
||||||
|
stream = new_stream(&tobjs, test->line);
|
||||||
|
|
||||||
|
const struct frame_step *step;
|
||||||
|
for (step = test->steps; step < test->steps + test->n_steps; ++step)
|
||||||
|
{
|
||||||
|
frame = new_frame_in_ext(&tobjs, step->frame_spec.off,
|
||||||
|
step->frame_spec.len, step->frame_spec.fin,
|
||||||
|
&data[step->frame_spec.off]);
|
||||||
|
s = lsquic_stream_frame_in(stream, frame);
|
||||||
|
assert(s == step->insert_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread == test->sz);
|
||||||
|
assert(0 == memcmp(data, buf, test->sz));
|
||||||
|
nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread == test->second_read);
|
||||||
|
if (nread < 0)
|
||||||
|
assert(EWOULDBLOCK == errno);
|
||||||
|
|
||||||
|
lsquic_stream_destroy(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LSQ_NOTICE("Special test on line %d", __LINE__);
|
||||||
|
stream = new_stream(&tobjs, __LINE__);
|
||||||
|
frame = new_frame_in_ext(&tobjs, 0, 5, 0, &data[0]);
|
||||||
|
s = lsquic_stream_frame_in(stream, frame);
|
||||||
|
assert(0 == s);
|
||||||
|
ssize_t nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread == 5);
|
||||||
|
assert(0 == memcmp(data, buf, 5));
|
||||||
|
nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread < 0);
|
||||||
|
assert(EWOULDBLOCK == errno);
|
||||||
|
/* Test that a frame with FIN that ends before the read offset
|
||||||
|
* results in an error.
|
||||||
|
*/
|
||||||
|
frame = new_frame_in_ext(&tobjs, 0, 3, 1, &data[0]);
|
||||||
|
s = lsquic_stream_frame_in(stream, frame);
|
||||||
|
assert(s < 0);
|
||||||
|
/* This frame should be a DUP: the next read should still return -1.
|
||||||
|
*/
|
||||||
|
frame = new_frame_in_ext(&tobjs, 3, 2, 0, &data[3]);
|
||||||
|
s = lsquic_stream_frame_in(stream, frame);
|
||||||
|
assert(s == 0);
|
||||||
|
nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread < 0);
|
||||||
|
assert(EWOULDBLOCK == errno);
|
||||||
|
/* This frame should be an overlap: FIN should register and
|
||||||
|
* the next read should return 0.
|
||||||
|
*/
|
||||||
|
frame = new_frame_in_ext(&tobjs, 0, 5, 1, &data[0]);
|
||||||
|
s = lsquic_stream_frame_in(stream, frame);
|
||||||
|
assert(s == 0);
|
||||||
|
nread = lsquic_stream_read(stream, buf, sizeof(buf));
|
||||||
|
assert(nread == 0);
|
||||||
|
lsquic_stream_destroy(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
tobjs.ctor_flags &= ~SCF_ALLOW_OVERLAP;
|
||||||
|
deinit_test_objs(&tobjs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_writing_to_stream_schedule_stream_packets_immediately (void)
|
test_writing_to_stream_schedule_stream_packets_immediately (void)
|
||||||
{
|
{
|
||||||
|
@ -2215,6 +2430,7 @@ main (int argc, char **argv)
|
||||||
stream_ctor_flags |= SCF_USE_DI_HASH;
|
stream_ctor_flags |= SCF_USE_DI_HASH;
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
|
lsquic_log_to_fstream(stderr, 0);
|
||||||
lsquic_logger_lopt(optarg);
|
lsquic_logger_lopt(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2231,6 +2447,7 @@ main (int argc, char **argv)
|
||||||
test_forced_flush_when_conn_blocked();
|
test_forced_flush_when_conn_blocked();
|
||||||
test_blocked_flags();
|
test_blocked_flags();
|
||||||
test_reading_from_stream2();
|
test_reading_from_stream2();
|
||||||
|
test_overlaps();
|
||||||
|
|
||||||
{
|
{
|
||||||
int idx[6];
|
int idx[6];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue