Compare commits

...

7 Commits

Author SHA1 Message Date
George Wang 0b9f50b5f0 Release 4.0.9 2024-06-12 18:32:52 -04:00
LiteSpeed Tech c4f359fcb0
Update README.md 2024-05-28 23:42:55 -04:00
George Wang aa3b438a67 Release 4.0.8 2024-03-12 17:46:16 -04:00
George Wang f416a13afe Release 4.0.7 2024-02-28 19:05:41 -05:00
George Wang 851b0b0a57 update README. 2024-02-27 14:18:19 -05:00
George Wang e8a78e300e Update docker build. 2024-02-27 14:17:30 -05:00
George Wang c8cb6aa3e2 Release 4.0.6 2024-02-23 18:40:48 -05:00
11 changed files with 269 additions and 57 deletions

View File

@ -1,3 +1,22 @@
2024-06-12
- 4.0.9
- Fix bpq_count (issue #504).
2024-03-12
- 4.0.8
- Fix RETIRE_CONNECTION_ID frame abuse.
- Fix some assert failures.
2024-02-28
- 4.0.7
- Fix overly strict 0-RTT packet DCID validation.
- Update docker build.
2024-02-23
- 4.0.6
- Fix ACK handling.
- Do not apply congestion control to CONNECTION_CLOSE frame.
2024-02-07
- 4.0.5
- Fix CPU spinning due to STREAM_BLOCKED frame.

View File

@ -1,13 +1,17 @@
FROM ubuntu:16.04
FROM ubuntu:20.04 as build-lsquic
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && \
apt-get install -y build-essential git cmake software-properties-common \
apt-get install -y apt-utils build-essential git cmake software-properties-common \
zlib1g-dev libevent-dev
RUN add-apt-repository ppa:gophers/archive && \
RUN add-apt-repository ppa:longsleep/golang-backports && \
apt-get update && \
apt-get install -y golang-1.9-go && \
cp /usr/lib/go-1.9/bin/go* /usr/bin/.
apt-get install -y golang-1.21-go && \
cp /usr/lib/go-1.21/bin/go* /usr/bin/.
ENV GOROOT /usr/lib/go-1.21
RUN mkdir /src
WORKDIR /src
@ -15,14 +19,21 @@ WORKDIR /src
RUN mkdir /src/lsquic
COPY ./ /src/lsquic/
RUN git clone https://boringssl.googlesource.com/boringssl && \
RUN git clone https://github.com/google/boringssl.git && \
cd boringssl && \
git checkout a2278d4d2cabe73f6663e3299ea7808edfa306b9 && \
git checkout 9fc1c33e9c21439ce5f87855a6591a9324e569fd && \
cmake . && \
make
ENV EXTRA_CFLAGS -DLSQUIC_QIR=1
RUN cd /src/lsquic && \
cmake -DBORINGSSL_DIR=/src/boringssl . && \
make
RUN cd lsquic && make test && cp bin/http_client /usr/bin/ && cp bin/http_server /usr/bin
RUN cd lsquic && cp bin/http_client /usr/bin/ && cp bin/http_server /usr/bin
FROM martenseemann/quic-network-simulator-endpoint:latest as lsquic-qir
COPY --from=build-lsquic /usr/bin/http_client /usr/bin/http_server /usr/bin/
COPY qir/run_endpoint.sh .
RUN chmod +x run_endpoint.sh
ENTRYPOINT [ "./run_endpoint.sh" ]

View File

@ -22,22 +22,23 @@ Standard Compliance
LiteSpeed QUIC is mostly compliant to the follow RFCs:
- [RFC 9000](https://www.rfc-editor.org/rfc/rfc9000)
- [RFC 9001](https://www.rfc-editor.org/rfc/rfc9001)
- [RFC 9002](https://www.rfc-editor.org/rfc/rfc9002)
- [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114)
- [RFC 9204](https://www.rfc-editor.org/rfc/rfc9204)
- [RFC 9000](https://www.rfc-editor.org/rfc/rfc9000) QUIC: A UDP-Based Multiplexed and Secure Transport
- [RFC 9001](https://www.rfc-editor.org/rfc/rfc9001) Using TLS to Secure QUIC
- [RFC 9002](https://www.rfc-editor.org/rfc/rfc9002) QUIC Loss Detection and Congestion Control
- [RFC 9114](https://www.rfc-editor.org/rfc/rfc9114) HTTP/3
- [RFC 9204](https://www.rfc-editor.org/rfc/rfc9204) QPACK: Field Compression for HTTP/3
QUIC protocol extensions
------------------------
The following QUIC protocol extensions are implemented:
- [QUIC Version 2](https://www.rfc-editor.org/authors/rfc9369.html)
- [Compatible Version Negotiation](https://datatracker.ietf.org/doc/draft-ietf-quic-version-negotiation/)
- [Datagrams](https://datatracker.ietf.org/doc/html/rfc9221)
- [RFC 9368](https://www.rfc-editor.org/rfc/rfc9368) Compatible Version Negotiation for QUIC
- [RFC 9369](https://www.rfc-editor.org/rfc/rfc9369) QUIC Version 2
- [RFC 9218](https://www.rfc-editor.org/rfc/rfc9218) Extensible Prioritization Scheme for HTTP
- [RFC 9221](https://www.rfc-editor.org/rfc/rfc9221) An Unreliable Datagram Extension to QUIC
- [RFC 9287](https://www.rfc-editor.org/rfc/rfc9287) Greasing the QUIC Bit
- [ACK Frequency](https://datatracker.ietf.org/doc/draft-ietf-quic-ack-frequency/)
- [Greasing the QUIC Bit](https://datatracker.ietf.org/doc/html/rfc9287)
Documentation
-------------
@ -71,7 +72,7 @@ You may need to install pre-requisites like zlib and libevent.
2. Use specific BoringSSL version
```
git checkout 31bad2514d21f6207f3925ba56754611c462a873
git checkout 9fc1c33e9c21439ce5f87855a6591a9324e569fd
```
Or, just try the latest master branch.
@ -111,8 +112,7 @@ as follows:
```
git clone https://github.com/litespeedtech/lsquic.git
cd lsquic
git submodule init
git submodule update
git submodule update --init
```
2. Compile the library
@ -147,8 +147,7 @@ The library and the example client and server can be built with Docker.
Initialize Git submodules:
```
cd lsquic
git submodule init
git submodule update
git submodule update --init
```
Build the Docker image:

View File

@ -26,7 +26,7 @@ author = u'LiteSpeed Technologies'
# The short X.Y version
version = u'4.0'
# The full version, including alpha/beta/rc tags
release = u'4.0.5'
release = u'4.0.9'
# -- General configuration ---------------------------------------------------

View File

@ -27,7 +27,7 @@ extern "C" {
#define LSQUIC_MAJOR_VERSION 4
#define LSQUIC_MINOR_VERSION 0
#define LSQUIC_PATCH_VERSION 5
#define LSQUIC_PATCH_VERSION 9
/**
* Engine flags:

139
qir/run_endpoint.sh Normal file
View File

@ -0,0 +1,139 @@
#!/bin/bash
#
# run_endpoint.sh -- QUIC Interop Runner script for lsquic
#
/setup.sh
if [ "$ROLE" == "client" ]; then
# Wait for the simulator to start up.
/wait-for-it.sh sim:57832 -s -t 30
fi
echo TEST_PARAMS: $TEST_PARAMS
echo REQUESTS: "'$REQUESTS'"
eval $(perl <<'PERL'
@paths = split /\s+/, $ENV{REQUESTS};
s~^https?://[^/]+~-p ~ for @paths;
print "PATHS='@paths'\n";
$server = $ENV{REQUESTS};
$server =~ s~^https?://~~;
$server =~ s~/.*~~;
($server, $port) = split /:/, $server;
print "SERVER=$server\n";
print "PORT=$port\n";
print "N_REQS=", scalar(@paths), "\n";
print "N_reqs=", scalar(@paths), "\n";
if (@paths > 100) {
print "W=100\n";
} else {
print "W=1\n";
}
PERL
)
echo paths: $PATHS
echo server: $SERVER
echo port: $PORT
# lsquic command-line tools create one file per connection when -G option
# is used. Here we make a copy and give it required name.
#
function maybe_create_keylog() {
local NAME=/logs/keys.log
if ls /logs/*.keys; then
# There may be more than one of these, as one file is created per
# connection.
cat /logs/*.keys > $NAME
fi
if [ -f $NAME ]; then
echo $NAME exists
else
echo $NAME does not exit
fi
}
if [ "$ROLE" = server ]; then
if [ ! -z "$TESTCASE" ]; then
case "$TESTCASE" in
http3)
VERSIONS='-o version=h3-29 -o version=h3'
;;
v2)
VERSIONS='-o version=h3-v2 -o version=h3 -Q hq-interop'
;;
handshake|transfer|longrtt|resumption|blackhole|multiconnect|chacha20|zerortt)
VERSIONS='-o version=h3-29 -o version=h3 -o scid_iss_rate=0 -Q hq-interop'
;;
retry)
VERSIONS='-o version=h3-29 -o version=h3 -o srej=1 -Q hq-interop'
FORCE_RETRY=1
;;
ecn)
VERSIONS='-o version=h3-29 -o version=h3 -Q hq-interop'
ECN='-o ecn=1'
;;
*) exit 127 ;;
esac
fi
echo SERVER_PARAMS: $SERVER_PARAMS
exec env LSQUIC_FORCE_RETRY=$FORCE_RETRY /usr/bin/http_server $VERSIONS $ECN \
-c server,/certs/cert.pem,/certs/priv.key \
-c server4,/certs/cert.pem,/certs/priv.key \
-c server6,/certs/cert.pem,/certs/priv.key \
-c server46,/certs/cert.pem,/certs/priv.key \
-s ::0:443 -s 0.0.0.0:443 -s 193.167.100.100:12345 \
-r /www -L debug 2>/logs/$TESTCASE.out
elif [ "$ROLE" = debug-server ]; then
exec /usr/bin/http_server $SERVER_PARAMS
elif [ "$ROLE" = client ]; then
if [ ! -z "$TESTCASE" ]; then
case "$TESTCASE" in
http3)
VERSIONS='-o version=h3'
;;
v2)
VERSIONS='-o version=h3-v2 -o version=h3 -Q hq-interop'
;;
handshake|transfer|longrtt|retry|multiplexing|blackhole)
VERSIONS='-o version=h3 -Q hq-interop'
;;
multiconnect)
VERSIONS='-o version=h3 -Q hq-interop'
N_REQS=1
;;
ecn)
VERSIONS='-o version=h3 -Q hq-interop'
ECN='-o ecn=1'
;;
resumption)
VERSIONS='-o version=h3 -Q hq-interop'
RESUME='-0 /logs/resume.file'
;;
*) exit 127 ;;
esac
fi
echo CLIENT_PARAMS: $CLIENT_PARAMS
if [ "$TESTCASE" = resumption ]; then
# Fetch first file:
/usr/bin/http_client $VERSIONS -s $SERVER:$PORT $PATHS \
-r 1 -R 1 $RESUME \
-B -7 /downloads -G /logs \
-L debug 2>/logs/$TESTCASE-req1.out || exit $?
PATHS=`echo "$PATHS" | sed 's~-p /[^ ]* ~~'`
N_REQS=1
N_reqs=1
W=1
echo "first request successful, new args: $N_REQS; $N_reqs; $PATHS"
fi
/usr/bin/http_client $VERSIONS -s $SERVER:$PORT $PATHS \
-r $N_reqs -R $N_REQS -w $W $ECN $RESUME \
-B -7 /downloads -G /logs \
-L debug 2>/logs/$TESTCASE.out
EXIT_CODE=$?
maybe_create_keylog
sync
exit $EXIT_CODE
else
echo hi
exit 127
fi

View File

@ -467,6 +467,7 @@ struct ietf_full_conn
} ifc_peer_hq_settings;
struct dcid_elem *ifc_dces[MAX_IETF_CONN_DCIDS];
TAILQ_HEAD(, dcid_elem) ifc_to_retire;
unsigned ifc_n_to_retire;
unsigned ifc_scid_seqno;
lsquic_time_t ifc_scid_timestamp[MAX_SCID];
/* Last 8 packets had ECN markings? */
@ -1277,6 +1278,7 @@ ietf_full_conn_init (struct ietf_full_conn *conn,
TAILQ_INIT(&conn->ifc_pub.service_streams);
STAILQ_INIT(&conn->ifc_stream_ids_to_ss);
TAILQ_INIT(&conn->ifc_to_retire);
conn->ifc_n_to_retire = 0;
lsquic_alarmset_init(&conn->ifc_alset, &conn->ifc_conn);
lsquic_alarmset_init_alarm(&conn->ifc_alset, AL_IDLE, idle_alarm_expired, conn);
@ -1933,7 +1935,7 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
conn->ifc_flags |= IFC_ACK_HAD_MISS;
else
conn->ifc_flags &= ~IFC_ACK_HAD_MISS;
LSQ_DEBUG("Put %d bytes of ACK frame into packet %" PRIu64
LSQ_DEBUG("Put %d bytes of ACK frame into packet #%" PRIu64
" on outgoing queue", w, packet_out->po_packno);
if (conn->ifc_n_cons_unretx >= conn->ifc_ping_unretx_thresh &&
!lsquic_send_ctl_have_outgoing_retx_frames(&conn->ifc_send_ctl))
@ -1944,6 +1946,7 @@ generate_ack_frame_for_pns (struct ietf_full_conn *conn,
/* This gives a range [12, 27]: */
conn->ifc_ping_unretx_thresh = 12
+ lsquic_crand_get_nybble(conn->ifc_enpub->enp_crand);
conn->ifc_n_cons_unretx = 0;
}
conn->ifc_n_slack_akbl[pns] = 0;
@ -2292,6 +2295,7 @@ generate_retire_cid_frame (struct ietf_full_conn *conn)
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w);
TAILQ_REMOVE(&conn->ifc_to_retire, dce, de_next_to_ret);
--conn->ifc_n_to_retire;
lsquic_malo_put(dce);
if (TAILQ_EMPTY(&conn->ifc_to_retire))
@ -2306,6 +2310,13 @@ generate_retire_cid_frames (struct ietf_full_conn *conn, lsquic_time_t now)
{
int s;
if (conn->ifc_n_to_retire >= MAX_IETF_CONN_DCIDS * 3)
{
ABORT_QUIETLY(0, TEC_CONNECTION_ID_LIMIT_ERROR,
"too many (%d) CIDs to retire", conn->ifc_n_to_retire);
return;
}
do
s = generate_retire_cid_frame(conn);
while (0 == s && (conn->ifc_send_flags & SF_SEND_RETIRE_CID));
@ -3026,6 +3037,7 @@ retire_dcid (struct ietf_full_conn *conn, struct dcid_elem **dce)
if ((*dce)->de_hash_el.qhe_flags & QHE_HASHED)
lsquic_hash_erase(conn->ifc_enpub->enp_srst_hash, &(*dce)->de_hash_el);
TAILQ_INSERT_TAIL(&conn->ifc_to_retire, *dce, de_next_to_ret);
++conn->ifc_n_to_retire;
LSQ_DEBUG("prepare to retire DCID seqno %"PRIu32"", (*dce)->de_seqno);
*dce = NULL;
conn->ifc_send_flags |= SF_SEND_RETIRE_CID;
@ -3043,6 +3055,7 @@ retire_seqno (struct ietf_full_conn *conn, unsigned seqno)
memset(dce, 0, sizeof(*dce));
dce->de_seqno = seqno;
TAILQ_INSERT_TAIL(&conn->ifc_to_retire, dce, de_next_to_ret);
++conn->ifc_n_to_retire;
LSQ_DEBUG("prepare to retire DCID seqno %"PRIu32, seqno);
conn->ifc_send_flags |= SF_SEND_RETIRE_CID;
}
@ -3174,6 +3187,7 @@ ietf_full_conn_ci_destroy (struct lsquic_conn *lconn)
while ((dce = TAILQ_FIRST(&conn->ifc_to_retire)))
{
TAILQ_REMOVE(&conn->ifc_to_retire, dce, de_next_to_ret);
--conn->ifc_n_to_retire;
lsquic_malo_put(dce);
}
lsquic_send_ctl_cleanup(&conn->ifc_send_ctl);
@ -3375,6 +3389,7 @@ retire_cid_from_tp (struct ietf_full_conn *conn,
sizeof(dce->de_srst));
dce->de_flags = DE_SRST;
TAILQ_INSERT_TAIL(&conn->ifc_to_retire, dce, de_next_to_ret);
++conn->ifc_n_to_retire;
LSQ_DEBUG("prepare to retire DCID seqno %"PRIu32, dce->de_seqno);
conn->ifc_send_flags |= SF_SEND_RETIRE_CID;
}
@ -7523,7 +7538,7 @@ process_regular_packet (struct ietf_full_conn *conn,
packet_in);
else
{
if (is_dcid_changed)
if (is_dcid_changed && HETY_0RTT != packet_in->pi_header_type)
{
if (LSQUIC_CIDS_EQ(&conn->ifc_conn.cn_cces[0].cce_cid,
&packet_in->pi_dcid)
@ -7941,7 +7956,7 @@ ietf_full_conn_ci_packet_sent (struct lsquic_conn *lconn,
struct ietf_full_conn *const conn = (struct ietf_full_conn *) lconn;
int s;
if (packet_out->po_frame_types & (IQUIC_FRAME_RETX_MASK | QUIC_FTBIT_ACK))
if (packet_out->po_frame_types & (IQUIC_FRAME_RETX_MASK))
conn->ifc_n_cons_unretx = 0;
else
++conn->ifc_n_cons_unretx;
@ -8574,7 +8589,8 @@ ietf_full_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
|| 0 != lsquic_send_ctl_n_scheduled(&conn->ifc_send_ctl))
)
{
RETURN_IF_OUT_OF_PACKETS();
/* CONNECTION_CLOSE frame should not be congestion controlled.
RETURN_IF_OUT_OF_PACKETS(); */
generate_connection_close_packet(conn);
tick |= TICK_SEND|TICK_CLOSE;
}

View File

@ -232,10 +232,12 @@ lsquic_dcid_from_packet (const unsigned char *buf, size_t bufsz,
{
/* Xs vary, Gs are iGnored: */
/* 1X11 XGGG: */
/*
case (0x80|0x40|0x20|0x10|0x08) >> 3:
case (0x80|0x00|0x20|0x10|0x08) >> 3:
case (0x80|0x40|0x20|0x10|0x00) >> 3:
case (0x80|0x00|0x20|0x10|0x00) >> 3:
*/
Q046_long:
/* lsquic_Q046_parse_packet_in_long_begin */
if (bufsz < 14)

View File

@ -1606,7 +1606,7 @@ lsquic_send_ctl_cleanup (lsquic_send_ctl_t *ctl)
send_ctl_destroy_packet(ctl, packet_out);
}
assert(0 == ctl->sc_n_scheduled);
assert(0 == ctl->sc_bytes_scheduled);
//assert(0 == ctl->sc_bytes_scheduled);
for (pns = PNS_INIT; pns < N_PNS; ++pns)
while ((packet_out = TAILQ_FIRST(&ctl->sc_unacked_packets[pns])))
{
@ -1704,16 +1704,23 @@ lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *ctl)
static int
send_ctl_can_send (struct lsquic_send_ctl *ctl)
{
uint64_t cwnd = ctl->sc_ci->cci_get_cwnd(CGP(ctl));
const unsigned n_out = send_ctl_all_bytes_out(ctl);
LSQ_DEBUG("%s: n_out: %u (unacked_all: %u); cwnd: %"PRIu64
"; ccfc: %"PRIu64"/%"PRIu64, __func__,
n_out, ctl->sc_bytes_unacked_all,
ctl->sc_ci->cci_get_cwnd(CGP(ctl)),
LSQ_DEBUG("%s: sc_flags: 0x%X, b_out: %u = (%u + %u); b_retx: %u; cwnd: %"PRIu64
"; ccfc: %"PRIu64"/%"PRIu64"; n_scheduled: %d, n_in_flight_all: %d"
"; pa_burst: %d; pa_next: %lu; pa_now: %lu"
, __func__, ctl->sc_flags,
n_out, ctl->sc_bytes_unacked_all, ctl->sc_bytes_scheduled,
ctl->sc_bytes_unacked_retx, cwnd,
ctl->sc_conn_pub->conn_cap.cc_sent,
ctl->sc_conn_pub->conn_cap.cc_max);
ctl->sc_conn_pub->conn_cap.cc_max,
ctl->sc_n_scheduled, ctl->sc_n_in_flight_all,
ctl->sc_pacer.pa_burst_tokens,
ctl->sc_pacer.pa_next_sched, ctl->sc_pacer.pa_now);
if (ctl->sc_flags & SC_PACE)
{
if (n_out >= ctl->sc_ci->cci_get_cwnd(CGP(ctl)))
if (n_out >= cwnd)
return 0;
if (lsquic_pacer_can_schedule(&ctl->sc_pacer,
ctl->sc_n_scheduled + ctl->sc_n_in_flight_all))
@ -1728,7 +1735,7 @@ send_ctl_can_send (struct lsquic_send_ctl *ctl)
return 0;
}
else
return n_out < ctl->sc_ci->cci_get_cwnd(CGP(ctl));
return n_out < cwnd;
}
@ -3162,7 +3169,7 @@ split_buffered_packet (lsquic_send_ctl_t *ctl,
LSQ_DEBUG("drop oversized buffered packet #%"PRIu64, packet_out->po_packno);
TAILQ_REMOVE(&packet_q->bpq_packets, packet_out, po_next);
++packet_q->bpq_count;
--packet_q->bpq_count;
assert(packet_out->po_loss_chain == packet_out);
send_ctl_destroy_packet(ctl, packet_out);
return 0;

View File

@ -285,32 +285,41 @@ lsquic_send_ctl_ack_to_front (struct lsquic_send_ctl *, unsigned n_acks);
#define lsquic_send_ctl_n_stop_waiting(ctl) \
(+(ctl)->sc_n_stop_waiting)
#define lsquic_send_ctl_n_stop_waiting_reset(ctl) do { \
(ctl)->sc_n_stop_waiting = 0; \
} while (0)
static inline void
lsquic_send_ctl_n_stop_waiting_reset(lsquic_send_ctl_t *ctl)
{
ctl->sc_n_stop_waiting = 0;
}
void
lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *);
#define lsquic_send_ctl_tick_in(ctl, now) do { \
if ((ctl)->sc_flags & SC_PACE) \
{ \
(ctl)->sc_flags |= SC_SCHED_TICK; \
lsquic_pacer_tick_in(&(ctl)->sc_pacer, now); \
} \
(ctl)->sc_flags &= ~SC_APP_LIMITED; \
} while (0)
static inline void
lsquic_send_ctl_tick_in(lsquic_send_ctl_t *ctl, lsquic_time_t now)
{
if ((ctl)->sc_flags & SC_PACE)
{
(ctl)->sc_flags |= SC_SCHED_TICK;
lsquic_pacer_tick_in(&(ctl)->sc_pacer, now);
}
(ctl)->sc_flags &= ~SC_APP_LIMITED;
}
#define lsquic_send_ctl_tick_out(ctl) do { \
if ((ctl)->sc_flags & SC_PACE) \
lsquic_pacer_tick_out(&(ctl)->sc_pacer); \
} while (0)
static inline void
lsquic_send_ctl_tick_out(lsquic_send_ctl_t *ctl)
{
if ((ctl)->sc_flags & SC_PACE)
lsquic_pacer_tick_out(&(ctl)->sc_pacer);
}
#define lsquic_send_ctl_next_pacer_time(ctl) ( \
((ctl)->sc_flags & SC_PACE) \
&& lsquic_pacer_delayed(&(ctl)->sc_pacer) \
? lsquic_pacer_next_sched(&(ctl)->sc_pacer) \
: 0 )
static inline lsquic_time_t
lsquic_send_ctl_next_pacer_time(lsquic_send_ctl_t *ctl)
{
return ((ctl)->sc_flags & SC_PACE)
&& lsquic_pacer_delayed(&(ctl)->sc_pacer)
? lsquic_pacer_next_sched(&(ctl)->sc_pacer)
: 0;
}
enum packno_bits
lsquic_send_ctl_packno_bits (struct lsquic_send_ctl *, enum packnum_space);

View File

@ -1888,6 +1888,11 @@ stream_shutdown_write (lsquic_stream_t *stream)
{
LSQ_DEBUG("turned on FIN flag in the yet-unsent STREAM frame");
stream->stream_flags |= STREAM_FIN_SENT;
if (stream->sm_qflags & SMQF_WANT_FLUSH)
{
LSQ_DEBUG("turned off SMQF_WANT_FLUSH flag as FIN flag is turned on.");
maybe_remove_from_write_q(stream, SMQF_WANT_FLUSH);
}
}
else
{
@ -3459,6 +3464,11 @@ stream_write_to_packets (lsquic_stream_t *stream, struct lsquic_reader *reader,
if (use_framing && seen_ok)
maybe_close_varsize_hq_frame(stream);
stream->stream_flags |= STREAM_FIN_SENT;
if (stream->sm_qflags & SMQF_WANT_FLUSH)
{
LSQ_DEBUG("turned off SMQF_WANT_FLUSH flag as FIN has been sent.");
maybe_remove_from_write_q(stream, SMQF_WANT_FLUSH);
}
goto end;
}
else