mirror of
https://github.com/nodejs/node.git
synced 2025-04-28 13:40:37 +00:00
deps: add ngtcp2 and nghttp3
Reintroduces the ngtcp2 and nghttp3 dependencies, building those by default if the vendored-in openssl (with QUIC support) is used or the shared openssl defines `OPENSSL_INFO_QUIC`. Upates the version metadata to reflect whether ngtcp2 and nghttp3 are present. ngtcp2 as of2381f7f7b6
nghttp3 as of66ad30f0a8
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/37682 Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
2b710c1413
commit
43f599b534
52
LICENSE
52
LICENSE
@ -1578,3 +1578,55 @@ The externally maintained libraries used by Node.js are:
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- ngtcp2, located at deps/ngtcp2/ngtcp2/, is licensed as follows:
|
||||
"""
|
||||
The MIT License
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
- nghttp3, located at deps/ngtcp2/nghttp3/, is licensed as follows:
|
||||
"""
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 nghttp3 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.
|
||||
"""
|
||||
|
48
configure.py
48
configure.py
@ -284,6 +284,50 @@ shared_optgroup.add_argument('--shared-nghttp2-libpath',
|
||||
dest='shared_nghttp2_libpath',
|
||||
help='a directory to search for the shared nghttp2 DLLs')
|
||||
|
||||
shared_optgroup.add_argument('--shared-nghttp3',
|
||||
action='store_true',
|
||||
dest='shared_nghttp3',
|
||||
default=None,
|
||||
help='link to a shared nghttp3 DLL instead of static linking')
|
||||
|
||||
shared_optgroup.add_argument('--shared-nghttp3-includes',
|
||||
action='store',
|
||||
dest='shared_nghttp3_includes',
|
||||
help='directory containing nghttp3 header files')
|
||||
|
||||
shared_optgroup.add_argument('--shared-nghttp3-libname',
|
||||
action='store',
|
||||
dest='shared_nghttp3_libname',
|
||||
default='nghttp3',
|
||||
help='alternative lib name to link to [default: %(default)s]')
|
||||
|
||||
shared_optgroup.add_argument('--shared-nghttp3-libpath',
|
||||
action='store',
|
||||
dest='shared_nghttp3_libpath',
|
||||
help='a directory to search for the shared nghttp3 DLLs')
|
||||
|
||||
shared_optgroup.add_argument('--shared-ngtcp2',
|
||||
action='store_true',
|
||||
dest='shared_ngtcp2',
|
||||
default=None,
|
||||
help='link to a shared ngtcp2 DLL instead of static linking')
|
||||
|
||||
shared_optgroup.add_argument('--shared-ngtcp2-includes',
|
||||
action='store',
|
||||
dest='shared_ngtcp2_includes',
|
||||
help='directory containing ngtcp2 header files')
|
||||
|
||||
shared_optgroup.add_argument('--shared-ngtcp2-libname',
|
||||
action='store',
|
||||
dest='shared_ngtcp2_libname',
|
||||
default='ngtcp2',
|
||||
help='alternative lib name to link to [default: %(default)s]')
|
||||
|
||||
shared_optgroup.add_argument('--shared-ngtcp2-libpath',
|
||||
action='store',
|
||||
dest='shared_ngtcp2_libpath',
|
||||
help='a directory to search for the shared tcp2 DLLs')
|
||||
|
||||
shared_optgroup.add_argument('--shared-openssl',
|
||||
action='store_true',
|
||||
dest='shared_openssl',
|
||||
@ -1347,6 +1391,8 @@ def configure_openssl(o):
|
||||
variables = o['variables']
|
||||
variables['node_use_openssl'] = b(not options.without_ssl)
|
||||
variables['node_shared_openssl'] = b(options.shared_openssl)
|
||||
variables['node_shared_ngtcp2'] = b(options.shared_ngtcp2)
|
||||
variables['node_shared_nghttp3'] = b(options.shared_nghttp3)
|
||||
variables['openssl_is_fips'] = b(options.openssl_is_fips)
|
||||
variables['openssl_fips'] = ''
|
||||
variables['openssl_quic'] = b(True)
|
||||
@ -1836,6 +1882,8 @@ configure_library('libuv', output)
|
||||
configure_library('brotli', output, pkgname=['libbrotlidec', 'libbrotlienc'])
|
||||
configure_library('cares', output, pkgname='libcares')
|
||||
configure_library('nghttp2', output, pkgname='libnghttp2')
|
||||
configure_library('nghttp3', output, pkgname='libnghttp3')
|
||||
configure_library('ngtcp2', output, pkgname='libngtcp2')
|
||||
configure_v8(output)
|
||||
configure_openssl(output)
|
||||
configure_intl(output)
|
||||
|
8
deps/ngtcp2/.gitignore
vendored
Normal file
8
deps/ngtcp2/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.in
|
||||
*.am
|
||||
*.txt
|
||||
*.pc
|
||||
Makefile
|
||||
*gnutls*
|
||||
ngtcp2/**/.gitignore
|
||||
ngtcp2/**/.deps
|
22
deps/ngtcp2/LICENSE_nghttp3
vendored
Normal file
22
deps/ngtcp2/LICENSE_nghttp3
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2019 nghttp3 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.
|
22
deps/ngtcp2/LICENSE_ngtcp2
vendored
Normal file
22
deps/ngtcp2/LICENSE_ngtcp2
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License
|
||||
|
||||
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.
|
45
deps/ngtcp2/README.md
vendored
Normal file
45
deps/ngtcp2/README.md
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
# ngtcp2 and nghttp3
|
||||
|
||||
The ngtcp2 and nghttp3 dependencies provide the core functionality for
|
||||
QUIC and HTTP/3.
|
||||
|
||||
The sources are pulled from:
|
||||
|
||||
* ngtcp2: https://github.com/ngtcp2/ngtcp2
|
||||
* nghttp3: https://github.com/ngtcp2/nghttp3
|
||||
|
||||
In both the `ngtcp2` and `nghttp3` git repos, the active development occurs
|
||||
in the default branch (currently named `master` in each).
|
||||
|
||||
We only use a subset of the sources for each.
|
||||
|
||||
## Updating
|
||||
|
||||
The `nghttp3` library depends on `ngtcp2`. Both should always be updated
|
||||
together. From `ngtcp2` we only want the contents of the `lib` and `crypto`
|
||||
directories; from `nghttp3` we only want the contents o the `lib`.
|
||||
|
||||
### Updating ngtcp2
|
||||
|
||||
To update ngtcp2:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/ngtcp2/ngtcp2
|
||||
$ cd ngtcp2
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only
|
||||
$ cp -R lib/* ../node/deps/ngtcp2/ngtcp2/lib/
|
||||
$ cp -R crypto/* ../node/deps/ngtcp2/ngtcp2/crypto/
|
||||
```
|
||||
|
||||
### Updating nghttp3
|
||||
|
||||
To update ngtcp2:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/ngtcp2/nghttp3
|
||||
$ cd nghttp3
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only
|
||||
$ cp -R lib/* ../node/deps/ngtcp2/nghttp3/lib/
|
||||
```
|
38
deps/ngtcp2/config.h
vendored
Normal file
38
deps/ngtcp2/config.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/* Edited to match src/node.h. */
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
# define _SSIZE_T_
|
||||
# define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
#else // !_WIN32
|
||||
# include <sys/types.h> // size_t, ssize_t
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <intrin.h>
|
||||
# define __builtin_popcount __popcnt
|
||||
#endif
|
||||
|
||||
/* Define to 1 to enable debug output. */
|
||||
/* #undef DEBUGBUILD */
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
/* #undef HAVE_ARPA_INET_H */
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #undef HAVE_UNISTD_H */
|
2666
deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h
vendored
Normal file
2666
deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
46
deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h
vendored
Normal file
46
deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_VERSION_H
|
||||
#define NGHTTP3_VERSION_H
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* Version number of the nghttp3 library release.
|
||||
*/
|
||||
#define NGHTTP3_VERSION "0.1.0-DEV"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* Numerical representation of the version number of the nghttp3
|
||||
* 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 NGHTTP3_VERSION_NUM 0x000100
|
||||
|
||||
#endif /* NGHTTP3_VERSION_H */
|
90
deps/ngtcp2/nghttp3/lib/nghttp3_buf.c
vendored
Normal file
90
deps/ngtcp2/nghttp3/lib/nghttp3_buf.c
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_buf.h"
|
||||
|
||||
void nghttp3_buf_init(nghttp3_buf *buf) {
|
||||
buf->begin = buf->end = buf->pos = buf->last = NULL;
|
||||
}
|
||||
|
||||
void nghttp3_buf_wrap_init(nghttp3_buf *buf, uint8_t *src, size_t len) {
|
||||
buf->begin = buf->pos = buf->last = src;
|
||||
buf->end = buf->begin + len;
|
||||
}
|
||||
|
||||
void nghttp3_buf_free(nghttp3_buf *buf, const nghttp3_mem *mem) {
|
||||
nghttp3_mem_free(mem, buf->begin);
|
||||
}
|
||||
|
||||
size_t nghttp3_buf_left(const nghttp3_buf *buf) {
|
||||
return (size_t)(buf->end - buf->last);
|
||||
}
|
||||
|
||||
size_t nghttp3_buf_len(const nghttp3_buf *buf) {
|
||||
return (size_t)(buf->last - buf->pos);
|
||||
}
|
||||
|
||||
size_t nghttp3_buf_cap(const nghttp3_buf *buf) {
|
||||
return (size_t)(buf->end - buf->begin);
|
||||
}
|
||||
|
||||
void nghttp3_buf_reset(nghttp3_buf *buf) { buf->pos = buf->last = buf->begin; }
|
||||
|
||||
int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem) {
|
||||
uint8_t *p;
|
||||
nghttp3_ssize pos_offset, last_offset;
|
||||
|
||||
if ((size_t)(buf->end - buf->begin) >= size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos_offset = buf->pos - buf->begin;
|
||||
last_offset = buf->last - buf->begin;
|
||||
|
||||
p = nghttp3_mem_realloc(mem, buf->begin, size);
|
||||
if (p == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
buf->begin = p;
|
||||
buf->end = p + size;
|
||||
buf->pos = p + pos_offset;
|
||||
buf->last = p + last_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_buf_swap(nghttp3_buf *a, nghttp3_buf *b) {
|
||||
nghttp3_buf c = *a;
|
||||
|
||||
*a = *b;
|
||||
*b = c;
|
||||
}
|
||||
|
||||
void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
|
||||
nghttp3_buf_type type) {
|
||||
tbuf->buf = *buf;
|
||||
tbuf->type = type;
|
||||
}
|
74
deps/ngtcp2/nghttp3/lib/nghttp3_buf.h
vendored
Normal file
74
deps/ngtcp2/nghttp3/lib/nghttp3_buf.h
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_BUF_H
|
||||
#define NGHTTP3_BUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
|
||||
void nghttp3_buf_wrap_init(nghttp3_buf *buf, uint8_t *src, size_t len);
|
||||
|
||||
/*
|
||||
* nghttp3_buf_cap returns the capacity of the buffer. In other
|
||||
* words, it returns buf->end - buf->begin.
|
||||
*/
|
||||
size_t nghttp3_buf_cap(const nghttp3_buf *buf);
|
||||
|
||||
int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_buf_swap swaps |a| and |b|.
|
||||
*/
|
||||
void nghttp3_buf_swap(nghttp3_buf *a, nghttp3_buf *b);
|
||||
|
||||
typedef enum nghttp3_buf_type {
|
||||
/* NGHTTP3_BUF_TYPE_PRIVATE indicates that memory is allocated for
|
||||
this buffer only and should be freed after its use. */
|
||||
NGHTTP3_BUF_TYPE_PRIVATE,
|
||||
/* NGHTTP3_BUF_TYPE_SHARED indicates that buffer points to shared
|
||||
memory. */
|
||||
NGHTTP3_BUF_TYPE_SHARED,
|
||||
/* NGHTTP3_BUF_TYPE_ALIEN indicates that the buffer points to a
|
||||
memory which comes from outside of the library. */
|
||||
NGHTTP3_BUF_TYPE_ALIEN,
|
||||
} nghttp3_buf_type;
|
||||
|
||||
typedef struct nghttp3_typed_buf {
|
||||
nghttp3_buf buf;
|
||||
nghttp3_buf_type type;
|
||||
} nghttp3_typed_buf;
|
||||
|
||||
void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
|
||||
nghttp3_buf_type type);
|
||||
|
||||
void nghttp3_typed_buf_free(nghttp3_typed_buf *tbuf);
|
||||
|
||||
#endif /* NGHTTP3_BUF_H */
|
3523
deps/ngtcp2/nghttp3/lib/nghttp3_conn.c
vendored
Normal file
3523
deps/ngtcp2/nghttp3/lib/nghttp3_conn.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
289
deps/ngtcp2/nghttp3/lib/nghttp3_conn.h
vendored
Normal file
289
deps/ngtcp2/nghttp3/lib/nghttp3_conn.h
vendored
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 NGHTTP3_CONN_H
|
||||
#define NGHTTP3_CONN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_stream.h"
|
||||
#include "nghttp3_map.h"
|
||||
#include "nghttp3_qpack.h"
|
||||
#include "nghttp3_tnode.h"
|
||||
#include "nghttp3_idtr.h"
|
||||
#include "nghttp3_gaptr.h"
|
||||
|
||||
#define NGHTTP3_VARINT_MAX ((1ull << 62) - 1)
|
||||
|
||||
/* NGHTTP3_QPACK_ENCODER_MAX_TABLE_CAPACITY is the maximum dynamic
|
||||
table size for QPACK encoder. */
|
||||
#define NGHTTP3_QPACK_ENCODER_MAX_TABLE_CAPACITY 16384
|
||||
|
||||
/* NGHTTP3_QPACK_ENCODER_MAX_BLOCK_STREAMS is the maximum number of
|
||||
blocked streams for QPACK encoder. */
|
||||
#define NGHTTP3_QPACK_ENCODER_MAX_BLOCK_STREAMS 100
|
||||
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_NONE 0x00
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_RECVED is set when PUSH_PROMISE is
|
||||
completely received. */
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_RECVED 0x01
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_RECV_CANCEL is set when push is
|
||||
cancelled by server before receiving PUSH_PROMISE completely.
|
||||
This flag should have no effect if push stream has already
|
||||
opened. */
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_RECV_CANCEL 0x02
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_SENT_CANCEL is set when push is
|
||||
canceled by the local endpoint. */
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_SENT_CANCEL 0x04
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_CANCELLED \
|
||||
(NGHTTP3_PUSH_PROMISE_FLAG_RECV_CANCEL | \
|
||||
NGHTTP3_PUSH_PROMISE_FLAG_SENT_CANCEL)
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_PUSH_ID_RECLAIMED indicates that
|
||||
unsent_max_pushes has been updated for this push ID. */
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_PUSH_ID_RECLAIMED 0x08
|
||||
/* NGHTTP3_PUSH_PROMISE_FLAG_BOUND is set if nghttp3_push_promise
|
||||
object is bound to a stream where PUSH_PROMISE frame is received
|
||||
first. nghttp3_push_promise object might be created before
|
||||
receiving any PUSH_PROMISE when pushed stream is received before
|
||||
it.*/
|
||||
#define NGHTTP3_PUSH_PROMISE_FLAG_BOUND 0x10
|
||||
|
||||
typedef struct nghttp3_push_promise {
|
||||
nghttp3_map_entry me;
|
||||
nghttp3_tnode node;
|
||||
nghttp3_http_state http;
|
||||
/* stream is server initiated unidirectional stream which fulfils
|
||||
the push promise. */
|
||||
nghttp3_stream *stream;
|
||||
/* stream_id is the stream ID where this PUSH_PROMISE is first
|
||||
received. PUSH_PROMISE with same push ID is allowed to be sent
|
||||
in the multiple streams. We ignore those duplicated PUSH_PROMISE
|
||||
entirely because we don't see any value to add extra cost of
|
||||
processing for it. Even ignoring those frame is not yet easy
|
||||
because we have to decode the header blocks. Server push is
|
||||
overly complex and there is no good use case after all. */
|
||||
int64_t stream_id;
|
||||
/* flags is bitwise OR of zero or more of
|
||||
NGHTTP3_PUSH_PROMISE_FLAG_*. */
|
||||
uint16_t flags;
|
||||
} nghttp3_push_promise;
|
||||
|
||||
/* NGHTTP3_CONN_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGHTTP3_CONN_FLAG_NONE 0x0000
|
||||
/* NGHTTP3_CONN_FLAG_SETTINGS_RECVED is set when SETTINGS frame has
|
||||
been received. */
|
||||
#define NGHTTP3_CONN_FLAG_SETTINGS_RECVED 0x0001
|
||||
/* NGHTTP3_CONN_FLAG_CONTROL_OPENED is set when a control stream has
|
||||
opened. */
|
||||
#define NGHTTP3_CONN_FLAG_CONTROL_OPENED 0x0002
|
||||
/* NGHTTP3_CONN_FLAG_QPACK_ENCODER_OPENED is set when a QPACK encoder
|
||||
stream has opened. */
|
||||
#define NGHTTP3_CONN_FLAG_QPACK_ENCODER_OPENED 0x0004
|
||||
/* NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED is set when a QPACK decoder
|
||||
stream has opened. */
|
||||
#define NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED 0x0008
|
||||
/* NGHTTP3_CONN_FLAG_MAX_PUSH_ID_QUEUED indicates that MAX_PUSH_ID has
|
||||
been queued to control stream. */
|
||||
#define NGHTTP3_CONN_FLAG_MAX_PUSH_ID_QUEUED 0x0010
|
||||
/* NGHTTP3_CONN_FLAG_GOAWAY_RECVED indicates that GOAWAY frame has
|
||||
received. */
|
||||
#define NGHTTP3_CONN_FLAG_GOAWAY_RECVED 0x0020
|
||||
/* NGHTTP3_CONN_FLAG_GOAWAY_QUEUED indicates that GOAWAY frame has
|
||||
been submitted for transmission. */
|
||||
#define NGHTTP3_CONN_FLAG_GOAWAY_QUEUED 0x0040
|
||||
|
||||
struct nghttp3_conn {
|
||||
nghttp3_callbacks callbacks;
|
||||
nghttp3_map streams;
|
||||
nghttp3_map pushes;
|
||||
nghttp3_qpack_decoder qdec;
|
||||
nghttp3_qpack_encoder qenc;
|
||||
nghttp3_pq qpack_blocked_streams;
|
||||
struct {
|
||||
nghttp3_pq spq;
|
||||
} sched[NGHTTP3_URGENCY_LEVELS];
|
||||
const nghttp3_mem *mem;
|
||||
void *user_data;
|
||||
int server;
|
||||
uint16_t flags;
|
||||
uint64_t next_seq;
|
||||
|
||||
struct {
|
||||
nghttp3_settings settings;
|
||||
struct {
|
||||
/* max_pushes is the number of push IDs that local endpoint can
|
||||
issue. This field is used by server only. */
|
||||
uint64_t max_pushes;
|
||||
/* next_push_id is the next push ID server uses. This field is
|
||||
used by server only. */
|
||||
int64_t next_push_id;
|
||||
} uni;
|
||||
} local;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
nghttp3_idtr idtr;
|
||||
/* max_client_streams is the cumulative number of client
|
||||
initiated bidirectional stream ID the remote endpoint can
|
||||
issue. This field is used on server side only. */
|
||||
uint64_t max_client_streams;
|
||||
} bidi;
|
||||
struct {
|
||||
/* push_idtr tracks which push ID has been used by remote
|
||||
server. This field is used by client only. */
|
||||
nghttp3_gaptr push_idtr;
|
||||
/* unsent_max_pushes is the maximum number of push which the local
|
||||
endpoint can accept. This limit is not yet notified to the
|
||||
remote endpoint. This field is used by client only. */
|
||||
uint64_t unsent_max_pushes;
|
||||
/* max_push is the maximum number of push which the local
|
||||
endpoint can accept. This field is used by client only. */
|
||||
uint64_t max_pushes;
|
||||
} uni;
|
||||
nghttp3_settings settings;
|
||||
} remote;
|
||||
|
||||
struct {
|
||||
/* goaway_id is the latest ID received in GOAWAY frame. */
|
||||
int64_t goaway_id;
|
||||
|
||||
int64_t max_stream_id_bidi;
|
||||
int64_t max_push_id;
|
||||
} rx;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
nghttp3_buf rbuf;
|
||||
nghttp3_buf ebuf;
|
||||
} qpack;
|
||||
nghttp3_stream *ctrl;
|
||||
nghttp3_stream *qenc;
|
||||
nghttp3_stream *qdec;
|
||||
/* goaway_id is the latest ID sent in GOAWAY frame. */
|
||||
int64_t goaway_id;
|
||||
} tx;
|
||||
};
|
||||
|
||||
nghttp3_stream *nghttp3_conn_find_stream(nghttp3_conn *conn, int64_t stream_id);
|
||||
|
||||
nghttp3_push_promise *nghttp3_conn_find_push_promise(nghttp3_conn *conn,
|
||||
int64_t push_id);
|
||||
|
||||
int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream,
|
||||
int64_t stream_id);
|
||||
|
||||
int nghttp3_conn_create_push_promise(nghttp3_conn *conn,
|
||||
nghttp3_push_promise **ppp,
|
||||
int64_t push_id,
|
||||
nghttp3_tnode *assoc_tnode);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc,
|
||||
nghttp3_stream *stream, const uint8_t *src,
|
||||
size_t srclen, int fin);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
|
||||
const uint8_t *src, size_t srclen, int fin);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
|
||||
nghttp3_stream *stream,
|
||||
const uint8_t *src, size_t srclen);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_push(nghttp3_conn *conn, size_t *pnproc,
|
||||
nghttp3_stream *stream, const uint8_t *src,
|
||||
size_t srclen, int fin);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_qpack_encoder(nghttp3_conn *conn,
|
||||
const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_read_qpack_decoder(nghttp3_conn *conn,
|
||||
const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
int nghttp3_conn_on_push_promise_push_id(nghttp3_conn *conn, int64_t push_id,
|
||||
nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_conn_on_client_cancel_push(nghttp3_conn *conn,
|
||||
const nghttp3_frame_cancel_push *fr);
|
||||
|
||||
int nghttp3_conn_on_server_cancel_push(nghttp3_conn *conn,
|
||||
const nghttp3_frame_cancel_push *fr);
|
||||
|
||||
int nghttp3_conn_on_stream_push_id(nghttp3_conn *conn, nghttp3_stream *stream,
|
||||
int64_t push_id);
|
||||
|
||||
int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream,
|
||||
const uint8_t *data, size_t datalen);
|
||||
|
||||
nghttp3_ssize nghttp3_conn_on_headers(nghttp3_conn *conn,
|
||||
nghttp3_stream *stream,
|
||||
nghttp3_push_promise *pp,
|
||||
const uint8_t *data, size_t datalen,
|
||||
int fin);
|
||||
|
||||
int nghttp3_conn_on_settings_entry_received(nghttp3_conn *conn,
|
||||
const nghttp3_frame_settings *fr);
|
||||
|
||||
int nghttp3_conn_qpack_blocked_streams_push(nghttp3_conn *conn,
|
||||
nghttp3_stream *stream);
|
||||
|
||||
void nghttp3_conn_qpack_blocked_streams_pop(nghttp3_conn *conn);
|
||||
|
||||
int nghttp3_conn_server_cancel_push(nghttp3_conn *conn, int64_t push_id);
|
||||
|
||||
int nghttp3_conn_client_cancel_push(nghttp3_conn *conn, int64_t push_id);
|
||||
|
||||
int nghttp3_conn_submit_max_push_id(nghttp3_conn *conn);
|
||||
|
||||
int nghttp3_conn_schedule_stream(nghttp3_conn *conn, nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_conn_ensure_stream_scheduled(nghttp3_conn *conn,
|
||||
nghttp3_stream *stream);
|
||||
|
||||
void nghttp3_conn_unschedule_stream(nghttp3_conn *conn, nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_conn_reject_stream(nghttp3_conn *conn, nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_conn_reject_push_stream(nghttp3_conn *conn, nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_conn_cancel_push_stream(nghttp3_conn *conn, nghttp3_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_conn_get_next_tx_stream returns next stream to send. It
|
||||
* returns NULL if there is no such stream.
|
||||
*/
|
||||
nghttp3_stream *nghttp3_conn_get_next_tx_stream(nghttp3_conn *conn);
|
||||
|
||||
int nghttp3_push_promise_new(nghttp3_push_promise **ppp, int64_t push_id,
|
||||
uint64_t seq, nghttp3_tnode *assoc_tnode,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
void nghttp3_push_promise_del(nghttp3_push_promise *pp, const nghttp3_mem *mem);
|
||||
|
||||
#endif /* NGHTTP3_CONN_H */
|
134
deps/ngtcp2/nghttp3/lib/nghttp3_conv.c
vendored
Normal file
134
deps/ngtcp2/nghttp3/lib/nghttp3_conv.c
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_conv.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_str.h"
|
||||
|
||||
int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) {
|
||||
union {
|
||||
char b[8];
|
||||
uint16_t n16;
|
||||
uint32_t n32;
|
||||
uint64_t n64;
|
||||
} n;
|
||||
|
||||
*plen = 1u << (*p >> 6);
|
||||
|
||||
switch (*plen) {
|
||||
case 1:
|
||||
return (int64_t)*p;
|
||||
case 2:
|
||||
memcpy(&n, p, 2);
|
||||
n.b[0] &= 0x3f;
|
||||
return (int64_t)ntohs(n.n16);
|
||||
case 4:
|
||||
memcpy(&n, p, 4);
|
||||
n.b[0] &= 0x3f;
|
||||
return (int64_t)ntohl(n.n32);
|
||||
case 8:
|
||||
memcpy(&n, p, 8);
|
||||
n.b[0] &= 0x3f;
|
||||
return (int64_t)nghttp3_ntohl64(n.n64);
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; }
|
||||
|
||||
size_t nghttp3_get_varint_len(const uint8_t *p) { return 1u << (*p >> 6); }
|
||||
|
||||
uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n) {
|
||||
n = nghttp3_htonl64(n);
|
||||
return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n));
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n) {
|
||||
n = nghttp3_htonl64(n);
|
||||
return nghttp3_cpymem(p, ((const uint8_t *)&n) + 2, 6);
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n) {
|
||||
n = htonl(n);
|
||||
return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n));
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_put_uint24be(uint8_t *p, uint32_t n) {
|
||||
n = htonl(n);
|
||||
return nghttp3_cpymem(p, ((const uint8_t *)&n) + 1, 3);
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n) {
|
||||
n = htons(n);
|
||||
return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n));
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n) {
|
||||
uint8_t *rv;
|
||||
if (n < 64) {
|
||||
*p++ = (uint8_t)n;
|
||||
return p;
|
||||
}
|
||||
if (n < 16384) {
|
||||
rv = nghttp3_put_uint16be(p, (uint16_t)n);
|
||||
*p |= 0x40;
|
||||
return rv;
|
||||
}
|
||||
if (n < 1073741824) {
|
||||
rv = nghttp3_put_uint32be(p, (uint32_t)n);
|
||||
*p |= 0x80;
|
||||
return rv;
|
||||
}
|
||||
assert(n < 4611686018427387904LL);
|
||||
rv = nghttp3_put_uint64be(p, (uint64_t)n);
|
||||
*p |= 0xc0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
size_t nghttp3_put_varint_len(int64_t n) {
|
||||
if (n < 64) {
|
||||
return 1;
|
||||
}
|
||||
if (n < 16384) {
|
||||
return 2;
|
||||
}
|
||||
if (n < 1073741824) {
|
||||
return 4;
|
||||
}
|
||||
assert(n < 4611686018427387904LL);
|
||||
return 8;
|
||||
}
|
||||
|
||||
uint64_t nghttp3_ord_stream_id(int64_t stream_id) {
|
||||
return (uint64_t)(stream_id >> 2) + 1;
|
||||
}
|
||||
|
||||
uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri) {
|
||||
return (uint8_t)((uint32_t)pri->inc << 7 | pri->urgency);
|
||||
}
|
221
deps/ngtcp2/nghttp3/lib/nghttp3_conv.h
vendored
Normal file
221
deps/ngtcp2/nghttp3/lib/nghttp3_conv.h
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_CONV_H
|
||||
#define NGHTTP3_CONV_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif /* HAVE_ARPA_INET_H */
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif /* HAVE_NETINET_IN_H */
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
# include <byteswap.h>
|
||||
#endif /* HAVE_BYTESWAP_H */
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif /* HAVE_ENDIAN_H */
|
||||
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
# include <sys/endian.h>
|
||||
#endif /* HAVE_SYS_ENDIAN_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#if defined(HAVE_BSWAP_64) || \
|
||||
(defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0)
|
||||
# define nghttp3_bswap64 bswap_64
|
||||
#else /* !HAVE_BSWAP_64 */
|
||||
# define nghttp3_bswap64(N) \
|
||||
((uint64_t)(ntohl((uint32_t)(N))) << 32 | ntohl((uint32_t)((N) >> 32)))
|
||||
#endif /* !HAVE_BSWAP_64 */
|
||||
|
||||
#if defined(HAVE_BE64TOH) || \
|
||||
(defined(HAVE_DECL_BE64TOH) && HAVE_DECL_BE64TOH > 0)
|
||||
# define nghttp3_ntohl64(N) be64toh(N)
|
||||
# define nghttp3_htonl64(N) htobe64(N)
|
||||
#else /* !HAVE_BE64TOH */
|
||||
# if defined(WORDS_BIGENDIAN)
|
||||
# define nghttp3_ntohl64(N) (N)
|
||||
# define nghttp3_htonl64(N) (N)
|
||||
# else /* !WORDS_BIGENDIAN */
|
||||
# define nghttp3_ntohl64(N) nghttp3_bswap64(N)
|
||||
# define nghttp3_htonl64(N) nghttp3_bswap64(N)
|
||||
# endif /* !WORDS_BIGENDIAN */
|
||||
#endif /* !HAVE_BE64TOH */
|
||||
|
||||
#if defined(WIN32)
|
||||
/* Windows requires ws2_32 library for ntonl family of functions. We
|
||||
define inline functions for those functions so that we don't have
|
||||
dependency on that lib. */
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# define STIN static __inline
|
||||
# else
|
||||
# define STIN static inline
|
||||
# endif
|
||||
|
||||
STIN uint32_t htonl(uint32_t hostlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostlong >> 24;
|
||||
*p++ = (hostlong >> 16) & 0xffu;
|
||||
*p++ = (hostlong >> 8) & 0xffu;
|
||||
*p = hostlong & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t htons(uint16_t hostshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostshort >> 8;
|
||||
*p = hostshort & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint32_t ntohl(uint32_t netlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&netlong;
|
||||
res = *p++ << 24;
|
||||
res += *p++ << 16;
|
||||
res += *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t ntohs(uint16_t netshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&netshort;
|
||||
res = *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
/*
|
||||
* nghttp3_get_varint reads variable-length integer from |p|, and
|
||||
* returns it in host byte order. The number of bytes read is stored
|
||||
* in |*plen|.
|
||||
*/
|
||||
int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p);
|
||||
|
||||
/*
|
||||
* nghttp3_get_varint_fb reads first byte of encoded variable-length
|
||||
* integer from |p|.
|
||||
*/
|
||||
int64_t nghttp3_get_varint_fb(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* nghttp3_get_varint_len returns the required number of bytes to read
|
||||
* variable-length integer starting at |p|.
|
||||
*/
|
||||
size_t nghttp3_get_varint_len(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* nghttp3_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 *nghttp3_put_uint64be(uint8_t *p, uint64_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_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 *nghttp3_put_uint48be(uint8_t *p, uint64_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_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 *nghttp3_put_uint32be(uint8_t *p, uint32_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_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 *nghttp3_put_uint24be(uint8_t *p, uint32_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_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 *nghttp3_put_uint16be(uint8_t *p, uint16_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_put_varint writes |n| in |p| using variable-length integer
|
||||
* encoding. It returns the one beyond of the last written position.
|
||||
*/
|
||||
uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_put_varint_len returns the required number of bytes to
|
||||
* encode |n|.
|
||||
*/
|
||||
size_t nghttp3_put_varint_len(int64_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_ord_stream_id returns the ordinal number of |stream_id|.
|
||||
*/
|
||||
uint64_t nghttp3_ord_stream_id(int64_t stream_id);
|
||||
|
||||
/*
|
||||
* NGHTTP3_PRI_INC_MASK is a bit mask to retrieve incremental bit from
|
||||
* a value produced by nghttp3_pri_to_uint8.
|
||||
*/
|
||||
#define NGHTTP3_PRI_INC_MASK (1 << 7)
|
||||
|
||||
/*
|
||||
* nghttp3_pri_to_uint8 encodes |pri| into uint8_t variable.
|
||||
*/
|
||||
uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri);
|
||||
|
||||
/*
|
||||
* nghttp3_pri_uint8_urgency extracts urgency from |PRI| which is
|
||||
* supposed to be constructed by nghttp3_pri_to_uint8.
|
||||
*/
|
||||
#define nghttp3_pri_uint8_urgency(PRI) \
|
||||
((uint32_t)((PRI) & ~NGHTTP3_PRI_INC_MASK))
|
||||
|
||||
/*
|
||||
* nghttp3_pri_uint8_inc extracts inc from |PRI| which is supposed to
|
||||
* be constructed by nghttp3_pri_to_uint8.
|
||||
*/
|
||||
#define nghttp3_pri_uint8_inc(PRI) (((PRI)&NGHTTP3_PRI_INC_MASK) != 0)
|
||||
|
||||
#endif /* NGHTTP3_CONV_H */
|
61
deps/ngtcp2/nghttp3/lib/nghttp3_debug.c
vendored
Normal file
61
deps/ngtcp2/nghttp3/lib/nghttp3_debug.c
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2016 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 "nghttp3_debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
static void nghttp3_default_debug_vfprintf_callback(const char *fmt,
|
||||
va_list args) {
|
||||
vfprintf(stderr, fmt, args);
|
||||
}
|
||||
|
||||
static nghttp3_debug_vprintf_callback static_debug_vprintf_callback =
|
||||
nghttp3_default_debug_vfprintf_callback;
|
||||
|
||||
void nghttp3_debug_vprintf(const char *format, ...) {
|
||||
if (static_debug_vprintf_callback) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
static_debug_vprintf_callback(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp3_set_debug_vprintf_callback(
|
||||
nghttp3_debug_vprintf_callback debug_vprintf_callback) {
|
||||
static_debug_vprintf_callback = debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#else /* !DEBUGBUILD */
|
||||
|
||||
void nghttp3_set_debug_vprintf_callback(
|
||||
nghttp3_debug_vprintf_callback debug_vprintf_callback) {
|
||||
(void)debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#endif /* !DEBUGBUILD */
|
44
deps/ngtcp2/nghttp3/lib/nghttp3_debug.h
vendored
Normal file
44
deps/ngtcp2/nghttp3/lib/nghttp3_debug.h
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2016 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 NGHTTP3_DEBUG_H
|
||||
#define NGHTTP3_DEBUG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
# define DEBUGF(...) nghttp3_debug_vprintf(__VA_ARGS__)
|
||||
void nghttp3_debug_vprintf(const char *format, ...);
|
||||
#else
|
||||
# define DEBUGF(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* NGHTTP3_DEBUG_H */
|
126
deps/ngtcp2/nghttp3/lib/nghttp3_err.c
vendored
Normal file
126
deps/ngtcp2/nghttp3/lib/nghttp3_err.c
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 "nghttp3_err.h"
|
||||
|
||||
const char *nghttp3_strerror(int liberr) {
|
||||
switch (liberr) {
|
||||
case NGHTTP3_ERR_INVALID_ARGUMENT:
|
||||
return "ERR_INVALID_ARGUMENT";
|
||||
case NGHTTP3_ERR_NOBUF:
|
||||
return "ERR_NOBUF";
|
||||
case NGHTTP3_ERR_INVALID_STATE:
|
||||
return "ERR_INVALID_STATE";
|
||||
case NGHTTP3_ERR_WOULDBLOCK:
|
||||
return "ERR_WOULDBLOCK";
|
||||
case NGHTTP3_ERR_STREAM_IN_USE:
|
||||
return "ERR_STREAM_IN_USE";
|
||||
case NGHTTP3_ERR_PUSH_ID_BLOCKED:
|
||||
return "ERR_PUSH_ID_BLOCKED";
|
||||
case NGHTTP3_ERR_MALFORMED_HTTP_HEADER:
|
||||
return "ERR_MALFORMED_HTTP_HEADER";
|
||||
case NGHTTP3_ERR_REMOVE_HTTP_HEADER:
|
||||
return "ERR_REMOVE_HTTP_HEADER";
|
||||
case NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING:
|
||||
return "ERR_MALFORMED_HTTP_MESSAGING";
|
||||
case NGHTTP3_ERR_QPACK_FATAL:
|
||||
return "ERR_QPACK_FATAL";
|
||||
case NGHTTP3_ERR_QPACK_HEADER_TOO_LARGE:
|
||||
return "ERR_QPACK_HEADER_TOO_LARGE";
|
||||
case NGHTTP3_ERR_IGNORE_STREAM:
|
||||
return "ERR_IGNORE_STREAM";
|
||||
case NGHTTP3_ERR_STREAM_NOT_FOUND:
|
||||
return "ERR_STREAM_NOT_FOUND";
|
||||
case NGHTTP3_ERR_IGNORE_PUSH_PROMISE:
|
||||
return "ERR_IGNORE_PUSH_PROMISE";
|
||||
case NGHTTP3_ERR_CONN_CLOSING:
|
||||
return "ERR_CONN_CLOSING";
|
||||
case NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED:
|
||||
return "ERR_QPACK_DECOMPRESSION_FAILED";
|
||||
case NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR:
|
||||
return "ERR_QPACK_ENCODER_STREAM_ERROR";
|
||||
case NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR:
|
||||
return "ERR_QPACK_DECODER_STREAM_ERROR";
|
||||
case NGHTTP3_ERR_H3_FRAME_UNEXPECTED:
|
||||
return "ERR_H3_FRAME_UNEXPECTED";
|
||||
case NGHTTP3_ERR_H3_FRAME_ERROR:
|
||||
return "ERR_H3_FRAME_ERROR";
|
||||
case NGHTTP3_ERR_H3_MISSING_SETTINGS:
|
||||
return "ERR_H3_MISSING_SETTINGS";
|
||||
case NGHTTP3_ERR_H3_INTERNAL_ERROR:
|
||||
return "ERR_H3_INTERNAL_ERROR";
|
||||
case NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM:
|
||||
return "ERR_CLOSED_CRITICAL_STREAM";
|
||||
case NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR:
|
||||
return "ERR_H3_GENERAL_PROTOCOL_ERROR";
|
||||
case NGHTTP3_ERR_H3_ID_ERROR:
|
||||
return "ERR_H3_ID_ERROR";
|
||||
case NGHTTP3_ERR_H3_SETTINGS_ERROR:
|
||||
return "ERR_H3_SETTINGS_ERROR";
|
||||
case NGHTTP3_ERR_H3_STREAM_CREATION_ERROR:
|
||||
return "ERR_H3_STREAM_CREATION_ERROR";
|
||||
case NGHTTP3_ERR_NOMEM:
|
||||
return "ERR_NOMEM";
|
||||
case NGHTTP3_ERR_CALLBACK_FAILURE:
|
||||
return "ERR_CALLBACK_FAILURE";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t nghttp3_err_infer_quic_app_error_code(int liberr) {
|
||||
switch (liberr) {
|
||||
case 0:
|
||||
return NGHTTP3_H3_NO_ERROR;
|
||||
case NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED:
|
||||
return NGHTTP3_QPACK_DECOMPRESSION_FAILED;
|
||||
case NGHTTP3_ERR_QPACK_ENCODER_STREAM_ERROR:
|
||||
return NGHTTP3_QPACK_ENCODER_STREAM_ERROR;
|
||||
case NGHTTP3_ERR_QPACK_DECODER_STREAM_ERROR:
|
||||
return NGHTTP3_QPACK_DECODER_STREAM_ERROR;
|
||||
case NGHTTP3_ERR_H3_FRAME_UNEXPECTED:
|
||||
return NGHTTP3_H3_FRAME_UNEXPECTED;
|
||||
case NGHTTP3_ERR_H3_FRAME_ERROR:
|
||||
return NGHTTP3_H3_FRAME_ERROR;
|
||||
case NGHTTP3_ERR_H3_MISSING_SETTINGS:
|
||||
return NGHTTP3_H3_MISSING_SETTINGS;
|
||||
case NGHTTP3_ERR_H3_INTERNAL_ERROR:
|
||||
return NGHTTP3_H3_INTERNAL_ERROR;
|
||||
case NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM:
|
||||
return NGHTTP3_H3_CLOSED_CRITICAL_STREAM;
|
||||
case NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR:
|
||||
return NGHTTP3_H3_GENERAL_PROTOCOL_ERROR;
|
||||
case NGHTTP3_ERR_H3_ID_ERROR:
|
||||
return NGHTTP3_H3_ID_ERROR;
|
||||
case NGHTTP3_ERR_H3_SETTINGS_ERROR:
|
||||
return NGHTTP3_H3_SETTINGS_ERROR;
|
||||
case NGHTTP3_ERR_H3_STREAM_CREATION_ERROR:
|
||||
return NGHTTP3_H3_STREAM_CREATION_ERROR;
|
||||
case NGHTTP3_ERR_MALFORMED_HTTP_HEADER:
|
||||
case NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING:
|
||||
return NGHTTP3_H3_MESSAGE_ERROR;
|
||||
default:
|
||||
return NGHTTP3_H3_GENERAL_PROTOCOL_ERROR;
|
||||
}
|
||||
}
|
34
deps/ngtcp2/nghttp3/lib/nghttp3_err.h
vendored
Normal file
34
deps/ngtcp2/nghttp3/lib/nghttp3_err.h
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 NGHTTP3_ERR_H
|
||||
#define NGHTTP3_ERR_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#endif /* NGHTTP3_ERR_H */
|
218
deps/ngtcp2/nghttp3/lib/nghttp3_frame.c
vendored
Normal file
218
deps/ngtcp2/nghttp3/lib/nghttp3_frame.c
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2013 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 "nghttp3_frame.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nghttp3_conv.h"
|
||||
#include "nghttp3_str.h"
|
||||
|
||||
uint8_t *nghttp3_frame_write_hd(uint8_t *p, const nghttp3_frame_hd *hd) {
|
||||
p = nghttp3_put_varint(p, hd->type);
|
||||
p = nghttp3_put_varint(p, hd->length);
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd) {
|
||||
return nghttp3_put_varint_len(hd->type) + nghttp3_put_varint_len(hd->length);
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_frame_write_settings(uint8_t *p,
|
||||
const nghttp3_frame_settings *fr) {
|
||||
size_t i;
|
||||
|
||||
p = nghttp3_frame_write_hd(p, &fr->hd);
|
||||
|
||||
for (i = 0; i < fr->niv; ++i) {
|
||||
p = nghttp3_put_varint(p, (int64_t)fr->iv[i].id);
|
||||
p = nghttp3_put_varint(p, (int64_t)fr->iv[i].value);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t nghttp3_frame_write_settings_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_settings *fr) {
|
||||
size_t payloadlen = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < fr->niv; ++i) {
|
||||
payloadlen += nghttp3_put_varint_len((int64_t)fr->iv[i].id) +
|
||||
nghttp3_put_varint_len((int64_t)fr->iv[i].value);
|
||||
}
|
||||
|
||||
*ppayloadlen = (int64_t)payloadlen;
|
||||
|
||||
return nghttp3_put_varint_len(NGHTTP3_FRAME_SETTINGS) +
|
||||
nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen;
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_frame_write_cancel_push(uint8_t *p,
|
||||
const nghttp3_frame_cancel_push *fr) {
|
||||
p = nghttp3_frame_write_hd(p, &fr->hd);
|
||||
p = nghttp3_put_varint(p, fr->push_id);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp3_frame_write_cancel_push_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_cancel_push *fr) {
|
||||
size_t payloadlen = nghttp3_put_varint_len(fr->push_id);
|
||||
|
||||
*ppayloadlen = (int64_t)payloadlen;
|
||||
|
||||
return nghttp3_put_varint_len(NGHTTP3_FRAME_CANCEL_PUSH) +
|
||||
nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen;
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_frame_write_max_push_id(uint8_t *p,
|
||||
const nghttp3_frame_max_push_id *fr) {
|
||||
p = nghttp3_frame_write_hd(p, &fr->hd);
|
||||
p = nghttp3_put_varint(p, fr->push_id);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp3_frame_write_max_push_id_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_max_push_id *fr) {
|
||||
size_t payloadlen = nghttp3_put_varint_len(fr->push_id);
|
||||
|
||||
*ppayloadlen = (int64_t)payloadlen;
|
||||
|
||||
return nghttp3_put_varint_len(NGHTTP3_FRAME_MAX_PUSH_ID) +
|
||||
nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen;
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_frame_write_goaway(uint8_t *p,
|
||||
const nghttp3_frame_goaway *fr) {
|
||||
p = nghttp3_frame_write_hd(p, &fr->hd);
|
||||
p = nghttp3_put_varint(p, fr->id);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_goaway *fr) {
|
||||
size_t payloadlen = nghttp3_put_varint_len(fr->id);
|
||||
|
||||
*ppayloadlen = (int64_t)payloadlen;
|
||||
|
||||
return nghttp3_put_varint_len(NGHTTP3_FRAME_GOAWAY) +
|
||||
nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen;
|
||||
}
|
||||
|
||||
int nghttp3_nva_copy(nghttp3_nv **pnva, const nghttp3_nv *nva, size_t nvlen,
|
||||
const nghttp3_mem *mem) {
|
||||
size_t i;
|
||||
uint8_t *data = NULL;
|
||||
size_t buflen = 0;
|
||||
nghttp3_nv *p;
|
||||
|
||||
if (nvlen == 0) {
|
||||
*pnva = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
/* + 1 for null-termination */
|
||||
if ((nva[i].flags & NGHTTP3_NV_FLAG_NO_COPY_NAME) == 0) {
|
||||
buflen += nva[i].namelen + 1;
|
||||
}
|
||||
if ((nva[i].flags & NGHTTP3_NV_FLAG_NO_COPY_VALUE) == 0) {
|
||||
buflen += nva[i].valuelen + 1;
|
||||
}
|
||||
}
|
||||
|
||||
buflen += sizeof(nghttp3_nv) * nvlen;
|
||||
|
||||
*pnva = nghttp3_mem_malloc(mem, buflen);
|
||||
|
||||
if (*pnva == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = *pnva;
|
||||
data = (uint8_t *)(*pnva) + sizeof(nghttp3_nv) * nvlen;
|
||||
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
p->flags = nva[i].flags;
|
||||
|
||||
if (nva[i].flags & NGHTTP3_NV_FLAG_NO_COPY_NAME) {
|
||||
p->name = nva[i].name;
|
||||
p->namelen = nva[i].namelen;
|
||||
} else {
|
||||
if (nva[i].namelen) {
|
||||
memcpy(data, nva[i].name, nva[i].namelen);
|
||||
}
|
||||
p->name = data;
|
||||
p->namelen = nva[i].namelen;
|
||||
data[p->namelen] = '\0';
|
||||
nghttp3_downcase(p->name, p->namelen);
|
||||
data += nva[i].namelen + 1;
|
||||
}
|
||||
|
||||
if (nva[i].flags & NGHTTP3_NV_FLAG_NO_COPY_VALUE) {
|
||||
p->value = nva[i].value;
|
||||
p->valuelen = nva[i].valuelen;
|
||||
} else {
|
||||
if (nva[i].valuelen) {
|
||||
memcpy(data, nva[i].value, nva[i].valuelen);
|
||||
}
|
||||
p->value = data;
|
||||
p->valuelen = nva[i].valuelen;
|
||||
data[p->valuelen] = '\0';
|
||||
data += nva[i].valuelen + 1;
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_nva_del(nghttp3_nv *nva, const nghttp3_mem *mem) {
|
||||
nghttp3_mem_free(mem, nva);
|
||||
}
|
||||
|
||||
void nghttp3_frame_headers_free(nghttp3_frame_headers *fr,
|
||||
const nghttp3_mem *mem) {
|
||||
if (fr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp3_nva_del(fr->nva, mem);
|
||||
}
|
||||
|
||||
void nghttp3_frame_push_promise_free(nghttp3_frame_push_promise *fr,
|
||||
const nghttp3_mem *mem) {
|
||||
if (fr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp3_nva_del(fr->nva, mem);
|
||||
}
|
243
deps/ngtcp2/nghttp3/lib/nghttp3_frame.h
vendored
Normal file
243
deps/ngtcp2/nghttp3/lib/nghttp3_frame.h
vendored
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2013 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 NGHTTP3_FRAME_H
|
||||
#define NGHTTP3_FRAME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_buf.h"
|
||||
|
||||
typedef enum nghttp3_frame_type {
|
||||
NGHTTP3_FRAME_DATA = 0x00,
|
||||
NGHTTP3_FRAME_HEADERS = 0x01,
|
||||
NGHTTP3_FRAME_CANCEL_PUSH = 0x03,
|
||||
NGHTTP3_FRAME_SETTINGS = 0x04,
|
||||
NGHTTP3_FRAME_PUSH_PROMISE = 0x05,
|
||||
NGHTTP3_FRAME_GOAWAY = 0x07,
|
||||
NGHTTP3_FRAME_MAX_PUSH_ID = 0x0d,
|
||||
} nghttp3_frame_type;
|
||||
|
||||
typedef enum nghttp3_h2_reserved_type {
|
||||
NGHTTP3_H2_FRAME_PRIORITY = 0x02,
|
||||
NGHTTP3_H2_FRAME_PING = 0x06,
|
||||
NGHTTP3_H2_FRAME_WINDOW_UPDATE = 0x08,
|
||||
NGHTTP3_H2_FRAME_CONTINUATION = 0x9,
|
||||
} nghttp3_h2_reserved_type;
|
||||
|
||||
typedef struct nghttp3_frame_hd {
|
||||
int64_t type;
|
||||
int64_t length;
|
||||
} nghttp3_frame_hd;
|
||||
|
||||
typedef struct nghttp3_frame_data {
|
||||
nghttp3_frame_hd hd;
|
||||
} nghttp3_frame_data;
|
||||
|
||||
typedef struct nghttp3_frame_headers {
|
||||
nghttp3_frame_hd hd;
|
||||
nghttp3_nv *nva;
|
||||
size_t nvlen;
|
||||
} nghttp3_frame_headers;
|
||||
|
||||
typedef struct nghttp3_frame_cancel_push {
|
||||
nghttp3_frame_hd hd;
|
||||
int64_t push_id;
|
||||
} nghttp3_frame_cancel_push;
|
||||
|
||||
#define NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE 0x06
|
||||
#define NGHTTP3_SETTINGS_ID_QPACK_MAX_TABLE_CAPACITY 0x01
|
||||
#define NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS 0x07
|
||||
|
||||
#define NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH 0x2
|
||||
#define NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS 0x3
|
||||
#define NGHTTP3_H2_SETTINGS_ID_INITIAL_WINDOW_SIZE 0x4
|
||||
#define NGHTTP3_H2_SETTINGS_ID_MAX_FRAME_SIZE 0x5
|
||||
|
||||
typedef struct nghttp3_settings_entry {
|
||||
uint64_t id;
|
||||
uint64_t value;
|
||||
} nghttp3_settings_entry;
|
||||
|
||||
typedef struct nghttp3_frame_settings {
|
||||
nghttp3_frame_hd hd;
|
||||
size_t niv;
|
||||
nghttp3_settings_entry iv[1];
|
||||
} nghttp3_frame_settings;
|
||||
|
||||
typedef struct nghttp3_frame_push_promise {
|
||||
nghttp3_frame_hd hd;
|
||||
nghttp3_nv *nva;
|
||||
size_t nvlen;
|
||||
int64_t push_id;
|
||||
} nghttp3_frame_push_promise;
|
||||
|
||||
typedef struct nghttp3_frame_goaway {
|
||||
nghttp3_frame_hd hd;
|
||||
int64_t id;
|
||||
} nghttp3_frame_goaway;
|
||||
|
||||
typedef struct nghttp3_frame_max_push_id {
|
||||
nghttp3_frame_hd hd;
|
||||
int64_t push_id;
|
||||
} nghttp3_frame_max_push_id;
|
||||
|
||||
typedef union nghttp3_frame {
|
||||
nghttp3_frame_hd hd;
|
||||
nghttp3_frame_data data;
|
||||
nghttp3_frame_headers headers;
|
||||
nghttp3_frame_cancel_push cancel_push;
|
||||
nghttp3_frame_settings settings;
|
||||
nghttp3_frame_push_promise push_promise;
|
||||
nghttp3_frame_goaway goaway;
|
||||
nghttp3_frame_max_push_id max_push_id;
|
||||
} nghttp3_frame;
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_hd writes frame header |hd| to |dest|. This
|
||||
* function assumes that |dest| has enough space to write |hd|.
|
||||
*
|
||||
* This function returns |dest| plus the number of bytes written.
|
||||
*/
|
||||
uint8_t *nghttp3_frame_write_hd(uint8_t *dest, const nghttp3_frame_hd *hd);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_hd_len returns the number of bytes required to
|
||||
* write |hd|. hd->length must be set.
|
||||
*/
|
||||
size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_settings writes SETTINGS frame |fr| to |dest|.
|
||||
* This function assumes that |dest| has enough space to write |fr|.
|
||||
*
|
||||
* This function returns |dest| plus the number of bytes written.
|
||||
*/
|
||||
uint8_t *nghttp3_frame_write_settings(uint8_t *dest,
|
||||
const nghttp3_frame_settings *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_settings_len returns the number of bytes
|
||||
* required to write |fr|. fr->hd.length is ignored. This function
|
||||
* stores payload length in |*ppayloadlen|.
|
||||
*/
|
||||
size_t nghttp3_frame_write_settings_len(int64_t *pppayloadlen,
|
||||
const nghttp3_frame_settings *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_cancel_push writes CANCEL_PUSH frame |fr| to
|
||||
* |dest|. This function assumes that |dest| has enough space to
|
||||
* write |fr|.
|
||||
*
|
||||
* This function returns |dest| plus the number of bytes written.
|
||||
*/
|
||||
uint8_t *nghttp3_frame_write_cancel_push(uint8_t *dest,
|
||||
const nghttp3_frame_cancel_push *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_cancel_push_len returns the number of bytes
|
||||
* required to write |fr|. fr->hd.length is ignored. This function
|
||||
* stores payload length in |*ppayloadlen|.
|
||||
*/
|
||||
size_t nghttp3_frame_write_cancel_push_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_cancel_push *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_max_push_id writes MAX_PUSH_ID frame |fr| to
|
||||
* |dest|. This function assumes that |dest| has enough space to
|
||||
* write |fr|.
|
||||
*
|
||||
* This function returns |dest| plus the number of bytes written.
|
||||
*/
|
||||
uint8_t *nghttp3_frame_write_max_push_id(uint8_t *dest,
|
||||
const nghttp3_frame_max_push_id *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_max_push_id_len returns the number of bytes
|
||||
* required to write |fr|. fr->hd.length is ignored. This function
|
||||
* stores payload length in |*ppayloadlen|.
|
||||
*/
|
||||
size_t nghttp3_frame_write_max_push_id_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_max_push_id *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_goaway writes GOAWAY frame |fr| to |dest|.
|
||||
* This function assumes that |dest| has enough space to write |fr|.
|
||||
*
|
||||
* This function returns |dest| plus the number of bytes written.
|
||||
*/
|
||||
uint8_t *nghttp3_frame_write_goaway(uint8_t *dest,
|
||||
const nghttp3_frame_goaway *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_write_goaway_len returns the number of bytes required
|
||||
* to write |fr|. fr->hd.length is ignored. This function stores
|
||||
* payload length in |*ppayloadlen|.
|
||||
*/
|
||||
size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen,
|
||||
const nghttp3_frame_goaway *fr);
|
||||
|
||||
/*
|
||||
* nghttp3_nva_copy copies name/value pairs from |nva|, which contains
|
||||
* |nvlen| pairs, to |*nva_ptr|, which is dynamically allocated so
|
||||
* that all items can be stored. The resultant name and value in
|
||||
* nghttp2_nv are guaranteed to be NULL-terminated even if the input
|
||||
* is not null-terminated.
|
||||
*
|
||||
* The |*pnva| must be freed using nghttp3_nva_del().
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_nva_copy(nghttp3_nv **pnva, const nghttp3_nv *nva, size_t nvlen,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_nva_del frees |nva|.
|
||||
*/
|
||||
void nghttp3_nva_del(nghttp3_nv *nva, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_headers_free frees memory allocated for |fr|. It
|
||||
* assumes that fr->nva is created by nghttp3_nva_copy() or NULL.
|
||||
*/
|
||||
void nghttp3_frame_headers_free(nghttp3_frame_headers *fr,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_frame_push_promise_free frees memory allocated for |fr|.
|
||||
* It assumes that fr->nva is created by nghttp3_nva_copy() or NULL.
|
||||
*/
|
||||
void nghttp3_frame_push_promise_free(nghttp3_frame_push_promise *fr,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
#endif /* NGHTTP3_FRAME_H */
|
130
deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c
vendored
Normal file
130
deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_gaptr.h"
|
||||
#include "nghttp3_range.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int nghttp3_gaptr_init(nghttp3_gaptr *gaptr, const nghttp3_mem *mem) {
|
||||
int rv;
|
||||
nghttp3_range range = {0, UINT64_MAX};
|
||||
|
||||
rv = nghttp3_ksl_init(&gaptr->gap, nghttp3_ksl_range_compar,
|
||||
sizeof(nghttp3_range), mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = nghttp3_ksl_insert(&gaptr->gap, NULL, &range, NULL);
|
||||
if (rv != 0) {
|
||||
nghttp3_ksl_free(&gaptr->gap);
|
||||
return rv;
|
||||
}
|
||||
|
||||
gaptr->mem = mem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_gaptr_free(nghttp3_gaptr *gaptr) {
|
||||
if (gaptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp3_ksl_free(&gaptr->gap);
|
||||
}
|
||||
|
||||
int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset, size_t datalen) {
|
||||
int rv;
|
||||
nghttp3_range k, m, l, r, q = {offset, offset + datalen};
|
||||
nghttp3_ksl_it it;
|
||||
|
||||
it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q,
|
||||
nghttp3_ksl_range_exclusive_compar);
|
||||
|
||||
for (; !nghttp3_ksl_it_end(&it);) {
|
||||
k = *(nghttp3_range *)nghttp3_ksl_it_key(&it);
|
||||
m = nghttp3_range_intersect(&q, &k);
|
||||
if (!nghttp3_range_len(&m)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (nghttp3_range_eq(&k, &m)) {
|
||||
nghttp3_ksl_remove(&gaptr->gap, &it, &k);
|
||||
continue;
|
||||
}
|
||||
nghttp3_range_cut(&l, &r, &k, &m);
|
||||
if (nghttp3_range_len(&l)) {
|
||||
nghttp3_ksl_update_key(&gaptr->gap, &k, &l);
|
||||
|
||||
if (nghttp3_range_len(&r)) {
|
||||
rv = nghttp3_ksl_insert(&gaptr->gap, &it, &r, NULL);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
} else if (nghttp3_range_len(&r)) {
|
||||
nghttp3_ksl_update_key(&gaptr->gap, &k, &r);
|
||||
}
|
||||
nghttp3_ksl_it_next(&it);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t nghttp3_gaptr_first_gap_offset(nghttp3_gaptr *gaptr) {
|
||||
nghttp3_ksl_it it = nghttp3_ksl_begin(&gaptr->gap);
|
||||
nghttp3_range r = *(nghttp3_range *)nghttp3_ksl_it_key(&it);
|
||||
return r.begin;
|
||||
}
|
||||
|
||||
nghttp3_ksl_it nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr,
|
||||
uint64_t offset) {
|
||||
nghttp3_range q = {offset, offset + 1};
|
||||
return nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q,
|
||||
nghttp3_ksl_range_exclusive_compar);
|
||||
}
|
||||
|
||||
int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset,
|
||||
size_t datalen) {
|
||||
nghttp3_range q = {offset, offset + datalen};
|
||||
nghttp3_ksl_it it = nghttp3_ksl_lower_bound_compar(
|
||||
&gaptr->gap, &q, nghttp3_ksl_range_exclusive_compar);
|
||||
nghttp3_range k = *(nghttp3_range *)nghttp3_ksl_it_key(&it);
|
||||
nghttp3_range m = nghttp3_range_intersect(&q, &k);
|
||||
return nghttp3_range_len(&m) == 0;
|
||||
}
|
||||
|
||||
void nghttp3_gaptr_drop_first_gap(nghttp3_gaptr *gaptr) {
|
||||
nghttp3_ksl_it it = nghttp3_ksl_begin(&gaptr->gap);
|
||||
nghttp3_range r;
|
||||
|
||||
assert(!nghttp3_ksl_it_end(&it));
|
||||
|
||||
r = *(nghttp3_range *)nghttp3_ksl_it_key(&it);
|
||||
|
||||
nghttp3_ksl_remove(&gaptr->gap, NULL, &r);
|
||||
}
|
104
deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.h
vendored
Normal file
104
deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.h
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_GAPTR_H
|
||||
#define NGHTTP3_GAPTR_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
#include "nghttp3_ksl.h"
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr maintains the gap in the range [0, UINT64_MAX).
|
||||
*/
|
||||
typedef struct nghttp3_gaptr {
|
||||
/* gap maintains the range of offset which is not received
|
||||
yet. Initially, its range is [0, UINT64_MAX). */
|
||||
nghttp3_ksl gap;
|
||||
/* mem is custom memory allocator */
|
||||
const nghttp3_mem *mem;
|
||||
} nghttp3_gaptr;
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr_init initializes |gaptr|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_gaptr_init(nghttp3_gaptr *gaptr, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr_free frees resources allocated for |gaptr|.
|
||||
*/
|
||||
void nghttp3_gaptr_free(nghttp3_gaptr *gaptr);
|
||||
|
||||
/*
|
||||
* nghttp3_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:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset, size_t datalen);
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr_first_gap_offset returns the offset to the first gap.
|
||||
* If there is no gap, it returns UINT64_MAX.
|
||||
*/
|
||||
uint64_t nghttp3_gaptr_first_gap_offset(nghttp3_gaptr *gaptr);
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr_get_first_gap_after returns the iterator pointing to
|
||||
* the first gap which overlaps or comes after |offset|.
|
||||
*/
|
||||
nghttp3_ksl_it nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr,
|
||||
uint64_t offset);
|
||||
|
||||
/*
|
||||
* nghttp3_gaptr_is_pushed returns nonzero if range [offset, offset +
|
||||
* datalen) is completely pushed into this object.
|
||||
*/
|
||||
int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset,
|
||||
size_t datalen);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_gaptr_drop_first_gap(nghttp3_gaptr *gaptr);
|
||||
|
||||
#endif /* NGHTTP3_GAPTR_H */
|
844
deps/ngtcp2/nghttp3/lib/nghttp3_http.c
vendored
Normal file
844
deps/ngtcp2/nghttp3/lib/nghttp3_http.c
vendored
Normal file
@ -0,0 +1,844 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2015 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 "nghttp3_http.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_stream.h"
|
||||
#include "nghttp3_macro.h"
|
||||
#include "nghttp3_conv.h"
|
||||
|
||||
static uint8_t downcase(uint8_t c) {
|
||||
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
||||
}
|
||||
|
||||
static int memieq(const void *a, const void *b, size_t n) {
|
||||
size_t i;
|
||||
const uint8_t *aa = a, *bb = b;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (downcase(aa[i]) != downcase(bb[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||
|
||||
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
int64_t n = 0;
|
||||
size_t i;
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if ('0' <= s[i] && s[i] <= '9') {
|
||||
if (n > INT64_MAX / 10) {
|
||||
return -1;
|
||||
}
|
||||
n *= 10;
|
||||
if (n > INT64_MAX - (s[i] - '0')) {
|
||||
return -1;
|
||||
}
|
||||
n += s[i] - '0';
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int lws(const uint8_t *s, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] != ' ' && s[i] != '\t') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_pseudo_header(nghttp3_http_state *http,
|
||||
const nghttp3_qpack_nv *nv, int flag) {
|
||||
if (http->flags & flag) {
|
||||
return 0;
|
||||
}
|
||||
if (lws(nv->value->base, nv->value->len)) {
|
||||
return 0;
|
||||
}
|
||||
http->flags = (uint16_t)(http->flags | flag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int expect_response_body(nghttp3_http_state *http) {
|
||||
return (http->flags & NGHTTP3_HTTP_FLAG_METH_HEAD) == 0 &&
|
||||
http->status_code / 100 != 1 && http->status_code != 304 &&
|
||||
http->status_code != 204;
|
||||
}
|
||||
|
||||
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
|
||||
header field to represent system-wide OPTIONS request. Otherwise,
|
||||
:path header field value must start with "/". This function must
|
||||
be called after ":method" header field was received. This function
|
||||
returns nonzero if path is valid.*/
|
||||
static int check_path(nghttp3_http_state *http) {
|
||||
return (http->flags & NGHTTP3_HTTP_FLAG_SCHEME_HTTP) == 0 ||
|
||||
((http->flags & NGHTTP3_HTTP_FLAG_PATH_REGULAR) ||
|
||||
((http->flags & NGHTTP3_HTTP_FLAG_METH_OPTIONS) &&
|
||||
(http->flags & NGHTTP3_HTTP_FLAG_PATH_ASTERISK)));
|
||||
}
|
||||
|
||||
int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value,
|
||||
size_t len) {
|
||||
nghttp3_pri pri = *dest;
|
||||
const uint8_t *p = value, *end = value + len;
|
||||
|
||||
for (;;) {
|
||||
for (; p != end && (*p == ' ' || *p == '\t'); ++p)
|
||||
;
|
||||
|
||||
if (p == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'u':
|
||||
++p;
|
||||
|
||||
if (p + 2 > end || *p++ != '=') {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!('0' <= *p && *p <= '7')) {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
pri.urgency = (uint32_t)(*p++ - '0');
|
||||
|
||||
if (p == end) {
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (*p++ != ',') {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'i':
|
||||
++p;
|
||||
|
||||
if (p == end) {
|
||||
pri.inc = 1;
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (*p == ',') {
|
||||
pri.inc = 1;
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
|
||||
if (p + 3 > end || *p != '=' || *(p + 1) != '?' ||
|
||||
(*(p + 2) != '0' && *(p + 2) != '1')) {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
pri.inc = *(p + 2) == '1';
|
||||
|
||||
p += 3;
|
||||
|
||||
if (p == end) {
|
||||
goto fin;
|
||||
}
|
||||
|
||||
if (*p++ != ',') {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (p == end) {
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
fin:
|
||||
|
||||
*dest = pri;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_request_on_header(nghttp3_http_state *http, int64_t frame_type,
|
||||
nghttp3_qpack_nv *nv, int trailers,
|
||||
int connect_protocol) {
|
||||
nghttp3_pri pri;
|
||||
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailers ||
|
||||
(http->flags & NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP3_QPACK_TOKEN__AUTHORITY:
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__AUTHORITY)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN__METHOD:
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__METHOD)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
switch (nv->value->len) {
|
||||
case 4:
|
||||
if (lstreq("HEAD", nv->value->base, nv->value->len)) {
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_METH_HEAD;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch (nv->value->base[6]) {
|
||||
case 'T':
|
||||
if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
|
||||
if (frame_type == NGHTTP3_FRAME_PUSH_PROMISE) {
|
||||
/* we won't allow CONNECT for push */
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_METH_CONNECT;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_METH_OPTIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN__PATH:
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__PATH)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->base[0] == '/') {
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_PATH_REGULAR;
|
||||
} else if (nv->value->len == 1 && nv->value->base[0] == '*') {
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_PATH_ASTERISK;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN__SCHEME:
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__SCHEME)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
|
||||
(nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_SCHEME_HTTP;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN__PROTOCOL:
|
||||
if (!connect_protocol) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__PROTOCOL)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN_HOST:
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG_HOST)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH: {
|
||||
/* https://tools.ietf.org/html/rfc7230#section-4.1.2: A sender
|
||||
MUST NOT generate a trailer that contains a field necessary for
|
||||
message framing (e.g., Transfer-Encoding and Content-Length),
|
||||
... */
|
||||
if (trailers) {
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (http->content_length != -1) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (http->content_length == -1) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP3_QPACK_TOKEN_CONNECTION:
|
||||
case NGHTTP3_QPACK_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP3_QPACK_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP3_QPACK_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP3_QPACK_TOKEN_UPGRADE:
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
case NGHTTP3_QPACK_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP3_QPACK_TOKEN_PRIORITY:
|
||||
pri.urgency = nghttp3_pri_uint8_urgency(http->pri);
|
||||
pri.inc = nghttp3_pri_uint8_inc(http->pri);
|
||||
if (nghttp3_http_parse_priority(&pri, nv->value->base, nv->value->len) ==
|
||||
0) {
|
||||
http->pri = nghttp3_pri_to_uint8(&pri);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_response_on_header(nghttp3_http_state *http,
|
||||
nghttp3_qpack_nv *nv, int trailers) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailers ||
|
||||
(http->flags & NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP3_QPACK_TOKEN__STATUS: {
|
||||
if (!check_pseudo_header(http, nv, NGHTTP3_HTTP_FLAG__STATUS)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->len != 3) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
|
||||
if (http->status_code < 100 || http->status_code == 101) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH: {
|
||||
/* https://tools.ietf.org/html/rfc7230#section-4.1.2: A sender
|
||||
MUST NOT generate a trailer that contains a field necessary for
|
||||
message framing (e.g., Transfer-Encoding and Content-Length),
|
||||
... */
|
||||
if (trailers) {
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (http->status_code == 204) {
|
||||
/* content-length header field in 204 response is prohibited by
|
||||
RFC 7230. But some widely used servers send content-length:
|
||||
0. Until they get fixed, we ignore it. */
|
||||
if (http->content_length != -1) {
|
||||
/* Found multiple content-length field */
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if (!lstrieq("0", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->content_length = 0;
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (http->status_code / 100 == 1) {
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
/* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
|
||||
if (http->status_code / 100 == 2 &&
|
||||
(http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT)) {
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (http->content_length != -1) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (http->content_length == -1) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP3_QPACK_TOKEN_CONNECTION:
|
||||
case NGHTTP3_QPACK_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP3_QPACK_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP3_QPACK_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP3_QPACK_TOKEN_UPGRADE:
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
case NGHTTP3_QPACK_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generated by genauthroitychartbl.py */
|
||||
static char VALID_AUTHORITY_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
|
||||
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
static int check_authority(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_AUTHORITY_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_scheme(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
last = value + len;
|
||||
++value;
|
||||
|
||||
for (; value != last; ++value) {
|
||||
if (!(('A' <= *value && *value <= 'Z') ||
|
||||
('a' <= *value && *value <= 'z') ||
|
||||
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
|
||||
*value == '.')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nghttp3_http_on_header(nghttp3_http_state *http, int64_t frame_type,
|
||||
nghttp3_qpack_nv *nv, int request, int trailers) {
|
||||
int rv;
|
||||
size_t i;
|
||||
uint8_t c;
|
||||
|
||||
if (!nghttp3_check_header_name(nv->name->base, nv->name->len)) {
|
||||
if (nv->name->len > 0 && nv->name->base[0] == ':') {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
/* header field name must be lower-cased without exception */
|
||||
for (i = 0; i < nv->name->len; ++i) {
|
||||
c = nv->name->base[i];
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
/* When ignoring regular header fields, we set this flag so that
|
||||
we still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
|
||||
assert(nv->name->len > 0);
|
||||
|
||||
if (nv->token == NGHTTP3_QPACK_TOKEN__AUTHORITY ||
|
||||
nv->token == NGHTTP3_QPACK_TOKEN_HOST) {
|
||||
rv = check_authority(nv->value->base, nv->value->len);
|
||||
} else if (nv->token == NGHTTP3_QPACK_TOKEN__SCHEME) {
|
||||
rv = check_scheme(nv->value->base, nv->value->len);
|
||||
} else {
|
||||
rv = nghttp3_check_header_value(nv->value->base, nv->value->len);
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
/* When ignoring regular header fields, we set this flag so that
|
||||
we still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (request) {
|
||||
rv = http_request_on_header(http, frame_type, nv, trailers,
|
||||
/* connect_protocol = */ 0);
|
||||
} else {
|
||||
rv = http_response_on_header(http, nv, trailers);
|
||||
}
|
||||
|
||||
if (nv->name->base[0] != ':') {
|
||||
switch (rv) {
|
||||
case 0:
|
||||
case NGHTTP3_ERR_REMOVE_HTTP_HEADER:
|
||||
http->flags |= NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp3_http_on_request_headers(nghttp3_http_state *http) {
|
||||
if (!(http->flags & NGHTTP3_HTTP_FLAG__PROTOCOL) &&
|
||||
(http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT)) {
|
||||
if ((http->flags & (NGHTTP3_HTTP_FLAG__SCHEME | NGHTTP3_HTTP_FLAG__PATH)) ||
|
||||
(http->flags & NGHTTP3_HTTP_FLAG__AUTHORITY) == 0) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
http->content_length = -1;
|
||||
} else {
|
||||
if ((http->flags & NGHTTP3_HTTP_FLAG_REQ_HEADERS) !=
|
||||
NGHTTP3_HTTP_FLAG_REQ_HEADERS ||
|
||||
(http->flags &
|
||||
(NGHTTP3_HTTP_FLAG__AUTHORITY | NGHTTP3_HTTP_FLAG_HOST)) == 0) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if ((http->flags & NGHTTP3_HTTP_FLAG__PROTOCOL) &&
|
||||
((http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) == 0 ||
|
||||
(http->flags & NGHTTP3_HTTP_FLAG__AUTHORITY) == 0)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
if (!check_path(http)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp3_http_on_response_headers(nghttp3_http_state *http) {
|
||||
if ((http->flags & NGHTTP3_HTTP_FLAG__STATUS) == 0) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (http->status_code / 100 == 1) {
|
||||
/* non-final response */
|
||||
http->flags = (uint16_t)((http->flags & NGHTTP3_HTTP_FLAG_METH_ALL) |
|
||||
NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
http->content_length = -1;
|
||||
http->status_code = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
http->flags =
|
||||
(uint16_t)(http->flags & ~NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
|
||||
if (!expect_response_body(http)) {
|
||||
http->content_length = 0;
|
||||
} else if (http->flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) {
|
||||
http->content_length = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp3_http_on_remote_end_stream(nghttp3_stream *stream) {
|
||||
if (stream->flags & NGHTTP3_STREAM_FLAG_RESET) {
|
||||
return 0;
|
||||
}
|
||||
if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
|
||||
(stream->rx.http.content_length != -1 &&
|
||||
stream->rx.http.content_length != stream->rx.http.recv_content_length)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp3_http_on_data_chunk(nghttp3_stream *stream, size_t n) {
|
||||
stream->rx.http.recv_content_length += (int64_t)n;
|
||||
|
||||
if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
|
||||
(stream->rx.http.content_length != -1 &&
|
||||
stream->rx.http.recv_content_length > stream->rx.http.content_length)) {
|
||||
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_http_record_request_method(nghttp3_stream *stream,
|
||||
const nghttp3_nv *nva, size_t nvlen) {
|
||||
size_t i;
|
||||
const nghttp3_nv *nv;
|
||||
|
||||
/* TODO we should do this strictly. */
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
nv = &nva[i];
|
||||
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
|
||||
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||
stream->rx.http.flags |= NGHTTP3_HTTP_FLAG_METH_CONNECT;
|
||||
return;
|
||||
}
|
||||
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||
stream->rx.http.flags |= NGHTTP3_HTTP_FLAG_METH_HEAD;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generated by gennmchartbl.py */
|
||||
static const int VALID_HD_NAME_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
|
||||
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
|
||||
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
|
||||
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
|
||||
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
|
||||
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
|
||||
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
|
||||
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
|
||||
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp3_check_header_name(const uint8_t *name, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (*name == ':') {
|
||||
if (len == 1) {
|
||||
return 0;
|
||||
}
|
||||
++name;
|
||||
--len;
|
||||
}
|
||||
for (last = name + len; name != last; ++name) {
|
||||
if (!VALID_HD_NAME_CHARS[*name]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genvchartbl.py */
|
||||
static const int VALID_HD_VALUE_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
|
||||
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
|
||||
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
|
||||
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
|
||||
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
|
||||
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
|
||||
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
|
||||
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
|
||||
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
|
||||
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
|
||||
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
|
||||
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
|
||||
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
|
||||
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
|
||||
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
|
||||
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
|
||||
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
|
||||
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
|
||||
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
|
||||
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
|
||||
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
|
||||
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
|
||||
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
|
||||
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
|
||||
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
|
||||
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
|
||||
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp3_check_header_value(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_HD_VALUE_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
146
deps/ngtcp2/nghttp3/lib/nghttp3_http.h
vendored
Normal file
146
deps/ngtcp2/nghttp3/lib/nghttp3_http.h
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2015 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 NGHTTP3_HTTP_H
|
||||
#define NGHTTP3_HTTP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
typedef struct nghttp3_stream nghttp3_stream;
|
||||
|
||||
typedef struct nghttp3_http_state nghttp3_http_state;
|
||||
|
||||
/* HTTP related flags to enforce HTTP semantics */
|
||||
|
||||
/* NGHTTP3_HTTP_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGHTTP3_HTTP_FLAG_NONE 0x00
|
||||
/* header field seen so far */
|
||||
#define NGHTTP3_HTTP_FLAG__AUTHORITY 0x01
|
||||
#define NGHTTP3_HTTP_FLAG__PATH 0x02
|
||||
#define NGHTTP3_HTTP_FLAG__METHOD 0x04
|
||||
#define NGHTTP3_HTTP_FLAG__SCHEME 0x08
|
||||
/* host is not pseudo header, but we require either host or
|
||||
:authority */
|
||||
#define NGHTTP3_HTTP_FLAG_HOST 0x10
|
||||
#define NGHTTP3_HTTP_FLAG__STATUS 0x20
|
||||
/* required header fields for HTTP request except for CONNECT
|
||||
method. */
|
||||
#define NGHTTP3_HTTP_FLAG_REQ_HEADERS \
|
||||
(NGHTTP3_HTTP_FLAG__METHOD | NGHTTP3_HTTP_FLAG__PATH | \
|
||||
NGHTTP3_HTTP_FLAG__SCHEME)
|
||||
#define NGHTTP3_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED 0x40
|
||||
/* HTTP method flags */
|
||||
#define NGHTTP3_HTTP_FLAG_METH_CONNECT 0x80
|
||||
#define NGHTTP3_HTTP_FLAG_METH_HEAD 0x0100
|
||||
#define NGHTTP3_HTTP_FLAG_METH_OPTIONS 0x0200
|
||||
#define NGHTTP3_HTTP_FLAG_METH_ALL \
|
||||
(NGHTTP3_HTTP_FLAG_METH_CONNECT | NGHTTP3_HTTP_FLAG_METH_HEAD | \
|
||||
NGHTTP3_HTTP_FLAG_METH_OPTIONS)
|
||||
/* :path category */
|
||||
/* path starts with "/" */
|
||||
#define NGHTTP3_HTTP_FLAG_PATH_REGULAR 0x0400
|
||||
/* path "*" */
|
||||
#define NGHTTP3_HTTP_FLAG_PATH_ASTERISK 0x0800
|
||||
/* scheme */
|
||||
/* "http" or "https" scheme */
|
||||
#define NGHTTP3_HTTP_FLAG_SCHEME_HTTP 0x1000
|
||||
/* set if final response is expected */
|
||||
#define NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE 0x2000
|
||||
/* NGHTTP3_HTTP_FLAG__PROTOCOL is set when :protocol pseudo header
|
||||
field is seen. */
|
||||
#define NGHTTP3_HTTP_FLAG__PROTOCOL 0x4000
|
||||
|
||||
/*
|
||||
* This function is called when HTTP header field |nv| in a frame of type
|
||||
* |frame_type| is received for |http|. This function will validate |nv|
|
||||
* against the current state of stream. Pass nonzero if this is request
|
||||
* headers. Pass nonzero to |trailers| if |nv| is included in trailers.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_MALFORMED_HTTP_HEADER
|
||||
* Invalid HTTP header field was received.
|
||||
* NGHTTP3_ERR_REMOVE_HTTP_HEADER
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
int nghttp3_http_on_header(nghttp3_http_state *http, int64_t frame_type,
|
||||
nghttp3_qpack_nv *nv, int request, int trailers);
|
||||
|
||||
/*
|
||||
* This function is called when request header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_MALFORMED_HTTP_HEADER
|
||||
* Required HTTP header field was not received; or an invalid
|
||||
* header field was received.
|
||||
*/
|
||||
int nghttp3_http_on_request_headers(nghttp3_http_state *http);
|
||||
|
||||
/*
|
||||
* This function is called when response header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_MALFORMED_HTTP_HEADER
|
||||
* Required HTTP header field was not received; or an invalid
|
||||
* header field was received.
|
||||
*/
|
||||
int nghttp3_http_on_response_headers(nghttp3_http_state *http);
|
||||
|
||||
/*
|
||||
* This function is called when read side stream is closed. This
|
||||
* function performs validation and returns 0 if it succeeds, or one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING
|
||||
* HTTP messaging is violated.
|
||||
*/
|
||||
int nghttp3_http_on_remote_end_stream(nghttp3_stream *stream);
|
||||
|
||||
/*
|
||||
* This function is called when chunk of data is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING
|
||||
* HTTP messaging is violated.
|
||||
*/
|
||||
int nghttp3_http_on_data_chunk(nghttp3_stream *stream, size_t n);
|
||||
|
||||
/*
|
||||
* This function inspects header fields in |nva| of length |nvlen| and
|
||||
* records its method in stream->http_flags.
|
||||
*/
|
||||
void nghttp3_http_record_request_method(nghttp3_stream *stream,
|
||||
const nghttp3_nv *nva, size_t nvlen);
|
||||
|
||||
#endif /* NGHTTP3_HTTP_H */
|
88
deps/ngtcp2/nghttp3/lib/nghttp3_idtr.c
vendored
Normal file
88
deps/ngtcp2/nghttp3/lib/nghttp3_idtr.c
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_idtr.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
int nghttp3_idtr_init(nghttp3_idtr *idtr, int server, const nghttp3_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp3_gaptr_init(&idtr->gap, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
idtr->server = server;
|
||||
idtr->mem = mem;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_idtr_free(nghttp3_idtr *idtr) {
|
||||
if (idtr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp3_gaptr_free(&idtr->gap);
|
||||
}
|
||||
|
||||
/*
|
||||
* id_from_stream_id translates |stream_id| to id space used by
|
||||
* nghttp3_idtr.
|
||||
*/
|
||||
static uint64_t id_from_stream_id(int64_t stream_id) {
|
||||
return (uint64_t)(stream_id >> 2);
|
||||
}
|
||||
|
||||
int nghttp3_idtr_open(nghttp3_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 (nghttp3_gaptr_is_pushed(&idtr->gap, q, 1)) {
|
||||
return NGHTTP3_ERR_STREAM_IN_USE;
|
||||
}
|
||||
|
||||
return nghttp3_gaptr_push(&idtr->gap, q, 1);
|
||||
}
|
||||
|
||||
int nghttp3_idtr_is_open(nghttp3_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 nghttp3_gaptr_is_pushed(&idtr->gap, q, 1);
|
||||
}
|
||||
|
||||
uint64_t nghttp3_idtr_first_gap(nghttp3_idtr *idtr) {
|
||||
return nghttp3_gaptr_first_gap_offset(&idtr->gap);
|
||||
}
|
99
deps/ngtcp2/nghttp3/lib/nghttp3_idtr.h
vendored
Normal file
99
deps/ngtcp2/nghttp3/lib/nghttp3_idtr.h
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_IDTR_H
|
||||
#define NGHTTP3_IDTR_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
#include "nghttp3_gaptr.h"
|
||||
|
||||
/*
|
||||
* nghttp3_idtr tracks the usage of stream ID.
|
||||
*/
|
||||
typedef struct nghttp3_idtr {
|
||||
/* gap maintains the range of ID which is not used yet. Initially,
|
||||
its range is [0, UINT64_MAX). */
|
||||
nghttp3_gaptr gap;
|
||||
/* server is nonzero if this object records server initiated stream
|
||||
ID. */
|
||||
int server;
|
||||
/* mem is custom memory allocator */
|
||||
const nghttp3_mem *mem;
|
||||
} nghttp3_idtr;
|
||||
|
||||
/*
|
||||
* nghttp3_idtr_init initializes |idtr|. |chunk| is the size of buffer
|
||||
* per chunk.
|
||||
*
|
||||
* If this object records server initiated ID (even number), set
|
||||
* |server| to nonzero.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_idtr_init(nghttp3_idtr *idtr, int server, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_idtr_free frees resources allocated for |idtr|.
|
||||
*/
|
||||
void nghttp3_idtr_free(nghttp3_idtr *idtr);
|
||||
|
||||
/*
|
||||
* nghttp3_idtr_open claims that |stream_id| is in used.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGHTTP3_ERR_STREAM_IN_USE
|
||||
* ID has already been used.
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_idtr_open(nghttp3_idtr *idtr, int64_t stream_id);
|
||||
|
||||
/*
|
||||
* nghttp3_idtr_open tells whether ID |stream_id| is in used or not.
|
||||
*
|
||||
* It returns nonzero if |stream_id| is used.
|
||||
*/
|
||||
int nghttp3_idtr_is_open(nghttp3_idtr *idtr, int64_t stream_id);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_idtr_first_gap(nghttp3_idtr *idtr);
|
||||
|
||||
#endif /* NGHTTP3_IDTR_H */
|
749
deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c
vendored
Normal file
749
deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c
vendored
Normal file
@ -0,0 +1,749 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_ksl.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp3_macro.h"
|
||||
#include "nghttp3_mem.h"
|
||||
#include "nghttp3_range.h"
|
||||
|
||||
static size_t ksl_nodelen(size_t keylen) {
|
||||
return (sizeof(nghttp3_ksl_node) + keylen - sizeof(uint64_t) + 0xf) &
|
||||
(size_t)~0xf;
|
||||
}
|
||||
|
||||
static size_t ksl_blklen(size_t nodelen) {
|
||||
return sizeof(nghttp3_ksl_blk) + nodelen * NGHTTP3_KSL_MAX_NBLK -
|
||||
sizeof(uint64_t);
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_node_set_key sets |key| to |node|.
|
||||
*/
|
||||
static void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node,
|
||||
const void *key) {
|
||||
memcpy(node->key, key, ksl->keylen);
|
||||
}
|
||||
|
||||
int nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, size_t keylen,
|
||||
const nghttp3_mem *mem) {
|
||||
size_t nodelen = ksl_nodelen(keylen);
|
||||
size_t blklen = ksl_blklen(nodelen);
|
||||
nghttp3_ksl_blk *head;
|
||||
|
||||
ksl->head = nghttp3_mem_malloc(mem, blklen);
|
||||
if (!ksl->head) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->compar = compar;
|
||||
ksl->keylen = keylen;
|
||||
ksl->nodelen = nodelen;
|
||||
ksl->n = 0;
|
||||
ksl->mem = mem;
|
||||
|
||||
head = ksl->head;
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_free_blk frees |blk| recursively.
|
||||
*/
|
||||
static void ksl_free_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
|
||||
size_t i;
|
||||
|
||||
if (!blk->leaf) {
|
||||
for (i = 0; i < blk->n; ++i) {
|
||||
ksl_free_blk(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_mem_free(ksl->mem, blk);
|
||||
}
|
||||
|
||||
void nghttp3_ksl_free(nghttp3_ksl *ksl) {
|
||||
if (!ksl) {
|
||||
return;
|
||||
}
|
||||
|
||||
ksl_free_blk(ksl, ksl->head);
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_split_blk splits |blk| into 2 nghttp3_ksl_blk objects. The new
|
||||
* nghttp3_ksl_blk is always the "right" block.
|
||||
*
|
||||
* It returns the pointer to the nghttp3_ksl_blk created which is the
|
||||
* located at the right of |blk|, or NULL which indicates out of
|
||||
* memory error.
|
||||
*/
|
||||
static nghttp3_ksl_blk *ksl_split_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
|
||||
nghttp3_ksl_blk *rblk;
|
||||
|
||||
rblk = nghttp3_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
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 >= NGHTTP3_KSL_MIN_NBLK);
|
||||
assert(rblk->n >= NGHTTP3_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:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int ksl_split_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
|
||||
nghttp3_ksl_node *node;
|
||||
nghttp3_ksl_blk *lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk, *rblk;
|
||||
|
||||
rblk = ksl_split_blk(ksl, lblk);
|
||||
if (rblk == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
memmove(blk->nodes + (i + 2) * ksl->nodelen,
|
||||
blk->nodes + (i + 1) * ksl->nodelen,
|
||||
ksl->nodelen * (blk->n - (i + 1)));
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
|
||||
node->blk = rblk;
|
||||
++blk->n;
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp3_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:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int ksl_split_head(nghttp3_ksl *ksl) {
|
||||
nghttp3_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
|
||||
nghttp3_ksl_node *node;
|
||||
|
||||
rblk = ksl_split_blk(ksl, ksl->head);
|
||||
if (rblk == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
lblk = ksl->head;
|
||||
|
||||
nhead = nghttp3_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
if (nhead == NULL) {
|
||||
nghttp3_mem_free(ksl->mem, rblk);
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
nhead->next = nhead->prev = NULL;
|
||||
nhead->n = 2;
|
||||
nhead->leaf = 0;
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, nhead, 0);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
||||
node->blk = lblk;
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, nhead, 1);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp3_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
|
||||
* NGHTTP3_KSL_MAX_NBLK.
|
||||
*/
|
||||
static void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i,
|
||||
const nghttp3_ksl_key *key, void *data) {
|
||||
nghttp3_ksl_node *node;
|
||||
|
||||
assert(blk->n < NGHTTP3_KSL_MAX_NBLK);
|
||||
|
||||
memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
|
||||
ksl->nodelen * (blk->n - i));
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
ksl_node_set_key(ksl, node, key);
|
||||
node->data = data;
|
||||
|
||||
++blk->n;
|
||||
}
|
||||
|
||||
static size_t ksl_bsearch(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
|
||||
const nghttp3_ksl_key *key,
|
||||
nghttp3_ksl_compar compar) {
|
||||
nghttp3_ssize left = -1, right = (nghttp3_ssize)blk->n, mid;
|
||||
nghttp3_ksl_node *node;
|
||||
|
||||
while (right - left > 1) {
|
||||
mid = (left + right) >> 1;
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, (size_t)mid);
|
||||
if (compar((nghttp3_ksl_key *)node->key, key)) {
|
||||
left = mid;
|
||||
} else {
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return (size_t)right;
|
||||
}
|
||||
|
||||
int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
|
||||
const nghttp3_ksl_key *key, void *data) {
|
||||
nghttp3_ksl_blk *blk = ksl->head;
|
||||
nghttp3_ksl_node *node;
|
||||
size_t i;
|
||||
int rv;
|
||||
|
||||
if (blk->n == NGHTTP3_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, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
|
||||
if (it) {
|
||||
*it = nghttp3_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
ksl_insert_node(ksl, blk, i, key, data);
|
||||
++ksl->n;
|
||||
if (it) {
|
||||
nghttp3_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 = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
|
||||
if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
|
||||
rv = ksl_split_node(ksl, blk, blk->n - 1);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
node = nghttp3_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) {
|
||||
nghttp3_ksl_it_init(it, ksl, blk, blk->n - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
|
||||
rv = ksl_split_node(ksl, blk, i);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
|
||||
if (ksl->compar((nghttp3_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(nghttp3_ksl *ksl, nghttp3_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 nghttp3_ksl_blk *ksl_merge_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
|
||||
size_t i) {
|
||||
nghttp3_ksl_blk *lblk, *rblk;
|
||||
|
||||
assert(i + 1 < blk->n);
|
||||
|
||||
lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
|
||||
rblk = nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk;
|
||||
|
||||
assert(lblk->n + rblk->n < NGHTTP3_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;
|
||||
}
|
||||
|
||||
nghttp3_mem_free(ksl->mem, rblk);
|
||||
|
||||
if (ksl->head == blk && blk->n == 2) {
|
||||
nghttp3_mem_free(ksl->mem, ksl->head);
|
||||
ksl->head = lblk;
|
||||
} else {
|
||||
ksl_remove_node(ksl, blk, i + 1);
|
||||
ksl_node_set_key(ksl, nghttp3_ksl_nth_node(ksl, blk, i),
|
||||
nghttp3_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(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
|
||||
nghttp3_ksl_node *lnode, *rnode;
|
||||
size_t n;
|
||||
|
||||
assert(i > 0);
|
||||
|
||||
lnode = nghttp3_ksl_nth_node(ksl, blk, i - 1);
|
||||
rnode = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
assert(lnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
|
||||
assert(rnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
|
||||
|
||||
n = (lnode->blk->n + rnode->blk->n + 1) / 2 - lnode->blk->n;
|
||||
|
||||
assert(n > 0);
|
||||
assert(lnode->blk->n <= NGHTTP3_KSL_MAX_NBLK - n);
|
||||
assert(rnode->blk->n >= NGHTTP3_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,
|
||||
nghttp3_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(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
|
||||
nghttp3_ksl_node *lnode, *rnode;
|
||||
size_t n;
|
||||
|
||||
assert(i < blk->n - 1);
|
||||
|
||||
lnode = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
rnode = nghttp3_ksl_nth_node(ksl, blk, i + 1);
|
||||
|
||||
assert(lnode->blk->n > NGHTTP3_KSL_MIN_NBLK);
|
||||
assert(rnode->blk->n < NGHTTP3_KSL_MAX_NBLK);
|
||||
|
||||
n = (lnode->blk->n + rnode->blk->n + 1) / 2 - rnode->blk->n;
|
||||
|
||||
assert(n > 0);
|
||||
assert(lnode->blk->n >= NGHTTP3_KSL_MIN_NBLK + n);
|
||||
assert(rnode->blk->n <= NGHTTP3_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,
|
||||
nghttp3_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(nghttp3_ksl_compar compar, const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs) {
|
||||
return !compar(lhs, rhs) && !compar(rhs, lhs);
|
||||
}
|
||||
|
||||
int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
|
||||
const nghttp3_ksl_key *key) {
|
||||
nghttp3_ksl_blk *blk = ksl->head;
|
||||
nghttp3_ksl_node *node;
|
||||
size_t i;
|
||||
|
||||
if (!blk->leaf && blk->n == 2 &&
|
||||
nghttp3_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP3_KSL_MIN_NBLK &&
|
||||
nghttp3_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP3_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 = nghttp3_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (blk->leaf) {
|
||||
if (ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
|
||||
if (it) {
|
||||
*it = nghttp3_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
ksl_remove_node(ksl, blk, i);
|
||||
--ksl->n;
|
||||
if (it) {
|
||||
if (blk->n == i && blk->next) {
|
||||
nghttp3_ksl_it_init(it, ksl, blk->next, 0);
|
||||
} else {
|
||||
nghttp3_ksl_it_init(it, ksl, blk, i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (node->blk->n > NGHTTP3_KSL_MIN_NBLK) {
|
||||
blk = node->blk;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(node->blk->n == NGHTTP3_KSL_MIN_NBLK);
|
||||
|
||||
if (i + 1 < blk->n &&
|
||||
nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
|
||||
ksl_shift_left(ksl, blk, i + 1);
|
||||
blk = node->blk;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > 0 &&
|
||||
nghttp3_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGHTTP3_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);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl,
|
||||
const nghttp3_ksl_key *key) {
|
||||
nghttp3_ksl_blk *blk = ksl->head;
|
||||
nghttp3_ksl_it it;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, ksl->compar);
|
||||
|
||||
if (blk->leaf) {
|
||||
if (i == blk->n && blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
}
|
||||
nghttp3_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 = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
|
||||
;
|
||||
if (blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
} else {
|
||||
i = blk->n;
|
||||
}
|
||||
nghttp3_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl,
|
||||
const nghttp3_ksl_key *key,
|
||||
nghttp3_ksl_compar compar) {
|
||||
nghttp3_ksl_blk *blk = ksl->head;
|
||||
nghttp3_ksl_it it;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, compar);
|
||||
|
||||
if (blk->leaf) {
|
||||
if (i == blk->n && blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
}
|
||||
nghttp3_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 = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
|
||||
;
|
||||
if (blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
} else {
|
||||
i = blk->n;
|
||||
}
|
||||
nghttp3_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
|
||||
const nghttp3_ksl_key *new_key) {
|
||||
nghttp3_ksl_blk *blk = ksl->head;
|
||||
nghttp3_ksl_node *node;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
|
||||
|
||||
assert(i < blk->n);
|
||||
node = nghttp3_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (blk->leaf) {
|
||||
assert(key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key));
|
||||
ksl_node_set_key(ksl, node, new_key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key) ||
|
||||
ksl->compar((nghttp3_ksl_key *)node->key, new_key)) {
|
||||
ksl_node_set_key(ksl, node, new_key);
|
||||
}
|
||||
|
||||
blk = node->blk;
|
||||
}
|
||||
}
|
||||
|
||||
static void ksl_print(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t level) {
|
||||
size_t i;
|
||||
nghttp3_ksl_node *node;
|
||||
|
||||
fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
|
||||
|
||||
if (blk->leaf) {
|
||||
for (i = 0; i < blk->n; ++i) {
|
||||
node = nghttp3_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, nghttp3_ksl_nth_node(ksl, blk, i)->blk, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nghttp3_ksl_len(nghttp3_ksl *ksl) { return ksl->n; }
|
||||
|
||||
void nghttp3_ksl_clear(nghttp3_ksl *ksl) {
|
||||
size_t i;
|
||||
nghttp3_ksl_blk *head;
|
||||
|
||||
if (!ksl->head->leaf) {
|
||||
for (i = 0; i < ksl->head->n; ++i) {
|
||||
ksl_free_blk(ksl, nghttp3_ksl_nth_node(ksl, ksl->head, i)->blk);
|
||||
}
|
||||
}
|
||||
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->n = 0;
|
||||
|
||||
head = ksl->head;
|
||||
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
}
|
||||
|
||||
void nghttp3_ksl_print(nghttp3_ksl *ksl) { ksl_print(ksl, ksl->head, 0); }
|
||||
|
||||
nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl) {
|
||||
nghttp3_ksl_it it;
|
||||
nghttp3_ksl_it_init(&it, ksl, ksl->front, 0);
|
||||
return it;
|
||||
}
|
||||
|
||||
nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl) {
|
||||
nghttp3_ksl_it it;
|
||||
nghttp3_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
|
||||
return it;
|
||||
}
|
||||
|
||||
void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
|
||||
nghttp3_ksl_blk *blk, size_t i) {
|
||||
it->ksl = ksl;
|
||||
it->blk = blk;
|
||||
it->i = i;
|
||||
}
|
||||
|
||||
void *nghttp3_ksl_it_get(const nghttp3_ksl_it *it) {
|
||||
assert(it->i < it->blk->n);
|
||||
return nghttp3_ksl_nth_node(it->ksl, it->blk, it->i)->data;
|
||||
}
|
||||
|
||||
void nghttp3_ksl_it_prev(nghttp3_ksl_it *it) {
|
||||
assert(!nghttp3_ksl_it_begin(it));
|
||||
|
||||
if (it->i == 0) {
|
||||
it->blk = it->blk->prev;
|
||||
it->i = it->blk->n - 1;
|
||||
} else {
|
||||
--it->i;
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it) {
|
||||
return it->i == 0 && it->blk->prev == NULL;
|
||||
}
|
||||
|
||||
int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs) {
|
||||
const nghttp3_range *a = lhs, *b = rhs;
|
||||
return a->begin < b->begin;
|
||||
}
|
||||
|
||||
int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs) {
|
||||
const nghttp3_range *a = lhs, *b = rhs;
|
||||
return a->begin < b->begin &&
|
||||
!(nghttp3_max(a->begin, b->begin) < nghttp3_min(a->end, b->end));
|
||||
}
|
331
deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h
vendored
Normal file
331
deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h
vendored
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_KSL_H
|
||||
#define NGHTTP3_KSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
/*
|
||||
* Skip List using single key instead of range.
|
||||
*/
|
||||
|
||||
#define NGHTTP3_KSL_DEGR 16
|
||||
/* NGHTTP3_KSL_MAX_NBLK is the maximum number of nodes which a single
|
||||
block can contain. */
|
||||
#define NGHTTP3_KSL_MAX_NBLK (2 * NGHTTP3_KSL_DEGR - 1)
|
||||
/* NGHTTP3_KSL_MIN_NBLK is the minimum number of nodes which a single
|
||||
block other than root must contains. */
|
||||
#define NGHTTP3_KSL_MIN_NBLK (NGHTTP3_KSL_DEGR - 1)
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_key represents key in nghttp3_ksl.
|
||||
*/
|
||||
typedef void nghttp3_ksl_key;
|
||||
|
||||
typedef struct nghttp3_ksl_node nghttp3_ksl_node;
|
||||
|
||||
typedef struct nghttp3_ksl_blk nghttp3_ksl_blk;
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_node is a node which contains either nghttp3_ksl_blk or
|
||||
* opaque data. If a node is an internal node, it contains
|
||||
* nghttp3_ksl_blk. Otherwise, it has data. The key is stored at the
|
||||
* location starting at key.
|
||||
*/
|
||||
struct nghttp3_ksl_node {
|
||||
union {
|
||||
nghttp3_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 nghttp3_ksl_init is
|
||||
called, the actual buffer will be allocated after this
|
||||
field. */
|
||||
uint8_t key[1];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_blk contains nghttp3_ksl_node objects.
|
||||
*/
|
||||
struct nghttp3_ksl_blk {
|
||||
/* next points to the next block if leaf field is nonzero. */
|
||||
nghttp3_ksl_blk *next;
|
||||
/* prev points to the previous block if leaf field is nonzero. */
|
||||
nghttp3_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 NGHTTP3_KSL_MAX_NBLK
|
||||
nghttp3_ksl_node objects. Because nghttp3_ksl_node object is
|
||||
allocated along with the additional variable length key
|
||||
storage, the size of buffer is unknown until nghttp3_ksl_init
|
||||
is called. */
|
||||
uint8_t nodes[1];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_compar is a function type which returns nonzero if key
|
||||
* |lhs| should be placed before |rhs|. It returns 0 otherwise.
|
||||
*/
|
||||
typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs);
|
||||
|
||||
typedef struct nghttp3_ksl nghttp3_ksl;
|
||||
|
||||
typedef struct nghttp3_ksl_it nghttp3_ksl_it;
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it is a forward iterator to iterate nodes.
|
||||
*/
|
||||
struct nghttp3_ksl_it {
|
||||
const nghttp3_ksl *ksl;
|
||||
nghttp3_ksl_blk *blk;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_ksl is a deterministic paged skip list.
|
||||
*/
|
||||
struct nghttp3_ksl {
|
||||
/* head points to the root block. */
|
||||
nghttp3_ksl_blk *head;
|
||||
/* front points to the first leaf block. */
|
||||
nghttp3_ksl_blk *front;
|
||||
/* back points to the last leaf block. */
|
||||
nghttp3_ksl_blk *back;
|
||||
nghttp3_ksl_compar compar;
|
||||
size_t n;
|
||||
/* keylen is the size of key */
|
||||
size_t keylen;
|
||||
/* nodelen is the actual size of nghttp3_ksl_node including key
|
||||
storage. */
|
||||
size_t nodelen;
|
||||
const nghttp3_mem *mem;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_init initializes |ksl|. |compar| specifies compare
|
||||
* function. |keylen| is the length of key.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, size_t keylen,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_ksl_free(nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_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:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_INVALID_ARGUMENT
|
||||
* |key| already exists.
|
||||
*/
|
||||
int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
|
||||
const nghttp3_ksl_key *key, void *data);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_ksl_end(ksl) is assigned to |*it|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_INVALID_ARGUMENT
|
||||
* |key| does not exist.
|
||||
*/
|
||||
int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
|
||||
const nghttp3_ksl_key *key);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_ksl_it_end(it)
|
||||
* != 0.
|
||||
*/
|
||||
nghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl,
|
||||
const nghttp3_ksl_key *key);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_lower_bound_compar works like nghttp3_ksl_lower_bound,
|
||||
* but it takes custom function |compar| to do lower bound search.
|
||||
*/
|
||||
nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl,
|
||||
const nghttp3_ksl_key *key,
|
||||
nghttp3_ksl_compar compar);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
|
||||
const nghttp3_ksl_key *new_key);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_begin returns the iterator which points to the first
|
||||
* node. If there is no node in |ksl|, it returns the iterator which
|
||||
* satisfies nghttp3_ksl_it_end(it) != 0.
|
||||
*/
|
||||
nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_end returns the iterator which points to the node
|
||||
* following the last node. The returned object satisfies
|
||||
* nghttp3_ksl_it_end(). If there is no node in |ksl|, it returns the
|
||||
* iterator which satisfies nghttp3_ksl_it_begin(it) != 0.
|
||||
*/
|
||||
nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_len returns the number of elements stored in |ksl|.
|
||||
*/
|
||||
size_t nghttp3_ksl_len(nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_clear removes all elements stored in |ksl|.
|
||||
*/
|
||||
void nghttp3_ksl_clear(nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_nth_node returns the |n|th node under |blk|.
|
||||
*/
|
||||
#define nghttp3_ksl_nth_node(KSL, BLK, N) \
|
||||
((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_ksl_print(nghttp3_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_init initializes |it|.
|
||||
*/
|
||||
void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
|
||||
nghttp3_ksl_blk *blk, size_t i);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_get returns the data associated to the node which
|
||||
* |it| points to. It is undefined to call this function when
|
||||
* nghttp3_ksl_it_end(it) returns nonzero.
|
||||
*/
|
||||
void *nghttp3_ksl_it_get(const nghttp3_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_next advances the iterator by one. It is undefined
|
||||
* if this function is called when nghttp3_ksl_it_end(it) returns
|
||||
* nonzero.
|
||||
*/
|
||||
#define nghttp3_ksl_it_next(IT) \
|
||||
(++(IT)->i == (IT)->blk->n && (IT)->blk->next \
|
||||
? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
|
||||
: 0)
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_prev moves backward the iterator by one. It is
|
||||
* undefined if this function is called when nghttp3_ksl_it_begin(it)
|
||||
* returns nonzero.
|
||||
*/
|
||||
void nghttp3_ksl_it_prev(nghttp3_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_end returns nonzero if |it| points to the beyond the
|
||||
* last node.
|
||||
*/
|
||||
#define nghttp3_ksl_it_end(IT) \
|
||||
((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_it_begin returns nonzero if |it| points to the first
|
||||
* node. |it| might satisfy both nghttp3_ksl_it_begin(&it) and
|
||||
* nghttp3_ksl_it_end(&it) if the skip list has no node.
|
||||
*/
|
||||
int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_key returns the key of the node which |it| points to.
|
||||
* It is undefined to call this function when nghttp3_ksl_it_end(it)
|
||||
* returns nonzero.
|
||||
*/
|
||||
#define nghttp3_ksl_it_key(IT) \
|
||||
((nghttp3_ksl_key *)nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_range_compar is an implementation of
|
||||
* nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to
|
||||
* nghttp3_range object and the function returns nonzero if (const
|
||||
* nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range
|
||||
* *)(rhs->ptr)->begin.
|
||||
*/
|
||||
int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs);
|
||||
|
||||
/*
|
||||
* nghttp3_ksl_range_exclusive_compar is an implementation of
|
||||
* nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to
|
||||
* nghttp3_range object and the function returns nonzero if (const
|
||||
* nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range
|
||||
* *)(rhs->ptr)->begin and the 2 ranges do not intersect.
|
||||
*/
|
||||
int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
|
||||
const nghttp3_ksl_key *rhs);
|
||||
|
||||
#endif /* NGHTTP3_KSL_H */
|
47
deps/ngtcp2/nghttp3/lib/nghttp3_macro.h
vendored
Normal file
47
deps/ngtcp2/nghttp3/lib/nghttp3_macro.h
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_MACRO_H
|
||||
#define NGHTTP3_MACRO_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#define nghttp3_min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define nghttp3_max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
#define nghttp3_struct_of(ptr, type, member) \
|
||||
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
|
||||
|
||||
#define nghttp3_arraylen(A) (sizeof(A) / sizeof(*(A)))
|
||||
|
||||
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
|
||||
|
||||
#endif /* NGHTTP3_MACRO_H */
|
336
deps/ngtcp2/nghttp3/lib/nghttp3_map.c
vendored
Normal file
336
deps/ngtcp2/nghttp3/lib/nghttp3_map.c
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_map.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_conv.h"
|
||||
|
||||
#define INITIAL_TABLE_LENGTH 256
|
||||
|
||||
int nghttp3_map_init(nghttp3_map *map, const nghttp3_mem *mem) {
|
||||
map->mem = mem;
|
||||
map->tablelen = INITIAL_TABLE_LENGTH;
|
||||
map->table =
|
||||
nghttp3_mem_calloc(mem, map->tablelen, sizeof(nghttp3_map_bucket));
|
||||
if (map->table == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_map_free(nghttp3_map *map) {
|
||||
size_t i;
|
||||
nghttp3_map_bucket *bkt;
|
||||
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp3_ksl_free(bkt->ksl);
|
||||
nghttp3_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_mem_free(map->mem, map->table);
|
||||
}
|
||||
|
||||
void nghttp3_map_each_free(nghttp3_map *map,
|
||||
int (*func)(nghttp3_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
uint32_t i;
|
||||
nghttp3_map_bucket *bkt;
|
||||
nghttp3_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
func(bkt->ptr, ptr);
|
||||
bkt->ptr = NULL;
|
||||
assert(bkt->ksl == NULL || nghttp3_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp3_ksl_begin(bkt->ksl); !nghttp3_ksl_it_end(&it);
|
||||
nghttp3_ksl_it_next(&it)) {
|
||||
func(nghttp3_ksl_it_get(&it), ptr);
|
||||
}
|
||||
|
||||
nghttp3_ksl_free(bkt->ksl);
|
||||
nghttp3_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp3_map_each(nghttp3_map *map,
|
||||
int (*func)(nghttp3_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
int rv;
|
||||
uint32_t i;
|
||||
nghttp3_map_bucket *bkt;
|
||||
nghttp3_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = func(bkt->ptr, ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
assert(bkt->ksl == NULL || nghttp3_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp3_ksl_begin(bkt->ksl); !nghttp3_ksl_it_end(&it);
|
||||
nghttp3_ksl_it_next(&it)) {
|
||||
rv = func(nghttp3_ksl_it_get(&it), ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_map_entry_init(nghttp3_map_entry *entry, key_type key) {
|
||||
entry->key = key;
|
||||
}
|
||||
|
||||
/* FNV1a hash */
|
||||
static uint32_t hash(key_type key, uint32_t mod) {
|
||||
uint8_t *p, *end;
|
||||
uint32_t h = 0x811C9DC5u;
|
||||
|
||||
key = nghttp3_htonl64(key);
|
||||
p = (uint8_t *)&key;
|
||||
end = p + sizeof(key_type);
|
||||
|
||||
for (; p != end;) {
|
||||
h ^= *p++;
|
||||
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
|
||||
}
|
||||
|
||||
return h & (mod - 1);
|
||||
}
|
||||
|
||||
static int less(const nghttp3_ksl_key *lhs, const nghttp3_ksl_key *rhs) {
|
||||
return *(key_type *)lhs < *(key_type *)rhs;
|
||||
}
|
||||
|
||||
static int map_insert(nghttp3_map *map, nghttp3_map_bucket *table,
|
||||
uint32_t tablelen, nghttp3_map_entry *entry) {
|
||||
uint32_t h = hash(entry->key, tablelen);
|
||||
nghttp3_map_bucket *bkt = &table[h];
|
||||
const nghttp3_mem *mem = map->mem;
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr == NULL &&
|
||||
(bkt->ksl == NULL || nghttp3_ksl_len(bkt->ksl) == 0)) {
|
||||
bkt->ptr = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bkt->ksl) {
|
||||
bkt->ksl = nghttp3_mem_malloc(mem, sizeof(*bkt->ksl));
|
||||
if (bkt->ksl == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
nghttp3_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
|
||||
}
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = nghttp3_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bkt->ptr = NULL;
|
||||
}
|
||||
|
||||
return nghttp3_ksl_insert(bkt->ksl, NULL, &entry->key, entry);
|
||||
}
|
||||
|
||||
/* new_tablelen must be power of 2 */
|
||||
static int map_resize(nghttp3_map *map, uint32_t new_tablelen) {
|
||||
uint32_t i;
|
||||
nghttp3_map_bucket *new_table;
|
||||
nghttp3_map_bucket *bkt;
|
||||
nghttp3_ksl_it it;
|
||||
int rv;
|
||||
|
||||
new_table =
|
||||
nghttp3_mem_calloc(map->mem, new_tablelen, sizeof(nghttp3_map_bucket));
|
||||
if (new_table == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = map_insert(map, new_table, new_tablelen, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
assert(bkt->ksl == NULL || nghttp3_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp3_ksl_begin(bkt->ksl); !nghttp3_ksl_it_end(&it);
|
||||
nghttp3_ksl_it_next(&it)) {
|
||||
rv = map_insert(map, new_table, new_tablelen, nghttp3_ksl_it_get(&it));
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp3_ksl_free(bkt->ksl);
|
||||
nghttp3_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_mem_free(map->mem, map->table);
|
||||
map->tablelen = new_tablelen;
|
||||
map->table = new_table;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < new_tablelen; ++i) {
|
||||
bkt = &new_table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp3_ksl_free(bkt->ksl);
|
||||
nghttp3_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_entry *new_entry) {
|
||||
int rv;
|
||||
|
||||
/* Load factor is 0.75 */
|
||||
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
||||
rv = map_resize(map, map->tablelen * 2);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = map_insert(map, map->table, map->tablelen, new_entry);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
++map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp3_map_entry *nghttp3_map_find(nghttp3_map *map, key_type key) {
|
||||
nghttp3_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
nghttp3_ksl_it it;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
return bkt->ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
it = nghttp3_ksl_lower_bound(bkt->ksl, &key);
|
||||
if (nghttp3_ksl_it_end(&it) ||
|
||||
*(key_type *)nghttp3_ksl_it_key(&it) != key) {
|
||||
return NULL;
|
||||
}
|
||||
return nghttp3_ksl_it_get(&it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nghttp3_map_remove(nghttp3_map *map, key_type key) {
|
||||
nghttp3_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
bkt->ptr = NULL;
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
rv = nghttp3_ksl_remove(bkt->ksl, NULL, &key);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NGHTTP3_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
void nghttp3_map_clear(nghttp3_map *map) {
|
||||
uint32_t i;
|
||||
nghttp3_map_bucket *bkt;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
bkt->ptr = NULL;
|
||||
if (bkt->ksl) {
|
||||
nghttp3_ksl_free(bkt->ksl);
|
||||
nghttp3_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
}
|
||||
|
||||
size_t nghttp3_map_size(nghttp3_map *map) { return map->size; }
|
154
deps/ngtcp2/nghttp3/lib/nghttp3_map.h
vendored
Normal file
154
deps/ngtcp2/nghttp3/lib/nghttp3_map.h
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_MAP_H
|
||||
#define NGHTTP3_MAP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
#include "nghttp3_ksl.h"
|
||||
|
||||
/* Implementation of unordered map */
|
||||
|
||||
typedef uint64_t key_type;
|
||||
|
||||
typedef struct nghttp3_map_entry nghttp3_map_entry;
|
||||
|
||||
struct nghttp3_map_entry {
|
||||
key_type key;
|
||||
};
|
||||
|
||||
typedef struct nghttp3_map_bucket {
|
||||
nghttp3_map_entry *ptr;
|
||||
nghttp3_ksl *ksl;
|
||||
} nghttp3_map_bucket;
|
||||
|
||||
typedef struct nghttp3_map {
|
||||
nghttp3_map_bucket *table;
|
||||
const nghttp3_mem *mem;
|
||||
size_t size;
|
||||
uint32_t tablelen;
|
||||
} nghttp3_map;
|
||||
|
||||
/*
|
||||
* Initializes the map |map|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp3_map_init(nghttp3_map *map, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |map|. The stored entries
|
||||
* are not freed by this function. Use nghttp3_map_each_free() to free
|
||||
* each entries.
|
||||
*/
|
||||
void nghttp3_map_free(nghttp3_map *map);
|
||||
|
||||
/*
|
||||
* Deallocates each entries using |func| function and any resources
|
||||
* allocated for |map|. The |func| function is responsible for freeing
|
||||
* given the |entry| object. The |ptr| will be passed to the |func| as
|
||||
* send argument. The return value of the |func| will be ignored.
|
||||
*/
|
||||
void nghttp3_map_each_free(nghttp3_map *map,
|
||||
int (*func)(nghttp3_map_entry *entry, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
/*
|
||||
* Initializes the |entry| with the |key|. All entries to be inserted
|
||||
* to the map must be initialized with this function.
|
||||
*/
|
||||
void nghttp3_map_entry_init(nghttp3_map_entry *entry, key_type key);
|
||||
|
||||
/*
|
||||
* Inserts the new |entry| with the key |entry->key| to the map |map|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_INVALID_ARGUMENT
|
||||
* The item associated by |key| already exists.
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_entry *entry);
|
||||
|
||||
/*
|
||||
* Returns the entry associated by the key |key|. If there is no such
|
||||
* entry, this function returns NULL.
|
||||
*/
|
||||
nghttp3_map_entry *nghttp3_map_find(nghttp3_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes the entry associated by the key |key| from the |map|. The
|
||||
* removed entry is not freed by this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_INVALID_ARGUMENT
|
||||
* The entry associated by |key| does not exist.
|
||||
*/
|
||||
int nghttp3_map_remove(nghttp3_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes all entries from |map|.
|
||||
*/
|
||||
void nghttp3_map_clear(nghttp3_map *map);
|
||||
|
||||
/*
|
||||
* Returns the number of items stored in the map |map|.
|
||||
*/
|
||||
size_t nghttp3_map_size(nghttp3_map *map);
|
||||
|
||||
/*
|
||||
* Applies the function |func| to each entry in the |map| with the
|
||||
* optional user supplied pointer |ptr|.
|
||||
*
|
||||
* If the |func| returns 0, this function calls the |func| with the
|
||||
* next entry. 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 entry. Use
|
||||
* nghttp3_map_each_free() instead.
|
||||
*/
|
||||
int nghttp3_map_each(nghttp3_map *map,
|
||||
int (*func)(nghttp3_map_entry *entry, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
#endif /* NGHTTP3_MAP_H */
|
77
deps/ngtcp2/nghttp3/lib/nghttp3_mem.c
vendored
Normal file
77
deps/ngtcp2/nghttp3/lib/nghttp3_mem.c
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_mem.h"
|
||||
|
||||
static void *default_malloc(size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void default_free(void *ptr, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
static void *default_realloc(void *ptr, size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
static nghttp3_mem mem_default = {NULL, default_malloc, default_free,
|
||||
default_calloc, default_realloc};
|
||||
|
||||
const nghttp3_mem *nghttp3_mem_default(void) { return &mem_default; }
|
||||
|
||||
void *nghttp3_mem_malloc(const nghttp3_mem *mem, size_t size) {
|
||||
return mem->malloc(size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp3_mem_free(const nghttp3_mem *mem, void *ptr) {
|
||||
mem->free(ptr, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp3_mem_free2(const nghttp3_free free_func, void *ptr,
|
||||
void *mem_user_data) {
|
||||
free_func(ptr, mem_user_data);
|
||||
}
|
||||
|
||||
void *nghttp3_mem_calloc(const nghttp3_mem *mem, size_t nmemb, size_t size) {
|
||||
return mem->calloc(nmemb, size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void *nghttp3_mem_realloc(const nghttp3_mem *mem, void *ptr, size_t size) {
|
||||
return mem->realloc(ptr, size, mem->mem_user_data);
|
||||
}
|
45
deps/ngtcp2/nghttp3/lib/nghttp3_mem.h
vendored
Normal file
45
deps/ngtcp2/nghttp3/lib/nghttp3_mem.h
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_MEM_H
|
||||
#define NGHTTP3_MEM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
/* Convenient wrapper functions to call allocator function in
|
||||
|mem|. */
|
||||
void *nghttp3_mem_malloc(const nghttp3_mem *mem, size_t size);
|
||||
void nghttp3_mem_free(const nghttp3_mem *mem, void *ptr);
|
||||
void nghttp3_mem_free2(const nghttp3_free free_func, void *ptr,
|
||||
void *mem_user_data);
|
||||
void *nghttp3_mem_calloc(const nghttp3_mem *mem, size_t nmemb, size_t size);
|
||||
void *nghttp3_mem_realloc(const nghttp3_mem *mem, void *ptr, size_t size);
|
||||
|
||||
#endif /* NGHTTP3_MEM_H */
|
168
deps/ngtcp2/nghttp3/lib/nghttp3_pq.c
vendored
Normal file
168
deps/ngtcp2/nghttp3/lib/nghttp3_pq.c
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_pq.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_macro.h"
|
||||
|
||||
void nghttp3_pq_init(nghttp3_pq *pq, nghttp3_less less,
|
||||
const nghttp3_mem *mem) {
|
||||
pq->mem = mem;
|
||||
pq->capacity = 0;
|
||||
pq->q = NULL;
|
||||
pq->length = 0;
|
||||
pq->less = less;
|
||||
}
|
||||
|
||||
void nghttp3_pq_free(nghttp3_pq *pq) {
|
||||
nghttp3_mem_free(pq->mem, pq->q);
|
||||
pq->q = NULL;
|
||||
}
|
||||
|
||||
static void swap(nghttp3_pq *pq, size_t i, size_t j) {
|
||||
nghttp3_pq_entry *a = pq->q[i];
|
||||
nghttp3_pq_entry *b = pq->q[j];
|
||||
|
||||
pq->q[i] = b;
|
||||
b->index = i;
|
||||
pq->q[j] = a;
|
||||
a->index = j;
|
||||
}
|
||||
|
||||
static void bubble_up(nghttp3_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 nghttp3_pq_push(nghttp3_pq *pq, nghttp3_pq_entry *item) {
|
||||
if (pq->capacity <= pq->length) {
|
||||
void *nq;
|
||||
size_t ncapacity;
|
||||
|
||||
ncapacity = nghttp3_max(4, (pq->capacity * 2));
|
||||
|
||||
nq = nghttp3_mem_realloc(pq->mem, pq->q,
|
||||
ncapacity * sizeof(nghttp3_pq_entry *));
|
||||
if (nq == NULL) {
|
||||
return NGHTTP3_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;
|
||||
}
|
||||
|
||||
nghttp3_pq_entry *nghttp3_pq_top(const nghttp3_pq *pq) {
|
||||
assert(pq->length);
|
||||
return pq->q[0];
|
||||
}
|
||||
|
||||
static void bubble_down(nghttp3_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 nghttp3_pq_pop(nghttp3_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 nghttp3_pq_remove(nghttp3_pq *pq, nghttp3_pq_entry *item) {
|
||||
assert(pq->q[item->index] == item);
|
||||
|
||||
if (item->index == 0) {
|
||||
nghttp3_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 nghttp3_pq_empty(const nghttp3_pq *pq) { return pq->length == 0; }
|
||||
|
||||
size_t nghttp3_pq_size(const nghttp3_pq *pq) { return pq->length; }
|
||||
|
||||
int nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_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;
|
||||
}
|
||||
|
||||
void nghttp3_pq_clear(nghttp3_pq *pq) { pq->length = 0; }
|
129
deps/ngtcp2/nghttp3/lib/nghttp3_pq.h
vendored
Normal file
129
deps/ngtcp2/nghttp3/lib/nghttp3_pq.h
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_PQ_H
|
||||
#define NGHTTP3_PQ_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
|
||||
/* Implementation of priority queue */
|
||||
|
||||
/* NGHTTP3_PQ_BAD_INDEX is the priority queue index which indicates
|
||||
that an entry is not queued. Assigning this value to
|
||||
nghttp3_pq_entry.index can check that the entry is queued or not. */
|
||||
#define NGHTTP3_PQ_BAD_INDEX SIZE_MAX
|
||||
|
||||
typedef struct nghttp3_pq_entry {
|
||||
size_t index;
|
||||
} nghttp3_pq_entry;
|
||||
|
||||
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
|
||||
typedef int (*nghttp3_less)(const nghttp3_pq_entry *lhs,
|
||||
const nghttp3_pq_entry *rhs);
|
||||
|
||||
typedef struct nghttp3_pq {
|
||||
/* The pointer to the pointer to the item stored */
|
||||
nghttp3_pq_entry **q;
|
||||
/* Memory allocator */
|
||||
const nghttp3_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 */
|
||||
nghttp3_less less;
|
||||
} nghttp3_pq;
|
||||
|
||||
/*
|
||||
* Initializes priority queue |pq| with compare function |cmp|.
|
||||
*/
|
||||
void nghttp3_pq_init(nghttp3_pq *pq, nghttp3_less less, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |pq|. The stored items are
|
||||
* not freed by this function.
|
||||
*/
|
||||
void nghttp3_pq_free(nghttp3_pq *pq);
|
||||
|
||||
/*
|
||||
* Adds |item| to the priority queue |pq|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_pq_push(nghttp3_pq *pq, nghttp3_pq_entry *item);
|
||||
|
||||
/*
|
||||
* Returns item at the top of the queue |pq|. It is undefined if the
|
||||
* queue is empty.
|
||||
*/
|
||||
nghttp3_pq_entry *nghttp3_pq_top(const nghttp3_pq *pq);
|
||||
|
||||
/*
|
||||
* Pops item at the top of the queue |pq|. The popped item is not
|
||||
* freed by this function.
|
||||
*/
|
||||
void nghttp3_pq_pop(nghttp3_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the queue |pq| is empty.
|
||||
*/
|
||||
int nghttp3_pq_empty(const nghttp3_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns the number of items in the queue |pq|.
|
||||
*/
|
||||
size_t nghttp3_pq_size(const nghttp3_pq *pq);
|
||||
|
||||
typedef int (*nghttp3_pq_item_cb)(nghttp3_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 nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_pq_item_cb fun, void *arg);
|
||||
|
||||
/*
|
||||
* Removes |item| from priority queue.
|
||||
*/
|
||||
void nghttp3_pq_remove(nghttp3_pq *pq, nghttp3_pq_entry *item);
|
||||
|
||||
void nghttp3_pq_clear(nghttp3_pq *pq);
|
||||
|
||||
#endif /* NGHTTP3_PQ_H */
|
4095
deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c
vendored
Normal file
4095
deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
961
deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h
vendored
Normal file
961
deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h
vendored
Normal file
@ -0,0 +1,961 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2013 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 NGHTTP3_QPACK_H
|
||||
#define NGHTTP3_QPACK_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_rcbuf.h"
|
||||
#include "nghttp3_map.h"
|
||||
#include "nghttp3_pq.h"
|
||||
#include "nghttp3_ringbuf.h"
|
||||
#include "nghttp3_buf.h"
|
||||
#include "nghttp3_ksl.h"
|
||||
#include "nghttp3_qpack_huffman.h"
|
||||
|
||||
#define NGHTTP3_QPACK_INT_MAX ((1ull << 62) - 1)
|
||||
|
||||
/* NGHTTP3_QPACK_MAX_NAMELEN is the maximum (compressed) length of
|
||||
header name this library can decode. */
|
||||
#define NGHTTP3_QPACK_MAX_NAMELEN 256
|
||||
/* NGHTTP3_QPACK_MAX_VALUELEN is the maximum (compressed) length of
|
||||
header value this library can decode. */
|
||||
#define NGHTTP3_QPACK_MAX_VALUELEN 65536
|
||||
|
||||
/* nghttp3_qpack_indexing_mode is a indexing strategy. */
|
||||
typedef enum nghttp3_qpack_indexing_mode {
|
||||
/* NGHTTP3_QPACK_INDEXING_MODE_LITERAL means that header field
|
||||
should not be inserted into dynamic table. */
|
||||
NGHTTP3_QPACK_INDEXING_MODE_LITERAL,
|
||||
/* NGHTTP3_QPACK_INDEXING_MODE_STORE means that header field can be
|
||||
inserted into dynamic table. */
|
||||
NGHTTP3_QPACK_INDEXING_MODE_STORE,
|
||||
/* NGHTTP3_QPACK_INDEXING_MODE_NEVER means that header field should
|
||||
not be inserted into dynamic table and this must be true for all
|
||||
forwarding paths. */
|
||||
NGHTTP3_QPACK_INDEXING_MODE_NEVER,
|
||||
} nghttp3_qpack_indexing_mode;
|
||||
|
||||
typedef struct nghttp3_qpack_entry nghttp3_qpack_entry;
|
||||
|
||||
struct nghttp3_qpack_entry {
|
||||
/* The header field name/value pair */
|
||||
nghttp3_qpack_nv nv;
|
||||
/* map_next points to the entry which shares same bucket in hash
|
||||
table. */
|
||||
nghttp3_qpack_entry *map_next;
|
||||
/* sum is the sum of all entries inserted up to this entry. This
|
||||
value does not contain the space required for this entry. */
|
||||
size_t sum;
|
||||
/* absidx is the absolute index of this entry. */
|
||||
uint64_t absidx;
|
||||
/* The hash value for header name (nv.name). */
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
/* The entry used for static table. */
|
||||
typedef struct nghttp3_qpack_static_entry {
|
||||
uint64_t absidx;
|
||||
int32_t token;
|
||||
uint32_t hash;
|
||||
} nghttp3_qpack_static_entry;
|
||||
|
||||
typedef struct nghttp3_qpack_static_header {
|
||||
nghttp3_rcbuf name;
|
||||
nghttp3_rcbuf value;
|
||||
int32_t token;
|
||||
} nghttp3_qpack_static_header;
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_header_block_ref is created per encoded header block
|
||||
* and includes the required insert count and the minimum insert count
|
||||
* of dynamic table entry it refers to.
|
||||
*/
|
||||
typedef struct nghttp3_qpack_header_block_ref {
|
||||
nghttp3_pq_entry max_cnts_pe;
|
||||
nghttp3_pq_entry min_cnts_pe;
|
||||
/* max_cnt is the required insert count. */
|
||||
uint64_t max_cnt;
|
||||
/* min_cnt is the minimum insert count of dynamic table entry it
|
||||
refers to. In other words, this is the minimum absolute index of
|
||||
dynamic header table entry this encoded block refers to plus
|
||||
1. */
|
||||
uint64_t min_cnt;
|
||||
} nghttp3_qpack_header_block_ref;
|
||||
|
||||
int nghttp3_qpack_header_block_ref_new(nghttp3_qpack_header_block_ref **pref,
|
||||
uint64_t max_cnt, uint64_t min_cnt,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
void nghttp3_qpack_header_block_ref_del(nghttp3_qpack_header_block_ref *ref,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
typedef struct nghttp3_qpack_stream {
|
||||
nghttp3_map_entry me;
|
||||
/* refs is an array of pointer to nghttp3_qpack_header_block_ref in
|
||||
the order of the time they are encoded. HTTP/3 allows multiple
|
||||
header blocks (e.g., non-final response headers, final response
|
||||
headers, trailers, and push promises) per stream. */
|
||||
nghttp3_ringbuf refs;
|
||||
/* max_cnts is a priority queue sorted by descending order of
|
||||
max_cnt of nghttp3_qpack_header_block_ref. */
|
||||
nghttp3_pq max_cnts;
|
||||
} nghttp3_qpack_stream;
|
||||
|
||||
int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
void nghttp3_qpack_stream_del(nghttp3_qpack_stream *stream,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
uint64_t nghttp3_qpack_stream_get_max_cnt(const nghttp3_qpack_stream *stream);
|
||||
|
||||
int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream,
|
||||
nghttp3_qpack_header_block_ref *ref);
|
||||
|
||||
void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream);
|
||||
|
||||
#define NGHTTP3_QPACK_ENTRY_OVERHEAD 32
|
||||
|
||||
typedef struct nghttp3_qpack_context {
|
||||
/* dtable is a dynamic table */
|
||||
nghttp3_ringbuf dtable;
|
||||
/* mem is memory allocator */
|
||||
const nghttp3_mem *mem;
|
||||
/* dtable_size is abstracted buffer size of dtable as described in
|
||||
the spec. This is the sum of length of name/value in dtable +
|
||||
NGHTTP3_QPACK_ENTRY_OVERHEAD bytes overhead per each entry. */
|
||||
size_t dtable_size;
|
||||
size_t dtable_sum;
|
||||
/* hard_max_dtable_size is the maximum size of dynamic table. In
|
||||
HTTP/3, it is notified by decoder as
|
||||
SETTINGS_QPACK_MAX_TABLE_CAPACITY. Any value lower than or equal
|
||||
to SETTINGS_QPACK_MAX_TABLE_CAPACITY is OK because encoder has
|
||||
the authority to decide how many entries are inserted into
|
||||
dynamic table. */
|
||||
size_t hard_max_dtable_size;
|
||||
/* max_dtable_size is the effective maximum size of dynamic table. */
|
||||
size_t max_dtable_size;
|
||||
/* max_blocked is the maximum number of stream which can be
|
||||
blocked. */
|
||||
size_t max_blocked;
|
||||
/* next_absidx is the next absolute index for nghttp3_qpack_entry.
|
||||
It is equivalent to insert count. */
|
||||
uint64_t next_absidx;
|
||||
/* If inflate/deflate error occurred, this value is set to 1 and
|
||||
further invocation of inflate/deflate will fail with
|
||||
NGHTTP3_ERR_QPACK_FATAL. */
|
||||
uint8_t bad;
|
||||
} nghttp3_qpack_context;
|
||||
|
||||
typedef struct nghttp3_qpack_read_state {
|
||||
nghttp3_qpack_huffman_decode_context huffman_ctx;
|
||||
nghttp3_buf namebuf;
|
||||
nghttp3_buf valuebuf;
|
||||
nghttp3_rcbuf *name;
|
||||
nghttp3_rcbuf *value;
|
||||
uint64_t left;
|
||||
size_t prefix;
|
||||
size_t shift;
|
||||
uint64_t absidx;
|
||||
int never;
|
||||
int dynamic;
|
||||
int huffman_encoded;
|
||||
} nghttp3_qpack_read_state;
|
||||
|
||||
void nghttp3_qpack_read_state_free(nghttp3_qpack_read_state *rstate);
|
||||
|
||||
void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate);
|
||||
|
||||
#define NGHTTP3_QPACK_MAP_SIZE 64
|
||||
|
||||
typedef struct nghttp3_qpack_map {
|
||||
nghttp3_qpack_entry *table[NGHTTP3_QPACK_MAP_SIZE];
|
||||
} nghttp3_qpack_map;
|
||||
|
||||
/* nghttp3_qpack_decoder_stream_state is a set of states when decoding
|
||||
decoder stream. */
|
||||
typedef enum nghttp3_qpack_decoder_stream_state {
|
||||
NGHTTP3_QPACK_DS_STATE_OPCODE,
|
||||
NGHTTP3_QPACK_DS_STATE_READ_NUMBER,
|
||||
} nghttp3_qpack_decoder_stream_state;
|
||||
|
||||
/* nghttp3_qpack_decoder_stream_opcode is opcode used in decoder
|
||||
stream. */
|
||||
typedef enum nghttp3_qpack_decoder_stream_opcode {
|
||||
NGHTTP3_QPACK_DS_OPCODE_ICNT_INCREMENT,
|
||||
NGHTTP3_QPACK_DS_OPCODE_SECTION_ACK,
|
||||
NGHTTP3_QPACK_DS_OPCODE_STREAM_CANCEL,
|
||||
} nghttp3_qpack_decoder_stream_opcode;
|
||||
|
||||
/* QPACK encoder flags */
|
||||
|
||||
/* NGHTTP3_QPACK_ENCODER_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGHTTP3_QPACK_ENCODER_FLAG_NONE 0x00
|
||||
/* NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP indicates that
|
||||
Set Dynamic Table Capacity is required. */
|
||||
#define NGHTTP3_QPACK_ENCODER_FLAG_PENDING_SET_DTABLE_CAP 0x01
|
||||
|
||||
struct nghttp3_qpack_encoder {
|
||||
nghttp3_qpack_context ctx;
|
||||
/* dtable_map is a map of hash to nghttp3_qpack_entry to provide
|
||||
fast access to an entry in dynamic table. */
|
||||
nghttp3_qpack_map dtable_map;
|
||||
/* streams is a map of stream ID to nghttp3_qpack_stream to keep
|
||||
track of unacknowledged streams. */
|
||||
nghttp3_map streams;
|
||||
/* blocked_streams is an ordered list of nghttp3_qpack_stream, in
|
||||
descending order of max_cnt, to search the unblocked streams by
|
||||
received known count. */
|
||||
nghttp3_ksl blocked_streams;
|
||||
/* min_cnts is a priority queue of nghttp3_qpack_header_block_ref
|
||||
sorted by ascending order of min_cnt to know that an entry can be
|
||||
evicted from dynamic table. */
|
||||
nghttp3_pq min_cnts;
|
||||
/* krcnt is Known Received Count. */
|
||||
uint64_t krcnt;
|
||||
/* state is a current state of reading decoder stream. */
|
||||
nghttp3_qpack_decoder_stream_state state;
|
||||
/* opcode is a decoder stream opcode being processed. */
|
||||
nghttp3_qpack_decoder_stream_opcode opcode;
|
||||
/* rstate is a set of intermediate state which are used to process
|
||||
decoder stream. */
|
||||
nghttp3_qpack_read_state rstate;
|
||||
/* min_dtable_update is the minimum dynamic table size required. */
|
||||
size_t min_dtable_update;
|
||||
/* last_max_dtable_update is the dynamic table size last
|
||||
requested. */
|
||||
size_t last_max_dtable_update;
|
||||
/* flags is bitwise OR of zero or more of
|
||||
NGHTTP3_QPACK_ENCODER_FLAG_*. */
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_init initializes |encoder|.
|
||||
* |max_dtable_size| is the maximum size of dynamic table.
|
||||
* |max_blocked| is the maximum number of stream which can be blocked.
|
||||
* |mem| is a memory allocator.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
|
||||
size_t max_dtable_size, size_t max_blocked,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_free frees memory allocated for |encoder|.
|
||||
* This function does not free memory pointed by |encoder|.
|
||||
*/
|
||||
void nghttp3_qpack_encoder_free(nghttp3_qpack_encoder *encoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_encode_nv encodes |nv|. It writes request
|
||||
* stream into |rbuf| and writes encoder stream into |ebuf|. |nv| is
|
||||
* a header field to encode. |base| is base. |allow_blocking| is
|
||||
* nonzero if this stream can be blocked (or it has been blocked
|
||||
* already).
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder,
|
||||
uint64_t *pmax_cnt, uint64_t *pmin_cnt,
|
||||
nghttp3_buf *rbuf, nghttp3_buf *ebuf,
|
||||
const nghttp3_nv *nv, uint64_t base,
|
||||
int allow_blocking);
|
||||
|
||||
/* nghttp3_qpack_lookup_result stores a result of table lookup. */
|
||||
typedef struct nghttp3_qpack_lookup_result {
|
||||
/* index is an index of matched entry. -1 if no match is made. */
|
||||
nghttp3_ssize index;
|
||||
/* name_value_match is nonzero if both name and value are
|
||||
matched. */
|
||||
int name_value_match;
|
||||
/* pb_index is the absolute index of matched post-based dynamic
|
||||
table entry. -1 if no such entry exists. */
|
||||
nghttp3_ssize pb_index;
|
||||
} nghttp3_qpack_lookup_result;
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_lookup_stable searches |nv| in static table. |token|
|
||||
* is a token of nv->name and it is -1 if there is no corresponding
|
||||
* token defined. |indexing_mode| provides indexing strategy.
|
||||
*/
|
||||
nghttp3_qpack_lookup_result
|
||||
nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token,
|
||||
nghttp3_qpack_indexing_mode indexing_mode);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_lookup_dtable searches |nv| in dynamic table.
|
||||
* |token| is a token of nv->name and it is -1 if there is no
|
||||
* corresponding token defined. |hash| is a hash of nv->name.
|
||||
* |indexing_mode| provides indexing strategy. |krcnt| is Known
|
||||
* Received Count. |allow_blocking| is nonzero if this stream can be
|
||||
* blocked (or it has been blocked already).
|
||||
*/
|
||||
nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable(
|
||||
nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token,
|
||||
uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt,
|
||||
int allow_blocking);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_field_section_prefix writes Encoded
|
||||
* Field Section Prefix into |pbuf|. |ricnt| is Required Insert
|
||||
* Count. |base| is Base.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_field_section_prefix(
|
||||
nghttp3_qpack_encoder *encoder, nghttp3_buf *pbuf, uint64_t ricnt,
|
||||
uint64_t base);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_static_indexed writes Indexed Header
|
||||
* Field to |rbuf|. |absidx| is an absolute index into static table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_static_indexed(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *rbuf,
|
||||
uint64_t absidx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_dynamic_indexed writes Indexed Header
|
||||
* Field to |rbuf|. |absidx| is an absolute index into dynamic table.
|
||||
* |base| is base.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_dynamic_indexed(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *rbuf,
|
||||
uint64_t absidx, uint64_t base);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_static_indexed writes Literal Header
|
||||
* Field With Name Reference to |rbuf|. |absidx| is an absolute index
|
||||
* into static table to reference a name. |nv| is a header field to
|
||||
* encode.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_static_indexed_name(
|
||||
nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
|
||||
const nghttp3_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_dynamic_indexed writes Literal Header
|
||||
* Field With Name Reference to |rbuf|. |absidx| is an absolute index
|
||||
* into dynamic table to reference a name. |base| is a base. |nv| is
|
||||
* a header field to encode.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_dynamic_indexed_name(
|
||||
nghttp3_qpack_encoder *encoder, nghttp3_buf *rbuf, uint64_t absidx,
|
||||
uint64_t base, const nghttp3_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_literal writes Literal Header Field
|
||||
* With Literal Name to |rbuf|. |nv| is a header field to encode.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *rbuf,
|
||||
const nghttp3_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_static_insert writes Insert With Name
|
||||
* Reference to |ebuf|. |absidx| is an absolute index into static
|
||||
* table to reference a name. |nv| is a header field to insert.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_static_insert(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf,
|
||||
uint64_t absidx,
|
||||
const nghttp3_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_dynamic_insert writes Insert With Name
|
||||
* Reference to |ebuf|. |absidx| is an absolute index into dynamic
|
||||
* table to reference a name. |nv| is a header field to insert.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_dynamic_insert(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf,
|
||||
uint64_t absidx,
|
||||
const nghttp3_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_duplicate_insert writes Duplicate to
|
||||
* |ebuf|. |absidx| is an absolute index into dynamic table to
|
||||
* reference an entry.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_duplicate_insert(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf,
|
||||
uint64_t absidx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_literal_insert writes Insert With
|
||||
* Literal Name to |ebuf|. |nv| is a header field to insert.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_literal_insert(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf,
|
||||
const nghttp3_nv *nv);
|
||||
|
||||
int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_qpack_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_block_stream blocks |stream|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_qpack_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_unblock_stream unblocks |stream|.
|
||||
*/
|
||||
void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_qpack_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_unblock unblocks stream whose max_cnt is less
|
||||
* than or equal to |max_cnt|.
|
||||
*/
|
||||
void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder,
|
||||
uint64_t max_cnt);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_find_stream returns stream whose stream ID is
|
||||
* |stream_id|. This function returns NULL if there is no such
|
||||
* stream.
|
||||
*/
|
||||
nghttp3_qpack_stream *
|
||||
nghttp3_qpack_encoder_find_stream(nghttp3_qpack_encoder *encoder,
|
||||
int64_t stream_id);
|
||||
|
||||
uint64_t nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder *encoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_shrink_dtable shrinks dynamic table so that
|
||||
* the dynamic table size is less than or equal to maximum size.
|
||||
*/
|
||||
void nghttp3_qpack_encoder_shrink_dtable(nghttp3_qpack_encoder *encoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_process_dtable_update processes pending
|
||||
* dynamic table size update. It might write encoder stream into
|
||||
* |ebuf|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_process_dtable_update(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_write_set_dtable_cap writes Set Dynamic Table
|
||||
* Capacity. to |ebuf|. |cap| is the capacity of dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_write_set_dtable_cap(nghttp3_qpack_encoder *encoder,
|
||||
nghttp3_buf *ebuf, size_t cap);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_context_dtable_add adds |qnv| to dynamic table. If
|
||||
* |ctx| is a part of encoder, |dtable_map| is not NULL. |hash| is a
|
||||
* hash value of name.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx,
|
||||
nghttp3_qpack_nv *qnv,
|
||||
nghttp3_qpack_map *dtable_map,
|
||||
uint32_t hash);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_dtable_static_add adds |nv| to dynamic table
|
||||
* by referencing static table entry at an absolute index |absidx|.
|
||||
* The hash of name is given as |hash|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_dtable_static_add(nghttp3_qpack_encoder *encoder,
|
||||
uint64_t absidx,
|
||||
const nghttp3_nv *nv,
|
||||
uint32_t hash);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_dtable_dynamic_add adds |nv| to dynamic table
|
||||
* by referencing dynamic table entry at an absolute index |absidx|.
|
||||
* The hash of name is given as |hash|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_dtable_dynamic_add(nghttp3_qpack_encoder *encoder,
|
||||
uint64_t absidx,
|
||||
const nghttp3_nv *nv,
|
||||
uint32_t hash);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_dtable_duplicate_add duplicates dynamic table
|
||||
* entry at an absolute index |absidx|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_dtable_duplicate_add(nghttp3_qpack_encoder *encoder,
|
||||
uint64_t absidx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_encoder_dtable_literal_add adds |nv| to dynamic
|
||||
* table. |token| is a token of name and is -1 if it has no token
|
||||
* value defined. |hash| is a hash of name.
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_encoder_dtable_literal_add(nghttp3_qpack_encoder *encoder,
|
||||
const nghttp3_nv *nv,
|
||||
int32_t token, uint32_t hash);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_context_dtable_get returns dynamic table entry whose
|
||||
* absolute index is |absidx|. This function assumes that such entry
|
||||
* exists.
|
||||
*/
|
||||
nghttp3_qpack_entry *
|
||||
nghttp3_qpack_context_dtable_get(nghttp3_qpack_context *ctx, uint64_t absidx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_context_dtable_top returns latest dynamic table
|
||||
* entry. This function assumes dynamic table is not empty.
|
||||
*/
|
||||
nghttp3_qpack_entry *
|
||||
nghttp3_qpack_context_dtable_top(nghttp3_qpack_context *ctx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_entry_init initializes |ent|. |qnv| is a header
|
||||
* field. |sum| is the sum of table space occupied by all entries
|
||||
* inserted so far. It does not include this entry. |absidx| is an
|
||||
* absolute index of this entry. |hash| is a hash of header field
|
||||
* name. This function increases reference count of qnv->nv.name and
|
||||
* qnv->nv.value.
|
||||
*/
|
||||
void nghttp3_qpack_entry_init(nghttp3_qpack_entry *ent, nghttp3_qpack_nv *qnv,
|
||||
size_t sum, uint64_t absidx, uint32_t hash);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_entry_free frees memory allocated for |ent|.
|
||||
*/
|
||||
void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_put_varint_len returns the required number of bytes
|
||||
* to encode |n| with |prefix| bits.
|
||||
*/
|
||||
size_t nghttp3_qpack_put_varint_len(uint64_t n, size_t prefix);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_put_varint encodes |n| using variable integer
|
||||
* encoding with |prefix| bits into |buf|. This function assumes the
|
||||
* buffer pointed by |buf| has enough space. This function returns
|
||||
* the one byte beyond the last write (buf +
|
||||
* nghttp3_qpack_put_varint_len(n, prefix)).
|
||||
*/
|
||||
uint8_t *nghttp3_qpack_put_varint(uint8_t *buf, uint64_t n, size_t prefix);
|
||||
|
||||
/* nghttp3_qpack_encoder_stream_state is a set of states for encoder
|
||||
stream decoding. */
|
||||
typedef enum nghttp3_qpack_encoder_stream_state {
|
||||
NGHTTP3_QPACK_ES_STATE_OPCODE,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_INDEX,
|
||||
NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_NAMELEN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_NAME_HUFFMAN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_NAME,
|
||||
NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_VALUELEN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_VALUE_HUFFMAN,
|
||||
NGHTTP3_QPACK_ES_STATE_READ_VALUE,
|
||||
} nghttp3_qpack_encoder_stream_state;
|
||||
|
||||
/* nghttp3_qpack_encoder_stream_opcode is a set of opcodes used in
|
||||
encoder stream. */
|
||||
typedef enum nghttp3_qpack_encoder_stream_opcode {
|
||||
NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED,
|
||||
NGHTTP3_QPACK_ES_OPCODE_INSERT,
|
||||
NGHTTP3_QPACK_ES_OPCODE_DUPLICATE,
|
||||
NGHTTP3_QPACK_ES_OPCODE_SET_DTABLE_CAP,
|
||||
} nghttp3_qpack_encoder_stream_opcode;
|
||||
|
||||
/* nghttp3_qpack_request_stream_state is a set of states for request
|
||||
stream decoding. */
|
||||
typedef enum nghttp3_qpack_request_stream_state {
|
||||
NGHTTP3_QPACK_RS_STATE_RICNT,
|
||||
NGHTTP3_QPACK_RS_STATE_DBASE_SIGN,
|
||||
NGHTTP3_QPACK_RS_STATE_DBASE,
|
||||
NGHTTP3_QPACK_RS_STATE_OPCODE,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_INDEX,
|
||||
NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_NAMELEN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_NAME_HUFFMAN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_NAME,
|
||||
NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_VALUELEN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_VALUE_HUFFMAN,
|
||||
NGHTTP3_QPACK_RS_STATE_READ_VALUE,
|
||||
NGHTTP3_QPACK_RS_STATE_BLOCKED,
|
||||
} nghttp3_qpack_request_stream_state;
|
||||
|
||||
/* nghttp3_qpack_request_stream_opcode is a set of opcodes used in
|
||||
request stream. */
|
||||
typedef enum nghttp3_qpack_request_stream_opcode {
|
||||
NGHTTP3_QPACK_RS_OPCODE_INDEXED,
|
||||
NGHTTP3_QPACK_RS_OPCODE_INDEXED_PB,
|
||||
NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME,
|
||||
NGHTTP3_QPACK_RS_OPCODE_INDEXED_NAME_PB,
|
||||
NGHTTP3_QPACK_RS_OPCODE_LITERAL,
|
||||
} nghttp3_qpack_request_stream_opcode;
|
||||
|
||||
struct nghttp3_qpack_decoder {
|
||||
nghttp3_qpack_context ctx;
|
||||
/* state is a current state of reading encoder stream. */
|
||||
nghttp3_qpack_encoder_stream_state state;
|
||||
/* opcode is an encoder stream opcode being processed. */
|
||||
nghttp3_qpack_encoder_stream_opcode opcode;
|
||||
/* rstate is a set of intermediate state which are used to process
|
||||
encoder stream. */
|
||||
nghttp3_qpack_read_state rstate;
|
||||
/* dbuf is decoder stream. */
|
||||
nghttp3_buf dbuf;
|
||||
/* written_icnt is Insert Count written to decoder stream so far. */
|
||||
uint64_t written_icnt;
|
||||
/* max_concurrent_streams is the number of concurrent streams that a
|
||||
remote endpoint can open, including both bidirectional and
|
||||
unidirectional streams which potentially receives QPACK encoded
|
||||
HEADER frame. */
|
||||
size_t max_concurrent_streams;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_init initializes |decoder|.
|
||||
* |max_dtable_size| is the maximum size of dynamic table.
|
||||
* |max_blocked| is the maximum number of stream which can be blocked.
|
||||
* |mem| is a memory allocator.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
|
||||
size_t max_dtable_size, size_t max_blocked,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_free frees memory allocated for |decoder|.
|
||||
* This function does not free memory pointed by |decoder|.
|
||||
*/
|
||||
void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_dtable_indexed_add adds entry received in
|
||||
* Insert With Name Reference to dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Space required for a decoded entry exceeds max dynamic table
|
||||
* size.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_dtable_indexed_add(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_dtable_static_add adds entry received in
|
||||
* Insert With Name Reference (static) to dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Space required for a decoded entry exceeds max dynamic table
|
||||
* size.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_dtable_dynamic_add adds entry received in
|
||||
* Insert With Name Reference (dynamic) to dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Space required for a decoded entry exceeds max dynamic table
|
||||
* size.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_dtable_duplicate_add adds entry received in
|
||||
* Duplicate to dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Space required for a decoded entry exceeds max dynamic table
|
||||
* size.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_dtable_duplicate_add(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_dtable_literal_add adds entry received in
|
||||
* Insert With Literal Name to dynamic table.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Space required for a decoded entry exceeds max dynamic table
|
||||
* size.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder);
|
||||
|
||||
struct nghttp3_qpack_stream_context {
|
||||
/* state is a current state of reading request stream. */
|
||||
nghttp3_qpack_request_stream_state state;
|
||||
/* rstate is a set of intermediate state which are used to process
|
||||
request stream. */
|
||||
nghttp3_qpack_read_state rstate;
|
||||
const nghttp3_mem *mem;
|
||||
/* opcode is a request stream opcode being processed. */
|
||||
nghttp3_qpack_request_stream_opcode opcode;
|
||||
int64_t stream_id;
|
||||
/* ricnt is Required Insert Count to decode this header block. */
|
||||
uint64_t ricnt;
|
||||
/* base is Base in Header Block Prefix. */
|
||||
uint64_t base;
|
||||
/* dbase_sign is the delta base sign in Header Block Prefix. */
|
||||
int dbase_sign;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_stream_context_init initializes |sctx|.
|
||||
*/
|
||||
void nghttp3_qpack_stream_context_init(nghttp3_qpack_stream_context *sctx,
|
||||
int64_t stream_id,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_stream_context_free frees memory allocated for
|
||||
* |sctx|. This function does not free memory pointed by |sctx|.
|
||||
*/
|
||||
void nghttp3_qpack_stream_context_free(nghttp3_qpack_stream_context *sctx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_reconstruct_ricnt reconstructs Required
|
||||
* Insert Count from the encoded form |encricnt| and stores Required
|
||||
* Insert Count in |*dest|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED
|
||||
* Unable to reconstruct Required Insert Count.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_reconstruct_ricnt(nghttp3_qpack_decoder *decoder,
|
||||
uint64_t *dest, uint64_t encricnt);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_rel2abs converts relative index rstate->left
|
||||
* received in encoder stream to absolute index and stores it in
|
||||
* rstate->absidx.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_QPACK_ENCODER_STREAM
|
||||
* Relative index is invalid.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_rel2abs(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_read_state *rstate);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_brel2abs converts Base relative index
|
||||
* rstate->left received in request stream to absolute index and
|
||||
* stores it in rstate->absidx.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED
|
||||
* Base relative index is invalid.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_brel2abs(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_stream_context *sctx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_pbrel2abs converts Post-Base relative index
|
||||
* rstate->left received in request stream to absolute index and
|
||||
* stores it in rstate->absidx.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED
|
||||
* Post-Base relative index is invalid.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_pbrel2abs(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_stream_context *sctx);
|
||||
|
||||
void nghttp3_qpack_decoder_emit_indexed(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_stream_context *sctx,
|
||||
nghttp3_qpack_nv *nv);
|
||||
|
||||
void nghttp3_qpack_decoder_emit_indexed_name(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_stream_context *sctx,
|
||||
nghttp3_qpack_nv *nv);
|
||||
|
||||
void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder,
|
||||
nghttp3_qpack_stream_context *sctx,
|
||||
nghttp3_qpack_nv *nv);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_decoder_write_section_ack writes Section
|
||||
* Acknowledgement to decoder stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP3_ERR_QPACK_FATAL
|
||||
* Decoder stream overflow.
|
||||
*/
|
||||
int nghttp3_qpack_decoder_write_section_ack(
|
||||
nghttp3_qpack_decoder *decoder, const nghttp3_qpack_stream_context *sctx);
|
||||
|
||||
#endif /* NGHTTP3_QPACK_H */
|
122
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c
vendored
Normal file
122
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2013 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 "nghttp3_qpack_huffman.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp3_conv.h"
|
||||
|
||||
size_t nghttp3_qpack_huffman_encode_count(const uint8_t *src, size_t len) {
|
||||
size_t i;
|
||||
size_t nbits = 0;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
nbits += huffman_sym_table[src[i]].nbits;
|
||||
}
|
||||
/* pad the prefix of EOS (256) */
|
||||
return (nbits + 7) / 8;
|
||||
}
|
||||
|
||||
uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src,
|
||||
size_t srclen) {
|
||||
const nghttp3_qpack_huffman_sym *sym;
|
||||
const uint8_t *end = src + srclen;
|
||||
uint64_t code = 0;
|
||||
size_t nbits = 0;
|
||||
uint32_t x;
|
||||
|
||||
for (; src != end;) {
|
||||
sym = &huffman_sym_table[*src++];
|
||||
code |= (uint64_t)sym->code << (32 - nbits);
|
||||
nbits += sym->nbits;
|
||||
if (nbits < 32) {
|
||||
continue;
|
||||
}
|
||||
x = htonl((uint32_t)(code >> 32));
|
||||
memcpy(dest, &x, 4);
|
||||
dest += 4;
|
||||
code <<= 32;
|
||||
nbits -= 32;
|
||||
}
|
||||
|
||||
for (; nbits >= 8;) {
|
||||
*dest++ = (uint8_t)(code >> 56);
|
||||
code <<= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
if (nbits) {
|
||||
*dest++ = (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1));
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void nghttp3_qpack_huffman_decode_context_init(
|
||||
nghttp3_qpack_huffman_decode_context *ctx) {
|
||||
ctx->fstate = NGHTTP3_QPACK_HUFFMAN_ACCEPTED;
|
||||
}
|
||||
|
||||
nghttp3_ssize
|
||||
nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx,
|
||||
uint8_t *dest, const uint8_t *src, size_t srclen,
|
||||
int fin) {
|
||||
uint8_t *p = dest;
|
||||
const uint8_t *end = src + srclen;
|
||||
nghttp3_qpack_huffman_decode_node node = {ctx->fstate, 0};
|
||||
const nghttp3_qpack_huffman_decode_node *t = &node;
|
||||
uint8_t c;
|
||||
|
||||
/* We use the decoding algorithm described in
|
||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||
for (; src != end;) {
|
||||
c = *src++;
|
||||
t = &qpack_huffman_decode_table[t->fstate & 0x1ff][c >> 4];
|
||||
if (t->fstate & NGHTTP3_QPACK_HUFFMAN_SYM) {
|
||||
*p++ = t->sym;
|
||||
}
|
||||
|
||||
t = &qpack_huffman_decode_table[t->fstate & 0x1ff][c & 0xf];
|
||||
if (t->fstate & NGHTTP3_QPACK_HUFFMAN_SYM) {
|
||||
*p++ = t->sym;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->fstate = t->fstate;
|
||||
|
||||
if (fin && !(ctx->fstate & NGHTTP3_QPACK_HUFFMAN_ACCEPTED)) {
|
||||
return NGHTTP3_ERR_QPACK_FATAL;
|
||||
}
|
||||
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
int nghttp3_qpack_huffman_decode_failure_state(
|
||||
nghttp3_qpack_huffman_decode_context *ctx) {
|
||||
return ctx->fstate == 0x100;
|
||||
}
|
108
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h
vendored
Normal file
108
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2013 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 NGHTTP3_QPACK_HUFFMAN_H
|
||||
#define NGHTTP3_QPACK_HUFFMAN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
typedef struct nghttp3_qpack_huffman_sym {
|
||||
/* The number of bits in this code */
|
||||
uint32_t nbits;
|
||||
/* Huffman code aligned to LSB */
|
||||
uint32_t code;
|
||||
} nghttp3_qpack_huffman_sym;
|
||||
|
||||
extern const nghttp3_qpack_huffman_sym huffman_sym_table[];
|
||||
|
||||
size_t nghttp3_qpack_huffman_encode_count(const uint8_t *src, size_t len);
|
||||
|
||||
uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
typedef enum nghttp3_qpack_huffman_decode_flag {
|
||||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP3_QPACK_HUFFMAN_ACCEPTED = 1 << 14,
|
||||
/* This state emits symbol */
|
||||
NGHTTP3_QPACK_HUFFMAN_SYM = 1 << 15,
|
||||
} nghttp3_qpack_huffman_decode_flag;
|
||||
|
||||
typedef struct nghttp3_qpack_huffman_decode_node {
|
||||
/* fstate is the current huffman decoding state, which is actually
|
||||
the node ID of internal huffman tree with
|
||||
nghttp3_qpack_huffman_decode_flag OR-ed. We have 257 leaf nodes,
|
||||
but they are identical to root node other than emitting a symbol,
|
||||
so we have 256 internal nodes [1..256], inclusive. The node ID
|
||||
256 is a special node and it is a terminal state that means
|
||||
decoding failed. */
|
||||
uint16_t fstate;
|
||||
/* symbol if NGHTTP3_QPACK_HUFFMAN_SYM flag set */
|
||||
uint8_t sym;
|
||||
} nghttp3_qpack_huffman_decode_node;
|
||||
|
||||
typedef struct nghttp3_qpack_huffman_decode_context {
|
||||
/* fstate is the current huffman decoding state. */
|
||||
uint16_t fstate;
|
||||
} nghttp3_qpack_huffman_decode_context;
|
||||
|
||||
extern const nghttp3_qpack_huffman_decode_node qpack_huffman_decode_table[][16];
|
||||
|
||||
void nghttp3_qpack_huffman_decode_context_init(
|
||||
nghttp3_qpack_huffman_decode_context *ctx);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_huffman_decode decodes huffman encoded byte string
|
||||
* stored in |src| of length |srclen|. |ctx| is a decoding context.
|
||||
* |ctx| remembers the decoding state, and caller can call this
|
||||
* function multiple times to feed each chunk of huffman encoded
|
||||
* substring. |fin| must be nonzero if |src| contains the last chunk
|
||||
* of huffman string. The decoded string is written to the buffer
|
||||
* pointed by |dest|. This function assumes that the buffer pointed
|
||||
* by |dest| contains enough memory to store decoded byte string.
|
||||
*
|
||||
* This function returns the number of bytes written to |dest|, or one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_QPACK_FATAL
|
||||
* Could not decode huffman string.
|
||||
*/
|
||||
nghttp3_ssize
|
||||
nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx,
|
||||
uint8_t *dest, const uint8_t *src, size_t srclen,
|
||||
int fin);
|
||||
|
||||
/*
|
||||
* nghttp3_qpack_huffman_decode_failure_state returns nonzero if |ctx|
|
||||
* indicates that huffman decoding context is in failure state.
|
||||
*/
|
||||
int nghttp3_qpack_huffman_decode_failure_state(
|
||||
nghttp3_qpack_huffman_decode_context *ctx);
|
||||
|
||||
#endif /* NGHTTP3_QPACK_HUFFMAN_H */
|
4981
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c
vendored
Normal file
4981
deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
62
deps/ngtcp2/nghttp3/lib/nghttp3_range.c
vendored
Normal file
62
deps/ngtcp2/nghttp3/lib/nghttp3_range.c
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_range.h"
|
||||
#include "nghttp3_macro.h"
|
||||
|
||||
void nghttp3_range_init(nghttp3_range *r, uint64_t begin, uint64_t end) {
|
||||
r->begin = begin;
|
||||
r->end = end;
|
||||
}
|
||||
|
||||
nghttp3_range nghttp3_range_intersect(const nghttp3_range *a,
|
||||
const nghttp3_range *b) {
|
||||
nghttp3_range r = {0, 0};
|
||||
uint64_t begin = nghttp3_max(a->begin, b->begin);
|
||||
uint64_t end = nghttp3_min(a->end, b->end);
|
||||
if (begin < end) {
|
||||
nghttp3_range_init(&r, begin, end);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t nghttp3_range_len(const nghttp3_range *r) { return r->end - r->begin; }
|
||||
|
||||
int nghttp3_range_eq(const nghttp3_range *a, const nghttp3_range *b) {
|
||||
return a->begin == b->begin && a->end == b->end;
|
||||
}
|
||||
|
||||
void nghttp3_range_cut(nghttp3_range *left, nghttp3_range *right,
|
||||
const nghttp3_range *a, const nghttp3_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 nghttp3_range_not_after(const nghttp3_range *a, const nghttp3_range *b) {
|
||||
return a->end <= b->end;
|
||||
}
|
81
deps/ngtcp2/nghttp3/lib/nghttp3_range.h
vendored
Normal file
81
deps/ngtcp2/nghttp3/lib/nghttp3_range.h
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_RANGE_H
|
||||
#define NGHTTP3_RANGE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
/*
|
||||
* nghttp3_range represents half-closed range [begin, end).
|
||||
*/
|
||||
typedef struct nghttp3_range {
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
} nghttp3_range;
|
||||
|
||||
/*
|
||||
* nghttp3_range_init initializes |r| with the range [|begin|, |end|).
|
||||
*/
|
||||
void nghttp3_range_init(nghttp3_range *r, uint64_t begin, uint64_t end);
|
||||
|
||||
/*
|
||||
* nghttp3_range_intersect returns the intersection of |a| and |b|.
|
||||
* If they do not overlap, it returns empty range.
|
||||
*/
|
||||
nghttp3_range nghttp3_range_intersect(const nghttp3_range *a,
|
||||
const nghttp3_range *b);
|
||||
|
||||
/*
|
||||
* nghttp3_range_len returns the length of |r|.
|
||||
*/
|
||||
uint64_t nghttp3_range_len(const nghttp3_range *r);
|
||||
|
||||
/*
|
||||
* nghttp3_range_eq returns nonzero if |a| equals |b|, such that
|
||||
* a->begin == b->begin, and a->end == b->end hold.
|
||||
*/
|
||||
int nghttp3_range_eq(const nghttp3_range *a, const nghttp3_range *b);
|
||||
|
||||
/*
|
||||
* nghttp3_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 nghttp3_range_cut(nghttp3_range *left, nghttp3_range *right,
|
||||
const nghttp3_range *a, const nghttp3_range *b);
|
||||
|
||||
/*
|
||||
* nghttp3_range_not_after returns nonzero if the right edge of |a|
|
||||
* does not go beyond of the right edge of |b|.
|
||||
*/
|
||||
int nghttp3_range_not_after(const nghttp3_range *a, const nghttp3_range *b);
|
||||
|
||||
#endif /* NGHTTP3_RANGE_H */
|
109
deps/ngtcp2/nghttp3/lib/nghttp3_rcbuf.c
vendored
Normal file
109
deps/ngtcp2/nghttp3/lib/nghttp3_rcbuf.c
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2016 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 "nghttp3_rcbuf.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
#include "nghttp3_str.h"
|
||||
|
||||
int nghttp3_rcbuf_new(nghttp3_rcbuf **rcbuf_ptr, size_t size,
|
||||
const nghttp3_mem *mem) {
|
||||
uint8_t *p;
|
||||
|
||||
p = nghttp3_mem_malloc(mem, sizeof(nghttp3_rcbuf) + size);
|
||||
if (p == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
*rcbuf_ptr = (void *)p;
|
||||
|
||||
(*rcbuf_ptr)->mem_user_data = mem->mem_user_data;
|
||||
(*rcbuf_ptr)->free = mem->free;
|
||||
(*rcbuf_ptr)->base = p + sizeof(nghttp3_rcbuf);
|
||||
(*rcbuf_ptr)->len = size;
|
||||
(*rcbuf_ptr)->ref = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp3_rcbuf_new2(nghttp3_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, const nghttp3_mem *mem) {
|
||||
int rv;
|
||||
uint8_t *p;
|
||||
|
||||
rv = nghttp3_rcbuf_new(rcbuf_ptr, srclen + 1, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
(*rcbuf_ptr)->len = srclen;
|
||||
p = (*rcbuf_ptr)->base;
|
||||
|
||||
if (srclen) {
|
||||
p = nghttp3_cpymem(p, src, srclen);
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp3_rcbuf_del(nghttp3_rcbuf *rcbuf) {
|
||||
nghttp3_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp3_rcbuf_incref(nghttp3_rcbuf *rcbuf) {
|
||||
if (rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
++rcbuf->ref;
|
||||
}
|
||||
|
||||
void nghttp3_rcbuf_decref(nghttp3_rcbuf *rcbuf) {
|
||||
if (rcbuf == NULL || rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(rcbuf->ref > 0);
|
||||
|
||||
if (--rcbuf->ref == 0) {
|
||||
nghttp3_rcbuf_del(rcbuf);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp3_vec nghttp3_rcbuf_get_buf(const nghttp3_rcbuf *rcbuf) {
|
||||
nghttp3_vec res = {rcbuf->base, rcbuf->len};
|
||||
return res;
|
||||
}
|
||||
|
||||
int nghttp3_rcbuf_is_static(const nghttp3_rcbuf *rcbuf) {
|
||||
return rcbuf->ref == -1;
|
||||
}
|
82
deps/ngtcp2/nghttp3/lib/nghttp3_rcbuf.h
vendored
Normal file
82
deps/ngtcp2/nghttp3/lib/nghttp3_rcbuf.h
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* Copyright (c) 2016 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 NGHTTP3_RCBUF_H
|
||||
#define NGHTTP3_RCBUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
struct nghttp3_rcbuf {
|
||||
/* custom memory allocator belongs to the mem parameter when
|
||||
creating this object. */
|
||||
void *mem_user_data;
|
||||
nghttp3_free free;
|
||||
/* The pointer to the underlying buffer */
|
||||
uint8_t *base;
|
||||
/* Size of buffer pointed by |base|. */
|
||||
size_t len;
|
||||
/* Reference count */
|
||||
int32_t ref;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocates nghttp3_rcbuf object with |size| as initial buffer size.
|
||||
* When the function succeeds, the reference count becomes 1.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_rcbuf_new(nghttp3_rcbuf **rcbuf_ptr, size_t size,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* Like nghttp3_rcbuf_new(), but initializes the buffer with |src| of
|
||||
* length |srclen|. This function allocates additional byte at the
|
||||
* end and puts '\0' into it, so that the resulting buffer could be
|
||||
* used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to
|
||||
* |srclen|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_rcbuf_new2(nghttp3_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp3_rcbuf_del(nghttp3_rcbuf *rcbuf);
|
||||
|
||||
#endif /* NGHTTP3_RCBUF_H */
|
159
deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c
vendored
Normal file
159
deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c
vendored
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_ringbuf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#ifdef WIN32
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "nghttp3_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 nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size,
|
||||
const nghttp3_mem *mem) {
|
||||
if (nmemb) {
|
||||
#ifdef WIN32
|
||||
assert(1 == __popcnt((unsigned int)nmemb));
|
||||
#else
|
||||
assert(1 == __builtin_popcount((unsigned int)nmemb));
|
||||
#endif
|
||||
|
||||
rb->buf = nghttp3_mem_malloc(mem, nmemb * size);
|
||||
if (rb->buf == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
} else {
|
||||
rb->buf = NULL;
|
||||
}
|
||||
|
||||
rb->mem = mem;
|
||||
rb->nmemb = nmemb;
|
||||
rb->size = size;
|
||||
rb->first = 0;
|
||||
rb->len = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp3_ringbuf_free(nghttp3_ringbuf *rb) {
|
||||
if (rb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp3_mem_free(rb->mem, rb->buf);
|
||||
}
|
||||
|
||||
void *nghttp3_ringbuf_push_front(nghttp3_ringbuf *rb) {
|
||||
rb->first = (rb->first - 1) & (rb->nmemb - 1);
|
||||
rb->len = nghttp3_min(rb->nmemb, rb->len + 1);
|
||||
|
||||
return (void *)&rb->buf[rb->first * rb->size];
|
||||
}
|
||||
|
||||
void *nghttp3_ringbuf_push_back(nghttp3_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 nghttp3_ringbuf_pop_front(nghttp3_ringbuf *rb) {
|
||||
rb->first = (rb->first + 1) & (rb->nmemb - 1);
|
||||
--rb->len;
|
||||
}
|
||||
|
||||
void nghttp3_ringbuf_pop_back(nghttp3_ringbuf *rb) {
|
||||
assert(rb->len);
|
||||
--rb->len;
|
||||
}
|
||||
|
||||
void nghttp3_ringbuf_resize(nghttp3_ringbuf *rb, size_t len) {
|
||||
assert(len <= rb->nmemb);
|
||||
rb->len = len;
|
||||
}
|
||||
|
||||
void *nghttp3_ringbuf_get(nghttp3_ringbuf *rb, size_t offset) {
|
||||
assert(offset < rb->len);
|
||||
offset = (rb->first + offset) & (rb->nmemb - 1);
|
||||
return &rb->buf[offset * rb->size];
|
||||
}
|
||||
|
||||
int nghttp3_ringbuf_full(nghttp3_ringbuf *rb) { return rb->len == rb->nmemb; }
|
||||
|
||||
int nghttp3_ringbuf_reserve(nghttp3_ringbuf *rb, size_t nmemb) {
|
||||
uint8_t *buf;
|
||||
|
||||
if (rb->nmemb >= nmemb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
assert(1 == __popcnt((unsigned int)nmemb));
|
||||
#else
|
||||
assert(1 == __builtin_popcount((unsigned int)nmemb));
|
||||
#endif
|
||||
|
||||
buf = nghttp3_mem_malloc(rb->mem, nmemb * rb->size);
|
||||
if (buf == NULL) {
|
||||
return NGHTTP3_ERR_NOMEM;
|
||||
}
|
||||
|
||||
if (rb->buf != NULL) {
|
||||
if (rb->first + rb->len <= rb->nmemb) {
|
||||
memcpy(buf, rb->buf + rb->first * rb->size, rb->len * rb->size);
|
||||
rb->first = 0;
|
||||
} else {
|
||||
memcpy(buf, rb->buf + rb->first * rb->size,
|
||||
(rb->nmemb - rb->first) * rb->size);
|
||||
memcpy(buf + (rb->nmemb - rb->first) * rb->size, rb->buf,
|
||||
(rb->len - (rb->nmemb - rb->first)) * rb->size);
|
||||
rb->first = 0;
|
||||
}
|
||||
|
||||
nghttp3_mem_free(rb->mem, rb->buf);
|
||||
}
|
||||
|
||||
rb->buf = buf;
|
||||
rb->nmemb = nmemb;
|
||||
|
||||
return 0;
|
||||
}
|
113
deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h
vendored
Normal file
113
deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_RINGBUF_H
|
||||
#define NGHTTP3_RINGBUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_mem.h"
|
||||
|
||||
typedef struct nghttp3_ringbuf {
|
||||
/* buf points to the underlying buffer. */
|
||||
uint8_t *buf;
|
||||
const nghttp3_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;
|
||||
} nghttp3_ringbuf;
|
||||
|
||||
/*
|
||||
* nghttp3_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:
|
||||
*
|
||||
* NGHTTP3_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp3_ringbuf_free frees resources allocated for |rb|. This
|
||||
* function does not free the memory pointed by |rb|.
|
||||
*/
|
||||
void nghttp3_ringbuf_free(nghttp3_ringbuf *rb);
|
||||
|
||||
/* nghttp3_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 *nghttp3_ringbuf_push_front(nghttp3_ringbuf *rb);
|
||||
|
||||
/* nghttp3_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 *nghttp3_ringbuf_push_back(nghttp3_ringbuf *rb);
|
||||
|
||||
/*
|
||||
* nghttp3_ringbuf_pop_front removes first element in |rb|.
|
||||
*/
|
||||
void nghttp3_ringbuf_pop_front(nghttp3_ringbuf *rb);
|
||||
|
||||
/*
|
||||
* nghttp3_ringbuf_pop_back removes the last element in |rb|.
|
||||
*/
|
||||
void nghttp3_ringbuf_pop_back(nghttp3_ringbuf *rb);
|
||||
|
||||
/* nghttp3_ringbuf_resize changes the number of elements stored. This
|
||||
does not change the capacity of the underlying buffer. */
|
||||
void nghttp3_ringbuf_resize(nghttp3_ringbuf *rb, size_t len);
|
||||
|
||||
/* nghttp3_ringbuf_get returns the pointer to the element at
|
||||
|offset|. */
|
||||
void *nghttp3_ringbuf_get(nghttp3_ringbuf *rb, size_t offset);
|
||||
|
||||
/* nghttp3_ringbuf_len returns the number of elements stored. */
|
||||
#define nghttp3_ringbuf_len(RB) ((RB)->len)
|
||||
|
||||
/* nghttp3_ringbuf_full returns nonzero if |rb| is full. */
|
||||
int nghttp3_ringbuf_full(nghttp3_ringbuf *rb);
|
||||
|
||||
int nghttp3_ringbuf_reserve(nghttp3_ringbuf *rb, size_t nmemb);
|
||||
|
||||
#endif /* NGHTTP3_RINGBUF_H */
|
110
deps/ngtcp2/nghttp3/lib/nghttp3_str.c
vendored
Normal file
110
deps/ngtcp2/nghttp3/lib/nghttp3_str.c
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_str.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
uint8_t *nghttp3_cpymem(uint8_t *dest, const uint8_t *src, size_t n) {
|
||||
memcpy(dest, src, n);
|
||||
return dest + n;
|
||||
}
|
||||
|
||||
/* Generated by gendowncasetbl.py */
|
||||
static const uint8_t DOWNCASE_TBL[] = {
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
};
|
||||
|
||||
void nghttp3_downcase(uint8_t *s, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
s[i] = DOWNCASE_TBL[s[i]];
|
||||
}
|
||||
}
|
40
deps/ngtcp2/nghttp3/lib/nghttp3_str.h
vendored
Normal file
40
deps/ngtcp2/nghttp3/lib/nghttp3_str.h
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_STR_H
|
||||
#define NGHTTP3_STR_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
uint8_t *nghttp3_cpymem(uint8_t *dest, const uint8_t *src, size_t n);
|
||||
|
||||
void nghttp3_downcase(uint8_t *s, size_t len);
|
||||
|
||||
#endif /* NGHTTP3_STR_H */
|
1287
deps/ngtcp2/nghttp3/lib/nghttp3_stream.c
vendored
Normal file
1287
deps/ngtcp2/nghttp3/lib/nghttp3_stream.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
407
deps/ngtcp2/nghttp3/lib/nghttp3_stream.h
vendored
Normal file
407
deps/ngtcp2/nghttp3/lib/nghttp3_stream.h
vendored
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 NGHTTP3_STREAM_H
|
||||
#define NGHTTP3_STREAM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_map.h"
|
||||
#include "nghttp3_tnode.h"
|
||||
#include "nghttp3_ringbuf.h"
|
||||
#include "nghttp3_buf.h"
|
||||
#include "nghttp3_frame.h"
|
||||
#include "nghttp3_qpack.h"
|
||||
|
||||
#define NGHTTP3_STREAM_MIN_CHUNK_SIZE 256
|
||||
|
||||
/* NGHTTP3_MIN_UNSENT_BYTES is the minimum unsent bytes which is large
|
||||
enough to fill outgoing single QUIC packet. */
|
||||
#define NGHTTP3_MIN_UNSENT_BYTES 4096
|
||||
|
||||
/* NGHTTP3_STREAM_MIN_WRITELEN is the minimum length of write to cause
|
||||
the stream to reschedule. */
|
||||
#define NGHTTP3_STREAM_MIN_WRITELEN 800
|
||||
|
||||
/* nghttp3_stream_type is unidirectional stream type. */
|
||||
typedef enum nghttp3_stream_type {
|
||||
NGHTTP3_STREAM_TYPE_CONTROL = 0x00,
|
||||
NGHTTP3_STREAM_TYPE_PUSH = 0x01,
|
||||
NGHTTP3_STREAM_TYPE_QPACK_ENCODER = 0x02,
|
||||
NGHTTP3_STREAM_TYPE_QPACK_DECODER = 0x03,
|
||||
NGHTTP3_STREAM_TYPE_UNKNOWN = UINT64_MAX,
|
||||
} nghttp3_stream_type;
|
||||
|
||||
typedef enum nghttp3_ctrl_stream_state {
|
||||
NGHTTP3_CTRL_STREAM_STATE_FRAME_TYPE,
|
||||
NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH,
|
||||
NGHTTP3_CTRL_STREAM_STATE_CANCEL_PUSH,
|
||||
NGHTTP3_CTRL_STREAM_STATE_SETTINGS,
|
||||
NGHTTP3_CTRL_STREAM_STATE_GOAWAY,
|
||||
NGHTTP3_CTRL_STREAM_STATE_MAX_PUSH_ID,
|
||||
NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME,
|
||||
NGHTTP3_CTRL_STREAM_STATE_SETTINGS_ID,
|
||||
NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE,
|
||||
} nghttp3_ctrl_stream_state;
|
||||
|
||||
typedef enum nghttp3_req_stream_state {
|
||||
NGHTTP3_REQ_STREAM_STATE_FRAME_TYPE,
|
||||
NGHTTP3_REQ_STREAM_STATE_FRAME_LENGTH,
|
||||
NGHTTP3_REQ_STREAM_STATE_DATA,
|
||||
NGHTTP3_REQ_STREAM_STATE_HEADERS,
|
||||
NGHTTP3_REQ_STREAM_STATE_PUSH_PROMISE_PUSH_ID,
|
||||
NGHTTP3_REQ_STREAM_STATE_PUSH_PROMISE,
|
||||
NGHTTP3_REQ_STREAM_STATE_IGN_PUSH_PROMISE,
|
||||
NGHTTP3_REQ_STREAM_STATE_IGN_FRAME,
|
||||
NGHTTP3_REQ_STREAM_STATE_IGN_REST,
|
||||
} nghttp3_req_stream_state;
|
||||
|
||||
typedef enum nghttp3_push_stream_state {
|
||||
NGHTTP3_PUSH_STREAM_STATE_FRAME_TYPE,
|
||||
NGHTTP3_PUSH_STREAM_STATE_FRAME_LENGTH,
|
||||
NGHTTP3_PUSH_STREAM_STATE_DATA,
|
||||
NGHTTP3_PUSH_STREAM_STATE_HEADERS,
|
||||
NGHTTP3_PUSH_STREAM_STATE_IGN_FRAME,
|
||||
NGHTTP3_PUSH_STREAM_STATE_PUSH_ID,
|
||||
NGHTTP3_PUSH_STREAM_STATE_IGN_REST,
|
||||
} nghttp3_push_stream_state;
|
||||
|
||||
typedef struct nghttp3_varint_read_state {
|
||||
int64_t acc;
|
||||
size_t left;
|
||||
} nghttp3_varint_read_state;
|
||||
|
||||
typedef struct nghttp3_stream_read_state {
|
||||
nghttp3_varint_read_state rvint;
|
||||
nghttp3_frame fr;
|
||||
int state;
|
||||
int64_t left;
|
||||
} nghttp3_stream_read_state;
|
||||
|
||||
/* NGHTTP3_STREAM_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGHTTP3_STREAM_FLAG_NONE 0x0000
|
||||
/* NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED is set when a unidirectional
|
||||
stream type is identified. */
|
||||
#define NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED 0x0001
|
||||
/* NGHTTP3_STREAM_FLAG_FC_BLOCKED indicates that stream is blocked by
|
||||
QUIC flow control. */
|
||||
#define NGHTTP3_STREAM_FLAG_FC_BLOCKED 0x0002
|
||||
/* NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED indicates that application is
|
||||
temporarily unable to provide data. */
|
||||
#define NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED 0x0004
|
||||
/* NGHTTP3_STREAM_FLAG_WRITE_END_STREAM indicates that application
|
||||
finished to feed outgoing data. */
|
||||
#define NGHTTP3_STREAM_FLAG_WRITE_END_STREAM 0x0008
|
||||
/* NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED indicates that stream is
|
||||
blocked due to QPACK decoding. */
|
||||
#define NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED 0x0010
|
||||
/* NGHTTP3_STREAM_FLAG_READ_EOF indicates that remote endpoint sent
|
||||
fin. */
|
||||
#define NGHTTP3_STREAM_FLAG_READ_EOF 0x0020
|
||||
/* NGHTTP3_STREAM_FLAG_CLOSED indicates that QUIC stream was closed.
|
||||
nghttp3_stream object can still alive because it might be blocked
|
||||
by QPACK decoder. */
|
||||
#define NGHTTP3_STREAM_FLAG_CLOSED 0x0040
|
||||
/* NGHTTP3_STREAM_FLAG_PUSH_PROMISE_BLOCKED indicates that stream is
|
||||
blocked because the corresponding PUSH_PROMISE has not been
|
||||
received yet. */
|
||||
#define NGHTTP3_STREAM_FLAG_PUSH_PROMISE_BLOCKED 0x0080
|
||||
/* NGHTTP3_STREAM_FLAG_SHUT_WR indicates that any further write
|
||||
operation to a stream is prohibited. */
|
||||
#define NGHTTP3_STREAM_FLAG_SHUT_WR 0x0100
|
||||
/* NGHTTP3_STREAM_FLAG_RESET indicates that stream is reset. */
|
||||
#define NGHTTP3_STREAM_FLAG_RESET 0x0200
|
||||
|
||||
typedef enum nghttp3_stream_http_state {
|
||||
NGHTTP3_HTTP_STATE_NONE,
|
||||
NGHTTP3_HTTP_STATE_REQ_INITIAL,
|
||||
NGHTTP3_HTTP_STATE_REQ_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_REQ_HEADERS_END,
|
||||
NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_REQ_DATA_END,
|
||||
NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_REQ_TRAILERS_END,
|
||||
NGHTTP3_HTTP_STATE_REQ_END,
|
||||
NGHTTP3_HTTP_STATE_RESP_INITIAL,
|
||||
NGHTTP3_HTTP_STATE_RESP_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_RESP_HEADERS_END,
|
||||
NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_RESP_DATA_END,
|
||||
NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN,
|
||||
NGHTTP3_HTTP_STATE_RESP_TRAILERS_END,
|
||||
NGHTTP3_HTTP_STATE_RESP_END,
|
||||
} nghttp3_stream_http_state;
|
||||
|
||||
typedef enum nghttp3_stream_http_event {
|
||||
NGHTTP3_HTTP_EVENT_DATA_BEGIN,
|
||||
NGHTTP3_HTTP_EVENT_DATA_END,
|
||||
NGHTTP3_HTTP_EVENT_HEADERS_BEGIN,
|
||||
NGHTTP3_HTTP_EVENT_HEADERS_END,
|
||||
NGHTTP3_HTTP_EVENT_PUSH_PROMISE_BEGIN,
|
||||
NGHTTP3_HTTP_EVENT_PUSH_PROMISE_END,
|
||||
NGHTTP3_HTTP_EVENT_MSG_END,
|
||||
} nghttp3_stream_http_event;
|
||||
|
||||
typedef struct nghttp3_stream nghttp3_stream;
|
||||
|
||||
typedef struct nghttp3_push_promise nghttp3_push_promise;
|
||||
|
||||
/*
|
||||
* nghttp3_stream_acked_data is a callback function which is invoked
|
||||
* when data sent on stream denoted by |stream_id| supplied from
|
||||
* application is acknowledged by remote endpoint. The number of
|
||||
* bytes acknowledged is given in |datalen|.
|
||||
*
|
||||
* The implementation of this callback must return 0 if it succeeds.
|
||||
* Returning NGHTTP3_ERR_CALLBACK_FAILURE will return to the caller
|
||||
* immediately. Any values other than 0 is treated as
|
||||
* NGHTTP3_ERR_CALLBACK_FAILURE.
|
||||
*/
|
||||
typedef int (*nghttp3_stream_acked_data)(nghttp3_stream *stream,
|
||||
int64_t stream_id, size_t datalen,
|
||||
void *user_data);
|
||||
|
||||
typedef struct nghttp3_stream_callbacks {
|
||||
nghttp3_stream_acked_data acked_data;
|
||||
} nghttp3_stream_callbacks;
|
||||
|
||||
typedef struct nghttp3_http_state {
|
||||
/* status_code is HTTP status code received. This field is used
|
||||
if connection is initialized as client. */
|
||||
int32_t status_code;
|
||||
/* content_length is the value of received content-length header
|
||||
field. */
|
||||
int64_t content_length;
|
||||
/* recv_content_length is the number of body bytes received so
|
||||
far. */
|
||||
int64_t recv_content_length;
|
||||
uint16_t flags;
|
||||
/* pri is a stream priority produced by nghttp3_pri_to_uint8. */
|
||||
uint8_t pri;
|
||||
} nghttp3_http_state;
|
||||
|
||||
struct nghttp3_stream {
|
||||
const nghttp3_mem *mem;
|
||||
nghttp3_map_entry me;
|
||||
/* node is a node in dependency tree. For server initiated
|
||||
unidirectional stream (push), scheduling is done via
|
||||
corresponding nghttp3_push_promise object pointed by pp. */
|
||||
nghttp3_tnode node;
|
||||
nghttp3_pq_entry qpack_blocked_pe;
|
||||
nghttp3_stream_callbacks callbacks;
|
||||
nghttp3_ringbuf frq;
|
||||
nghttp3_ringbuf chunks;
|
||||
nghttp3_ringbuf outq;
|
||||
/* inq stores the stream raw data which cannot be read because
|
||||
stream is blocked by QPACK decoder. */
|
||||
nghttp3_ringbuf inq;
|
||||
nghttp3_qpack_stream_context qpack_sctx;
|
||||
/* conn is a reference to underlying connection. It could be NULL
|
||||
if stream is not a request/push stream. */
|
||||
nghttp3_conn *conn;
|
||||
void *user_data;
|
||||
/* unsent_bytes is the number of bytes in outq not written yet */
|
||||
size_t unsent_bytes;
|
||||
/* outq_idx is an index into outq where next write is made. */
|
||||
size_t outq_idx;
|
||||
/* outq_offset is write offset relative to the element at outq_idx
|
||||
in outq. */
|
||||
size_t outq_offset;
|
||||
/* ack_offset is offset acknowledged by peer relative to the first
|
||||
element in outq. */
|
||||
uint64_t ack_offset;
|
||||
/* ack_done is the number of bytes notified to an application that
|
||||
they are acknowledged inside the first outq element if it is of
|
||||
type NGHTTP3_BUF_TYPE_ALIEN. */
|
||||
size_t ack_done;
|
||||
size_t unscheduled_nwrite;
|
||||
nghttp3_stream_type type;
|
||||
nghttp3_stream_read_state rstate;
|
||||
/* pp is nghttp3_push_promise that this stream fulfills. */
|
||||
nghttp3_push_promise *pp;
|
||||
/* error_code indicates the reason of closure of this stream. */
|
||||
uint64_t error_code;
|
||||
|
||||
struct {
|
||||
nghttp3_stream_http_state hstate;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
nghttp3_stream_http_state hstate;
|
||||
nghttp3_http_state http;
|
||||
} rx;
|
||||
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
typedef struct nghttp3_frame_entry {
|
||||
nghttp3_frame fr;
|
||||
union {
|
||||
struct {
|
||||
nghttp3_settings *local_settings;
|
||||
} settings;
|
||||
struct {
|
||||
nghttp3_data_reader dr;
|
||||
} data;
|
||||
} aux;
|
||||
} nghttp3_frame_entry;
|
||||
|
||||
int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id,
|
||||
uint64_t seq, const nghttp3_stream_callbacks *callbacks,
|
||||
const nghttp3_mem *mem);
|
||||
|
||||
void nghttp3_stream_del(nghttp3_stream *stream);
|
||||
|
||||
void nghttp3_varint_read_state_reset(nghttp3_varint_read_state *rvint);
|
||||
|
||||
void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate);
|
||||
|
||||
nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint,
|
||||
const uint8_t *src, size_t srclen, int fin);
|
||||
|
||||
int nghttp3_stream_frq_add(nghttp3_stream *stream,
|
||||
const nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_fill_outq(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_write_stream_type(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_write_stream_type_push_id(nghttp3_stream *stream);
|
||||
|
||||
nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin,
|
||||
nghttp3_vec *vec, size_t veccnt);
|
||||
|
||||
int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_outq_is_full(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_outq_add(nghttp3_stream *stream,
|
||||
const nghttp3_typed_buf *tbuf);
|
||||
|
||||
int nghttp3_stream_write_headers(nghttp3_stream *stream,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_write_push_promise(nghttp3_stream *stream,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_write_header_block(nghttp3_stream *stream,
|
||||
nghttp3_qpack_encoder *qenc,
|
||||
nghttp3_stream *qenc_stream,
|
||||
nghttp3_buf *rbuf, nghttp3_buf *ebuf,
|
||||
int64_t frame_type, int64_t push_id,
|
||||
const nghttp3_nv *nva, size_t nvlen);
|
||||
|
||||
int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_write_settings(nghttp3_stream *stream,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_write_cancel_push(nghttp3_stream *stream,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_write_max_push_id(nghttp3_stream *stream,
|
||||
nghttp3_frame_entry *frent);
|
||||
|
||||
int nghttp3_stream_ensure_chunk(nghttp3_stream *stream, size_t need);
|
||||
|
||||
nghttp3_buf *nghttp3_stream_get_chunk(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_is_blocked(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_stream_outq_write_done returns nonzero if all contents in
|
||||
* outq have been written.
|
||||
*/
|
||||
int nghttp3_stream_outq_write_done(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n);
|
||||
|
||||
/*
|
||||
* nghttp3_stream_is_active returns nonzero if |stream| is active. In
|
||||
* other words, it has something to send. This function does not take
|
||||
* into account its descendants.
|
||||
*/
|
||||
int nghttp3_stream_is_active(nghttp3_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_stream_require_schedule returns nonzero if |stream| should
|
||||
* be scheduled. In other words, |stream| or its descendants have
|
||||
* something to send.
|
||||
*/
|
||||
int nghttp3_stream_require_schedule(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_buffer_data(nghttp3_stream *stream, const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
size_t nghttp3_stream_get_buffered_datalen(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_ensure_qpack_stream_context(nghttp3_stream *stream);
|
||||
|
||||
void nghttp3_stream_delete_qpack_stream_context(nghttp3_stream *stream);
|
||||
|
||||
int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
|
||||
nghttp3_stream_http_event event);
|
||||
|
||||
int nghttp3_stream_empty_headers_allowed(nghttp3_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_stream_bidi_or_push returns nonzero if |stream| is
|
||||
* bidirectional or push stream.
|
||||
*/
|
||||
int nghttp3_stream_bidi_or_push(nghttp3_stream *stream);
|
||||
|
||||
/*
|
||||
* nghttp3_stream_uni returns nonzero if stream identified by
|
||||
* |stream_id| is unidirectional.
|
||||
*/
|
||||
int nghttp3_stream_uni(int64_t stream_id);
|
||||
|
||||
/*
|
||||
* nghttp3_client_stream_bidi returns nonzero if stream identified by
|
||||
* |stream_id| is client initiated bidirectional stream.
|
||||
*/
|
||||
int nghttp3_client_stream_bidi(int64_t stream_id);
|
||||
|
||||
/*
|
||||
* nghttp3_client_stream_uni returns nonzero if stream identified by
|
||||
* |stream_id| is client initiated unidirectional stream.
|
||||
*/
|
||||
int nghttp3_client_stream_uni(int64_t stream_id);
|
||||
|
||||
/*
|
||||
* nghttp3_server_stream_uni returns nonzero if stream identified by
|
||||
* |stream_id| is server initiated unidirectional stream.
|
||||
*/
|
||||
int nghttp3_server_stream_uni(int64_t stream_id);
|
||||
|
||||
#endif /* NGHTTP3_STREAM_H */
|
110
deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c
vendored
Normal file
110
deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c
vendored
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 "nghttp3_tnode.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp3_macro.h"
|
||||
#include "nghttp3_stream.h"
|
||||
#include "nghttp3_conn.h"
|
||||
#include "nghttp3_conv.h"
|
||||
|
||||
nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid,
|
||||
nghttp3_node_id_type type, int64_t id) {
|
||||
nid->type = type;
|
||||
nid->id = id;
|
||||
return nid;
|
||||
}
|
||||
|
||||
int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b) {
|
||||
return a->type == b->type && a->id == b->id;
|
||||
}
|
||||
|
||||
void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid,
|
||||
uint64_t seq, uint8_t pri) {
|
||||
assert(nghttp3_pri_uint8_urgency(pri) < NGHTTP3_URGENCY_LEVELS);
|
||||
|
||||
tnode->pe.index = NGHTTP3_PQ_BAD_INDEX;
|
||||
tnode->nid = *nid;
|
||||
tnode->seq = seq;
|
||||
tnode->cycle = 0;
|
||||
tnode->pri = pri;
|
||||
}
|
||||
|
||||
void nghttp3_tnode_free(nghttp3_tnode *tnode) { (void)tnode; }
|
||||
|
||||
static void tnode_unschedule(nghttp3_tnode *tnode, nghttp3_pq *pq) {
|
||||
assert(tnode->pe.index != NGHTTP3_PQ_BAD_INDEX);
|
||||
|
||||
nghttp3_pq_remove(pq, &tnode->pe);
|
||||
tnode->pe.index = NGHTTP3_PQ_BAD_INDEX;
|
||||
}
|
||||
|
||||
void nghttp3_tnode_unschedule(nghttp3_tnode *tnode, nghttp3_pq *pq) {
|
||||
if (tnode->pe.index == NGHTTP3_PQ_BAD_INDEX) {
|
||||
return;
|
||||
}
|
||||
|
||||
tnode_unschedule(tnode, pq);
|
||||
}
|
||||
|
||||
static uint64_t pq_get_first_cycle(nghttp3_pq *pq) {
|
||||
nghttp3_tnode *top;
|
||||
|
||||
if (nghttp3_pq_empty(pq)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
top = nghttp3_struct_of(nghttp3_pq_top(pq), nghttp3_tnode, pe);
|
||||
return top->cycle;
|
||||
}
|
||||
|
||||
int nghttp3_tnode_schedule(nghttp3_tnode *tnode, nghttp3_pq *pq,
|
||||
size_t nwrite) {
|
||||
uint64_t penalty = nwrite / NGHTTP3_STREAM_MIN_WRITELEN;
|
||||
|
||||
if (tnode->pe.index == NGHTTP3_PQ_BAD_INDEX) {
|
||||
tnode->cycle = pq_get_first_cycle(pq) +
|
||||
((nwrite == 0 || !nghttp3_pri_uint8_inc(tnode->pri))
|
||||
? 0
|
||||
: nghttp3_max(1, penalty));
|
||||
} else if (nwrite > 0) {
|
||||
if (!nghttp3_pri_uint8_inc(tnode->pri) || nghttp3_pq_size(pq) == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp3_pq_remove(pq, &tnode->pe);
|
||||
tnode->pe.index = NGHTTP3_PQ_BAD_INDEX;
|
||||
tnode->cycle += nghttp3_max(1, penalty);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nghttp3_pq_push(pq, &tnode->pe);
|
||||
}
|
||||
|
||||
int nghttp3_tnode_is_scheduled(nghttp3_tnode *tnode) {
|
||||
return tnode->pe.index != NGHTTP3_PQ_BAD_INDEX;
|
||||
}
|
82
deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h
vendored
Normal file
82
deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 NGHTTP3_TNODE_H
|
||||
#define NGHTTP3_TNODE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "nghttp3_pq.h"
|
||||
|
||||
#define NGHTTP3_TNODE_MAX_CYCLE_GAP (1llu << 24)
|
||||
|
||||
typedef enum nghttp3_node_id_type {
|
||||
NGHTTP3_NODE_ID_TYPE_STREAM = 0x00,
|
||||
NGHTTP3_NODE_ID_TYPE_PUSH = 0x01,
|
||||
} nghttp3_node_id_type;
|
||||
|
||||
typedef struct nghttp3_node_id {
|
||||
nghttp3_node_id_type type;
|
||||
int64_t id;
|
||||
} nghttp3_node_id;
|
||||
|
||||
nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid,
|
||||
nghttp3_node_id_type type, int64_t id);
|
||||
|
||||
int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b);
|
||||
|
||||
typedef struct nghttp3_tnode {
|
||||
nghttp3_pq_entry pe;
|
||||
size_t num_children;
|
||||
nghttp3_node_id nid;
|
||||
uint64_t seq;
|
||||
uint64_t cycle;
|
||||
/* pri is a stream priority produced by nghttp3_pri_to_uint8. */
|
||||
uint8_t pri;
|
||||
} nghttp3_tnode;
|
||||
|
||||
void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid,
|
||||
uint64_t seq, uint8_t pri);
|
||||
|
||||
void nghttp3_tnode_free(nghttp3_tnode *tnode);
|
||||
|
||||
void nghttp3_tnode_unschedule(nghttp3_tnode *tnode, nghttp3_pq *pq);
|
||||
|
||||
/*
|
||||
* nghttp3_tnode_schedule schedules |tnode| using |nwrite| as penalty.
|
||||
* If |tnode| has already been scheduled, it is rescheduled by the
|
||||
* amount of |nwrite|.
|
||||
*/
|
||||
int nghttp3_tnode_schedule(nghttp3_tnode *tnode, nghttp3_pq *pq, size_t nwrite);
|
||||
|
||||
/*
|
||||
* nghttp3_tnode_is_scheduled returns nonzero if |tnode| is scheduled.
|
||||
*/
|
||||
int nghttp3_tnode_is_scheduled(nghttp3_tnode *tnode);
|
||||
|
||||
#endif /* NGHTTP3_TNODE_H */
|
38
deps/ngtcp2/nghttp3/lib/nghttp3_vec.c
vendored
Normal file
38
deps/ngtcp2/nghttp3/lib/nghttp3_vec.c
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 "nghttp3_vec.h"
|
||||
#include "nghttp3_macro.h"
|
||||
|
||||
size_t nghttp3_vec_len(const nghttp3_vec *vec, size_t n) {
|
||||
size_t i;
|
||||
size_t res = 0;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
res += vec[i].len;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
35
deps/ngtcp2/nghttp3/lib/nghttp3_vec.h
vendored
Normal file
35
deps/ngtcp2/nghttp3/lib/nghttp3_vec.h
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 contributors
|
||||
* 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 NGHTTP3_VEC_H
|
||||
#define NGHTTP3_VEC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#endif /* NGHTTP3_VEC_H */
|
39
deps/ngtcp2/nghttp3/lib/nghttp3_version.c
vendored
Normal file
39
deps/ngtcp2/nghttp3/lib/nghttp3_version.c
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* nghttp3
|
||||
*
|
||||
* Copyright (c) 2019 nghttp3 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 <nghttp3/nghttp3.h>
|
||||
|
||||
static nghttp3_info version = {NGHTTP3_VERSION_AGE, NGHTTP3_VERSION_NUM,
|
||||
NGHTTP3_VERSION};
|
||||
|
||||
nghttp3_info *nghttp3_version(int least_version) {
|
||||
if (least_version > NGHTTP3_VERSION_NUM) {
|
||||
return NULL;
|
||||
}
|
||||
return &version;
|
||||
}
|
174
deps/ngtcp2/ngtcp2.gyp
vendored
Normal file
174
deps/ngtcp2/ngtcp2.gyp
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
{
|
||||
'target_defaults': {
|
||||
'defines': [ '_U_=' ]
|
||||
},
|
||||
'variables': {
|
||||
'ngtcp2_sources': [
|
||||
'ngtcp2/lib/ngtcp2_acktr.c',
|
||||
'ngtcp2/lib/ngtcp2_addr.c',
|
||||
'ngtcp2/lib/ngtcp2_buf.c',
|
||||
'ngtcp2/lib/ngtcp2_cc.c',
|
||||
'ngtcp2/lib/ngtcp2_cid.c',
|
||||
'ngtcp2/lib/ngtcp2_conn.c',
|
||||
'ngtcp2/lib/ngtcp2_conv.c',
|
||||
'ngtcp2/lib/ngtcp2_crypto.c',
|
||||
'ngtcp2/lib/ngtcp2_err.c',
|
||||
'ngtcp2/lib/ngtcp2_gaptr.c',
|
||||
'ngtcp2/lib/ngtcp2_idtr.c',
|
||||
'ngtcp2/lib/ngtcp2_ksl.c',
|
||||
'ngtcp2/lib/ngtcp2_log.c',
|
||||
'ngtcp2/lib/ngtcp2_map.c',
|
||||
'ngtcp2/lib/ngtcp2_mem.c',
|
||||
'ngtcp2/lib/ngtcp2_path.c',
|
||||
'ngtcp2/lib/ngtcp2_pkt.c',
|
||||
'ngtcp2/lib/ngtcp2_ppe.c',
|
||||
'ngtcp2/lib/ngtcp2_pq.c',
|
||||
'ngtcp2/lib/ngtcp2_pv.c',
|
||||
'ngtcp2/lib/ngtcp2_qlog.c',
|
||||
'ngtcp2/lib/ngtcp2_range.c',
|
||||
'ngtcp2/lib/ngtcp2_ringbuf.c',
|
||||
'ngtcp2/lib/ngtcp2_rob.c',
|
||||
'ngtcp2/lib/ngtcp2_rst.c',
|
||||
'ngtcp2/lib/ngtcp2_rtb.c',
|
||||
'ngtcp2/lib/ngtcp2_str.c',
|
||||
'ngtcp2/lib/ngtcp2_strm.c',
|
||||
'ngtcp2/lib/ngtcp2_vec.c',
|
||||
'ngtcp2/lib/ngtcp2_version.c',
|
||||
'ngtcp2/crypto/shared.c',
|
||||
],
|
||||
'ngtcp2_sources_openssl': [
|
||||
'ngtcp2/crypto/openssl/openssl.c'
|
||||
],
|
||||
'ngtcp2_sources_boringssl': [
|
||||
'ngtcp2/crypto/boringssl/boringssl.c'
|
||||
],
|
||||
'nghttp3_sources': [
|
||||
'nghttp3/lib/nghttp3_buf.c',
|
||||
'nghttp3/lib/nghttp3_conn.c',
|
||||
'nghttp3/lib/nghttp3_conv.c',
|
||||
'nghttp3/lib/nghttp3_debug.c',
|
||||
'nghttp3/lib/nghttp3_err.c',
|
||||
'nghttp3/lib/nghttp3_frame.c',
|
||||
'nghttp3/lib/nghttp3_gaptr.c',
|
||||
'nghttp3/lib/nghttp3_http.c',
|
||||
'nghttp3/lib/nghttp3_idtr.c',
|
||||
'nghttp3/lib/nghttp3_ksl.c',
|
||||
'nghttp3/lib/nghttp3_map.c',
|
||||
'nghttp3/lib/nghttp3_mem.c',
|
||||
'nghttp3/lib/nghttp3_pq.c',
|
||||
'nghttp3/lib/nghttp3_qpack.c',
|
||||
'nghttp3/lib/nghttp3_qpack_huffman.c',
|
||||
'nghttp3/lib/nghttp3_qpack_huffman_data.c',
|
||||
'nghttp3/lib/nghttp3_range.c',
|
||||
'nghttp3/lib/nghttp3_rcbuf.c',
|
||||
'nghttp3/lib/nghttp3_ringbuf.c',
|
||||
'nghttp3/lib/nghttp3_str.c',
|
||||
'nghttp3/lib/nghttp3_stream.c',
|
||||
'nghttp3/lib/nghttp3_tnode.c',
|
||||
'nghttp3/lib/nghttp3_vec.c',
|
||||
'nghttp3/lib/nghttp3_version.c'
|
||||
]
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'ngtcp2',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [
|
||||
'',
|
||||
'ngtcp2/lib/includes/',
|
||||
'ngtcp2/crypto/includes/',
|
||||
'ngtcp2/lib/',
|
||||
'ngtcp2/crypto/',
|
||||
],
|
||||
'defines': [
|
||||
'BUILDING_NGTCP2',
|
||||
'NGTCP2_STATICLIB',
|
||||
],
|
||||
'conditions': [
|
||||
['node_shared_openssl=="false"', {
|
||||
'dependencies': [
|
||||
'../openssl/openssl.gyp:openssl'
|
||||
]
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WIN32',
|
||||
'_WINDOWS',
|
||||
'HAVE_CONFIG_H',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'CompileAs': '1'
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="linux"', {
|
||||
'defines': [
|
||||
'HAVE_ARPA_INET_H',
|
||||
'HAVE_NETINET_IN_H',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'NGTCP2_STATICLIB',
|
||||
],
|
||||
'include_dirs': [
|
||||
'',
|
||||
'ngtcp2/lib/includes',
|
||||
'ngtcp2/crypto/includes',
|
||||
]
|
||||
},
|
||||
'sources': [
|
||||
'<@(ngtcp2_sources)',
|
||||
'<@(ngtcp2_sources_openssl)',
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'nghttp3',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [
|
||||
'nghttp3/lib/includes/',
|
||||
'nghttp3/lib/'
|
||||
],
|
||||
'defines': [
|
||||
'BUILDING_NGHTTP3',
|
||||
'NGHTTP3_STATICLIB'
|
||||
],
|
||||
'dependencies': [
|
||||
'ngtcp2'
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WIN32',
|
||||
'_WINDOWS',
|
||||
'HAVE_CONFIG_H',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'CompileAs': '1'
|
||||
},
|
||||
},
|
||||
}],
|
||||
['OS=="linux"', {
|
||||
'defines': [
|
||||
'HAVE_ARPA_INET_H',
|
||||
'HAVE_NETINET_IN_H',
|
||||
],
|
||||
}],
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [
|
||||
'NGHTTP3_STATICLIB'
|
||||
],
|
||||
'include_dirs': [
|
||||
'nghttp3/lib/includes'
|
||||
]
|
||||
},
|
||||
'sources': [
|
||||
'<@(nghttp3_sources)'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
540
deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c
vendored
Normal file
540
deps/ngtcp2/ngtcp2/crypto/boringssl/boringssl.c
vendored
Normal file
@ -0,0 +1,540 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 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 <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hkdf.h>
|
||||
#include <openssl/chacha.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
/* Define cipher types because BoringSSL does not implement EVP
|
||||
interface for chacha20. */
|
||||
typedef enum ngtcp2_crypto_boringssl_cipher_type {
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_128_CTR,
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_256_CTR,
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_CHACHA20,
|
||||
} ngtcp2_crypto_boringssl_cipher_type;
|
||||
|
||||
typedef struct ngtcp2_crypto_boringssl_cipher {
|
||||
ngtcp2_crypto_boringssl_cipher_type type;
|
||||
} ngtcp2_crypto_boringssl_cipher;
|
||||
|
||||
static ngtcp2_crypto_boringssl_cipher crypto_cipher_evp_aes_128_ctr = {
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_128_CTR,
|
||||
};
|
||||
|
||||
static ngtcp2_crypto_boringssl_cipher crypto_cipher_evp_aes_256_ctr = {
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_256_CTR,
|
||||
};
|
||||
|
||||
static ngtcp2_crypto_boringssl_cipher crypto_cipher_chacha20 = {
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_CHACHA20,
|
||||
};
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
||||
ngtcp2_crypto_aead_init(&ctx->aead, (void *)EVP_aead_aes_128_gcm());
|
||||
ctx->md.native_handle = (void *)EVP_sha256();
|
||||
ctx->hp.native_handle = (void *)&crypto_cipher_evp_aes_128_ctr;
|
||||
ctx->max_encryption = 0;
|
||||
ctx->max_decryption_failure = 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead,
|
||||
void *aead_native_handle) {
|
||||
aead->native_handle = aead_native_handle;
|
||||
aead->max_overhead = EVP_AEAD_max_overhead(aead->native_handle);
|
||||
return aead;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) {
|
||||
return ngtcp2_crypto_aead_init(aead, (void *)EVP_aead_aes_128_gcm());
|
||||
}
|
||||
|
||||
static const EVP_AEAD *crypto_ssl_get_aead(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_CK_AES_128_GCM_SHA256:
|
||||
return EVP_aead_aes_128_gcm();
|
||||
case TLS1_CK_AES_256_GCM_SHA384:
|
||||
return EVP_aead_aes_256_gcm();
|
||||
case TLS1_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_aead_chacha20_poly1305();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM;
|
||||
case TLS1_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM;
|
||||
case TLS1_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const ngtcp2_crypto_boringssl_cipher *crypto_ssl_get_hp(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_CK_AES_128_GCM_SHA256:
|
||||
return &crypto_cipher_evp_aes_128_ctr;
|
||||
case TLS1_CK_AES_256_GCM_SHA384:
|
||||
return &crypto_cipher_evp_aes_256_ctr;
|
||||
case TLS1_CK_CHACHA20_POLY1305_SHA256:
|
||||
return &crypto_cipher_chacha20;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const EVP_MD *crypto_ssl_get_md(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_sha256();
|
||||
case TLS1_CK_AES_256_GCM_SHA384:
|
||||
return EVP_sha384();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
|
||||
void *tls_native_handle) {
|
||||
SSL *ssl = tls_native_handle;
|
||||
ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl));
|
||||
ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl);
|
||||
ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl);
|
||||
ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl);
|
||||
ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx,
|
||||
void *tls_native_handle) {
|
||||
return ngtcp2_crypto_ctx_tls(ctx, tls_native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_md_hashlen(const EVP_MD *md) {
|
||||
return (size_t)EVP_MD_size(md);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_md_hashlen(const ngtcp2_crypto_md *md) {
|
||||
return crypto_md_hashlen(md->native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_aead_keylen(const EVP_AEAD *aead) {
|
||||
return (size_t)EVP_AEAD_key_length(aead);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_aead_keylen(const ngtcp2_crypto_aead *aead) {
|
||||
return crypto_aead_keylen(aead->native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_aead_noncelen(const EVP_AEAD *aead) {
|
||||
return (size_t)EVP_AEAD_nonce_length(aead);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_aead_noncelen(const ngtcp2_crypto_aead *aead) {
|
||||
return crypto_aead_noncelen(aead->native_handle);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen) {
|
||||
const EVP_AEAD *cipher = aead->native_handle;
|
||||
size_t keylen = crypto_aead_keylen(cipher);
|
||||
EVP_AEAD_CTX *actx;
|
||||
|
||||
(void)noncelen;
|
||||
|
||||
actx = EVP_AEAD_CTX_new(cipher, key, keylen, EVP_AEAD_DEFAULT_TAG_LENGTH);
|
||||
if (actx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
aead_ctx->native_handle = actx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen) {
|
||||
return ngtcp2_crypto_aead_ctx_encrypt_init(aead_ctx, aead, key, noncelen);
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) {
|
||||
if (aead_ctx->native_handle) {
|
||||
EVP_AEAD_CTX_free(aead_ctx->native_handle);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum ngtcp2_crypto_boringssl_cipher_ctx_type {
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_EVP,
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_CHACHA20,
|
||||
} ngtcp2_crypto_boringssl_cipher_ctx_type;
|
||||
|
||||
typedef struct ngtcp2_crypto_boringssl_cipher_ctx {
|
||||
ngtcp2_crypto_boringssl_cipher_ctx_type type;
|
||||
union {
|
||||
/* ctx is EVP_CIPHER_CTX used when type ==
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_EVP. */
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
/* key contains an encryption key when type ==
|
||||
NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_CHACHA20. */
|
||||
uint8_t key[32];
|
||||
};
|
||||
} ngtcp2_crypto_boringssl_cipher_ctx;
|
||||
|
||||
int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
|
||||
const ngtcp2_crypto_cipher *cipher,
|
||||
const uint8_t *key) {
|
||||
ngtcp2_crypto_boringssl_cipher *hp_cipher = cipher->native_handle;
|
||||
ngtcp2_crypto_boringssl_cipher_ctx *ctx;
|
||||
EVP_CIPHER_CTX *actx;
|
||||
const EVP_CIPHER *evp_cipher;
|
||||
|
||||
switch (hp_cipher->type) {
|
||||
case NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_128_CTR:
|
||||
evp_cipher = EVP_aes_128_ctr();
|
||||
break;
|
||||
case NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_EVP_AES_256_CTR:
|
||||
evp_cipher = EVP_aes_256_ctr();
|
||||
break;
|
||||
case NGTCP2_CRYPTO_BORINGSSL_CIPHER_TYPE_CHACHA20:
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->type = NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_CHACHA20;
|
||||
memcpy(ctx->key, key, sizeof(ctx->key));
|
||||
|
||||
cipher_ctx->native_handle = ctx;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
assert(0);
|
||||
};
|
||||
|
||||
actx = EVP_CIPHER_CTX_new();
|
||||
if (actx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_EncryptInit_ex(actx, evp_cipher, NULL, key, NULL)) {
|
||||
EVP_CIPHER_CTX_free(actx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx = malloc(sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
EVP_CIPHER_CTX_free(actx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->type = NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_EVP;
|
||||
ctx->ctx = actx;
|
||||
|
||||
cipher_ctx->native_handle = ctx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx) {
|
||||
ngtcp2_crypto_boringssl_cipher_ctx *ctx;
|
||||
|
||||
if (!cipher_ctx->native_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = cipher_ctx->native_handle;
|
||||
|
||||
if (ctx->type == NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_EVP) {
|
||||
EVP_CIPHER_CTX_free(ctx->ctx);
|
||||
}
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const uint8_t *salt, size_t saltlen) {
|
||||
const EVP_MD *prf = md->native_handle;
|
||||
size_t destlen = (size_t)EVP_MD_size(prf);
|
||||
|
||||
if (HKDF_extract(dest, &destlen, prf, secret, secretlen, salt, saltlen) !=
|
||||
1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_crypto_md *md, const uint8_t *secret,
|
||||
size_t secretlen, const uint8_t *info,
|
||||
size_t infolen) {
|
||||
const EVP_MD *prf = md->native_handle;
|
||||
|
||||
if (HKDF_expand(dest, destlen, prf, secret, secretlen, info, infolen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *plaintext, size_t plaintextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
const EVP_AEAD *cipher = aead->native_handle;
|
||||
EVP_AEAD_CTX *actx = aead_ctx->native_handle;
|
||||
size_t max_outlen = plaintextlen + EVP_AEAD_max_overhead(cipher);
|
||||
size_t outlen;
|
||||
|
||||
if (EVP_AEAD_CTX_seal(actx, dest, &outlen, max_outlen, nonce, noncelen,
|
||||
plaintext, plaintextlen, ad, adlen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *ciphertext, size_t ciphertextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
EVP_AEAD_CTX *actx = aead_ctx->native_handle;
|
||||
size_t max_outlen = ciphertextlen;
|
||||
size_t outlen;
|
||||
|
||||
(void)aead;
|
||||
|
||||
if (EVP_AEAD_CTX_open(actx, dest, &outlen, max_outlen, nonce, noncelen,
|
||||
ciphertext, ciphertextlen, ad, adlen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
||||
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
||||
const uint8_t *sample) {
|
||||
static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
||||
ngtcp2_crypto_boringssl_cipher_ctx *ctx = hp_ctx->native_handle;
|
||||
EVP_CIPHER_CTX *actx;
|
||||
int len;
|
||||
uint32_t counter;
|
||||
|
||||
(void)hp;
|
||||
|
||||
switch (ctx->type) {
|
||||
case NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_EVP:
|
||||
actx = ctx->ctx;
|
||||
if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
||||
!EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT,
|
||||
sizeof(PLAINTEXT) - 1) ||
|
||||
!EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
case NGTCP2_CRYPTO_BORINGSSL_CIPHER_CTX_TYPE_CHACHA20:
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
counter = (uint32_t)sample[0] + (uint32_t)(sample[1] << 8) +
|
||||
(uint32_t)(sample[2] << 16) + (uint32_t)(sample[3] << 24);
|
||||
#else /* !WORDS_BIGENDIAN */
|
||||
memcpy(&counter, sample, sizeof(counter));
|
||||
#endif /* !WORDS_BIGENDIAN */
|
||||
CRYPTO_chacha_20(dest, PLAINTEXT, sizeof(PLAINTEXT) - 1, ctx->key,
|
||||
sample + sizeof(counter), counter);
|
||||
return 0;
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
|
||||
ngtcp2_crypto_level crypto_level,
|
||||
const uint8_t *data, size_t datalen) {
|
||||
SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn);
|
||||
int rv;
|
||||
int err;
|
||||
|
||||
if (SSL_provide_quic_data(
|
||||
ssl, ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level(crypto_level),
|
||||
data, datalen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ngtcp2_conn_get_handshake_completed(conn)) {
|
||||
retry:
|
||||
rv = SSL_do_handshake(ssl);
|
||||
if (rv <= 0) {
|
||||
err = SSL_get_error(ssl, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return 0;
|
||||
case SSL_ERROR_SSL:
|
||||
return -1;
|
||||
case SSL_ERROR_EARLY_DATA_REJECTED:
|
||||
assert(!ngtcp2_conn_is_server(conn));
|
||||
|
||||
SSL_reset_early_data_reject(ssl);
|
||||
|
||||
rv = ngtcp2_conn_early_data_rejected(conn);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
goto retry;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_in_early_data(ssl)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_conn_handshake_completed(conn);
|
||||
}
|
||||
|
||||
rv = SSL_process_quic_post_handshake(ssl);
|
||||
if (rv != 1) {
|
||||
err = SSL_get_error(ssl, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return 0;
|
||||
case SSL_ERROR_SSL:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) {
|
||||
SSL *ssl = tls;
|
||||
ngtcp2_transport_params_type exttype =
|
||||
ngtcp2_conn_is_server(conn)
|
||||
? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO
|
||||
: NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS;
|
||||
const uint8_t *tp;
|
||||
size_t tplen;
|
||||
ngtcp2_transport_params params;
|
||||
int rv;
|
||||
|
||||
SSL_get_peer_quic_transport_params(ssl, &tp, &tplen);
|
||||
|
||||
rv = ngtcp2_decode_transport_params(¶ms, exttype, tp, tplen);
|
||||
if (rv != 0) {
|
||||
ngtcp2_conn_set_tls_error(conn, rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_set_remote_transport_params(conn, ¶ms);
|
||||
if (rv != 0) {
|
||||
ngtcp2_conn_set_tls_error(conn, rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf,
|
||||
size_t len) {
|
||||
if (SSL_set_quic_transport_params(tls, buf, len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_level ngtcp2_crypto_boringssl_from_ssl_encryption_level(
|
||||
enum ssl_encryption_level_t ssl_level) {
|
||||
switch (ssl_level) {
|
||||
case ssl_encryption_initial:
|
||||
return NGTCP2_CRYPTO_LEVEL_INITIAL;
|
||||
case ssl_encryption_early_data:
|
||||
return NGTCP2_CRYPTO_LEVEL_EARLY;
|
||||
case ssl_encryption_handshake:
|
||||
return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
|
||||
case ssl_encryption_application:
|
||||
return NGTCP2_CRYPTO_LEVEL_APPLICATION;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
enum ssl_encryption_level_t ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level(
|
||||
ngtcp2_crypto_level crypto_level) {
|
||||
switch (crypto_level) {
|
||||
case NGTCP2_CRYPTO_LEVEL_INITIAL:
|
||||
return ssl_encryption_initial;
|
||||
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
|
||||
return ssl_encryption_handshake;
|
||||
case NGTCP2_CRYPTO_LEVEL_APPLICATION:
|
||||
return ssl_encryption_application;
|
||||
case NGTCP2_CRYPTO_LEVEL_EARLY:
|
||||
return ssl_encryption_early_data;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
688
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
vendored
Normal file
688
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto.h
vendored
Normal file
@ -0,0 +1,688 @@
|
||||
/*
|
||||
* 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_CRYPTO_H
|
||||
#define NGTCP2_CRYPTO_H
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_INITIAL_SECRETLEN` is the length of secret
|
||||
* for Initial packets.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_INITIAL_KEYLEN` is the length of key for
|
||||
* Initial packets.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_INITIAL_KEYLEN 16
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_INITIAL_IVLEN` is the length of IV for
|
||||
* Initial packets.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_INITIAL_IVLEN 12
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_ctx_initial` initializes |ctx| for Initial packet
|
||||
* encryption and decryption.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_ctx *
|
||||
ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_ctx_tls` initializes |ctx| by extracting negotiated
|
||||
* ciphers and message digests from native TLS session
|
||||
* |tls_native_handle|. This is used for encrypting/decrypting
|
||||
* Handshake and Short packets.
|
||||
*
|
||||
* If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be
|
||||
* a pointer to SSL object.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
|
||||
void *tls_native_handle);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_ctx_tls_early` initializes |ctx| by extracting early
|
||||
* ciphers and message digests from native TLS session
|
||||
* |tls_native_handle|. This is used for encrypting/decrypting 0RTT
|
||||
* packets.
|
||||
*
|
||||
* If libngtcp2_crypto_openssl is linked, |tls_native_handle| must be
|
||||
* a pointer to SSL object.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_ctx *
|
||||
ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx, void *tls_native_handle);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_init` initializes |aead| with the provided
|
||||
* |aead_native_handle| which is an underlying AEAD object.
|
||||
*
|
||||
* If libngtcp2_crypto_openssl is linked, |aead_native_handle| must be
|
||||
* a pointer to EVP_CIPHER.
|
||||
*
|
||||
* If libngtcp2_crypto_gnutls is linked, |aead_native_handle| must be
|
||||
* gnutls_cipher_algorithm_t casted to ``void *``.
|
||||
*
|
||||
* If libngtcp2_crypto_boringssl is linked, |aead_native_handle| must
|
||||
* be a pointer to EVP_AEAD.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_aead *
|
||||
ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead, void *aead_native_handle);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_retry` initializes |aead| with the AEAD cipher
|
||||
* AEAD_AES_128_GCM for Retry packet integrity protection.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_aead *
|
||||
ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_md_init` initializes |md| with the provided
|
||||
* |md_native_handle| which is an underlying message digest object.
|
||||
*
|
||||
* If libngtcp2_crypto_openssl is linked, |md_native_handle| must be a
|
||||
* pointer to EVP_MD.
|
||||
*
|
||||
* If libngtcp2_crypto_gnutls is linked, |md_native_handle| must be
|
||||
* gnutls_mac_algorithm_t casted to ``void *``.
|
||||
*
|
||||
* If libngtcp2_crypto_boringssl is linked, |md_native_handle| must be
|
||||
* a pointer to EVP_MD.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_md *ngtcp2_crypto_md_init(ngtcp2_crypto_md *md,
|
||||
void *md_native_handle);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_md_hashlen` returns the length of |md| output.
|
||||
*/
|
||||
NGTCP2_EXTERN size_t ngtcp2_crypto_md_hashlen(const ngtcp2_crypto_md *md);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_keylen` returns the length of key for |aead|.
|
||||
*/
|
||||
NGTCP2_EXTERN size_t ngtcp2_crypto_aead_keylen(const ngtcp2_crypto_aead *aead);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_noncelen` returns the length of nonce for
|
||||
* |aead|.
|
||||
*/
|
||||
NGTCP2_EXTERN size_t
|
||||
ngtcp2_crypto_aead_noncelen(const ngtcp2_crypto_aead *aead);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_hkdf_extract` performs HKDF extract operation. The
|
||||
* result is the length of |md| and is stored to the buffer pointed by
|
||||
* |dest|. The caller is responsible to specify the buffer that can
|
||||
* store the output.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const uint8_t *salt, size_t saltlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_hkdf_expand` performs HKDF expand operation. The
|
||||
* result is |destlen| bytes long and is stored to the buffer pointed
|
||||
* by |dest|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen,
|
||||
const uint8_t *info,
|
||||
size_t infolen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_hkdf_expand_label` performs HKDF expand label. The
|
||||
* result is |destlen| bytes long and is stored to the buffer pointed
|
||||
* by |dest|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen,
|
||||
const uint8_t *label,
|
||||
size_t labellen);
|
||||
|
||||
/**
|
||||
* @enum
|
||||
*
|
||||
* :type:`ngtcp2_crypto_side` indicates which side the application
|
||||
* implements; client or server.
|
||||
*/
|
||||
typedef enum ngtcp2_crypto_side {
|
||||
/**
|
||||
* :enum:`NGTCP2_CRYPTO_SIDE_CLIENT` indicates that the application
|
||||
* is client.
|
||||
*/
|
||||
NGTCP2_CRYPTO_SIDE_CLIENT,
|
||||
/**
|
||||
* :enum:`NGTCP2_CRYPTO_SIDE_SERVER` indicates that the application
|
||||
* is server.
|
||||
*/
|
||||
NGTCP2_CRYPTO_SIDE_SERVER
|
||||
} ngtcp2_crypto_side;
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_packet_protection_ivlen` returns the length of IV
|
||||
* used to encrypt QUIC packet.
|
||||
*/
|
||||
NGTCP2_EXTERN size_t
|
||||
ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_derive_packet_protection_key` derives packet
|
||||
* protection key. This function writes packet protection key into
|
||||
* the buffer pointed by |key|. |key| must point to the buffer which
|
||||
* is at least ngtcp2_crypto_aead_keylen(aead) bytes long. This
|
||||
* function writes packet protection IV into |iv|. |iv| must point to
|
||||
* the buffer which is at least
|
||||
* ngtcp2_crypto_packet_protection_ivlen(aead). |key| is
|
||||
* ngtcp2_crypto_aead_keylen(aead) bytes long. |iv| is
|
||||
* ngtcp2_crypto_packet_protection_ivlen(aead) bytes long.
|
||||
*
|
||||
* If |hp| is not NULL, this function also derives packet header
|
||||
* protection key and writes the key into the buffer pointed by |hp|.
|
||||
* The length of key is ngtcp2_crypto_aead_keylen(aead) bytes long.
|
||||
* |hp|, if not NULL, must have enough capacity to store the key.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_derive_packet_protection_key(
|
||||
uint8_t *key, uint8_t *iv, uint8_t *hp, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_encrypt` encrypts |plaintext| of length
|
||||
* |plaintextlen| and writes the ciphertext into the buffer pointed by
|
||||
* |dest|. The length of ciphertext is plaintextlen +
|
||||
* ngtcp2_crypto_aead_max_overhead(aead) bytes long. |dest| must have
|
||||
* enough capacity to store the ciphertext. It is allowed to specify
|
||||
* the same value to |dest| and |plaintext|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_encrypt(uint8_t *dest,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *plaintext,
|
||||
size_t plaintextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_encrypt_cb` is a wrapper function around
|
||||
* `ngtcp2_crypto_encrypt`. It can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.encrypt` field.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *plaintext, size_t plaintextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_decrypt` decrypts |ciphertext| of length
|
||||
* |ciphertextlen| and writes the plaintext into the buffer pointed by
|
||||
* |dest|. The length of plaintext is ciphertextlen -
|
||||
* ngtcp2_crypto_aead_max_overhead(aead) bytes long. |dest| must have
|
||||
* enough capacity to store the plaintext. It is allowed to specify
|
||||
* the same value to |dest| and |ciphertext|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_decrypt(uint8_t *dest,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *ciphertext,
|
||||
size_t ciphertextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_decrypt_cb` is a wrapper function around
|
||||
* `ngtcp2_crypto_decrypt`. It can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.decrypt` field.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_TLS_DECRYPT`.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *ciphertext, size_t ciphertextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_hp_mask` generates mask which is used in packet
|
||||
* header encryption. The mask is written to the buffer pointed by
|
||||
* |dest|. The length of mask is 5 bytes. |dest| must have enough
|
||||
* capacity to store the mask.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_hp_mask(uint8_t *dest,
|
||||
const ngtcp2_crypto_cipher *hp,
|
||||
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
||||
const uint8_t *sample);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_hp_mask_cb` is a wrapper function around
|
||||
* `ngtcp2_crypto_hp_mask`. It can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.hp_mask` field.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
||||
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
||||
const uint8_t *sample);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_derive_and_install_rx_key` derives the rx keys from
|
||||
* |secret| and installs new keys to |conn|.
|
||||
*
|
||||
* If |key| is not NULL, the derived packet protection key for
|
||||
* decryption is written to the buffer pointed by |key|. If |iv| is
|
||||
* not NULL, the derived packet protection IV for decryption is
|
||||
* written to the buffer pointed by |iv|. If |hp| is not NULL, the
|
||||
* derived header protection key for decryption is written to the
|
||||
* buffer pointed by |hp|.
|
||||
*
|
||||
* |secretlen| specifies the length of |secret|.
|
||||
*
|
||||
* The length of packet protection key and header protection key is
|
||||
* ngtcp2_crypto_aead(ctx->aead), and the length of packet protection
|
||||
* IV is ngtcp2_crypto_packet_protection_ivlen(ctx->aead) where ctx
|
||||
* can be obtained by `ngtcp2_crypto_ctx_tls`.
|
||||
*
|
||||
* In the first call of this function, it calls
|
||||
* `ngtcp2_conn_set_crypto_ctx` to set negotiated AEAD and message
|
||||
* digest algorithm. After the successful call of this function,
|
||||
* application can use `ngtcp2_conn_get_crypto_ctx` to get the object.
|
||||
* It also calls `ngtcp2_conn_set_aead_overhead` to set AEAD tag
|
||||
* length.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_rx_key(
|
||||
ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp,
|
||||
ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_derive_and_install_tx_key` derives the tx keys from
|
||||
* |secret| and installs new keys to |conn|.
|
||||
*
|
||||
* If |key| is not NULL, the derived packet protection key for
|
||||
* encryption is written to the buffer pointed by |key|. If |iv| is
|
||||
* not NULL, the derived packet protection IV for encryption is
|
||||
* written to the buffer pointed by |iv|. If |hp| is not NULL, the
|
||||
* derived header protection key for encryption is written to the
|
||||
* buffer pointed by |hp|.
|
||||
*
|
||||
* |secretlen| specifies the length of |secret|.
|
||||
*
|
||||
* The length of packet protection key and header protection key is
|
||||
* ngtcp2_crypto_aead(ctx->aead), and the length of packet protection
|
||||
* IV is ngtcp2_crypto_packet_protection_ivlen(ctx->aead) where ctx
|
||||
* can be obtained by `ngtcp2_crypto_ctx_tls`.
|
||||
*
|
||||
* In the first call of this function, it calls
|
||||
* `ngtcp2_conn_set_crypto_ctx` to set negotiated AEAD and message
|
||||
* digest algorithm. After the successful call of this function,
|
||||
* application can use `ngtcp2_conn_get_crypto_ctx` to get the object.
|
||||
* It also calls `ngtcp2_conn_set_aead_overhead` to set AEAD tag
|
||||
* length.
|
||||
*
|
||||
* If |level| is NGTCP2_CRYPTO_LEVEL_APP, this function retrieves a
|
||||
* remote QUIC transport parameters extension from |tls| and sets it
|
||||
* to |conn|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_derive_and_install_tx_key(
|
||||
ngtcp2_conn *conn, uint8_t *key, uint8_t *iv, uint8_t *hp,
|
||||
ngtcp2_crypto_level level, const uint8_t *secret, size_t secretlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_update_key` updates traffic keying materials.
|
||||
*
|
||||
* The new traffic secret for decryption is written to the buffer
|
||||
* pointed by |rx_secret|. The length of secret is |secretlen| bytes,
|
||||
* and |rx_secret| must point to the buffer which has enough capacity.
|
||||
*
|
||||
* The new traffic secret for encryption is written to the buffer
|
||||
* pointed by |tx_secret|. The length of secret is |secretlen| bytes,
|
||||
* and |tx_secret| must point to the buffer which has enough capacity.
|
||||
*
|
||||
* The derived packet protection key for decryption is written to the
|
||||
* buffer pointed by |rx_key|. The derived packet protection IV for
|
||||
* decryption is written to the buffer pointed by |rx_iv|.
|
||||
* |rx_aead_ctx| must be constructed with |rx_key|.
|
||||
*
|
||||
* The derived packet protection key for encryption is written to the
|
||||
* buffer pointed by |tx_key|. The derived packet protection IV for
|
||||
* encryption is written to the buffer pointed by |tx_iv|.
|
||||
* |tx_aead_ctx| must be constructed with |rx_key|.
|
||||
*
|
||||
* |current_rx_secret| and |current_tx_secret| are the current traffic
|
||||
* secrets for decryption and encryption. |secretlen| specifies the
|
||||
* length of |rx_secret| and |tx_secret|.
|
||||
*
|
||||
* The length of packet protection key and header protection key is
|
||||
* ngtcp2_crypto_aead(ctx->aead), and the length of packet protection
|
||||
* IV is ngtcp2_crypto_packet_protection_ivlen(ctx->aead) where ctx
|
||||
* can be obtained by `ngtcp2_conn_get_crypto_ctx`.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_update_key(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
|
||||
size_t secretlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_update_key_cb` is a wrapper function around
|
||||
* `ngtcp2_crypto_update_key`. It can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.update_key` field.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_update_key_cb(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
|
||||
size_t secretlen, void *user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_client_initial_cb` installs initial secrets and
|
||||
* encryption keys and sets QUIC transport parameters.
|
||||
*
|
||||
* This function can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.client_initial` field. It is only
|
||||
* used by client.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_recv_retry_cb` re-installs initial secrets in
|
||||
* response to incoming Retry packet.
|
||||
*
|
||||
* This function can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.recv_retry` field. It is only used
|
||||
* by client.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn,
|
||||
const ngtcp2_pkt_hd *hd,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_recv_client_initial_cb` installs initial secrets in
|
||||
* response to an incoming Initial packet from client, and sets QUIC
|
||||
* transport parameters.
|
||||
*
|
||||
* This function can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.recv_client_initial` field. It is
|
||||
* only used by server.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or
|
||||
* :macro:`NGTCP2_ERR_CALLBACK_FAILURE`.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn,
|
||||
const ngtcp2_cid *dcid,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_read_write_crypto_data` reads CRYPTO data |data| of
|
||||
* length |datalen| in encryption level |crypto_level| and may feed
|
||||
* outgoing CRYPTO data to |conn|. This function can drive handshake.
|
||||
* This function can be also used after handshake completes. It is
|
||||
* allowed to call this function with datalen == 0. In this case, no
|
||||
* additional read operation is done.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or a negative error code.
|
||||
* The generic error code is -1 if a specific error code is not
|
||||
* suitable. The error codes less than -10000 are specific to
|
||||
* underlying TLS implementation. For OpenSSL, the error codes are
|
||||
* defined in *ngtcp2_crypto_openssl.h*.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
|
||||
ngtcp2_crypto_level crypto_level,
|
||||
const uint8_t *data, size_t datalen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_generate_stateless_reset_token` generates a
|
||||
* stateless reset token using HKDF extraction with |md| using the
|
||||
* given |cid| and static key |secret| as input. The token will be
|
||||
* written to the buffer pointed by |token| and it must have a
|
||||
* capacity of at least :macro:`NGTCP2_STATELESS_RESET_TOKENLEN`
|
||||
* bytes.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int ngtcp2_crypto_generate_stateless_reset_token(
|
||||
uint8_t *token, const ngtcp2_crypto_md *md, const uint8_t *secret,
|
||||
size_t secretlen, const ngtcp2_cid *cid);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_write_connection_close` writes Initial packet
|
||||
* containing CONNECTION_CLOSE with the given |error_code| to the
|
||||
* buffer pointed by |dest| of length |destlen|. This function is
|
||||
* designed for server to close connection without committing the
|
||||
* state when validating Retry token fails. This function must not be
|
||||
* used by client. The |dcid| must be the Source Connection ID in
|
||||
* Initial packet from client. The |scid| must be the Destination
|
||||
* Connection ID in Initial packet from client. |scid| is used to
|
||||
* derive initial keying materials.
|
||||
*
|
||||
* This function wraps around `ngtcp2_pkt_write_connection_close` for
|
||||
* easier use.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_write_connection_close(
|
||||
uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, uint64_t error_code);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_write_retry` writes Retry packet to the buffer
|
||||
* pointed by |dest| of length |destlen|. |odcid| specifies Original
|
||||
* Destination Connection ID. |token| specifies Retry Token, and
|
||||
* |tokenlen| specifies its length.
|
||||
*
|
||||
* This function wraps around `ngtcp2_pkt_write_retry` for easier use.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_ssize ngtcp2_crypto_write_retry(
|
||||
uint8_t *dest, size_t destlen, uint32_t version, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid, const ngtcp2_cid *odcid, const uint8_t *token,
|
||||
size_t tokenlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_ctx_encrypt_init` initializes |aead_ctx| with
|
||||
* new AEAD cipher context object for encryption which is constructed
|
||||
* to use |key| as encryption key. |aead| specifies AEAD cipher to
|
||||
* use. |noncelen| is the length of nonce.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_ctx_decrypt_init` initializes |aead_ctx| with
|
||||
* new AEAD cipher context object for decryption which is constructed
|
||||
* to use |key| as encryption key. |aead| specifies AEAD cipher to
|
||||
* use. |noncelen| is the length of nonce.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
NGTCP2_EXTERN int
|
||||
ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_aead_ctx_free` frees up resources used by
|
||||
* |aead_ctx|. This function does not free the memory pointed by
|
||||
* |aead_ctx| itself.
|
||||
*/
|
||||
NGTCP2_EXTERN void
|
||||
ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_delete_crypto_aead_ctx_cb` deletes the given |aead_ctx|.
|
||||
*
|
||||
* This function can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.delete_crypto_aead_ctx` field.
|
||||
*/
|
||||
NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_aead_ctx_cb(
|
||||
ngtcp2_conn *conn, ngtcp2_crypto_aead_ctx *aead_ctx, void *user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_delete_crypto_cipher_ctx_cb` deletes the given
|
||||
* |cipher_ctx|.
|
||||
*
|
||||
* This function can be directly passed to
|
||||
* :member:`ngtcp2_conn_callbacks.delete_crypto_cipher_ctx` field.
|
||||
*/
|
||||
NGTCP2_EXTERN void ngtcp2_crypto_delete_crypto_cipher_ctx_cb(
|
||||
ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NGTCP2_CRYPTO_H */
|
62
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h
vendored
Normal file
62
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_boringssl.h
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* ngtcp2
|
||||
*
|
||||
* Copyright (c) 2020 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_BORINGSSL_H
|
||||
#define NGTCP2_CRYPTO_BORINGSSL_H
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_boringssl_from_ssl_encryption_level` translates
|
||||
* |ssl_level| to :type:`ngtcp2_crypto_level`. This function is only
|
||||
* available for BoringSSL backend.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_level
|
||||
ngtcp2_crypto_boringssl_from_ssl_encryption_level(
|
||||
enum ssl_encryption_level_t ssl_level);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level` translates
|
||||
* |crypto_level| to ssl_encryption_level_t. This function is only
|
||||
* available for BoringSSL backend.
|
||||
*/
|
||||
NGTCP2_EXTERN enum ssl_encryption_level_t
|
||||
ngtcp2_crypto_boringssl_from_ngtcp2_crypto_level(
|
||||
ngtcp2_crypto_level crypto_level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NGTCP2_CRYPTO_BORINGSSL_H */
|
90
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h
vendored
Normal file
90
deps/ngtcp2/ngtcp2/crypto/includes/ngtcp2/ngtcp2_crypto_openssl.h
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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_CRYPTO_OPENSSL_H
|
||||
#define NGTCP2_CRYPTO_OPENSSL_H
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @macrosection
|
||||
*
|
||||
* OpenSSL specific error codes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP` is the
|
||||
* error code which indicates that TLS handshake routine is
|
||||
* interrupted by X509 certificate lookup. See
|
||||
* :macro:`SSL_ERROR_WANT_X509_LOOKUP` error description from
|
||||
* `SSL_do_handshake`.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP -10001
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB` is the
|
||||
* error code which indicates that TLS handshake routine is
|
||||
* interrupted by client hello callback. See
|
||||
* :macro:`SSL_ERROR_WANT_CLIENT_HELLO_CB` error description from
|
||||
* `SSL_do_handshake`.
|
||||
*/
|
||||
#define NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB -10002
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_openssl_from_ossl_encryption_level` translates
|
||||
* |ossl_level| to :type:`ngtcp2_crypto_level`. This function is only
|
||||
* available for OpenSSL backend.
|
||||
*/
|
||||
NGTCP2_EXTERN ngtcp2_crypto_level
|
||||
ngtcp2_crypto_openssl_from_ossl_encryption_level(
|
||||
OSSL_ENCRYPTION_LEVEL ossl_level);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_openssl_from_ngtcp2_crypto_level` translates
|
||||
* |crypto_level| to OSSL_ENCRYPTION_LEVEL. This function is only
|
||||
* available for OpenSSL backend.
|
||||
*/
|
||||
NGTCP2_EXTERN OSSL_ENCRYPTION_LEVEL
|
||||
ngtcp2_crypto_openssl_from_ngtcp2_crypto_level(
|
||||
ngtcp2_crypto_level crypto_level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NGTCP2_CRYPTO_OPENSSL_H */
|
526
deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c
vendored
Normal file
526
deps/ngtcp2/ngtcp2/crypto/openssl/openssl.c
vendored
Normal file
@ -0,0 +1,526 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_openssl.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
static size_t crypto_aead_max_overhead(const EVP_CIPHER *aead) {
|
||||
switch (EVP_CIPHER_nid(aead)) {
|
||||
case NID_aes_128_gcm:
|
||||
case NID_aes_256_gcm:
|
||||
return EVP_GCM_TLS_TAG_LEN;
|
||||
case NID_chacha20_poly1305:
|
||||
return EVP_CHACHAPOLY_TLS_TAG_LEN;
|
||||
case NID_aes_128_ccm:
|
||||
return EVP_CCM_TLS_TAG_LEN;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_initial(ngtcp2_crypto_ctx *ctx) {
|
||||
ngtcp2_crypto_aead_init(&ctx->aead, (void *)EVP_aes_128_gcm());
|
||||
ctx->md.native_handle = (void *)EVP_sha256();
|
||||
ctx->hp.native_handle = (void *)EVP_aes_128_ctr();
|
||||
ctx->max_encryption = 0;
|
||||
ctx->max_decryption_failure = 0;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_aead *ngtcp2_crypto_aead_init(ngtcp2_crypto_aead *aead,
|
||||
void *aead_native_handle) {
|
||||
aead->native_handle = aead_native_handle;
|
||||
aead->max_overhead = crypto_aead_max_overhead(aead_native_handle);
|
||||
return aead;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_aead *ngtcp2_crypto_aead_retry(ngtcp2_crypto_aead *aead) {
|
||||
return ngtcp2_crypto_aead_init(aead, (void *)EVP_aes_128_gcm());
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *crypto_ssl_get_aead(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
return EVP_aes_128_gcm();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_aes_256_gcm();
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_chacha20_poly1305();
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return EVP_aes_128_ccm();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t crypto_ssl_get_aead_max_encryption(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM;
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305;
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t crypto_ssl_get_aead_max_decryption_failure(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM;
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305;
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const EVP_CIPHER *crypto_ssl_get_hp(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return EVP_aes_128_ctr();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_aes_256_ctr();
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
return EVP_chacha20();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const EVP_MD *crypto_ssl_get_md(SSL *ssl) {
|
||||
switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl))) {
|
||||
case TLS1_3_CK_AES_128_GCM_SHA256:
|
||||
case TLS1_3_CK_CHACHA20_POLY1305_SHA256:
|
||||
case TLS1_3_CK_AES_128_CCM_SHA256:
|
||||
return EVP_sha256();
|
||||
case TLS1_3_CK_AES_256_GCM_SHA384:
|
||||
return EVP_sha384();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls(ngtcp2_crypto_ctx *ctx,
|
||||
void *tls_native_handle) {
|
||||
SSL *ssl = tls_native_handle;
|
||||
ngtcp2_crypto_aead_init(&ctx->aead, (void *)crypto_ssl_get_aead(ssl));
|
||||
ctx->md.native_handle = (void *)crypto_ssl_get_md(ssl);
|
||||
ctx->hp.native_handle = (void *)crypto_ssl_get_hp(ssl);
|
||||
ctx->max_encryption = crypto_ssl_get_aead_max_encryption(ssl);
|
||||
ctx->max_decryption_failure = crypto_ssl_get_aead_max_decryption_failure(ssl);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx *ngtcp2_crypto_ctx_tls_early(ngtcp2_crypto_ctx *ctx,
|
||||
void *tls_native_handle) {
|
||||
return ngtcp2_crypto_ctx_tls(ctx, tls_native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_md_hashlen(const EVP_MD *md) {
|
||||
return (size_t)EVP_MD_size(md);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_md_hashlen(const ngtcp2_crypto_md *md) {
|
||||
return crypto_md_hashlen(md->native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_aead_keylen(const EVP_CIPHER *aead) {
|
||||
return (size_t)EVP_CIPHER_key_length(aead);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_aead_keylen(const ngtcp2_crypto_aead *aead) {
|
||||
return crypto_aead_keylen(aead->native_handle);
|
||||
}
|
||||
|
||||
static size_t crypto_aead_noncelen(const EVP_CIPHER *aead) {
|
||||
return (size_t)EVP_CIPHER_iv_length(aead);
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_aead_noncelen(const ngtcp2_crypto_aead *aead) {
|
||||
return crypto_aead_noncelen(aead->native_handle);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_aead_ctx_encrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen) {
|
||||
const EVP_CIPHER *cipher = aead->native_handle;
|
||||
int cipher_nid = EVP_CIPHER_nid(cipher);
|
||||
EVP_CIPHER_CTX *actx;
|
||||
|
||||
actx = EVP_CIPHER_CTX_new();
|
||||
if (actx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_EncryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
|
||||
NULL) ||
|
||||
(cipher_nid == NID_aes_128_ccm &&
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG,
|
||||
(int)crypto_aead_max_overhead(cipher), NULL)) ||
|
||||
!EVP_EncryptInit_ex(actx, NULL, NULL, key, NULL)) {
|
||||
EVP_CIPHER_CTX_free(actx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
aead_ctx->native_handle = actx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_aead_ctx_decrypt_init(ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const ngtcp2_crypto_aead *aead,
|
||||
const uint8_t *key, size_t noncelen) {
|
||||
const EVP_CIPHER *cipher = aead->native_handle;
|
||||
int cipher_nid = EVP_CIPHER_nid(cipher);
|
||||
EVP_CIPHER_CTX *actx;
|
||||
|
||||
actx = EVP_CIPHER_CTX_new();
|
||||
if (actx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_DecryptInit_ex(actx, cipher, NULL, NULL, NULL) ||
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_IVLEN, (int)noncelen,
|
||||
NULL) ||
|
||||
(cipher_nid == NID_aes_128_ccm &&
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG,
|
||||
(int)crypto_aead_max_overhead(cipher), NULL)) ||
|
||||
!EVP_DecryptInit_ex(actx, NULL, NULL, key, NULL)) {
|
||||
EVP_CIPHER_CTX_free(actx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
aead_ctx->native_handle = actx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_aead_ctx_free(ngtcp2_crypto_aead_ctx *aead_ctx) {
|
||||
if (aead_ctx->native_handle) {
|
||||
EVP_CIPHER_CTX_free(aead_ctx->native_handle);
|
||||
}
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
|
||||
const ngtcp2_crypto_cipher *cipher,
|
||||
const uint8_t *key) {
|
||||
EVP_CIPHER_CTX *actx;
|
||||
|
||||
actx = EVP_CIPHER_CTX_new();
|
||||
if (actx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!EVP_EncryptInit_ex(actx, cipher->native_handle, NULL, key, NULL)) {
|
||||
EVP_CIPHER_CTX_free(actx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cipher_ctx->native_handle = actx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx) {
|
||||
if (cipher_ctx->native_handle) {
|
||||
EVP_CIPHER_CTX_free(cipher_ctx->native_handle);
|
||||
}
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hkdf_extract(uint8_t *dest, const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const uint8_t *salt, size_t saltlen) {
|
||||
const EVP_MD *prf = md->native_handle;
|
||||
int rv = 0;
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
size_t destlen = (size_t)EVP_MD_size(prf);
|
||||
|
||||
if (pctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_derive_init(pctx) != 1 ||
|
||||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) != 1 ||
|
||||
EVP_PKEY_CTX_set_hkdf_md(pctx, prf) != 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, (int)saltlen) != 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, (int)secretlen) != 1 ||
|
||||
EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hkdf_expand(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_crypto_md *md, const uint8_t *secret,
|
||||
size_t secretlen, const uint8_t *info,
|
||||
size_t infolen) {
|
||||
const EVP_MD *prf = md->native_handle;
|
||||
int rv = 0;
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
if (pctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_derive_init(pctx) != 1 ||
|
||||
EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) != 1 ||
|
||||
EVP_PKEY_CTX_set_hkdf_md(pctx, prf) != 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_salt(pctx, "", 0) != 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, (int)secretlen) != 1 ||
|
||||
EVP_PKEY_CTX_add1_hkdf_info(pctx, info, (int)infolen) != 1 ||
|
||||
EVP_PKEY_derive(pctx, dest, &destlen) != 1) {
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_encrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *plaintext, size_t plaintextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
const EVP_CIPHER *cipher = aead->native_handle;
|
||||
size_t taglen = crypto_aead_max_overhead(cipher);
|
||||
int cipher_nid = EVP_CIPHER_nid(cipher);
|
||||
EVP_CIPHER_CTX *actx = aead_ctx->native_handle;
|
||||
int len;
|
||||
|
||||
(void)noncelen;
|
||||
|
||||
if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, nonce) ||
|
||||
(cipher_nid == NID_aes_128_ccm &&
|
||||
!EVP_EncryptUpdate(actx, NULL, &len, NULL, (int)plaintextlen)) ||
|
||||
!EVP_EncryptUpdate(actx, NULL, &len, ad, (int)adlen) ||
|
||||
!EVP_EncryptUpdate(actx, dest, &len, plaintext, (int)plaintextlen) ||
|
||||
!EVP_EncryptFinal_ex(actx, dest + len, &len) ||
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_GET_TAG, (int)taglen,
|
||||
dest + plaintextlen)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_decrypt(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *ciphertext, size_t ciphertextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
const EVP_CIPHER *cipher = aead->native_handle;
|
||||
size_t taglen = crypto_aead_max_overhead(cipher);
|
||||
int cipher_nid = EVP_CIPHER_nid(cipher);
|
||||
EVP_CIPHER_CTX *actx = aead_ctx->native_handle;
|
||||
int len;
|
||||
const uint8_t *tag;
|
||||
|
||||
(void)noncelen;
|
||||
|
||||
if (taglen > ciphertextlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ciphertextlen -= taglen;
|
||||
tag = ciphertext + ciphertextlen;
|
||||
|
||||
if (!EVP_DecryptInit_ex(actx, NULL, NULL, NULL, nonce) ||
|
||||
!EVP_CIPHER_CTX_ctrl(actx, EVP_CTRL_AEAD_SET_TAG, (int)taglen,
|
||||
(uint8_t *)tag) ||
|
||||
(cipher_nid == NID_aes_128_ccm &&
|
||||
!EVP_DecryptUpdate(actx, NULL, &len, NULL, (int)ciphertextlen)) ||
|
||||
!EVP_DecryptUpdate(actx, NULL, &len, ad, (int)adlen) ||
|
||||
!EVP_DecryptUpdate(actx, dest, &len, ciphertext, (int)ciphertextlen) ||
|
||||
(cipher_nid != NID_aes_128_ccm &&
|
||||
!EVP_DecryptFinal_ex(actx, dest + ciphertextlen, &len))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hp_mask(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
||||
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
||||
const uint8_t *sample) {
|
||||
static const uint8_t PLAINTEXT[] = "\x00\x00\x00\x00\x00";
|
||||
EVP_CIPHER_CTX *actx = hp_ctx->native_handle;
|
||||
int len;
|
||||
|
||||
(void)hp;
|
||||
|
||||
if (!EVP_EncryptInit_ex(actx, NULL, NULL, NULL, sample) ||
|
||||
!EVP_EncryptUpdate(actx, dest, &len, PLAINTEXT, sizeof(PLAINTEXT) - 1) ||
|
||||
!EVP_EncryptFinal_ex(actx, dest + sizeof(PLAINTEXT) - 1, &len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_read_write_crypto_data(ngtcp2_conn *conn,
|
||||
ngtcp2_crypto_level crypto_level,
|
||||
const uint8_t *data, size_t datalen) {
|
||||
SSL *ssl = ngtcp2_conn_get_tls_native_handle(conn);
|
||||
int rv;
|
||||
int err;
|
||||
|
||||
if (SSL_provide_quic_data(
|
||||
ssl, ngtcp2_crypto_openssl_from_ngtcp2_crypto_level(crypto_level),
|
||||
data, datalen) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ngtcp2_conn_get_handshake_completed(conn)) {
|
||||
rv = SSL_do_handshake(ssl);
|
||||
if (rv <= 0) {
|
||||
err = SSL_get_error(ssl, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return 0;
|
||||
case SSL_ERROR_WANT_CLIENT_HELLO_CB:
|
||||
return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB;
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP;
|
||||
case SSL_ERROR_SSL:
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_conn_handshake_completed(conn);
|
||||
}
|
||||
|
||||
rv = SSL_process_quic_post_handshake(ssl);
|
||||
if (rv != 1) {
|
||||
err = SSL_get_error(ssl, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return 0;
|
||||
case SSL_ERROR_SSL:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls) {
|
||||
SSL *ssl = tls;
|
||||
ngtcp2_transport_params_type exttype =
|
||||
ngtcp2_conn_is_server(conn)
|
||||
? NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO
|
||||
: NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS;
|
||||
const uint8_t *tp;
|
||||
size_t tplen;
|
||||
ngtcp2_transport_params params;
|
||||
int rv;
|
||||
|
||||
SSL_get_peer_quic_transport_params(ssl, &tp, &tplen);
|
||||
|
||||
rv = ngtcp2_decode_transport_params(¶ms, exttype, tp, tplen);
|
||||
if (rv != 0) {
|
||||
ngtcp2_conn_set_tls_error(conn, rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_set_remote_transport_params(conn, ¶ms);
|
||||
if (rv != 0) {
|
||||
ngtcp2_conn_set_tls_error(conn, rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf,
|
||||
size_t len) {
|
||||
if (SSL_set_quic_transport_params(tls, buf, len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_level ngtcp2_crypto_openssl_from_ossl_encryption_level(
|
||||
OSSL_ENCRYPTION_LEVEL ossl_level) {
|
||||
switch (ossl_level) {
|
||||
case ssl_encryption_initial:
|
||||
return NGTCP2_CRYPTO_LEVEL_INITIAL;
|
||||
case ssl_encryption_early_data:
|
||||
return NGTCP2_CRYPTO_LEVEL_EARLY;
|
||||
case ssl_encryption_handshake:
|
||||
return NGTCP2_CRYPTO_LEVEL_HANDSHAKE;
|
||||
case ssl_encryption_application:
|
||||
return NGTCP2_CRYPTO_LEVEL_APPLICATION;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
OSSL_ENCRYPTION_LEVEL
|
||||
ngtcp2_crypto_openssl_from_ngtcp2_crypto_level(
|
||||
ngtcp2_crypto_level crypto_level) {
|
||||
switch (crypto_level) {
|
||||
case NGTCP2_CRYPTO_LEVEL_INITIAL:
|
||||
return ssl_encryption_initial;
|
||||
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
|
||||
return ssl_encryption_handshake;
|
||||
case NGTCP2_CRYPTO_LEVEL_APPLICATION:
|
||||
return ssl_encryption_application;
|
||||
case NGTCP2_CRYPTO_LEVEL_EARLY:
|
||||
return ssl_encryption_early_data;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
831
deps/ngtcp2/ngtcp2/crypto/shared.c
vendored
Normal file
831
deps/ngtcp2/ngtcp2/crypto/shared.c
vendored
Normal file
@ -0,0 +1,831 @@
|
||||
/*
|
||||
* 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 "shared.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ngtcp2_macro.h"
|
||||
|
||||
ngtcp2_crypto_md *ngtcp2_crypto_md_init(ngtcp2_crypto_md *md,
|
||||
void *md_native_handle) {
|
||||
md->native_handle = md_native_handle;
|
||||
return md;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hkdf_expand_label(uint8_t *dest, size_t destlen,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret, size_t secretlen,
|
||||
const uint8_t *label, size_t labellen) {
|
||||
static const uint8_t LABEL[] = "tls13 ";
|
||||
uint8_t info[256];
|
||||
uint8_t *p = info;
|
||||
|
||||
*p++ = (uint8_t)(destlen / 256);
|
||||
*p++ = (uint8_t)(destlen % 256);
|
||||
*p++ = (uint8_t)(sizeof(LABEL) - 1 + labellen);
|
||||
memcpy(p, LABEL, sizeof(LABEL) - 1);
|
||||
p += sizeof(LABEL) - 1;
|
||||
memcpy(p, label, labellen);
|
||||
p += labellen;
|
||||
*p++ = 0;
|
||||
|
||||
return ngtcp2_crypto_hkdf_expand(dest, destlen, md, secret, secretlen, info,
|
||||
(size_t)(p - info));
|
||||
}
|
||||
|
||||
#define NGTCP2_CRYPTO_INITIAL_SECRETLEN 32
|
||||
|
||||
int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret,
|
||||
uint8_t *tx_secret,
|
||||
uint8_t *initial_secret,
|
||||
const ngtcp2_cid *client_dcid,
|
||||
ngtcp2_crypto_side side) {
|
||||
static const uint8_t CLABEL[] = "client in";
|
||||
static const uint8_t SLABEL[] = "server in";
|
||||
uint8_t initial_secret_buf[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t *client_secret;
|
||||
uint8_t *server_secret;
|
||||
ngtcp2_crypto_ctx ctx;
|
||||
const uint8_t *salt;
|
||||
size_t saltlen;
|
||||
|
||||
if (!initial_secret) {
|
||||
initial_secret = initial_secret_buf;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_ctx_initial(&ctx);
|
||||
|
||||
if (version == NGTCP2_PROTO_VER_V1) {
|
||||
salt = (const uint8_t *)NGTCP2_INITIAL_SALT_V1;
|
||||
saltlen = sizeof(NGTCP2_INITIAL_SALT_V1) - 1;
|
||||
} else {
|
||||
salt = (const uint8_t *)NGTCP2_INITIAL_SALT_DRAFT;
|
||||
saltlen = sizeof(NGTCP2_INITIAL_SALT_DRAFT) - 1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_hkdf_extract(initial_secret, &ctx.md, client_dcid->data,
|
||||
client_dcid->datalen, salt, saltlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (side == NGTCP2_CRYPTO_SIDE_SERVER) {
|
||||
client_secret = rx_secret;
|
||||
server_secret = tx_secret;
|
||||
} else {
|
||||
client_secret = tx_secret;
|
||||
server_secret = rx_secret;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_hkdf_expand_label(
|
||||
client_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md,
|
||||
initial_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, CLABEL,
|
||||
sizeof(CLABEL) - 1) != 0 ||
|
||||
ngtcp2_crypto_hkdf_expand_label(
|
||||
server_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, &ctx.md,
|
||||
initial_secret, NGTCP2_CRYPTO_INITIAL_SECRETLEN, SLABEL,
|
||||
sizeof(SLABEL) - 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ngtcp2_crypto_packet_protection_ivlen(const ngtcp2_crypto_aead *aead) {
|
||||
size_t noncelen = ngtcp2_crypto_aead_noncelen(aead);
|
||||
return ngtcp2_max(8, noncelen);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_derive_packet_protection_key(
|
||||
uint8_t *key, uint8_t *iv, uint8_t *hp_key, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_md *md, const uint8_t *secret, size_t secretlen) {
|
||||
static const uint8_t KEY_LABEL[] = "quic key";
|
||||
static const uint8_t IV_LABEL[] = "quic iv";
|
||||
static const uint8_t HP_KEY_LABEL[] = "quic hp";
|
||||
size_t keylen = ngtcp2_crypto_aead_keylen(aead);
|
||||
size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
|
||||
|
||||
if (ngtcp2_crypto_hkdf_expand_label(key, keylen, md, secret, secretlen,
|
||||
KEY_LABEL, sizeof(KEY_LABEL) - 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_hkdf_expand_label(iv, ivlen, md, secret, secretlen,
|
||||
IV_LABEL, sizeof(IV_LABEL) - 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hp_key != NULL && ngtcp2_crypto_hkdf_expand_label(
|
||||
hp_key, keylen, md, secret, secretlen, HP_KEY_LABEL,
|
||||
sizeof(HP_KEY_LABEL) - 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_update_traffic_secret(uint8_t *dest,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen) {
|
||||
static const uint8_t LABEL[] = "quic ku";
|
||||
|
||||
if (ngtcp2_crypto_hkdf_expand_label(dest, secretlen, md, secret, secretlen,
|
||||
LABEL, sizeof(LABEL) - 1) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_derive_and_install_rx_key(ngtcp2_conn *conn, uint8_t *key,
|
||||
uint8_t *iv, uint8_t *hp_key,
|
||||
ngtcp2_crypto_level level,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen) {
|
||||
const ngtcp2_crypto_ctx *ctx;
|
||||
const ngtcp2_crypto_aead *aead;
|
||||
const ngtcp2_crypto_md *md;
|
||||
const ngtcp2_crypto_cipher *hp;
|
||||
ngtcp2_crypto_aead_ctx aead_ctx = {0};
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx = {0};
|
||||
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
|
||||
uint8_t keybuf[64], ivbuf[64], hp_keybuf[64];
|
||||
size_t ivlen;
|
||||
int rv;
|
||||
ngtcp2_crypto_ctx cctx;
|
||||
|
||||
if (level == NGTCP2_CRYPTO_LEVEL_EARLY && !ngtcp2_conn_is_server(conn)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
key = keybuf;
|
||||
}
|
||||
if (!iv) {
|
||||
iv = ivbuf;
|
||||
}
|
||||
if (!hp_key) {
|
||||
hp_key = hp_keybuf;
|
||||
}
|
||||
|
||||
if (level == NGTCP2_CRYPTO_LEVEL_EARLY) {
|
||||
ngtcp2_crypto_ctx_tls_early(&cctx, tls);
|
||||
ngtcp2_conn_set_early_crypto_ctx(conn, &cctx);
|
||||
ctx = ngtcp2_conn_get_early_crypto_ctx(conn);
|
||||
} else {
|
||||
ctx = ngtcp2_conn_get_crypto_ctx(conn);
|
||||
|
||||
if (!ctx->aead.native_handle) {
|
||||
ngtcp2_crypto_ctx_tls(&cctx, tls);
|
||||
ngtcp2_conn_set_crypto_ctx(conn, &cctx);
|
||||
ctx = ngtcp2_conn_get_crypto_ctx(conn);
|
||||
}
|
||||
}
|
||||
|
||||
aead = &ctx->aead;
|
||||
md = &ctx->md;
|
||||
hp = &ctx->hp;
|
||||
ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md,
|
||||
secret, secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_decrypt_init(&aead_ctx, aead, key, ivlen) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
case NGTCP2_CRYPTO_LEVEL_EARLY:
|
||||
rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
|
||||
rv = ngtcp2_conn_install_rx_handshake_key(conn, &aead_ctx, iv, ivlen,
|
||||
&hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NGTCP2_CRYPTO_LEVEL_APPLICATION:
|
||||
if (!ngtcp2_conn_is_server(conn)) {
|
||||
rv = ngtcp2_crypto_set_remote_transport_params(conn, tls);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_install_rx_key(conn, secret, secretlen, &aead_ctx, iv,
|
||||
ivlen, &hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
|
||||
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_set_local_transport_params gets local QUIC transport
|
||||
* parameters from |conn| and sets it to |tls|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
static int crypto_set_local_transport_params(ngtcp2_conn *conn, void *tls) {
|
||||
ngtcp2_transport_params_type exttype =
|
||||
ngtcp2_conn_is_server(conn)
|
||||
? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS
|
||||
: NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO;
|
||||
ngtcp2_transport_params params;
|
||||
ngtcp2_ssize nwrite;
|
||||
uint8_t buf[256];
|
||||
|
||||
ngtcp2_conn_get_local_transport_params(conn, ¶ms);
|
||||
|
||||
nwrite = ngtcp2_encode_transport_params(buf, sizeof(buf), exttype, ¶ms);
|
||||
if (nwrite < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_set_local_transport_params(tls, buf, (size_t)nwrite) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_derive_and_install_tx_key(ngtcp2_conn *conn, uint8_t *key,
|
||||
uint8_t *iv, uint8_t *hp_key,
|
||||
ngtcp2_crypto_level level,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen) {
|
||||
const ngtcp2_crypto_ctx *ctx;
|
||||
const ngtcp2_crypto_aead *aead;
|
||||
const ngtcp2_crypto_md *md;
|
||||
const ngtcp2_crypto_cipher *hp;
|
||||
ngtcp2_crypto_aead_ctx aead_ctx = {0};
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx = {0};
|
||||
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
|
||||
uint8_t keybuf[64], ivbuf[64], hp_keybuf[64];
|
||||
size_t ivlen;
|
||||
int rv;
|
||||
ngtcp2_crypto_ctx cctx;
|
||||
|
||||
if (level == NGTCP2_CRYPTO_LEVEL_EARLY && ngtcp2_conn_is_server(conn)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
key = keybuf;
|
||||
}
|
||||
if (!iv) {
|
||||
iv = ivbuf;
|
||||
}
|
||||
if (!hp_key) {
|
||||
hp_key = hp_keybuf;
|
||||
}
|
||||
|
||||
if (level == NGTCP2_CRYPTO_LEVEL_EARLY) {
|
||||
ngtcp2_crypto_ctx_tls_early(&cctx, tls);
|
||||
ngtcp2_conn_set_early_crypto_ctx(conn, &cctx);
|
||||
ctx = ngtcp2_conn_get_early_crypto_ctx(conn);
|
||||
} else {
|
||||
ctx = ngtcp2_conn_get_crypto_ctx(conn);
|
||||
|
||||
if (!ctx->aead.native_handle) {
|
||||
ngtcp2_crypto_ctx_tls(&cctx, tls);
|
||||
ngtcp2_conn_set_crypto_ctx(conn, &cctx);
|
||||
ctx = ngtcp2_conn_get_crypto_ctx(conn);
|
||||
}
|
||||
}
|
||||
|
||||
aead = &ctx->aead;
|
||||
md = &ctx->md;
|
||||
hp = &ctx->hp;
|
||||
ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(key, iv, hp_key, aead, md,
|
||||
secret, secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, aead, key, ivlen) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, hp, hp_key) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
case NGTCP2_CRYPTO_LEVEL_EARLY:
|
||||
rv = ngtcp2_conn_install_early_key(conn, &aead_ctx, iv, ivlen, &hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case NGTCP2_CRYPTO_LEVEL_HANDSHAKE:
|
||||
rv = ngtcp2_conn_install_tx_handshake_key(conn, &aead_ctx, iv, ivlen,
|
||||
&hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_conn_is_server(conn)) {
|
||||
rv = ngtcp2_crypto_set_remote_transport_params(conn, tls);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (crypto_set_local_transport_params(conn, tls) != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case NGTCP2_CRYPTO_LEVEL_APPLICATION:
|
||||
rv = ngtcp2_conn_install_tx_key(conn, secret, secretlen, &aead_ctx, iv,
|
||||
ivlen, &hp_ctx);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
|
||||
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_derive_and_install_initial_key(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
uint8_t *initial_secret, uint8_t *rx_key, uint8_t *rx_iv,
|
||||
uint8_t *rx_hp_key, uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp_key,
|
||||
const ngtcp2_cid *client_dcid) {
|
||||
uint8_t rx_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t tx_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t initial_secretbuf[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t rx_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
uint8_t rx_ivbuf[NGTCP2_CRYPTO_INITIAL_IVLEN];
|
||||
uint8_t rx_hp_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
uint8_t tx_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
uint8_t tx_ivbuf[NGTCP2_CRYPTO_INITIAL_IVLEN];
|
||||
uint8_t tx_hp_keybuf[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
ngtcp2_crypto_ctx ctx;
|
||||
ngtcp2_crypto_aead retry_aead;
|
||||
ngtcp2_crypto_aead_ctx rx_aead_ctx = {0};
|
||||
ngtcp2_crypto_cipher_ctx rx_hp_ctx = {0};
|
||||
ngtcp2_crypto_aead_ctx tx_aead_ctx = {0};
|
||||
ngtcp2_crypto_cipher_ctx tx_hp_ctx = {0};
|
||||
ngtcp2_crypto_aead_ctx retry_aead_ctx = {0};
|
||||
int rv;
|
||||
int server = ngtcp2_conn_is_server(conn);
|
||||
uint32_t version = ngtcp2_conn_get_negotiated_version(conn);
|
||||
const uint8_t *retry_key;
|
||||
size_t retry_noncelen;
|
||||
|
||||
ngtcp2_crypto_ctx_initial(&ctx);
|
||||
|
||||
if (!rx_secret) {
|
||||
rx_secret = rx_secretbuf;
|
||||
}
|
||||
if (!tx_secret) {
|
||||
tx_secret = tx_secretbuf;
|
||||
}
|
||||
if (!initial_secret) {
|
||||
initial_secret = initial_secretbuf;
|
||||
}
|
||||
|
||||
if (!rx_key) {
|
||||
rx_key = rx_keybuf;
|
||||
}
|
||||
if (!rx_iv) {
|
||||
rx_iv = rx_ivbuf;
|
||||
}
|
||||
if (!rx_hp_key) {
|
||||
rx_hp_key = rx_hp_keybuf;
|
||||
}
|
||||
if (!tx_key) {
|
||||
tx_key = tx_keybuf;
|
||||
}
|
||||
if (!tx_iv) {
|
||||
tx_iv = tx_ivbuf;
|
||||
}
|
||||
if (!tx_hp_key) {
|
||||
tx_hp_key = tx_hp_keybuf;
|
||||
}
|
||||
|
||||
ngtcp2_conn_set_initial_crypto_ctx(conn, &ctx);
|
||||
|
||||
if (ngtcp2_crypto_derive_initial_secrets(
|
||||
version, rx_secret, tx_secret, initial_secret, client_dcid,
|
||||
server ? NGTCP2_CRYPTO_SIDE_SERVER : NGTCP2_CRYPTO_SIDE_CLIENT) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(
|
||||
rx_key, rx_iv, rx_hp_key, &ctx.aead, &ctx.md, rx_secret,
|
||||
NGTCP2_CRYPTO_INITIAL_SECRETLEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(
|
||||
tx_key, tx_iv, tx_hp_key, &ctx.aead, &ctx.md, tx_secret,
|
||||
NGTCP2_CRYPTO_INITIAL_SECRETLEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_decrypt_init(&rx_aead_ctx, &ctx.aead, rx_key,
|
||||
NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_cipher_ctx_encrypt_init(&rx_hp_ctx, &ctx.hp, rx_hp_key) !=
|
||||
0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(&tx_aead_ctx, &ctx.aead, tx_key,
|
||||
NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_cipher_ctx_encrypt_init(&tx_hp_ctx, &ctx.hp, tx_hp_key) !=
|
||||
0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!server && !ngtcp2_conn_after_retry(conn)) {
|
||||
ngtcp2_crypto_aead_retry(&retry_aead);
|
||||
|
||||
if (ngtcp2_conn_get_negotiated_version(conn) == NGTCP2_PROTO_VER_V1) {
|
||||
retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
|
||||
retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
||||
} else {
|
||||
retry_key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT;
|
||||
retry_noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(&retry_aead_ctx, &retry_aead,
|
||||
retry_key, retry_noncelen) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ngtcp2_conn_install_initial_key(conn, &rx_aead_ctx, rx_iv, &rx_hp_ctx,
|
||||
&tx_aead_ctx, tx_iv, &tx_hp_ctx,
|
||||
NGTCP2_CRYPTO_INITIAL_IVLEN);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (retry_aead_ctx.native_handle) {
|
||||
ngtcp2_conn_set_retry_aead(conn, &retry_aead, &retry_aead_ctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ngtcp2_crypto_aead_ctx_free(&retry_aead_ctx);
|
||||
ngtcp2_crypto_cipher_ctx_free(&tx_hp_ctx);
|
||||
ngtcp2_crypto_aead_ctx_free(&tx_aead_ctx);
|
||||
ngtcp2_crypto_cipher_ctx_free(&rx_hp_ctx);
|
||||
ngtcp2_crypto_aead_ctx_free(&rx_aead_ctx);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_update_key(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_key, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_key, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
|
||||
size_t secretlen) {
|
||||
const ngtcp2_crypto_ctx *ctx = ngtcp2_conn_get_crypto_ctx(conn);
|
||||
const ngtcp2_crypto_aead *aead = &ctx->aead;
|
||||
const ngtcp2_crypto_md *md = &ctx->md;
|
||||
size_t ivlen = ngtcp2_crypto_packet_protection_ivlen(aead);
|
||||
|
||||
if (ngtcp2_crypto_update_traffic_secret(rx_secret, md, current_rx_secret,
|
||||
secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(rx_key, rx_iv, NULL, aead, md,
|
||||
rx_secret, secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_update_traffic_secret(tx_secret, md, current_tx_secret,
|
||||
secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(tx_key, tx_iv, NULL, aead, md,
|
||||
tx_secret, secretlen) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_decrypt_init(rx_aead_ctx, aead, rx_key, ivlen) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(tx_aead_ctx, aead, tx_key, ivlen) !=
|
||||
0) {
|
||||
ngtcp2_crypto_aead_ctx_free(rx_aead_ctx);
|
||||
rx_aead_ctx->native_handle = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_encrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *plaintext, size_t plaintextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
if (ngtcp2_crypto_encrypt(dest, aead, aead_ctx, plaintext, plaintextlen,
|
||||
nonce, noncelen, ad, adlen) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_decrypt_cb(uint8_t *dest, const ngtcp2_crypto_aead *aead,
|
||||
const ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
const uint8_t *ciphertext, size_t ciphertextlen,
|
||||
const uint8_t *nonce, size_t noncelen,
|
||||
const uint8_t *ad, size_t adlen) {
|
||||
if (ngtcp2_crypto_decrypt(dest, aead, aead_ctx, ciphertext, ciphertextlen,
|
||||
nonce, noncelen, ad, adlen) != 0) {
|
||||
return NGTCP2_ERR_TLS_DECRYPT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_hp_mask_cb(uint8_t *dest, const ngtcp2_crypto_cipher *hp,
|
||||
const ngtcp2_crypto_cipher_ctx *hp_ctx,
|
||||
const uint8_t *sample) {
|
||||
if (ngtcp2_crypto_hp_mask(dest, hp, hp_ctx, sample) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_update_key_cb(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
ngtcp2_crypto_aead_ctx *rx_aead_ctx, uint8_t *rx_iv,
|
||||
ngtcp2_crypto_aead_ctx *tx_aead_ctx, uint8_t *tx_iv,
|
||||
const uint8_t *current_rx_secret, const uint8_t *current_tx_secret,
|
||||
size_t secretlen, void *user_data) {
|
||||
uint8_t rx_key[64];
|
||||
uint8_t tx_key[64];
|
||||
(void)conn;
|
||||
(void)user_data;
|
||||
|
||||
if (ngtcp2_crypto_update_key(conn, rx_secret, tx_secret, rx_aead_ctx, rx_key,
|
||||
rx_iv, tx_aead_ctx, tx_key, tx_iv,
|
||||
current_rx_secret, current_tx_secret,
|
||||
secretlen) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_generate_stateless_reset_token(uint8_t *token,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen,
|
||||
const ngtcp2_cid *cid) {
|
||||
uint8_t buf[64];
|
||||
int rv;
|
||||
|
||||
assert(ngtcp2_crypto_md_hashlen(md) <= sizeof(buf));
|
||||
assert(NGTCP2_STATELESS_RESET_TOKENLEN <= sizeof(buf));
|
||||
|
||||
rv = ngtcp2_crypto_hkdf_extract(buf, md, secret, secretlen, cid->data,
|
||||
cid->datalen);
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(token, buf, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_write_connection_close(uint8_t *dest, size_t destlen,
|
||||
uint32_t version,
|
||||
const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid,
|
||||
uint64_t error_code) {
|
||||
uint8_t rx_secret[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t tx_secret[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t initial_secret[NGTCP2_CRYPTO_INITIAL_SECRETLEN];
|
||||
uint8_t tx_key[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
uint8_t tx_iv[NGTCP2_CRYPTO_INITIAL_IVLEN];
|
||||
uint8_t tx_hp_key[NGTCP2_CRYPTO_INITIAL_KEYLEN];
|
||||
ngtcp2_crypto_ctx ctx;
|
||||
ngtcp2_ssize spktlen;
|
||||
ngtcp2_crypto_aead_ctx aead_ctx = {0};
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx = {0};
|
||||
|
||||
ngtcp2_crypto_ctx_initial(&ctx);
|
||||
|
||||
if (ngtcp2_crypto_derive_initial_secrets(version, rx_secret, tx_secret,
|
||||
initial_secret, scid,
|
||||
NGTCP2_CRYPTO_SIDE_SERVER) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_derive_packet_protection_key(
|
||||
tx_key, tx_iv, tx_hp_key, &ctx.aead, &ctx.md, tx_secret,
|
||||
NGTCP2_CRYPTO_INITIAL_SECRETLEN) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &ctx.aead, tx_key,
|
||||
NGTCP2_CRYPTO_INITIAL_IVLEN) != 0) {
|
||||
spktlen = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_cipher_ctx_encrypt_init(&hp_ctx, &ctx.hp, tx_hp_key) != 0) {
|
||||
spktlen = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
spktlen = ngtcp2_pkt_write_connection_close(
|
||||
dest, destlen, version, dcid, scid, error_code, ngtcp2_crypto_encrypt_cb,
|
||||
&ctx.aead, &aead_ctx, tx_iv, ngtcp2_crypto_hp_mask_cb, &ctx.hp, &hp_ctx);
|
||||
if (spktlen < 0) {
|
||||
spktlen = -1;
|
||||
}
|
||||
|
||||
end:
|
||||
ngtcp2_crypto_cipher_ctx_free(&hp_ctx);
|
||||
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
||||
|
||||
return spktlen;
|
||||
}
|
||||
|
||||
ngtcp2_ssize ngtcp2_crypto_write_retry(uint8_t *dest, size_t destlen,
|
||||
uint32_t version, const ngtcp2_cid *dcid,
|
||||
const ngtcp2_cid *scid,
|
||||
const ngtcp2_cid *odcid,
|
||||
const uint8_t *token, size_t tokenlen) {
|
||||
ngtcp2_crypto_aead aead;
|
||||
ngtcp2_ssize spktlen;
|
||||
ngtcp2_crypto_aead_ctx aead_ctx = {0};
|
||||
const uint8_t *key;
|
||||
size_t noncelen;
|
||||
|
||||
ngtcp2_crypto_aead_retry(&aead);
|
||||
|
||||
if (version == NGTCP2_PROTO_VER_V1) {
|
||||
key = (const uint8_t *)NGTCP2_RETRY_KEY_V1;
|
||||
noncelen = sizeof(NGTCP2_RETRY_NONCE_V1) - 1;
|
||||
} else {
|
||||
key = (const uint8_t *)NGTCP2_RETRY_KEY_DRAFT;
|
||||
noncelen = sizeof(NGTCP2_RETRY_NONCE_DRAFT) - 1;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_aead_ctx_encrypt_init(&aead_ctx, &aead, key, noncelen) !=
|
||||
0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
spktlen = ngtcp2_pkt_write_retry(dest, destlen, version, dcid, scid, odcid,
|
||||
token, tokenlen, ngtcp2_crypto_encrypt_cb,
|
||||
&aead, &aead_ctx);
|
||||
if (spktlen < 0) {
|
||||
spktlen = -1;
|
||||
}
|
||||
|
||||
ngtcp2_crypto_aead_ctx_free(&aead_ctx);
|
||||
|
||||
return spktlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_setup_initial_crypto establishes the initial secrets and
|
||||
* encryption keys, and prepares local QUIC transport parameters.
|
||||
*/
|
||||
static int crypto_setup_initial_crypto(ngtcp2_conn *conn,
|
||||
const ngtcp2_cid *dcid) {
|
||||
return ngtcp2_crypto_derive_and_install_initial_key(
|
||||
conn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dcid);
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_client_initial_cb(ngtcp2_conn *conn, void *user_data) {
|
||||
const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(conn);
|
||||
void *tls = ngtcp2_conn_get_tls_native_handle(conn);
|
||||
(void)user_data;
|
||||
|
||||
if (crypto_setup_initial_crypto(conn, dcid) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (crypto_set_local_transport_params(conn, tls) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (ngtcp2_crypto_read_write_crypto_data(conn, NGTCP2_CRYPTO_LEVEL_INITIAL,
|
||||
NULL, 0) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_recv_retry_cb(ngtcp2_conn *conn, const ngtcp2_pkt_hd *hd,
|
||||
void *user_data) {
|
||||
(void)user_data;
|
||||
|
||||
if (ngtcp2_crypto_derive_and_install_initial_key(conn, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
&hd->scid) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ngtcp2_crypto_recv_client_initial_cb(ngtcp2_conn *conn,
|
||||
const ngtcp2_cid *dcid,
|
||||
void *user_data) {
|
||||
(void)user_data;
|
||||
|
||||
if (crypto_setup_initial_crypto(conn, dcid) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_delete_crypto_aead_ctx_cb(ngtcp2_conn *conn,
|
||||
ngtcp2_crypto_aead_ctx *aead_ctx,
|
||||
void *user_data) {
|
||||
(void)conn;
|
||||
(void)user_data;
|
||||
|
||||
ngtcp2_crypto_aead_ctx_free(aead_ctx);
|
||||
}
|
||||
|
||||
void ngtcp2_crypto_delete_crypto_cipher_ctx_cb(
|
||||
ngtcp2_conn *conn, ngtcp2_crypto_cipher_ctx *cipher_ctx, void *user_data) {
|
||||
(void)conn;
|
||||
(void)user_data;
|
||||
|
||||
ngtcp2_crypto_cipher_ctx_free(cipher_ctx);
|
||||
}
|
211
deps/ngtcp2/ngtcp2/crypto/shared.h
vendored
Normal file
211
deps/ngtcp2/ngtcp2/crypto/shared.h
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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_SHARED_H
|
||||
#define NGTCP2_SHARED_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_INITIAL_SALT_DRAFT` is a salt value which is used to
|
||||
* derive initial secret. It is used for QUIC draft versions.
|
||||
*/
|
||||
#define NGTCP2_INITIAL_SALT_DRAFT \
|
||||
"\xaf\xbf\xec\x28\x99\x93\xd2\x4c\x9e\x97\x86\xf1\x9c\x61\x11\xe0\x43\x90" \
|
||||
"\xa8\x99"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
*
|
||||
* :macro:`NGTCP2_INITIAL_SALT_V1` is a salt value which is used to
|
||||
* derive initial secret. It is used for QUIC v1.
|
||||
*/
|
||||
#define NGTCP2_INITIAL_SALT_V1 \
|
||||
"\x38\x76\x2c\xf7\xf5\x59\x34\xb3\x4d\x17\x9a\xe6\xa4\xc8\x0c\xad\xcc\xbb" \
|
||||
"\x7f\x0a"
|
||||
|
||||
/* Maximum key usage (encryption) limits */
|
||||
#define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_GCM (1ULL << 23)
|
||||
#define NGTCP2_CRYPTO_MAX_ENCRYPTION_CHACHA20_POLY1305 (1ULL << 62)
|
||||
#define NGTCP2_CRYPTO_MAX_ENCRYPTION_AES_CCM (2965820ULL)
|
||||
|
||||
/* Maximum authentication failure (decryption) limits during the
|
||||
lifetime of a connection. */
|
||||
#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_GCM (1ULL << 52)
|
||||
#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_CHACHA20_POLY1305 (1ULL << 36)
|
||||
#define NGTCP2_CRYPTO_MAX_DECRYPTION_FAILURE_AES_CCM (2965820ULL)
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_derive_initial_secrets` derives initial secrets.
|
||||
* |rx_secret| and |tx_secret| must point to the buffer of at least 32
|
||||
* bytes capacity. rx for read and tx for write. This function
|
||||
* writes rx and tx secrets into |rx_secret| and |tx_secret|
|
||||
* respectively. The length of secret is 32 bytes long.
|
||||
* |client_dcid| is the destination connection ID in first Initial
|
||||
* packet of client. If |initial_secret| is not NULL, the initial
|
||||
* secret is written to it. It must point to the buffer which has at
|
||||
* least 32 bytes capacity. The initial secret is 32 bytes long.
|
||||
* |side| specifies the side of application.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_derive_initial_secrets(uint32_t version, uint8_t *rx_secret,
|
||||
uint8_t *tx_secret,
|
||||
uint8_t *initial_secret,
|
||||
const ngtcp2_cid *client_dcid,
|
||||
ngtcp2_crypto_side side);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_update_traffic_secret` derives the next generation
|
||||
* of the traffic secret. |secret| specifies the current secret and
|
||||
* its length is given in |secretlen|. The length of new key is the
|
||||
* same as the current key. This function writes new key into the
|
||||
* buffer pointed by |dest|. |dest| must have the enough capacity to
|
||||
* store the new key.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_update_traffic_secret(uint8_t *dest,
|
||||
const ngtcp2_crypto_md *md,
|
||||
const uint8_t *secret,
|
||||
size_t secretlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_set_local_transport_params` sets QUIC transport
|
||||
* parameter, which is encoded in wire format and stored in the buffer
|
||||
* pointed by |buf| of length |len|, to the native handle |tls|.
|
||||
*
|
||||
* |tls| points to a implementation dependent TLS session object. If
|
||||
* libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL
|
||||
* object.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_set_local_transport_params(void *tls, const uint8_t *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_set_remote_transport_params` retrieves a remote QUIC
|
||||
* transport parameters from |tls| and sets it to |conn| using
|
||||
* `ngtcp2_conn_set_remote_transport_params`.
|
||||
*
|
||||
* |tls| points to a implementation dependent TLS session object. If
|
||||
* libngtcp2_crypto_openssl is linked, |tls| must be a pointer to SSL
|
||||
* object.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_set_remote_transport_params(ngtcp2_conn *conn, void *tls);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_derive_and_install_initial_key` derives initial
|
||||
* keying materials and installs keys to |conn|.
|
||||
*
|
||||
* If |rx_secret| is not NULL, the secret for decryption is written to
|
||||
* the buffer pointed by |rx_secret|. The length of secret is 32
|
||||
* bytes, and |rx_secret| must point to the buffer which has enough
|
||||
* capacity.
|
||||
*
|
||||
* If |tx_secret| is not NULL, the secret for encryption is written to
|
||||
* the buffer pointed by |tx_secret|. The length of secret is 32
|
||||
* bytes, and |tx_secret| must point to the buffer which has enough
|
||||
* capacity.
|
||||
*
|
||||
* If |initial_secret| is not NULL, the initial secret is written to
|
||||
* the buffer pointed by |initial_secret|. The length of secret is 32
|
||||
* bytes, and |initial_secret| must point to the buffer which has
|
||||
* enough capacity.
|
||||
*
|
||||
* |client_dcid| is the destination connection ID in first Initial
|
||||
* packet of client.
|
||||
*
|
||||
* If |rx_key| is not NULL, the derived packet protection key for
|
||||
* decryption is written to the buffer pointed by |rx_key|. If
|
||||
* |rx_iv| is not NULL, the derived packet protection IV for
|
||||
* decryption is written to the buffer pointed by |rx_iv|. If |rx_hp|
|
||||
* is not NULL, the derived header protection key for decryption is
|
||||
* written to the buffer pointed by |rx_hp|.
|
||||
*
|
||||
* If |tx_key| is not NULL, the derived packet protection key for
|
||||
* encryption is written to the buffer pointed by |tx_key|. If
|
||||
* |tx_iv| is not NULL, the derived packet protection IV for
|
||||
* encryption is written to the buffer pointed by |tx_iv|. If |tx_hp|
|
||||
* is not NULL, the derived header protection key for encryption is
|
||||
* written to the buffer pointed by |tx_hp|.
|
||||
*
|
||||
* The length of packet protection key and header protection key is 16
|
||||
* bytes long. The length of packet protection IV is 12 bytes long.
|
||||
*
|
||||
* This function calls `ngtcp2_conn_set_initial_crypto_ctx` to set
|
||||
* initial AEAD and message digest algorithm. After the successful
|
||||
* call of this function, application can use
|
||||
* `ngtcp2_conn_get_initial_crypto_ctx` to get the object.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_derive_and_install_initial_key(
|
||||
ngtcp2_conn *conn, uint8_t *rx_secret, uint8_t *tx_secret,
|
||||
uint8_t *initial_secret, uint8_t *rx_key, uint8_t *rx_iv, uint8_t *rx_hp,
|
||||
uint8_t *tx_key, uint8_t *tx_iv, uint8_t *tx_hp,
|
||||
const ngtcp2_cid *client_dcid);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_cipher_ctx_encrypt_init` initializes |cipher_ctx|
|
||||
* with new cipher context object for encryption which is constructed
|
||||
* to use |key| as encryption key. |cipher| specifies cipher to use.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int ngtcp2_crypto_cipher_ctx_encrypt_init(ngtcp2_crypto_cipher_ctx *cipher_ctx,
|
||||
const ngtcp2_crypto_cipher *cipher,
|
||||
const uint8_t *key);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_crypto_cipher_ctx_free` frees up resources used by
|
||||
* |cipher_ctx|. This function does not free the memory pointed by
|
||||
* |cipher_ctx| itself.
|
||||
*/
|
||||
void ngtcp2_crypto_cipher_ctx_free(ngtcp2_crypto_cipher_ctx *cipher_ctx);
|
||||
|
||||
#endif /* NGTCP2_SHARED_H */
|
4831
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
vendored
Normal file
4831
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/ngtcp2.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
51
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h
vendored
Normal file
51
deps/ngtcp2/ngtcp2/lib/includes/ngtcp2/version.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.1.0-DEV"
|
||||
|
||||
/**
|
||||
* @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 0x000100
|
||||
|
||||
#endif /* VERSION_H */
|
318
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c
vendored
Normal file
318
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.c
vendored
Normal file
@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
int ngtcp2_acktr_entry_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
|
||||
ngtcp2_tstamp tstamp, const ngtcp2_mem *mem) {
|
||||
*ent = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_acktr_entry));
|
||||
if (*ent == NULL) {
|
||||
return NGTCP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
(*ent)->pkt_num = pkt_num;
|
||||
(*ent)->len = 1;
|
||||
(*ent)->tstamp = tstamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_acktr_entry_del(ngtcp2_acktr_entry *ent, const ngtcp2_mem *mem) {
|
||||
ngtcp2_mem_free(mem, 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;
|
||||
|
||||
rv = ngtcp2_ringbuf_init(&acktr->acks, 128, sizeof(ngtcp2_acktr_ack_entry),
|
||||
mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = ngtcp2_ksl_init(&acktr->ents, greater, sizeof(int64_t), mem);
|
||||
if (rv != 0) {
|
||||
ngtcp2_ringbuf_free(&acktr->acks);
|
||||
return rv;
|
||||
}
|
||||
|
||||
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) {
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
if (acktr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (it = ngtcp2_ksl_begin(&acktr->ents); !ngtcp2_ksl_it_end(&it);
|
||||
ngtcp2_ksl_it_next(&it)) {
|
||||
ngtcp2_acktr_entry_del(ngtcp2_ksl_it_get(&it), acktr->mem);
|
||||
}
|
||||
ngtcp2_ksl_free(&acktr->ents);
|
||||
|
||||
ngtcp2_ringbuf_free(&acktr->acks);
|
||||
}
|
||||
|
||||
int ngtcp2_acktr_add(ngtcp2_acktr *acktr, int64_t pkt_num, int active_ack,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_ksl_it 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 {
|
||||
ngtcp2_ksl_it_prev(&it);
|
||||
prev_ent = ngtcp2_ksl_it_get(&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(&acktr->ents, NULL, &ent->pkt_num);
|
||||
ngtcp2_acktr_entry_del(ent, acktr->mem);
|
||||
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_new(&ent, pkt_num, ts, acktr->mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
rv = ngtcp2_ksl_insert(&acktr->ents, NULL, &ent->pkt_num, ent);
|
||||
if (rv != 0) {
|
||||
ngtcp2_acktr_entry_del(ent, acktr->mem);
|
||||
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(&acktr->ents, NULL, &delent->pkt_num);
|
||||
ngtcp2_acktr_entry_del(delent, acktr->mem);
|
||||
}
|
||||
|
||||
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(&acktr->ents, &it, &ent->pkt_num);
|
||||
ngtcp2_acktr_entry_del(ent, acktr->mem);
|
||||
}
|
||||
}
|
||||
|
||||
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|. 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(&acktr->ents, it, &ent->pkt_num);
|
||||
ngtcp2_acktr_entry_del(ent, acktr->mem);
|
||||
}
|
||||
|
||||
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_blklen;
|
||||
|
||||
if (min_ack <= ent->pkt_num && ent->pkt_num <= largest_ack) {
|
||||
acktr_on_ack(acktr, rb, j);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < fr->num_blks && j < nacks; ++i) {
|
||||
largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2;
|
||||
min_ack = largest_ack - (int64_t)fr->blks[i].blklen;
|
||||
|
||||
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 <= ts - max_ack_delay;
|
||||
}
|
||||
|
||||
void ngtcp2_acktr_immediate_ack(ngtcp2_acktr *acktr) {
|
||||
acktr->flags |= NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK;
|
||||
}
|
212
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h
vendored
Normal file
212
deps/ngtcp2/ngtcp2/lib/ngtcp2_acktr.h
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/* 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 {
|
||||
/* 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_acktr_entry;
|
||||
|
||||
/*
|
||||
* ngtcp2_acktr_entry_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_new(ngtcp2_acktr_entry **ent, int64_t pkt_num,
|
||||
ngtcp2_tstamp tstamp, const ngtcp2_mem *mem);
|
||||
|
||||
/*
|
||||
* ngtcp2_acktr_entry_del deallocates memory allocated for |ent|. It
|
||||
* deallocates memory pointed by |ent|.
|
||||
*/
|
||||
void ngtcp2_acktr_entry_del(ngtcp2_acktr_entry *ent, const ngtcp2_mem *mem);
|
||||
|
||||
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 0x00
|
||||
/* NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK indicates that immediate
|
||||
acknowledgement is required. */
|
||||
#define NGTCP2_ACKTR_FLAG_IMMEDIATE_ACK 0x01
|
||||
/* NGTCP2_ACKTR_FLAG_ACTIVE_ACK indicates that there are pending
|
||||
protected packet to be acknowledged. */
|
||||
#define NGTCP2_ACKTR_FLAG_ACTIVE_ACK 0x02
|
||||
/* NGTCP2_ACKTR_FLAG_ACK_FINISHED_ACK is set when server received
|
||||
acknowledgement for ACK which acknowledges the last handshake
|
||||
packet from client (which contains TLSv1.3 Finished message). */
|
||||
#define NGTCP2_ACKTR_FLAG_ACK_FINISHED_ACK 0x80
|
||||
/* NGTCP2_ACKTR_FLAG_CANCEL_TIMER is set when ACK delay timer is
|
||||
expired and canceled. */
|
||||
#define NGTCP2_ACKTR_FLAG_CANCEL_TIMER 0x0100
|
||||
|
||||
/*
|
||||
* ngtcp2_acktr tracks received packets which we have to send ack.
|
||||
*/
|
||||
typedef struct ngtcp2_acktr {
|
||||
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 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 */
|
131
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c
vendored
Normal file
131
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.c
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <netinet/ip.h>
|
||||
# include <netinet/tcp.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
ngtcp2_addr *ngtcp2_addr_init(ngtcp2_addr *dest, const struct sockaddr *addr,
|
||||
size_t addrlen, void *user_data) {
|
||||
dest->addrlen = addrlen;
|
||||
dest->addr = (struct sockaddr *)addr;
|
||||
dest->user_data = user_data;
|
||||
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, src->addrlen);
|
||||
}
|
||||
dest->user_data = src->user_data;
|
||||
}
|
||||
|
||||
void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const struct sockaddr *addr,
|
||||
size_t addrlen) {
|
||||
dest->addrlen = addrlen;
|
||||
if (addrlen) {
|
||||
memcpy(dest->addr, addr, addrlen);
|
||||
}
|
||||
}
|
||||
|
||||
static int sockaddr_eq(const struct sockaddr *a, const struct sockaddr *b) {
|
||||
assert(a->sa_family == b->sa_family);
|
||||
|
||||
switch (a->sa_family) {
|
||||
case AF_INET: {
|
||||
const struct sockaddr_in *ai = (const struct sockaddr_in *)(void *)a,
|
||||
*bi = (const struct sockaddr_in *)(void *)b;
|
||||
return ai->sin_port == bi->sin_port &&
|
||||
memcmp(&ai->sin_addr, &bi->sin_addr, sizeof(ai->sin_addr)) == 0;
|
||||
}
|
||||
case AF_INET6: {
|
||||
const struct sockaddr_in6 *ai = (const struct sockaddr_in6 *)(void *)a,
|
||||
*bi = (const struct sockaddr_in6 *)(void *)b;
|
||||
return ai->sin6_port == bi->sin6_port &&
|
||||
memcmp(&ai->sin6_addr, &bi->sin6_addr, sizeof(ai->sin6_addr)) == 0;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
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 struct sockaddr *a = aa->addr;
|
||||
const struct sockaddr *b = bb->addr;
|
||||
|
||||
if (a->sa_family != b->sa_family) {
|
||||
return NGTCP2_ADDR_COMPARE_FLAG_FAMILY;
|
||||
}
|
||||
|
||||
switch (a->sa_family) {
|
||||
case AF_INET: {
|
||||
const struct sockaddr_in *ai = (const struct sockaddr_in *)(void *)a,
|
||||
*bi = (const struct 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 AF_INET6: {
|
||||
const struct sockaddr_in6 *ai = (const struct sockaddr_in6 *)(void *)a,
|
||||
*bi = (const struct 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:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int ngtcp2_addr_empty(const ngtcp2_addr *addr) { return addr->addrlen == 0; }
|
78
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h
vendored
Normal file
78
deps/ngtcp2/ngtcp2/lib/ngtcp2_addr.h
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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_copy_byte copies |addr| of length |addrlen| into the
|
||||
* buffer pointed by dest->addr. dest->len is updated to have
|
||||
* |addrlen|. This function assumes that dest->addr points to a
|
||||
* buffer which have sufficient size to store the copy.
|
||||
*/
|
||||
void ngtcp2_addr_copy_byte(ngtcp2_addr *dest, const struct sockaddr *addr,
|
||||
size_t addrlen);
|
||||
|
||||
/*
|
||||
* 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 0x0
|
||||
/* NGTCP2_ADDR_COMPARE_FLAG_ADDR indicates IP addresses do not
|
||||
match. */
|
||||
#define NGTCP2_ADDR_COMPARE_FLAG_ADDR 0x1
|
||||
/* NGTCP2_ADDR_COMPARE_FLAG_PORT indicates ports do not match. */
|
||||
#define NGTCP2_ADDR_COMPARE_FLAG_PORT 0x2
|
||||
/* NGTCP2_ADDR_COMPARE_FLAG_FAMILY indicates address families do not
|
||||
match. */
|
||||
#define NGTCP2_ADDR_COMPARE_FLAG_FAMILY 0x4
|
||||
|
||||
/*
|
||||
* 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 */
|
44
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.c
vendored
Normal file
44
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.c
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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_left(const ngtcp2_buf *buf) {
|
||||
return (size_t)(buf->end - buf->last);
|
||||
}
|
||||
|
||||
size_t ngtcp2_buf_len(const ngtcp2_buf *buf) {
|
||||
return (size_t)(buf->last - buf->pos);
|
||||
}
|
||||
|
||||
size_t ngtcp2_buf_cap(const ngtcp2_buf *buf) {
|
||||
return (size_t)(buf->end - buf->begin);
|
||||
}
|
79
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.h
vendored
Normal file
79
deps/ngtcp2/ngtcp2/lib/ngtcp2_buf.h
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
size_t ngtcp2_buf_left(const ngtcp2_buf *buf);
|
||||
|
||||
/*
|
||||
* ngtcp2_buf_len returns the number of bytes left to read. In other
|
||||
* words, it returns buf->last - buf->pos.
|
||||
*/
|
||||
size_t ngtcp2_buf_len(const ngtcp2_buf *buf);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#endif /* NGTCP2_BUF_H */
|
536
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c
vendored
Normal file
536
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.c
vendored
Normal file
@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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 ts_sent) {
|
||||
pkt->pkt_num = pkt_num;
|
||||
pkt->pktlen = pktlen;
|
||||
pkt->pktns_id = pktns_id;
|
||||
pkt->ts_sent = ts_sent;
|
||||
|
||||
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->ts_sent)) {
|
||||
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_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 ts_sent,
|
||||
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, ts_sent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cstat->congestion_recovery_start_ts = ts;
|
||||
cstat->cwnd >>= NGTCP2_LOSS_REDUCTION_FACTOR_BITS;
|
||||
min_cwnd = 2 * cstat->max_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_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,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
|
||||
uint64_t target_cwnd, initcwnd;
|
||||
(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_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_reno_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_reno_cc, ccb);
|
||||
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->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_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, min_rtt, eta;
|
||||
uint64_t target;
|
||||
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->ts_sent)) {
|
||||
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_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_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;
|
||||
}
|
||||
|
||||
min_rtt = cstat->min_rtt == UINT64_MAX ? cstat->initial_rtt : cstat->min_rtt;
|
||||
|
||||
t = ts + min_rtt - cc->epoch_start;
|
||||
|
||||
tx = (t << 4) / NGTCP2_SECONDS;
|
||||
kx = (cc->k << 4);
|
||||
|
||||
if (tx > kx) {
|
||||
time_delta = tx - kx;
|
||||
} else {
|
||||
time_delta = kx - tx;
|
||||
}
|
||||
|
||||
delta = cstat->max_udp_payload_size *
|
||||
((((time_delta * time_delta) >> 4) * time_delta) >> 8) * 4 / 10;
|
||||
|
||||
if (tx > kx) {
|
||||
target = cc->origin_point + delta;
|
||||
} else {
|
||||
target = cc->origin_point - delta;
|
||||
}
|
||||
|
||||
if (target > cstat->cwnd) {
|
||||
m = cc->pending_add + cstat->max_udp_payload_size * (target - cstat->cwnd);
|
||||
add = m / cstat->cwnd;
|
||||
cc->pending_add = m % cstat->cwnd;
|
||||
} else {
|
||||
m = cc->pending_add + cstat->max_udp_payload_size;
|
||||
add = m / (100 * cstat->cwnd);
|
||||
cc->pending_add = m % (100 * cstat->cwnd);
|
||||
}
|
||||
|
||||
m = cc->pending_w_add + cstat->max_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_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 ts_sent,
|
||||
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, ts_sent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_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_persistent_congestion(ngtcp2_cc *ccx,
|
||||
ngtcp2_conn_stat *cstat,
|
||||
ngtcp2_tstamp ts) {
|
||||
(void)ccx;
|
||||
(void)ts;
|
||||
|
||||
cstat->cwnd = 2 * cstat->max_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,
|
||||
ngtcp2_tstamp ts) {
|
||||
ngtcp2_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
|
||||
uint64_t target_cwnd, initcwnd;
|
||||
(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_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_cubic_cc *cc = ngtcp2_struct_of(ccx->ccb, ngtcp2_cubic_cc, ccb);
|
||||
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;
|
||||
}
|
135
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h
vendored
Normal file
135
deps/ngtcp2/ngtcp2/lib/ngtcp2_cc.h
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* 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 ts_sent);
|
||||
|
||||
/* 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 ts_sent,
|
||||
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,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_cc_reno_cc_reset(ngtcp2_cc *cc);
|
||||
|
||||
/* 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;
|
||||
/* 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 ts_sent,
|
||||
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,
|
||||
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);
|
||||
|
||||
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 */
|
121
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c
vendored
Normal file
121
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.c
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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) { cid->datalen = 0; }
|
||||
|
||||
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,
|
||||
const uint8_t *token) {
|
||||
scid->pe.index = NGTCP2_PQ_BAD_INDEX;
|
||||
scid->seq = seq;
|
||||
scid->cid = *cid;
|
||||
scid->ts_retired = UINT64_MAX;
|
||||
scid->flags = NGTCP2_SCID_FLAG_NONE;
|
||||
if (token) {
|
||||
memcpy(scid->token, token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||
} else {
|
||||
memset(scid->token, 0, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||
}
|
||||
}
|
||||
|
||||
void ngtcp2_scid_copy(ngtcp2_scid *dest, const ngtcp2_scid *src) {
|
||||
ngtcp2_scid_init(dest, src->seq, &src->cid, src->token);
|
||||
dest->ts_retired = src->ts_retired;
|
||||
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);
|
||||
} else {
|
||||
memset(dcid->token, 0, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||
}
|
||||
ngtcp2_path_storage_zero(&dcid->ps);
|
||||
dcid->ts_retired = UINT64_MAX;
|
||||
dcid->flags = NGTCP2_DCID_FLAG_NONE;
|
||||
dcid->bytes_sent = 0;
|
||||
dcid->bytes_recv = 0;
|
||||
}
|
||||
|
||||
void ngtcp2_dcid_copy(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
|
||||
ngtcp2_dcid_init(dest, src->seq, &src->cid, src->token);
|
||||
ngtcp2_path_copy(&dest->ps.path, &src->ps.path);
|
||||
dest->ts_retired = src->ts_retired;
|
||||
dest->flags = src->flags;
|
||||
dest->bytes_sent = src->bytes_sent;
|
||||
dest->bytes_recv = src->bytes_recv;
|
||||
}
|
||||
|
||||
void ngtcp2_dcid_copy_cid_token(ngtcp2_dcid *dest, const ngtcp2_dcid *src) {
|
||||
dest->seq = src->seq;
|
||||
dest->cid = src->cid;
|
||||
memcpy(dest->token, src->token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||
}
|
||||
|
||||
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) &&
|
||||
memcmp(dcid->token, token,
|
||||
NGTCP2_STATELESS_RESET_TOKENLEN) == 0
|
||||
? 0
|
||||
: NGTCP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
return !ngtcp2_cid_eq(&dcid->cid, cid) ? 0 : NGTCP2_ERR_PROTO;
|
||||
}
|
153
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h
vendored
Normal file
153
deps/ngtcp2/ngtcp2/lib/ngtcp2_cid.h
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 indicats that no flag is set. */
|
||||
#define NGTCP2_SCID_FLAG_NONE 0x00
|
||||
/* NGTCP2_SCID_FLAG_USED indicates that a local endpoint observed that
|
||||
a remote endpoint uses a particular Connection ID. */
|
||||
#define NGTCP2_SCID_FLAG_USED 0x01
|
||||
/* NGTCP2_SCID_FLAG_RETIRED indicates that a particular Connection ID
|
||||
is retired. */
|
||||
#define NGTCP2_SCID_FLAG_RETIRED 0x02
|
||||
|
||||
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;
|
||||
/* ts_retired is the timestamp when peer tells that this CID is
|
||||
retired. */
|
||||
ngtcp2_tstamp ts_retired;
|
||||
/* flags is the bitwise OR of zero or more of NGTCP2_SCID_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_scid;
|
||||
|
||||
/* NGTCP2_DCID_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGTCP2_DCID_FLAG_NONE 0x00
|
||||
/* NGTCP2_DCID_FLAG_PATH_VALIDATED indicates that an associated path
|
||||
has been validated. */
|
||||
#define NGTCP2_DCID_FLAG_PATH_VALIDATED 0x01
|
||||
|
||||
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;
|
||||
/* ts_retired is the timestamp when peer tells that this CID is
|
||||
retired. */
|
||||
ngtcp2_tstamp ts_retired;
|
||||
/* 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;
|
||||
/* 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_eq returns nonzero if |cid| and |other| share the same
|
||||
* connection ID.
|
||||
*/
|
||||
int ngtcp2_cid_eq(const ngtcp2_cid *cid, const ngtcp2_cid *other);
|
||||
|
||||
/*
|
||||
* 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. If
|
||||
* |token| is NULL, the function fills scid->token it with 0. |token|
|
||||
* must be NGTCP2_STATELESS_RESET_TOKENLEN bytes long.
|
||||
*/
|
||||
void ngtcp2_scid_init(ngtcp2_scid *scid, uint64_t seq, const ngtcp2_cid *cid,
|
||||
const uint8_t *token);
|
||||
|
||||
/*
|
||||
* 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_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);
|
||||
|
||||
#endif /* NGTCP2_CID_H */
|
11236
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c
vendored
Normal file
11236
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
822
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h
vendored
Normal file
822
deps/ngtcp2/ngtcp2/lib/ngtcp2_conn.h
vendored
Normal file
@ -0,0 +1,822 @@
|
||||
/*
|
||||
* 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_CONN_H
|
||||
#define NGTCP2_CONN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#include "ngtcp2_mem.h"
|
||||
#include "ngtcp2_crypto.h"
|
||||
#include "ngtcp2_acktr.h"
|
||||
#include "ngtcp2_rtb.h"
|
||||
#include "ngtcp2_strm.h"
|
||||
#include "ngtcp2_mem.h"
|
||||
#include "ngtcp2_idtr.h"
|
||||
#include "ngtcp2_str.h"
|
||||
#include "ngtcp2_pkt.h"
|
||||
#include "ngtcp2_log.h"
|
||||
#include "ngtcp2_pq.h"
|
||||
#include "ngtcp2_cc.h"
|
||||
#include "ngtcp2_pv.h"
|
||||
#include "ngtcp2_cid.h"
|
||||
#include "ngtcp2_buf.h"
|
||||
#include "ngtcp2_ppe.h"
|
||||
#include "ngtcp2_qlog.h"
|
||||
#include "ngtcp2_rst.h"
|
||||
|
||||
typedef enum {
|
||||
/* Client specific handshake states */
|
||||
NGTCP2_CS_CLIENT_INITIAL,
|
||||
NGTCP2_CS_CLIENT_WAIT_HANDSHAKE,
|
||||
NGTCP2_CS_CLIENT_TLS_HANDSHAKE_FAILED,
|
||||
/* Server specific handshake states */
|
||||
NGTCP2_CS_SERVER_INITIAL,
|
||||
NGTCP2_CS_SERVER_WAIT_HANDSHAKE,
|
||||
NGTCP2_CS_SERVER_TLS_HANDSHAKE_FAILED,
|
||||
/* Shared by both client and server */
|
||||
NGTCP2_CS_POST_HANDSHAKE,
|
||||
NGTCP2_CS_CLOSING,
|
||||
NGTCP2_CS_DRAINING,
|
||||
} ngtcp2_conn_state;
|
||||
|
||||
/* NGTCP2_MAX_STREAMS is the maximum number of streams. */
|
||||
#define NGTCP2_MAX_STREAMS (1LL << 60)
|
||||
|
||||
/* NGTCP2_MAX_NUM_BUFFED_RX_PKTS is the maximum number of buffered
|
||||
reordered packets. */
|
||||
#define NGTCP2_MAX_NUM_BUFFED_RX_PKTS 4
|
||||
|
||||
/* NGTCP2_MAX_REORDERED_CRYPTO_DATA is the maximum offset of crypto
|
||||
data which is not continuous. In other words, there is a gap of
|
||||
unreceived data. */
|
||||
#define NGTCP2_MAX_REORDERED_CRYPTO_DATA 65536
|
||||
|
||||
/* NGTCP2_MAX_RX_INITIAL_CRYPTO_DATA is the maximum offset of received
|
||||
crypto stream in Initial packet. We set this hard limit here
|
||||
because crypto stream is unbounded. */
|
||||
#define NGTCP2_MAX_RX_INITIAL_CRYPTO_DATA 65536
|
||||
/* NGTCP2_MAX_RX_HANDSHAKE_CRYPTO_DATA is the maximum offset of
|
||||
received crypto stream in Handshake packet. We set this hard limit
|
||||
here because crypto stream is unbounded. */
|
||||
#define NGTCP2_MAX_RX_HANDSHAKE_CRYPTO_DATA 65536
|
||||
|
||||
/* NGTCP2_MAX_RETRIES is the number of Retry packet which client can
|
||||
accept. */
|
||||
#define NGTCP2_MAX_RETRIES 3
|
||||
|
||||
/* NGTCP2_MAX_BOUND_DCID_POOL_SIZE is the maximum number of
|
||||
destination connection ID which have been bound to a particular
|
||||
path, but not yet used as primary path and path validation is not
|
||||
performed from the local endpoint. */
|
||||
#define NGTCP2_MAX_BOUND_DCID_POOL_SIZE 4
|
||||
/* NGTCP2_MAX_DCID_POOL_SIZE is the maximum number of destination
|
||||
connection ID the remote endpoint provides to store. It must be
|
||||
the power of 2. */
|
||||
#define NGTCP2_MAX_DCID_POOL_SIZE 8
|
||||
/* NGTCP2_MAX_DCID_RETIRED_SIZE is the maximum number of retired DCID
|
||||
kept to catch in-flight packet on retired path. */
|
||||
#define NGTCP2_MAX_DCID_RETIRED_SIZE 2
|
||||
/* NGTCP2_MAX_SCID_POOL_SIZE is the maximum number of source
|
||||
connection ID the local endpoint provides to the remote endpoint.
|
||||
The chosen value was described in old draft. Now a remote endpoint
|
||||
tells the maximum value. The value can be quite large, and we have
|
||||
to put the sane limit.*/
|
||||
#define NGTCP2_MAX_SCID_POOL_SIZE 8
|
||||
|
||||
/* NGTCP2_MAX_NON_ACK_TX_PKT is the maximum number of continuous non
|
||||
ACK-eliciting packets. */
|
||||
#define NGTCP2_MAX_NON_ACK_TX_PKT 3
|
||||
|
||||
/* NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS is the maximum number of ECN marked
|
||||
packets sent in NGTCP2_ECN_STATE_TESTING period. */
|
||||
#define NGTCP2_ECN_MAX_NUM_VALIDATION_PKTS 10
|
||||
|
||||
/*
|
||||
* ngtcp2_max_frame is defined so that it covers the largest ACK
|
||||
* frame.
|
||||
*/
|
||||
typedef union ngtcp2_max_frame {
|
||||
ngtcp2_frame fr;
|
||||
struct {
|
||||
ngtcp2_ack ack;
|
||||
/* ack includes 1 ngtcp2_ack_blk. */
|
||||
ngtcp2_ack_blk blks[NGTCP2_MAX_ACK_BLKS - 1];
|
||||
} ackfr;
|
||||
} ngtcp2_max_frame;
|
||||
|
||||
typedef struct ngtcp2_path_challenge_entry {
|
||||
ngtcp2_path_storage ps;
|
||||
uint8_t data[8];
|
||||
} ngtcp2_path_challenge_entry;
|
||||
|
||||
void ngtcp2_path_challenge_entry_init(ngtcp2_path_challenge_entry *pcent,
|
||||
const ngtcp2_path *path,
|
||||
const uint8_t *data);
|
||||
|
||||
/* NGTCP2_CONN_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGTCP2_CONN_FLAG_NONE 0x00
|
||||
/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED is set if handshake
|
||||
completed. */
|
||||
#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED 0x01
|
||||
/* NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED is set if connection ID is
|
||||
negotiated. This is only used for client. */
|
||||
#define NGTCP2_CONN_FLAG_CONN_ID_NEGOTIATED 0x02
|
||||
/* NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED is set if transport
|
||||
parameters are received. */
|
||||
#define NGTCP2_CONN_FLAG_TRANSPORT_PARAM_RECVED 0x04
|
||||
/* NGTCP2_CONN_FLAG_RECV_PROTECTED_PKT is set when a protected packet
|
||||
is received, and decrypted successfully. This flag is used to stop
|
||||
retransmitting handshake packets. It might be replaced with an
|
||||
another mechanism when we implement key update. */
|
||||
#define NGTCP2_CONN_FLAG_RECV_PROTECTED_PKT 0x08
|
||||
/* NGTCP2_CONN_FLAG_RECV_RETRY is set when a client receives Retry
|
||||
packet. */
|
||||
#define NGTCP2_CONN_FLAG_RECV_RETRY 0x10
|
||||
/* NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED is set when 0-RTT packet is
|
||||
rejected by a peer. */
|
||||
#define NGTCP2_CONN_FLAG_EARLY_DATA_REJECTED 0x20
|
||||
/* NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED is set when an endpoint
|
||||
confirmed completion of handshake. */
|
||||
#define NGTCP2_CONN_FLAG_HANDSHAKE_CONFIRMED 0x80
|
||||
/* NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED is set when the
|
||||
library transitions its state to "post handshake". */
|
||||
#define NGTCP2_CONN_FLAG_HANDSHAKE_COMPLETED_HANDLED 0x0100
|
||||
/* NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT is set when the early
|
||||
handshake retransmission has done when server receives overlapping
|
||||
Initial crypto data. */
|
||||
#define NGTCP2_CONN_FLAG_HANDSHAKE_EARLY_RETRANSMIT 0x0200
|
||||
/* NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED is set when key update is
|
||||
not confirmed by the local endpoint. That is, it has not received
|
||||
ACK frame which acknowledges packet which is encrypted with new
|
||||
key. */
|
||||
#define NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED 0x0800
|
||||
/* NGTCP2_CONN_FLAG_PPE_PENDING is set when
|
||||
NGTCP2_WRITE_STREAM_FLAG_MORE is used and the intermediate state of
|
||||
ngtcp2_ppe is stored in pkt struct of ngtcp2_conn. */
|
||||
#define NGTCP2_CONN_FLAG_PPE_PENDING 0x1000
|
||||
/* NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE is set when idle timer
|
||||
should be restarted on next write. */
|
||||
#define NGTCP2_CONN_FLAG_RESTART_IDLE_TIMER_ON_WRITE 0x2000
|
||||
/* NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED indicates that server as peer
|
||||
verified client address. This flag is only used by client. */
|
||||
#define NGTCP2_CONN_FLAG_SERVER_ADDR_VERIFIED 0x4000
|
||||
|
||||
typedef struct ngtcp2_crypto_data {
|
||||
ngtcp2_buf buf;
|
||||
/* pkt_type is the type of packet to send data in buf. If it is 0,
|
||||
it must be sent in Short packet. Otherwise, it is sent the long
|
||||
packet type denoted by pkt_type. */
|
||||
uint8_t pkt_type;
|
||||
} ngtcp2_crypto_data;
|
||||
|
||||
typedef struct ngtcp2_pktns {
|
||||
struct {
|
||||
/* last_pkt_num is the packet number which the local endpoint sent
|
||||
last time.*/
|
||||
int64_t last_pkt_num;
|
||||
ngtcp2_frame_chain *frq;
|
||||
/* num_non_ack_pkt is the number of continuous non ACK-eliciting
|
||||
packets. */
|
||||
size_t num_non_ack_pkt;
|
||||
|
||||
struct {
|
||||
/* ect0 is the number of QUIC packets, not UDP datagram, which
|
||||
are sent in UDP datagram with ECT0 marking. */
|
||||
size_t ect0;
|
||||
/* start_pkt_num is the lowest packet number that are sent
|
||||
during ECN validation period. */
|
||||
int64_t start_pkt_num;
|
||||
/* validation_pkt_sent is the number of QUIC packets sent during
|
||||
validation period. */
|
||||
size_t validation_pkt_sent;
|
||||
/* validation_pkt_lost is the number of QUIC packets lost during
|
||||
validation period. */
|
||||
size_t validation_pkt_lost;
|
||||
} ecn;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
/* pngap tracks received packet number in order to suppress
|
||||
duplicated packet number. */
|
||||
ngtcp2_gaptr pngap;
|
||||
/* max_pkt_num is the largest packet number received so far. */
|
||||
int64_t max_pkt_num;
|
||||
/* max_pkt_ts is the timestamp when max_pkt_num packet is
|
||||
received. */
|
||||
ngtcp2_tstamp max_pkt_ts;
|
||||
/* max_ack_eliciting_pkt_num is the largest ack-eliciting packet
|
||||
number received so far. */
|
||||
int64_t max_ack_eliciting_pkt_num;
|
||||
/*
|
||||
* buffed_pkts is buffered packets which cannot be decrypted with
|
||||
* the current encryption level.
|
||||
*
|
||||
* In server Initial encryption level, 0-RTT packet may be buffered.
|
||||
* In server Handshake encryption level, Short packet may be buffered.
|
||||
*
|
||||
* In client Initial encryption level, Handshake or Short packet may
|
||||
* be buffered. In client Handshake encryption level, Short packet
|
||||
* may be buffered.
|
||||
*
|
||||
* - 0-RTT packet is only buffered in server Initial encryption
|
||||
* level ngtcp2_pktns.
|
||||
*
|
||||
* - Handshake packet is only buffered in client Handshake
|
||||
* encryption level ngtcp2_pktns.
|
||||
*
|
||||
* - Short packet is only buffered in Short encryption level
|
||||
* ngtcp2_pktns.
|
||||
*/
|
||||
ngtcp2_pkt_chain *buffed_pkts;
|
||||
|
||||
struct {
|
||||
/* ect0, ect1, and ce are the number of QUIC packets received
|
||||
with those markings. */
|
||||
size_t ect0;
|
||||
size_t ect1;
|
||||
size_t ce;
|
||||
struct {
|
||||
/* ect0, ect1, ce are the ECN counts received in the latest
|
||||
ACK frame. */
|
||||
size_t ect0;
|
||||
size_t ect1;
|
||||
size_t ce;
|
||||
} ack;
|
||||
} ecn;
|
||||
} rx;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
/* frq contains crypto data sorted by their offset. */
|
||||
ngtcp2_ksl frq;
|
||||
/* offset is the offset of crypto stream in this packet number
|
||||
space. */
|
||||
uint64_t offset;
|
||||
/* ckm is a cryptographic key, and iv to encrypt outgoing
|
||||
packets. */
|
||||
ngtcp2_crypto_km *ckm;
|
||||
/* hp_ctx is cipher context for packet header protection. */
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
/* ckm is a cryptographic key, and iv to decrypt incoming
|
||||
packets. */
|
||||
ngtcp2_crypto_km *ckm;
|
||||
/* hp_ctx is cipher context for packet header protection. */
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx;
|
||||
} rx;
|
||||
|
||||
ngtcp2_strm strm;
|
||||
ngtcp2_crypto_ctx ctx;
|
||||
} crypto;
|
||||
|
||||
ngtcp2_acktr acktr;
|
||||
ngtcp2_rtb rtb;
|
||||
} ngtcp2_pktns;
|
||||
|
||||
typedef enum ngtcp2_ecn_state {
|
||||
NGTCP2_ECN_STATE_TESTING,
|
||||
NGTCP2_ECN_STATE_UNKNOWN,
|
||||
NGTCP2_ECN_STATE_FAILED,
|
||||
NGTCP2_ECN_STATE_CAPABLE,
|
||||
} ngtcp2_ecn_state;
|
||||
|
||||
struct ngtcp2_conn {
|
||||
ngtcp2_conn_state state;
|
||||
ngtcp2_callbacks callbacks;
|
||||
/* rcid is a connection ID present in Initial or 0-RTT packet from
|
||||
client as destination connection ID. Server uses this field to
|
||||
check that duplicated Initial or 0-RTT packet are indeed sent to
|
||||
this connection. It is also sent to client as
|
||||
original_destination_connection_id transport parameter. Client
|
||||
uses this field to validate original_destination_connection_id
|
||||
transport parameter if no Retry packet is involved. */
|
||||
ngtcp2_cid rcid;
|
||||
/* oscid is the source connection ID initially used by the local
|
||||
endpoint. */
|
||||
ngtcp2_cid oscid;
|
||||
/* retry_scid is the source connection ID from Retry packet. Client
|
||||
records it in order to verify retry_source_connection_id
|
||||
transport parameter. Server does not use this field. */
|
||||
ngtcp2_cid retry_scid;
|
||||
ngtcp2_pktns *in_pktns;
|
||||
ngtcp2_pktns *hs_pktns;
|
||||
ngtcp2_pktns pktns;
|
||||
|
||||
struct {
|
||||
/* current is the current destination connection ID. */
|
||||
ngtcp2_dcid current;
|
||||
/* bound is a set of destination connection IDs which are bound to
|
||||
particular paths. These paths are not validated yet. */
|
||||
ngtcp2_ringbuf bound;
|
||||
/* unused is a set of unused CID received from peer. */
|
||||
ngtcp2_ringbuf unused;
|
||||
/* retired is a set of CID retired by local endpoint. Keep them
|
||||
in 3*PTO to catch packets in flight along the old path. */
|
||||
ngtcp2_ringbuf retired;
|
||||
/* seqgap tracks received sequence numbers in order to ignore
|
||||
retransmitted duplicated NEW_CONNECTION_ID frame. */
|
||||
ngtcp2_gaptr seqgap;
|
||||
/* retire_prior_to is the largest retire_prior_to received so
|
||||
far. */
|
||||
uint64_t retire_prior_to;
|
||||
/* num_retire_queued is the number of RETIRE_CONNECTION_ID frames
|
||||
queued for transmission. */
|
||||
size_t num_retire_queued;
|
||||
/* zerolen_seq is a pseudo sequence number of zero-length
|
||||
Destination Connection ID in order to distinguish between
|
||||
them. */
|
||||
uint64_t zerolen_seq;
|
||||
} dcid;
|
||||
|
||||
struct {
|
||||
/* set is a set of CID sent to peer. The peer can use any CIDs in
|
||||
this set. This includes used CID as well as unused ones. */
|
||||
ngtcp2_ksl set;
|
||||
/* used is a set of CID used by peer. The sort function of this
|
||||
priority queue takes timestamp when CID is retired and sorts
|
||||
them in ascending order. */
|
||||
ngtcp2_pq used;
|
||||
/* last_seq is the last sequence number of connection ID. */
|
||||
uint64_t last_seq;
|
||||
/* num_retired is the number of retired Connection ID still
|
||||
included in set. */
|
||||
size_t num_retired;
|
||||
} scid;
|
||||
|
||||
struct {
|
||||
/* strmq contains ngtcp2_strm which has frames to send. */
|
||||
ngtcp2_pq strmq;
|
||||
/* ack is ACK frame. The underlying buffer is reused. */
|
||||
ngtcp2_frame *ack;
|
||||
/* max_ack_blks is the number of additional ngtcp2_ack_blk which
|
||||
ack can contain. */
|
||||
size_t max_ack_blks;
|
||||
/* offset is the offset the local endpoint has sent to the remote
|
||||
endpoint. */
|
||||
uint64_t offset;
|
||||
/* max_offset is the maximum offset that local endpoint can
|
||||
send. */
|
||||
uint64_t max_offset;
|
||||
/* last_max_data_ts is the timestamp when last MAX_DATA frame is
|
||||
sent. */
|
||||
ngtcp2_tstamp last_max_data_ts;
|
||||
|
||||
struct {
|
||||
/* state is the state of ECN validation */
|
||||
ngtcp2_ecn_state state;
|
||||
/* validation_start_ts is the timestamp when ECN validation is
|
||||
started. It is UINT64_MAX if it has not started yet. */
|
||||
ngtcp2_tstamp validation_start_ts;
|
||||
/* dgram_sent is the number of UDP datagram sent during ECN
|
||||
validation period. */
|
||||
size_t dgram_sent;
|
||||
} ecn;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
/* unsent_max_offset is the maximum offset that remote endpoint
|
||||
can send without extending MAX_DATA. This limit is not yet
|
||||
notified to the remote endpoint. */
|
||||
uint64_t unsent_max_offset;
|
||||
/* offset is the cumulative sum of stream data received for this
|
||||
connection. */
|
||||
uint64_t offset;
|
||||
/* max_offset is the maximum offset that remote endpoint can
|
||||
send. */
|
||||
uint64_t max_offset;
|
||||
/* window is the connection-level flow control window size. */
|
||||
uint64_t window;
|
||||
/* path_challenge stores received PATH_CHALLENGE data. */
|
||||
ngtcp2_ringbuf path_challenge;
|
||||
/* ccec is the received connection close error code. */
|
||||
ngtcp2_connection_close_error_code ccec;
|
||||
} rx;
|
||||
|
||||
struct {
|
||||
ngtcp2_crypto_km *ckm;
|
||||
ngtcp2_crypto_cipher_ctx hp_ctx;
|
||||
ngtcp2_crypto_ctx ctx;
|
||||
/* discard_started_ts is the timestamp when the timer to discard
|
||||
early key has started. Used by server only. */
|
||||
ngtcp2_tstamp discard_started_ts;
|
||||
} early;
|
||||
|
||||
struct {
|
||||
ngtcp2_settings settings;
|
||||
/* transport_params is the local transport parameters. It is used
|
||||
for Short packet only. */
|
||||
ngtcp2_transport_params transport_params;
|
||||
struct {
|
||||
/* max_streams is the maximum number of bidirectional streams which
|
||||
the local endpoint can open. */
|
||||
uint64_t max_streams;
|
||||
/* next_stream_id is the bidirectional stream ID which the local
|
||||
endpoint opens next. */
|
||||
int64_t next_stream_id;
|
||||
} bidi;
|
||||
|
||||
struct {
|
||||
/* max_streams is the maximum number of unidirectional streams
|
||||
which the local endpoint can open. */
|
||||
uint64_t max_streams;
|
||||
/* next_stream_id is the unidirectional stream ID which the
|
||||
local endpoint opens next. */
|
||||
int64_t next_stream_id;
|
||||
} uni;
|
||||
} local;
|
||||
|
||||
struct {
|
||||
/* transport_params is the received transport parameters during
|
||||
handshake. It is used for Short packet only. */
|
||||
ngtcp2_transport_params transport_params;
|
||||
/* pending_transport_params is received transport parameters
|
||||
during handshake. It is copied to transport_params when 1RTT
|
||||
key is available. */
|
||||
ngtcp2_transport_params pending_transport_params;
|
||||
struct {
|
||||
ngtcp2_idtr idtr;
|
||||
/* unsent_max_streams is the maximum number of streams of peer
|
||||
initiated bidirectional stream which the local endpoint can
|
||||
accept. This limit is not yet notified to the remote
|
||||
endpoint. */
|
||||
uint64_t unsent_max_streams;
|
||||
/* max_streams is the maximum number of streams of peer
|
||||
initiated bidirectional stream which the local endpoint can
|
||||
accept. */
|
||||
uint64_t max_streams;
|
||||
} bidi;
|
||||
|
||||
struct {
|
||||
ngtcp2_idtr idtr;
|
||||
/* unsent_max_streams is the maximum number of streams of peer
|
||||
initiated unidirectional stream which the local endpoint can
|
||||
accept. This limit is not yet notified to the remote
|
||||
endpoint. */
|
||||
uint64_t unsent_max_streams;
|
||||
/* max_streams is the maximum number of streams of peer
|
||||
initiated unidirectional stream which the local endpoint can
|
||||
accept. */
|
||||
uint64_t max_streams;
|
||||
} uni;
|
||||
} remote;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
/* new_tx_ckm is a new sender 1RTT key which has not been
|
||||
used. */
|
||||
ngtcp2_crypto_km *new_tx_ckm;
|
||||
/* new_rx_ckm is a new receiver 1RTT key which has not
|
||||
successfully decrypted incoming packet yet. */
|
||||
ngtcp2_crypto_km *new_rx_ckm;
|
||||
/* old_rx_ckm is an old receiver 1RTT key. */
|
||||
ngtcp2_crypto_km *old_rx_ckm;
|
||||
/* confirmed_ts is the time instant when the key update is
|
||||
confirmed by the local endpoint last time. UINT64_MAX means
|
||||
undefined value. */
|
||||
ngtcp2_tstamp confirmed_ts;
|
||||
} key_update;
|
||||
|
||||
/* tls_native_handle is a native handle to TLS session object. */
|
||||
void *tls_native_handle;
|
||||
/* decrypt_hp_buf is a buffer which is used to write unprotected
|
||||
packet header. */
|
||||
ngtcp2_vec decrypt_hp_buf;
|
||||
/* decrypt_buf is a buffer which is used to write decrypted data. */
|
||||
ngtcp2_vec decrypt_buf;
|
||||
/* retry_aead is AEAD to verify Retry packet integrity. It is
|
||||
used by client only. */
|
||||
ngtcp2_crypto_aead retry_aead;
|
||||
/* retry_aead_ctx is AEAD cipher context to verify Retry packet
|
||||
integrity. It is used by client only. */
|
||||
ngtcp2_crypto_aead_ctx retry_aead_ctx;
|
||||
/* tls_error is TLS related error. */
|
||||
int tls_error;
|
||||
/* decryption_failure_count is the number of received packets that
|
||||
fail authentication. */
|
||||
uint64_t decryption_failure_count;
|
||||
} crypto;
|
||||
|
||||
/* pkt contains the packet intermediate construction data to support
|
||||
NGTCP2_WRITE_STREAM_FLAG_MORE */
|
||||
struct {
|
||||
ngtcp2_crypto_cc cc;
|
||||
ngtcp2_pkt_hd hd;
|
||||
ngtcp2_ppe ppe;
|
||||
ngtcp2_frame_chain **pfrc;
|
||||
int pkt_empty;
|
||||
int hd_logged;
|
||||
uint8_t rtb_entry_flags;
|
||||
int was_client_initial;
|
||||
ngtcp2_ssize hs_spktlen;
|
||||
} pkt;
|
||||
|
||||
ngtcp2_map strms;
|
||||
ngtcp2_conn_stat cstat;
|
||||
ngtcp2_pv *pv;
|
||||
ngtcp2_log log;
|
||||
ngtcp2_qlog qlog;
|
||||
ngtcp2_rst rst;
|
||||
ngtcp2_cc_algo cc_algo;
|
||||
ngtcp2_cc cc;
|
||||
const ngtcp2_mem *mem;
|
||||
/* idle_ts is the time instant when idle timer started. */
|
||||
ngtcp2_tstamp idle_ts;
|
||||
void *user_data;
|
||||
uint32_t version;
|
||||
/* flags is bitwise OR of zero or more of NGTCP2_CONN_FLAG_*. */
|
||||
uint16_t flags;
|
||||
int server;
|
||||
};
|
||||
|
||||
typedef enum ngtcp2_vmsg_type {
|
||||
NGTCP2_VMSG_TYPE_STREAM,
|
||||
NGTCP2_VMSG_TYPE_DATAGRAM,
|
||||
} ngtcp2_vmsg_type;
|
||||
|
||||
typedef struct ngtcp2_vmsg_stream {
|
||||
/* strm is a stream that data is sent to. */
|
||||
ngtcp2_strm *strm;
|
||||
/* flags is bitwise OR of zero or more of
|
||||
NGTCP2_WRITE_STREAM_FLAG_*. */
|
||||
uint32_t flags;
|
||||
/* data is the pointer to ngtcp2_vec array which contains the stream
|
||||
data to send. */
|
||||
const ngtcp2_vec *data;
|
||||
/* datacnt is the number of ngtcp2_vec pointed by data. */
|
||||
size_t datacnt;
|
||||
/* pdatalen is the pointer to the variable which the number of bytes
|
||||
written is assigned to if pdatalen is not NULL. */
|
||||
ngtcp2_ssize *pdatalen;
|
||||
} ngtcp2_vmsg_stream;
|
||||
|
||||
typedef struct ngtcp2_vmsg_datagram {
|
||||
/* data is the pointer to ngtcp2_vec array which contains the data
|
||||
to send. */
|
||||
const ngtcp2_vec *data;
|
||||
/* datacnt is the number of ngtcp2_vec pointed by data. */
|
||||
size_t datacnt;
|
||||
/* flags is bitwise OR of zero or more of
|
||||
NGTCP2_WRITE_DATAGRAM_FLAG_*. */
|
||||
uint32_t flags;
|
||||
/* paccepted is the pointer to the variable which, if it is not
|
||||
NULL, is assigned nonzero if data is written to a packet. */
|
||||
int *paccepted;
|
||||
} ngtcp2_vmsg_datagram;
|
||||
|
||||
typedef struct ngtcp2_vmsg {
|
||||
ngtcp2_vmsg_type type;
|
||||
union {
|
||||
ngtcp2_vmsg_stream stream;
|
||||
ngtcp2_vmsg_datagram datagram;
|
||||
};
|
||||
} ngtcp2_vmsg;
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_sched_ack stores packet number |pkt_num| and its
|
||||
* reception timestamp |ts| in order to send its ACK.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGTCP2_ERR_PROTO
|
||||
* Same packet number has already been added.
|
||||
*/
|
||||
int ngtcp2_conn_sched_ack(ngtcp2_conn *conn, ngtcp2_acktr *acktr,
|
||||
int64_t pkt_num, int active_ack, ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_find_stream returns a stream whose stream ID is
|
||||
* |stream_id|. If no such stream is found, it returns NULL.
|
||||
*/
|
||||
ngtcp2_strm *ngtcp2_conn_find_stream(ngtcp2_conn *conn, int64_t stream_id);
|
||||
|
||||
/*
|
||||
* conn_init_stream initializes |strm|. Its stream ID is |stream_id|.
|
||||
* This function adds |strm| to conn->strms. |strm| must be allocated
|
||||
* by the caller.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGTCP2_ERR_CALLBACK_FAILURE
|
||||
* User-callback function failed.
|
||||
*/
|
||||
int ngtcp2_conn_init_stream(ngtcp2_conn *conn, ngtcp2_strm *strm,
|
||||
int64_t stream_id, void *stream_user_data);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_close_stream closes stream |strm|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_INVALID_ARGUMENT
|
||||
* Stream is not found.
|
||||
* NGTCP2_ERR_CALLBACK_FAILURE
|
||||
* User-defined callback function failed.
|
||||
*/
|
||||
int ngtcp2_conn_close_stream(ngtcp2_conn *conn, ngtcp2_strm *strm,
|
||||
uint64_t app_error_code);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_close_stream closes stream |strm| if no further
|
||||
* transmission and reception are allowed, and all reordered incoming
|
||||
* data are emitted to the application, and the transmitted data are
|
||||
* acked.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_INVALID_ARGUMENT
|
||||
* Stream is not found.
|
||||
* NGTCP2_ERR_CALLBACK_FAILURE
|
||||
* User-defined callback function failed.
|
||||
*/
|
||||
int ngtcp2_conn_close_stream_if_shut_rdwr(ngtcp2_conn *conn, ngtcp2_strm *strm,
|
||||
uint64_t app_error_code);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_update_rtt updates RTT measurements. |rtt| is a latest
|
||||
* RTT which is not adjusted by ack delay. |ack_delay| is unscaled
|
||||
* ack_delay included in ACK frame. |ack_delay| is actually tainted
|
||||
* (sent by peer), so don't assume that |ack_delay| is always smaller
|
||||
* than, or equals to |rtt|.
|
||||
*/
|
||||
void ngtcp2_conn_update_rtt(ngtcp2_conn *conn, ngtcp2_duration rtt,
|
||||
ngtcp2_duration ack_delay, ngtcp2_tstamp ts);
|
||||
|
||||
void ngtcp2_conn_set_loss_detection_timer(ngtcp2_conn *conn, ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_detect_lost_pkt detects lost packets.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int ngtcp2_conn_detect_lost_pkt(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
||||
ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_tx_strmq_top returns the ngtcp2_strm which sits on the
|
||||
* top of queue. tx_strmq must not be empty.
|
||||
*/
|
||||
ngtcp2_strm *ngtcp2_conn_tx_strmq_top(ngtcp2_conn *conn);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_tx_strmq_pop pops the ngtcp2_strm from the queue.
|
||||
* tx_strmq must not be empty.
|
||||
*/
|
||||
void ngtcp2_conn_tx_strmq_pop(ngtcp2_conn *conn);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_tx_strmq_push pushes |strm| into tx_strmq.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int ngtcp2_conn_tx_strmq_push(ngtcp2_conn *conn, ngtcp2_strm *strm);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_internal_expiry returns the minimum expiry time among
|
||||
* all timers in |conn|.
|
||||
*/
|
||||
ngtcp2_tstamp ngtcp2_conn_internal_expiry(ngtcp2_conn *conn);
|
||||
|
||||
ngtcp2_ssize ngtcp2_conn_write_vmsg(ngtcp2_conn *conn, ngtcp2_path *path,
|
||||
ngtcp2_pkt_info *pi, uint8_t *dest,
|
||||
size_t destlen, ngtcp2_vmsg *vmsg,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_write_single_frame_pkt writes a packet which contains |fr|
|
||||
* frame only in the buffer pointed by |dest| whose length if
|
||||
* |destlen|. |type| is a long packet type to send. If |type| is 0,
|
||||
* Short packet is used. |dcid| is used as a destination connection
|
||||
* ID.
|
||||
*
|
||||
* The packet written by this function will not be retransmitted.
|
||||
*
|
||||
* This function returns the number of bytes written in |dest| if it
|
||||
* succeeds, or one of the following negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_CALLBACK_FAILURE
|
||||
* User-defined callback function failed.
|
||||
*/
|
||||
ngtcp2_ssize ngtcp2_conn_write_single_frame_pkt(
|
||||
ngtcp2_conn *conn, ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen,
|
||||
uint8_t type, const ngtcp2_cid *dcid, ngtcp2_frame *fr, uint8_t rtb_flags,
|
||||
const ngtcp2_path *path, ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_commit_local_transport_params commits the local
|
||||
* transport parameters, which is currently set to
|
||||
* conn->local.settings.transport_params. This function will do some
|
||||
* amends on transport parameters for adjusting default values.
|
||||
*
|
||||
* 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
|
||||
* CID in preferred address equals to the original SCID.
|
||||
*/
|
||||
int ngtcp2_conn_commit_local_transport_params(ngtcp2_conn *conn);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_lost_pkt_expiry returns the earliest expiry time of
|
||||
* lost packet.
|
||||
*/
|
||||
ngtcp2_tstamp ngtcp2_conn_lost_pkt_expiry(ngtcp2_conn *conn);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_remove_lost_pkt removes the expired lost packet.
|
||||
*/
|
||||
void ngtcp2_conn_remove_lost_pkt(ngtcp2_conn *conn, ngtcp2_tstamp ts);
|
||||
|
||||
/*
|
||||
* ngtcp2_conn_resched_frames reschedules frames linked from |*pfrc|
|
||||
* 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_conn_resched_frames(ngtcp2_conn *conn, ngtcp2_pktns *pktns,
|
||||
ngtcp2_frame_chain **pfrc);
|
||||
|
||||
uint64_t ngtcp2_conn_tx_strmq_first_cycle(ngtcp2_conn *conn);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_ack_delay_expiry` returns the expiry time point of
|
||||
* delayed protected ACK. One should call
|
||||
* `ngtcp2_conn_cancel_expired_ack_delay_timer` and
|
||||
* `ngtcp2_conn_write_pkt` (or `ngtcp2_conn_writev_stream`) when it
|
||||
* expires. It returns UINT64_MAX if there is no expiry.
|
||||
*/
|
||||
ngtcp2_tstamp ngtcp2_conn_ack_delay_expiry(ngtcp2_conn *conn);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_cancel_expired_ack_delay_timer` stops expired ACK
|
||||
* delay timer. |ts| is the current time. This function must be
|
||||
* called when `ngtcp2_conn_ack_delay_expiry` <= ts.
|
||||
*/
|
||||
void ngtcp2_conn_cancel_expired_ack_delay_timer(ngtcp2_conn *conn,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* `ngtcp2_conn_loss_detection_expiry` returns the expiry time point
|
||||
* of loss detection timer. One should call
|
||||
* `ngtcp2_conn_on_loss_detection_timer` and `ngtcp2_conn_write_pkt`
|
||||
* (or `ngtcp2_conn_writev_stream`) when it expires. It returns
|
||||
* UINT64_MAX if loss detection timer is not armed.
|
||||
*/
|
||||
ngtcp2_tstamp ngtcp2_conn_loss_detection_expiry(ngtcp2_conn *conn);
|
||||
|
||||
#endif /* NGTCP2_CONN_H */
|
257
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c
vendored
Normal file
257
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.c
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
uint64_t ngtcp2_get_uint64(const uint8_t *p) {
|
||||
uint64_t n;
|
||||
memcpy(&n, p, 8);
|
||||
return ngtcp2_ntohl64(n);
|
||||
}
|
||||
|
||||
uint64_t ngtcp2_get_uint48(const uint8_t *p) {
|
||||
uint64_t n = 0;
|
||||
memcpy(((uint8_t *)&n) + 2, p, 6);
|
||||
return ngtcp2_ntohl64(n);
|
||||
}
|
||||
|
||||
uint32_t ngtcp2_get_uint32(const uint8_t *p) {
|
||||
uint32_t n;
|
||||
memcpy(&n, p, 4);
|
||||
return ngtcp2_ntohl(n);
|
||||
}
|
||||
|
||||
uint32_t ngtcp2_get_uint24(const uint8_t *p) {
|
||||
uint32_t n = 0;
|
||||
memcpy(((uint8_t *)&n) + 1, p, 3);
|
||||
return ngtcp2_ntohl(n);
|
||||
}
|
||||
|
||||
uint16_t ngtcp2_get_uint16(const uint8_t *p) {
|
||||
uint16_t n;
|
||||
memcpy(&n, p, 2);
|
||||
return ngtcp2_ntohs(n);
|
||||
}
|
||||
|
||||
uint64_t ngtcp2_get_varint(size_t *plen, const uint8_t *p) {
|
||||
union {
|
||||
char b[8];
|
||||
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.b[0] &= 0x3f;
|
||||
return ngtcp2_ntohs(n.n16);
|
||||
case 4:
|
||||
memcpy(&n, p, 4);
|
||||
n.b[0] &= 0x3f;
|
||||
return ngtcp2_ntohl(n.n32);
|
||||
case 8:
|
||||
memcpy(&n, p, 8);
|
||||
n.b[0] &= 0x3f;
|
||||
return ngtcp2_ntohl64(n.n64);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t ngtcp2_get_pkt_num(const uint8_t *p, size_t pkt_numlen) {
|
||||
switch (pkt_numlen) {
|
||||
case 1:
|
||||
return *p;
|
||||
case 2:
|
||||
return (int64_t)ngtcp2_get_uint16(p);
|
||||
case 3:
|
||||
return (int64_t)ngtcp2_get_uint24(p);
|
||||
case 4:
|
||||
return (int64_t)ngtcp2_get_uint32(p);
|
||||
default:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
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_varint(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_varint14(uint8_t *p, uint16_t n) {
|
||||
uint8_t *rv;
|
||||
|
||||
assert(n < 16384);
|
||||
|
||||
rv = ngtcp2_put_uint16be(p, n);
|
||||
*p |= 0x40;
|
||||
|
||||
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:
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
size_t ngtcp2_get_varint_len(const uint8_t *p) {
|
||||
return (size_t)(1u << (*p >> 6));
|
||||
}
|
||||
|
||||
size_t ngtcp2_put_varint_len(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;
|
||||
}
|
285
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h
vendored
Normal file
285
deps/ngtcp2/ngtcp2/lib/ngtcp2_conv.h
vendored
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif /* HAVE_ARPA_INET_H */
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif /* HAVE_NETINET_IN_H */
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
# include <byteswap.h>
|
||||
#endif /* HAVE_BYTESWAP_H */
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
# include <endian.h>
|
||||
#endif /* HAVE_ENDIAN_H */
|
||||
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
# include <sys/endian.h>
|
||||
#endif /* HAVE_SYS_ENDIAN_H */
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#if defined(HAVE_BSWAP_64) || \
|
||||
(defined(HAVE_DECL_BSWAP_64) && HAVE_DECL_BSWAP_64 > 0)
|
||||
# define ngtcp2_bswap64 bswap_64
|
||||
#else /* !HAVE_BSWAP_64 */
|
||||
# define ngtcp2_bswap64(N) \
|
||||
((uint64_t)(ngtcp2_ntohl((uint32_t)(N))) << 32 | \
|
||||
ngtcp2_ntohl((uint32_t)((N) >> 32)))
|
||||
#endif /* !HAVE_BSWAP_64 */
|
||||
|
||||
#if defined(HAVE_BE64TOH) || \
|
||||
(defined(HAVE_DECL_BE64TOH) && HAVE_DECL_BE64TOH > 0)
|
||||
# define ngtcp2_ntohl64(N) be64toh(N)
|
||||
# define ngtcp2_htonl64(N) htobe64(N)
|
||||
#else /* !HAVE_BE64TOH */
|
||||
# if defined(WORDS_BIGENDIAN)
|
||||
# define ngtcp2_ntohl64(N) (N)
|
||||
# define ngtcp2_htonl64(N) (N)
|
||||
# else /* !WORDS_BIGENDIAN */
|
||||
# define ngtcp2_ntohl64(N) ngtcp2_bswap64(N)
|
||||
# define ngtcp2_htonl64(N) ngtcp2_bswap64(N)
|
||||
# endif /* !WORDS_BIGENDIAN */
|
||||
#endif /* !HAVE_BE64TOH */
|
||||
|
||||
#if defined(WIN32)
|
||||
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||
define inline functions for those function so that we don't have
|
||||
dependeny on that lib. */
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# define STIN static __inline
|
||||
# else
|
||||
# define STIN static inline
|
||||
# endif
|
||||
|
||||
STIN uint32_t ngtcp2_htonl(uint32_t hostlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostlong >> 24;
|
||||
*p++ = (hostlong >> 16) & 0xffu;
|
||||
*p++ = (hostlong >> 8) & 0xffu;
|
||||
*p = hostlong & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t ngtcp2_htons(uint16_t hostshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostshort >> 8;
|
||||
*p = hostshort & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint32_t ngtcp2_ntohl(uint32_t netlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&netlong;
|
||||
res = *p++ << 24;
|
||||
res += *p++ << 16;
|
||||
res += *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t ngtcp2_ntohs(uint16_t netshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&netshort;
|
||||
res = *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
#else /* !WIN32 */
|
||||
|
||||
# define ngtcp2_htonl htonl
|
||||
# define ngtcp2_htons htons
|
||||
# define ngtcp2_ntohl ntohl
|
||||
# define ngtcp2_ntohs ntohs
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
/*
|
||||
* ngtcp2_get_uint64 reads 8 bytes from |p| as 64 bits unsigned
|
||||
* integer encoded as network byte order, and returns it in host byte
|
||||
* order.
|
||||
*/
|
||||
uint64_t ngtcp2_get_uint64(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_get_uint48 reads 6 bytes from |p| as 48 bits unsigned
|
||||
* integer encoded as network byte order, and returns it in host byte
|
||||
* order.
|
||||
*/
|
||||
uint64_t ngtcp2_get_uint48(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_get_uint32 reads 4 bytes from |p| as 32 bits unsigned
|
||||
* integer encoded as network byte order, and returns it in host byte
|
||||
* order.
|
||||
*/
|
||||
uint32_t ngtcp2_get_uint32(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_get_uint24 reads 3 bytes from |p| as 24 bits unsigned
|
||||
* integer encoded as network byte order, and returns it in host byte
|
||||
* order.
|
||||
*/
|
||||
uint32_t ngtcp2_get_uint24(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_get_uint16 reads 2 bytes from |p| as 16 bits unsigned
|
||||
* integer encoded as network byte order, and returns it in host byte
|
||||
* order.
|
||||
*/
|
||||
uint16_t ngtcp2_get_uint16(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_get_varint reads variable-length integer from |p|, and
|
||||
* returns it in host byte order. The number of bytes read is stored
|
||||
* in |*plen|.
|
||||
*/
|
||||
uint64_t ngtcp2_get_varint(size_t *plen, 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_varint writes |n| in |p| using variable-length integer
|
||||
* encoding. It returns the one beyond of the last written position.
|
||||
*/
|
||||
uint8_t *ngtcp2_put_varint(uint8_t *p, uint64_t n);
|
||||
|
||||
/*
|
||||
* ngtcp2_put_varint14 writes |n| in |p| using variable-length integer
|
||||
* encoding. |n| must be strictly less than 16384. The function
|
||||
* always encodes |n| in 2 bytes. It returns the one beyond of the
|
||||
* last written position.
|
||||
*/
|
||||
uint8_t *ngtcp2_put_varint14(uint8_t *p, uint16_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_varint_len returns the required number of bytes to read
|
||||
* variable-length integer starting at |p|.
|
||||
*/
|
||||
size_t ngtcp2_get_varint_len(const uint8_t *p);
|
||||
|
||||
/*
|
||||
* ngtcp2_put_varint_len returns the required number of bytes to
|
||||
* encode |n|.
|
||||
*/
|
||||
size_t ngtcp2_put_varint_len(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 */
|
749
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c
vendored
Normal file
749
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.c
vendored
Normal file
@ -0,0 +1,749 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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;
|
||||
|
||||
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_varint_len(param);
|
||||
return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(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_varint(p, id);
|
||||
p = ngtcp2_put_varint(p, ngtcp2_put_varint_len(value));
|
||||
return ngtcp2_put_varint(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_varint_len(id) + ngtcp2_put_varint_len(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_varint(p, id);
|
||||
p = ngtcp2_put_varint(p, cid->datalen);
|
||||
if (cid->datalen) {
|
||||
p = ngtcp2_cpymem(p, cid->data, cid->datalen);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
ngtcp2_ssize
|
||||
ngtcp2_encode_transport_params(uint8_t *dest, size_t destlen,
|
||||
ngtcp2_transport_params_type exttype,
|
||||
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;
|
||||
|
||||
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_varint_len(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
|
||||
ngtcp2_put_varint_len(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_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
|
||||
ngtcp2_put_varint_len(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_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_varint_len(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) +
|
||||
ngtcp2_put_varint_len(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 (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_varint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN);
|
||||
p = ngtcp2_put_varint(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_varint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS);
|
||||
p = ngtcp2_put_varint(p, preferred_addrlen);
|
||||
|
||||
p = ngtcp2_cpymem(p, params->preferred_address.ipv4_addr,
|
||||
sizeof(params->preferred_address.ipv4_addr));
|
||||
p = ngtcp2_put_uint16be(p, params->preferred_address.ipv4_port);
|
||||
|
||||
p = ngtcp2_cpymem(p, params->preferred_address.ipv6_addr,
|
||||
sizeof(params->preferred_address.ipv6_addr));
|
||||
p = ngtcp2_put_uint16be(p, params->preferred_address.ipv6_port);
|
||||
|
||||
*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_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_varint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION);
|
||||
p = ngtcp2_put_varint(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);
|
||||
}
|
||||
|
||||
assert((size_t)(p - dest) == len);
|
||||
|
||||
return (ngtcp2_ssize)len;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_varint decodes a single varint from the buffer pointed by
|
||||
* |p| of length |end - p|. If it decodes an integer successfully, it
|
||||
* stores the integer in |*pdest| and returns 0. Otherwise it returns
|
||||
* -1.
|
||||
*/
|
||||
static ngtcp2_ssize decode_varint(uint64_t *pdest, const uint8_t *p,
|
||||
const uint8_t *end) {
|
||||
size_t len;
|
||||
|
||||
if (p == end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ngtcp2_get_varint_len(p);
|
||||
if ((uint64_t)(end - p) < len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pdest = ngtcp2_get_varint(&len, p);
|
||||
|
||||
return (ngtcp2_ssize)len;
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_varint_param decodes length prefixed value from the buffer
|
||||
* pointed by |p| of length |end - p|. The length and value are
|
||||
* encoded in varint form. If it decodes a value successfully, it
|
||||
* stores the value in |*pdest| and returns 0. Otherwise it returns
|
||||
* -1.
|
||||
*/
|
||||
static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p,
|
||||
const uint8_t *end) {
|
||||
const uint8_t *begin = p;
|
||||
ngtcp2_ssize nread;
|
||||
uint64_t valuelen;
|
||||
size_t n;
|
||||
|
||||
nread = decode_varint(&valuelen, p, end);
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
p += nread;
|
||||
|
||||
if (p == end) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((uint64_t)(end - p) < valuelen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_get_varint_len(p) != valuelen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pdest = ngtcp2_get_varint(&n, p);
|
||||
|
||||
p += valuelen;
|
||||
|
||||
return (ngtcp2_ssize)(p - begin);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode_cid_param decodes length prefixed ngtcp2_cid from the buffer
|
||||
* pointed by |p| of length |end - p|. The length is encoded in
|
||||
* varint form. If it decodes a value successfully, it stores the
|
||||
* value in |*pdest| and returns the number of bytes read. Otherwise
|
||||
* it returns -1.
|
||||
*/
|
||||
static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p,
|
||||
const uint8_t *end) {
|
||||
const uint8_t *begin = p;
|
||||
uint64_t valuelen;
|
||||
ngtcp2_ssize nread = decode_varint(&valuelen, p, end);
|
||||
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
|
||||
p += nread;
|
||||
|
||||
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;
|
||||
|
||||
return (ngtcp2_ssize)(p - begin);
|
||||
}
|
||||
|
||||
int ngtcp2_decode_transport_params(ngtcp2_transport_params *params,
|
||||
ngtcp2_transport_params_type exttype,
|
||||
const uint8_t *data, size_t datalen) {
|
||||
const uint8_t *p, *end;
|
||||
size_t len;
|
||||
uint64_t param_type;
|
||||
uint64_t valuelen;
|
||||
ngtcp2_ssize nread;
|
||||
int initial_scid_present = 0;
|
||||
int original_dcid_present = 0;
|
||||
|
||||
p = data;
|
||||
end = data + datalen;
|
||||
|
||||
/* 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_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));
|
||||
|
||||
if (datalen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; (size_t)(end - p) >= 2;) {
|
||||
nread = decode_varint(¶m_type, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
|
||||
switch (param_type) {
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
|
||||
nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_local,
|
||||
p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
|
||||
nread = decode_varint_param(¶ms->initial_max_stream_data_bidi_remote,
|
||||
p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI:
|
||||
nread = decode_varint_param(¶ms->initial_max_stream_data_uni, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA:
|
||||
nread = decode_varint_param(¶ms->initial_max_data, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI:
|
||||
nread = decode_varint_param(¶ms->initial_max_streams_bidi, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI:
|
||||
nread = decode_varint_param(¶ms->initial_max_streams_uni, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT:
|
||||
nread = decode_varint_param(¶ms->max_idle_timeout, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
params->max_idle_timeout *= NGTCP2_MILLISECONDS;
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE:
|
||||
nread = decode_varint_param(¶ms->max_udp_payload_size, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN:
|
||||
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
nread = decode_varint(&valuelen, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy(params->stateless_reset_token, p,
|
||||
sizeof(params->stateless_reset_token));
|
||||
params->stateless_reset_token_present = 1;
|
||||
|
||||
p += sizeof(params->stateless_reset_token);
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT:
|
||||
nread = decode_varint_param(¶ms->ack_delay_exponent, p, end);
|
||||
if (nread < 0 || params->ack_delay_exponent > 20) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS:
|
||||
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
nread = decode_varint(&valuelen, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
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;
|
||||
}
|
||||
|
||||
memcpy(params->preferred_address.ipv4_addr, p,
|
||||
sizeof(params->preferred_address.ipv4_addr));
|
||||
p += sizeof(params->preferred_address.ipv4_addr);
|
||||
params->preferred_address.ipv4_port = ngtcp2_get_uint16(p);
|
||||
p += sizeof(uint16_t);
|
||||
|
||||
memcpy(params->preferred_address.ipv6_addr, p,
|
||||
sizeof(params->preferred_address.ipv6_addr));
|
||||
p += sizeof(params->preferred_address.ipv6_addr);
|
||||
params->preferred_address.ipv6_port = ngtcp2_get_uint16(p);
|
||||
p += sizeof(uint16_t);
|
||||
|
||||
/* 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) {
|
||||
memcpy(params->preferred_address.cid.data, p,
|
||||
params->preferred_address.cid.datalen);
|
||||
p += params->preferred_address.cid.datalen;
|
||||
}
|
||||
|
||||
/* stateless reset token */
|
||||
memcpy(params->preferred_address.stateless_reset_token, p,
|
||||
sizeof(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:
|
||||
nread = decode_varint(&valuelen, p, end);
|
||||
if (nread < 0 || valuelen != 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
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;
|
||||
}
|
||||
nread = decode_cid_param(¶ms->original_dcid, p, end);
|
||||
if (nread < 0) {
|
||||
return (int)nread;
|
||||
}
|
||||
original_dcid_present = 1;
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID:
|
||||
if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
nread = decode_cid_param(¶ms->retry_scid, p, end);
|
||||
if (nread < 0) {
|
||||
return (int)nread;
|
||||
}
|
||||
params->retry_scid_present = 1;
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID:
|
||||
nread = decode_cid_param(¶ms->initial_scid, p, end);
|
||||
if (nread < 0) {
|
||||
return (int)nread;
|
||||
}
|
||||
initial_scid_present = 1;
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY:
|
||||
nread = decode_varint_param(¶ms->max_ack_delay, p, end);
|
||||
if (nread < 0 || params->max_ack_delay >= 16384) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
params->max_ack_delay *= NGTCP2_MILLISECONDS;
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT:
|
||||
nread = decode_varint_param(¶ms->active_connection_id_limit, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE:
|
||||
nread = decode_varint_param(¶ms->max_datagram_frame_size, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
break;
|
||||
default:
|
||||
/* Ignore unknown parameter */
|
||||
nread = decode_varint(&valuelen, p, end);
|
||||
if (nread < 0) {
|
||||
return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
|
||||
}
|
||||
p += nread;
|
||||
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;
|
||||
}
|
103
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h
vendored
Normal file
103
deps/ngtcp2/ngtcp2/lib/ngtcp2_crypto.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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_CRYPTO_KM_FLAG_NONE indicates that no flag is set. */
|
||||
#define NGTCP2_CRYPTO_KM_FLAG_NONE 0x00
|
||||
/* NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE is set if key phase bit is
|
||||
set. */
|
||||
#define NGTCP2_CRYPTO_KM_FLAG_KEY_PHASE_ONE 0x01
|
||||
|
||||
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);
|
||||
|
||||
#endif /* NGTCP2_CRYPTO_H */
|
144
deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c
vendored
Normal file
144
deps/ngtcp2/ngtcp2/lib/ngtcp2_err.c
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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_TLS_DECRYPT:
|
||||
return "ERR_TLS_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_PATH_VALIDATION_FAILED:
|
||||
return "ERR_PATH_VALIDATION_FAILED";
|
||||
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";
|
||||
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:
|
||||
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;
|
||||
default:
|
||||
return NGTCP2_PROTOCOL_VIOLATION;
|
||||
}
|
||||
}
|
34
deps/ngtcp2/ngtcp2/lib/ngtcp2_err.h
vendored
Normal file
34
deps/ngtcp2/ngtcp2/lib/ngtcp2_err.h
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 */
|
129
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
vendored
Normal file
129
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.c
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 "ngtcp2_range.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int ngtcp2_gaptr_init(ngtcp2_gaptr *gaptr, const ngtcp2_mem *mem) {
|
||||
int rv;
|
||||
ngtcp2_range range = {0, UINT64_MAX};
|
||||
|
||||
rv = ngtcp2_ksl_init(&gaptr->gap, ngtcp2_ksl_range_compar,
|
||||
sizeof(ngtcp2_range), mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = ngtcp2_ksl_insert(&gaptr->gap, NULL, &range, NULL);
|
||||
if (rv != 0) {
|
||||
ngtcp2_ksl_free(&gaptr->gap);
|
||||
return rv;
|
||||
}
|
||||
|
||||
gaptr->mem = mem;
|
||||
|
||||
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, size_t datalen) {
|
||||
int rv;
|
||||
ngtcp2_range k, m, l, r, q = {offset, offset + datalen};
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
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(&gaptr->gap, &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_ksl_begin(&gaptr->gap);
|
||||
ngtcp2_range r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
|
||||
return r.begin;
|
||||
}
|
||||
|
||||
ngtcp2_ksl_it ngtcp2_gaptr_get_first_gap_after(ngtcp2_gaptr *gaptr,
|
||||
uint64_t offset) {
|
||||
ngtcp2_range q = {offset, offset + 1};
|
||||
return ngtcp2_ksl_lower_bound_compar(&gaptr->gap, &q,
|
||||
ngtcp2_ksl_range_exclusive_compar);
|
||||
}
|
||||
|
||||
int ngtcp2_gaptr_is_pushed(ngtcp2_gaptr *gaptr, uint64_t offset,
|
||||
size_t datalen) {
|
||||
ngtcp2_range q = {offset, offset + datalen};
|
||||
ngtcp2_ksl_it it = ngtcp2_ksl_lower_bound_compar(
|
||||
&gaptr->gap, &q, ngtcp2_ksl_range_exclusive_compar);
|
||||
ngtcp2_range k = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
|
||||
ngtcp2_range 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_ksl_begin(&gaptr->gap);
|
||||
ngtcp2_range r;
|
||||
|
||||
assert(!ngtcp2_ksl_it_end(&it));
|
||||
|
||||
r = *(ngtcp2_range *)ngtcp2_ksl_it_key(&it);
|
||||
|
||||
ngtcp2_ksl_remove(&gaptr->gap, NULL, &r);
|
||||
}
|
103
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.h
vendored
Normal file
103
deps/ngtcp2/ngtcp2/lib/ngtcp2_gaptr.h
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* 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|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int 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, size_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 iterator pointing to
|
||||
* the first gap which overlaps or comes after |offset|.
|
||||
*/
|
||||
ngtcp2_ksl_it 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,
|
||||
size_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 */
|
86
deps/ngtcp2/ngtcp2/lib/ngtcp2_idtr.c
vendored
Normal file
86
deps/ngtcp2/ngtcp2/lib/ngtcp2_idtr.c
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
int ngtcp2_idtr_init(ngtcp2_idtr *idtr, int server, const ngtcp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = ngtcp2_gaptr_init(&idtr->gap, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
idtr->server = server;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
95
deps/ngtcp2/ngtcp2/lib/ngtcp2_idtr.h
vendored
Normal file
95
deps/ngtcp2/ngtcp2/lib/ngtcp2_idtr.h
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int 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 */
|
741
deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c
vendored
Normal file
741
deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.c
vendored
Normal file
@ -0,0 +1,741 @@
|
||||
/*
|
||||
* 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 size_t ksl_nodelen(size_t keylen) {
|
||||
return (sizeof(ngtcp2_ksl_node) + keylen - sizeof(uint64_t) + 0xf) &
|
||||
(size_t)~0xf;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int ngtcp2_ksl_init(ngtcp2_ksl *ksl, ngtcp2_ksl_compar compar, size_t keylen,
|
||||
const ngtcp2_mem *mem) {
|
||||
size_t nodelen = ksl_nodelen(keylen);
|
||||
size_t blklen = ksl_blklen(nodelen);
|
||||
ngtcp2_ksl_blk *head;
|
||||
|
||||
ksl->head = ngtcp2_mem_malloc(mem, blklen);
|
||||
if (!ksl->head) {
|
||||
return NGTCP2_ERR_NOMEM;
|
||||
}
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->compar = compar;
|
||||
ksl->keylen = keylen;
|
||||
ksl->nodelen = nodelen;
|
||||
ksl->n = 0;
|
||||
ksl->mem = mem;
|
||||
|
||||
head = ksl->head;
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_mem_free(ksl->mem, blk);
|
||||
}
|
||||
|
||||
void ngtcp2_ksl_free(ngtcp2_ksl *ksl) {
|
||||
if (!ksl) {
|
||||
return;
|
||||
}
|
||||
|
||||
ksl_free_blk(ksl, ksl->head);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 = ngtcp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
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 = ngtcp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
if (nhead == NULL) {
|
||||
ngtcp2_mem_free(ksl->mem, 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) {
|
||||
ngtcp2_ssize left = -1, right = (ngtcp2_ssize)blk->n, mid;
|
||||
ngtcp2_ksl_node *node;
|
||||
|
||||
while (right - left > 1) {
|
||||
mid = (left + right) >> 1;
|
||||
node = ngtcp2_ksl_nth_node(ksl, blk, (size_t)mid);
|
||||
if (compar((ngtcp2_ksl_key *)node->key, key)) {
|
||||
left = mid;
|
||||
} else {
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return (size_t)right;
|
||||
}
|
||||
|
||||
int ngtcp2_ksl_insert(ngtcp2_ksl *ksl, ngtcp2_ksl_it *it,
|
||||
const ngtcp2_ksl_key *key, void *data) {
|
||||
ngtcp2_ksl_blk *blk = ksl->head;
|
||||
ngtcp2_ksl_node *node;
|
||||
size_t i;
|
||||
int rv;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ngtcp2_mem_free(ksl->mem, rblk);
|
||||
|
||||
if (ksl->head == blk && blk->n == 2) {
|
||||
ngtcp2_mem_free(ksl->mem, 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(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 (!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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
size_t i;
|
||||
ngtcp2_ksl_blk *head;
|
||||
|
||||
if (!ksl->head->leaf) {
|
||||
for (i = 0; i < ksl->head->n; ++i) {
|
||||
ksl_free_blk(ksl, ngtcp2_ksl_nth_node(ksl, ksl->head, i)->blk);
|
||||
}
|
||||
}
|
||||
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->n = 0;
|
||||
|
||||
head = ksl->head;
|
||||
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
}
|
||||
|
||||
void ngtcp2_ksl_print(ngtcp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); }
|
||||
|
||||
ngtcp2_ksl_it ngtcp2_ksl_begin(const ngtcp2_ksl *ksl) {
|
||||
ngtcp2_ksl_it it;
|
||||
ngtcp2_ksl_it_init(&it, ksl, ksl->front, 0);
|
||||
return it;
|
||||
}
|
||||
|
||||
ngtcp2_ksl_it ngtcp2_ksl_end(const ngtcp2_ksl *ksl) {
|
||||
ngtcp2_ksl_it it;
|
||||
ngtcp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
|
||||
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_get(const ngtcp2_ksl_it *it) {
|
||||
assert(it->i < it->blk->n);
|
||||
return ngtcp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
329
deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h
vendored
Normal file
329
deps/ngtcp2/ngtcp2/lib/ngtcp2_ksl.h
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
/* 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_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 {
|
||||
/* 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;
|
||||
const ngtcp2_mem *mem;
|
||||
};
|
||||
|
||||
/*
|
||||
* ngtcp2_ksl_init initializes |ksl|. |compar| specifies compare
|
||||
* function. |keylen| is the length of key.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int 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_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.
|
||||
*/
|
||||
void *ngtcp2_ksl_it_get(const ngtcp2_ksl_it *it);
|
||||
|
||||
/*
|
||||
* 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 */
|
767
deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c
vendored
Normal file
767
deps/ngtcp2/ngtcp2/lib/ngtcp2_log.c
vendored
Normal file
@ -0,0 +1,767 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
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>(<PKTTYPE>) <FRAMENAME>(<FRAMETYPE>)
|
||||
*
|
||||
* <DIR>:
|
||||
* Flow direction. tx=transmission, rx=reception
|
||||
*
|
||||
* <PKN>:
|
||||
* Packet number.
|
||||
*
|
||||
* <PKTNAME>:
|
||||
* Packet name. (e.g., Initial, Handshake, S01)
|
||||
*
|
||||
* <PKTTYPE>:
|
||||
* Packet type in hex string.
|
||||
*
|
||||
* <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(0x%02x)"
|
||||
#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), hd->type
|
||||
|
||||
#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), hd->type
|
||||
|
||||
#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";
|
||||
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_VERSION_NEGOTIATION:
|
||||
return "VN";
|
||||
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);
|
||||
}
|
||||
return "Short";
|
||||
}
|
||||
|
||||
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=%zu 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_block_count=%zu"),
|
||||
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, fr->largest_ack,
|
||||
fr->ack_delay_unscaled / NGTCP2_MILLISECONDS, fr->ack_delay,
|
||||
fr->num_blks);
|
||||
|
||||
largest_ack = fr->largest_ack;
|
||||
min_ack = fr->largest_ack - (int64_t)fr->first_ack_blklen;
|
||||
|
||||
log->log_printf(log->user_data,
|
||||
(NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64
|
||||
"] block_count=%" PRIu64),
|
||||
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack, min_ack,
|
||||
fr->first_ack_blklen);
|
||||
|
||||
for (i = 0; i < fr->num_blks; ++i) {
|
||||
const ngtcp2_ack_blk *blk = &fr->blks[i];
|
||||
largest_ack = min_ack - (int64_t)blk->gap - 2;
|
||||
min_ack = largest_ack - (int64_t)blk->blklen;
|
||||
log->log_printf(log->user_data,
|
||||
(NGTCP2_LOG_PKT " ACK(0x%02x) block=[%" PRId64 "..%" PRId64
|
||||
"] gap=%" PRIu64 " block_count=%" PRIu64),
|
||||
NGTCP2_LOG_FRM_HD_FIELDS(dir), fr->type, largest_ack,
|
||||
min_ack, blk->gap, blk->blklen);
|
||||
}
|
||||
|
||||
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) {
|
||||
size_t datalen = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < fr->datacnt; ++i) {
|
||||
datalen += fr->data[i].len;
|
||||
}
|
||||
|
||||
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, datalen);
|
||||
}
|
||||
|
||||
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->token.len > 64) {
|
||||
p = ngtcp2_encode_hex(buf, fr->token.base, 64);
|
||||
p[128] = '*';
|
||||
p[129] = '\0';
|
||||
} else {
|
||||
p = ngtcp2_encode_hex(buf, fr->token.base, fr->token.len);
|
||||
}
|
||||
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->token.len);
|
||||
}
|
||||
|
||||
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=%zu"),
|
||||
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:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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];
|
||||
|
||||
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) {
|
||||
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, params->preferred_address.ipv4_addr));
|
||||
log->log_printf(
|
||||
log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv4_port=%u"),
|
||||
NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv4_port);
|
||||
|
||||
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, params->preferred_address.ipv6_addr));
|
||||
log->log_printf(
|
||||
log->user_data, (NGTCP2_LOG_TP " preferred_address.ipv6_port=%u"),
|
||||
NGTCP2_LOG_TP_HD_FIELDS, params->preferred_address.ipv6_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);
|
||||
}
|
||||
|
||||
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(0x%02x) sent_ts=%" PRIu64, pkt_num,
|
||||
(flags & NGTCP2_PKT_FLAG_LONG_FORM) ? strpkttype_long(type) : "Short",
|
||||
type, 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;
|
||||
}
|
||||
|
||||
ngtcp2_log_info(
|
||||
log, NGTCP2_LOG_EVENT_PKT,
|
||||
"%s pkn=%" PRId64 " dcid=0x%s scid=0x%s type=%s(0x%02x) len=%zu k=%d",
|
||||
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->flags & NGTCP2_PKT_FLAG_LONG_FORM) ? strpkttype_long(hd->type)
|
||||
: "Short",
|
||||
hd->type, hd->len, (hd->flags & NGTCP2_PKT_FLAG_KEY_PHASE) != 0);
|
||||
}
|
||||
|
||||
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(0x%02x)", hd->pkt_num,
|
||||
strpkttype(hd), hd->type);
|
||||
}
|
80
deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h
vendored
Normal file
80
deps/ngtcp2/ngtcp2/lib/ngtcp2_log.h
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 ngtcp2_log;
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#endif /* NGTCP2_LOG_H */
|
53
deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h
vendored
Normal file
53
deps/ngtcp2/ngtcp2/lib/ngtcp2_macro.h
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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_MACRO_H
|
||||
#define NGTCP2_MACRO_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
|
||||
#define ngtcp2_min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define ngtcp2_max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
#define ngtcp2_struct_of(ptr, type, member) \
|
||||
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
|
||||
|
||||
/* ngtcp2_list_insert inserts |T| before |*PD|. The contract is that
|
||||
this is singly linked list, and the next element is pointed by next
|
||||
field of the previous element. |PD| must be a pointer to the
|
||||
pointer to the next field of the previous element of |*PD|: if C is
|
||||
the previous element of |PD|, PD = &C->next. */
|
||||
#define ngtcp2_list_insert(T, PD) \
|
||||
do { \
|
||||
(T)->next = *(PD); \
|
||||
*(PD) = (T); \
|
||||
} while (0)
|
||||
|
||||
#endif /* NGTCP2_MACRO_H */
|
332
deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c
vendored
Normal file
332
deps/ngtcp2/ngtcp2/lib/ngtcp2_map.c
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
/*
|
||||
* 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 "ngtcp2_conv.h"
|
||||
|
||||
#define INITIAL_TABLE_LENGTH 256
|
||||
|
||||
int ngtcp2_map_init(ngtcp2_map *map, const ngtcp2_mem *mem) {
|
||||
map->mem = mem;
|
||||
map->tablelen = INITIAL_TABLE_LENGTH;
|
||||
map->table = ngtcp2_mem_calloc(mem, map->tablelen, sizeof(ngtcp2_map_bucket));
|
||||
if (map->table == NULL) {
|
||||
return NGTCP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_map_free(ngtcp2_map *map) {
|
||||
size_t i;
|
||||
ngtcp2_map_bucket *bkt;
|
||||
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
ngtcp2_ksl_free(bkt->ksl);
|
||||
ngtcp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_mem_free(map->mem, map->table);
|
||||
}
|
||||
|
||||
void ngtcp2_map_each_free(ngtcp2_map *map,
|
||||
int (*func)(ngtcp2_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
uint32_t i;
|
||||
ngtcp2_map_bucket *bkt;
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
func(bkt->ptr, ptr);
|
||||
bkt->ptr = NULL;
|
||||
assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
|
||||
ngtcp2_ksl_it_next(&it)) {
|
||||
func(ngtcp2_ksl_it_get(&it), ptr);
|
||||
}
|
||||
|
||||
ngtcp2_ksl_free(bkt->ksl);
|
||||
ngtcp2_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ngtcp2_map_each(ngtcp2_map *map,
|
||||
int (*func)(ngtcp2_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
int rv;
|
||||
uint32_t i;
|
||||
ngtcp2_map_bucket *bkt;
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = func(bkt->ptr, ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
|
||||
ngtcp2_ksl_it_next(&it)) {
|
||||
rv = func(ngtcp2_ksl_it_get(&it), ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ngtcp2_map_entry_init(ngtcp2_map_entry *entry, key_type key) {
|
||||
entry->key = key;
|
||||
}
|
||||
|
||||
/* FNV1a hash */
|
||||
static uint32_t hash(key_type key, uint32_t mod) {
|
||||
uint8_t *p, *end;
|
||||
uint32_t h = 0x811C9DC5u;
|
||||
|
||||
key = ngtcp2_htonl64(key);
|
||||
p = (uint8_t *)&key;
|
||||
end = p + sizeof(key_type);
|
||||
|
||||
for (; p != end;) {
|
||||
h ^= *p++;
|
||||
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
|
||||
}
|
||||
|
||||
return h & (mod - 1);
|
||||
}
|
||||
|
||||
static int less(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) {
|
||||
return *(key_type *)lhs < *(key_type *)rhs;
|
||||
}
|
||||
|
||||
static int map_insert(ngtcp2_map *map, ngtcp2_map_bucket *table,
|
||||
uint32_t tablelen, ngtcp2_map_entry *entry) {
|
||||
uint32_t h = hash(entry->key, tablelen);
|
||||
ngtcp2_map_bucket *bkt = &table[h];
|
||||
const ngtcp2_mem *mem = map->mem;
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr == NULL && (bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0)) {
|
||||
bkt->ptr = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bkt->ksl) {
|
||||
bkt->ksl = ngtcp2_mem_malloc(mem, sizeof(*bkt->ksl));
|
||||
if (bkt->ksl == NULL) {
|
||||
return NGTCP2_ERR_NOMEM;
|
||||
}
|
||||
ngtcp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
|
||||
}
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = ngtcp2_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bkt->ptr = NULL;
|
||||
}
|
||||
|
||||
return ngtcp2_ksl_insert(bkt->ksl, NULL, &entry->key, entry);
|
||||
}
|
||||
|
||||
/* new_tablelen must be power of 2 */
|
||||
static int map_resize(ngtcp2_map *map, uint32_t new_tablelen) {
|
||||
uint32_t i;
|
||||
ngtcp2_map_bucket *new_table;
|
||||
ngtcp2_map_bucket *bkt;
|
||||
ngtcp2_ksl_it it;
|
||||
int 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->ptr) {
|
||||
rv = map_insert(map, new_table, new_tablelen, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
assert(bkt->ksl == NULL || ngtcp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = ngtcp2_ksl_begin(bkt->ksl); !ngtcp2_ksl_it_end(&it);
|
||||
ngtcp2_ksl_it_next(&it)) {
|
||||
rv = map_insert(map, new_table, new_tablelen, ngtcp2_ksl_it_get(&it));
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
ngtcp2_ksl_free(bkt->ksl);
|
||||
ngtcp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
ngtcp2_mem_free(map->mem, map->table);
|
||||
map->tablelen = new_tablelen;
|
||||
map->table = new_table;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < new_tablelen; ++i) {
|
||||
bkt = &new_table[i];
|
||||
if (bkt->ksl) {
|
||||
ngtcp2_ksl_free(bkt->ksl);
|
||||
ngtcp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ngtcp2_map_insert(ngtcp2_map *map, ngtcp2_map_entry *new_entry) {
|
||||
int rv;
|
||||
|
||||
/* Load factor is 0.75 */
|
||||
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
||||
rv = map_resize(map, map->tablelen * 2);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = map_insert(map, map->table, map->tablelen, new_entry);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
++map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngtcp2_map_entry *ngtcp2_map_find(ngtcp2_map *map, key_type key) {
|
||||
ngtcp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
ngtcp2_ksl_it it;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
return bkt->ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
it = ngtcp2_ksl_lower_bound(bkt->ksl, &key);
|
||||
if (ngtcp2_ksl_it_end(&it) || *(key_type *)ngtcp2_ksl_it_key(&it) != key) {
|
||||
return NULL;
|
||||
}
|
||||
return ngtcp2_ksl_it_get(&it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ngtcp2_map_remove(ngtcp2_map *map, key_type key) {
|
||||
ngtcp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
bkt->ptr = NULL;
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
return NGTCP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
rv = ngtcp2_ksl_remove(bkt->ksl, NULL, &key);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NGTCP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
void ngtcp2_map_clear(ngtcp2_map *map) {
|
||||
uint32_t i;
|
||||
ngtcp2_map_bucket *bkt;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
bkt->ptr = NULL;
|
||||
if (bkt->ksl) {
|
||||
ngtcp2_ksl_free(bkt->ksl);
|
||||
ngtcp2_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
}
|
||||
|
||||
size_t ngtcp2_map_size(ngtcp2_map *map) { return map->size; }
|
152
deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h
vendored
Normal file
152
deps/ngtcp2/ngtcp2/lib/ngtcp2_map.h
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "ngtcp2_ksl.h"
|
||||
|
||||
/* Implementation of unordered map */
|
||||
|
||||
typedef uint64_t key_type;
|
||||
|
||||
typedef struct ngtcp2_map_entry ngtcp2_map_entry;
|
||||
|
||||
struct ngtcp2_map_entry {
|
||||
key_type key;
|
||||
};
|
||||
|
||||
typedef struct ngtcp2_map_bucket {
|
||||
ngtcp2_map_entry *ptr;
|
||||
ngtcp2_ksl *ksl;
|
||||
} ngtcp2_map_bucket;
|
||||
|
||||
typedef struct ngtcp2_map {
|
||||
ngtcp2_map_bucket *table;
|
||||
const ngtcp2_mem *mem;
|
||||
size_t size;
|
||||
uint32_t tablelen;
|
||||
} ngtcp2_map;
|
||||
|
||||
/*
|
||||
* Initializes the map |map|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGTCP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int 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 |entry| 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)(ngtcp2_map_entry *entry, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
/*
|
||||
* Initializes the |entry| with the |key|. All entries to be inserted
|
||||
* to the map must be initialized with this function.
|
||||
*/
|
||||
void ngtcp2_map_entry_init(ngtcp2_map_entry *entry, key_type key);
|
||||
|
||||
/*
|
||||
* Inserts the new |entry| with the key |entry->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_entry *entry);
|
||||
|
||||
/*
|
||||
* Returns the entry associated by the key |key|. If there is no such
|
||||
* entry, this function returns NULL.
|
||||
*/
|
||||
ngtcp2_map_entry *ngtcp2_map_find(ngtcp2_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes the entry associated by the key |key| from the |map|. The
|
||||
* removed entry 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 entry associated by |key| does not exist.
|
||||
*/
|
||||
int ngtcp2_map_remove(ngtcp2_map *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 entry in the |map| with the
|
||||
* optional user supplied pointer |ptr|.
|
||||
*
|
||||
* If the |func| returns 0, this function calls the |func| with the
|
||||
* next entry. 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 entry. Use
|
||||
* ngtcp2_map_each_free() instead.
|
||||
*/
|
||||
int ngtcp2_map_each(ngtcp2_map *map,
|
||||
int (*func)(ngtcp2_map_entry *entry, void *ptr), void *ptr);
|
||||
|
||||
#endif /* NGTCP2_MAP_H */
|
75
deps/ngtcp2/ngtcp2/lib/ngtcp2_mem.c
vendored
Normal file
75
deps/ngtcp2/ngtcp2/lib/ngtcp2_mem.c
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
static void *default_malloc(size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void default_free(void *ptr, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
static void *default_realloc(void *ptr, size_t size, void *mem_user_data) {
|
||||
(void)mem_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; }
|
||||
|
||||
void *ngtcp2_mem_malloc(const ngtcp2_mem *mem, size_t size) {
|
||||
return mem->malloc(size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void ngtcp2_mem_free(const ngtcp2_mem *mem, void *ptr) {
|
||||
mem->free(ptr, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void ngtcp2_mem_free2(ngtcp2_free free_func, void *ptr, void *mem_user_data) {
|
||||
free_func(ptr, mem_user_data);
|
||||
}
|
||||
|
||||
void *ngtcp2_mem_calloc(const ngtcp2_mem *mem, size_t nmemb, size_t size) {
|
||||
return mem->calloc(nmemb, size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void *ngtcp2_mem_realloc(const ngtcp2_mem *mem, void *ptr, size_t size) {
|
||||
return mem->realloc(ptr, size, mem->mem_user_data);
|
||||
}
|
43
deps/ngtcp2/ngtcp2/lib/ngtcp2_mem.h
vendored
Normal file
43
deps/ngtcp2/ngtcp2/lib/ngtcp2_mem.h
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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|. */
|
||||
void *ngtcp2_mem_malloc(const ngtcp2_mem *mem, size_t size);
|
||||
void ngtcp2_mem_free(const ngtcp2_mem *mem, void *ptr);
|
||||
void ngtcp2_mem_free2(ngtcp2_free free_func, void *ptr, void *mem_user_data);
|
||||
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);
|
||||
|
||||
#endif /* NGTCP2_MEM_H */
|
74
deps/ngtcp2/ngtcp2/lib/ngtcp2_path.c
vendored
Normal file
74
deps/ngtcp2/ngtcp2/lib/ngtcp2_path.c
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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 struct sockaddr *local_addr,
|
||||
size_t local_addrlen, void *local_user_data,
|
||||
const struct sockaddr *remote_addr,
|
||||
size_t remote_addrlen, void *remote_user_data) {
|
||||
ngtcp2_addr_init(&ps->path.local, (const struct sockaddr *)&ps->local_addrbuf,
|
||||
0, local_user_data);
|
||||
ngtcp2_addr_init(&ps->path.remote,
|
||||
(const struct sockaddr *)&ps->remote_addrbuf, 0,
|
||||
remote_user_data);
|
||||
|
||||
ngtcp2_addr_copy_byte(&ps->path.local, local_addr, local_addrlen);
|
||||
ngtcp2_addr_copy_byte(&ps->path.remote, remote_addr, remote_addrlen);
|
||||
}
|
||||
|
||||
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->local.user_data, path->remote.addr,
|
||||
path->remote.addrlen, path->remote.user_data);
|
||||
}
|
||||
|
||||
void ngtcp2_path_storage_zero(ngtcp2_path_storage *ps) {
|
||||
ngtcp2_addr_init(&ps->path.local, (const struct sockaddr *)&ps->local_addrbuf,
|
||||
0, NULL);
|
||||
ngtcp2_addr_init(&ps->path.remote,
|
||||
(const struct sockaddr *)&ps->remote_addrbuf, 0, NULL);
|
||||
}
|
49
deps/ngtcp2/ngtcp2/lib/ngtcp2_path.h
vendored
Normal file
49
deps/ngtcp2/ngtcp2/lib/ngtcp2_path.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 */
|
2432
deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c
vendored
Normal file
2432
deps/ngtcp2/ngtcp2/lib/ngtcp2_pkt.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user