Release 1.20.0

[FEATURE] Add support for Q046.
This commit is contained in:
Dmitri Tikhonov 2019-04-01 11:41:55 -04:00
parent 428530e38e
commit c7d81ce135
29 changed files with 576 additions and 185 deletions

View file

@ -1,3 +1,7 @@
2019-04-01
- 1.20.0
- [FEATURE] Add support for Q046.
2019-03-19
- 1.19.6
- [BUGFIX] Ensure that Largest Observed does not decrease in ACKs we

View file

@ -24,8 +24,8 @@ extern "C" {
#endif
#define LSQUIC_MAJOR_VERSION 1
#define LSQUIC_MINOR_VERSION 19
#define LSQUIC_PATCH_VERSION 6
#define LSQUIC_MINOR_VERSION 20
#define LSQUIC_PATCH_VERSION 0
/**
* Engine flags:
@ -103,6 +103,11 @@ enum lsquic_version
*/
LSQVER_044,
/**
* Q046. Use IETF Draft-17 compatible packet headers.
*/
LSQVER_046,
#if LSQUIC_USE_Q098
/**
* Q098. This is a made-up, experimental version used to test version
@ -119,7 +124,7 @@ enum lsquic_version
};
/**
* We currently support versions 35, 39, 43, and 44.
* We currently support versions 35, 39, 43, 44, and 46.
* @see lsquic_version
*/
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
@ -135,7 +140,7 @@ enum lsquic_version
/**
* List of versions in which the server never includes CID in short packets.
*/
#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_044)
#define LSQUIC_FORCED_TCID0_VERSIONS ((1 << LSQVER_044) | (1 << LSQVER_046))
enum lsquic_hsk_status
{
@ -371,8 +376,8 @@ struct lsquic_engine_settings {
* (source-addr, dest-addr) tuple, thereby making it necessary to create
* a socket for each connection.
*
* This option has no effect in Q044, as the server never includes CIDs
* in the short packets.
* This option has no effect in Q044 or Q046, as the server never includes
* CIDs in the short packets.
*
* The default is @ref LSQUIC_DF_SUPPORT_TCID0.
*/

View file

@ -53,6 +53,7 @@ SET(lsquic_STAT_SRCS
lsquic_min_heap.c
../lshpack/lshpack.c
lsquic_parse_Q044.c
lsquic_parse_Q046.c
lsquic_http1x_if.c
)

View file

@ -1667,7 +1667,7 @@ process_stop_waiting_frame (struct full_conn *conn, lsquic_packet_in_t *packet_i
const unsigned char *p, size_t len)
{
lsquic_packno_t least, cutoff;
enum lsquic_packno_bits bits;
enum packno_bits bits;
int parsed_len;
bits = lsquic_packet_in_packno_bits(packet_in);
@ -1948,12 +1948,14 @@ static void
reconstruct_packet_number (struct full_conn *conn, lsquic_packet_in_t *packet_in)
{
lsquic_packno_t cur_packno, max_packno;
enum lsquic_packno_bits bits;
enum packno_bits bits;
unsigned packet_len;
cur_packno = packet_in->pi_packno;
max_packno = lsquic_rechist_largest_packno(&conn->fc_rechist);
bits = lsquic_packet_in_packno_bits(packet_in);
packet_in->pi_packno = restore_packno(cur_packno, bits, max_packno);
packet_len = conn->fc_conn.cn_pf->pf_packno_bits2len(bits);
packet_in->pi_packno = restore_packno(cur_packno, packet_len, max_packno);
LSQ_DEBUG("reconstructed (bits: %u, packno: %"PRIu64", max: %"PRIu64") "
"to %"PRIu64"", bits, cur_packno, max_packno, packet_in->pi_packno);
}
@ -2377,14 +2379,16 @@ generate_stop_waiting_frame (struct full_conn *conn)
lsquic_packet_out_t *packet_out;
/* Get packet that has room for the minimum size STOP_WAITING frame: */
packet_out = get_writeable_packet(conn, 1 + packno_bits2len(PACKNO_LEN_1));
packnum_len = conn->fc_conn.cn_pf->pf_packno_bits2len(GQUIC_PACKNO_LEN_1);
packet_out = get_writeable_packet(conn, 1 + packnum_len);
if (!packet_out)
return;
/* Now calculate number of bytes we really need. If there is not enough
* room in the current packet, get a new one.
*/
packnum_len = packno_bits2len(lsquic_packet_out_packno_bits(packet_out));
packnum_len = conn->fc_conn.cn_pf->pf_packno_bits2len(
lsquic_packet_out_packno_bits(packet_out));
if ((unsigned) lsquic_packet_out_avail(packet_out) < 1 + packnum_len)
{
packet_out = get_writeable_packet(conn, 1 + packnum_len);

View file

@ -979,7 +979,8 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
n_opts = 0;
/* CHLO is not regenerated during version negotiation. Hence we always
* include this option to cover the case when Q044 gets negotiated down.
* include this option to cover the case when Q044 or Q046 gets negotiated
* down.
*/
if (settings->es_support_nstp)
opts[ n_opts++ ] = QTAG_NSTP;

View file

@ -43,7 +43,7 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz,
}
enum lsquic_packno_bits
enum packno_bits
calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
uint64_t n_in_flight)
{
@ -65,14 +65,13 @@ calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
lsquic_packno_t
restore_packno (lsquic_packno_t cur_packno,
enum lsquic_packno_bits cur_packno_bits,
unsigned len,
lsquic_packno_t max_packno)
{
lsquic_packno_t candidates[3], epoch_delta;
int64_t diffs[3];
unsigned min, len;
unsigned min;
len = packno_bits2len(cur_packno_bits);
epoch_delta = 1ULL << (len << 3);
candidates[1] = (max_packno & ~(epoch_delta - 1)) + cur_packno;
candidates[0] = candidates[1] - epoch_delta;

View file

@ -157,13 +157,36 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit);
#define QUIC_GOAWAY_FRAME_SZ 11 /* Type (1) + Error code (4) + Stream ID (4) +
Reason phrase length (2) */
/* Bitmask to be used as bits 4 and 5 (0x30) in common header's flag field: */
enum lsquic_packno_bits
/* This value represents a different number of bytes used to encode the packet
* length based on whether GQUIC or IQUIC is used.
*/
enum packno_bits
{
PACKNO_LEN_1 = 0,
PACKNO_LEN_2 = 1,
PACKNO_LEN_4 = 2,
PACKNO_LEN_6 = 3,
PACKNO_BITS_0 = 0,
PACKNO_BITS_1 = 1,
PACKNO_BITS_2 = 2,
PACKNO_BITS_3 = 3,
};
/* GQUIC maps 0, 1, 2, 3 -> 1, 2, 4, 6 */
enum
{
GQUIC_PACKNO_LEN_1 = PACKNO_BITS_0,
GQUIC_PACKNO_LEN_2 = PACKNO_BITS_1,
GQUIC_PACKNO_LEN_4 = PACKNO_BITS_2,
GQUIC_PACKNO_LEN_6 = PACKNO_BITS_3,
};
/* IQUIC maps 0, 1, 2, 3 -> 1, 2, 3, 4 (as of ID-17) */
enum
{
IQUIC_PACKNO_LEN_1 = PACKNO_BITS_0,
IQUIC_PACKNO_LEN_2 = PACKNO_BITS_1,
IQUIC_PACKNO_LEN_3 = PACKNO_BITS_2,
IQUIC_PACKNO_LEN_4 = PACKNO_BITS_3,
};
@ -179,15 +202,15 @@ enum header_type
extern const char *const lsquic_hety2str[];
enum lsquic_packno_bits
enum packno_bits
calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
uint64_t n_in_flight);
#define packno_bits2len(b) (((b) << 1) + !(b))
#define gquic_packno_bits2len(b) (((b) << 1) + !(b))
lsquic_packno_t
restore_packno (lsquic_packno_t cur_packno,
enum lsquic_packno_bits cur_packno_bits,
unsigned packet_len,
lsquic_packno_t max_packno);
#endif

View file

@ -61,7 +61,10 @@ typedef struct lsquic_packet_in
PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */
PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */
PI_GQUIC = (1 << 7),
} pi_flags:8;
#define PIBIT_BITS_SHIFT 8
PI_BITS_BIT_0 = (1 << 8),
PI_BITS_BIT_1 = (1 << 9),
} pi_flags:16;
enum header_type pi_header_type:8;
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
* packet data, which is NOT TO BE MODIFIED.
@ -81,10 +84,7 @@ typedef struct lsquic_packet_in
(p)->pi_header_type == HETY_VERNEG)
#define lsquic_packet_in_packno_bits(p) \
(((p)->pi_flags & PI_GQUIC) ? \
((lsquic_packet_in_public_flags(p) >> 4) & 3) : \
((p)->pi_header_type == HETY_NOT_SET ? \
((p)->pi_data[0] & 3) : PACKNO_LEN_4))
(((p)->pi_flags >> PIBIT_BITS_SHIFT) & 3)
#define lsquic_packet_in_upref(p) (++(p)->pi_refcnt)

View file

@ -183,7 +183,7 @@ lsquic_packet_out_add_stream (lsquic_packet_out_t *packet_out,
lsquic_packet_out_t *
lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
const struct lsquic_conn *lconn, enum lsquic_packno_bits bits,
const struct lsquic_conn *lconn, enum packno_bits bits,
const lsquic_ver_tag_t *ver_tag, const unsigned char *nonce)
{
lsquic_packet_out_t *packet_out;
@ -204,10 +204,10 @@ lsquic_packet_out_new (struct lsquic_mm *mm, struct malo *malo, int use_cid,
)
{
flags |= PO_LONGHEAD;
if (!((1 << lconn->cn_version) & LSQUIC_GQUIC_HEADER_VERSIONS))
if (lconn->cn_version == LSQVER_044)
{
flags &= ~(3 << POBIT_SHIFT);
flags |= PACKNO_LEN_4 << POBIT_SHIFT;
flags |= GQUIC_PACKNO_LEN_4 << POBIT_SHIFT;
}
}

View file

@ -203,7 +203,7 @@ posi_next (struct packet_out_srec_iter *posi);
lsquic_packet_out_t *
lsquic_packet_out_new (struct lsquic_mm *, struct malo *, int use_cid,
const struct lsquic_conn *, enum lsquic_packno_bits,
const struct lsquic_conn *, enum packno_bits,
const lsquic_ver_tag_t *, const unsigned char *nonce);
void

View file

@ -60,7 +60,7 @@ typedef size_t (*gsf_read_f) (void *stream, void *buf, size_t len, int *fin);
/* This structure contains functions that parse and generate packets and
* frames in version-specific manner. To begin with, there is difference
* between GQUIC's little-endian (Q038 and lower) and big-endian formats
* (Q039 and higher). Q044 uses different format for packet headers.
* (Q039 and higher). Q044 and higher uses different format for packet headers.
*/
struct parse_funcs
{
@ -96,14 +96,14 @@ struct parse_funcs
int *has_missing, lsquic_packno_t *largest_received);
int
(*pf_gen_stop_waiting_frame) (unsigned char *buf, size_t buf_len,
lsquic_packno_t cur_packno, enum lsquic_packno_bits,
lsquic_packno_t cur_packno, enum packno_bits,
lsquic_packno_t least_unacked_packno);
int
(*pf_parse_stop_waiting_frame) (const unsigned char *buf, size_t buf_len,
lsquic_packno_t cur_packno, enum lsquic_packno_bits,
lsquic_packno_t cur_packno, enum packno_bits,
lsquic_packno_t *least_unacked);
int
(*pf_skip_stop_waiting_frame) (size_t buf_len, enum lsquic_packno_bits);
(*pf_skip_stop_waiting_frame) (size_t buf_len, enum packno_bits);
int
(*pf_gen_window_update_frame) (unsigned char *buf, int buf_len,
uint32_t stream_id, uint64_t offset);
@ -160,19 +160,28 @@ struct parse_funcs
size_t
(*pf_packout_header_size) (const struct lsquic_conn *,
enum packet_out_flags);
enum packno_bits
(*pf_calc_packno_bits) (lsquic_packno_t packno,
lsquic_packno_t least_unacked, uint64_t n_in_flight);
unsigned
(*pf_packno_bits2len) (enum packno_bits);
};
extern const struct parse_funcs lsquic_parse_funcs_gquic_le;
/* Q039 and later are big-endian: */
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q039;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q044;
extern const struct parse_funcs lsquic_parse_funcs_gquic_Q046;
#define select_pf_by_ver(ver) ( \
((1 << (ver)) & (1 << LSQVER_035)) \
? &lsquic_parse_funcs_gquic_le \
: (ver) < LSQVER_044 \
? &lsquic_parse_funcs_gquic_Q039 \
: &lsquic_parse_funcs_gquic_Q044)
: (ver) < LSQVER_046 \
? &lsquic_parse_funcs_gquic_Q044 \
: &lsquic_parse_funcs_gquic_Q046)
int
lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *, size_t length,
@ -229,4 +238,11 @@ acki2str (const struct ack_info *acki, size_t *sz);
void
lsquic_turn_on_fin_Q035_thru_Q039 (unsigned char *);
enum packno_bits
lsquic_gquic_calc_packno_bits (lsquic_packno_t packno,
lsquic_packno_t least_unacked, uint64_t n_in_flight);
unsigned
lsquic_gquic_packno_bits2len (enum packno_bits);
#endif

View file

@ -38,11 +38,11 @@ gen_short_pkt_header (const struct lsquic_conn *lconn,
size_t bufsz)
{
unsigned packno_len, need;
enum lsquic_packno_bits bits;
enum packno_bits bits;
uint32_t packno;
bits = (packet_out->po_flags >> POBIT_SHIFT) & 0x3;
packno_len = packno_bits2len(bits);
packno_len = gquic_packno_bits2len(bits);
need = 1 + 8 /* CID */ + packno_len;
@ -138,13 +138,13 @@ static size_t
gquic_Q044_packout_header_size_short (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
enum lsquic_packno_bits bits;
enum packno_bits bits;
size_t sz;
bits = (flags >> POBIT_SHIFT) & 0x3;
sz = 1; /* Type */
sz += 8; /* CID */
sz += packno_bits2len(bits);
sz += gquic_packno_bits2len(bits);
return sz;
}
@ -210,4 +210,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q044 =
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = gquic_Q044_packout_size,
.pf_packout_header_size = gquic_Q044_packout_header_size,
.pf_calc_packno_bits = lsquic_gquic_calc_packno_bits,
.pf_packno_bits2len = lsquic_gquic_packno_bits2len,
};

View file

@ -0,0 +1,260 @@
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
/*
* lsquic_parse_Q046.c -- Parsing functions specific to GQUIC Q046
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include <sys/queue.h>
#ifndef WIN32
#include <sys/types.h>
#else
#include <vc_compat.h>
#endif
#include "lsquic_types.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_in.h"
#include "lsquic_packet_out.h"
#include "lsquic_parse.h"
#include "lsquic_parse_common.h"
#include "lsquic_version.h"
#include "lsquic.h"
#include "lsquic_parse_gquic_be.h"
#include "lsquic_byteswap.h"
#include "lsquic_conn.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PARSE
#include "lsquic_logger.h"
static unsigned
gquic_Q046_packno_bits2len (enum packno_bits bits)
{
return bits + 1;
}
#define iquic_packno_bits2len gquic_Q046_packno_bits2len
static enum packno_bits
gquic_Q046_calc_packno_bits (lsquic_packno_t packno,
lsquic_packno_t least_unacked, uint64_t n_in_flight)
{
uint64_t delta;
unsigned bits;
delta = packno - least_unacked;
if (n_in_flight > delta)
delta = n_in_flight;
delta *= 4;
bits = (delta >= (1ULL << 8))
+ (delta >= (1ULL << 16))
+ (delta >= (1ULL << 24))
;
return bits;
}
static unsigned
write_packno (unsigned char *p, lsquic_packno_t packno, enum packno_bits bits)
{
unsigned char *const begin = p;
switch (bits)
{
case IQUIC_PACKNO_LEN_4:
*p++ = packno >> 24;
case IQUIC_PACKNO_LEN_3:
*p++ = packno >> 16;
case IQUIC_PACKNO_LEN_2:
*p++ = packno >> 8;
default:
*p++ = packno;
}
return p - begin;
}
static int
gen_short_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
unsigned packno_len, need;
enum packno_bits bits;
bits = lsquic_packet_out_packno_bits(packet_out);
packno_len = iquic_packno_bits2len(bits);
need = 1 + 8 /* CID */ + packno_len;
if (need > bufsz)
return -1;
*buf++ = 0x40 | bits;
memcpy(buf, &lconn->cn_cid, 8);
buf += 8;
(void) write_packno(buf, packet_out->po_packno, bits);
return need;
}
static size_t
gquic_Q046_packout_header_size_long (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
return GQUIC_IETF_LONG_HEADER_SIZE;
}
/* [draft-ietf-quic-transport-17] Section-17.2 */
static const unsigned char header_type_to_bin[] = {
[HETY_INITIAL] = 0x0,
[HETY_0RTT] = 0x1,
[HETY_HANDSHAKE] = 0x2,
[HETY_RETRY] = 0x3,
};
static int
gen_long_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
enum packno_bits packno_bits;
lsquic_ver_tag_t ver_tag;
unsigned char *p;
size_t need;
need = gquic_Q046_packout_header_size_long(lconn, packet_out->po_flags);
if (need > bufsz)
{
errno = EINVAL;
return -1;
}
p = buf;
packno_bits = IQUIC_PACKNO_LEN_4;
*p++ = 0x80 | 0x40
| (header_type_to_bin[ packet_out->po_header_type ] << 4)
| packno_bits;
ver_tag = lsquic_ver2tag(lconn->cn_version);
memcpy(p, &ver_tag, sizeof(ver_tag));
p += sizeof(ver_tag);
*p++ = 0x50;
memcpy(p, &lconn->cn_cid, 8);
p += 8;
p += write_packno(p, packet_out->po_packno, packno_bits);
assert(need == (unsigned int)(p - buf));
return p - buf;
}
static int
gquic_Q046_gen_reg_pkt_header (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out, unsigned char *buf,
size_t bufsz)
{
if (0 == (packet_out->po_flags & PO_LONGHEAD))
return gen_short_pkt_header(lconn, packet_out, buf, bufsz);
else
return gen_long_pkt_header(lconn, packet_out, buf, bufsz);
}
static size_t
gquic_Q046_packout_header_size_short (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
enum packno_bits bits;
size_t sz;
bits = (flags >> POBIT_SHIFT) & 0x3;
sz = 1; /* Type */
sz += 8; /* CID */
sz += iquic_packno_bits2len(bits);
return sz;
}
static size_t
gquic_Q046_packout_header_size (const struct lsquic_conn *lconn,
enum packet_out_flags flags)
{
if (0 == (flags & PO_LONGHEAD))
return gquic_Q046_packout_header_size_short(lconn, flags);
else
return gquic_Q046_packout_header_size_long(lconn, flags);
}
static size_t
gquic_Q046_packout_size (const struct lsquic_conn *lconn,
const struct lsquic_packet_out *packet_out)
{
size_t sz;
if (0 == (packet_out->po_flags & PO_LONGHEAD))
sz = gquic_Q046_packout_header_size_short(lconn, packet_out->po_flags);
else
sz = gquic_Q046_packout_header_size_long(lconn, packet_out->po_flags);
sz += packet_out->po_data_sz;
sz += QUIC_PACKET_HASH_SZ;
return sz;
}
const struct parse_funcs lsquic_parse_funcs_gquic_Q046 =
{
.pf_gen_reg_pkt_header = gquic_Q046_gen_reg_pkt_header,
.pf_parse_packet_in_finish = gquic_be_parse_packet_in_finish,
.pf_gen_stream_frame = gquic_be_gen_stream_frame,
.pf_calc_stream_frame_header_sz = calc_stream_frame_header_sz_gquic,
.pf_parse_stream_frame = gquic_be_parse_stream_frame,
.pf_parse_ack_frame = gquic_be_parse_ack_frame,
.pf_gen_ack_frame = gquic_be_gen_ack_frame,
.pf_gen_stop_waiting_frame = gquic_be_gen_stop_waiting_frame,
.pf_parse_stop_waiting_frame = gquic_be_parse_stop_waiting_frame,
.pf_skip_stop_waiting_frame = gquic_be_skip_stop_waiting_frame,
.pf_gen_window_update_frame = gquic_be_gen_window_update_frame,
.pf_parse_window_update_frame = gquic_be_parse_window_update_frame,
.pf_gen_blocked_frame = gquic_be_gen_blocked_frame,
.pf_parse_blocked_frame = gquic_be_parse_blocked_frame,
.pf_gen_rst_frame = gquic_be_gen_rst_frame,
.pf_parse_rst_frame = gquic_be_parse_rst_frame,
.pf_gen_connect_close_frame = gquic_be_gen_connect_close_frame,
.pf_parse_connect_close_frame = gquic_be_parse_connect_close_frame,
.pf_gen_goaway_frame = gquic_be_gen_goaway_frame,
.pf_parse_goaway_frame = gquic_be_parse_goaway_frame,
.pf_gen_ping_frame = gquic_be_gen_ping_frame,
#ifndef NDEBUG
.pf_write_float_time16 = gquic_be_write_float_time16,
.pf_read_float_time16 = gquic_be_read_float_time16,
#endif
.pf_parse_frame_type = parse_frame_type_gquic_Q035_thru_Q039,
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = gquic_Q046_packout_size,
.pf_packout_header_size = gquic_Q046_packout_header_size,
.pf_calc_packno_bits = gquic_Q046_calc_packno_bits,
.pf_packno_bits2len = gquic_Q046_packno_bits2len,
};

View file

@ -17,10 +17,12 @@ lsquic_parse_packet_in_begin (lsquic_packet_in_t *packet_in, size_t length,
{
if (length > 0)
{
switch (packet_in->pi_data[0] & 0x88)
switch (packet_in->pi_data[0] & 0xC8)
{
case 0x88:
case 0x80:
case 0xC8:
case 0xC0:
return lsquic_iquic_parse_packet_in_long_begin(packet_in, length,
is_server, state);
case 0x08:

View file

@ -108,12 +108,12 @@ gquic_be_gen_reg_pkt_header (const struct lsquic_conn *lconn,
size_t bufsz)
{
unsigned packnum_len, header_len;
enum lsquic_packno_bits bits;
enum packno_bits bits;
lsquic_packno_t packno;
unsigned char *p;
bits = lsquic_packet_out_packno_bits(packet_out);
packnum_len = packno_bits2len(bits);
packnum_len = gquic_packno_bits2len(bits);
if (0 == (packet_out->po_flags & (PO_CONN_ID|PO_VERSION|PO_NONCE)))
{
@ -500,11 +500,11 @@ gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *
int
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 packno_bits bits,
lsquic_packno_t least_unacked_packno)
{
lsquic_packno_t delta;
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
{
@ -524,11 +524,11 @@ gquic_be_gen_stop_waiting_frame(unsigned char *buf, size_t buf_len,
int
gquic_be_parse_stop_waiting_frame (const unsigned char *buf, size_t buf_len,
lsquic_packno_t cur_packno, enum lsquic_packno_bits bits,
lsquic_packno_t cur_packno, enum packno_bits bits,
lsquic_packno_t *least_unacked)
{
lsquic_packno_t delta;
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
{
@ -542,9 +542,9 @@ gquic_be_parse_stop_waiting_frame (const unsigned char *buf, size_t buf_len,
int
gquic_be_skip_stop_waiting_frame (size_t buf_len, enum lsquic_packno_bits bits)
gquic_be_skip_stop_waiting_frame (size_t buf_len, enum packno_bits bits)
{
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
return 1 + packnum_len;
else
@ -976,4 +976,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_Q039 =
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = lsquic_gquic_packout_size,
.pf_packout_header_size = lsquic_gquic_packout_header_size,
.pf_calc_packno_bits = lsquic_gquic_calc_packno_bits,
.pf_packno_bits2len = lsquic_gquic_packno_bits2len,
};

View file

@ -57,16 +57,16 @@ gquic_be_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *
int
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 packno_bits bits,
lsquic_packno_t least_unacked_packno);
int
gquic_be_parse_stop_waiting_frame (const unsigned char *buf, size_t buf_len,
lsquic_packno_t cur_packno, enum lsquic_packno_bits bits,
lsquic_packno_t cur_packno, enum packno_bits bits,
lsquic_packno_t *least_unacked);
int
gquic_be_skip_stop_waiting_frame (size_t buf_len, enum lsquic_packno_bits bits);
gquic_be_skip_stop_waiting_frame (size_t buf_len, enum packno_bits bits);
int
gquic_be_gen_window_update_frame (unsigned char *buf, int buf_len, uint32_t stream_id,

View file

@ -132,6 +132,7 @@ lsquic_gquic_parse_packet_in_begin (struct lsquic_packet_in *packet_in,
packet_in->pi_refcnt = 0;
packet_in->pi_received = 0;
packet_in->pi_flags |= PI_GQUIC;
packet_in->pi_flags |= ((public_flags >> 4) & 3) << PIBIT_BITS_SHIFT;
return 0;
}
@ -475,7 +476,7 @@ lsquic_gquic_po_header_sz (enum packet_out_flags flags)
+ (!!(flags & PO_CONN_ID) << 3) /* Connection ID */
+ (!!(flags & PO_VERSION) << 2) /* Version */
+ (!!(flags & PO_NONCE) << 5) /* Nonce */
+ packno_bits2len((flags >> POBIT_SHIFT) & 0x3) /* Packet number */
+ gquic_packno_bits2len((flags >> POBIT_SHIFT) & 0x3) /* Packet number */
;
}
@ -499,3 +500,28 @@ lsquic_gquic_packout_header_size (const struct lsquic_conn *conn,
}
unsigned
lsquic_gquic_packno_bits2len (enum packno_bits bits)
{
return gquic_packno_bits2len(bits);
}
enum packno_bits
lsquic_gquic_calc_packno_bits (lsquic_packno_t packno,
lsquic_packno_t least_unacked, uint64_t n_in_flight)
{
uint64_t delta;
unsigned bits;
delta = packno - least_unacked;
if (n_in_flight > delta)
delta = n_in_flight;
delta *= 4;
bits = (delta > (1ULL << 8))
+ (delta > (1ULL << 16))
+ (delta > (1ULL << 32));
return bits;
}

View file

@ -127,10 +127,10 @@ gquic_le_gen_reg_pkt_header (const struct lsquic_conn *lconn,
{
unsigned packnum_len, header_len;
unsigned char *p;
enum lsquic_packno_bits bits;
enum packno_bits bits;
bits = lsquic_packet_out_packno_bits(packet_out);
packnum_len = packno_bits2len(bits);
packnum_len = gquic_packno_bits2len(bits);
header_len = 1
+ (!!(packet_out->po_flags & PO_CONN_ID) << 3)
@ -420,11 +420,11 @@ gquic_le_parse_ack_frame (const unsigned char *buf, size_t buf_len, ack_info_t *
static int
gquic_le_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 packno_bits bits,
lsquic_packno_t least_unacked_packno)
{
lsquic_packno_t delta;
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
{
@ -440,11 +440,11 @@ gquic_le_gen_stop_waiting_frame(unsigned char *buf, size_t buf_len,
static int
gquic_le_parse_stop_waiting_frame (const unsigned char *buf, size_t buf_len,
lsquic_packno_t cur_packno, enum lsquic_packno_bits bits,
lsquic_packno_t cur_packno, enum packno_bits bits,
lsquic_packno_t *least_unacked)
{
lsquic_packno_t delta;
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
{
@ -459,9 +459,9 @@ gquic_le_parse_stop_waiting_frame (const unsigned char *buf, size_t buf_len,
static int
gquic_le_skip_stop_waiting_frame (size_t buf_len, enum lsquic_packno_bits bits)
gquic_le_skip_stop_waiting_frame (size_t buf_len, enum packno_bits bits)
{
unsigned packnum_len = packno_bits2len(bits);
unsigned packnum_len = gquic_packno_bits2len(bits);
if (buf_len >= 1 + packnum_len)
return 1 + packnum_len;
else
@ -846,4 +846,6 @@ const struct parse_funcs lsquic_parse_funcs_gquic_le =
.pf_turn_on_fin = lsquic_turn_on_fin_Q035_thru_Q039,
.pf_packout_size = lsquic_gquic_packout_size,
.pf_packout_header_size = lsquic_gquic_packout_header_size,
.pf_calc_packno_bits = lsquic_gquic_calc_packno_bits,
.pf_packno_bits2len = lsquic_gquic_packno_bits2len,
};

View file

@ -21,7 +21,7 @@
#include "lsquic_handshake.h"
static const enum header_type bin_2_header_type[0x100] =
static const enum header_type bin_2_header_type_Q044[0x100] =
{
[0x80 | 0x7F] = HETY_INITIAL,
[0x80 | 0x7E] = HETY_RETRY,
@ -30,6 +30,17 @@ static const enum header_type bin_2_header_type[0x100] =
};
/* [draft-ietf-quic-transport-17] Section-17.2 */
static const enum header_type bits2ht[4] =
{
[0] = HETY_INITIAL,
[1] = HETY_0RTT,
[2] = HETY_HANDSHAKE,
[3] = HETY_RETRY,
};
/* This function supports versions Q044 and higher */
int
lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
size_t length, int is_server, struct packin_parse_state *state)
@ -38,8 +49,9 @@ lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
const unsigned char *const end = p + length;
lsquic_ver_tag_t tag;
enum header_type header_type;
unsigned dcil, scil;
unsigned dcil, scil, packet_len;
int verneg;
enum lsquic_version version;
unsigned char first_byte;
const unsigned cid_len = 8;
@ -52,9 +64,15 @@ lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
verneg = 0 == tag;
if (!verneg)
{
header_type = bin_2_header_type[ first_byte ];
if (!header_type)
return -1;
version = lsquic_tag2ver(tag);
if (version == LSQVER_044)
{
header_type = bin_2_header_type_Q044[ first_byte ];
if (!header_type)
return -1;
}
else
header_type = bits2ht[ (first_byte >> 4) & 3 ];
}
else
header_type = HETY_VERNEG;
@ -73,8 +91,8 @@ lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
* CID of 8 bytes and source CID of 0 bytes and the server does it the
* other way around.
*
* XXX When IETF branch is merged, this check for Q044 will have to be
* moved to the pf_parse_packet_in_finish().
* XXX When IETF branch is merged, this check for Q044 and higher will
* have to be moved to the pf_parse_packet_in_finish().
*/
if (is_server)
{
@ -87,14 +105,27 @@ lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
return -1;
}
const unsigned packet_len = 4;
/* XXX This checks both packet length or the first version of the version
* array in a version negotiation packet. This is because the sizes of
* the packet number field and the version tag are the same. The check
* will probably have to be split in the future.
*/
if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
return -1;
if (!verneg)
{
if (version == LSQVER_044)
{
packet_in->pi_flags |= GQUIC_PACKNO_LEN_4 << PIBIT_BITS_SHIFT;
packet_len = 4;
}
else
{
packet_in->pi_flags |= (first_byte & 3) << PIBIT_BITS_SHIFT;
packet_len = 1 + (first_byte & 3);
}
if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
return -1;
}
else
{
/* Need at least one version in the version array: add 4 */
if (end - p < (ptrdiff_t) (dcil + scil + 4))
return -1;
}
memcpy(&packet_in->pi_conn_id, p, cid_len);
p += cid_len;
@ -146,13 +177,19 @@ lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
unsigned cid_len = 8; /* XXX this will need to be passed in */
unsigned packet_len;
if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
return -1;
if (*p & 0x40) /* Q046 and higher */
packet_len = 1 + (*p & 3);
else
{
if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
return -1;
packet_len = 1 << (*p & 3);
}
packet_len = 1 << (*p & 3);
if (pend - p < (ptrdiff_t) (1 + cid_len + packet_len))
return -1;
packet_in->pi_flags |= (*p & 3) << PIBIT_BITS_SHIFT;
++p;
if (is_server)

View file

@ -103,10 +103,10 @@ static
#elif __GNUC__
__attribute__((weak))
#endif
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_guess_packno_bits (lsquic_send_ctl_t *ctl)
{
return PACKNO_LEN_2;
return PACKNO_BITS_1; /* This is 2 bytes in both GQUIC and IQUIC */
}
@ -257,7 +257,7 @@ lsquic_send_ctl_init (lsquic_send_ctl_t *ctl, struct lsquic_alarmset *alset,
for (i = 0; i < sizeof(ctl->sc_buffered_packets) /
sizeof(ctl->sc_buffered_packets[0]); ++i)
TAILQ_INIT(&ctl->sc_buffered_packets[i].bpq_packets);
ctl->sc_max_packno_bits = PACKNO_LEN_4; /* Safe value before verneg */
ctl->sc_max_packno_bits = PACKNO_BITS_2; /* Safe value before verneg */
}
@ -1195,7 +1195,7 @@ lsquic_send_ctl_have_outgoing_retx_frames (const lsquic_send_ctl_t *ctl)
static lsquic_packet_out_t *
send_ctl_allocate_packet (lsquic_send_ctl_t *ctl, enum lsquic_packno_bits bits,
send_ctl_allocate_packet (lsquic_send_ctl_t *ctl, enum packno_bits bits,
unsigned need_at_least)
{
lsquic_packet_out_t *packet_out;
@ -1226,7 +1226,7 @@ lsquic_packet_out_t *
lsquic_send_ctl_new_packet_out (lsquic_send_ctl_t *ctl, unsigned need_at_least)
{
lsquic_packet_out_t *packet_out;
enum lsquic_packno_bits bits;
enum packno_bits bits;
bits = lsquic_send_ctl_packno_bits(ctl);
packet_out = send_ctl_allocate_packet(ctl, bits, need_at_least);
@ -1675,7 +1675,7 @@ send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
&ctl->sc_buffered_packets[packet_type];
struct lsquic_conn *const lconn = ctl->sc_conn_pub->lconn;
lsquic_packet_out_t *packet_out;
enum lsquic_packno_bits bits;
enum packno_bits bits;
enum { AA_STEAL, AA_GENERATE, AA_NONE, } ack_action;
packet_out = TAILQ_LAST(&packet_q->bpq_packets, lsquic_packets_tailq);
@ -1778,11 +1778,11 @@ static
#elif __GNUC__
__attribute__((weak))
#endif
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_calc_packno_bits (lsquic_send_ctl_t *ctl)
{
lsquic_packno_t smallest_unacked;
enum lsquic_packno_bits bits;
enum packno_bits bits;
unsigned n_in_flight;
smallest_unacked = lsquic_send_ctl_smallest_unacked(ctl);
@ -1796,7 +1796,7 @@ lsquic_send_ctl_calc_packno_bits (lsquic_send_ctl_t *ctl)
}
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_packno_bits (lsquic_send_ctl_t *ctl)
{
@ -1810,7 +1810,7 @@ lsquic_send_ctl_packno_bits (lsquic_send_ctl_t *ctl)
static int
split_buffered_packet (lsquic_send_ctl_t *ctl,
enum buf_packet_type packet_type, lsquic_packet_out_t *packet_out,
enum lsquic_packno_bits bits, unsigned excess_bytes)
enum packno_bits bits, unsigned excess_bytes)
{
struct buf_packet_q *const packet_q =
&ctl->sc_buffered_packets[packet_type];
@ -1847,12 +1847,13 @@ lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *ctl,
{
struct buf_packet_q *const packet_q =
&ctl->sc_buffered_packets[packet_type];
const struct parse_funcs *const pf = ctl->sc_conn_pub->lconn->cn_pf;
lsquic_packet_out_t *packet_out;
unsigned used, excess;
assert(lsquic_send_ctl_schedule_stream_packets_immediately(ctl));
const enum lsquic_packno_bits bits = lsquic_send_ctl_calc_packno_bits(ctl);
const unsigned need = packno_bits2len(bits);
const enum packno_bits bits = lsquic_send_ctl_calc_packno_bits(ctl);
const unsigned need = pf->pf_packno_bits2len(bits);
while ((packet_out = TAILQ_FIRST(&packet_q->bpq_packets)) &&
lsquic_send_ctl_can_send(ctl))
@ -1873,7 +1874,8 @@ lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *ctl,
}
if (bits != lsquic_packet_out_packno_bits(packet_out))
{
used = packno_bits2len(lsquic_packet_out_packno_bits(packet_out));
used = pf->pf_packno_bits2len(
lsquic_packet_out_packno_bits(packet_out));
if (need > used
&& need - used > lsquic_packet_out_avail(packet_out))
{
@ -1954,12 +1956,10 @@ lsquic_send_ctl_mem_used (const struct lsquic_send_ctl *ctl)
void
lsquic_send_ctl_verneg_done (struct lsquic_send_ctl *ctl)
{
if ((1 << ctl->sc_conn_pub->lconn->cn_version) &
LSQUIC_GQUIC_HEADER_VERSIONS)
ctl->sc_max_packno_bits = PACKNO_LEN_6;
if (ctl->sc_conn_pub->lconn->cn_version == LSQVER_044)
ctl->sc_max_packno_bits = PACKNO_BITS_2;
else
/* Assuming Q044 */
ctl->sc_max_packno_bits = PACKNO_LEN_4;
ctl->sc_max_packno_bits = PACKNO_BITS_3;
LSQ_DEBUG("version negotiation done (%s): max packno bits: %u",
lsquic_ver2str[ ctl->sc_conn_pub->lconn->cn_version ],
ctl->sc_max_packno_bits);

View file

@ -95,7 +95,7 @@ typedef struct lsquic_send_ctl {
} sc_cached_bpt;
unsigned sc_next_limit;
unsigned sc_n_scheduled;
enum lsquic_packno_bits sc_max_packno_bits;
enum packno_bits sc_max_packno_bits;
#if LSQUIC_SEND_STATS
struct {
unsigned n_total_sent,
@ -233,7 +233,7 @@ lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *);
? pacer_next_sched(&(ctl)->sc_pacer) \
: 0 )
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_packno_bits (lsquic_send_ctl_t *);
int
@ -248,7 +248,7 @@ lsquic_send_ctl_schedule_buffered (lsquic_send_ctl_t *, enum buf_packet_type);
} while (0)
#ifndef NDEBUG
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_guess_packno_bits (struct lsquic_send_ctl *);
int
@ -258,7 +258,7 @@ enum buf_packet_type
lsquic_send_ctl_determine_bpt (struct lsquic_send_ctl *,
const struct lsquic_stream *);
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_calc_packno_bits (struct lsquic_send_ctl *);
#endif

View file

@ -1388,7 +1388,7 @@ static
lsquic_stream_flush_threshold (const struct lsquic_stream *stream)
{
enum packet_out_flags flags;
enum lsquic_packno_bits bits;
enum packno_bits bits;
unsigned packet_header_sz, stream_header_sz;
size_t threshold;

View file

@ -12,6 +12,7 @@ static const unsigned char version_tags[N_LSQVER][4] =
[LSQVER_039] = { 'Q', '0', '3', '9', },
[LSQVER_043] = { 'Q', '0', '4', '3', },
[LSQVER_044] = { 'Q', '0', '4', '4', },
[LSQVER_046] = { 'Q', '0', '4', '6', },
#if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', },
#endif
@ -63,6 +64,7 @@ const char *const lsquic_ver2str[N_LSQVER] = {
[LSQVER_039] = "Q039",
[LSQVER_043] = "Q043",
[LSQVER_044] = "Q044",
[LSQVER_046] = "Q046",
#if LSQUIC_USE_Q098
[LSQVER_098] = "Q098",
#endif

View file

@ -954,7 +954,7 @@ send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count)
msg.dwBufferCount = 1;
msg.dwFlags = 0;
#endif
if (sport->sp_flags & SPORT_SERVER)
if ((sport->sp_flags & SPORT_SERVER) && specs[n].local_sa->sa_family)
setup_control_msg(&msg, &specs[n], ancil.buf, sizeof(ancil.buf));
else
{

View file

@ -15,6 +15,9 @@
#include "lsquic_parse.h"
static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_039);
struct packno_bits_test {
int pbt_lineno;
/* Inputs: */
@ -22,7 +25,7 @@ struct packno_bits_test {
pbt_least_unacked;
uint64_t pbt_n_in_flight;
/* Output: */
enum lsquic_packno_bits pbt_packno_bits;
enum packno_bits pbt_packno_bits;
};
@ -32,112 +35,112 @@ static const struct packno_bits_test pb_tests[] = {
.pbt_packno = 1,
.pbt_least_unacked = 0,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 101,
.pbt_least_unacked = 100,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 10001,
.pbt_least_unacked = 10000,
.pbt_n_in_flight = 1 << 6,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 10001,
.pbt_least_unacked = 10000,
.pbt_n_in_flight = (1 << 6) + 1,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 16) + 1,
.pbt_least_unacked = 1 << 16,
.pbt_n_in_flight = 1 << 14,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 16) + 1,
.pbt_least_unacked = 1 << 16,
.pbt_n_in_flight = (1 << 14) + 1,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1ULL << 33) + 1,
.pbt_least_unacked = 1ULL << 33,
.pbt_n_in_flight = 1ULL << 30,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1ULL << 33) + 1,
.pbt_least_unacked = 1ULL << 33,
.pbt_n_in_flight = (1ULL << 30) + 1,
.pbt_packno_bits = PACKNO_LEN_6,
.pbt_packno_bits = GQUIC_PACKNO_LEN_6,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 100,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 3,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 100,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 99,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 1 + (1 << 6),
.pbt_least_unacked = 1,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 1 + (1 << 6) + 1,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 20) + (1 << 14),
.pbt_least_unacked = 1 << 20,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 20) + (1 << 14) + 1,
.pbt_least_unacked = 1 << 20,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 20) + (1ULL << 30),
.pbt_least_unacked = 1 << 20,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = (1 << 20) + (1ULL << 30) + 1,
.pbt_least_unacked = 1 << 20,
.pbt_n_in_flight = 0,
.pbt_packno_bits = PACKNO_LEN_6,
.pbt_packno_bits = GQUIC_PACKNO_LEN_6,
},
/* Tests from Chrome: */
@ -145,56 +148,56 @@ static const struct packno_bits_test pb_tests[] = {
.pbt_packno = 65,
.pbt_least_unacked = 2,
.pbt_n_in_flight = 7,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 64 * 256 - 1,
.pbt_least_unacked = 2,
.pbt_n_in_flight = 7,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 64 * 256 * 256 - 1,
.pbt_least_unacked = 2,
.pbt_n_in_flight = 7,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 64ULL * 256 * 256 * 256 * 256 - 1,
.pbt_least_unacked = 2,
.pbt_n_in_flight = 7,
.pbt_packno_bits = PACKNO_LEN_6,
.pbt_packno_bits = GQUIC_PACKNO_LEN_6,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 2,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 7,
.pbt_packno_bits = PACKNO_LEN_1,
.pbt_packno_bits = GQUIC_PACKNO_LEN_1,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 2,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 1896,
.pbt_packno_bits = PACKNO_LEN_2,
.pbt_packno_bits = GQUIC_PACKNO_LEN_2,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 2,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 48545,
.pbt_packno_bits = PACKNO_LEN_4,
.pbt_packno_bits = GQUIC_PACKNO_LEN_4,
},
{ .pbt_lineno = __LINE__,
.pbt_packno = 2,
.pbt_least_unacked = 1,
.pbt_n_in_flight = 3181457256ULL,
.pbt_packno_bits = PACKNO_LEN_6,
.pbt_packno_bits = GQUIC_PACKNO_LEN_6,
},
};
@ -204,13 +207,14 @@ static void
run_pbt (int i)
{
const struct packno_bits_test *const pbt = &pb_tests[i];
enum lsquic_packno_bits packno_bits = calc_packno_bits(pbt->pbt_packno,
enum packno_bits packno_bits = pf->pf_calc_packno_bits(pbt->pbt_packno,
pbt->pbt_least_unacked, pbt->pbt_n_in_flight);
assert(packno_bits == pbt->pbt_packno_bits);
unsigned packet_len = pf->pf_packno_bits2len(packno_bits);
/* Now see if we can restore it back: */
lsquic_packno_t cur_packno = pbt->pbt_packno &
((1ULL << (packno_bits2len(packno_bits) << 3)) - 1);
lsquic_packno_t orig_packno = restore_packno(cur_packno, packno_bits,
((1ULL << (packet_len << 3)) - 1);
lsquic_packno_t orig_packno = restore_packno(cur_packno, packet_len,
pbt->pbt_least_unacked);
assert(orig_packno == pbt->pbt_packno);
}
@ -219,7 +223,7 @@ run_pbt (int i)
struct restore_packno_test {
int rpt_lineno;
/* Input */
enum lsquic_packno_bits rpt_packno_bits;
enum packno_bits rpt_packno_bits;
lsquic_packno_t rpt_cur_packno;
lsquic_packno_t rpt_max_packno;
/* Output */
@ -232,7 +236,7 @@ static const struct restore_packno_test rp_tests[] =
{ .rpt_lineno = __LINE__,
.rpt_max_packno = 0,
.rpt_cur_packno = 1,
.rpt_packno_bits = PACKNO_LEN_1,
.rpt_packno_bits = GQUIC_PACKNO_LEN_1,
.rpt_orig_packno = 1,
},
@ -243,14 +247,15 @@ static void
run_rpt (int i)
{
const struct restore_packno_test *const rpt = &rp_tests[i];
unsigned packet_len = pf->pf_packno_bits2len(rpt->rpt_packno_bits);
lsquic_packno_t orig_packno = restore_packno(rpt->rpt_cur_packno,
rpt->rpt_packno_bits, rpt->rpt_max_packno);
packet_len, rpt->rpt_max_packno);
assert(orig_packno == rpt->rpt_orig_packno);
}
static void
test_restore (enum lsquic_packno_bits bits)
test_restore (enum packno_bits bits)
{
unsigned len, n;
enum { OP_PLUS, OP_MINUS, N_OPS } op;
@ -260,7 +265,7 @@ test_restore (enum lsquic_packno_bits bits)
#ifdef WIN32
orig_packno = 0;
#endif
len = packno_bits2len(bits);
len = pf->pf_packno_bits2len(bits);
epoch_delta = 1ULL << (len << 3);
epoch = epoch_delta * 11 /* Just some number */;
@ -276,7 +281,7 @@ test_restore (enum lsquic_packno_bits bits)
else
assert(0);
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch);
restored_packno = restore_packno(cur_packno, len, epoch);
assert(orig_packno == restored_packno);
/* Test in the middle of the epoch */
if (op == OP_MINUS)
@ -284,7 +289,7 @@ test_restore (enum lsquic_packno_bits bits)
else
orig_packno = epoch + n;
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch);
restored_packno = restore_packno(cur_packno, len, epoch);
assert(orig_packno == restored_packno);
}
@ -294,12 +299,12 @@ test_restore (enum lsquic_packno_bits bits)
/* Test at the end of the epoch */
orig_packno = epoch + epoch_delta / 2 - n - 1;
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch - epoch_delta * 3 / 4);
restored_packno = restore_packno(cur_packno, len, epoch - epoch_delta * 3 / 4);
assert(orig_packno == restored_packno + epoch_delta);
/* Test in the middle of the epoch */
orig_packno = epoch + 2 - n;
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch - epoch_delta * 3 / 4);
restored_packno = restore_packno(cur_packno, len, epoch - epoch_delta * 3 / 4);
assert(orig_packno == restored_packno + epoch_delta);
}
@ -309,12 +314,12 @@ test_restore (enum lsquic_packno_bits bits)
/* Test at the end of the epoch */
orig_packno = epoch - epoch_delta / 2 + n;
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch + epoch_delta * 3 / 4);
restored_packno = restore_packno(cur_packno, len, epoch + epoch_delta * 3 / 4);
assert(orig_packno == restored_packno - epoch_delta);
/* Test in the middle of the epoch */
orig_packno = epoch + 2 - n;
cur_packno = orig_packno & (epoch_delta - 1);
restored_packno = restore_packno(cur_packno, bits, epoch + epoch_delta * 3 / 4);
restored_packno = restore_packno(cur_packno, len, epoch + epoch_delta * 3 / 4);
assert(orig_packno == restored_packno - epoch_delta);
}
@ -329,9 +334,9 @@ main (void)
run_pbt(i);
for (i = 0; i < sizeof(rp_tests) / sizeof(rp_tests[0]); ++i)
run_rpt(i);
test_restore(PACKNO_LEN_1);
test_restore(PACKNO_LEN_2);
test_restore(PACKNO_LEN_4);
test_restore(PACKNO_LEN_6);
test_restore(GQUIC_PACKNO_LEN_1);
test_restore(GQUIC_PACKNO_LEN_2);
test_restore(GQUIC_PACKNO_LEN_4);
test_restore(GQUIC_PACKNO_LEN_6);
return 0;
}

View file

@ -23,7 +23,7 @@ struct test {
lsquic_cid_t cid; /* Zero means connection ID is not specified */
const char *nonce;
lsquic_packno_t packno;
enum lsquic_packno_bits
enum packno_bits
bits; /* The test has been retrofitted by adding bits parameter. The test can
* be made more complicated by calculating packet number length based on
* some other inputs. However, this is tested elsewhere.
@ -47,7 +47,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NULL,
.packno = 0x01020304,
.bits = PACKNO_LEN_4,
.bits = GQUIC_PACKNO_LEN_4,
.len = 1 + 8 + 0 + 4,
.out = { (0 << 2) /* Nonce present */
| 0x08 /* Connection ID present */
@ -64,7 +64,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NULL,
.packno = 0x01020304,
.bits = PACKNO_LEN_4,
.bits = GQUIC_PACKNO_LEN_4,
.len = 1 + 8 + 0 + 4,
.out = { (0 << 2) /* Nonce present */
| 0x08 /* Connection ID present */
@ -81,7 +81,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NULL,
.packno = 0x00,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.len = 1 + 8 + 0 + 1,
.out = { (0 << 2) /* Nonce present */
| 0x08 /* Connection ID present */
@ -98,7 +98,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NULL,
.packno = 0x00,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.ver.buf= { 'Q', '0', '3', '5', },
.len = 1 + 8 + 4 + 0 + 1,
.out = { (0 << 2) /* Nonce present */
@ -118,7 +118,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NULL,
.packno = 0x09,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.ver.buf= { 'Q', '0', '3', '9', },
.len = 1 + 8 + 4 + 0 + 1,
.out = { (0 << 2) /* Nonce present */
@ -141,7 +141,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NONCENSE,
.packno = 0x00,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.len = 1 + 8 + 32 + 1,
.out = { (1 << 2) /* Nonce present */
| 0x08 /* Connection ID present */
@ -159,7 +159,7 @@ static const struct test tests[] = {
.cid = 0, /* Do not set connection ID */
.nonce = NONCENSE,
.packno = 0x00,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.len = 1 + 0 + 32 + 1,
.out = { (1 << 2) /* Nonce present */
| 0x00 /* Packet number length */
@ -175,7 +175,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NONCENSE,
.packno = 0x00,
.bits = PACKNO_LEN_1,
.bits = GQUIC_PACKNO_LEN_1,
.ver.buf= { 'Q', '0', '3', '5', },
.len = 1 + 8 + 4 + 32 + 1,
.out = { (1 << 2) /* Nonce present */
@ -196,7 +196,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NONCENSE,
.packno = 0xA0A1A2A3A4A5A6A7UL,
.bits = PACKNO_LEN_6,
.bits = GQUIC_PACKNO_LEN_6,
.len = 1 + 8 + 32 + 6,
.out = { (1 << 2) /* Nonce present */
| 0x08 /* Connection ID present */
@ -214,7 +214,7 @@ static const struct test tests[] = {
.cid = 0x0102030405060708UL,
.nonce = NONCENSE,
.packno = 0xA0A1A2A3A4A5A6A7UL,
.bits = PACKNO_LEN_6,
.bits = GQUIC_PACKNO_LEN_6,
.len = 1 + 8 + 32 + 6,
.out = { (1 << 2) /* Nonce present */
| 0x08 /* Connection ID present */

View file

@ -20,7 +20,7 @@ struct parse_test {
unsigned char buf[0x10];
size_t buf_len;
lsquic_packno_t cur_packno;
enum lsquic_packno_bits
enum packno_bits
bits;
/* Expected values: */
int retval;
@ -33,7 +33,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 3,
.least_unacked = 0x1111,
.cur_packno = 0x4523,
.bits = PACKNO_LEN_2,
.bits = GQUIC_PACKNO_LEN_2,
.retval = 3,
},
@ -42,7 +42,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 2,
.least_unacked = 0x1111,
.cur_packno = 0x4523,
.bits = PACKNO_LEN_2,
.bits = GQUIC_PACKNO_LEN_2,
.retval = -1,
},
@ -51,7 +51,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 7,
.least_unacked = 0x1122324252627282,
.cur_packno = 0x1122334455667788,
.bits = PACKNO_LEN_6,
.bits = GQUIC_PACKNO_LEN_6,
.retval = 7,
},

View file

@ -20,7 +20,7 @@ struct parse_test {
unsigned char buf[0x10];
size_t buf_len;
lsquic_packno_t cur_packno;
enum lsquic_packno_bits
enum packno_bits
bits;
/* Expected values: */
int retval;
@ -33,7 +33,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 3,
.least_unacked = 0x1111,
.cur_packno = 0x4523,
.bits = PACKNO_LEN_2,
.bits = GQUIC_PACKNO_LEN_2,
.retval = 3,
},
@ -42,7 +42,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 2,
.least_unacked = 0x1111,
.cur_packno = 0x4523,
.bits = PACKNO_LEN_2,
.bits = GQUIC_PACKNO_LEN_2,
.retval = -1,
},
@ -51,7 +51,7 @@ static const struct parse_test parse_tests[] = {
.buf_len = 7,
.least_unacked = 0x1122324252627282,
.cur_packno = 0x1122334455667788,
.bits = PACKNO_LEN_6,
.bits = GQUIC_PACKNO_LEN_6,
.retval = 7,
},

View file

@ -47,7 +47,7 @@ struct test_ctl_settings
int tcs_can_send;
enum buf_packet_type
tcs_bp_type;
enum lsquic_packno_bits
enum packno_bits
tcs_guess_packno_bits,
tcs_calc_packno_bits;
};
@ -68,8 +68,8 @@ init_test_ctl_settings (struct test_ctl_settings *settings)
settings->tcs_have_delayed_packets = 0;
settings->tcs_can_send = 1;
settings->tcs_bp_type = BPT_HIGHEST_PRIO;
settings->tcs_guess_packno_bits = PACKNO_LEN_2;
settings->tcs_calc_packno_bits = PACKNO_LEN_2;
settings->tcs_guess_packno_bits = GQUIC_PACKNO_LEN_2;
settings->tcs_calc_packno_bits = GQUIC_PACKNO_LEN_2;
}
@ -83,7 +83,7 @@ apply_test_ctl_settings (const struct test_ctl_settings *settings)
}
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_calc_packno_bits (struct lsquic_send_ctl *ctl)
{
return g_ctl_settings.tcs_calc_packno_bits;
@ -111,7 +111,7 @@ lsquic_send_ctl_can_send (struct lsquic_send_ctl *ctl)
}
enum lsquic_packno_bits
enum packno_bits
lsquic_send_ctl_guess_packno_bits (struct lsquic_send_ctl *ctl)
{
return g_ctl_settings.tcs_guess_packno_bits;
@ -2049,7 +2049,7 @@ test_bad_packbits_guess_2 (void)
init_test_ctl_settings(&g_ctl_settings);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 0;
g_ctl_settings.tcs_guess_packno_bits = PACKNO_LEN_1;
g_ctl_settings.tcs_guess_packno_bits = GQUIC_PACKNO_LEN_1;
init_test_objs(&tobjs, 0x1000, 0x1000, NULL);
streams[0] = new_stream(&tobjs, 5);
@ -2082,7 +2082,7 @@ test_bad_packbits_guess_2 (void)
assert(1 == streams[2]->n_unacked);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
g_ctl_settings.tcs_calc_packno_bits = PACKNO_LEN_6;
g_ctl_settings.tcs_calc_packno_bits = GQUIC_PACKNO_LEN_6;
s = lsquic_send_ctl_schedule_buffered(&tobjs.send_ctl,
g_ctl_settings.tcs_bp_type);
assert(2 == lsquic_send_ctl_n_scheduled(&tobjs.send_ctl));
@ -2105,12 +2105,12 @@ test_bad_packbits_guess_2 (void)
/* Verify packets */
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) == GQUIC_PACKNO_LEN_6);
assert(1 == packet_out->po_packno);
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);
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
assert(lsquic_packet_out_packno_bits(packet_out) == GQUIC_PACKNO_LEN_6);
assert(2 == packet_out->po_packno);
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
@ -2152,7 +2152,7 @@ test_bad_packbits_guess_3 (void)
init_test_ctl_settings(&g_ctl_settings);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 0;
g_ctl_settings.tcs_guess_packno_bits = PACKNO_LEN_1;
g_ctl_settings.tcs_guess_packno_bits = GQUIC_PACKNO_LEN_1;
init_test_objs(&tobjs, 0x1000, 0x1000, NULL);
streams[0] = new_stream(&tobjs, 5);
@ -2173,7 +2173,7 @@ test_bad_packbits_guess_3 (void)
assert(1 == streams[0]->n_unacked);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
g_ctl_settings.tcs_calc_packno_bits = PACKNO_LEN_4;
g_ctl_settings.tcs_calc_packno_bits = GQUIC_PACKNO_LEN_4;
s = lsquic_send_ctl_schedule_buffered(&tobjs.send_ctl,
g_ctl_settings.tcs_bp_type);
assert(2 == lsquic_send_ctl_n_scheduled(&tobjs.send_ctl));
@ -2187,12 +2187,12 @@ test_bad_packbits_guess_3 (void)
/* Verify packets */
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) == GQUIC_PACKNO_LEN_4);
assert(1 == packet_out->po_packno);
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);
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_4);
assert(lsquic_packet_out_packno_bits(packet_out) == GQUIC_PACKNO_LEN_4);
assert(2 == packet_out->po_packno);
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);
@ -2616,7 +2616,7 @@ test_bad_packbits_guess_1 (void)
init_test_ctl_settings(&g_ctl_settings);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 0;
g_ctl_settings.tcs_guess_packno_bits = PACKNO_LEN_1;
g_ctl_settings.tcs_guess_packno_bits = GQUIC_PACKNO_LEN_1;
init_test_objs(&tobjs, 0x1000, 0x1000, NULL);
streams[0] = new_stream(&tobjs, 5);
@ -2649,7 +2649,7 @@ test_bad_packbits_guess_1 (void)
assert(1 == streams[2]->n_unacked);
g_ctl_settings.tcs_schedule_stream_packets_immediately = 1;
g_ctl_settings.tcs_calc_packno_bits = PACKNO_LEN_6;
g_ctl_settings.tcs_calc_packno_bits = GQUIC_PACKNO_LEN_6;
s = lsquic_send_ctl_schedule_buffered(&tobjs.send_ctl,
g_ctl_settings.tcs_bp_type);
assert(2 == lsquic_send_ctl_n_scheduled(&tobjs.send_ctl));
@ -2672,12 +2672,12 @@ test_bad_packbits_guess_1 (void)
/* Verify packets */
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) == GQUIC_PACKNO_LEN_6);
assert(1 == packet_out->po_packno);
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);
assert(lsquic_packet_out_packno_bits(packet_out) == PACKNO_LEN_6);
assert(lsquic_packet_out_packno_bits(packet_out) == GQUIC_PACKNO_LEN_6);
assert(2 == packet_out->po_packno);
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
lsquic_send_ctl_sent_packet(&tobjs.send_ctl, packet_out, 1);