mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 2.24.0
- [FEATURE] QUIC and HTTP/3 Internet Draft 31 support. Drop ID-30 and ID-31 support. - [BUGFIX] Divide-by-zero in newly enabled conn stats code when no packets were sent. - [BUGFIX] Memory leak in gQUIC client when server hello cannot be parsed. - [BUGFIX] Server Initial packet size calculation. - Log user-agent and CONN_CLOSE reason when peer reports error. - Example programs: Specify ALPN for echo and md5 clients and servers (issue #184). - Example programs: Don't add "QUIC_" prefix to lines in keylog file (issue #185). - http_server: Fix fd leak in preadv mode; fix preadv() usage when reading from disk.
This commit is contained in:
parent
078f53798c
commit
4429f8ea1e
33 changed files with 249 additions and 117 deletions
17
CHANGELOG
17
CHANGELOG
|
@ -1,3 +1,20 @@
|
|||
2020-10-28
|
||||
- 2.24.0
|
||||
- [FEATURE] QUIC and HTTP/3 Internet Draft 31 support. Drop ID-30
|
||||
and ID-31 support.
|
||||
- [BUGFIX] Divide-by-zero in newly enabled conn stats code when no
|
||||
packets were sent.
|
||||
- [BUGFIX] Memory leak in gQUIC client when server hello cannot be
|
||||
parsed.
|
||||
- [BUGFIX] Server Initial packet size calculation.
|
||||
- Log user-agent and CONN_CLOSE reason when peer reports error.
|
||||
- Example programs: Specify ALPN for echo and md5 clients and servers
|
||||
(issue #184).
|
||||
- Example programs: Don't add "QUIC_" prefix to lines in keylog file
|
||||
(issue #185).
|
||||
- http_server: Fix fd leak in preadv mode; fix preadv() usage when
|
||||
reading from disk.
|
||||
|
||||
2020-10-22
|
||||
- 2.23.3
|
||||
- [BUGFIX] Update packetization threshold when writing to stream
|
||||
|
|
|
@ -14,8 +14,7 @@ distribution is used in our own products: LiteSpeed Web Server, LiteSpeed ADC,
|
|||
and OpenLiteSpeed.
|
||||
|
||||
Currently supported QUIC versions are Q043, Q046, Q050, ID-27, ID-28, ID-29,
|
||||
ID-30, and ID-31. Support for newer versions is added soon after they
|
||||
are released.
|
||||
and ID-32. Support for newer versions is added soon after they are released.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
|
|
@ -213,6 +213,7 @@ main (int argc, char **argv)
|
|||
|
||||
TAILQ_INIT(&sports);
|
||||
prog_init(&prog, 0, &sports, &client_echo_stream_if, &client_ctx);
|
||||
prog.prog_api.ea_alpn = "echo";
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "h")))
|
||||
{
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include "lsquic.h"
|
||||
#include "test_common.h"
|
||||
#include "../src/liblsquic/lsquic_hash.h"
|
||||
#include "test_cert.h"
|
||||
#include "prog.h"
|
||||
|
||||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
|
@ -218,6 +220,7 @@ main (int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
add_alpn("echo");
|
||||
if (0 != prog_prep(&prog))
|
||||
{
|
||||
LSQ_ERROR("could not prep");
|
||||
|
|
|
@ -582,13 +582,39 @@ my_preadv (void *user_data, const struct iovec *iov, int iovcnt)
|
|||
{
|
||||
#if HAVE_PREADV
|
||||
lsquic_stream_ctx_t *const st_h = user_data;
|
||||
return preadv(st_h->file_fd, iov, iovcnt, st_h->written);
|
||||
ssize_t nread = preadv(st_h->file_fd, iov, iovcnt, st_h->written);
|
||||
LSQ_DEBUG("%s: wrote %zd bytes", __func__, (size_t) nread);
|
||||
return nread;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
pwritev_fallback_read (void *lsqr_ctx, void *buf, size_t count)
|
||||
{
|
||||
lsquic_stream_ctx_t *const st_h = lsqr_ctx;
|
||||
struct iovec iov;
|
||||
size_t ntoread;
|
||||
|
||||
ntoread = st_h->file_size - st_h->written;
|
||||
if (ntoread > count)
|
||||
count = ntoread;
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = count;
|
||||
return my_preadv(lsqr_ctx, &iov, 1);
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
pwritev_fallback_size (void *lsqr_ctx)
|
||||
{
|
||||
lsquic_stream_ctx_t *const st_h = lsqr_ctx;
|
||||
return st_h->file_size - st_h->written;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
http_server_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||
{
|
||||
|
@ -624,11 +650,17 @@ http_server_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
|||
to_write = s_pwritev;
|
||||
nw = lsquic_stream_pwritev(stream, my_preadv, st_h, to_write);
|
||||
if (nw == 0)
|
||||
goto use_reader;
|
||||
{
|
||||
struct lsquic_reader reader = {
|
||||
.lsqr_read = pwritev_fallback_read,
|
||||
.lsqr_size = pwritev_fallback_size,
|
||||
.lsqr_ctx = st_h,
|
||||
};
|
||||
nw = lsquic_stream_writef(stream, &reader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
use_reader:
|
||||
nw = lsquic_stream_writef(stream, &st_h->reader);
|
||||
}
|
||||
if (nw < 0)
|
||||
|
@ -1006,6 +1038,8 @@ http_server_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
|||
free(st_h->req_path);
|
||||
if (st_h->reader.lsqr_ctx)
|
||||
destroy_lsquic_reader_ctx(st_h->reader.lsqr_ctx);
|
||||
if (s_pwritev)
|
||||
close(st_h->file_fd);
|
||||
if (st_h->req)
|
||||
interop_server_hset_destroy(st_h->req);
|
||||
free(st_h);
|
||||
|
|
|
@ -460,6 +460,7 @@ main (int argc, char **argv)
|
|||
|
||||
TAILQ_INIT(&sports);
|
||||
prog_init(&prog, 0, &sports, &client_file_stream_if, &client_ctx);
|
||||
prog.prog_api.ea_alpn = "md5";
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "bhr:f:p:")))
|
||||
{
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "lsquic.h"
|
||||
#include "test_common.h"
|
||||
#include "../src/liblsquic/lsquic_hash.h"
|
||||
#include "test_cert.h"
|
||||
#include "prog.h"
|
||||
|
||||
#include "../src/liblsquic/lsquic_logger.h"
|
||||
|
@ -325,6 +327,7 @@ main (int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
add_alpn("md5");
|
||||
if (0 != prog_prep(&prog))
|
||||
{
|
||||
LSQ_ERROR("could not prep");
|
||||
|
|
|
@ -610,11 +610,6 @@ keylog_open (void *ctx, lsquic_conn_t *conn)
|
|||
static void
|
||||
keylog_log_line (void *handle, const char *line)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(line);
|
||||
if (len < sizeof("QUIC_") - 1 || strncmp(line, "QUIC_", 5))
|
||||
fputs("QUIC_", handle);
|
||||
fputs(line, handle);
|
||||
fputs("\n", handle);
|
||||
fflush(handle);
|
||||
|
|
|
@ -58,13 +58,9 @@ developed by the IETF. Both types are included in a single enum:
|
|||
|
||||
IETF QUIC version ID 29
|
||||
|
||||
.. member:: LSQVER_ID30
|
||||
.. member:: LSQVER_ID32
|
||||
|
||||
IETF QUIC version ID 30; this version is deprecated.
|
||||
|
||||
.. member:: LSQVER_ID31
|
||||
|
||||
IETF QUIC version ID 31
|
||||
IETF QUIC version ID 32
|
||||
|
||||
.. member:: N_LSQVER
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
|
|||
author = u'LiteSpeed Technologies'
|
||||
|
||||
# The short X.Y version
|
||||
version = u'2.23'
|
||||
version = u'2.24'
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'2.23.3'
|
||||
release = u'2.24.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
@ -17,7 +17,7 @@ Most of the code in this distribution has been used in our own products
|
|||
since 2017.
|
||||
|
||||
Currently supported QUIC versions are Q043, Q046, Q050, ID-27, ID-28,
|
||||
ID-29, ID-30, and ID-31.
|
||||
ID-29, and ID-32.
|
||||
Support for newer versions will be added soon after they are released.
|
||||
|
||||
LSQUIC is licensed under the `MIT License`_; see LICENSE in the source
|
||||
|
|
|
@ -24,8 +24,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 23
|
||||
#define LSQUIC_PATCH_VERSION 3
|
||||
#define LSQUIC_MINOR_VERSION 24
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
@ -92,14 +92,9 @@ enum lsquic_version
|
|||
LSQVER_ID29,
|
||||
|
||||
/**
|
||||
* IETF QUIC Draft-30
|
||||
* IETF QUIC Draft-32
|
||||
*/
|
||||
LSQVER_ID30,
|
||||
|
||||
/**
|
||||
* IETF QUIC Draft-31
|
||||
*/
|
||||
LSQVER_ID31,
|
||||
LSQVER_ID32,
|
||||
|
||||
/**
|
||||
* Special version to trigger version negotiation.
|
||||
|
@ -112,7 +107,7 @@ enum lsquic_version
|
|||
|
||||
/**
|
||||
* We currently support versions 43, 46, 50, Draft-27, Draft-28, Draft-29,
|
||||
* Draft-30, and Draft-31.
|
||||
* and Draft-32.
|
||||
* @see lsquic_version
|
||||
*/
|
||||
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
|
||||
|
@ -125,18 +120,17 @@ enum lsquic_version
|
|||
#define LSQUIC_EXPERIMENTAL_VERSIONS ( \
|
||||
(1 << LSQVER_VERNEG) | LSQUIC_EXPERIMENTAL_Q098)
|
||||
|
||||
#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
|
||||
| (1 << LSQVER_ID30))
|
||||
#define LSQUIC_DEPRECATED_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28))
|
||||
|
||||
#define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043)
|
||||
|
||||
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
|
||||
| (1 << LSQVER_ID29) | (1 << LSQVER_ID30) \
|
||||
| (1 << LSQVER_ID31) | (1 << LSQVER_VERNEG))
|
||||
| (1 << LSQVER_ID29) \
|
||||
| (1 << LSQVER_ID32) | (1 << LSQVER_VERNEG))
|
||||
|
||||
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
|
||||
| (1 << LSQVER_ID29) | (1 << LSQVER_ID30) \
|
||||
| (1 << LSQVER_ID31) | (1 << LSQVER_VERNEG))
|
||||
| (1 << LSQVER_ID29) \
|
||||
| (1 << LSQVER_ID32) | (1 << LSQVER_VERNEG))
|
||||
|
||||
enum lsquic_hsk_status
|
||||
{
|
||||
|
|
|
@ -133,6 +133,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
/* fallthru */
|
||||
case DATA_FORMAT_ERROR:
|
||||
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
|
||||
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
||||
c_hsk->buf_in = NULL;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
|
||||
|
|
|
@ -338,8 +338,7 @@ extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
|
|||
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID28 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID29 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID30 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID31 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_ID32 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
|
||||
&lsquic_enc_session_common_gquic_1 )
|
||||
|
|
|
@ -74,9 +74,8 @@ static const struct alpn_map {
|
|||
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
|
||||
{ LSQVER_ID28, (unsigned char *) "\x05h3-28", },
|
||||
{ LSQVER_ID29, (unsigned char *) "\x05h3-29", },
|
||||
{ LSQVER_ID30, (unsigned char *) "\x05h3-30", },
|
||||
{ LSQVER_ID31, (unsigned char *) "\x05h3-31", },
|
||||
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-31", },
|
||||
{ LSQVER_ID32, (unsigned char *) "\x05h3-32", },
|
||||
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-32", },
|
||||
};
|
||||
|
||||
struct enc_sess_iquic;
|
||||
|
|
|
@ -1114,7 +1114,8 @@ full_conn_ci_destroy (lsquic_conn_t *lconn)
|
|||
conn->fc_stats.in.packets, conn->fc_stats.in.undec_packets,
|
||||
conn->fc_stats.in.dup_packets, conn->fc_stats.in.err_packets,
|
||||
conn->fc_stats.out.packets,
|
||||
conn->fc_stats.out.stream_data_sz / conn->fc_stats.out.packets);
|
||||
conn->fc_stats.out.stream_data_sz /
|
||||
(conn->fc_stats.out.packets ? conn->fc_stats.out.packets : 1));
|
||||
LSQ_NOTICE("ACKs: in: %lu; processed: %lu; merged: %lu",
|
||||
conn->fc_stats.in.n_acks, conn->fc_stats.in.n_acks_proc,
|
||||
conn->fc_stats.in.n_acks_merged);
|
||||
|
|
|
@ -3103,7 +3103,8 @@ ietf_full_conn_ci_destroy (struct lsquic_conn *lconn)
|
|||
conn->ifc_stats.in.packets, conn->ifc_stats.in.undec_packets,
|
||||
conn->ifc_stats.in.dup_packets, conn->ifc_stats.in.err_packets,
|
||||
conn->ifc_stats.out.packets,
|
||||
conn->ifc_stats.out.stream_data_sz / conn->ifc_stats.out.packets);
|
||||
conn->ifc_stats.out.stream_data_sz /
|
||||
(conn->ifc_stats.out.packets ? conn->ifc_stats.out.packets : 1));
|
||||
LSQ_NOTICE("ACKs: in: %lu; processed: %lu; merged: %lu",
|
||||
conn->ifc_stats.in.n_acks, conn->ifc_stats.in.n_acks_proc,
|
||||
conn->ifc_stats.in.n_acks_merged);
|
||||
|
@ -4471,6 +4472,24 @@ generate_ack_frequency_frame (struct ietf_full_conn *conn, lsquic_time_t unused)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
maybe_pad_packet (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
unsigned short avail;
|
||||
|
||||
avail = lsquic_packet_out_avail(packet_out);
|
||||
if (avail)
|
||||
{
|
||||
memset(packet_out->po_data + packet_out->po_data_sz, 0, avail);
|
||||
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, avail);
|
||||
packet_out->po_frame_types |= QUIC_FTBIT_PADDING;
|
||||
LSQ_DEBUG("added %hu-byte PADDING frame to packet %"PRIu64, avail,
|
||||
packet_out->po_packno);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
generate_path_chal_frame (struct ietf_full_conn *conn, lsquic_time_t now,
|
||||
unsigned path_id)
|
||||
|
@ -4530,6 +4549,7 @@ generate_path_chal_frame (struct ietf_full_conn *conn, lsquic_time_t now,
|
|||
packet_out->po_frame_types |= QUIC_FTBIT_PATH_CHALLENGE;
|
||||
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w);
|
||||
packet_out->po_regen_sz += w;
|
||||
maybe_pad_packet(conn, packet_out);
|
||||
conn->ifc_send_flags &= ~(SF_SEND_PATH_CHAL << path_id);
|
||||
lsquic_alarmset_set(&conn->ifc_alset, AL_PATH_CHAL + path_id,
|
||||
now + (INITIAL_CHAL_TIMEOUT << (copath->cop_n_chals - 1)));
|
||||
|
@ -4600,6 +4620,7 @@ generate_path_resp_frame (struct ietf_full_conn *conn, lsquic_time_t now,
|
|||
}
|
||||
packet_out->po_frame_types |= QUIC_FTBIT_PATH_RESPONSE;
|
||||
lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, w);
|
||||
maybe_pad_packet(conn, packet_out);
|
||||
packet_out->po_regen_sz += w;
|
||||
conn->ifc_send_flags &= ~(SF_SEND_PATH_RESP << path_id);
|
||||
}
|
||||
|
@ -5699,6 +5720,34 @@ process_ping_frame (struct ietf_full_conn *conn,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
is_benign_transport_error_code (uint64_t error_code)
|
||||
{
|
||||
switch (error_code)
|
||||
{
|
||||
case TEC_NO_ERROR:
|
||||
case TEC_INTERNAL_ERROR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
is_benign_application_error_code (uint64_t error_code)
|
||||
{
|
||||
switch (error_code)
|
||||
{
|
||||
case HEC_NO_ERROR:
|
||||
case HEC_INTERNAL_ERROR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
process_connection_close_frame (struct ietf_full_conn *conn,
|
||||
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
|
||||
|
@ -5709,6 +5758,7 @@ process_connection_close_frame (struct ietf_full_conn *conn,
|
|||
uint16_t reason_len;
|
||||
uint8_t reason_off;
|
||||
int parsed_len, app_error;
|
||||
const char *ua;
|
||||
|
||||
parsed_len = conn->ifc_conn.cn_pf->pf_parse_connect_close_frame(p, len,
|
||||
&app_error, &error_code, &reason_len, &reason_off);
|
||||
|
@ -5716,7 +5766,25 @@ process_connection_close_frame (struct ietf_full_conn *conn,
|
|||
return 0;
|
||||
EV_LOG_CONNECTION_CLOSE_FRAME_IN(LSQUIC_LOG_CONN_ID, error_code,
|
||||
(int) reason_len, (const char *) p + reason_off);
|
||||
LSQ_INFO("Received CONNECTION_CLOSE frame (%s-level code: %"PRIu64"; "
|
||||
if (LSQ_LOG_ENABLED(LSQ_LOG_NOTICE)
|
||||
&& !( (!app_error && is_benign_transport_error_code(error_code))
|
||||
||( app_error && is_benign_application_error_code(error_code))))
|
||||
{
|
||||
if (conn->ifc_flags & IFC_HTTP)
|
||||
{
|
||||
ua = lsquic_qdh_get_ua(&conn->ifc_qdh);
|
||||
if (!ua)
|
||||
ua = "unknown peer";
|
||||
}
|
||||
else
|
||||
ua = "non-HTTP/3 peer";
|
||||
LSQ_NOTICE("Received CONNECTION_CLOSE from <%s> with %s-level error "
|
||||
"code %"PRIu64", reason: `%.*s'", ua,
|
||||
app_error ? "application" : "transport", error_code,
|
||||
(int) reason_len, (const char *) p + reason_off);
|
||||
}
|
||||
else
|
||||
LSQ_INFO("Received CONNECTION_CLOSE frame (%s-level code: %"PRIu64"; "
|
||||
"reason: %.*s)", app_error ? "application" : "transport",
|
||||
error_code, (int) reason_len, (const char *) p + reason_off);
|
||||
conn->ifc_flags |= IFC_RECV_CLOSE;
|
||||
|
@ -9126,16 +9194,14 @@ hcsi_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
|
|||
callbacks = &hcsi_callbacks_server_28;
|
||||
break;
|
||||
case (0 << 8) | LSQVER_ID29:
|
||||
case (0 << 8) | LSQVER_ID30:
|
||||
case (0 << 8) | LSQVER_ID31:
|
||||
case (0 << 8) | LSQVER_ID32:
|
||||
callbacks = &hcsi_callbacks_client_29;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
/* fallthru */
|
||||
case (1 << 8) | LSQVER_ID29:
|
||||
case (1 << 8) | LSQVER_ID30:
|
||||
case (1 << 8) | LSQVER_ID31:
|
||||
case (1 << 8) | LSQVER_ID32:
|
||||
callbacks = &hcsi_callbacks_server_29;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -887,7 +887,8 @@ allocate_packet_out (struct mini_conn *mc, const unsigned char *nonce)
|
|||
return NULL;
|
||||
}
|
||||
packet_out = lsquic_packet_out_new(&mc->mc_enpub->enp_mm, NULL, 1,
|
||||
&mc->mc_conn, GQUIC_PACKNO_LEN_1, NULL, nonce, &mc->mc_path);
|
||||
&mc->mc_conn, GQUIC_PACKNO_LEN_1, NULL, nonce, &mc->mc_path,
|
||||
HETY_NOT_SET);
|
||||
if (!packet_out)
|
||||
{
|
||||
LSQ_WARN("could not allocate packet: %s", strerror(errno));
|
||||
|
|
|
@ -121,7 +121,8 @@ imico_get_packet_out (struct ietf_mini_conn *conn,
|
|||
}
|
||||
|
||||
packet_out = lsquic_packet_out_new(&conn->imc_enpub->enp_mm, NULL, 1,
|
||||
&conn->imc_conn, IQUIC_PACKNO_LEN_1, NULL, NULL, &conn->imc_path);
|
||||
&conn->imc_conn, IQUIC_PACKNO_LEN_1, NULL, NULL, &conn->imc_path,
|
||||
header_type);
|
||||
if (!packet_out)
|
||||
{
|
||||
LSQ_WARN("could not allocate packet: %s", strerror(errno));
|
||||
|
@ -696,6 +697,18 @@ imico_can_send (const struct ietf_mini_conn *conn, size_t size)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
imico_zero_pad (struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
size_t pad_size;
|
||||
|
||||
pad_size = lsquic_packet_out_avail(packet_out);
|
||||
memset(packet_out->po_data + packet_out->po_data_sz, 0, pad_size);
|
||||
packet_out->po_data_sz += pad_size;
|
||||
packet_out->po_frame_types |= QUIC_FTBIT_PADDING;
|
||||
}
|
||||
|
||||
|
||||
static struct lsquic_packet_out *
|
||||
ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
||||
const struct to_coal *to_coal)
|
||||
|
@ -708,6 +721,16 @@ ietf_mini_conn_ci_next_packet_to_send (struct lsquic_conn *lconn,
|
|||
{
|
||||
if (packet_out->po_flags & PO_SENT)
|
||||
continue;
|
||||
/* [draft-ietf-quic-transport-32] Section 14.1:
|
||||
" a server MUST expand the payload of all UDP datagrams carrying
|
||||
" ack-eliciting Initial packets to at least the smallest allowed
|
||||
" maximum datagram size of 1200 bytes.
|
||||
*/
|
||||
if (packet_out->po_header_type == HETY_INITIAL
|
||||
&& !(packet_out->po_frame_types & (1 << QUIC_FRAME_PADDING))
|
||||
&& (packet_out->po_frame_types & IQUIC_FRAME_ACKABLE_MASK)
|
||||
&& lsquic_packet_out_avail(packet_out) > 0)
|
||||
imico_zero_pad(packet_out);
|
||||
packet_size = lsquic_packet_out_total_sz(lconn, packet_out);
|
||||
if (!(to_coal
|
||||
&& (packet_size + to_coal->prev_sz_sum
|
||||
|
|
|
@ -204,7 +204,7 @@ lsquic_packet_out_t *
|
|||
lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
|
||||
const struct lsquic_conn *lconn, enum packno_bits bits,
|
||||
const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce,
|
||||
const struct network_path *path)
|
||||
const struct network_path *path, enum header_type header_type)
|
||||
{
|
||||
lsquic_packet_out_t *packet_out;
|
||||
enum packet_out_flags flags;
|
||||
|
@ -222,7 +222,7 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
|
|||
flags |= PO_LONGHEAD;
|
||||
|
||||
header_size = lconn->cn_pf->pf_packout_max_header_size(lconn, flags,
|
||||
path->np_dcid.len);
|
||||
path->np_dcid.len, header_type);
|
||||
tag_len = lconn->cn_esf_c->esf_tag_len;
|
||||
max_size = path->np_pack_size;
|
||||
if (header_size + tag_len >= max_size)
|
||||
|
|
|
@ -229,8 +229,9 @@ typedef struct lsquic_packet_out
|
|||
(p)->po_flags |= ((b) & 1) << POSPIN_SHIFT; \
|
||||
} while (0)
|
||||
|
||||
#define lsquic_po_header_length(lconn, po_flags, dcid_len) ( \
|
||||
lconn->cn_pf->pf_packout_max_header_size(lconn, po_flags, dcid_len))
|
||||
#define lsquic_po_header_length(lconn, po_flags, dcid_len, header_type) ( \
|
||||
lconn->cn_pf->pf_packout_max_header_size(lconn, po_flags, dcid_len, \
|
||||
header_type)) \
|
||||
|
||||
#define lsquic_packet_out_total_sz(lconn, p) (\
|
||||
(lconn)->cn_pf->pf_packout_size(lconn, p))
|
||||
|
@ -308,7 +309,7 @@ lsquic_packet_out_t *
|
|||
lsquic_packet_out_new (struct lsquic_mm *, struct malo *, int use_cid,
|
||||
const struct lsquic_conn *, enum packno_bits,
|
||||
const lsquic_ver_tag_t *, const unsigned char *nonce,
|
||||
const struct network_path *);
|
||||
const struct network_path *, enum header_type);
|
||||
|
||||
void
|
||||
lsquic_packet_out_destroy (lsquic_packet_out_t *,
|
||||
|
|
|
@ -222,7 +222,7 @@ struct parse_funcs
|
|||
*/
|
||||
size_t
|
||||
(*pf_packout_max_header_size) (const struct lsquic_conn *,
|
||||
enum packet_out_flags, size_t dcid_len);
|
||||
enum packet_out_flags, size_t dcid_len, enum header_type);
|
||||
|
||||
enum packno_bits
|
||||
(*pf_calc_packno_bits) (lsquic_packno_t packno,
|
||||
|
@ -381,7 +381,7 @@ lsquic_gquic_packout_size (const struct lsquic_conn *,
|
|||
|
||||
size_t
|
||||
lsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
|
||||
enum packet_out_flags flags, size_t unused);
|
||||
enum packet_out_flags flags, size_t unused, enum header_type);
|
||||
|
||||
size_t
|
||||
lsquic_gquic_po_header_sz (enum packet_out_flags flags);
|
||||
|
|
|
@ -215,7 +215,8 @@ gquic_Q046_packout_header_size_short (const struct lsquic_conn *lconn,
|
|||
|
||||
static size_t
|
||||
gquic_Q046_packout_header_size (const struct lsquic_conn *lconn,
|
||||
enum packet_out_flags flags, size_t dcid_len_unused)
|
||||
enum packet_out_flags flags, size_t dcid_len_unused,
|
||||
enum header_type unused)
|
||||
{
|
||||
if (0 == (flags & PO_LONGHEAD))
|
||||
return gquic_Q046_packout_header_size_short(lconn, flags);
|
||||
|
|
|
@ -459,7 +459,8 @@ gquic_Q050_packout_header_size_short (const struct lsquic_conn *lconn,
|
|||
|
||||
static size_t
|
||||
gquic_Q050_packout_max_header_size (const struct lsquic_conn *lconn,
|
||||
enum packet_out_flags flags, size_t dcid_len_unused)
|
||||
enum packet_out_flags flags, size_t dcid_len_unused,
|
||||
enum header_type unused)
|
||||
{
|
||||
if (lconn->cn_flags & LSCONN_SERVER)
|
||||
{
|
||||
|
|
|
@ -220,37 +220,7 @@ lsquic_cid_from_packet (const unsigned char *buf, size_t bufsz,
|
|||
/* See [draft-ietf-quic-transport-28], Section 12.4 (Table 3) */
|
||||
const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
|
||||
{
|
||||
[LSQVER_ID31] = {
|
||||
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
||||
| QUIC_FTBIT_STREAMS_BLOCKED
|
||||
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
||||
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
|
||||
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
|
||||
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
|
||||
| QUIC_FTBIT_BLOCKED
|
||||
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
|
||||
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
|
||||
| QUIC_FTBIT_STREAMS_BLOCKED
|
||||
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
|
||||
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
|
||||
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
|
||||
| QUIC_FTBIT_TIMESTAMP
|
||||
| QUIC_FTBIT_DATAGRAM
|
||||
,
|
||||
},
|
||||
[LSQVER_ID30] = {
|
||||
[LSQVER_ID32] = {
|
||||
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
|
||||
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
|
||||
|
|
|
@ -574,7 +574,8 @@ lsquic_gquic_packout_size (const struct lsquic_conn *conn,
|
|||
|
||||
size_t
|
||||
lsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
|
||||
enum packet_out_flags flags, size_t dcid_len)
|
||||
enum packet_out_flags flags, size_t dcid_len,
|
||||
enum header_type unused)
|
||||
{
|
||||
return lsquic_gquic_po_header_sz(flags);
|
||||
}
|
||||
|
|
|
@ -122,8 +122,7 @@ ietf_v1_packout_header_size_long_by_packet (const struct lsquic_conn *lconn,
|
|||
|
||||
|
||||
static size_t
|
||||
ietf_v1_packout_header_size_short (const struct lsquic_conn *lconn,
|
||||
enum packet_out_flags flags, size_t dcid_len)
|
||||
ietf_v1_packout_header_size_short (enum packet_out_flags flags, size_t dcid_len)
|
||||
{
|
||||
enum packno_bits bits;
|
||||
size_t sz;
|
||||
|
@ -140,19 +139,13 @@ ietf_v1_packout_header_size_short (const struct lsquic_conn *lconn,
|
|||
|
||||
static size_t
|
||||
ietf_v1_packout_max_header_size (const struct lsquic_conn *lconn,
|
||||
enum packet_out_flags flags, size_t dcid_len)
|
||||
enum packet_out_flags flags, size_t dcid_len, enum header_type header_type)
|
||||
{
|
||||
if (lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
return ietf_v1_packout_header_size_short(lconn, flags, dcid_len);
|
||||
else if (lconn->cn_flags & LSCONN_SERVER)
|
||||
/* Server does not set the token in its Initial packet header: set
|
||||
* the packet type to something else in order not to overestimate
|
||||
* header size.
|
||||
*/
|
||||
return ietf_v1_packout_header_size_long_by_flags(lconn, HETY_HANDSHAKE,
|
||||
flags, dcid_len);
|
||||
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& header_type == HETY_NOT_SET)
|
||||
return ietf_v1_packout_header_size_short(flags, dcid_len);
|
||||
else
|
||||
return ietf_v1_packout_header_size_long_by_flags(lconn, HETY_INITIAL,
|
||||
return ietf_v1_packout_header_size_long_by_flags(lconn, header_type,
|
||||
flags, dcid_len);
|
||||
}
|
||||
|
||||
|
@ -309,7 +302,7 @@ ietf_v1_packout_size (const struct lsquic_conn *lconn,
|
|||
|
||||
if ((lconn->cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& packet_out->po_header_type == HETY_NOT_SET)
|
||||
sz = ietf_v1_packout_header_size_short(lconn, packet_out->po_flags,
|
||||
sz = ietf_v1_packout_header_size_short(packet_out->po_flags,
|
||||
packet_out->po_path->np_dcid.len);
|
||||
else
|
||||
sz = ietf_v1_packout_header_size_long_by_packet(lconn, packet_out);
|
||||
|
|
|
@ -165,6 +165,8 @@ lsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn,
|
|||
if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL)
|
||||
dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL;
|
||||
|
||||
if (conn->cn_flags & LSCONN_SERVER)
|
||||
qdh->qdh_flags |= QDH_SERVER;
|
||||
if (enpub->enp_settings.es_qpack_experiment)
|
||||
{
|
||||
qdh->qdh_exp_rec = lsquic_qpack_exp_new();
|
||||
|
@ -176,6 +178,8 @@ lsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn,
|
|||
qdh->qdh_exp_rec->qer_used_max_blocked = max_risked_streams;
|
||||
}
|
||||
}
|
||||
if (!qdh->qdh_exp_rec && LSQ_LOG_ENABLED_EXT(LSQ_LOG_NOTICE, LSQLM_CONN))
|
||||
qdh->qdh_flags |= QDH_SAVE_UA;
|
||||
|
||||
qdh->qdh_conn = conn;
|
||||
lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL);
|
||||
|
@ -226,6 +230,11 @@ lsquic_qdh_cleanup (struct qpack_dec_hdl *qdh)
|
|||
LSQ_DEBUG("cleanup");
|
||||
if (qdh->qdh_exp_rec)
|
||||
qdh_log_and_clean_exp_rec(qdh);
|
||||
if (qdh->qdh_ua)
|
||||
{
|
||||
free(qdh->qdh_ua);
|
||||
qdh->qdh_ua = NULL;
|
||||
}
|
||||
lsqpack_dec_cleanup(&qdh->qdh_decoder);
|
||||
lsquic_frab_list_cleanup(&qdh->qdh_fral);
|
||||
qdh->qdh_flags &= ~QDH_INITIALIZED;
|
||||
|
@ -531,17 +540,16 @@ qdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space)
|
|||
|
||||
static void
|
||||
qdh_maybe_set_user_agent (struct qpack_dec_hdl *qdh,
|
||||
const struct lsxpack_header *xhdr)
|
||||
const struct lsxpack_header *xhdr, char **ua)
|
||||
{
|
||||
/* Flipped: we are the *decoder* */
|
||||
const char *const name = qdh->qdh_exp_rec->qer_flags & QER_SERVER ?
|
||||
const char *const name = qdh->qdh_flags & QDH_SERVER ?
|
||||
"user-agent" : "server";
|
||||
const size_t len = qdh->qdh_exp_rec->qer_flags & QER_SERVER ? 10 : 6;
|
||||
const size_t len = qdh->qdh_flags & QDH_SERVER ? 10 : 6;
|
||||
|
||||
if (len == xhdr->name_len
|
||||
&& 0 == memcmp(name, lsxpack_header_get_name(xhdr), len))
|
||||
qdh->qdh_exp_rec->qer_user_agent
|
||||
= strndup(lsxpack_header_get_value(xhdr), xhdr->val_len);
|
||||
*ua = strndup(lsxpack_header_get_value(xhdr), xhdr->val_len);
|
||||
}
|
||||
|
||||
|
||||
|
@ -572,7 +580,9 @@ qdh_process_header (void *stream_p, struct lsxpack_header *xhdr)
|
|||
sizeof(*stream->conn_pub->mm->acki));
|
||||
}
|
||||
else if (qdh->qdh_exp_rec && !qdh->qdh_exp_rec->qer_user_agent)
|
||||
qdh_maybe_set_user_agent(qdh, xhdr);
|
||||
qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_exp_rec->qer_user_agent);
|
||||
else if ((qdh->qdh_flags & QDH_SAVE_UA) && !qdh->qdh_ua)
|
||||
qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_ua);
|
||||
|
||||
return qdh->qdh_enpub->enp_hsi_if->hsi_process_header(u->ctx.hset, xhdr);
|
||||
}
|
||||
|
@ -844,3 +854,15 @@ lsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *),
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
lsquic_qdh_get_ua (const struct qpack_dec_hdl *qdh)
|
||||
{
|
||||
if (qdh->qdh_ua)
|
||||
return qdh->qdh_ua;
|
||||
else if (qdh->qdh_exp_rec && qdh->qdh_exp_rec->qer_user_agent)
|
||||
return qdh->qdh_exp_rec->qer_user_agent;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ struct qpack_dec_hdl
|
|||
enum {
|
||||
QDH_INITIALIZED = 1 << 0,
|
||||
QDH_PUSH_PROMISE = 1 << 1,
|
||||
QDH_SAVE_UA = 1 << 2,
|
||||
QDH_SERVER = 1 << 3,
|
||||
} qdh_flags;
|
||||
struct lsqpack_dec qdh_decoder;
|
||||
struct lsquic_stream *qdh_enc_sm_in;
|
||||
|
@ -35,6 +37,7 @@ struct qpack_dec_hdl
|
|||
void (*qdh_on_dec_sent_func)(void *);
|
||||
void *qdh_on_dec_sent_ctx;
|
||||
struct qpack_exp_record *qdh_exp_rec;
|
||||
char *qdh_ua;
|
||||
};
|
||||
|
||||
int
|
||||
|
@ -74,6 +77,9 @@ lsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *, lsquic_stream_id_t);
|
|||
int
|
||||
lsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *, void (*)(void *), void *);
|
||||
|
||||
const char *
|
||||
lsquic_qdh_get_ua (const struct qpack_dec_hdl *);
|
||||
|
||||
extern const struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if;
|
||||
extern const struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if;
|
||||
|
||||
|
|
|
@ -2043,12 +2043,18 @@ send_ctl_allocate_packet (struct lsquic_send_ctl *ctl, enum packno_bits bits,
|
|||
unsigned need_at_least, enum packnum_space pns,
|
||||
const struct network_path *path)
|
||||
{
|
||||
static const enum header_type pns2hety[] =
|
||||
{
|
||||
[PNS_INIT] = HETY_INITIAL,
|
||||
[PNS_HSK] = HETY_HANDSHAKE,
|
||||
[PNS_APP] = HETY_NOT_SET,
|
||||
};
|
||||
lsquic_packet_out_t *packet_out;
|
||||
|
||||
packet_out = lsquic_packet_out_new(&ctl->sc_enpub->enp_mm,
|
||||
ctl->sc_conn_pub->packet_out_malo,
|
||||
!(ctl->sc_flags & SC_TCID0), ctl->sc_conn_pub->lconn, bits,
|
||||
ctl->sc_ver_neg->vn_tag, NULL, path);
|
||||
ctl->sc_ver_neg->vn_tag, NULL, path, pns2hety[pns]);
|
||||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -2483,7 +2483,7 @@ lsquic_stream_flush_threshold (const struct lsquic_stream *stream,
|
|||
flags |= PO_LONGHEAD;
|
||||
|
||||
packet_header_sz = lsquic_po_header_length(stream->conn_pub->lconn, flags,
|
||||
stream->conn_pub->path->np_dcid.len);
|
||||
stream->conn_pub->path->np_dcid.len, HETY_NOT_SET);
|
||||
stream_header_sz = stream->sm_frame_header_sz(stream, data_sz);
|
||||
tag_len = stream->conn_pub->lconn->cn_esf_c->esf_tag_len;
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
|
|||
[LSQVER_ID27] = { 0xFF, 0, 0, 27, },
|
||||
[LSQVER_ID28] = { 0xFF, 0, 0, 28, },
|
||||
[LSQVER_ID29] = { 0xFF, 0, 0, 29, },
|
||||
[LSQVER_ID30] = { 0xFF, 0, 0, 30, },
|
||||
[LSQVER_ID31] = { 0xFF, 0, 0, 31, },
|
||||
[LSQVER_ID32] = { 0xFF, 0, 0, 32, },
|
||||
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
|
||||
};
|
||||
|
||||
|
@ -62,8 +61,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
|
|||
[LSQVER_ID27] = "FF00001B",
|
||||
[LSQVER_ID28] = "FF00001C",
|
||||
[LSQVER_ID29] = "FF00001D",
|
||||
[LSQVER_ID30] = "FF00001E",
|
||||
[LSQVER_ID31] = "FF00001F",
|
||||
[LSQVER_ID32] = "FF000020",
|
||||
[LSQVER_VERNEG] = "FAFAFAFA",
|
||||
};
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ new_packet (struct test_ctx *ctx)
|
|||
*/
|
||||
|
||||
packet_out = lsquic_packet_out_new(&ctx->enpub.enp_mm, ctx->enpub.enp_mm.malo.packet_out, 1,
|
||||
&ctx->lconn, PACKNO_BITS_0, 0, NULL, &ctx->path);
|
||||
&ctx->lconn, PACKNO_BITS_0, 0, NULL, &ctx->path, HETY_NOT_SET);
|
||||
if (packet_out)
|
||||
packet_out->po_packno = packno++;
|
||||
|
||||
|
|
Loading…
Reference in a new issue