mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Latest changes
- [API Change] lsquic_engine_connect() returns pointer to the connection object. - [API Change] Add lsquic_conn_get_engine() to get engine object from connection object. - [API Change] Add lsquic_conn_status() to query connection status. - [API Change] Add add lsquic_conn_set_ctx(). - [API Change] Add new timestamp format, e.g. 2017-03-21 13:43:46.671345 - [OPTIMIZATION] Process handshake STREAM frames as soon as packet arrives. - [OPTIMIZATION] Do not compile expensive send controller sanity check by default. - [OPTIMIZATION] Add fast path to gquic_be_gen_reg_pkt_header. - [OPTIMIZATION] Only make squeeze function call if necessary. - [OPTIMIZATION] Speed up Q039 ACK frame parsing. - [OPTIMIZATION] Fit most used elements of packet_out into first 64 bytes. - [OPTIMIZATION] Keep track of scheduled bytes instead of calculating. - [OPTIMIZATION] Prefetch next unacked packet when processing ACK. - [OPTIMIZATION] Leverage fact that ACK ranges and unacked list are. ordered. - [OPTIMIZATION] Reduce function pointer use for STREAM frame generation - Fix: reset incoming streams that arrive after we send GOAWAY. - Fix: delay client on_new_conn() call until connection is fully set up. - Fixes to buffered packets logic: splitting, STREAM frame elision. - Fix: do not dispatch on_write callback if no packets are available. - Fix WINDOW_UPDATE send and resend logic. - Fix STREAM frame extension code. - Fix: Drop unflushed data when stream is reset. - Switch to tracking CWND using bytes rather than packets. - Fix TCP friendly adjustment in cubic. - Fix: do not generate invalid STOP_WAITING frames during high packet loss. - Pacer fixes.
This commit is contained in:
parent
7edaabaafe
commit
bfc7bfd842
46 changed files with 1140 additions and 547 deletions
40
CHANGELOG
40
CHANGELOG
|
@ -1,3 +1,43 @@
|
||||||
|
2018-02-26
|
||||||
|
- [API Change] lsquic_engine_connect() returns pointer to the connection
|
||||||
|
object.
|
||||||
|
- [API Change] Add lsquic_conn_get_engine() to get engine object from
|
||||||
|
connection object.
|
||||||
|
- [API Change] Add lsquic_conn_status() to query connection status.
|
||||||
|
- [API Change] Add add lsquic_conn_set_ctx().
|
||||||
|
- [API Change] Add new timestamp format, e.g. 2017-03-21 13:43:46.671345
|
||||||
|
- [OPTIMIZATION] Process handshake STREAM frames as soon as packet
|
||||||
|
arrives.
|
||||||
|
- [OPTIMIZATION] Do not compile expensive send controller sanity check
|
||||||
|
by default.
|
||||||
|
- [OPTIMIZATION] Add fast path to gquic_be_gen_reg_pkt_header.
|
||||||
|
- [OPTIMIZATION] Only make squeeze function call if necessary.
|
||||||
|
- [OPTIMIZATION] Speed up Q039 ACK frame parsing.
|
||||||
|
- [OPTIMIZATION] Fit most used elements of packet_out into first 64 bytes.
|
||||||
|
- [OPTIMIZATION] Keep track of scheduled bytes instead of calculating.
|
||||||
|
- [OPTIMIZATION] Prefetch next unacked packet when processing ACK.
|
||||||
|
- [OPTIMIZATION] Leverage fact that ACK ranges and unacked list are.
|
||||||
|
ordered.
|
||||||
|
- [OPTIMIZATION] Reduce function pointer use for STREAM frame generation
|
||||||
|
- Fix: reset incoming streams that arrive after we send GOAWAY.
|
||||||
|
- Fix: delay client on_new_conn() call until connection is fully set up.
|
||||||
|
- Fixes to buffered packets logic: splitting, STREAM frame elision.
|
||||||
|
- Fix: do not dispatch on_write callback if no packets are available.
|
||||||
|
- Fix WINDOW_UPDATE send and resend logic.
|
||||||
|
- Fix STREAM frame extension code.
|
||||||
|
- Fix: Drop unflushed data when stream is reset.
|
||||||
|
- Switch to tracking CWND using bytes rather than packets.
|
||||||
|
- Fix TCP friendly adjustment in cubic.
|
||||||
|
- Fix: do not generate invalid STOP_WAITING frames during high packet
|
||||||
|
loss.
|
||||||
|
- Pacer fixes.
|
||||||
|
|
||||||
|
2017-12-18
|
||||||
|
|
||||||
|
- Fix: better follow cubic curve after idle period
|
||||||
|
- Fix: add missing parts to outgoing packet splitting code
|
||||||
|
- Fix: compilation using gcc 4.8.4
|
||||||
|
|
||||||
2017-10-31
|
2017-10-31
|
||||||
|
|
||||||
- Add APIs.txt -- describes LSQUIC APIs
|
- Add APIs.txt -- describes LSQUIC APIs
|
||||||
|
|
|
@ -91,13 +91,7 @@ target_link_libraries(http_client lsquic event pthread libssl.a libcrypto.a ${FI
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
IF(DEVEL_MODE EQUAL 1)
|
add_subdirectory(test)
|
||||||
# Our test framework relies on assertions, only compile if assertions are
|
|
||||||
# enabled.
|
|
||||||
#
|
|
||||||
add_subdirectory(test)
|
|
||||||
enable_testing()
|
|
||||||
ENDIF()
|
|
||||||
|
|
||||||
|
|
||||||
ADD_CUSTOM_TARGET(docs doxygen dox.cfg)
|
ADD_CUSTOM_TARGET(docs doxygen dox.cfg)
|
||||||
|
|
20
EXAMPLES.txt
20
EXAMPLES.txt
|
@ -81,15 +81,6 @@ lsquic_engine_settings.
|
||||||
Control LSQUIC Behavior via Environment Variables
|
Control LSQUIC Behavior via Environment Variables
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
LSQUIC_CUBIC_SHIFT_EPOCH
|
|
||||||
|
|
||||||
This environment variable determines whether cubic epoch is shifted
|
|
||||||
when sender is application-limited.
|
|
||||||
|
|
||||||
This is a leftover from the time when application-limited behavior was
|
|
||||||
implemented and is only available in debug builds. By default, the
|
|
||||||
epoch is shifted.
|
|
||||||
|
|
||||||
LSQUIC_PACER_INTERTICK
|
LSQUIC_PACER_INTERTICK
|
||||||
|
|
||||||
Number of microsecods to use as constant intertick time in lieu of the
|
Number of microsecods to use as constant intertick time in lieu of the
|
||||||
|
@ -97,6 +88,12 @@ LSQUIC_PACER_INTERTICK
|
||||||
|
|
||||||
Only available in debug builds.
|
Only available in debug builds.
|
||||||
|
|
||||||
|
LSQUIC_CUBIC_SAMPLING_RATE
|
||||||
|
|
||||||
|
Number of microseconds between times CWND is logged at info level.
|
||||||
|
|
||||||
|
Only available in debug builds.
|
||||||
|
|
||||||
Control Network-Related Stuff
|
Control Network-Related Stuff
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
@ -136,3 +133,8 @@ More Compilation Options
|
||||||
-DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_WARN
|
-DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_WARN
|
||||||
|
|
||||||
If you want to go even faster: compile out some log levels entirely.
|
If you want to go even faster: compile out some log levels entirely.
|
||||||
|
|
||||||
|
-DLSQUIC_EXTRA_CHECKS=1
|
||||||
|
|
||||||
|
Add relatively expensive run-time sanity checks
|
||||||
|
|
||||||
|
|
|
@ -476,10 +476,10 @@ lsquic_engine_new (unsigned lsquic_engine_flags,
|
||||||
* If `max_packet_size' is set to zero, it is inferred based on `peer_sa':
|
* If `max_packet_size' is set to zero, it is inferred based on `peer_sa':
|
||||||
* 1350 for IPv6 and 1370 for IPv4.
|
* 1350 for IPv6 and 1370 for IPv4.
|
||||||
*/
|
*/
|
||||||
int
|
lsquic_conn_t *
|
||||||
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *peer_sa,
|
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *peer_sa,
|
||||||
void *peer_ctx, const char *hostname,
|
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||||
unsigned short max_packet_size);
|
const char *hostname, unsigned short max_packet_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass incoming packet to the QUIC engine. This function can be called
|
* Pass incoming packet to the QUIC engine. This function can be called
|
||||||
|
@ -734,6 +734,10 @@ lsquic_conn_get_stream_by_id (lsquic_conn_t *c, uint32_t stream_id);
|
||||||
lsquic_cid_t
|
lsquic_cid_t
|
||||||
lsquic_conn_id (const lsquic_conn_t *c);
|
lsquic_conn_id (const lsquic_conn_t *c);
|
||||||
|
|
||||||
|
/** Get pointer to the engine */
|
||||||
|
lsquic_engine_t *
|
||||||
|
lsquic_conn_get_engine (lsquic_conn_t *c);
|
||||||
|
|
||||||
int lsquic_conn_get_sockaddr(const lsquic_conn_t *c,
|
int lsquic_conn_get_sockaddr(const lsquic_conn_t *c,
|
||||||
const struct sockaddr **local, const struct sockaddr **peer);
|
const struct sockaddr **local, const struct sockaddr **peer);
|
||||||
|
|
||||||
|
@ -777,6 +781,12 @@ enum lsquic_logger_timestamp_style {
|
||||||
*/
|
*/
|
||||||
LLTS_HHMMSSUS,
|
LLTS_HHMMSSUS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date and time using microsecond resolution,
|
||||||
|
* e.g: 2017-03-21 13:43:46.671123
|
||||||
|
*/
|
||||||
|
LLTS_YYYYMMDD_HHMMSSUS,
|
||||||
|
|
||||||
N_LLTS
|
N_LLTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -863,6 +873,11 @@ lsquic_str2ver (const char *str, size_t len);
|
||||||
lsquic_conn_ctx_t *
|
lsquic_conn_ctx_t *
|
||||||
lsquic_conn_get_ctx (const lsquic_conn_t *c);
|
lsquic_conn_get_ctx (const lsquic_conn_t *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set user-supplied context associated with the connection.
|
||||||
|
*/
|
||||||
|
void lsquic_conn_set_ctx (lsquic_conn_t *c, lsquic_conn_ctx_t *h);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get peer context associated with the connection.
|
* Get peer context associated with the connection.
|
||||||
*/
|
*/
|
||||||
|
@ -890,6 +905,25 @@ lsquic_engine_earliest_adv_tick (lsquic_engine_t *engine, int *diff);
|
||||||
unsigned
|
unsigned
|
||||||
lsquic_engine_count_attq (lsquic_engine_t *engine, int from_now);
|
lsquic_engine_count_attq (lsquic_engine_t *engine, int from_now);
|
||||||
|
|
||||||
|
enum LSQUIC_CONN_STATUS
|
||||||
|
{
|
||||||
|
LSCONN_ST_HSK_IN_PROGRESS,
|
||||||
|
LSCONN_ST_CONNECTED,
|
||||||
|
LSCONN_ST_HSK_FAILURE,
|
||||||
|
LSCONN_ST_GOING_AWAY,
|
||||||
|
LSCONN_ST_TIMED_OUT,
|
||||||
|
/* If es_honor_prst is not set, the connection will never get public
|
||||||
|
* reset packets and this flag will not be set.
|
||||||
|
*/
|
||||||
|
LSCONN_ST_RESET,
|
||||||
|
LSCONN_ST_USER_ABORTED,
|
||||||
|
LSCONN_ST_ERROR,
|
||||||
|
LSCONN_ST_CLOSED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LSQUIC_CONN_STATUS
|
||||||
|
lsquic_conn_status (lsquic_conn_t *, char *errbuf, size_t bufsz);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,6 +95,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
||||||
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
||||||
c_hsk->buf_in = NULL;
|
c_hsk->buf_in = NULL;
|
||||||
lsquic_stream_wantread(stream, 0);
|
lsquic_stream_wantread(stream, 0);
|
||||||
|
c_hsk->lconn->cn_if->ci_handshake_failed(c_hsk->lconn);
|
||||||
lsquic_conn_close(c_hsk->lconn);
|
lsquic_conn_close(c_hsk->lconn);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -104,8 +105,8 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
||||||
lsquic_stream_wantread(stream, 0);
|
lsquic_stream_wantread(stream, 0);
|
||||||
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("handshake is complete, inform connection");
|
LSQ_DEBUG("handshake is successful, inform connection");
|
||||||
c_hsk->lconn->cn_if->ci_handshake_done(c_hsk->lconn);
|
c_hsk->lconn->cn_if->ci_handshake_ok(c_hsk->lconn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -118,6 +119,10 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
||||||
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
|
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
|
||||||
case DATA_FORMAT_ERROR:
|
case DATA_FORMAT_ERROR:
|
||||||
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
|
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
|
||||||
|
c_hsk->buf_in = NULL;
|
||||||
|
lsquic_stream_wantread(stream, 0);
|
||||||
|
c_hsk->lconn->cn_if->ci_handshake_failed(c_hsk->lconn);
|
||||||
|
lsquic_conn_close(c_hsk->lconn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ enum lsquic_conn_flags {
|
||||||
LSCONN_ATTQ = (1 <<19),
|
LSCONN_ATTQ = (1 <<19),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TICK_BIT_PROGRESS 3
|
#define TICK_BIT_PROGRESS 2
|
||||||
|
|
||||||
/* A connection may have things to send and be closed at the same time.
|
/* A connection may have things to send and be closed at the same time.
|
||||||
*/
|
*/
|
||||||
|
@ -72,7 +72,10 @@ struct conn_iface
|
||||||
(*ci_packet_not_sent) (struct lsquic_conn *, struct lsquic_packet_out *);
|
(*ci_packet_not_sent) (struct lsquic_conn *, struct lsquic_packet_out *);
|
||||||
|
|
||||||
void
|
void
|
||||||
(*ci_handshake_done) (struct lsquic_conn *);
|
(*ci_handshake_ok) (struct lsquic_conn *);
|
||||||
|
|
||||||
|
void
|
||||||
|
(*ci_handshake_failed) (struct lsquic_conn *);
|
||||||
|
|
||||||
int
|
int
|
||||||
(*ci_user_wants_read) (struct lsquic_conn *);
|
(*ci_user_wants_read) (struct lsquic_conn *);
|
||||||
|
|
|
@ -29,24 +29,24 @@ static void
|
||||||
cubic_reset (struct lsquic_cubic *cubic)
|
cubic_reset (struct lsquic_cubic *cubic)
|
||||||
{
|
{
|
||||||
memset(cubic, 0, offsetof(struct lsquic_cubic, cu_cid));
|
memset(cubic, 0, offsetof(struct lsquic_cubic, cu_cid));
|
||||||
cubic->cu_cwnd = 32;
|
cubic->cu_cwnd = 32 * TCP_MSS;
|
||||||
cubic->cu_last_max_cwnd = 32;
|
cubic->cu_last_max_cwnd = 32 * TCP_MSS;
|
||||||
|
cubic->cu_tcp_cwnd = 32 * TCP_MSS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cubic_update (struct lsquic_cubic *cubic, lsquic_time_t now)
|
cubic_update (struct lsquic_cubic *cubic, lsquic_time_t now, unsigned n_bytes)
|
||||||
{
|
{
|
||||||
lsquic_time_t delta_t, t, target;
|
double delta_t, t;
|
||||||
unsigned tcp_cwnd;
|
lsquic_time_t target;
|
||||||
|
|
||||||
if (0 == cubic->cu_epoch_start)
|
if (0 == cubic->cu_epoch_start)
|
||||||
{
|
{
|
||||||
cubic->cu_epoch_start = now;
|
cubic->cu_epoch_start = now;
|
||||||
if (cubic->cu_cwnd < cubic->cu_last_max_cwnd)
|
if (cubic->cu_cwnd < cubic->cu_last_max_cwnd)
|
||||||
{
|
{
|
||||||
cubic->cu_K = cbrt((cubic->cu_last_max_cwnd - cubic->cu_cwnd) *
|
cubic->cu_K = cbrt(cubic->cu_last_max_cwnd / TCP_MSS / 2);
|
||||||
ONE_OVER_C / 1024) * 1000000;
|
|
||||||
cubic->cu_origin_point = cubic->cu_last_max_cwnd;
|
cubic->cu_origin_point = cubic->cu_last_max_cwnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -54,36 +54,38 @@ cubic_update (struct lsquic_cubic *cubic, lsquic_time_t now)
|
||||||
cubic->cu_K = 0;
|
cubic->cu_K = 0;
|
||||||
cubic->cu_origin_point = cubic->cu_cwnd;
|
cubic->cu_origin_point = cubic->cu_cwnd;
|
||||||
}
|
}
|
||||||
}
|
LSQ_DEBUG("cwnd: %lu; last_max_cwnd: %lu; K: %lf; origin_point: %lu",
|
||||||
else if ((cubic->cu_flags & CU_SHIFT_EPOCH) && cubic->cu_app_limited)
|
cubic->cu_cwnd, cubic->cu_last_max_cwnd, cubic->cu_K, cubic->cu_origin_point);
|
||||||
{
|
|
||||||
LSQ_DEBUG("increment epoch_start by %"PRIu64" microseconds", now - cubic->cu_app_limited);
|
|
||||||
cubic->cu_epoch_start += now - cubic->cu_app_limited;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delta_t = now + cubic->cu_min_delay - cubic->cu_epoch_start;
|
delta_t = (double) (now + cubic->cu_min_delay - cubic->cu_epoch_start) / 1000000;
|
||||||
if (delta_t < cubic->cu_K)
|
if (delta_t < cubic->cu_K)
|
||||||
{
|
{
|
||||||
t = cubic->cu_K - delta_t;
|
t = cubic->cu_K - delta_t;
|
||||||
t /= 62500;
|
target = cubic->cu_origin_point - t * t * t * 0.4 * TCP_MSS;
|
||||||
target = cubic->cu_origin_point - C * t * t * t / 1024 / 4096;
|
LSQ_DEBUG("delta_t: %lf; t: %lf; target 1: %"PRIu64, delta_t, t, target);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t = delta_t - cubic->cu_K;
|
t = delta_t - cubic->cu_K;
|
||||||
t /= 62500;
|
target = cubic->cu_origin_point + t * t * t * 0.4 * TCP_MSS;
|
||||||
target = cubic->cu_origin_point + C * t * t * t / 1024 / 4096;
|
LSQ_DEBUG("target 2: %"PRIu64, target);
|
||||||
if (cubic->cu_flags & CU_TCP_FRIENDLY)
|
}
|
||||||
{
|
|
||||||
tcp_cwnd = cubic->cu_last_max_cwnd * ONE_MINUS_BETA / 1024 +
|
if (cubic->cu_flags & CU_TCP_FRIENDLY)
|
||||||
(delta_t - cubic->cu_K) * C / 1024 / cubic->cu_min_delay;
|
{
|
||||||
if (tcp_cwnd > target)
|
cubic->cu_tcp_cwnd += n_bytes * TCP_MSS * ONE_MINUS_BETA / 1024
|
||||||
target = tcp_cwnd;
|
/ cubic->cu_tcp_cwnd;
|
||||||
}
|
LSQ_DEBUG("delta_t: %lf; last_max: %lu; cu_tcp_cwnd: %lu; target: "
|
||||||
|
"%"PRIu64"; over: %d; left: %d", delta_t, cubic->cu_last_max_cwnd,
|
||||||
|
cubic->cu_tcp_cwnd, target, cubic->cu_tcp_cwnd > target,
|
||||||
|
delta_t < cubic->cu_K);
|
||||||
|
if (cubic->cu_tcp_cwnd > target)
|
||||||
|
target = cubic->cu_tcp_cwnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target == 0)
|
if (target == 0)
|
||||||
target = 1;
|
target = TCP_MSS;
|
||||||
|
|
||||||
cubic->cu_cwnd = target;
|
cubic->cu_cwnd = target;
|
||||||
}
|
}
|
||||||
|
@ -94,23 +96,18 @@ lsquic_cubic_init_ext (struct lsquic_cubic *cubic, lsquic_cid_t cid,
|
||||||
enum cubic_flags flags)
|
enum cubic_flags flags)
|
||||||
{
|
{
|
||||||
cubic_reset(cubic);
|
cubic_reset(cubic);
|
||||||
cubic->cu_ssthresh = 10000; /* Emulate "unbounded" slow start */
|
cubic->cu_ssthresh = 10000 * TCP_MSS; /* Emulate "unbounded" slow start */
|
||||||
cubic->cu_cid = cid;
|
cubic->cu_cid = cid;
|
||||||
cubic->cu_flags = flags;
|
cubic->cu_flags = flags;
|
||||||
LSQ_DEBUG("%s(cubic, %"PRIu64", 0x%X)", __func__, cid, flags);
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
{
|
const char *s;
|
||||||
const char *shift;
|
s = getenv("LSQUIC_CUBIC_SAMPLING_RATE");
|
||||||
shift = getenv("LSQUIC_CUBIC_SHIFT_EPOCH");
|
if (s)
|
||||||
if (shift)
|
cubic->cu_sampling_rate = atoi(s);
|
||||||
{
|
else
|
||||||
if (atoi(shift))
|
|
||||||
cubic->cu_flags |= CU_SHIFT_EPOCH;
|
|
||||||
else
|
|
||||||
cubic->cu_flags &= ~CU_SHIFT_EPOCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
cubic->cu_sampling_rate = 100000;
|
||||||
|
LSQ_DEBUG("%s(cubic, %"PRIu64", 0x%X)", __func__, cid, flags);
|
||||||
LSQ_INFO("initialized");
|
LSQ_INFO("initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,20 +115,29 @@ lsquic_cubic_init_ext (struct lsquic_cubic *cubic, lsquic_cid_t cid,
|
||||||
#define LOG_CWND(c) do { \
|
#define LOG_CWND(c) do { \
|
||||||
if (LSQ_LOG_ENABLED(LSQ_LOG_INFO)) { \
|
if (LSQ_LOG_ENABLED(LSQ_LOG_INFO)) { \
|
||||||
lsquic_time_t now = lsquic_time_now(); \
|
lsquic_time_t now = lsquic_time_now(); \
|
||||||
now -= now % 100000; \
|
now -= now % (c)->cu_sampling_rate; \
|
||||||
if (now > (c)->cu_last_logged) { \
|
if (now > (c)->cu_last_logged) { \
|
||||||
LSQ_INFO("CWND: %u", (c)->cu_cwnd); \
|
LSQ_INFO("CWND: %lu", (c)->cu_cwnd); \
|
||||||
(c)->cu_last_logged = now; \
|
(c)->cu_last_logged = now; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_cubic_was_quiet (struct lsquic_cubic *cubic, lsquic_time_t now)
|
||||||
|
{
|
||||||
|
LSQ_DEBUG("%s(cubic, %"PRIu64")", __func__, now);
|
||||||
|
cubic->cu_epoch_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
||||||
lsquic_time_t rtt, int app_limited)
|
lsquic_time_t rtt, int app_limited, unsigned n_bytes)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("%s(cubic, %"PRIu64", %"PRIu64", %d)", __func__, now, rtt,
|
LSQ_DEBUG("%s(cubic, %"PRIu64", %"PRIu64", %d, %u)", __func__, now, rtt,
|
||||||
app_limited);
|
app_limited, n_bytes);
|
||||||
if (0 == cubic->cu_min_delay || rtt < cubic->cu_min_delay)
|
if (0 == cubic->cu_min_delay || rtt < cubic->cu_min_delay)
|
||||||
{
|
{
|
||||||
cubic->cu_min_delay = rtt;
|
cubic->cu_min_delay = rtt;
|
||||||
|
@ -140,31 +146,15 @@ lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
||||||
|
|
||||||
if (cubic->cu_cwnd <= cubic->cu_ssthresh)
|
if (cubic->cu_cwnd <= cubic->cu_ssthresh)
|
||||||
{
|
{
|
||||||
++cubic->cu_cwnd;
|
cubic->cu_cwnd += TCP_MSS;
|
||||||
LSQ_DEBUG("ACK: slow threshold, cwnd: %u", cubic->cu_cwnd);
|
LSQ_DEBUG("ACK: slow threshold, cwnd: %lu", cubic->cu_cwnd);
|
||||||
}
|
}
|
||||||
else
|
else if (!app_limited)
|
||||||
{
|
{
|
||||||
if (app_limited)
|
cubic_update(cubic, now, n_bytes);
|
||||||
{
|
LSQ_DEBUG("ACK: cwnd: %lu", cubic->cu_cwnd);
|
||||||
if (cubic->cu_flags & CU_SHIFT_EPOCH)
|
|
||||||
{
|
|
||||||
if (0 == cubic->cu_app_limited)
|
|
||||||
{
|
|
||||||
cubic->cu_app_limited = now;
|
|
||||||
LSQ_DEBUG("set app_limited to %"PRIu64, now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cubic->cu_epoch_start = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cubic_update(cubic, now);
|
|
||||||
cubic->cu_app_limited = 0;
|
|
||||||
}
|
|
||||||
LSQ_DEBUG("ACK: cwnd: %u", cubic->cu_cwnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_CWND(cubic);
|
LOG_CWND(cubic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,14 +164,14 @@ lsquic_cubic_loss (struct lsquic_cubic *cubic)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("%s(cubic)", __func__);
|
LSQ_DEBUG("%s(cubic)", __func__);
|
||||||
cubic->cu_epoch_start = 0;
|
cubic->cu_epoch_start = 0;
|
||||||
cubic->cu_app_limited = 0;
|
|
||||||
if (FAST_CONVERGENCE && cubic->cu_cwnd < cubic->cu_last_max_cwnd)
|
if (FAST_CONVERGENCE && cubic->cu_cwnd < cubic->cu_last_max_cwnd)
|
||||||
cubic->cu_last_max_cwnd = cubic->cu_cwnd * TWO_MINUS_BETA_OVER_TWO / 1024;
|
cubic->cu_last_max_cwnd = cubic->cu_cwnd * TWO_MINUS_BETA_OVER_TWO / 1024;
|
||||||
else
|
else
|
||||||
cubic->cu_last_max_cwnd = cubic->cu_cwnd;
|
cubic->cu_last_max_cwnd = cubic->cu_cwnd;
|
||||||
cubic->cu_cwnd = cubic->cu_cwnd * ONE_MINUS_BETA / 1024;
|
cubic->cu_cwnd = cubic->cu_cwnd * ONE_MINUS_BETA / 1024;
|
||||||
|
cubic->cu_tcp_cwnd = cubic->cu_cwnd;
|
||||||
cubic->cu_ssthresh = cubic->cu_cwnd;
|
cubic->cu_ssthresh = cubic->cu_cwnd;
|
||||||
LSQ_INFO("loss detected, last_max_cwnd: %u, cwnd: %u",
|
LSQ_INFO("loss detected, last_max_cwnd: %lu, cwnd: %lu",
|
||||||
cubic->cu_last_max_cwnd, cubic->cu_cwnd);
|
cubic->cu_last_max_cwnd, cubic->cu_cwnd);
|
||||||
LOG_CWND(cubic);
|
LOG_CWND(cubic);
|
||||||
}
|
}
|
||||||
|
@ -193,6 +183,7 @@ lsquic_cubic_timeout (struct lsquic_cubic *cubic)
|
||||||
LSQ_DEBUG("%s(cubic)", __func__);
|
LSQ_DEBUG("%s(cubic)", __func__);
|
||||||
cubic_reset(cubic);
|
cubic_reset(cubic);
|
||||||
cubic->cu_ssthresh = cubic->cu_cwnd;
|
cubic->cu_ssthresh = cubic->cu_cwnd;
|
||||||
LSQ_INFO("timeout, cwnd: %u", cubic->cu_cwnd);
|
cubic->cu_tcp_cwnd = cubic->cu_cwnd;
|
||||||
|
LSQ_INFO("timeout, cwnd: %lu", cubic->cu_cwnd);
|
||||||
LOG_CWND(cubic);
|
LOG_CWND(cubic);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,23 @@
|
||||||
struct lsquic_cubic {
|
struct lsquic_cubic {
|
||||||
lsquic_time_t cu_min_delay;
|
lsquic_time_t cu_min_delay;
|
||||||
lsquic_time_t cu_epoch_start;
|
lsquic_time_t cu_epoch_start;
|
||||||
lsquic_time_t cu_K;
|
double cu_K;
|
||||||
lsquic_time_t cu_app_limited;
|
unsigned long cu_origin_point;
|
||||||
unsigned cu_origin_point;
|
unsigned long cu_last_max_cwnd;
|
||||||
unsigned cu_last_max_cwnd;
|
unsigned long cu_cwnd;
|
||||||
unsigned cu_cwnd;
|
unsigned long cu_tcp_cwnd;
|
||||||
unsigned cu_ssthresh;
|
unsigned long cu_ssthresh;
|
||||||
lsquic_cid_t cu_cid; /* Used for logging */
|
lsquic_cid_t cu_cid; /* Used for logging */
|
||||||
enum cubic_flags {
|
enum cubic_flags {
|
||||||
CU_TCP_FRIENDLY = (1 << 0),
|
CU_TCP_FRIENDLY = (1 << 0),
|
||||||
CU_SHIFT_EPOCH = (1 << 1),
|
|
||||||
} cu_flags;
|
} cu_flags;
|
||||||
|
unsigned cu_sampling_rate;
|
||||||
lsquic_time_t cu_last_logged;
|
lsquic_time_t cu_last_logged;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_CUBIC_FLAGS (CU_TCP_FRIENDLY|CU_SHIFT_EPOCH)
|
#define DEFAULT_CUBIC_FLAGS (CU_TCP_FRIENDLY)
|
||||||
|
|
||||||
|
#define TCP_MSS 1460
|
||||||
|
|
||||||
void
|
void
|
||||||
lsquic_cubic_init_ext (struct lsquic_cubic *, lsquic_cid_t, enum cubic_flags);
|
lsquic_cubic_init_ext (struct lsquic_cubic *, lsquic_cid_t, enum cubic_flags);
|
||||||
|
@ -33,7 +35,7 @@ lsquic_cubic_init_ext (struct lsquic_cubic *, lsquic_cid_t, enum cubic_flags);
|
||||||
|
|
||||||
void
|
void
|
||||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
||||||
lsquic_time_t rtt, int app_limited);
|
lsquic_time_t rtt, int app_limited, unsigned n_bytes);
|
||||||
|
|
||||||
void
|
void
|
||||||
lsquic_cubic_loss (struct lsquic_cubic *cubic);
|
lsquic_cubic_loss (struct lsquic_cubic *cubic);
|
||||||
|
@ -41,6 +43,9 @@ lsquic_cubic_loss (struct lsquic_cubic *cubic);
|
||||||
void
|
void
|
||||||
lsquic_cubic_timeout (struct lsquic_cubic *cubic);
|
lsquic_cubic_timeout (struct lsquic_cubic *cubic);
|
||||||
|
|
||||||
|
void
|
||||||
|
lsquic_cubic_was_quiet (struct lsquic_cubic *, lsquic_time_t now);
|
||||||
|
|
||||||
#define lsquic_cubic_get_cwnd(c) (+(c)->cu_cwnd)
|
#define lsquic_cubic_get_cwnd(c) (+(c)->cu_cwnd)
|
||||||
|
|
||||||
#define lsquic_cubic_in_slow_start(cubic) \
|
#define lsquic_cubic_in_slow_start(cubic) \
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "lsquic_int_types.h"
|
#include "lsquic_int_types.h"
|
||||||
#include "lsquic_types.h"
|
#include "lsquic_types.h"
|
||||||
#include "lsquic_conn_flow.h"
|
#include "lsquic_conn_flow.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
#include "lsquic_rtt.h"
|
#include "lsquic_rtt.h"
|
||||||
#include "lsquic_sfcw.h"
|
#include "lsquic_sfcw.h"
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include "lsquic_types.h"
|
#include "lsquic_types.h"
|
||||||
#include "lsquic_int_types.h"
|
#include "lsquic_int_types.h"
|
||||||
#include "lsquic_conn_flow.h"
|
#include "lsquic_conn_flow.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
#include "lsquic_rtt.h"
|
#include "lsquic_rtt.h"
|
||||||
#include "lsquic_sfcw.h"
|
#include "lsquic_sfcw.h"
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "lsquic_eng_hist.h"
|
#include "lsquic_eng_hist.h"
|
||||||
#include "lsquic_ev_log.h"
|
#include "lsquic_ev_log.h"
|
||||||
#include "lsquic_version.h"
|
#include "lsquic_version.h"
|
||||||
|
#include "lsquic_hash.h"
|
||||||
#include "lsquic_attq.h"
|
#include "lsquic_attq.h"
|
||||||
|
|
||||||
#define LSQUIC_LOGGER_MODULE LSQLM_ENGINE
|
#define LSQUIC_LOGGER_MODULE LSQLM_ENGINE
|
||||||
|
@ -134,6 +135,8 @@ struct out_heap
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct lsquic_engine
|
struct lsquic_engine
|
||||||
{
|
{
|
||||||
struct lsquic_engine_public pub;
|
struct lsquic_engine_public pub;
|
||||||
|
@ -467,9 +470,11 @@ shrink_batch_size (struct lsquic_engine *engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper to make sure LSCONN_NEVER_PEND_RW gets set */
|
/* Wrapper to make sure important things occur before the connection is
|
||||||
|
* really destroyed.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
destroy_conn (lsquic_conn_t *conn)
|
destroy_conn (struct lsquic_engine *engine, lsquic_conn_t *conn)
|
||||||
{
|
{
|
||||||
conn->cn_flags |= LSCONN_NEVER_PEND_RW;
|
conn->cn_flags |= LSCONN_NEVER_PEND_RW;
|
||||||
conn->cn_if->ci_destroy(conn);
|
conn->cn_if->ci_destroy(conn);
|
||||||
|
@ -491,7 +496,7 @@ new_full_conn_client (lsquic_engine_t *engine, const char *hostname,
|
||||||
{
|
{
|
||||||
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
|
LSQ_WARN("cannot add connection %"PRIu64" to hash - destroy",
|
||||||
conn->cn_cid);
|
conn->cn_cid);
|
||||||
destroy_conn(conn);
|
destroy_conn(engine, conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
assert(!(conn->cn_flags &
|
assert(!(conn->cn_flags &
|
||||||
|
@ -849,17 +854,17 @@ conn_iter_next_one (lsquic_engine_t *engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
lsquic_conn_t *
|
||||||
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
||||||
void *conn_ctx, const char *hostname,
|
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||||
unsigned short max_packet_size)
|
const char *hostname, unsigned short max_packet_size)
|
||||||
{
|
{
|
||||||
lsquic_conn_t *conn;
|
lsquic_conn_t *conn;
|
||||||
|
|
||||||
if (engine->flags & ENG_SERVER)
|
if (engine->flags & ENG_SERVER)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("`%s' must only be called in client mode", __func__);
|
LSQ_ERROR("`%s' must only be called in client mode", __func__);
|
||||||
return -1;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == max_packet_size)
|
if (0 == max_packet_size)
|
||||||
|
@ -877,14 +882,16 @@ lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *peer_sa,
|
||||||
|
|
||||||
conn = new_full_conn_client(engine, hostname, max_packet_size);
|
conn = new_full_conn_client(engine, hostname, max_packet_size);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return -1;
|
return NULL;
|
||||||
ENGINE_IN(engine);
|
ENGINE_IN(engine);
|
||||||
lsquic_conn_record_peer_sa(conn, peer_sa);
|
lsquic_conn_record_peer_sa(conn, peer_sa);
|
||||||
conn->cn_peer_ctx = conn_ctx;
|
conn->cn_peer_ctx = peer_ctx;
|
||||||
|
lsquic_conn_set_ctx(conn, conn_ctx);
|
||||||
engine->iter_state.one.conn = conn;
|
engine->iter_state.one.conn = conn;
|
||||||
|
full_conn_client_call_on_new(conn);
|
||||||
process_connections(engine, conn_iter_next_one);
|
process_connections(engine, conn_iter_next_one);
|
||||||
ENGINE_OUT(engine);
|
ENGINE_OUT(engine);
|
||||||
return 0;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -938,7 +945,7 @@ engine_decref_conn (lsquic_engine_t *engine, lsquic_conn_t *conn,
|
||||||
if (0 == (conn->cn_flags & CONN_REF_FLAGS))
|
if (0 == (conn->cn_flags & CONN_REF_FLAGS))
|
||||||
{
|
{
|
||||||
eng_hist_inc(&engine->history, 0, sl_del_full_conns);
|
eng_hist_inc(&engine->history, 0, sl_del_full_conns);
|
||||||
destroy_conn(conn);
|
destroy_conn(engine, conn);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1034,13 +1041,24 @@ lsquic_engine_proc_all (lsquic_engine_t *engine)
|
||||||
void
|
void
|
||||||
lsquic_engine_process_conns_to_tick (lsquic_engine_t *engine)
|
lsquic_engine_process_conns_to_tick (lsquic_engine_t *engine)
|
||||||
{
|
{
|
||||||
lsquic_time_t prev_min, cutoff;
|
lsquic_time_t prev_min, now;
|
||||||
|
|
||||||
|
now = lsquic_time_now();
|
||||||
|
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
|
||||||
|
{
|
||||||
|
const lsquic_time_t *expected_time;
|
||||||
|
int64_t diff;
|
||||||
|
expected_time = attq_next_time(engine->attq);
|
||||||
|
if (expected_time)
|
||||||
|
diff = *expected_time - now;
|
||||||
|
else
|
||||||
|
diff = -1;
|
||||||
|
LSQ_DEBUG("process connections in attq; time diff: %"PRIi64, diff);
|
||||||
|
}
|
||||||
|
|
||||||
LSQ_DEBUG("process connections in attq");
|
|
||||||
ENGINE_IN(engine);
|
ENGINE_IN(engine);
|
||||||
cutoff = lsquic_time_now();
|
prev_min = attq_set_min(engine->attq, now); /* Prevent infinite loop */
|
||||||
prev_min = attq_set_min(engine->attq, cutoff); /* Prevent infinite loop */
|
engine->iter_state.attq.cutoff = now;
|
||||||
engine->iter_state.attq.cutoff = cutoff;
|
|
||||||
process_connections(engine, conn_iter_next_attq);
|
process_connections(engine, conn_iter_next_attq);
|
||||||
attq_set_min(engine->attq, prev_min); /* Restore previos value */
|
attq_set_min(engine->attq, prev_min); /* Restore previos value */
|
||||||
ENGINE_OUT(engine);
|
ENGINE_OUT(engine);
|
||||||
|
|
|
@ -91,10 +91,11 @@ enum full_conn_flags {
|
||||||
FC_GOT_PRST = (1 <<18), /* Received public reset packet */
|
FC_GOT_PRST = (1 <<18), /* Received public reset packet */
|
||||||
FC_FIRST_TICK = (1 <<19),
|
FC_FIRST_TICK = (1 <<19),
|
||||||
FC_TICK_CLOSE = (1 <<20), /* We returned TICK_CLOSE */
|
FC_TICK_CLOSE = (1 <<20), /* We returned TICK_CLOSE */
|
||||||
|
FC_HSK_FAILED = (1 <<21),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FC_IMMEDIATE_CLOSE_FLAGS \
|
#define FC_IMMEDIATE_CLOSE_FLAGS \
|
||||||
(FC_TIMED_OUT|FC_ERROR|FC_ABORTED)
|
(FC_TIMED_OUT|FC_ERROR|FC_ABORTED|FC_HSK_FAILED)
|
||||||
|
|
||||||
#if LSQUIC_KEEP_STREAM_HISTORY
|
#if LSQUIC_KEEP_STREAM_HISTORY
|
||||||
#define KEEP_CLOSED_STREAM_HISTORY 0
|
#define KEEP_CLOSED_STREAM_HISTORY 0
|
||||||
|
@ -111,6 +112,35 @@ struct stream_history
|
||||||
#define SHIST_MASK ((1 << SHIST_BITS) - 1)
|
#define SHIST_MASK ((1 << SHIST_BITS) - 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef KEEP_PACKET_HISTORY
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define KEEP_PACKET_HISTORY 0
|
||||||
|
#else
|
||||||
|
#define KEEP_PACKET_HISTORY 16
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KEEP_PACKET_HISTORY
|
||||||
|
struct packet_el
|
||||||
|
{
|
||||||
|
lsquic_time_t time;
|
||||||
|
enum quic_ft_bit frame_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct recent_packets
|
||||||
|
{
|
||||||
|
struct packet_el els[KEEP_PACKET_HISTORY];
|
||||||
|
unsigned idx;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct stream_id_to_reset
|
||||||
|
{
|
||||||
|
STAILQ_ENTRY(stream_id_to_reset) sitr_next;
|
||||||
|
uint32_t sitr_stream_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct full_conn
|
struct full_conn
|
||||||
{
|
{
|
||||||
struct lsquic_conn fc_conn;
|
struct lsquic_conn fc_conn;
|
||||||
|
@ -167,10 +197,26 @@ struct full_conn
|
||||||
struct stream_history fc_stream_histories[1 << SHIST_BITS];
|
struct stream_history fc_stream_histories[1 << SHIST_BITS];
|
||||||
unsigned fc_stream_hist_idx;
|
unsigned fc_stream_hist_idx;
|
||||||
#endif
|
#endif
|
||||||
|
char *fc_errmsg;
|
||||||
|
#if KEEP_PACKET_HISTORY
|
||||||
|
struct recent_packets fc_recent_packets[2]; /* 0: in; 1: out */
|
||||||
|
#endif
|
||||||
|
STAILQ_HEAD(, stream_id_to_reset)
|
||||||
|
fc_stream_ids_to_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_ERRMSG 256
|
||||||
|
|
||||||
|
#define SET_ERRMSG(conn, errmsg...) do { \
|
||||||
|
if (!(conn)->fc_errmsg) \
|
||||||
|
(conn)->fc_errmsg = malloc(MAX_ERRMSG); \
|
||||||
|
if ((conn)->fc_errmsg) \
|
||||||
|
snprintf((conn)->fc_errmsg, MAX_ERRMSG, errmsg); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define ABORT_WITH_FLAG(conn, flag, errmsg...) do { \
|
#define ABORT_WITH_FLAG(conn, flag, errmsg...) do { \
|
||||||
|
SET_ERRMSG(conn, errmsg); \
|
||||||
(conn)->fc_flags |= flag; \
|
(conn)->fc_flags |= flag; \
|
||||||
LSQ_ERROR("Abort connection: " errmsg); \
|
LSQ_ERROR("Abort connection: " errmsg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -197,6 +243,12 @@ new_stream (struct full_conn *conn, uint32_t stream_id, enum stream_ctor_flags);
|
||||||
static void
|
static void
|
||||||
reset_ack_state (struct full_conn *conn);
|
reset_ack_state (struct full_conn *conn);
|
||||||
|
|
||||||
|
static int
|
||||||
|
write_is_possible (struct full_conn *);
|
||||||
|
|
||||||
|
static int
|
||||||
|
dispatch_stream_read_events (struct full_conn *, struct lsquic_stream *);
|
||||||
|
|
||||||
static const struct headers_stream_callbacks headers_callbacks;
|
static const struct headers_stream_callbacks headers_callbacks;
|
||||||
|
|
||||||
#if KEEP_CLOSED_STREAM_HISTORY
|
#if KEEP_CLOSED_STREAM_HISTORY
|
||||||
|
@ -242,6 +294,32 @@ find_stream_history (const struct full_conn *conn, uint32_t stream_id)
|
||||||
# define SAVE_STREAM_HISTORY(conn, stream)
|
# define SAVE_STREAM_HISTORY(conn, stream)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if KEEP_PACKET_HISTORY
|
||||||
|
static void
|
||||||
|
recent_packet_hist_new (struct full_conn *conn, unsigned out,
|
||||||
|
lsquic_time_t time)
|
||||||
|
{
|
||||||
|
unsigned idx;
|
||||||
|
idx = conn->fc_recent_packets[out].idx++ % KEEP_PACKET_HISTORY;
|
||||||
|
conn->fc_recent_packets[out].els[idx].time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
recent_packet_hist_frames (struct full_conn *conn, unsigned out,
|
||||||
|
enum quic_ft_bit frame_types)
|
||||||
|
{
|
||||||
|
unsigned idx;
|
||||||
|
idx = (conn->fc_recent_packets[out].idx - 1) % KEEP_PACKET_HISTORY;
|
||||||
|
conn->fc_recent_packets[out].els[idx].frame_types |= frame_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define recent_packet_hist_new(conn, out, time)
|
||||||
|
#define recent_packet_hist_frames(conn, out, frames)
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
highest_bit_set (unsigned sz)
|
highest_bit_set (unsigned sz)
|
||||||
{
|
{
|
||||||
|
@ -486,6 +564,7 @@ new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
|
||||||
TAILQ_INIT(&conn->fc_pub.read_streams);
|
TAILQ_INIT(&conn->fc_pub.read_streams);
|
||||||
TAILQ_INIT(&conn->fc_pub.write_streams);
|
TAILQ_INIT(&conn->fc_pub.write_streams);
|
||||||
TAILQ_INIT(&conn->fc_pub.service_streams);
|
TAILQ_INIT(&conn->fc_pub.service_streams);
|
||||||
|
STAILQ_INIT(&conn->fc_stream_ids_to_reset);
|
||||||
lsquic_conn_cap_init(&conn->fc_pub.conn_cap, LSQUIC_MIN_FCW);
|
lsquic_conn_cap_init(&conn->fc_pub.conn_cap, LSQUIC_MIN_FCW);
|
||||||
lsquic_alarmset_init(&conn->fc_alset, cid);
|
lsquic_alarmset_init(&conn->fc_alset, cid);
|
||||||
lsquic_alarmset_init_alarm(&conn->fc_alset, AL_IDLE, idle_alarm_expired, conn);
|
lsquic_alarmset_init_alarm(&conn->fc_alset, AL_IDLE, idle_alarm_expired, conn);
|
||||||
|
@ -597,13 +676,22 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
conn->fc_flags |= FC_CREATED_OK;
|
conn->fc_flags |= FC_CREATED_OK;
|
||||||
conn->fc_conn_ctx = stream_if->on_new_conn(stream_if_ctx, &conn->fc_conn);
|
|
||||||
LSQ_INFO("Created new client connection");
|
LSQ_INFO("Created new client connection");
|
||||||
EV_LOG_CONN_EVENT(cid, "created full connection");
|
EV_LOG_CONN_EVENT(cid, "created full connection");
|
||||||
return &conn->fc_conn;
|
return &conn->fc_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
full_conn_client_call_on_new (struct lsquic_conn *lconn)
|
||||||
|
{
|
||||||
|
struct full_conn *const conn = (struct full_conn *) lconn;
|
||||||
|
assert(conn->fc_flags & FC_CREATED_OK);
|
||||||
|
conn->fc_conn_ctx = conn->fc_stream_ifs[STREAM_IF_STD].stream_if
|
||||||
|
->on_new_conn(conn->fc_stream_ifs[STREAM_IF_STD].stream_if_ctx, lconn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_our_stream (const struct full_conn *conn, const lsquic_stream_t *stream)
|
is_our_stream (const struct full_conn *conn, const lsquic_stream_t *stream)
|
||||||
{
|
{
|
||||||
|
@ -644,6 +732,7 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
|
||||||
struct full_conn *conn = (struct full_conn *) lconn;
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
struct lsquic_hash_elem *el;
|
struct lsquic_hash_elem *el;
|
||||||
struct lsquic_stream *stream;
|
struct lsquic_stream *stream;
|
||||||
|
struct stream_id_to_reset *sitr;
|
||||||
|
|
||||||
LSQ_DEBUG("destroy connection");
|
LSQ_DEBUG("destroy connection");
|
||||||
conn->fc_flags |= FC_CLOSING;
|
conn->fc_flags |= FC_CLOSING;
|
||||||
|
@ -676,7 +765,13 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
|
||||||
conn->fc_stats.n_packets_out,
|
conn->fc_stats.n_packets_out,
|
||||||
conn->fc_stats.stream_data_sz / conn->fc_stats.n_packets_out);
|
conn->fc_stats.stream_data_sz / conn->fc_stats.n_packets_out);
|
||||||
#endif
|
#endif
|
||||||
|
while ((sitr = STAILQ_FIRST(&conn->fc_stream_ids_to_reset)))
|
||||||
|
{
|
||||||
|
STAILQ_REMOVE_HEAD(&conn->fc_stream_ids_to_reset, sitr_next);
|
||||||
|
free(sitr);
|
||||||
|
}
|
||||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "full connection destroyed");
|
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "full connection destroyed");
|
||||||
|
free(conn->fc_errmsg);
|
||||||
free(conn);
|
free(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,6 +974,14 @@ lsquic_conn_get_stream_by_id (lsquic_conn_t *lconn, uint32_t stream_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lsquic_engine_t *
|
||||||
|
lsquic_conn_get_engine (lsquic_conn_t *lconn)
|
||||||
|
{
|
||||||
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
|
return conn->fc_enpub->enp_engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
count_zero_bytes (const unsigned char *p, size_t len)
|
count_zero_bytes (const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -926,6 +1029,24 @@ is_peer_initiated (const struct full_conn *conn, uint32_t stream_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_schedule_reset_for_stream (struct full_conn *conn, uint32_t stream_id)
|
||||||
|
{
|
||||||
|
struct stream_id_to_reset *sitr;
|
||||||
|
|
||||||
|
if (conn_is_stream_closed(conn, stream_id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sitr = malloc(sizeof(*sitr));
|
||||||
|
if (!sitr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sitr->sitr_stream_id = stream_id;
|
||||||
|
STAILQ_INSERT_TAIL(&conn->fc_stream_ids_to_reset, sitr, sitr_next);
|
||||||
|
conn_mark_stream_closed(conn, stream_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
||||||
const unsigned char *p, size_t len)
|
const unsigned char *p, size_t len)
|
||||||
|
@ -992,8 +1113,9 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
||||||
if ((conn->fc_flags & FC_GOING_AWAY) &&
|
if ((conn->fc_flags & FC_GOING_AWAY) &&
|
||||||
stream_frame->stream_id > conn->fc_max_peer_stream_id)
|
stream_frame->stream_id > conn->fc_max_peer_stream_id)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("going away: drop frame for new stream %u",
|
LSQ_DEBUG("going away: reset new incoming stream %"PRIu32,
|
||||||
stream_frame->stream_id);
|
stream_frame->stream_id);
|
||||||
|
maybe_schedule_reset_for_stream(conn, stream_frame->stream_id);
|
||||||
lsquic_malo_put(stream_frame);
|
lsquic_malo_put(stream_frame);
|
||||||
return parsed_len;
|
return parsed_len;
|
||||||
}
|
}
|
||||||
|
@ -1022,6 +1144,20 @@ process_stream_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream->id == LSQUIC_STREAM_HANDSHAKE
|
||||||
|
&& !(conn->fc_flags & FC_SERVER)
|
||||||
|
&& !(conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE))
|
||||||
|
{ /* To enable decryption, process handshake stream as soon as its
|
||||||
|
* data frames are received.
|
||||||
|
*
|
||||||
|
* TODO: this does not work when packets are reordered. A more
|
||||||
|
* flexible solution would defer packet decryption if handshake
|
||||||
|
* has not been completed yet. Nevertheless, this is good enough
|
||||||
|
* for now.
|
||||||
|
*/
|
||||||
|
dispatch_stream_read_events(conn, stream);
|
||||||
|
}
|
||||||
|
|
||||||
return parsed_len;
|
return parsed_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,6 +1518,7 @@ process_packet_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
|
||||||
{
|
{
|
||||||
enum QUIC_FRAME_TYPE type = conn->fc_conn.cn_pf->pf_parse_frame_type(p[0]);
|
enum QUIC_FRAME_TYPE type = conn->fc_conn.cn_pf->pf_parse_frame_type(p[0]);
|
||||||
packet_in->pi_frame_types |= 1 << type;
|
packet_in->pi_frame_types |= 1 << type;
|
||||||
|
recent_packet_hist_frames(conn, 0, 1 << type);
|
||||||
return process_frames[type](conn, packet_in, p, len);
|
return process_frames[type](conn, packet_in, p, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1485,6 +1622,7 @@ static int
|
||||||
process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
||||||
{
|
{
|
||||||
enum received_st st;
|
enum received_st st;
|
||||||
|
enum quic_ft_bit frame_types;
|
||||||
int was_missing;
|
int was_missing;
|
||||||
|
|
||||||
reconstruct_packet_number(conn, packet_in);
|
reconstruct_packet_number(conn, packet_in);
|
||||||
|
@ -1515,11 +1653,11 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
||||||
parse_regular_packet(conn, packet_in);
|
parse_regular_packet(conn, packet_in);
|
||||||
if (0 == (conn->fc_flags & FC_ACK_QUEUED))
|
if (0 == (conn->fc_flags & FC_ACK_QUEUED))
|
||||||
{
|
{
|
||||||
|
frame_types = packet_in->pi_frame_types;
|
||||||
was_missing = packet_in->pi_packno !=
|
was_missing = packet_in->pi_packno !=
|
||||||
lsquic_rechist_largest_packno(&conn->fc_rechist);
|
lsquic_rechist_largest_packno(&conn->fc_rechist);
|
||||||
conn->fc_n_slack_all += 1;
|
conn->fc_n_slack_all += 1;
|
||||||
conn->fc_n_slack_akbl +=
|
conn->fc_n_slack_akbl += !!(frame_types & QFRAME_ACKABLE_MASK);
|
||||||
!!(packet_in->pi_frame_types & QFRAME_ACKABLE_MASK);
|
|
||||||
try_queueing_ack(conn, was_missing, packet_in->pi_received);
|
try_queueing_ack(conn, was_missing, packet_in->pi_received);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1545,6 +1683,7 @@ process_regular_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
||||||
static int
|
static int
|
||||||
process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
process_incoming_packet (struct full_conn *conn, lsquic_packet_in_t *packet_in)
|
||||||
{
|
{
|
||||||
|
recent_packet_hist_new(conn, 0, packet_in->pi_received);
|
||||||
LSQ_DEBUG("Processing packet %"PRIu64, packet_in->pi_packno);
|
LSQ_DEBUG("Processing packet %"PRIu64, packet_in->pi_packno);
|
||||||
/* See flowchart in Section 4.1 of [draft-ietf-quic-transport-00]. We test
|
/* See flowchart in Section 4.1 of [draft-ietf-quic-transport-00]. We test
|
||||||
* for the common case first.
|
* for the common case first.
|
||||||
|
@ -1653,7 +1792,7 @@ generate_wuf_stream (struct full_conn *conn, lsquic_stream_t *stream)
|
||||||
ABORT_ERROR("gen_window_update_frame failed");
|
ABORT_ERROR("gen_window_update_frame failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_WINDOW_UPDATE;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_WINDOW_UPDATE;
|
||||||
LSQ_DEBUG("wrote WUF: stream %u; offset 0x%"PRIX64, stream->id, recv_off);
|
LSQ_DEBUG("wrote WUF: stream %u; offset 0x%"PRIX64, stream->id, recv_off);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1675,7 +1814,7 @@ generate_wuf_conn (struct full_conn *conn)
|
||||||
ABORT_ERROR("gen_window_update_frame failed");
|
ABORT_ERROR("gen_window_update_frame failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_WINDOW_UPDATE;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_WINDOW_UPDATE;
|
||||||
conn->fc_flags &= ~FC_SEND_WUF;
|
conn->fc_flags &= ~FC_SEND_WUF;
|
||||||
LSQ_DEBUG("wrote connection WUF: offset 0x%"PRIX64, recv_off);
|
LSQ_DEBUG("wrote connection WUF: offset 0x%"PRIX64, recv_off);
|
||||||
|
@ -1698,7 +1837,7 @@ generate_goaway_frame (struct full_conn *conn)
|
||||||
ABORT_ERROR("gen_goaway_frame failed");
|
ABORT_ERROR("gen_goaway_frame failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_GOAWAY;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_GOAWAY;
|
||||||
conn->fc_flags &= ~FC_SEND_GOAWAY;
|
conn->fc_flags &= ~FC_SEND_GOAWAY;
|
||||||
conn->fc_flags |= FC_GOAWAY_SENT;
|
conn->fc_flags |= FC_GOAWAY_SENT;
|
||||||
|
@ -1726,7 +1865,7 @@ generate_connection_close_packet (struct full_conn *conn)
|
||||||
ABORT_ERROR("generate_connection_close_packet failed");
|
ABORT_ERROR("generate_connection_close_packet failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
|
||||||
LSQ_DEBUG("generated CONNECTION_CLOSE frame in its own packet");
|
LSQ_DEBUG("generated CONNECTION_CLOSE frame in its own packet");
|
||||||
}
|
}
|
||||||
|
@ -1746,7 +1885,7 @@ generate_blocked_frame (struct full_conn *conn, uint32_t stream_id)
|
||||||
ABORT_ERROR("gen_blocked_frame failed");
|
ABORT_ERROR("gen_blocked_frame failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_BLOCKED;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_BLOCKED;
|
||||||
LSQ_DEBUG("wrote blocked frame: stream %u", stream_id);
|
LSQ_DEBUG("wrote blocked frame: stream %u", stream_id);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1772,8 +1911,6 @@ generate_rst_stream_frame (struct full_conn *conn, lsquic_stream_t *stream)
|
||||||
lsquic_packet_out_t *packet_out;
|
lsquic_packet_out_t *packet_out;
|
||||||
int sz, s;
|
int sz, s;
|
||||||
|
|
||||||
assert(stream->n_unacked == 0);
|
|
||||||
|
|
||||||
packet_out = get_writeable_packet(conn, QUIC_RST_STREAM_SZ);
|
packet_out = get_writeable_packet(conn, QUIC_RST_STREAM_SZ);
|
||||||
if (!packet_out)
|
if (!packet_out)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1791,7 +1928,7 @@ generate_rst_stream_frame (struct full_conn *conn, lsquic_stream_t *stream)
|
||||||
ABORT_ERROR("gen_rst_frame failed");
|
ABORT_ERROR("gen_rst_frame failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_RST_STREAM;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_RST_STREAM;
|
||||||
s = lsquic_packet_out_add_stream(packet_out, conn->fc_pub.mm, stream,
|
s = lsquic_packet_out_add_stream(packet_out, conn->fc_pub.mm, stream,
|
||||||
QUIC_FRAME_RST_STREAM, 0, 0);
|
QUIC_FRAME_RST_STREAM, 0, 0);
|
||||||
|
@ -1823,7 +1960,7 @@ generate_ping_frame (struct full_conn *conn)
|
||||||
ABORT_ERROR("gen_blocked_frame failed");
|
ABORT_ERROR("gen_blocked_frame failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_PING;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_PING;
|
||||||
LSQ_DEBUG("wrote PING frame");
|
LSQ_DEBUG("wrote PING frame");
|
||||||
}
|
}
|
||||||
|
@ -1870,7 +2007,7 @@ generate_stop_waiting_frame (struct full_conn *conn)
|
||||||
ABORT_ERROR("gen_stop_waiting_frame failed");
|
ABORT_ERROR("gen_stop_waiting_frame failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_regen_sz += sz;
|
packet_out->po_regen_sz += sz;
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_STOP_WAITING;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_STOP_WAITING;
|
||||||
conn->fc_flags &= ~FC_SEND_STOP_WAITING;
|
conn->fc_flags &= ~FC_SEND_STOP_WAITING;
|
||||||
|
@ -1914,6 +2051,49 @@ process_streams_ready_to_send (struct full_conn *conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if packetized, false otherwise */
|
||||||
|
static int
|
||||||
|
packetize_standalone_stream_reset (struct full_conn *conn, uint32_t stream_id)
|
||||||
|
{
|
||||||
|
lsquic_packet_out_t *packet_out;
|
||||||
|
int sz;
|
||||||
|
|
||||||
|
packet_out = get_writeable_packet(conn, QUIC_RST_STREAM_SZ);
|
||||||
|
if (!packet_out)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sz = conn->fc_conn.cn_pf->pf_gen_rst_frame(
|
||||||
|
packet_out->po_data + packet_out->po_data_sz,
|
||||||
|
lsquic_packet_out_avail(packet_out), stream_id,
|
||||||
|
0, 0x10 /* QUIC_PEER_GOING_AWAY */);
|
||||||
|
if (sz < 0) {
|
||||||
|
ABORT_ERROR("gen_rst_frame failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_RST_STREAM;
|
||||||
|
LSQ_DEBUG("generated standaloen RST_STREAM frame for stream %"PRIu32,
|
||||||
|
stream_id);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
packetize_standalone_stream_resets (struct full_conn *conn)
|
||||||
|
{
|
||||||
|
struct stream_id_to_reset *sitr;
|
||||||
|
|
||||||
|
while ((sitr = STAILQ_FIRST(&conn->fc_stream_ids_to_reset)))
|
||||||
|
if (packetize_standalone_stream_reset(conn, sitr->sitr_stream_id))
|
||||||
|
{
|
||||||
|
STAILQ_REMOVE_HEAD(&conn->fc_stream_ids_to_reset, sitr_next);
|
||||||
|
free(sitr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
service_streams (struct full_conn *conn)
|
service_streams (struct full_conn *conn)
|
||||||
{
|
{
|
||||||
|
@ -2040,7 +2220,7 @@ process_streams_write_events (struct full_conn *conn, int high_prio)
|
||||||
else
|
else
|
||||||
lsquic_spi_drop_high(&spi);
|
lsquic_spi_drop_high(&spi);
|
||||||
|
|
||||||
for (stream = lsquic_spi_first(&spi); stream;
|
for (stream = lsquic_spi_first(&spi); stream && write_is_possible(conn);
|
||||||
stream = lsquic_spi_next(&spi))
|
stream = lsquic_spi_next(&spi))
|
||||||
lsquic_stream_dispatch_write_events(stream);
|
lsquic_stream_dispatch_write_events(stream);
|
||||||
|
|
||||||
|
@ -2145,7 +2325,7 @@ generate_ack_frame (struct full_conn *conn)
|
||||||
verify_ack_frame(conn, packet_out->po_data + packet_out->po_data_sz, w);
|
verify_ack_frame(conn, packet_out->po_data + packet_out->po_data_sz, w);
|
||||||
lsquic_send_ctl_scheduled_ack(&conn->fc_send_ctl);
|
lsquic_send_ctl_scheduled_ack(&conn->fc_send_ctl);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_ACK;
|
||||||
packet_out->po_data_sz += w;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, w);
|
||||||
packet_out->po_regen_sz += w;
|
packet_out->po_regen_sz += w;
|
||||||
if (has_missing)
|
if (has_missing)
|
||||||
conn->fc_flags |= FC_ACK_HAD_MISS;
|
conn->fc_flags |= FC_ACK_HAD_MISS;
|
||||||
|
@ -2236,7 +2416,7 @@ immediate_close (struct full_conn *conn)
|
||||||
LSQ_WARN("%s failed", __func__);
|
LSQ_WARN("%s failed", __func__);
|
||||||
return TICK_CLOSE;
|
return TICK_CLOSE;
|
||||||
}
|
}
|
||||||
packet_out->po_data_sz += sz;
|
lsquic_send_ctl_incr_pack_sz(&conn->fc_send_ctl, packet_out, sz);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_CONNECTION_CLOSE;
|
||||||
LSQ_DEBUG("generated CONNECTION_CLOSE frame in its own packet");
|
LSQ_DEBUG("generated CONNECTION_CLOSE frame in its own packet");
|
||||||
return TICK_SEND|TICK_CLOSE;
|
return TICK_SEND|TICK_CLOSE;
|
||||||
|
@ -2323,6 +2503,9 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
||||||
progress_tick |= progress_made << TICK_BIT_PROGRESS;
|
progress_tick |= progress_made << TICK_BIT_PROGRESS;
|
||||||
CLOSE_IF_NECESSARY();
|
CLOSE_IF_NECESSARY();
|
||||||
|
|
||||||
|
if (lsquic_send_ctl_pacer_blocked(&conn->fc_send_ctl))
|
||||||
|
goto skip_write;
|
||||||
|
|
||||||
if (conn->fc_flags & FC_FIRST_TICK)
|
if (conn->fc_flags & FC_FIRST_TICK)
|
||||||
{
|
{
|
||||||
conn->fc_flags &= ~FC_FIRST_TICK;
|
conn->fc_flags &= ~FC_FIRST_TICK;
|
||||||
|
@ -2335,7 +2518,7 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
||||||
* we sometimes add is a packet with an ACK frame, and we add it
|
* we sometimes add is a packet with an ACK frame, and we add it
|
||||||
* to the *front* of the queue.
|
* to the *front* of the queue.
|
||||||
*/
|
*/
|
||||||
have_delayed_packets = lsquic_send_ctl_squeeze_sched(
|
have_delayed_packets = lsquic_send_ctl_maybe_squeeze_sched(
|
||||||
&conn->fc_send_ctl);
|
&conn->fc_send_ctl);
|
||||||
|
|
||||||
if ((conn->fc_flags & FC_ACK_QUEUED) ||
|
if ((conn->fc_flags & FC_ACK_QUEUED) ||
|
||||||
|
@ -2383,8 +2566,6 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_OUT_OF_PACKETS();
|
|
||||||
|
|
||||||
/* Try to fit any of the following three frames -- STOP_WAITING,
|
/* Try to fit any of the following three frames -- STOP_WAITING,
|
||||||
* WINDOW_UPDATE, and GOAWAY -- before checking if we have run
|
* WINDOW_UPDATE, and GOAWAY -- before checking if we have run
|
||||||
* out of packets. If either of them does not fit, it will be
|
* out of packets. If either of them does not fit, it will be
|
||||||
|
@ -2424,6 +2605,12 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
||||||
RETURN_IF_OUT_OF_PACKETS();
|
RETURN_IF_OUT_OF_PACKETS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!STAILQ_EMPTY(&conn->fc_stream_ids_to_reset))
|
||||||
|
{
|
||||||
|
packetize_standalone_stream_resets(conn);
|
||||||
|
CLOSE_IF_NECESSARY();
|
||||||
|
}
|
||||||
|
|
||||||
if (!TAILQ_EMPTY(&conn->fc_pub.sending_streams))
|
if (!TAILQ_EMPTY(&conn->fc_pub.sending_streams))
|
||||||
{
|
{
|
||||||
process_streams_ready_to_send(conn);
|
process_streams_ready_to_send(conn);
|
||||||
|
@ -2464,6 +2651,7 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
||||||
progress_made = (n_sched < lsquic_send_ctl_n_scheduled(&conn->fc_send_ctl));
|
progress_made = (n_sched < lsquic_send_ctl_n_scheduled(&conn->fc_send_ctl));
|
||||||
progress_tick |= progress_made << TICK_BIT_PROGRESS;
|
progress_tick |= progress_made << TICK_BIT_PROGRESS;
|
||||||
|
|
||||||
|
skip_write:
|
||||||
service_streams(conn);
|
service_streams(conn);
|
||||||
CLOSE_IF_NECESSARY();
|
CLOSE_IF_NECESSARY();
|
||||||
|
|
||||||
|
@ -2559,6 +2747,9 @@ full_conn_ci_packet_sent (lsquic_conn_t *lconn, lsquic_packet_out_t *packet_out)
|
||||||
struct full_conn *conn = (struct full_conn *) lconn;
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
recent_packet_hist_new(conn, 1, packet_out->po_sent);
|
||||||
|
recent_packet_hist_frames(conn, 1, packet_out->po_frame_types);
|
||||||
|
|
||||||
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
{
|
{
|
||||||
conn->fc_n_cons_unretx = 0;
|
conn->fc_n_cons_unretx = 0;
|
||||||
|
@ -2567,7 +2758,7 @@ full_conn_ci_packet_sent (lsquic_conn_t *lconn, lsquic_packet_out_t *packet_out)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++conn->fc_n_cons_unretx;
|
++conn->fc_n_cons_unretx;
|
||||||
s = lsquic_send_ctl_sent_packet(&conn->fc_send_ctl, packet_out);
|
s = lsquic_send_ctl_sent_packet(&conn->fc_send_ctl, packet_out, 1);
|
||||||
if (s != 0)
|
if (s != 0)
|
||||||
ABORT_ERROR("sent packet failed: %s", strerror(errno));
|
ABORT_ERROR("sent packet failed: %s", strerror(errno));
|
||||||
#if FULL_CONN_STATS
|
#if FULL_CONN_STATS
|
||||||
|
@ -2585,7 +2776,7 @@ full_conn_ci_packet_not_sent (lsquic_conn_t *lconn, lsquic_packet_out_t *packet_
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
full_conn_ci_handshake_done (lsquic_conn_t *lconn)
|
full_conn_ci_handshake_ok (lsquic_conn_t *lconn)
|
||||||
{
|
{
|
||||||
struct full_conn *conn = (struct full_conn *) lconn;
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
LSQ_DEBUG("handshake reportedly done");
|
LSQ_DEBUG("handshake reportedly done");
|
||||||
|
@ -2597,6 +2788,16 @@ full_conn_ci_handshake_done (lsquic_conn_t *lconn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
full_conn_ci_handshake_failed (lsquic_conn_t *lconn)
|
||||||
|
{
|
||||||
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
|
LSQ_DEBUG("handshake failed");
|
||||||
|
lsquic_alarmset_unset(&conn->fc_alset, AL_HANDSHAKE);
|
||||||
|
conn->fc_flags |= FC_HSK_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
full_conn_ci_user_wants_read (lsquic_conn_t *lconn)
|
full_conn_ci_user_wants_read (lsquic_conn_t *lconn)
|
||||||
{
|
{
|
||||||
|
@ -2615,7 +2816,7 @@ lsquic_conn_abort (lsquic_conn_t *lconn)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
full_conn_close_internal (lsquic_conn_t *lconn, int is_user)
|
lsquic_conn_close (lsquic_conn_t *lconn)
|
||||||
{
|
{
|
||||||
struct full_conn *conn = (struct full_conn *) lconn;
|
struct full_conn *conn = (struct full_conn *) lconn;
|
||||||
lsquic_stream_t *stream;
|
lsquic_stream_t *stream;
|
||||||
|
@ -2623,8 +2824,6 @@ full_conn_close_internal (lsquic_conn_t *lconn, int is_user)
|
||||||
|
|
||||||
if (!(conn->fc_flags & FC_CLOSING))
|
if (!(conn->fc_flags & FC_CLOSING))
|
||||||
{
|
{
|
||||||
if (is_user)
|
|
||||||
LSQ_INFO("User closed connection");
|
|
||||||
for (el = lsquic_hash_first(conn->fc_pub.all_streams); el;
|
for (el = lsquic_hash_first(conn->fc_pub.all_streams); el;
|
||||||
el = lsquic_hash_next(conn->fc_pub.all_streams))
|
el = lsquic_hash_next(conn->fc_pub.all_streams))
|
||||||
{
|
{
|
||||||
|
@ -2638,13 +2837,6 @@ full_conn_close_internal (lsquic_conn_t *lconn, int is_user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
lsquic_conn_close (lsquic_conn_t *lconn)
|
|
||||||
{
|
|
||||||
full_conn_close_internal(lconn, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lsquic_conn_going_away (lsquic_conn_t *lconn)
|
lsquic_conn_going_away (lsquic_conn_t *lconn)
|
||||||
{
|
{
|
||||||
|
@ -2707,8 +2899,8 @@ find_stream_on_non_stream_frame (struct full_conn *conn, uint32_t stream_id,
|
||||||
if ((conn->fc_flags & FC_GOING_AWAY) &&
|
if ((conn->fc_flags & FC_GOING_AWAY) &&
|
||||||
stream_id > conn->fc_max_peer_stream_id)
|
stream_id > conn->fc_max_peer_stream_id)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("going away: drop headers for new stream %u",
|
maybe_schedule_reset_for_stream(conn, stream_id);
|
||||||
stream_id);
|
LSQ_DEBUG("going away: reset new incoming stream %u", stream_id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2882,6 +3074,63 @@ lsquic_conn_get_ctx (const lsquic_conn_t *lconn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lsquic_conn_set_ctx (lsquic_conn_t *lconn, lsquic_conn_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
struct full_conn *const conn = (struct full_conn *) lconn;
|
||||||
|
conn->fc_conn_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum LSQUIC_CONN_STATUS
|
||||||
|
lsquic_conn_status (lsquic_conn_t *lconn, char *errbuf, size_t bufsz)
|
||||||
|
{
|
||||||
|
struct full_conn *const conn = (struct full_conn *) lconn;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Test the common case first: */
|
||||||
|
if (!(conn->fc_flags & (FC_ERROR
|
||||||
|
|FC_TIMED_OUT
|
||||||
|
|FC_ABORTED
|
||||||
|
|FC_GOT_PRST
|
||||||
|
|FC_HSK_FAILED
|
||||||
|
|FC_CLOSING
|
||||||
|
|FC_GOING_AWAY)))
|
||||||
|
{
|
||||||
|
if (lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||||
|
return LSCONN_ST_CONNECTED;
|
||||||
|
else
|
||||||
|
return LSCONN_ST_HSK_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errbuf && bufsz)
|
||||||
|
{
|
||||||
|
if (conn->fc_errmsg)
|
||||||
|
{
|
||||||
|
n = bufsz < MAX_ERRMSG ? bufsz : MAX_ERRMSG;
|
||||||
|
strncpy(errbuf, conn->fc_errmsg, n);
|
||||||
|
errbuf[n - 1] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
errbuf[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn->fc_flags & FC_ERROR)
|
||||||
|
return LSCONN_ST_ERROR;
|
||||||
|
if (conn->fc_flags & FC_TIMED_OUT)
|
||||||
|
return LSCONN_ST_TIMED_OUT;
|
||||||
|
if (conn->fc_flags & FC_ABORTED)
|
||||||
|
return LSCONN_ST_USER_ABORTED;
|
||||||
|
if (conn->fc_flags & FC_GOT_PRST)
|
||||||
|
return LSCONN_ST_RESET;
|
||||||
|
if (conn->fc_flags & FC_HSK_FAILED)
|
||||||
|
return LSCONN_ST_HSK_FAILURE;
|
||||||
|
if (conn->fc_flags & FC_CLOSING)
|
||||||
|
return LSCONN_ST_CLOSED;
|
||||||
|
assert(conn->fc_flags & FC_GOING_AWAY);
|
||||||
|
return LSCONN_ST_GOING_AWAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct headers_stream_callbacks headers_callbacks =
|
static const struct headers_stream_callbacks headers_callbacks =
|
||||||
{
|
{
|
||||||
.hsc_on_headers = headers_stream_on_incoming_headers,
|
.hsc_on_headers = headers_stream_on_incoming_headers,
|
||||||
|
@ -2896,7 +3145,8 @@ static const struct headers_stream_callbacks headers_callbacks =
|
||||||
|
|
||||||
static const struct conn_iface full_conn_iface = {
|
static const struct conn_iface full_conn_iface = {
|
||||||
.ci_destroy = full_conn_ci_destroy,
|
.ci_destroy = full_conn_ci_destroy,
|
||||||
.ci_handshake_done = full_conn_ci_handshake_done,
|
.ci_handshake_failed = full_conn_ci_handshake_failed,
|
||||||
|
.ci_handshake_ok = full_conn_ci_handshake_ok,
|
||||||
.ci_next_packet_to_send = full_conn_ci_next_packet_to_send,
|
.ci_next_packet_to_send = full_conn_ci_next_packet_to_send,
|
||||||
.ci_packet_in = full_conn_ci_packet_in,
|
.ci_packet_in = full_conn_ci_packet_in,
|
||||||
.ci_packet_not_sent = full_conn_ci_packet_not_sent,
|
.ci_packet_not_sent = full_conn_ci_packet_not_sent,
|
||||||
|
|
|
@ -14,6 +14,6 @@ full_conn_client_new (struct lsquic_engine_public *,
|
||||||
const char *hostname, unsigned short max_packet_size);
|
const char *hostname, unsigned short max_packet_size);
|
||||||
|
|
||||||
void
|
void
|
||||||
full_conn_close_internal (lsquic_conn_t *, int is_user);
|
full_conn_client_call_on_new (struct lsquic_conn *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -68,6 +68,7 @@ typedef struct hs_ctx_st
|
||||||
HSET_TCID = (1 << 0), /* tcid is set */
|
HSET_TCID = (1 << 0), /* tcid is set */
|
||||||
HSET_SMHL = (1 << 1), /* smhl is set */
|
HSET_SMHL = (1 << 1), /* smhl is set */
|
||||||
HSET_SCID = (1 << 2),
|
HSET_SCID = (1 << 2),
|
||||||
|
HSET_IRTT = (1 << 3),
|
||||||
} set;
|
} set;
|
||||||
enum {
|
enum {
|
||||||
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
|
HOPT_NSTP = (1 << 0), /* NSTP option present in COPT */
|
||||||
|
@ -302,7 +303,7 @@ make_cert_hash_item (lsquic_str_t *domain, lsquic_str_t **certs, int count)
|
||||||
|
|
||||||
|
|
||||||
/* client */
|
/* client */
|
||||||
void
|
static void
|
||||||
c_free_cert_hash_item (cert_hash_item_t *item)
|
c_free_cert_hash_item (cert_hash_item_t *item)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -572,7 +573,9 @@ static int parse_hs_data (lsquic_enc_session_t *enc_session, uint32_t tag,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QTAG_IRTT:
|
case QTAG_IRTT:
|
||||||
hs_ctx->irtt = get_tag_value_i32(val, len);
|
if (0 != get_tag_val_u32(val, len, &hs_ctx->irtt))
|
||||||
|
return -1;
|
||||||
|
hs_ctx->set |= HSET_IRTT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QTAG_COPT:
|
case QTAG_COPT:
|
||||||
|
@ -1701,6 +1704,14 @@ lsquic_enc_session_get_peer_setting (const lsquic_enc_session_t *enc_session,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
case QTAG_IRTT:
|
||||||
|
if (enc_session->hs_ctx.set & HSET_IRTT)
|
||||||
|
{
|
||||||
|
*val = enc_session->hs_ctx.irtt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX For the following values, there is no record which were present
|
/* XXX For the following values, there is no record which were present
|
||||||
|
|
|
@ -126,7 +126,11 @@ print_timestamp (void)
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
localtime_r(&tv.tv_sec, &tm);
|
localtime_r(&tv.tv_sec, &tm);
|
||||||
if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
|
if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
|
||||||
|
lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ",
|
||||||
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||||
|
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec));
|
||||||
|
else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
|
||||||
lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
|
lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
|
||||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
|
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
|
||||||
|
|
|
@ -41,6 +41,15 @@ pacer_init (struct pacer *pacer, lsquic_cid_t cid, unsigned max_intertick)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
pacer_cleanup (struct pacer *pacer)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
LSQ_NOTICE("scheduled calls: %u", pacer->pa_stats.n_scheduled);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
|
pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
|
||||||
int in_recovery, tx_time_f tx_time, void *tx_ctx)
|
int in_recovery, tx_time_f tx_time, void *tx_ctx)
|
||||||
|
@ -48,6 +57,10 @@ pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
|
||||||
lsquic_time_t delay, sched_time;
|
lsquic_time_t delay, sched_time;
|
||||||
int app_limited, making_up;
|
int app_limited, making_up;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
++pacer->pa_stats.n_scheduled;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (n_in_flight == 0 && !in_recovery)
|
if (n_in_flight == 0 && !in_recovery)
|
||||||
{
|
{
|
||||||
pacer->pa_burst_tokens = 10;
|
pacer->pa_burst_tokens = 10;
|
||||||
|
@ -100,12 +113,7 @@ pacer_loss_event (struct pacer *pacer)
|
||||||
static unsigned
|
static unsigned
|
||||||
clock_granularity (const struct pacer *pacer)
|
clock_granularity (const struct pacer *pacer)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
return pacer->pa_intertick_avg;
|
||||||
if (pacer->pa_flags & PA_CONSTANT_INTERTICK)
|
|
||||||
return pacer->pa_max_intertick;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return pacer->pa_intertick_var;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,11 @@ struct pacer
|
||||||
PA_CONSTANT_INTERTICK = (1 << 1), /* Use fake intertick time for testing */
|
PA_CONSTANT_INTERTICK = (1 << 1), /* Use fake intertick time for testing */
|
||||||
#endif
|
#endif
|
||||||
} pa_flags:8;
|
} pa_flags:8;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
struct {
|
||||||
|
unsigned n_scheduled;
|
||||||
|
} pa_stats;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +41,9 @@ typedef lsquic_time_t (*tx_time_f)(void *ctx);
|
||||||
void
|
void
|
||||||
pacer_init (struct pacer *, lsquic_cid_t, unsigned max_intertick);
|
pacer_init (struct pacer *, lsquic_cid_t, unsigned max_intertick);
|
||||||
|
|
||||||
|
void
|
||||||
|
pacer_cleanup (struct pacer *);
|
||||||
|
|
||||||
void
|
void
|
||||||
pacer_tick (struct pacer *, lsquic_time_t);
|
pacer_tick (struct pacer *, lsquic_time_t);
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ const size_t lsquic_frame_types_str_sz =
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
lsquic_frame_types_to_str (char *buf, size_t bufsz, short frame_types)
|
lsquic_frame_types_to_str (char *buf, size_t bufsz,
|
||||||
|
enum quic_ft_bit frame_types)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
int i, w;
|
int i, w;
|
||||||
|
|
|
@ -36,10 +36,24 @@ enum QUIC_FRAME_TYPE
|
||||||
N_QUIC_FRAMES
|
N_QUIC_FRAMES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum quic_ft_bit {
|
||||||
|
QUIC_FTBIT_INVALID = 1 << QUIC_FRAME_INVALID,
|
||||||
|
QUIC_FTBIT_STREAM = 1 << QUIC_FRAME_STREAM,
|
||||||
|
QUIC_FTBIT_ACK = 1 << QUIC_FRAME_ACK,
|
||||||
|
QUIC_FTBIT_PADDING = 1 << QUIC_FRAME_PADDING,
|
||||||
|
QUIC_FTBIT_RST_STREAM = 1 << QUIC_FRAME_RST_STREAM,
|
||||||
|
QUIC_FTBIT_CONNECTION_CLOSE = 1 << QUIC_FRAME_CONNECTION_CLOSE,
|
||||||
|
QUIC_FTBIT_GOAWAY = 1 << QUIC_FRAME_GOAWAY,
|
||||||
|
QUIC_FTBIT_WINDOW_UPDATE = 1 << QUIC_FRAME_WINDOW_UPDATE,
|
||||||
|
QUIC_FTBIT_BLOCKED = 1 << QUIC_FRAME_BLOCKED,
|
||||||
|
QUIC_FTBIT_STOP_WAITING = 1 << QUIC_FRAME_STOP_WAITING,
|
||||||
|
QUIC_FTBIT_PING = 1 << QUIC_FRAME_PING,
|
||||||
|
};
|
||||||
|
|
||||||
extern const size_t lsquic_frame_types_str_sz;
|
extern const size_t lsquic_frame_types_str_sz;
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
lsquic_frame_types_to_str (char *buf, size_t bufsz, short frame_types);
|
lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit);
|
||||||
|
|
||||||
#define QFRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \
|
#define QFRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \
|
||||||
| (1 << QUIC_FRAME_STOP_WAITING))
|
| (1 << QUIC_FRAME_STOP_WAITING))
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "lsquic_int_types.h"
|
#include "lsquic_int_types.h"
|
||||||
#include "lsquic_types.h"
|
#include "lsquic_types.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ typedef struct lsquic_packet_in
|
||||||
* list.
|
* list.
|
||||||
*/
|
*/
|
||||||
unsigned short pi_refcnt;
|
unsigned short pi_refcnt;
|
||||||
short pi_frame_types;
|
enum quic_ft_bit pi_frame_types:16;
|
||||||
unsigned short pi_hsk_stream; /* Offset to handshake stream
|
unsigned short pi_hsk_stream; /* Offset to handshake stream
|
||||||
* frame, only valid if
|
* frame, only valid if
|
||||||
* PI_HSK_STREAM is set.
|
* PI_HSK_STREAM is set.
|
||||||
|
|
|
@ -128,6 +128,8 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
int last_taken;
|
int last_taken;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
|
assert(!(new_stream->stream_flags & STREAM_FINISHED));
|
||||||
|
|
||||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||||
if (srec->sr_stream == new_stream)
|
if (srec->sr_stream == new_stream)
|
||||||
{
|
{
|
||||||
|
@ -150,8 +152,6 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
else if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM) & (1 << frame_type))
|
else if (srec->sr_frame_types & (1 << QUIC_FRAME_STREAM) & (1 << frame_type))
|
||||||
assert(srec->sr_off < off); /* Check that STREAM frames are added in order */
|
assert(srec->sr_off < off); /* Check that STREAM frames are added in order */
|
||||||
|
|
||||||
++new_stream->n_unacked;
|
|
||||||
|
|
||||||
if (!(packet_out->po_flags & PO_SREC_ARR))
|
if (!(packet_out->po_flags & PO_SREC_ARR))
|
||||||
{
|
{
|
||||||
if (!srec_taken(&packet_out->po_srecs.one))
|
if (!srec_taken(&packet_out->po_srecs.one))
|
||||||
|
@ -160,6 +160,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
packet_out->po_srecs.one.sr_stream = new_stream;
|
packet_out->po_srecs.one.sr_stream = new_stream;
|
||||||
packet_out->po_srecs.one.sr_off = off;
|
packet_out->po_srecs.one.sr_off = off;
|
||||||
packet_out->po_srecs.one.sr_len = len;
|
packet_out->po_srecs.one.sr_len = len;
|
||||||
|
++new_stream->n_unacked;
|
||||||
return 0; /* Insert in first slot */
|
return 0; /* Insert in first slot */
|
||||||
}
|
}
|
||||||
srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
|
srec_arr = lsquic_malo_get(mm->malo.stream_rec_arr);
|
||||||
|
@ -190,6 +191,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
srec_arr->srecs[i].sr_stream = new_stream;
|
srec_arr->srecs[i].sr_stream = new_stream;
|
||||||
srec_arr->srecs[i].sr_off = off;
|
srec_arr->srecs[i].sr_off = off;
|
||||||
srec_arr->srecs[i].sr_len = len;
|
srec_arr->srecs[i].sr_len = len;
|
||||||
|
++new_stream->n_unacked;
|
||||||
return 0; /* Insert in existing srec */
|
return 0; /* Insert in existing srec */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,6 +205,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
srec_arr->srecs[0].sr_off = off;
|
srec_arr->srecs[0].sr_off = off;
|
||||||
srec_arr->srecs[0].sr_len = len;
|
srec_arr->srecs[0].sr_len = len;
|
||||||
TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, next_stream_rec_arr);
|
TAILQ_INSERT_TAIL(&packet_out->po_srecs.arr, srec_arr, next_stream_rec_arr);
|
||||||
|
++new_stream->n_unacked;
|
||||||
return 0; /* Insert in new srec */
|
return 0; /* Insert in new srec */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +286,7 @@ lsquic_packet_out_destroy (lsquic_packet_out_t *packet_out,
|
||||||
/* If `stream_id' is zero, stream frames from all reset streams are elided.
|
/* If `stream_id' is zero, stream frames from all reset streams are elided.
|
||||||
* Otherwise, elision is limited to the specified stream.
|
* Otherwise, elision is limited to the specified stream.
|
||||||
*/
|
*/
|
||||||
void
|
unsigned
|
||||||
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
||||||
uint32_t stream_id)
|
uint32_t stream_id)
|
||||||
{
|
{
|
||||||
|
@ -335,6 +338,8 @@ lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
||||||
assert(n_stream_frames);
|
assert(n_stream_frames);
|
||||||
if (n_elided == n_stream_frames)
|
if (n_elided == n_stream_frames)
|
||||||
packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
||||||
|
|
||||||
|
return adj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -532,8 +537,8 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
new_packet_out->po_data + new_packet_out->po_data_sz,
|
new_packet_out->po_data + new_packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(new_packet_out), frame.stream_id,
|
lsquic_packet_out_avail(new_packet_out), frame.stream_id,
|
||||||
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
frame.data_frame.df_offset + frame.data_frame.df_size / 2,
|
||||||
split_reader_fin, split_reader_size, split_reader_read,
|
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
||||||
&reader_ctx);
|
split_reader_read, &reader_ctx);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not generate new frame 1");
|
LSQ_ERROR("could not generate new frame 1");
|
||||||
|
@ -544,6 +549,11 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
new_packet_out->po_data_sz, len))
|
new_packet_out->po_data_sz, len))
|
||||||
return -1;
|
return -1;
|
||||||
new_packet_out->po_data_sz += len;
|
new_packet_out->po_data_sz += len;
|
||||||
|
if (0 == lsquic_packet_out_avail(new_packet_out))
|
||||||
|
{
|
||||||
|
assert(0); /* We really should not fill here, but JIC */
|
||||||
|
new_packet_out->po_flags |= PO_STREAM_END;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(reader_ctx.buf, frame.data_frame.df_data,
|
memcpy(reader_ctx.buf, frame.data_frame.df_data,
|
||||||
frame.data_frame.df_size / 2);
|
frame.data_frame.df_size / 2);
|
||||||
|
@ -553,8 +563,8 @@ split_largest_frame (struct lsquic_mm *mm, lsquic_packet_out_t *packet_out,
|
||||||
len = pf->pf_gen_stream_frame(
|
len = pf->pf_gen_stream_frame(
|
||||||
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
packet_out->po_data + max_srec->sr_off, max_srec->sr_len,
|
||||||
frame.stream_id, frame.data_frame.df_offset,
|
frame.stream_id, frame.data_frame.df_offset,
|
||||||
split_reader_fin, split_reader_size, split_reader_read,
|
split_reader_fin(&reader_ctx), split_reader_size(&reader_ctx),
|
||||||
&reader_ctx);
|
split_reader_read, &reader_ctx);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not generate new frame 2");
|
LSQ_ERROR("could not generate new frame 2");
|
||||||
|
@ -611,11 +621,15 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
#endif
|
#endif
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
/* We only split buffered packets; buffered packets contain only STREAM
|
||||||
|
* frames:
|
||||||
|
*/
|
||||||
assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM));
|
assert(packet_out->po_frame_types == (1 << QUIC_FRAME_STREAM));
|
||||||
|
|
||||||
n_srecs = 0;
|
n_srecs = 0;
|
||||||
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
for (srec = posi_first(&posi, packet_out); srec; srec = posi_next(&posi))
|
||||||
{
|
{
|
||||||
|
/* We only expect references to STREAM frames (buffered packets): */
|
||||||
assert(srec->sr_frame_types == (1 << QUIC_FRAME_STREAM));
|
assert(srec->sr_frame_types == (1 << QUIC_FRAME_STREAM));
|
||||||
if (n_srecs >= n_srecs_alloced)
|
if (n_srecs >= n_srecs_alloced)
|
||||||
{
|
{
|
||||||
|
@ -688,13 +702,14 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
|
||||||
end:
|
end:
|
||||||
if (srecs != local_arr)
|
if (srecs != local_arr)
|
||||||
free(srecs);
|
free(srecs);
|
||||||
#ifndef NDEBUG
|
|
||||||
if (0 == rv)
|
if (0 == rv)
|
||||||
{
|
{
|
||||||
|
new_packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
|
||||||
|
#ifndef NDEBUG
|
||||||
verify_srecs(packet_out);
|
verify_srecs(packet_out);
|
||||||
verify_srecs(new_packet_out);
|
verify_srecs(new_packet_out);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct stream_rec {
|
||||||
struct lsquic_stream *sr_stream;
|
struct lsquic_stream *sr_stream;
|
||||||
unsigned short sr_off,
|
unsigned short sr_off,
|
||||||
sr_len;
|
sr_len;
|
||||||
short sr_frame_types;
|
enum quic_ft_bit sr_frame_types:16;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define srec_taken(srec) ((srec)->sr_frame_types)
|
#define srec_taken(srec) ((srec)->sr_frame_types)
|
||||||
|
@ -65,6 +65,36 @@ typedef struct lsquic_packet_out
|
||||||
lsquic_time_t po_sent; /* Time sent */
|
lsquic_time_t po_sent; /* Time sent */
|
||||||
lsquic_packno_t po_packno;
|
lsquic_packno_t po_packno;
|
||||||
|
|
||||||
|
enum packet_out_flags {
|
||||||
|
PO_HELLO = (1 << 1), /* Packet contains SHLO or CHLO data */
|
||||||
|
PO_ENCRYPTED= (1 << 3), /* po_enc_data has encrypted data */
|
||||||
|
PO_SREC_ARR = (1 << 4),
|
||||||
|
#define POBIT_SHIFT 5
|
||||||
|
PO_BITS_0 = (1 << 5), /* PO_BITS_0 and PO_BITS_1 encode the */
|
||||||
|
PO_BITS_1 = (1 << 6), /* packet number length. See macros below. */
|
||||||
|
PO_NONCE = (1 << 7), /* Use value in `po_nonce' to generate header */
|
||||||
|
PO_VERSION = (1 << 8), /* Use value in `po_ver_tag' to generate header */
|
||||||
|
PO_CONN_ID = (1 << 9), /* Include connection ID in public header */
|
||||||
|
PO_REPACKNO = (1 <<10), /* Regenerate packet number */
|
||||||
|
PO_NOENCRYPT= (1 <<11), /* Do not encrypt data in po_data */
|
||||||
|
PO_VERNEG = (1 <<12), /* Version negotiation packet. */
|
||||||
|
PO_STREAM_END
|
||||||
|
= (1 <<13), /* STREAM frame reaches the end of the packet: no
|
||||||
|
* further writes are allowed.
|
||||||
|
*/
|
||||||
|
PO_SCHED = (1 <<14), /* On scheduled queue */
|
||||||
|
} po_flags:16;
|
||||||
|
enum quic_ft_bit po_frame_types:16; /* Bitmask of QUIC_FRAME_* */
|
||||||
|
unsigned short po_data_sz; /* Number of usable bytes in data */
|
||||||
|
unsigned short po_enc_data_sz; /* Number of usable bytes in data */
|
||||||
|
unsigned short po_regen_sz; /* Number of bytes at the beginning
|
||||||
|
* of data containing bytes that are
|
||||||
|
* not to be retransmitted, e.g. ACK
|
||||||
|
* frames.
|
||||||
|
*/
|
||||||
|
unsigned short po_n_alloc; /* Total number of bytes allocated in po_data */
|
||||||
|
unsigned char *po_data;
|
||||||
|
|
||||||
/* A lot of packets contain data belonging to only one stream. Thus,
|
/* A lot of packets contain data belonging to only one stream. Thus,
|
||||||
* `one' is used first. If this is not enough, any number of
|
* `one' is used first. If this is not enough, any number of
|
||||||
* stream_rec_arr structures can be allocated to handle more stream
|
* stream_rec_arr structures can be allocated to handle more stream
|
||||||
|
@ -81,31 +111,7 @@ typedef struct lsquic_packet_out
|
||||||
unsigned char *po_enc_data;
|
unsigned char *po_enc_data;
|
||||||
|
|
||||||
lsquic_ver_tag_t po_ver_tag; /* Set if PO_VERSION is set */
|
lsquic_ver_tag_t po_ver_tag; /* Set if PO_VERSION is set */
|
||||||
short po_frame_types; /* Bitmask of QUIC_FRAME_* */
|
|
||||||
unsigned short po_data_sz; /* Number of usable bytes in data */
|
|
||||||
unsigned short po_enc_data_sz; /* Number of usable bytes in data */
|
|
||||||
unsigned short po_regen_sz; /* Number of bytes at the beginning
|
|
||||||
* of data containing bytes that are
|
|
||||||
* not to be retransmitted, e.g. ACK
|
|
||||||
* frames.
|
|
||||||
*/
|
|
||||||
unsigned short po_n_alloc; /* Total number of bytes allocated in po_data */
|
|
||||||
enum packet_out_flags {
|
|
||||||
PO_HELLO = (1 << 1), /* Packet contains SHLO or CHLO data */
|
|
||||||
PO_ENCRYPTED= (1 << 3), /* po_enc_data has encrypted data */
|
|
||||||
PO_SREC_ARR = (1 << 4),
|
|
||||||
#define POBIT_SHIFT 5
|
|
||||||
PO_BITS_0 = (1 << 5), /* PO_BITS_0 and PO_BITS_1 encode the */
|
|
||||||
PO_BITS_1 = (1 << 6), /* packet number length. See macros below. */
|
|
||||||
PO_NONCE = (1 << 7), /* Use value in `po_nonce' to generate header */
|
|
||||||
PO_VERSION = (1 << 8), /* Use value in `po_ver_tag' to generate header */
|
|
||||||
PO_CONN_ID = (1 << 9), /* Include connection ID in public header */
|
|
||||||
PO_REPACKNO = (1 <<10), /* Regenerate packet number */
|
|
||||||
PO_NOENCRYPT= (1 <<11), /* Do not encrypt data in po_data */
|
|
||||||
PO_VERNEG = (1 <<12), /* Version negotiation packet. */
|
|
||||||
} po_flags:16;
|
|
||||||
unsigned char *po_nonce; /* Use to generate header if PO_NONCE is set */
|
unsigned char *po_nonce; /* Use to generate header if PO_NONCE is set */
|
||||||
unsigned char *po_data;
|
|
||||||
} lsquic_packet_out_t;
|
} lsquic_packet_out_t;
|
||||||
|
|
||||||
/* The size of lsquic_packet_out_t could be further reduced:
|
/* The size of lsquic_packet_out_t could be further reduced:
|
||||||
|
@ -119,7 +125,11 @@ typedef struct lsquic_packet_out
|
||||||
|
|
||||||
#define lsquic_packet_out_packno_bits(p) (((p)->po_flags >> POBIT_SHIFT) & 0x3)
|
#define lsquic_packet_out_packno_bits(p) (((p)->po_flags >> POBIT_SHIFT) & 0x3)
|
||||||
|
|
||||||
/* XXX This will need to be made into a method for Q041 */
|
#define lsquic_packet_out_set_packno_bits(p, b) do { \
|
||||||
|
(p)->po_flags &= ~(0x3 << POBIT_SHIFT); \
|
||||||
|
(p)->po_flags |= ((b) & 0x3) << POBIT_SHIFT; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define lsquic_po_header_length(po_flags) ( \
|
#define lsquic_po_header_length(po_flags) ( \
|
||||||
1 /* Type */ \
|
1 /* Type */ \
|
||||||
+ (!!((po_flags) & PO_CONN_ID) << 3) /* Connection ID */ \
|
+ (!!((po_flags) & PO_CONN_ID) << 3) /* Connection ID */ \
|
||||||
|
@ -128,6 +138,10 @@ typedef struct lsquic_packet_out
|
||||||
+ packno_bits2len(((po_flags) >> POBIT_SHIFT) & 0x3) /* Packet number */ \
|
+ packno_bits2len(((po_flags) >> POBIT_SHIFT) & 0x3) /* Packet number */ \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#define lsquic_packet_out_total_sz(p) \
|
||||||
|
((p)->po_data_sz + lsquic_po_header_length((p)->po_flags) \
|
||||||
|
+ QUIC_PACKET_HASH_SZ)
|
||||||
|
|
||||||
#define lsquic_packet_out_verneg(p) \
|
#define lsquic_packet_out_verneg(p) \
|
||||||
(((p)->po_flags & (PO_NOENCRYPT|PO_VERNEG)) == (PO_NOENCRYPT|PO_VERNEG))
|
(((p)->po_flags & (PO_NOENCRYPT|PO_VERNEG)) == (PO_NOENCRYPT|PO_VERNEG))
|
||||||
|
|
||||||
|
@ -163,7 +177,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
|
||||||
enum QUIC_FRAME_TYPE,
|
enum QUIC_FRAME_TYPE,
|
||||||
unsigned short off, unsigned short len);
|
unsigned short off, unsigned short len);
|
||||||
|
|
||||||
void
|
unsigned
|
||||||
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *, uint32_t);
|
lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *, uint32_t);
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -17,9 +17,7 @@ typedef struct ack_info
|
||||||
unsigned n_ranges; /* This is at least 1 */
|
unsigned n_ranges; /* This is at least 1 */
|
||||||
/* Largest acked is ack_info.ranges[0].high */
|
/* Largest acked is ack_info.ranges[0].high */
|
||||||
lsquic_time_t lack_delta;
|
lsquic_time_t lack_delta;
|
||||||
struct {
|
struct lsquic_packno_range ranges[256];
|
||||||
lsquic_packno_t high, low;
|
|
||||||
} ranges[256];
|
|
||||||
#if LSQUIC_PARSE_ACK_TIMESTAMPS
|
#if LSQUIC_PARSE_ACK_TIMESTAMPS
|
||||||
struct {
|
struct {
|
||||||
/* Currently we just read these timestamps in (assuming it is
|
/* Currently we just read these timestamps in (assuming it is
|
||||||
|
@ -47,8 +45,6 @@ typedef lsquic_time_t
|
||||||
(*gaf_rechist_largest_recv_f) (void *rechist);
|
(*gaf_rechist_largest_recv_f) (void *rechist);
|
||||||
|
|
||||||
/* gsf_: generate stream frame */
|
/* gsf_: generate stream frame */
|
||||||
typedef int (*gsf_fin_f) (void *stream);
|
|
||||||
typedef size_t (*gsf_size_f) (void *stream);
|
|
||||||
typedef size_t (*gsf_read_f) (void *stream, void *buf, size_t len, int *fin);
|
typedef size_t (*gsf_read_f) (void *stream, void *buf, size_t len, int *fin);
|
||||||
|
|
||||||
struct packin_parse_state {
|
struct packin_parse_state {
|
||||||
|
@ -81,7 +77,7 @@ struct parse_funcs
|
||||||
int
|
int
|
||||||
(*pf_gen_stream_frame) (unsigned char *buf, size_t bufsz,
|
(*pf_gen_stream_frame) (unsigned char *buf, size_t bufsz,
|
||||||
uint32_t stream_id, uint64_t offset,
|
uint32_t stream_id, uint64_t offset,
|
||||||
gsf_fin_f, gsf_size_f, gsf_read_f, void *stream);
|
int fin, size_t size, gsf_read_f, void *stream);
|
||||||
unsigned
|
unsigned
|
||||||
(*pf_parse_stream_frame_header_sz) (unsigned char type);
|
(*pf_parse_stream_frame_header_sz) (unsigned char type);
|
||||||
int
|
int
|
||||||
|
|
|
@ -164,13 +164,12 @@ gquic_ietf_calc_stream_frame_header_sz (uint32_t stream_id, uint64_t offset)
|
||||||
|
|
||||||
int
|
int
|
||||||
gquic_ietf_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
gquic_ietf_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
||||||
uint64_t offset, gsf_fin_f gsf_fin, gsf_size_f gsf_size,
|
uint64_t offset, int fin, size_t size,
|
||||||
gsf_read_f gsf_read, void *stream)
|
gsf_read_f gsf_read, void *stream)
|
||||||
{
|
{
|
||||||
/* 11FSSOOD */
|
/* 11FSSOOD */
|
||||||
unsigned slen, olen, dlen;
|
unsigned slen, olen, dlen;
|
||||||
unsigned char *p = buf + 1;
|
unsigned char *p = buf + 1;
|
||||||
int fin;
|
|
||||||
|
|
||||||
/* SS: Stream ID length: 1, 2, 3, or 4 bytes */
|
/* SS: Stream ID length: 1, 2, 3, or 4 bytes */
|
||||||
slen = (stream_id > 0x0000FF)
|
slen = (stream_id > 0x0000FF)
|
||||||
|
@ -184,13 +183,11 @@ gquic_ietf_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream
|
||||||
+ ((offset > 1) << 1)
|
+ ((offset > 1) << 1)
|
||||||
;
|
;
|
||||||
|
|
||||||
fin = gsf_fin(stream);
|
|
||||||
if (!fin)
|
if (!fin)
|
||||||
{
|
{
|
||||||
unsigned size, n_avail;
|
unsigned n_avail;
|
||||||
uint16_t nr;
|
uint16_t nr;
|
||||||
|
|
||||||
size = gsf_size(stream);
|
|
||||||
n_avail = buf_len - (p + slen + olen - buf);
|
n_avail = buf_len - (p + slen + olen - buf);
|
||||||
|
|
||||||
/* If we cannot fill remaining buffer, we need to include data
|
/* If we cannot fill remaining buffer, we need to include data
|
||||||
|
|
|
@ -128,40 +128,55 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
|
||||||
|
|
||||||
packnum_len = packno_bits2len(bits);
|
packnum_len = packno_bits2len(bits);
|
||||||
|
|
||||||
header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5)
|
if (!(conn_id || ver || nonce))
|
||||||
+ packnum_len;
|
|
||||||
if (header_len > bufsz)
|
|
||||||
{
|
{
|
||||||
errno = ENOBUFS;
|
header_len = 1 + packnum_len;
|
||||||
return -1;
|
if (header_len > bufsz)
|
||||||
|
{
|
||||||
|
errno = ENOBUFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
p = buf;
|
||||||
|
*p = bits << 4;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header_len = 1 + (!!conn_id << 3) + (!!ver << 2) + ((!!nonce) << 5)
|
||||||
|
+ packnum_len;
|
||||||
|
if (header_len > bufsz)
|
||||||
|
{
|
||||||
|
errno = ENOBUFS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
|
||||||
|
*p = (!!conn_id << 3)
|
||||||
|
| (bits << 4)
|
||||||
|
| ((!!nonce) << 2)
|
||||||
|
| !!ver;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (conn_id)
|
||||||
|
{
|
||||||
|
memcpy(p, conn_id , sizeof(*conn_id));
|
||||||
|
p += sizeof(*conn_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ver)
|
||||||
|
{
|
||||||
|
memcpy(p, ver, 4);
|
||||||
|
p += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonce)
|
||||||
|
{
|
||||||
|
memcpy(p, nonce , 32);
|
||||||
|
p += 32;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = buf;
|
|
||||||
|
|
||||||
*p = (!!conn_id << 3)
|
|
||||||
| (bits << 4)
|
|
||||||
| ((!!nonce) << 2)
|
|
||||||
| !!ver;
|
|
||||||
++p;
|
|
||||||
|
|
||||||
if (conn_id)
|
|
||||||
{
|
|
||||||
memcpy(p, conn_id , sizeof(*conn_id));
|
|
||||||
p += sizeof(*conn_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ver)
|
|
||||||
{
|
|
||||||
memcpy(p, ver, 4);
|
|
||||||
p += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonce)
|
|
||||||
{
|
|
||||||
memcpy(p, nonce , 32);
|
|
||||||
p += 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
packno = bswap_64(packno);
|
packno = bswap_64(packno);
|
||||||
#endif
|
#endif
|
||||||
|
@ -176,13 +191,12 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
|
||||||
|
|
||||||
int
|
int
|
||||||
gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
||||||
uint64_t offset, gsf_fin_f gsf_fin, gsf_size_f gsf_size,
|
uint64_t offset, int fin, size_t size,
|
||||||
gsf_read_f gsf_read, void *stream)
|
gsf_read_f gsf_read, void *stream)
|
||||||
{
|
{
|
||||||
/* 1fdoooss */
|
/* 1fdoooss */
|
||||||
unsigned slen, olen, dlen;
|
unsigned slen, olen, dlen;
|
||||||
unsigned char *p = buf + 1;
|
unsigned char *p = buf + 1;
|
||||||
int fin;
|
|
||||||
|
|
||||||
/* ss: Stream ID length: 1, 2, 3, or 4 bytes */
|
/* ss: Stream ID length: 1, 2, 3, or 4 bytes */
|
||||||
slen = (stream_id > 0x0000FF)
|
slen = (stream_id > 0x0000FF)
|
||||||
|
@ -199,13 +213,11 @@ gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_i
|
||||||
+ (offset >= (1ULL << 16))
|
+ (offset >= (1ULL << 16))
|
||||||
+ ((offset > 0) << 1);
|
+ ((offset > 0) << 1);
|
||||||
|
|
||||||
fin = gsf_fin(stream);
|
|
||||||
if (!fin)
|
if (!fin)
|
||||||
{
|
{
|
||||||
unsigned size, n_avail;
|
unsigned n_avail;
|
||||||
uint16_t nr;
|
uint16_t nr;
|
||||||
|
|
||||||
size = gsf_size(stream);
|
|
||||||
n_avail = buf_len - (p + slen + olen - buf);
|
n_avail = buf_len - (p + slen + olen - buf);
|
||||||
|
|
||||||
/* If we cannot fill remaining buffer, we need to include data
|
/* If we cannot fill remaining buffer, we need to include data
|
||||||
|
@ -371,11 +383,51 @@ gquic_be_parse_ack_high (const unsigned char *buf, size_t buf_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return parsed (used) buffer length.
|
static int
|
||||||
* If parsing failed, negative value is returned.
|
parse_ack_frame_without_blocks (const unsigned char *buf, size_t buf_len,
|
||||||
*/
|
ack_info_t *ack)
|
||||||
int
|
{
|
||||||
gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *ack)
|
/* 01nullmm */
|
||||||
|
lsquic_packno_t tmp_packno;
|
||||||
|
const unsigned char type = buf[0];
|
||||||
|
const unsigned char *p = buf + 1;
|
||||||
|
const unsigned char *const pend = buf + buf_len;
|
||||||
|
|
||||||
|
const int ack_block_len = twobit_to_1246(type & 3); /* mm */
|
||||||
|
const int largest_obs_len = twobit_to_1246((type >> 2) & 3); /* ll */
|
||||||
|
|
||||||
|
CHECK_SPACE(largest_obs_len + 2 + ack_block_len + 1, p, pend);
|
||||||
|
|
||||||
|
READ_UINT(ack->ranges[0].high, 64, p, largest_obs_len);
|
||||||
|
p += largest_obs_len;
|
||||||
|
|
||||||
|
ack->lack_delta = gquic_be_read_float_time16(p);
|
||||||
|
p += 2;
|
||||||
|
|
||||||
|
READ_UINT(tmp_packno, 64, p, ack_block_len);
|
||||||
|
ack->ranges[0].low = ack->ranges[0].high - tmp_packno + 1;
|
||||||
|
p += ack_block_len;
|
||||||
|
|
||||||
|
ack->n_ranges = 1;
|
||||||
|
|
||||||
|
ack->n_timestamps = *p;
|
||||||
|
++p;
|
||||||
|
|
||||||
|
if (ack->n_timestamps)
|
||||||
|
{
|
||||||
|
unsigned timestamps_size = 5 + 3 * (ack->n_timestamps - 1);
|
||||||
|
CHECK_SPACE(timestamps_size, p, pend);
|
||||||
|
p += timestamps_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(p <= pend);
|
||||||
|
|
||||||
|
return p - (unsigned char *) buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_ack_frame_with_blocks (const unsigned char *buf, size_t buf_len, ack_info_t *ack)
|
||||||
{
|
{
|
||||||
/* 01nullmm */
|
/* 01nullmm */
|
||||||
lsquic_packno_t tmp_packno;
|
lsquic_packno_t tmp_packno;
|
||||||
|
@ -388,54 +440,42 @@ gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *
|
||||||
const int ack_block_len = twobit_to_1246(type & 3); /* mm */
|
const int ack_block_len = twobit_to_1246(type & 3); /* mm */
|
||||||
const int largest_obs_len = twobit_to_1246((type >> 2) & 3); /* ll */
|
const int largest_obs_len = twobit_to_1246((type >> 2) & 3); /* ll */
|
||||||
|
|
||||||
CHECK_SPACE(largest_obs_len, p , pend);
|
CHECK_SPACE(largest_obs_len + 2 + 1 + ack_block_len, p, pend);
|
||||||
|
|
||||||
READ_UINT(ack->ranges[0].high, 64, p, largest_obs_len);
|
READ_UINT(ack->ranges[0].high, 64, p, largest_obs_len);
|
||||||
p += largest_obs_len;
|
p += largest_obs_len;
|
||||||
|
|
||||||
CHECK_SPACE(2, p , pend);
|
|
||||||
ack->lack_delta = gquic_be_read_float_time16(p);
|
ack->lack_delta = gquic_be_read_float_time16(p);
|
||||||
p += 2;
|
p += 2;
|
||||||
|
|
||||||
unsigned n_blocks;
|
unsigned n_blocks;
|
||||||
if (type & 0x20)
|
CHECK_SPACE(1, p , pend);
|
||||||
{
|
n_blocks = *p;
|
||||||
CHECK_SPACE(1, p , pend);
|
++p;
|
||||||
n_blocks = *p;
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
n_blocks = 0;
|
|
||||||
|
|
||||||
CHECK_SPACE(ack_block_len, p , pend);
|
|
||||||
READ_UINT(tmp_packno, 64, p, ack_block_len);
|
READ_UINT(tmp_packno, 64, p, ack_block_len);
|
||||||
ack->ranges[0].low = ack->ranges[0].high - tmp_packno + 1;
|
ack->ranges[0].low = ack->ranges[0].high - tmp_packno + 1;
|
||||||
p += ack_block_len;
|
p += ack_block_len;
|
||||||
|
|
||||||
if (n_blocks)
|
CHECK_SPACE((ack_block_len + 1) * n_blocks + /* timestamp count: */ 1,
|
||||||
|
p , pend);
|
||||||
|
unsigned i, n, gap;
|
||||||
|
for (i = 0, n = 1, gap = 0; i < n_blocks; ++i)
|
||||||
{
|
{
|
||||||
CHECK_SPACE((ack_block_len + 1) * n_blocks, p , pend);
|
uint64_t length;
|
||||||
unsigned i, n, gap;
|
gap += *p;
|
||||||
for (i = 0, n = 1, gap = 0; i < n_blocks; ++i)
|
READ_UINT(length, 64, p + 1, ack_block_len);
|
||||||
|
p += 1 + ack_block_len;
|
||||||
|
if (length)
|
||||||
{
|
{
|
||||||
uint64_t length;
|
ack->ranges[n].high = ack->ranges[n - 1].low - gap - 1;
|
||||||
gap += *p;
|
ack->ranges[n].low = ack->ranges[n].high - length + 1;
|
||||||
READ_UINT(length, 64, p + 1, ack_block_len);
|
++n;
|
||||||
p += 1 + ack_block_len;
|
gap = 0;
|
||||||
if (length)
|
|
||||||
{
|
|
||||||
ack->ranges[n].high = ack->ranges[n - 1].low - gap - 1;
|
|
||||||
ack->ranges[n].low = ack->ranges[n].high - length + 1;
|
|
||||||
++n;
|
|
||||||
gap = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ack->n_ranges = n;
|
|
||||||
}
|
}
|
||||||
else
|
ack->n_ranges = n;
|
||||||
ack->n_ranges = 1;
|
|
||||||
|
|
||||||
CHECK_SPACE(1, p , pend);
|
|
||||||
ack->n_timestamps = *p;
|
ack->n_timestamps = *p;
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
|
@ -469,6 +509,19 @@ gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return parsed (used) buffer length.
|
||||||
|
* If parsing failed, negative value is returned.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *ack)
|
||||||
|
{
|
||||||
|
if (!(buf[0] & 0x20))
|
||||||
|
return parse_ack_frame_without_blocks(buf, buf_len, ack);
|
||||||
|
else
|
||||||
|
return parse_ack_frame_with_blocks(buf, buf_len, ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
gquic_be_gen_stop_waiting_frame(unsigned char *buf, size_t buf_len,
|
gquic_be_gen_stop_waiting_frame(unsigned char *buf, size_t buf_len,
|
||||||
lsquic_packno_t cur_packno, enum lsquic_packno_bits bits,
|
lsquic_packno_t cur_packno, enum lsquic_packno_bits bits,
|
||||||
|
|
|
@ -61,7 +61,7 @@ gquic_be_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
|
||||||
|
|
||||||
int
|
int
|
||||||
gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
gquic_be_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
||||||
uint64_t offset, gsf_fin_f gsf_fin, gsf_size_f gsf_size,
|
uint64_t offset, int fin, size_t size,
|
||||||
gsf_read_f gsf_read, void *stream);
|
gsf_read_f gsf_read, void *stream);
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -193,13 +193,12 @@ gquic_le_gen_reg_pkt_header (unsigned char *buf, size_t bufsz, const lsquic_cid_
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gquic_le_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
gquic_le_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_id,
|
||||||
uint64_t offset, gsf_fin_f gsf_fin, gsf_size_f gsf_size,
|
uint64_t offset, int fin, size_t size,
|
||||||
gsf_read_f gsf_read, void *stream)
|
gsf_read_f gsf_read, void *stream)
|
||||||
{
|
{
|
||||||
/* 1fdoooss */
|
/* 1fdoooss */
|
||||||
unsigned slen, olen, dlen;
|
unsigned slen, olen, dlen;
|
||||||
unsigned char *p = buf + 1;
|
unsigned char *p = buf + 1;
|
||||||
int fin;
|
|
||||||
|
|
||||||
/* ss: Stream ID length: 1, 2, 3, or 4 bytes */
|
/* ss: Stream ID length: 1, 2, 3, or 4 bytes */
|
||||||
slen = (stream_id > 0x0000FF)
|
slen = (stream_id > 0x0000FF)
|
||||||
|
@ -216,13 +215,11 @@ gquic_le_gen_stream_frame (unsigned char *buf, size_t buf_len, uint32_t stream_i
|
||||||
+ (offset >= (1ULL << 16))
|
+ (offset >= (1ULL << 16))
|
||||||
+ ((offset > 0) << 1);
|
+ ((offset > 0) << 1);
|
||||||
|
|
||||||
fin = gsf_fin(stream);
|
|
||||||
if (!fin)
|
if (!fin)
|
||||||
{
|
{
|
||||||
unsigned size, n_avail;
|
unsigned n_avail;
|
||||||
uint16_t nr;
|
uint16_t nr;
|
||||||
|
|
||||||
size = gsf_size(stream);
|
|
||||||
n_avail = buf_len - (p + slen + olen - buf);
|
n_avail = buf_len - (p + slen + olen - buf);
|
||||||
|
|
||||||
/* If we cannot fill remaining buffer, we need to include data
|
/* If we cannot fill remaining buffer, we need to include data
|
||||||
|
|
|
@ -78,6 +78,9 @@ set_retx_alarm (lsquic_send_ctl_t *ctl);
|
||||||
static void
|
static void
|
||||||
send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time);
|
send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time);
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
send_ctl_retx_bytes_out (const struct lsquic_send_ctl *ctl);
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
static
|
static
|
||||||
|
@ -275,7 +278,7 @@ calculate_tlp_delay (lsquic_send_ctl_t *ctl)
|
||||||
lsquic_time_t srtt, delay;
|
lsquic_time_t srtt, delay;
|
||||||
|
|
||||||
srtt = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
srtt = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
||||||
if (ctl->sc_n_in_flight > 1)
|
if (ctl->sc_n_in_flight_all > 1)
|
||||||
{
|
{
|
||||||
delay = 10000; /* 10 ms is the minimum tail loss probe delay */
|
delay = 10000; /* 10 ms is the minimum tail loss probe delay */
|
||||||
if (delay < 2 * srtt)
|
if (delay < 2 * srtt)
|
||||||
|
@ -313,9 +316,14 @@ set_retx_alarm (lsquic_send_ctl_t *ctl)
|
||||||
* handshake_count++;
|
* handshake_count++;
|
||||||
*/
|
*/
|
||||||
delay = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
delay = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
||||||
delay += delay / 2;
|
if (delay)
|
||||||
if (10000 > delay)
|
{
|
||||||
delay = 10000;
|
delay += delay / 2;
|
||||||
|
if (10000 > delay)
|
||||||
|
delay = 10000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
delay = 150000;
|
||||||
delay <<= ctl->sc_n_hsk;
|
delay <<= ctl->sc_n_hsk;
|
||||||
++ctl->sc_n_hsk;
|
++ctl->sc_n_hsk;
|
||||||
break;
|
break;
|
||||||
|
@ -363,13 +371,13 @@ send_ctl_transfer_time (void *ctx)
|
||||||
lsquic_send_ctl_t *const ctl = ctx;
|
lsquic_send_ctl_t *const ctl = ctx;
|
||||||
uint64_t bandwidth, pacing_rate;
|
uint64_t bandwidth, pacing_rate;
|
||||||
lsquic_time_t srtt, tx_time;
|
lsquic_time_t srtt, tx_time;
|
||||||
unsigned cwnd;
|
unsigned long cwnd;
|
||||||
|
|
||||||
srtt = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
srtt = lsquic_rtt_stats_get_srtt(&ctl->sc_conn_pub->rtt_stats);
|
||||||
if (srtt == 0)
|
if (srtt == 0)
|
||||||
srtt = 50000;
|
srtt = 50000;
|
||||||
cwnd = lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
cwnd = lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
||||||
bandwidth = (uint64_t) cwnd * (uint64_t) ctl->sc_pack_size * 1000000 / srtt;
|
bandwidth = cwnd * 1000000 / srtt;
|
||||||
if (send_ctl_in_slow_start(ctl))
|
if (send_ctl_in_slow_start(ctl))
|
||||||
pacing_rate = bandwidth * 2;
|
pacing_rate = bandwidth * 2;
|
||||||
else if (send_ctl_in_recovery(ctl))
|
else if (send_ctl_in_recovery(ctl))
|
||||||
|
@ -378,31 +386,113 @@ send_ctl_transfer_time (void *ctx)
|
||||||
pacing_rate = bandwidth + bandwidth / 4;
|
pacing_rate = bandwidth + bandwidth / 4;
|
||||||
|
|
||||||
tx_time = (uint64_t) ctl->sc_pack_size * 1000000 / pacing_rate;
|
tx_time = (uint64_t) ctl->sc_pack_size * 1000000 / pacing_rate;
|
||||||
LSQ_DEBUG("srtt: %"PRIu64"; ss: %d; rec: %d; cwnd: %u; bandwidth: "
|
LSQ_DEBUG("srtt: %"PRIu64"; ss: %d; rec: %d; cwnd: %lu; bandwidth: "
|
||||||
"%"PRIu64"; tx_time: %"PRIu64, srtt, send_ctl_in_slow_start(ctl),
|
"%"PRIu64"; tx_time: %"PRIu64, srtt, send_ctl_in_slow_start(ctl),
|
||||||
send_ctl_in_recovery(ctl), cwnd, bandwidth, tx_time);
|
send_ctl_in_recovery(ctl), cwnd, bandwidth, tx_time);
|
||||||
return tx_time;
|
return tx_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_unacked_append (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
TAILQ_INSERT_TAIL(&ctl->sc_unacked_packets, packet_out, po_next);
|
||||||
|
ctl->sc_bytes_unacked_all += lsquic_packet_out_total_sz(packet_out);
|
||||||
|
ctl->sc_n_in_flight_all += 1;
|
||||||
|
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
|
{
|
||||||
|
ctl->sc_bytes_unacked_retx += lsquic_packet_out_total_sz(packet_out);
|
||||||
|
++ctl->sc_n_in_flight_retx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_unacked_remove (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
unsigned packet_sz;
|
||||||
|
|
||||||
|
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
||||||
|
packet_sz = lsquic_packet_out_total_sz(packet_out);
|
||||||
|
assert(ctl->sc_bytes_unacked_all >= packet_sz);
|
||||||
|
ctl->sc_bytes_unacked_all -= packet_sz;
|
||||||
|
ctl->sc_n_in_flight_all -= 1;
|
||||||
|
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
|
{
|
||||||
|
ctl->sc_bytes_unacked_retx -= packet_sz;
|
||||||
|
--ctl->sc_n_in_flight_retx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_sched_Xpend_common (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
packet_out->po_flags |= PO_SCHED;
|
||||||
|
++ctl->sc_n_scheduled;
|
||||||
|
ctl->sc_bytes_scheduled += lsquic_packet_out_total_sz(packet_out);
|
||||||
|
lsquic_send_ctl_sanity_check(ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_sched_append (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
TAILQ_INSERT_TAIL(&ctl->sc_scheduled_packets, packet_out, po_next);
|
||||||
|
send_ctl_sched_Xpend_common(ctl, packet_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_sched_prepend (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
TAILQ_INSERT_HEAD(&ctl->sc_scheduled_packets, packet_out, po_next);
|
||||||
|
send_ctl_sched_Xpend_common(ctl, packet_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ctl_sched_remove (struct lsquic_send_ctl *ctl,
|
||||||
|
struct lsquic_packet_out *packet_out)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
||||||
|
packet_out->po_flags &= ~PO_SCHED;
|
||||||
|
assert(ctl->sc_n_scheduled);
|
||||||
|
--ctl->sc_n_scheduled;
|
||||||
|
ctl->sc_bytes_scheduled -= lsquic_packet_out_total_sz(packet_out);
|
||||||
|
lsquic_send_ctl_sanity_check(ctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
|
lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
|
||||||
struct lsquic_packet_out *packet_out)
|
struct lsquic_packet_out *packet_out, int account)
|
||||||
{
|
{
|
||||||
char frames[lsquic_frame_types_str_sz];
|
char frames[lsquic_frame_types_str_sz];
|
||||||
LSQ_DEBUG("packet %"PRIu64" has been sent (frame types: %s)",
|
LSQ_DEBUG("packet %"PRIu64" has been sent (frame types: %s)",
|
||||||
packet_out->po_packno, lsquic_frame_types_to_str(frames,
|
packet_out->po_packno, lsquic_frame_types_to_str(frames,
|
||||||
sizeof(frames), packet_out->po_frame_types));
|
sizeof(frames), packet_out->po_frame_types));
|
||||||
|
if (account)
|
||||||
|
ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out);
|
||||||
if (0 == lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno))
|
if (0 == lsquic_senhist_add(&ctl->sc_senhist, packet_out->po_packno))
|
||||||
{
|
{
|
||||||
TAILQ_INSERT_TAIL(&ctl->sc_unacked_packets, packet_out, po_next);
|
send_ctl_unacked_append(ctl, packet_out);
|
||||||
if ((packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK) &&
|
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
!lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX))
|
{
|
||||||
set_retx_alarm(ctl);
|
if (!lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX))
|
||||||
|
set_retx_alarm(ctl);
|
||||||
|
if (ctl->sc_n_in_flight_retx == 1)
|
||||||
|
ctl->sc_flags |= SC_WAS_QUIET;
|
||||||
|
}
|
||||||
|
/* TODO: Do we really want to use those for RTT info? Revisit this. */
|
||||||
/* Hold on to packets that are not retransmittable because we need them
|
/* Hold on to packets that are not retransmittable because we need them
|
||||||
* to sample RTT information. They are released when ACK is received.
|
* to sample RTT information. They are released when ACK is received.
|
||||||
*/
|
*/
|
||||||
++ctl->sc_n_in_flight;
|
|
||||||
#if LSQUIC_SEND_STATS
|
#if LSQUIC_SEND_STATS
|
||||||
++ctl->sc_stats.n_total_sent;
|
++ctl->sc_stats.n_total_sent;
|
||||||
#endif
|
#endif
|
||||||
|
@ -413,28 +503,6 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
in_acked_range (const ack_info_t *acki, lsquic_packno_t packno)
|
|
||||||
{
|
|
||||||
int i, low, high;
|
|
||||||
|
|
||||||
low = 0, high = (int) acki->n_ranges - 1;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
i = low + (high - low) / 2;
|
|
||||||
if (acki->ranges[i].low <= packno && acki->ranges[i].high >= packno)
|
|
||||||
return 1;
|
|
||||||
else if (acki->ranges[i].high < packno)
|
|
||||||
high = i - 1;
|
|
||||||
else
|
|
||||||
low = i + 1;
|
|
||||||
}
|
|
||||||
while (low <= high);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
take_rtt_sample (lsquic_send_ctl_t *ctl, const lsquic_packet_out_t *packet_out,
|
take_rtt_sample (lsquic_send_ctl_t *ctl, const lsquic_packet_out_t *packet_out,
|
||||||
lsquic_time_t now, lsquic_time_t lack_delta)
|
lsquic_time_t now, lsquic_time_t lack_delta)
|
||||||
|
@ -459,9 +527,8 @@ static int
|
||||||
send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl,
|
send_ctl_handle_lost_packet (lsquic_send_ctl_t *ctl,
|
||||||
lsquic_packet_out_t *packet_out)
|
lsquic_packet_out_t *packet_out)
|
||||||
{
|
{
|
||||||
assert(ctl->sc_n_in_flight);
|
assert(ctl->sc_n_in_flight_all);
|
||||||
--ctl->sc_n_in_flight;
|
send_ctl_unacked_remove(ctl, packet_out);
|
||||||
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
|
||||||
if (packet_out->po_flags & PO_ENCRYPTED) {
|
if (packet_out->po_flags & PO_ENCRYPTED) {
|
||||||
ctl->sc_enpub->enp_pmi->pmi_release(ctl->sc_enpub->enp_pmi_ctx,
|
ctl->sc_enpub->enp_pmi->pmi_release(ctl->sc_enpub->enp_pmi_ctx,
|
||||||
packet_out->po_enc_data);
|
packet_out->po_enc_data);
|
||||||
|
@ -512,7 +579,6 @@ send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time)
|
||||||
|
|
||||||
largest_retx_packno = largest_retx_packet_number(ctl);
|
largest_retx_packno = largest_retx_packet_number(ctl);
|
||||||
largest_lost_packno = 0;
|
largest_lost_packno = 0;
|
||||||
assert(largest_retx_packno); /* Otherwise, why detect losses? */
|
|
||||||
ctl->sc_loss_to = 0;
|
ctl->sc_loss_to = 0;
|
||||||
|
|
||||||
for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets);
|
for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets);
|
||||||
|
@ -531,8 +597,9 @@ send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK) &&
|
if (largest_retx_packno
|
||||||
largest_retx_packno <= ctl->sc_largest_acked_packno)
|
&& (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
|
&& largest_retx_packno <= ctl->sc_largest_acked_packno)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("loss by early retransmit detected, packet %"PRIu64,
|
LSQ_DEBUG("loss by early retransmit detected, packet %"PRIu64,
|
||||||
packet_out->po_packno);
|
packet_out->po_packno);
|
||||||
|
@ -550,7 +617,9 @@ send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("loss by sent time detected: packet %"PRIu64,
|
LSQ_DEBUG("loss by sent time detected: packet %"PRIu64,
|
||||||
packet_out->po_packno);
|
packet_out->po_packno);
|
||||||
largest_lost_packno = packet_out->po_packno;
|
if (packet_out->po_frame_types & QFRAME_RETRANSMITTABLE_MASK)
|
||||||
|
largest_lost_packno = packet_out->po_packno;
|
||||||
|
else { /* don't count it as a loss */; }
|
||||||
(void) send_ctl_handle_lost_packet(ctl, packet_out);
|
(void) send_ctl_handle_lost_packet(ctl, packet_out);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -561,6 +630,8 @@ send_ctl_detect_losses (lsquic_send_ctl_t *ctl, lsquic_time_t time)
|
||||||
LSQ_DEBUG("detected new loss: packet %"PRIu64"; new lsac: "
|
LSQ_DEBUG("detected new loss: packet %"PRIu64"; new lsac: "
|
||||||
"%"PRIu64, largest_lost_packno, ctl->sc_largest_sent_at_cutback);
|
"%"PRIu64, largest_lost_packno, ctl->sc_largest_sent_at_cutback);
|
||||||
lsquic_cubic_loss(&ctl->sc_cubic);
|
lsquic_cubic_loss(&ctl->sc_cubic);
|
||||||
|
if (ctl->sc_flags & SC_PACE)
|
||||||
|
pacer_loss_event(&ctl->sc_pacer);
|
||||||
ctl->sc_largest_sent_at_cutback =
|
ctl->sc_largest_sent_at_cutback =
|
||||||
lsquic_senhist_largest(&ctl->sc_senhist);
|
lsquic_senhist_largest(&ctl->sc_senhist);
|
||||||
}
|
}
|
||||||
|
@ -581,6 +652,10 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
{
|
{
|
||||||
struct lsquic_packets_tailq acked_acks =
|
struct lsquic_packets_tailq acked_acks =
|
||||||
TAILQ_HEAD_INITIALIZER(acked_acks);
|
TAILQ_HEAD_INITIALIZER(acked_acks);
|
||||||
|
#if !LSQUIC_CAN_REORDER
|
||||||
|
const struct lsquic_packno_range *range =
|
||||||
|
&acki->ranges[ acki->n_ranges - 1 ];
|
||||||
|
#endif
|
||||||
lsquic_packet_out_t *packet_out, *next;
|
lsquic_packet_out_t *packet_out, *next;
|
||||||
lsquic_time_t now = lsquic_time_now();
|
lsquic_time_t now = lsquic_time_now();
|
||||||
lsquic_packno_t high;
|
lsquic_packno_t high;
|
||||||
|
@ -601,6 +676,13 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctl->sc_flags & SC_WAS_QUIET)
|
||||||
|
{
|
||||||
|
ctl->sc_flags &= ~SC_WAS_QUIET;
|
||||||
|
LSQ_DEBUG("ACK comes after a period of quiescence");
|
||||||
|
lsquic_cubic_was_quiet(&ctl->sc_cubic, now);
|
||||||
|
}
|
||||||
|
|
||||||
/* Peer is acking packets that have been acked already. Schedule ACK
|
/* Peer is acking packets that have been acked already. Schedule ACK
|
||||||
* and STOP_WAITING frame to chop the range if we get two of these in
|
* and STOP_WAITING frame to chop the range if we get two of these in
|
||||||
* a row.
|
* a row.
|
||||||
|
@ -610,16 +692,31 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
else
|
else
|
||||||
ctl->sc_n_stop_waiting = 0;
|
ctl->sc_n_stop_waiting = 0;
|
||||||
|
|
||||||
app_limited = ctl->sc_n_in_flight + 3 /* This is the "maximum
|
app_limited = send_ctl_retx_bytes_out(ctl) + 3 * ctl->sc_pack_size /* This
|
||||||
burst" parameter */ < lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
is the "maximum burst" parameter */
|
||||||
|
< lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
||||||
|
|
||||||
for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets);
|
for (packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets);
|
||||||
packet_out && packet_out->po_packno <= largest_acked(acki);
|
packet_out
|
||||||
|
#if !LSQUIC_CAN_REORDER
|
||||||
|
&& packet_out->po_packno <= largest_acked(acki)
|
||||||
|
#endif
|
||||||
|
;
|
||||||
packet_out = next)
|
packet_out = next)
|
||||||
{
|
{
|
||||||
next = TAILQ_NEXT(packet_out, po_next);
|
next = TAILQ_NEXT(packet_out, po_next);
|
||||||
|
#if LSQUIC_CAN_REORDER
|
||||||
if (!in_acked_range(acki, packet_out->po_packno))
|
if (!in_acked_range(acki, packet_out->po_packno))
|
||||||
continue;
|
continue;
|
||||||
|
#else
|
||||||
|
/* This is faster than binary search in the normal case when the number
|
||||||
|
* of ranges is not much larger than the number of unacked packets.
|
||||||
|
*/
|
||||||
|
while (range->high < packet_out->po_packno)
|
||||||
|
--range;
|
||||||
|
if (range->low > packet_out->po_packno)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
ctl->sc_largest_acked_packno = packet_out->po_packno;
|
ctl->sc_largest_acked_packno = packet_out->po_packno;
|
||||||
ctl->sc_largest_acked_sent_time = packet_out->po_sent;
|
ctl->sc_largest_acked_sent_time = packet_out->po_sent;
|
||||||
if (packet_out->po_packno == largest_acked(acki))
|
if (packet_out->po_packno == largest_acked(acki))
|
||||||
|
@ -628,18 +725,20 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
++rtt_updated;
|
++rtt_updated;
|
||||||
}
|
}
|
||||||
lsquic_cubic_ack(&ctl->sc_cubic, now, now - packet_out->po_sent,
|
lsquic_cubic_ack(&ctl->sc_cubic, now, now - packet_out->po_sent,
|
||||||
app_limited);
|
app_limited, lsquic_packet_out_total_sz(packet_out));
|
||||||
LSQ_DEBUG("Got ACK for packet %"PRIu64", remove from unacked queue",
|
LSQ_DEBUG("Got ACK for packet %"PRIu64", remove from unacked queue",
|
||||||
packet_out->po_packno);
|
packet_out->po_packno);
|
||||||
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
assert(ctl->sc_n_in_flight_all);
|
||||||
|
send_ctl_unacked_remove(ctl, packet_out);
|
||||||
lsquic_packet_out_ack_streams(packet_out);
|
lsquic_packet_out_ack_streams(packet_out);
|
||||||
|
#if __GNUC__
|
||||||
|
__builtin_prefetch(next);
|
||||||
|
#endif
|
||||||
if ((ctl->sc_flags & SC_NSTP) &&
|
if ((ctl->sc_flags & SC_NSTP) &&
|
||||||
(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK)))
|
(packet_out->po_frame_types & (1 << QUIC_FRAME_ACK)))
|
||||||
TAILQ_INSERT_TAIL(&acked_acks, packet_out, po_next);
|
TAILQ_INSERT_TAIL(&acked_acks, packet_out, po_next);
|
||||||
else
|
else
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
assert(ctl->sc_n_in_flight);
|
|
||||||
--ctl->sc_n_in_flight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtt_updated)
|
if (rtt_updated)
|
||||||
|
@ -649,20 +748,12 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
ctl->sc_n_tlp = 0;
|
ctl->sc_n_tlp = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send_ctl_detect_losses(ctl, ack_recv_time);
|
||||||
if (send_ctl_first_unacked_retx_packet(ctl))
|
if (send_ctl_first_unacked_retx_packet(ctl))
|
||||||
{
|
set_retx_alarm(ctl);
|
||||||
send_ctl_detect_losses(ctl, ack_recv_time);
|
|
||||||
if (send_ctl_first_unacked_retx_packet(ctl))
|
|
||||||
set_retx_alarm(ctl);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LSQ_DEBUG("All retransmittable packets lost: clear alarm");
|
|
||||||
lsquic_alarmset_unset(ctl->sc_alset, AL_RETX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("No unacked retransmittable packets: clear retx alarm");
|
LSQ_DEBUG("No retransmittable packets: clear alarm");
|
||||||
lsquic_alarmset_unset(ctl->sc_alset, AL_RETX);
|
lsquic_alarmset_unset(ctl->sc_alset, AL_RETX);
|
||||||
}
|
}
|
||||||
lsquic_send_ctl_sanity_check(ctl);
|
lsquic_send_ctl_sanity_check(ctl);
|
||||||
|
@ -686,6 +777,9 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
||||||
while ((packet_out = next));
|
while ((packet_out = next));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctl->sc_n_in_flight_retx == 0)
|
||||||
|
ctl->sc_flags |= SC_WAS_QUIET;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,19 +789,6 @@ lsquic_send_ctl_smallest_unacked (lsquic_send_ctl_t *ctl)
|
||||||
{
|
{
|
||||||
const lsquic_packet_out_t *packet_out;
|
const lsquic_packet_out_t *packet_out;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if ((ctl->sc_senhist.sh_flags & SH_REORDER) &&
|
|
||||||
!TAILQ_EMPTY(&ctl->sc_unacked_packets))
|
|
||||||
{
|
|
||||||
lsquic_packno_t smallest_unacked = UINT64_MAX;
|
|
||||||
TAILQ_FOREACH(packet_out, &ctl->sc_unacked_packets, po_next)
|
|
||||||
if (packet_out->po_packno < smallest_unacked)
|
|
||||||
smallest_unacked = packet_out->po_packno;
|
|
||||||
assert(smallest_unacked < UINT64_MAX);
|
|
||||||
return smallest_unacked;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
/* Packets are always sent out in order (unless we are reordering them
|
/* Packets are always sent out in order (unless we are reordering them
|
||||||
* on purpose). Thus, the first packet on the unacked packets list has
|
* on purpose). Thus, the first packet on the unacked packets list has
|
||||||
* the smallest packet number of all packets on that list.
|
* the smallest packet number of all packets on that list.
|
||||||
|
@ -751,23 +832,26 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
|
||||||
lsquic_senhist_cleanup(&ctl->sc_senhist);
|
lsquic_senhist_cleanup(&ctl->sc_senhist);
|
||||||
while ((packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets)))
|
while ((packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets)))
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_remove(ctl, packet_out);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
--ctl->sc_n_scheduled;
|
|
||||||
}
|
}
|
||||||
assert(0 == ctl->sc_n_scheduled);
|
assert(0 == ctl->sc_n_scheduled);
|
||||||
|
assert(0 == ctl->sc_bytes_scheduled);
|
||||||
while ((packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets)))
|
while ((packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets)))
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
TAILQ_REMOVE(&ctl->sc_unacked_packets, packet_out, po_next);
|
||||||
|
ctl->sc_bytes_unacked_all -= lsquic_packet_out_total_sz(packet_out);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
--ctl->sc_n_in_flight;
|
--ctl->sc_n_in_flight_all;
|
||||||
}
|
}
|
||||||
assert(0 == ctl->sc_n_in_flight);
|
assert(0 == ctl->sc_n_in_flight_all);
|
||||||
|
assert(0 == ctl->sc_bytes_unacked_all);
|
||||||
while ((packet_out = TAILQ_FIRST(&ctl->sc_lost_packets)))
|
while ((packet_out = TAILQ_FIRST(&ctl->sc_lost_packets)))
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&ctl->sc_lost_packets, packet_out, po_next);
|
TAILQ_REMOVE(&ctl->sc_lost_packets, packet_out, po_next);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
}
|
}
|
||||||
|
pacer_cleanup(&ctl->sc_pacer);
|
||||||
#if LSQUIC_SEND_STATS
|
#if LSQUIC_SEND_STATS
|
||||||
LSQ_NOTICE("stats: n_total_sent: %u; n_resent: %u; n_delayed: %u",
|
LSQ_NOTICE("stats: n_total_sent: %u; n_resent: %u; n_delayed: %u",
|
||||||
ctl->sc_stats.n_total_sent, ctl->sc_stats.n_resent,
|
ctl->sc_stats.n_total_sent, ctl->sc_stats.n_resent,
|
||||||
|
@ -776,18 +860,40 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned
|
||||||
|
send_ctl_retx_bytes_out (const struct lsquic_send_ctl *ctl)
|
||||||
|
{
|
||||||
|
return ctl->sc_bytes_scheduled
|
||||||
|
+ ctl->sc_bytes_unacked_retx
|
||||||
|
+ ctl->sc_bytes_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *ctl)
|
||||||
|
{
|
||||||
|
return (ctl->sc_flags & SC_PACE)
|
||||||
|
&& !pacer_can_schedule(&ctl->sc_pacer,
|
||||||
|
ctl->sc_n_scheduled + ctl->sc_n_in_flight_all);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
__attribute__((weak))
|
__attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
|
lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
|
||||||
{
|
{
|
||||||
const unsigned n_out = ctl->sc_n_scheduled + ctl->sc_n_in_flight;
|
const unsigned n_out = send_ctl_retx_bytes_out(ctl);
|
||||||
|
LSQ_DEBUG("%s: n_out: %u (unacked_retx: %u, out: %u); cwnd: %lu", __func__,
|
||||||
|
n_out, ctl->sc_bytes_unacked_retx, ctl->sc_bytes_out,
|
||||||
|
lsquic_cubic_get_cwnd(&ctl->sc_cubic));
|
||||||
if (ctl->sc_flags & SC_PACE)
|
if (ctl->sc_flags & SC_PACE)
|
||||||
{
|
{
|
||||||
if (n_out >= lsquic_cubic_get_cwnd(&ctl->sc_cubic))
|
if (n_out >= lsquic_cubic_get_cwnd(&ctl->sc_cubic))
|
||||||
return 0;
|
return 0;
|
||||||
if (pacer_can_schedule(&ctl->sc_pacer, n_out))
|
if (pacer_can_schedule(&ctl->sc_pacer,
|
||||||
|
ctl->sc_n_scheduled + ctl->sc_n_in_flight_all))
|
||||||
return 1;
|
return 1;
|
||||||
if (ctl->sc_flags & SC_SCHED_TICK)
|
if (ctl->sc_flags & SC_SCHED_TICK)
|
||||||
{
|
{
|
||||||
|
@ -853,12 +959,12 @@ lsquic_send_ctl_expire_all (lsquic_send_ctl_t *ctl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#if LSQUIC_EXTRA_CHECKS
|
||||||
void
|
void
|
||||||
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
||||||
{
|
{
|
||||||
const struct lsquic_packet_out *packet_out;
|
const struct lsquic_packet_out *packet_out;
|
||||||
unsigned count;
|
unsigned count, sched_bytes;
|
||||||
|
|
||||||
assert(!send_ctl_first_unacked_retx_packet(ctl) ||
|
assert(!send_ctl_first_unacked_retx_packet(ctl) ||
|
||||||
lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX));
|
lsquic_alarmset_is_set(ctl->sc_alset, AL_RETX));
|
||||||
|
@ -871,7 +977,17 @@ lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl)
|
||||||
count = 0;
|
count = 0;
|
||||||
TAILQ_FOREACH(packet_out, &ctl->sc_unacked_packets, po_next)
|
TAILQ_FOREACH(packet_out, &ctl->sc_unacked_packets, po_next)
|
||||||
++count;
|
++count;
|
||||||
assert(count == ctl->sc_n_in_flight);
|
assert(count == ctl->sc_n_in_flight_all);
|
||||||
|
|
||||||
|
count = 0, sched_bytes = 0;
|
||||||
|
TAILQ_FOREACH(packet_out, &ctl->sc_scheduled_packets, po_next)
|
||||||
|
{
|
||||||
|
assert(packet_out->po_flags & PO_SCHED);
|
||||||
|
sched_bytes += lsquic_packet_out_total_sz(packet_out);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
assert(count == ctl->sc_n_scheduled);
|
||||||
|
assert(sched_bytes == ctl->sc_bytes_scheduled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -889,8 +1005,13 @@ lsquic_send_ctl_scheduled_one (lsquic_send_ctl_t *ctl,
|
||||||
assert((last->po_flags & PO_REPACKNO) ||
|
assert((last->po_flags & PO_REPACKNO) ||
|
||||||
last->po_packno < packet_out->po_packno);
|
last->po_packno < packet_out->po_packno);
|
||||||
#endif
|
#endif
|
||||||
TAILQ_INSERT_TAIL(&ctl->sc_scheduled_packets, packet_out, po_next);
|
if (ctl->sc_flags & SC_PACE)
|
||||||
++ctl->sc_n_scheduled;
|
{
|
||||||
|
unsigned n_out = ctl->sc_n_in_flight_retx + ctl->sc_n_scheduled;
|
||||||
|
pacer_packet_scheduled(&ctl->sc_pacer, n_out,
|
||||||
|
send_ctl_in_recovery(ctl), send_ctl_transfer_time, ctl);
|
||||||
|
}
|
||||||
|
send_ctl_sched_append(ctl, packet_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -918,8 +1039,8 @@ lsquic_send_ctl_next_packet_to_send (lsquic_send_ctl_t *ctl)
|
||||||
packet_out->po_flags &= ~PO_REPACKNO;
|
packet_out->po_flags &= ~PO_REPACKNO;
|
||||||
}
|
}
|
||||||
|
|
||||||
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_remove(ctl, packet_out);
|
||||||
--ctl->sc_n_scheduled;
|
ctl->sc_bytes_out += lsquic_packet_out_total_sz(packet_out);
|
||||||
return packet_out;
|
return packet_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,8 +1049,8 @@ void
|
||||||
lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
|
lsquic_send_ctl_delayed_one (lsquic_send_ctl_t *ctl,
|
||||||
lsquic_packet_out_t *packet_out)
|
lsquic_packet_out_t *packet_out)
|
||||||
{
|
{
|
||||||
TAILQ_INSERT_HEAD(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_prepend(ctl, packet_out);
|
||||||
++ctl->sc_n_scheduled;
|
ctl->sc_bytes_out -= lsquic_packet_out_total_sz(packet_out);
|
||||||
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
|
LSQ_DEBUG("packet %"PRIu64" has been delayed", packet_out->po_packno);
|
||||||
#if LSQUIC_SEND_STATS
|
#if LSQUIC_SEND_STATS
|
||||||
++ctl->sc_stats.n_delayed;
|
++ctl->sc_stats.n_delayed;
|
||||||
|
@ -1013,12 +1134,12 @@ lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *ctl,
|
||||||
unsigned need_at_least, int *is_err)
|
unsigned need_at_least, int *is_err)
|
||||||
{
|
{
|
||||||
lsquic_packet_out_t *packet_out;
|
lsquic_packet_out_t *packet_out;
|
||||||
unsigned n_out;
|
|
||||||
|
|
||||||
assert(need_at_least > 0);
|
assert(need_at_least > 0);
|
||||||
|
|
||||||
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
||||||
if (packet_out
|
if (packet_out
|
||||||
|
&& !(packet_out->po_flags & PO_STREAM_END)
|
||||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least)
|
&& lsquic_packet_out_avail(packet_out) >= need_at_least)
|
||||||
{
|
{
|
||||||
return packet_out;
|
return packet_out;
|
||||||
|
@ -1032,15 +1153,7 @@ lsquic_send_ctl_get_writeable_packet (lsquic_send_ctl_t *ctl,
|
||||||
|
|
||||||
packet_out = lsquic_send_ctl_new_packet_out(ctl, need_at_least);
|
packet_out = lsquic_send_ctl_new_packet_out(ctl, need_at_least);
|
||||||
if (packet_out)
|
if (packet_out)
|
||||||
{
|
|
||||||
if (ctl->sc_flags & SC_PACE)
|
|
||||||
{
|
|
||||||
n_out = ctl->sc_n_in_flight + ctl->sc_n_scheduled;
|
|
||||||
pacer_packet_scheduled(&ctl->sc_pacer, n_out,
|
|
||||||
send_ctl_in_recovery(ctl), send_ctl_transfer_time, ctl);
|
|
||||||
}
|
|
||||||
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
*is_err = 1;
|
*is_err = 1;
|
||||||
return packet_out;
|
return packet_out;
|
||||||
|
@ -1052,12 +1165,12 @@ send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl,
|
||||||
unsigned need_at_least, const lsquic_stream_t *stream)
|
unsigned need_at_least, const lsquic_stream_t *stream)
|
||||||
{
|
{
|
||||||
lsquic_packet_out_t *packet_out;
|
lsquic_packet_out_t *packet_out;
|
||||||
unsigned n_out;
|
|
||||||
|
|
||||||
assert(need_at_least > 0);
|
assert(need_at_least > 0);
|
||||||
|
|
||||||
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
packet_out = lsquic_send_ctl_last_scheduled(ctl);
|
||||||
if (packet_out
|
if (packet_out
|
||||||
|
&& !(packet_out->po_flags & PO_STREAM_END)
|
||||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
||||||
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
||||||
{
|
{
|
||||||
|
@ -1071,12 +1184,6 @@ send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl,
|
||||||
if (!packet_out)
|
if (!packet_out)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (ctl->sc_flags & SC_PACE)
|
|
||||||
{
|
|
||||||
n_out = ctl->sc_n_in_flight + ctl->sc_n_scheduled;
|
|
||||||
pacer_packet_scheduled(&ctl->sc_pacer, n_out,
|
|
||||||
send_ctl_in_recovery(ctl), send_ctl_transfer_time, ctl);
|
|
||||||
}
|
|
||||||
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
lsquic_send_ctl_scheduled_one(ctl, packet_out);
|
||||||
return packet_out;
|
return packet_out;
|
||||||
}
|
}
|
||||||
|
@ -1106,12 +1213,11 @@ update_for_resending (lsquic_send_ctl_t *ctl, lsquic_packet_out_t *packet_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(packet_out->po_regen_sz < packet_out->po_data_sz);
|
assert(packet_out->po_regen_sz < packet_out->po_data_sz);
|
||||||
/* TODO: in Q038 and later, we can simply replace the ACK with NUL bytes
|
|
||||||
* representing PADDING frame instead of doing memmove and adjusting
|
|
||||||
* offsets.
|
|
||||||
*/
|
|
||||||
if (packet_out->po_regen_sz)
|
if (packet_out->po_regen_sz)
|
||||||
|
{
|
||||||
|
assert(!(packet_out->po_flags & PO_SCHED));
|
||||||
lsquic_packet_out_chop_regen(packet_out);
|
lsquic_packet_out_chop_regen(packet_out);
|
||||||
|
}
|
||||||
LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
|
LSQ_DEBUG("Packet %"PRIu64" repackaged for resending as packet %"PRIu64,
|
||||||
oldno, packno);
|
oldno, packno);
|
||||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
|
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "packet %"PRIu64" repackaged for "
|
||||||
|
@ -1119,21 +1225,6 @@ update_for_resending (lsquic_send_ctl_t *ctl, lsquic_packet_out_t *packet_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* A droppable hello packet is a packet that contains a part of hello message
|
|
||||||
* after handshake has been completed.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
droppable_hello_packet (const lsquic_send_ctl_t *ctl,
|
|
||||||
const lsquic_packet_out_t *packet_out)
|
|
||||||
{
|
|
||||||
return 0 /* TODO: we cannot not resend HELLO packets if we are server.
|
|
||||||
* For now, do not discard any HELLO packets.
|
|
||||||
*/
|
|
||||||
&& (packet_out->po_flags & PO_HELLO)
|
|
||||||
&& (ctl->sc_conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
lsquic_send_ctl_reschedule_packets (lsquic_send_ctl_t *ctl)
|
lsquic_send_ctl_reschedule_packets (lsquic_send_ctl_t *ctl)
|
||||||
{
|
{
|
||||||
|
@ -1143,8 +1234,7 @@ lsquic_send_ctl_reschedule_packets (lsquic_send_ctl_t *ctl)
|
||||||
while (lsquic_send_ctl_can_send(ctl) &&
|
while (lsquic_send_ctl_can_send(ctl) &&
|
||||||
(packet_out = send_ctl_next_lost(ctl)))
|
(packet_out = send_ctl_next_lost(ctl)))
|
||||||
{
|
{
|
||||||
if ((packet_out->po_regen_sz < packet_out->po_data_sz)
|
if (packet_out->po_regen_sz < packet_out->po_data_sz)
|
||||||
&& !droppable_hello_packet(ctl, packet_out))
|
|
||||||
{
|
{
|
||||||
++n;
|
++n;
|
||||||
update_for_resending(ctl, packet_out);
|
update_for_resending(ctl, packet_out);
|
||||||
|
@ -1193,7 +1283,7 @@ void
|
||||||
lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
||||||
{
|
{
|
||||||
struct lsquic_packet_out *packet_out, *next;
|
struct lsquic_packet_out *packet_out, *next;
|
||||||
unsigned n;
|
unsigned n, adj;
|
||||||
|
|
||||||
for (packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets); packet_out;
|
for (packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets); packet_out;
|
||||||
packet_out = next)
|
packet_out = next)
|
||||||
|
@ -1203,15 +1293,15 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
||||||
if ((packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
if ((packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, stream_id);
|
adj = lsquic_packet_out_elide_reset_stream_frames(packet_out,
|
||||||
|
stream_id);
|
||||||
|
ctl->sc_bytes_scheduled -= adj;
|
||||||
if (0 == packet_out->po_frame_types)
|
if (0 == packet_out->po_frame_types)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
||||||
"stream %"PRIu32, packet_out->po_packno, stream_id);
|
"stream %"PRIu32, packet_out->po_packno, stream_id);
|
||||||
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_remove(ctl, packet_out);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
assert(ctl->sc_n_scheduled);
|
|
||||||
--ctl->sc_n_scheduled;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1225,10 +1315,11 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
||||||
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM)))
|
if (!(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM)))
|
||||||
continue;
|
continue;
|
||||||
next = TAILQ_NEXT(packet_out, po_next);
|
next = TAILQ_NEXT(packet_out, po_next);
|
||||||
|
lsquic_packet_out_elide_reset_stream_frames(packet_out, stream_id);
|
||||||
if (0 == packet_out->po_frame_types)
|
if (0 == packet_out->po_frame_types)
|
||||||
{
|
{
|
||||||
LSQ_DEBUG("cancel packet %"PRIu64" after eliding frames for "
|
LSQ_DEBUG("cancel buffered packet in queue #%u after eliding "
|
||||||
"stream %"PRIu32, packet_out->po_packno, stream_id);
|
"frames for stream %"PRIu32, n, stream_id);
|
||||||
TAILQ_REMOVE(&ctl->sc_buffered_packets[n].bpq_packets,
|
TAILQ_REMOVE(&ctl->sc_buffered_packets[n].bpq_packets,
|
||||||
packet_out, po_next);
|
packet_out, po_next);
|
||||||
--ctl->sc_buffered_packets[n].bpq_count;
|
--ctl->sc_buffered_packets[n].bpq_count;
|
||||||
|
@ -1322,8 +1413,7 @@ lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *ctl)
|
||||||
packet_out = next)
|
packet_out = next)
|
||||||
{
|
{
|
||||||
next = TAILQ_NEXT(packet_out, po_next);
|
next = TAILQ_NEXT(packet_out, po_next);
|
||||||
if (packet_out->po_regen_sz < packet_out->po_data_sz
|
if (packet_out->po_regen_sz < packet_out->po_data_sz)
|
||||||
&& !droppable_hello_packet(ctl, packet_out))
|
|
||||||
{
|
{
|
||||||
if (packet_out->po_flags & PO_ENCRYPTED)
|
if (packet_out->po_flags & PO_ENCRYPTED)
|
||||||
{
|
{
|
||||||
|
@ -1341,9 +1431,7 @@ lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *ctl)
|
||||||
LOG_PACKET_Q(&ctl->sc_scheduled_packets,
|
LOG_PACKET_Q(&ctl->sc_scheduled_packets,
|
||||||
"unacked packets before squeezing");
|
"unacked packets before squeezing");
|
||||||
#endif
|
#endif
|
||||||
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_remove(ctl, packet_out);
|
||||||
assert(ctl->sc_n_scheduled);
|
|
||||||
--ctl->sc_n_scheduled;
|
|
||||||
LSQ_DEBUG("Dropping packet %"PRIu64" from scheduled queue",
|
LSQ_DEBUG("Dropping packet %"PRIu64" from scheduled queue",
|
||||||
packet_out->po_packno);
|
packet_out->po_packno);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
|
@ -1394,9 +1482,8 @@ lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *ctl)
|
||||||
const unsigned n = ctl->sc_n_scheduled;
|
const unsigned n = ctl->sc_n_scheduled;
|
||||||
while ((packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets)))
|
while ((packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets)))
|
||||||
{
|
{
|
||||||
TAILQ_REMOVE(&ctl->sc_scheduled_packets, packet_out, po_next);
|
send_ctl_sched_remove(ctl, packet_out);
|
||||||
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
lsquic_packet_out_destroy(packet_out, ctl->sc_enpub);
|
||||||
--ctl->sc_n_scheduled;
|
|
||||||
}
|
}
|
||||||
assert(0 == ctl->sc_n_scheduled);
|
assert(0 == ctl->sc_n_scheduled);
|
||||||
LSQ_DEBUG("dropped %u scheduled packet%s", n, n != 0 ? "s" : "");
|
LSQ_DEBUG("dropped %u scheduled packet%s", n, n != 0 ? "s" : "");
|
||||||
|
@ -1457,10 +1544,10 @@ send_ctl_max_bpq_count (const lsquic_send_ctl_t *ctl,
|
||||||
return MAX_BPQ_COUNT;
|
return MAX_BPQ_COUNT;
|
||||||
case BPT_HIGHEST_PRIO:
|
case BPT_HIGHEST_PRIO:
|
||||||
default: /* clang does not complain about absence of `default'... */
|
default: /* clang does not complain about absence of `default'... */
|
||||||
count = ctl->sc_n_scheduled + ctl->sc_n_in_flight;
|
count = ctl->sc_n_scheduled + ctl->sc_n_in_flight_retx;
|
||||||
if (count < lsquic_cubic_get_cwnd(&ctl->sc_cubic))
|
if (count < lsquic_cubic_get_cwnd(&ctl->sc_cubic) / ctl->sc_pack_size)
|
||||||
{
|
{
|
||||||
count -= lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
count -= lsquic_cubic_get_cwnd(&ctl->sc_cubic) / ctl->sc_pack_size;
|
||||||
if (count > MAX_BPQ_COUNT)
|
if (count > MAX_BPQ_COUNT)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -1481,6 +1568,7 @@ send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
|
||||||
|
|
||||||
packet_out = TAILQ_LAST(&packet_q->bpq_packets, lsquic_packets_tailq);
|
packet_out = TAILQ_LAST(&packet_q->bpq_packets, lsquic_packets_tailq);
|
||||||
if (packet_out
|
if (packet_out
|
||||||
|
&& !(packet_out->po_flags & PO_STREAM_END)
|
||||||
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
&& lsquic_packet_out_avail(packet_out) >= need_at_least
|
||||||
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
&& !lsquic_packet_out_has_frame(packet_out, stream, QUIC_FRAME_STREAM))
|
||||||
{
|
{
|
||||||
|
@ -1532,7 +1620,7 @@ lsquic_send_ctl_calc_packno_bits (lsquic_send_ctl_t *ctl)
|
||||||
unsigned n_in_flight;
|
unsigned n_in_flight;
|
||||||
|
|
||||||
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
|
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
|
||||||
n_in_flight = lsquic_cubic_get_cwnd(&ctl->sc_cubic);
|
n_in_flight = lsquic_cubic_get_cwnd(&ctl->sc_cubic) / ctl->sc_pack_size;
|
||||||
return calc_packno_bits(ctl->sc_cur_packno + 1, smallest_unacked,
|
return calc_packno_bits(ctl->sc_cur_packno + 1, smallest_unacked,
|
||||||
n_in_flight);
|
n_in_flight);
|
||||||
}
|
}
|
||||||
|
@ -1567,6 +1655,7 @@ split_buffered_packet (lsquic_send_ctl_t *ctl,
|
||||||
if (0 == lsquic_packet_out_split_in_two(&ctl->sc_enpub->enp_mm, packet_out,
|
if (0 == lsquic_packet_out_split_in_two(&ctl->sc_enpub->enp_mm, packet_out,
|
||||||
new_packet_out, ctl->sc_conn_pub->lconn->cn_pf, excess_bytes))
|
new_packet_out, ctl->sc_conn_pub->lconn->cn_pf, excess_bytes))
|
||||||
{
|
{
|
||||||
|
lsquic_packet_out_set_packno_bits(packet_out, bits);
|
||||||
TAILQ_INSERT_AFTER(&packet_q->bpq_packets, packet_out, new_packet_out,
|
TAILQ_INSERT_AFTER(&packet_q->bpq_packets, packet_out, new_packet_out,
|
||||||
po_next);
|
po_next);
|
||||||
++packet_q->bpq_count;
|
++packet_q->bpq_count;
|
||||||
|
|
|
@ -59,10 +59,15 @@ typedef struct lsquic_send_ctl {
|
||||||
uint32_t stream_id;
|
uint32_t stream_id;
|
||||||
enum buf_packet_type packet_type;
|
enum buf_packet_type packet_type;
|
||||||
} sc_cached_bpt;
|
} sc_cached_bpt;
|
||||||
|
unsigned sc_bytes_out;
|
||||||
|
unsigned sc_bytes_unacked_all;
|
||||||
|
unsigned sc_bytes_unacked_retx;
|
||||||
unsigned sc_n_consec_rtos;
|
unsigned sc_n_consec_rtos;
|
||||||
unsigned sc_next_limit;
|
unsigned sc_next_limit;
|
||||||
unsigned sc_n_in_flight; /* Number of packets in flight */
|
unsigned sc_n_in_flight_all;
|
||||||
|
unsigned sc_n_in_flight_retx;
|
||||||
unsigned sc_n_scheduled;
|
unsigned sc_n_scheduled;
|
||||||
|
unsigned sc_bytes_scheduled;
|
||||||
unsigned sc_n_stop_waiting;
|
unsigned sc_n_stop_waiting;
|
||||||
unsigned short sc_pack_size;
|
unsigned short sc_pack_size;
|
||||||
enum {
|
enum {
|
||||||
|
@ -72,6 +77,7 @@ typedef struct lsquic_send_ctl {
|
||||||
SC_PACE = (1 << 3),
|
SC_PACE = (1 << 3),
|
||||||
SC_SCHED_TICK = (1 << 4),
|
SC_SCHED_TICK = (1 << 4),
|
||||||
SC_BUFFER_STREAM= (1 << 5),
|
SC_BUFFER_STREAM= (1 << 5),
|
||||||
|
SC_WAS_QUIET = (1 << 6),
|
||||||
} sc_flags:8;
|
} sc_flags:8;
|
||||||
unsigned char sc_n_hsk;
|
unsigned char sc_n_hsk;
|
||||||
unsigned char sc_n_tlp;
|
unsigned char sc_n_tlp;
|
||||||
|
@ -90,7 +96,8 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *, struct lsquic_alarmset *,
|
||||||
struct lsquic_conn_public *, unsigned short max_packet_size);
|
struct lsquic_conn_public *, unsigned short max_packet_size);
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *, struct lsquic_packet_out *);
|
lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *, struct lsquic_packet_out *,
|
||||||
|
int);
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_got_ack (lsquic_send_ctl_t *, const struct ack_info *,
|
lsquic_send_ctl_got_ack (lsquic_send_ctl_t *, const struct ack_info *,
|
||||||
|
@ -126,11 +133,11 @@ lsquic_send_ctl_expire_all (lsquic_send_ctl_t *ctl);
|
||||||
|
|
||||||
#define lsquic_send_ctl_largest_ack2ed(ctl) (+(ctl)->sc_largest_ack2ed)
|
#define lsquic_send_ctl_largest_ack2ed(ctl) (+(ctl)->sc_largest_ack2ed)
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#if LSQUIC_EXTRA_CHECKS
|
||||||
# define lsquic_send_ctl_sanity_check(ctl)
|
|
||||||
#else
|
|
||||||
void
|
void
|
||||||
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl);
|
lsquic_send_ctl_sanity_check (const lsquic_send_ctl_t *ctl);
|
||||||
|
#else
|
||||||
|
# define lsquic_send_ctl_sanity_check(ctl)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -173,6 +180,10 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *, uint32_t);
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *);
|
lsquic_send_ctl_squeeze_sched (lsquic_send_ctl_t *);
|
||||||
|
|
||||||
|
#define lsquic_send_ctl_maybe_squeeze_sched(ctl) ( \
|
||||||
|
(ctl)->sc_n_scheduled && lsquic_send_ctl_squeeze_sched(ctl) \
|
||||||
|
)
|
||||||
|
|
||||||
/* Same return value as for squeezing, but without actual squeezing. */
|
/* Same return value as for squeezing, but without actual squeezing. */
|
||||||
int
|
int
|
||||||
lsquic_send_ctl_have_delayed_packets (const lsquic_send_ctl_t *ctl);
|
lsquic_send_ctl_have_delayed_packets (const lsquic_send_ctl_t *ctl);
|
||||||
|
@ -237,4 +248,14 @@ int
|
||||||
lsquic_send_ctl_turn_on_fin (struct lsquic_send_ctl *,
|
lsquic_send_ctl_turn_on_fin (struct lsquic_send_ctl *,
|
||||||
const struct lsquic_stream *);
|
const struct lsquic_stream *);
|
||||||
|
|
||||||
|
int
|
||||||
|
lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *);
|
||||||
|
|
||||||
|
#define lsquic_send_ctl_incr_pack_sz(ctl, packet, delta) do { \
|
||||||
|
(packet)->po_data_sz += delta; \
|
||||||
|
if ((packet)->po_flags & PO_SCHED) \
|
||||||
|
(ctl)->sc_bytes_scheduled += delta; \
|
||||||
|
lsquic_send_ctl_sanity_check(ctl); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,16 +17,6 @@ void
|
||||||
lsquic_senhist_init (lsquic_senhist_t *hist)
|
lsquic_senhist_init (lsquic_senhist_t *hist)
|
||||||
{
|
{
|
||||||
lsquic_packints_init(&hist->sh_pints);
|
lsquic_packints_init(&hist->sh_pints);
|
||||||
#ifndef NDEBUG
|
|
||||||
{
|
|
||||||
const char *env;
|
|
||||||
env = getenv("LSQUIC_REORDER_SENT");
|
|
||||||
if (env && atoi(env))
|
|
||||||
hist->sh_flags = SH_REORDER;
|
|
||||||
else
|
|
||||||
hist->sh_flags = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,32 +65,9 @@ senhist_add_fast (lsquic_senhist_t *hist, lsquic_packno_t packno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static int
|
|
||||||
senhist_add_slow (lsquic_senhist_t *hist, lsquic_packno_t packno)
|
|
||||||
{
|
|
||||||
switch (lsquic_packints_add(&hist->sh_pints, packno))
|
|
||||||
{
|
|
||||||
case PACKINTS_OK:
|
|
||||||
return 0;
|
|
||||||
case PACKINTS_DUP: /* We should not generate duplicate packet numbers! */
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
case PACKINTS_ERR:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
lsquic_senhist_add (lsquic_senhist_t *hist, lsquic_packno_t packno)
|
lsquic_senhist_add (lsquic_senhist_t *hist, lsquic_packno_t packno)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
|
||||||
if (hist->sh_flags & SH_REORDER)
|
|
||||||
return senhist_add_slow(hist, packno);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
return senhist_add_fast(hist, packno);
|
return senhist_add_fast(hist, packno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,3 +124,5 @@ lsquic_senhist_mem_used (const struct lsquic_senhist *hist)
|
||||||
- sizeof(hist->sh_pints)
|
- sizeof(hist->sh_pints)
|
||||||
+ lsquic_packints_mem_used(&hist->sh_pints);
|
+ lsquic_packints_mem_used(&hist->sh_pints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,6 @@ typedef struct lsquic_senhist {
|
||||||
* b) the peer sends an invalid ACK.
|
* b) the peer sends an invalid ACK.
|
||||||
*/
|
*/
|
||||||
struct packints sh_pints;
|
struct packints sh_pints;
|
||||||
#ifndef NDEBUG
|
|
||||||
enum {
|
|
||||||
SH_REORDER = (1 << 0),
|
|
||||||
} sh_flags;
|
|
||||||
#endif
|
|
||||||
} lsquic_senhist_t;
|
} lsquic_senhist_t;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -86,6 +86,9 @@ stream_flush (lsquic_stream_t *stream);
|
||||||
static int
|
static int
|
||||||
stream_flush_nocheck (lsquic_stream_t *stream);
|
stream_flush_nocheck (lsquic_stream_t *stream);
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_remove_from_write_q (lsquic_stream_t *stream, enum stream_flags flag);
|
||||||
|
|
||||||
|
|
||||||
#if LSQUIC_KEEP_STREAM_HISTORY
|
#if LSQUIC_KEEP_STREAM_HISTORY
|
||||||
/* These values are printable ASCII characters for ease of printing the
|
/* These values are printable ASCII characters for ease of printing the
|
||||||
|
@ -251,7 +254,7 @@ lsquic_stream_new_ext (uint32_t id, struct lsquic_conn_public *conn_pub,
|
||||||
stream->data_in = data_in_hash_new(conn_pub, id, 0);
|
stream->data_in = data_in_hash_new(conn_pub, id, 0);
|
||||||
else
|
else
|
||||||
stream->data_in = data_in_nocopy_new(conn_pub, id);
|
stream->data_in = data_in_nocopy_new(conn_pub, id);
|
||||||
LSQ_DEBUG("created stream %u", id);
|
LSQ_DEBUG("created stream %u @%p", id, stream);
|
||||||
SM_HISTORY_APPEND(stream, SHE_CREATED);
|
SM_HISTORY_APPEND(stream, SHE_CREATED);
|
||||||
if (ctor_flags & SCF_DI_AUTOSWITCH)
|
if (ctor_flags & SCF_DI_AUTOSWITCH)
|
||||||
stream->stream_flags |= STREAM_AUTOSWITCH;
|
stream->stream_flags |= STREAM_AUTOSWITCH;
|
||||||
|
@ -294,6 +297,8 @@ drop_buffered_data (struct lsquic_stream *stream)
|
||||||
{
|
{
|
||||||
decr_conn_cap(stream, stream->sm_n_buffered);
|
decr_conn_cap(stream, stream->sm_n_buffered);
|
||||||
stream->sm_n_buffered = 0;
|
stream->sm_n_buffered = 0;
|
||||||
|
if (stream->stream_flags & STREAM_WRITE_Q_FLAGS)
|
||||||
|
maybe_remove_from_write_q(stream, STREAM_WRITE_Q_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,7 +326,7 @@ lsquic_stream_destroy (lsquic_stream_t *stream)
|
||||||
free(stream->push_req);
|
free(stream->push_req);
|
||||||
free(stream->uh);
|
free(stream->uh);
|
||||||
free(stream->sm_buf);
|
free(stream->sm_buf);
|
||||||
LSQ_DEBUG("destroyed stream %u", stream->id);
|
LSQ_DEBUG("destroyed stream %u @%p", stream->id, stream);
|
||||||
SM_HISTORY_DUMP_REMAINING(stream);
|
SM_HISTORY_DUMP_REMAINING(stream);
|
||||||
free(stream);
|
free(stream);
|
||||||
}
|
}
|
||||||
|
@ -340,8 +345,7 @@ stream_is_finished (const lsquic_stream_t *stream)
|
||||||
*/
|
*/
|
||||||
&& 0 == (stream->stream_flags & STREAM_SEND_RST)
|
&& 0 == (stream->stream_flags & STREAM_SEND_RST)
|
||||||
&& ((stream->stream_flags & STREAM_FORCE_FINISH)
|
&& ((stream->stream_flags & STREAM_FORCE_FINISH)
|
||||||
|| (((stream->stream_flags & (STREAM_FIN_SENT |STREAM_RST_SENT))
|
|| ((stream->stream_flags & (STREAM_FIN_SENT |STREAM_RST_SENT))
|
||||||
|| lsquic_stream_is_pushed(stream))
|
|
||||||
&& (stream->stream_flags & (STREAM_FIN_RECVD|STREAM_RST_RECVD))));
|
&& (stream->stream_flags & (STREAM_FIN_RECVD|STREAM_RST_RECVD))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,6 +607,7 @@ lsquic_stream_rst_in (lsquic_stream_t *stream, uint64_t offset,
|
||||||
|
|
||||||
lsquic_sfcw_consume_rem(&stream->fc);
|
lsquic_sfcw_consume_rem(&stream->fc);
|
||||||
drop_frames_in(stream);
|
drop_frames_in(stream);
|
||||||
|
drop_buffered_data(stream);
|
||||||
maybe_elide_stream_frames(stream);
|
maybe_elide_stream_frames(stream);
|
||||||
|
|
||||||
if (!(stream->stream_flags &
|
if (!(stream->stream_flags &
|
||||||
|
@ -1492,7 +1497,7 @@ static struct lsquic_packet_out * (* const get_packet[])(
|
||||||
|
|
||||||
|
|
||||||
static enum { SWTP_OK, SWTP_STOP, SWTP_ERROR }
|
static enum { SWTP_OK, SWTP_STOP, SWTP_ERROR }
|
||||||
stream_write_to_packet (struct frame_gen_ctx *fg_ctx)
|
stream_write_to_packet (struct frame_gen_ctx *fg_ctx, const size_t size)
|
||||||
{
|
{
|
||||||
lsquic_stream_t *const stream = fg_ctx->fgc_stream;
|
lsquic_stream_t *const stream = fg_ctx->fgc_stream;
|
||||||
const struct parse_funcs *const pf = stream->conn_pub->lconn->cn_pf;
|
const struct parse_funcs *const pf = stream->conn_pub->lconn->cn_pf;
|
||||||
|
@ -1503,7 +1508,7 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx)
|
||||||
|
|
||||||
stream_header_sz = pf->pf_calc_stream_frame_header_sz(stream->id,
|
stream_header_sz = pf->pf_calc_stream_frame_header_sz(stream->id,
|
||||||
stream->tosend_off);
|
stream->tosend_off);
|
||||||
need_at_least = stream_header_sz + (frame_gen_size(fg_ctx) > 0);
|
need_at_least = stream_header_sz + (size > 0);
|
||||||
hsk = LSQUIC_STREAM_HANDSHAKE == stream->id;
|
hsk = LSQUIC_STREAM_HANDSHAKE == stream->id;
|
||||||
packet_out = get_packet[hsk](send_ctl, need_at_least, stream);
|
packet_out = get_packet[hsk](send_ctl, need_at_least, stream);
|
||||||
if (!packet_out)
|
if (!packet_out)
|
||||||
|
@ -1514,7 +1519,7 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx)
|
||||||
packet_out->po_data + packet_out->po_data_sz,
|
packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out), stream->id,
|
lsquic_packet_out_avail(packet_out), stream->id,
|
||||||
stream->tosend_off,
|
stream->tosend_off,
|
||||||
frame_gen_fin, frame_gen_size, frame_gen_read, fg_ctx);
|
frame_gen_fin(fg_ctx), size, frame_gen_read, fg_ctx);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
LSQ_ERROR("could not generate stream frame");
|
LSQ_ERROR("could not generate stream frame");
|
||||||
|
@ -1523,8 +1528,10 @@ stream_write_to_packet (struct frame_gen_ctx *fg_ctx)
|
||||||
|
|
||||||
EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, pf,
|
EV_LOG_GENERATED_STREAM_FRAME(LSQUIC_LOG_CONN_ID, pf,
|
||||||
packet_out->po_data + packet_out->po_data_sz, len);
|
packet_out->po_data + packet_out->po_data_sz, len);
|
||||||
packet_out->po_data_sz += len;
|
lsquic_send_ctl_incr_pack_sz(send_ctl, packet_out, len);
|
||||||
packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
|
packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM;
|
||||||
|
if (0 == lsquic_packet_out_avail(packet_out))
|
||||||
|
packet_out->po_flags |= PO_STREAM_END;
|
||||||
s = lsquic_packet_out_add_stream(packet_out, stream->conn_pub->mm,
|
s = lsquic_packet_out_add_stream(packet_out, stream->conn_pub->mm,
|
||||||
stream, QUIC_FRAME_STREAM, off, len);
|
stream, QUIC_FRAME_STREAM, off, len);
|
||||||
if (s != 0)
|
if (s != 0)
|
||||||
|
@ -1573,7 +1580,7 @@ stream_write_to_packets (lsquic_stream_t *stream, struct lsquic_reader *reader,
|
||||||
while ((size = frame_gen_size(&fg_ctx), thresh ? size >= thresh : size > 0)
|
while ((size = frame_gen_size(&fg_ctx), thresh ? size >= thresh : size > 0)
|
||||||
|| frame_gen_fin(&fg_ctx))
|
|| frame_gen_fin(&fg_ctx))
|
||||||
{
|
{
|
||||||
switch (stream_write_to_packet(&fg_ctx))
|
switch (stream_write_to_packet(&fg_ctx, size))
|
||||||
{
|
{
|
||||||
case SWTP_OK:
|
case SWTP_OK:
|
||||||
if (frame_gen_fin(&fg_ctx))
|
if (frame_gen_fin(&fg_ctx))
|
||||||
|
@ -1877,6 +1884,7 @@ lsquic_stream_reset_ext (lsquic_stream_t *stream, uint32_t error_code,
|
||||||
stream->stream_flags &= ~STREAM_SENDING_FLAGS;
|
stream->stream_flags &= ~STREAM_SENDING_FLAGS;
|
||||||
stream->stream_flags |= STREAM_SEND_RST;
|
stream->stream_flags |= STREAM_SEND_RST;
|
||||||
|
|
||||||
|
drop_buffered_data(stream);
|
||||||
maybe_elide_stream_frames(stream);
|
maybe_elide_stream_frames(stream);
|
||||||
maybe_schedule_call_on_close(stream);
|
maybe_schedule_call_on_close(stream);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@ CHECK_SYMBOL_EXISTS(
|
||||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/test_config.h)
|
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/test_config.h)
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(unittests)
|
IF(DEVEL_MODE EQUAL 1)
|
||||||
|
# Our test framework relies on assertions, only compile if assertions are
|
||||||
enable_testing()
|
# enabled.
|
||||||
|
#
|
||||||
|
add_subdirectory(unittests)
|
||||||
|
enable_testing()
|
||||||
|
ENDIF()
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct http_client_ctx {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
HCC_DISCARD_RESPONSE = (1 << 0),
|
HCC_DISCARD_RESPONSE = (1 << 0),
|
||||||
|
HCC_SEEN_FIN = (1 << 1),
|
||||||
|
HCC_ABORT_ON_INCOMPLETE = (1 << 2),
|
||||||
} hcc_flags;
|
} hcc_flags;
|
||||||
struct prog *prog;
|
struct prog *prog;
|
||||||
};
|
};
|
||||||
|
@ -110,7 +112,16 @@ static void
|
||||||
http_client_on_conn_closed (lsquic_conn_t *conn)
|
http_client_on_conn_closed (lsquic_conn_t *conn)
|
||||||
{
|
{
|
||||||
lsquic_conn_ctx_t *conn_h = lsquic_conn_get_ctx(conn);
|
lsquic_conn_ctx_t *conn_h = lsquic_conn_get_ctx(conn);
|
||||||
LSQ_INFO("Connection closed");
|
enum LSQUIC_CONN_STATUS status;
|
||||||
|
char errmsg[80];
|
||||||
|
|
||||||
|
status = lsquic_conn_status(conn, errmsg, sizeof(errmsg));
|
||||||
|
LSQ_INFO("Connection closed. Status: %d. Message: %s", status,
|
||||||
|
errmsg[0] ? errmsg : "<not set>");
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (conn_h->client_ctx->hcc_flags & HCC_ABORT_ON_INCOMPLETE)
|
||||||
|
assert(conn_h->client_ctx->hcc_flags & HCC_SEEN_FIN);
|
||||||
|
#endif
|
||||||
TAILQ_REMOVE(&conn_h->client_ctx->conn_ctxs, conn_h, next_ch);
|
TAILQ_REMOVE(&conn_h->client_ctx->conn_ctxs, conn_h, next_ch);
|
||||||
--conn_h->client_ctx->hcc_n_open_conns;
|
--conn_h->client_ctx->hcc_n_open_conns;
|
||||||
create_connections(conn_h->client_ctx);
|
create_connections(conn_h->client_ctx);
|
||||||
|
@ -282,10 +293,9 @@ http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
static void
|
static void
|
||||||
http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
{
|
{
|
||||||
const struct http_client_ctx *const client_ctx = st_h->client_ctx;
|
struct http_client_ctx *const client_ctx = st_h->client_ctx;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
unsigned old_prio, new_prio;
|
unsigned old_prio, new_prio;
|
||||||
int s;
|
|
||||||
unsigned char buf[0x200];
|
unsigned char buf[0x200];
|
||||||
unsigned nreads = 0;
|
unsigned nreads = 0;
|
||||||
|
|
||||||
|
@ -300,7 +310,10 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
{
|
{
|
||||||
old_prio = lsquic_stream_priority(stream);
|
old_prio = lsquic_stream_priority(stream);
|
||||||
new_prio = random() & 0xFF;
|
new_prio = random() & 0xFF;
|
||||||
s = lsquic_stream_set_priority(stream, new_prio);
|
#ifndef NDEBUG
|
||||||
|
const int s =
|
||||||
|
#endif
|
||||||
|
lsquic_stream_set_priority(stream, new_prio);
|
||||||
assert(s == 0);
|
assert(s == 0);
|
||||||
LSQ_NOTICE("changed stream %u priority from %u to %u",
|
LSQ_NOTICE("changed stream %u priority from %u to %u",
|
||||||
lsquic_stream_id(stream), old_prio, new_prio);
|
lsquic_stream_id(stream), old_prio, new_prio);
|
||||||
|
@ -308,6 +321,7 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
}
|
}
|
||||||
else if (0 == nread)
|
else if (0 == nread)
|
||||||
{
|
{
|
||||||
|
client_ctx->hcc_flags |= HCC_SEEN_FIN;
|
||||||
lsquic_stream_shutdown(stream, 0);
|
lsquic_stream_shutdown(stream, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -389,6 +403,7 @@ usage (const char *prog)
|
||||||
" content-type: application/octet-stream and\n"
|
" content-type: application/octet-stream and\n"
|
||||||
" content-length\n"
|
" content-length\n"
|
||||||
" -K Discard server response\n"
|
" -K Discard server response\n"
|
||||||
|
" -I Abort on incomplete reponse from server\n"
|
||||||
, prog);
|
, prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +435,9 @@ main (int argc, char **argv)
|
||||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "r:R:Ku:EP:M:n:H:p:h")))
|
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "r:R:Ku:EP:M:n:H:p:h")))
|
||||||
{
|
{
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'I':
|
||||||
|
client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE;
|
||||||
|
break;
|
||||||
case 'K':
|
case 'K':
|
||||||
client_ctx.hcc_flags |= HCC_DISCARD_RESPONSE;
|
client_ctx.hcc_flags |= HCC_DISCARD_RESPONSE;
|
||||||
break;
|
break;
|
||||||
|
|
24
test/prog.c
24
test/prog.c
|
@ -110,6 +110,8 @@ prog_print_common_options (const struct prog *prog, FILE *out)
|
||||||
" Example: 1223/104613.946956\n"
|
" Example: 1223/104613.946956\n"
|
||||||
" 4 Microsecond time.\n"
|
" 4 Microsecond time.\n"
|
||||||
" Example: 11:04:05.196308\n"
|
" Example: 11:04:05.196308\n"
|
||||||
|
" 5 Full date and microsecond time.\n"
|
||||||
|
" Example: 2017-03-21 13:43:46.671345\n"
|
||||||
" -S opt=val Socket options. Supported options:\n"
|
" -S opt=val Socket options. Supported options:\n"
|
||||||
" sndbuf=12345 # Sets SO_SNDBUF\n"
|
" sndbuf=12345 # Sets SO_SNDBUF\n"
|
||||||
" rcvbuf=12345 # Sets SO_RCVBUF\n"
|
" rcvbuf=12345 # Sets SO_RCVBUF\n"
|
||||||
|
@ -233,8 +235,8 @@ prog_connect (struct prog *prog)
|
||||||
struct service_port *sport;
|
struct service_port *sport;
|
||||||
|
|
||||||
sport = TAILQ_FIRST(prog->prog_sports);
|
sport = TAILQ_FIRST(prog->prog_sports);
|
||||||
if (0 != lsquic_engine_connect(prog->prog_engine,
|
if (NULL == lsquic_engine_connect(prog->prog_engine,
|
||||||
(struct sockaddr *) &sport->sas, sport,
|
(struct sockaddr *) &sport->sas, sport, NULL,
|
||||||
prog->prog_hostname ? prog->prog_hostname : sport->host,
|
prog->prog_hostname ? prog->prog_hostname : sport->host,
|
||||||
prog->prog_max_packet_size))
|
prog->prog_max_packet_size))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -382,12 +384,18 @@ prog_stop (struct prog *prog)
|
||||||
}
|
}
|
||||||
|
|
||||||
drop_onetimer(prog);
|
drop_onetimer(prog);
|
||||||
event_del(prog->prog_timer);
|
if (prog->prog_timer)
|
||||||
event_free(prog->prog_timer);
|
{
|
||||||
prog->prog_timer = NULL;
|
event_del(prog->prog_timer);
|
||||||
event_del(prog->prog_usr1);
|
event_free(prog->prog_timer);
|
||||||
event_free(prog->prog_usr1);
|
prog->prog_timer = NULL;
|
||||||
prog->prog_usr1 = NULL;
|
}
|
||||||
|
if (prog->prog_usr1)
|
||||||
|
{
|
||||||
|
event_del(prog->prog_usr1);
|
||||||
|
event_free(prog->prog_usr1);
|
||||||
|
prog->prog_usr1 = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ prog_init (struct prog *, unsigned lsquic_engine_flags, struct sport_head *,
|
||||||
# define IP_DONTFRAG_FLAG ""
|
# define IP_DONTFRAG_FLAG ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PROG_OPTS "i:m:c:y:L:l:o:H:s:S:z:" SENDMMSG_FLAG IP_DONTFRAG_FLAG
|
#define PROG_OPTS "i:m:c:y:L:l:o:H:s:S:Y:z:" SENDMMSG_FLAG IP_DONTFRAG_FLAG
|
||||||
|
|
||||||
/* Returns:
|
/* Returns:
|
||||||
* 0 Applied
|
* 0 Applied
|
||||||
|
|
|
@ -231,5 +231,9 @@ add_executable(test_buf test_buf.c)
|
||||||
target_link_libraries(test_buf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
|
target_link_libraries(test_buf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
|
||||||
add_test(buf test_buf)
|
add_test(buf test_buf)
|
||||||
|
|
||||||
|
add_executable(test_cubic test_cubic.c)
|
||||||
|
target_link_libraries(test_cubic lsquic pthread libssl.a libcrypto.a m ${FIULIB})
|
||||||
|
add_test(cubic test_cubic)
|
||||||
|
|
||||||
add_executable(test_dec test_dec.c)
|
add_executable(test_dec test_dec.c)
|
||||||
target_link_libraries(test_dec libssl.a libcrypto.a z m pthread ${FIULIB})
|
target_link_libraries(test_dec libssl.a libcrypto.a z m pthread ${FIULIB})
|
||||||
|
|
|
@ -88,7 +88,7 @@ main (int argc, char **argv)
|
||||||
n = i + atoi(optarg);
|
n = i + atoi(optarg);
|
||||||
for ( ; i < n; ++i)
|
for ( ; i < n; ++i)
|
||||||
{
|
{
|
||||||
lsquic_cubic_ack(&cubic, MS(unit * i), MS(rtt_ms), app_limited);
|
lsquic_cubic_ack(&cubic, MS(unit * i), MS(rtt_ms), app_limited, 1370);
|
||||||
REC(EV_ACK);
|
REC(EV_ACK);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -98,8 +98,8 @@ elide_single_stream_frame (void)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[0]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[0]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[0]);
|
&streams[0]);
|
||||||
packet_out->po_data_sz += len;
|
packet_out->po_data_sz += len;
|
||||||
|
@ -163,8 +163,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(ref_out),
|
lsquic_packet_out_avail(ref_out),
|
||||||
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[0]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[0]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[0]);
|
&streams[0]);
|
||||||
b_off = ref_out->po_data_sz;
|
b_off = ref_out->po_data_sz;
|
||||||
|
@ -178,8 +178,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(ref_out->po_data + ref_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(ref_out),
|
lsquic_packet_out_avail(ref_out),
|
||||||
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[0]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[0]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[0]);
|
&streams[0]);
|
||||||
d_off = ref_out->po_data_sz;
|
d_off = ref_out->po_data_sz;
|
||||||
|
@ -200,8 +200,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
streams[0].id, lsquic_stream_tosend_offset(&streams[0]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[0]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[0]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[0]);
|
&streams[0]);
|
||||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
|
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[0],
|
||||||
|
@ -213,8 +213,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[1].id, lsquic_stream_tosend_offset(&streams[1]),
|
streams[1].id, lsquic_stream_tosend_offset(&streams[1]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[1]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[1]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[1]);
|
&streams[1]);
|
||||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
|
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[1],
|
||||||
|
@ -226,8 +226,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[2].id, lsquic_stream_tosend_offset(&streams[2]),
|
streams[2].id, lsquic_stream_tosend_offset(&streams[2]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[2]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[2]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[2]);
|
&streams[2]);
|
||||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2],
|
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[2],
|
||||||
|
@ -245,8 +245,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[3].id, lsquic_stream_tosend_offset(&streams[3]),
|
streams[3].id, lsquic_stream_tosend_offset(&streams[3]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[3]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[3]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[3]);
|
&streams[3]);
|
||||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3],
|
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[3],
|
||||||
|
@ -258,8 +258,8 @@ elide_three_stream_frames (int chop_regen)
|
||||||
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
len = pf->pf_gen_stream_frame(packet_out->po_data + packet_out->po_data_sz,
|
||||||
lsquic_packet_out_avail(packet_out),
|
lsquic_packet_out_avail(packet_out),
|
||||||
streams[4].id, lsquic_stream_tosend_offset(&streams[4]),
|
streams[4].id, lsquic_stream_tosend_offset(&streams[4]),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(&streams[4]),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(&streams[4]),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
&streams[4]);
|
&streams[4]);
|
||||||
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4],
|
lsquic_packet_out_add_stream(packet_out, &enpub.enp_mm, &streams[4],
|
||||||
|
|
|
@ -37,6 +37,7 @@ main (void)
|
||||||
struct stream_rec *srec;
|
struct stream_rec *srec;
|
||||||
|
|
||||||
memset(&enpub, 0, sizeof(enpub));
|
memset(&enpub, 0, sizeof(enpub));
|
||||||
|
memset(&streams, 0, sizeof(streams));
|
||||||
lsquic_mm_init(&enpub.enp_mm);
|
lsquic_mm_init(&enpub.enp_mm);
|
||||||
packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, QUIC_MAX_PAYLOAD_SZ);
|
packet_out = lsquic_mm_get_packet_out(&enpub.enp_mm, NULL, QUIC_MAX_PAYLOAD_SZ);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "lsquic_parse.h"
|
#include "lsquic_parse.h"
|
||||||
#include "lsquic_sfcw.h"
|
#include "lsquic_sfcw.h"
|
||||||
#include "lsquic_stream.h"
|
#include "lsquic_stream.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
|
|
||||||
struct lsquic_stream_if;
|
struct lsquic_stream_if;
|
||||||
|
@ -77,8 +78,8 @@ static int make_complex_packet(unsigned char *pkt_buf, int max_buf_len)
|
||||||
|
|
||||||
buf_len = pf->pf_gen_stream_frame(p, pend - p,
|
buf_len = pf->pf_gen_stream_frame(p, pend - p,
|
||||||
stream->id, lsquic_stream_tosend_offset(stream),
|
stream->id, lsquic_stream_tosend_offset(stream),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(stream),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(stream),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
stream);
|
stream);
|
||||||
p += buf_len;
|
p += buf_len;
|
||||||
|
@ -99,8 +100,8 @@ void test_stream_frame()
|
||||||
uint8_t buf[1500];
|
uint8_t buf[1500];
|
||||||
int buf_len = pf->pf_gen_stream_frame(buf, 1500,
|
int buf_len = pf->pf_gen_stream_frame(buf, 1500,
|
||||||
stream->id, lsquic_stream_tosend_offset(stream),
|
stream->id, lsquic_stream_tosend_offset(stream),
|
||||||
(gsf_fin_f) lsquic_stream_tosend_fin,
|
lsquic_stream_tosend_fin(stream),
|
||||||
(gsf_size_f) lsquic_stream_tosend_sz,
|
lsquic_stream_tosend_sz(stream),
|
||||||
(gsf_read_f) lsquic_stream_tosend_read,
|
(gsf_read_f) lsquic_stream_tosend_read,
|
||||||
stream);
|
stream);
|
||||||
stream_frame_t stream_frame2;
|
stream_frame_t stream_frame2;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
|
|
||||||
#include "lsquic_alarmset.h"
|
#include "lsquic_alarmset.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
#include "lsquic_conn_flow.h"
|
#include "lsquic_conn_flow.h"
|
||||||
#include "lsquic_sfcw.h"
|
#include "lsquic_sfcw.h"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
|
|
||||||
#include "lsquic_alarmset.h"
|
#include "lsquic_alarmset.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
#include "lsquic_conn_flow.h"
|
#include "lsquic_conn_flow.h"
|
||||||
#include "lsquic_rtt.h"
|
#include "lsquic_rtt.h"
|
||||||
|
@ -494,7 +495,7 @@ test_loc_FIN_rem_FIN (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
s = lsquic_stream_shutdown(stream, 1);
|
s = lsquic_stream_shutdown(stream, 1);
|
||||||
assert(s == 0);
|
assert(s == 0);
|
||||||
|
@ -508,7 +509,7 @@ test_loc_FIN_rem_FIN (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out this packet as well: */
|
/* Pretend we sent out this packet as well: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
||||||
|
|
||||||
|
@ -592,7 +593,7 @@ test_rem_FIN_loc_FIN (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
||||||
|
|
||||||
|
@ -612,7 +613,7 @@ test_rem_FIN_loc_FIN (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out this packet as well: */
|
/* Pretend we sent out this packet as well: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
/* Cannot free stream yet: packets have not been acked */
|
/* Cannot free stream yet: packets have not been acked */
|
||||||
assert(!TAILQ_EMPTY(&tobjs->conn_pub.service_streams));
|
assert(!TAILQ_EMPTY(&tobjs->conn_pub.service_streams));
|
||||||
|
@ -718,7 +719,7 @@ test_loc_FIN_rem_RST (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
s = lsquic_stream_shutdown(stream, 1);
|
s = lsquic_stream_shutdown(stream, 1);
|
||||||
assert(s == 0);
|
assert(s == 0);
|
||||||
|
@ -732,7 +733,7 @@ test_loc_FIN_rem_RST (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out this packet as well: */
|
/* Pretend we sent out this packet as well: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
assert(TAILQ_EMPTY(&tobjs->conn_pub.service_streams)); /* No need to close stream yet */
|
||||||
|
|
||||||
|
@ -804,7 +805,7 @@ test_loc_data_rem_RST (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
s = lsquic_stream_frame_in(stream, new_frame_in(tobjs, 0, 100, 0));
|
s = lsquic_stream_frame_in(stream, new_frame_in(tobjs, 0, 100, 0));
|
||||||
assert(0 == s);
|
assert(0 == s);
|
||||||
|
@ -877,7 +878,7 @@ test_loc_RST_rem_FIN (struct test_objs *tobjs)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs->send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs->send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(1 == stream->n_unacked);
|
assert(1 == stream->n_unacked);
|
||||||
ack_packet(&tobjs->send_ctl, 1);
|
ack_packet(&tobjs->send_ctl, 1);
|
||||||
|
@ -1569,7 +1570,7 @@ test_window_update1 (void)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
|
|
||||||
lsquic_stream_window_update(stream, 20);
|
lsquic_stream_window_update(stream, 20);
|
||||||
nw = lsquic_stream_write(stream, "4567890", 7);
|
nw = lsquic_stream_write(stream, "4567890", 7);
|
||||||
|
@ -1663,13 +1664,15 @@ test_bad_packbits_guess_2 (void)
|
||||||
|
|
||||||
/* Verify packets */
|
/* Verify packets */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_1);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
||||||
assert(1 == packet_out->po_packno);
|
assert(1 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
||||||
assert(2 == packet_out->po_packno);
|
assert(2 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(1 == streams[0]->n_unacked);
|
assert(1 == streams[0]->n_unacked);
|
||||||
assert(1 == streams[1]->n_unacked);
|
assert(1 == streams[1]->n_unacked);
|
||||||
|
@ -1743,13 +1746,15 @@ test_bad_packbits_guess_3 (void)
|
||||||
|
|
||||||
/* Verify packets */
|
/* Verify packets */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_1);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_4);
|
||||||
assert(1 == packet_out->po_packno);
|
assert(1 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_4);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_4);
|
||||||
assert(2 == packet_out->po_packno);
|
assert(2 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(2 == streams[0]->n_unacked);
|
assert(2 == streams[0]->n_unacked);
|
||||||
ack_packet(&tobjs.send_ctl, 1);
|
ack_packet(&tobjs.send_ctl, 1);
|
||||||
|
@ -1964,7 +1969,7 @@ test_window_update2 (void)
|
||||||
|
|
||||||
/* Pretend we sent out a packet: */
|
/* Pretend we sent out a packet: */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
|
|
||||||
lsquic_stream_window_update(stream, 20);
|
lsquic_stream_window_update(stream, 20);
|
||||||
nw = lsquic_stream_write(stream, "4567890", 7);
|
nw = lsquic_stream_write(stream, "4567890", 7);
|
||||||
|
@ -2048,7 +2053,7 @@ test_forced_flush_when_conn_blocked (void)
|
||||||
static int
|
static int
|
||||||
my_gen_stream_frame_err (unsigned char *buf, size_t bufsz,
|
my_gen_stream_frame_err (unsigned char *buf, size_t bufsz,
|
||||||
uint32_t stream_id, uint64_t offset,
|
uint32_t stream_id, uint64_t offset,
|
||||||
gsf_fin_f fin, gsf_size_f size, gsf_read_f read,
|
int fin, size_t size, gsf_read_f read,
|
||||||
void *stream)
|
void *stream)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2159,13 +2164,15 @@ test_bad_packbits_guess_1 (void)
|
||||||
|
|
||||||
/* Verify packets */
|
/* Verify packets */
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_1);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
||||||
assert(1 == packet_out->po_packno);
|
assert(1 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
packet_out = lsquic_send_ctl_next_packet_to_send(&tobjs.send_ctl);
|
||||||
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
|
||||||
assert(2 == packet_out->po_packno);
|
assert(2 == packet_out->po_packno);
|
||||||
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out);
|
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||||
|
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
|
||||||
|
|
||||||
assert(1 == streams[0]->n_unacked);
|
assert(1 == streams[0]->n_unacked);
|
||||||
assert(1 == streams[1]->n_unacked);
|
assert(1 == streams[1]->n_unacked);
|
||||||
|
|
|
@ -796,21 +796,24 @@ run_test (int i)
|
||||||
for (min = 0; min < test->min_sz; ++min)
|
for (min = 0; min < test->min_sz; ++min)
|
||||||
{
|
{
|
||||||
reset_ctx(test);
|
reset_ctx(test);
|
||||||
len = test->pf->pf_gen_stream_frame(out, min, test->stream_id, test_ctx.test->offset,
|
len = test->pf->pf_gen_stream_frame(out, min, test->stream_id,
|
||||||
stream_tosend_fin, stream_tosend_size, stream_tosend_read, &test_ctx);
|
test_ctx.test->offset, stream_tosend_fin(&test_ctx),
|
||||||
|
stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
|
||||||
assert(-1 == len);
|
assert(-1 == len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test that it succeeds now: */
|
/* Test that it succeeds now: */
|
||||||
reset_ctx(test);
|
reset_ctx(test);
|
||||||
len = test->pf->pf_gen_stream_frame(out, min, test->stream_id, test_ctx.test->offset,
|
len = test->pf->pf_gen_stream_frame(out, min, test->stream_id,
|
||||||
stream_tosend_fin, stream_tosend_size, stream_tosend_read, &test_ctx);
|
test_ctx.test->offset, stream_tosend_fin(&test_ctx),
|
||||||
|
stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
|
||||||
assert(len == (int) min);
|
assert(len == (int) min);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_ctx(test);
|
reset_ctx(test);
|
||||||
len = test->pf->pf_gen_stream_frame(out, test->avail, test->stream_id, test_ctx.test->offset,
|
len = test->pf->pf_gen_stream_frame(out, test->avail, test->stream_id,
|
||||||
stream_tosend_fin, stream_tosend_size, stream_tosend_read, &test_ctx);
|
test_ctx.test->offset, stream_tosend_fin(&test_ctx),
|
||||||
|
stream_tosend_size(&test_ctx), stream_tosend_read, &test_ctx);
|
||||||
|
|
||||||
if (test->len > 0) {
|
if (test->len > 0) {
|
||||||
/* Check parser operation */
|
/* Check parser operation */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "lsquic_types.h"
|
#include "lsquic_types.h"
|
||||||
#include "lsquic_alarmset.h"
|
#include "lsquic_alarmset.h"
|
||||||
#include "lsquic_parse.h"
|
#include "lsquic_parse.h"
|
||||||
|
#include "lsquic_packet_common.h"
|
||||||
#include "lsquic_packet_in.h"
|
#include "lsquic_packet_in.h"
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue