if (ngtcp2_conn_is_server(conn) &&
crypto_set_local_transport_params(conn, tls) != 0) {
- goto fail;
+ /* Just return -1 because aead_ctx and hp_ctx are now owned by
+ conn. */
+ return -1;
}
break;
return addrlen;
}
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN is the maximum length of
+ opaque data embedded in a regular token. */
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN 256
+
+/* NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN is the maximum length
+ of plaintext included in a regular token. */
+#define NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN \
+ (sizeof(ngtcp2_tstamp) + NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN)
+
static const uint8_t regular_token_info_prefix[] = "regular_token";
-ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
+static ngtcp2_ssize crypto_generate_regular_token(
uint8_t *token, const uint8_t *secret, size_t secretlen,
const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
- ngtcp2_tstamp ts) {
- uint8_t plaintext[sizeof(ngtcp2_tstamp)];
+ const void *data, size_t datalen, ngtcp2_tstamp ts) {
+ uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
uint8_t rand_data[NGTCP2_CRYPTO_TOKEN_RAND_DATALEN];
uint8_t key[16];
uint8_t iv[12];
int rv;
(void)remote_addrlen;
+ if (datalen > NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_DATALEN) {
+ return -1;
+ }
+
memcpy(p, &ts_be, sizeof(ts_be));
p += sizeof(ts_be);
+ if (datalen) {
+ memcpy(p, data, datalen);
+ p += datalen;
+ }
+
plaintextlen = (size_t)(p - plaintext);
if (ngtcp2_crypto_random(rand_data, sizeof(rand_data)) != 0) {
return p - token;
}
-int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
- const uint8_t *secret, size_t secretlen,
- const ngtcp2_sockaddr *remote_addr,
- ngtcp2_socklen remote_addrlen,
- ngtcp2_duration timeout,
- ngtcp2_tstamp ts) {
- uint8_t plaintext[sizeof(ngtcp2_tstamp)];
+static ngtcp2_ssize crypto_verify_regular_token(
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
+ uint8_t plaintext[NGTCP2_CRYPTO_MAX_REGULAR_TOKEN_PLAINTEXTLEN];
uint8_t key[16];
uint8_t iv[12];
size_t keylen;
const uint8_t *rand_data;
const uint8_t *ciphertext;
size_t ciphertextlen;
+ size_t datalen;
int rv;
ngtcp2_tstamp gen_ts;
(void)remote_addrlen;
- if (tokenlen != NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
+ if (tokenlen < NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN ||
token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR) {
- return -1;
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
}
rand_data = token + tokenlen - NGTCP2_CRYPTO_TOKEN_RAND_DATALEN;
ngtcp2_crypto_aead_aes_128_gcm(&aead);
ngtcp2_crypto_md_sha256(&md);
+ if (ciphertextlen > sizeof(plaintext) + aead.max_overhead) {
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
+ }
+
keylen = ngtcp2_crypto_aead_keylen(&aead);
ivlen = ngtcp2_crypto_aead_noncelen(&aead);
rand_data, NGTCP2_CRYPTO_TOKEN_RAND_DATALEN,
regular_token_info_prefix,
sizeof(regular_token_info_prefix) - 1) != 0) {
- return -1;
+ return NGTCP2_CRYPTO_ERR_INTERNAL;
}
aadlen = crypto_generate_regular_token_aad(aad, remote_addr);
if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, &aead, key, ivlen) != 0) {
- return -1;
+ return NGTCP2_CRYPTO_ERR_INTERNAL;
}
rv = ngtcp2_crypto_decrypt(plaintext, &aead, &aead_ctx, ciphertext,
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
if (rv != 0) {
- return -1;
+ return NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN;
}
memcpy(&gen_ts, plaintext, sizeof(gen_ts));
gen_ts = ngtcp2_ntohl64(gen_ts);
if (gen_ts + timeout <= ts) {
+ return NGTCP2_CRYPTO_ERR_VERIFY_TOKEN;
+ }
+
+ if (max_datalen == 0) {
+ return 0;
+ }
+
+ datalen = ciphertextlen - aead.max_overhead - sizeof(gen_ts);
+ if (datalen > max_datalen) {
+ return 0;
+ }
+
+ memcpy(data, plaintext + sizeof(gen_ts), datalen);
+
+ return (ngtcp2_ssize)datalen;
+}
+
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token(
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+ ngtcp2_tstamp ts) {
+ return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
+ remote_addrlen, NULL, 0, ts);
+}
+
+int ngtcp2_crypto_verify_regular_token(const uint8_t *token, size_t tokenlen,
+ const uint8_t *secret, size_t secretlen,
+ const ngtcp2_sockaddr *remote_addr,
+ ngtcp2_socklen remote_addrlen,
+ ngtcp2_duration timeout,
+ ngtcp2_tstamp ts) {
+ ngtcp2_ssize datalen =
+ crypto_verify_regular_token(NULL, 0, token, tokenlen, secret, secretlen,
+ remote_addr, remote_addrlen, timeout, ts);
+
+ if (datalen < 0) {
return -1;
}
+ assert(0 == datalen);
+
return 0;
}
+ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+ const void *data, size_t datalen, ngtcp2_tstamp ts) {
+ return crypto_generate_regular_token(token, secret, secretlen, remote_addr,
+ remote_addrlen, data, datalen, ts);
+}
+
+ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts) {
+ return crypto_verify_regular_token(data, max_datalen, token, tokenlen, secret,
+ secretlen, remote_addr, remote_addrlen,
+ timeout, ts);
+}
+
ngtcp2_ssize ngtcp2_crypto_write_connection_close(
uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
const ngtcp2_cid *scid, uint64_t error_code, const uint8_t *reason,
static void acktr_entry_init(ngtcp2_acktr_entry *ent, int64_t pkt_num,
ngtcp2_tstamp tstamp) {
- ent->pkt_num = pkt_num;
- ent->len = 1;
- ent->tstamp = tstamp;
+ *ent = (ngtcp2_acktr_entry){
+ .pkt_num = pkt_num,
+ .len = 1,
+ .tstamp = tstamp,
+ };
}
int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
int64_t largest_ack) {
ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks.rb);
- ent->largest_ack = largest_ack;
- ent->pkt_num = pkt_num;
+ *ent = (ngtcp2_acktr_ack_entry){
+ .largest_ack = largest_ack,
+ .pkt_num = pkt_num,
+ };
return ent;
}
ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
ngtcp2_socklen addrlen) {
- dest->addrlen = addrlen;
- dest->addr = (ngtcp2_sockaddr *)addr;
+ *dest = (ngtcp2_addr){
+ .addr = (ngtcp2_sockaddr *)addr,
+ .addrlen = addrlen,
+ };
+
return dest;
}
static void bbr_mark_connection_app_limited(ngtcp2_cc_bbr *bbr,
ngtcp2_conn_stat *cstat) {
- uint64_t app_limited = bbr->rst->delivered + cstat->bytes_in_flight;
-
- if (app_limited) {
- bbr->rst->app_limited = app_limited;
- } else {
- bbr->rst->app_limited = cstat->max_tx_udp_payload_size;
- }
+ bbr->rst->app_limited =
+ ngtcp2_max_uint64(bbr->rst->delivered + cstat->bytes_in_flight, 1);
}
static void bbr_exit_probe_rtt(ngtcp2_cc_bbr *bbr, ngtcp2_tstamp ts) {
#include "ngtcp2_mem.h"
void ngtcp2_buf_init(ngtcp2_buf *buf, uint8_t *begin, size_t len) {
- buf->begin = buf->pos = buf->last = begin;
- buf->end = begin + len;
+ *buf = (ngtcp2_buf){
+ .begin = begin,
+ .end = begin + len,
+ .pos = begin,
+ .last = begin,
+ };
}
void ngtcp2_buf_reset(ngtcp2_buf *buf) { buf->pos = buf->last = buf->begin; }
y <<= 1;
b = 3 * y * (y + 1) + 1;
if (n >= b) {
- n -= b;
y++;
}
* @functypedef
*
* :type:`ngtcp2_cc_on_pkt_sent` is a callback function which is
- * called when an ack-eliciting packet is sent.
+ * called when an ack-eliciting packet is sent. The lost,
+ * tx_in_flight, and is_app_limited fields in |pkt| are set to 0.
*/
typedef void (*ngtcp2_cc_on_pkt_sent)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt);
-/**
- * @functypedef
- *
- * :type:`ngtcp2_cc_new_rtt_sample` is a callback function which is
- * called when new RTT sample is obtained.
- */
-typedef void (*ngtcp2_cc_new_rtt_sample)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
- ngtcp2_tstamp ts);
-
/**
* @functypedef
*
typedef void (*ngtcp2_cc_reset)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
-/**
- * @enum
- *
- * :type:`ngtcp2_cc_event_type` defines congestion control events.
- */
-typedef enum ngtcp2_cc_event_type {
- /**
- * :enum:`NGTCP2_CC_EVENT_TX_START` occurs when ack-eliciting packet
- * is sent and no other ack-eliciting packet is present.
- */
- NGTCP2_CC_EVENT_TYPE_TX_START
-} ngtcp2_cc_event_type;
-
-/**
- * @functypedef
- *
- * :type:`ngtcp2_cc_event` is a callback function which is called when
- * a specific event happens.
- */
-typedef void (*ngtcp2_cc_event)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
- ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
-
/**
* @struct
*
* ack-eliciting packet is sent.
*/
ngtcp2_cc_on_pkt_sent on_pkt_sent;
- /**
- * :member:`new_rtt_sample` is a callback function which is called
- * when new RTT sample is obtained.
- */
- ngtcp2_cc_new_rtt_sample new_rtt_sample;
/**
* :member:`reset` is a callback function which is called when
* congestion control state must be reset.
*/
ngtcp2_cc_reset reset;
- /**
- * :member:`event` is a callback function which is called when a
- * specific event happens.
- */
- ngtcp2_cc_event event;
} ngtcp2_cc;
/*
int ngtcp2_cid_empty(const ngtcp2_cid *cid) { return cid->datalen == 0; }
void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid) {
- scid->pe.index = NGTCP2_PQ_BAD_INDEX;
- scid->seq = seq;
- scid->cid = *cid;
- scid->retired_ts = UINT64_MAX;
- scid->flags = NGTCP2_SCID_FLAG_NONE;
+ *scid = (ngtcp2_scid){
+ .pe.index = NGTCP2_PQ_BAD_INDEX,
+ .seq = seq,
+ .cid = *cid,
+ .retired_ts = UINT64_MAX,
+ .flags = NGTCP2_SCID_FLAG_NONE,
+ };
}
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
return 0;
}
-// pktns_init initializes |pktns|. It assumes that the object pointed
-// by |pktns| is zero-cleared.
+/*
+ * pktns_init initializes |pktns|. It assumes that the object pointed
+ * by |pktns| is zero-cleared.
+ */
static void pktns_init(ngtcp2_pktns *pktns, ngtcp2_pktns_id pktns_id,
ngtcp2_rst *rst, ngtcp2_cc *cc, int64_t initial_pkt_num,
ngtcp2_log *log, ngtcp2_qlog *qlog,
fail_token:
ngtcp2_mem_free(mem, *pconn);
+ *pconn = NULL;
+
return rv;
}
rv = ngtcp2_conn_commit_local_transport_params(*pconn);
if (rv != 0) {
ngtcp2_conn_del(*pconn);
+ *pconn = NULL;
+
return rv;
}
static int conn_on_pkt_sent(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
ngtcp2_rtb_entry *ent) {
ngtcp2_rtb *rtb = &pktns->rtb;
+ ngtcp2_cc_pkt cc_pkt;
int rv;
+ if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
+ conn->cc.on_pkt_sent) {
+ conn->cc.on_pkt_sent(
+ &conn->cc, &conn->cstat,
+ ngtcp2_cc_pkt_init(&cc_pkt, ent->hd.pkt_num, ent->pktlen, pktns->id,
+ ent->ts, /* lost = */ 0,
+ /* tx_in_flight = */ 0, /* is_app_limited = */ 0));
+ }
+
/* This function implements OnPacketSent, but it handles only
non-ACK-only packet. */
rv = ngtcp2_rtb_add(rtb, ent, &conn->cstat);
return 1;
}
+ /* We might send Handshake packet even if exceeding CWND. In that
+ case, we do not write non-probe 1RTT packet. */
+ if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
+ return 1;
+ }
+
min_payloadlen = NGTCP2_MIN_COALESCED_PAYLOADLEN;
}
}
/* ngtcp2_frame_chain for the removed data */
- removed_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
- removed_frc->fr.stream.offset = (*pfrc)->fr.stream.offset + offset;
- removed_frc->fr.stream.datacnt = 1;
- removed_frc->fr.stream.data[0] = (ngtcp2_vec){
- .base = data->base + offset,
- .len = removed_data->len,
+ removed_frc->fr.stream = (ngtcp2_stream){
+ .type = NGTCP2_FRAME_CRYPTO,
+ .offset = (*pfrc)->fr.stream.offset + offset,
+ .datacnt = 1,
+ .data[0] =
+ {
+ .base = data->base + offset,
+ .len = removed_data->len,
+ },
};
rv = ngtcp2_strm_streamfrq_push(crypto_strm, removed_frc);
return rv;
}
- left_frc->fr.stream.type = NGTCP2_FRAME_CRYPTO;
- left_frc->fr.stream.offset = (*pfrc)->fr.stream.offset;
- left_frc->fr.stream.datacnt = 1;
- left_frc->fr.stream.data[0] = (ngtcp2_vec){
- .base = data[0].base,
- .len = offset,
+ left_frc->fr.stream = (ngtcp2_stream){
+ .type = NGTCP2_FRAME_CRYPTO,
+ .offset = (*pfrc)->fr.stream.offset,
+ .datacnt = 1,
+ .data[0] =
+ {
+ .base = data[0].base,
+ .len = offset,
+ },
};
left_frc->next = right_frc;
dest += nwrite;
destlen -= (size_t)nwrite;
- /* If initial packet size is at least
- NGTCP2_MAX_UDP_PAYLOAD_SIZE, no extra padding is needed in a
- subsequent packet. */
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE) {
- if (conn->server) {
- it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
- if (!ngtcp2_ksl_it_end(&it)) {
- rtbent = ngtcp2_ksl_it_get(&it);
- if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
+ if (conn->server) {
+ it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
+ if (!ngtcp2_ksl_it_end(&it)) {
+ rtbent = ngtcp2_ksl_it_get(&it);
+ if (rtbent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
}
- } else {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
}
+ } else {
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
}
}
}
size_t min_pktlen = conn_min_pktlen(conn);
int min_padded = 0;
int padded = 0;
- ngtcp2_cc_pkt cc_pkt;
uint64_t crypto_offset;
uint64_t stream_offset;
ngtcp2_ssize num_reclaimed;
conn->tx.last_max_data_ts = ts;
- nfrc->fr.type = NGTCP2_FRAME_MAX_DATA;
- nfrc->fr.max_data.max_data = conn->rx.unsent_max_offset + delta;
+ nfrc->fr.max_data = (ngtcp2_max_data){
+ .type = NGTCP2_FRAME_MAX_DATA,
+ .max_data = conn->rx.unsent_max_offset + delta,
+ };
nfrc->next = pktns->tx.frq;
pktns->tx.frq = nfrc;
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_RESET_STREAM;
- nfrc->fr.reset_stream.stream_id = strm->stream_id;
- nfrc->fr.reset_stream.app_error_code =
- strm->tx.reset_stream_app_error_code;
- nfrc->fr.reset_stream.final_size = strm->tx.offset;
+ nfrc->fr.reset_stream = (ngtcp2_reset_stream){
+ .type = NGTCP2_FRAME_RESET_STREAM,
+ .stream_id = strm->stream_id,
+ .app_error_code = strm->tx.reset_stream_app_error_code,
+ .final_size = strm->tx.offset,
+ };
*pfrc = nfrc;
strm->flags &= ~NGTCP2_STRM_FLAG_SEND_RESET_STREAM;
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_STOP_SENDING;
- nfrc->fr.stop_sending.stream_id = strm->stream_id;
- nfrc->fr.stop_sending.app_error_code =
- strm->tx.stop_sending_app_error_code;
+ nfrc->fr.stop_sending = (ngtcp2_stop_sending){
+ .type = NGTCP2_FRAME_STOP_SENDING,
+ .stream_id = strm->stream_id,
+ .app_error_code = strm->tx.stop_sending_app_error_code,
+ };
*pfrc = nfrc;
strm->flags &= ~NGTCP2_STRM_FLAG_SEND_STOP_SENDING;
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
+ nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
+ .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
+ .stream_id = strm->stream_id,
+ .offset = strm->tx.max_offset,
+ };
*pfrc = nfrc;
strm->tx.last_blocked_offset = strm->tx.max_offset;
strm->tx.last_max_stream_data_ts = ts;
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAM_DATA;
- nfrc->fr.max_stream_data.stream_id = strm->stream_id;
- nfrc->fr.max_stream_data.max_stream_data =
- strm->rx.unsent_max_offset + delta;
+ nfrc->fr.max_stream_data = (ngtcp2_max_stream_data){
+ .type = NGTCP2_FRAME_MAX_STREAM_DATA,
+ .stream_id = strm->stream_id,
+ .max_stream_data = strm->rx.unsent_max_offset + delta,
+ };
*pfrc = nfrc;
strm->rx.max_offset = strm->rx.unsent_max_offset =
assert(ngtcp2_err_is_fatal(rv));
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_BIDI;
- nfrc->fr.max_streams.max_streams = conn->remote.bidi.unsent_max_streams;
+ nfrc->fr.max_streams = (ngtcp2_max_streams){
+ .type = NGTCP2_FRAME_MAX_STREAMS_BIDI,
+ .max_streams = conn->remote.bidi.unsent_max_streams,
+ };
*pfrc = nfrc;
conn->remote.bidi.max_streams = conn->remote.bidi.unsent_max_streams;
assert(ngtcp2_err_is_fatal(rv));
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_MAX_STREAMS_UNI;
- nfrc->fr.max_streams.max_streams = conn->remote.uni.unsent_max_streams;
+ nfrc->fr.max_streams = (ngtcp2_max_streams){
+ .type = NGTCP2_FRAME_MAX_STREAMS_UNI,
+ .max_streams = conn->remote.uni.unsent_max_streams,
+ };
*pfrc = nfrc;
conn->remote.uni.max_streams = conn->remote.uni.unsent_max_streams;
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_DATA_BLOCKED;
- nfrc->fr.data_blocked.offset = conn->tx.offset;
+ nfrc->fr.data_blocked = (ngtcp2_data_blocked){
+ .type = NGTCP2_FRAME_DATA_BLOCKED,
+ .offset = conn->tx.offset,
+ };
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
if (rv != 0) {
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_STREAM_DATA_BLOCKED;
- nfrc->fr.stream_data_blocked.stream_id = strm->stream_id;
- nfrc->fr.stream_data_blocked.offset = strm->tx.max_offset;
+ nfrc->fr.stream_data_blocked = (ngtcp2_stream_data_blocked){
+ .type = NGTCP2_FRAME_STREAM_DATA_BLOCKED,
+ .stream_id = strm->stream_id,
+ .offset = strm->tx.max_offset,
+ };
rv = conn_ppe_write_frame_hd_log(conn, ppe, &hd_logged, hd, &nfrc->fr);
if (rv != 0) {
rtb_entry_flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING;
}
pktns->tx.non_ack_pkt_start_ts = UINT64_MAX;
- pkt_empty = 0;
}
} else if (pktns->tx.non_ack_pkt_start_ts == UINT64_MAX) {
pktns->tx.non_ack_pkt_start_ts = ts;
*pfrc = NULL;
}
- if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
- pktns->rtb.num_ack_eliciting == 0 && conn->cc.event) {
- conn->cc.event(&conn->cc, &conn->cstat, NGTCP2_CC_EVENT_TYPE_TX_START,
- ts);
- }
-
rv = conn_on_pkt_sent(conn, pktns, ent);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
return rv;
}
- if (rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) {
- if (conn->cc.on_pkt_sent) {
- conn->cc.on_pkt_sent(
- &conn->cc, &conn->cstat,
- ngtcp2_cc_pkt_init(&cc_pkt, hd->pkt_num, (size_t)nwrite,
- NGTCP2_PKTNS_ID_APPLICATION, ts, ent->rst.lost,
- ent->rst.tx_in_flight, ent->rst.is_app_limited));
- }
-
- if (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE) {
- conn_restart_timer_on_write(conn, ts);
- }
+ if ((rtb_entry_flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING) &&
+ (conn->flags & NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE)) {
+ conn_restart_timer_on_write(conn, ts);
}
} else if (pi && conn->tx.ecn.state == NGTCP2_ECN_STATE_CAPABLE) {
conn_handle_tx_ecn(conn, pi, NULL, pktns, hd, ts);
padded = 0;
}
+ break;
+ case NGTCP2_FRAME_CONNECTION_CLOSE:
+ case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
+ /* Clear padded so that we never store the terminal packet in
+ ngtcp2_rtb. */
+ padded = 0;
+
break;
}
return rv;
}
- nfrc->fr.type = NGTCP2_FRAME_RETIRE_CONNECTION_ID;
- nfrc->fr.retire_connection_id.seq = seq;
+ nfrc->fr.retire_connection_id = (ngtcp2_retire_connection_id){
+ .type = NGTCP2_FRAME_RETIRE_CONNECTION_ID,
+ .seq = seq,
+ };
nfrc->next = pktns->tx.frq;
pktns->tx.frq = nfrc;
ngtcp2_pktns *in_pktns = conn->in_pktns;
ngtcp2_rtb *rtb = &conn->pktns.rtb;
ngtcp2_rtb *in_rtb;
- uint8_t cidbuf[sizeof(retry.odcid.data) * 2 + 1];
+ char cidbuf[sizeof(retry.odcid.data) * 2 + 1];
uint8_t *token;
if (!in_pktns || (conn->flags & NGTCP2_CONN_FLAG_RECV_RETRY)) {
return rv;
}
- ngtcp2_log_infof(&conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
- (const char *)ngtcp2_encode_hex(cidbuf, retry.odcid.data,
- retry.odcid.datalen));
+ ngtcp2_log_infof(
+ &conn->log, NGTCP2_LOG_EVENT_PKT, "odcid=0x%s",
+ ngtcp2_encode_hex_cstr(cidbuf, retry.odcid.data, retry.odcid.datalen));
if (retry.tokenlen == 0) {
return NGTCP2_ERR_PROTO;
ngtcp2_pv *pv = NULL;
int rv;
ngtcp2_duration pto;
- int require_new_cid;
int local_addr_eq;
int pref_addr_migration;
uint32_t remote_addr_cmp;
* continue to use the current connection ID with the new remote
* address while still sending from the same local address.
*/
- require_new_cid = conn->dcid.current.cid.datalen &&
- ((new_cid_used && remote_addr_cmp) || !local_addr_eq);
-
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
"non-probing packet was received from new remote address");
ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON,
"Found DCID which has already been bound to the new path");
- require_new_cid = 0;
-
if (dcid.cid.datalen) {
rv = conn_call_activate_dcid(conn, &dcid);
if (rv != 0) {
}
}
} else {
- if (require_new_cid) {
+ if (conn->dcid.current.cid.datalen &&
+ ((new_cid_used && remote_addr_cmp) || !local_addr_eq)) {
+ /* New DCID is required. */
if (ngtcp2_dcidtr_unused_empty(&conn->dcid.dtr)) {
return NGTCP2_ERR_CONN_ID_BLOCKED;
}
}
res += nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
}
if (res == 0) {
}
res += nwrite;
- dest += nwrite;
- origlen -= (size_t)nwrite;
}
return res;
rv = ngtcp2_crypto_km_new(&pktns->crypto.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
conn->mem);
if (rv != 0) {
+ ngtcp2_crypto_km_del(pktns->crypto.rx.ckm, conn->mem);
+ pktns->crypto.rx.ckm = NULL;
+
return rv;
}
rv = ngtcp2_crypto_km_new(&conn->vneg.tx.ckm, NULL, 0, NULL, tx_iv, ivlen,
conn->mem);
if (rv != 0) {
+ ngtcp2_crypto_km_del(conn->vneg.rx.ckm, conn->mem);
+ conn->vneg.rx.ckm = NULL;
+
return rv;
}
if (conn->server) {
rv = ngtcp2_conn_commit_local_transport_params(conn);
if (rv != 0) {
- return rv;
+ goto fail;
}
}
rv = conn_call_recv_tx_key(conn, NGTCP2_ENCRYPTION_LEVEL_HANDSHAKE);
if (rv != 0) {
- ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
- pktns->crypto.tx.ckm = NULL;
-
- memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
-
- return rv;
+ goto fail;
}
return 0;
+
+fail:
+ /* If this function fails, aead_ctx and hp_ctx are still owned by
+ the caller. Delete the install key to remove the any reference
+ to them. */
+ ngtcp2_crypto_km_del(pktns->crypto.tx.ckm, conn->mem);
+ pktns->crypto.tx.ckm = NULL;
+
+ memset(&pktns->crypto.tx.hp_ctx, 0, sizeof(pktns->crypto.tx.hp_ctx));
+
+ return rv;
}
int ngtcp2_conn_install_0rtt_key(ngtcp2_conn *conn,
packet is produced, if it is set, we are sure that we
are not app-limited. */
!(conn->flags & NGTCP2_CONN_FLAG_AGGREGATE_PKTS)) {
- conn->rst.app_limited = conn->rst.delivered + cstat->bytes_in_flight;
-
- if (conn->rst.app_limited == 0) {
- conn->rst.app_limited = cstat->max_tx_udp_payload_size;
- }
+ conn->rst.app_limited =
+ ngtcp2_max_uint64(conn->rst.delivered + cstat->bytes_in_flight, 1);
}
return nwrite;
conn_client_write_handshake(conn, pi, dest, destlen, wflags, vmsg, ts);
/* We might be unable to write a packet because of depletion of
congestion window budget, perhaps due to packet loss that
- shrinks the window drastically. */
- if (nwrite <= 0) {
+ shrinks the window drastically. Then continue if we are in
+ post-handshake. There, we might be able to write packets
+ exceeding CWND to avoid deadlock. */
+ if (nwrite < 0) {
return nwrite;
}
if (conn->state != NGTCP2_CS_POST_HANDSHAKE) {
return nwrite;
}
- assert(nwrite);
- assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
- assert(conn->negotiated_version);
+ if (nwrite) {
+ assert(dest[0] & NGTCP2_HEADER_FORM_BIT);
+ assert(conn->negotiated_version);
- if (nwrite < NGTCP2_MAX_UDP_PAYLOAD_SIZE &&
- ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
+ if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
NGTCP2_PKT_INITIAL) {
- wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
- }
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
+ }
- res = nwrite;
- dest += nwrite;
- destlen -= (size_t)nwrite;
+ res = nwrite;
+ dest += nwrite;
+ destlen -= (size_t)nwrite;
+ }
/* Break here so that we can coalesces 1RTT packet. */
break;
case NGTCP2_CS_SERVER_INITIAL:
dest += nwrite;
destlen -= (size_t)nwrite;
- if (res < NGTCP2_MAX_UDP_PAYLOAD_SIZE && conn->in_pktns && nwrite > 0) {
+ if (conn->in_pktns && nwrite > 0) {
it = ngtcp2_rtb_head(&conn->in_pktns->rtb);
if (!ngtcp2_ksl_it_end(&it)) {
rtbent = ngtcp2_ksl_it_get(&it);
return nwrite;
}
if (nwrite > 0) {
+ /* This makes 1RTT packet padded. If 1RTT packet is not going
+ to be sent, packet is already padded. */
+ if (ngtcp2_pkt_get_type_long(conn->negotiated_version, dest[0]) ==
+ NGTCP2_PKT_INITIAL) {
+ wflags |= NGTCP2_WRITE_PKT_FLAG_REQUIRE_PADDING;
+ }
+
res = nwrite;
dest += nwrite;
destlen -= (size_t)nwrite;
+
+ /* We only exceed CWND to avoid deadlock. Do no write 1RTT
+ packet if CWND is depleted. */
+ if (conn_cwnd_is_zero(conn) && conn->pktns.rtb.probe_pkt_left == 0) {
+ goto fin;
+ }
} else if (destlen == 0) {
res = conn_write_handshake_ack_pkts(conn, pi, dest, origlen, ts);
if (res) {
ngtcp2_frame fr;
uint8_t flags = NGTCP2_WRITE_PKT_FLAG_NONE;
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE;
- fr.connection_close.error_code = error_code;
- fr.connection_close.frame_type = 0;
- fr.connection_close.reasonlen = reasonlen;
- fr.connection_close.reason = (uint8_t *)reason;
+ fr.connection_close = (ngtcp2_connection_close){
+ .type = NGTCP2_FRAME_CONNECTION_CLOSE,
+ .error_code = error_code,
+ .reasonlen = reasonlen,
+ .reason = (uint8_t *)reason,
+ };
if (!(conn->flags & NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED) &&
pkt_type != NGTCP2_PKT_INITIAL) {
assert(conn->pktns.crypto.tx.ckm);
- fr.type = NGTCP2_FRAME_CONNECTION_CLOSE_APP;
- fr.connection_close.error_code = app_error_code;
- fr.connection_close.frame_type = 0;
- fr.connection_close.reasonlen = reasonlen;
- fr.connection_close.reason = (uint8_t *)reason;
+ fr.connection_close = (ngtcp2_connection_close){
+ .type = NGTCP2_FRAME_CONNECTION_CLOSE_APP,
+ .error_code = app_error_code,
+ .reasonlen = reasonlen,
+ .reason = (uint8_t *)reason,
+ };
nwrite = ngtcp2_conn_write_single_frame_pkt(
conn, pi, dest, destlen, NGTCP2_PKT_1RTT, NGTCP2_WRITE_PKT_FLAG_NONE,
static void ccerr_init(ngtcp2_ccerr *ccerr, ngtcp2_ccerr_type type,
uint64_t error_code, const uint8_t *reason,
size_t reasonlen) {
- ccerr->type = type;
- ccerr->error_code = error_code;
- ccerr->frame_type = 0;
- ccerr->reason = (uint8_t *)reason;
- ccerr->reasonlen = reasonlen;
+ *ccerr = (ngtcp2_ccerr){
+ .type = type,
+ .error_code = error_code,
+ .reason = (uint8_t *)reason,
+ .reasonlen = reasonlen,
+ };
}
void ngtcp2_ccerr_default(ngtcp2_ccerr *ccerr) {
return (conn->flags & NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED) != 0;
}
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
- ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
+void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
+ ngtcp2_duration ack_delay, ngtcp2_tstamp ts) {
ngtcp2_conn_stat *cstat = &conn->cstat;
assert(rtt > 0);
" min_rtt=%" PRIu64 " ack_delay=%" PRIu64,
rtt / NGTCP2_MILLISECONDS, cstat->min_rtt / NGTCP2_MILLISECONDS,
ack_delay / NGTCP2_MILLISECONDS);
- return NGTCP2_ERR_INVALID_ARGUMENT;
+ return;
}
cstat->latest_rtt = rtt;
cstat->min_rtt / NGTCP2_MILLISECONDS,
cstat->smoothed_rtt / NGTCP2_MILLISECONDS,
cstat->rttvar / NGTCP2_MILLISECONDS, ack_delay / NGTCP2_MILLISECONDS);
-
- return 0;
}
void ngtcp2_conn_get_conn_info_versioned(ngtcp2_conn *conn,
const uint8_t *data, const size_t datalen) {
ngtcp2_pktns *pktns;
ngtcp2_frame_chain *frc;
- ngtcp2_stream *fr;
int rv;
if (datalen == 0) {
return rv;
}
- fr = &frc->fr.stream;
-
- fr->type = NGTCP2_FRAME_CRYPTO;
- fr->flags = 0;
- fr->fin = 0;
- fr->stream_id = 0;
- fr->offset = pktns->crypto.tx.offset;
- fr->datacnt = 1;
- fr->data[0].len = datalen;
- fr->data[0].base = (uint8_t *)data;
+ frc->fr.stream = (ngtcp2_stream){
+ .type = NGTCP2_FRAME_CRYPTO,
+ .offset = pktns->crypto.tx.offset,
+ .datacnt = 1,
+ .data[0] =
+ {
+ .base = (uint8_t *)data,
+ .len = datalen,
+ },
+ };
rv = ngtcp2_strm_streamfrq_push(&pktns->crypto.strm, frc);
if (rv != 0) {
* ack_delay included in ACK frame. |ack_delay| is actually tainted
* (sent by peer), so don't assume that |ack_delay| is always smaller
* than, or equals to |rtt|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGTCP2_ERR_INVALID_ARGUMENT
- * RTT sample is ignored.
*/
-int ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
- ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
+void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
+ ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts);
}
p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
- (*pckm)->secret.base = p;
- (*pckm)->secret.len = secretlen;
- p += secretlen;
- (*pckm)->iv.base = p;
- (*pckm)->iv.len = ivlen;
- (*pckm)->aead_ctx.native_handle = NULL;
- (*pckm)->pkt_num = -1;
- (*pckm)->use_count = 0;
- (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
+
+ **pckm = (ngtcp2_crypto_km){
+ .secret =
+ {
+ .base = p,
+ .len = secretlen,
+ },
+ .iv =
+ {
+ .base = p + secretlen,
+ .len = ivlen,
+ },
+ .pkt_num = -1,
+ .flags = NGTCP2_CRYPTO_KM_FLAG_NONE,
+ };
return 0;
}
ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent)
-static size_t ksl_nodelen(size_t keylen) {
- assert(keylen >= sizeof(uint64_t));
-
- return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0x7u) &
- ~(uintptr_t)0x7u;
-}
-
-static size_t ksl_blklen(size_t nodelen) {
- return sizeof(ngtcp2_ksl_blk) + nodelen * NGTCP2_KSL_MAX_NBLK -
+static size_t ksl_blklen(size_t aligned_keylen) {
+ return sizeof(ngtcp2_ksl_blk) + NGTCP2_KSL_MAX_NBLK * aligned_keylen -
sizeof(uint64_t);
}
/*
- * ksl_node_set_key sets |key| to |node|.
+ * ksl_set_nth_key sets |key| to |n|th node under |blk|.
*/
-static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node,
- const void *key) {
- memcpy(node->key, key, ksl->keylen);
+static void ksl_set_nth_key(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
+ size_t n, const ngtcp2_ksl_key *key) {
+ memcpy(blk->keys + n * ksl->aligned_keylen, key, ksl->keylen);
}
void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar,
ngtcp2_ksl_search search, size_t keylen,
const ngtcp2_mem *mem) {
- size_t nodelen = ksl_nodelen(keylen);
+ size_t aligned_keylen;
+
+ assert(keylen >= sizeof(uint64_t));
+
+ aligned_keylen = (keylen + 0x7u) & ~0x7u;
ngtcp2_objalloc_init(&ksl->blkalloc,
- (ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu, mem);
+ (ksl_blklen(aligned_keylen) + 0xfu) & ~(uintptr_t)0xfu,
+ mem);
ksl->head = NULL;
ksl->front = ksl->back = NULL;
ksl->search = search;
ksl->n = 0;
ksl->keylen = keylen;
- ksl->nodelen = nodelen;
+ ksl->aligned_keylen = aligned_keylen;
}
static ngtcp2_ksl_blk *ksl_blk_objalloc_new(ngtcp2_ksl *ksl) {
return ngtcp2_objalloc_ksl_blk_len_get(&ksl->blkalloc,
- ksl_blklen(ksl->nodelen));
+ ksl_blklen(ksl->aligned_keylen));
}
static void ksl_blk_objalloc_del(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
if (!blk->leaf) {
for (i = 0; i < blk->n; ++i) {
- ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk);
+ ksl_free_blk(ksl, blk->nodes[i].blk);
}
}
rblk->n = blk->n / 2;
blk->n -= rblk->n;
- memcpy(rblk->nodes, blk->nodes + ksl->nodelen * blk->n,
- ksl->nodelen * rblk->n);
+ memcpy(rblk->nodes, blk->nodes + blk->n, rblk->n * sizeof(ngtcp2_ksl_node));
+
+ memcpy(rblk->keys, blk->keys + blk->n * ksl->aligned_keylen,
+ rblk->n * ksl->aligned_keylen);
assert(blk->n >= NGTCP2_KSL_MIN_NBLK);
assert(rblk->n >= NGTCP2_KSL_MIN_NBLK);
* Out of memory.
*/
static int ksl_split_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
- ngtcp2_ksl_node *node;
- ngtcp2_ksl_blk *lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
+ ngtcp2_ksl_blk *lblk = blk->nodes[i].blk, *rblk;
rblk = ksl_split_blk(ksl, lblk);
if (rblk == NULL) {
return NGTCP2_ERR_NOMEM;
}
- memmove(blk->nodes + (i + 2) * ksl->nodelen,
- blk->nodes + (i + 1) * ksl->nodelen,
- ksl->nodelen * (blk->n - (i + 1)));
+ memmove(blk->nodes + (i + 2), blk->nodes + (i + 1),
+ (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
- node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
- node->blk = rblk;
+ memmove(blk->keys + (i + 2) * ksl->aligned_keylen,
+ blk->keys + (i + 1) * ksl->aligned_keylen,
+ (blk->n - (i + 1)) * ksl->aligned_keylen);
+
+ blk->nodes[i + 1].blk = rblk;
++blk->n;
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
+ ksl_set_nth_key(ksl, blk, i + 1, ngtcp2_ksl_nth_key(ksl, rblk, rblk->n - 1));
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_nth_key(ksl, lblk, lblk->n - 1));
return 0;
}
*/
static int ksl_split_head(ngtcp2_ksl *ksl) {
ngtcp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
- ngtcp2_ksl_node *node;
rblk = ksl_split_blk(ksl, ksl->head);
if (rblk == NULL) {
nhead->n = 2;
nhead->leaf = 0;
- node = ngtcp2_ksl_nth_node(ksl, nhead, 0);
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
- node->blk = lblk;
+ ksl_set_nth_key(ksl, nhead, 0, ngtcp2_ksl_nth_key(ksl, lblk, lblk->n - 1));
+ nhead->nodes[0].blk = lblk;
- node = ngtcp2_ksl_nth_node(ksl, nhead, 1);
- ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
- node->blk = rblk;
+ ksl_set_nth_key(ksl, nhead, 1, ngtcp2_ksl_nth_key(ksl, rblk, rblk->n - 1));
+ nhead->nodes[1].blk = rblk;
ksl->head = nhead;
*/
static void ksl_insert_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i,
const ngtcp2_ksl_key *key, void *data) {
- ngtcp2_ksl_node *node;
-
assert(blk->n < NGTCP2_KSL_MAX_NBLK);
- memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
- ksl->nodelen * (blk->n - i));
+ memmove(blk->nodes + (i + 1), blk->nodes + i,
+ (blk->n - i) * sizeof(ngtcp2_ksl_node));
+
+ memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
+ blk->keys + i * ksl->aligned_keylen,
+ (blk->n - i) * ksl->aligned_keylen);
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
- ksl_node_set_key(ksl, node, key);
- node->data = data;
+ ksl_set_nth_key(ksl, blk, i, key);
+ blk->nodes[i].data = data;
++blk->n;
}
i = ksl->search(ksl, blk, key);
if (blk->leaf) {
- if (i < blk->n &&
- !ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+ if (i < blk->n && !ksl->compar(key, ngtcp2_ksl_nth_key(ksl, blk, i))) {
if (it) {
*it = ngtcp2_ksl_end(ksl);
}
if (i == blk->n) {
/* This insertion extends the largest key in this subtree. */
for (; !blk->leaf;) {
- node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
+ node = &blk->nodes[blk->n - 1];
if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, blk->n - 1);
if (rv != 0) {
return rv;
}
- node = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1);
+ node = &blk->nodes[blk->n - 1];
}
- ksl_node_set_key(ksl, node, key);
+ ksl_set_nth_key(ksl, blk, blk->n - 1, key);
blk = node->blk;
}
return 0;
}
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
+ node = &blk->nodes[i];
if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, i);
return rv;
}
- if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
- node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
+ if (ksl->compar(ngtcp2_ksl_nth_key(ksl, blk, i), key)) {
+ node = &blk->nodes[i + 1];
- if (ksl->compar((ngtcp2_ksl_key *)node->key, key)) {
- ksl_node_set_key(ksl, node, key);
+ if (ksl->compar(ngtcp2_ksl_nth_key(ksl, blk, i + 1), key)) {
+ ksl_set_nth_key(ksl, blk, i + 1, key);
}
}
}
* |i|.
*/
static void ksl_remove_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
- memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
- ksl->nodelen * (blk->n - (i + 1)));
+ memmove(blk->nodes + i, blk->nodes + (i + 1),
+ (blk->n - (i + 1)) * sizeof(ngtcp2_ksl_node));
+
+ memmove(blk->keys + i * ksl->aligned_keylen,
+ blk->keys + (i + 1) * ksl->aligned_keylen,
+ (blk->n - (i + 1)) * ksl->aligned_keylen);
--blk->n;
}
assert(i + 1 < blk->n);
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
+ lnode = &blk->nodes[i];
lblk = lnode->blk;
- rblk = ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk;
+ rblk = blk->nodes[i + 1].blk;
assert(lblk->n + rblk->n < NGTCP2_KSL_MAX_NBLK);
- memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
- ksl->nodelen * rblk->n);
+ memcpy(lblk->nodes + lblk->n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
+
+ memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
+ rblk->n * ksl->aligned_keylen);
lblk->n += rblk->n;
lblk->next = rblk->next;
ksl->head = lblk;
} else {
ksl_remove_node(ksl, blk, i + 1);
- ksl_node_set_key(ksl, lnode,
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_nth_key(ksl, lblk, lblk->n - 1));
}
return lblk;
assert(i > 0);
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i - 1);
- rnode = ngtcp2_ksl_nth_node(ksl, blk, i);
+ lnode = &blk->nodes[i - 1];
+ rnode = &blk->nodes[i];
lblk = lnode->blk;
rblk = rnode->blk;
assert(lblk->n <= NGTCP2_KSL_MAX_NBLK - n);
assert(rblk->n >= NGTCP2_KSL_MIN_NBLK + n);
- memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes, ksl->nodelen * n);
+ memcpy(lblk->nodes + lblk->n, rblk->nodes, n * sizeof(ngtcp2_ksl_node));
+
+ memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
+ n * ksl->aligned_keylen);
lblk->n += (uint32_t)n;
rblk->n -= (uint32_t)n;
- ksl_node_set_key(ksl, lnode,
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+ ksl_set_nth_key(ksl, blk, i - 1, ngtcp2_ksl_nth_key(ksl, lblk, lblk->n - 1));
+
+ memmove(rblk->nodes, rblk->nodes + n, rblk->n * sizeof(ngtcp2_ksl_node));
- memmove(rblk->nodes, rblk->nodes + ksl->nodelen * n, ksl->nodelen * rblk->n);
+ memmove(rblk->keys, rblk->keys + n * ksl->aligned_keylen,
+ rblk->n * ksl->aligned_keylen);
}
/*
assert(i < blk->n - 1);
- lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
- rnode = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
+ lnode = &blk->nodes[i];
+ rnode = &blk->nodes[i + 1];
lblk = lnode->blk;
rblk = rnode->blk;
assert(lblk->n >= NGTCP2_KSL_MIN_NBLK + n);
assert(rblk->n <= NGTCP2_KSL_MAX_NBLK - n);
- memmove(rblk->nodes + ksl->nodelen * n, rblk->nodes, ksl->nodelen * rblk->n);
+ memmove(rblk->nodes + n, rblk->nodes, rblk->n * sizeof(ngtcp2_ksl_node));
+
+ memmove(rblk->keys + n * ksl->aligned_keylen, rblk->keys,
+ rblk->n * ksl->aligned_keylen);
rblk->n += (uint32_t)n;
lblk->n -= (uint32_t)n;
- memcpy(rblk->nodes, lblk->nodes + ksl->nodelen * lblk->n, ksl->nodelen * n);
+ memcpy(rblk->nodes, lblk->nodes + lblk->n, n * sizeof(ngtcp2_ksl_node));
- ksl_node_set_key(ksl, lnode,
- ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
+ memcpy(rblk->keys, lblk->keys + lblk->n * ksl->aligned_keylen,
+ n * ksl->aligned_keylen);
+
+ ksl_set_nth_key(ksl, blk, i, ngtcp2_ksl_nth_key(ksl, lblk, lblk->n - 1));
}
/*
}
if (!blk->leaf && blk->n == 2 &&
- ngtcp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGTCP2_KSL_MIN_NBLK &&
- ngtcp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGTCP2_KSL_MIN_NBLK) {
+ blk->nodes[0].blk->n == NGTCP2_KSL_MIN_NBLK &&
+ blk->nodes[1].blk->n == NGTCP2_KSL_MIN_NBLK) {
blk = ksl_merge_node(ksl, blk, 0);
}
}
if (blk->leaf) {
- if (ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
+ if (ksl->compar(key, ngtcp2_ksl_nth_key(ksl, blk, i))) {
if (it) {
*it = ngtcp2_ksl_end(ksl);
}
return 0;
}
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
+ node = &blk->nodes[i];
if (node->blk->n > NGTCP2_KSL_MIN_NBLK) {
blk = node->blk;
assert(node->blk->n == NGTCP2_KSL_MIN_NBLK);
- if (i + 1 < blk->n &&
- ngtcp2_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
+ if (i + 1 < blk->n && blk->nodes[i + 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
ksl_shift_left(ksl, blk, i + 1);
blk = node->blk;
continue;
}
- if (i > 0 &&
- ngtcp2_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGTCP2_KSL_MIN_NBLK) {
+ if (i > 0 && blk->nodes[i - 1].blk->n > NGTCP2_KSL_MIN_NBLK) {
ksl_shift_right(ksl, blk, i - 1);
blk = node->blk;
if (i == blk->n) {
/* This happens if descendant has smaller key. Fast forward to
find last node in this subtree. */
- for (; !blk->leaf; blk = ngtcp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
+ for (; !blk->leaf; blk = blk->nodes[blk->n - 1].blk)
;
if (blk->next) {
return it;
}
- blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
+ blk = blk->nodes[i].blk;
}
}
const ngtcp2_ksl_key *new_key) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_node *node;
+ const ngtcp2_ksl_key *node_key;
size_t i;
assert(ksl->head);
i = ksl->search(ksl, blk, old_key);
assert(i < blk->n);
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
+ node = &blk->nodes[i];
+ node_key = ngtcp2_ksl_nth_key(ksl, blk, i);
if (blk->leaf) {
- assert(key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key));
- ksl_node_set_key(ksl, node, new_key);
+ assert(key_equal(ksl->compar, node_key, old_key));
+ ksl_set_nth_key(ksl, blk, i, new_key);
return;
}
- if (key_equal(ksl->compar, (ngtcp2_ksl_key *)node->key, old_key) ||
- ksl->compar((ngtcp2_ksl_key *)node->key, new_key)) {
- ksl_node_set_key(ksl, node, new_key);
+ if (key_equal(ksl->compar, node_key, old_key) ||
+ ksl->compar(node_key, new_key)) {
+ ksl_set_nth_key(ksl, blk, i, new_key);
}
blk = node->blk;
static void ksl_print(const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
size_t level) {
size_t i;
- ngtcp2_ksl_node *node;
fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
if (blk->leaf) {
for (i = 0; i < blk->n; ++i) {
- node = ngtcp2_ksl_nth_node(ksl, blk, i);
- fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
+ fprintf(stderr, " %" PRId64, *(int64_t *)ngtcp2_ksl_nth_key(ksl, blk, i));
}
fprintf(stderr, "\n");
}
for (i = 0; i < blk->n; ++i) {
- ksl_print(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
+ ksl_print(ksl, blk->nodes[i].blk, level + 1);
}
}
/*
* ngtcp2_ksl_node is a node which contains either ngtcp2_ksl_blk or
* opaque data. If a node is an internal node, it contains
- * ngtcp2_ksl_blk. Otherwise, it has data. The key is stored at the
- * location starting at key.
+ * ngtcp2_ksl_blk. Otherwise, it has data.
*/
struct ngtcp2_ksl_node {
union {
ngtcp2_ksl_blk *blk;
void *data;
};
- union {
- uint64_t align;
- /* key is a buffer to include key associated to this node.
- Because the length of key is unknown until ngtcp2_ksl_init is
- called, the actual buffer will be allocated after this
- field. */
- uint8_t key[1];
- };
};
/*
uint32_t n;
/* leaf is nonzero if this block contains leaf nodes. */
uint32_t leaf;
+ ngtcp2_ksl_node nodes[NGTCP2_KSL_MAX_NBLK];
union {
uint64_t align;
- /* nodes is a buffer to contain NGTCP2_KSL_MAX_NBLK
- ngtcp2_ksl_node objects. Because ngtcp2_ksl_node object is
- allocated along with the additional variable length key
- storage, the size of buffer is unknown until ngtcp2_ksl_init is
- called. */
- uint8_t nodes[1];
+ /* keys is a buffer to include NGTCP2_KSL_MAX_NBLK keys.
+ Because the length of key is unknown until ngtcp2_ksl_init
+ is called, the actual buffer will be allocated after this
+ field. */
+ uint8_t keys[1];
};
};
static size_t ksl_##NAME##_search( \
const ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, const ngtcp2_ksl_key *key) { \
size_t i; \
- ngtcp2_ksl_node *node; \
+ uint8_t *node_key; \
\
- for (i = 0, node = (ngtcp2_ksl_node *)(void *)blk->nodes; \
- i < blk->n && COMPAR((ngtcp2_ksl_key *)node->key, key); ++i, \
- node = (ngtcp2_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \
+ for (i = 0, node_key = blk->keys; i < blk->n && COMPAR(node_key, key); \
+ ++i, node_key += ksl->aligned_keylen) \
; \
\
return i; \
size_t n;
/* keylen is the size of key */
size_t keylen;
- /* nodelen is the actual size of ngtcp2_ksl_node including key
- storage. */
- size_t nodelen;
+ size_t aligned_keylen;
};
/*
void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
/*
- * ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
+ * ngtcp2_ksl_nth_key returns the |n|th key under |blk|.
*/
-static inline ngtcp2_ksl_node *ngtcp2_ksl_nth_node(const ngtcp2_ksl *ksl,
- const ngtcp2_ksl_blk *blk,
- size_t n) {
- return (ngtcp2_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n);
+static inline const ngtcp2_ksl_key *
+ngtcp2_ksl_nth_key(const ngtcp2_ksl *ksl, const ngtcp2_ksl_blk *blk, size_t n) {
+ return blk->keys + n * ksl->aligned_keylen;
}
#ifndef WIN32
* ngtcp2_ksl_it_end(it) returns nonzero.
*/
static inline void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it) {
- return ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
+ return it->blk->nodes[it->i].data;
}
/*
* It is undefined to call this function when ngtcp2_ksl_it_end(it)
* returns nonzero.
*/
-static inline ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
- return (ngtcp2_ksl_key *)ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->key;
+static inline const ngtcp2_ksl_key *ngtcp2_ksl_it_key(const ngtcp2_ksl_it *it) {
+ return ngtcp2_ksl_nth_key(it->ksl, it->blk, it->i);
}
/*
ngtcp2_printf log_printf, ngtcp2_tstamp ts,
void *user_data) {
if (scid) {
- ngtcp2_encode_hex(log->scid, scid->data, scid->datalen);
+ ngtcp2_encode_hex_cstr(log->scid, scid->data, scid->datalen);
} else {
log->scid[0] = '\0';
}
fr->type == NGTCP2_FRAME_CONNECTION_CLOSE ? strerrorcode(fr->error_code)
: strapperrorcode(fr->error_code),
fr->error_code, fr->frame_type, fr->reasonlen,
- ngtcp2_encode_printable_ascii(reason, fr->reason, reasonlen));
+ ngtcp2_encode_printable_ascii_cstr(reason, fr->reason, reasonlen));
}
static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
static void log_fr_new_connection_id(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_new_connection_id *fr,
const char *dir) {
- uint8_t buf[sizeof(fr->stateless_reset_token) * 2 + 1];
- uint8_t cid[sizeof(fr->cid.data) * 2 + 1];
+ char buf[sizeof(fr->stateless_reset_token) * 2 + 1];
+ char cid[sizeof(fr->cid.data) * 2 + 1];
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_FRM,
" cid=0x%s retire_prior_to=%" PRIu64
" stateless_reset_token=0x%s",
NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, fr->seq,
- (const char *)ngtcp2_encode_hex(cid, fr->cid.data, fr->cid.datalen),
+ ngtcp2_encode_hex_cstr(cid, fr->cid.data, fr->cid.datalen),
fr->retire_prior_to,
- (const char *)ngtcp2_encode_hex(buf, fr->stateless_reset_token,
- sizeof(fr->stateless_reset_token)));
+ ngtcp2_encode_hex_cstr(buf, fr->stateless_reset_token,
+ sizeof(fr->stateless_reset_token)));
}
static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
static void log_fr_path_challenge(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_path_challenge *fr,
const char *dir) {
- uint8_t buf[sizeof(fr->data) * 2 + 1];
+ char buf[sizeof(fr->data) * 2 + 1];
- ngtcp2_log_infof_raw(
- log, NGTCP2_LOG_EVENT_FRM,
- NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64 ") data=0x%s",
- NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
- (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+ NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02" PRIx64
+ ") data=0x%s",
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
+ ngtcp2_encode_hex_cstr(buf, fr->data, sizeof(fr->data)));
}
static void log_fr_path_response(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_path_response *fr,
const char *dir) {
- uint8_t buf[sizeof(fr->data) * 2 + 1];
+ char buf[sizeof(fr->data) * 2 + 1];
- ngtcp2_log_infof_raw(
- log, NGTCP2_LOG_EVENT_FRM,
- NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64 ") data=0x%s",
- NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
- (const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_FRM,
+ NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02" PRIx64
+ ") data=0x%s",
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type,
+ ngtcp2_encode_hex_cstr(buf, fr->data, sizeof(fr->data)));
}
static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_new_token *fr, const char *dir) {
/* Show at most first 64 bytes of token. If token is longer than 64
bytes, log first 64 bytes and then append "*" */
- uint8_t buf[128 + 1 + 1];
- uint8_t *p;
+ char buf[128 + 1 + 1];
+ char *p;
if (fr->tokenlen > 64) {
- p = ngtcp2_encode_hex(buf, fr->token, 64);
+ p = ngtcp2_encode_hex_cstr(buf, fr->token, 64);
p[128] = '*';
p[129] = '\0';
} else {
- p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen);
+ p = ngtcp2_encode_hex_cstr(buf, fr->token, fr->tokenlen);
}
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_FRM,
NGTCP2_LOG_PKT " NEW_TOKEN(0x%02" PRIx64 ") token=0x%s len=%zu",
- NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen);
+ NGTCP2_LOG_PKT_HD_FIELDS(dir), fr->type, p, fr->tokenlen);
}
static void log_fr_retire_connection_id(ngtcp2_log *log,
}
void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
- uint8_t buf[sizeof(sr->stateless_reset_token) * 2 + 1];
+ char buf[sizeof(sr->stateless_reset_token) * 2 + 1];
ngtcp2_pkt_hd shd;
ngtcp2_pkt_hd *hd = &shd;
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_PKT, NGTCP2_LOG_PKT " token=0x%s randlen=%zu",
NGTCP2_LOG_PKT_HD_FIELDS("rx"),
- (const char *)ngtcp2_encode_hex(buf, sr->stateless_reset_token,
- sizeof(sr->stateless_reset_token)),
+ ngtcp2_encode_hex_cstr(buf, sr->stateless_reset_token,
+ sizeof(sr->stateless_reset_token)),
sr->randlen);
}
void ngtcp2_log_remote_tp(ngtcp2_log *log,
const ngtcp2_transport_params *params) {
- uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1];
- uint8_t addr[16 * 2 + 7 + 1];
- uint8_t cid[NGTCP2_MAX_CIDLEN * 2 + 1];
+ char token[NGTCP2_STATELESS_RESET_TOKENLEN * 2 + 1];
+ char addr[16 * 2 + 7 + 1];
+ char cid[NGTCP2_MAX_CIDLEN * 2 + 1];
size_t i;
const ngtcp2_sockaddr_in *sa_in;
const ngtcp2_sockaddr_in6 *sa_in6;
if (params->stateless_reset_token_present) {
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " stateless_reset_token=0x%s",
- (const char *)ngtcp2_encode_hex(token, params->stateless_reset_token,
- sizeof(params->stateless_reset_token)));
+ ngtcp2_encode_hex_cstr(token, params->stateless_reset_token,
+ sizeof(params->stateless_reset_token)));
}
if (params->preferred_addr_present) {
if (params->preferred_addr.ipv4_present) {
sa_in = ¶ms->preferred_addr.ipv4;
- ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
- NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s",
- (const char *)ngtcp2_encode_ipv4(
- addr, (const uint8_t *)&sa_in->sin_addr));
+ ngtcp2_log_infof_raw(
+ log, NGTCP2_LOG_EVENT_CRY,
+ NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s",
+ ngtcp2_encode_ipv4_cstr(addr, (const uint8_t *)&sa_in->sin_addr));
ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
NGTCP2_LOG_TP " preferred_address.ipv4_port=%u",
ngtcp2_ntohs(sa_in->sin_port));
if (params->preferred_addr.ipv6_present) {
sa_in6 = ¶ms->preferred_addr.ipv6;
- ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
- NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s",
- (const char *)ngtcp2_encode_ipv6(
- addr, (const uint8_t *)&sa_in6->sin6_addr));
+ ngtcp2_log_infof_raw(
+ log, NGTCP2_LOG_EVENT_CRY,
+ NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s",
+ ngtcp2_encode_ipv6_cstr(addr, (const uint8_t *)&sa_in6->sin6_addr));
ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
NGTCP2_LOG_TP " preferred_address.ipv6_port=%u",
ngtcp2_ntohs(sa_in6->sin6_port));
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_CRY, NGTCP2_LOG_TP " preferred_address.cid=0x%s",
- (const char *)ngtcp2_encode_hex(cid, params->preferred_addr.cid.data,
- params->preferred_addr.cid.datalen));
+ ngtcp2_encode_hex_cstr(cid, params->preferred_addr.cid.data,
+ params->preferred_addr.cid.datalen));
ngtcp2_log_infof_raw(
log, NGTCP2_LOG_EVENT_CRY,
NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s",
- (const char *)ngtcp2_encode_hex(
+ ngtcp2_encode_hex_cstr(
token, params->preferred_addr.stateless_reset_token,
sizeof(params->preferred_addr.stateless_reset_token)));
}
if (params->original_dcid_present) {
- ngtcp2_log_infof_raw(
- log, NGTCP2_LOG_EVENT_CRY,
- NGTCP2_LOG_TP " original_destination_connection_id=0x%s",
- (const char *)ngtcp2_encode_hex(cid, params->original_dcid.data,
- params->original_dcid.datalen));
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+ NGTCP2_LOG_TP
+ " original_destination_connection_id=0x%s",
+ ngtcp2_encode_hex_cstr(cid, params->original_dcid.data,
+ params->original_dcid.datalen));
}
if (params->retry_scid_present) {
- ngtcp2_log_infof_raw(
- log, NGTCP2_LOG_EVENT_CRY,
- NGTCP2_LOG_TP " retry_source_connection_id=0x%s",
- (const char *)ngtcp2_encode_hex(cid, params->retry_scid.data,
- params->retry_scid.datalen));
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+ NGTCP2_LOG_TP " retry_source_connection_id=0x%s",
+ ngtcp2_encode_hex_cstr(cid, params->retry_scid.data,
+ params->retry_scid.datalen));
}
if (params->initial_scid_present) {
- ngtcp2_log_infof_raw(
- log, NGTCP2_LOG_EVENT_CRY,
- NGTCP2_LOG_TP " initial_source_connection_id=0x%s",
- (const char *)ngtcp2_encode_hex(cid, params->initial_scid.data,
- params->initial_scid.datalen));
+ ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
+ NGTCP2_LOG_TP " initial_source_connection_id=0x%s",
+ ngtcp2_encode_hex_cstr(cid, params->initial_scid.data,
+ params->initial_scid.datalen));
}
ngtcp2_log_infof_raw(log, NGTCP2_LOG_EVENT_CRY,
static void log_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const char *dir) {
- uint8_t dcid[sizeof(hd->dcid.data) * 2 + 1];
- uint8_t scid[sizeof(hd->scid.data) * 2 + 1];
+ char dcid[sizeof(hd->dcid.data) * 2 + 1];
+ char scid[sizeof(hd->scid.data) * 2 + 1];
if (!log->log_printf || !(log->events & NGTCP2_LOG_EVENT_PKT)) {
return;
ngtcp2_log_infof(
log, NGTCP2_LOG_EVENT_PKT, "%s pkn=%" PRId64 " dcid=0x%s type=%s k=%d",
dir, hd->pkt_num,
- (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
+ ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
strpkttype(hd), (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0);
} else {
ngtcp2_log_infof(
log, NGTCP2_LOG_EVENT_PKT,
"%s pkn=%" PRId64 " dcid=0x%s scid=0x%s version=0x%08x type=%s len=%zu",
dir, hd->pkt_num,
- (const char *)ngtcp2_encode_hex(dcid, hd->dcid.data, hd->dcid.datalen),
- (const char *)ngtcp2_encode_hex(scid, hd->scid.data, hd->scid.datalen),
+ ngtcp2_encode_hex_cstr(dcid, hd->dcid.data, hd->dcid.datalen),
+ ngtcp2_encode_hex_cstr(scid, hd->scid.data, hd->scid.datalen),
hd->version, strpkttype(hd), hd->len);
}
}
log_pritnf. */
void *user_data;
/* scid is SCID encoded as NULL-terminated hex string. */
- uint8_t scid[NGTCP2_MAX_CIDLEN * 2 + 1];
+ char scid[NGTCP2_MAX_CIDLEN * 2 + 1];
} ngtcp2_log;
/**
#define NGTCP2_INITIAL_HASHBITS 4
void ngtcp2_map_init(ngtcp2_map *map, uint64_t seed, const ngtcp2_mem *mem) {
- map->mem = mem;
- map->hashbits = 0;
- map->table = NULL;
- map->seed = seed;
- map->size = 0;
+ *map = (ngtcp2_map){
+ .mem = mem,
+ .seed = seed,
+ };
}
void ngtcp2_map_free(ngtcp2_map *map) {
return;
}
- ngtcp2_mem_free(map->mem, map->table);
+ ngtcp2_mem_free(map->mem, map->keys);
}
int ngtcp2_map_each(const ngtcp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
size_t i;
- ngtcp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return 0;
}
- tablelen = 1u << map->hashbits;
+ tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
- bkt = &map->table[i];
-
- if (bkt->data == NULL) {
+ if (map->psl[i] == 0) {
continue;
}
- rv = func(bkt->data, ptr);
+ rv = func(map->data[i], ptr);
if (rv != 0) {
return rv;
}
return 0;
}
-static size_t map_hash(const ngtcp2_map *map, ngtcp2_map_key_type key) {
- /* hasher from
- https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
- We do not perform finalization here because we use top bits
- anyway. */
- key += map->seed;
- key *= 0xf1357aea2e62a9c5ull;
- return (size_t)((key * 11400714819323198485llu) >> (64 - map->hashbits));
-}
-
-static void map_bucket_swap(ngtcp2_map_bucket *a, ngtcp2_map_bucket *b) {
- ngtcp2_map_bucket c = *a;
+/* Hasher from
+ https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
+ to maximize the output's sensitivity to all input bits. */
+#define NGTCP2_MAP_HASHER 0xf1357aea2e62a9c5ull
+/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
+ the high bits with the good distribution. */
+#define NGTCP2_MAP_FIBO 0x9e3779b97f4a7c15ull
- *a = *b;
- *b = c;
+static size_t map_index(const ngtcp2_map *map, ngtcp2_map_key_type key) {
+ key += map->seed;
+ key *= NGTCP2_MAP_HASHER;
+ return (size_t)((key * NGTCP2_MAP_FIBO) >> (64 - map->hashbits));
}
#ifndef WIN32
void ngtcp2_map_print_distance(const ngtcp2_map *map) {
size_t i;
size_t idx;
- ngtcp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return;
}
- tablelen = 1u << map->hashbits;
+ tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
- bkt = &map->table[i];
-
- if (bkt->data == NULL) {
+ if (map->psl[i] == 0) {
fprintf(stderr, "@%zu <EMPTY>\n", i);
continue;
}
- idx = map_hash(map, bkt->key);
- fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
- map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
+ idx = map_index(map, map->keys[i]);
+ fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
+ map->keys[i], idx, map->psl[i] - 1);
}
}
#endif /* !defined(WIN32) */
-static int map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
- size_t idx = map_hash(map, key);
- ngtcp2_map_bucket b = {
- .key = key,
- .data = data,
- };
- ngtcp2_map_bucket *bkt;
- size_t mask = (1u << map->hashbits) - 1;
+static void map_set_entry(ngtcp2_map *map, size_t idx, ngtcp2_map_key_type key,
+ void *data, size_t psl) {
+ map->keys[idx] = key;
+ map->data[idx] = data;
+ map->psl[idx] = (uint8_t)psl;
+}
+
+#define NGTCP2_SWAP(TYPE, A, B) \
+ do { \
+ TYPE t = (TYPE) * (A); \
+ \
+ *(A) = *(B); \
+ *(B) = t; \
+ } while (0)
+
+/*
+ * map_insert inserts |key| and |data| to |map|, and returns the index
+ * where the pair is stored if it succeeds. Otherwise, it returns one
+ * of the following negative error codes:
+ *
+ * NGTCP2_ERR_INVALID_ARGUMENT
+ * The another data associated to |key| is already present.
+ */
+static ngtcp2_ssize map_insert(ngtcp2_map *map, ngtcp2_map_key_type key,
+ void *data) {
+ size_t idx = map_index(map, key);
+ size_t mask = ((size_t)1 << map->hashbits) - 1;
+ size_t psl = 1;
+ size_t kpsl;
for (;;) {
- bkt = &map->table[idx];
+ kpsl = map->psl[idx];
- if (bkt->data == NULL) {
- *bkt = b;
+ if (kpsl == 0) {
+ map_set_entry(map, idx, key, data, psl);
++map->size;
- return 0;
+
+ return (ngtcp2_ssize)idx;
}
- if (b.psl > bkt->psl) {
- map_bucket_swap(bkt, &b);
- } else if (bkt->key == key) {
- /* TODO This check is just a waste after first swap or if this
- function is called from map_resize. That said, there is no
- difference with or without this conditional in performance
- wise. */
+ if (psl > kpsl) {
+ NGTCP2_SWAP(ngtcp2_map_key_type, &key, &map->keys[idx]);
+ NGTCP2_SWAP(void *, &data, &map->data[idx]);
+ NGTCP2_SWAP(uint8_t, &psl, &map->psl[idx]);
+ } else if (map->keys[idx] == key) {
+ /* This check ensures that no duplicate keys are inserted. But
+ it is just a waste after first swap or if this function is
+ called from map_resize. That said, there is no difference
+ with or without this conditional in performance wise. */
return NGTCP2_ERR_INVALID_ARGUMENT;
}
- ++b.psl;
+ ++psl;
idx = (idx + 1) & mask;
}
}
+/* NGTCP2_MAP_MAX_HASHBITS is the maximum number of bits used for hash
+ table. The theoretical limit of the maximum number of keys that
+ can be stored is 1 << NGTCP2_MAP_MAX_HASHBITS. */
+#define NGTCP2_MAP_MAX_HASHBITS (sizeof(size_t) * 8 - 1)
+
static int map_resize(ngtcp2_map *map, size_t new_hashbits) {
size_t i;
- ngtcp2_map_bucket *bkt;
size_t tablelen;
- int rv;
+ ngtcp2_ssize idx;
ngtcp2_map new_map = {
- .table = ngtcp2_mem_calloc(map->mem, 1u << new_hashbits,
- sizeof(ngtcp2_map_bucket)),
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
- (void)rv;
+ void *buf;
+ (void)idx;
- if (new_map.table == NULL) {
+ if (new_hashbits > NGTCP2_MAP_MAX_HASHBITS) {
return NGTCP2_ERR_NOMEM;
}
+ tablelen = (size_t)1 << new_hashbits;
+
+ buf = ngtcp2_mem_calloc(map->mem, tablelen,
+ sizeof(ngtcp2_map_key_type) + sizeof(void *) +
+ sizeof(uint8_t));
+ if (buf == NULL) {
+ return NGTCP2_ERR_NOMEM;
+ }
+
+ new_map.keys = buf;
+ new_map.data =
+ (void *)((uint8_t *)new_map.keys + tablelen * sizeof(ngtcp2_map_key_type));
+ new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
+
if (map->size) {
- tablelen = 1u << map->hashbits;
+ tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
- bkt = &map->table[i];
- if (bkt->data == NULL) {
+ if (map->psl[i] == 0) {
continue;
}
- rv = map_insert(&new_map, bkt->key, bkt->data);
+ idx = map_insert(&new_map, map->keys[i], map->data[i]);
- assert(0 == rv);
+ /* map_insert must not fail because all keys are unique during
+ resize. */
+ assert(idx >= 0);
}
}
- ngtcp2_mem_free(map->mem, map->table);
- map->table = new_map.table;
+ ngtcp2_mem_free(map->mem, map->keys);
+ map->keys = new_map.keys;
+ map->data = new_map.data;
+ map->psl = new_map.psl;
map->hashbits = new_hashbits;
return 0;
}
+/* NGTCP2_MAX_PSL_RESIZE_THRESH is the maximum psl threshold. If
+ reached, resize the table. */
+#define NGTCP2_MAX_PSL_RESIZE_THRESH 128
+
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
int rv;
+ size_t tablelen;
+ ngtcp2_ssize idx;
assert(data);
- /* Load factor is 7/8 */
- /* Under the very initial condition, that is map->size == 0 and
- map->hashbits == 0, 8 > 7 still holds nicely. */
- if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
- if (map->hashbits) {
- rv = map_resize(map, map->hashbits + 1);
- if (rv != 0) {
- return rv;
- }
- } else {
- rv = map_resize(map, NGTCP2_INITIAL_HASHBITS);
- if (rv != 0) {
- return rv;
- }
+ /* tablelen is incorrect if map->hashbits == 0 which leads to
+ tablelen = 1, but it is only used to check the load factor, and
+ it works in this special case. */
+ tablelen = (size_t)1 << map->hashbits;
+
+ /* Load factor is 7 / 8. Because tablelen is power of 2, (tablelen
+ - (tablelen >> 3)) computes tablelen * 7 / 8. */
+ if (map->size + 1 >= (tablelen - (tablelen >> 3))) {
+ rv = map_resize(map, map->hashbits ? map->hashbits + 1
+ : NGTCP2_INITIAL_HASHBITS);
+ if (rv != 0) {
+ return rv;
}
+
+ idx = map_insert(map, key, data);
+ if (idx < 0) {
+ return (int)idx;
+ }
+
+ return 0;
}
- rv = map_insert(map, key, data);
- if (rv != 0) {
- return rv;
+ idx = map_insert(map, key, data);
+ if (idx < 0) {
+ return (int)idx;
}
- return 0;
+ /* Resize if psl reaches really large value which is almost
+ improbable, but just in case. */
+ if (map->psl[idx] - 1 < NGTCP2_MAX_PSL_RESIZE_THRESH) {
+ return 0;
+ }
+
+ return map_resize(map, map->hashbits + 1);
}
void *ngtcp2_map_find(const ngtcp2_map *map, ngtcp2_map_key_type key) {
size_t idx;
- ngtcp2_map_bucket *bkt;
- size_t psl = 0;
+ size_t psl = 1;
size_t mask;
if (map->size == 0) {
return NULL;
}
- idx = map_hash(map, key);
- mask = (1u << map->hashbits) - 1;
+ idx = map_index(map, key);
+ mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
- bkt = &map->table[idx];
-
- if (bkt->data == NULL || psl > bkt->psl) {
+ if (psl > map->psl[idx]) {
return NULL;
}
- if (bkt->key == key) {
- return bkt->data;
+ if (map->keys[idx] == key) {
+ return map->data[idx];
}
++psl;
int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
size_t idx;
- ngtcp2_map_bucket *b, *bkt;
- size_t psl = 0;
+ size_t dest;
+ size_t psl = 1, kpsl;
size_t mask;
if (map->size == 0) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
- idx = map_hash(map, key);
- mask = (1u << map->hashbits) - 1;
+ idx = map_index(map, key);
+ mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
- bkt = &map->table[idx];
-
- if (bkt->data == NULL || psl > bkt->psl) {
+ if (psl > map->psl[idx]) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
- if (bkt->key == key) {
- b = bkt;
+ if (map->keys[idx] == key) {
+ dest = idx;
idx = (idx + 1) & mask;
for (;;) {
- bkt = &map->table[idx];
- if (bkt->data == NULL || bkt->psl == 0) {
- b->data = NULL;
+ kpsl = map->psl[idx];
+ if (kpsl <= 1) {
+ map->psl[dest] = 0;
break;
}
- --bkt->psl;
- *b = *bkt;
- b = bkt;
+ map_set_entry(map, dest, map->keys[idx], map->data[idx], kpsl - 1);
+
+ dest = idx;
idx = (idx + 1) & mask;
}
return;
}
- memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
+ memset(map->psl, 0, sizeof(*map->psl) * ((size_t)1 << map->hashbits));
map->size = 0;
}
typedef uint64_t ngtcp2_map_key_type;
-typedef struct ngtcp2_map_bucket {
- uint32_t psl;
- ngtcp2_map_key_type key;
- void *data;
-} ngtcp2_map_bucket;
-
typedef struct ngtcp2_map {
- ngtcp2_map_bucket *table;
+ ngtcp2_map_key_type *keys;
+ void **data;
+ /* psl is the Probe Sequence Length. 0 has special meaning that the
+ element is not stored at i-th position if psl[i] == 0. Because
+ of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
+ uint8_t *psl;
const ngtcp2_mem *mem;
uint64_t seed;
size_t size;
#include "ngtcp2_addr.h"
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
- const ngtcp2_addr *remote) {
- path->local = *local;
- path->remote = *remote;
-}
-
void ngtcp2_path_copy(ngtcp2_path *dest, const ngtcp2_path *src) {
ngtcp2_addr_copy(&dest->local, &src->local);
ngtcp2_addr_copy(&dest->remote, &src->remote);
#include <ngtcp2/ngtcp2.h>
-/*
- * ngtcp2_path_init initializes |path| with the given addresses. Note
- * that the buffer pointed by local->addr and remote->addr are not
- * copied. Their pointer values are assigned instead.
- */
-void ngtcp2_path_init(ngtcp2_path *path, const ngtcp2_addr *local,
- const ngtcp2_addr *remote);
-
/*
* ngtcp2_path_storage_init2 initializes |ps| using |path| as initial
* data.
}
static uint32_t pcg_rotr_32(uint32_t value, unsigned int rot) {
- return (value >> rot) | (value << ((-rot) & 31));
+ return (value >> rot) | (value << ((32 - rot) & 31));
}
static uint32_t pcg_output_xsh_rr_64_32(uint64_t state) {
return NGTCP2_ERR_FRAME_ENCODING;
}
- p = ngtcp2_get_uvarint(&vi, p);
+ ngtcp2_get_uvarint(&vi, p);
if (payloadlen - len < vi) {
return NGTCP2_ERR_FRAME_ENCODING;
}
(void)payload;
(void)payloadlen;
+ assert(payloadlen > 0);
+
dest->type = NGTCP2_FRAME_PING;
return 1;
}
return NGTCP2_ERR_FRAME_ENCODING;
}
- p = ngtcp2_get_uvarint(&vi, p);
+ ngtcp2_get_uvarint(&vi, p);
if (payloadlen - len < vi) {
return NGTCP2_ERR_FRAME_ENCODING;
}
(void)payload;
(void)payloadlen;
+ assert(payloadlen > 0);
+
dest->type = NGTCP2_FRAME_HANDSHAKE_DONE;
return 1;
}
size_t n;
uint64_t vi;
- if (payloadlen < len) {
- return NGTCP2_ERR_FRAME_ENCODING;
- }
+ assert(payloadlen > 0);
type = payload[0];
#define write_string(DEST, S) \
write_string_impl((DEST), (const uint8_t *)(S), sizeof(S) - 1)
-#define NGTCP2_LOWER_XDIGITS "0123456789abcdef"
-
static uint8_t *write_hex(uint8_t *p, const uint8_t *data, size_t datalen) {
- const uint8_t *b = data, *end = data + datalen;
*p++ = '"';
- for (; b != end; ++b) {
- *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b >> 4];
- *p++ = (uint8_t)NGTCP2_LOWER_XDIGITS[*b & 0xf];
- }
+ p = ngtcp2_encode_hex(p, data, datalen);
*p++ = '"';
return p;
}
return write_hex(p, cid->data, cid->datalen);
}
-static uint8_t *write_number(uint8_t *p, uint64_t n) {
- size_t nlen = 0;
- uint64_t t;
- uint8_t *res;
-
- if (n == 0) {
- *p++ = '0';
- return p;
- }
- for (t = n; t; t /= 10, ++nlen)
- ;
- p += nlen;
- res = p;
- for (; n; n /= 10) {
- *--p = (uint8_t)((n % 10) + '0');
- }
- return res;
-}
-
static uint8_t *write_tstamp(uint8_t *p, ngtcp2_tstamp ts) {
- return write_number(p, ts / NGTCP2_MILLISECONDS);
+ return ngtcp2_encode_uint(p, ts / NGTCP2_MILLISECONDS);
}
static uint8_t *write_duration(uint8_t *p, ngtcp2_duration duration) {
- return write_number(p, duration / NGTCP2_MILLISECONDS);
+ return ngtcp2_encode_uint(p, duration / NGTCP2_MILLISECONDS);
}
static uint8_t *write_bool(uint8_t *p, int b) {
size_t namelen, uint64_t value) {
p = write_string_impl(p, name, namelen);
*p++ = ':';
- return write_number(p, value);
+ return ngtcp2_encode_uint(p, value);
}
#define write_pair_number(DEST, NAME, VALUE) \
min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
*p++ = '[';
- p = write_number(p, (uint64_t)min_ack);
+ p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
if (largest_ack != min_ack) {
*p++ = ',';
- p = write_number(p, (uint64_t)largest_ack);
+ p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
}
*p++ = ']';
min_ack = largest_ack - (int64_t)range->len;
*p++ = ',';
*p++ = '[';
- p = write_number(p, (uint64_t)min_ack);
+ p = ngtcp2_encode_uint(p, (uint64_t)min_ack);
if (largest_ack != min_ack) {
*p++ = ',';
- p = write_number(p, (uint64_t)largest_ack);
+ p = ngtcp2_encode_uint(p, (uint64_t)largest_ack);
}
*p++ = ']';
}
p = write_verbatim(p, "],\"header\":");
p = write_pkt_hd(p, hd);
p = write_verbatim(p, ",\"raw\":{\"length\":");
- p = write_number(p, pktlen);
+ p = ngtcp2_encode_uint(p, pktlen);
p = write_verbatim(p, "}}}\n");
qlog->buf.last = p;
return NGTCP2_ERR_NOMEM;
}
- (*pg)->range.begin = begin;
- (*pg)->range.end = end;
+ **pg = (ngtcp2_rob_gap){
+ .range =
+ {
+ .begin = begin,
+ .end = end,
+ },
+ };
return 0;
}
return NGTCP2_ERR_NOMEM;
}
- (*pd)->range.begin = offset;
- (*pd)->range.end = offset + chunk;
- (*pd)->begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data);
+ **pd = (ngtcp2_rob_data){
+ .range =
+ {
+ .begin = offset,
+ .end = offset + chunk,
+ },
+ .begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data),
+ };
return 0;
}
}
if (offset < g->range.end) {
- ngtcp2_range r = {offset, g->range.end};
-
- ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r);
+ ngtcp2_ksl_update_key(&rob->gapksl, &g->range,
+ &(ngtcp2_range){
+ .begin = offset,
+ .end = g->range.end,
+ });
g->range.begin = offset;
break;
#include "ngtcp2_conn_stat.h"
void ngtcp2_rs_init(ngtcp2_rs *rs) {
- rs->interval = UINT64_MAX;
- rs->delivered = 0;
- rs->prior_delivered = 0;
- rs->prior_ts = UINT64_MAX;
- rs->tx_in_flight = 0;
- rs->lost = 0;
- rs->send_elapsed = 0;
- rs->ack_elapsed = 0;
- rs->last_end_seq = -1;
- rs->is_app_limited = 0;
+ *rs = (ngtcp2_rs){
+ .interval = UINT64_MAX,
+ .prior_ts = UINT64_MAX,
+ .last_end_seq = -1,
+ };
}
void ngtcp2_rst_init(ngtcp2_rst *rst) {
int rv;
(void)rv;
+ rtb_on_remove(rtb, ent, cstat);
+
rv = ngtcp2_ksl_remove_hint(&rtb->ents, it, it, &ent->hd.pkt_num);
assert(0 == rv);
- rtb_on_remove(rtb, ent, cstat);
assert(ent->next == NULL);
cc_ack.rtt = ngtcp2_max_uint64(pkt_ts - cc_ack.largest_pkt_sent_ts,
NGTCP2_NANOSECONDS);
- rv = ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
- if (rv == 0 && cc->new_rtt_sample &&
- rtb->largest_acked_tx_pkt_num >= rtb->cc_pkt_num) {
- cc->new_rtt_sample(cc, cstat, ts);
- }
+ ngtcp2_conn_update_rtt(conn, cc_ack.rtt, fr->ack_delay_unscaled, ts);
}
if (conn) {
int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
- ngtcp2_cc_ack cc_ack = {
- .largest_pkt_sent_ts = UINT64_MAX,
- .rtt = UINT64_MAX,
- };
-
- return rtb_detect_lost_pkt(rtb, &cc_ack, conn, pktns, cstat, ts);
+ return rtb_detect_lost_pkt(rtb,
+ &(ngtcp2_cc_ack){
+ .largest_pkt_sent_ts = UINT64_MAX,
+ .rtt = UINT64_MAX,
+ },
+ conn, pktns, cstat, ts);
}
void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) {
ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
- if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED) ||
- ts - ent->lost_ts < timeout) {
+ assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED);
+
+ if (ts - ent->lost_ts < timeout) {
return;
}
ngtcp2_log_infof(rtb->log, NGTCP2_LOG_EVENT_LDC,
"pkn=%" PRId64 " has already been reclaimed on PTO",
ent->hd.pkt_num);
+
+ ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
+ rtb->frc_objalloc, rtb->mem);
+
continue;
}
if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE) &&
(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_DATAGRAM) ||
!conn->callbacks.lost_datagram)) {
+ ngtcp2_rtb_entry_objalloc_del(ent, rtb->rtb_entry_objalloc,
+ rtb->frc_objalloc, rtb->mem);
+
continue;
}
/* NGTCP2_DEFAULT_GLITCH_RATELIM_BURST is the maximum number of tokens
in glitch rate limiter. It is also the initial value. */
-#define NGTCP2_DEFAULT_GLITCH_RATELIM_BURST 1000
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_BURST 4000
/* NGTCP2_DEFAULT_GLITCH_RATELIM_RATE is the rate of tokens generated
per second for glitch rate limiter. */
-#define NGTCP2_DEFAULT_GLITCH_RATELIM_RATE 33
+#define NGTCP2_DEFAULT_GLITCH_RATELIM_RATE 132
/*
* ngtcp2_settings_convert_to_latest converts |src| of version
*p++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf];
}
+ return p;
+}
+
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len) {
+ uint8_t *p = ngtcp2_encode_hex((uint8_t *)dest, data, len);
+
*p = '\0';
return dest;
}
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
- size_t len) {
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
+ size_t len) {
size_t i;
char *p = dest;
uint8_t c;
return dest;
}
-/*
- * write_uint writes |n| to the buffer pointed by |p| in decimal
- * representation. It returns |p| plus the number of bytes written.
- * The function assumes that the buffer has enough capacity to contain
- * a string.
- */
-static uint8_t *write_uint(uint8_t *p, uint64_t n) {
- size_t nlen = 0;
- uint64_t t;
- uint8_t *res;
-
- if (n == 0) {
- *p++ = '0';
- return p;
- }
- for (t = n; t; t /= 10, ++nlen)
- ;
- p += nlen;
- res = p;
- for (; n; n /= 10) {
- *--p = (uint8_t)((n % 10) + '0');
- }
- return res;
-}
-
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr) {
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr) {
size_t i;
- uint8_t *p = dest;
+ char *p = dest;
- p = write_uint(p, addr[0]);
+ p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[0]);
for (i = 1; i < 4; ++i) {
*p++ = '.';
- p = write_uint(p, addr[i]);
+ p = (char *)ngtcp2_encode_uint((uint8_t *)p, addr[i]);
}
*p = '\0';
* length |len| to |dest| in hex string. Any leading zeros are
* suppressed. It returns |dest| plus the number of bytes written.
*/
-static uint8_t *write_hex_zsup(uint8_t *dest, const uint8_t *data, size_t len) {
+static char *write_hex_zsup(char *dest, const uint8_t *data, size_t len) {
size_t i;
- uint8_t *p = dest;
+ char *p = dest;
uint8_t d;
for (i = 0; i < len; ++i) {
d &= 0xf;
if (d) {
- *p++ = (uint8_t)LOWER_XDIGITS[d];
+ *p++ = LOWER_XDIGITS[d];
++i;
break;
}
for (; i < len; ++i) {
d = data[i];
- *p++ = (uint8_t)LOWER_XDIGITS[d >> 4];
- *p++ = (uint8_t)LOWER_XDIGITS[d & 0xf];
+ *p++ = LOWER_XDIGITS[d >> 4];
+ *p++ = LOWER_XDIGITS[d & 0xf];
}
return p;
}
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr) {
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr) {
uint16_t blks[8];
size_t i;
size_t zlen, zoff;
size_t max_zlen = 0, max_zoff = 8;
- uint8_t *p = dest;
+ char *p = dest;
for (i = 0; i < 16; i += sizeof(uint16_t)) {
/* Copy in network byte order. */
return rv == 0;
}
+
+/* countl_zero counts the number of leading zeros in |x|. It is
+ undefined if |x| is 0. */
+static int countl_zero(uint64_t x) {
+#ifdef __GNUC__
+ return __builtin_clzll(x);
+#else /* !defined(__GNUC__) */
+ /* This is the same implementation of Go's LeadingZeros64 in
+ math/bits package. */
+ static const uint8_t len8tab[] = {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ };
+ int n = 0;
+
+ if (x >= 1ull << 32) {
+ x >>= 32;
+ n += 32;
+ }
+
+ if (x >= 1 << 16) {
+ x >>= 16;
+ n += 16;
+ }
+
+ if (x >= 1 << 8) {
+ x >>= 8;
+ n += 8;
+ }
+
+ return 64 - (n + len8tab[x]);
+#endif /* !defined(__GNUC__) */
+}
+
+/*
+ * count_digit returns the minimum number of digits to represent |x|
+ * in base 10.
+ *
+ * credit:
+ * https://lemire.me/blog/2025/01/07/counting-the-digits-of-64-bit-integers/
+ */
+static size_t count_digit(uint64_t x) {
+ static const uint64_t count_digit_tbl[] = {
+ 9ull,
+ 99ull,
+ 999ull,
+ 9999ull,
+ 99999ull,
+ 999999ull,
+ 9999999ull,
+ 99999999ull,
+ 999999999ull,
+ 9999999999ull,
+ 99999999999ull,
+ 999999999999ull,
+ 9999999999999ull,
+ 99999999999999ull,
+ 999999999999999ull,
+ 9999999999999999ull,
+ 99999999999999999ull,
+ 999999999999999999ull,
+ 9999999999999999999ull,
+ };
+ size_t y = (size_t)(19 * (63 - countl_zero(x | 1)) >> 6);
+
+ y += x > count_digit_tbl[y];
+
+ return y + 1;
+}
+
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n) {
+ static const uint8_t uint_digits[] =
+ "00010203040506070809101112131415161718192021222324252627282930313233343536"
+ "37383940414243444546474849505152535455565758596061626364656667686970717273"
+ "7475767778798081828384858687888990919293949596979899";
+ uint8_t *p;
+ const uint8_t *tp;
+
+ if (n < 10) {
+ *dest++ = (uint8_t)('0' + n);
+ return dest;
+ }
+
+ if (n < 100) {
+ tp = &uint_digits[n * 2];
+ *dest++ = *tp++;
+ *dest++ = *tp;
+ return dest;
+ }
+
+ dest += count_digit(n);
+ p = dest;
+
+ for (; n >= 100; n /= 100) {
+ p -= 2;
+ tp = &uint_digits[(n % 100) * 2];
+ p[0] = *tp++;
+ p[1] = *tp;
+ }
+
+ if (n < 10) {
+ *--p = (uint8_t)('0' + n);
+ return dest;
+ }
+
+ p -= 2;
+ tp = &uint_digits[n * 2];
+ p[0] = *tp++;
+ p[1] = *tp;
+
+ return dest;
+}
const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n);
/*
- * ngtcp2_encode_hex encodes |data| of length |len| in hex string. It
- * writes additional NULL bytes at the end of the buffer. The buffer
- * pointed by |dest| must have at least |len| * 2 + 1 bytes space.
- * This function returns |dest|.
+ * ngtcp2_encode_hex encodes |data| of length |len| in hex string.
+ * The buffer pointed by |dest| must have at least |len| * 2 bytes
+ * space. This function returns |dest| + |len| * 2.
*/
uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len);
/*
- * ngtcp2_encode_ipv4 encodes binary form IPv4 address stored in
+ * ngtcp2_encode_hex_cstr encodes |data| of length |len| in hex
+ * string. It writes additional NULL bytes at the end of the buffer.
+ * The buffer pointed by |dest| must have at least |len| * 2 + 1 bytes
+ * space. This function returns |dest|.
+ */
+char *ngtcp2_encode_hex_cstr(char *dest, const uint8_t *data, size_t len);
+
+/*
+ * ngtcp2_encode_ipv4_cstr encodes binary form IPv4 address stored in
* |addr| to human readable text form in the buffer pointed by |dest|.
* The capacity of buffer must have enough length to store a text form
* plus a terminating NULL byte. The resulting text form ends with
* NULL byte. The function returns |dest|.
*/
-uint8_t *ngtcp2_encode_ipv4(uint8_t *dest, const uint8_t *addr);
+char *ngtcp2_encode_ipv4_cstr(char *dest, const uint8_t *addr);
/*
- * ngtcp2_encode_ipv6 encodes binary form IPv6 address stored in
+ * ngtcp2_encode_ipv6_cstr encodes binary form IPv6 address stored in
* |addr| to human readable text form in the buffer pointed by |dest|.
* The capacity of buffer must have enough length to store a text form
* plus a terminating NULL byte. The resulting text form ends with
* https://tools.ietf.org/html/rfc5952#section-4. The function
* returns |dest|.
*/
-uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr);
+char *ngtcp2_encode_ipv6_cstr(char *dest, const uint8_t *addr);
/*
* ngtcp2_encode_printable_ascii encodes |data| of length |len| in
* writes additional NULL bytes at the end of the buffer. |dest| must
* have at least |len| + 1 bytes. This function returns |dest|.
*/
-char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
- size_t len);
+char *ngtcp2_encode_printable_ascii_cstr(char *dest, const uint8_t *data,
+ size_t len);
/*
* ngtcp2_cmemeq returns nonzero if the first |n| bytes of the buffers
*/
int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n);
+/*
+ * ngtcp2_encode_uint encodes |n| as a decimal integer to the buffer
+ * pointed by |dest|. This function assumes that the buffer contains
+ * the sufficient capacity to write the number. This function returns
+ * the pointer to the buffer past the last byte written.
+ */
+uint8_t *ngtcp2_encode_uint(uint8_t *dest, uint64_t n);
+
#endif /* !defined(NGTCP2_STR_H) */
uint64_t max_rx_offset, uint64_t max_tx_offset,
void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
const ngtcp2_mem *mem) {
- strm->pe.index = NGTCP2_PQ_BAD_INDEX;
- strm->cycle = 0;
- strm->frc_objalloc = frc_objalloc;
- strm->tx.acked_offset = NULL;
- strm->tx.cont_acked_offset = 0;
- strm->tx.streamfrq = NULL;
- strm->tx.offset = 0;
- strm->tx.max_offset = max_tx_offset;
- strm->tx.last_blocked_offset = UINT64_MAX;
- strm->tx.last_max_stream_data_ts = UINT64_MAX;
- strm->tx.loss_count = 0;
- strm->tx.last_lost_pkt_num = -1;
- strm->tx.stop_sending_app_error_code = 0;
- strm->tx.reset_stream_app_error_code = 0;
- strm->rx.rob = NULL;
- strm->rx.cont_offset = 0;
- strm->rx.last_offset = 0;
- strm->rx.max_offset = strm->rx.unsent_max_offset = strm->rx.window =
- max_rx_offset;
- strm->mem = mem;
- strm->stream_id = stream_id;
- strm->stream_user_data = stream_user_data;
- strm->flags = flags;
- strm->app_error_code = 0;
+ *strm = (ngtcp2_strm){
+ .pe.index = NGTCP2_PQ_BAD_INDEX,
+ .frc_objalloc = frc_objalloc,
+ .tx =
+ {
+ .max_offset = max_tx_offset,
+ .last_blocked_offset = UINT64_MAX,
+ .last_max_stream_data_ts = UINT64_MAX,
+ .last_lost_pkt_num = -1,
+ },
+ .rx =
+ {
+ .max_offset = max_rx_offset,
+ .unsent_max_offset = max_rx_offset,
+ .window = max_rx_offset,
+ },
+ .mem = mem,
+ .stream_id = stream_id,
+ .stream_user_data = stream_user_data,
+ .flags = flags,
+ };
}
void ngtcp2_strm_free(ngtcp2_strm *strm) {
/* strm_rob_heavily_fragmented returns nonzero if the number of gaps
in |rob| exceeds the limit. */
static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
- return ngtcp2_ksl_len(&rob->gapksl) >= 1000;
+ return ngtcp2_ksl_len(&rob->gapksl) >= 4000;
}
ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
ngtcp2_range ngtcp2_strm_get_unacked_range_after(const ngtcp2_strm *strm,
uint64_t offset) {
- ngtcp2_range gap;
-
if (strm->tx.acked_offset == NULL) {
- gap.begin = strm->tx.cont_acked_offset;
- gap.end = UINT64_MAX;
- return gap;
+ return (ngtcp2_range){
+ .begin = strm->tx.cont_acked_offset,
+ .end = UINT64_MAX,
+ };
}
return ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
return rv;
}
- if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 1000) {
+ if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 4000) {
return NGTCP2_ERR_INTERNAL;
}
#include "ngtcp2_str.h"
ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len) {
- vec->base = (uint8_t *)base;
- vec->len = len;
+ *vec = (ngtcp2_vec){
+ .base = (uint8_t *)base,
+ .len = len,
+ };
+
return vec;
}
} else if (*pdstcnt == maxcnt) {
break;
} else {
- dst[*pdstcnt].len = left;
- dst[*pdstcnt].base = b->base;
+ dst[*pdstcnt] = (ngtcp2_vec){
+ .base = b->base,
+ .len = left,
+ };
++*pdstcnt;
}
}
if (src[i].len > left) {
- dst[j].base = src[i].base;
- dst[j].len = left;
+ dst[j] = (ngtcp2_vec){
+ .base = src[i].base,
+ .len = left,
+ };
return j + 1;
}
* |destlen| could be shorten by some factors (e.g., server side
* amplification limit). This function returns
* :macro:`NGTCP2_ERR_NOBUF` if the resulting buffer is too small even
- * if the given buffer has enough space.
+ * if the given buffer has enough space. This can happen if sending a
+ * packet would exceed a transmission limit (e.g., for amplification
+ * attack protection).
*
* This function must not be called from inside the callback
* functions.
* :macro:`NGTCP2_ERR_NOMEM`
* Out of memory
* :macro:`NGTCP2_ERR_NOBUF`
- * Buffer is too small
+ * Buffer is too small or packet would exceed the transmission
+ * limit (e.g., for amplification attack protection).
* :macro:`NGTCP2_ERR_INVALID_STATE`
* The current state does not allow sending CONNECTION_CLOSE
* frame.
* * :member:`handshake_timeout <ngtcp2_settings.handshake_timeout>` =
* ``UINT64_MAX``
* * :member:`glitch_ratelim_burst
- * <ngtcp2_settings.glitch_ratelim_burst>` = 1000
+ * <ngtcp2_settings.glitch_ratelim_burst>` = 4000
* * :member:`glitch_ratelim_rate
- * <ngtcp2_settings.glitch_ratelim_rate>` = 33
+ * <ngtcp2_settings.glitch_ratelim_rate>` = 132
*/
NGTCP2_EXTERN void ngtcp2_settings_default_versioned(int settings_version,
ngtcp2_settings *settings);
* @macro
*
* :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` is the maximum length
- * of a token generated by `ngtcp2_crypto_generate_regular_token`.
+ * of a token generated by `ngtcp2_crypto_generate_regular_token`.
+ * `ngtcp2_crypto_generate_regular_token2` generates a token of length
+ * at most :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` bytes + the
+ * length of the provided opaque data.
*/
#define NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN \
(/* magic = */ 1 + sizeof(ngtcp2_tstamp) + /* aead tag = */ 16 + \
size_t secretlen, const ngtcp2_sockaddr *remote_addr,
ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_generate_regular_token2` generates a token in the
+ * buffer pointed by |token| that is sent with NEW_TOKEN frame. The
+ * buffer pointed by |token| must have at least
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN` + |datalen| bytes long.
+ * The successfully generated token starts with
+ * :macro:`NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR`. |secret| of length
+ * |secretlen| is a keying material to generate keys to encrypt the
+ * token. |remote_addr| of length |remote_addrlen| is an address of
+ * client. |ts| is the timestamp when the token is generated. |data|
+ * of length |datalen| is an opaque data embedded in the token.
+ * |datalen| must be less than or equal to 256.
+ *
+ * Calling this function with |datalen| = 0 is equivalent to calling
+ * `ngtcp2_crypto_generate_regular_token`.
+ *
+ * To get the opaque data after successful verification, use
+ * `ngtcp2_crypto_verify_regular_token2`.
+ * `ngtcp2_crypto_verify_regular_token` can verify the token with
+ * |datalen| > 0, but it discards the opaque data.
+ *
+ * This function returns the length of generated token if it succeeds,
+ * or -1.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_generate_regular_token2(
+ uint8_t *token, const uint8_t *secret, size_t secretlen,
+ const ngtcp2_sockaddr *remote_addr, ngtcp2_socklen remote_addrlen,
+ const void *data, size_t datalen, ngtcp2_tstamp ts);
+
+/**
+ * @function
+ *
+ * `ngtcp2_crypto_verify_regular_token2` verifies a regular token
+ * stored in the buffer pointed by |token| of length |tokenlen|.
+ * |secret| of length |secretlen| is a keying material to generate
+ * keys to decrypt the token. |remote_addr| of length
+ * |remote_addrlen| is an address of client. |timeout| is the period
+ * during which the token is valid. |ts| is the current timestamp.
+ * |data| is the pointer to the buffer of length at least
+ * |max_datalen| bytes. If the token is verified successfully, the
+ * opaque data embedded in the token is copied to the buffer pointed
+ * by |data|.
+ *
+ * If |tokenlen| is less than
+ * :macro:`NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN`, this function returns
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`.
+ *
+ * If the length of opaque data is larger than |max_datalen|, the
+ * verification still succeeds, but nothing is written to the buffer
+ * pointed by |data|, and this function returns 0. In other words,
+ * the opaque data is discarded.
+ *
+ * This function returns the number of the opaque data written to the
+ * buffer pointed by |data| if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :macro:`NGTCP2_CRYPTO_ERR_UNREADABLE_TOKEN`
+ * A token is badly formatted; or verifying the integrity
+ * protection failed.
+ * :macro:`NGTCP2_CRYPTO_ERR_VERIFY_TOKEN`
+ * A token validity has expired.
+ * :macro:`NGTCP2_CRYPTO_ERR_INTERNAL`
+ * Internal error occurred.
+ */
+NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_verify_regular_token2(
+ void *data, size_t max_datalen, const uint8_t *token, size_t tokenlen,
+ const uint8_t *secret, size_t secretlen, const ngtcp2_sockaddr *remote_addr,
+ ngtcp2_socklen remote_addrlen, ngtcp2_duration timeout, ngtcp2_tstamp ts);
+
/**
* @function
*
*
* Version number of the ngtcp2 library release.
*/
-#define NGTCP2_VERSION "1.17.0"
+#define NGTCP2_VERSION "1.18.0"
/**
* @macro
* number, 8 bits for minor and 8 bits for patch. Version 1.2.3
* becomes 0x010203.
*/
-#define NGTCP2_VERSION_NUM 0x011100
+#define NGTCP2_VERSION_NUM 0x011200
#endif /* !defined(NGTCP2_VERSION_H) */