This commit is contained in:
Daniel Salzman 2023-03-21 20:45:03 +01:00
parent 18aa9aaea4
commit 56187dd5a2
80 changed files with 5 additions and 42928 deletions

View file

@ -564,15 +564,16 @@ AC_ARG_ENABLE([quic],
[], [enable_quic=auto])
AS_CASE([$enable_quic],
[auto], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 >= 0.13.0 libngtcp2_crypto_gnutls], [enable_quic=yes], [enable_quic=no])],
[yes], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 >= 0.13.0 libngtcp2_crypto_gnutls], [enable_quic=yes],
[auto], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 >= 0.13.0], [enable_quic=yes], [enable_quic=no])],
[yes], [PKG_CHECK_MODULES([libngtcp2], [libngtcp2 >= 0.13.0], [
AS_IF([test "$gnutls_quic" = "yes"],
[enable_quic=embedded
embedded_libngtcp2_CFLAGS="-I\$(top_srcdir)/src/contrib/libngtcp2 -I\$(top_srcdir)/src/contrib/libngtcp2/ngtcp2/lib"
embedded_libngtcp2_LIBS=$libelf_LIBS
libngtcp2_CFLAGS="-I\$(top_srcdir)/src/contrib/libngtcp2"],
[enable_quic=no
AC_MSG_WARN([gnutls >= 3.7.2 is required for QUIC])]))],
AC_MSG_WARN([gnutls >= 3.7.2 is required for QUIC])])
], [enable_quic=no])],
[no], [],
[*], [AC_MSG_ERROR([Invalid value of --enable-quic.])]
)

View file

@ -132,86 +132,8 @@ libembngtcp2_la_SOURCES = \
contrib/libngtcp2/ngtcp2/crypto/gnutls.c \
contrib/libngtcp2/ngtcp2/crypto/shared.c \
contrib/libngtcp2/ngtcp2/crypto/shared.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_acktr.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_addr.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_addr.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_balloc.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr2.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_bbr2.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_buf.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_cc.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_cid.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_conn.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_conv.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_conv.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_crypto.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_crypto.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_err.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_err.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_gaptr.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_idtr.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_idtr.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ksl.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_log.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_macro.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_map.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_mem.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_mem.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_net.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_objalloc.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_objalloc.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_opl.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_opl.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_path.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_path.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pkt.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pmtud.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pmtud.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ppe.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pq.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pq.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_pv.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_qlog.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_qlog.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_range.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_range.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rcvry.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_ringbuf.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rob.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rst.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_rtb.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_str.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_str.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_strm.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_unreachable.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_unreachable.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_vec.h \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_version.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_window_filter.c \
contrib/libngtcp2/ngtcp2/lib/ngtcp2_window_filter.h \
contrib/libngtcp2/ngtcp2/ngtcp2.h \
contrib/libngtcp2/ngtcp2/ngtcp2_crypto.h \
contrib/libngtcp2/ngtcp2/ngtcp2_crypto_gnutls.h \
contrib/libngtcp2/ngtcp2/version.h
contrib/libngtcp2/ngtcp2/ngtcp2_crypto_gnutls.h
endif EMBEDDED_LIBNGTCP2

View file

@ -1,335 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_acktr.h"
#include <assert.h>
#include "ngtcp2_macro.h"
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;
}
int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
ngtcp2_tstamp tstamp,
ngtcp2_objalloc *objalloc) {
*ent = ngtcp2_objalloc_acktr_entry_get(objalloc);
if (*ent == NULL) {
return NGTCP2_ERR_NOMEM;
}
acktr_entry_init(*ent, pkt_num, tstamp);
return 0;
}
void ngtcp2_acktr_entry_objalloc_del(ngtcp2_acktr_entry *ent,
ngtcp2_objalloc *objalloc) {
ngtcp2_objalloc_acktr_entry_release(objalloc, ent);
}
static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
return *(int64_t *)lhs > *(int64_t *)rhs;
}
int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
const ngtcp2_mem *mem) {
int rv;
ngtcp2_objalloc_acktr_entry_init(&acktr->objalloc, 32, mem);
rv = ngtcp2_ringbuf_init(&acktr->acks, 32, sizeof(ngtcp2_acktr_ack_entry),
mem);
if (rv != 0) {
return rv;
}
ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem);
acktr->log = log;
acktr->mem = mem;
acktr->flags = NGTCP2_ACKTR_FLAG_NONE;
acktr->first_unacked_ts = UINT64_MAX;
acktr->rx_npkt = 0;
return 0;
}
void ngtcp2_acktr_free(ngtcp2_acktr *acktr) {
#ifdef NOMEMPOOL
ngtcp2_ksl_it it;
#endif /* NOMEMPOOL */
if (acktr == NULL) {
return;
}
#ifdef NOMEMPOOL
for (it = ngtcp2_ksl_begin(&acktr->ents); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
ngtcp2_acktr_entry_objalloc_del(ngtcp2_ksl_it_get(&it), &acktr->objalloc);
}
#endif /* NOMEMPOOL */
ngtcp2_ksl_free(&acktr->ents);
ngtcp2_ringbuf_free(&acktr->acks);
ngtcp2_objalloc_free(&acktr->objalloc);
}
int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
ngtcp2_tstamp ts) {
ngtcp2_ksl_it it, prev_it;
ngtcp2_acktr_entry *ent, *prev_ent, *delent;
int rv;
int added = 0;
if (ngtcp2_ksl_len(&acktr->ents)) {
it = ngtcp2_ksl_lower_bound(&acktr->ents, &pkt_num);
if (ngtcp2_ksl_it_end(&it)) {
ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
assert(ent->pkt_num >= pkt_num + (int64_t)ent->len);
if (ent->pkt_num == pkt_num + (int64_t)ent->len) {
++ent->len;
added = 1;
}
} else {
ent = ngtcp2_ksl_it_get(&it);
assert(ent->pkt_num != pkt_num);
if (ngtcp2_ksl_it_begin(&it)) {
if (ent->pkt_num + 1 == pkt_num) {
ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num);
ent->pkt_num = pkt_num;
ent->tstamp = ts;
++ent->len;
added = 1;
}
} else {
prev_it = it;
ngtcp2_ksl_it_prev(&prev_it);
prev_ent = ngtcp2_ksl_it_get(&prev_it);
assert(prev_ent->pkt_num >= pkt_num + (int64_t)prev_ent->len);
if (ent->pkt_num + 1 == pkt_num) {
if (prev_ent->pkt_num == pkt_num + (int64_t)prev_ent->len) {
prev_ent->len += ent->len + 1;
ngtcp2_ksl_remove_hint(&acktr->ents, NULL, &it, &ent->pkt_num);
ngtcp2_acktr_entry_objalloc_del(ent, &acktr->objalloc);
added = 1;
} else {
ngtcp2_ksl_update_key(&acktr->ents, &ent->pkt_num, &pkt_num);
ent->pkt_num = pkt_num;
ent->tstamp = ts;
++ent->len;
added = 1;
}
} else if (prev_ent->pkt_num == pkt_num + (int64_t)prev_ent->len) {
++prev_ent->len;
added = 1;
}
}
}
}
if (!added) {
rv = ngtcp2_acktr_entry_objalloc_new(&ent, pkt_num, ts, &acktr->objalloc);
if (rv != 0) {
return rv;
}
rv = ngtcp2_ksl_insert(&acktr->ents, NULL, &ent->pkt_num, ent);
if (rv != 0) {
ngtcp2_acktr_entry_objalloc_del(ent, &acktr->objalloc);
return rv;
}
}
if (active_ack) {
acktr->flags |= NGTCP2_ACKTR_FLAG_ACTIVE_ACK;
if (acktr->first_unacked_ts == UINT64_MAX) {
acktr->first_unacked_ts = ts;
}
}
if (ngtcp2_ksl_len(&acktr->ents) > NGTCP2_ACKTR_MAX_ENT) {
it = ngtcp2_ksl_end(&acktr->ents);
ngtcp2_ksl_it_prev(&it);
delent = ngtcp2_ksl_it_get(&it);
ngtcp2_ksl_remove_hint(&acktr->ents, NULL, &it, &delent->pkt_num);
ngtcp2_acktr_entry_objalloc_del(delent, &acktr->objalloc);
}
return 0;
}
void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent) {
ngtcp2_ksl_it it;
it = ngtcp2_ksl_lower_bound(&acktr->ents, &ent->pkt_num);
assert(*(int64_t *)ngtcp2_ksl_it_key(&it) == (int64_t)ent->pkt_num);
for (; !ngtcp2_ksl_it_end(&it);) {
ent = ngtcp2_ksl_it_get(&it);
ngtcp2_ksl_remove_hint(&acktr->ents, &it, &it, &ent->pkt_num);
ngtcp2_acktr_entry_objalloc_del(ent, &acktr->objalloc);
}
}
ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr) {
return ngtcp2_ksl_begin(&acktr->ents);
}
int ngtcp2_acktr_empty(ngtcp2_acktr *acktr) {
ngtcp2_ksl_it it = ngtcp2_ksl_begin(&acktr->ents);
return ngtcp2_ksl_it_end(&it);
}
ngtcp2_acktr_ack_entry *ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr,
int64_t pkt_num,
int64_t largest_ack) {
ngtcp2_acktr_ack_entry *ent = ngtcp2_ringbuf_push_front(&acktr->acks);
ent->largest_ack = largest_ack;
ent->pkt_num = pkt_num;
return ent;
}
/*
* acktr_remove removes |ent| from |acktr|. |it| must point to the
* node whose key identifies |ent|. The iterator which points to the
* entry next to |ent| is assigned to |it|.
*/
static void acktr_remove(ngtcp2_acktr *acktr, ngtcp2_ksl_it *it,
ngtcp2_acktr_entry *ent) {
ngtcp2_ksl_remove_hint(&acktr->ents, it, it, &ent->pkt_num);
ngtcp2_acktr_entry_objalloc_del(ent, &acktr->objalloc);
}
static void acktr_on_ack(ngtcp2_acktr *acktr, ngtcp2_ringbuf *rb,
size_t ack_ent_offset) {
ngtcp2_acktr_ack_entry *ack_ent;
ngtcp2_acktr_entry *ent;
ngtcp2_ksl_it it;
assert(ngtcp2_ringbuf_len(rb));
ack_ent = ngtcp2_ringbuf_get(rb, ack_ent_offset);
/* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
it = ngtcp2_ksl_lower_bound(&acktr->ents, &ack_ent->largest_ack);
for (; !ngtcp2_ksl_it_end(&it);) {
ent = ngtcp2_ksl_it_get(&it);
acktr_remove(acktr, &it, ent);
}
if (ngtcp2_ksl_len(&acktr->ents)) {
assert(ngtcp2_ksl_it_end(&it));
ngtcp2_ksl_it_prev(&it);
ent = ngtcp2_ksl_it_get(&it);
if (ent->pkt_num > ack_ent->largest_ack &&
ack_ent->largest_ack >= ent->pkt_num - (int64_t)(ent->len - 1)) {
ent->len = (size_t)(ent->pkt_num - ack_ent->largest_ack);
}
}
ngtcp2_ringbuf_resize(rb, ack_ent_offset);
}
void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr) {
ngtcp2_acktr_ack_entry *ent;
int64_t largest_ack = fr->largest_ack, min_ack;
size_t i, j;
ngtcp2_ringbuf *rb = &acktr->acks;
size_t nacks = ngtcp2_ringbuf_len(rb);
/* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */
for (j = 0; j < nacks; ++j) {
ent = ngtcp2_ringbuf_get(rb, j);
if (largest_ack >= ent->pkt_num) {
break;
}
}
if (j == nacks) {
return;
}
min_ack = largest_ack - (int64_t)fr->first_ack_range;
if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) {
acktr_on_ack(acktr, rb, j);
return;
}
for (i = 0; i < fr->rangecnt && j < nacks; ++i) {
largest_ack = min_ack - (int64_t)fr->ranges[i].gap - 2;
min_ack = largest_ack - (int64_t)fr->ranges[i].len;
for (;;) {
if (ent->pkt_num > largest_ack) {
++j;
if (j == nacks) {
return;
}
ent = ngtcp2_ringbuf_get(rb, j);
continue;
}
if (ent->pkt_num < min_ack) {
break;
}
acktr_on_ack(acktr, rb, j);
return;
}
}
}
void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr) {
acktr->flags &= (uint16_t) ~(NGTCP2_ACKTR_FLAG_ACTIVE_ACK |
NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK |
NGTCP2_ACKTR_FLAG_CANCEL_TIMER);
acktr->first_unacked_ts = UINT64_MAX;
acktr->rx_npkt = 0;
}
int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr,
ngtcp2_duration max_ack_delay,
ngtcp2_tstamp ts) {
return acktr->first_unacked_ts != UINT64_MAX &&
acktr->first_unacked_ts + max_ack_delay <= ts;
}
void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
}

View file

@ -1,221 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_ACKTR_H
#define NGTCP2_ACKTR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_ringbuf.h"
#include "ngtcp2_ksl.h"
#include "ngtcp2_pkt.h"
#include "ngtcp2_objalloc.h"
/* NGTCP2_ACKTR_MAX_ENT is the maximum number of ngtcp2_acktr_entry
which ngtcp2_acktr stores. */
#define NGTCP2_ACKTR_MAX_ENT 1024
typedef struct ngtcp2_log ngtcp2_log;
/*
* ngtcp2_acktr_entry is a range of packets which need to be acked.
*/
typedef struct ngtcp2_acktr_entry {
union {
struct {
/* pkt_num is the largest packet number to acknowledge in this
range. */
int64_t pkt_num;
/* len is the consecutive packets started from pkt_num which
includes pkt_num itself counting in decreasing order. So pkt_num
= 987 and len = 2, this entry includes packet 987 and 986. */
size_t len;
/* tstamp is the timestamp when a packet denoted by pkt_num is
received. */
ngtcp2_tstamp tstamp;
};
ngtcp2_opl_entry oplent;
};
} ngtcp2_acktr_entry;
ngtcp2_objalloc_def(acktr_entry, ngtcp2_acktr_entry, oplent);
/*
* ngtcp2_acktr_entry_objalloc_new allocates memory for ent, and
* initializes it with the given parameters. The pointer to the
* allocated object is stored to |*ent|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_acktr_entry_objalloc_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
ngtcp2_tstamp tstamp,
ngtcp2_objalloc *objalloc);
/*
* ngtcp2_acktr_entry_objalloc_del deallocates memory allocated for
* |ent|.
*/
void ngtcp2_acktr_entry_objalloc_del(ngtcp2_acktr_entry *ent,
ngtcp2_objalloc *objalloc);
typedef struct ngtcp2_acktr_ack_entry {
/* largest_ack is the largest packet number in outgoing ACK frame */
int64_t largest_ack;
/* pkt_num is the packet number that ACK frame is included. */
int64_t pkt_num;
} ngtcp2_acktr_ack_entry;
/* NGTCP2_ACKTR_FLAG_NONE indicates that no flag set. */
#define NGTCP2_ACKTR_FLAG_NONE 0x00u
/* NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK indicates that immediate
acknowledgement is required. */
#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01u
/* NGTCP2_ACKTR_FLAG_ACTIVE_ACK indicates that there are pending
protected packet to be acknowledged. */
#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02u
/* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is
expired and canceled. */
#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100u
/*
* ngtcp2_acktr tracks received packets which we have to send ack.
*/
typedef struct ngtcp2_acktr {
ngtcp2_objalloc objalloc;
ngtcp2_ringbuf acks;
/* ents includes ngtcp2_acktr_entry sorted by decreasing order of
packet number. */
ngtcp2_ksl ents;
ngtcp2_log *log;
const ngtcp2_mem *mem;
/* flags is bitwise OR of zero, or more of NGTCP2_ACKTR_FLAG_*. */
uint16_t flags;
/* first_unacked_ts is timestamp when ngtcp2_acktr_entry is added
first time after the last outgoing ACK frame. */
ngtcp2_tstamp first_unacked_ts;
/* rx_npkt is the number of ACK eliciting packets received without
sending ACK. */
size_t rx_npkt;
} ngtcp2_acktr;
/*
* ngtcp2_acktr_init initializes |acktr|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_acktr_init(ngtcp2_acktr *acktr, ngtcp2_log *log,
const ngtcp2_mem *mem);
/*
* ngtcp2_acktr_free frees resources allocated for |acktr|. It frees
* any ngtcp2_acktr_entry added to |acktr|.
*/
void ngtcp2_acktr_free(ngtcp2_acktr *acktr);
/*
* ngtcp2_acktr_add adds packet number |pkt_num| to |acktr|.
* |active_ack| is nonzero if |pkt_num| is retransmittable packet.
*
* This function assumes that |acktr| does not contain |pkt_num|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* OUt of memory.
*/
int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
ngtcp2_tstamp ts);
/*
* ngtcp2_acktr_forget removes all entries which have the packet
* number that is equal to or less than ent->pkt_num. This function
* assumes that |acktr| includes |ent|.
*/
void ngtcp2_acktr_forget(ngtcp2_acktr *acktr, ngtcp2_acktr_entry *ent);
/*
* ngtcp2_acktr_get returns the pointer to pointer to the entry which
* has the largest packet number to be acked. If there is no entry,
* returned value satisfies ngtcp2_ksl_it_end(&it) != 0.
*/
ngtcp2_ksl_it ngtcp2_acktr_get(ngtcp2_acktr *acktr);
/*
* ngtcp2_acktr_empty returns nonzero if it has no packet to
* acknowledge.
*/
int ngtcp2_acktr_empty(ngtcp2_acktr *acktr);
/*
* ngtcp2_acktr_add_ack records outgoing ACK frame whose largest
* acknowledged packet number is |largest_ack|. |pkt_num| is the
* packet number of a packet in which ACK frame is included. This
* function returns a pointer to the object it adds.
*/
ngtcp2_acktr_ack_entry *
ngtcp2_acktr_add_ack(ngtcp2_acktr *acktr, int64_t pkt_num, int64_t largest_ack);
/*
* ngtcp2_acktr_recv_ack processes the incoming ACK frame |fr|.
* |pkt_num| is a packet number which includes |fr|. If we receive
* ACK which acknowledges the ACKs added by ngtcp2_acktr_add_ack,
* ngtcp2_acktr_entry which the outgoing ACK acknowledges is removed.
*/
void ngtcp2_acktr_recv_ack(ngtcp2_acktr *acktr, const ngtcp2_ack *fr);
/*
* ngtcp2_acktr_commit_ack tells |acktr| that ACK frame is generated.
*/
void ngtcp2_acktr_commit_ack(ngtcp2_acktr *acktr);
/*
* ngtcp2_acktr_require_active_ack returns nonzero if ACK frame should
* be generated actively.
*/
int ngtcp2_acktr_require_active_ack(ngtcp2_acktr *acktr,
ngtcp2_duration max_ack_delay,
ngtcp2_tstamp ts);
/*
* ngtcp2_acktr_immediate_ack tells |acktr| that immediate
* acknowledgement is required.
*/
void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr);
#endif /* NGTCP2_ACKTR_H */

View file

@ -1,117 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_addr.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_unreachable.h"
ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
ngtcp2_socklen addrlen) {
dest->addrlen = addrlen;
dest->addr = (ngtcp2_sockaddr *)addr;
return dest;
}
void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src) {
dest->addrlen = src->addrlen;
if (src->addrlen) {
memcpy(dest->addr, src->addr, (size_t)src->addrlen);
}
}
void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const ngtcp2_sockaddr *addr,
ngtcp2_socklen addrlen) {
dest->addrlen = addrlen;
if (addrlen) {
memcpy(dest->addr, addr, (size_t)addrlen);
}
}
static int sockaddr_eq(const ngtcp2_sockaddr *a, const ngtcp2_sockaddr *b) {
assert(a->sa_family == b->sa_family);
switch (a->sa_family) {
case NGTCP2_AF_INET: {
const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
*bi = (const ngtcp2_sockaddr_in *)(void *)b;
return ai->sin_port == bi->sin_port &&
memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
}
case NGTCP2_AF_INET6: {
const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
*bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
return ai->sin6_port == bi->sin6_port &&
memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
}
default:
ngtcp2_unreachable();
}
}
int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b) {
return a->addr->sa_family == b->addr->sa_family &&
sockaddr_eq(a->addr, b->addr);
}
uint32_t ngtcp2_addr_compare(const ngtcp2_addr *aa, const ngtcp2_addr *bb) {
uint32_t flags = NGTCP2_ADDR_COMPARE_FLAG_NONE;
const ngtcp2_sockaddr *a = aa->addr;
const ngtcp2_sockaddr *b = bb->addr;
if (a->sa_family != b->sa_family) {
return NGTCP2_ADDR_COMPARE_FLAG_FAMILY;
}
switch (a->sa_family) {
case NGTCP2_AF_INET: {
const ngtcp2_sockaddr_in *ai = (const ngtcp2_sockaddr_in *)(void *)a,
*bi = (const ngtcp2_sockaddr_in *)(void *)b;
if (memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr))) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_ADDR;
}
if (ai->sin_port != bi->sin_port) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_PORT;
}
return flags;
}
case NGTCP2_AF_INET6: {
const ngtcp2_sockaddr_in6 *ai = (const ngtcp2_sockaddr_in6 *)(void *)a,
*bi = (const ngtcp2_sockaddr_in6 *)(void *)b;
if (memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr))) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_ADDR;
}
if (ai->sin6_port != bi->sin6_port) {
flags |= NGTCP2_ADDR_COMPARE_FLAG_PORT;
}
return flags;
}
default:
ngtcp2_unreachable();
}
}
int ngtcp2_addr_empty(const ngtcp2_addr *addr) { return addr->addrlen == 0; }

View file

@ -1,69 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_ADDR_H
#define NGTCP2_ADDR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
/*
* ngtcp2_addr_copy copies |src| to |dest|. This function assumes
* that dest->addr points to a buffer which have sufficient size to
* store the copy.
*/
void ngtcp2_addr_copy(ngtcp2_addr *dest, const ngtcp2_addr *src);
/*
* ngtcp2_addr_eq returns nonzero if |a| equals |b|.
*/
int ngtcp2_addr_eq(const ngtcp2_addr *a, const ngtcp2_addr *b);
/* NGTCP2_ADDR_COMPARE_FLAG_NONE indicates that no flag set. */
#define NGTCP2_ADDR_COMPARE_FLAG_NONE 0x0u
/* NGTCP2_ADDR_COMPARE_FLAG_ADDR indicates IP addresses do not
match. */
#define NGTCP2_ADDR_COMPARE_FLAG_ADDR 0x1u
/* NGTCP2_ADDR_COMPARE_FLAG_PORT indicates ports do not match. */
#define NGTCP2_ADDR_COMPARE_FLAG_PORT 0x2u
/* NGTCP2_ADDR_COMPARE_FLAG_FAMILY indicates address families do not
match. */
#define NGTCP2_ADDR_COMPARE_FLAG_FAMILY 0x4u
/*
* ngtcp2_addr_compare compares address and port between |a| and |b|,
* and returns zero or more of NGTCP2_ADDR_COMPARE_FLAG_*.
*/
uint32_t ngtcp2_addr_compare(const ngtcp2_addr *a, const ngtcp2_addr *b);
/*
* ngtcp2_addr_empty returns nonzero if |addr| has zero length
* address.
*/
int ngtcp2_addr_empty(const ngtcp2_addr *addr);
#endif /* NGTCP2_ADDR_H */

View file

@ -1,90 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_balloc.h"
#include <assert.h>
#include "ngtcp2_mem.h"
void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen,
const ngtcp2_mem *mem) {
assert((blklen & 0xfu) == 0);
balloc->mem = mem;
balloc->blklen = blklen;
balloc->head = NULL;
ngtcp2_buf_init(&balloc->buf, (void *)"", 0);
}
void ngtcp2_balloc_free(ngtcp2_balloc *balloc) {
if (balloc == NULL) {
return;
}
ngtcp2_balloc_clear(balloc);
}
void ngtcp2_balloc_clear(ngtcp2_balloc *balloc) {
ngtcp2_memblock_hd *p, *next;
for (p = balloc->head; p; p = next) {
next = p->next;
ngtcp2_mem_free(balloc->mem, p);
}
balloc->head = NULL;
ngtcp2_buf_init(&balloc->buf, (void *)"", 0);
}
int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n) {
uint8_t *p;
ngtcp2_memblock_hd *hd;
assert(n <= balloc->blklen);
if (ngtcp2_buf_left(&balloc->buf) < n) {
p = ngtcp2_mem_malloc(balloc->mem,
sizeof(ngtcp2_memblock_hd) + 0x10u + balloc->blklen);
if (p == NULL) {
return NGTCP2_ERR_NOMEM;
}
hd = (ngtcp2_memblock_hd *)(void *)p;
hd->next = balloc->head;
balloc->head = hd;
ngtcp2_buf_init(
&balloc->buf,
(uint8_t *)(((uintptr_t)p + sizeof(ngtcp2_memblock_hd) + 0xfu) &
~(uintptr_t)0xfu),
balloc->blklen);
}
assert(((uintptr_t)balloc->buf.last & 0xfu) == 0);
*pbuf = balloc->buf.last;
balloc->buf.last += (n + 0xfu) & ~(uintptr_t)0xfu;
return 0;
}

View file

@ -1,91 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_BALLOC_H
#define NGTCP2_BALLOC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_buf.h"
typedef struct ngtcp2_memblock_hd ngtcp2_memblock_hd;
/*
* ngtcp2_memblock_hd is the header of memory block.
*/
struct ngtcp2_memblock_hd {
ngtcp2_memblock_hd *next;
};
/*
* ngtcp2_balloc is a custom memory allocator. It allocates |blklen|
* bytes of memory at once on demand, and returns its slice when the
* allocation is requested.
*/
typedef struct ngtcp2_balloc {
/* mem is the underlying memory allocator. */
const ngtcp2_mem *mem;
/* blklen is the size of memory block. */
size_t blklen;
/* head points to the list of memory block allocated so far. */
ngtcp2_memblock_hd *head;
/* buf wraps the current memory block for allocation requests. */
ngtcp2_buf buf;
} ngtcp2_balloc;
/*
* ngtcp2_balloc_init initializes |balloc| with |blklen| which is the
* size of memory block.
*/
void ngtcp2_balloc_init(ngtcp2_balloc *balloc, size_t blklen,
const ngtcp2_mem *mem);
/*
* ngtcp2_balloc_free releases all allocated memory blocks.
*/
void ngtcp2_balloc_free(ngtcp2_balloc *balloc);
/*
* ngtcp2_balloc_get allocates |n| bytes of memory and assigns its
* pointer to |*pbuf|.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_balloc_get(ngtcp2_balloc *balloc, void **pbuf, size_t n);
/*
* ngtcp2_balloc_clear releases all allocated memory blocks and
* initializes its state.
*/
void ngtcp2_balloc_clear(ngtcp2_balloc *balloc);
#endif /* NGTCP2_BALLOC_H */

View file

@ -1,692 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2021 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_bbr.h"
#include <assert.h>
#include "ngtcp2_log.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_mem.h"
#include "ngtcp2_rcvry.h"
#include "ngtcp2_rst.h"
static const double pacing_gain_cycle[] = {1.25, 0.75, 1, 1, 1, 1, 1, 1};
#define NGTCP2_BBR_GAIN_CYCLELEN ngtcp2_arraylen(pacing_gain_cycle)
#define NGTCP2_BBR_HIGH_GAIN 2.89
#define NGTCP2_BBR_PROBE_RTT_DURATION (200 * NGTCP2_MILLISECONDS)
#define NGTCP2_RTPROP_FILTERLEN (10 * NGTCP2_SECONDS)
#define NGTCP2_BBR_BTL_BW_FILTERLEN 10
static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts);
static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_init_round_counting(ngtcp2_bbr_cc *cc);
static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack);
static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
double pacing_gain);
static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat);
static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat);
static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack);
static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp initial_ts);
static void bbr_enter_startup(ngtcp2_bbr_cc *cc);
static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc);
static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc);
static void bbr_enter_drain(ngtcp2_bbr_cc *cc);
static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat);
static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc);
static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts);
void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_rst *rst, ngtcp2_tstamp initial_ts,
ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx,
ngtcp2_log *log) {
cc->ccb.log = log;
cc->rst = rst;
cc->rand = rand;
cc->rand_ctx = *rand_ctx;
cc->initial_cwnd = cstat->cwnd;
bbr_init(cc, cstat, initial_ts);
}
void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc) { (void)cc; }
int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
const ngtcp2_rand_ctx *rand_ctx,
const ngtcp2_mem *mem) {
ngtcp2_bbr_cc *bbr_cc;
bbr_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_bbr_cc));
if (bbr_cc == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_bbr_cc_init(bbr_cc, cstat, rst, initial_ts, rand, rand_ctx, log);
cc->ccb = &bbr_cc->ccb;
cc->on_pkt_acked = ngtcp2_cc_bbr_cc_on_pkt_acked;
cc->congestion_event = ngtcp2_cc_bbr_cc_congestion_event;
cc->on_spurious_congestion = ngtcp2_cc_bbr_cc_on_spurious_congestion;
cc->on_persistent_congestion = ngtcp2_cc_bbr_cc_on_persistent_congestion;
cc->on_ack_recv = ngtcp2_cc_bbr_cc_on_ack_recv;
cc->on_pkt_sent = ngtcp2_cc_bbr_cc_on_pkt_sent;
cc->new_rtt_sample = ngtcp2_cc_bbr_cc_new_rtt_sample;
cc->reset = ngtcp2_cc_bbr_cc_reset;
cc->event = ngtcp2_cc_bbr_cc_event;
return 0;
}
void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) {
ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_bbr_cc, ccb);
ngtcp2_bbr_cc_free(bbr_cc);
ngtcp2_mem_free(mem, bbr_cc);
}
void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts) {
(void)ccx;
(void)cstat;
(void)pkt;
(void)ts;
}
static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_time) {
return cstat->congestion_recovery_start_ts != UINT64_MAX &&
sent_time <= cstat->congestion_recovery_start_ts;
}
void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts) {
ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
if (cc->in_loss_recovery || cc->congestion_recovery_start_ts != UINT64_MAX ||
in_congestion_recovery(cstat, sent_ts)) {
return;
}
cc->congestion_recovery_start_ts = ts;
}
void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
(void)ts;
cc->congestion_recovery_start_ts = UINT64_MAX;
cstat->congestion_recovery_start_ts = UINT64_MAX;
if (cc->in_loss_recovery) {
cc->in_loss_recovery = 0;
cc->packet_conservation = 0;
bbr_restore_cwnd(cc, cstat);
}
}
void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_bbr_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
(void)ts;
cstat->congestion_recovery_start_ts = UINT64_MAX;
cc->congestion_recovery_start_ts = UINT64_MAX;
cc->in_loss_recovery = 0;
cc->packet_conservation = 0;
bbr_save_cwnd(cc, cstat);
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
}
void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
bbr_update_on_ack(bbr_cc, cstat, ack, ts);
}
void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt) {
ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
(void)pkt;
bbr_on_transmit(bbr_cc, cstat);
}
void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
(void)ccx;
(void)cstat;
(void)ts;
}
void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_bbr_cc *bbr_cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_bbr_cc, ccb);
bbr_init(bbr_cc, cstat, ts);
}
void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_cc_event_type event, ngtcp2_tstamp ts) {
(void)ccx;
(void)cstat;
(void)event;
(void)ts;
}
static void bbr_update_on_ack(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
bbr_update_model_and_state(cc, cstat, ack, ts);
bbr_update_control_parameters(cc, cstat, ack);
}
static void bbr_update_model_and_state(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts) {
bbr_update_btl_bw(cc, cstat, ack);
bbr_check_cycle_phase(cc, cstat, ack, ts);
bbr_check_full_pipe(cc);
bbr_check_drain(cc, cstat, ts);
bbr_update_rtprop(cc, cstat, ts);
bbr_check_probe_rtt(cc, cstat, ts);
}
static void bbr_update_control_parameters(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
bbr_set_pacing_rate(cc, cstat);
bbr_set_send_quantum(cc, cstat);
bbr_set_cwnd(cc, cstat, ack);
}
static void bbr_on_transmit(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
bbr_handle_restart_from_idle(cc, cstat);
}
static void bbr_init_round_counting(ngtcp2_bbr_cc *cc) {
cc->next_round_delivered = 0;
cc->round_start = 0;
cc->round_count = 0;
}
static void bbr_update_round(ngtcp2_bbr_cc *cc, const ngtcp2_cc_ack *ack) {
if (ack->pkt_delivered >= cc->next_round_delivered) {
cc->next_round_delivered = cc->rst->delivered;
++cc->round_count;
cc->round_start = 1;
return;
}
cc->round_start = 0;
}
static void bbr_handle_recovery(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
if (cc->in_loss_recovery) {
if (ack->pkt_delivered >= cc->congestion_recovery_next_round_delivered) {
cc->packet_conservation = 0;
}
if (!in_congestion_recovery(cstat, ack->largest_acked_sent_ts)) {
cc->in_loss_recovery = 0;
cc->packet_conservation = 0;
bbr_restore_cwnd(cc, cstat);
}
return;
}
if (cc->congestion_recovery_start_ts != UINT64_MAX) {
cc->in_loss_recovery = 1;
bbr_save_cwnd(cc, cstat);
cstat->cwnd =
cstat->bytes_in_flight +
ngtcp2_max(ack->bytes_delivered, cstat->max_tx_udp_payload_size);
cstat->congestion_recovery_start_ts = cc->congestion_recovery_start_ts;
cc->congestion_recovery_start_ts = UINT64_MAX;
cc->packet_conservation = 1;
cc->congestion_recovery_next_round_delivered = cc->rst->delivered;
}
}
static void bbr_update_btl_bw(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
bbr_update_round(cc, ack);
bbr_handle_recovery(cc, cstat, ack);
if (cstat->delivery_rate_sec < cc->btl_bw && cc->rst->rs.is_app_limited) {
return;
}
ngtcp2_window_filter_update(&cc->btl_bw_filter, cstat->delivery_rate_sec,
cc->round_count);
cc->btl_bw = ngtcp2_window_filter_get_best(&cc->btl_bw_filter);
}
static void bbr_update_rtprop(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
cc->rtprop_expired = ts > cc->rtprop_stamp + NGTCP2_RTPROP_FILTERLEN;
/* Need valid RTT sample */
if (cstat->latest_rtt &&
(cstat->latest_rtt <= cc->rt_prop || cc->rtprop_expired)) {
cc->rt_prop = cstat->latest_rtt;
cc->rtprop_stamp = ts;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr update RTprop=%" PRIu64, cc->rt_prop);
}
}
static void bbr_init_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
double nominal_bandwidth =
(double)cc->initial_cwnd / (double)NGTCP2_MILLISECONDS;
cstat->pacing_rate = cc->pacing_gain * nominal_bandwidth;
}
static void bbr_set_pacing_rate_with_gain(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
double pacing_gain) {
double rate = pacing_gain * (double)cc->btl_bw / NGTCP2_SECONDS;
if (cc->filled_pipe || rate > cstat->pacing_rate) {
cstat->pacing_rate = rate;
}
}
static void bbr_set_pacing_rate(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
bbr_set_pacing_rate_with_gain(cc, cstat, cc->pacing_gain);
}
static void bbr_set_send_quantum(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
uint64_t send_quantum;
(void)cc;
if (cstat->pacing_rate < 1.2 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
cstat->send_quantum = cstat->max_tx_udp_payload_size;
} else if (cstat->pacing_rate < 24.0 * 1024 * 1024 / 8 / NGTCP2_SECONDS) {
cstat->send_quantum = cstat->max_tx_udp_payload_size * 2;
} else {
send_quantum =
(uint64_t)(cstat->pacing_rate * (double)(cstat->min_rtt == UINT64_MAX
? NGTCP2_MILLISECONDS
: cstat->min_rtt));
cstat->send_quantum = (size_t)ngtcp2_min(send_quantum, 64 * 1024);
}
cstat->send_quantum =
ngtcp2_max(cstat->send_quantum, cstat->max_tx_udp_payload_size * 10);
}
static uint64_t bbr_inflight(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
double gain) {
uint64_t quanta = 3 * cstat->send_quantum;
double estimated_bdp;
if (cc->rt_prop == UINT64_MAX) {
/* no valid RTT samples yet */
return cc->initial_cwnd;
}
estimated_bdp = (double)cc->btl_bw * (double)cc->rt_prop / NGTCP2_SECONDS;
return (uint64_t)(gain * estimated_bdp) + quanta;
}
static void bbr_update_target_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
cc->target_cwnd = bbr_inflight(cc, cstat, cc->cwnd_gain);
}
static void bbr_modulate_cwnd_for_recovery(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
if (ack->bytes_lost > 0) {
if (cstat->cwnd > ack->bytes_lost) {
cstat->cwnd -= ack->bytes_lost;
cstat->cwnd = ngtcp2_max(cstat->cwnd, 2 * cstat->max_tx_udp_payload_size);
} else {
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
}
}
if (cc->packet_conservation) {
cstat->cwnd =
ngtcp2_max(cstat->cwnd, cstat->bytes_in_flight + ack->bytes_delivered);
}
}
static void bbr_save_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
if (!cc->in_loss_recovery && cc->state != NGTCP2_BBR_STATE_PROBE_RTT) {
cc->prior_cwnd = cstat->cwnd;
return;
}
cc->prior_cwnd = ngtcp2_max(cc->prior_cwnd, cstat->cwnd);
}
static void bbr_restore_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat) {
cstat->cwnd = ngtcp2_max(cstat->cwnd, cc->prior_cwnd);
}
static uint64_t min_pipe_cwnd(size_t max_udp_payload_size) {
return max_udp_payload_size * 4;
}
static void bbr_modulate_cwnd_for_probe_rtt(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat) {
if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
cstat->cwnd =
ngtcp2_min(cstat->cwnd, min_pipe_cwnd(cstat->max_tx_udp_payload_size));
}
}
static void bbr_set_cwnd(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack) {
bbr_update_target_cwnd(cc, cstat);
bbr_modulate_cwnd_for_recovery(cc, cstat, ack);
if (!cc->packet_conservation) {
if (cc->filled_pipe) {
cstat->cwnd =
ngtcp2_min(cstat->cwnd + ack->bytes_delivered, cc->target_cwnd);
} else if (cstat->cwnd < cc->target_cwnd ||
cc->rst->delivered < cc->initial_cwnd) {
cstat->cwnd += ack->bytes_delivered;
}
cstat->cwnd =
ngtcp2_max(cstat->cwnd, min_pipe_cwnd(cstat->max_tx_udp_payload_size));
}
bbr_modulate_cwnd_for_probe_rtt(cc, cstat);
}
static void bbr_init(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp initial_ts) {
cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
cc->prior_cwnd = 0;
cc->target_cwnd = 0;
cc->btl_bw = 0;
cc->rt_prop = UINT64_MAX;
cc->rtprop_stamp = initial_ts;
cc->cycle_stamp = UINT64_MAX;
cc->probe_rtt_done_stamp = UINT64_MAX;
cc->cycle_index = 0;
cc->rtprop_expired = 0;
cc->idle_restart = 0;
cc->packet_conservation = 0;
cc->probe_rtt_round_done = 0;
cc->congestion_recovery_start_ts = UINT64_MAX;
cc->congestion_recovery_next_round_delivered = 0;
cc->in_loss_recovery = 0;
cstat->send_quantum = cstat->max_tx_udp_payload_size * 10;
ngtcp2_window_filter_init(&cc->btl_bw_filter, NGTCP2_BBR_BTL_BW_FILTERLEN);
bbr_init_round_counting(cc);
bbr_init_full_pipe(cc);
bbr_init_pacing_rate(cc, cstat);
bbr_enter_startup(cc);
}
static void bbr_enter_startup(ngtcp2_bbr_cc *cc) {
cc->state = NGTCP2_BBR_STATE_STARTUP;
cc->pacing_gain = NGTCP2_BBR_HIGH_GAIN;
cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
}
static void bbr_init_full_pipe(ngtcp2_bbr_cc *cc) {
cc->filled_pipe = 0;
cc->full_bw = 0;
cc->full_bw_count = 0;
}
static void bbr_check_full_pipe(ngtcp2_bbr_cc *cc) {
if (cc->filled_pipe || !cc->round_start || cc->rst->rs.is_app_limited) {
/* no need to check for a full pipe now. */
return;
}
/* cc->btl_bw still growing? */
if (cc->btl_bw * 100 >= cc->full_bw * 125) {
/* record new baseline level */
cc->full_bw = cc->btl_bw;
cc->full_bw_count = 0;
return;
}
/* another round w/o much growth */
++cc->full_bw_count;
if (cc->full_bw_count >= 3) {
cc->filled_pipe = 1;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr filled pipe, btl_bw=%" PRIu64, cc->btl_bw);
}
}
static void bbr_enter_drain(ngtcp2_bbr_cc *cc) {
cc->state = NGTCP2_BBR_STATE_DRAIN;
/* pace slowly */
cc->pacing_gain = 1.0 / NGTCP2_BBR_HIGH_GAIN;
/* maintain cwnd */
cc->cwnd_gain = NGTCP2_BBR_HIGH_GAIN;
}
static void bbr_check_drain(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
if (cc->state == NGTCP2_BBR_STATE_STARTUP && cc->filled_pipe) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr exit Startup and enter Drain");
bbr_enter_drain(cc);
}
if (cc->state == NGTCP2_BBR_STATE_DRAIN &&
cstat->bytes_in_flight <= bbr_inflight(cc, cstat, 1.0)) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr exit Drain and enter ProbeBW");
/* we estimate queue is drained */
bbr_enter_probe_bw(cc, ts);
}
}
static void bbr_enter_probe_bw(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
uint8_t rand;
cc->state = NGTCP2_BBR_STATE_PROBE_BW;
cc->pacing_gain = 1;
cc->cwnd_gain = 2;
assert(cc->rand);
cc->rand(&rand, 1, &cc->rand_ctx);
cc->cycle_index = NGTCP2_BBR_GAIN_CYCLELEN - 1 - (size_t)(rand * 7 / 256);
bbr_advance_cycle_phase(cc, ts);
}
static void bbr_check_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
if (cc->state == NGTCP2_BBR_STATE_PROBE_BW &&
bbr_is_next_cycle_phase(cc, cstat, ack, ts)) {
bbr_advance_cycle_phase(cc, ts);
}
}
static void bbr_advance_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
cc->cycle_stamp = ts;
cc->cycle_index = (cc->cycle_index + 1) & (NGTCP2_BBR_GAIN_CYCLELEN - 1);
cc->pacing_gain = pacing_gain_cycle[cc->cycle_index];
}
static int bbr_is_next_cycle_phase(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
int is_full_length = (ts - cc->cycle_stamp) > cc->rt_prop;
if (cc->pacing_gain > 1) {
return is_full_length && (ack->bytes_lost > 0 ||
ack->prior_bytes_in_flight >=
bbr_inflight(cc, cstat, cc->pacing_gain));
}
if (cc->pacing_gain < 1) {
return is_full_length ||
ack->prior_bytes_in_flight <= bbr_inflight(cc, cstat, 1);
}
return is_full_length;
}
static void bbr_handle_restart_from_idle(ngtcp2_bbr_cc *cc,
ngtcp2_conn_stat *cstat) {
if (cstat->bytes_in_flight == 0 && cc->rst->app_limited) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr restart from idle");
cc->idle_restart = 1;
if (cc->state == NGTCP2_BBR_STATE_PROBE_BW) {
bbr_set_pacing_rate_with_gain(cc, cstat, 1);
}
}
}
static void bbr_check_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
if (cc->state != NGTCP2_BBR_STATE_PROBE_RTT && cc->rtprop_expired &&
!cc->idle_restart) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV, "bbr enter ProbeRTT");
bbr_enter_probe_rtt(cc);
bbr_save_cwnd(cc, cstat);
cc->probe_rtt_done_stamp = UINT64_MAX;
}
if (cc->state == NGTCP2_BBR_STATE_PROBE_RTT) {
bbr_handle_probe_rtt(cc, cstat, ts);
}
cc->idle_restart = 0;
}
static void bbr_enter_probe_rtt(ngtcp2_bbr_cc *cc) {
cc->state = NGTCP2_BBR_STATE_PROBE_RTT;
cc->pacing_gain = 1;
cc->cwnd_gain = 1;
}
static void bbr_handle_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
uint64_t app_limited = cc->rst->delivered + cstat->bytes_in_flight;
/* Ignore low rate samples during NGTCP2_BBR_STATE_PROBE_RTT. */
cc->rst->app_limited = app_limited ? app_limited : 1;
if (cc->probe_rtt_done_stamp == UINT64_MAX &&
cstat->bytes_in_flight <= min_pipe_cwnd(cstat->max_tx_udp_payload_size)) {
cc->probe_rtt_done_stamp = ts + NGTCP2_BBR_PROBE_RTT_DURATION;
cc->probe_rtt_round_done = 0;
cc->next_round_delivered = cc->rst->delivered;
return;
}
if (cc->probe_rtt_done_stamp != UINT64_MAX) {
if (cc->round_start) {
cc->probe_rtt_round_done = 1;
}
if (cc->probe_rtt_round_done && ts > cc->probe_rtt_done_stamp) {
cc->rtprop_stamp = ts;
bbr_restore_cwnd(cc, cstat);
bbr_exit_probe_rtt(cc, ts);
}
}
}
static void bbr_exit_probe_rtt(ngtcp2_bbr_cc *cc, ngtcp2_tstamp ts) {
if (cc->filled_pipe) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr exit ProbeRTT and enter ProbeBW");
bbr_enter_probe_bw(cc, ts);
return;
}
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"bbr exit ProbeRTT and enter Startup");
bbr_enter_startup(cc);
}

View file

@ -1,156 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2021 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_BBR_H
#define NGTCP2_BBR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_cc.h"
#include "ngtcp2_window_filter.h"
typedef struct ngtcp2_rst ngtcp2_rst;
typedef enum ngtcp2_bbr_state {
NGTCP2_BBR_STATE_STARTUP,
NGTCP2_BBR_STATE_DRAIN,
NGTCP2_BBR_STATE_PROBE_BW,
NGTCP2_BBR_STATE_PROBE_RTT,
} ngtcp2_bbr_state;
/*
* ngtcp2_bbr_cc is BBR congestion controller, described in
* https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00
*/
typedef struct ngtcp2_bbr_cc {
ngtcp2_cc_base ccb;
/* The max filter used to estimate BBR.BtlBw. */
ngtcp2_window_filter btl_bw_filter;
uint64_t initial_cwnd;
ngtcp2_rst *rst;
ngtcp2_rand rand;
ngtcp2_rand_ctx rand_ctx;
/* BBR variables */
/* The dynamic gain factor used to scale BBR.BtlBw to
produce BBR.pacing_rate. */
double pacing_gain;
/* The dynamic gain factor used to scale the estimated BDP to produce a
congestion window (cwnd). */
double cwnd_gain;
uint64_t full_bw;
/* packet.delivered value denoting the end of a packet-timed round trip. */
uint64_t next_round_delivered;
/* Count of packet-timed round trips. */
uint64_t round_count;
uint64_t prior_cwnd;
/* target_cwnd is the upper bound on the volume of data BBR
allows in flight. */
uint64_t target_cwnd;
/* BBR's estimated bottleneck bandwidth available to the
transport flow, estimated from the maximum delivery rate sample in a
sliding window. */
uint64_t btl_bw;
/* BBR's estimated two-way round-trip propagation delay of
the path, estimated from the windowed minimum recent round-trip delay
sample. */
ngtcp2_duration rt_prop;
/* The wall clock time at which the current BBR.RTProp
sample was obtained. */
ngtcp2_tstamp rtprop_stamp;
ngtcp2_tstamp cycle_stamp;
ngtcp2_tstamp probe_rtt_done_stamp;
/* congestion_recovery_start_ts is the time when congestion recovery
period started.*/
ngtcp2_tstamp congestion_recovery_start_ts;
uint64_t congestion_recovery_next_round_delivered;
size_t full_bw_count;
size_t cycle_index;
ngtcp2_bbr_state state;
/* A boolean that records whether BBR estimates that it has ever fully
utilized its available bandwidth ("filled the pipe"). */
int filled_pipe;
/* A boolean that BBR sets to true once per packet-timed round trip,
on ACKs that advance BBR.round_count. */
int round_start;
int rtprop_expired;
int idle_restart;
int packet_conservation;
int probe_rtt_round_done;
/* in_loss_recovery becomes nonzero when BBR enters loss recovery
period. */
int in_loss_recovery;
} ngtcp2_bbr_cc;
int ngtcp2_cc_bbr_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
const ngtcp2_rand_ctx *rand_ctx,
const ngtcp2_mem *mem);
void ngtcp2_cc_bbr_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem);
void ngtcp2_bbr_cc_init(ngtcp2_bbr_cc *bbr_cc, ngtcp2_conn_stat *cstat,
ngtcp2_rst *rst, ngtcp2_tstamp initial_ts,
ngtcp2_rand rand, const ngtcp2_rand_ctx *rand_ctx,
ngtcp2_log *log);
void ngtcp2_bbr_cc_free(ngtcp2_bbr_cc *cc);
void ngtcp2_cc_bbr_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts, ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_on_spurious_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_on_persistent_congestion(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt);
void ngtcp2_cc_bbr_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_bbr_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
#endif /* NGTCP2_BBR_H */

File diff suppressed because it is too large Load diff

View file

@ -1,149 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2021 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_BBR2_H
#define NGTCP2_BBR2_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_cc.h"
#include "ngtcp2_window_filter.h"
typedef struct ngtcp2_rst ngtcp2_rst;
typedef enum ngtcp2_bbr2_state {
NGTCP2_BBR2_STATE_STARTUP,
NGTCP2_BBR2_STATE_DRAIN,
NGTCP2_BBR2_STATE_PROBE_BW_DOWN,
NGTCP2_BBR2_STATE_PROBE_BW_CRUISE,
NGTCP2_BBR2_STATE_PROBE_BW_REFILL,
NGTCP2_BBR2_STATE_PROBE_BW_UP,
NGTCP2_BBR2_STATE_PROBE_RTT,
} ngtcp2_bbr2_state;
typedef enum ngtcp2_bbr2_ack_phase {
NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STARTING,
NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_STOPPING,
NGTCP2_BBR2_ACK_PHASE_ACKS_PROBE_FEEDBACK,
NGTCP2_BBR2_ACK_PHASE_ACKS_REFILLING,
} ngtcp2_bbr2_ack_phase;
/*
* ngtcp2_bbr2_cc is BBR v2 congestion controller, described in
* https://datatracker.ietf.org/doc/html/draft-cardwell-iccrg-bbr-congestion-control-01
*/
typedef struct ngtcp2_bbr2_cc {
ngtcp2_cc_base ccb;
uint64_t initial_cwnd;
ngtcp2_rst *rst;
ngtcp2_rand rand;
ngtcp2_rand_ctx rand_ctx;
/* max_bw_filter for tracking the maximum recent delivery rate
samples for estimating max_bw. */
ngtcp2_window_filter max_bw_filter;
ngtcp2_window_filter extra_acked_filter;
ngtcp2_duration min_rtt;
ngtcp2_tstamp min_rtt_stamp;
ngtcp2_tstamp probe_rtt_done_stamp;
int probe_rtt_round_done;
uint64_t prior_cwnd;
int idle_restart;
ngtcp2_tstamp extra_acked_interval_start;
uint64_t extra_acked_delivered;
/* Congestion signals */
int loss_in_round;
uint64_t bw_latest;
uint64_t inflight_latest;
/* Lower bounds */
uint64_t bw_lo;
uint64_t inflight_lo;
/* Round counting */
uint64_t next_round_delivered;
int round_start;
uint64_t round_count;
/* Full pipe */
int filled_pipe;
uint64_t full_bw;
size_t full_bw_count;
/* Pacing rate */
double pacing_gain;
ngtcp2_bbr2_state state;
double cwnd_gain;
int loss_round_start;
uint64_t loss_round_delivered;
uint64_t rounds_since_bw_probe;
uint64_t max_bw;
uint64_t bw;
uint64_t cycle_count;
uint64_t extra_acked;
uint64_t bytes_lost_in_round;
size_t loss_events_in_round;
uint64_t offload_budget;
uint64_t probe_up_cnt;
ngtcp2_tstamp cycle_stamp;
ngtcp2_bbr2_ack_phase ack_phase;
ngtcp2_duration bw_probe_wait;
int bw_probe_samples;
size_t bw_probe_up_rounds;
uint64_t bw_probe_up_acks;
uint64_t inflight_hi;
uint64_t bw_hi;
int probe_rtt_expired;
ngtcp2_duration probe_rtt_min_delay;
ngtcp2_tstamp probe_rtt_min_stamp;
int in_loss_recovery;
int packet_conservation;
uint64_t max_inflight;
ngtcp2_tstamp congestion_recovery_start_ts;
uint64_t congestion_recovery_next_round_delivered;
uint64_t prior_inflight_lo;
uint64_t prior_inflight_hi;
uint64_t prior_bw_lo;
} ngtcp2_bbr2_cc;
int ngtcp2_cc_bbr2_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
ngtcp2_conn_stat *cstat, ngtcp2_rst *rst,
ngtcp2_tstamp initial_ts, ngtcp2_rand rand,
const ngtcp2_rand_ctx *rand_ctx,
const ngtcp2_mem *mem);
void ngtcp2_cc_bbr2_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem);
#endif /* NGTCP2_BBR2_H */

View file

@ -1,56 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_buf.h"
#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;
}
void ngtcp2_buf_reset(ngtcp2_buf *buf) { buf->pos = buf->last = buf->begin; }
size_t ngtcp2_buf_cap(const ngtcp2_buf *buf) {
return (size_t)(buf->end - buf->begin);
}
int ngtcp2_buf_chain_new(ngtcp2_buf_chain **pbufchain, size_t len,
const ngtcp2_mem *mem) {
*pbufchain = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_buf_chain) + len);
if (*pbufchain == NULL) {
return NGTCP2_ERR_NOMEM;
}
(*pbufchain)->next = NULL;
ngtcp2_buf_init(&(*pbufchain)->buf,
(uint8_t *)(*pbufchain) + sizeof(ngtcp2_buf_chain), len);
return 0;
}
void ngtcp2_buf_chain_del(ngtcp2_buf_chain *bufchain, const ngtcp2_mem *mem) {
ngtcp2_mem_free(mem, bufchain);
}

View file

@ -1,108 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_BUF_H
#define NGTCP2_BUF_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
typedef struct ngtcp2_buf {
/* begin points to the beginning of the buffer. */
uint8_t *begin;
/* end points to the one beyond of the last byte of the buffer */
uint8_t *end;
/* pos pointers to the start of data. Typically, this points to the
point that next data should be read. Initially, it points to
|begin|. */
uint8_t *pos;
/* last points to the one beyond of the last data of the buffer.
Typically, new data is written at this point. Initially, it
points to |begin|. */
uint8_t *last;
} ngtcp2_buf;
/*
* ngtcp2_buf_init initializes |buf| with the given buffer.
*/
void ngtcp2_buf_init(ngtcp2_buf *buf, uint8_t *begin, size_t len);
/*
* ngtcp2_buf_reset resets pos and last fields to match begin field to
* make ngtcp2_buf_len(buf) return 0.
*/
void ngtcp2_buf_reset(ngtcp2_buf *buf);
/*
* ngtcp2_buf_left returns the number of additional bytes which can be
* written to the underlying buffer. In other words, it returns
* buf->end - buf->last.
*/
#define ngtcp2_buf_left(BUF) (size_t)((BUF)->end - (BUF)->last)
/*
* ngtcp2_buf_len returns the number of bytes left to read. In other
* words, it returns buf->last - buf->pos.
*/
#define ngtcp2_buf_len(BUF) (size_t)((BUF)->last - (BUF)->pos)
/*
* ngtcp2_buf_cap returns the capacity of the buffer. In other words,
* it returns buf->end - buf->begin.
*/
size_t ngtcp2_buf_cap(const ngtcp2_buf *buf);
/*
* ngtcp2_buf_chain is a linked list of ngtcp2_buf.
*/
typedef struct ngtcp2_buf_chain ngtcp2_buf_chain;
struct ngtcp2_buf_chain {
ngtcp2_buf_chain *next;
ngtcp2_buf buf;
};
/*
* ngtcp2_buf_chain_new creates new ngtcp2_buf_chain and initializes
* the internal buffer with |len| bytes space.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_buf_chain_new(ngtcp2_buf_chain **pbufchain, size_t len,
const ngtcp2_mem *mem);
/*
* ngtcp2_buf_chain_del deletes the resource allocated by |bufchain|.
* It also deletes the memory pointed by |bufchain|.
*/
void ngtcp2_buf_chain_del(ngtcp2_buf_chain *bufchain, const ngtcp2_mem *mem);
#endif /* NGTCP2_BUF_H */

View file

@ -1,615 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_cc.h"
#include <assert.h>
#if defined(_MSC_VER)
# include <intrin.h>
#endif
#include "ngtcp2_log.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_mem.h"
#include "ngtcp2_rcvry.h"
uint64_t ngtcp2_cc_compute_initcwnd(size_t max_udp_payload_size) {
uint64_t n = 2 * max_udp_payload_size;
n = ngtcp2_max(n, 14720);
return ngtcp2_min(10 * max_udp_payload_size, n);
}
ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
size_t pktlen, ngtcp2_pktns_id pktns_id,
ngtcp2_tstamp sent_ts, uint64_t lost,
uint64_t tx_in_flight, int is_app_limited) {
pkt->pkt_num = pkt_num;
pkt->pktlen = pktlen;
pkt->pktns_id = pktns_id;
pkt->sent_ts = sent_ts;
pkt->lost = lost;
pkt->tx_in_flight = tx_in_flight;
pkt->is_app_limited = is_app_limited;
return pkt;
}
static void reno_cc_reset(ngtcp2_reno_cc *cc) {
cc->max_delivery_rate_sec = 0;
cc->target_cwnd = 0;
cc->pending_add = 0;
}
void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log) {
cc->ccb.log = log;
reno_cc_reset(cc);
}
void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc) { (void)cc; }
int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
const ngtcp2_mem *mem) {
ngtcp2_reno_cc *reno_cc;
reno_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_reno_cc));
if (reno_cc == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_reno_cc_init(reno_cc, log);
cc->ccb = &reno_cc->ccb;
cc->on_pkt_acked = ngtcp2_cc_reno_cc_on_pkt_acked;
cc->congestion_event = ngtcp2_cc_reno_cc_congestion_event;
cc->on_persistent_congestion = ngtcp2_cc_reno_cc_on_persistent_congestion;
cc->on_ack_recv = ngtcp2_cc_reno_cc_on_ack_recv;
cc->reset = ngtcp2_cc_reno_cc_reset;
return 0;
}
void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) {
ngtcp2_reno_cc *reno_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_reno_cc, ccb);
ngtcp2_reno_cc_free(reno_cc);
ngtcp2_mem_free(mem, reno_cc);
}
static int in_congestion_recovery(const ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_time) {
return cstat->congestion_recovery_start_ts != UINT64_MAX &&
sent_time <= cstat->congestion_recovery_start_ts;
}
void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt,
ngtcp2_tstamp ts) {
ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
uint64_t m;
(void)ts;
if (in_congestion_recovery(cstat, pkt->sent_ts)) {
return;
}
if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) {
return;
}
if (cstat->cwnd < cstat->ssthresh) {
cstat->cwnd += pkt->pktlen;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
pkt->pkt_num, cstat->cwnd);
return;
}
m = cstat->max_tx_udp_payload_size * pkt->pktlen + cc->pending_add;
cc->pending_add = m % cstat->cwnd;
cstat->cwnd += m / cstat->cwnd;
}
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts) {
ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
uint64_t min_cwnd;
if (in_congestion_recovery(cstat, sent_ts)) {
return;
}
cstat->congestion_recovery_start_ts = ts;
cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS;
min_cwnd = 2 * cstat->max_tx_udp_payload_size;
cstat->cwnd = ngtcp2_max(cstat->cwnd, min_cwnd);
cstat->ssthresh = cstat->cwnd;
cc->pending_add = 0;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"reduce cwnd because of packet loss cwnd=%" PRIu64,
cstat->cwnd);
}
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
(void)ccx;
(void)ts;
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
cstat->congestion_recovery_start_ts = UINT64_MAX;
}
void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts) {
ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
uint64_t target_cwnd, initcwnd;
(void)ack;
(void)ts;
/* TODO Use sliding window for min rtt measurement */
/* TODO Use sliding window */
cc->max_delivery_rate_sec =
ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec);
if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) {
target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS;
initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size);
cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64
" min_rtt=%" PRIu64,
cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt);
}
}
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
(void)cstat;
(void)ts;
reno_cc_reset(cc);
}
static void cubic_cc_reset(ngtcp2_cubic_cc *cc) {
cc->max_delivery_rate_sec = 0;
cc->target_cwnd = 0;
cc->w_last_max = 0;
cc->w_tcp = 0;
cc->origin_point = 0;
cc->epoch_start = UINT64_MAX;
cc->k = 0;
cc->prior.cwnd = 0;
cc->prior.ssthresh = 0;
cc->prior.w_last_max = 0;
cc->prior.w_tcp = 0;
cc->prior.origin_point = 0;
cc->prior.epoch_start = UINT64_MAX;
cc->prior.k = 0;
cc->rtt_sample_count = 0;
cc->current_round_min_rtt = UINT64_MAX;
cc->last_round_min_rtt = UINT64_MAX;
cc->window_end = -1;
}
void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log) {
cc->ccb.log = log;
cubic_cc_reset(cc);
}
void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc) { (void)cc; }
int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
const ngtcp2_mem *mem) {
ngtcp2_cubic_cc *cubic_cc;
cubic_cc = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_cubic_cc));
if (cubic_cc == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_cubic_cc_init(cubic_cc, log);
cc->ccb = &cubic_cc->ccb;
cc->on_pkt_acked = ngtcp2_cc_cubic_cc_on_pkt_acked;
cc->congestion_event = ngtcp2_cc_cubic_cc_congestion_event;
cc->on_spurious_congestion = ngtcp2_cc_cubic_cc_on_spurious_congestion;
cc->on_persistent_congestion = ngtcp2_cc_cubic_cc_on_persistent_congestion;
cc->on_ack_recv = ngtcp2_cc_cubic_cc_on_ack_recv;
cc->on_pkt_sent = ngtcp2_cc_cubic_cc_on_pkt_sent;
cc->new_rtt_sample = ngtcp2_cc_cubic_cc_new_rtt_sample;
cc->reset = ngtcp2_cc_cubic_cc_reset;
cc->event = ngtcp2_cc_cubic_cc_event;
return 0;
}
void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem) {
ngtcp2_cubic_cc *cubic_cc = ngtcp2_struct_of(cc->ccb, ngtcp2_cubic_cc, ccb);
ngtcp2_cubic_cc_free(cubic_cc);
ngtcp2_mem_free(mem, cubic_cc);
}
static uint64_t ngtcp2_cbrt(uint64_t n) {
int d;
uint64_t a;
if (n == 0) {
return 0;
}
#if defined(_MSC_VER)
# if defined(_M_X64)
d = (int)__lzcnt64(n);
# elif defined(_M_ARM64)
{
unsigned long index;
d = sizeof(uint64_t) * CHAR_BIT;
if (_BitScanReverse64(&index, n)) {
d = d - 1 - index;
}
}
# else
if ((n >> 32) != 0) {
d = __lzcnt((unsigned int)(n >> 32));
} else {
d = 32 + __lzcnt((unsigned int)n);
}
# endif
#else
d = __builtin_clzll(n);
#endif
a = 1ULL << ((64 - d) / 3 + 1);
for (; a * a * a > n;) {
a = (2 * a + n / a / a) / 3;
}
return a;
}
/* HyStart++ constants */
#define NGTCP2_HS_MIN_SSTHRESH 16
#define NGTCP2_HS_N_RTT_SAMPLE 8
#define NGTCP2_HS_MIN_ETA (4 * NGTCP2_MILLISECONDS)
#define NGTCP2_HS_MAX_ETA (16 * NGTCP2_MILLISECONDS)
void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
ngtcp2_duration t, eta;
uint64_t target, cwnd_thres;
uint64_t tx, kx, time_delta, delta;
uint64_t add, tcp_add;
uint64_t m;
if (pkt->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && cc->window_end != -1 &&
cc->window_end <= pkt->pkt_num) {
cc->window_end = -1;
}
if (in_congestion_recovery(cstat, pkt->sent_ts)) {
return;
}
if (cc->target_cwnd && cc->target_cwnd < cstat->cwnd) {
return;
}
if (cstat->cwnd < cstat->ssthresh) {
/* slow-start */
cstat->cwnd += pkt->pktlen;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"pkn=%" PRId64 " acked, slow start cwnd=%" PRIu64,
pkt->pkt_num, cstat->cwnd);
if (cc->last_round_min_rtt != UINT64_MAX &&
cc->current_round_min_rtt != UINT64_MAX &&
cstat->cwnd >=
NGTCP2_HS_MIN_SSTHRESH * cstat->max_tx_udp_payload_size &&
cc->rtt_sample_count >= NGTCP2_HS_N_RTT_SAMPLE) {
eta = cc->last_round_min_rtt / 8;
if (eta < NGTCP2_HS_MIN_ETA) {
eta = NGTCP2_HS_MIN_ETA;
} else if (eta > NGTCP2_HS_MAX_ETA) {
eta = NGTCP2_HS_MAX_ETA;
}
if (cc->current_round_min_rtt >= cc->last_round_min_rtt + eta) {
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"HyStart++ exit slow start");
cc->w_last_max = cstat->cwnd;
cstat->ssthresh = cstat->cwnd;
}
}
return;
}
/* congestion avoidance */
if (cc->epoch_start == UINT64_MAX) {
cc->epoch_start = ts;
if (cstat->cwnd < cc->w_last_max) {
cc->k = ngtcp2_cbrt((cc->w_last_max - cstat->cwnd) * 10 / 4 /
cstat->max_tx_udp_payload_size);
cc->origin_point = cc->w_last_max;
} else {
cc->k = 0;
cc->origin_point = cstat->cwnd;
}
cc->w_tcp = cstat->cwnd;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"cubic-ca epoch_start=%" PRIu64 " k=%" PRIu64
" origin_point=%" PRIu64,
cc->epoch_start, cc->k, cc->origin_point);
cc->pending_add = 0;
cc->pending_w_add = 0;
}
t = ts - cc->epoch_start;
tx = (t << 10) / NGTCP2_SECONDS;
kx = (cc->k << 10);
if (tx > kx) {
time_delta = tx - kx;
} else {
time_delta = kx - tx;
}
delta = cstat->max_tx_udp_payload_size *
((((time_delta * time_delta) >> 10) * time_delta) >> 10) * 4 / 10;
delta >>= 10;
if (tx > kx) {
target = cc->origin_point + delta;
} else {
target = cc->origin_point - delta;
}
cwnd_thres =
(target * (((t + cstat->smoothed_rtt) << 10) / NGTCP2_SECONDS)) >> 10;
if (cwnd_thres < cstat->cwnd) {
target = cstat->cwnd;
} else if (2 * cwnd_thres > 3 * cstat->cwnd) {
target = cstat->cwnd * 3 / 2;
} else {
target = cwnd_thres;
}
if (target > cstat->cwnd) {
m = cc->pending_add +
cstat->max_tx_udp_payload_size * (target - cstat->cwnd);
add = m / cstat->cwnd;
cc->pending_add = m % cstat->cwnd;
} else {
m = cc->pending_add + cstat->max_tx_udp_payload_size;
add = m / (100 * cstat->cwnd);
cc->pending_add = m % (100 * cstat->cwnd);
}
m = cc->pending_w_add + cstat->max_tx_udp_payload_size * pkt->pktlen;
cc->w_tcp += m / cstat->cwnd;
cc->pending_w_add = m % cstat->cwnd;
if (cc->w_tcp > cstat->cwnd) {
tcp_add = cstat->max_tx_udp_payload_size * (cc->w_tcp - cstat->cwnd) /
cstat->cwnd;
if (tcp_add > add) {
add = tcp_add;
}
}
cstat->cwnd += add;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"pkn=%" PRId64 " acked, cubic-ca cwnd=%" PRIu64 " t=%" PRIu64
" k=%" PRIi64 " time_delta=%" PRIu64 " delta=%" PRIu64
" target=%" PRIu64 " w_tcp=%" PRIu64,
pkt->pkt_num, cstat->cwnd, t, cc->k, time_delta >> 4, delta,
target, cc->w_tcp);
}
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
uint64_t min_cwnd;
if (in_congestion_recovery(cstat, sent_ts)) {
return;
}
if (cc->prior.cwnd < cstat->cwnd) {
cc->prior.cwnd = cstat->cwnd;
cc->prior.ssthresh = cstat->ssthresh;
cc->prior.w_last_max = cc->w_last_max;
cc->prior.w_tcp = cc->w_tcp;
cc->prior.origin_point = cc->origin_point;
cc->prior.epoch_start = cc->epoch_start;
cc->prior.k = cc->k;
}
cstat->congestion_recovery_start_ts = ts;
cc->epoch_start = UINT64_MAX;
if (cstat->cwnd < cc->w_last_max) {
cc->w_last_max = cstat->cwnd * 17 / 10 / 2;
} else {
cc->w_last_max = cstat->cwnd;
}
min_cwnd = 2 * cstat->max_tx_udp_payload_size;
cstat->ssthresh = cstat->cwnd * 7 / 10;
cstat->ssthresh = ngtcp2_max(cstat->ssthresh, min_cwnd);
cstat->cwnd = cstat->ssthresh;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"reduce cwnd because of packet loss cwnd=%" PRIu64,
cstat->cwnd);
}
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
(void)ts;
if (cstat->cwnd >= cc->prior.cwnd) {
return;
}
cstat->congestion_recovery_start_ts = UINT64_MAX;
cstat->cwnd = cc->prior.cwnd;
cstat->ssthresh = cc->prior.ssthresh;
cc->w_last_max = cc->prior.w_last_max;
cc->w_tcp = cc->prior.w_tcp;
cc->origin_point = cc->prior.origin_point;
cc->epoch_start = cc->prior.epoch_start;
cc->k = cc->prior.k;
cc->prior.cwnd = 0;
cc->prior.ssthresh = 0;
cc->prior.w_last_max = 0;
cc->prior.w_tcp = 0;
cc->prior.origin_point = 0;
cc->prior.epoch_start = UINT64_MAX;
cc->prior.k = 0;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"spurious congestion is detected and congestion state is "
"restored cwnd=%" PRIu64,
cstat->cwnd);
}
void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
(void)ccx;
(void)ts;
cstat->cwnd = 2 * cstat->max_tx_udp_payload_size;
cstat->congestion_recovery_start_ts = UINT64_MAX;
}
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
uint64_t target_cwnd, initcwnd;
(void)ack;
(void)ts;
/* TODO Use sliding window for min rtt measurement */
/* TODO Use sliding window */
cc->max_delivery_rate_sec =
ngtcp2_max(cc->max_delivery_rate_sec, cstat->delivery_rate_sec);
if (cstat->min_rtt != UINT64_MAX && cc->max_delivery_rate_sec) {
target_cwnd = cc->max_delivery_rate_sec * cstat->min_rtt / NGTCP2_SECONDS;
initcwnd = ngtcp2_cc_compute_initcwnd(cstat->max_tx_udp_payload_size);
cc->target_cwnd = ngtcp2_max(initcwnd, target_cwnd) * 289 / 100;
ngtcp2_log_info(cc->ccb.log, NGTCP2_LOG_EVENT_RCV,
"target_cwnd=%" PRIu64 " max_delivery_rate_sec=%" PRIu64
" min_rtt=%" PRIu64,
cc->target_cwnd, cc->max_delivery_rate_sec, cstat->min_rtt);
}
}
void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
(void)cstat;
if (pkt->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || cc->window_end != -1) {
return;
}
cc->window_end = pkt->pkt_num;
cc->last_round_min_rtt = cc->current_round_min_rtt;
cc->current_round_min_rtt = UINT64_MAX;
cc->rtt_sample_count = 0;
}
void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
(void)ts;
if (cc->window_end == -1) {
return;
}
cc->current_round_min_rtt =
ngtcp2_min(cc->current_round_min_rtt, cstat->latest_rtt);
++cc->rtt_sample_count;
}
void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
(void)cstat;
(void)ts;
cubic_cc_reset(cc);
}
void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *ccx, ngtcp2_conn_stat *cstat,
ngtcp2_cc_event_type event, ngtcp2_tstamp ts) {
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
ngtcp2_tstamp last_ts;
if (event != NGTCP2_CC_EVENT_TYPE_TX_START || cc->epoch_start == UINT64_MAX) {
return;
}
last_ts = cstat->last_tx_pkt_ts[NGTCP2_PKTNS_ID_APPLICATION];
if (last_ts == UINT64_MAX || last_ts <= cc->epoch_start) {
return;
}
assert(ts >= last_ts);
cc->epoch_start += ts - last_ts;
}

View file

@ -1,421 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CC_H
#define NGTCP2_CC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#define NGTCP2_LOSS_REDUCTION_FACTOR_BITS 1
#define NGTCP2_PERSISTENT_CONGESTION_THRESHOLD 3
typedef struct ngtcp2_log ngtcp2_log;
/**
* @struct
*
* :type:`ngtcp2_cc_base` is the base structure of custom congestion
* control algorithm. It must be the first field of custom congestion
* controller.
*/
typedef struct ngtcp2_cc_base {
/**
* :member:`log` is ngtcp2 library internal logger.
*/
ngtcp2_log *log;
} ngtcp2_cc_base;
/**
* @struct
*
* :type:`ngtcp2_cc_pkt` is a convenient structure to include
* acked/lost/sent packet.
*/
typedef struct ngtcp2_cc_pkt {
/**
* :member:`pkt_num` is the packet number
*/
int64_t pkt_num;
/**
* :member:`pktlen` is the length of packet.
*/
size_t pktlen;
/**
* :member:`pktns_id` is the ID of packet number space which this
* packet belongs to.
*/
ngtcp2_pktns_id pktns_id;
/**
* :member:`sent_ts` is the timestamp when packet is sent.
*/
ngtcp2_tstamp sent_ts;
/**
* :member:`lost` is the number of bytes lost when this packet was
* sent.
*/
uint64_t lost;
/**
* :member:`tx_in_flight` is the bytes in flight when this packet
* was sent.
*/
uint64_t tx_in_flight;
/**
* :member:`is_app_limited` is nonzero if the connection is
* app-limited when this packet was sent.
*/
int is_app_limited;
} ngtcp2_cc_pkt;
/**
* @struct
*
* :type:`ngtcp2_cc_ack` is a convenient structure which stores
* acknowledged and lost bytes.
*/
typedef struct ngtcp2_cc_ack {
/**
* :member:`prior_bytes_in_flight` is the in-flight bytes before
* processing this ACK.
*/
uint64_t prior_bytes_in_flight;
/**
* :member:`bytes_delivered` is the number of bytes acknowledged.
*/
uint64_t bytes_delivered;
/**
* :member:`bytes_lost` is the number of bytes declared lost.
*/
uint64_t bytes_lost;
/**
* :member:`pkt_delivered` is the cumulative acknowledged bytes when
* the last packet acknowledged by this ACK was sent.
*/
uint64_t pkt_delivered;
/**
* :member:`largest_acked_sent_ts` is the time when the largest
* acknowledged packet was sent.
*/
ngtcp2_tstamp largest_acked_sent_ts;
/**
* :member:`rtt` is the RTT sample. It is UINT64_MAX if no RTT
* sample is available.
*/
ngtcp2_duration rtt;
} ngtcp2_cc_ack;
typedef struct ngtcp2_cc ngtcp2_cc;
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_pkt_acked` is a callback function which is
* called with an acknowledged packet.
*/
typedef void (*ngtcp2_cc_on_pkt_acked)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_pkt_lost` is a callback function which is
* called with a lost packet.
*/
typedef void (*ngtcp2_cc_on_pkt_lost)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_congestion_event` is a callback function which is
* called when congestion event happens (e.g., when packet is lost).
*/
typedef void (*ngtcp2_cc_congestion_event)(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_spurious_congestion` is a callback function
* which is called when a spurious congestion is detected.
*/
typedef void (*ngtcp2_cc_on_spurious_congestion)(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_persistent_congestion` is a callback function
* which is called when persistent congestion is established.
*/
typedef void (*ngtcp2_cc_on_persistent_congestion)(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_ack_recv` is a callback function which is
* called when an acknowledgement is received.
*/
typedef void (*ngtcp2_cc_on_ack_recv)(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack,
ngtcp2_tstamp ts);
/**
* @functypedef
*
* :type:`ngtcp2_cc_on_pkt_sent` is a callback function which is
* called when an ack-eliciting packet is sent.
*/
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
*
* :type:`ngtcp2_cc_reset` is a callback function which is called when
* congestion state must be reset.
*/
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
*
* :type:`ngtcp2_cc` is congestion control algorithm interface to
* allow custom implementation.
*/
typedef struct ngtcp2_cc {
/**
* :member:`ccb` is a pointer to :type:`ngtcp2_cc_base` which
* usually contains a state.
*/
ngtcp2_cc_base *ccb;
/**
* :member:`on_pkt_acked` is a callback function which is called
* when a packet is acknowledged.
*/
ngtcp2_cc_on_pkt_acked on_pkt_acked;
/**
* :member:`on_pkt_lost` is a callback function which is called when
* a packet is lost.
*/
ngtcp2_cc_on_pkt_lost on_pkt_lost;
/**
* :member:`congestion_event` is a callback function which is called
* when congestion event happens (.e.g, packet is lost).
*/
ngtcp2_cc_congestion_event congestion_event;
/**
* :member:`on_spurious_congestion` is a callback function which is
* called when a spurious congestion is detected.
*/
ngtcp2_cc_on_spurious_congestion on_spurious_congestion;
/**
* :member:`on_persistent_congestion` is a callback function which
* is called when persistent congestion is established.
*/
ngtcp2_cc_on_persistent_congestion on_persistent_congestion;
/**
* :member:`on_ack_recv` is a callback function which is called when
* an acknowledgement is received.
*/
ngtcp2_cc_on_ack_recv on_ack_recv;
/**
* :member:`on_pkt_sent` is a callback function which is called when
* 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;
/*
* ngtcp2_cc_compute_initcwnd computes initial cwnd.
*/
uint64_t ngtcp2_cc_compute_initcwnd(size_t max_packet_size);
ngtcp2_cc_pkt *ngtcp2_cc_pkt_init(ngtcp2_cc_pkt *pkt, int64_t pkt_num,
size_t pktlen, ngtcp2_pktns_id pktns_id,
ngtcp2_tstamp sent_ts, uint64_t lost,
uint64_t tx_in_flight, int is_app_limited);
/* ngtcp2_reno_cc is the RENO congestion controller. */
typedef struct ngtcp2_reno_cc {
ngtcp2_cc_base ccb;
uint64_t max_delivery_rate_sec;
uint64_t target_cwnd;
uint64_t pending_add;
} ngtcp2_reno_cc;
int ngtcp2_cc_reno_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
const ngtcp2_mem *mem);
void ngtcp2_cc_reno_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem);
void ngtcp2_reno_cc_init(ngtcp2_reno_cc *cc, ngtcp2_log *log);
void ngtcp2_reno_cc_free(ngtcp2_reno_cc *cc);
void ngtcp2_cc_reno_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt, ngtcp2_tstamp ts);
void ngtcp2_cc_reno_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts);
void ngtcp2_cc_reno_cc_on_persistent_congestion(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_reno_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
/* ngtcp2_cubic_cc is CUBIC congestion controller. */
typedef struct ngtcp2_cubic_cc {
ngtcp2_cc_base ccb;
uint64_t max_delivery_rate_sec;
uint64_t target_cwnd;
uint64_t w_last_max;
uint64_t w_tcp;
uint64_t origin_point;
ngtcp2_tstamp epoch_start;
uint64_t k;
/* prior stores the congestion state when a congestion event occurs
in order to restore the state when it turns out that the event is
spurious. */
struct {
uint64_t cwnd;
uint64_t ssthresh;
uint64_t w_last_max;
uint64_t w_tcp;
uint64_t origin_point;
ngtcp2_tstamp epoch_start;
uint64_t k;
} prior;
/* HyStart++ variables */
size_t rtt_sample_count;
uint64_t current_round_min_rtt;
uint64_t last_round_min_rtt;
int64_t window_end;
uint64_t pending_add;
uint64_t pending_w_add;
} ngtcp2_cubic_cc;
int ngtcp2_cc_cubic_cc_init(ngtcp2_cc *cc, ngtcp2_log *log,
const ngtcp2_mem *mem);
void ngtcp2_cc_cubic_cc_free(ngtcp2_cc *cc, const ngtcp2_mem *mem);
void ngtcp2_cubic_cc_init(ngtcp2_cubic_cc *cc, ngtcp2_log *log);
void ngtcp2_cubic_cc_free(ngtcp2_cubic_cc *cc);
void ngtcp2_cc_cubic_cc_on_pkt_acked(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_congestion_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp sent_ts,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_on_spurious_congestion(ngtcp2_cc *ccx,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_on_persistent_congestion(ngtcp2_cc *cc,
ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_on_ack_recv(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_ack *ack, ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_on_pkt_sent(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
const ngtcp2_cc_pkt *pkt);
void ngtcp2_cc_cubic_cc_new_rtt_sample(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_reset(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
void ngtcp2_cc_cubic_cc_event(ngtcp2_cc *cc, ngtcp2_conn_stat *cstat,
ngtcp2_cc_event_type event, ngtcp2_tstamp ts);
#endif /* NGTCP2_CC_H */

View file

@ -1,147 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_cid.h"
#include <assert.h>
#include <string.h>
#include "ngtcp2_path.h"
#include "ngtcp2_str.h"
void ngtcp2_cid_zero(ngtcp2_cid *cid) { memset(cid, 0, sizeof(*cid)); }
void ngtcp2_cid_init(ngtcp2_cid *cid, const uint8_t *data, size_t datalen) {
assert(datalen <= NGTCP2_MAX_CIDLEN);
cid->datalen = datalen;
if (datalen) {
ngtcp2_cpymem(cid->data, data, datalen);
}
}
int ngtcp2_cid_eq(const ngtcp2_cid *cid, const ngtcp2_cid *other) {
return cid->datalen == other->datalen &&
0 == memcmp(cid->data, other->data, cid->datalen);
}
int ngtcp2_cid_less(const ngtcp2_cid *lhs, const ngtcp2_cid *rhs) {
int s = lhs->datalen < rhs->datalen;
size_t n = s ? lhs->datalen : rhs->datalen;
int c = memcmp(lhs->data, rhs->data, n);
return c < 0 || (c == 0 && s);
}
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;
}
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
ngtcp2_scid_init(dest, src->seq, &src->cid);
dest->retired_ts = src->retired_ts;
dest->flags = src->flags;
}
void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
const uint8_t *token) {
dcid->seq = seq;
dcid->cid = *cid;
if (token) {
memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
dcid->flags = NGTCP2_DCID_FLAG_TOKEN_PRESENT;
} else {
dcid->flags = NGTCP2_DCID_FLAG_NONE;
}
ngtcp2_path_storage_zero(&dcid->ps);
dcid->retired_ts = UINT64_MAX;
dcid->bound_ts = UINT64_MAX;
dcid->bytes_sent = 0;
dcid->bytes_recv = 0;
dcid->max_udp_payload_size = NGTCP2_MAX_UDP_PAYLOAD_SIZE;
}
void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token) {
assert(token);
dcid->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
memcpy(dcid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
}
void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path) {
ngtcp2_path_copy(&dcid->ps.path, path);
}
void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
ngtcp2_dcid_init(dest, src->seq, &src->cid,
(src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) ? src->token
: NULL);
ngtcp2_path_copy(&dest->ps.path, &src->ps.path);
dest->retired_ts = src->retired_ts;
dest->bound_ts = src->bound_ts;
dest->flags = src->flags;
dest->bytes_sent = src->bytes_sent;
dest->bytes_recv = src->bytes_recv;
dest->max_udp_payload_size = src->max_udp_payload_size;
}
void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
dest->seq = src->seq;
dest->cid = src->cid;
if (src->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
dest->flags |= NGTCP2_DCID_FLAG_TOKEN_PRESENT;
memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
} else if (dest->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) {
dest->flags &= (uint8_t)~NGTCP2_DCID_FLAG_TOKEN_PRESENT;
}
}
int ngtcp2_dcid_verify_uniqueness(ngtcp2_dcid *dcid, uint64_t seq,
const ngtcp2_cid *cid, const uint8_t *token) {
if (dcid->seq == seq) {
return ngtcp2_cid_eq(&dcid->cid, cid) &&
(dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
memcmp(dcid->token, token,
NGTCP2_STATELESS_RESET_TOKENLEN) == 0
? 0
: NGTCP2_ERR_PROTO;
}
return !ngtcp2_cid_eq(&dcid->cid, cid) ? 0 : NGTCP2_ERR_PROTO;
}
int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
const uint8_t *token) {
return (dcid->flags & NGTCP2_DCID_FLAG_TOKEN_PRESENT) &&
ngtcp2_cmemeq(dcid->token, token,
NGTCP2_STATELESS_RESET_TOKENLEN)
? 0
: NGTCP2_ERR_INVALID_ARGUMENT;
}

View file

@ -1,175 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CID_H
#define NGTCP2_CID_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_pq.h"
#include "ngtcp2_path.h"
/* NGTCP2_SCID_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_SCID_FLAG_NONE 0x00u
/* NGTCP2_SCID_FLAG_USED indicates that a local endpoint observed that
a remote endpoint uses a particular Connection ID. */
#define NGTCP2_SCID_FLAG_USED 0x01u
/* NGTCP2_SCID_FLAG_RETIRED indicates that a particular Connection ID
is retired. */
#define NGTCP2_SCID_FLAG_RETIRED 0x02u
typedef struct ngtcp2_scid {
ngtcp2_pq_entry pe;
/* seq is the sequence number associated to the CID. */
uint64_t seq;
/* cid is a connection ID */
ngtcp2_cid cid;
/* retired_ts is the timestamp when peer tells that this CID is
retired. */
ngtcp2_tstamp retired_ts;
/* flags is the bitwise OR of zero or more of NGTCP2_SCID_FLAG_*. */
uint8_t flags;
} ngtcp2_scid;
/* NGTCP2_DCID_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_DCID_FLAG_NONE 0x00u
/* NGTCP2_DCID_FLAG_PATH_VALIDATED indicates that an associated path
has been validated. */
#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01u
/* NGTCP2_DCID_FLAG_TOKEN_PRESENT indicates that a stateless reset
token is set in token field. */
#define NGTCP2_DCID_FLAG_TOKEN_PRESENT 0x02u
typedef struct ngtcp2_dcid {
/* seq is the sequence number associated to the CID. */
uint64_t seq;
/* cid is a connection ID */
ngtcp2_cid cid;
/* path is a path which cid is bound to. The addresses are zero
length if cid has not been bound to a particular path yet. */
ngtcp2_path_storage ps;
/* retired_ts is the timestamp when peer tells that this CID is
retired. */
ngtcp2_tstamp retired_ts;
/* bound_ts is the timestamp when this connection ID is bound to a
particular path. It is only assigned when a connection ID is
used just for sending PATH_RESPONSE and is not zero-length. */
ngtcp2_tstamp bound_ts;
/* bytes_sent is the number of bytes sent to an associated path. */
uint64_t bytes_sent;
/* bytes_recv is the number of bytes received from an associated
path. */
uint64_t bytes_recv;
/* max_udp_payload_size is the maximum size of UDP payload that is
allowed to send to this path. */
size_t max_udp_payload_size;
/* flags is bitwise OR of zero or more of NGTCP2_DCID_FLAG_*. */
uint8_t flags;
/* token is a stateless reset token associated to this CID.
Actually, the stateless reset token is tied to the connection,
not to the particular connection ID. */
uint8_t token[NGTCP2_STATELESS_RESET_TOKENLEN];
} ngtcp2_dcid;
/* ngtcp2_cid_zero makes |cid| zero-length. */
void ngtcp2_cid_zero(ngtcp2_cid *cid);
/*
* ngtcp2_cid_less returns nonzero if |lhs| is lexicographical smaller
* than |rhs|.
*/
int ngtcp2_cid_less(const ngtcp2_cid *lhs, const ngtcp2_cid *rhs);
/*
* ngtcp2_cid_empty returns nonzero if |cid| includes empty connection
* ID.
*/
int ngtcp2_cid_empty(const ngtcp2_cid *cid);
/*
* ngtcp2_scid_init initializes |scid| with the given parameters.
*/
void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid);
/*
* ngtcp2_scid_copy copies |src| into |dest|.
*/
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src);
/*
* ngtcp2_dcid_init initializes |dcid| with the given parameters. If
* |token| is NULL, the function fills dcid->token it with 0. |token|
* must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
*/
void ngtcp2_dcid_init(ngtcp2_dcid *dcid, uint64_t seq, const ngtcp2_cid *cid,
const uint8_t *token);
/*
* ngtcp2_dcid_set_token sets |token| to |dcid|. |token| must not be
* NULL and must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
*/
void ngtcp2_dcid_set_token(ngtcp2_dcid *dcid, const uint8_t *token);
/*
* ngtcp2_dcid_set_path sets |path| to |dcid|. It sets
* max_udp_payload_size to the minimum UDP payload size supported
* by the IP protocol version.
*/
void ngtcp2_dcid_set_path(ngtcp2_dcid *dcid, const ngtcp2_path *path);
/*
* ngtcp2_dcid_copy copies |src| into |dest|.
*/
void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src);
/*
* ngtcp2_dcid_copy_cid_token behaves like ngtcp2_dcid_copy, but it
* only copies cid, seq, and path.
*/
void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src);
/*
* ngtcp2_dcid_verify_uniqueness verifies uniqueness of (|seq|, |cid|,
* |token|) tuple against |dcid|.
*/
int ngtcp2_dcid_verify_uniqueness(ngtcp2_dcid *dcid, uint64_t seq,
const ngtcp2_cid *cid, const uint8_t *token);
/*
* ngtcp2_dcid_verify_stateless_reset_token verifies stateless reset
* token |token| against the one included in |dcid|. This function
* returns 0 if the verification succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* Tokens do not match; or |dcid| does not contain a token.
*/
int ngtcp2_dcid_verify_stateless_reset_token(const ngtcp2_dcid *dcid,
const uint8_t *token);
#endif /* NGTCP2_CID_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,291 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_conv.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_str.h"
#include "ngtcp2_pkt.h"
#include "ngtcp2_net.h"
#include "ngtcp2_unreachable.h"
const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p) {
uint64_t n;
memcpy(&n, p, sizeof(n));
*dest = ngtcp2_ntohl64(n);
return p + sizeof(n);
}
const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p) {
uint64_t n = 0;
memcpy(((uint8_t *)&n) + 2, p, 6);
*dest = ngtcp2_ntohl64(n);
return p + 6;
}
const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p) {
uint32_t n;
memcpy(&n, p, sizeof(n));
*dest = ngtcp2_ntohl(n);
return p + sizeof(n);
}
const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p) {
uint32_t n = 0;
memcpy(((uint8_t *)&n) + 1, p, 3);
*dest = ngtcp2_ntohl(n);
return p + 3;
}
const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p) {
uint16_t n;
memcpy(&n, p, sizeof(n));
*dest = ngtcp2_ntohs(n);
return p + sizeof(n);
}
const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p) {
memcpy(dest, p, sizeof(*dest));
return p + sizeof(*dest);
}
static uint64_t get_uvarint(size_t *plen, const uint8_t *p) {
union {
uint8_t n8;
uint16_t n16;
uint32_t n32;
uint64_t n64;
} n;
*plen = (size_t)(1u << (*p >> 6));
switch (*plen) {
case 1:
return *p;
case 2:
memcpy(&n, p, 2);
n.n8 &= 0x3f;
return ngtcp2_ntohs(n.n16);
case 4:
memcpy(&n, p, 4);
n.n8 &= 0x3f;
return ngtcp2_ntohl(n.n32);
case 8:
memcpy(&n, p, 8);
n.n8 &= 0x3f;
return ngtcp2_ntohl64(n.n64);
default:
ngtcp2_unreachable();
}
}
const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p) {
size_t len;
*dest = get_uvarint(&len, p);
return p + len;
}
const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p) {
size_t len;
*dest = (int64_t)get_uvarint(&len, p);
return p + len;
}
int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen) {
uint32_t l;
uint16_t s;
switch (pkt_numlen) {
case 1:
return *p;
case 2:
ngtcp2_get_uint16(&s, p);
return (int64_t)s;
case 3:
ngtcp2_get_uint24(&l, p);
return (int64_t)l;
case 4:
ngtcp2_get_uint32(&l, p);
return (int64_t)l;
default:
ngtcp2_unreachable();
}
}
uint8_t *ngtcp2_put_uint64be(uint8_t *p, uint64_t n) {
n = ngtcp2_htonl64(n);
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
uint8_t *ngtcp2_put_uint48be(uint8_t *p, uint64_t n) {
n = ngtcp2_htonl64(n);
return ngtcp2_cpymem(p, ((const uint8_t *)&n) + 2, 6);
}
uint8_t *ngtcp2_put_uint32be(uint8_t *p, uint32_t n) {
n = ngtcp2_htonl(n);
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
uint8_t *ngtcp2_put_uint24be(uint8_t *p, uint32_t n) {
n = ngtcp2_htonl(n);
return ngtcp2_cpymem(p, ((const uint8_t *)&n) + 1, 3);
}
uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n) {
n = ngtcp2_htons(n);
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n) {
return ngtcp2_cpymem(p, (const uint8_t *)&n, sizeof(n));
}
uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n) {
uint8_t *rv;
if (n < 64) {
*p++ = (uint8_t)n;
return p;
}
if (n < 16384) {
rv = ngtcp2_put_uint16be(p, (uint16_t)n);
*p |= 0x40;
return rv;
}
if (n < 1073741824) {
rv = ngtcp2_put_uint32be(p, (uint32_t)n);
*p |= 0x80;
return rv;
}
assert(n < 4611686018427387904ULL);
rv = ngtcp2_put_uint64be(p, n);
*p |= 0xc0;
return rv;
}
uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n) {
uint8_t *rv;
assert(n < 1073741824);
rv = ngtcp2_put_uint32be(p, n);
*p |= 0x80;
return rv;
}
uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len) {
switch (len) {
case 1:
*p++ = (uint8_t)pkt_num;
return p;
case 2:
ngtcp2_put_uint16be(p, (uint16_t)pkt_num);
return p + 2;
case 3:
ngtcp2_put_uint24be(p, (uint32_t)pkt_num);
return p + 3;
case 4:
ngtcp2_put_uint32be(p, (uint32_t)pkt_num);
return p + 4;
default:
ngtcp2_unreachable();
}
}
size_t ngtcp2_get_uvarintlen(const uint8_t *p) {
return (size_t)(1u << (*p >> 6));
}
size_t ngtcp2_put_uvarintlen(uint64_t n) {
if (n < 64) {
return 1;
}
if (n < 16384) {
return 2;
}
if (n < 1073741824) {
return 4;
}
assert(n < 4611686018427387904ULL);
return 8;
}
int64_t ngtcp2_nth_server_bidi_id(uint64_t n) {
if (n == 0) {
return 0;
}
if ((NGTCP2_MAX_VARINT >> 2) < n - 1) {
return NGTCP2_MAX_SERVER_STREAM_ID_BIDI;
}
return (int64_t)(((n - 1) << 2) | 0x01);
}
int64_t ngtcp2_nth_client_bidi_id(uint64_t n) {
if (n == 0) {
return 0;
}
if ((NGTCP2_MAX_VARINT >> 2) < n - 1) {
return NGTCP2_MAX_CLIENT_STREAM_ID_BIDI;
}
return (int64_t)((n - 1) << 2);
}
int64_t ngtcp2_nth_server_uni_id(uint64_t n) {
if (n == 0) {
return 0;
}
if ((NGTCP2_MAX_VARINT >> 2) < n - 1) {
return NGTCP2_MAX_SERVER_STREAM_ID_UNI;
}
return (int64_t)(((n - 1) << 2) | 0x03);
}
int64_t ngtcp2_nth_client_uni_id(uint64_t n) {
if (n == 0) {
return 0;
}
if ((NGTCP2_MAX_VARINT >> 2) < n - 1) {
return NGTCP2_MAX_CLIENT_STREAM_ID_UNI;
}
return (int64_t)(((n - 1) << 2) | 0x02);
}
uint64_t ngtcp2_ord_stream_id(int64_t stream_id) {
return (uint64_t)(stream_id >> 2) + 1;
}

View file

@ -1,208 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CONV_H
#define NGTCP2_CONV_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
/*
* ngtcp2_get_uint64 reads 8 bytes from |p| as 64 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| in host byte order. It returns |p| + 8.
*/
const uint8_t *ngtcp2_get_uint64(uint64_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uint48 reads 6 bytes from |p| as 48 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| in host byte order. It returns |p| + 6.
*/
const uint8_t *ngtcp2_get_uint48(uint64_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uint32 reads 4 bytes from |p| as 32 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| in host byte order. It returns |p| + 4.
*/
const uint8_t *ngtcp2_get_uint32(uint32_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uint24 reads 3 bytes from |p| as 24 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| in host byte order. It returns |p| + 3.
*/
const uint8_t *ngtcp2_get_uint24(uint32_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uint16 reads 2 bytes from |p| as 16 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| in host byte order. It returns |p| + 2.
*/
const uint8_t *ngtcp2_get_uint16(uint16_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uint16be reads 2 bytes from |p| as 16 bits unsigned
* integer encoded as network byte order, and stores it in the buffer
* pointed by |dest| as is. It returns |p| + 2.
*/
const uint8_t *ngtcp2_get_uint16be(uint16_t *dest, const uint8_t *p);
/*
* ngtcp2_get_uvarint reads variable-length unsigned integer from |p|,
* and stores it in the buffer pointed by |dest| in host byte order.
* It returns |p| plus the number of bytes read from |p|.
*/
const uint8_t *ngtcp2_get_uvarint(uint64_t *dest, const uint8_t *p);
/*
* ngtcp2_get_varint reads variable-length unsigned integer from |p|,
* and casts it to the signed integer, and stores it in the buffer
* pointed by |dest| in host byte order. No information should be
* lost in this cast, because the variable-length integer is 62
* bits. It returns |p| plus the number of bytes read from |p|.
*/
const uint8_t *ngtcp2_get_varint(int64_t *dest, const uint8_t *p);
/*
* ngtcp2_get_pkt_num reads encoded packet number from |p|. The
* packet number is encoed in |pkt_numlen| bytes.
*/
int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen);
/*
* ngtcp2_put_uint64be writes |n| in host byte order in |p| in network
* byte order. It returns the one beyond of the last written
* position.
*/
uint8_t *ngtcp2_put_uint64be(uint8_t *p, uint64_t n);
/*
* ngtcp2_put_uint48be writes |n| in host byte order in |p| in network
* byte order. It writes only least significant 48 bits. It returns
* the one beyond of the last written position.
*/
uint8_t *ngtcp2_put_uint48be(uint8_t *p, uint64_t n);
/*
* ngtcp2_put_uint32be writes |n| in host byte order in |p| in network
* byte order. It returns the one beyond of the last written
* position.
*/
uint8_t *ngtcp2_put_uint32be(uint8_t *p, uint32_t n);
/*
* ngtcp2_put_uint24be writes |n| in host byte order in |p| in network
* byte order. It writes only least significant 24 bits. It returns
* the one beyond of the last written position.
*/
uint8_t *ngtcp2_put_uint24be(uint8_t *p, uint32_t n);
/*
* ngtcp2_put_uint16be writes |n| in host byte order in |p| in network
* byte order. It returns the one beyond of the last written
* position.
*/
uint8_t *ngtcp2_put_uint16be(uint8_t *p, uint16_t n);
/*
* ngtcp2_put_uint16 writes |n| as is in |p|. It returns the one
* beyond of the last written position.
*/
uint8_t *ngtcp2_put_uint16(uint8_t *p, uint16_t n);
/*
* ngtcp2_put_uvarint writes |n| in |p| using variable-length integer
* encoding. It returns the one beyond of the last written position.
*/
uint8_t *ngtcp2_put_uvarint(uint8_t *p, uint64_t n);
/*
* ngtcp2_put_uvarint30 writes |n| in |p| using variable-length
* integer encoding. |n| must be strictly less than 1073741824. The
* function always encodes |n| in 4 bytes. It returns the one beyond
* of the last written position.
*/
uint8_t *ngtcp2_put_uvarint30(uint8_t *p, uint32_t n);
/*
* ngtcp2_put_pkt_num encodes |pkt_num| using |len| bytes. It
* returns the one beyond of the last written position.
*/
uint8_t *ngtcp2_put_pkt_num(uint8_t *p, int64_t pkt_num, size_t len);
/*
* ngtcp2_get_uvarintlen returns the required number of bytes to read
* variable-length integer starting at |p|.
*/
size_t ngtcp2_get_uvarintlen(const uint8_t *p);
/*
* ngtcp2_put_uvarintlen returns the required number of bytes to
* encode |n|.
*/
size_t ngtcp2_put_uvarintlen(uint64_t n);
/*
* ngtcp2_nth_server_bidi_id returns |n|-th server bidirectional
* stream ID. If |n| is 0, it returns 0. If the |n|-th stream ID is
* larger than NGTCP2_MAX_SERVER_STREAM_ID_BIDI, this function returns
* NGTCP2_MAX_SERVER_STREAM_ID_BIDI.
*/
int64_t ngtcp2_nth_server_bidi_id(uint64_t n);
/*
* ngtcp2_nth_client_bidi_id returns |n|-th client bidirectional
* stream ID. If |n| is 0, it returns 0. If the |n|-th stream ID is
* larger than NGTCP2_MAX_CLIENT_STREAM_ID_BIDI, this function returns
* NGTCP2_MAX_CLIENT_STREAM_ID_BIDI.
*/
int64_t ngtcp2_nth_client_bidi_id(uint64_t n);
/*
* ngtcp2_nth_server_uni_id returns |n|-th server unidirectional
* stream ID. If |n| is 0, it returns 0. If the |n|-th stream ID is
* larger than NGTCP2_MAX_SERVER_STREAM_ID_UNI, this function returns
* NGTCP2_MAX_SERVER_STREAM_ID_UNI.
*/
int64_t ngtcp2_nth_server_uni_id(uint64_t n);
/*
* ngtcp2_nth_client_uni_id returns |n|-th client unidirectional
* stream ID. If |n| is 0, it returns 0. If the |n|-th stream ID is
* larger than NGTCP2_MAX_CLIENT_STREAM_ID_UNI, this function returns
* NGTCP2_MAX_CLIENT_STREAM_ID_UNI.
*/
int64_t ngtcp2_nth_client_uni_id(uint64_t n);
/*
* ngtcp2_ord_stream_id returns the ordinal number of |stream_id|.
*/
uint64_t ngtcp2_ord_stream_id(int64_t stream_id);
#endif /* NGTCP2_CONV_H */

View file

@ -1,895 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_crypto.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_str.h"
#include "ngtcp2_conv.h"
#include "ngtcp2_conn.h"
#include "ngtcp2_net.h"
int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
size_t secretlen,
const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *iv, size_t ivlen,
const ngtcp2_mem *mem) {
int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, ivlen, mem);
if (rv != 0) {
return rv;
}
if (secretlen) {
memcpy((*pckm)->secret.base, secret, secretlen);
}
if (aead_ctx) {
(*pckm)->aead_ctx = *aead_ctx;
}
memcpy((*pckm)->iv.base, iv, ivlen);
return 0;
}
int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
size_t ivlen, const ngtcp2_mem *mem) {
size_t len;
uint8_t *p;
len = sizeof(ngtcp2_crypto_km) + secretlen + ivlen;
*pckm = ngtcp2_mem_malloc(mem, len);
if (*pckm == NULL) {
return NGTCP2_ERR_NOMEM;
}
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;
return 0;
}
void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem) {
if (ckm == NULL) {
return;
}
ngtcp2_mem_free(mem, ckm);
}
void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen,
int64_t pkt_num) {
size_t i;
uint64_t n;
assert(ivlen >= 8);
memcpy(dest, iv, ivlen);
n = ngtcp2_htonl64((uint64_t)pkt_num);
for (i = 0; i < 8; ++i) {
dest[ivlen - 8 + i] ^= ((uint8_t *)&n)[i];
}
}
/*
* varint_paramlen returns the length of a single transport parameter
* which has variable integer in its parameter.
*/
static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) {
size_t valuelen = ngtcp2_put_uvarintlen(param);
return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(valuelen) + valuelen;
}
/*
* write_varint_param writes parameter |id| of the given |value| in
* varint encoding. It returns p + the number of bytes written.
*/
static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id,
uint64_t value) {
p = ngtcp2_put_uvarint(p, id);
p = ngtcp2_put_uvarint(p, ngtcp2_put_uvarintlen(value));
return ngtcp2_put_uvarint(p, value);
}
/*
* cid_paramlen returns the length of a single transport parameter
* which has |cid| as value.
*/
static size_t cid_paramlen(ngtcp2_transport_param_id id,
const ngtcp2_cid *cid) {
return ngtcp2_put_uvarintlen(id) + ngtcp2_put_uvarintlen(cid->datalen) +
cid->datalen;
}
/*
* write_cid_param writes parameter |id| of the given |cid|. It
* returns p + the number of bytes written.
*/
static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id,
const ngtcp2_cid *cid) {
assert(cid->datalen == 0 || cid->datalen >= NGTCP2_MIN_CIDLEN);
assert(cid->datalen <= NGTCP2_MAX_CIDLEN);
p = ngtcp2_put_uvarint(p, id);
p = ngtcp2_put_uvarint(p, cid->datalen);
if (cid->datalen) {
p = ngtcp2_cpymem(p, cid->data, cid->datalen);
}
return p;
}
static const uint8_t empty_address[16];
ngtcp2_ssize ngtcp2_encode_transport_params_versioned(
uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype,
int transport_params_version, const ngtcp2_transport_params *params) {
uint8_t *p;
size_t len = 0;
/* For some reason, gcc 7.3.0 requires this initialization. */
size_t preferred_addrlen = 0;
size_t version_infolen = 0;
const ngtcp2_sockaddr_in *sa_in;
const ngtcp2_sockaddr_in6 *sa_in6;
(void)transport_params_version;
switch (exttype) {
case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO:
break;
case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS:
len +=
cid_paramlen(NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
&params->original_dcid);
if (params->stateless_reset_token_present) {
len +=
ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
ngtcp2_put_uvarintlen(NGTCP2_STATELESS_RESET_TOKENLEN) +
NGTCP2_STATELESS_RESET_TOKENLEN;
}
if (params->preferred_address_present) {
assert(params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN);
assert(params->preferred_address.cid.datalen <= NGTCP2_MAX_CIDLEN);
preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ +
16 /* ipv6Address */ + 2 /* ipv6Port */
+ 1 +
params->preferred_address.cid.datalen /* CID */ +
NGTCP2_STATELESS_RESET_TOKENLEN;
len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
ngtcp2_put_uvarintlen(preferred_addrlen) + preferred_addrlen;
}
if (params->retry_scid_present) {
len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
&params->retry_scid);
}
break;
default:
return NGTCP2_ERR_INVALID_ARGUMENT;
}
len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
&params->initial_scid);
if (params->initial_max_stream_data_bidi_local) {
len += varint_paramlen(
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
params->initial_max_stream_data_bidi_local);
}
if (params->initial_max_stream_data_bidi_remote) {
len += varint_paramlen(
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
params->initial_max_stream_data_bidi_remote);
}
if (params->initial_max_stream_data_uni) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
params->initial_max_stream_data_uni);
}
if (params->initial_max_data) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
params->initial_max_data);
}
if (params->initial_max_streams_bidi) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
params->initial_max_streams_bidi);
}
if (params->initial_max_streams_uni) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
params->initial_max_streams_uni);
}
if (params->max_udp_payload_size !=
NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
params->max_udp_payload_size);
}
if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
params->ack_delay_exponent);
}
if (params->disable_active_migration) {
len +=
ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) +
ngtcp2_put_uvarintlen(0);
}
if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
params->max_ack_delay / NGTCP2_MILLISECONDS);
}
if (params->max_idle_timeout) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
params->max_idle_timeout / NGTCP2_MILLISECONDS);
}
if (params->active_connection_id_limit &&
params->active_connection_id_limit !=
NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
params->active_connection_id_limit);
}
if (params->max_datagram_frame_size) {
len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
params->max_datagram_frame_size);
}
if (params->grease_quic_bit) {
len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) +
ngtcp2_put_uvarintlen(0);
}
if (params->version_info_present) {
version_infolen =
sizeof(uint32_t) + params->version_info.available_versionslen;
len += ngtcp2_put_uvarintlen(NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION) +
ngtcp2_put_uvarintlen(version_infolen) + version_infolen;
}
if (dest == NULL && destlen == 0) {
return (ngtcp2_ssize)len;
}
if (destlen < len) {
return NGTCP2_ERR_NOBUF;
}
p = dest;
if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
p = write_cid_param(
p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
&params->original_dcid);
if (params->stateless_reset_token_present) {
p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN);
p = ngtcp2_put_uvarint(p, sizeof(params->stateless_reset_token));
p = ngtcp2_cpymem(p, params->stateless_reset_token,
sizeof(params->stateless_reset_token));
}
if (params->preferred_address_present) {
p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS);
p = ngtcp2_put_uvarint(p, preferred_addrlen);
if (params->preferred_address.ipv4_present) {
sa_in = &params->preferred_address.ipv4;
p = ngtcp2_cpymem(p, &sa_in->sin_addr, sizeof(sa_in->sin_addr));
p = ngtcp2_put_uint16(p, sa_in->sin_port);
} else {
p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in->sin_addr));
p = ngtcp2_put_uint16(p, 0);
}
if (params->preferred_address.ipv6_present) {
sa_in6 = &params->preferred_address.ipv6;
p = ngtcp2_cpymem(p, &sa_in6->sin6_addr, sizeof(sa_in6->sin6_addr));
p = ngtcp2_put_uint16(p, sa_in6->sin6_port);
} else {
p = ngtcp2_cpymem(p, empty_address, sizeof(sa_in6->sin6_addr));
p = ngtcp2_put_uint16(p, 0);
}
*p++ = (uint8_t)params->preferred_address.cid.datalen;
if (params->preferred_address.cid.datalen) {
p = ngtcp2_cpymem(p, params->preferred_address.cid.data,
params->preferred_address.cid.datalen);
}
p = ngtcp2_cpymem(
p, params->preferred_address.stateless_reset_token,
sizeof(params->preferred_address.stateless_reset_token));
}
if (params->retry_scid_present) {
p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
&params->retry_scid);
}
}
p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
&params->initial_scid);
if (params->initial_max_stream_data_bidi_local) {
p = write_varint_param(
p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
params->initial_max_stream_data_bidi_local);
}
if (params->initial_max_stream_data_bidi_remote) {
p = write_varint_param(
p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
params->initial_max_stream_data_bidi_remote);
}
if (params->initial_max_stream_data_uni) {
p = write_varint_param(p,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
params->initial_max_stream_data_uni);
}
if (params->initial_max_data) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
params->initial_max_data);
}
if (params->initial_max_streams_bidi) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
params->initial_max_streams_bidi);
}
if (params->initial_max_streams_uni) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
params->initial_max_streams_uni);
}
if (params->max_udp_payload_size !=
NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
params->max_udp_payload_size);
}
if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
params->ack_delay_exponent);
}
if (params->disable_active_migration) {
p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION);
p = ngtcp2_put_uvarint(p, 0);
}
if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
params->max_ack_delay / NGTCP2_MILLISECONDS);
}
if (params->max_idle_timeout) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
params->max_idle_timeout / NGTCP2_MILLISECONDS);
}
if (params->active_connection_id_limit &&
params->active_connection_id_limit !=
NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
params->active_connection_id_limit);
}
if (params->max_datagram_frame_size) {
p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
params->max_datagram_frame_size);
}
if (params->grease_quic_bit) {
p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT);
p = ngtcp2_put_uvarint(p, 0);
}
if (params->version_info_present) {
p = ngtcp2_put_uvarint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION);
p = ngtcp2_put_uvarint(p, version_infolen);
p = ngtcp2_put_uint32be(p, params->version_info.chosen_version);
if (params->version_info.available_versionslen) {
p = ngtcp2_cpymem(p, params->version_info.available_versions,
params->version_info.available_versionslen);
}
}
assert((size_t)(p - dest) == len);
return (ngtcp2_ssize)len;
}
/*
* decode_varint decodes a single varint from the buffer pointed by
* |*pp| of length |end - *pp|. If it decodes an integer
* successfully, it stores the integer in |*pdest|, increment |*pp| by
* the number of bytes read from |*pp|, and returns 0. Otherwise it
* returns -1.
*/
static int decode_varint(uint64_t *pdest, const uint8_t **pp,
const uint8_t *end) {
const uint8_t *p = *pp;
size_t len;
if (p == end) {
return -1;
}
len = ngtcp2_get_uvarintlen(p);
if ((uint64_t)(end - p) < len) {
return -1;
}
*pp = ngtcp2_get_uvarint(pdest, p);
return 0;
}
/*
* decode_varint_param decodes length prefixed value from the buffer
* pointed by |*pp| of length |end - *pp|. The length and value are
* encoded in varint form. If it decodes a value successfully, it
* stores the value in |*pdest|, increment |*pp| by the number of
* bytes read from |*pp|, and returns 0. Otherwise it returns -1.
*/
static int decode_varint_param(uint64_t *pdest, const uint8_t **pp,
const uint8_t *end) {
const uint8_t *p = *pp;
uint64_t valuelen;
if (decode_varint(&valuelen, &p, end) != 0) {
return -1;
}
if (p == end) {
return -1;
}
if ((uint64_t)(end - p) < valuelen) {
return -1;
}
if (ngtcp2_get_uvarintlen(p) != valuelen) {
return -1;
}
*pp = ngtcp2_get_uvarint(pdest, p);
return 0;
}
/*
* decode_cid_param decodes length prefixed ngtcp2_cid from the buffer
* pointed by |*pp| of length |end - *pp|. The length is encoded in
* varint form. If it decodes a value successfully, it stores the
* value in |*pdest|, increment |*pp| by the number of read from
* |*pp|, and returns the number of bytes read. Otherwise it returns
* the one of the negative error code:
*
* NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM
* Could not decode Connection ID.
*/
static int decode_cid_param(ngtcp2_cid *pdest, const uint8_t **pp,
const uint8_t *end) {
const uint8_t *p = *pp;
uint64_t valuelen;
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((valuelen != 0 && valuelen < NGTCP2_MIN_CIDLEN) ||
valuelen > NGTCP2_MAX_CIDLEN || (size_t)(end - p) < valuelen) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
ngtcp2_cid_init(pdest, p, (size_t)valuelen);
p += valuelen;
*pp = p;
return 0;
}
int ngtcp2_decode_transport_params_versioned(
int transport_params_version, ngtcp2_transport_params *params,
ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) {
const uint8_t *p, *end, *lend;
size_t len;
uint64_t param_type;
uint64_t valuelen;
int rv;
int initial_scid_present = 0;
int original_dcid_present = 0;
ngtcp2_sockaddr_in *sa_in;
ngtcp2_sockaddr_in6 *sa_in6;
uint32_t version;
(void)transport_params_version;
if (datalen == 0) {
return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
}
/* Set default values */
memset(params, 0, sizeof(*params));
params->initial_max_streams_bidi = 0;
params->initial_max_streams_uni = 0;
params->initial_max_stream_data_bidi_local = 0;
params->initial_max_stream_data_bidi_remote = 0;
params->initial_max_stream_data_uni = 0;
params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
params->stateless_reset_token_present = 0;
params->preferred_address_present = 0;
params->disable_active_migration = 0;
params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
params->max_idle_timeout = 0;
params->active_connection_id_limit =
NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
params->retry_scid_present = 0;
params->max_datagram_frame_size = 0;
memset(&params->retry_scid, 0, sizeof(params->retry_scid));
memset(&params->initial_scid, 0, sizeof(params->initial_scid));
memset(&params->original_dcid, 0, sizeof(params->original_dcid));
params->version_info_present = 0;
p = data;
end = data + datalen;
for (; (size_t)(end - p) >= 2;) {
if (decode_varint(&param_type, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
switch (param_type) {
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
if (decode_varint_param(&params->initial_max_stream_data_bidi_local, &p,
end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
if (decode_varint_param(&params->initial_max_stream_data_bidi_remote, &p,
end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI:
if (decode_varint_param(&params->initial_max_stream_data_uni, &p, end) !=
0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA:
if (decode_varint_param(&params->initial_max_data, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI:
if (decode_varint_param(&params->initial_max_streams_bidi, &p, end) !=
0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI:
if (decode_varint_param(&params->initial_max_streams_uni, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT:
if (decode_varint_param(&params->max_idle_timeout, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
params->max_idle_timeout *= NGTCP2_MILLISECONDS;
break;
case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE:
if (decode_varint_param(&params->max_udp_payload_size, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN:
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((size_t)valuelen != sizeof(params->stateless_reset_token)) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((size_t)(end - p) < sizeof(params->stateless_reset_token)) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
p = ngtcp2_get_bytes(params->stateless_reset_token, p,
sizeof(params->stateless_reset_token));
params->stateless_reset_token_present = 1;
break;
case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT:
if (decode_varint_param(&params->ack_delay_exponent, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (params->ack_delay_exponent > 20) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS:
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((size_t)(end - p) < valuelen) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ +
2 /* ipv6Port */
+ 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN;
if (valuelen < len) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
sa_in = &params->preferred_address.ipv4;
p = ngtcp2_get_bytes(&sa_in->sin_addr, p, sizeof(sa_in->sin_addr));
p = ngtcp2_get_uint16be(&sa_in->sin_port, p);
if (sa_in->sin_port || memcmp(empty_address, &sa_in->sin_addr,
sizeof(sa_in->sin_addr)) != 0) {
sa_in->sin_family = AF_INET;
params->preferred_address.ipv4_present = 1;
}
sa_in6 = &params->preferred_address.ipv6;
p = ngtcp2_get_bytes(&sa_in6->sin6_addr, p, sizeof(sa_in6->sin6_addr));
p = ngtcp2_get_uint16be(&sa_in6->sin6_port, p);
if (sa_in6->sin6_port || memcmp(empty_address, &sa_in6->sin6_addr,
sizeof(sa_in6->sin6_addr)) != 0) {
sa_in6->sin6_family = AF_INET6;
params->preferred_address.ipv6_present = 1;
}
/* cid */
params->preferred_address.cid.datalen = *p++;
len += params->preferred_address.cid.datalen;
if (valuelen != len ||
params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN ||
params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (params->preferred_address.cid.datalen) {
p = ngtcp2_get_bytes(params->preferred_address.cid.data, p,
params->preferred_address.cid.datalen);
}
/* stateless reset token */
p = ngtcp2_get_bytes(
params->preferred_address.stateless_reset_token, p,
sizeof(params->preferred_address.stateless_reset_token));
params->preferred_address_present = 1;
break;
case NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION:
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (valuelen != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
params->disable_active_migration = 1;
break;
case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID:
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
rv = decode_cid_param(&params->original_dcid, &p, end);
if (rv != 0) {
return rv;
}
original_dcid_present = 1;
break;
case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID:
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
rv = decode_cid_param(&params->retry_scid, &p, end);
if (rv != 0) {
return rv;
}
params->retry_scid_present = 1;
break;
case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID:
rv = decode_cid_param(&params->initial_scid, &p, end);
if (rv != 0) {
return rv;
}
initial_scid_present = 1;
break;
case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY:
if (decode_varint_param(&params->max_ack_delay, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (params->max_ack_delay >= 16384) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
params->max_ack_delay *= NGTCP2_MILLISECONDS;
break;
case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT:
if (decode_varint_param(&params->active_connection_id_limit, &p, end) !=
0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE:
if (decode_varint_param(&params->max_datagram_frame_size, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
break;
case NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT:
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (valuelen != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
params->grease_quic_bit = 1;
break;
case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION:
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((size_t)(end - p) < valuelen) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (valuelen < sizeof(uint32_t) || (valuelen & 0x3)) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
p = ngtcp2_get_uint32(&params->version_info.chosen_version, p);
if (params->version_info.chosen_version == 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (valuelen > sizeof(uint32_t)) {
params->version_info.available_versions = (uint8_t *)p;
params->version_info.available_versionslen =
(size_t)valuelen - sizeof(uint32_t);
for (lend = p + (valuelen - sizeof(uint32_t)); p != lend;) {
p = ngtcp2_get_uint32(&version, p);
if (version == 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
}
}
params->version_info_present = 1;
break;
default:
/* Ignore unknown parameter */
if (decode_varint(&valuelen, &p, end) != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if ((size_t)(end - p) < valuelen) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
p += valuelen;
break;
}
}
if (end - p != 0) {
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
}
if (!initial_scid_present ||
(exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS &&
!original_dcid_present)) {
return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
}
return 0;
}
static int transport_params_copy_new(ngtcp2_transport_params **pdest,
const ngtcp2_transport_params *src,
const ngtcp2_mem *mem) {
size_t len = sizeof(**pdest);
ngtcp2_transport_params *dest;
uint8_t *p;
if (src->version_info_present) {
len += src->version_info.available_versionslen;
}
dest = ngtcp2_mem_malloc(mem, len);
if (dest == NULL) {
return NGTCP2_ERR_NOMEM;
}
*dest = *src;
if (src->version_info_present && src->version_info.available_versionslen) {
p = (uint8_t *)dest + sizeof(*dest);
memcpy(p, src->version_info.available_versions,
src->version_info.available_versionslen);
dest->version_info.available_versions = p;
}
*pdest = dest;
return 0;
}
int ngtcp2_decode_transport_params_new(ngtcp2_transport_params **pparams,
ngtcp2_transport_params_type exttype,
const uint8_t *data, size_t datalen,
const ngtcp2_mem *mem) {
int rv;
ngtcp2_transport_params params;
rv = ngtcp2_decode_transport_params(&params, exttype, data, datalen);
if (rv < 0) {
return rv;
}
if (mem == NULL) {
mem = ngtcp2_mem_default();
}
return transport_params_copy_new(pparams, &params, mem);
}
void ngtcp2_transport_params_del(ngtcp2_transport_params *params,
const ngtcp2_mem *mem) {
if (params == NULL) {
return;
}
if (mem == NULL) {
mem = ngtcp2_mem_default();
}
ngtcp2_mem_free(mem, params);
}
int ngtcp2_transport_params_copy_new(ngtcp2_transport_params **pdest,
const ngtcp2_transport_params *src,
const ngtcp2_mem *mem) {
if (src == NULL) {
*pdest = NULL;
return 0;
}
return transport_params_copy_new(pdest, src, mem);
}

View file

@ -1,148 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_CRYPTO_H
#define NGTCP2_CRYPTO_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
/* NGTCP2_INITIAL_AEAD_OVERHEAD is an overhead of AEAD used by Initial
packets. Because QUIC uses AEAD_AES_128_GCM, the overhead is 16
bytes. */
#define NGTCP2_INITIAL_AEAD_OVERHEAD 16
/* NGTCP2_MAX_AEAD_OVERHEAD is expected maximum AEAD overhead. */
#define NGTCP2_MAX_AEAD_OVERHEAD 16
/* ngtcp2_transport_param_id is the registry of QUIC transport
parameter ID. */
typedef enum ngtcp2_transport_param_id {
NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID = 0x0000,
NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT = 0x0001,
NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN = 0x0002,
NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE = 0x0003,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA = 0x0004,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = 0x0005,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = 0x0006,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI = 0x0007,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI = 0x0008,
NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI = 0x0009,
NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT = 0x000a,
NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY = 0x000b,
NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION = 0x000c,
NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS = 0x000d,
NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT = 0x000e,
NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f,
NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010,
/* https://datatracker.ietf.org/doc/html/rfc9221 */
NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE = 0x0020,
NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT = 0x2ab2,
/* https://datatracker.ietf.org/doc/html/draft-ietf-quic-version-negotiation-14
*/
NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION = 0x11,
} ngtcp2_transport_param_id;
/* NGTCP2_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00u
/* NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE is set if key phase bit is
set. */
#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01u
typedef struct ngtcp2_crypto_km {
ngtcp2_vec secret;
ngtcp2_crypto_aead_ctx aead_ctx;
ngtcp2_vec iv;
/* pkt_num is a packet number of a packet which uses this keying
material. For encryption key, it is the lowest packet number of
a packet. For decryption key, it is the lowest packet number of
a packet which can be decrypted with this keying material. */
int64_t pkt_num;
/* use_count is the number of encryption applied with this key.
This field is only used for tx key. */
uint64_t use_count;
/* flags is the bitwise OR of zero or more of
NGTCP2_CRYPTO_KM_FLAG_*. */
uint8_t flags;
} ngtcp2_crypto_km;
/*
* ngtcp2_crypto_km_new creates new ngtcp2_crypto_km object and
* assigns its pointer to |*pckm|. The |secret| of length
* |secretlen|, the |key| of length |keylen| and the |iv| of length
* |ivlen| are copied to |*pckm|. If |secretlen| == 0, the function
* assumes no secret is given which is acceptable. The sole reason to
* store secret is update keys. Only 1RTT key can be updated.
*/
int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
size_t secretlen,
const ngtcp2_crypto_aead_ctx *aead_ctx,
const uint8_t *iv, size_t ivlen,
const ngtcp2_mem *mem);
/*
* ngtcp2_crypto_km_nocopy_new is similar to ngtcp2_crypto_km_new, but
* it does not copy secret, key and IV.
*/
int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
size_t ivlen, const ngtcp2_mem *mem);
void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem);
typedef struct ngtcp2_crypto_cc {
ngtcp2_crypto_aead aead;
ngtcp2_crypto_cipher hp;
ngtcp2_crypto_km *ckm;
ngtcp2_crypto_cipher_ctx hp_ctx;
ngtcp2_encrypt encrypt;
ngtcp2_decrypt decrypt;
ngtcp2_hp_mask hp_mask;
} ngtcp2_crypto_cc;
void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen,
int64_t pkt_num);
/*
* ngtcp2_transport_params_copy_new makes a copy of |src|, and assigns
* it to |*pdest|. If |src| is NULL, NULL is assigned to |*pdest|.
*
* Caller is responsible to call ngtcp2_transport_params_del to free
* the memory assigned to |*pdest|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_transport_params_copy_new(ngtcp2_transport_params **pdest,
const ngtcp2_transport_params *src,
const ngtcp2_mem *mem);
#endif /* NGTCP2_CRYPTO_H */

View file

@ -1,154 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_err.h"
const char *ngtcp2_strerror(int liberr) {
switch (liberr) {
case 0:
return "NO_ERROR";
case NGTCP2_ERR_INVALID_ARGUMENT:
return "ERR_INVALID_ARGUMENT";
case NGTCP2_ERR_NOBUF:
return "ERR_NOBUF";
case NGTCP2_ERR_PROTO:
return "ERR_PROTO";
case NGTCP2_ERR_INVALID_STATE:
return "ERR_INVALID_STATE";
case NGTCP2_ERR_ACK_FRAME:
return "ERR_ACK_FRAME";
case NGTCP2_ERR_STREAM_ID_BLOCKED:
return "ERR_STREAM_ID_BLOCKED";
case NGTCP2_ERR_STREAM_IN_USE:
return "ERR_STREAM_IN_USE";
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
return "ERR_STREAM_DATA_BLOCKED";
case NGTCP2_ERR_FLOW_CONTROL:
return "ERR_FLOW_CONTROL";
case NGTCP2_ERR_CONNECTION_ID_LIMIT:
return "ERR_CONNECTION_ID_LIMIT";
case NGTCP2_ERR_STREAM_LIMIT:
return "ERR_STREAM_LIMIT";
case NGTCP2_ERR_FINAL_SIZE:
return "ERR_FINAL_SIZE";
case NGTCP2_ERR_CRYPTO:
return "ERR_CRYPTO";
case NGTCP2_ERR_PKT_NUM_EXHAUSTED:
return "ERR_PKT_NUM_EXHAUSTED";
case NGTCP2_ERR_NOMEM:
return "ERR_NOMEM";
case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
return "ERR_REQUIRED_TRANSPORT_PARAM";
case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
return "ERR_MALFORMED_TRANSPORT_PARAM";
case NGTCP2_ERR_FRAME_ENCODING:
return "ERR_FRAME_ENCODING";
case NGTCP2_ERR_DECRYPT:
return "ERR_DECRYPT";
case NGTCP2_ERR_STREAM_SHUT_WR:
return "ERR_STREAM_SHUT_WR";
case NGTCP2_ERR_STREAM_NOT_FOUND:
return "ERR_STREAM_NOT_FOUND";
case NGTCP2_ERR_STREAM_STATE:
return "ERR_STREAM_STATE";
case NGTCP2_ERR_RECV_VERSION_NEGOTIATION:
return "ERR_RECV_VERSION_NEGOTIATION";
case NGTCP2_ERR_CLOSING:
return "ERR_CLOSING";
case NGTCP2_ERR_DRAINING:
return "ERR_DRAINING";
case NGTCP2_ERR_TRANSPORT_PARAM:
return "ERR_TRANSPORT_PARAM";
case NGTCP2_ERR_DISCARD_PKT:
return "ERR_DISCARD_PKT";
case NGTCP2_ERR_CONN_ID_BLOCKED:
return "ERR_CONN_ID_BLOCKED";
case NGTCP2_ERR_CALLBACK_FAILURE:
return "ERR_CALLBACK_FAILURE";
case NGTCP2_ERR_INTERNAL:
return "ERR_INTERNAL";
case NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED:
return "ERR_CRYPTO_BUFFER_EXCEEDED";
case NGTCP2_ERR_WRITE_MORE:
return "ERR_WRITE_MORE";
case NGTCP2_ERR_RETRY:
return "ERR_RETRY";
case NGTCP2_ERR_DROP_CONN:
return "ERR_DROP_CONN";
case NGTCP2_ERR_AEAD_LIMIT_REACHED:
return "ERR_AEAD_LIMIT_REACHED";
case NGTCP2_ERR_NO_VIABLE_PATH:
return "ERR_NO_VIABLE_PATH";
case NGTCP2_ERR_VERSION_NEGOTIATION:
return "ERR_VERSION_NEGOTIATION";
case NGTCP2_ERR_HANDSHAKE_TIMEOUT:
return "ERR_HANDSHAKE_TIMEOUT";
case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
return "ERR_VERSION_NEGOTIATION_FAILURE";
case NGTCP2_ERR_IDLE_CLOSE:
return "ERR_IDLE_CLOSE";
default:
return "(unknown)";
}
}
int ngtcp2_err_is_fatal(int liberr) { return liberr < NGTCP2_ERR_FATAL; }
uint64_t ngtcp2_err_infer_quic_transport_error_code(int liberr) {
switch (liberr) {
case 0:
return NGTCP2_NO_ERROR;
case NGTCP2_ERR_ACK_FRAME:
case NGTCP2_ERR_FRAME_ENCODING:
return NGTCP2_FRAME_ENCODING_ERROR;
case NGTCP2_ERR_FLOW_CONTROL:
return NGTCP2_FLOW_CONTROL_ERROR;
case NGTCP2_ERR_CONNECTION_ID_LIMIT:
return NGTCP2_CONNECTION_ID_LIMIT_ERROR;
case NGTCP2_ERR_STREAM_LIMIT:
return NGTCP2_STREAM_LIMIT_ERROR;
case NGTCP2_ERR_FINAL_SIZE:
return NGTCP2_FINAL_SIZE_ERROR;
case NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM:
case NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM:
case NGTCP2_ERR_TRANSPORT_PARAM:
return NGTCP2_TRANSPORT_PARAMETER_ERROR;
case NGTCP2_ERR_INVALID_ARGUMENT:
case NGTCP2_ERR_NOMEM:
case NGTCP2_ERR_CALLBACK_FAILURE:
return NGTCP2_INTERNAL_ERROR;
case NGTCP2_ERR_STREAM_STATE:
return NGTCP2_STREAM_STATE_ERROR;
case NGTCP2_ERR_CRYPTO_BUFFER_EXCEEDED:
return NGTCP2_CRYPTO_BUFFER_EXCEEDED;
case NGTCP2_ERR_AEAD_LIMIT_REACHED:
return NGTCP2_AEAD_LIMIT_REACHED;
case NGTCP2_ERR_NO_VIABLE_PATH:
return NGTCP2_NO_VIABLE_PATH;
case NGTCP2_ERR_VERSION_NEGOTIATION_FAILURE:
return NGTCP2_VERSION_NEGOTIATION_ERROR;
default:
return NGTCP2_PROTOCOL_VIOLATION;
}
}

View file

@ -1,34 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_ERR_H
#define NGTCP2_ERR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#endif /* NGTCP2_ERR_H */

View file

@ -1,167 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_gaptr.h"
#include <string.h>
#include <assert.h>
void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
ngtcp2_ksl_init(&gaptr->gap, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
mem);
gaptr->mem = mem;
}
static int gaptr_gap_init(ngtcp2_gaptr *gaptr) {
ngtcp2_range range = {0, UINT64_MAX};
int rv;
rv = ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
if (rv != 0) {
return rv;
}
return 0;
}
void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr) {
if (gaptr == NULL) {
return;
}
ngtcp2_ksl_free(&gaptr->gap);
}
int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, uint64_t datalen) {
int rv;
ngtcp2_range k, m, l, r, q = {offset, offset + datalen};
ngtcp2_ksl_it it;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
rv = gaptr_gap_init(gaptr);
if (rv != 0) {
return rv;
}
}
it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
ngtcp2_ksl_range_exclusive_compar);
for (; !ngtcp2_ksl_it_end(&it);) {
k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
m = ngtcp2_range_intersect(&q, &k);
if (!ngtcp2_range_len(&m)) {
break;
}
if (ngtcp2_range_eq(&k, &m)) {
ngtcp2_ksl_remove_hint(&gaptr->gap, &it, &it, &k);
continue;
}
ngtcp2_range_cut(&l, &r, &k, &m);
if (ngtcp2_range_len(&l)) {
ngtcp2_ksl_update_key(&gaptr->gap, &k, &l);
if (ngtcp2_range_len(&r)) {
rv = ngtcp2_ksl_insert(&gaptr->gap, &it, &r, NULL);
if (rv != 0) {
return rv;
}
}
} else if (ngtcp2_range_len(&r)) {
ngtcp2_ksl_update_key(&gaptr->gap, &k, &r);
}
ngtcp2_ksl_it_next(&it);
}
return 0;
}
uint64_t ngtcp2_gaptr_first_gap_offset(ngtcp2_gaptr *gaptr) {
ngtcp2_ksl_it it;
ngtcp2_range r;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
return 0;
}
it = ngtcp2_ksl_begin(&gaptr->gap);
r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
return r.begin;
}
ngtcp2_range ngtcp2_gaptr_get_first_gap_after(ngtcp2_gaptr *gaptr,
uint64_t offset) {
ngtcp2_range q = {offset, offset + 1};
ngtcp2_ksl_it it;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
ngtcp2_range r = {0, UINT64_MAX};
return r;
}
it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
ngtcp2_ksl_range_exclusive_compar);
assert(!ngtcp2_ksl_it_end(&it));
return *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
}
int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset,
uint64_t datalen) {
ngtcp2_range q = {offset, offset + datalen};
ngtcp2_ksl_it it;
ngtcp2_range k;
ngtcp2_range m;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
return 0;
}
it = ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
ngtcp2_ksl_range_exclusive_compar);
k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
m = ngtcp2_range_intersect(&q, &k);
return ngtcp2_range_len(&m) == 0;
}
void ngtcp2_gaptr_drop_first_gap(ngtcp2_gaptr *gaptr) {
ngtcp2_ksl_it it;
ngtcp2_range r;
if (ngtcp2_ksl_len(&gaptr->gap) == 0) {
return;
}
it = ngtcp2_ksl_begin(&gaptr->gap);
assert(!ngtcp2_ksl_it_end(&it));
r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
ngtcp2_ksl_remove_hint(&gaptr->gap, NULL, &it, &r);
}

View file

@ -1,98 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_GAPTR_H
#define NGTCP2_GAPTR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_ksl.h"
#include "ngtcp2_range.h"
/*
* ngtcp2_gaptr maintains the gap in the range [0, UINT64_MAX).
*/
typedef struct ngtcp2_gaptr {
/* gap maintains the range of offset which is not received
yet. Initially, its range is [0, UINT64_MAX). */
ngtcp2_ksl gap;
/* mem is custom memory allocator */
const ngtcp2_mem *mem;
} ngtcp2_gaptr;
/*
* ngtcp2_gaptr_init initializes |gaptr|.
*/
void ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem);
/*
* ngtcp2_gaptr_free frees resources allocated for |gaptr|.
*/
void ngtcp2_gaptr_free(ngtcp2_gaptr *gaptr);
/*
* ngtcp2_gaptr_push adds new data of length |datalen| at the stream
* offset |offset|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_gaptr_push(ngtcp2_gaptr *gaptr, uint64_t offset, uint64_t datalen);
/*
* ngtcp2_gaptr_first_gap_offset returns the offset to the first gap.
* If there is no gap, it returns UINT64_MAX.
*/
uint64_t ngtcp2_gaptr_first_gap_offset(ngtcp2_gaptr *gaptr);
/*
* ngtcp2_gaptr_get_first_gap_after returns the first gap which
* overlaps or comes after |offset|.
*/
ngtcp2_range ngtcp2_gaptr_get_first_gap_after(ngtcp2_gaptr *gaptr,
uint64_t offset);
/*
* ngtcp2_gaptr_is_pushed returns nonzero if range [offset, offset +
* datalen) is completely pushed into this object.
*/
int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset,
uint64_t datalen);
/*
* ngtcp2_gaptr_drop_first_gap deletes the first gap entirely as if
* the range is pushed. This function assumes that at least one gap
* exists.
*/
void ngtcp2_gaptr_drop_first_gap(ngtcp2_gaptr *gaptr);
#endif /* NGTCP2_GAPTR_H */

View file

@ -1,79 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_idtr.h"
#include <assert.h>
void ngtcp2_idtr_init(ngtcp2_idtr *idtr, int server, const ngtcp2_mem *mem) {
ngtcp2_gaptr_init(&idtr->gap, mem);
idtr->server = server;
}
void ngtcp2_idtr_free(ngtcp2_idtr *idtr) {
if (idtr == NULL) {
return;
}
ngtcp2_gaptr_free(&idtr->gap);
}
/*
* id_from_stream_id translates |stream_id| to id space used by
* ngtcp2_idtr.
*/
static uint64_t id_from_stream_id(int64_t stream_id) {
return (uint64_t)(stream_id >> 2);
}
int ngtcp2_idtr_open(ngtcp2_idtr *idtr, int64_t stream_id) {
uint64_t q;
assert((idtr->server && (stream_id % 2)) ||
(!idtr->server && (stream_id % 2)) == 0);
q = id_from_stream_id(stream_id);
if (ngtcp2_gaptr_is_pushed(&idtr->gap, q, 1)) {
return NGTCP2_ERR_STREAM_IN_USE;
}
return ngtcp2_gaptr_push(&idtr->gap, q, 1);
}
int ngtcp2_idtr_is_open(ngtcp2_idtr *idtr, int64_t stream_id) {
uint64_t q;
assert((idtr->server && (stream_id % 2)) ||
(!idtr->server && (stream_id % 2)) == 0);
q = id_from_stream_id(stream_id);
return ngtcp2_gaptr_is_pushed(&idtr->gap, q, 1);
}
uint64_t ngtcp2_idtr_first_gap(ngtcp2_idtr *idtr) {
return ngtcp2_gaptr_first_gap_offset(&idtr->gap);
}

View file

@ -1,89 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_IDTR_H
#define NGTCP2_IDTR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_gaptr.h"
/*
* ngtcp2_idtr tracks the usage of stream ID.
*/
typedef struct ngtcp2_idtr {
/* gap maintains the range of ID which is not used yet. Initially,
its range is [0, UINT64_MAX). */
ngtcp2_gaptr gap;
/* server is nonzero if this object records server initiated stream
ID. */
int server;
} ngtcp2_idtr;
/*
* ngtcp2_idtr_init initializes |idtr|.
*
* If this object records server initiated ID (even number), set
* |server| to nonzero.
*/
void ngtcp2_idtr_init(ngtcp2_idtr *idtr, int server, const ngtcp2_mem *mem);
/*
* ngtcp2_idtr_free frees resources allocated for |idtr|.
*/
void ngtcp2_idtr_free(ngtcp2_idtr *idtr);
/*
* ngtcp2_idtr_open claims that |stream_id| is in used.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_STREAM_IN_USE
* ID has already been used.
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_idtr_open(ngtcp2_idtr *idtr, int64_t stream_id);
/*
* ngtcp2_idtr_open tells whether ID |stream_id| is in used or not.
*
* It returns nonzero if |stream_id| is used.
*/
int ngtcp2_idtr_is_open(ngtcp2_idtr *idtr, int64_t stream_id);
/*
* ngtcp2_idtr_first_gap returns the first id of first gap. If there
* is no gap, it returns UINT64_MAX. The returned id is an id space
* used in this object internally, and not stream ID.
*/
uint64_t ngtcp2_idtr_first_gap(ngtcp2_idtr *idtr);
#endif /* NGTCP2_IDTR_H */

View file

@ -1,819 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_ksl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "ngtcp2_macro.h"
#include "ngtcp2_mem.h"
#include "ngtcp2_range.h"
static ngtcp2_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}};
static size_t ksl_nodelen(size_t keylen) {
return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0xfu) &
~(uintptr_t)0xfu;
}
static size_t ksl_blklen(size_t nodelen) {
return sizeof(ngtcp2_ksl_blk) + nodelen * NGTCP2_KSL_MAX_NBLK -
sizeof(uint64_t);
}
/*
* ksl_node_set_key sets |key| to |node|.
*/
static void ksl_node_set_key(ngtcp2_ksl *ksl, ngtcp2_ksl_node *node,
const void *key) {
memcpy(node->key, key, ksl->keylen);
}
void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
const ngtcp2_mem *mem) {
size_t nodelen = ksl_nodelen(keylen);
ngtcp2_objalloc_init(&ksl->blkalloc,
((ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu) * 8,
mem);
ksl->head = NULL;
ksl->front = ksl->back = NULL;
ksl->compar = compar;
ksl->keylen = keylen;
ksl->nodelen = nodelen;
ksl->n = 0;
}
static ngtcp2_ksl_blk *ksl_blk_objalloc_new(ngtcp2_ksl *ksl) {
return ngtcp2_objalloc_ksl_blk_len_get(&ksl->blkalloc,
ksl_blklen(ksl->nodelen));
}
static void ksl_blk_objalloc_del(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
ngtcp2_objalloc_ksl_blk_release(&ksl->blkalloc, blk);
}
static int ksl_head_init(ngtcp2_ksl *ksl) {
ngtcp2_ksl_blk *head = ksl_blk_objalloc_new(ksl);
if (!head) {
return NGTCP2_ERR_NOMEM;
}
head->next = head->prev = NULL;
head->n = 0;
head->leaf = 1;
ksl->head = head;
ksl->front = ksl->back = head;
return 0;
}
#ifdef NOMEMPOOL
/*
* ksl_free_blk frees |blk| recursively.
*/
static void ksl_free_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
size_t i;
if (!blk->leaf) {
for (i = 0; i < blk->n; ++i) {
ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk);
}
}
ksl_blk_objalloc_del(ksl, blk);
}
#endif /* NOMEMPOOL */
void ngtcp2_ksl_free(ngtcp2_ksl *ksl) {
if (!ksl || !ksl->head) {
return;
}
#ifdef NOMEMPOOL
ksl_free_blk(ksl, ksl->head);
#endif /* NOMEMPOOL */
ngtcp2_objalloc_free(&ksl->blkalloc);
}
/*
* ksl_split_blk splits |blk| into 2 ngtcp2_ksl_blk objects. The new
* ngtcp2_ksl_blk is always the "right" block.
*
* It returns the pointer to the ngtcp2_ksl_blk created which is the
* located at the right of |blk|, or NULL which indicates out of
* memory error.
*/
static ngtcp2_ksl_blk *ksl_split_blk(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk) {
ngtcp2_ksl_blk *rblk;
rblk = ksl_blk_objalloc_new(ksl);
if (rblk == NULL) {
return NULL;
}
rblk->next = blk->next;
blk->next = rblk;
if (rblk->next) {
rblk->next->prev = rblk;
} else if (ksl->back == blk) {
ksl->back = rblk;
}
rblk->prev = blk;
rblk->leaf = blk->leaf;
rblk->n = blk->n / 2;
memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
ksl->nodelen * rblk->n);
blk->n -= rblk->n;
assert(blk->n >= NGTCP2_KSL_MIN_NBLK);
assert(rblk->n >= NGTCP2_KSL_MIN_NBLK);
return rblk;
}
/*
* ksl_split_node splits a node included in |blk| at the position |i|
* into 2 adjacent nodes. The new node is always inserted at the
* position |i+1|.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_NOMEM
* 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;
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)));
node = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
node->blk = rblk;
++blk->n;
ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
node = ngtcp2_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node, ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
return 0;
}
/*
* ksl_split_head splits a head (root) block. It increases the height
* of skip list by 1.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
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) {
return NGTCP2_ERR_NOMEM;
}
lblk = ksl->head;
nhead = ksl_blk_objalloc_new(ksl);
if (nhead == NULL) {
ksl_blk_objalloc_del(ksl, rblk);
return NGTCP2_ERR_NOMEM;
}
nhead->next = nhead->prev = 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;
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->head = nhead;
return 0;
}
/*
* insert_node inserts a node whose key is |key| with the associated
* |data| at the index of |i|. This function assumes that the number
* of nodes contained by |blk| is strictly less than
* NGTCP2_KSL_MAX_NBLK.
*/
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));
node = ngtcp2_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node, key);
node->data = data;
++blk->n;
}
static size_t ksl_bsearch(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
const ngtcp2_ksl_key *key, ngtcp2_ksl_compar compar) {
size_t i;
ngtcp2_ksl_node *node;
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))
;
return i;
}
int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_key *key, void *data) {
ngtcp2_ksl_blk *blk;
ngtcp2_ksl_node *node;
size_t i;
int rv;
if (!ksl->head) {
rv = ksl_head_init(ksl);
if (rv != 0) {
return rv;
}
}
blk = ksl->head;
if (blk->n == NGTCP2_KSL_MAX_NBLK) {
rv = ksl_split_head(ksl);
if (rv != 0) {
return rv;
}
blk = ksl->head;
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (blk->leaf) {
if (i < blk->n &&
!ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
if (it) {
*it = ngtcp2_ksl_end(ksl);
}
return NGTCP2_ERR_INVALID_ARGUMENT;
}
ksl_insert_node(ksl, blk, i, key, data);
++ksl->n;
if (it) {
ngtcp2_ksl_it_init(it, ksl, blk, i);
}
return 0;
}
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);
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);
}
ksl_node_set_key(ksl, node, key);
blk = node->blk;
}
ksl_insert_node(ksl, blk, blk->n, key, data);
++ksl->n;
if (it) {
ngtcp2_ksl_it_init(it, ksl, blk, blk->n - 1);
}
return 0;
}
node = ngtcp2_ksl_nth_node(ksl, blk, i);
if (node->blk->n == NGTCP2_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, i);
if (rv != 0) {
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_key *)node->key, key)) {
ksl_node_set_key(ksl, node, key);
}
}
}
blk = node->blk;
}
}
/*
* ksl_remove_node removes the node included in |blk| at the index of
* |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)));
--blk->n;
}
/*
* ksl_merge_node merges 2 nodes which are the nodes at the index of
* |i| and |i + 1|.
*
* If |blk| is the direct descendant of head (root) block and the head
* block contains just 2 nodes, the merged block becomes head block,
* which decreases the height of |ksl| by 1.
*
* This function returns the pointer to the merged block.
*/
static ngtcp2_ksl_blk *ksl_merge_node(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk,
size_t i) {
ngtcp2_ksl_blk *lblk, *rblk;
assert(i + 1 < blk->n);
lblk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
rblk = ngtcp2_ksl_nth_node(ksl, blk, 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);
lblk->n += rblk->n;
lblk->next = rblk->next;
if (lblk->next) {
lblk->next->prev = lblk;
} else if (ksl->back == rblk) {
ksl->back = lblk;
}
ksl_blk_objalloc_del(ksl, rblk);
if (ksl->head == blk && blk->n == 2) {
ksl_blk_objalloc_del(ksl, ksl->head);
ksl->head = lblk;
} else {
ksl_remove_node(ksl, blk, i + 1);
ksl_node_set_key(ksl, ngtcp2_ksl_nth_node(ksl, blk, i),
ngtcp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
}
return lblk;
}
/*
* ksl_shift_left moves the first nodes in blk->nodes[i]->blk->nodes
* to blk->nodes[i - 1]->blk->nodes in a manner that they have the
* same amount of nodes as much as possible.
*/
static void ksl_shift_left(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
ngtcp2_ksl_node *lnode, *rnode;
size_t n;
assert(i > 0);
lnode = ngtcp2_ksl_nth_node(ksl, blk, i - 1);
rnode = ngtcp2_ksl_nth_node(ksl, blk, i);
assert(lnode->blk->n < NGTCP2_KSL_MAX_NBLK);
assert(rnode->blk->n > NGTCP2_KSL_MIN_NBLK);
n = (lnode->blk->n + rnode->blk->n + 1) / 2 - lnode->blk->n;
assert(n > 0);
assert(lnode->blk->n <= NGTCP2_KSL_MAX_NBLK - n);
assert(rnode->blk->n >= NGTCP2_KSL_MIN_NBLK + n);
memcpy(lnode->blk->nodes + ksl->nodelen * lnode->blk->n, rnode->blk->nodes,
ksl->nodelen * n);
lnode->blk->n += (uint32_t)n;
rnode->blk->n -= (uint32_t)n;
ksl_node_set_key(
ksl, lnode, ngtcp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen * n,
ksl->nodelen * rnode->blk->n);
}
/*
* ksl_shift_right moves the last nodes in blk->nodes[i]->blk->nodes
* to blk->nodes[i + 1]->blk->nodes in a manner that they have the
* same amount of nodes as much as possible..
*/
static void ksl_shift_right(ngtcp2_ksl *ksl, ngtcp2_ksl_blk *blk, size_t i) {
ngtcp2_ksl_node *lnode, *rnode;
size_t n;
assert(i < blk->n - 1);
lnode = ngtcp2_ksl_nth_node(ksl, blk, i);
rnode = ngtcp2_ksl_nth_node(ksl, blk, i + 1);
assert(lnode->blk->n > NGTCP2_KSL_MIN_NBLK);
assert(rnode->blk->n < NGTCP2_KSL_MAX_NBLK);
n = (lnode->blk->n + rnode->blk->n + 1) / 2 - rnode->blk->n;
assert(n > 0);
assert(lnode->blk->n >= NGTCP2_KSL_MIN_NBLK + n);
assert(rnode->blk->n <= NGTCP2_KSL_MAX_NBLK - n);
memmove(rnode->blk->nodes + ksl->nodelen * n, rnode->blk->nodes,
ksl->nodelen * rnode->blk->n);
rnode->blk->n += (uint32_t)n;
lnode->blk->n -= (uint32_t)n;
memcpy(rnode->blk->nodes, lnode->blk->nodes + ksl->nodelen * lnode->blk->n,
ksl->nodelen * n);
ksl_node_set_key(
ksl, lnode, ngtcp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
}
/*
* key_equal returns nonzero if |lhs| and |rhs| are equal using the
* function |compar|.
*/
static int key_equal(ngtcp2_ksl_compar compar, const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs) {
return !compar(lhs, rhs) && !compar(rhs, lhs);
}
int ngtcp2_ksl_remove_hint(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_it *hint,
const ngtcp2_ksl_key *key) {
ngtcp2_ksl_blk *blk = hint->blk;
assert(ksl->head);
if (blk->n <= NGTCP2_KSL_MIN_NBLK) {
return ngtcp2_ksl_remove(ksl, it, key);
}
ksl_remove_node(ksl, blk, hint->i);
--ksl->n;
if (it) {
if (hint->i == blk->n && blk->next) {
ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
} else {
ngtcp2_ksl_it_init(it, ksl, blk, hint->i);
}
}
return 0;
}
int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_key *key) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_node *node;
size_t i;
if (!ksl->head) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
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 = ksl_merge_node(ksl, ksl->head, 0);
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (i == blk->n) {
if (it) {
*it = ngtcp2_ksl_end(ksl);
}
return NGTCP2_ERR_INVALID_ARGUMENT;
}
if (blk->leaf) {
if (ksl->compar(key, ngtcp2_ksl_nth_node(ksl, blk, i)->key)) {
if (it) {
*it = ngtcp2_ksl_end(ksl);
}
return NGTCP2_ERR_INVALID_ARGUMENT;
}
ksl_remove_node(ksl, blk, i);
--ksl->n;
if (it) {
if (blk->n == i && blk->next) {
ngtcp2_ksl_it_init(it, ksl, blk->next, 0);
} else {
ngtcp2_ksl_it_init(it, ksl, blk, i);
}
}
return 0;
}
node = ngtcp2_ksl_nth_node(ksl, blk, i);
if (node->blk->n > NGTCP2_KSL_MIN_NBLK) {
blk = node->blk;
continue;
}
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) {
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) {
ksl_shift_right(ksl, blk, i - 1);
blk = node->blk;
continue;
}
if (i + 1 < blk->n) {
blk = ksl_merge_node(ksl, blk, i);
continue;
}
assert(i > 0);
blk = ksl_merge_node(ksl, blk, i - 1);
}
}
ngtcp2_ksl_it ngtcp2_ksl_lower_bound(ngtcp2_ksl *ksl,
const ngtcp2_ksl_key *key) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_it it;
size_t i;
if (!blk) {
ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
return it;
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, ksl->compar);
if (blk->leaf) {
if (i == blk->n && blk->next) {
blk = blk->next;
i = 0;
}
ngtcp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
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)
;
if (blk->next) {
blk = blk->next;
i = 0;
} else {
i = blk->n;
}
ngtcp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
}
}
ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(ngtcp2_ksl *ksl,
const ngtcp2_ksl_key *key,
ngtcp2_ksl_compar compar) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_it it;
size_t i;
if (!blk) {
ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
return it;
}
for (;;) {
i = ksl_bsearch(ksl, blk, key, compar);
if (blk->leaf) {
if (i == blk->n && blk->next) {
blk = blk->next;
i = 0;
}
ngtcp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
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)
;
if (blk->next) {
blk = blk->next;
i = 0;
} else {
i = blk->n;
}
ngtcp2_ksl_it_init(&it, ksl, blk, i);
return it;
}
blk = ngtcp2_ksl_nth_node(ksl, blk, i)->blk;
}
}
void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
const ngtcp2_ksl_key *new_key) {
ngtcp2_ksl_blk *blk = ksl->head;
ngtcp2_ksl_node *node;
size_t i;
assert(ksl->head);
for (;;) {
i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
assert(i < blk->n);
node = ngtcp2_ksl_nth_node(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);
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);
}
blk = node->blk;
}
}
static void ksl_print(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, "\n");
return;
}
for (i = 0; i < blk->n; ++i) {
ksl_print(ksl, ngtcp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
}
}
size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl) { return ksl->n; }
void ngtcp2_ksl_clear(ngtcp2_ksl *ksl) {
if (!ksl->head) {
return;
}
#ifdef NOMEMPOOL
ksl_free_blk(ksl, ksl->head);
#endif /* NOMEMPOOL */
ksl->front = ksl->back = ksl->head = NULL;
ksl->n = 0;
ngtcp2_objalloc_clear(&ksl->blkalloc);
}
void ngtcp2_ksl_print(ngtcp2_ksl *ksl) {
if (!ksl->head) {
return;
}
ksl_print(ksl, ksl->head, 0);
}
ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) {
ngtcp2_ksl_it it;
if (ksl->head) {
ngtcp2_ksl_it_init(&it, ksl, ksl->front, 0);
} else {
ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
}
return it;
}
ngtcp2_ksl_it ngtcp2_ksl_end(const ngtcp2_ksl *ksl) {
ngtcp2_ksl_it it;
if (ksl->head) {
ngtcp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
} else {
ngtcp2_ksl_it_init(&it, ksl, &null_blk, 0);
}
return it;
}
void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
ngtcp2_ksl_blk *blk, size_t i) {
it->ksl = ksl;
it->blk = blk;
it->i = i;
}
void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it) {
assert(!ngtcp2_ksl_it_begin(it));
if (it->i == 0) {
it->blk = it->blk->prev;
it->i = it->blk->n - 1;
} else {
--it->i;
}
}
int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it) {
return it->i == 0 && it->blk->prev == NULL;
}
int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs) {
const ngtcp2_range *a = lhs, *b = rhs;
return a->begin < b->begin;
}
int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs) {
const ngtcp2_range *a = lhs, *b = rhs;
return a->begin < b->begin &&
!(ngtcp2_max(a->begin, b->begin) < ngtcp2_min(a->end, b->end));
}

View file

@ -1,345 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_KSL_H
#define NGTCP2_KSL_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <stdlib.h>
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_objalloc.h"
/*
* Skip List using single key instead of range.
*/
#define NGTCP2_KSL_DEGR 16
/* NGTCP2_KSL_MAX_NBLK is the maximum number of nodes which a single
block can contain. */
#define NGTCP2_KSL_MAX_NBLK (2 * NGTCP2_KSL_DEGR - 1)
/* NGTCP2_KSL_MIN_NBLK is the minimum number of nodes which a single
block other than root must contains. */
#define NGTCP2_KSL_MIN_NBLK (NGTCP2_KSL_DEGR - 1)
/*
* ngtcp2_ksl_key represents key in ngtcp2_ksl.
*/
typedef void ngtcp2_ksl_key;
typedef struct ngtcp2_ksl_node ngtcp2_ksl_node;
typedef struct ngtcp2_ksl_blk ngtcp2_ksl_blk;
/*
* 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.
*/
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];
};
};
/*
* ngtcp2_ksl_blk contains ngtcp2_ksl_node objects.
*/
struct ngtcp2_ksl_blk {
union {
struct {
/* next points to the next block if leaf field is nonzero. */
ngtcp2_ksl_blk *next;
/* prev points to the previous block if leaf field is nonzero. */
ngtcp2_ksl_blk *prev;
/* n is the number of nodes this object contains in nodes. */
uint32_t n;
/* leaf is nonzero if this block contains leaf nodes. */
uint32_t leaf;
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];
};
};
ngtcp2_opl_entry oplent;
};
};
ngtcp2_objalloc_def(ksl_blk, ngtcp2_ksl_blk, oplent);
/*
* ngtcp2_ksl_compar is a function type which returns nonzero if key
* |lhs| should be placed before |rhs|. It returns 0 otherwise.
*/
typedef int (*ngtcp2_ksl_compar)(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs);
typedef struct ngtcp2_ksl ngtcp2_ksl;
typedef struct ngtcp2_ksl_it ngtcp2_ksl_it;
/*
* ngtcp2_ksl_it is a forward iterator to iterate nodes.
*/
struct ngtcp2_ksl_it {
const ngtcp2_ksl *ksl;
ngtcp2_ksl_blk *blk;
size_t i;
};
/*
* ngtcp2_ksl is a deterministic paged skip list.
*/
struct ngtcp2_ksl {
ngtcp2_objalloc blkalloc;
/* head points to the root block. */
ngtcp2_ksl_blk *head;
/* front points to the first leaf block. */
ngtcp2_ksl_blk *front;
/* back points to the last leaf block. */
ngtcp2_ksl_blk *back;
ngtcp2_ksl_compar compar;
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;
};
/*
* ngtcp2_ksl_init initializes |ksl|. |compar| specifies compare
* function. |keylen| is the length of key.
*/
void ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
const ngtcp2_mem *mem);
/*
* ngtcp2_ksl_free frees resources allocated for |ksl|. If |ksl| is
* NULL, this function does nothing. It does not free the memory
* region pointed by |ksl| itself.
*/
void ngtcp2_ksl_free(ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_insert inserts |key| with its associated |data|. On
* successful insertion, the iterator points to the inserted node is
* stored in |*it|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
* NGTCP2_ERR_INVALID_ARGUMENT
* |key| already exists.
*/
int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_key *key, void *data);
/*
* ngtcp2_ksl_remove removes the |key| from |ksl|.
*
* This function assigns the iterator to |*it|, which points to the
* node which is located at the right next of the removed node if |it|
* is not NULL. If |key| is not found, no deletion takes place and
* the return value of ngtcp2_ksl_end(ksl) is assigned to |*it|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* |key| does not exist.
*/
int ngtcp2_ksl_remove(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_key *key);
/*
* ngtcp2_ksl_remove_hint removes the |key| from |ksl|. |hint| must
* point to the same node denoted by |key|. |hint| is used to remove
* a node efficiently in some cases. Other than that, it behaves
* exactly like ngtcp2_ksl_remove. |it| and |hint| can point to the
* same object.
*/
int ngtcp2_ksl_remove_hint(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
const ngtcp2_ksl_it *hint,
const ngtcp2_ksl_key *key);
/*
* ngtcp2_ksl_lower_bound returns the iterator which points to the
* first node which has the key which is equal to |key| or the last
* node which satisfies !compar(&node->key, key). If there is no such
* node, it returns the iterator which satisfies ngtcp2_ksl_it_end(it)
* != 0.
*/
ngtcp2_ksl_it ngtcp2_ksl_lower_bound(ngtcp2_ksl *ksl,
const ngtcp2_ksl_key *key);
/*
* ngtcp2_ksl_lower_bound_compar works like ngtcp2_ksl_lower_bound,
* but it takes custom function |compar| to do lower bound search.
*/
ngtcp2_ksl_it ngtcp2_ksl_lower_bound_compar(ngtcp2_ksl *ksl,
const ngtcp2_ksl_key *key,
ngtcp2_ksl_compar compar);
/*
* ngtcp2_ksl_update_key replaces the key of nodes which has |old_key|
* with |new_key|. |new_key| must be strictly greater than the
* previous node and strictly smaller than the next node.
*/
void ngtcp2_ksl_update_key(ngtcp2_ksl *ksl, const ngtcp2_ksl_key *old_key,
const ngtcp2_ksl_key *new_key);
/*
* ngtcp2_ksl_begin returns the iterator which points to the first
* node. If there is no node in |ksl|, it returns the iterator which
* satisfies ngtcp2_ksl_it_end(it) != 0.
*/
ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_end returns the iterator which points to the node
* following the last node. The returned object satisfies
* ngtcp2_ksl_it_end(). If there is no node in |ksl|, it returns the
* iterator which satisfies ngtcp2_ksl_it_begin(it) != 0.
*/
ngtcp2_ksl_it ngtcp2_ksl_end(const ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_len returns the number of elements stored in |ksl|.
*/
size_t ngtcp2_ksl_len(ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_clear removes all elements stored in |ksl|.
*/
void ngtcp2_ksl_clear(ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_nth_node returns the |n|th node under |blk|.
*/
#define ngtcp2_ksl_nth_node(KSL, BLK, N) \
((ngtcp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
/*
* ngtcp2_ksl_print prints its internal state in stderr. It assumes
* that the key is of type int64_t. This function should be used for
* the debugging purpose only.
*/
void ngtcp2_ksl_print(ngtcp2_ksl *ksl);
/*
* ngtcp2_ksl_it_init initializes |it|.
*/
void ngtcp2_ksl_it_init(ngtcp2_ksl_it *it, const ngtcp2_ksl *ksl,
ngtcp2_ksl_blk *blk, size_t i);
/*
* ngtcp2_ksl_it_get returns the data associated to the node which
* |it| points to. It is undefined to call this function when
* ngtcp2_ksl_it_end(it) returns nonzero.
*/
#define ngtcp2_ksl_it_get(IT) \
ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
/*
* ngtcp2_ksl_it_next advances the iterator by one. It is undefined
* if this function is called when ngtcp2_ksl_it_end(it) returns
* nonzero.
*/
#define ngtcp2_ksl_it_next(IT) \
(++(IT)->i == (IT)->blk->n && (IT)->blk->next \
? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
: 0)
/*
* ngtcp2_ksl_it_prev moves backward the iterator by one. It is
* undefined if this function is called when ngtcp2_ksl_it_begin(it)
* returns nonzero.
*/
void ngtcp2_ksl_it_prev(ngtcp2_ksl_it *it);
/*
* ngtcp2_ksl_it_end returns nonzero if |it| points to the beyond the
* last node.
*/
#define ngtcp2_ksl_it_end(IT) \
((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
/*
* ngtcp2_ksl_it_begin returns nonzero if |it| points to the first
* node. |it| might satisfy both ngtcp2_ksl_it_begin(&it) and
* ngtcp2_ksl_it_end(&it) if the skip list has no node.
*/
int ngtcp2_ksl_it_begin(const ngtcp2_ksl_it *it);
/*
* ngtcp2_ksl_key returns the key of the node which |it| points to.
* It is undefined to call this function when ngtcp2_ksl_it_end(it)
* returns nonzero.
*/
#define ngtcp2_ksl_it_key(IT) \
((ngtcp2_ksl_key *)ngtcp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
/*
* ngtcp2_ksl_range_compar is an implementation of ngtcp2_ksl_compar.
* lhs->ptr and rhs->ptr must point to ngtcp2_range object and the
* function returns nonzero if (const ngtcp2_range *)(lhs->ptr)->begin
* < (const ngtcp2_range *)(rhs->ptr)->begin.
*/
int ngtcp2_ksl_range_compar(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs);
/*
* ngtcp2_ksl_range_exclusive_compar is an implementation of
* ngtcp2_ksl_compar. lhs->ptr and rhs->ptr must point to
* ngtcp2_range object and the function returns nonzero if (const
* ngtcp2_range *)(lhs->ptr)->begin < (const ngtcp2_range
* *)(rhs->ptr)->begin and the 2 ranges do not intersect.
*/
int ngtcp2_ksl_range_exclusive_compar(const ngtcp2_ksl_key *lhs,
const ngtcp2_ksl_key *rhs);
#endif /* NGTCP2_KSL_H */

View file

@ -1,822 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_log.h"
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <assert.h>
#include <string.h>
#include "ngtcp2_str.h"
#include "ngtcp2_vec.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_conv.h"
#include "ngtcp2_unreachable.h"
#include "ngtcp2_net.h"
void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid,
ngtcp2_printf log_printf, ngtcp2_tstamp ts,
void *user_data) {
if (scid) {
ngtcp2_encode_hex(log->scid, scid->data, scid->datalen);
} else {
log->scid[0] = '\0';
}
log->log_printf = log_printf;
log->ts = log->last_ts = ts;
log->user_data = user_data;
}
/*
* # Log header
*
* <LEVEL><TIMESTAMP> <SCID> <EVENT>
*
* <LEVEL>:
* Log level. I=Info, W=Warning, E=Error
*
* <TIMESTAMP>:
* Timestamp relative to ngtcp2_log.ts field in milliseconds
* resolution.
*
* <SCID>:
* Source Connection ID in hex string.
*
* <EVENT>:
* Event. pkt=packet, frm=frame, rcv=recovery, cry=crypto,
* con=connection(catch all)
*
* # Frame event
*
* <DIR> <PKN> <PKTNAME> <FRAMENAME>(<FRAMETYPE>)
*
* <DIR>:
* Flow direction. tx=transmission, rx=reception
*
* <PKN>:
* Packet number.
*
* <PKTNAME>:
* Packet name. (e.g., Initial, Handshake, 1RTT)
*
* <FRAMENAME>:
* Frame name. (e.g., STREAM, ACK, PING)
*
* <FRAMETYPE>:
* Frame type in hex string.
*/
#define NGTCP2_LOG_BUFLEN 4096
/* TODO Split second and remaining fraction with comma */
#define NGTCP2_LOG_HD "I%08" PRIu64 " 0x%s %s"
#define NGTCP2_LOG_PKT NGTCP2_LOG_HD " %s %" PRId64 " %s"
#define NGTCP2_LOG_TP NGTCP2_LOG_HD " remote transport_parameters"
#define NGTCP2_LOG_FRM_HD_FIELDS(DIR) \
timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "frm", \
(DIR), hd->pkt_num, strpkttype(hd)
#define NGTCP2_LOG_PKT_HD_FIELDS(DIR) \
timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "pkt", \
(DIR), hd->pkt_num, strpkttype(hd)
#define NGTCP2_LOG_TP_HD_FIELDS \
timestamp_cast(log->last_ts - log->ts), (const char *)log->scid, "cry"
static const char *strerrorcode(uint64_t error_code) {
switch (error_code) {
case NGTCP2_NO_ERROR:
return "NO_ERROR";
case NGTCP2_INTERNAL_ERROR:
return "INTERNAL_ERROR";
case NGTCP2_CONNECTION_REFUSED:
return "CONNECTION_REFUSED";
case NGTCP2_FLOW_CONTROL_ERROR:
return "FLOW_CONTROL_ERROR";
case NGTCP2_STREAM_LIMIT_ERROR:
return "STREAM_LIMIT_ERROR";
case NGTCP2_STREAM_STATE_ERROR:
return "STREAM_STATE_ERROR";
case NGTCP2_FINAL_SIZE_ERROR:
return "FINAL_SIZE_ERROR";
case NGTCP2_FRAME_ENCODING_ERROR:
return "FRAME_ENCODING_ERROR";
case NGTCP2_TRANSPORT_PARAMETER_ERROR:
return "TRANSPORT_PARAMETER_ERROR";
case NGTCP2_CONNECTION_ID_LIMIT_ERROR:
return "CONNECTION_ID_LIMIT_ERROR";
case NGTCP2_PROTOCOL_VIOLATION:
return "PROTOCOL_VIOLATION";
case NGTCP2_INVALID_TOKEN:
return "INVALID_TOKEN";
case NGTCP2_APPLICATION_ERROR:
return "APPLICATION_ERROR";
case NGTCP2_CRYPTO_BUFFER_EXCEEDED:
return "CRYPTO_BUFFER_EXCEEDED";
case NGTCP2_KEY_UPDATE_ERROR:
return "KEY_UPDATE_ERROR";
case NGTCP2_VERSION_NEGOTIATION_ERROR:
return "VERSION_NEGOTIATION_ERROR";
default:
if (0x100u <= error_code && error_code <= 0x1ffu) {
return "CRYPTO_ERROR";
}
return "(unknown)";
}
}
static const char *strapperrorcode(uint64_t app_error_code) {
(void)app_error_code;
return "(unknown)";
}
static const char *strpkttype_long(uint8_t type) {
switch (type) {
case NGTCP2_PKT_INITIAL:
return "Initial";
case NGTCP2_PKT_RETRY:
return "Retry";
case NGTCP2_PKT_HANDSHAKE:
return "Handshake";
case NGTCP2_PKT_0RTT:
return "0RTT";
default:
return "(unknown)";
}
}
static const char *strpkttype(const ngtcp2_pkt_hd *hd) {
if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
return strpkttype_long(hd->type);
}
switch (hd->type) {
case NGTCP2_PKT_VERSION_NEGOTIATION:
return "VN";
case NGTCP2_PKT_STATELESS_RESET:
return "SR";
case NGTCP2_PKT_1RTT:
return "1RTT";
default:
return "(unknown)";
}
}
static const char *strpkttype_type_flags(uint8_t type, uint8_t flags) {
ngtcp2_pkt_hd hd = {0};
hd.type = type;
hd.flags = flags;
return strpkttype(&hd);
}
static const char *strevent(ngtcp2_log_event ev) {
switch (ev) {
case NGTCP2_LOG_EVENT_CON:
return "con";
case NGTCP2_LOG_EVENT_PKT:
return "pkt";
case NGTCP2_LOG_EVENT_FRM:
return "frm";
case NGTCP2_LOG_EVENT_RCV:
return "rcv";
case NGTCP2_LOG_EVENT_CRY:
return "cry";
case NGTCP2_LOG_EVENT_PTV:
return "ptv";
case NGTCP2_LOG_EVENT_NONE:
default:
return "non";
}
}
static uint64_t timestamp_cast(uint64_t ns) { return ns / NGTCP2_MILLISECONDS; }
static void log_fr_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_stream *fr, const char *dir) {
log->log_printf(
log->user_data,
(NGTCP2_LOG_PKT " STREAM(0x%02x) id=0x%" PRIx64 " fin=%d offset=%" PRIu64
" len=%" PRIu64 " uni=%d"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type | fr->flags, fr->stream_id,
fr->fin, fr->offset, ngtcp2_vec_len(fr->data, fr->datacnt),
(fr->stream_id & 0x2) != 0);
}
static void log_fr_ack(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_ack *fr, const char *dir) {
int64_t largest_ack, min_ack;
size_t i;
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " ACK(0x%02x) largest_ack=%" PRId64
" ack_delay=%" PRIu64 "(%" PRIu64
") ack_range_count=%zu"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack,
fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay,
fr->rangecnt);
largest_ack = fr->largest_ack;
min_ack = fr->largest_ack - (int64_t)fr->first_ack_range;
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " ACK(0x%02x) range=[%" PRId64 "..%" PRId64
"] len=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack,
fr->first_ack_range);
for (i = 0; i < fr->rangecnt; ++i) {
const ngtcp2_ack_range *range = &fr->ranges[i];
largest_ack = min_ack - (int64_t)range->gap - 2;
min_ack = largest_ack - (int64_t)range->len;
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " ACK(0x%02x) range=[%" PRId64 "..%" PRId64
"] gap=%" PRIu64 " len=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack,
min_ack, range->gap, range->len);
}
if (fr->type == NGTCP2_FRAME_ACK_ECN) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " ACK(0x%02x) ect0=%" PRIu64
" ect1=%" PRIu64 " ce=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->ecn.ect0,
fr->ecn.ect1, fr->ecn.ce);
}
}
static void log_fr_padding(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_padding *fr, const char *dir) {
log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PADDING(0x%02x) len=%zu"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->len);
}
static void log_fr_reset_stream(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_reset_stream *fr,
const char *dir) {
log->log_printf(
log->user_data,
(NGTCP2_LOG_PKT " RESET_STREAM(0x%02x) id=0x%" PRIx64
" app_error_code=%s(0x%" PRIx64 ") final_size=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
strapperrorcode(fr->app_error_code), fr->app_error_code, fr->final_size);
}
static void log_fr_connection_close(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_connection_close *fr,
const char *dir) {
char reason[256];
size_t reasonlen = ngtcp2_min(sizeof(reason) - 1, fr->reasonlen);
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT
" CONNECTION_CLOSE(0x%02x) error_code=%s(0x%" PRIx64 ") "
"frame_type=%" PRIx64 " reason_len=%zu reason=[%s]"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
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));
}
static void log_fr_max_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_max_data *fr, const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " MAX_DATA(0x%02x) max_data=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_data);
}
static void log_fr_max_stream_data(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_max_stream_data *fr,
const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " MAX_STREAM_DATA(0x%02x) id=0x%" PRIx64
" max_stream_data=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
fr->max_stream_data);
}
static void log_fr_max_streams(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_max_streams *fr, const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " MAX_STREAMS(0x%02x) max_streams=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
}
static void log_fr_ping(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_ping *fr, const char *dir) {
log->log_printf(log->user_data, (NGTCP2_LOG_PKT " PING(0x%02x)"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
}
static void log_fr_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_data_blocked *fr,
const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " DATA_BLOCKED(0x%02x) offset=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset);
}
static void log_fr_stream_data_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_stream_data_blocked *fr,
const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " STREAM_DATA_BLOCKED(0x%02x) id=0x%" PRIx64
" offset=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
fr->offset);
}
static void log_fr_streams_blocked(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_streams_blocked *fr,
const char *dir) {
log->log_printf(
log->user_data,
(NGTCP2_LOG_PKT " STREAMS_BLOCKED(0x%02x) max_streams=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->max_streams);
}
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];
log->log_printf(
log->user_data,
(NGTCP2_LOG_PKT " NEW_CONNECTION_ID(0x%02x) seq=%" PRIu64
" cid=0x%s retire_prior_to=%" PRIu64
" stateless_reset_token=0x%s"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq,
(const char *)ngtcp2_encode_hex(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)));
}
static void log_fr_stop_sending(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_stop_sending *fr,
const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " STOP_SENDING(0x%02x) id=0x%" PRIx64
" app_error_code=%s(0x%" PRIx64 ")"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->stream_id,
strapperrorcode(fr->app_error_code), fr->app_error_code);
}
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];
log->log_printf(
log->user_data, (NGTCP2_LOG_PKT " PATH_CHALLENGE(0x%02x) data=0x%s"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
(const char *)ngtcp2_encode_hex(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];
log->log_printf(
log->user_data, (NGTCP2_LOG_PKT " PATH_RESPONSE(0x%02x) data=0x%s"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
(const char *)ngtcp2_encode_hex(buf, fr->data, sizeof(fr->data)));
}
static void log_fr_crypto(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_crypto *fr, const char *dir) {
log->log_printf(
log->user_data,
(NGTCP2_LOG_PKT " CRYPTO(0x%02x) offset=%" PRIu64 " len=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->offset,
ngtcp2_vec_len(fr->data, fr->datacnt));
}
static void log_fr_new_token(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;
if (fr->tokenlen > 64) {
p = ngtcp2_encode_hex(buf, fr->token, 64);
p[128] = '*';
p[129] = '\0';
} else {
p = ngtcp2_encode_hex(buf, fr->token, fr->tokenlen);
}
log->log_printf(
log->user_data, (NGTCP2_LOG_PKT " NEW_TOKEN(0x%02x) token=0x%s len=%zu"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, (const char *)p, fr->tokenlen);
}
static void log_fr_retire_connection_id(ngtcp2_log *log,
const ngtcp2_pkt_hd *hd,
const ngtcp2_retire_connection_id *fr,
const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " RETIRE_CONNECTION_ID(0x%02x) seq=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->seq);
}
static void log_fr_handshake_done(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_handshake_done *fr,
const char *dir) {
log->log_printf(log->user_data, (NGTCP2_LOG_PKT " HANDSHAKE_DONE(0x%02x)"),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type);
}
static void log_fr_datagram(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_datagram *fr, const char *dir) {
log->log_printf(log->user_data,
(NGTCP2_LOG_PKT " DATAGRAM(0x%02x) len=%" PRIu64),
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type,
ngtcp2_vec_len(fr->data, fr->datacnt));
}
static void log_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_frame *fr, const char *dir) {
switch (fr->type) {
case NGTCP2_FRAME_STREAM:
log_fr_stream(log, hd, &fr->stream, dir);
break;
case NGTCP2_FRAME_ACK:
case NGTCP2_FRAME_ACK_ECN:
log_fr_ack(log, hd, &fr->ack, dir);
break;
case NGTCP2_FRAME_PADDING:
log_fr_padding(log, hd, &fr->padding, dir);
break;
case NGTCP2_FRAME_RESET_STREAM:
log_fr_reset_stream(log, hd, &fr->reset_stream, dir);
break;
case NGTCP2_FRAME_CONNECTION_CLOSE:
case NGTCP2_FRAME_CONNECTION_CLOSE_APP:
log_fr_connection_close(log, hd, &fr->connection_close, dir);
break;
case NGTCP2_FRAME_MAX_DATA:
log_fr_max_data(log, hd, &fr->max_data, dir);
break;
case NGTCP2_FRAME_MAX_STREAM_DATA:
log_fr_max_stream_data(log, hd, &fr->max_stream_data, dir);
break;
case NGTCP2_FRAME_MAX_STREAMS_BIDI:
case NGTCP2_FRAME_MAX_STREAMS_UNI:
log_fr_max_streams(log, hd, &fr->max_streams, dir);
break;
case NGTCP2_FRAME_PING:
log_fr_ping(log, hd, &fr->ping, dir);
break;
case NGTCP2_FRAME_DATA_BLOCKED:
log_fr_data_blocked(log, hd, &fr->data_blocked, dir);
break;
case NGTCP2_FRAME_STREAM_DATA_BLOCKED:
log_fr_stream_data_blocked(log, hd, &fr->stream_data_blocked, dir);
break;
case NGTCP2_FRAME_STREAMS_BLOCKED_BIDI:
case NGTCP2_FRAME_STREAMS_BLOCKED_UNI:
log_fr_streams_blocked(log, hd, &fr->streams_blocked, dir);
break;
case NGTCP2_FRAME_NEW_CONNECTION_ID:
log_fr_new_connection_id(log, hd, &fr->new_connection_id, dir);
break;
case NGTCP2_FRAME_STOP_SENDING:
log_fr_stop_sending(log, hd, &fr->stop_sending, dir);
break;
case NGTCP2_FRAME_PATH_CHALLENGE:
log_fr_path_challenge(log, hd, &fr->path_challenge, dir);
break;
case NGTCP2_FRAME_PATH_RESPONSE:
log_fr_path_response(log, hd, &fr->path_response, dir);
break;
case NGTCP2_FRAME_CRYPTO:
log_fr_crypto(log, hd, &fr->crypto, dir);
break;
case NGTCP2_FRAME_NEW_TOKEN:
log_fr_new_token(log, hd, &fr->new_token, dir);
break;
case NGTCP2_FRAME_RETIRE_CONNECTION_ID:
log_fr_retire_connection_id(log, hd, &fr->retire_connection_id, dir);
break;
case NGTCP2_FRAME_HANDSHAKE_DONE:
log_fr_handshake_done(log, hd, &fr->handshake_done, dir);
break;
case NGTCP2_FRAME_DATAGRAM:
case NGTCP2_FRAME_DATAGRAM_LEN:
log_fr_datagram(log, hd, &fr->datagram, dir);
break;
default:
ngtcp2_unreachable();
}
}
void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_frame *fr) {
if (!log->log_printf) {
return;
}
log_fr(log, hd, fr, "rx");
}
void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_frame *fr) {
if (!log->log_printf) {
return;
}
log_fr(log, hd, fr, "tx");
}
void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const uint32_t *sv, size_t nsv) {
size_t i;
if (!log->log_printf) {
return;
}
for (i = 0; i < nsv; ++i) {
log->log_printf(log->user_data, (NGTCP2_LOG_PKT " v=0x%08x"),
NGTCP2_LOG_PKT_HD_FIELDS("rx"), sv[i]);
}
}
void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr) {
uint8_t buf[sizeof(sr->stateless_reset_token) * 2 + 1];
ngtcp2_pkt_hd shd;
ngtcp2_pkt_hd *hd = &shd;
if (!log->log_printf) {
return;
}
memset(&shd, 0, sizeof(shd));
shd.type = NGTCP2_PKT_STATELESS_RESET;
log->log_printf(
log->user_data, (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)),
sr->randlen);
}
void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype,
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];
size_t i;
const ngtcp2_sockaddr_in *sa_in;
const ngtcp2_sockaddr_in6 *sa_in6;
const uint8_t *p;
uint32_t version;
if (!log->log_printf) {
return;
}
if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
if (params->stateless_reset_token_present) {
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " stateless_reset_token=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(
token, params->stateless_reset_token,
sizeof(params->stateless_reset_token)));
}
if (params->preferred_address_present) {
if (params->preferred_address.ipv4_present) {
sa_in = &params->preferred_address.ipv4;
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " preferred_address.ipv4_addr=%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_ipv4(
addr, (const uint8_t *)&sa_in->sin_addr));
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"),
NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in->sin_port));
}
if (params->preferred_address.ipv6_present) {
sa_in6 = &params->preferred_address.ipv6;
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " preferred_address.ipv6_addr=%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_ipv6(
addr, (const uint8_t *)&sa_in6->sin6_addr));
log->log_printf(
log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"),
NGTCP2_LOG_TP_HD_FIELDS, ngtcp2_ntohs(sa_in6->sin6_port));
}
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " preferred_address.cid=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(
cid, params->preferred_address.cid.data,
params->preferred_address.cid.datalen));
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " preferred_address.stateless_reset_token=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(
token, params->preferred_address.stateless_reset_token,
sizeof(params->preferred_address.stateless_reset_token)));
}
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " original_destination_connection_id=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(cid, params->original_dcid.data,
params->original_dcid.datalen));
if (params->retry_scid_present) {
log->log_printf(
log->user_data, (NGTCP2_LOG_TP " retry_source_connection_id=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(cid, params->retry_scid.data,
params->retry_scid.datalen));
}
}
log->log_printf(
log->user_data, (NGTCP2_LOG_TP " initial_source_connection_id=0x%s"),
NGTCP2_LOG_TP_HD_FIELDS,
(const char *)ngtcp2_encode_hex(cid, params->initial_scid.data,
params->initial_scid.datalen));
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " initial_max_stream_data_bidi_local=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_local);
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " initial_max_stream_data_bidi_remote=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_bidi_remote);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " initial_max_stream_data_uni=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_stream_data_uni);
log->log_printf(log->user_data, (NGTCP2_LOG_TP " initial_max_data=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_data);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " initial_max_streams_bidi=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_bidi);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " initial_max_streams_uni=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->initial_max_streams_uni);
log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_idle_timeout=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS,
params->max_idle_timeout / NGTCP2_MILLISECONDS);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " max_udp_payload_size=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->max_udp_payload_size);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " ack_delay_exponent=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->ack_delay_exponent);
log->log_printf(log->user_data, (NGTCP2_LOG_TP " max_ack_delay=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS,
params->max_ack_delay / NGTCP2_MILLISECONDS);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " active_connection_id_limit=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->active_connection_id_limit);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " disable_active_migration=%d"),
NGTCP2_LOG_TP_HD_FIELDS, params->disable_active_migration);
log->log_printf(log->user_data,
(NGTCP2_LOG_TP " max_datagram_frame_size=%" PRIu64),
NGTCP2_LOG_TP_HD_FIELDS, params->max_datagram_frame_size);
log->log_printf(log->user_data, (NGTCP2_LOG_TP " grease_quic_bit=%d"),
NGTCP2_LOG_TP_HD_FIELDS, params->grease_quic_bit);
if (params->version_info_present) {
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " version_information.chosen_version=0x%08x"),
NGTCP2_LOG_TP_HD_FIELDS, params->version_info.chosen_version);
assert(!(params->version_info.available_versionslen & 0x3));
for (i = 0, p = params->version_info.available_versions;
i < params->version_info.available_versionslen;
i += sizeof(uint32_t)) {
p = ngtcp2_get_uint32(&version, p);
log->log_printf(
log->user_data,
(NGTCP2_LOG_TP " version_information.available_versions[%zu]=0x%08x"),
NGTCP2_LOG_TP_HD_FIELDS, i >> 2, version);
}
}
}
void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type,
uint8_t flags, ngtcp2_tstamp sent_ts) {
if (!log->log_printf) {
return;
}
ngtcp2_log_info(log, NGTCP2_LOG_EVENT_RCV,
"pkn=%" PRId64 " lost type=%s sent_ts=%" PRIu64, pkt_num,
strpkttype_type_flags(type, flags), sent_ts);
}
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];
if (!log->log_printf) {
return;
}
if (hd->type == NGTCP2_PKT_1RTT) {
ngtcp2_log_info(
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),
strpkttype(hd), (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0);
} else {
ngtcp2_log_info(
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),
hd->version, strpkttype(hd), hd->len);
}
}
void ngtcp2_log_rx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
log_pkt_hd(log, hd, "rx");
}
void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
log_pkt_hd(log, hd, "tx");
}
void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
...) {
va_list ap;
int n;
char buf[NGTCP2_LOG_BUFLEN];
if (!log->log_printf) {
return;
}
va_start(ap, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (n < 0 || (size_t)n >= sizeof(buf)) {
return;
}
log->log_printf(log->user_data, (NGTCP2_LOG_HD " %s"),
timestamp_cast(log->last_ts - log->ts), log->scid,
strevent(ev), buf);
}
void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd) {
ngtcp2_log_info(log, NGTCP2_LOG_EVENT_PKT,
"cancel tx pkn=%" PRId64 " type=%s", hd->pkt_num,
strpkttype(hd));
}

View file

@ -1,123 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_LOG_H
#define NGTCP2_LOG_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_pkt.h"
typedef struct ngtcp2_log {
/* log_printf is a sink to write log. NULL means no logging
output. */
ngtcp2_printf log_printf;
/* ts is the time point used to write time delta in the log. */
ngtcp2_tstamp ts;
/* last_ts is the most recent time point that this object is
told. */
ngtcp2_tstamp last_ts;
/* user_data is user-defined opaque data which is passed to
log_pritnf. */
void *user_data;
/* scid is SCID encoded as NULL-terminated hex string. */
uint8_t scid[NGTCP2_MAX_CIDLEN * 2 + 1];
} ngtcp2_log;
/**
* @enum
*
* :type:`ngtcp2_log_event` defines an event of ngtcp2 library
* internal logger.
*/
typedef enum ngtcp2_log_event {
/**
* :enum:`NGTCP2_LOG_EVENT_NONE` represents no event.
*/
NGTCP2_LOG_EVENT_NONE,
/**
* :enum:`NGTCP2_LOG_EVENT_CON` is a connection (catch-all) event
*/
NGTCP2_LOG_EVENT_CON,
/**
* :enum:`NGTCP2_LOG_EVENT_PKT` is a packet event.
*/
NGTCP2_LOG_EVENT_PKT,
/**
* :enum:`NGTCP2_LOG_EVENT_FRM` is a QUIC frame event.
*/
NGTCP2_LOG_EVENT_FRM,
/**
* :enum:`NGTCP2_LOG_EVENT_RCV` is a congestion and recovery event.
*/
NGTCP2_LOG_EVENT_RCV,
/**
* :enum:`NGTCP2_LOG_EVENT_CRY` is a crypto event.
*/
NGTCP2_LOG_EVENT_CRY,
/**
* :enum:`NGTCP2_LOG_EVENT_PTV` is a path validation event.
*/
NGTCP2_LOG_EVENT_PTV,
} ngtcp2_log_event;
void ngtcp2_log_init(ngtcp2_log *log, const ngtcp2_cid *scid,
ngtcp2_printf log_printf, ngtcp2_tstamp ts,
void *user_data);
void ngtcp2_log_rx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_frame *fr);
void ngtcp2_log_tx_fr(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const ngtcp2_frame *fr);
void ngtcp2_log_rx_vn(ngtcp2_log *log, const ngtcp2_pkt_hd *hd,
const uint32_t *sv, size_t nsv);
void ngtcp2_log_rx_sr(ngtcp2_log *log, const ngtcp2_pkt_stateless_reset *sr);
void ngtcp2_log_remote_tp(ngtcp2_log *log, uint8_t exttype,
const ngtcp2_transport_params *params);
void ngtcp2_log_pkt_lost(ngtcp2_log *log, int64_t pkt_num, uint8_t type,
uint8_t flags, ngtcp2_tstamp sent_ts);
void ngtcp2_log_rx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
void ngtcp2_log_tx_pkt_hd(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
void ngtcp2_log_tx_cancel(ngtcp2_log *log, const ngtcp2_pkt_hd *hd);
/**
* @function
*
* `ngtcp2_log_info` writes info level log.
*/
void ngtcp2_log_info(ngtcp2_log *log, ngtcp2_log_event ev, const char *fmt,
...);
#endif /* NGTCP2_LOG_H */

View file

@ -1,336 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_map.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "ngtcp2_conv.h"
#define NGTCP2_INITIAL_TABLE_LENBITS 4
void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
map->mem = mem;
map->tablelen = 0;
map->tablelenbits = 0;
map->table = NULL;
map->size = 0;
}
void ngtcp2_map_free(ngtcp2_map *map) {
if (!map) {
return;
}
ngtcp2_mem_free(map->mem, map->table);
}
void ngtcp2_map_each_free(ngtcp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
uint32_t i;
ngtcp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}
func(bkt->data, ptr);
}
}
int ngtcp2_map_each(ngtcp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
uint32_t i;
ngtcp2_map_bucket *bkt;
if (map->size == 0) {
return 0;
}
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}
rv = func(bkt->data, ptr);
if (rv != 0) {
return rv;
}
}
return 0;
}
static uint32_t hash(ngtcp2_map_key_type key) {
return (uint32_t)((key * 11400714819323198485llu) >> 32);
}
static size_t h2idx(uint32_t hash, uint32_t bits) {
return hash >> (32 - bits);
}
static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
ngtcp2_map_bucket *bkt, size_t idx) {
return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
}
static void map_bucket_swap(ngtcp2_map_bucket *bkt, uint32_t *phash,
ngtcp2_map_key_type *pkey, void **pdata) {
uint32_t h = bkt->hash;
ngtcp2_map_key_type key = bkt->key;
void *data = bkt->data;
bkt->hash = *phash;
bkt->key = *pkey;
bkt->data = *pdata;
*phash = h;
*pkey = key;
*pdata = data;
}
static void map_bucket_set_data(ngtcp2_map_bucket *bkt, uint32_t hash,
ngtcp2_map_key_type key, void *data) {
bkt->hash = hash;
bkt->key = key;
bkt->data = data;
}
void ngtcp2_map_print_distance(ngtcp2_map *map) {
uint32_t i;
size_t idx;
ngtcp2_map_bucket *bkt;
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
fprintf(stderr, "@%u <EMPTY>\n", i);
continue;
}
idx = h2idx(bkt->hash, map->tablelenbits);
fprintf(stderr, "@%u hash=%08x key=%" PRIu64 " base=%zu distance=%zu\n", i,
bkt->hash, bkt->key, idx,
distance(map->tablelen, map->tablelenbits, bkt, idx));
}
}
static int insert(ngtcp2_map_bucket *table, uint32_t tablelen,
uint32_t tablelenbits, uint32_t hash, ngtcp2_map_key_type key,
void *data) {
size_t idx = h2idx(hash, tablelenbits);
size_t d = 0, dd;
ngtcp2_map_bucket *bkt;
for (;;) {
bkt = &table[idx];
if (bkt->data == NULL) {
map_bucket_set_data(bkt, hash, key, data);
return 0;
}
dd = distance(tablelen, tablelenbits, bkt, idx);
if (d > dd) {
map_bucket_swap(bkt, &hash, &key, &data);
d = dd;
} 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. */
return NGTCP2_ERR_INVALID_ARGUMENT;
}
++d;
idx = (idx + 1) & (tablelen - 1);
}
}
/* new_tablelen must be power of 2 and new_tablelen == (1 <<
new_tablelenbits) must hold. */
static int map_resize(ngtcp2_map *map, uint32_t new_tablelen,
uint32_t new_tablelenbits) {
uint32_t i;
ngtcp2_map_bucket *new_table;
ngtcp2_map_bucket *bkt;
int rv;
(void)rv;
new_table =
ngtcp2_mem_calloc(map->mem, new_tablelen, sizeof(ngtcp2_map_bucket));
if (new_table == NULL) {
return NGTCP2_ERR_NOMEM;
}
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
continue;
}
rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
bkt->data);
assert(0 == rv);
}
ngtcp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
map->tablelenbits = new_tablelenbits;
map->table = new_table;
return 0;
}
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data) {
int rv;
assert(data);
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
if (map->tablelen) {
rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
if (rv != 0) {
return rv;
}
} else {
rv = map_resize(map, 1 << NGTCP2_INITIAL_TABLE_LENBITS,
NGTCP2_INITIAL_TABLE_LENBITS);
if (rv != 0) {
return rv;
}
}
}
rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
data);
if (rv != 0) {
return rv;
}
++map->size;
return 0;
}
void *ngtcp2_map_find(ngtcp2_map *map, ngtcp2_map_key_type key) {
uint32_t h;
size_t idx;
ngtcp2_map_bucket *bkt;
size_t d = 0;
if (map->size == 0) {
return NULL;
}
h = hash(key);
idx = h2idx(h, map->tablelenbits);
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NULL;
}
if (bkt->key == key) {
return bkt->data;
}
++d;
idx = (idx + 1) & (map->tablelen - 1);
}
}
int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key) {
uint32_t h;
size_t idx, didx;
ngtcp2_map_bucket *bkt;
size_t d = 0;
if (map->size == 0) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
h = hash(key);
idx = h2idx(h, map->tablelenbits);
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL ||
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
return NGTCP2_ERR_INVALID_ARGUMENT;
}
if (bkt->key == key) {
map_bucket_set_data(bkt, 0, 0, NULL);
didx = idx;
idx = (idx + 1) & (map->tablelen - 1);
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL ||
distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
break;
}
map->table[didx] = *bkt;
map_bucket_set_data(bkt, 0, 0, NULL);
didx = idx;
idx = (idx + 1) & (map->tablelen - 1);
}
--map->size;
return 0;
}
++d;
idx = (idx + 1) & (map->tablelen - 1);
}
}
void ngtcp2_map_clear(ngtcp2_map *map) {
if (map->tablelen == 0) {
return;
}
memset(map->table, 0, sizeof(*map->table) * map->tablelen);
map->size = 0;
}
size_t ngtcp2_map_size(ngtcp2_map *map) { return map->size; }

View file

@ -1,136 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_MAP_H
#define NGTCP2_MAP_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
/* Implementation of unordered map */
typedef uint64_t ngtcp2_map_key_type;
typedef struct ngtcp2_map_bucket {
uint32_t hash;
ngtcp2_map_key_type key;
void *data;
} ngtcp2_map_bucket;
typedef struct ngtcp2_map {
ngtcp2_map_bucket *table;
const ngtcp2_mem *mem;
size_t size;
uint32_t tablelen;
uint32_t tablelenbits;
} ngtcp2_map;
/*
* Initializes the map |map|.
*/
void ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem);
/*
* Deallocates any resources allocated for |map|. The stored entries
* are not freed by this function. Use ngtcp2_map_each_free() to free
* each entries.
*/
void ngtcp2_map_free(ngtcp2_map *map);
/*
* Deallocates each entries using |func| function and any resources
* allocated for |map|. The |func| function is responsible for freeing
* given the |data| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
void ngtcp2_map_each_free(ngtcp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
/*
* Inserts the new |data| with the |key| to the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* The item associated by |key| already exists.
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_key_type key, void *data);
/*
* Returns the data associated by the key |key|. If there is no such
* data, this function returns NULL.
*/
void *ngtcp2_map_find(ngtcp2_map *map, ngtcp2_map_key_type key);
/*
* Removes the data associated by the key |key| from the |map|. The
* removed data is not freed by this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_INVALID_ARGUMENT
* The data associated by |key| does not exist.
*/
int ngtcp2_map_remove(ngtcp2_map *map, ngtcp2_map_key_type key);
/*
* Removes all entries from |map|.
*/
void ngtcp2_map_clear(ngtcp2_map *map);
/*
* Returns the number of items stored in the map |map|.
*/
size_t ngtcp2_map_size(ngtcp2_map *map);
/*
* Applies the function |func| to each data in the |map| with the
* optional user supplied pointer |ptr|.
*
* If the |func| returns 0, this function calls the |func| with the
* next data. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns.
*
* Don't use this function to free each data. Use
* ngtcp2_map_each_free() instead.
*/
int ngtcp2_map_each(ngtcp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
void ngtcp2_map_print_distance(ngtcp2_map *map);
#endif /* NGTCP2_MAP_H */

View file

@ -1,113 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2014 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_mem.h"
#include <stdio.h>
static void *default_malloc(size_t size, void *user_data) {
(void)user_data;
return malloc(size);
}
static void default_free(void *ptr, void *user_data) {
(void)user_data;
free(ptr);
}
static void *default_calloc(size_t nmemb, size_t size, void *user_data) {
(void)user_data;
return calloc(nmemb, size);
}
static void *default_realloc(void *ptr, size_t size, void *user_data) {
(void)user_data;
return realloc(ptr, size);
}
static const ngtcp2_mem mem_default = {NULL, default_malloc, default_free,
default_calloc, default_realloc};
const ngtcp2_mem *ngtcp2_mem_default(void) { return &mem_default; }
#ifndef MEMDEBUG
void *ngtcp2_mem_malloc(const ngtcp2_mem *mem, size_t size) {
return mem->malloc(size, mem->user_data);
}
void ngtcp2_mem_free(const ngtcp2_mem *mem, void *ptr) {
mem->free(ptr, mem->user_data);
}
void *ngtcp2_mem_calloc(const ngtcp2_mem *mem, size_t nmemb, size_t size) {
return mem->calloc(nmemb, size, mem->user_data);
}
void *ngtcp2_mem_realloc(const ngtcp2_mem *mem, void *ptr, size_t size) {
return mem->realloc(ptr, size, mem->user_data);
}
#else /* MEMDEBUG */
void *ngtcp2_mem_malloc_debug(const ngtcp2_mem *mem, size_t size,
const char *func, const char *file, size_t line) {
void *nptr = mem->malloc(size, mem->user_data);
fprintf(stderr, "malloc %p size=%zu in %s at %s:%zu\n", nptr, size, func,
file, line);
return nptr;
}
void ngtcp2_mem_free_debug(const ngtcp2_mem *mem, void *ptr, const char *func,
const char *file, size_t line) {
fprintf(stderr, "free ptr=%p in %s at %s:%zu\n", ptr, func, file, line);
mem->free(ptr, mem->user_data);
}
void *ngtcp2_mem_calloc_debug(const ngtcp2_mem *mem, size_t nmemb, size_t size,
const char *func, const char *file, size_t line) {
void *nptr = mem->calloc(nmemb, size, mem->user_data);
fprintf(stderr, "calloc %p nmemb=%zu size=%zu in %s at %s:%zu\n", nptr, nmemb,
size, func, file, line);
return nptr;
}
void *ngtcp2_mem_realloc_debug(const ngtcp2_mem *mem, void *ptr, size_t size,
const char *func, const char *file,
size_t line) {
void *nptr = mem->realloc(ptr, size, mem->user_data);
fprintf(stderr, "realloc %p ptr=%p size=%zu in %s at %s:%zu\n", nptr, ptr,
size, func, file, line);
return nptr;
}
#endif /* MEMDEBUG */

View file

@ -1,72 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2014 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_MEM_H
#define NGTCP2_MEM_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
/* Convenient wrapper functions to call allocator function in
|mem|. */
#ifndef MEMDEBUG
void *ngtcp2_mem_malloc(const ngtcp2_mem *mem, size_t size);
void ngtcp2_mem_free(const ngtcp2_mem *mem, void *ptr);
void *ngtcp2_mem_calloc(const ngtcp2_mem *mem, size_t nmemb, size_t size);
void *ngtcp2_mem_realloc(const ngtcp2_mem *mem, void *ptr, size_t size);
#else /* MEMDEBUG */
void *ngtcp2_mem_malloc_debug(const ngtcp2_mem *mem, size_t size,
const char *func, const char *file, size_t line);
# define ngtcp2_mem_malloc(MEM, SIZE) \
ngtcp2_mem_malloc_debug((MEM), (SIZE), __func__, __FILE__, __LINE__)
void ngtcp2_mem_free_debug(const ngtcp2_mem *mem, void *ptr, const char *func,
const char *file, size_t line);
# define ngtcp2_mem_free(MEM, PTR) \
ngtcp2_mem_free_debug((MEM), (PTR), __func__, __FILE__, __LINE__)
void *ngtcp2_mem_calloc_debug(const ngtcp2_mem *mem, size_t nmemb, size_t size,
const char *func, const char *file, size_t line);
# define ngtcp2_mem_calloc(MEM, NMEMB, SIZE) \
ngtcp2_mem_calloc_debug((MEM), (NMEMB), (SIZE), __func__, __FILE__, \
__LINE__)
void *ngtcp2_mem_realloc_debug(const ngtcp2_mem *mem, void *ptr, size_t size,
const char *func, const char *file, size_t line);
# define ngtcp2_mem_realloc(MEM, PTR, SIZE) \
ngtcp2_mem_realloc_debug((MEM), (PTR), (SIZE), __func__, __FILE__, __LINE__)
#endif /* MEMDEBUG */
#endif /* NGTCP2_MEM_H */

View file

@ -1,40 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_objalloc.h"
void ngtcp2_objalloc_init(ngtcp2_objalloc *objalloc, size_t blklen,
const ngtcp2_mem *mem) {
ngtcp2_balloc_init(&objalloc->balloc, blklen, mem);
ngtcp2_opl_init(&objalloc->opl);
}
void ngtcp2_objalloc_free(ngtcp2_objalloc *objalloc) {
ngtcp2_balloc_free(&objalloc->balloc);
}
void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc) {
ngtcp2_opl_clear(&objalloc->opl);
ngtcp2_balloc_clear(&objalloc->balloc);
}

View file

@ -1,140 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_OBJALLOC_H
#define NGTCP2_OBJALLOC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_balloc.h"
#include "ngtcp2_opl.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_mem.h"
/*
* ngtcp2_objalloc combines ngtcp2_balloc and ngtcp2_opl, and provides
* an object pool with the custom allocator to reduce the allocation
* and deallocation overheads for small objects.
*/
typedef struct ngtcp2_objalloc {
ngtcp2_balloc balloc;
ngtcp2_opl opl;
} ngtcp2_objalloc;
/*
* ngtcp2_objalloc_init initializes |objalloc|. |blklen| is directly
* passed to ngtcp2_balloc_init.
*/
void ngtcp2_objalloc_init(ngtcp2_objalloc *objalloc, size_t blklen,
const ngtcp2_mem *mem);
/*
* ngtcp2_objalloc_free releases all allocated resources.
*/
void ngtcp2_objalloc_free(ngtcp2_objalloc *objalloc);
/*
* ngtcp2_objalloc_clear releases all allocated resources and
* initializes its state.
*/
void ngtcp2_objalloc_clear(ngtcp2_objalloc *objalloc);
#ifndef NOMEMPOOL
# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \
inline static void ngtcp2_objalloc_##NAME##_init( \
ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \
ngtcp2_objalloc_init( \
objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \
} \
\
inline static TYPE *ngtcp2_objalloc_##NAME##_get( \
ngtcp2_objalloc *objalloc) { \
ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \
TYPE *obj; \
int rv; \
\
if (!oplent) { \
rv = \
ngtcp2_balloc_get(&objalloc->balloc, (void **)&obj, sizeof(TYPE)); \
if (rv != 0) { \
return NULL; \
} \
\
return obj; \
} \
\
return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \
} \
\
inline static TYPE *ngtcp2_objalloc_##NAME##_len_get( \
ngtcp2_objalloc *objalloc, size_t len) { \
ngtcp2_opl_entry *oplent = ngtcp2_opl_pop(&objalloc->opl); \
TYPE *obj; \
int rv; \
\
if (!oplent) { \
rv = ngtcp2_balloc_get(&objalloc->balloc, (void **)&obj, len); \
if (rv != 0) { \
return NULL; \
} \
\
return obj; \
} \
\
return ngtcp2_struct_of(oplent, TYPE, OPLENTFIELD); \
} \
\
inline static void ngtcp2_objalloc_##NAME##_release( \
ngtcp2_objalloc *objalloc, TYPE *obj) { \
ngtcp2_opl_push(&objalloc->opl, &obj->OPLENTFIELD); \
}
#else /* NOMEMPOOL */
# define ngtcp2_objalloc_def(NAME, TYPE, OPLENTFIELD) \
inline static void ngtcp2_objalloc_##NAME##_init( \
ngtcp2_objalloc *objalloc, size_t nmemb, const ngtcp2_mem *mem) { \
ngtcp2_objalloc_init( \
objalloc, ((sizeof(TYPE) + 0xfu) & ~(uintptr_t)0xfu) * nmemb, mem); \
} \
\
inline static TYPE *ngtcp2_objalloc_##NAME##_get( \
ngtcp2_objalloc *objalloc) { \
return ngtcp2_mem_malloc(objalloc->balloc.mem, sizeof(TYPE)); \
} \
\
inline static TYPE *ngtcp2_objalloc_##NAME##_len_get( \
ngtcp2_objalloc *objalloc, size_t len) { \
return ngtcp2_mem_malloc(objalloc->balloc.mem, len); \
} \
\
inline static void ngtcp2_objalloc_##NAME##_release( \
ngtcp2_objalloc *objalloc, TYPE *obj) { \
ngtcp2_mem_free(objalloc->balloc.mem, obj); \
}
#endif /* NOMEMPOOL */
#endif /* NGTCP2_OBJALLOC_H */

View file

@ -1,46 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_opl.h"
void ngtcp2_opl_init(ngtcp2_opl *opl) { opl->head = NULL; }
void ngtcp2_opl_push(ngtcp2_opl *opl, ngtcp2_opl_entry *ent) {
ent->next = opl->head;
opl->head = ent;
}
ngtcp2_opl_entry *ngtcp2_opl_pop(ngtcp2_opl *opl) {
ngtcp2_opl_entry *ent = opl->head;
if (!ent) {
return NULL;
}
opl->head = ent->next;
return ent;
}
void ngtcp2_opl_clear(ngtcp2_opl *opl) { opl->head = NULL; }

View file

@ -1,65 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_OPL_H
#define NGTCP2_OPL_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
typedef struct ngtcp2_opl_entry ngtcp2_opl_entry;
struct ngtcp2_opl_entry {
ngtcp2_opl_entry *next;
};
/*
* ngtcp2_opl is an object memory pool.
*/
typedef struct ngtcp2_opl {
ngtcp2_opl_entry *head;
} ngtcp2_opl;
/*
* ngtcp2_opl_init initializes |opl|.
*/
void ngtcp2_opl_init(ngtcp2_opl *opl);
/*
* ngtcp2_opl_push inserts |ent| to |opl| head.
*/
void ngtcp2_opl_push(ngtcp2_opl *opl, ngtcp2_opl_entry *ent);
/*
* ngtcp2_opl_pop removes the first ngtcp2_opl_entry from |opl| and
* returns it. If |opl| does not have any entry, it returns NULL.
*/
ngtcp2_opl_entry *ngtcp2_opl_pop(ngtcp2_opl *opl);
void ngtcp2_opl_clear(ngtcp2_opl *opl);
#endif /* NGTCP2_OPL_H */

View file

@ -1,77 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_path.h"
#include <string.h>
#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);
dest->user_data = src->user_data;
}
int ngtcp2_path_eq(const ngtcp2_path *a, const ngtcp2_path *b) {
return ngtcp2_addr_eq(&a->local, &b->local) &&
ngtcp2_addr_eq(&a->remote, &b->remote);
}
void ngtcp2_path_storage_init(ngtcp2_path_storage *ps,
const ngtcp2_sockaddr *local_addr,
ngtcp2_socklen local_addrlen,
const ngtcp2_sockaddr *remote_addr,
ngtcp2_socklen remote_addrlen, void *user_data) {
ngtcp2_addr_init(&ps->path.local, (const ngtcp2_sockaddr *)&ps->local_addrbuf,
0);
ngtcp2_addr_init(&ps->path.remote,
(const ngtcp2_sockaddr *)&ps->remote_addrbuf, 0);
ngtcp2_addr_copy_byte(&ps->path.local, local_addr, local_addrlen);
ngtcp2_addr_copy_byte(&ps->path.remote, remote_addr, remote_addrlen);
ps->path.user_data = user_data;
}
void ngtcp2_path_storage_init2(ngtcp2_path_storage *ps,
const ngtcp2_path *path) {
ngtcp2_path_storage_init(ps, path->local.addr, path->local.addrlen,
path->remote.addr, path->remote.addrlen,
path->user_data);
}
void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps) {
ngtcp2_addr_init(&ps->path.local, (const ngtcp2_sockaddr *)&ps->local_addrbuf,
0);
ngtcp2_addr_init(&ps->path.remote,
(const ngtcp2_sockaddr *)&ps->remote_addrbuf, 0);
ps->path.user_data = NULL;
}

View file

@ -1,49 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_PATH_H
#define NGTCP2_PATH_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#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.
*/
void ngtcp2_path_storage_init2(ngtcp2_path_storage *ps,
const ngtcp2_path *path);
#endif /* NGTCP2_PATH_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,160 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_pmtud.h"
#include <assert.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_macro.h"
/* NGTCP2_PMTUD_PROBE_NUM_MAX is the maximum number of packets sent
for each probe. */
#define NGTCP2_PMTUD_PROBE_NUM_MAX 3
static size_t mtu_probes[] = {
1454 - 48, /* The well known MTU used by a domestic optic fiber
service in Japan. */
1390 - 48, /* Typical Tunneled MTU */
1280 - 48, /* IPv6 minimum MTU */
1492 - 48, /* PPPoE */
};
#define NGTCP2_MTU_PROBESLEN ngtcp2_arraylen(mtu_probes)
int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size,
size_t hard_max_udp_payload_size, int64_t tx_pkt_num,
const ngtcp2_mem *mem) {
ngtcp2_pmtud *pmtud = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pmtud));
if (pmtud == NULL) {
return NGTCP2_ERR_NOMEM;
}
pmtud->mem = mem;
pmtud->mtu_idx = 0;
pmtud->num_pkts_sent = 0;
pmtud->expiry = UINT64_MAX;
pmtud->tx_pkt_num = tx_pkt_num;
pmtud->max_udp_payload_size = max_udp_payload_size;
pmtud->hard_max_udp_payload_size = hard_max_udp_payload_size;
pmtud->min_fail_udp_payload_size = SIZE_MAX;
for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) {
if (mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) {
continue;
}
if (mtu_probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) {
break;
}
}
*ppmtud = pmtud;
return 0;
}
void ngtcp2_pmtud_del(ngtcp2_pmtud *pmtud) {
if (!pmtud) {
return;
}
ngtcp2_mem_free(pmtud->mem, pmtud);
}
size_t ngtcp2_pmtud_probelen(ngtcp2_pmtud *pmtud) {
assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN);
return mtu_probes[pmtud->mtu_idx];
}
void ngtcp2_pmtud_probe_sent(ngtcp2_pmtud *pmtud, ngtcp2_duration pto,
ngtcp2_tstamp ts) {
ngtcp2_tstamp timeout;
if (++pmtud->num_pkts_sent < NGTCP2_PMTUD_PROBE_NUM_MAX) {
timeout = pto;
} else {
timeout = 3 * pto;
}
pmtud->expiry = ts + timeout;
}
int ngtcp2_pmtud_require_probe(ngtcp2_pmtud *pmtud) {
return pmtud->expiry == UINT64_MAX;
}
static void pmtud_next_probe(ngtcp2_pmtud *pmtud) {
assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN);
++pmtud->mtu_idx;
pmtud->num_pkts_sent = 0;
pmtud->expiry = UINT64_MAX;
for (; pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN; ++pmtud->mtu_idx) {
if (mtu_probes[pmtud->mtu_idx] <= pmtud->max_udp_payload_size ||
mtu_probes[pmtud->mtu_idx] > pmtud->hard_max_udp_payload_size) {
continue;
}
if (mtu_probes[pmtud->mtu_idx] < pmtud->min_fail_udp_payload_size) {
break;
}
}
}
void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen) {
pmtud->max_udp_payload_size =
ngtcp2_max(pmtud->max_udp_payload_size, payloadlen);
assert(pmtud->mtu_idx < NGTCP2_MTU_PROBESLEN);
if (mtu_probes[pmtud->mtu_idx] > pmtud->max_udp_payload_size) {
return;
}
pmtud_next_probe(pmtud);
}
void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts) {
if (ts < pmtud->expiry) {
return;
}
pmtud->expiry = UINT64_MAX;
if (pmtud->num_pkts_sent < NGTCP2_PMTUD_PROBE_NUM_MAX) {
return;
}
pmtud->min_fail_udp_payload_size =
ngtcp2_min(pmtud->min_fail_udp_payload_size, mtu_probes[pmtud->mtu_idx]);
pmtud_next_probe(pmtud);
}
int ngtcp2_pmtud_finished(ngtcp2_pmtud *pmtud) {
return pmtud->mtu_idx >= NGTCP2_MTU_PROBESLEN;
}

View file

@ -1,123 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_PMTUD_H
#define NGTCP2_PMTUD_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
typedef struct ngtcp2_pmtud {
const ngtcp2_mem *mem;
/* mtu_idx is the index of UDP payload size candidates to try
out. */
size_t mtu_idx;
/* num_pkts_sent is the number of mtu_idx sized UDP datagram payload
sent */
size_t num_pkts_sent;
/* expiry is the expired, if it is reached, send out the next UDP
datagram. UINT64_MAX means no expiry, or expiration is canceled.
In either case, new probe packet should be sent unless we have
done all attempts. */
ngtcp2_tstamp expiry;
/* tx_pkt_num is the smallest outgoing packet number where the
current discovery is performed. In other words, acknowledging
packet whose packet number lower than that does not indicate the
success of Path MTU Discovery. */
int64_t tx_pkt_num;
/* max_udp_payload_size is the maximum UDP payload size which is
known to work. */
size_t max_udp_payload_size;
/* hard_max_udp_payload_size is the maximum UDP payload size that is
going to be probed. */
size_t hard_max_udp_payload_size;
/* min_fail_udp_payload_size is the minimum UDP payload size that is
known to fail. */
size_t min_fail_udp_payload_size;
} ngtcp2_pmtud;
/*
* ngtcp2_pmtud_new creates new ngtcp2_pmtud object, and assigns its
* pointer to |*ppmtud|. |max_udp_payload_size| is the maximum UDP
* payload size that is known to work for the current path.
* |tx_pkt_num| should be the next packet number to send, which is
* used to differentiate the PMTUD probe packet sent by the previous
* PMTUD. PMTUD might finish immediately if |max_udp_payload_size| is
* larger than or equal to all UDP payload probe candidates.
* Therefore, call ngtcp2_pmtud_finished to check this situation.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_pmtud_new(ngtcp2_pmtud **ppmtud, size_t max_udp_payload_size,
size_t hard_max_udp_payload_size, int64_t tx_pkt_num,
const ngtcp2_mem *mem);
/*
* ngtcp2_pmtud_del deletes |pmtud|.
*/
void ngtcp2_pmtud_del(ngtcp2_pmtud *pmtud);
/*
* ngtcp2_pmtud_probelen returns the length of UDP payload size for a
* PMTUD probe packet.
*/
size_t ngtcp2_pmtud_probelen(ngtcp2_pmtud *pmtud);
/*
* ngtcp2_pmtud_probe_sent should be invoked when a PMTUD probe packet is
* sent.
*/
void ngtcp2_pmtud_probe_sent(ngtcp2_pmtud *pmtud, ngtcp2_duration pto,
ngtcp2_tstamp ts);
/*
* ngtcp2_pmtud_require_probe returns nonzero if a PMTUD probe packet
* should be sent.
*/
int ngtcp2_pmtud_require_probe(ngtcp2_pmtud *pmtud);
/*
* ngtcp2_pmtud_probe_success should be invoked when a PMTUD probe
* UDP datagram sized |payloadlen| is acknowledged.
*/
void ngtcp2_pmtud_probe_success(ngtcp2_pmtud *pmtud, size_t payloadlen);
/*
* ngtcp2_pmtud_handle_expiry handles expiry.
*/
void ngtcp2_pmtud_handle_expiry(ngtcp2_pmtud *pmtud, ngtcp2_tstamp ts);
/*
* ngtcp2_pmtud_finished returns nonzero if PMTUD has finished.
*/
int ngtcp2_pmtud_finished(ngtcp2_pmtud *pmtud);
#endif /* NGTCP2_PMTUD_H */

View file

@ -1,230 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_ppe.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_str.h"
#include "ngtcp2_conv.h"
void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen,
ngtcp2_crypto_cc *cc) {
ngtcp2_buf_init(&ppe->buf, out, outlen);
ppe->hdlen = 0;
ppe->len_offset = 0;
ppe->pkt_num_offset = 0;
ppe->pkt_numlen = 0;
ppe->pkt_num = 0;
ppe->sample_offset = 0;
ppe->cc = cc;
}
int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd) {
ngtcp2_ssize rv;
ngtcp2_buf *buf = &ppe->buf;
ngtcp2_crypto_cc *cc = ppe->cc;
if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
return NGTCP2_ERR_NOBUF;
}
if (hd->flags & NGTCP2_PKT_FLAG_LONG_FORM) {
ppe->len_offset = 1 + 4 + 1 + hd->dcid.datalen + 1 + hd->scid.datalen;
if (hd->type == NGTCP2_PKT_INITIAL) {
ppe->len_offset += ngtcp2_put_uvarintlen(hd->tokenlen) + hd->tokenlen;
}
ppe->pkt_num_offset = ppe->len_offset + NGTCP2_PKT_LENGTHLEN;
rv = ngtcp2_pkt_encode_hd_long(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
} else {
ppe->pkt_num_offset = 1 + hd->dcid.datalen;
rv = ngtcp2_pkt_encode_hd_short(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, hd);
}
if (rv < 0) {
return (int)rv;
}
ppe->sample_offset = ppe->pkt_num_offset + 4;
buf->last += rv;
ppe->pkt_numlen = hd->pkt_numlen;
ppe->hdlen = (size_t)rv;
ppe->pkt_num = hd->pkt_num;
return 0;
}
int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr) {
ngtcp2_ssize rv;
ngtcp2_buf *buf = &ppe->buf;
ngtcp2_crypto_cc *cc = ppe->cc;
if (ngtcp2_buf_left(buf) < cc->aead.max_overhead) {
return NGTCP2_ERR_NOBUF;
}
rv = ngtcp2_pkt_encode_frame(
buf->last, ngtcp2_buf_left(buf) - cc->aead.max_overhead, fr);
if (rv < 0) {
return (int)rv;
}
buf->last += rv;
return 0;
}
ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt) {
ngtcp2_buf *buf = &ppe->buf;
ngtcp2_crypto_cc *cc = ppe->cc;
uint8_t *payload = buf->begin + ppe->hdlen;
size_t payloadlen = ngtcp2_buf_len(buf) - ppe->hdlen;
uint8_t mask[NGTCP2_HP_SAMPLELEN];
uint8_t *p;
size_t i;
int rv;
assert(cc->encrypt);
assert(cc->hp_mask);
if (ppe->len_offset) {
ngtcp2_put_uvarint30(
buf->begin + ppe->len_offset,
(uint16_t)(payloadlen + ppe->pkt_numlen + cc->aead.max_overhead));
}
ngtcp2_crypto_create_nonce(ppe->nonce, cc->ckm->iv.base, cc->ckm->iv.len,
ppe->pkt_num);
rv = cc->encrypt(payload, &cc->aead, &cc->ckm->aead_ctx, payload, payloadlen,
ppe->nonce, cc->ckm->iv.len, buf->begin, ppe->hdlen);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
buf->last = payload + payloadlen + cc->aead.max_overhead;
/* TODO Check that we have enough space to get sample */
assert(ppe->sample_offset + NGTCP2_HP_SAMPLELEN <= ngtcp2_buf_len(buf));
rv = cc->hp_mask(mask, &cc->hp, &cc->hp_ctx, buf->begin + ppe->sample_offset);
if (rv != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
p = buf->begin;
if (*p & NGTCP2_HEADER_FORM_BIT) {
*p = (uint8_t)(*p ^ (mask[0] & 0x0f));
} else {
*p = (uint8_t)(*p ^ (mask[0] & 0x1f));
}
p = buf->begin + ppe->pkt_num_offset;
for (i = 0; i < ppe->pkt_numlen; ++i) {
*(p + i) ^= mask[i + 1];
}
if (ppkt != NULL) {
*ppkt = buf->begin;
}
return (ngtcp2_ssize)ngtcp2_buf_len(buf);
}
size_t ngtcp2_ppe_left(ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
if (ngtcp2_buf_left(&ppe->buf) < cc->aead.max_overhead) {
return 0;
}
return ngtcp2_buf_left(&ppe->buf) - cc->aead.max_overhead;
}
size_t ngtcp2_ppe_pktlen(ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
return ngtcp2_buf_len(&ppe->buf) + cc->aead.max_overhead;
}
size_t ngtcp2_ppe_padding(ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
ngtcp2_buf *buf = &ppe->buf;
size_t len;
assert(ngtcp2_buf_left(buf) >= cc->aead.max_overhead);
len = ngtcp2_buf_left(buf) - cc->aead.max_overhead;
memset(buf->last, 0, len);
buf->last += len;
return len;
}
size_t ngtcp2_ppe_padding_hp_sample(ngtcp2_ppe *ppe) {
ngtcp2_crypto_cc *cc = ppe->cc;
ngtcp2_buf *buf = &ppe->buf;
size_t max_samplelen;
size_t len = 0;
assert(cc->aead.max_overhead);
max_samplelen =
ngtcp2_buf_len(buf) + cc->aead.max_overhead - ppe->sample_offset;
if (max_samplelen < NGTCP2_HP_SAMPLELEN) {
len = NGTCP2_HP_SAMPLELEN - max_samplelen;
assert(ngtcp2_ppe_left(ppe) >= len);
memset(buf->last, 0, len);
buf->last += len;
}
return len;
}
size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n) {
ngtcp2_crypto_cc *cc = ppe->cc;
ngtcp2_buf *buf = &ppe->buf;
size_t pktlen = ngtcp2_buf_len(buf) + cc->aead.max_overhead;
size_t len;
if (pktlen >= n) {
return 0;
}
len = n - pktlen;
buf->last = ngtcp2_setmem(buf->last, 0, len);
return len;
}
int ngtcp2_ppe_ensure_hp_sample(ngtcp2_ppe *ppe) {
ngtcp2_buf *buf = &ppe->buf;
return ngtcp2_buf_left(buf) >= (4 - ppe->pkt_numlen) + NGTCP2_HP_SAMPLELEN;
}

View file

@ -1,153 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_PPE_H
#define NGTCP2_PPE_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_pkt.h"
#include "ngtcp2_buf.h"
#include "ngtcp2_crypto.h"
/*
* ngtcp2_ppe is the Protected Packet Encoder.
*/
typedef struct ngtcp2_ppe {
ngtcp2_buf buf;
ngtcp2_crypto_cc *cc;
/* hdlen is the number of bytes for packet header written in buf. */
size_t hdlen;
/* len_offset is the offset to Length field. */
size_t len_offset;
/* pkt_num_offset is the offset to packet number field. */
size_t pkt_num_offset;
/* pkt_numlen is the number of bytes used to encode a packet
number */
size_t pkt_numlen;
/* sample_offset is the offset to sample for packet number
encryption. */
size_t sample_offset;
/* pkt_num is the packet number written in buf. */
int64_t pkt_num;
/* nonce is the buffer to store nonce. It should be equal or longer
than then length of IV. */
uint8_t nonce[32];
} ngtcp2_ppe;
/*
* ngtcp2_ppe_init initializes |ppe| with the given buffer.
*/
void ngtcp2_ppe_init(ngtcp2_ppe *ppe, uint8_t *out, size_t outlen,
ngtcp2_crypto_cc *cc);
/*
* ngtcp2_ppe_encode_hd encodes |hd|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOBUF
* The buffer is too small.
*/
int ngtcp2_ppe_encode_hd(ngtcp2_ppe *ppe, const ngtcp2_pkt_hd *hd);
/*
* ngtcp2_ppe_encode_frame encodes |fr|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOBUF
* The buffer is too small.
*/
int ngtcp2_ppe_encode_frame(ngtcp2_ppe *ppe, ngtcp2_frame *fr);
/*
* ngtcp2_ppe_final encrypts QUIC packet payload. If |**ppkt| is not
* NULL, the pointer to the packet is assigned to it.
*
* This function returns the length of QUIC packet, including header,
* and payload if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_CALLBACK_FAILURE
* User-defined callback function failed.
*/
ngtcp2_ssize ngtcp2_ppe_final(ngtcp2_ppe *ppe, const uint8_t **ppkt);
/*
* ngtcp2_ppe_left returns the number of bytes left to write
* additional frames. This does not count AEAD overhead.
*/
size_t ngtcp2_ppe_left(ngtcp2_ppe *ppe);
/*
* ngtcp2_ppe_pktlen returns the provisional packet length. It
* includes AEAD overhead.
*/
size_t ngtcp2_ppe_pktlen(ngtcp2_ppe *ppe);
/**
* @function
*
* `ngtcp2_ppe_padding` encodes PADDING frames to the end of the
* buffer. This function returns the number of bytes padded.
*/
size_t ngtcp2_ppe_padding(ngtcp2_ppe *ppe);
/*
* ngtcp2_ppe_padding_hp_sample adds PADDING frame if the current
* payload does not have enough space for header protection sample.
* This function should be called just before calling
* ngtcp2_ppe_final().
*
* This function returns the number of bytes added as padding.
*/
size_t ngtcp2_ppe_padding_hp_sample(ngtcp2_ppe *ppe);
/*
* ngtcp2_ppe_padding_size adds PADDING frame so that the size of QUIC
* packet is at least |n| bytes long. If it is unable to add PADDING
* in that way, this function still adds PADDING frame as much as
* possible. This function should be called just before calling
* ngtcp2_ppe_final(). For Short packet, this function should be
* called instead of ngtcp2_ppe_padding_hp_sample.
*
* This function returns the number of bytes added as padding.
*/
size_t ngtcp2_ppe_padding_size(ngtcp2_ppe *ppe, size_t n);
/*
* ngtcp2_ppe_ensure_hp_sample returns nonzero if the buffer has
* enough space for header protection sample. This should be called
* right after packet header is written.
*/
int ngtcp2_ppe_ensure_hp_sample(ngtcp2_ppe *ppe);
#endif /* NGTCP2_PPE_H */

View file

@ -1,164 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_pq.h"
#include <assert.h>
#include "ngtcp2_macro.h"
void ngtcp2_pq_init(ngtcp2_pq *pq, ngtcp2_less less, const ngtcp2_mem *mem) {
pq->mem = mem;
pq->capacity = 0;
pq->q = NULL;
pq->length = 0;
pq->less = less;
}
void ngtcp2_pq_free(ngtcp2_pq *pq) {
ngtcp2_mem_free(pq->mem, pq->q);
pq->q = NULL;
}
static void swap(ngtcp2_pq *pq, size_t i, size_t j) {
ngtcp2_pq_entry *a = pq->q[i];
ngtcp2_pq_entry *b = pq->q[j];
pq->q[i] = b;
b->index = i;
pq->q[j] = a;
a->index = j;
}
static void bubble_up(ngtcp2_pq *pq, size_t index) {
size_t parent;
while (index != 0) {
parent = (index - 1) / 2;
if (!pq->less(pq->q[index], pq->q[parent])) {
return;
}
swap(pq, parent, index);
index = parent;
}
}
int ngtcp2_pq_push(ngtcp2_pq *pq, ngtcp2_pq_entry *item) {
if (pq->capacity <= pq->length) {
void *nq;
size_t ncapacity;
ncapacity = ngtcp2_max(4, (pq->capacity * 2));
nq = ngtcp2_mem_realloc(pq->mem, pq->q,
ncapacity * sizeof(ngtcp2_pq_entry *));
if (nq == NULL) {
return NGTCP2_ERR_NOMEM;
}
pq->capacity = ncapacity;
pq->q = nq;
}
pq->q[pq->length] = item;
item->index = pq->length;
++pq->length;
bubble_up(pq, pq->length - 1);
return 0;
}
ngtcp2_pq_entry *ngtcp2_pq_top(ngtcp2_pq *pq) {
assert(pq->length);
return pq->q[0];
}
static void bubble_down(ngtcp2_pq *pq, size_t index) {
size_t i, j, minindex;
for (;;) {
j = index * 2 + 1;
minindex = index;
for (i = 0; i < 2; ++i, ++j) {
if (j >= pq->length) {
break;
}
if (pq->less(pq->q[j], pq->q[minindex])) {
minindex = j;
}
}
if (minindex == index) {
return;
}
swap(pq, index, minindex);
index = minindex;
}
}
void ngtcp2_pq_pop(ngtcp2_pq *pq) {
if (pq->length > 0) {
pq->q[0] = pq->q[pq->length - 1];
pq->q[0]->index = 0;
--pq->length;
bubble_down(pq, 0);
}
}
void ngtcp2_pq_remove(ngtcp2_pq *pq, ngtcp2_pq_entry *item) {
assert(pq->q[item->index] == item);
if (item->index == 0) {
ngtcp2_pq_pop(pq);
return;
}
if (item->index == pq->length - 1) {
--pq->length;
return;
}
pq->q[item->index] = pq->q[pq->length - 1];
pq->q[item->index]->index = item->index;
--pq->length;
if (pq->less(item, pq->q[item->index])) {
bubble_down(pq, item->index);
} else {
bubble_up(pq, item->index);
}
}
int ngtcp2_pq_empty(ngtcp2_pq *pq) { return pq->length == 0; }
size_t ngtcp2_pq_size(ngtcp2_pq *pq) { return pq->length; }
int ngtcp2_pq_each(ngtcp2_pq *pq, ngtcp2_pq_item_cb fun, void *arg) {
size_t i;
if (pq->length == 0) {
return 0;
}
for (i = 0; i < pq->length; ++i) {
if ((*fun)(pq->q[i], arg)) {
return 1;
}
}
return 0;
}

View file

@ -1,126 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
* Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_PQ_H
#define NGTCP2_PQ_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
/* Implementation of priority queue */
/* NGTCP2_PQ_BAD_INDEX is the priority queue index which indicates
that an entry is not queued. Assigning this value to
ngtcp2_pq_entry.index can check that the entry is queued or not. */
#define NGTCP2_PQ_BAD_INDEX SIZE_MAX
typedef struct ngtcp2_pq_entry {
size_t index;
} ngtcp2_pq_entry;
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
typedef int (*ngtcp2_less)(const ngtcp2_pq_entry *lhs,
const ngtcp2_pq_entry *rhs);
typedef struct ngtcp2_pq {
/* The pointer to the pointer to the item stored */
ngtcp2_pq_entry **q;
/* Memory allocator */
const ngtcp2_mem *mem;
/* The number of items stored */
size_t length;
/* The maximum number of items this pq can store. This is
automatically extended when length is reached to this value. */
size_t capacity;
/* The less function between items */
ngtcp2_less less;
} ngtcp2_pq;
/*
* Initializes priority queue |pq| with compare function |cmp|.
*/
void ngtcp2_pq_init(ngtcp2_pq *pq, ngtcp2_less less, const ngtcp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are
* not freed by this function.
*/
void ngtcp2_pq_free(ngtcp2_pq *pq);
/*
* Adds |item| to the priority queue |pq|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_pq_push(ngtcp2_pq *pq, ngtcp2_pq_entry *item);
/*
* Returns item at the top of the queue |pq|. It is undefined if the
* queue is empty.
*/
ngtcp2_pq_entry *ngtcp2_pq_top(ngtcp2_pq *pq);
/*
* Pops item at the top of the queue |pq|. The popped item is not
* freed by this function.
*/
void ngtcp2_pq_pop(ngtcp2_pq *pq);
/*
* Returns nonzero if the queue |pq| is empty.
*/
int ngtcp2_pq_empty(ngtcp2_pq *pq);
/*
* Returns the number of items in the queue |pq|.
*/
size_t ngtcp2_pq_size(ngtcp2_pq *pq);
typedef int (*ngtcp2_pq_item_cb)(ngtcp2_pq_entry *item, void *arg);
/*
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
* parameter to callback function. This function must not change the
* ordering key. If the return value from callback is nonzero, this
* function returns 1 immediately without iterating remaining items.
* Otherwise this function returns 0.
*/
int ngtcp2_pq_each(ngtcp2_pq *pq, ngtcp2_pq_item_cb fun, void *arg);
/*
* Removes |item| from priority queue.
*/
void ngtcp2_pq_remove(ngtcp2_pq *pq, ngtcp2_pq_entry *item);
#endif /* NGTCP2_PQ_H */

View file

@ -1,172 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_pv.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_log.h"
#include "ngtcp2_macro.h"
#include "ngtcp2_addr.h"
void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
ngtcp2_tstamp expiry, uint8_t flags) {
memcpy(pvent->data, data, sizeof(pvent->data));
pvent->expiry = expiry;
pvent->flags = flags;
}
int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
ngtcp2_duration timeout, uint8_t flags, ngtcp2_log *log,
const ngtcp2_mem *mem) {
(*ppv) = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_pv));
if (*ppv == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_static_ringbuf_pv_ents_init(&(*ppv)->ents);
ngtcp2_dcid_copy(&(*ppv)->dcid, dcid);
(*ppv)->mem = mem;
(*ppv)->log = log;
(*ppv)->timeout = timeout;
(*ppv)->fallback_pto = 0;
(*ppv)->started_ts = UINT64_MAX;
(*ppv)->probe_pkt_left = NGTCP2_PV_NUM_PROBE_PKT;
(*ppv)->round = 0;
(*ppv)->flags = flags;
return 0;
}
void ngtcp2_pv_del(ngtcp2_pv *pv) {
if (pv == NULL) {
return;
}
ngtcp2_mem_free(pv->mem, pv);
}
void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
ngtcp2_tstamp expiry, uint8_t flags,
ngtcp2_tstamp ts) {
ngtcp2_pv_entry *ent;
assert(pv->probe_pkt_left);
if (ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
pv->started_ts = ts;
}
ent = ngtcp2_ringbuf_push_back(&pv->ents.rb);
ngtcp2_pv_entry_init(ent, data, expiry, flags);
pv->flags &= (uint8_t)~NGTCP2_PV_FLAG_CANCEL_TIMER;
--pv->probe_pkt_left;
}
int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data) {
size_t len = ngtcp2_ringbuf_len(&pv->ents.rb);
size_t i;
ngtcp2_pv_entry *ent;
if (len == 0) {
return NGTCP2_ERR_INVALID_STATE;
}
for (i = 0; i < len; ++i) {
ent = ngtcp2_ringbuf_get(&pv->ents.rb, i);
if (memcmp(ent->data, data, sizeof(ent->data)) == 0) {
*pflags = ent->flags;
ngtcp2_log_info(pv->log, NGTCP2_LOG_EVENT_PTV, "path has been validated");
return 0;
}
}
return NGTCP2_ERR_INVALID_ARGUMENT;
}
void ngtcp2_pv_handle_entry_expiry(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
ngtcp2_pv_entry *ent;
if (ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
return;
}
ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
if (ent->expiry > ts) {
return;
}
++pv->round;
pv->probe_pkt_left = NGTCP2_PV_NUM_PROBE_PKT;
}
int ngtcp2_pv_should_send_probe(ngtcp2_pv *pv) {
return pv->probe_pkt_left > 0;
}
int ngtcp2_pv_validation_timed_out(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
ngtcp2_tstamp t;
ngtcp2_pv_entry *ent;
if (pv->started_ts == UINT64_MAX) {
return 0;
}
assert(ngtcp2_ringbuf_len(&pv->ents.rb));
ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
t = pv->started_ts + pv->timeout;
t = ngtcp2_max(t, ent->expiry);
return t <= ts;
}
ngtcp2_tstamp ngtcp2_pv_next_expiry(ngtcp2_pv *pv) {
ngtcp2_pv_entry *ent;
if ((pv->flags & NGTCP2_PV_FLAG_CANCEL_TIMER) ||
ngtcp2_ringbuf_len(&pv->ents.rb) == 0) {
return UINT64_MAX;
}
ent = ngtcp2_ringbuf_get(&pv->ents.rb, ngtcp2_ringbuf_len(&pv->ents.rb) - 1);
return ent->expiry;
}
void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts) {
ngtcp2_tstamp expiry = ngtcp2_pv_next_expiry(pv);
if (expiry > ts) {
return;
}
pv->flags |= NGTCP2_PV_FLAG_CANCEL_TIMER;
}

View file

@ -1,198 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_PV_H
#define NGTCP2_PV_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_cid.h"
#include "ngtcp2_ringbuf.h"
/* NGTCP2_PV_MAX_ENTRIES is the maximum number of entries that
ngtcp2_pv can contain. It must be power of 2. */
#define NGTCP2_PV_MAX_ENTRIES 8
/* NGTCP2_PV_NUM_PROBE_PKT is the number of probe packets containing
PATH_CHALLENGE sent at a time. */
#define NGTCP2_PV_NUM_PROBE_PKT 2
typedef struct ngtcp2_log ngtcp2_log;
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
/* NGTCP2_PV_ENTRY_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_PV_ENTRY_FLAG_NONE 0x00u
/* NGTCP2_PV_ENTRY_FLAG_UNDERSIZED indicates that UDP datagram which
contains PATH_CHALLENGE is undersized (< 1200 bytes) */
#define NGTCP2_PV_ENTRY_FLAG_UNDERSIZED 0x01u
typedef struct ngtcp2_pv_entry {
/* expiry is the timestamp when this PATH_CHALLENGE expires. */
ngtcp2_tstamp expiry;
/* flags is zero or more of NGTCP2_PV_ENTRY_FLAG_*. */
uint8_t flags;
/* data is a byte string included in PATH_CHALLENGE. */
uint8_t data[8];
} ngtcp2_pv_entry;
void ngtcp2_pv_entry_init(ngtcp2_pv_entry *pvent, const uint8_t *data,
ngtcp2_tstamp expiry, uint8_t flags);
/* NGTCP2_PV_FLAG_NONE indicates no flag is set. */
#define NGTCP2_PV_FLAG_NONE 0x00u
/* NGTCP2_PV_FLAG_DONT_CARE indicates that the outcome of path
validation should be ignored entirely. */
#define NGTCP2_PV_FLAG_DONT_CARE 0x01u
/* NGTCP2_PV_FLAG_CANCEL_TIMER indicates that the expiry timer is
cancelled. */
#define NGTCP2_PV_FLAG_CANCEL_TIMER 0x02u
/* NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE indicates that fallback DCID is
available in ngtcp2_pv. If path validation fails, fallback to the
fallback DCID. If path validation succeeds, fallback DCID is
retired if it does not equal to the current DCID. */
#define NGTCP2_PV_FLAG_FALLBACK_ON_FAILURE 0x04u
/* NGTCP2_PV_FLAG_MTU_PROBE indicates that a validation must probe
least MTU that QUIC requires, which is 1200 bytes. If it fails, a
path is not viable. */
#define NGTCP2_PV_FLAG_MTU_PROBE 0x08u
/* NGTCP2_PV_FLAG_PREFERRED_ADDR indicates that client is migrating to
server's preferred address. This flag is only used by client. */
#define NGTCP2_PV_FLAG_PREFERRED_ADDR 0x10u
typedef struct ngtcp2_pv ngtcp2_pv;
ngtcp2_static_ringbuf_def(pv_ents, NGTCP2_PV_MAX_ENTRIES,
sizeof(ngtcp2_pv_entry));
/*
* ngtcp2_pv is the context of a single path validation.
*/
struct ngtcp2_pv {
const ngtcp2_mem *mem;
ngtcp2_log *log;
/* dcid is DCID and path this path validation uses. */
ngtcp2_dcid dcid;
/* fallback_dcid is the usually validated DCID and used as a
fallback if this path validation fails. */
ngtcp2_dcid fallback_dcid;
/* ents is the ring buffer of ngtcp2_pv_entry */
ngtcp2_static_ringbuf_pv_ents ents;
/* timeout is the duration within which this path validation should
succeed. */
ngtcp2_duration timeout;
/* fallback_pto is PTO of fallback connection. */
ngtcp2_duration fallback_pto;
/* started_ts is the timestamp this path validation starts. */
ngtcp2_tstamp started_ts;
/* round is the number of times that probe_pkt_left is reset. */
size_t round;
/* probe_pkt_left is the number of probe packets containing
PATH_CHALLENGE which can be send without waiting for an
expiration of a previous flight. */
size_t probe_pkt_left;
/* flags is bitwise-OR of zero or more of NGTCP2_PV_FLAG_*. */
uint8_t flags;
};
/*
* ngtcp2_pv_new creates new ngtcp2_pv object and assigns its pointer
* to |*ppv|. This function makes a copy of |dcid|. |timeout| is a
* duration within which this path validation must succeed.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_pv_new(ngtcp2_pv **ppv, const ngtcp2_dcid *dcid,
ngtcp2_duration timeout, uint8_t flags, ngtcp2_log *log,
const ngtcp2_mem *mem);
/*
* ngtcp2_pv_del deallocates |pv|. This function frees memory |pv|
* points too.
*/
void ngtcp2_pv_del(ngtcp2_pv *pv);
/*
* ngtcp2_pv_add_entry adds new entry with |data|. |expiry| is the
* expiry time of the entry.
*/
void ngtcp2_pv_add_entry(ngtcp2_pv *pv, const uint8_t *data,
ngtcp2_tstamp expiry, uint8_t flags, ngtcp2_tstamp ts);
/*
* ngtcp2_pv_full returns nonzero if |pv| is full of ngtcp2_pv_entry.
*/
int ngtcp2_pv_full(ngtcp2_pv *pv);
/*
* ngtcp2_pv_validate validates that the received |data| matches the
* one of the existing entry. The flag of ngtcp2_pv_entry that
* matches |data| is assigned to |*pflags| if this function succeeds.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_PATH_VALIDATION_FAILED
* path validation has failed and must be abandoned
* NGTCP2_ERR_INVALID_STATE
* |pv| includes no entry
* NGTCP2_ERR_INVALID_ARGUMENT
* |pv| does not have an entry which has |data| and |path|
*/
int ngtcp2_pv_validate(ngtcp2_pv *pv, uint8_t *pflags, const uint8_t *data);
/*
* ngtcp2_pv_handle_entry_expiry checks expiry of existing entries.
*/
void ngtcp2_pv_handle_entry_expiry(ngtcp2_pv *pv, ngtcp2_tstamp ts);
/*
* ngtcp2_pv_should_send_probe returns nonzero if new entry can be
* added by ngtcp2_pv_add_entry.
*/
int ngtcp2_pv_should_send_probe(ngtcp2_pv *pv);
/*
* ngtcp2_pv_validation_timed_out returns nonzero if the path
* validation fails because of timeout.
*/
int ngtcp2_pv_validation_timed_out(ngtcp2_pv *pv, ngtcp2_tstamp ts);
/*
* ngtcp2_pv_next_expiry returns the earliest expiry.
*/
ngtcp2_tstamp ngtcp2_pv_next_expiry(ngtcp2_pv *pv);
/*
* ngtcp2_pv_cancel_expired_timer cancels the expired timer.
*/
void ngtcp2_pv_cancel_expired_timer(ngtcp2_pv *pv, ngtcp2_tstamp ts);
#endif /* NGTCP2_PV_H */

File diff suppressed because it is too large Load diff

View file

@ -1,161 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_QLOG_H
#define NGTCP2_QLOG_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_pkt.h"
#include "ngtcp2_cc.h"
#include "ngtcp2_buf.h"
#include "ngtcp2_rtb.h"
/* NGTCP2_QLOG_BUFLEN is the length of heap allocated buffer for
qlog. */
#define NGTCP2_QLOG_BUFLEN 4096
typedef enum ngtcp2_qlog_side {
NGTCP2_QLOG_SIDE_LOCAL,
NGTCP2_QLOG_SIDE_REMOTE,
} ngtcp2_qlog_side;
typedef struct ngtcp2_qlog {
/* write is a callback function to write qlog. */
ngtcp2_qlog_write write;
/* ts is the initial timestamp */
ngtcp2_tstamp ts;
/* last_ts is the timestamp observed last time. */
ngtcp2_tstamp last_ts;
/* buf is a heap allocated buffer to write exclusively
packet_received and packet_sent. */
ngtcp2_buf buf;
/* user_data is an opaque pointer which is passed to write
callback. */
void *user_data;
} ngtcp2_qlog;
/*
* ngtcp2_qlog_init initializes |qlog|.
*/
void ngtcp2_qlog_init(ngtcp2_qlog *qlog, ngtcp2_qlog_write write,
ngtcp2_tstamp ts, void *user_data);
/*
* ngtcp2_qlog_start writes qlog preamble.
*/
void ngtcp2_qlog_start(ngtcp2_qlog *qlog, const ngtcp2_cid *odcid, int server);
/*
* ngtcp2_qlog_end writes closing part of qlog.
*/
void ngtcp2_qlog_end(ngtcp2_qlog *qlog);
/*
* ngtcp2_qlog_write_frame writes |fr| to qlog->buf.
* ngtcp2_qlog_pkt_received_start or ngtcp2_qlog_pkt_sent_start must
* be called before calling this function.
*/
void ngtcp2_qlog_write_frame(ngtcp2_qlog *qlog, const ngtcp2_frame *fr);
/*
* ngtcp2_qlog_pkt_received_start starts to write packet_received
* event. It initializes qlog->buf. It writes qlog to qlog->buf.
* ngtcp2_qlog_pkt_received_end will flush the content of qlog->buf to
* write callback.
*/
void ngtcp2_qlog_pkt_received_start(ngtcp2_qlog *qlog);
/*
* ngtcp2_qlog_pkt_received_end ends packet_received event and sends
* the content of qlog->buf to qlog->write callback.
*/
void ngtcp2_qlog_pkt_received_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
size_t pktlen);
/*
* ngtcp2_qlog_pkt_sent_start starts to write packet_sent event. It
* initializes qlog->buf. It writes qlog to qlog->buf.
* ngtcp2_qlog_pkt_sent_end will flush the content of qlog->buf to
* write callback.
*/
void ngtcp2_qlog_pkt_sent_start(ngtcp2_qlog *qlog);
/*
* ngtcp2_qlog_pkt_sent_end ends packet_sent event and sends the
* content of qlog->buf to qlog->write callback.
*/
void ngtcp2_qlog_pkt_sent_end(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
size_t pktlen);
/*
* ngtcp2_qlog_parameters_set_transport_params writes |params| to qlog
* as parameters_set event. |server| is nonzero if the local endpoint
* is server. If |local| is nonzero, it is "owner" field becomes
* "local", otherwise "remote".
*/
void ngtcp2_qlog_parameters_set_transport_params(
ngtcp2_qlog *qlog, const ngtcp2_transport_params *params, int server,
ngtcp2_qlog_side side);
/*
* ngtcp2_qlog_metrics_updated writes metrics_updated event of
* recovery category.
*/
void ngtcp2_qlog_metrics_updated(ngtcp2_qlog *qlog,
const ngtcp2_conn_stat *cstat);
/*
* ngtcp2_qlog_pkt_lost writes packet_lost event.
*/
void ngtcp2_qlog_pkt_lost(ngtcp2_qlog *qlog, ngtcp2_rtb_entry *ent);
/*
* ngtcp2_qlog_retry_pkt_received writes packet_received event for a
* received Retry packet.
*/
void ngtcp2_qlog_retry_pkt_received(ngtcp2_qlog *qlog, const ngtcp2_pkt_hd *hd,
const ngtcp2_pkt_retry *retry);
/*
* ngtcp2_qlog_stateless_reset_pkt_received writes packet_received
* event for a received Stateless Reset packet.
*/
void ngtcp2_qlog_stateless_reset_pkt_received(
ngtcp2_qlog *qlog, const ngtcp2_pkt_stateless_reset *sr);
/*
* ngtcp2_qlog_version_negotiation_pkt_received writes packet_received
* event for a received Version Negotiation packet.
*/
void ngtcp2_qlog_version_negotiation_pkt_received(ngtcp2_qlog *qlog,
const ngtcp2_pkt_hd *hd,
const uint32_t *sv,
size_t nsv);
#endif /* NGTCP2_QLOG_H */

View file

@ -1,61 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_range.h"
#include "ngtcp2_macro.h"
void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end) {
r->begin = begin;
r->end = end;
}
ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a,
const ngtcp2_range *b) {
ngtcp2_range r = {0, 0};
uint64_t begin = ngtcp2_max(a->begin, b->begin);
uint64_t end = ngtcp2_min(a->end, b->end);
if (begin < end) {
ngtcp2_range_init(&r, begin, end);
}
return r;
}
uint64_t ngtcp2_range_len(const ngtcp2_range *r) { return r->end - r->begin; }
int ngtcp2_range_eq(const ngtcp2_range *a, const ngtcp2_range *b) {
return a->begin == b->begin && a->end == b->end;
}
void ngtcp2_range_cut(ngtcp2_range *left, ngtcp2_range *right,
const ngtcp2_range *a, const ngtcp2_range *b) {
/* Assume that b is included in a */
left->begin = a->begin;
left->end = b->begin;
right->begin = b->end;
right->end = a->end;
}
int ngtcp2_range_not_after(const ngtcp2_range *a, const ngtcp2_range *b) {
return a->end <= b->end;
}

View file

@ -1,80 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_RANGE_H
#define NGTCP2_RANGE_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
/*
* ngtcp2_range represents half-closed range [begin, end).
*/
typedef struct ngtcp2_range {
uint64_t begin;
uint64_t end;
} ngtcp2_range;
/*
* ngtcp2_range_init initializes |r| with the range [|begin|, |end|).
*/
void ngtcp2_range_init(ngtcp2_range *r, uint64_t begin, uint64_t end);
/*
* ngtcp2_range_intersect returns the intersection of |a| and |b|. If
* they do not overlap, it returns empty range.
*/
ngtcp2_range ngtcp2_range_intersect(const ngtcp2_range *a,
const ngtcp2_range *b);
/*
* ngtcp2_range_len returns the length of |r|.
*/
uint64_t ngtcp2_range_len(const ngtcp2_range *r);
/*
* ngtcp2_range_eq returns nonzero if |a| equals |b|, such that
* a->begin == b->begin, and a->end == b->end hold.
*/
int ngtcp2_range_eq(const ngtcp2_range *a, const ngtcp2_range *b);
/*
* ngtcp2_range_cut returns the left and right range after removing
* |b| from |a|. This function assumes that |a| completely includes
* |b|. In other words, a->begin <= b->begin and b->end <= a->end
* hold.
*/
void ngtcp2_range_cut(ngtcp2_range *left, ngtcp2_range *right,
const ngtcp2_range *a, const ngtcp2_range *b);
/*
* ngtcp2_range_not_after returns nonzero if the right edge of |a|
* does not go beyond of the right edge of |b|.
*/
int ngtcp2_range_not_after(const ngtcp2_range *a, const ngtcp2_range *b);
#endif /* NGTCP2_RANGE_H */

View file

@ -1,40 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_RCVRY_H
#define NGTCP2_RCVRY_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
/* NGTCP2_PKT_THRESHOLD is kPacketThreshold described in RFC 9002. */
#define NGTCP2_PKT_THRESHOLD 3
/* NGTCP2_GRANULARITY is kGranularity described in RFC 9002. */
#define NGTCP2_GRANULARITY NGTCP2_MILLISECONDS
#endif /* NGTCP2_RCVRY_H */

View file

@ -1,120 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_ringbuf.h"
#include <assert.h>
#ifdef WIN32
# include <intrin.h>
#endif
#include "ngtcp2_macro.h"
#if defined(_MSC_VER) && defined(_M_ARM64)
unsigned int __popcnt(unsigned int x) {
unsigned int c = 0;
for (; x; ++c) {
x &= x - 1;
}
return c;
}
#endif
int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
const ngtcp2_mem *mem) {
uint8_t *buf = ngtcp2_mem_malloc(mem, nmemb * size);
if (buf == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_ringbuf_buf_init(rb, nmemb, size, buf, mem);
return 0;
}
void ngtcp2_ringbuf_buf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
uint8_t *buf, const ngtcp2_mem *mem) {
#ifdef WIN32
assert(1 == __popcnt((unsigned int)nmemb));
#else
assert(1 == __builtin_popcount((unsigned int)nmemb));
#endif
rb->buf = buf;
rb->mem = mem;
rb->nmemb = nmemb;
rb->size = size;
rb->first = 0;
rb->len = 0;
}
void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb) {
if (rb == NULL) {
return;
}
ngtcp2_mem_free(rb->mem, rb->buf);
}
void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb) {
rb->first = (rb->first - 1) & (rb->nmemb - 1);
rb->len = ngtcp2_min(rb->nmemb, rb->len + 1);
return (void *)&rb->buf[rb->first * rb->size];
}
void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb) {
size_t offset = (rb->first + rb->len) & (rb->nmemb - 1);
if (rb->len == rb->nmemb) {
rb->first = (rb->first + 1) & (rb->nmemb - 1);
} else {
++rb->len;
}
return (void *)&rb->buf[offset * rb->size];
}
void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb) {
rb->first = (rb->first + 1) & (rb->nmemb - 1);
--rb->len;
}
void ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf *rb) {
assert(rb->len);
--rb->len;
}
void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len) {
assert(len <= rb->nmemb);
rb->len = len;
}
void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset) {
assert(offset < rb->len);
offset = (rb->first + offset) & (rb->nmemb - 1);
return &rb->buf[offset * rb->size];
}
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb) { return rb->len == rb->nmemb; }

View file

@ -1,132 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_RINGBUF_H
#define NGTCP2_RINGBUF_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
typedef struct ngtcp2_ringbuf {
/* buf points to the underlying buffer. */
uint8_t *buf;
const ngtcp2_mem *mem;
/* nmemb is the number of elements that can be stored in this ring
buffer. */
size_t nmemb;
/* size is the size of each element. */
size_t size;
/* first is the offset to the first element. */
size_t first;
/* len is the number of elements actually stored. */
size_t len;
} ngtcp2_ringbuf;
/*
* ngtcp2_ringbuf_init initializes |rb|. |nmemb| is the number of
* elements that can be stored in this buffer. |size| is the size of
* each element. |size| must be power of 2.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_ringbuf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
const ngtcp2_mem *mem);
/*
* ngtcp2_ringbuf_buf_init initializes |rb| with given buffer and
* size.
*/
void ngtcp2_ringbuf_buf_init(ngtcp2_ringbuf *rb, size_t nmemb, size_t size,
uint8_t *buf, const ngtcp2_mem *mem);
/*
* ngtcp2_ringbuf_free frees resources allocated for |rb|. This
* function does not free the memory pointed by |rb|.
*/
void ngtcp2_ringbuf_free(ngtcp2_ringbuf *rb);
/* ngtcp2_ringbuf_push_front moves the offset to the first element in
the buffer backward, and returns the pointer to the element.
Caller can store data to the buffer pointed by the returned
pointer. If this action exceeds the capacity of the ring buffer,
the last element is silently overwritten, and rb->len remains
unchanged. */
void *ngtcp2_ringbuf_push_front(ngtcp2_ringbuf *rb);
/* ngtcp2_ringbuf_push_back moves the offset to the last element in
the buffer forward, and returns the pointer to the element. Caller
can store data to the buffer pointed by the returned pointer. If
this action exceeds the capacity of the ring buffer, the first
element is silently overwritten, and rb->len remains unchanged. */
void *ngtcp2_ringbuf_push_back(ngtcp2_ringbuf *rb);
/*
* ngtcp2_ringbuf_pop_front removes first element in |rb|.
*/
void ngtcp2_ringbuf_pop_front(ngtcp2_ringbuf *rb);
/*
* ngtcp2_ringbuf_pop_back removes the last element in |rb|.
*/
void ngtcp2_ringbuf_pop_back(ngtcp2_ringbuf *rb);
/* ngtcp2_ringbuf_resize changes the number of elements stored. This
does not change the capacity of the underlying buffer. */
void ngtcp2_ringbuf_resize(ngtcp2_ringbuf *rb, size_t len);
/* ngtcp2_ringbuf_get returns the pointer to the element at
|offset|. */
void *ngtcp2_ringbuf_get(ngtcp2_ringbuf *rb, size_t offset);
/* ngtcp2_ringbuf_len returns the number of elements stored. */
#define ngtcp2_ringbuf_len(RB) ((RB)->len)
/* ngtcp2_ringbuf_full returns nonzero if |rb| is full. */
int ngtcp2_ringbuf_full(ngtcp2_ringbuf *rb);
/* ngtcp2_static_ringbuf_def defines ngtcp2_ringbuf struct wrapper
which uses a statically allocated buffer that is suitable for a
usage that does not change buffer size with ngtcp2_ringbuf_resize.
ngtcp2_ringbuf_free should never be called for rb field. */
#define ngtcp2_static_ringbuf_def(NAME, NMEMB, SIZE) \
typedef struct ngtcp2_static_ringbuf_##NAME { \
ngtcp2_ringbuf rb; \
uint8_t buf[(NMEMB) * (SIZE)]; \
} ngtcp2_static_ringbuf_##NAME; \
\
static inline void ngtcp2_static_ringbuf_##NAME##_init( \
ngtcp2_static_ringbuf_##NAME *srb) { \
ngtcp2_ringbuf_buf_init(&srb->rb, (NMEMB), (SIZE), srb->buf, NULL); \
}
#endif /* NGTCP2_RINGBUF_H */

View file

@ -1,319 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_rob.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_macro.h"
int ngtcp2_rob_gap_new(ngtcp2_rob_gap **pg, uint64_t begin, uint64_t end,
const ngtcp2_mem *mem) {
*pg = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_rob_gap));
if (*pg == NULL) {
return NGTCP2_ERR_NOMEM;
}
(*pg)->range.begin = begin;
(*pg)->range.end = end;
return 0;
}
void ngtcp2_rob_gap_del(ngtcp2_rob_gap *g, const ngtcp2_mem *mem) {
ngtcp2_mem_free(mem, g);
}
int ngtcp2_rob_data_new(ngtcp2_rob_data **pd, uint64_t offset, size_t chunk,
const ngtcp2_mem *mem) {
*pd = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_rob_data) + chunk);
if (*pd == NULL) {
return NGTCP2_ERR_NOMEM;
}
(*pd)->range.begin = offset;
(*pd)->range.end = offset + chunk;
(*pd)->begin = (uint8_t *)(*pd) + sizeof(ngtcp2_rob_data);
(*pd)->end = (*pd)->begin + chunk;
return 0;
}
void ngtcp2_rob_data_del(ngtcp2_rob_data *d, const ngtcp2_mem *mem) {
ngtcp2_mem_free(mem, d);
}
int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem) {
int rv;
ngtcp2_rob_gap *g;
ngtcp2_ksl_init(&rob->gapksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
mem);
rv = ngtcp2_rob_gap_new(&g, 0, UINT64_MAX, mem);
if (rv != 0) {
goto fail_rob_gap_new;
}
rv = ngtcp2_ksl_insert(&rob->gapksl, NULL, &g->range, g);
if (rv != 0) {
goto fail_gapksl_ksl_insert;
}
ngtcp2_ksl_init(&rob->dataksl, ngtcp2_ksl_range_compar, sizeof(ngtcp2_range),
mem);
rob->chunk = chunk;
rob->mem = mem;
return 0;
fail_gapksl_ksl_insert:
ngtcp2_rob_gap_del(g, mem);
fail_rob_gap_new:
ngtcp2_ksl_free(&rob->gapksl);
return rv;
}
void ngtcp2_rob_free(ngtcp2_rob *rob) {
ngtcp2_ksl_it it;
if (rob == NULL) {
return;
}
for (it = ngtcp2_ksl_begin(&rob->dataksl); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
ngtcp2_rob_data_del(ngtcp2_ksl_it_get(&it), rob->mem);
}
for (it = ngtcp2_ksl_begin(&rob->gapksl); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
ngtcp2_rob_gap_del(ngtcp2_ksl_it_get(&it), rob->mem);
}
ngtcp2_ksl_free(&rob->dataksl);
ngtcp2_ksl_free(&rob->gapksl);
}
static int rob_write_data(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
size_t len) {
size_t n;
int rv;
ngtcp2_rob_data *d;
ngtcp2_range range = {offset, offset + len};
ngtcp2_ksl_it it;
for (it = ngtcp2_ksl_lower_bound_compar(&rob->dataksl, &range,
ngtcp2_ksl_range_exclusive_compar);
len; ngtcp2_ksl_it_next(&it)) {
if (ngtcp2_ksl_it_end(&it)) {
d = NULL;
} else {
d = ngtcp2_ksl_it_get(&it);
}
if (d == NULL || offset < d->range.begin) {
rv = ngtcp2_rob_data_new(&d, (offset / rob->chunk) * rob->chunk,
rob->chunk, rob->mem);
if (rv != 0) {
return rv;
}
rv = ngtcp2_ksl_insert(&rob->dataksl, &it, &d->range, d);
if (rv != 0) {
ngtcp2_rob_data_del(d, rob->mem);
return rv;
}
}
n = (size_t)ngtcp2_min((uint64_t)len, d->range.begin + rob->chunk - offset);
memcpy(d->begin + (offset - d->range.begin), data, n);
offset += n;
data += n;
len -= n;
}
return 0;
}
int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
size_t datalen) {
int rv;
ngtcp2_rob_gap *g;
ngtcp2_range m, l, r, q = {offset, offset + datalen};
ngtcp2_ksl_it it;
it = ngtcp2_ksl_lower_bound_compar(&rob->gapksl, &q,
ngtcp2_ksl_range_exclusive_compar);
for (; !ngtcp2_ksl_it_end(&it);) {
g = ngtcp2_ksl_it_get(&it);
m = ngtcp2_range_intersect(&q, &g->range);
if (!ngtcp2_range_len(&m)) {
break;
}
if (ngtcp2_range_eq(&g->range, &m)) {
ngtcp2_ksl_remove_hint(&rob->gapksl, &it, &it, &g->range);
ngtcp2_rob_gap_del(g, rob->mem);
rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
(size_t)ngtcp2_range_len(&m));
if (rv != 0) {
return rv;
}
continue;
}
ngtcp2_range_cut(&l, &r, &g->range, &m);
if (ngtcp2_range_len(&l)) {
ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &l);
g->range = l;
if (ngtcp2_range_len(&r)) {
ngtcp2_rob_gap *ng;
rv = ngtcp2_rob_gap_new(&ng, r.begin, r.end, rob->mem);
if (rv != 0) {
return rv;
}
rv = ngtcp2_ksl_insert(&rob->gapksl, &it, &ng->range, ng);
if (rv != 0) {
ngtcp2_rob_gap_del(ng, rob->mem);
return rv;
}
}
} else if (ngtcp2_range_len(&r)) {
ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r);
g->range = r;
}
rv = rob_write_data(rob, m.begin, data + (m.begin - offset),
(size_t)ngtcp2_range_len(&m));
if (rv != 0) {
return rv;
}
ngtcp2_ksl_it_next(&it);
}
return 0;
}
int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset) {
ngtcp2_rob_gap *g;
ngtcp2_rob_data *d;
ngtcp2_ksl_it it;
it = ngtcp2_ksl_begin(&rob->gapksl);
for (; !ngtcp2_ksl_it_end(&it);) {
g = ngtcp2_ksl_it_get(&it);
if (offset <= g->range.begin) {
break;
}
if (offset < g->range.end) {
ngtcp2_range r = {offset, g->range.end};
ngtcp2_ksl_update_key(&rob->gapksl, &g->range, &r);
g->range.begin = offset;
break;
}
ngtcp2_ksl_remove_hint(&rob->gapksl, &it, &it, &g->range);
ngtcp2_rob_gap_del(g, rob->mem);
}
it = ngtcp2_ksl_begin(&rob->dataksl);
for (; !ngtcp2_ksl_it_end(&it);) {
d = ngtcp2_ksl_it_get(&it);
if (offset < d->range.begin + rob->chunk) {
return 0;
}
ngtcp2_ksl_remove_hint(&rob->dataksl, &it, &it, &d->range);
ngtcp2_rob_data_del(d, rob->mem);
}
return 0;
}
size_t ngtcp2_rob_data_at(ngtcp2_rob *rob, const uint8_t **pdest,
uint64_t offset) {
ngtcp2_rob_gap *g;
ngtcp2_rob_data *d;
ngtcp2_ksl_it it;
it = ngtcp2_ksl_begin(&rob->gapksl);
if (ngtcp2_ksl_it_end(&it)) {
return 0;
}
g = ngtcp2_ksl_it_get(&it);
if (g->range.begin <= offset) {
return 0;
}
it = ngtcp2_ksl_begin(&rob->dataksl);
d = ngtcp2_ksl_it_get(&it);
assert(d);
assert(d->range.begin <= offset);
assert(offset < d->range.begin + rob->chunk);
*pdest = d->begin + (offset - d->range.begin);
return (size_t)(ngtcp2_min(g->range.begin, d->range.begin + rob->chunk) -
offset);
}
void ngtcp2_rob_pop(ngtcp2_rob *rob, uint64_t offset, size_t len) {
ngtcp2_ksl_it it;
ngtcp2_rob_data *d;
it = ngtcp2_ksl_begin(&rob->dataksl);
d = ngtcp2_ksl_it_get(&it);
assert(d);
if (offset + len < d->range.begin + rob->chunk) {
return;
}
ngtcp2_ksl_remove_hint(&rob->dataksl, NULL, &it, &d->range);
ngtcp2_rob_data_del(d, rob->mem);
}
uint64_t ngtcp2_rob_first_gap_offset(ngtcp2_rob *rob) {
ngtcp2_ksl_it it = ngtcp2_ksl_begin(&rob->gapksl);
ngtcp2_rob_gap *g;
if (ngtcp2_ksl_it_end(&it)) {
return UINT64_MAX;
}
g = ngtcp2_ksl_it_get(&it);
return g->range.begin;
}
int ngtcp2_rob_data_buffered(ngtcp2_rob *rob) {
return ngtcp2_ksl_len(&rob->dataksl) != 0;
}

View file

@ -1,197 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_ROB_H
#define NGTCP2_ROB_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
#include "ngtcp2_range.h"
#include "ngtcp2_ksl.h"
/*
* ngtcp2_rob_gap represents the gap, which is the range of stream
* data that is not received yet.
*/
typedef struct ngtcp2_rob_gap {
/* range is the range of this gap. */
ngtcp2_range range;
} ngtcp2_rob_gap;
/*
* ngtcp2_rob_gap_new allocates new ngtcp2_rob_gap object, and assigns
* its pointer to |*pg|. The caller should call ngtcp2_rob_gap_del to
* delete it when it is no longer used. The range of the gap is
* [begin, end). |mem| is custom memory allocator to allocate memory.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_rob_gap_new(ngtcp2_rob_gap **pg, uint64_t begin, uint64_t end,
const ngtcp2_mem *mem);
/*
* ngtcp2_rob_gap_del deallocates |g|. It deallocates the memory
* pointed by |g| it self. |mem| is custom memory allocator to
* deallocate memory.
*/
void ngtcp2_rob_gap_del(ngtcp2_rob_gap *g, const ngtcp2_mem *mem);
/*
* ngtcp2_rob_data holds the buffered stream data.
*/
typedef struct ngtcp2_rob_data {
/* range is the range of this gap. */
ngtcp2_range range;
/* begin points to the buffer. */
uint8_t *begin;
/* end points to the one beyond of the last byte of the buffer */
uint8_t *end;
} ngtcp2_rob_data;
/*
* ngtcp2_rob_data_new allocates new ngtcp2_rob_data object, and
* assigns its pointer to |*pd|. The caller should call
* ngtcp2_rob_data_del to delete it when it is no longer used.
* |offset| is the stream offset of the first byte of this data.
* |chunk| is the size of the buffer. |offset| must be multiple of
* |chunk|. |mem| is custom memory allocator to allocate memory.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_rob_data_new(ngtcp2_rob_data **pd, uint64_t offset, size_t chunk,
const ngtcp2_mem *mem);
/*
* ngtcp2_rob_data_del deallocates |d|. It deallocates the memory
* pointed by |d| itself. |mem| is custom memory allocator to
* deallocate memory.
*/
void ngtcp2_rob_data_del(ngtcp2_rob_data *d, const ngtcp2_mem *mem);
/*
* ngtcp2_rob is the reorder buffer which reassembles stream data
* received in out of order.
*/
typedef struct ngtcp2_rob {
/* gapksl maintains the range of offset which is not received
yet. Initially, its range is [0, UINT64_MAX). */
ngtcp2_ksl gapksl;
/* dataksl maintains the list of buffers which store received data
ordered by stream offset. */
ngtcp2_ksl dataksl;
/* mem is custom memory allocator */
const ngtcp2_mem *mem;
/* chunk is the size of each buffer in data field */
size_t chunk;
} ngtcp2_rob;
/*
* ngtcp2_rob_init initializes |rob|. |chunk| is the size of buffer
* per chunk.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_rob_init(ngtcp2_rob *rob, size_t chunk, const ngtcp2_mem *mem);
/*
* ngtcp2_rob_free frees resources allocated for |rob|.
*/
void ngtcp2_rob_free(ngtcp2_rob *rob);
/*
* ngtcp2_rob_push adds new data of length |datalen| at the stream
* offset |offset|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_rob_push(ngtcp2_rob *rob, uint64_t offset, const uint8_t *data,
size_t datalen);
/*
* ngtcp2_rob_remove_prefix removes gap up to |offset|, exclusive. It
* also removes data buffer if it is completely included in |offset|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_rob_remove_prefix(ngtcp2_rob *rob, uint64_t offset);
/*
* ngtcp2_rob_data_at stores the pointer to the buffer of stream
* offset |offset| to |*pdest| if it is available, and returns the
* valid length of available data. If no data is available, it
* returns 0.
*/
size_t ngtcp2_rob_data_at(ngtcp2_rob *rob, const uint8_t **pdest,
uint64_t offset);
/*
* ngtcp2_rob_pop clears data at stream offset |offset| of length
* |len|.
*
* |offset| must be the offset given in ngtcp2_rob_data_at. |len|
* must be the return value of ngtcp2_rob_data_at when |offset| is
* passed.
*
* Caller should call this function from offset 0 in non-decreasing
* order.
*/
void ngtcp2_rob_pop(ngtcp2_rob *rob, uint64_t offset, size_t len);
/*
* ngtcp2_rob_first_gap_offset returns the offset to the first gap.
* If there is no gap, it returns UINT64_MAX.
*/
uint64_t ngtcp2_rob_first_gap_offset(ngtcp2_rob *rob);
/*
* ngtcp2_rob_data_buffered returns nonzero if any data is buffered.
*/
int ngtcp2_rob_data_buffered(ngtcp2_rob *rob);
#endif /* NGTCP2_ROB_H */

View file

@ -1,137 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_rst.h"
#include <assert.h>
#include "ngtcp2_rtb.h"
#include "ngtcp2_cc.h"
#include "ngtcp2_macro.h"
void ngtcp2_rs_init(ngtcp2_rs *rs) {
rs->interval = UINT64_MAX;
rs->delivered = 0;
rs->prior_delivered = 0;
rs->prior_ts = 0;
rs->tx_in_flight = 0;
rs->lost = 0;
rs->prior_lost = 0;
rs->send_elapsed = 0;
rs->ack_elapsed = 0;
rs->is_app_limited = 0;
}
void ngtcp2_rst_init(ngtcp2_rst *rst) {
ngtcp2_rs_init(&rst->rs);
ngtcp2_window_filter_init(&rst->wf, 12);
rst->delivered = 0;
rst->delivered_ts = 0;
rst->first_sent_ts = 0;
rst->app_limited = 0;
rst->next_round_delivered = 0;
rst->round_count = 0;
rst->is_cwnd_limited = 0;
rst->lost = 0;
}
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
const ngtcp2_conn_stat *cstat) {
if (cstat->bytes_in_flight == 0) {
rst->first_sent_ts = rst->delivered_ts = ent->ts;
}
ent->rst.first_sent_ts = rst->first_sent_ts;
ent->rst.delivered_ts = rst->delivered_ts;
ent->rst.delivered = rst->delivered;
ent->rst.is_app_limited = rst->app_limited != 0;
ent->rst.tx_in_flight = cstat->bytes_in_flight + ent->pktlen;
ent->rst.lost = rst->lost;
}
int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat,
uint64_t pkt_delivered) {
ngtcp2_rs *rs = &rst->rs;
uint64_t rate;
if (rst->app_limited && rst->delivered > rst->app_limited) {
rst->app_limited = 0;
}
if (pkt_delivered >= rst->next_round_delivered) {
rst->next_round_delivered = pkt_delivered;
++rst->round_count;
}
if (rs->prior_ts == 0) {
return 0;
}
rs->interval = ngtcp2_max(rs->send_elapsed, rs->ack_elapsed);
rs->delivered = rst->delivered - rs->prior_delivered;
rs->lost = rst->lost - rs->prior_lost;
if (rs->interval < cstat->min_rtt) {
rs->interval = UINT64_MAX;
return 0;
}
if (!rs->interval) {
return 0;
}
rate = rs->delivered * NGTCP2_SECONDS / rs->interval;
if (rate > ngtcp2_window_filter_get_best(&rst->wf) || !rst->app_limited) {
ngtcp2_window_filter_update(&rst->wf, rate, rst->round_count);
cstat->delivery_rate_sec = ngtcp2_window_filter_get_best(&rst->wf);
}
return 0;
}
void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
ngtcp2_tstamp ts) {
ngtcp2_rs *rs = &rst->rs;
rst->delivered += ent->pktlen;
rst->delivered_ts = ts;
if (ent->rst.delivered > rs->prior_delivered) {
rs->prior_delivered = ent->rst.delivered;
rs->prior_ts = ent->rst.delivered_ts;
rs->is_app_limited = ent->rst.is_app_limited;
rs->send_elapsed = ent->ts - ent->rst.first_sent_ts;
rs->ack_elapsed = rst->delivered_ts - ent->rst.delivered_ts;
rs->tx_in_flight = ent->rst.tx_in_flight;
rs->prior_lost = ent->rst.lost;
rst->first_sent_ts = ent->ts;
}
}
void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat) {
(void)rst;
(void)cstat;
/* TODO Not implemented */
}

View file

@ -1,85 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_RST_H
#define NGTCP2_RST_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_window_filter.h"
typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
/**
* @struct
*
* ngtcp2_rs contains connection state for delivery rate estimation.
*/
typedef struct ngtcp2_rs {
ngtcp2_duration interval;
uint64_t delivered;
uint64_t prior_delivered;
ngtcp2_tstamp prior_ts;
uint64_t tx_in_flight;
uint64_t lost;
uint64_t prior_lost;
ngtcp2_duration send_elapsed;
ngtcp2_duration ack_elapsed;
int is_app_limited;
} ngtcp2_rs;
void ngtcp2_rs_init(ngtcp2_rs *rs);
/*
* ngtcp2_rst implements delivery rate estimation described in
* https://tools.ietf.org/html/draft-cheng-iccrg-delivery-rate-estimation-00
*/
typedef struct ngtcp2_rst {
ngtcp2_rs rs;
ngtcp2_window_filter wf;
uint64_t delivered;
ngtcp2_tstamp delivered_ts;
ngtcp2_tstamp first_sent_ts;
uint64_t app_limited;
uint64_t next_round_delivered;
uint64_t round_count;
uint64_t lost;
int is_cwnd_limited;
} ngtcp2_rst;
void ngtcp2_rst_init(ngtcp2_rst *rst);
void ngtcp2_rst_on_pkt_sent(ngtcp2_rst *rst, ngtcp2_rtb_entry *ent,
const ngtcp2_conn_stat *cstat);
int ngtcp2_rst_on_ack_recv(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat,
uint64_t pkt_delivered);
void ngtcp2_rst_update_rate_sample(ngtcp2_rst *rst, const ngtcp2_rtb_entry *ent,
ngtcp2_tstamp ts);
void ngtcp2_rst_update_app_limited(ngtcp2_rst *rst, ngtcp2_conn_stat *cstat);
#endif /* NGTCP2_RST_H */

File diff suppressed because it is too large Load diff

View file

@ -1,467 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_RTB_H
#define NGTCP2_RTB_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_pkt.h"
#include "ngtcp2_ksl.h"
#include "ngtcp2_pq.h"
#include "ngtcp2_objalloc.h"
typedef struct ngtcp2_conn ngtcp2_conn;
typedef struct ngtcp2_pktns ngtcp2_pktns;
typedef struct ngtcp2_log ngtcp2_log;
typedef struct ngtcp2_qlog ngtcp2_qlog;
typedef struct ngtcp2_strm ngtcp2_strm;
typedef struct ngtcp2_rst ngtcp2_rst;
typedef struct ngtcp2_cc ngtcp2_cc;
/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE indicates that no flag is
set. */
#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_NONE 0x00u
/* NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK indicates that an information
which a frame carries has been acknowledged. */
#define NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK 0x01u
/*
* ngtcp2_frame_chain_binder binds 2 or more of ngtcp2_frame_chain to
* share the acknowledgement state. In general, all
* ngtcp2_frame_chains bound to the same binder must have the same
* information.
*/
typedef struct ngtcp2_frame_chain_binder {
size_t refcount;
/* flags is bitwise OR of zero or more of
NGTCP2_FRAME_CHAIN_BINDER_FLAG_*. */
uint32_t flags;
} ngtcp2_frame_chain_binder;
int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder,
const ngtcp2_mem *mem);
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
/*
* ngtcp2_frame_chain chains frames in a single packet.
*/
struct ngtcp2_frame_chain {
union {
struct {
ngtcp2_frame_chain *next;
ngtcp2_frame_chain_binder *binder;
ngtcp2_frame fr;
};
ngtcp2_opl_entry oplent;
};
};
ngtcp2_objalloc_def(frame_chain, ngtcp2_frame_chain, oplent);
/*
* ngtcp2_bind_frame_chains binds two frame chains |a| and |b| using
* new or existing ngtcp2_frame_chain_binder. |a| might have non-NULL
* a->binder. |b| must not have non-NULL b->binder.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b,
const ngtcp2_mem *mem);
/* NGTCP2_MAX_STREAM_DATACNT is the maximum number of ngtcp2_vec that
a ngtcp2_stream can include. */
#define NGTCP2_MAX_STREAM_DATACNT 256
/* NGTCP2_MAX_CRYPTO_DATACNT is the maximum number of ngtcp2_vec that
a ngtcp2_crypto can include. */
#define NGTCP2_MAX_CRYPTO_DATACNT 8
/*
* ngtcp2_frame_chain_new allocates ngtcp2_frame_chain object and
* assigns its pointer to |*pfrc|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory.
*/
int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_objalloc_new behaves like
* ngtcp2_frame_chain_new, but it uses |objalloc| to allocate the object.
*/
int ngtcp2_frame_chain_objalloc_new(ngtcp2_frame_chain **pfrc,
ngtcp2_objalloc *objalloc);
/*
* ngtcp2_frame_chain_extralen_new works like ngtcp2_frame_chain_new,
* but it allocates extra memory |extralen| in order to extend
* ngtcp2_frame.
*/
int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen,
const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_stream_datacnt_objalloc_new works like
* ngtcp2_frame_chain_new, but it allocates enough data to store
* additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_stream
* object. If no additional space is required,
* ngtcp2_frame_chain_objalloc_new is called internally.
*/
int ngtcp2_frame_chain_stream_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
size_t datacnt,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_crypto_datacnt_objalloc_new works like
* ngtcp2_frame_chain_new, but it allocates enough data to store
* additional |datacnt| - 1 ngtcp2_vec object after ngtcp2_crypto
* object. If no additional space is required,
* ngtcp2_frame_chain_objalloc_new is called internally.
*/
int ngtcp2_frame_chain_crypto_datacnt_objalloc_new(ngtcp2_frame_chain **pfrc,
size_t datacnt,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
int ngtcp2_frame_chain_new_token_objalloc_new(ngtcp2_frame_chain **pfrc,
const uint8_t *token,
size_t tokenlen,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_del deallocates |frc|. It also deallocates the
* memory pointed by |frc|.
*/
void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_objalloc_del adds |frc| to |objalloc| for reuse.
* It might just delete |frc| depending on the frame type and the size
* of |frc|.
*/
void ngtcp2_frame_chain_objalloc_del(ngtcp2_frame_chain *frc,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_frame_chain_init initializes |frc|.
*/
void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc);
/*
* ngtcp2_frame_chain_list_objalloc_del adds all ngtcp2_frame_chain
* linked from |frc| to |objalloc| for reuse. Depending on the frame type
* and its size, ngtcp2_frame_chain might be deleted instead.
*/
void ngtcp2_frame_chain_list_objalloc_del(ngtcp2_frame_chain *frc,
ngtcp2_objalloc *objalloc,
const ngtcp2_mem *mem);
/* NGTCP2_RTB_ENTRY_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_RTB_ENTRY_FLAG_NONE 0x00u
/* NGTCP2_RTB_ENTRY_FLAG_PROBE indicates that the entry includes a
probe packet. */
#define NGTCP2_RTB_ENTRY_FLAG_PROBE 0x01u
/* NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE indicates that the entry
includes a frame which must be retransmitted until it is
acknowledged. In most cases, this flag is used along with
NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING and
NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING. */
#define NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE 0x02u
/* NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING indicates that the entry
elicits acknowledgement. */
#define NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING 0x04u
/* NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED indicates that the packet has
been reclaimed on PTO. It is not marked lost yet and still
consumes congestion window. */
#define NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED 0x08u
/* NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED indicates that the entry
has been marked lost and, optionally, scheduled to retransmit. */
#define NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED 0x10u
/* NGTCP2_RTB_ENTRY_FLAG_ECN indicates that the entry is included in a
UDP datagram with ECN marking. */
#define NGTCP2_RTB_ENTRY_FLAG_ECN 0x20u
/* NGTCP2_RTB_ENTRY_FLAG_DATAGRAM indicates that the entry includes
DATAGRAM frame. */
#define NGTCP2_RTB_ENTRY_FLAG_DATAGRAM 0x40u
/* NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE indicates that the entry includes
a PMTUD probe packet. */
#define NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE 0x80u
/* NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING indicates that the entry
includes a packet which elicits PTO probe packets. */
#define NGTCP2_RTB_ENTRY_FLAG_PTO_ELICITING 0x100u
typedef struct ngtcp2_rtb_entry ngtcp2_rtb_entry;
/*
* ngtcp2_rtb_entry is an object stored in ngtcp2_rtb. It corresponds
* to the one packet which is waiting for its ACK.
*/
struct ngtcp2_rtb_entry {
union {
struct {
ngtcp2_rtb_entry *next;
struct {
int64_t pkt_num;
uint8_t type;
uint8_t flags;
} hd;
ngtcp2_frame_chain *frc;
/* ts is the time point when a packet included in this entry is sent
to a peer. */
ngtcp2_tstamp ts;
/* lost_ts is the time when this entry is marked lost. */
ngtcp2_tstamp lost_ts;
/* pktlen is the length of QUIC packet */
size_t pktlen;
struct {
uint64_t delivered;
ngtcp2_tstamp delivered_ts;
ngtcp2_tstamp first_sent_ts;
uint64_t tx_in_flight;
uint64_t lost;
int is_app_limited;
} rst;
/* flags is bitwise-OR of zero or more of
NGTCP2_RTB_ENTRY_FLAG_*. */
uint16_t flags;
};
ngtcp2_opl_entry oplent;
};
};
ngtcp2_objalloc_def(rtb_entry, ngtcp2_rtb_entry, oplent);
/*
* ngtcp2_rtb_entry_new allocates ngtcp2_rtb_entry object, and assigns
* its pointer to |*pent|.
*/
int ngtcp2_rtb_entry_objalloc_new(ngtcp2_rtb_entry **pent,
const ngtcp2_pkt_hd *hd,
ngtcp2_frame_chain *frc, ngtcp2_tstamp ts,
size_t pktlen, uint16_t flags,
ngtcp2_objalloc *objalloc);
/*
* ngtcp2_rtb_entry_objalloc_del adds |ent| to |objalloc| for reuse.
* ngtcp2_frame_chain linked from ent->frc are also added to
* |frc_objalloc| depending on their frame type and size.
*/
void ngtcp2_rtb_entry_objalloc_del(ngtcp2_rtb_entry *ent,
ngtcp2_objalloc *objalloc,
ngtcp2_objalloc *frc_objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_rtb tracks sent packets, and its ACK timeout for
* retransmission.
*/
typedef struct ngtcp2_rtb {
ngtcp2_objalloc *frc_objalloc;
ngtcp2_objalloc *rtb_entry_objalloc;
/* ents includes ngtcp2_rtb_entry sorted by decreasing order of
packet number. */
ngtcp2_ksl ents;
/* crypto is CRYPTO stream. */
ngtcp2_strm *crypto;
ngtcp2_rst *rst;
ngtcp2_cc *cc;
ngtcp2_log *log;
ngtcp2_qlog *qlog;
const ngtcp2_mem *mem;
/* largest_acked_tx_pkt_num is the largest packet number
acknowledged by the peer. */
int64_t largest_acked_tx_pkt_num;
/* num_ack_eliciting is the number of ACK eliciting entries. */
size_t num_ack_eliciting;
/* num_retransmittable is the number of packets which contain frames
that must be retransmitted on loss. */
size_t num_retransmittable;
/* num_pto_eliciting is the number of packets that elicit PTO probe
packets. */
size_t num_pto_eliciting;
/* probe_pkt_left is the number of probe packet to send */
size_t probe_pkt_left;
/* pktns_id is the identifier of packet number space. */
ngtcp2_pktns_id pktns_id;
/* cc_pkt_num is the smallest packet number that is contributed to
ngtcp2_conn_stat.bytes_in_flight. */
int64_t cc_pkt_num;
/* cc_bytes_in_flight is the number of in-flight bytes that is
contributed to ngtcp2_conn_stat.bytes_in_flight. It only
includes the bytes after congestion state is reset. */
uint64_t cc_bytes_in_flight;
/* persistent_congestion_start_ts is the time when persistent
congestion evaluation is started. It happens roughly after
handshake is confirmed. */
ngtcp2_tstamp persistent_congestion_start_ts;
/* num_lost_pkts is the number entries in ents which has
NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED flag set. */
size_t num_lost_pkts;
/* num_lost_pmtud_pkts is the number of entries in ents which have
both NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED and
NGTCP2_RTB_ENTRY_FLAG_PMTUD_PROBE flags set. */
size_t num_lost_pmtud_pkts;
} ngtcp2_rtb;
/*
* ngtcp2_rtb_init initializes |rtb|.
*/
void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id,
ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc,
ngtcp2_log *log, ngtcp2_qlog *qlog,
ngtcp2_objalloc *rtb_entry_objalloc,
ngtcp2_objalloc *frc_objalloc, const ngtcp2_mem *mem);
/*
* ngtcp2_rtb_free deallocates resources allocated for |rtb|.
*/
void ngtcp2_rtb_free(ngtcp2_rtb *rtb);
/*
* ngtcp2_rtb_add adds |ent| to |rtb|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent,
ngtcp2_conn_stat *cstat);
/*
* ngtcp2_rtb_head returns the iterator which points to the entry
* which has the largest packet number. If there is no entry,
* returned value satisfies ngtcp2_ksl_it_end(&it) != 0.
*/
ngtcp2_ksl_it ngtcp2_rtb_head(ngtcp2_rtb *rtb);
/*
* ngtcp2_rtb_recv_ack removes acked ngtcp2_rtb_entry from |rtb|.
* |pkt_num| is a packet number which includes |fr|. |pkt_ts| is the
* timestamp when packet is received. |ts| should be the current
* time. Usually they are the same, but for buffered packets,
* |pkt_ts| would be earlier than |ts|.
*
* This function returns the number of newly acknowledged packets if
* it succeeds, or one of the following negative error codes:
*
* NGTCP2_ERR_CALLBACK_FAILURE
* User callback failed
* NGTCP2_ERR_NOMEM
* Out of memory
*/
ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr,
ngtcp2_conn_stat *cstat, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_tstamp pkt_ts,
ngtcp2_tstamp ts);
/*
* ngtcp2_rtb_detect_lost_pkt detects lost packets and prepends the
* frames contained them to |*pfrc|. Even when this function fails,
* some frames might be prepended to |*pfrc| and the caller should
* handle them.
*/
int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat,
ngtcp2_tstamp ts);
/*
* ngtcp2_rtb_remove_expired_lost_pkt removes expired lost packet.
*/
void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto,
ngtcp2_tstamp ts);
/*
* ngtcp2_rtb_lost_pkt_ts returns the earliest time when the still
* retained packet was lost. It returns UINT64_MAX if no such packet
* exists.
*/
ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(ngtcp2_rtb *rtb);
/*
* ngtcp2_rtb_remove_all removes all packets from |rtb| and prepends
* all frames to |*pfrc|. Even when this function fails, some frames
* might be prepended to |*pfrc| and the caller should handle them.
*/
int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat);
/*
* ngtcp2_rtb_remove_early_data removes all entries for 0RTT packets.
*/
void ngtcp2_rtb_remove_early_data(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat);
/*
* ngtcp2_rtb_empty returns nonzero if |rtb| have no entry.
*/
int ngtcp2_rtb_empty(ngtcp2_rtb *rtb);
/*
* ngtcp2_rtb_reset_cc_state resets congestion state in |rtb|.
* |cc_pkt_num| is the next outbound packet number which is sent under
* new congestion state.
*/
void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num);
/*
* ngtcp2_rtb_remove_expired_lost_pkt ensures that the number of lost
* packets at most |n|.
*/
void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n);
/*
* ngtcp2_rtb_reclaim_on_pto reclaims up to |num_pkts| packets which
* are in-flight and not marked lost to send them in PTO probe. The
* reclaimed frames are chained to |*pfrc|.
*
* This function returns the number of packets reclaimed if it
* succeeds, or one of the following negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn,
ngtcp2_pktns *pktns, size_t num_pkts);
#endif /* NGTCP2_RTB_H */

View file

@ -1,233 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_str.h"
#include <string.h>
#include "ngtcp2_macro.h"
void *ngtcp2_cpymem(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
return (uint8_t *)dest + n;
}
uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n) {
memset(dest, b, n);
return dest + n;
}
const void *ngtcp2_get_bytes(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
return (uint8_t *)src + n;
}
#define LOWER_XDIGITS "0123456789abcdef"
uint8_t *ngtcp2_encode_hex(uint8_t *dest, const uint8_t *data, size_t len) {
size_t i;
uint8_t *p = dest;
for (i = 0; i < len; ++i) {
*p++ = (uint8_t)LOWER_XDIGITS[data[i] >> 4];
*p++ = (uint8_t)LOWER_XDIGITS[data[i] & 0xf];
}
*p = '\0';
return dest;
}
char *ngtcp2_encode_printable_ascii(char *dest, const uint8_t *data,
size_t len) {
size_t i;
char *p = dest;
uint8_t c;
for (i = 0; i < len; ++i) {
c = data[i];
if (0x20 <= c && c <= 0x7e) {
*p++ = (char)c;
} else {
*p++ = '.';
}
}
*p = '\0';
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) {
size_t i;
uint8_t *p = dest;
p = write_uint(p, addr[0]);
for (i = 1; i < 4; ++i) {
*p++ = '.';
p = write_uint(p, addr[i]);
}
*p = '\0';
return dest;
}
/*
* write_hex_zsup writes the content of buffer pointed by |data| of
* 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) {
size_t i;
uint8_t *p = dest;
uint8_t d;
for (i = 0; i < len; ++i) {
d = data[i];
if (d >> 4) {
break;
}
d &= 0xf;
if (d) {
*p++ = (uint8_t)LOWER_XDIGITS[d];
++i;
break;
}
}
if (p == dest && i == len) {
*p++ = '0';
return p;
}
for (; i < len; ++i) {
d = data[i];
*p++ = (uint8_t)LOWER_XDIGITS[d >> 4];
*p++ = (uint8_t)LOWER_XDIGITS[d & 0xf];
}
return p;
}
uint8_t *ngtcp2_encode_ipv6(uint8_t *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;
for (i = 0; i < 16; i += sizeof(uint16_t)) {
/* Copy in network byte order. */
memcpy(&blks[i / sizeof(uint16_t)], addr + i, sizeof(uint16_t));
}
for (i = 0; i < 8;) {
if (blks[i]) {
++i;
continue;
}
zlen = 1;
zoff = i;
++i;
for (; i < 8 && blks[i] == 0; ++i, ++zlen)
;
if (zlen > max_zlen) {
max_zlen = zlen;
max_zoff = zoff;
}
}
/* Do not suppress a single '0' block */
if (max_zlen == 1) {
max_zoff = 8;
}
if (max_zoff != 0) {
p = write_hex_zsup(p, (const uint8_t *)blks, sizeof(uint16_t));
for (i = 1; i < max_zoff; ++i) {
*p++ = ':';
p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t));
}
}
if (max_zoff != 8) {
*p++ = ':';
if (max_zoff + max_zlen == 8) {
*p++ = ':';
} else {
for (i = max_zoff + max_zlen; i < 8; ++i) {
*p++ = ':';
p = write_hex_zsup(p, (const uint8_t *)(blks + i), sizeof(uint16_t));
}
}
}
*p = '\0';
return dest;
}
int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n) {
size_t i;
int rv = 0;
for (i = 0; i < n; ++i) {
rv |= a[i] ^ b[i];
}
return rv == 0;
}

View file

@ -1,94 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_STR_H
#define NGTCP2_STR_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
void *ngtcp2_cpymem(void *dest, const void *src, size_t n);
/*
* ngtcp2_setmem writes a string of length |n| consisting only |b| to
* the buffer pointed by |dest|. It returns dest + n;
*/
uint8_t *ngtcp2_setmem(uint8_t *dest, uint8_t b, size_t n);
/*
* ngtcp2_get_bytes copies |n| bytes from |src| to |dest|, and returns
* |src| + |n|.
*/
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|.
*/
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
* |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);
/*
* ngtcp2_encode_ipv6 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
* NULL byte. The function produces the canonical form of IPv6 text
* representation described in
* https://tools.ietf.org/html/rfc5952#section-4. The function
* returns |dest|.
*/
uint8_t *ngtcp2_encode_ipv6(uint8_t *dest, const uint8_t *addr);
/*
* ngtcp2_encode_printable_ascii encodes |data| of length |len| in
* |dest| in the following manner: printable ascii characters are
* copied as is. The other characters are converted to ".". It
* 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);
/*
* ngtcp2_cmemeq returns nonzero if the first |n| bytes of the buffers
* pointed by |a| and |b| are equal. The comparison is done in a
* constant time manner.
*/
int ngtcp2_cmemeq(const uint8_t *a, const uint8_t *b, size_t n);
#endif /* NGTCP2_STR_H */

View file

@ -1,698 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_strm.h"
#include <string.h>
#include <assert.h>
#include "ngtcp2_rtb.h"
#include "ngtcp2_pkt.h"
#include "ngtcp2_vec.h"
static int offset_less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
return *(int64_t *)lhs < *(int64_t *)rhs;
}
void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
uint64_t max_rx_offset, uint64_t max_tx_offset,
void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
const ngtcp2_mem *mem) {
strm->frc_objalloc = frc_objalloc;
strm->cycle = 0;
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_max_stream_data_ts = UINT64_MAX;
strm->tx.loss_count = 0;
strm->tx.last_lost_pkt_num = -1;
strm->rx.rob = NULL;
strm->rx.cont_offset = 0;
strm->rx.last_offset = 0;
strm->stream_id = stream_id;
strm->flags = flags;
strm->stream_user_data = stream_user_data;
strm->rx.window = strm->rx.max_offset = strm->rx.unsent_max_offset =
max_rx_offset;
strm->pe.index = NGTCP2_PQ_BAD_INDEX;
strm->mem = mem;
strm->app_error_code = 0;
}
void ngtcp2_strm_free(ngtcp2_strm *strm) {
ngtcp2_ksl_it it;
if (strm == NULL) {
return;
}
if (strm->tx.streamfrq) {
for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
ngtcp2_frame_chain_objalloc_del(ngtcp2_ksl_it_get(&it),
strm->frc_objalloc, strm->mem);
}
ngtcp2_ksl_free(strm->tx.streamfrq);
ngtcp2_mem_free(strm->mem, strm->tx.streamfrq);
}
if (strm->rx.rob) {
ngtcp2_rob_free(strm->rx.rob);
ngtcp2_mem_free(strm->mem, strm->rx.rob);
}
if (strm->tx.acked_offset) {
ngtcp2_gaptr_free(strm->tx.acked_offset);
ngtcp2_mem_free(strm->mem, strm->tx.acked_offset);
}
}
static int strm_rob_init(ngtcp2_strm *strm) {
int rv;
ngtcp2_rob *rob = ngtcp2_mem_malloc(strm->mem, sizeof(*rob));
if (rob == NULL) {
return NGTCP2_ERR_NOMEM;
}
rv = ngtcp2_rob_init(rob, 8 * 1024, strm->mem);
if (rv != 0) {
ngtcp2_mem_free(strm->mem, rob);
return rv;
}
strm->rx.rob = rob;
return 0;
}
uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm) {
if (strm->rx.rob == NULL) {
return strm->rx.cont_offset;
}
return ngtcp2_rob_first_gap_offset(strm->rx.rob);
}
/* strm_rob_heavily_fragmented returns nonzero if the number of gaps
in |rob| exceeds the limit. */
static int strm_rob_heavily_fragmented(ngtcp2_rob *rob) {
return ngtcp2_ksl_len(&rob->gapksl) >= 1000;
}
int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
size_t datalen, uint64_t offset) {
int rv;
if (strm->rx.rob == NULL) {
rv = strm_rob_init(strm);
if (rv != 0) {
return rv;
}
if (strm->rx.cont_offset) {
rv = ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset);
if (rv != 0) {
return rv;
}
}
}
if (strm_rob_heavily_fragmented(strm->rx.rob)) {
return NGTCP2_ERR_INTERNAL;
}
return ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
}
int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
if (strm->rx.rob == NULL) {
strm->rx.cont_offset = offset;
return 0;
}
return ngtcp2_rob_remove_prefix(strm->rx.rob, offset);
}
void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) {
strm->flags |= flags & NGTCP2_STRM_FLAG_SHUT_RDWR;
}
static int strm_streamfrq_init(ngtcp2_strm *strm) {
ngtcp2_ksl *streamfrq = ngtcp2_mem_malloc(strm->mem, sizeof(*streamfrq));
if (streamfrq == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_ksl_init(streamfrq, offset_less, sizeof(uint64_t), strm->mem);
strm->tx.streamfrq = streamfrq;
return 0;
}
int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
int rv;
assert(frc->fr.type == NGTCP2_FRAME_STREAM);
assert(frc->next == NULL);
if (strm->tx.streamfrq == NULL) {
rv = strm_streamfrq_init(strm);
if (rv != 0) {
return rv;
}
}
return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
frc);
}
static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
ngtcp2_frame_chain **pfrc) {
ngtcp2_frame_chain *frc, *nfrc;
ngtcp2_stream *fr, *nfr;
uint64_t offset, end_offset;
size_t idx, end_idx;
uint64_t base_offset, end_base_offset;
ngtcp2_range gap;
ngtcp2_vec *v;
int rv;
ngtcp2_ksl_it it;
*pfrc = NULL;
assert(strm->tx.streamfrq);
assert(ngtcp2_ksl_len(strm->tx.streamfrq));
for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);) {
frc = ngtcp2_ksl_it_get(&it);
fr = &frc->fr.stream;
ngtcp2_ksl_remove_hint(strm->tx.streamfrq, &it, &it, &fr->offset);
idx = 0;
offset = fr->offset;
base_offset = 0;
gap = ngtcp2_strm_get_unacked_range_after(strm, offset);
if (gap.begin < offset) {
gap.begin = offset;
}
for (; idx < fr->datacnt && offset < gap.begin; ++idx) {
v = &fr->data[idx];
if (offset + v->len > gap.begin) {
base_offset = gap.begin - offset;
break;
}
offset += v->len;
}
if (idx == fr->datacnt) {
if (fr->fin) {
if (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) {
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
assert(ngtcp2_ksl_len(strm->tx.streamfrq) == 0);
return 0;
}
fr->offset += ngtcp2_vec_len(fr->data, fr->datacnt);
fr->datacnt = 0;
*pfrc = frc;
return 0;
}
if (fr->offset == 0 && fr->datacnt == 0 && strm->tx.offset == 0 &&
!(strm->flags & NGTCP2_STRM_FLAG_ANY_ACKED)) {
*pfrc = frc;
return 0;
}
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
continue;
}
assert(gap.begin == offset + base_offset);
end_idx = idx;
end_offset = offset;
end_base_offset = 0;
for (; end_idx < fr->datacnt; ++end_idx) {
v = &fr->data[end_idx];
if (end_offset + v->len > gap.end) {
end_base_offset = gap.end - end_offset;
break;
}
end_offset += v->len;
}
if (fr->offset == offset && base_offset == 0 && fr->datacnt == end_idx) {
*pfrc = frc;
return 0;
}
if (fr->datacnt == end_idx) {
memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
assert(fr->data[0].len > base_offset);
fr->offset = offset + base_offset;
fr->datacnt = end_idx - idx;
fr->data[0].base += base_offset;
fr->data[0].len -= (size_t)base_offset;
*pfrc = frc;
return 0;
}
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
&nfrc, fr->datacnt - end_idx, strm->frc_objalloc, strm->mem);
if (rv != 0) {
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
nfr = &nfrc->fr.stream;
memcpy(nfr->data, fr->data + end_idx,
sizeof(nfr->data[0]) * (fr->datacnt - end_idx));
assert(nfr->data[0].len > end_base_offset);
nfr->type = NGTCP2_FRAME_STREAM;
nfr->flags = 0;
nfr->fin = fr->fin;
nfr->stream_id = fr->stream_id;
nfr->offset = end_offset + end_base_offset;
nfr->datacnt = fr->datacnt - end_idx;
nfr->data[0].base += end_base_offset;
nfr->data[0].len -= (size_t)end_base_offset;
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
if (end_base_offset) {
++end_idx;
}
memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
assert(fr->data[0].len > base_offset);
fr->fin = 0;
fr->offset = offset + base_offset;
fr->datacnt = end_idx - idx;
if (end_base_offset) {
assert(fr->data[fr->datacnt - 1].len > end_base_offset);
fr->data[fr->datacnt - 1].len = (size_t)end_base_offset;
}
fr->data[0].base += base_offset;
fr->data[0].len -= (size_t)base_offset;
*pfrc = frc;
return 0;
}
return 0;
}
int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
size_t left) {
ngtcp2_stream *fr, *nfr;
ngtcp2_frame_chain *frc, *nfrc;
int rv;
size_t nmerged;
uint64_t datalen;
ngtcp2_vec a[NGTCP2_MAX_STREAM_DATACNT];
ngtcp2_vec b[NGTCP2_MAX_STREAM_DATACNT];
size_t acnt, bcnt;
uint64_t unacked_offset;
if (strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0) {
*pfrc = NULL;
return 0;
}
rv = strm_streamfrq_unacked_pop(strm, &frc);
if (rv != 0) {
return rv;
}
if (frc == NULL) {
*pfrc = NULL;
return 0;
}
fr = &frc->fr.stream;
datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
if (left == 0) {
/* datalen could be zero if 0 length STREAM has been sent */
if (datalen || ngtcp2_ksl_len(strm->tx.streamfrq) > 1) {
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
*pfrc = NULL;
return 0;
}
}
if (datalen > left) {
ngtcp2_vec_copy(a, fr->data, fr->datacnt);
acnt = fr->datacnt;
bcnt = 0;
ngtcp2_vec_split(a, &acnt, b, &bcnt, left, NGTCP2_MAX_STREAM_DATACNT);
assert(acnt > 0);
assert(bcnt > 0);
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
&nfrc, bcnt, strm->frc_objalloc, strm->mem);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
nfr = &nfrc->fr.stream;
nfr->type = NGTCP2_FRAME_STREAM;
nfr->flags = 0;
nfr->fin = fr->fin;
nfr->stream_id = fr->stream_id;
nfr->offset = fr->offset + left;
nfr->datacnt = bcnt;
ngtcp2_vec_copy(nfr->data, b, bcnt);
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
&nfrc, acnt, strm->frc_objalloc, strm->mem);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
nfr = &nfrc->fr.stream;
*nfr = *fr;
nfr->fin = 0;
nfr->datacnt = acnt;
ngtcp2_vec_copy(nfr->data, a, acnt);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
*pfrc = nfrc;
return 0;
}
left -= (size_t)datalen;
ngtcp2_vec_copy(a, fr->data, fr->datacnt);
acnt = fr->datacnt;
for (; left && ngtcp2_ksl_len(strm->tx.streamfrq);) {
unacked_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
if (unacked_offset != fr->offset + datalen) {
assert(fr->offset + datalen < unacked_offset);
break;
}
rv = strm_streamfrq_unacked_pop(strm, &nfrc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
if (nfrc == NULL) {
break;
}
nfr = &nfrc->fr.stream;
if (nfr->fin && nfr->datacnt == 0) {
fr->fin = 1;
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
break;
}
nmerged = ngtcp2_vec_merge(a, &acnt, nfr->data, &nfr->datacnt, left,
NGTCP2_MAX_STREAM_DATACNT);
if (nmerged == 0) {
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
if (rv != 0) {
assert(ngtcp2_err_is_fatal(rv));
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
break;
}
datalen += nmerged;
left -= nmerged;
if (nfr->datacnt == 0) {
fr->fin = nfr->fin;
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
continue;
}
nfr->offset += nmerged;
rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
if (rv != 0) {
ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
break;
}
if (acnt == fr->datacnt) {
if (acnt > 0) {
fr->data[acnt - 1] = a[acnt - 1];
}
*pfrc = frc;
return 0;
}
assert(acnt > fr->datacnt);
rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
&nfrc, acnt, strm->frc_objalloc, strm->mem);
if (rv != 0) {
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
return rv;
}
nfr = &nfrc->fr.stream;
*nfr = *fr;
nfr->datacnt = acnt;
ngtcp2_vec_copy(nfr->data, a, acnt);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
*pfrc = nfrc;
return 0;
}
uint64_t ngtcp2_strm_streamfrq_unacked_offset(ngtcp2_strm *strm) {
ngtcp2_frame_chain *frc;
ngtcp2_stream *fr;
ngtcp2_range gap;
ngtcp2_ksl_it it;
uint64_t datalen;
assert(strm->tx.streamfrq);
assert(ngtcp2_ksl_len(strm->tx.streamfrq));
for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
frc = ngtcp2_ksl_it_get(&it);
fr = &frc->fr.stream;
gap = ngtcp2_strm_get_unacked_range_after(strm, fr->offset);
datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
if (gap.begin <= fr->offset) {
return fr->offset;
}
if (gap.begin < fr->offset + datalen) {
return gap.begin;
}
if (fr->offset + datalen == gap.begin && fr->fin &&
!(strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED)) {
return fr->offset + datalen;
}
}
return (uint64_t)-1;
}
ngtcp2_frame_chain *ngtcp2_strm_streamfrq_top(ngtcp2_strm *strm) {
ngtcp2_ksl_it it;
assert(strm->tx.streamfrq);
assert(ngtcp2_ksl_len(strm->tx.streamfrq));
it = ngtcp2_ksl_begin(strm->tx.streamfrq);
return ngtcp2_ksl_it_get(&it);
}
int ngtcp2_strm_streamfrq_empty(ngtcp2_strm *strm) {
return strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0;
}
void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm) {
ngtcp2_frame_chain *frc;
ngtcp2_ksl_it it;
if (strm->tx.streamfrq == NULL) {
return;
}
for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
ngtcp2_ksl_it_next(&it)) {
frc = ngtcp2_ksl_it_get(&it);
ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
}
ngtcp2_ksl_clear(strm->tx.streamfrq);
}
int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm) {
return strm->pe.index != NGTCP2_PQ_BAD_INDEX;
}
int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm) {
if (strm->tx.acked_offset == NULL) {
return strm->tx.cont_acked_offset == strm->tx.offset;
}
return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset) ==
strm->tx.offset;
}
int ngtcp2_strm_is_all_tx_data_fin_acked(ngtcp2_strm *strm) {
return (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) &&
ngtcp2_strm_is_all_tx_data_acked(strm);
}
ngtcp2_range ngtcp2_strm_get_unacked_range_after(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_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
}
uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm) {
if (strm->tx.acked_offset == NULL) {
return strm->tx.cont_acked_offset;
}
return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset);
}
static int strm_acked_offset_init(ngtcp2_strm *strm) {
ngtcp2_gaptr *acked_offset =
ngtcp2_mem_malloc(strm->mem, sizeof(*acked_offset));
if (acked_offset == NULL) {
return NGTCP2_ERR_NOMEM;
}
ngtcp2_gaptr_init(acked_offset, strm->mem);
strm->tx.acked_offset = acked_offset;
return 0;
}
int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
int rv;
if (strm->tx.acked_offset == NULL) {
if (strm->tx.cont_acked_offset == offset) {
strm->tx.cont_acked_offset += len;
return 0;
}
rv = strm_acked_offset_init(strm);
if (rv != 0) {
return rv;
}
rv =
ngtcp2_gaptr_push(strm->tx.acked_offset, 0, strm->tx.cont_acked_offset);
if (rv != 0) {
return rv;
}
}
return ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
}
void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,
uint64_t app_error_code) {
if (strm->flags & NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET) {
return;
}
assert(0 == strm->app_error_code);
strm->flags |= NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET;
strm->app_error_code = app_error_code;
}

View file

@ -1,310 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2017 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_STRM_H
#define NGTCP2_STRM_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_rob.h"
#include "ngtcp2_map.h"
#include "ngtcp2_gaptr.h"
#include "ngtcp2_ksl.h"
#include "ngtcp2_pq.h"
typedef struct ngtcp2_frame_chain ngtcp2_frame_chain;
/* NGTCP2_STRM_FLAG_NONE indicates that no flag is set. */
#define NGTCP2_STRM_FLAG_NONE 0x00u
/* NGTCP2_STRM_FLAG_SHUT_RD indicates that further reception of stream
data is not allowed. */
#define NGTCP2_STRM_FLAG_SHUT_RD 0x01u
/* NGTCP2_STRM_FLAG_SHUT_WR indicates that further transmission of
stream data is not allowed. */
#define NGTCP2_STRM_FLAG_SHUT_WR 0x02u
#define NGTCP2_STRM_FLAG_SHUT_RDWR \
(NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_SHUT_WR)
/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is sent from
the local endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_WR is also
set. */
#define NGTCP2_STRM_FLAG_SENT_RST 0x04u
/* NGTCP2_STRM_FLAG_SENT_RST indicates that RST_STREAM is received
from the remote endpoint. In this case, NGTCP2_STRM_FLAG_SHUT_RD
is also set. */
#define NGTCP2_STRM_FLAG_RECV_RST 0x08u
/* NGTCP2_STRM_FLAG_STOP_SENDING indicates that STOP_SENDING is sent
from the local endpoint. */
#define NGTCP2_STRM_FLAG_STOP_SENDING 0x10u
/* NGTCP2_STRM_FLAG_RST_ACKED indicates that the outgoing RST_STREAM
is acknowledged by peer. */
#define NGTCP2_STRM_FLAG_RST_ACKED 0x20u
/* NGTCP2_STRM_FLAG_FIN_ACKED indicates that a STREAM with FIN bit set
is acknowledged by a remote endpoint. */
#define NGTCP2_STRM_FLAG_FIN_ACKED 0x40u
/* NGTCP2_STRM_FLAG_ANY_ACKED indicates that any portion of stream
data, including 0 length segment, is acknowledged. */
#define NGTCP2_STRM_FLAG_ANY_ACKED 0x80u
/* NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET indicates that app_error_code
field is set. This resolves the ambiguity that the initial
app_error_code value 0 might be a proper application error code.
In this case, without this flag, we are unable to distinguish
assigned value from unassigned one. */
#define NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET 0x100u
/* NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED is set when
stream_stop_sending callback is called. */
#define NGTCP2_STRM_FLAG_STREAM_STOP_SENDING_CALLED 0x200u
typedef struct ngtcp2_strm ngtcp2_strm;
struct ngtcp2_strm {
union {
struct {
ngtcp2_pq_entry pe;
uint64_t cycle;
ngtcp2_objalloc *frc_objalloc;
struct {
/* acked_offset tracks acknowledged outgoing data. */
ngtcp2_gaptr *acked_offset;
/* cont_acked_offset is the offset that all data up to this offset
is acknowledged by a remote endpoint. It is used until the
remote endpoint acknowledges data in out-of-order. After that,
acked_offset is used instead. */
uint64_t cont_acked_offset;
/* streamfrq contains STREAM frame for retransmission. The flow
control credits have been paid when they are transmitted first
time. There are no restriction regarding flow control for
retransmission. */
ngtcp2_ksl *streamfrq;
/* offset is the next offset of outgoing data. In other words, it
is the number of bytes sent in this stream without
duplication. */
uint64_t offset;
/* max_tx_offset is the maximum offset that local endpoint can
send for this stream. */
uint64_t max_offset;
/* last_max_stream_data_ts is the timestamp when last
MAX_STREAM_DATA frame is sent. */
ngtcp2_tstamp last_max_stream_data_ts;
/* loss_count is the number of packets that contain STREAM
frame for this stream and are declared to be lost. It may
include the spurious losses. It does not include a packet
whose contents have been reclaimed for PTO and which is
later declared to be lost. Those data are not blocked by
the flow control and will be sent immediately if no other
restrictions are applied. */
size_t loss_count;
/* last_lost_pkt_num is the packet number of the packet that
is counted to loss_count. It is used to avoid to count
multiple STREAM frames in one lost packet. */
int64_t last_lost_pkt_num;
} tx;
struct {
/* rob is the reorder buffer for incoming stream data. The data
received in out of order is buffered and sorted by its offset
in this object. */
ngtcp2_rob *rob;
/* cont_offset is the largest offset of consecutive data. It is
used until the endpoint receives out-of-order data. After
that, rob is used to track the offset and data. */
uint64_t cont_offset;
/* last_offset is the largest offset of stream data received for
this stream. */
uint64_t last_offset;
/* max_offset is the maximum offset that remote endpoint can send
to this stream. */
uint64_t max_offset;
/* unsent_max_offset is the maximum offset that remote endpoint
can send to this stream, and it is not notified to the remote
endpoint. unsent_max_offset >= max_offset must be hold. */
uint64_t unsent_max_offset;
/* window is the stream-level flow control window size. */
uint64_t window;
} rx;
const ngtcp2_mem *mem;
int64_t stream_id;
void *stream_user_data;
/* flags is bit-wise OR of zero or more of NGTCP2_STRM_FLAG_*. */
uint32_t flags;
/* app_error_code is an error code the local endpoint sent in
RESET_STREAM or STOP_SENDING, or received from a remote endpoint
in RESET_STREAM or STOP_SENDING. First application error code is
chosen and when set, NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET flag is
set in flags field. */
uint64_t app_error_code;
};
ngtcp2_opl_entry oplent;
};
};
/*
* ngtcp2_strm_init initializes |strm|.
*/
void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
uint64_t max_rx_offset, uint64_t max_tx_offset,
void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
const ngtcp2_mem *mem);
/*
* ngtcp2_strm_free deallocates memory allocated for |strm|. This
* function does not free the memory pointed by |strm| itself.
*/
void ngtcp2_strm_free(ngtcp2_strm *strm);
/*
* ngtcp2_strm_rx_offset returns the minimum offset of stream data
* which is not received yet.
*/
uint64_t ngtcp2_strm_rx_offset(ngtcp2_strm *strm);
/*
* ngtcp2_strm_recv_reordering handles reordered data.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
size_t datalen, uint64_t offset);
/*
* ngtcp2_strm_update_rx_offset tells that data up to offset bytes are
* received in order.
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset);
/*
* ngtcp2_strm_shutdown shutdowns |strm|. |flags| should be
* NGTCP2_STRM_FLAG_SHUT_RD, and/or NGTCP2_STRM_FLAG_SHUT_WR.
*/
void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags);
/*
* ngtcp2_strm_streamfrq_push pushes |frc| to streamfrq for
* retransmission.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc);
/*
* ngtcp2_strm_streamfrq_pop pops the first ngtcp2_frame_chain and
* assigns it to |*pfrc|. This function splits into or merges several
* ngtcp2_frame_chain objects so that the returned ngtcp2_frame_chain
* has at most |left| data length. If there is no frames to send,
* this function returns 0 and |*pfrc| is NULL.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGTCP2_ERR_NOMEM
* Out of memory
*/
int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
size_t left);
/*
* ngtcp2_strm_streamfrq_unacked_offset returns the smallest offset of
* unacknowledged stream data held in strm->tx.streamfrq.
*/
uint64_t ngtcp2_strm_streamfrq_unacked_offset(ngtcp2_strm *strm);
/*
* ngtcp2_strm_streamfrq_top returns the first ngtcp2_frame_chain.
* The queue must not be empty.
*/
ngtcp2_frame_chain *ngtcp2_strm_streamfrq_top(ngtcp2_strm *strm);
/*
* ngtcp2_strm_streamfrq_empty returns nonzero if streamfrq is empty.
*/
int ngtcp2_strm_streamfrq_empty(ngtcp2_strm *strm);
/*
* ngtcp2_strm_streamfrq_clear removes all frames from streamfrq.
*/
void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm);
/*
* ngtcp2_strm_is_tx_queued returns nonzero if |strm| is queued.
*/
int ngtcp2_strm_is_tx_queued(ngtcp2_strm *strm);
/*
* ngtcp2_strm_is_all_tx_data_acked returns nonzero if all outgoing
* data for |strm| which have sent so far have been acknowledged.
*/
int ngtcp2_strm_is_all_tx_data_acked(ngtcp2_strm *strm);
/*
* ngtcp2_strm_is_all_tx_data_fin_acked behaves like
* ngtcp2_strm_is_all_tx_data_acked, but it also requires that STREAM
* frame with fin bit set is acknowledged.
*/
int ngtcp2_strm_is_all_tx_data_fin_acked(ngtcp2_strm *strm);
/*
* ngtcp2_strm_get_unacked_range_after returns the range that is not
* acknowledged yet and intersects or comes after |offset|.
*/
ngtcp2_range ngtcp2_strm_get_unacked_range_after(ngtcp2_strm *strm,
uint64_t offset);
/*
* ngtcp2_strm_get_acked_offset returns offset, that is the data up to
* this offset have been acknowledged by a remote endpoint. It
* returns 0 if no data is acknowledged.
*/
uint64_t ngtcp2_strm_get_acked_offset(ngtcp2_strm *strm);
/*
* ngtcp2_strm_ack_data tells |strm| that the data [offset,
* offset+len) is acknowledged by a remote endpoint.
*/
int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len);
/*
* ngtcp2_strm_set_app_error_code sets |app_error_code| to |strm| and
* set NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET flag. If the flag is
* already set, this function does nothing.
*/
void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm, uint64_t app_error_code);
#endif /* NGTCP2_STRM_H */

View file

@ -1,71 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_unreachable.h"
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <stdlib.h>
#ifdef WIN32
# include <io.h>
#endif /* WIN32 */
void ngtcp2_unreachable_fail(const char *file, int line, const char *func) {
char *buf;
size_t buflen;
int rv;
#define NGTCP2_UNREACHABLE_TEMPLATE "%s:%d %s: Unreachable.\n"
rv = snprintf(NULL, 0, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func);
if (rv < 0) {
abort();
}
/* here we explicitly use system malloc */
buflen = (size_t)rv + 1;
buf = malloc(buflen);
if (buf == NULL) {
abort();
}
rv = snprintf(buf, buflen, NGTCP2_UNREACHABLE_TEMPLATE, file, line, func);
if (rv < 0) {
abort();
}
#ifndef WIN32
while (write(STDERR_FILENO, buf, (size_t)rv) == -1 && errno == EINTR)
;
#else /* WIN32 */
_write(_fileno(stderr), buf, (unsigned int)rv);
#endif /* WIN32 */
free(buf);
abort();
}

View file

@ -1,46 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2022 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_UNREACHABLE_H
#define NGTCP2_UNREACHABLE_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#define ngtcp2_unreachable() \
ngtcp2_unreachable_fail(__FILE__, __LINE__, __func__)
#ifdef _MSC_VER
__declspec(noreturn)
#endif /* _MSC_VER */
void ngtcp2_unreachable_fail(const char *file, int line, const char *func)
#ifndef _MSC_VER
__attribute__((noreturn))
#endif /* !_MSC_VER */
;
#endif /* NGTCP2_UNREACHABLE_H */

View file

@ -1,243 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ngtcp2_vec.h"
#include <string.h>
#include <assert.h>
#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;
return vec;
}
int ngtcp2_vec_new(ngtcp2_vec **pvec, const uint8_t *data, size_t datalen,
const ngtcp2_mem *mem) {
size_t len;
uint8_t *p;
len = sizeof(ngtcp2_vec) + datalen;
*pvec = ngtcp2_mem_malloc(mem, len);
if (*pvec == NULL) {
return NGTCP2_ERR_NOMEM;
}
p = (uint8_t *)(*pvec) + sizeof(ngtcp2_vec);
(*pvec)->base = p;
(*pvec)->len = datalen;
if (datalen) {
/* p = */ ngtcp2_cpymem(p, data, datalen);
}
return 0;
}
void ngtcp2_vec_del(ngtcp2_vec *vec, const ngtcp2_mem *mem) {
ngtcp2_mem_free(mem, vec);
}
uint64_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n) {
size_t i;
size_t res = 0;
for (i = 0; i < n; ++i) {
res += vec[i].len;
}
return res;
}
int64_t ngtcp2_vec_len_varint(const ngtcp2_vec *vec, size_t n) {
uint64_t res = 0;
size_t len;
size_t i;
for (i = 0; i < n; ++i) {
len = vec[i].len;
if (len > NGTCP2_MAX_VARINT - res) {
return -1;
}
res += len;
}
return (int64_t)res;
}
ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst,
size_t *pdstcnt, size_t left, size_t maxcnt) {
size_t i;
size_t srccnt = *psrccnt;
size_t nmove;
size_t extra = 0;
for (i = 0; i < srccnt; ++i) {
if (left >= src[i].len) {
left -= src[i].len;
continue;
}
if (*pdstcnt && src[srccnt - 1].base + src[srccnt - 1].len == dst[0].base) {
if (*pdstcnt + srccnt - i - 1 > maxcnt) {
return -1;
}
dst[0].len += src[srccnt - 1].len;
dst[0].base = src[srccnt - 1].base;
extra = src[srccnt - 1].len;
--srccnt;
} else if (*pdstcnt + srccnt - i > maxcnt) {
return -1;
}
if (left == 0) {
*psrccnt = i;
} else {
*psrccnt = i + 1;
}
nmove = srccnt - i;
if (nmove) {
memmove(dst + nmove, dst, sizeof(ngtcp2_vec) * (*pdstcnt));
*pdstcnt += nmove;
memcpy(dst, src + i, sizeof(ngtcp2_vec) * nmove);
}
dst[0].len -= left;
dst[0].base += left;
src[i].len = left;
if (nmove == 0) {
extra -= left;
}
return (ngtcp2_ssize)(ngtcp2_vec_len(dst, nmove) + extra);
}
return 0;
}
size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
size_t *psrccnt, size_t left, size_t maxcnt) {
size_t orig_left = left;
size_t i;
ngtcp2_vec *a, *b;
assert(maxcnt);
if (*pdstcnt == 0) {
if (*psrccnt == 0) {
return 0;
}
a = &dst[0];
b = &src[0];
if (left >= b->len) {
*a = *b;
++*pdstcnt;
left -= b->len;
i = 1;
} else {
a->len = left;
a->base = b->base;
b->len -= left;
b->base += left;
return left;
}
} else {
i = 0;
}
for (; left && i < *psrccnt; ++i) {
a = &dst[*pdstcnt - 1];
b = &src[i];
if (left >= b->len) {
if (a->base + a->len == b->base) {
a->len += b->len;
} else if (*pdstcnt == maxcnt) {
break;
} else {
dst[(*pdstcnt)++] = *b;
}
left -= b->len;
continue;
}
if (a->base + a->len == b->base) {
a->len += left;
} else if (*pdstcnt == maxcnt) {
break;
} else {
dst[*pdstcnt].len = left;
dst[*pdstcnt].base = b->base;
++*pdstcnt;
}
b->len -= left;
b->base += left;
left = 0;
break;
}
memmove(src, src + i, sizeof(ngtcp2_vec) * (*psrccnt - i));
*psrccnt -= i;
return orig_left - left;
}
size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
const ngtcp2_vec *src, size_t srccnt,
size_t left) {
size_t i, j;
for (i = 0, j = 0; left > 0 && i < srccnt && j < dstcnt;) {
if (src[i].len == 0) {
++i;
continue;
}
dst[j] = src[i];
if (dst[j].len > left) {
dst[j].len = left;
return j + 1;
}
left -= dst[j].len;
++i;
++j;
}
return j;
}
void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt) {
memcpy(dst, src, sizeof(ngtcp2_vec) * cnt);
}

View file

@ -1,120 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2018 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGTCP2_VEC_H
#define NGTCP2_VEC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
#include "ngtcp2_mem.h"
/*
* ngtcp2_vec_lit is a convenient macro to fill the object pointed by
* |DEST| with the literal string |LIT|.
*/
#define ngtcp2_vec_lit(DEST, LIT) \
((DEST)->base = (uint8_t *)(LIT), (DEST)->len = sizeof(LIT) - 1, (DEST))
/*
* ngtcp2_vec_init initializes |vec| with the given parameters. It
* returns |vec|.
*/
ngtcp2_vec *ngtcp2_vec_init(ngtcp2_vec *vec, const uint8_t *base, size_t len);
/*
* ngtcp2_vec_new allocates and initializes |*pvec| with given |data|
* of length |datalen|. This function allocates memory for |*pvec|
* and the given data with a single allocation, and the contents
* pointed by |data| is copied into the allocated memory space. To
* free the allocated memory, call ngtcp2_vec_del.
*/
int ngtcp2_vec_new(ngtcp2_vec **pvec, const uint8_t *data, size_t datalen,
const ngtcp2_mem *mem);
/*
* ngtcp2_vec_del frees the memory allocated by |vec| which is
* allocated and initialized by ngtcp2_vec_new.
*/
void ngtcp2_vec_del(ngtcp2_vec *vec, const ngtcp2_mem *mem);
/*
* ngtcp2_vec_len returns the sum of length in |vec| of |n| elements.
*/
uint64_t ngtcp2_vec_len(const ngtcp2_vec *vec, size_t n);
/*
* ngtcp2_vec_len_varint is similar to ngtcp2_vec_len, but it returns
* -1 if the sum of the length exceeds NGTCP2_MAX_VARINT.
*/
int64_t ngtcp2_vec_len_varint(const ngtcp2_vec *vec, size_t n);
/*
* ngtcp2_vec_split splits |src| to |dst| so that the sum of the
* length in |src| does not exceed |left| bytes. The |maxcnt| is the
* maximum number of elements which |dst| array can contain. The
* caller must set |*psrccnt| to the number of elements of |src|.
* Similarly, the caller must set |*pdstcnt| to the number of elements
* of |dst|. The split does not necessarily occur at the boundary of
* ngtcp2_vec object. After split has done, this function updates
* |*psrccnt| and |*pdstcnt|. This function returns the number of
* bytes moved from |src| to |dst|. If split cannot be made because
* doing so exceeds |maxcnt|, this function returns -1.
*/
ngtcp2_ssize ngtcp2_vec_split(ngtcp2_vec *src, size_t *psrccnt, ngtcp2_vec *dst,
size_t *pdstcnt, size_t left, size_t maxcnt);
/*
* ngtcp2_vec_merge merges |src| into |dst| by moving at most |left|
* bytes from |src|. The |maxcnt| is the maximum number of elements
* which |dst| array can contain. The caller must set |*pdstcnt| to
* the number of elements of |dst|. Similarly, the caller must set
* |*psrccnt| to the number of elements of |src|. After merge has
* done, this function updates |*psrccnt| and |*pdstcnt|. This
* function returns the number of bytes moved from |src| to |dst|.
*/
size_t ngtcp2_vec_merge(ngtcp2_vec *dst, size_t *pdstcnt, ngtcp2_vec *src,
size_t *psrccnt, size_t left, size_t maxcnt);
/*
* ngtcp2_vec_copy_at_most copies |src| of length |srccnt| to |dst| of
* length |dstcnt|. The total number of bytes which the copied
* ngtcp2_vec refers to is at most |left|. The empty elements in
* |src| are ignored. This function returns the number of elements
* copied.
*/
size_t ngtcp2_vec_copy_at_most(ngtcp2_vec *dst, size_t dstcnt,
const ngtcp2_vec *src, size_t srccnt,
size_t left);
/*
* ngtcp2_vec_copy copies |src| of length |cnt| to |dst|. |dst| must
* have sufficient capacity.
*/
void ngtcp2_vec_copy(ngtcp2_vec *dst, const ngtcp2_vec *src, size_t cnt);
#endif /* NGTCP2_VEC_H */

View file

@ -1,39 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2019 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
static ngtcp2_info version = {NGTCP2_VERSION_AGE, NGTCP2_VERSION_NUM,
NGTCP2_VERSION};
const ngtcp2_info *ngtcp2_version(int least_version) {
if (least_version > NGTCP2_VERSION_NUM) {
return NULL;
}
return &version;
}

View file

@ -1,99 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2021 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Translated to C from the original C++ code
* https://quiche.googlesource.com/quiche/+/5be974e29f7e71a196e726d6e2272676d33ab77d/quic/core/congestion_control/windowed_filter.h
* with the following license:
*
* // Copyright (c) 2016 The Chromium Authors. All rights reserved.
* // Use of this source code is governed by a BSD-style license that can be
* // found in the LICENSE file.
*/
#include "ngtcp2_window_filter.h"
#include <string.h>
void ngtcp2_window_filter_init(ngtcp2_window_filter *wf,
uint64_t window_length) {
wf->window_length = window_length;
memset(wf->estimates, 0, sizeof(wf->estimates));
}
void ngtcp2_window_filter_update(ngtcp2_window_filter *wf, uint64_t new_sample,
uint64_t new_time) {
if (wf->estimates[0].sample == 0 || new_sample > wf->estimates[0].sample ||
new_time - wf->estimates[2].time > wf->window_length) {
ngtcp2_window_filter_reset(wf, new_sample, new_time);
return;
}
if (new_sample > wf->estimates[1].sample) {
wf->estimates[1].sample = new_sample;
wf->estimates[1].time = new_time;
wf->estimates[2] = wf->estimates[1];
} else if (new_sample > wf->estimates[2].sample) {
wf->estimates[2].sample = new_sample;
wf->estimates[2].time = new_time;
}
if (new_time - wf->estimates[0].time > wf->window_length) {
wf->estimates[0] = wf->estimates[1];
wf->estimates[1] = wf->estimates[2];
wf->estimates[2].sample = new_sample;
wf->estimates[2].time = new_time;
if (new_time - wf->estimates[0].time > wf->window_length) {
wf->estimates[0] = wf->estimates[1];
wf->estimates[1] = wf->estimates[2];
}
return;
}
if (wf->estimates[1].sample == wf->estimates[0].sample &&
new_time - wf->estimates[1].time > wf->window_length >> 2) {
wf->estimates[2].sample = new_sample;
wf->estimates[2].time = new_time;
wf->estimates[1] = wf->estimates[2];
return;
}
if (wf->estimates[2].sample == wf->estimates[1].sample &&
new_time - wf->estimates[2].time > wf->window_length >> 1) {
wf->estimates[2].sample = new_sample;
wf->estimates[2].time = new_time;
}
}
void ngtcp2_window_filter_reset(ngtcp2_window_filter *wf, uint64_t new_sample,
uint64_t new_time) {
wf->estimates[0].sample = new_sample;
wf->estimates[0].time = new_time;
wf->estimates[1] = wf->estimates[2] = wf->estimates[0];
}
uint64_t ngtcp2_window_filter_get_best(ngtcp2_window_filter *wf) {
return wf->estimates[0].sample;
}

View file

@ -1,65 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2021 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Translated to C from the original C++ code
* https://quiche.googlesource.com/quiche/+/5be974e29f7e71a196e726d6e2272676d33ab77d/quic/core/congestion_control/windowed_filter.h
* with the following license:
*
* // Copyright (c) 2016 The Chromium Authors. All rights reserved.
* // Use of this source code is governed by a BSD-style license that can be
* // found in the LICENSE file.
*/
#ifndef NGTCP2_WINDOW_FILTER_H
#define NGTCP2_WINDOW_FILTER_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <ngtcp2/ngtcp2.h>
typedef struct ngtcp2_window_filter_sample {
uint64_t sample;
uint64_t time;
} ngtcp2_window_filter_sample;
typedef struct ngtcp2_window_filter {
uint64_t window_length;
ngtcp2_window_filter_sample estimates[3];
} ngtcp2_window_filter;
void ngtcp2_window_filter_init(ngtcp2_window_filter *wf,
uint64_t window_length);
void ngtcp2_window_filter_update(ngtcp2_window_filter *wf, uint64_t new_sample,
uint64_t new_time);
void ngtcp2_window_filter_reset(ngtcp2_window_filter *wf, uint64_t new_sample,
uint64_t new_time);
uint64_t ngtcp2_window_filter_get_best(ngtcp2_window_filter *wf);
#endif /* NGTCP2_WINDOW_FILTER_H */

File diff suppressed because it is too large Load diff

View file

@ -1,51 +0,0 @@
/*
* ngtcp2
*
* Copyright (c) 2016 ngtcp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef VERSION_H
#define VERSION_H
/**
* @macrosection
*
* Library version macros
*/
/**
* @macro
*
* Version number of the ngtcp2 library release.
*/
#define NGTCP2_VERSION "0.13.1"
/**
* @macro
*
* Numerical representation of the version number of the ngtcp2
* library release. This is a 24 bit number with 8 bits for major
* number, 8 bits for minor and 8 bits for patch. Version 1.2.3
* becomes 0x010203.
*/
#define NGTCP2_VERSION_NUM 0x000d01
#endif /* VERSION_H */