mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-02-03 18:49:28 -05:00
test
This commit is contained in:
parent
18aa9aaea4
commit
56187dd5a2
80 changed files with 5 additions and 42928 deletions
|
|
@ -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.])]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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; }
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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,
|
||||
¶ms->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,
|
||||
¶ms->retry_scid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return NGTCP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
|
||||
¶ms->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,
|
||||
¶ms->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 = ¶ms->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 = ¶ms->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,
|
||||
¶ms->retry_scid);
|
||||
}
|
||||
}
|
||||
|
||||
p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
|
||||
¶ms->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(¶ms->retry_scid, 0, sizeof(params->retry_scid));
|
||||
memset(¶ms->initial_scid, 0, sizeof(params->initial_scid));
|
||||
memset(¶ms->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(¶m_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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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 = ¶ms->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 = ¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms, exttype, data, datalen);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mem == NULL) {
|
||||
mem = ngtcp2_mem_default();
|
||||
}
|
||||
|
||||
return transport_params_copy_new(pparams, ¶ms, 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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 = ¶ms->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 = ¶ms->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));
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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; }
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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; }
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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; }
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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 */
|
||||
Loading…
Reference in a new issue