Release 2.2.0: server included, ID-22 supported (#76)
This commit is contained in:
parent
8cba36d873
commit
5392f7a3b0
|
@ -9,10 +9,13 @@ task:
|
|||
# This is so that both GQUIC and IETF branches build. Just picking
|
||||
# a known good revision:
|
||||
- git checkout 32e59d2d3264e4e104b355ef73663b8b79ac4093
|
||||
- patch -p1 -i ../patches/boringssl-meds.patch
|
||||
- cmake .
|
||||
- make
|
||||
- cd -
|
||||
script:
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
- cmake -DBORINGSSL_DIR=$PWD/boringssl .
|
||||
- make
|
||||
- make test
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[submodule "src/liblsquic/ls-qpack"]
|
||||
path = src/liblsquic/ls-qpack
|
||||
url = https://github.com/litespeedtech/ls-qpack
|
||||
branch = v0.9.13
|
|
@ -24,9 +24,12 @@ before_script:
|
|||
# This is so that both GQUIC and IETF branches build. Just picking
|
||||
# a known good revision:
|
||||
- git checkout 32e59d2d3264e4e104b355ef73663b8b79ac4093
|
||||
- patch -p1 -i ../patches/boringssl-meds.patch
|
||||
- cmake .
|
||||
- make
|
||||
- cd -
|
||||
- git submodule init
|
||||
- git submodule update
|
||||
- cmake -DBORINGSSL_DIR=$PWD/boringssl .
|
||||
script:
|
||||
# Now build lsquic-client
|
||||
|
|
3
APIs.txt
3
APIs.txt
|
@ -99,6 +99,9 @@ struct lsquic_engine_settings and struct lsquic_stream_if, as well as:
|
|||
- Interface for sending outgoing packets, ea_packets_out
|
||||
- Interface for allocating memory for outgoing packet buffers
|
||||
(optional).
|
||||
- Interface for share memory hash, ea_shi
|
||||
- Optional interface for reporting connections whose handshake
|
||||
did not complete (ea_bad_handshake)
|
||||
|
||||
ea_packets_out is a pointer to a function of type lsquic_packets_out_f.
|
||||
The engine calls this function when it is appropriate to send out packets
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2019-09-11
|
||||
- 2.2.0
|
||||
- [FEATURE] Server code is included in the library
|
||||
- [FEATURE] IETF QUIC and HTTP/3 Support (ID-22)
|
||||
|
||||
2019-05-13
|
||||
- 1.21.2
|
||||
- [OPTIMIZATION] HPACK: use history to improve compression performance
|
||||
|
|
|
@ -18,7 +18,6 @@ IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
|||
SET(CMAKE_BUILD_TYPE Debug)
|
||||
ENDIF()
|
||||
|
||||
|
||||
MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
|
||||
|
@ -26,22 +25,30 @@ IF (NOT MSVC)
|
|||
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wall -Wextra -Wno-unused-parameter")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fno-omit-frame-pointer")
|
||||
INCLUDE(CheckCCompilerFlag)
|
||||
CHECK_C_COMPILER_FLAG(-Wno-implicit-fallthrough HAS_NO_IMPLICIT_FALLTHROUGH)
|
||||
IF (HAS_NO_IMPLICIT_FALLTHROUGH)
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wno-implicit-fallthrough")
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.3)
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wno-missing-field-initializers")
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O0 -g3")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Werror")
|
||||
IF(CMAKE_C_COMPILER MATCHES "clang" AND
|
||||
NOT "$ENV{TRAVIS}" MATCHES "^true$")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fsanitize=address")
|
||||
ENDIF()
|
||||
# Uncomment to enable fault injection testing via libfiu:
|
||||
#SET (MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DFIU_ENABLE=1")
|
||||
# Uncomment to enable cleartext protocol mode (no crypto):
|
||||
#SET (MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLSQUIC_ENABLE_HANDSHAKE_DISABLE=1")
|
||||
#SET(LIBS ${LIBS} fiu)
|
||||
ELSE()
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -O3 -g0")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DNDEBUG")
|
||||
# Comment out the following line to compile out debug messages:
|
||||
#SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_INFO")
|
||||
ENDIF()
|
||||
|
@ -70,7 +77,6 @@ IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|||
#SET(LIBS ${LIBS} fiu)
|
||||
ELSE()
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Ox")
|
||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DNDEBUG")
|
||||
# Comment out the following line to compile out debug messages:
|
||||
#SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_INFO")
|
||||
ENDIF()
|
||||
|
@ -189,19 +195,24 @@ ELSE()
|
|||
MESSAGE(STATUS "libevent not found")
|
||||
ENDIF()
|
||||
|
||||
add_executable(http_server test/http_server.c test/prog.c test/test_common.c test/test_cert.c)
|
||||
|
||||
|
||||
SET(LIBS lsquic ${EVENT_LIB} ${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${ZLIB_LIB} ${LIBS})
|
||||
|
||||
IF (NOT MSVC)
|
||||
|
||||
add_executable(http_client
|
||||
test/http_client.c
|
||||
test/prog.c
|
||||
test/test_common.c
|
||||
test/test_cert.c
|
||||
)
|
||||
LIST(APPEND LIBS pthread m)
|
||||
|
||||
#MSVC
|
||||
ELSE()
|
||||
|
||||
add_executable(http_client
|
||||
test/http_client.c
|
||||
test/prog.c
|
||||
|
@ -214,13 +225,13 @@ LIST(APPEND LIBS ws2_32)
|
|||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES(http_client ${LIBS})
|
||||
|
||||
TARGET_LINK_LIBRARIES(http_server ${LIBS})
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
IF(NOT (CMAKE_C_FLAGS MATCHES "-DNDEBUG"))
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# Our test framework relies on assertions, only compile if assertions are
|
||||
# enabled.
|
||||
#
|
||||
|
|
123
EXAMPLES.txt
123
EXAMPLES.txt
|
@ -2,7 +2,18 @@
|
|||
LSQUIC Examples
|
||||
===============
|
||||
|
||||
test/http_client.c demonstrates how to use HTTP features of QUIC.
|
||||
LSQUIC comes with several examples of how the library is used.
|
||||
|
||||
The client and server programs described below are built on a common
|
||||
framework and share many options.
|
||||
|
||||
HTTP client and server
|
||||
----------------------
|
||||
|
||||
See test/http_{client,server}.c
|
||||
|
||||
This pair of programs is to demonstrate how to use HTTP features of QUIC.
|
||||
HTTP server is interoperable with proto-quic's quic_client.
|
||||
|
||||
Usage Examples
|
||||
--------------
|
||||
|
@ -65,10 +76,41 @@ To perform load testing, it is good to mix sending and receiving data:
|
|||
If you don't want to create a hundred 256-megabyte out-get.* files, use -K
|
||||
flag to discard output.
|
||||
|
||||
Testing Large Packet Sizes
|
||||
---------------------------------
|
||||
|
||||
IETF QUIC supports all valid UDP packet sizes. This section outlines the
|
||||
environment setup and testing parameters necessary to test this feature.
|
||||
|
||||
Compilation
|
||||
- Make sure to compile the library in DEBUG mode so that the NDEBUG
|
||||
define is off.
|
||||
- Build both the http_client and http_server test programs.
|
||||
|
||||
Running Instructions
|
||||
- On the server side, define the environment variable
|
||||
LSQUIC_CN_PACK_SIZE and set it to the intended packet size.
|
||||
Valid sizes are up to 65507 (IPv4).
|
||||
- Use the -W flag for http_client and http_server for the ability
|
||||
to send packets of large size.
|
||||
- On the client side, use the -z flag to specify the maximum size
|
||||
of packet that the client will accept.
|
||||
|
||||
Example Usage
|
||||
./http_client -p /file-1M -H www.litespeedtech.com -s 192.168.0.85:5443
|
||||
-o version=FF000014 -z 65507 -W
|
||||
./http_server -c www.litespeedtech.com,certschain,privkey
|
||||
-s 0.0.0.0:5443 -W
|
||||
|
||||
Additional Notes
|
||||
Since this feature does not have MTU discovery enabled at the time of
|
||||
writing, make sure to use client and server machines that share a path
|
||||
with the intended MTU.
|
||||
|
||||
Control QUIC Settings via -o Flag
|
||||
---------------------------------
|
||||
|
||||
Most of the settings in struct lsquic_engine_settings can be controlled
|
||||
Most of the settings in struct squic_engine_settings can be controlled
|
||||
via -o flag. With exception of es_versions, which is a bit mask, other
|
||||
es_* options can be mapped to corresponding -o value via s/^es_//:
|
||||
|
||||
|
@ -77,6 +119,16 @@ es_* options can be mapped to corresponding -o value via s/^es_//:
|
|||
|
||||
And so on.
|
||||
|
||||
For example, to test version negotiation:
|
||||
|
||||
./http_server -c www.litespeedtech.com,certschain,privkey \
|
||||
-o version=Q035 -L debug 2>server.out &
|
||||
./http_client -H www.litespeedtech.com -p Makefile -L debug 2>client.out
|
||||
|
||||
Above, the client will start with the default, which is the highest supported
|
||||
QUIC version, which the server should negotiate down. You should see it from
|
||||
the log files.
|
||||
|
||||
The code to set options via -o flag lives in set_engine_option(). It is good
|
||||
to update this function at the same time as member fields are added to struct
|
||||
lsquic_engine_settings.
|
||||
|
@ -84,6 +136,46 @@ lsquic_engine_settings.
|
|||
Control LSQUIC Behavior via Environment Variables
|
||||
-------------------------------------------------
|
||||
|
||||
LSQUIC_PACKET_OUT_LIMIT
|
||||
|
||||
If set, the value of this environment variable is the maximum number
|
||||
of packets that can be sent out in one shot. The limit is in the test
|
||||
program framework's ea_packets_out() callback.
|
||||
|
||||
It is not applicable when sendmmsg(2) is used.
|
||||
|
||||
Note 1: sendmmsg can be enabled using -g option, if available for your
|
||||
platform.
|
||||
|
||||
Note 2: see -m option for a related packet-out limitation.
|
||||
|
||||
LSQUIC_DISABLE_HANDSHAKE
|
||||
|
||||
If set (to anything, not any particular value), the QUIC handshake is
|
||||
disabled and packets are not encrypted. This can be useful to:
|
||||
a) profile functions in LSQUIC without accounting for crypto stuff,
|
||||
which tends to dwarf everything else;
|
||||
b) see bytes in the clear on the wire; and
|
||||
c) compare throughput performance to TCP without crypto.
|
||||
|
||||
This functionality is compiled in if the somewhat-awkwardly named
|
||||
LSQUIC_ENABLE_HANDSHAKE_DISABLE is set to 1. By default, it is enabled
|
||||
in debug builds and disabled in optimized builds.
|
||||
|
||||
LSQUIC_LOSE_PACKETS_RE
|
||||
|
||||
If set, this regular expression specifies the numbers of packets which
|
||||
the sender will lose on purpose. For example:
|
||||
|
||||
export LSQUIC_LOSE_PACKETS_RE='^(3|5|10)$'
|
||||
|
||||
The act of losing a packet is performed by changing its payload to
|
||||
zero-filled buffer of the same size, which is almost as good as
|
||||
not sending anything. The latter is difficult to implement without
|
||||
negatively affecting the regular code flow.
|
||||
|
||||
Only available in debug builds.
|
||||
|
||||
LSQUIC_PACER_INTERTICK
|
||||
|
||||
Number of microsecods to use as constant intertick time in lieu of the
|
||||
|
@ -104,6 +196,21 @@ LSQUIC_RANDOM_SEND_FAILURE
|
|||
|
||||
Only available when compiled with -DLSQUIC_RANDOM_SEND_FAILURE=1
|
||||
|
||||
LSQUIC_LOG_SECRETS
|
||||
|
||||
If set to true value, crypto secrets will be logged. Applies to
|
||||
IETF QUIC only.
|
||||
|
||||
LSQUIC_COALESCE
|
||||
|
||||
If set to false, packets are not coalesced. Defaults to true.
|
||||
|
||||
LSQUIC_USE_POOLS
|
||||
|
||||
If set to false, all memory pooling code is replaced with calls to
|
||||
malloc() and free(). This facilitates debugging memory issues.
|
||||
The default is true.
|
||||
|
||||
Control Network-Related Stuff
|
||||
-----------------------------
|
||||
|
||||
|
@ -116,9 +223,16 @@ Control Network-Related Stuff
|
|||
sndbuf=12345 # Sets SO_SNDBUF
|
||||
rcvbuf=12345 # Sets SO_RCVBUF
|
||||
|
||||
-g Use sendmmsg() to send packets. This is only compiled in
|
||||
if available.
|
||||
|
||||
More Compilation Options
|
||||
------------------------
|
||||
|
||||
-DLSQUIC_ENABLE_HANDSHAKE_DISABLE=1
|
||||
|
||||
Support disabling of handshake. See above.
|
||||
|
||||
-DLSQUIC_CONN_STATS=1
|
||||
|
||||
Track some statistics about connections -- packets in, sent, delayed,
|
||||
|
@ -140,6 +254,11 @@ More Compilation Options
|
|||
Turn off statistics collection performed by the send controller: number
|
||||
of packets sent, resent, and delayed.
|
||||
|
||||
-DLOG_PACKET_CHECKSUM=1
|
||||
|
||||
When turned on, CRC32 checksum of each sent and received packet is
|
||||
logged as an event.
|
||||
|
||||
-DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_WARN
|
||||
|
||||
If you want to go even faster: compile out some log levels entirely.
|
||||
|
|
60
README.md
60
README.md
|
@ -1,25 +1,22 @@
|
|||
[![Build Status](https://travis-ci.org/litespeedtech/lsquic-client.svg?branch=master)](https://travis-ci.org/litespeedtech/lsquic-client)
|
||||
[![Build Status](https://api.cirrus-ci.com/github/litespeedtech/lsquic-client.svg)](https://cirrus-ci.com/github/litespeedtech/lsquic-client)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/kei9649t9leoqicr?svg=true)](https://ci.appveyor.com/project/litespeedtech/lsquic-client)
|
||||
[![Build Status](https://travis-ci.org/litespeedtech/lsquic.svg?branch=master)](https://travis-ci.org/litespeedtech/lsquic)
|
||||
[![Build Status](https://api.cirrus-ci.com/github/litespeedtech/lsquic.svg)](https://cirrus-ci.com/github/litespeedtech/lsquic)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/kei9649t9leoqicr?svg=true)](https://ci.appveyor.com/project/litespeedtech/lsquic)
|
||||
|
||||
LiteSpeed QUIC (LSQUIC) Client Library README
|
||||
LiteSpeed QUIC (LSQUIC) Library README
|
||||
=============================================
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
LiteSpeed QUIC (LSQUIC) Client Library is an open-source implementation
|
||||
of QUIC functionality for clients. It is released in the hope to speed
|
||||
LiteSpeed QUIC (LSQUIC) Library is an open-source implementation of QUIC
|
||||
functionality for servers and clients. It is released in the hope to speed
|
||||
the adoption of QUIC. Most of the code in this distribution is used in
|
||||
our own products: LiteSpeed Web Server and ADC. We think it is free of
|
||||
major problems. Nevertheless, do not hesitate to report bugs back to us.
|
||||
Even better, send us fixes and improvements!
|
||||
our own products: LiteSpeed Web Server, LiteSpeed ADC, and OpenLiteSpeed.
|
||||
We think it is free of major problems. Nevertheless, do not hesitate to
|
||||
report bugs back to us. Even better, send us fixes and improvements!
|
||||
|
||||
Currently supported QUIC versions are Q035, Q039, Q043, and Q044. Support
|
||||
for newer versions will be added soon after they are released. The
|
||||
version(s) specified by IETF QUIC WG are being developed on
|
||||
[one or more branches](https://github.com/litespeedtech/lsquic-client/branches).
|
||||
When deemed stable, the IETF QUIC support will be added to the master branch.
|
||||
Currently supported QUIC versions are Q039, Q043, Q046, and ID-22. Support
|
||||
for newer versions will be added soon after they are released.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
@ -49,13 +46,9 @@ git clone https://boringssl.googlesource.com/boringssl
|
|||
cd boringssl
|
||||
```
|
||||
|
||||
2. Check out stable branch:
|
||||
You may need to install pre-requisites like zlib and libevent.
|
||||
|
||||
```
|
||||
git checkout chromium-stable
|
||||
```
|
||||
|
||||
3. Compile the library
|
||||
2. Compile the library
|
||||
|
||||
```
|
||||
cmake . && make
|
||||
|
@ -72,17 +65,20 @@ If you want to turn on optimizations, do
|
|||
cmake -DCMAKE_BUILD_TYPE=Release . && make
|
||||
```
|
||||
|
||||
Building LSQUIC Client Library
|
||||
------------------------------
|
||||
Building LSQUIC Library
|
||||
-----------------------
|
||||
|
||||
LSQUIC's `http_client` and the tests link BoringSSL libraries statically.
|
||||
Following previous section, you can build LSQUIC as follows:
|
||||
LSQUIC's `http_client`, `http_server`, and the tests link BoringSSL
|
||||
libraries statically. Following previous section, you can build LSQUIC
|
||||
as follows:
|
||||
|
||||
1. Get the source code
|
||||
|
||||
```
|
||||
git clone https://github.com/litespeedtech/lsquic-client.git
|
||||
cd lsquic-client
|
||||
git clone https://github.com/litespeedtech/lsquic.git
|
||||
cd lsquic
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
2. Compile the library
|
||||
|
@ -104,31 +100,31 @@ Building with Docker
|
|||
---------
|
||||
The library and http_client example can be built with Docker.
|
||||
```
|
||||
docker build -t lsquic-client .
|
||||
docker build -t lsquic .
|
||||
```
|
||||
|
||||
Then you can use the http_client example from the command line.
|
||||
```
|
||||
docker run -it --rm lsquic-client http_client -H www.google.com -s 74.125.22.106:443 -p /
|
||||
docker run -it --rm lsquic http_client -H www.google.com -s 74.125.22.106:443 -p /
|
||||
```
|
||||
|
||||
Platforms
|
||||
---------
|
||||
|
||||
The client library has been tested on the following platforms:
|
||||
The library has been tested on the following platforms:
|
||||
- Linux
|
||||
- i386
|
||||
- x86_64
|
||||
- ARM (Raspberry Pi 3)
|
||||
- FreeBSD
|
||||
- i386
|
||||
- Windows
|
||||
- x86_64
|
||||
- MacOS
|
||||
- x86_64
|
||||
- Windows (this needs updating for the server part, now broken)
|
||||
- x86_64
|
||||
|
||||
Have fun,
|
||||
|
||||
LiteSpeed QUIC Team.
|
||||
|
||||
Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc
|
||||
Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc
|
||||
|
|
602
include/lsquic.h
602
include/lsquic.h
|
@ -23,9 +23,9 @@ struct sockaddr;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LSQUIC_MAJOR_VERSION 1
|
||||
#define LSQUIC_MINOR_VERSION 21
|
||||
#define LSQUIC_PATCH_VERSION 2
|
||||
#define LSQUIC_MAJOR_VERSION 2
|
||||
#define LSQUIC_MINOR_VERSION 2
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
|
||||
/**
|
||||
* Engine flags:
|
||||
|
@ -49,7 +49,9 @@ enum lsquic_version
|
|||
{
|
||||
|
||||
/** Q035. This is the first version to be supported by LSQUIC. */
|
||||
LSQVER_035,
|
||||
/* Support for this version has been removed. The comment remains to
|
||||
* document the changes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Q037. This version is like Q035, except the way packet hashes are
|
||||
|
@ -101,7 +103,9 @@ enum lsquic_version
|
|||
* Q044. IETF-like packet headers are used. Frames are the same as
|
||||
* in Q043. Server never includes CIDs in short packets.
|
||||
*/
|
||||
LSQVER_044,
|
||||
/* Support for this version has been removed. The comment remains to
|
||||
* document the changes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Q046. Use IETF Draft-17 compatible packet headers.
|
||||
|
@ -120,27 +124,41 @@ enum lsquic_version
|
|||
#define LSQUIC_EXPERIMENTAL_Q098 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IETF QUIC Draft-22
|
||||
*/
|
||||
LSQVER_ID22,
|
||||
|
||||
/**
|
||||
* Special version to trigger version negotiation.
|
||||
* [draft-ietf-quic-transport-11], Section 3.
|
||||
*/
|
||||
LSQVER_VERNEG,
|
||||
|
||||
N_LSQVER
|
||||
};
|
||||
|
||||
/**
|
||||
* We currently support versions 35, 39, 43, 44, and 46.
|
||||
* We currently support versions 39, 43, 46, and IETF Draft-22
|
||||
* @see lsquic_version
|
||||
*/
|
||||
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
|
||||
|
||||
#define LSQUIC_EXPERIMENTAL_VERSIONS (0 \
|
||||
| LSQUIC_EXPERIMENTAL_Q098)
|
||||
|
||||
#define LSQUIC_DEPRECATED_VERSIONS 0
|
||||
|
||||
#define LSQUIC_GQUIC_HEADER_VERSIONS ( \
|
||||
(1 << LSQVER_035) | (1 << LSQVER_039) | (1 << LSQVER_043))
|
||||
|
||||
/**
|
||||
* List of versions in which the server never includes CID in short packets.
|
||||
*/
|
||||
#define LSQUIC_FORCED_TCID0_VERSIONS ((1 << LSQVER_044) | (1 << LSQVER_046))
|
||||
#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_046)
|
||||
|
||||
#define LSQUIC_EXPERIMENTAL_VERSIONS ( \
|
||||
(1 << LSQVER_VERNEG) | LSQUIC_EXPERIMENTAL_Q098)
|
||||
|
||||
#define LSQUIC_DEPRECATED_VERSIONS 0
|
||||
|
||||
#define LSQUIC_GQUIC_HEADER_VERSIONS ((1 << LSQVER_039) | (1 << LSQVER_043))
|
||||
|
||||
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID22) | (1 << LSQVER_VERNEG))
|
||||
|
||||
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID22) | (1 << LSQVER_VERNEG))
|
||||
|
||||
enum lsquic_hsk_status
|
||||
{
|
||||
|
@ -156,6 +174,11 @@ enum lsquic_hsk_status
|
|||
* The handshake succeeded with 0-RTT.
|
||||
*/
|
||||
LSQ_HSK_0RTT_OK,
|
||||
/**
|
||||
* The handshake failed because of 0-RTT (early data rejected). Retry
|
||||
* the connection without 0-RTT.
|
||||
*/
|
||||
LSQ_HSK_0RTT_FAIL,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -192,6 +215,7 @@ struct lsquic_stream_if {
|
|||
void (*on_read) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
|
||||
void (*on_write) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
|
||||
void (*on_close) (lsquic_stream_t *s, lsquic_stream_ctx_t *h);
|
||||
/* This callback in only called in client mode */
|
||||
/**
|
||||
* When handshake is completed, this callback is called. `ok' is set
|
||||
* to true if handshake was successful; otherwise, `ok' is set to
|
||||
|
@ -200,8 +224,31 @@ struct lsquic_stream_if {
|
|||
* This callback is optional.
|
||||
*/
|
||||
void (*on_hsk_done)(lsquic_conn_t *c, enum lsquic_hsk_status s);
|
||||
/**
|
||||
* When server sends a token in NEW_TOKEN frame, this callback is called.
|
||||
* The callback is optional.
|
||||
*/
|
||||
void (*on_new_token)(lsquic_conn_t *c, const unsigned char *token,
|
||||
size_t token_size);
|
||||
/**
|
||||
* This optional callback lets client record information needed to
|
||||
* perform a zero-RTT handshake next time around.
|
||||
*/
|
||||
void (*on_zero_rtt_info)(lsquic_conn_t *c, const unsigned char *, size_t);
|
||||
};
|
||||
|
||||
struct ssl_ctx_st;
|
||||
struct ssl_st;
|
||||
|
||||
/**
|
||||
* QUIC engine in server role needs access to certificates. This is
|
||||
* accomplished by providing a callback and a context to the engine
|
||||
* constructor.
|
||||
*/
|
||||
|
||||
typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
|
||||
void *lsquic_cert_lookup_ctx, const struct sockaddr *local, const char *sni);
|
||||
|
||||
/**
|
||||
* Minimum flow control window is set to 16 KB for both client and server.
|
||||
* This means we can send up to this amount of data before handshake gets
|
||||
|
@ -226,12 +273,36 @@ struct lsquic_stream_if {
|
|||
#define LSQUIC_DF_SFCW_CLIENT (6 * 1024 * 1024)
|
||||
#define LSQUIC_DF_MAX_STREAMS_IN 100
|
||||
|
||||
/* IQUIC uses different names for these: */
|
||||
#define LSQUIC_DF_INIT_MAX_DATA_SERVER LSQUIC_DF_CFCW_SERVER
|
||||
#define LSQUIC_DF_INIT_MAX_DATA_CLIENT LSQUIC_DF_CFCW_CLIENT
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_BIDI_REMOTE_SERVER LSQUIC_DF_SFCW_SERVER
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_BIDI_LOCAL_SERVER 0
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_BIDI_REMOTE_CLIENT 0
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_BIDI_LOCAL_CLIENT LSQUIC_DF_SFCW_CLIENT
|
||||
#define LSQUIC_DF_INIT_MAX_STREAMS_BIDI LSQUIC_DF_MAX_STREAMS_IN
|
||||
#define LSQUIC_DF_INIT_MAX_STREAMS_UNI_CLIENT 100
|
||||
#define LSQUIC_DF_INIT_MAX_STREAMS_UNI_SERVER 3
|
||||
/* XXX What's a good value here? */
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_UNI_CLIENT (32 * 1024)
|
||||
#define LSQUIC_DF_INIT_MAX_STREAM_DATA_UNI_SERVER (12 * 1024)
|
||||
|
||||
/**
|
||||
* Default idle connection time in seconds.
|
||||
*/
|
||||
#define LSQUIC_DF_IDLE_TIMEOUT 30
|
||||
|
||||
/**
|
||||
* Default ping period in seconds.
|
||||
*/
|
||||
#define LSQUIC_DF_PING_PERIOD 15
|
||||
|
||||
/**
|
||||
* Default handshake timeout in microseconds.
|
||||
*/
|
||||
#define LSQUIC_DF_HANDSHAKE_TO (10 * 1000 * 1000)
|
||||
|
||||
#define LSQUIC_DF_IDLE_CONN_TO (30 * 1000 * 1000)
|
||||
#define LSQUIC_DF_IDLE_CONN_TO (LSQUIC_DF_IDLE_TIMEOUT * 1000 * 1000)
|
||||
#define LSQUIC_DF_SILENT_CLOSE 1
|
||||
|
||||
/** Default value of maximum header list size. If set to non-zero value,
|
||||
|
@ -249,11 +320,18 @@ struct lsquic_stream_if {
|
|||
#define LSQUIC_DF_SUPPORT_SREJ_CLIENT 0 /* TODO: client support */
|
||||
/** Do not use NSTP by default */
|
||||
#define LSQUIC_DF_SUPPORT_NSTP 0
|
||||
/** TODO: IETF QUIC clients do not support push */
|
||||
#define LSQUIC_DF_SUPPORT_PUSH 1
|
||||
#define LSQUIC_DF_SUPPORT_TCID0 0
|
||||
#define LSQUIC_DF_SUPPORT_TCID0 1
|
||||
/** By default, LSQUIC ignores Public Reset packets. */
|
||||
#define LSQUIC_DF_HONOR_PRST 0
|
||||
|
||||
/**
|
||||
* By default, LSQUIC will not send Public Reset packets in response to
|
||||
* packets that specify unknown connections.
|
||||
*/
|
||||
#define LSQUIC_DF_SEND_PRST 0
|
||||
|
||||
/** By default, infinite loop checks are turned on */
|
||||
#define LSQUIC_DF_PROGRESS_CHECK 1000
|
||||
|
||||
|
@ -269,6 +347,32 @@ struct lsquic_stream_if {
|
|||
/** Default clock granularity is 1000 microseconds */
|
||||
#define LSQUIC_DF_CLOCK_GRANULARITY 1000
|
||||
|
||||
/** The default value is 8 for simplicity */
|
||||
#define LSQUIC_DF_SCID_LEN 8
|
||||
|
||||
/** The default value is 60 CIDs per minute */
|
||||
#define LSQUIC_DF_SCID_ISS_RATE 60
|
||||
|
||||
#define LSQUIC_DF_QPACK_DEC_MAX_BLOCKED 100
|
||||
#define LSQUIC_DF_QPACK_DEC_MAX_SIZE 4096
|
||||
#define LSQUIC_DF_QPACK_ENC_MAX_BLOCKED 100
|
||||
#define LSQUIC_DF_QPACK_ENC_MAX_SIZE 4096
|
||||
|
||||
/** ECN is enabled by default */
|
||||
#define LSQUIC_DF_ECN 1
|
||||
|
||||
/**
|
||||
* The default number of the priority placeholders is higher than the
|
||||
* recommended value of 16 to give the clients even more freedom.
|
||||
*/
|
||||
#define LSQUIC_DF_H3_PLACEHOLDERS 50
|
||||
|
||||
/** Allow migration by default */
|
||||
#define LSQUIC_DF_ALLOW_MIGRATION 1
|
||||
|
||||
/* 1: Cubic; 2: BBR */
|
||||
#define LSQUIC_DF_CC_ALGO 1
|
||||
|
||||
struct lsquic_engine_settings {
|
||||
/**
|
||||
* This is a bit mask wherein each bit corresponds to a value in
|
||||
|
@ -276,6 +380,8 @@ struct lsquic_engine_settings {
|
|||
* version and goes down. Server supports either of the versions
|
||||
* specified here.
|
||||
*
|
||||
* This setting applies to both Google and IETF QUIC.
|
||||
*
|
||||
* @see lsquic_version
|
||||
*/
|
||||
unsigned es_versions;
|
||||
|
@ -325,10 +431,12 @@ struct lsquic_engine_settings {
|
|||
* For client, this can be set to an arbitrary value (zero turns the
|
||||
* timeout off).
|
||||
*
|
||||
* For server, this value is limited to about 16 seconds. Do not set
|
||||
* it to zero.
|
||||
*/
|
||||
unsigned long es_handshake_to;
|
||||
|
||||
/** ICSL in microseconds */
|
||||
/** ICSL in microseconds; GQUIC only */
|
||||
unsigned long es_idle_conn_to;
|
||||
|
||||
/** SCLS (silent close) */
|
||||
|
@ -344,10 +452,20 @@ struct lsquic_engine_settings {
|
|||
/** UAID -- User-Agent ID. Defaults to @ref LSQUIC_DF_UA. */
|
||||
const char *es_ua;
|
||||
|
||||
/**
|
||||
* More parameters for server
|
||||
*/
|
||||
uint64_t es_sttl; /* SCFG TTL in seconds */
|
||||
|
||||
uint32_t es_pdmd; /* One fixed value X509 */
|
||||
uint32_t es_aead; /* One fixed value AESG */
|
||||
uint32_t es_kexs; /* One fixed value C255 */
|
||||
|
||||
/* Maximum number of incoming connections in inchoate state. This is
|
||||
* only applicable in server mode.
|
||||
*/
|
||||
unsigned es_max_inchoate;
|
||||
|
||||
/**
|
||||
* Support SREJ: for client side, this means supporting server's SREJ
|
||||
* responses (this does not work yet) and for server side, this means
|
||||
|
@ -364,6 +482,8 @@ struct lsquic_engine_settings {
|
|||
* b) All incoming pushed streams get reset immediately.
|
||||
* (For maximum effect, set es_max_streams_in to 0.)
|
||||
*
|
||||
* For server:
|
||||
* lsquic_conn_push_stream() will return -1.
|
||||
*/
|
||||
int es_support_push;
|
||||
|
||||
|
@ -376,7 +496,7 @@ struct lsquic_engine_settings {
|
|||
* (source-addr, dest-addr) tuple, thereby making it necessary to create
|
||||
* a socket for each connection.
|
||||
*
|
||||
* This option has no effect in Q044 or Q046, as the server never includes
|
||||
* This option has no effect in Q046, as the server never includes
|
||||
* CIDs in the short packets.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_SUPPORT_TCID0.
|
||||
|
@ -402,6 +522,13 @@ struct lsquic_engine_settings {
|
|||
*/
|
||||
int es_honor_prst;
|
||||
|
||||
/**
|
||||
* If set to true value, the library will send Public Reset packets
|
||||
* in response to incoming packets with unknown Connection IDs.
|
||||
* The default is @ref LSQUIC_DF_SEND_PRST.
|
||||
*/
|
||||
int es_send_prst;
|
||||
|
||||
/**
|
||||
* A non-zero value enables internal checks that identify suspected
|
||||
* infinite loops in user @ref on_read and @ref on_write callbacks
|
||||
|
@ -461,6 +588,169 @@ struct lsquic_engine_settings {
|
|||
* is in microseconds; default is @ref LSQUIC_DF_CLOCK_GRANULARITY.
|
||||
*/
|
||||
unsigned es_clock_granularity;
|
||||
|
||||
/* The following settings are specific to IETF QUIC. */
|
||||
/* vvvvvvvvvvv */
|
||||
|
||||
/**
|
||||
* Initial max data.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* Depending on the engine mode, the default value is either
|
||||
* @ref LSQUIC_DF_INIT_MAX_DATA_CLIENT or
|
||||
* @ref LSQUIC_DF_INIT_MAX_DATA_SERVER.
|
||||
*/
|
||||
unsigned es_init_max_data;
|
||||
|
||||
/**
|
||||
* Initial max stream data.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* Depending on the engine mode, the default value is either
|
||||
* @ref LSQUIC_DF_INIT_MAX_STREAM_DATA_CLIENT or
|
||||
* @ref LSQUIC_DF_INIT_MAX_STREAM_DATA_BIDI_REMOTE_SERVER.
|
||||
*/
|
||||
unsigned es_init_max_stream_data_bidi_remote;
|
||||
unsigned es_init_max_stream_data_bidi_local;
|
||||
|
||||
/**
|
||||
* Initial max stream data for unidirectional streams initiated
|
||||
* by remote endpoint.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* Depending on the engine mode, the default value is either
|
||||
* @ref LSQUIC_DF_INIT_MAX_STREAM_DATA_UNI_CLIENT or
|
||||
* @ref LSQUIC_DF_INIT_MAX_STREAM_DATA_UNI_SERVER.
|
||||
*/
|
||||
unsigned es_init_max_stream_data_uni;
|
||||
|
||||
/**
|
||||
* Maximum initial number of bidirectional stream.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_INIT_MAX_STREAMS_BIDI.
|
||||
*/
|
||||
unsigned es_init_max_streams_bidi;
|
||||
|
||||
/**
|
||||
* Maximum initial number of unidirectional stream.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_INIT_MAX_STREAMS_UNI_CLIENT or
|
||||
* @ref LSQUIC_DF_INIT_MAX_STREAM_DATA_UNI_SERVER.
|
||||
*/
|
||||
unsigned es_init_max_streams_uni;
|
||||
|
||||
/**
|
||||
* Idle connection timeout.
|
||||
*
|
||||
* This is a transport parameter.
|
||||
*
|
||||
* (Note: es_idle_conn_to is not reused because it is in microseconds,
|
||||
* which, I now realize, was not a good choice. Since it will be
|
||||
* obsoleted some time after the switchover to IETF QUIC, we do not
|
||||
* have to keep on using strange units.)
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_IDLE_TIMEOUT.
|
||||
*
|
||||
* Maximum value is 600 seconds.
|
||||
*/
|
||||
unsigned es_idle_timeout;
|
||||
|
||||
/**
|
||||
* Ping period. If set to non-zero value, the connection will generate and
|
||||
* send PING frames in the absence of other activity.
|
||||
*
|
||||
* By default, the server does not send PINGs and the period is set to zero.
|
||||
* The client's defaut value is @ref LSQUIC_DF_PING_PERIOD.
|
||||
*/
|
||||
unsigned es_ping_period;
|
||||
|
||||
/**
|
||||
* Source Connection ID length. Only applicable to the IETF QUIC
|
||||
* versions. Valid values are 4 through 18, inclusive.
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_SCID_LEN.
|
||||
*/
|
||||
unsigned es_scid_len;
|
||||
|
||||
/**
|
||||
* Source Connection ID issuance rate. Only applicable to the IETF QUIC
|
||||
* versions. This field is measured in CIDs per minute. Using value 0
|
||||
* indicates that there is no rate limit for CID issuance.
|
||||
*
|
||||
* Default value is @ref LSQUIC_DF_SCID_ISS_RATE.
|
||||
*/
|
||||
unsigned es_scid_iss_rate;
|
||||
|
||||
/**
|
||||
* Maximum size of the QPACK dynamic table that the QPACK decoder will
|
||||
* use.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_QPACK_DEC_MAX_SIZE.
|
||||
*/
|
||||
unsigned es_qpack_dec_max_size;
|
||||
|
||||
/**
|
||||
* Maximum number of blocked streams that the QPACK decoder is willing
|
||||
* to tolerate.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_QPACK_DEC_MAX_BLOCKED.
|
||||
*/
|
||||
unsigned es_qpack_dec_max_blocked;
|
||||
|
||||
/**
|
||||
* Maximum size of the dynamic table that the encoder is willing to use.
|
||||
* The actual size of the dynamic table will not exceed the minimum of
|
||||
* this value and the value advertized by peer.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_QPACK_ENC_MAX_SIZE.
|
||||
*/
|
||||
unsigned es_qpack_enc_max_size;
|
||||
|
||||
/**
|
||||
* Maximum number of blocked streams that the QPACK encoder is willing
|
||||
* to risk. The actual number of blocked streams will not exceed the
|
||||
* minimum of this value and the value advertized by peer.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_QPACK_ENC_MAX_BLOCKED.
|
||||
*/
|
||||
unsigned es_qpack_enc_max_blocked;
|
||||
|
||||
/**
|
||||
* Enable ECN support.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_ECN
|
||||
*/
|
||||
int es_ecn;
|
||||
|
||||
/**
|
||||
* Number of HTTP/3 priorify placeholders.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_H3_PLACEHOLDERS
|
||||
*/
|
||||
unsigned es_h3_placeholders;
|
||||
|
||||
/**
|
||||
* Allow peer to migrate connection.
|
||||
*
|
||||
* The default is @ref LSQUIC_DF_ALLOW_MIGRATION
|
||||
*/
|
||||
int es_allow_migration;
|
||||
|
||||
/**
|
||||
* Congestion control algorithm to use.
|
||||
*
|
||||
* 0: Use default (@ref LSQUIC_DF_CC_ALGO)
|
||||
* 1: Cubic
|
||||
* 2: BBR
|
||||
*/
|
||||
unsigned es_cc_algo;
|
||||
};
|
||||
|
||||
/* Initialize `settings' to default values */
|
||||
|
@ -491,11 +781,12 @@ lsquic_engine_check_settings (const struct lsquic_engine_settings *settings,
|
|||
|
||||
struct lsquic_out_spec
|
||||
{
|
||||
const unsigned char *buf;
|
||||
size_t sz;
|
||||
struct iovec *iov;
|
||||
size_t iovlen;
|
||||
const struct sockaddr *local_sa;
|
||||
const struct sockaddr *dest_sa;
|
||||
void *peer_ctx;
|
||||
int ecn; /* Valid values are 0 - 3. See RFC 3168 */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -511,6 +802,41 @@ typedef int (*lsquic_packets_out_f)(
|
|||
unsigned n_packets_out
|
||||
);
|
||||
|
||||
/**
|
||||
* The shared hash interface is used to share data between multiple LSQUIC
|
||||
* instances.
|
||||
*/
|
||||
struct lsquic_shared_hash_if
|
||||
{
|
||||
/**
|
||||
* If you want your item to never expire, set `expiry' to zero.
|
||||
* Returns 0 on success, -1 on failure.
|
||||
*
|
||||
* If inserted successfully, `free()' will be called on `data' and 'key'
|
||||
* pointer when the element is deleted, whether due to expiration
|
||||
* or explicit deletion.
|
||||
*/
|
||||
int (*shi_insert)(void *shi_ctx, void *key, unsigned key_sz,
|
||||
void *data, unsigned data_sz, time_t expiry);
|
||||
/**
|
||||
* Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
int (*shi_delete)(void *shi_ctx, const void *key, unsigned key_sz);
|
||||
|
||||
/**
|
||||
* `data' is pointed to the result and `data_sz' is set to the
|
||||
* object size. The implementation may choose to copy the object
|
||||
* into buffer pointed to by `data', so you should have it ready.
|
||||
*
|
||||
* @retval 1 found.
|
||||
* @retval 0 not found.
|
||||
* @retval -1 error (perhaps not enough room in `data' if copy was
|
||||
* attempted).
|
||||
*/
|
||||
int (*shi_lookup)(void *shi_ctx, const void *key, unsigned key_sz,
|
||||
void **data, unsigned *data_sz);
|
||||
};
|
||||
|
||||
/**
|
||||
* The packet out memory interface is used by LSQUIC to get buffers to
|
||||
* which outgoing packets will be written before they are passed to
|
||||
|
@ -539,6 +865,9 @@ struct lsquic_packout_mem_if
|
|||
char is_ipv6);
|
||||
};
|
||||
|
||||
typedef void (*lsquic_cids_update_f)(void *ctx, void **peer_ctx,
|
||||
const lsquic_cid_t *cids, unsigned n_cids);
|
||||
|
||||
struct stack_st_X509;
|
||||
|
||||
/**
|
||||
|
@ -554,7 +883,8 @@ enum lsquic_header_status
|
|||
LSQUIC_HDR_ERR_INCOMPL_REQ_PSDO_HDR,
|
||||
/** Unnecessary request pseudo-header present in the response */
|
||||
LSQUIC_HDR_ERR_UNNEC_REQ_PSDO_HDR,
|
||||
LSQUIC_HDR_ERR_BAD_REQ_HEADER = LSQUIC_HDR_ERR_UNNEC_REQ_PSDO_HDR,
|
||||
/** Prohibited header in request */
|
||||
LSQUIC_HDR_ERR_BAD_REQ_HEADER,
|
||||
/** Not all response pseudo-headers are present */
|
||||
LSQUIC_HDR_ERR_INCOMPL_RESP_PSDO_HDR,
|
||||
/** Unnecessary response pseudo-header present in the response. */
|
||||
|
@ -590,9 +920,12 @@ struct lsquic_hset_if
|
|||
* `hdr_set' is the header set object returned by
|
||||
* @ref hsi_create_header_set().
|
||||
*
|
||||
* `name_idx' is set to the index in the HPACK static table whose entry's
|
||||
* name element matches `name'. If there is no such match, `name_idx' is
|
||||
* set to zero.
|
||||
* `name_idx' is set to the index in either the HPACK or QPACK static table
|
||||
* whose entry's name element matches `name'. The values are as follows:
|
||||
* - if there is no such match, `name_idx' is set to zero;
|
||||
* - if HPACK is used, the value is between 1 and 61; and
|
||||
* - if QPACK is used, the value is 62+ (subtract 62 to get the QPACK
|
||||
* static table index).
|
||||
*
|
||||
* If `name' is NULL, this means that no more header are going to be
|
||||
* added to the set.
|
||||
|
@ -608,6 +941,26 @@ struct lsquic_hset_if
|
|||
void (*hsi_discard_header_set)(void *hdr_set);
|
||||
};
|
||||
|
||||
/**
|
||||
* SSL keylog interface.
|
||||
*/
|
||||
struct lsquic_keylog_if
|
||||
{
|
||||
/** Return keylog handle or NULL if no key logging is desired */
|
||||
void * (*kli_open) (void *keylog_ctx, lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* Log line. The first argument is the pointer returned by
|
||||
* @ref kli_open.
|
||||
*/
|
||||
void (*kli_log_line) (void *handle, const char *line);
|
||||
|
||||
/**
|
||||
* Close handle.
|
||||
*/
|
||||
void (*kli_close) (void *handle);
|
||||
};
|
||||
|
||||
/* TODO: describe this important data structure */
|
||||
typedef struct lsquic_engine_api
|
||||
{
|
||||
|
@ -616,11 +969,27 @@ typedef struct lsquic_engine_api
|
|||
void *ea_stream_if_ctx;
|
||||
lsquic_packets_out_f ea_packets_out;
|
||||
void *ea_packets_out_ctx;
|
||||
lsquic_lookup_cert_f ea_lookup_cert;
|
||||
void *ea_cert_lu_ctx;
|
||||
struct ssl_ctx_st * (*ea_get_ssl_ctx)(void *peer_ctx);
|
||||
/**
|
||||
* Shared hash interface is optional. If set to zero, performance of
|
||||
* multiple LSQUIC instances will be degraded.
|
||||
*/
|
||||
const struct lsquic_shared_hash_if *ea_shi;
|
||||
void *ea_shi_ctx;
|
||||
/**
|
||||
* Memory interface is optional.
|
||||
*/
|
||||
const struct lsquic_packout_mem_if *ea_pmi;
|
||||
void *ea_pmi_ctx;
|
||||
/**
|
||||
* Optional interface to report new and old source connection IDs.
|
||||
*/
|
||||
lsquic_cids_update_f ea_new_scids;
|
||||
lsquic_cids_update_f ea_live_scids;
|
||||
lsquic_cids_update_f ea_old_scids;
|
||||
void *ea_cids_update_ctx;
|
||||
/**
|
||||
* Function to verify server certificate. The chain contains at least
|
||||
* one element. The first element in the chain is the server
|
||||
|
@ -650,6 +1019,12 @@ typedef struct lsquic_engine_api
|
|||
*/
|
||||
void /* FILE, really */ *ea_stats_fh;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Optional SSL key logging interface.
|
||||
*/
|
||||
const struct lsquic_keylog_if *ea_keylog_if;
|
||||
void *ea_keylog_ctx;
|
||||
} lsquic_engine_api_t;
|
||||
|
||||
/**
|
||||
|
@ -672,7 +1047,9 @@ lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *local_sa,
|
|||
const struct sockaddr *peer_sa,
|
||||
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len,
|
||||
/** Resumption token: optional */
|
||||
const unsigned char *token, size_t token_sz);
|
||||
|
||||
/**
|
||||
* Pass incoming packet to the QUIC engine. This function can be called
|
||||
|
@ -681,6 +1058,10 @@ lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *local_sa,
|
|||
*
|
||||
* @retval 0 Packet was processed by a real connection.
|
||||
*
|
||||
* @retval 1 Packet was handled successfully, but not by a connection.
|
||||
* This may happen with version negotiation and public reset
|
||||
* packets as well as some packets that may be ignored.
|
||||
*
|
||||
* @retval -1 Some error occurred. Possible reasons are invalid packet
|
||||
* size or failure to allocate memory.
|
||||
*/
|
||||
|
@ -688,7 +1069,7 @@ int
|
|||
lsquic_engine_packet_in (lsquic_engine_t *,
|
||||
const unsigned char *packet_in_data, size_t packet_in_size,
|
||||
const struct sockaddr *sa_local, const struct sockaddr *sa_peer,
|
||||
void *peer_ctx);
|
||||
void *peer_ctx, int ecn);
|
||||
|
||||
/**
|
||||
* Process tickable connections. This function must be called often enough so
|
||||
|
@ -722,7 +1103,8 @@ lsquic_engine_destroy (lsquic_engine_t *);
|
|||
unsigned
|
||||
lsquic_conn_n_avail_streams (const lsquic_conn_t *);
|
||||
|
||||
void lsquic_conn_make_stream(lsquic_conn_t *);
|
||||
void
|
||||
lsquic_conn_make_stream (lsquic_conn_t *);
|
||||
|
||||
/** Return number of delayed streams currently pending */
|
||||
unsigned
|
||||
|
@ -735,21 +1117,48 @@ lsquic_conn_cancel_pending_streams (lsquic_conn_t *, unsigned n);
|
|||
/**
|
||||
* Mark connection as going away: send GOAWAY frame and do not accept
|
||||
* any more incoming streams, nor generate streams of our own.
|
||||
*
|
||||
* In the server mode, of course, we can call this function just fine in both
|
||||
* Google and IETF QUIC.
|
||||
*
|
||||
* In client mode, calling this function in for an IETF QUIC connection does
|
||||
* not do anything, as the client MUST NOT send GOAWAY frames.
|
||||
* See [draft-ietf-quic-http-17] Section 4.2.7.
|
||||
*/
|
||||
void
|
||||
lsquic_conn_going_away(lsquic_conn_t *conn);
|
||||
lsquic_conn_going_away (lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* This forces connection close. on_conn_closed and on_close callbacks
|
||||
* will be called.
|
||||
*/
|
||||
void lsquic_conn_close(lsquic_conn_t *conn);
|
||||
void
|
||||
lsquic_conn_close (lsquic_conn_t *);
|
||||
|
||||
int lsquic_stream_wantread(lsquic_stream_t *s, int is_want);
|
||||
ssize_t lsquic_stream_read(lsquic_stream_t *s, void *buf, size_t len);
|
||||
ssize_t lsquic_stream_readv(lsquic_stream_t *s, const struct iovec *,
|
||||
int iovcnt);
|
||||
|
||||
/**
|
||||
* This function allows user-supplied callback to read the stream contents.
|
||||
* It is meant to be used for zero-copy stream processing.
|
||||
*/
|
||||
ssize_t
|
||||
lsquic_stream_readf (lsquic_stream_t *s,
|
||||
/**
|
||||
* The callback takes four parameters:
|
||||
* - Pointer to user-supplied context;
|
||||
* - Pointer to the data;
|
||||
* - Data size (can be zero); and
|
||||
* - Indicator whether the FIN follows the data.
|
||||
*
|
||||
* The callback returns number of bytes processed. If this number is zero
|
||||
* or is smaller than `len', reading from stream stops.
|
||||
*/
|
||||
size_t (*readf)(void *ctx, const unsigned char *buf, size_t len, int fin),
|
||||
void *ctx);
|
||||
|
||||
int lsquic_stream_wantwrite(lsquic_stream_t *s, int is_want);
|
||||
|
||||
/**
|
||||
|
@ -838,7 +1247,33 @@ int lsquic_stream_send_headers(lsquic_stream_t *s,
|
|||
void *
|
||||
lsquic_stream_get_hset (lsquic_stream_t *);
|
||||
|
||||
int lsquic_conn_is_push_enabled(lsquic_conn_t *c);
|
||||
/**
|
||||
* A server may push a stream. This call creates a new stream in reference
|
||||
* to stream `s'. It will behave as if the client made a request: it will
|
||||
* trigger on_new_stream() event and it can be used as a regular client-
|
||||
* initiated stream.
|
||||
*
|
||||
* If `hdr_set' is not set, it is generated by using `ea_hsi_if' callbacks.
|
||||
* In either case, the header set object belongs to the connection. The
|
||||
* user is not to free this object until (@ref hsi_discard_header_set) is
|
||||
* called.
|
||||
*
|
||||
* @retval 0 Stream pushed successfully.
|
||||
* @retval 1 Stream push failed because it is disabled or because we hit
|
||||
* stream limit or connection is going away.
|
||||
* @retval -1 Stream push failed because of an internal error.
|
||||
*/
|
||||
int
|
||||
lsquic_conn_push_stream (lsquic_conn_t *c, void *hdr_set, lsquic_stream_t *s,
|
||||
const struct iovec* url, const struct iovec* authority,
|
||||
const lsquic_http_headers_t *headers);
|
||||
|
||||
/**
|
||||
* Only makes sense in server mode: the client cannot push a stream and this
|
||||
* function always returns false in client mode.
|
||||
*/
|
||||
int
|
||||
lsquic_conn_is_push_enabled (lsquic_conn_t *);
|
||||
|
||||
/** Possible values for how are 0, 1, and 2. See shutdown(2). */
|
||||
int lsquic_stream_shutdown(lsquic_stream_t *s, int how);
|
||||
|
@ -857,16 +1292,8 @@ int lsquic_stream_close(lsquic_stream_t *s);
|
|||
struct stack_st_X509 *
|
||||
lsquic_conn_get_server_cert_chain (lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* Get server config zero_rtt from the encryption session.
|
||||
* Returns the number of bytes written to the zero_rtt.
|
||||
*/
|
||||
ssize_t
|
||||
lsquic_conn_get_zero_rtt(const lsquic_conn_t *,
|
||||
unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
|
||||
/** Returns ID of the stream */
|
||||
uint32_t
|
||||
lsquic_stream_id_t
|
||||
lsquic_stream_id (const lsquic_stream_t *s);
|
||||
|
||||
/**
|
||||
|
@ -880,6 +1307,13 @@ lsquic_stream_get_ctx (const lsquic_stream_t *s);
|
|||
int
|
||||
lsquic_stream_is_pushed (const lsquic_stream_t *s);
|
||||
|
||||
/**
|
||||
* Returns true if this stream was rejected, false otherwise. Use this as
|
||||
* an aid to distinguish between errors.
|
||||
*/
|
||||
int
|
||||
lsquic_stream_is_rejected (const lsquic_stream_t *s);
|
||||
|
||||
/**
|
||||
* Refuse pushed stream. Call it from @ref on_new_stream.
|
||||
*
|
||||
|
@ -902,8 +1336,8 @@ lsquic_stream_refuse_push (lsquic_stream_t *s);
|
|||
* @retval -1 This is not a pushed stream.
|
||||
*/
|
||||
int
|
||||
lsquic_stream_push_info (const lsquic_stream_t *, uint32_t *ref_stream_id,
|
||||
void **hdr_set);
|
||||
lsquic_stream_push_info (const lsquic_stream_t *,
|
||||
lsquic_stream_id_t *ref_stream_id, void **hdr_set);
|
||||
|
||||
/** Return current priority of the stream */
|
||||
unsigned lsquic_stream_priority (const lsquic_stream_t *s);
|
||||
|
@ -923,21 +1357,22 @@ int lsquic_stream_set_priority (lsquic_stream_t *s, unsigned priority);
|
|||
lsquic_conn_t * lsquic_stream_conn(const lsquic_stream_t *s);
|
||||
|
||||
lsquic_stream_t *
|
||||
lsquic_conn_get_stream_by_id (lsquic_conn_t *c, uint32_t stream_id);
|
||||
lsquic_conn_get_stream_by_id (lsquic_conn_t *c, lsquic_stream_id_t stream_id);
|
||||
|
||||
/** Get connection ID */
|
||||
lsquic_cid_t
|
||||
const lsquic_cid_t *
|
||||
lsquic_conn_id (const lsquic_conn_t *c);
|
||||
|
||||
/** Get pointer to the engine */
|
||||
lsquic_engine_t *
|
||||
lsquic_conn_get_engine (lsquic_conn_t *c);
|
||||
|
||||
int lsquic_conn_get_sockaddr(const lsquic_conn_t *c,
|
||||
int
|
||||
lsquic_conn_get_sockaddr(lsquic_conn_t *c,
|
||||
const struct sockaddr **local, const struct sockaddr **peer);
|
||||
|
||||
struct lsquic_logger_if {
|
||||
int (*vprintf)(void *logger_ctx, const char *fmt, va_list args);
|
||||
int (*log_buf)(void *logger_ctx, const char *buf, size_t len);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1058,31 +1493,98 @@ lsquic_global_cleanup (void);
|
|||
enum lsquic_version
|
||||
lsquic_conn_quic_version (const lsquic_conn_t *c);
|
||||
|
||||
/* Return keysize or -1 on error */
|
||||
int
|
||||
lsquic_conn_crypto_keysize (const lsquic_conn_t *c);
|
||||
|
||||
/* Return algorithm keysize or -1 on error */
|
||||
int
|
||||
lsquic_conn_crypto_alg_keysize (const lsquic_conn_t *c);
|
||||
|
||||
enum lsquic_crypto_ver
|
||||
{
|
||||
LSQ_CRY_QUIC,
|
||||
LSQ_CRY_TLSv13,
|
||||
};
|
||||
|
||||
enum lsquic_crypto_ver
|
||||
lsquic_conn_crypto_ver (const lsquic_conn_t *c);
|
||||
|
||||
/* Return cipher or NULL on error */
|
||||
const char *
|
||||
lsquic_conn_crypto_cipher (const lsquic_conn_t *c);
|
||||
|
||||
/** Translate string QUIC version to LSQUIC QUIC version representation */
|
||||
enum lsquic_version
|
||||
lsquic_str2ver (const char *str, size_t len);
|
||||
|
||||
/**
|
||||
* This function closes all mini connections and marks all full connection
|
||||
* as going away. In server mode, this also causes the engine to stop
|
||||
* creating new connections.
|
||||
*/
|
||||
void
|
||||
lsquic_engine_cooldown (lsquic_engine_t *);
|
||||
|
||||
struct ssl_st *
|
||||
lsquic_hsk_getssl(lsquic_conn_t *conn);
|
||||
|
||||
/**
|
||||
* Get user-supplied context associated with the connection.
|
||||
*/
|
||||
lsquic_conn_ctx_t *
|
||||
lsquic_conn_get_ctx (const lsquic_conn_t *c);
|
||||
lsquic_conn_get_ctx (const lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* Set user-supplied context associated with the connection.
|
||||
*/
|
||||
void lsquic_conn_set_ctx (lsquic_conn_t *c, lsquic_conn_ctx_t *h);
|
||||
void
|
||||
lsquic_conn_set_ctx (lsquic_conn_t *, lsquic_conn_ctx_t *);
|
||||
|
||||
/**
|
||||
* Get peer context associated with the connection.
|
||||
*/
|
||||
void *lsquic_conn_get_peer_ctx( const lsquic_conn_t *lconn);
|
||||
void *
|
||||
lsquic_conn_get_peer_ctx (lsquic_conn_t *, const struct sockaddr *local_sa);
|
||||
|
||||
/**
|
||||
* Abort connection.
|
||||
*/
|
||||
void
|
||||
lsquic_conn_abort (lsquic_conn_t *c);
|
||||
lsquic_conn_abort (lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* Helper function: convert list of versions as specified in the argument
|
||||
* bitmask to string that can be included as argument to "v=" part of the
|
||||
* Alt-Svc header.
|
||||
*
|
||||
* For example (1<<LSQVER_037)|(1<<LSQVER_038) => "37,38"
|
||||
*
|
||||
* This is only applicable to Google QUIC versions.
|
||||
*/
|
||||
const char *
|
||||
lsquic_get_alt_svc_versions (unsigned versions);
|
||||
|
||||
/**
|
||||
* Return a NULL-terminated list of HTTP/3 ALPNs, e.g "h3-17", "h3-18", "h3".
|
||||
*/
|
||||
const char *const *
|
||||
lsquic_get_h3_alpns (unsigned versions);
|
||||
|
||||
/**
|
||||
* Returns true if provided buffer could be a valid handshake-stage packet,
|
||||
* false otherwise. Do not call this function if a connection has already
|
||||
* been established: it will return incorrect result.
|
||||
*/
|
||||
int
|
||||
lsquic_is_valid_hs_packet (lsquic_engine_t *, const unsigned char *, size_t);
|
||||
|
||||
/**
|
||||
* Parse cid from packet stored in `buf' and store it to `cid'. Returns 0
|
||||
* on success and -1 on failure.
|
||||
*/
|
||||
int
|
||||
lsquic_cid_from_packet (const unsigned char *, size_t bufsz, lsquic_cid_t *cid);
|
||||
|
||||
/**
|
||||
* Returns true if there are connections to be processed, false otherwise.
|
||||
|
|
|
@ -9,10 +9,30 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_CID_LEN 20
|
||||
#define GQUIC_CID_LEN 8
|
||||
|
||||
/**
|
||||
* Connection ID
|
||||
*/
|
||||
typedef uint64_t lsquic_cid_t;
|
||||
typedef struct lsquic_cid
|
||||
{
|
||||
uint_fast8_t len;
|
||||
union {
|
||||
uint8_t buf[MAX_CID_LEN];
|
||||
uint64_t id;
|
||||
} u_cid;
|
||||
#define idbuf u_cid.buf
|
||||
}
|
||||
lsquic_cid_t;
|
||||
|
||||
|
||||
#define LSQUIC_CIDS_EQ(a, b) ((a)->len == 8 ? \
|
||||
(b)->len == 8 && (a)->u_cid.id == (b)->u_cid.id : \
|
||||
(a)->len == (b)->len && 0 == memcmp((a)->idbuf, (b)->idbuf, (a)->len))
|
||||
|
||||
/** Stream ID */
|
||||
typedef uint64_t lsquic_stream_id_t;
|
||||
|
||||
/** LSQUIC engine */
|
||||
typedef struct lsquic_engine lsquic_engine_t;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
commit 46f967bfe44a80bb4bc0e7e9d4b03de3f91d03fb
|
||||
Author: Dmitri Tikhonov <dtikhonov@litespeedtech.com>
|
||||
Date: Fri Feb 22 11:51:21 2019 -0500
|
||||
|
||||
Add support for QUIC's use of max_early_data_size
|
||||
|
||||
The server MUST set this value to 0xFFFFFFFF in NewSessionTicket,
|
||||
while the client should be able to examine it in order to verify
|
||||
this requirement.
|
||||
|
||||
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
|
||||
index 59b9eac..2e6cefb 100644
|
||||
--- a/include/openssl/ssl.h
|
||||
+++ b/include/openssl/ssl.h
|
||||
@@ -1744,6 +1744,11 @@ OPENSSL_EXPORT int SSL_SESSION_set_ticket(SSL_SESSION *session,
|
||||
OPENSSL_EXPORT uint32_t
|
||||
SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session);
|
||||
|
||||
+// SSL_SESSION_get_max_early_data_size returns ticket max early data size of
|
||||
+// |session| in bytes or zero if none was set.
|
||||
+OPENSSL_EXPORT uint32_t
|
||||
+SSL_SESSION_get_max_early_data_size(const SSL_SESSION *session);
|
||||
+
|
||||
// SSL_SESSION_get0_cipher returns the cipher negotiated by the connection which
|
||||
// established |session|.
|
||||
//
|
||||
diff --git a/ssl/internal.h b/ssl/internal.h
|
||||
index 1116bad..98dcfa3 100644
|
||||
--- a/ssl/internal.h
|
||||
+++ b/ssl/internal.h
|
||||
@@ -2506,6 +2506,10 @@ struct SSL_CONFIG {
|
||||
// kMaxEarlyDataSkipped in tls_record.c, which is measured in ciphertext.
|
||||
static const size_t kMaxEarlyDataAccepted = 14336;
|
||||
|
||||
+// kQUICMaxEarlyData is the value to which the max_early_data_size field
|
||||
+// in a NewSessionTicket must be set when sent by a QUIC server.
|
||||
+static const uint32_t kQUICMaxEarlyData = 0xffffffffu;
|
||||
+
|
||||
UniquePtr<CERT> ssl_cert_dup(CERT *cert);
|
||||
void ssl_cert_clear_certs(CERT *cert);
|
||||
bool ssl_set_cert(CERT *cert, UniquePtr<CRYPTO_BUFFER> buffer);
|
||||
diff --git a/ssl/ssl_session.cc b/ssl/ssl_session.cc
|
||||
index 927dd1b..cd5b5bb 100644
|
||||
--- a/ssl/ssl_session.cc
|
||||
+++ b/ssl/ssl_session.cc
|
||||
@@ -1025,6 +1025,10 @@ uint32_t SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *session) {
|
||||
return session->ticket_lifetime_hint;
|
||||
}
|
||||
|
||||
+uint32_t SSL_SESSION_get_max_early_data_size(const SSL_SESSION *session) {
|
||||
+ return session->ticket_max_early_data;
|
||||
+}
|
||||
+
|
||||
const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *session) {
|
||||
return session->cipher;
|
||||
}
|
||||
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
|
||||
index 562fecb..4edd0ef 100644
|
||||
--- a/ssl/tls13_server.cc
|
||||
+++ b/ssl/tls13_server.cc
|
||||
@@ -179,7 +179,11 @@ static bool add_new_session_tickets(SSL_HANDSHAKE *hs, bool *out_sent_tickets) {
|
||||
}
|
||||
session->ticket_age_add_valid = true;
|
||||
if (ssl->enable_early_data) {
|
||||
- session->ticket_max_early_data = kMaxEarlyDataAccepted;
|
||||
+ if (ssl->quic_method == nullptr) {
|
||||
+ session->ticket_max_early_data = kMaxEarlyDataAccepted;
|
||||
+ } else {
|
||||
+ session->ticket_max_early_data = kQUICMaxEarlyData;
|
||||
+ }
|
||||
}
|
||||
|
||||
static_assert(kNumTickets < 256, "Too many tickets");
|
|
@ -1,67 +1,109 @@
|
|||
# Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE.
|
||||
SET(lsquic_STAT_SRCS
|
||||
ls-qpack/lsqpack.c
|
||||
lsquic_alarmset.c
|
||||
lsquic_conn.c
|
||||
lsquic_full_conn.c
|
||||
lsquic_arr.c
|
||||
lsquic_attq.c
|
||||
lsquic_bbr.c
|
||||
lsquic_buf.c
|
||||
lsquic_bw_sampler.c
|
||||
lsquic_cfcw.c
|
||||
lsquic_chsk_stream.c
|
||||
lsquic_engine.c
|
||||
lsquic_parse_gquic_common.c
|
||||
lsquic_parse_iquic_common.c
|
||||
lsquic_parse_common.c
|
||||
lsquic_parse_gquic_le.c
|
||||
lsquic_parse_gquic_be.c
|
||||
lsquic_packet_in.c
|
||||
lsquic_packet_out.c
|
||||
lsquic_conn.c
|
||||
lsquic_crt_compress.c
|
||||
lsquic_crypto.c
|
||||
lsquic_cubic.c
|
||||
lsquic_di_error.c
|
||||
lsquic_di_hash.c
|
||||
lsquic_di_nocopy.c
|
||||
lsquic_enc_sess_common.c
|
||||
lsquic_enc_sess_ietf.c
|
||||
lsquic_eng_hist.c
|
||||
lsquic_engine.c
|
||||
lsquic_ev_log.c
|
||||
lsquic_frab_list.c
|
||||
lsquic_frame_common.c
|
||||
lsquic_frame_reader.c
|
||||
lsquic_frame_writer.c
|
||||
lsquic_full_conn.c
|
||||
lsquic_full_conn_ietf.c
|
||||
lsquic_global.c
|
||||
lsquic_h3_prio.c
|
||||
lsquic_handshake.c
|
||||
lsquic_hash.c
|
||||
lsquic_hcsi_reader.c
|
||||
lsquic_hcso_writer.c
|
||||
lsquic_headers_stream.c
|
||||
lsquic_hkdf.c
|
||||
lsquic_hq.c
|
||||
lsquic_hspack_valid.c
|
||||
lsquic_http1x_if.c
|
||||
lsquic_logger.c
|
||||
lsquic_malo.c
|
||||
lsquic_min_heap.c
|
||||
lsquic_mini_conn.c
|
||||
lsquic_mini_conn_ietf.c
|
||||
lsquic_minmax.c
|
||||
lsquic_mm.c
|
||||
lsquic_pacer.c
|
||||
lsquic_packet_common.c
|
||||
lsquic_packet_gquic.c
|
||||
lsquic_packet_in.c
|
||||
lsquic_packet_out.c
|
||||
lsquic_packints.c
|
||||
lsquic_parse_Q046.c
|
||||
lsquic_parse_common.c
|
||||
lsquic_parse_gquic_be.c
|
||||
lsquic_parse_gquic_common.c
|
||||
lsquic_parse_ietf_v1.c
|
||||
lsquic_parse_iquic_common.c
|
||||
lsquic_pr_queue.c
|
||||
lsquic_purga.c
|
||||
lsquic_qdec_hdl.c
|
||||
lsquic_qenc_hdl.c
|
||||
lsquic_qlog.c
|
||||
lsquic_rechist.c
|
||||
lsquic_rtt.c
|
||||
lsquic_send_ctl.c
|
||||
lsquic_senhist.c
|
||||
lsquic_cfcw.c
|
||||
lsquic_sfcw.c
|
||||
lsquic_stream.c
|
||||
lsquic_util.c
|
||||
lsquic_cubic.c
|
||||
lsquic_set.c
|
||||
lsquic_headers_stream.c
|
||||
lsquic_frame_reader.c
|
||||
lsquic_frame_writer.c
|
||||
lsquic_crt_compress.c
|
||||
lsquic_conn_hash.c
|
||||
lsquic_eng_hist.c
|
||||
lsquic_sfcw.c
|
||||
lsquic_shsk_stream.c
|
||||
lsquic_spi.c
|
||||
lsquic_di_nocopy.c
|
||||
lsquic_di_hash.c
|
||||
lsquic_di_error.c
|
||||
lsquic_global.c
|
||||
lsquic_packet_common.c
|
||||
lsquic_qlog.c
|
||||
lsquic_ev_log.c
|
||||
lsquic_frame_common.c
|
||||
lsquic_packints.c
|
||||
lsquic_version.c
|
||||
lsquic_pacer.c
|
||||
lsquic_attq.c
|
||||
lsquic_stock_shi.c
|
||||
lsquic_str.c
|
||||
lsquic_arr.c
|
||||
lsquic_hash.c
|
||||
lsquic_xxhash.c
|
||||
lsquic_buf.c
|
||||
lsquic_min_heap.c
|
||||
../lshpack/lshpack.c
|
||||
lsquic_parse_Q044.c
|
||||
lsquic_parse_Q046.c
|
||||
lsquic_http1x_if.c
|
||||
lsquic_stream.c
|
||||
lsquic_tokgen.c
|
||||
lsquic_trans_params.c
|
||||
lsquic_util.c
|
||||
lsquic_varint.c
|
||||
lsquic_version.c
|
||||
)
|
||||
|
||||
set_source_files_properties(ls-qpack/lsqpack.c PROPERTIES COMPILE_FLAGS -Wno-uninitialized)
|
||||
|
||||
include_directories(ls-qpack)
|
||||
|
||||
IF(PROJECT_NAME STREQUAL "openlitespeed")
|
||||
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/spdy)
|
||||
ELSE()
|
||||
SET(lsquic_STAT_SRCS ${lsquic_STAT_SRCS}
|
||||
lsquic_xxhash.c
|
||||
../lshpack/lshpack.c
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/liblsquic/lsquic_versions_to_string.c
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/src/liblsquic/gen-verstrs
|
||||
ARGS ${PROJECT_SOURCE_DIR}/include/lsquic.h ${PROJECT_SOURCE_DIR}/src/liblsquic/lsquic_versions_to_string.c
|
||||
DEPENDS ./gen-verstrs ${PROJECT_SOURCE_DIR}/include/lsquic.h
|
||||
)
|
||||
SET(lsquic_STAT_SRCS ${lsquic_STAT_SRCS} lsquic_versions_to_string.c)
|
||||
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXXH_HEADER_NAME=\\\"lsquic_xxhash.h\\\"")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLSQPACK_ENC_LOGGER_HEADER=\\\"lsquic_qpack_enc_logger.h\\\"")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLSQPACK_DEC_LOGGER_HEADER=\\\"lsquic_qpack_dec_logger.h\\\"")
|
||||
|
||||
add_library(lsquic STATIC ${lsquic_STAT_SRCS} )
|
||||
|
||||
link_directories(${PROJECT_SOURCE_DIR}/ssl/ /usr/local/lib)
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/env perl
|
||||
#
|
||||
# Generate C file that contains version strings
|
||||
|
||||
($header # This is lsquic.h that contains version enum which we parse
|
||||
, $outfile # This is destination C file
|
||||
) = @ARGV;
|
||||
|
||||
open HEADER, $header
|
||||
or die "cannot open $header for reading: $!";
|
||||
open OUT, ">$outfile"
|
||||
or die "cannot open $outfile for writing: $!";
|
||||
|
||||
while (<HEADER>) {
|
||||
if (/^enum lsquic_version$/ .. /^}/) {
|
||||
if (/^\s*(LSQVER_0*(\d+)),\s*$/ && $1 ne 'LSQVER_098') {
|
||||
push @enums, $1;
|
||||
push @versions, $2;
|
||||
}
|
||||
if (/^\s*LSQVER_ID(\d+)\b/) {
|
||||
push @draft_versions, $1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close HEADER;
|
||||
|
||||
$timestamp = localtime;
|
||||
|
||||
print OUT <<C_CODE;
|
||||
/*
|
||||
* Auto-generated by $0 on $timestamp
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
|
||||
struct lsquic_engine;
|
||||
|
||||
static const char *const versions_to_string[ 1 << N_LSQVER ] = {
|
||||
C_CODE
|
||||
|
||||
$max_mask = (1 << @versions) - 1;
|
||||
|
||||
for ($mask = 0; $mask <= $max_mask; ++$mask) {
|
||||
my @indexes;
|
||||
for ($i = 0; $i < @versions; ++$i) {
|
||||
if ($mask & (1 << $i)) {
|
||||
push @indexes, $i;
|
||||
}
|
||||
}
|
||||
print OUT " [",
|
||||
join('|', map "(1<<$_)", @enums[@indexes]) || 0,
|
||||
"] = \"",
|
||||
join(',', @versions[@indexes]),
|
||||
"\",\n";
|
||||
}
|
||||
|
||||
$enums = join '|', map "(1<<$_)", sort @enums;
|
||||
|
||||
print OUT <<"C_CODE";
|
||||
};
|
||||
|
||||
|
||||
const char *
|
||||
lsquic_get_alt_svc_versions (unsigned versions)
|
||||
{
|
||||
/* Limit to versions in versions_to_string: */
|
||||
versions &= ($enums);
|
||||
return versions_to_string[ versions ];
|
||||
}
|
||||
|
||||
C_CODE
|
||||
|
||||
|
||||
$draft_version_count = @draft_versions;
|
||||
$draft_version_count_and_null = $draft_version_count + 1;
|
||||
|
||||
print OUT <<"C_CODE";
|
||||
static const struct {
|
||||
unsigned versions;
|
||||
const char *h3_alpns[$draft_version_count_and_null];
|
||||
} vers_2_h3_alnps[] = {
|
||||
C_CODE
|
||||
|
||||
for ($i = 0; $i < (1 << @draft_versions); ++$i)
|
||||
{
|
||||
my @vers;
|
||||
for ($j = 0; $j < @draft_versions; ++$j)
|
||||
{
|
||||
if ($i & (1 << $j))
|
||||
{
|
||||
push @vers, $draft_versions[$j];
|
||||
}
|
||||
}
|
||||
print OUT " {", join("|", 0, map "(1<<LSQVER_ID$_)", @vers), ", ",
|
||||
"{ ", join(", ", map "\"h3-$_\"", @vers), @vers ? ", " : "", "NULL }},\n";
|
||||
}
|
||||
|
||||
$draft_versions = join("|", map "(1<<LSQVER_ID$_)", @draft_versions);
|
||||
|
||||
print OUT <<"C_CODE";
|
||||
};
|
||||
|
||||
const char *const *
|
||||
lsquic_get_h3_alpns (unsigned versions)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
versions &= $draft_versions;
|
||||
|
||||
for (i = 0; i < sizeof(vers_2_h3_alnps) / sizeof(vers_2_h3_alnps[0]); ++i)
|
||||
if (versions == vers_2_h3_alnps[i].versions)
|
||||
return vers_2_h3_alnps[i].h3_alpns;
|
||||
|
||||
assert(0);
|
||||
return vers_2_h3_alnps[0].h3_alpns;
|
||||
}
|
||||
C_CODE
|
||||
|
||||
close OUT;
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9a7952e41acad045ea7a6d4935b976872d73c111
|
|
@ -7,17 +7,18 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_alarmset.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_ALARMSET
|
||||
#define LSQUIC_LOG_CONN_ID alset->as_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(alset->as_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
void
|
||||
lsquic_alarmset_init (lsquic_alarmset_t *alset, lsquic_cid_t cid)
|
||||
lsquic_alarmset_init (lsquic_alarmset_t *alset, const struct lsquic_conn *conn)
|
||||
{
|
||||
alset->as_cid = cid;
|
||||
alset->as_conn = conn;
|
||||
alset->as_armed_set = 0;
|
||||
}
|
||||
|
||||
|
@ -31,6 +32,24 @@ lsquic_alarmset_init_alarm (lsquic_alarmset_t *alset, enum alarm_id al_id,
|
|||
}
|
||||
|
||||
|
||||
static const char *const lsquic_alid2str[] =
|
||||
{
|
||||
[AL_HANDSHAKE] = "HANDSHAKE",
|
||||
[AL_RETX_INIT] = "RETX_INIT",
|
||||
[AL_RETX_HSK] = "RETX_HSK",
|
||||
[AL_RETX_APP] = "RETX_APP",
|
||||
[AL_PING] = "PING",
|
||||
[AL_IDLE] = "IDLE",
|
||||
[AL_ACK_INIT] = "ACK_INIT",
|
||||
[AL_ACK_HSK] = "ACK_HSK",
|
||||
[AL_ACK_APP] = "ACK_APP",
|
||||
[AL_RET_CIDS] = "RET_CIDS",
|
||||
[AL_CID_THROT] = "CID_THROT",
|
||||
[AL_PATH_CHAL_0] = "PATH_CHAL_0",
|
||||
[AL_PATH_CHAL_1] = "PATH_CHAL_1",
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
lsquic_alarmset_ring_expired (lsquic_alarmset_t *alset, lsquic_time_t now)
|
||||
{
|
||||
|
@ -45,8 +64,8 @@ lsquic_alarmset_ring_expired (lsquic_alarmset_t *alset, lsquic_time_t now)
|
|||
if (alset->as_expiry[al_id] < now)
|
||||
{
|
||||
alset->as_armed_set &= ~(1 << al_id);
|
||||
LSQ_INFO("ring expired alarm %d", al_id);
|
||||
alset->as_alarms[al_id].callback(
|
||||
LSQ_INFO("ring expired %s alarm", lsquic_alid2str[al_id]);
|
||||
alset->as_alarms[al_id].callback(al_id,
|
||||
alset->as_alarms[al_id].cb_ctx,
|
||||
alset->as_expiry[al_id], now);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
|
||||
#include "lsquic_int_types.h"
|
||||
|
||||
typedef void (*lsquic_alarm_cb_f)(void *cb_ctx,
|
||||
enum alarm_id;
|
||||
struct lsquic_conn;
|
||||
|
||||
typedef void (*lsquic_alarm_cb_f)(enum alarm_id, void *cb_ctx,
|
||||
lsquic_time_t expiry, lsquic_time_t now);
|
||||
|
||||
typedef struct lsquic_alarm {
|
||||
|
@ -19,33 +22,51 @@ typedef struct lsquic_alarm {
|
|||
|
||||
enum alarm_id {
|
||||
AL_HANDSHAKE,
|
||||
AL_RETX,
|
||||
AL_ACK,
|
||||
AL_RETX_INIT,
|
||||
AL_RETX_HSK = AL_RETX_INIT + PNS_HSK,
|
||||
AL_RETX_APP = AL_RETX_INIT + PNS_APP,
|
||||
AL_PING,
|
||||
AL_IDLE,
|
||||
AL_ACK_INIT,
|
||||
AL_ACK_HSK = AL_ACK_INIT + PNS_HSK,
|
||||
AL_ACK_APP = AL_ACK_INIT + PNS_APP,
|
||||
AL_RET_CIDS,
|
||||
AL_CID_THROT,
|
||||
AL_PATH_CHAL,
|
||||
AL_PATH_CHAL_0 = AL_PATH_CHAL,
|
||||
AL_PATH_CHAL_1,
|
||||
MAX_LSQUIC_ALARMS
|
||||
};
|
||||
|
||||
|
||||
enum alarm_id_bit {
|
||||
ALBIT_HANDSHAKE = 1 << AL_HANDSHAKE,
|
||||
ALBIT_RETX = 1 << AL_RETX,
|
||||
ALBIT_ACK = 1 << AL_ACK,
|
||||
ALBIT_RETX_INIT = 1 << AL_RETX_INIT,
|
||||
ALBIT_RETX_HSK = 1 << AL_RETX_HSK,
|
||||
ALBIT_RETX_APP = 1 << AL_RETX_APP,
|
||||
ALBIT_ACK_APP = 1 << AL_ACK_APP,
|
||||
ALBIT_ACK_INIT = 1 << AL_ACK_INIT,
|
||||
ALBIT_ACK_HSK = 1 << AL_ACK_HSK,
|
||||
ALBIT_PING = 1 << AL_PING,
|
||||
ALBIT_IDLE = 1 << AL_IDLE,
|
||||
ALBIT_RET_CIDS = 1 << AL_RET_CIDS,
|
||||
ALBIT_CID_THROT = 1 << AL_CID_THROT,
|
||||
ALBIT_PATH_CHAL = 1 << AL_PATH_CHAL,
|
||||
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
|
||||
ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1,
|
||||
};
|
||||
|
||||
|
||||
typedef struct lsquic_alarmset {
|
||||
enum alarm_id_bit as_armed_set;
|
||||
lsquic_time_t as_expiry[MAX_LSQUIC_ALARMS];
|
||||
lsquic_cid_t as_cid; /* Used for logging */
|
||||
const struct lsquic_conn *as_conn; /* Used for logging */
|
||||
struct lsquic_alarm as_alarms[MAX_LSQUIC_ALARMS];
|
||||
} lsquic_alarmset_t;
|
||||
|
||||
|
||||
void
|
||||
lsquic_alarmset_init (lsquic_alarmset_t *, lsquic_cid_t);
|
||||
lsquic_alarmset_init (lsquic_alarmset_t *, const struct lsquic_conn *);
|
||||
|
||||
void
|
||||
lsquic_alarmset_init_alarm (lsquic_alarmset_t *, enum alarm_id,
|
||||
|
@ -63,6 +84,9 @@ lsquic_alarmset_init_alarm (lsquic_alarmset_t *, enum alarm_id,
|
|||
#define lsquic_alarmset_is_set(alarmset, al_id) \
|
||||
((alarmset)->as_armed_set & (1 << (al_id)))
|
||||
|
||||
#define lsquic_alarmset_are_set(alarmset, flags) \
|
||||
((alarmset)->as_armed_set & (flags))
|
||||
|
||||
/* Timers "fire," alarms "ring." */
|
||||
void
|
||||
lsquic_alarmset_ring_expired (lsquic_alarmset_t *, lsquic_time_t now);
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
#ifdef WIN32
|
||||
#include <vc_compat.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_attq.h"
|
||||
#include "lsquic_malo.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
|
||||
|
||||
|
@ -212,7 +214,6 @@ attq_remove (struct attq *q, struct lsquic_conn *conn)
|
|||
assert(conn->cn_attq_elem == el);
|
||||
|
||||
conn->cn_attq_elem = NULL;
|
||||
lsquic_malo_put(el);
|
||||
|
||||
q->aq_heap[ idx ] = q->aq_heap[ --q->aq_nelem ];
|
||||
q->aq_heap[ idx ]->ae_heap_idx = idx;
|
||||
|
@ -229,6 +230,7 @@ attq_remove (struct attq *q, struct lsquic_conn *conn)
|
|||
}
|
||||
else if (q->aq_nelem > 1 && idx < q->aq_nelem)
|
||||
attq_heapify(q, idx);
|
||||
lsquic_malo_put(el);
|
||||
attq_verify(q);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,210 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_BBR_H
|
||||
#define LSQUIC_BBR_H
|
||||
|
||||
/* Our BBR implementation is copied from Chromium with some modifications.
|
||||
* Besides the obvious translation from C++ to C, differences are:
|
||||
*
|
||||
* 1. Instead of OnCongestionEvent(), the ACK information is processed at the
|
||||
* same time as the ACK itself using cci_begin_ack(), cci_ack(), and
|
||||
* cci_end_ack() methods. This is done to fit with the flow in
|
||||
* lsquic_send_ctl_got_ack().
|
||||
*
|
||||
* 2. The bandwidth sampler does not use a hash. Instead, the sample
|
||||
* information is attached directly to the packet via po_bwp_state.
|
||||
*
|
||||
* In this file and in lsquic_bbr.c, C++-style comments are those copied
|
||||
* verbatim from Chromium. C-style comments are ours.
|
||||
*
|
||||
* Code is based on bbr_sender.cc 1a578a76c16abc942205a1a80584a288c262d03a in
|
||||
* the "quiche" repository. (Not to be confused with Cloudflare's "quiche".)
|
||||
*
|
||||
* The BBR I-D is here:
|
||||
* https://tools.ietf.org/html/draft-cardwell-iccrg-bbr-congestion-control-00
|
||||
*
|
||||
* As for quiche, see
|
||||
* http://www.bernstein-plus-sons.com/RPDEQ.html
|
||||
*
|
||||
* Chromium copyright notice follows.
|
||||
*/
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE.chrome file.
|
||||
|
||||
struct lsquic_bbr
|
||||
{
|
||||
struct lsquic_conn *bbr_conn;
|
||||
|
||||
enum bbr_mode
|
||||
{
|
||||
BBR_MODE_STARTUP,
|
||||
BBR_MODE_DRAIN,
|
||||
BBR_MODE_PROBE_BW,
|
||||
BBR_MODE_PROBE_RTT,
|
||||
} bbr_mode;
|
||||
|
||||
enum
|
||||
{
|
||||
BBR_RS_NOT_IN_RECOVERY,
|
||||
BBR_RS_CONSERVATION,
|
||||
BBR_RS_GROWTH,
|
||||
} bbr_recovery_state;
|
||||
|
||||
enum
|
||||
{
|
||||
BBR_FLAG_IN_ACK = 1 << 0, /* cci_begin_ack() has been called */
|
||||
BBR_FLAG_LAST_SAMPLE_APP_LIMITED = 1 << 1,
|
||||
BBR_FLAG_HAS_NON_APP_LIMITED = 1 << 2,
|
||||
BBR_FLAG_APP_LIMITED_SINCE_LAST_PROBE_RTT
|
||||
= 1 << 3,
|
||||
BBR_FLAG_PROBE_RTT_DISABLED_IF_APP_LIMITED
|
||||
= 1 << 4,
|
||||
BBR_FLAG_PROBE_RTT_SKIPPED_IF_SIMILAR_RTT
|
||||
= 1 << 5,
|
||||
BBR_FLAG_EXIT_STARTUP_ON_LOSS = 1 << 6,
|
||||
BBR_FLAG_IS_AT_FULL_BANDWIDTH = 1 << 7,
|
||||
BBR_FLAG_EXITING_QUIESCENCE = 1 << 8,
|
||||
BBR_FLAG_PROBE_RTT_ROUND_PASSED = 1 << 9,
|
||||
BBR_FLAG_FLEXIBLE_APP_LIMITED = 1 << 10,
|
||||
// If true, will not exit low gain mode until bytes_in_flight drops
|
||||
// below BDP or it's time for high gain mode.
|
||||
BBR_FLAG_DRAIN_TO_TARGET = 1 << 11,
|
||||
// When true, expire the windowed ack aggregation values in STARTUP
|
||||
// when bandwidth increases more than 25%.
|
||||
BBR_FLAG_EXPIRE_ACK_AGG_IN_STARTUP
|
||||
= 1 << 12,
|
||||
// If true, use a CWND of 0.75*BDP during probe_rtt instead of 4
|
||||
// packets.
|
||||
BBR_FLAG_PROBE_RTT_BASED_ON_BDP = 1 << 13,
|
||||
// When true, pace at 1.5x and disable packet conservation in STARTUP.
|
||||
BBR_FLAG_SLOWER_STARTUP = 1 << 14,
|
||||
// When true, add the most recent ack aggregation measurement during STARTUP.
|
||||
BBR_FLAG_ENABLE_ACK_AGG_IN_STARTUP
|
||||
= 1 << 15,
|
||||
// When true, disables packet conservation in STARTUP.
|
||||
BBR_FLAG_RATE_BASED_STARTUP = 1 << 16,
|
||||
} bbr_flags;
|
||||
|
||||
// Number of round-trips in PROBE_BW mode, used for determining the current
|
||||
// pacing gain cycle.
|
||||
unsigned bbr_cycle_current_offset;
|
||||
|
||||
const struct lsquic_rtt_stats
|
||||
*bbr_rtt_stats;
|
||||
|
||||
struct bw_sampler bbr_bw_sampler;
|
||||
|
||||
/*
|
||||
" BBR.BtlBwFilter: The max filter used to estimate BBR.BtlBw.
|
||||
*/
|
||||
struct minmax bbr_max_bandwidth;
|
||||
|
||||
// Tracks the maximum number of bytes acked faster than the sending rate.
|
||||
struct minmax bbr_max_ack_height;
|
||||
|
||||
// The initial value of the bbr_cwnd.
|
||||
uint64_t bbr_init_cwnd;
|
||||
// The smallest value the bbr_cwnd can achieve.
|
||||
uint64_t bbr_min_cwnd;
|
||||
// The largest value the bbr_cwnd can achieve.
|
||||
uint64_t bbr_max_cwnd;
|
||||
// The maximum allowed number of bytes in flight.
|
||||
uint64_t bbr_cwnd;
|
||||
|
||||
// The time this aggregation started and the number of bytes acked during it.
|
||||
lsquic_time_t bbr_aggregation_epoch_start_time;
|
||||
uint64_t bbr_aggregation_epoch_bytes;
|
||||
|
||||
lsquic_packno_t bbr_last_sent_packno;
|
||||
lsquic_packno_t bbr_current_round_trip_end;
|
||||
|
||||
// Receiving acknowledgement of a packet after |bbr_end_recovery_at| will
|
||||
// cause BBR to exit the recovery mode. A value above zero indicates at
|
||||
// least one loss has been detected, so it must not be set back to zero.
|
||||
lsquic_packno_t bbr_end_recovery_at;
|
||||
|
||||
/*
|
||||
" BBR.round_count: Count of packet-timed round trips.
|
||||
*/
|
||||
uint64_t bbr_round_count;
|
||||
|
||||
/* Not documented in the draft: */
|
||||
uint64_t bbr_full_bw;
|
||||
|
||||
/* Not documented in the draft: */
|
||||
uint64_t bbr_full_bw_count;
|
||||
|
||||
/*
|
||||
" BBR.pacing_rate: The current pacing rate for a BBR flow, which
|
||||
" controls inter-packet spacing.
|
||||
*/
|
||||
struct bandwidth bbr_pacing_rate;
|
||||
|
||||
// Sum of bytes lost in STARTUP.
|
||||
uint64_t bbr_startup_bytes_lost;
|
||||
|
||||
/*
|
||||
" BBR.pacing_gain: The dynamic gain factor used to scale BBR.BtlBw to
|
||||
" produce BBR.pacing_rate.
|
||||
*/
|
||||
float bbr_pacing_gain;
|
||||
|
||||
// The pacing gain applied during the STARTUP phase.
|
||||
float bbr_high_gain;
|
||||
|
||||
// The CWND gain applied during the STARTUP phase.
|
||||
float bbr_high_cwnd_gain;
|
||||
|
||||
// The pacing gain applied during the DRAIN phase.
|
||||
float bbr_drain_gain;
|
||||
|
||||
// The number of RTTs to stay in STARTUP mode. Defaults to 3.
|
||||
unsigned bbr_num_startup_rtts;
|
||||
|
||||
// Number of rounds during which there was no significant bandwidth
|
||||
// increase.
|
||||
unsigned bbr_round_wo_bw_gain;
|
||||
|
||||
/*
|
||||
" BBR.cwnd_gain: The dynamic gain factor used to scale the estimated
|
||||
" BDP to produce a congestion window (cwnd).
|
||||
*/
|
||||
float bbr_cwnd_gain;
|
||||
|
||||
// The bandwidth compared to which the increase is measured.
|
||||
struct bandwidth bbr_bw_at_last_round;
|
||||
|
||||
// The time at which the last pacing gain cycle was started.
|
||||
lsquic_time_t bbr_last_cycle_start;
|
||||
|
||||
// Time at which PROBE_RTT has to be exited. Setting it to zero indicates
|
||||
// that the time is yet unknown as the number of packets in flight has not
|
||||
// reached the required value.
|
||||
lsquic_time_t bbr_exit_probe_rtt_at;
|
||||
|
||||
lsquic_time_t bbr_min_rtt_since_last_probe;
|
||||
lsquic_time_t bbr_min_rtt;
|
||||
lsquic_time_t bbr_min_rtt_timestamp;
|
||||
|
||||
// A window used to limit the number of bytes in flight during loss recovery
|
||||
uint64_t bbr_recovery_window;
|
||||
|
||||
/* Accumulate information from a single ACK. Gets processed when
|
||||
* cci_end_ack() is called.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
TAILQ_HEAD(, bw_sample) samples;
|
||||
lsquic_time_t ack_time;
|
||||
lsquic_packno_t max_packno;
|
||||
uint64_t acked_bytes;
|
||||
uint64_t lost_bytes;
|
||||
uint64_t total_bytes_acked_before;
|
||||
uint64_t in_flight;
|
||||
int has_losses;
|
||||
} bbr_ack_state;
|
||||
};
|
||||
|
||||
extern const struct cong_ctl_if lsquic_cong_bbr_if;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,273 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_malo.h"
|
||||
#include "lsquic_util.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_out.h"
|
||||
#include "lsquic_parse.h"
|
||||
#include "lsquic_bw_sampler.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_BW_SAMPLER
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(sampler->bws_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
int
|
||||
lsquic_bw_sampler_init (struct bw_sampler *sampler, struct lsquic_conn *conn,
|
||||
enum quic_ft_bit retx_frames)
|
||||
{
|
||||
struct malo *malo;
|
||||
|
||||
assert(lsquic_is_zero(sampler, sizeof(*sampler)));
|
||||
|
||||
malo = lsquic_malo_create(sizeof(struct bwp_state));
|
||||
if (!malo)
|
||||
return -1;
|
||||
|
||||
sampler->bws_malo = malo;
|
||||
sampler->bws_conn = conn;
|
||||
sampler->bws_retx_frames = retx_frames;
|
||||
LSQ_DEBUG("init");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_app_limited (struct bw_sampler *sampler)
|
||||
{
|
||||
sampler->bws_flags |= BWS_APP_LIMITED;
|
||||
sampler->bws_end_of_app_limited_phase = sampler->bws_last_sent_packno;
|
||||
LSQ_DEBUG("app limited, end of limited phase is %"PRIu64,
|
||||
sampler->bws_end_of_app_limited_phase);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_cleanup (struct bw_sampler *sampler)
|
||||
{
|
||||
if (sampler->bws_conn)
|
||||
LSQ_DEBUG("cleanup");
|
||||
if (sampler->bws_malo)
|
||||
lsquic_malo_destroy(sampler->bws_malo);
|
||||
}
|
||||
|
||||
|
||||
/* This module only fails when it is unable to allocate memory. This rarely
|
||||
* happens, so we avoid having to check return values and abort the connection
|
||||
* instead.
|
||||
*/
|
||||
static void
|
||||
bw_sampler_abort_conn (struct bw_sampler *sampler)
|
||||
{
|
||||
if (!(sampler->bws_flags & BWS_CONN_ABORTED))
|
||||
{
|
||||
sampler->bws_flags |= BWS_CONN_ABORTED;
|
||||
LSQ_WARN("aborting connection");
|
||||
sampler->bws_conn->cn_if->ci_internal_error(sampler->bws_conn,
|
||||
"resources exhausted");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define BW_WARN_ONCE(msg...) do { \
|
||||
if (!(sampler->bws_flags & BWS_WARNED)) \
|
||||
{ \
|
||||
sampler->bws_flags |= BWS_WARNED; \
|
||||
LSQ_WARN(msg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_packet_sent (struct bw_sampler *sampler,
|
||||
struct lsquic_packet_out *packet_out, uint64_t in_flight)
|
||||
{
|
||||
struct bwp_state *state;
|
||||
unsigned short sent_sz;
|
||||
|
||||
if (packet_out->po_bwp_state)
|
||||
{
|
||||
BW_WARN_ONCE("sent: packet %"PRIu64" already has state",
|
||||
packet_out->po_packno);
|
||||
return;
|
||||
}
|
||||
|
||||
sampler->bws_last_sent_packno = packet_out->po_packno;
|
||||
|
||||
if (!(packet_out->po_frame_types & sampler->bws_retx_frames))
|
||||
return;
|
||||
|
||||
sent_sz = lsquic_packet_out_sent_sz(sampler->bws_conn, packet_out);
|
||||
sampler->bws_total_sent += sent_sz;
|
||||
|
||||
// If there are no packets in flight, the time at which the new transmission
|
||||
// opens can be treated as the A_0 point for the purpose of bandwidth
|
||||
// sampling. This underestimates bandwidth to some extent, and produces some
|
||||
// artificially low samples for most packets in flight, but it provides with
|
||||
// samples at important points where we would not have them otherwise, most
|
||||
// importantly at the beginning of the connection.
|
||||
if (in_flight == 0)
|
||||
{
|
||||
sampler->bws_last_acked_packet_time = packet_out->po_sent;
|
||||
sampler->bws_last_acked_total_sent = sampler->bws_total_sent;
|
||||
// In this situation ack compression is not a concern, set send rate to
|
||||
// effectively infinite.
|
||||
sampler->bws_last_acked_sent_time = packet_out->po_sent;
|
||||
}
|
||||
|
||||
state = lsquic_malo_get(sampler->bws_malo);
|
||||
if (!state)
|
||||
{
|
||||
bw_sampler_abort_conn(sampler);
|
||||
return;
|
||||
}
|
||||
|
||||
state->bwps_send_state = (struct bwps_send_state) {
|
||||
.total_bytes_sent = sampler->bws_total_sent,
|
||||
.total_bytes_acked = sampler->bws_total_acked,
|
||||
.total_bytes_lost = sampler->bws_total_lost,
|
||||
.is_app_limited = !!(sampler->bws_flags & BWS_APP_LIMITED),
|
||||
};
|
||||
state->bwps_sent_at_last_ack = sampler->bws_last_acked_total_sent;
|
||||
state->bwps_last_ack_sent_time = sampler->bws_last_acked_sent_time;
|
||||
state->bwps_last_ack_ack_time = sampler->bws_last_acked_packet_time;
|
||||
state->bwps_packet_size = sent_sz;
|
||||
|
||||
packet_out->po_bwp_state = state;
|
||||
|
||||
LSQ_DEBUG("add info for packet %"PRIu64, packet_out->po_packno);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_packet_lost (struct bw_sampler *sampler,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
if (!packet_out->po_bwp_state)
|
||||
return;
|
||||
|
||||
sampler->bws_total_lost += packet_out->po_bwp_state->bwps_packet_size;
|
||||
lsquic_malo_put(packet_out->po_bwp_state);
|
||||
packet_out->po_bwp_state = NULL;
|
||||
LSQ_DEBUG("packet %"PRIu64" lost, total_lost goes to %"PRIu64,
|
||||
packet_out->po_packno, sampler->bws_total_lost);
|
||||
}
|
||||
|
||||
|
||||
struct bw_sample *
|
||||
lsquic_bw_sampler_packet_acked (struct bw_sampler *sampler,
|
||||
struct lsquic_packet_out *packet_out, lsquic_time_t ack_time)
|
||||
{
|
||||
const struct bwp_state *state;
|
||||
struct bw_sample *sample;
|
||||
struct bandwidth send_rate, ack_rate;
|
||||
lsquic_time_t rtt;
|
||||
unsigned short sent_sz;
|
||||
int is_app_limited;
|
||||
|
||||
if (!packet_out->po_bwp_state)
|
||||
return 0;
|
||||
|
||||
state = packet_out->po_bwp_state;
|
||||
sent_sz = lsquic_packet_out_sent_sz(sampler->bws_conn, packet_out);
|
||||
|
||||
sampler->bws_total_acked += sent_sz;
|
||||
sampler->bws_last_acked_total_sent = state->bwps_send_state.total_bytes_sent;
|
||||
sampler->bws_last_acked_sent_time = packet_out->po_sent;
|
||||
sampler->bws_last_acked_packet_time = ack_time;
|
||||
|
||||
// Exit app-limited phase once a packet that was sent while the connection
|
||||
// is not app-limited is acknowledged.
|
||||
if ((sampler->bws_flags & BWS_APP_LIMITED)
|
||||
&& packet_out->po_packno > sampler->bws_end_of_app_limited_phase)
|
||||
{
|
||||
sampler->bws_flags &= ~BWS_APP_LIMITED;
|
||||
LSQ_DEBUG("exit app-limited phase due to packet %"PRIu64" being acked",
|
||||
packet_out->po_packno);
|
||||
}
|
||||
|
||||
// There might have been no packets acknowledged at the moment when the
|
||||
// current packet was sent. In that case, there is no bandwidth sample to
|
||||
// make.
|
||||
if (state->bwps_last_ack_sent_time == 0)
|
||||
goto no_sample;
|
||||
|
||||
// Infinite rate indicates that the sampler is supposed to discard the
|
||||
// current send rate sample and use only the ack rate.
|
||||
if (packet_out->po_sent > state->bwps_last_ack_sent_time)
|
||||
send_rate = BW_FROM_BYTES_AND_DELTA(
|
||||
state->bwps_send_state.total_bytes_sent
|
||||
- state->bwps_sent_at_last_ack,
|
||||
packet_out->po_sent - state->bwps_last_ack_sent_time);
|
||||
else
|
||||
send_rate = BW_INFINITE();
|
||||
|
||||
// During the slope calculation, ensure that ack time of the current packet is
|
||||
// always larger than the time of the previous packet, otherwise division by
|
||||
// zero or integer underflow can occur.
|
||||
if (ack_time <= state->bwps_last_ack_ack_time)
|
||||
{
|
||||
BW_WARN_ONCE("Time of the previously acked packet (%"PRIu64") is "
|
||||
"is larger than the ack time of the current packet (%"PRIu64")",
|
||||
state->bwps_last_ack_ack_time, ack_time);
|
||||
goto no_sample;
|
||||
}
|
||||
|
||||
ack_rate = BW_FROM_BYTES_AND_DELTA(
|
||||
sampler->bws_total_acked - state->bwps_send_state.total_bytes_acked,
|
||||
ack_time - state->bwps_last_ack_ack_time);
|
||||
LSQ_DEBUG("send rate: %"PRIu64"; ack rate: %"PRIu64, send_rate.value,
|
||||
ack_rate.value);
|
||||
|
||||
// Note: this sample does not account for delayed acknowledgement time.
|
||||
// This means that the RTT measurements here can be artificially high,
|
||||
// especially on low bandwidth connections.
|
||||
rtt = ack_time - packet_out->po_sent;
|
||||
is_app_limited = state->bwps_send_state.is_app_limited;
|
||||
|
||||
/* After this point, we switch `sample' to point to `state' and don't
|
||||
* reference `state' anymore.
|
||||
*/
|
||||
sample = (void *) packet_out->po_bwp_state;
|
||||
packet_out->po_bwp_state = NULL;
|
||||
if (BW_VALUE(&send_rate) < BW_VALUE(&ack_rate))
|
||||
sample->bandwidth = send_rate;
|
||||
else
|
||||
sample->bandwidth = ack_rate;
|
||||
sample->rtt = rtt;
|
||||
sample->is_app_limited = is_app_limited;
|
||||
|
||||
LSQ_DEBUG("packet %"PRIu64" acked, bandwidth: %"PRIu64" bps",
|
||||
packet_out->po_packno, BW_VALUE(&sample->bandwidth));
|
||||
|
||||
return sample;
|
||||
|
||||
no_sample:
|
||||
lsquic_malo_put(packet_out->po_bwp_state);
|
||||
packet_out->po_bwp_state = NULL;
|
||||
return NULL;;
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
lsquic_bw_sampler_entry_count (const struct bw_sampler *sampler)
|
||||
{
|
||||
void *el;
|
||||
unsigned count;
|
||||
|
||||
count = 0;
|
||||
for (el = lsquic_malo_first(sampler->bws_malo); el;
|
||||
el = lsquic_malo_next(sampler->bws_malo))
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_BW_SAMPLER_H
|
||||
#define LSQUIC_BW_SAMPLER_H 1
|
||||
|
||||
/* Translated from Chromium. */
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
|
||||
struct lsquic_packet_out;
|
||||
|
||||
/* This struct provides a type for bits per second units. It's made into
|
||||
* a struct so that it is a little harder to make a mistake. The Chromium
|
||||
* equivalent of this is QuicBandwidth. Use macros to operate.
|
||||
*/
|
||||
struct bandwidth
|
||||
{
|
||||
uint64_t value; /* Bits per second */
|
||||
};
|
||||
|
||||
#define BW_INFINITE() ((struct bandwidth) { .value = UINT64_MAX, })
|
||||
#define BW_ZERO() ((struct bandwidth) { .value = 0, })
|
||||
#define BW_FROM_BYTES_AND_DELTA(bytes_, usecs_) \
|
||||
((struct bandwidth) { .value = (bytes_) * 8 * 1000000 / (usecs_), })
|
||||
#define BW_IS_ZERO(bw_) ((bw_)->value == 0)
|
||||
#define BW_TO_BYTES_PER_SEC(bw_) ((bw_)->value / 8)
|
||||
#define BW_VALUE(bw_) (+(bw_)->value)
|
||||
#define BW_TIMES(bw_, factor_) \
|
||||
((struct bandwidth) { .value = BW_VALUE(bw_) * (factor_), })
|
||||
#define BW(initial_value_) ((struct bandwidth) { .value = (initial_value_) })
|
||||
|
||||
struct bw_sampler
|
||||
{
|
||||
struct lsquic_conn *bws_conn;
|
||||
uint64_t bws_total_sent,
|
||||
bws_total_acked,
|
||||
bws_total_lost;
|
||||
/* Value of bws_total_sent at the time last ACKed packet was sent. Only
|
||||
* valid if bws_last_acked_sent_time is valid.
|
||||
*/
|
||||
uint64_t bws_last_acked_total_sent;
|
||||
/* Time when last acked packet was sent. Zero if no valid timestamp is
|
||||
* available.
|
||||
*/
|
||||
lsquic_time_t bws_last_acked_sent_time;
|
||||
lsquic_time_t bws_last_acked_packet_time;
|
||||
lsquic_packno_t bws_last_sent_packno;
|
||||
lsquic_packno_t bws_end_of_app_limited_phase;
|
||||
struct malo *bws_malo; /* For struct osp_state objects */
|
||||
enum quic_ft_bit bws_retx_frames;
|
||||
enum {
|
||||
BWS_CONN_ABORTED = 1 << 0,
|
||||
BWS_WARNED = 1 << 1,
|
||||
BWS_APP_LIMITED = 1 << 2,
|
||||
} bws_flags;
|
||||
};
|
||||
|
||||
struct bw_sample
|
||||
{
|
||||
TAILQ_ENTRY(bw_sample) next;
|
||||
struct bandwidth bandwidth;
|
||||
lsquic_time_t rtt;
|
||||
int is_app_limited;
|
||||
};
|
||||
|
||||
int
|
||||
lsquic_bw_sampler_init (struct bw_sampler *, struct lsquic_conn *,
|
||||
enum quic_ft_bit);
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_packet_sent (struct bw_sampler *, struct lsquic_packet_out *,
|
||||
uint64_t in_flight);
|
||||
|
||||
/* Free returned sample via lsquic_malo_put() after you're done */
|
||||
struct bw_sample *
|
||||
lsquic_bw_sampler_packet_acked (struct bw_sampler *, struct lsquic_packet_out *,
|
||||
lsquic_time_t ack_time);
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_packet_lost (struct bw_sampler *, struct lsquic_packet_out *);
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_app_limited (struct bw_sampler *);
|
||||
|
||||
void
|
||||
lsquic_bw_sampler_cleanup (struct bw_sampler *);
|
||||
|
||||
unsigned
|
||||
lsquic_bw_sampler_entry_count (const struct bw_sampler *);
|
||||
|
||||
#define lsquic_bw_sampler_total_acked(sampler_) (+(sampler_)->bws_total_acked)
|
||||
|
||||
/* The following types are exposed in the header file because of unit tests.
|
||||
* Do not use outside of lsquic_bw_sampler.c.
|
||||
*/
|
||||
struct bwps_send_state
|
||||
{
|
||||
uint64_t total_bytes_sent,
|
||||
total_bytes_acked,
|
||||
total_bytes_lost;
|
||||
int is_app_limited;
|
||||
};
|
||||
|
||||
struct bwp_state /* BWP State stands for Bandwidth Packet State */
|
||||
{
|
||||
struct bwps_send_state bwps_send_state;
|
||||
uint64_t bwps_sent_at_last_ack;
|
||||
lsquic_time_t bwps_last_ack_sent_time;
|
||||
lsquic_time_t bwps_last_ack_ack_time;
|
||||
unsigned short bwps_packet_size;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
#include <sys/endian.h>
|
||||
#define bswap_16 bswap16
|
||||
#define bswap_32 bswap32
|
||||
#define bswap_64 bswap64
|
||||
#define bswap_16 bswap16
|
||||
#define bswap_32 bswap32
|
||||
#define bswap_64 bswap64
|
||||
#elif defined(__APPLE__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define bswap_16 OSSwapInt16
|
||||
|
@ -21,4 +21,19 @@
|
|||
#include <byteswap.h>
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define READ_UINT(varname, varwidth, src, nbytes) do { \
|
||||
varname = 0; \
|
||||
memcpy((unsigned char *) &(varname) + varwidth / 8 - (nbytes), (src), \
|
||||
(nbytes)); \
|
||||
varname = bswap_##varwidth(varname); \
|
||||
} while (0)
|
||||
#else
|
||||
#define READ_UINT(varname, varwidth, src, nbytes) do { \
|
||||
varname = 0; \
|
||||
memcpy((unsigned char *) &(varname) + varwidth / 8 - (nbytes), (src), \
|
||||
(nbytes)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "lsquic_rtt.h"
|
||||
#include "lsquic_conn_flow.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_conn_public.h"
|
||||
#include "lsquic_mm.h"
|
||||
|
@ -20,7 +23,7 @@
|
|||
#include "lsquic_ev_log.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_CFCW
|
||||
#define LSQUIC_LOG_CONN_ID fc->cf_conn_pub->lconn->cn_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->cf_conn_pub->lconn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
|
|
|
@ -11,19 +11,23 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic.h"
|
||||
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_chsk_stream.h"
|
||||
#include "lsquic_ver_neg.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_sizes.h"
|
||||
#include "lsquic_full_conn.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HSK_ADAPTER
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(c_hsk->lconn)
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(c_hsk->lconn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
|
@ -34,6 +38,15 @@ hsk_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
|||
|
||||
LSQ_DEBUG("stream created");
|
||||
|
||||
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
|
||||
if (getenv("LSQUIC_DISABLE_HANDSHAKE"))
|
||||
{
|
||||
LSQ_WARN("Handshake disabled: faking it");
|
||||
c_hsk->lconn->cn_flags |= LSCONN_NO_CRYPTO;
|
||||
c_hsk->lconn->cn_if->ci_handshake_ok(c_hsk->lconn);
|
||||
return (void *) c_hsk;
|
||||
}
|
||||
#endif
|
||||
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
|
||||
|
@ -80,7 +93,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
}
|
||||
c_hsk->buf_off += nread;
|
||||
|
||||
s = c_hsk->lconn->cn_esf->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
|
||||
s = c_hsk->lconn->cn_esf.g->esf_handle_chlo_reply(c_hsk->lconn->cn_enc_session,
|
||||
c_hsk->buf_in, c_hsk->buf_off);
|
||||
LSQ_DEBUG("lsquic_enc_session_handle_chlo_reply returned %d", s);
|
||||
switch (s)
|
||||
|
@ -104,10 +117,10 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
||||
c_hsk->buf_in = NULL;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
||||
if (c_hsk->lconn->cn_esf.g->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
||||
{
|
||||
LSQ_DEBUG("handshake is successful, inform connection");
|
||||
status = (c_hsk->lconn->cn_esf->esf_did_zero_rtt_succeed(
|
||||
status = (c_hsk->lconn->cn_esf_c->esf_did_zero_rtt_succeed(
|
||||
c_hsk->lconn->cn_enc_session)) ? LSQ_HSK_0RTT_OK : LSQ_HSK_OK;
|
||||
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, status);
|
||||
}
|
||||
|
@ -118,6 +131,13 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
lsquic_stream_wantwrite(stream, 1);
|
||||
}
|
||||
break;
|
||||
case HS_SREJ:
|
||||
LSQ_DEBUG("got HS_SREJ");
|
||||
c_hsk->buf_off = 0;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
if (0 == lsquic_gquic_full_conn_srej(c_hsk->lconn))
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
break;
|
||||
default:
|
||||
LSQ_WARN("lsquic_enc_session_handle_chlo_reply returned unknown value %d", s);
|
||||
/* fallthru */
|
||||
|
@ -154,7 +174,7 @@ hsk_client_on_write (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
}
|
||||
len = 4 * 1024;
|
||||
|
||||
if (0 != c_hsk->lconn->cn_esf->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
|
||||
if (0 != c_hsk->lconn->cn_esf.g->esf_gen_chlo(c_hsk->lconn->cn_enc_session,
|
||||
c_hsk->ver_neg->vn_ver, buf, &len))
|
||||
{
|
||||
LSQ_WARN("cannot create CHLO message");
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_cong_ctl.h -- congestion control interface
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_CONG_CTL_H
|
||||
#define LSQUIC_CONG_CTL_H
|
||||
|
||||
|
||||
struct lsquic_conn_public;
|
||||
struct lsquic_packet_out;
|
||||
enum quic_ft_bit;
|
||||
|
||||
|
||||
/* All the methods don't quite match up between Cubic and BBR. Thus, some of
|
||||
* the methods are optional; they are marked as such in the comments below.
|
||||
* Reconciling Cubic and BBR to have similar interface is left as an exercise
|
||||
* for the future.
|
||||
*/
|
||||
struct cong_ctl_if
|
||||
{
|
||||
void
|
||||
(*cci_init) (void *cong_ctl, const struct lsquic_conn_public *,
|
||||
enum quic_ft_bit);
|
||||
|
||||
void
|
||||
(*cci_ack) (void *cong_ctl, struct lsquic_packet_out *, unsigned packet_sz,
|
||||
lsquic_time_t now, int app_limited);
|
||||
|
||||
void
|
||||
(*cci_loss) (void *cong_ctl);
|
||||
|
||||
/* Optional method */
|
||||
void
|
||||
(*cci_begin_ack) (void *cong_ctl, lsquic_time_t ack_time,
|
||||
uint64_t in_flight);
|
||||
|
||||
/* Optional method */
|
||||
void
|
||||
(*cci_end_ack) (void *cong_ctl, uint64_t in_flight);
|
||||
|
||||
/* Optional method */
|
||||
void
|
||||
(*cci_sent) (void *cong_ctl, struct lsquic_packet_out *,
|
||||
uint64_t in_flight);
|
||||
|
||||
/* Optional method */
|
||||
void
|
||||
(*cci_lost) (void *cong_ctl, struct lsquic_packet_out *,
|
||||
unsigned packet_sz);
|
||||
|
||||
void
|
||||
(*cci_timeout) (void *cong_ctl);
|
||||
|
||||
void
|
||||
(*cci_was_quiet) (void *cong_ctl, lsquic_time_t now, uint64_t in_flight);
|
||||
|
||||
uint64_t
|
||||
(*cci_get_cwnd) (void *cong_ctl);
|
||||
|
||||
uint64_t
|
||||
(*cci_pacing_rate) (void *cong_ctl, int in_recovery);
|
||||
|
||||
void
|
||||
(*cci_cleanup) (void *cong_ctl);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2,68 +2,63 @@
|
|||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_engine_public.h"
|
||||
#include "lsquic_ev_log.h"
|
||||
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
lsquic_cid_t
|
||||
const lsquic_cid_t *
|
||||
lsquic_conn_id (const lsquic_conn_t *lconn)
|
||||
{
|
||||
return lconn->cn_cid;
|
||||
/* TODO */
|
||||
return lsquic_conn_log_cid(lconn);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
lsquic_conn_get_peer_ctx( const lsquic_conn_t *lconn)
|
||||
lsquic_conn_get_peer_ctx (struct lsquic_conn *lconn,
|
||||
const struct sockaddr *local_sa)
|
||||
{
|
||||
return lconn->cn_peer_ctx;
|
||||
const struct network_path *path;
|
||||
|
||||
path = lconn->cn_if->ci_get_path(lconn, local_sa);
|
||||
return path->np_peer_ctx;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn,
|
||||
const struct sockaddr *local, const struct sockaddr *peer)
|
||||
unsigned char
|
||||
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn, void *peer_ctx,
|
||||
const struct sockaddr *local_sa, const struct sockaddr *peer_sa)
|
||||
{
|
||||
assert(local->sa_family == peer->sa_family);
|
||||
switch (local->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
lconn->cn_flags |= LSCONN_HAS_PEER_SA|LSCONN_HAS_LOCAL_SA;
|
||||
memcpy(lconn->cn_local_addr, local, sizeof(struct sockaddr_in));
|
||||
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in));
|
||||
break;
|
||||
case AF_INET6:
|
||||
lconn->cn_flags |= LSCONN_HAS_PEER_SA|LSCONN_HAS_LOCAL_SA;
|
||||
memcpy(lconn->cn_local_addr, local, sizeof(struct sockaddr_in6));
|
||||
memcpy(lconn->cn_peer_addr, peer, sizeof(struct sockaddr_in6));
|
||||
break;
|
||||
}
|
||||
return lconn->cn_if->ci_record_addrs(lconn, peer_ctx, local_sa, peer_sa);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_get_sockaddr (const lsquic_conn_t *lconn,
|
||||
lsquic_conn_get_sockaddr (struct lsquic_conn *lconn,
|
||||
const struct sockaddr **local, const struct sockaddr **peer)
|
||||
{
|
||||
if ((lconn->cn_flags & (LSCONN_HAS_PEER_SA|LSCONN_HAS_LOCAL_SA)) ==
|
||||
(LSCONN_HAS_PEER_SA|LSCONN_HAS_LOCAL_SA))
|
||||
{
|
||||
*local = (struct sockaddr *) lconn->cn_local_addr;
|
||||
*peer = (struct sockaddr *) lconn->cn_peer_addr;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
const struct network_path *path;
|
||||
|
||||
path = lconn->cn_if->ci_get_path(lconn, NULL);
|
||||
*local = NP_LOCAL_SA(path);
|
||||
*peer = NP_PEER_SA(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,8 +68,8 @@ lsquic_conn_copy_and_release_pi_data (const lsquic_conn_t *conn,
|
|||
{
|
||||
assert(!(packet_in->pi_flags & PI_OWN_DATA));
|
||||
/* The size should be guarded in lsquic_engine_packet_in(): */
|
||||
assert(packet_in->pi_data_sz <= QUIC_MAX_PACKET_SZ);
|
||||
unsigned char *const copy = lsquic_mm_get_1370(&enpub->enp_mm);
|
||||
assert(packet_in->pi_data_sz <= GQUIC_MAX_PACKET_SZ);
|
||||
unsigned char *const copy = lsquic_mm_get_packet_in_buf(&enpub->enp_mm, 1370);
|
||||
if (!copy)
|
||||
{
|
||||
LSQ_WARN("cannot allocate memory to copy incoming packet data");
|
||||
|
@ -87,51 +82,6 @@ lsquic_conn_copy_and_release_pi_data (const lsquic_conn_t *conn,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
||||
struct lsquic_engine_public *enpub,
|
||||
lsquic_packet_in_t *packet_in)
|
||||
{
|
||||
size_t header_len, data_len;
|
||||
enum enc_level enc_level;
|
||||
size_t out_len = 0;
|
||||
unsigned char *copy = lsquic_mm_get_1370(&enpub->enp_mm);
|
||||
if (!copy)
|
||||
{
|
||||
LSQ_WARN("cannot allocate memory to copy incoming packet data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
header_len = packet_in->pi_header_sz;
|
||||
data_len = packet_in->pi_data_sz - packet_in->pi_header_sz;
|
||||
enc_level = lconn->cn_esf->esf_decrypt(lconn->cn_enc_session,
|
||||
lconn->cn_version, 0,
|
||||
packet_in->pi_packno, packet_in->pi_data,
|
||||
&header_len, data_len,
|
||||
lsquic_packet_in_nonce(packet_in),
|
||||
copy, 1370, &out_len);
|
||||
if ((enum enc_level) -1 == enc_level)
|
||||
{
|
||||
lsquic_mm_put_1370(&enpub->enp_mm, copy);
|
||||
EV_LOG_CONN_EVENT(lconn->cn_cid, "could not decrypt packet %"PRIu64,
|
||||
packet_in->pi_packno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(header_len + out_len <= 1370);
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
lsquic_mm_put_1370(&enpub->enp_mm, packet_in->pi_data);
|
||||
packet_in->pi_data = copy;
|
||||
packet_in->pi_flags |= PI_OWN_DATA | PI_DECRYPTED
|
||||
| (enc_level << PIBIT_ENC_LEV_SHIFT);
|
||||
packet_in->pi_header_sz = header_len;
|
||||
packet_in->pi_data_sz = out_len + header_len;
|
||||
EV_LOG_CONN_EVENT(lconn->cn_cid, "decrypted packet %"PRIu64" crypto: %s",
|
||||
packet_in->pi_packno, lsquic_enclev2str[ enc_level ]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_conn_quic_version (const lsquic_conn_t *lconn)
|
||||
{
|
||||
|
@ -142,24 +92,185 @@ lsquic_conn_quic_version (const lsquic_conn_t *lconn)
|
|||
}
|
||||
|
||||
|
||||
struct stack_st_X509 *
|
||||
lsquic_conn_get_server_cert_chain (struct lsquic_conn *lconn)
|
||||
enum lsquic_crypto_ver
|
||||
lsquic_conn_crypto_ver (const lsquic_conn_t *lconn)
|
||||
{
|
||||
return LSQ_CRY_QUIC;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
lsquic_conn_crypto_cipher (const lsquic_conn_t *lconn)
|
||||
{
|
||||
if (lconn->cn_enc_session)
|
||||
return lconn->cn_esf->esf_get_server_cert_chain(lconn->cn_enc_session);
|
||||
return lconn->cn_esf_c->esf_cipher(lconn->cn_enc_session);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
lsquic_conn_get_zero_rtt(const lsquic_conn_t *lconn,
|
||||
unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
int
|
||||
lsquic_conn_crypto_keysize (const lsquic_conn_t *lconn)
|
||||
{
|
||||
ssize_t ret = -1;
|
||||
if (lconn->cn_enc_session && (lconn->cn_flags & LSCONN_VER_SET))
|
||||
ret = lconn->cn_esf->esf_get_zero_rtt(lconn->cn_enc_session,
|
||||
lconn->cn_version,
|
||||
zero_rtt, zero_rtt_len);
|
||||
return ret;
|
||||
if (lconn->cn_enc_session)
|
||||
return lconn->cn_esf_c->esf_keysize(lconn->cn_enc_session);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_crypto_alg_keysize (const lsquic_conn_t *lconn)
|
||||
{
|
||||
if (lconn->cn_enc_session)
|
||||
return lconn->cn_esf_c->esf_alg_keysize(lconn->cn_enc_session);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct stack_st_X509 *
|
||||
lsquic_conn_get_server_cert_chain (struct lsquic_conn *lconn)
|
||||
{
|
||||
if (lconn->cn_enc_session)
|
||||
return lconn->cn_esf_c->esf_get_server_cert_chain(lconn->cn_enc_session);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_make_stream (struct lsquic_conn *lconn)
|
||||
{
|
||||
lconn->cn_if->ci_make_stream(lconn);
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
lsquic_conn_n_pending_streams (const struct lsquic_conn *lconn)
|
||||
{
|
||||
return lconn->cn_if->ci_n_pending_streams(lconn);
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
lsquic_conn_n_avail_streams (const struct lsquic_conn *lconn)
|
||||
{
|
||||
return lconn->cn_if->ci_n_avail_streams(lconn);
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
lsquic_conn_cancel_pending_streams (struct lsquic_conn *lconn, unsigned count)
|
||||
{
|
||||
return lconn->cn_if->ci_cancel_pending_streams(lconn, count);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_going_away (struct lsquic_conn *lconn)
|
||||
{
|
||||
lconn->cn_if->ci_going_away(lconn);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_close (struct lsquic_conn *lconn)
|
||||
{
|
||||
lconn->cn_if->ci_close(lconn);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_is_push_enabled (lsquic_conn_t *lconn)
|
||||
{
|
||||
return lconn->cn_if->ci_is_push_enabled(lconn);
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_conn_get_stream_by_id (struct lsquic_conn *lconn,
|
||||
lsquic_stream_id_t stream_id)
|
||||
{
|
||||
return lconn->cn_if->ci_get_stream_by_id(lconn, stream_id);
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_engine *
|
||||
lsquic_conn_get_engine (struct lsquic_conn *lconn)
|
||||
{
|
||||
return lconn->cn_if->ci_get_engine(lconn);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_conn_push_stream (struct lsquic_conn *lconn, void *hset,
|
||||
struct lsquic_stream *stream, const struct iovec* url,
|
||||
const struct iovec *authority, const struct lsquic_http_headers *headers)
|
||||
{
|
||||
return lconn->cn_if->ci_push_stream(lconn, hset, stream, url, authority,
|
||||
headers);
|
||||
}
|
||||
|
||||
|
||||
lsquic_conn_ctx_t *
|
||||
lsquic_conn_get_ctx (const struct lsquic_conn *lconn)
|
||||
{
|
||||
return lconn->cn_if->ci_get_ctx(lconn);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_set_ctx (struct lsquic_conn *lconn, lsquic_conn_ctx_t *ctx)
|
||||
{
|
||||
lconn->cn_if->ci_set_ctx(lconn, ctx);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_abort (struct lsquic_conn *lconn)
|
||||
{
|
||||
lconn->cn_if->ci_abort(lconn);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_generate_cid (lsquic_cid_t *cid, size_t len)
|
||||
{
|
||||
if (!len)
|
||||
/* If not set, generate ID between 8 and MAX_CID_LEN bytes in length */
|
||||
len = 8 + rand() % (MAX_CID_LEN - 7);
|
||||
RAND_bytes(cid->idbuf, len);
|
||||
cid->len = len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_generate_cid_gquic (lsquic_cid_t *cid)
|
||||
{
|
||||
lsquic_generate_cid(cid, GQUIC_CID_LEN);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_conn_retire_cid (struct lsquic_conn *lconn)
|
||||
{
|
||||
if (lconn->cn_if->ci_retire_cid)
|
||||
lconn->cn_if->ci_retire_cid(lconn);
|
||||
}
|
||||
|
||||
|
||||
enum LSQUIC_CONN_STATUS
|
||||
lsquic_conn_status (struct lsquic_conn *lconn, char *errbuf, size_t bufsz)
|
||||
{
|
||||
return lconn->cn_if->ci_status(lconn, errbuf, bufsz);
|
||||
}
|
||||
|
||||
|
||||
const lsquic_cid_t *
|
||||
lsquic_conn_log_cid (const struct lsquic_conn *lconn)
|
||||
{
|
||||
if (lconn->cn_if && lconn->cn_if->ci_get_log_cid)
|
||||
return lconn->cn_if->ci_get_log_cid(lconn);
|
||||
return CN_SCID(lconn);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
/*
|
||||
* lsquic_conn.h -- Connection interface
|
||||
*
|
||||
* There are two types of connections: full (lsquic_full_conn.h) and mini
|
||||
* (lsquic_mini_conn.h). The function pointers and struct in this header
|
||||
* file provide a unified interface engine.c can use to interact with
|
||||
* either of the connection types. For this to work, struct lsquic_conn
|
||||
* must be the first element of struct full_conn and struct mini_conn.
|
||||
*/
|
||||
#ifndef LSQUIC_CONN_H
|
||||
#define LSQUIC_CONN_H
|
||||
|
@ -15,7 +20,6 @@
|
|||
#endif
|
||||
|
||||
struct lsquic_conn;
|
||||
struct lsquic_enc_session;
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_packet_out;
|
||||
struct lsquic_packet_in;
|
||||
|
@ -30,8 +34,9 @@ enum lsquic_conn_flags {
|
|||
LSCONN_TICKED = (1 << 0),
|
||||
LSCONN_HAS_OUTGOING = (1 << 1),
|
||||
LSCONN_HASHED = (1 << 2),
|
||||
LSCONN_HAS_PEER_SA = (1 << 4),
|
||||
LSCONN_HAS_LOCAL_SA = (1 << 5),
|
||||
LSCONN_MINI = (1 << 3), /* This is a mini connection */
|
||||
LSCONN_UNUSED_4 = (1 << 4),
|
||||
LSCONN_UNUSED_5 = (1 << 5),
|
||||
LSCONN_HANDSHAKE_DONE = (1 << 6),
|
||||
LSCONN_CLOSING = (1 << 7),
|
||||
LSCONN_PEER_GOING_AWAY= (1 << 8),
|
||||
|
@ -42,8 +47,17 @@ enum lsquic_conn_flags {
|
|||
LSCONN_COI_ACTIVE = (1 <<13),
|
||||
LSCONN_COI_INACTIVE = (1 <<14),
|
||||
LSCONN_SEND_BLOCKED = (1 <<15), /* Send connection blocked frame */
|
||||
LSCONN_PROMOTED = (1 <<16), /* Promoted. Only set if LSCONN_MINI is set */
|
||||
LSCONN_NEVER_TICKABLE = (1 <<17), /* Do not put onto the Tickable Queue */
|
||||
LSCONN_UNUSED_18 = (1 <<18),
|
||||
LSCONN_ATTQ = (1 <<19),
|
||||
LSCONN_SKIP_ON_PROC = (1 <<20),
|
||||
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
|
||||
LSCONN_NO_CRYPTO = (1 <<21),
|
||||
#endif
|
||||
LSCONN_SERVER = (1 <<22),
|
||||
LSCONN_IETF = (1 <<23),
|
||||
LSCONN_RETRY_CONN = (1 <<24), /* This is a retry connection */
|
||||
};
|
||||
|
||||
/* A connection may have things to send and be closed at the same time.
|
||||
|
@ -51,10 +65,29 @@ enum lsquic_conn_flags {
|
|||
enum tick_st {
|
||||
TICK_SEND = (1 << 0),
|
||||
TICK_CLOSE = (1 << 1),
|
||||
TICK_PROMOTE = (1 << 2), /* Promote mini connection to full connection */
|
||||
};
|
||||
|
||||
#define TICK_QUIET 0
|
||||
|
||||
struct network_path
|
||||
{
|
||||
union {
|
||||
unsigned char buf[sizeof(struct sockaddr_in6)];
|
||||
struct sockaddr sockaddr;
|
||||
} np_local_addr_u;
|
||||
#define np_local_addr np_local_addr_u.buf
|
||||
unsigned char np_peer_addr[sizeof(struct sockaddr_in6)];
|
||||
void *np_peer_ctx;
|
||||
lsquic_cid_t np_dcid;
|
||||
unsigned short np_pack_size;
|
||||
unsigned char np_path_id; /* Used for logging */
|
||||
};
|
||||
|
||||
#define NP_LOCAL_SA(path_) (&(path_)->np_local_addr_u.sockaddr)
|
||||
#define NP_PEER_SA(path_) ((struct sockaddr *) (path_)->np_peer_addr)
|
||||
#define NP_IS_IPv6(path_) (AF_INET6 == NP_LOCAL_SA(path_)->sa_family)
|
||||
|
||||
struct conn_iface
|
||||
{
|
||||
enum tick_st
|
||||
|
@ -63,8 +96,16 @@ struct conn_iface
|
|||
void
|
||||
(*ci_packet_in) (struct lsquic_conn *, struct lsquic_packet_in *);
|
||||
|
||||
/* Note: all packets "checked out" by calling this method should be
|
||||
* returned back to the connection via ci_packet_sent() or
|
||||
* ci_packet_not_sent() calls before the connection is ticked next.
|
||||
* The connection, in turn, should not perform any extra processing
|
||||
* (especially schedule more packets) during any of these method
|
||||
* calls. This is because the checked out packets are not accounted
|
||||
* for by the congestion controller.
|
||||
*/
|
||||
struct lsquic_packet_out *
|
||||
(*ci_next_packet_to_send) (struct lsquic_conn *);
|
||||
(*ci_next_packet_to_send) (struct lsquic_conn *, size_t);
|
||||
|
||||
void
|
||||
(*ci_packet_sent) (struct lsquic_conn *, struct lsquic_packet_out *);
|
||||
|
@ -95,39 +136,198 @@ struct conn_iface
|
|||
const struct conn_stats *
|
||||
(*ci_get_stats) (struct lsquic_conn *);
|
||||
#endif
|
||||
|
||||
void
|
||||
(*ci_client_call_on_new) (struct lsquic_conn *);
|
||||
|
||||
enum LSQUIC_CONN_STATUS
|
||||
(*ci_status) (struct lsquic_conn *, char *errbuf, size_t bufsz);
|
||||
|
||||
unsigned
|
||||
(*ci_n_avail_streams) (const struct lsquic_conn *);
|
||||
|
||||
unsigned
|
||||
(*ci_n_pending_streams) (const struct lsquic_conn *);
|
||||
|
||||
unsigned
|
||||
(*ci_cancel_pending_streams) (struct lsquic_conn *, unsigned n);
|
||||
|
||||
void
|
||||
(*ci_going_away) (struct lsquic_conn *);
|
||||
|
||||
int
|
||||
(*ci_is_push_enabled) (struct lsquic_conn *);
|
||||
|
||||
struct lsquic_stream *
|
||||
(*ci_get_stream_by_id) (struct lsquic_conn *, lsquic_stream_id_t stream_id);
|
||||
|
||||
struct lsquic_engine *
|
||||
(*ci_get_engine) (struct lsquic_conn *);
|
||||
|
||||
struct lsquic_conn_ctx *
|
||||
(*ci_get_ctx) (const struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_set_ctx) (struct lsquic_conn *, struct lsquic_conn_ctx *);
|
||||
|
||||
void
|
||||
(*ci_make_stream) (struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_abort) (struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_retire_cid) (struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_close) (struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_stateless_reset) (struct lsquic_conn *);
|
||||
|
||||
int
|
||||
(*ci_crypto_keysize) (const struct lsquic_conn *);
|
||||
|
||||
int
|
||||
(*ci_crypto_alg_keysize) (const struct lsquic_conn *);
|
||||
|
||||
enum lsquic_crypto_ver
|
||||
(*ci_crypto_ver) (const struct lsquic_conn *);
|
||||
|
||||
const char *
|
||||
(*ci_crypto_cipher) (const struct lsquic_conn *);
|
||||
|
||||
int
|
||||
(*ci_push_stream) (struct lsquic_conn *, void *hset, struct lsquic_stream *,
|
||||
const struct iovec* url, const struct iovec* authority,
|
||||
const struct lsquic_http_headers *headers);
|
||||
|
||||
/* Use this to abort the connection when unlikely errors occur */
|
||||
void
|
||||
(*ci_internal_error) (struct lsquic_conn *, const char *format, ...)
|
||||
#if __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Abort connection with error */
|
||||
void
|
||||
(*ci_abort_error) (struct lsquic_conn *, int is_app, unsigned error_code,
|
||||
const char *format, ...)
|
||||
#if __GNUC__
|
||||
__attribute__((format(printf, 4, 5)))
|
||||
#endif
|
||||
;
|
||||
|
||||
void
|
||||
(*ci_tls_alert) (struct lsquic_conn *, uint8_t);
|
||||
|
||||
/* Returns 0 if connection is to be deleted immediately */
|
||||
lsquic_time_t
|
||||
(*ci_drain_time) (const struct lsquic_conn *);
|
||||
|
||||
/* Returns true if it's time to report the connection's CIDs' liveness */
|
||||
int
|
||||
(*ci_report_live) (struct lsquic_conn *, lsquic_time_t now);
|
||||
|
||||
/* If `local_sa' is NULL, return default path */
|
||||
struct network_path *
|
||||
(*ci_get_path) (struct lsquic_conn *, const struct sockaddr *local_sa);
|
||||
|
||||
unsigned char
|
||||
(*ci_record_addrs) (struct lsquic_conn *, void *peer_ctx,
|
||||
const struct sockaddr *local_sa, const struct sockaddr *peer_sa);
|
||||
|
||||
const lsquic_cid_t *
|
||||
(*ci_get_log_cid) (const struct lsquic_conn *);
|
||||
};
|
||||
|
||||
struct cert_susp_head;
|
||||
|
||||
#define LSCONN_CCE_BITS 3
|
||||
#define LSCONN_MAX_CCES (1 << LSCONN_CCE_BITS)
|
||||
|
||||
struct conn_cid_elem
|
||||
{
|
||||
struct lsquic_hash_elem cce_hash_el; /* Must be first element */
|
||||
lsquic_cid_t cce_cid;
|
||||
union {
|
||||
unsigned seqno;
|
||||
unsigned short port;
|
||||
} cce_u;
|
||||
#define cce_seqno cce_u.seqno
|
||||
#define cce_port cce_u.port
|
||||
enum conn_cce_flags {
|
||||
CCE_USED = 1 << 0, /* Connection ID has been used */
|
||||
CCE_SEQNO = 1 << 1, /* cce_seqno is set (CIDs in Initial
|
||||
* packets have no sequence number).
|
||||
*/
|
||||
CCE_REG = 1 << 2, /* CID has been registered */
|
||||
CCE_PORT = 1 << 3, /* It's not a CID element at all:
|
||||
* cce_port is the hash value.
|
||||
*/
|
||||
} cce_flags;
|
||||
};
|
||||
|
||||
struct lsquic_conn
|
||||
{
|
||||
void *cn_peer_ctx;
|
||||
struct lsquic_enc_session *cn_enc_session;
|
||||
const struct enc_session_funcs
|
||||
*cn_esf;
|
||||
lsquic_cid_t cn_cid;
|
||||
void *cn_enc_session;
|
||||
const struct enc_session_funcs_common
|
||||
*cn_esf_c;
|
||||
union {
|
||||
const struct enc_session_funcs_gquic *g;
|
||||
const struct enc_session_funcs_iquic *i;
|
||||
} cn_esf;
|
||||
#define cn_cid cn_cces[0].cce_cid
|
||||
STAILQ_ENTRY(lsquic_conn) cn_next_closed_conn;
|
||||
/* This and cn_next_closed_conn could be made into a union, as new full
|
||||
* connections are never closed.
|
||||
*/
|
||||
STAILQ_ENTRY(lsquic_conn) cn_next_new_full;
|
||||
TAILQ_ENTRY(lsquic_conn) cn_next_ticked;
|
||||
TAILQ_ENTRY(lsquic_conn) cn_next_out,
|
||||
cn_next_hash;
|
||||
TAILQ_ENTRY(lsquic_conn) cn_next_out;
|
||||
TAILQ_ENTRY(lsquic_conn) cn_next_susp_cert;
|
||||
/* Reuse this entry, as evanecsent connections are never suspended: */
|
||||
#define cn_next_pr cn_next_susp_cert
|
||||
const struct conn_iface *cn_if;
|
||||
const struct parse_funcs *cn_pf;
|
||||
struct attq_elem *cn_attq_elem;
|
||||
struct cert_susp_head *cn_cert_susp_head;
|
||||
lsquic_time_t cn_last_sent;
|
||||
lsquic_time_t cn_last_ticked;
|
||||
struct conn_cid_elem *cn_cces; /* At least one is available */
|
||||
enum lsquic_conn_flags cn_flags;
|
||||
enum lsquic_version cn_version;
|
||||
unsigned cn_hash;
|
||||
unsigned short cn_pack_size;
|
||||
unsigned char cn_local_addr[sizeof(struct sockaddr_in6)];
|
||||
union {
|
||||
unsigned char buf[sizeof(struct sockaddr_in6)];
|
||||
struct sockaddr sa;
|
||||
} cn_peer_addr_u;
|
||||
#define cn_peer_addr cn_peer_addr_u.buf
|
||||
enum lsquic_version cn_version:8;
|
||||
unsigned char cn_cces_mask; /* Those that are set */
|
||||
unsigned char cn_n_cces; /* Number of CCEs in cn_cces */
|
||||
unsigned char cn_cur_cce_idx;
|
||||
#if LSQUIC_TEST
|
||||
struct conn_cid_elem cn_cces_buf[8];
|
||||
#define LSCONN_INITIALIZER_CID(lsconn_, cid_) { \
|
||||
.cn_cces = (lsconn_).cn_cces_buf, \
|
||||
.cn_cces_buf[0].cce_seqno = 0, \
|
||||
.cn_cces_buf[0].cce_flags = CCE_SEQNO, \
|
||||
.cn_cces_buf[0].cce_cid = (cid_), \
|
||||
.cn_n_cces = 8, .cn_cces_mask = 1, }
|
||||
#define LSCONN_INITIALIZER_CIDLEN(lsconn_, len_) { \
|
||||
.cn_cces = (lsconn_).cn_cces_buf, \
|
||||
.cn_cces_buf[0].cce_seqno = 0, \
|
||||
.cn_cces_buf[0].cce_flags = CCE_SEQNO, \
|
||||
.cn_cces_buf[0].cce_cid = { .len = len_ }, \
|
||||
.cn_n_cces = 8, .cn_cces_mask = 1, }
|
||||
#define LSCONN_INITIALIZE(lsconn_) do { \
|
||||
(lsconn_)->cn_cces = (lsconn_)->cn_cces_buf; \
|
||||
(lsconn_)->cn_n_cces = 8; (lsconn_)->cn_cces_mask = 1; } while (0)
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn, const struct sockaddr *local,
|
||||
const struct sockaddr *peer);
|
||||
#define END_OF_CCES(conn) ((conn)->cn_cces + (conn)->cn_n_cces)
|
||||
|
||||
#define CN_SCID(conn) (&(conn)->cn_cces[(conn)->cn_cur_cce_idx].cce_cid)
|
||||
|
||||
unsigned char
|
||||
lsquic_conn_record_sockaddr (lsquic_conn_t *lconn, void *peer_ctx,
|
||||
const struct sockaddr *local_sa, const struct sockaddr *peer_sa);
|
||||
|
||||
int
|
||||
lsquic_conn_decrypt_packet (lsquic_conn_t *lconn,
|
||||
|
@ -137,6 +337,15 @@ int
|
|||
lsquic_conn_copy_and_release_pi_data (const lsquic_conn_t *conn,
|
||||
struct lsquic_engine_public *, struct lsquic_packet_in *);
|
||||
|
||||
void
|
||||
lsquic_generate_cid (lsquic_cid_t *cid, size_t len);
|
||||
|
||||
void
|
||||
lsquic_generate_cid_gquic (lsquic_cid_t *cid);
|
||||
|
||||
void
|
||||
lsquic_conn_retire_cid (lsquic_conn_t *lconn);
|
||||
|
||||
#define lsquic_conn_adv_time(c) ((c)->cn_attq_elem->ae_adv_time)
|
||||
|
||||
#if LSQUIC_CONN_STATS
|
||||
|
@ -164,6 +373,7 @@ struct conn_stats {
|
|||
unsigned long stream_frames;
|
||||
unsigned long acks;
|
||||
unsigned long packets; /* Number of sent packets */
|
||||
unsigned long acked_via_loss; /* Number of packets acked via loss record */
|
||||
unsigned long retx_packets; /* Number of retransmitted packets */
|
||||
unsigned long bytes; /* Overall bytes out */
|
||||
unsigned long headers_uncomp; /* Sum of uncompressed header bytes */
|
||||
|
|
|
@ -19,6 +19,10 @@ struct lsquic_send_ctl;
|
|||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats;
|
||||
#endif
|
||||
struct qpack_enc_hdl;
|
||||
struct qpack_dec_hdl;
|
||||
struct h3_prio_tree;
|
||||
struct network_path;
|
||||
|
||||
struct lsquic_conn_public {
|
||||
struct lsquic_streams_tailq sending_streams, /* Send RST_STREAM, BLOCKED, and WUF frames */
|
||||
|
@ -33,11 +37,25 @@ struct lsquic_conn_public {
|
|||
struct malo *packet_out_malo;
|
||||
struct lsquic_conn *lconn;
|
||||
struct lsquic_mm *mm;
|
||||
struct headers_stream *hs;
|
||||
union {
|
||||
struct {
|
||||
struct headers_stream *hs;
|
||||
} gquic;
|
||||
struct {
|
||||
struct qpack_enc_hdl *qeh;
|
||||
struct qpack_dec_hdl *qdh;
|
||||
struct h3_prio_tree *prio_tree;
|
||||
struct lsquic_hash *promises;
|
||||
} ietf;
|
||||
} u;
|
||||
enum {
|
||||
CP_STREAM_UNBLOCKED = 1 << 0, /* Set when a stream becomes unblocked */
|
||||
} cp_flags;
|
||||
struct lsquic_send_ctl *send_ctl;
|
||||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats *conn_stats;
|
||||
#endif
|
||||
const struct network_path *path;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -198,6 +198,75 @@ int get_common_cert(uint64_t hash, uint32_t index, lsquic_str_t *buf)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
comp_ls_str (lsquic_str_t * a, const void * b, size_t b_len)
|
||||
{
|
||||
size_t a_len;
|
||||
int r;
|
||||
|
||||
a_len = lsquic_str_len(a);
|
||||
r = memcmp(lsquic_str_buf(a), b, a_len < b_len ? a_len : b_len);
|
||||
if (r)
|
||||
return r;
|
||||
else
|
||||
return (a_len > b_len) - (b_len > a_len);
|
||||
}
|
||||
|
||||
|
||||
/* 0, matched -1, error */
|
||||
int match_common_cert(lsquic_str_t * cert, lsquic_str_t * common_set_hashes,
|
||||
uint64_t* out_hash, uint32_t* out_index)
|
||||
{
|
||||
size_t i, j;
|
||||
int n;
|
||||
uint64_t hash;
|
||||
size_t min, max, mid;
|
||||
|
||||
if (lsquic_str_len(common_set_hashes) % sizeof(uint64_t) != 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < lsquic_str_len(common_set_hashes) / sizeof(uint64_t); i++)
|
||||
{
|
||||
memcpy(&hash, lsquic_str_buf(common_set_hashes) + i * sizeof(uint64_t),
|
||||
sizeof(uint64_t));
|
||||
|
||||
for (j = 0; j < common_certs_num; j++)
|
||||
{
|
||||
if (common_cert_set[j].hash != hash)
|
||||
continue;
|
||||
|
||||
if (common_cert_set[j].num_certs == 0)
|
||||
continue;
|
||||
|
||||
min = 0;
|
||||
max = common_cert_set[j].num_certs - 1;
|
||||
while (max >= min)
|
||||
{
|
||||
mid = min + ((max - min) / 2);
|
||||
n = comp_ls_str(cert, common_cert_set[j].certs[mid],
|
||||
common_cert_set[j].lens[mid]);
|
||||
if (n < 0)
|
||||
{
|
||||
if (mid == 0)
|
||||
break;
|
||||
max = mid - 1;
|
||||
}
|
||||
else if (n > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
*out_hash = hash;
|
||||
*out_index = mid;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* result is written to dict */
|
||||
static void
|
||||
make_zlib_dict_for_entries(cert_entry_t *entries,
|
||||
|
@ -240,6 +309,59 @@ void get_certs_hash(lsquic_str_t *certs, size_t certs_count, uint64_t *hashs)
|
|||
}
|
||||
|
||||
|
||||
static void get_certs_entries(lsquic_str_t **certs, size_t certs_count,
|
||||
lsquic_str_t *client_common_set_hashes,
|
||||
lsquic_str_t *client_cached_cert_hashes,
|
||||
cert_entry_t *entries)
|
||||
{
|
||||
size_t i;
|
||||
int j;
|
||||
cert_entry_t *entry;
|
||||
uint64_t hash, cached_hash;
|
||||
bool cached;
|
||||
|
||||
const bool cached_valid = (lsquic_str_len(client_cached_cert_hashes) % sizeof(uint64_t) == 0)
|
||||
&& (lsquic_str_len(client_cached_cert_hashes) > 0);
|
||||
|
||||
assert(&entries[certs_count - 1]);
|
||||
|
||||
for (i = 0; i<certs_count; ++i)
|
||||
{
|
||||
entry = &entries[i];
|
||||
if (cached_valid)
|
||||
{
|
||||
cached = false;
|
||||
hash = fnv1a_64((const uint8_t *)lsquic_str_buf(certs[i]), lsquic_str_len(certs[i]));
|
||||
|
||||
for (j = 0; j < (int)lsquic_str_len(client_cached_cert_hashes);
|
||||
j += sizeof(uint64_t))
|
||||
{
|
||||
memcpy(&cached_hash, lsquic_str_buf(client_cached_cert_hashes) + j,
|
||||
sizeof(uint64_t));
|
||||
if (hash != cached_hash)
|
||||
continue;
|
||||
|
||||
entry->type = ENTRY_CACHED;
|
||||
entry->hash = hash;
|
||||
cached = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cached)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (0 == match_common_cert(certs[i], client_common_set_hashes,
|
||||
&entry->set_hash, &entry->index))
|
||||
{
|
||||
entry->type = ENTRY_COMMON;
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->type = ENTRY_COMPRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_entries_size(cert_entry_t *entries, size_t entries_count)
|
||||
{
|
||||
size_t i;
|
||||
|
@ -265,7 +387,6 @@ size_t get_entries_size(cert_entry_t *entries, size_t entries_count)
|
|||
return entries_size;
|
||||
}
|
||||
|
||||
|
||||
void serialize_cert_entries(uint8_t* out, int *out_len, cert_entry_t *entries,
|
||||
size_t entries_count)
|
||||
{
|
||||
|
@ -438,6 +559,116 @@ static int parse_entries(const unsigned char **in_out, const unsigned char *cons
|
|||
}
|
||||
|
||||
|
||||
/* return 0 for OK */
|
||||
int compress_certs(lsquic_str_t **certs, size_t certs_count,
|
||||
lsquic_str_t *client_common_set_hashes,
|
||||
lsquic_str_t *client_cached_cert_hashes,
|
||||
lsquic_str_t *result)
|
||||
{
|
||||
int rv;
|
||||
size_t i;
|
||||
size_t uncompressed_size = 0, compressed_size = 0 ;
|
||||
z_stream z;
|
||||
lsquic_str_t *dict;
|
||||
size_t entries_size, result_length;
|
||||
int out_len;
|
||||
uint8_t* out;
|
||||
uint32_t tmp_size_32;
|
||||
cert_entry_t *entries;
|
||||
|
||||
entries = malloc(sizeof(cert_entry_t) * certs_count);
|
||||
if (!entries)
|
||||
return -1;
|
||||
|
||||
dict = lsquic_str_new(NULL, 0);
|
||||
if (!dict)
|
||||
goto err;
|
||||
|
||||
get_certs_entries(certs, certs_count, client_common_set_hashes,
|
||||
client_cached_cert_hashes, entries);
|
||||
|
||||
for (i = 0; i < certs_count; i++)
|
||||
{
|
||||
if (entries[i].type == ENTRY_COMPRESSED)
|
||||
{
|
||||
/*uint32_t length + cert content*/
|
||||
uncompressed_size += 4 + lsquic_str_len(certs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (uncompressed_size > 0)
|
||||
{
|
||||
memset(&z, 0, sizeof(z));
|
||||
if (Z_OK != deflateInit(&z, Z_DEFAULT_COMPRESSION))
|
||||
goto err;
|
||||
|
||||
make_zlib_dict_for_entries(entries, certs, certs_count, dict);
|
||||
if(Z_OK != deflateSetDictionary(&z, (const unsigned char *)lsquic_str_buf(dict), lsquic_str_len(dict)))
|
||||
goto err;
|
||||
compressed_size = deflateBound(&z, uncompressed_size);
|
||||
}
|
||||
|
||||
entries_size = get_entries_size(entries, certs_count);
|
||||
result_length = entries_size + (uncompressed_size > 0 ? 4 : 0) +
|
||||
compressed_size;
|
||||
lsquic_str_prealloc(result, result_length);
|
||||
|
||||
out = (unsigned char *)lsquic_str_buf(result);
|
||||
serialize_cert_entries(out, &out_len, entries, certs_count);
|
||||
out += entries_size;
|
||||
|
||||
if (uncompressed_size == 0)
|
||||
{
|
||||
lsquic_str_setlen(result, entries_size);
|
||||
rv = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
tmp_size_32 = uncompressed_size;
|
||||
memcpy(out, &tmp_size_32, sizeof(uint32_t));
|
||||
out += sizeof(uint32_t);
|
||||
|
||||
z.next_out = out;
|
||||
z.avail_out = compressed_size;
|
||||
|
||||
for (i = 0; i < certs_count; ++i)
|
||||
{
|
||||
if (entries[i].type != ENTRY_COMPRESSED)
|
||||
continue;
|
||||
|
||||
tmp_size_32 = lsquic_str_len(certs[i]);
|
||||
z.next_in = (uint8_t*)(&tmp_size_32);
|
||||
z.avail_in = sizeof(tmp_size_32);
|
||||
if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
|
||||
goto err;
|
||||
z.next_in = (unsigned char *)lsquic_str_buf(certs[i]);
|
||||
z.avail_in = lsquic_str_len(certs[i]);
|
||||
if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
|
||||
goto err;
|
||||
}
|
||||
|
||||
z.avail_in = 0;
|
||||
if (Z_STREAM_END != deflate(&z, Z_FINISH))
|
||||
goto err;
|
||||
|
||||
rv = 0;
|
||||
result_length -= z.avail_out;
|
||||
lsquic_str_setlen(result, result_length);
|
||||
|
||||
cleanup:
|
||||
free(entries);
|
||||
if (dict)
|
||||
lsquic_str_delete(dict);
|
||||
if (uncompressed_size)
|
||||
deflateEnd(&z);
|
||||
return rv;
|
||||
|
||||
err:
|
||||
rv = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* 0: ok */
|
||||
int decompress_certs(const unsigned char *in, const unsigned char *in_end,
|
||||
lsquic_str_t *cached_certs, size_t cached_certs_count,
|
||||
|
|
|
@ -10,6 +10,7 @@ struct lsquic_str;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
enum entry_type {
|
||||
END_OF_LIST = 0,
|
||||
ENTRY_COMPRESSED = 1,
|
||||
|
@ -24,6 +25,7 @@ typedef struct cert_entry_st {
|
|||
uint64_t set_hash;
|
||||
} cert_entry_t;
|
||||
|
||||
|
||||
typedef struct common_cert_st
|
||||
{
|
||||
size_t num_certs;
|
||||
|
@ -34,6 +36,16 @@ typedef struct common_cert_st
|
|||
|
||||
struct lsquic_str * get_common_certs_hash();
|
||||
|
||||
|
||||
int get_common_cert(uint64_t hash, uint32_t index, struct lsquic_str *buf);
|
||||
int match_common_cert(struct lsquic_str * cert, struct lsquic_str * common_set_hashes,
|
||||
uint64_t* out_hash, uint32_t* out_index);
|
||||
|
||||
int compress_certs(struct lsquic_str **certs, size_t certs_count,
|
||||
struct lsquic_str *client_common_set_hashes,
|
||||
struct lsquic_str *client_cached_cert_hashes,
|
||||
struct lsquic_str *result);
|
||||
|
||||
int get_certs_count(struct lsquic_str *compressed_crt_buf);
|
||||
int decompress_certs(const unsigned char *in, const unsigned char *in_end,
|
||||
struct lsquic_str *cached_certs, size_t cached_certs_count,
|
||||
|
@ -43,8 +55,10 @@ int decompress_certs(const unsigned char *in, const unsigned char *in_end,
|
|||
void
|
||||
lsquic_crt_cleanup (void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //__LSQUIC_CRT_COMPRESS_H__
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_crypto.h"
|
||||
#include "lsquic_alarmset.h"
|
||||
#include "lsquic_parse.h"
|
||||
#include "lsquic_util.h"
|
||||
#include "lsquic_str.h"
|
||||
|
@ -81,17 +80,6 @@ void fnv1a_inc(uint128 *hash, const uint8_t *data, int len)
|
|||
}
|
||||
}
|
||||
|
||||
uint128 fnv1a_128_2(const uint8_t * data1, int len1, const uint8_t *data2, int len2)
|
||||
{
|
||||
uint128 hash;
|
||||
memcpy(&hash, &s_init_hash, 16);
|
||||
|
||||
fnv1a_inc(&hash, data1, len1);
|
||||
if (data2)
|
||||
fnv1a_inc(&hash, data2, len2);
|
||||
return hash;
|
||||
}
|
||||
|
||||
uint128 fnv1a_128_3(const uint8_t *data1, int len1,
|
||||
const uint8_t *data2, int len2,
|
||||
const uint8_t *data3, int len3)
|
||||
|
@ -105,12 +93,6 @@ uint128 fnv1a_128_3(const uint8_t *data1, int len1,
|
|||
return hash;
|
||||
}
|
||||
|
||||
void fnv1a_128_2_s(const uint8_t * data1, int len1, const uint8_t * data2, int len2, uint8_t *md)
|
||||
{
|
||||
uint128 hash = fnv1a_128_2(data1, len1, data2, len2);
|
||||
memcpy(md, (void *)&hash, 16);
|
||||
}
|
||||
|
||||
/* HS_PKT_HASH_LENGTH bytes of md */
|
||||
void serialize_fnv128_short(uint128 v, uint8_t *md)
|
||||
{
|
||||
|
@ -167,16 +149,6 @@ void fnv1a_inc(uint128 *hash, const uint8_t * data, int len)
|
|||
}
|
||||
|
||||
|
||||
uint128 fnv1a_128_2(const uint8_t * data1, int len1, const uint8_t * data2, int len2)
|
||||
{
|
||||
uint128 hash = {UINT64_C(7809847782465536322), UINT64_C(7113472399480571277)};
|
||||
fnv1a_inc(&hash, data1, len1);
|
||||
if (data2)
|
||||
fnv1a_inc(&hash, data2, len2);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
uint128 fnv1a_128_3(const uint8_t * data1, int len1,
|
||||
const uint8_t * data2, int len2,
|
||||
const uint8_t * data3, int len3)
|
||||
|
@ -189,13 +161,6 @@ uint128 fnv1a_128_3(const uint8_t * data1, int len1,
|
|||
}
|
||||
|
||||
|
||||
void fnv1a_128_2_s(const uint8_t * data1, int len1, const uint8_t * data2, int len2, uint8_t *md)
|
||||
{
|
||||
uint128 hash = fnv1a_128_2(data1, len1, data2, len2);
|
||||
memcpy(md, (void *)&hash.lo_, 8);
|
||||
memcpy(md + 8, (void *)&hash.hi_, 8);
|
||||
}
|
||||
|
||||
/* HS_PKT_HASH_LENGTH bytes of md */
|
||||
void serialize_fnv128_short(uint128 v, uint8_t *md)
|
||||
{
|
||||
|
@ -206,55 +171,8 @@ void serialize_fnv128_short(uint128 v, uint8_t *md)
|
|||
|
||||
#endif
|
||||
|
||||
uint128 fnv1a_128(const uint8_t * data, int len)
|
||||
{
|
||||
return fnv1a_128_2(data, len , NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
void fnv1a_128_s(const uint8_t * data, int len, uint8_t *md)
|
||||
{
|
||||
fnv1a_128_2_s(data, len, NULL, 0, md);
|
||||
}
|
||||
|
||||
|
||||
/* packet data = header + MD + payload */
|
||||
/* return 0 if OK */
|
||||
int verify_hs_pkt(const uint8_t *pkg_data, size_t header_len, size_t pkg_len)
|
||||
{
|
||||
uint8_t md[HS_PKT_HASH_LENGTH];
|
||||
uint128 hash;
|
||||
if (pkg_len < header_len + HS_PKT_HASH_LENGTH)
|
||||
return -1;
|
||||
|
||||
hash = fnv1a_128_2(pkg_data, header_len, pkg_data + header_len + HS_PKT_HASH_LENGTH,
|
||||
pkg_len - header_len - HS_PKT_HASH_LENGTH);
|
||||
serialize_fnv128_short(hash, md);
|
||||
return memcmp(md, pkg_data + header_len, HS_PKT_HASH_LENGTH);
|
||||
}
|
||||
|
||||
/* packet data = header + MD + payload, update the MD part */
|
||||
int update_hs_pkt_hash(uint8_t *pkg_data, int header_len, int pkg_len)
|
||||
{
|
||||
uint8_t md[HS_PKT_HASH_LENGTH];
|
||||
uint128 hash;
|
||||
if (pkg_len < header_len + HS_PKT_HASH_LENGTH)
|
||||
return -1;
|
||||
|
||||
hash = fnv1a_128_2(pkg_data, header_len, pkg_data + header_len + HS_PKT_HASH_LENGTH,
|
||||
pkg_len - header_len - HS_PKT_HASH_LENGTH);
|
||||
serialize_fnv128_short(hash, md);
|
||||
memcpy(pkg_data + header_len, md, HS_PKT_HASH_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_hs_pkt_hash_len()
|
||||
{
|
||||
return HS_PKT_HASH_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
void sha256(const uint8_t *buf, int len, uint8_t *h)
|
||||
static void sha256(const uint8_t *buf, int len, uint8_t *h)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
|
@ -499,17 +417,6 @@ int aes_aead_dec(EVP_AEAD_CTX *key,
|
|||
}
|
||||
}
|
||||
|
||||
/* aes 128, 16 bytes */
|
||||
int aes_get_key_length()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
void gen_nonce_s(char *buf, int length)
|
||||
{
|
||||
rand_bytes(buf, length);
|
||||
}
|
||||
|
||||
/* 32 bytes client nonce with 4 bytes tm, 8 bytes orbit */
|
||||
void gen_nonce_c(unsigned char *buf, uint64_t orbit)
|
||||
{
|
||||
|
@ -558,17 +465,6 @@ X509 *bio_to_crt(const void *buf, int len, int type)
|
|||
}
|
||||
|
||||
|
||||
int read_rsa_priv_key(const uint8_t *buf, int len, EVP_PKEY *pkey)
|
||||
{
|
||||
|
||||
RSA *rsa = RSA_private_key_from_bytes(buf, len);
|
||||
if (!rsa)
|
||||
return -1;
|
||||
|
||||
return EVP_PKEY_assign_RSA(pkey, rsa);
|
||||
}
|
||||
|
||||
|
||||
int gen_prof(const uint8_t *chlo_data, size_t chlo_data_len,
|
||||
const uint8_t *scfg_data, uint32_t scfg_data_len,
|
||||
const EVP_PKEY *priv_key, uint8_t *buf, size_t *buf_len)
|
||||
|
|
|
@ -13,6 +13,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct lsquic_str;
|
||||
struct evp_aead_ctx_st;
|
||||
struct evp_pkey_st;
|
||||
struct x509_st;
|
||||
|
||||
#if defined( __x86_64 )||defined( __x86_64__ )
|
||||
typedef __uint128_t uint128;
|
||||
|
@ -53,49 +56,32 @@ int c255_gen_share_key(unsigned char *priv_key, unsigned char *peer_pub_key, uns
|
|||
|
||||
uint64_t fnv1a_64(const uint8_t * data, int len);
|
||||
void fnv1a_64_s(const uint8_t * data, int len, char *md);
|
||||
uint128 fnv1a_128(const uint8_t * data, int len);
|
||||
void fnv1a_128_s(const uint8_t * data , int len, uint8_t *md);
|
||||
uint128 fnv1a_128_2(const uint8_t * data1, int len1, const uint8_t * data2, int len2);
|
||||
uint128 fnv1a_128_3(const uint8_t * data1, int len1,
|
||||
const uint8_t * data2, int len2,
|
||||
const uint8_t * data3, int len3);
|
||||
void fnv1a_128_2_s(const uint8_t * data1, int len1, const uint8_t * data2, int len2, uint8_t *md);
|
||||
void serialize_fnv128_short(uint128 v, uint8_t *md);
|
||||
|
||||
|
||||
/* before session handshake complete */
|
||||
int verify_hs_pkt(const uint8_t *pkg_data, size_t header_len, size_t pkg_len);
|
||||
int update_hs_pkt_hash(uint8_t *pkg_data, int header_len, int pkg_len);
|
||||
int get_hs_pkt_hash_len();
|
||||
|
||||
|
||||
/*16 bytes of h outputted */
|
||||
void sha256(const uint8_t *buf, int len, uint8_t *h);
|
||||
|
||||
|
||||
/* Encrypt plaint text to cipher test */
|
||||
int aes_aead_enc(EVP_AEAD_CTX *key,
|
||||
int aes_aead_enc(struct evp_aead_ctx_st *key,
|
||||
const uint8_t *ad, size_t ad_len,
|
||||
const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *plain, size_t plain_len,
|
||||
uint8_t *cypher, size_t *cypher_len);
|
||||
|
||||
int aes_aead_dec(EVP_AEAD_CTX *key,
|
||||
int aes_aead_dec(struct evp_aead_ctx_st *key,
|
||||
const uint8_t *ad, size_t ad_len,
|
||||
const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *cypher, size_t cypher_len,
|
||||
uint8_t *plain, size_t *plain_len);
|
||||
|
||||
int aes_get_key_length();
|
||||
|
||||
void gen_nonce_s(char *buf, int length);
|
||||
|
||||
/* 32 bytes client nonce with 4 bytes tm, 8 bytes orbit */
|
||||
void gen_nonce_c(unsigned char *buf, uint64_t orbit);
|
||||
|
||||
EVP_PKEY *PEM_to_key(const char *buf, int len);
|
||||
struct evp_pkey_st *PEM_to_key(const char *buf, int len);
|
||||
|
||||
X509 *bio_to_crt(const void *buf, int len, int type);
|
||||
struct x509_st *bio_to_crt(const void *buf, int len, int type);
|
||||
|
||||
int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_len,
|
||||
uint16_t c_key_len, uint8_t *c_key,
|
||||
|
@ -108,13 +94,13 @@ void lshkdf_extract(const unsigned char *ikm, int ikm_len, const unsigned char *
|
|||
|
||||
int gen_prof(const uint8_t *chlo_data, size_t chlo_data_len,
|
||||
const uint8_t *scfg_data, uint32_t scfg_data_len,
|
||||
const EVP_PKEY *priv_key, uint8_t *buf, size_t *len);
|
||||
const struct evp_pkey_st *priv_key, uint8_t *buf, size_t *len);
|
||||
int verify_prof0(const uint8_t *chlo_data, size_t chlo_data_len,
|
||||
const uint8_t *scfg_data, uint32_t scfg_data_len,
|
||||
const EVP_PKEY *pub_key, const uint8_t *buf, size_t len);
|
||||
const struct evp_pkey_st *pub_key, const uint8_t *buf, size_t len);
|
||||
|
||||
int verify_prof(const uint8_t *chlo_data, size_t chlo_data_len, struct lsquic_str * scfg,
|
||||
const EVP_PKEY *pub_key, const uint8_t *buf, size_t len);
|
||||
const struct evp_pkey_st *pub_key, const uint8_t *buf, size_t len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -8,17 +8,29 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#ifdef WIN32
|
||||
#include <vc_compat.h>
|
||||
#endif
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_cubic.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_util.h"
|
||||
#include "lsquic_cong_ctl.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_conn_flow.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_rtt.h"
|
||||
#include "lsquic_conn_public.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_out.h"
|
||||
#include "lsquic_cubic.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_CUBIC
|
||||
#define LSQUIC_LOG_CONN_ID cubic->cu_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(cubic->cu_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#define FAST_CONVERGENCE 1
|
||||
|
@ -31,7 +43,7 @@
|
|||
static void
|
||||
cubic_reset (struct lsquic_cubic *cubic)
|
||||
{
|
||||
memset(cubic, 0, offsetof(struct lsquic_cubic, cu_cid));
|
||||
memset(cubic, 0, offsetof(struct lsquic_cubic, cu_conn));
|
||||
cubic->cu_cwnd = 32 * TCP_MSS;
|
||||
cubic->cu_last_max_cwnd = 32 * TCP_MSS;
|
||||
cubic->cu_tcp_cwnd = 32 * TCP_MSS;
|
||||
|
@ -95,13 +107,23 @@ cubic_update (struct lsquic_cubic *cubic, lsquic_time_t now, unsigned n_bytes)
|
|||
|
||||
|
||||
void
|
||||
lsquic_cubic_init_ext (struct lsquic_cubic *cubic, lsquic_cid_t cid,
|
||||
enum cubic_flags flags)
|
||||
lsquic_cubic_set_flags (struct lsquic_cubic *cubic, enum cubic_flags flags)
|
||||
{
|
||||
LSQ_DEBUG("%s(cubic, 0x%X)", __func__, flags);
|
||||
cubic->cu_flags = flags;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lsquic_cubic_init (void *cong_ctl, const struct lsquic_conn_public *conn_pub,
|
||||
enum quic_ft_bit UNUSED_retx_frames)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
cubic_reset(cubic);
|
||||
cubic->cu_ssthresh = 10000 * TCP_MSS; /* Emulate "unbounded" slow start */
|
||||
cubic->cu_cid = cid;
|
||||
cubic->cu_flags = flags;
|
||||
cubic->cu_conn = conn_pub->lconn;
|
||||
cubic->cu_rtt_stats = &conn_pub->rtt_stats;
|
||||
cubic->cu_flags = DEFAULT_CUBIC_FLAGS;
|
||||
#ifndef NDEBUG
|
||||
const char *s;
|
||||
s = getenv("LSQUIC_CUBIC_SAMPLING_RATE");
|
||||
|
@ -110,7 +132,7 @@ lsquic_cubic_init_ext (struct lsquic_cubic *cubic, lsquic_cid_t cid,
|
|||
else
|
||||
#endif
|
||||
cubic->cu_sampling_rate = 100000;
|
||||
LSQ_DEBUG("%s(cubic, %"PRIu64", 0x%X)", __func__, cid, flags);
|
||||
LSQ_DEBUG("%s(cubic, $conn)", __func__);
|
||||
LSQ_INFO("initialized");
|
||||
}
|
||||
|
||||
|
@ -127,18 +149,23 @@ lsquic_cubic_init_ext (struct lsquic_cubic *cubic, lsquic_cid_t cid,
|
|||
} while (0)
|
||||
|
||||
|
||||
void
|
||||
lsquic_cubic_was_quiet (struct lsquic_cubic *cubic, lsquic_time_t now)
|
||||
static void
|
||||
lsquic_cubic_was_quiet (void *cong_ctl, lsquic_time_t now, uint64_t in_flight)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
LSQ_DEBUG("%s(cubic, %"PRIu64")", __func__, now);
|
||||
cubic->cu_epoch_start = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now_time,
|
||||
lsquic_time_t rtt, int app_limited, unsigned n_bytes)
|
||||
static void
|
||||
lsquic_cubic_ack (void *cong_ctl, struct lsquic_packet_out *packet_out,
|
||||
unsigned n_bytes, lsquic_time_t now_time, int app_limited)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
lsquic_time_t rtt;
|
||||
|
||||
rtt = now_time - packet_out->po_sent;
|
||||
LSQ_DEBUG("%s(cubic, %"PRIu64", %"PRIu64", %d, %u)", __func__, now_time, rtt,
|
||||
app_limited, n_bytes);
|
||||
if (0 == cubic->cu_min_delay || rtt < cubic->cu_min_delay)
|
||||
|
@ -162,9 +189,10 @@ lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now_time,
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_cubic_loss (struct lsquic_cubic *cubic)
|
||||
static void
|
||||
lsquic_cubic_loss (void *cong_ctl)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
LSQ_DEBUG("%s(cubic)", __func__);
|
||||
cubic->cu_epoch_start = 0;
|
||||
if (FAST_CONVERGENCE && cubic->cu_cwnd < cubic->cu_last_max_cwnd)
|
||||
|
@ -180,9 +208,10 @@ lsquic_cubic_loss (struct lsquic_cubic *cubic)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_cubic_timeout (struct lsquic_cubic *cubic)
|
||||
static void
|
||||
lsquic_cubic_timeout (void *cong_ctl)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
unsigned long cwnd;
|
||||
|
||||
cwnd = cubic->cu_cwnd;
|
||||
|
@ -194,3 +223,61 @@ lsquic_cubic_timeout (struct lsquic_cubic *cubic)
|
|||
LSQ_INFO("timeout, cwnd: %lu", cubic->cu_cwnd);
|
||||
LOG_CWND(cubic);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lsquic_cubic_cleanup (void *cong_ctl)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
lsquic_cubic_get_cwnd (void *cong_ctl)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
return cubic->cu_cwnd;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
in_slow_start (void *cong_ctl)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
return cubic->cu_cwnd < cubic->cu_ssthresh;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
lsquic_cubic_pacing_rate (void *cong_ctl, int in_recovery)
|
||||
{
|
||||
struct lsquic_cubic *const cubic = cong_ctl;
|
||||
uint64_t bandwidth, pacing_rate;
|
||||
lsquic_time_t srtt;
|
||||
|
||||
srtt = lsquic_rtt_stats_get_srtt(cubic->cu_rtt_stats);
|
||||
if (srtt == 0)
|
||||
srtt = 50000;
|
||||
bandwidth = cubic->cu_cwnd * 1000000 / srtt;
|
||||
if (in_slow_start(cubic))
|
||||
pacing_rate = bandwidth * 2;
|
||||
else if (in_recovery)
|
||||
pacing_rate = bandwidth;
|
||||
else
|
||||
pacing_rate = bandwidth + bandwidth / 4;
|
||||
|
||||
return pacing_rate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const struct cong_ctl_if lsquic_cong_cubic_if =
|
||||
{
|
||||
.cci_ack = lsquic_cubic_ack,
|
||||
.cci_cleanup = lsquic_cubic_cleanup,
|
||||
.cci_get_cwnd = lsquic_cubic_get_cwnd,
|
||||
.cci_init = lsquic_cubic_init,
|
||||
.cci_pacing_rate = lsquic_cubic_pacing_rate,
|
||||
.cci_loss = lsquic_cubic_loss,
|
||||
.cci_timeout = lsquic_cubic_timeout,
|
||||
.cci_was_quiet = lsquic_cubic_was_quiet,
|
||||
};
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef LSQUIC_CUBIC_H
|
||||
#define LSQUIC_CUBIC_H 1
|
||||
|
||||
struct lsquic_conn;
|
||||
|
||||
struct lsquic_cubic {
|
||||
lsquic_time_t cu_min_delay;
|
||||
lsquic_time_t cu_epoch_start;
|
||||
|
@ -15,7 +17,10 @@ struct lsquic_cubic {
|
|||
unsigned long cu_cwnd;
|
||||
unsigned long cu_tcp_cwnd;
|
||||
unsigned long cu_ssthresh;
|
||||
lsquic_cid_t cu_cid; /* Used for logging */
|
||||
const struct lsquic_conn
|
||||
*cu_conn; /* Used for logging */
|
||||
const struct lsquic_rtt_stats
|
||||
*cu_rtt_stats;
|
||||
enum cubic_flags {
|
||||
CU_TCP_FRIENDLY = (1 << 0),
|
||||
} cu_flags;
|
||||
|
@ -27,28 +32,9 @@ struct lsquic_cubic {
|
|||
|
||||
#define TCP_MSS 1460
|
||||
|
||||
void
|
||||
lsquic_cubic_init_ext (struct lsquic_cubic *, lsquic_cid_t, enum cubic_flags);
|
||||
|
||||
#define lsquic_cubic_init(cubic, cid) \
|
||||
lsquic_cubic_init_ext(cubic, cid, DEFAULT_CUBIC_FLAGS)
|
||||
extern const struct cong_ctl_if lsquic_cong_cubic_if;
|
||||
|
||||
void
|
||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
|
||||
lsquic_time_t rtt, int app_limited, unsigned n_bytes);
|
||||
|
||||
void
|
||||
lsquic_cubic_loss (struct lsquic_cubic *cubic);
|
||||
|
||||
void
|
||||
lsquic_cubic_timeout (struct lsquic_cubic *cubic);
|
||||
|
||||
void
|
||||
lsquic_cubic_was_quiet (struct lsquic_cubic *, lsquic_time_t now);
|
||||
|
||||
#define lsquic_cubic_get_cwnd(c) (+(c)->cu_cwnd)
|
||||
|
||||
#define lsquic_cubic_in_slow_start(cubic) \
|
||||
((cubic)->cu_cwnd < (cubic)->cu_ssthresh)
|
||||
lsquic_cubic_set_flags (struct lsquic_cubic *cubic, enum cubic_flags flags);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
#ifndef LSQUIC_DATA_IN_IF_H
|
||||
#define LSQUIC_DATA_IN_IF_H 1
|
||||
|
||||
|
||||
struct data_frame;
|
||||
struct data_in;
|
||||
struct lsquic_conn_public;
|
||||
struct stream_frame;
|
||||
|
||||
|
||||
enum ins_frame
|
||||
{
|
||||
INS_FRAME_OK,
|
||||
|
@ -19,6 +21,7 @@ enum ins_frame
|
|||
INS_FRAME_OVERLAP,
|
||||
};
|
||||
|
||||
|
||||
struct data_in_iface
|
||||
{
|
||||
void
|
||||
|
@ -55,8 +58,15 @@ struct data_in_iface
|
|||
size_t
|
||||
(*di_mem_used) (struct data_in *);
|
||||
|
||||
void
|
||||
(*di_dump_state) (struct data_in *);
|
||||
|
||||
/* Return number of bytes readable starting at offset `read_offset' */
|
||||
uint64_t
|
||||
(*di_readable_bytes) (struct data_in *, uint64_t read_offset);
|
||||
};
|
||||
|
||||
|
||||
struct data_in
|
||||
{
|
||||
const struct data_in_iface *di_if;
|
||||
|
@ -70,17 +80,18 @@ struct data_in
|
|||
} di_flags;
|
||||
};
|
||||
|
||||
|
||||
/* This implementation does not support overlapping frame and may return
|
||||
* INS_FRAME_OVERLAP.
|
||||
*/
|
||||
struct data_in *
|
||||
data_in_nocopy_new (struct lsquic_conn_public *, uint32_t stream_id);
|
||||
data_in_nocopy_new (struct lsquic_conn_public *, lsquic_stream_id_t);
|
||||
|
||||
/* This implementation supports overlapping frames and will never return
|
||||
* INS_FRAME_OVERLAP.
|
||||
*/
|
||||
struct data_in *
|
||||
data_in_hash_new (struct lsquic_conn_public *, uint32_t stream_id,
|
||||
data_in_hash_new (struct lsquic_conn_public *, lsquic_stream_id_t,
|
||||
uint64_t byteage);
|
||||
|
||||
enum ins_frame
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <vc_compat.h>
|
||||
#endif
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_data_in_if.h"
|
||||
|
||||
|
||||
|
@ -75,13 +76,28 @@ error_di_mem_used (struct data_in *data_in)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
error_di_dump_state (struct data_in *data_in)
|
||||
{
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
error_di_readable_bytes (struct data_in *data_in, uint64_t read_offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct data_in_iface di_if_error = {
|
||||
.di_destroy = error_di_destroy,
|
||||
.di_dump_state = error_di_dump_state,
|
||||
.di_empty = error_di_empty,
|
||||
.di_frame_done = error_di_frame_done,
|
||||
.di_get_frame = error_di_get_frame,
|
||||
.di_insert_frame = error_di_insert_frame,
|
||||
.di_mem_used = error_di_mem_used,
|
||||
.di_readable_bytes
|
||||
= error_di_readable_bytes,
|
||||
.di_switch_impl = error_di_switch_impl,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_rtt.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_malo.h"
|
||||
|
@ -36,7 +40,7 @@
|
|||
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_DI
|
||||
#define LSQUIC_LOG_CONN_ID hdi->hdi_conn_pub->lconn->cn_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(hdi->hdi_conn_pub->lconn)
|
||||
#define LSQUIC_LOG_STREAM_ID hdi->hdi_stream_id
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
@ -73,7 +77,7 @@ struct hash_data_in
|
|||
struct dblock_head *hdi_buckets;
|
||||
struct data_block *hdi_last_block;
|
||||
struct data_frame hdi_data_frame;
|
||||
uint32_t hdi_stream_id;
|
||||
lsquic_stream_id_t hdi_stream_id;
|
||||
unsigned hdi_count;
|
||||
unsigned hdi_nbits;
|
||||
enum {
|
||||
|
@ -111,8 +115,8 @@ my_log2 /* silly name to suppress compiler warning */ (unsigned sz)
|
|||
|
||||
|
||||
struct data_in *
|
||||
data_in_hash_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id,
|
||||
uint64_t byteage)
|
||||
data_in_hash_new (struct lsquic_conn_public *conn_pub,
|
||||
lsquic_stream_id_t stream_id, uint64_t byteage)
|
||||
{
|
||||
struct hash_data_in *hdi;
|
||||
unsigned n;
|
||||
|
@ -456,8 +460,6 @@ ctz (unsigned long long x)
|
|||
if (0 == (x & ((1ULL << 1) - 1))) { n += 1; x >>= 1; }
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -638,13 +640,46 @@ hash_di_mem_used (struct data_in *data_in)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
hash_di_dump_state (struct data_in *data_in)
|
||||
{
|
||||
const struct hash_data_in *const hdi = HDI_PTR(data_in);
|
||||
const struct data_block *block;
|
||||
unsigned n;
|
||||
|
||||
LSQ_DEBUG("hash state: flags: %X; fin off: %"PRIu64"; count: %u",
|
||||
hdi->hdi_flags, hdi->hdi_fin_off, hdi->hdi_count);
|
||||
for (n = 0; n < N_BUCKETS(hdi->hdi_nbits); ++n)
|
||||
TAILQ_FOREACH(block, &hdi->hdi_buckets[n], db_next)
|
||||
LSQ_DEBUG("block: off: %"PRIu64, block->db_off);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
hash_di_readable_bytes (struct data_in *data_in, uint64_t read_offset)
|
||||
{
|
||||
const struct data_frame *data_frame;
|
||||
uint64_t starting_offset;
|
||||
|
||||
starting_offset = read_offset;
|
||||
while (data_frame = hash_di_get_frame(data_in, read_offset),
|
||||
data_frame && data_frame->df_size - data_frame->df_read_off)
|
||||
read_offset += data_frame->df_size - data_frame->df_read_off;
|
||||
|
||||
return read_offset - starting_offset;
|
||||
}
|
||||
|
||||
|
||||
static const struct data_in_iface di_if_hash = {
|
||||
.di_destroy = hash_di_destroy,
|
||||
.di_dump_state = hash_di_dump_state,
|
||||
.di_empty = hash_di_empty,
|
||||
.di_frame_done = hash_di_frame_done,
|
||||
.di_get_frame = hash_di_get_frame,
|
||||
.di_insert_frame = hash_di_insert_frame,
|
||||
.di_mem_used = hash_di_mem_used,
|
||||
.di_readable_bytes
|
||||
= hash_di_readable_bytes,
|
||||
.di_switch_impl = hash_di_switch_impl,
|
||||
};
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@
|
|||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_rtt.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_malo.h"
|
||||
|
@ -66,7 +69,7 @@
|
|||
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_DI
|
||||
#define LSQUIC_LOG_CONN_ID ncdi->ncdi_conn_pub->lconn->cn_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(ncdi->ncdi_conn_pub->lconn)
|
||||
#define LSQUIC_LOG_STREAM_ID ncdi->ncdi_stream_id
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
@ -103,7 +106,7 @@ struct nocopy_data_in
|
|||
struct lsquic_conn_public *ncdi_conn_pub;
|
||||
uint64_t ncdi_byteage;
|
||||
uint64_t ncdi_fin_off;
|
||||
uint32_t ncdi_stream_id;
|
||||
lsquic_stream_id_t ncdi_stream_id;
|
||||
unsigned ncdi_n_frames;
|
||||
unsigned ncdi_n_holes;
|
||||
unsigned ncdi_cons_far;
|
||||
|
@ -125,7 +128,8 @@ static const struct data_in_iface *di_if_nocopy_ptr;
|
|||
|
||||
|
||||
struct data_in *
|
||||
data_in_nocopy_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id)
|
||||
data_in_nocopy_new (struct lsquic_conn_public *conn_pub,
|
||||
lsquic_stream_id_t stream_id)
|
||||
{
|
||||
struct nocopy_data_in *ncdi;
|
||||
|
||||
|
@ -164,12 +168,6 @@ nocopy_di_destroy (struct data_in *data_in)
|
|||
}
|
||||
|
||||
|
||||
#define DF_OFF(frame) (frame)->data_frame.df_offset
|
||||
#define DF_FIN(frame) (frame)->data_frame.df_fin
|
||||
#define DF_SIZE(frame) (frame)->data_frame.df_size
|
||||
#define DF_END(frame) (DF_OFF(frame) + DF_SIZE(frame))
|
||||
|
||||
|
||||
#if LSQUIC_EXTRA_CHECKS
|
||||
static int
|
||||
frame_list_is_sane (const struct nocopy_data_in *ncdi)
|
||||
|
@ -186,8 +184,6 @@ frame_list_is_sane (const struct nocopy_data_in *ncdi)
|
|||
}
|
||||
return ordered && !overlaps;
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_ORDER(ncdi) assert(frame_list_is_sane(ncdi))
|
||||
#else
|
||||
#define CHECK_ORDER(ncdi)
|
||||
|
@ -280,6 +276,8 @@ insert_frame (struct nocopy_data_in *ncdi, struct stream_frame *new_frame,
|
|||
&& read_offset == ncdi->ncdi_fin_off))
|
||||
return INS_FRAME_DUP | CASE('G');
|
||||
}
|
||||
else if (read_offset > DF_OFF(new_frame))
|
||||
return INS_FRAME_OVERLAP | CASE('N');
|
||||
goto list_was_empty;
|
||||
case 3: /* Both left and right neighbors */
|
||||
case 2: /* Only left neighbor (prev_frame) */
|
||||
|
@ -299,6 +297,8 @@ insert_frame (struct nocopy_data_in *ncdi, struct stream_frame *new_frame,
|
|||
case 1: /* Only right neighbor (next_frame) */
|
||||
if (DF_END(new_frame) > DF_OFF(next_frame))
|
||||
return INS_FRAME_OVERLAP | CASE('K');
|
||||
else if (read_offset > DF_OFF(new_frame))
|
||||
return INS_FRAME_OVERLAP | CASE('O');
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -512,13 +512,47 @@ nocopy_di_mem_used (struct data_in *data_in)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
nocopy_di_dump_state (struct data_in *data_in)
|
||||
{
|
||||
struct nocopy_data_in *const ncdi = NCDI_PTR(data_in);
|
||||
const struct stream_frame *frame;
|
||||
|
||||
LSQ_DEBUG("nocopy state: frames: %u; holes: %u; cons_far: %u",
|
||||
ncdi->ncdi_n_frames, ncdi->ncdi_n_holes, ncdi->ncdi_cons_far);
|
||||
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
||||
LSQ_DEBUG("frame: off: %"PRIu64"; read_off: %"PRIu16"; size: %"PRIu16
|
||||
"; fin: %d", DF_OFF(frame), frame->data_frame.df_read_off,
|
||||
DF_SIZE(frame), DF_FIN(frame));
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
nocopy_di_readable_bytes (struct data_in *data_in, uint64_t read_offset)
|
||||
{
|
||||
const struct nocopy_data_in *const ncdi = NCDI_PTR(data_in);
|
||||
const struct stream_frame *frame;
|
||||
uint64_t starting_offset;
|
||||
|
||||
starting_offset = read_offset;
|
||||
TAILQ_FOREACH(frame, &ncdi->ncdi_frames_in, next_frame)
|
||||
if (DF_ROFF(frame) == read_offset)
|
||||
read_offset += DF_END(frame) - DF_ROFF(frame);
|
||||
|
||||
return read_offset - starting_offset;
|
||||
}
|
||||
|
||||
|
||||
static const struct data_in_iface di_if_nocopy = {
|
||||
.di_destroy = nocopy_di_destroy,
|
||||
.di_dump_state = nocopy_di_dump_state,
|
||||
.di_empty = nocopy_di_empty,
|
||||
.di_frame_done = nocopy_di_frame_done,
|
||||
.di_get_frame = nocopy_di_get_frame,
|
||||
.di_insert_frame = nocopy_di_insert_frame,
|
||||
.di_mem_used = nocopy_di_mem_used,
|
||||
.di_readable_bytes
|
||||
= nocopy_di_readable_bytes,
|
||||
.di_switch_impl = nocopy_di_switch_impl,
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_ENC_SESS_H
|
||||
#define LSQUIC_ENC_SESS_H 1
|
||||
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_packet_out;
|
||||
struct lsquic_packet_in;
|
||||
struct stream_wrapper;
|
||||
struct ver_neg;
|
||||
struct lsquic_conn;
|
||||
struct transport_params;
|
||||
struct lsquic_cid;
|
||||
struct ssl_stream_method_st;
|
||||
struct ssl_st;
|
||||
struct sockaddr;
|
||||
struct conn_cid_elem;
|
||||
|
||||
#define DNONC_LENGTH 32
|
||||
#define SRST_LENGTH 16
|
||||
|
||||
/* From [draft-ietf-quic-tls-14]:
|
||||
*
|
||||
* Data is protected using a number of encryption levels:
|
||||
*
|
||||
* o Plaintext
|
||||
*
|
||||
* o Early Data (0-RTT) Keys
|
||||
*
|
||||
* o Handshake Keys
|
||||
*
|
||||
* o Application Data (1-RTT) Keys
|
||||
*/
|
||||
|
||||
/* This enum maps to the list above */
|
||||
enum enc_level
|
||||
{
|
||||
ENC_LEV_CLEAR,
|
||||
ENC_LEV_EARLY,
|
||||
ENC_LEV_INIT,
|
||||
ENC_LEV_FORW,
|
||||
N_ENC_LEVS
|
||||
};
|
||||
|
||||
enum handshake_error /* TODO: rename this enum */
|
||||
{
|
||||
DATA_NOT_ENOUGH = -2,
|
||||
DATA_FORMAT_ERROR = -1,
|
||||
HS_ERROR = -1,
|
||||
DATA_NO_ERROR = 0,
|
||||
HS_SHLO = 0,
|
||||
HS_1RTT = 1,
|
||||
HS_SREJ = 2,
|
||||
HS_DELAYED = 3,
|
||||
HS_PK_OFFLOAD = 4,
|
||||
};
|
||||
|
||||
#ifndef LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
# ifndef NDEBUG
|
||||
# define LSQUIC_KEEP_ENC_SESS_HISTORY 1
|
||||
# else
|
||||
# define LSQUIC_KEEP_ENC_SESS_HISTORY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
#define ESHIST_BITS 7
|
||||
#define ESHIST_MASK ((1 << ESHIST_BITS) - 1)
|
||||
#define ESHIST_STR_SIZE ((1 << ESHIST_BITS) + 1)
|
||||
#endif
|
||||
|
||||
enum enc_packout { ENCPA_OK, ENCPA_NOMEM, ENCPA_BADCRYPT, };
|
||||
|
||||
enum dec_packin {
|
||||
DECPI_OK,
|
||||
DECPI_NOMEM,
|
||||
DECPI_TOO_SHORT,
|
||||
DECPI_NOT_YET,
|
||||
DECPI_BADCRYPT,
|
||||
DECPI_VIOLATION,
|
||||
};
|
||||
|
||||
typedef void enc_session_t;
|
||||
|
||||
struct enc_session_funcs_common
|
||||
{
|
||||
/* Global initialization: call once per implementation */
|
||||
int (*esf_global_init)(int flags);
|
||||
|
||||
/* Global cleanup: call once per implementation */
|
||||
void (*esf_global_cleanup) (void);
|
||||
|
||||
const char *
|
||||
(*esf_cipher) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_keysize) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_alg_keysize) (enc_session_t *);
|
||||
|
||||
const char *
|
||||
(*esf_get_sni) (enc_session_t *);
|
||||
|
||||
enum enc_packout
|
||||
(*esf_encrypt_packet) (enc_session_t *, const struct lsquic_engine_public *,
|
||||
struct lsquic_conn *, struct lsquic_packet_out *);
|
||||
|
||||
enum dec_packin
|
||||
(*esf_decrypt_packet)(enc_session_t *, struct lsquic_engine_public *,
|
||||
const struct lsquic_conn *, struct lsquic_packet_in *);
|
||||
|
||||
struct stack_st_X509 *
|
||||
(*esf_get_server_cert_chain) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_verify_reset_token) (enc_session_t *, const unsigned char *, size_t);
|
||||
|
||||
int
|
||||
(*esf_did_zero_rtt_succeed) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_is_zero_rtt_enabled) (enc_session_t *);
|
||||
|
||||
unsigned
|
||||
esf_tag_len;
|
||||
};
|
||||
|
||||
struct enc_session_funcs_gquic
|
||||
{
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
/* Grab encryption session history */
|
||||
void (*esf_get_hist) (enc_session_t *,
|
||||
char buf[ESHIST_STR_SIZE]);
|
||||
#endif
|
||||
|
||||
/* Destroy enc session */
|
||||
void (*esf_destroy)(enc_session_t *enc_session);
|
||||
|
||||
/* Return true if handshake has been completed */
|
||||
int (*esf_is_hsk_done)(enc_session_t *enc_session);
|
||||
|
||||
/* Get value of setting specified by `tag' */
|
||||
int (*esf_get_peer_setting) (enc_session_t *, uint32_t tag,
|
||||
uint32_t *val);
|
||||
|
||||
/* Get value of peer option (that from COPT array) */
|
||||
int (*esf_get_peer_option) (enc_session_t *enc_session,
|
||||
uint32_t tag);
|
||||
|
||||
/* Create server session */
|
||||
enc_session_t *
|
||||
(*esf_create_server) (lsquic_cid_t cid, const struct lsquic_engine_public *);
|
||||
|
||||
/* out_len should have init value as the max length of out */
|
||||
enum handshake_error
|
||||
(*esf_handle_chlo) (enc_session_t *enc_session, enum lsquic_version,
|
||||
const uint8_t *in, int in_len, time_t t,
|
||||
const struct sockaddr *ip_addr, const struct sockaddr *local,
|
||||
uint8_t *out, size_t *out_len,
|
||||
uint8_t nonce[DNONC_LENGTH], int *nonce_set);
|
||||
|
||||
void (*esf_hsk_destroy)(void *hsk_ctx);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Need to expose this function for testing */
|
||||
int (*esf_determine_diversification_key) (enc_session_t *,
|
||||
uint8_t *diversification_nonce, int is_client);
|
||||
#endif
|
||||
|
||||
const char *
|
||||
(*esf_get_ua) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_have_key_gt_one) (enc_session_t *enc_session);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/* Functions that are only relevant in maintest. We may want to get rid
|
||||
* of them somehow and only use the public API to test.
|
||||
*/
|
||||
|
||||
uint8_t
|
||||
(*esf_have_key) (enc_session_t *);
|
||||
|
||||
void
|
||||
(*esf_set_have_key) (enc_session_t *, uint8_t);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_enc_key_i) (enc_session_t *);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_dec_key_i) (enc_session_t *);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_enc_key_nonce_i) (enc_session_t *);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_dec_key_nonce_i) (enc_session_t *);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_enc_key_nonce_f) (enc_session_t *);
|
||||
|
||||
const unsigned char *
|
||||
(*esf_get_dec_key_nonce_f) (enc_session_t *);
|
||||
#endif /* !defined(NDEBUG) */
|
||||
|
||||
#if LSQUIC_ENABLE_HANDSHAKE_DISABLE
|
||||
void
|
||||
(*esf_set_handshake_completed) (enc_session_t *);
|
||||
#endif
|
||||
|
||||
/* Create client session */
|
||||
enc_session_t *
|
||||
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
/* -1 error, 0, OK, response in `buf' */
|
||||
int
|
||||
(*esf_gen_chlo) (enc_session_t *, enum lsquic_version,
|
||||
uint8_t *buf, size_t *len);
|
||||
|
||||
int
|
||||
(*esf_handle_chlo_reply) (enc_session_t *,
|
||||
const uint8_t *data, int len);
|
||||
|
||||
size_t
|
||||
(*esf_mem_used)(enc_session_t *);
|
||||
|
||||
/* Zero-rtt serialization needs the knowledge of the QUIC version, that's
|
||||
* why there is a separate method for thus. Plus, we want to be able to
|
||||
* call it after the "handshake is done" callback is called.
|
||||
*/
|
||||
void (*esf_maybe_dispatch_zero_rtt) (enc_session_t *,
|
||||
struct lsquic_conn *conn,
|
||||
void (*cb)(struct lsquic_conn *, const unsigned char *, size_t));
|
||||
|
||||
void (*esf_reset_cid) (enc_session_t *, const lsquic_cid_t *);
|
||||
};
|
||||
|
||||
enum iquic_handshake_status {
|
||||
IHS_WANT_READ,
|
||||
IHS_WANT_WRITE,
|
||||
IHS_STOP,
|
||||
};
|
||||
|
||||
struct crypto_stream_if
|
||||
{
|
||||
ssize_t (*csi_write) (void *stream, const void *buf, size_t len);
|
||||
int (*csi_flush) (void *stream);
|
||||
ssize_t (*csi_readf) (void *stream,
|
||||
size_t (*readf)(void *, const unsigned char *, size_t, int), void *ctx);
|
||||
int (*csi_wantwrite) (void *stream, int is_want);
|
||||
int (*csi_wantread) (void *stream, int is_want);
|
||||
enum enc_level
|
||||
(*csi_enc_level) (void *stream);
|
||||
};
|
||||
|
||||
struct enc_session_funcs_iquic
|
||||
{
|
||||
enc_session_t *
|
||||
(*esfi_create_client) (const char *domain, struct lsquic_engine_public *,
|
||||
struct lsquic_conn *, const struct lsquic_cid *,
|
||||
const struct ver_neg *, void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
void
|
||||
(*esfi_destroy) (enc_session_t *);
|
||||
|
||||
struct ssl_st *
|
||||
(*esfi_get_ssl) (enc_session_t *);
|
||||
|
||||
struct transport_params *
|
||||
(*esfi_get_peer_transport_params) (enc_session_t *);
|
||||
|
||||
int
|
||||
(*esfi_reset_dcid) (enc_session_t *, const struct lsquic_cid *,
|
||||
const struct lsquic_cid *);
|
||||
|
||||
int
|
||||
(*esfi_init_server) (enc_session_t *);
|
||||
|
||||
void
|
||||
(*esfi_set_conn) (enc_session_t *, struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*esfi_set_streams) (enc_session_t *, void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *);
|
||||
|
||||
enc_session_t *
|
||||
(*esfi_create_server) (struct lsquic_engine_public *, struct lsquic_conn *,
|
||||
const struct lsquic_cid *,
|
||||
void *(crypto_streams)[4],
|
||||
const struct crypto_stream_if *,
|
||||
const struct lsquic_cid *odcid);
|
||||
|
||||
void
|
||||
(*esfi_shake_stream)(enc_session_t *, struct lsquic_stream *,
|
||||
const char *);
|
||||
|
||||
void
|
||||
(*esfi_1rtt_acked)(enc_session_t *);
|
||||
};
|
||||
|
||||
extern
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
struct enc_session_funcs_common lsquic_enc_session_common_gquic_1;
|
||||
extern const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1;
|
||||
|
||||
extern
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
struct enc_session_funcs_gquic lsquic_enc_session_gquic_gquic_1;
|
||||
|
||||
extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
|
||||
|
||||
#define select_esf_common_by_ver(ver) ( \
|
||||
ver == LSQVER_ID22 ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
|
||||
&lsquic_enc_session_common_gquic_1 )
|
||||
|
||||
#define select_esf_gquic_by_ver(ver) ( \
|
||||
ver ? &lsquic_enc_session_gquic_gquic_1 : &lsquic_enc_session_gquic_gquic_1)
|
||||
|
||||
#define select_esf_iquic_by_ver(ver) ( \
|
||||
ver ? &lsquic_enc_session_iquic_ietf_v1 : &lsquic_enc_session_iquic_ietf_v1)
|
||||
|
||||
extern const char *const lsquic_enclev2str[];
|
||||
|
||||
extern const struct lsquic_stream_if lsquic_cry_sm_if;
|
||||
|
||||
extern const struct lsquic_stream_if lsquic_mini_cry_sm_if;
|
||||
|
||||
/* RFC 7301, Section 3.2 */
|
||||
#define ALERT_NO_APPLICATION_PROTOCOL 120
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_zero_rtt_version (const unsigned char *, size_t);
|
||||
|
||||
/* This is seems to be true for all of the ciphers used by IETF QUIC.
|
||||
* XXX: Perhaps add a check?
|
||||
*/
|
||||
#define IQUIC_TAG_LEN 16
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_version.h"
|
||||
|
||||
|
||||
const char *const lsquic_enclev2str[] =
|
||||
{
|
||||
[ENC_LEV_EARLY] = "early",
|
||||
[ENC_LEV_CLEAR] = "clear",
|
||||
[ENC_LEV_INIT] = "initial",
|
||||
[ENC_LEV_FORW] = "forw-secure",
|
||||
};
|
||||
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_zero_rtt_version (const unsigned char *buf, size_t bufsz)
|
||||
{
|
||||
lsquic_ver_tag_t tag;
|
||||
|
||||
if (bufsz >= sizeof(tag))
|
||||
{
|
||||
memcpy(&tag, buf, sizeof(tag));
|
||||
return lsquic_tag2ver(tag);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@
|
|||
#if ENG_HIST_ENABLED
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_ENG_HIST
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,9 @@
|
|||
/*
|
||||
* lsquic_engine_public.h -- Engine's "public interface"
|
||||
*
|
||||
* This structure is used to bundle things in engine that connections
|
||||
* need. This way, the space per mini connection is one pointer instead
|
||||
* of several.
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_ENGINE_PUBLIC_H
|
||||
|
@ -10,10 +13,32 @@
|
|||
struct lsquic_conn;
|
||||
struct lsquic_engine;
|
||||
struct stack_st_X509;
|
||||
struct lsquic_hash;
|
||||
struct lsquic_stream_if;
|
||||
struct ssl_ctx_st;
|
||||
|
||||
enum warning_type
|
||||
{
|
||||
WT_ACKPARSE_MINI,
|
||||
WT_ACKPARSE_FULL,
|
||||
N_WARNING_TYPES,
|
||||
};
|
||||
|
||||
#define WARNING_INTERVAL (24ULL * 3600ULL * 1000000ULL)
|
||||
|
||||
struct lsquic_engine_public {
|
||||
struct lsquic_mm enp_mm;
|
||||
struct lsquic_engine_settings enp_settings;
|
||||
struct token_generator *enp_tokgen;
|
||||
lsquic_lookup_cert_f enp_lookup_cert;
|
||||
void *enp_cert_lu_ctx;
|
||||
struct ssl_ctx_st * (*enp_get_ssl_ctx)(void *peer_ctx);
|
||||
const struct lsquic_shared_hash_if
|
||||
*enp_shi;
|
||||
void *enp_shi_ctx;
|
||||
lsquic_time_t enp_last_warning[N_WARNING_TYPES];
|
||||
const struct lsquic_stream_if *enp_stream_if;
|
||||
void *enp_stream_if_ctx;
|
||||
const struct lsquic_hset_if *enp_hsi_if;
|
||||
void *enp_hsi_ctx;
|
||||
int (*enp_verify_cert)(void *verify_ctx,
|
||||
|
@ -22,13 +47,18 @@ struct lsquic_engine_public {
|
|||
const struct lsquic_packout_mem_if
|
||||
*enp_pmi;
|
||||
void *enp_pmi_ctx;
|
||||
const struct lsquic_keylog_if *enp_kli;
|
||||
void *enp_kli_ctx;
|
||||
struct lsquic_engine *enp_engine;
|
||||
struct lsquic_hash *enp_srst_hash;
|
||||
enum {
|
||||
ENPUB_PROC = (1 << 0), /* Being processed by one of the user-facing
|
||||
* functions.
|
||||
*/
|
||||
ENPUB_CAN_SEND = (1 << 1),
|
||||
} enp_flags;
|
||||
unsigned char enp_ver_tags_buf[ sizeof(lsquic_ver_tag_t) * N_LSQVER ];
|
||||
unsigned enp_ver_tags_len;
|
||||
};
|
||||
|
||||
/* Put connection onto the Tickable Queue if it is not already on it. If
|
||||
|
@ -44,4 +74,16 @@ void
|
|||
lsquic_engine_add_conn_to_attq (struct lsquic_engine_public *enpub,
|
||||
lsquic_conn_t *, lsquic_time_t);
|
||||
|
||||
void
|
||||
lsquic_engine_retire_cid (struct lsquic_engine_public *,
|
||||
struct lsquic_conn *, unsigned cce_idx, lsquic_time_t now);
|
||||
|
||||
int
|
||||
lsquic_engine_add_cid (struct lsquic_engine_public *,
|
||||
struct lsquic_conn *, unsigned cce_idx);
|
||||
|
||||
struct lsquic_conn *
|
||||
lsquic_engine_find_conn (const struct lsquic_engine_public *pub,
|
||||
const lsquic_cid_t *cid);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,14 +14,21 @@
|
|||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_packet_out.h"
|
||||
#include "lsquic_parse.h"
|
||||
#include "lsquic_frame_common.h"
|
||||
#include "lsquic_headers.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_frame_reader.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_ev_log.h"
|
||||
#include "lsquic_sizes.h"
|
||||
#include "lsquic_trans_params.h"
|
||||
#include "lsquic_util.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_EVENT
|
||||
#include "lsquic_logger.h"
|
||||
|
@ -39,24 +46,41 @@
|
|||
/* VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV */
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_in (lsquic_cid_t cid, const lsquic_packet_in_t *packet_in)
|
||||
lsquic_ev_log_packet_in (const lsquic_cid_t *cid,
|
||||
const lsquic_packet_in_t *packet_in)
|
||||
{
|
||||
switch (packet_in->pi_flags & (
|
||||
PI_FROM_MINI|
|
||||
PI_GQUIC))
|
||||
{
|
||||
case PI_FROM_MINI|PI_GQUIC:
|
||||
LCID("packet in: %"PRIu64" (from mini)", packet_in->pi_packno);
|
||||
break;
|
||||
case PI_FROM_MINI:
|
||||
LCID("packet in: %"PRIu64" (from mini), type: %s, ecn: %u",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
lsquic_packet_in_ecn(packet_in));
|
||||
break;
|
||||
case PI_GQUIC:
|
||||
LCID("packet in: %"PRIu64, packet_in->pi_packno);
|
||||
LCID("packet in: %"PRIu64", size: %u", packet_in->pi_packno,
|
||||
(unsigned) (packet_in->pi_data_sz + GQUIC_PACKET_HASH_SZ));
|
||||
break;
|
||||
default:
|
||||
LCID("packet in: %"PRIu64", type: %s",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type]);
|
||||
LCID("packet in: %"PRIu64", type: %s, size: %u; ecn: %u, spin: %d; "
|
||||
"path: %hhu",
|
||||
packet_in->pi_packno, lsquic_hety2str[packet_in->pi_header_type],
|
||||
(unsigned) (packet_in->pi_data_sz + IQUIC_TAG_LEN),
|
||||
lsquic_packet_in_ecn(packet_in),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_in_spin_bit(packet_in), packet_in->pi_path_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_ack_frame_in (lsquic_cid_t cid, const struct ack_info *acki)
|
||||
lsquic_ev_log_ack_frame_in (const lsquic_cid_t *cid,
|
||||
const struct ack_info *acki)
|
||||
{
|
||||
size_t sz;
|
||||
char *buf;
|
||||
|
@ -70,81 +94,101 @@ lsquic_ev_log_ack_frame_in (lsquic_cid_t cid, const struct ack_info *acki)
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_stream_frame_in (lsquic_cid_t cid,
|
||||
lsquic_ev_log_stream_frame_in (const lsquic_cid_t *cid,
|
||||
const struct stream_frame *frame)
|
||||
{
|
||||
LCID("STREAM frame in: stream %u; offset %"PRIu64"; size %"PRIu16
|
||||
LCID("STREAM frame in: stream %"PRIu64"; offset %"PRIu64"; size %"PRIu16
|
||||
"; fin: %d", frame->stream_id, frame->data_frame.df_offset,
|
||||
frame->data_frame.df_size, (int) frame->data_frame.df_fin);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_stop_waiting_frame_in (lsquic_cid_t cid, lsquic_packno_t least)
|
||||
lsquic_ev_log_crypto_frame_in (const lsquic_cid_t *cid,
|
||||
const struct stream_frame *frame, unsigned enc_level)
|
||||
{
|
||||
LCID("CRYPTO frame in: level %u; offset %"PRIu64"; size %"PRIu16,
|
||||
enc_level, frame->data_frame.df_offset, frame->data_frame.df_size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_stop_waiting_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_packno_t least)
|
||||
{
|
||||
LCID("STOP_WAITING frame in: least unacked packno %"PRIu64, least);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_window_update_frame_in (lsquic_cid_t cid, uint32_t stream_id,
|
||||
uint64_t offset)
|
||||
lsquic_ev_log_window_update_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t offset)
|
||||
{
|
||||
LCID("WINDOW_UPDATE frame in: stream %"PRIu32"; offset %"PRIu64,
|
||||
LCID("WINDOW_UPDATE frame in: stream %"PRIu64"; offset %"PRIu64,
|
||||
stream_id, offset);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_blocked_frame_in (lsquic_cid_t cid, uint32_t stream_id)
|
||||
lsquic_ev_log_blocked_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id)
|
||||
{
|
||||
LCID("BLOCKED frame in: stream %"PRIu32, stream_id);
|
||||
LCID("BLOCKED frame in: stream %"PRIu64, stream_id);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_connection_close_frame_in (lsquic_cid_t cid,
|
||||
uint32_t error_code, int reason_len, const char *reason)
|
||||
lsquic_ev_log_connection_close_frame_in (const lsquic_cid_t *cid,
|
||||
uint64_t error_code, int reason_len, const char *reason)
|
||||
{
|
||||
LCID("CONNECTION_CLOSE frame in: error code %"PRIu32", reason: %.*s",
|
||||
LCID("CONNECTION_CLOSE frame in: error code %"PRIu64", reason: %.*s",
|
||||
error_code, reason_len, reason);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_goaway_frame_in (lsquic_cid_t cid, uint32_t error_code,
|
||||
uint32_t stream_id, int reason_len, const char *reason)
|
||||
lsquic_ev_log_goaway_frame_in (const lsquic_cid_t *cid, uint32_t error_code,
|
||||
lsquic_stream_id_t stream_id, int reason_len, const char *reason)
|
||||
{
|
||||
LCID("GOAWAY frame in: error code %"PRIu32", stream %"PRIu32
|
||||
LCID("GOAWAY frame in: error code %"PRIu32", stream %"PRIu64
|
||||
", reason: %.*s", error_code, stream_id, reason_len, reason);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_rst_stream_frame_in (lsquic_cid_t cid, uint32_t stream_id,
|
||||
uint64_t offset, uint32_t error_code)
|
||||
lsquic_ev_log_rst_stream_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t offset, uint64_t error_code)
|
||||
{
|
||||
LCID("RST_STREAM frame in: error code %"PRIu32", stream %"PRIu32
|
||||
LCID("RST_STREAM frame in: error code %"PRIu64", stream %"PRIu64
|
||||
", offset: %"PRIu64, error_code, stream_id, offset);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_padding_frame_in (lsquic_cid_t cid, size_t len)
|
||||
lsquic_ev_log_stop_sending_frame_in (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint64_t error_code)
|
||||
{
|
||||
LCID("STOP_SENDING frame in: error code %"PRIu64", stream %"PRIu64,
|
||||
error_code, stream_id);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_padding_frame_in (const lsquic_cid_t *cid, size_t len)
|
||||
{
|
||||
LCID("PADDING frame in of %zd bytes", len);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_ping_frame_in (lsquic_cid_t cid)
|
||||
lsquic_ev_log_ping_frame_in (const lsquic_cid_t *cid)
|
||||
{
|
||||
LCID("PING frame in");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_created (lsquic_cid_t cid,
|
||||
lsquic_ev_log_packet_created (const lsquic_cid_t *cid,
|
||||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
LCID("created packet %"PRIu64"; flags: version=%d, nonce=%d, conn_id=%d",
|
||||
|
@ -156,16 +200,18 @@ lsquic_ev_log_packet_created (lsquic_cid_t cid,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_sent (lsquic_cid_t cid,
|
||||
lsquic_ev_log_packet_sent (const lsquic_cid_t *cid,
|
||||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
char frames[lsquic_frame_types_str_sz];
|
||||
if (lsquic_packet_out_verneg(packet_out))
|
||||
LCID("sent version negotiation packet, size %hu",
|
||||
packet_out->po_data_sz);
|
||||
else if (lsquic_packet_out_retry(packet_out))
|
||||
LCID("sent stateless retry packet, size %hu", packet_out->po_data_sz);
|
||||
else if (lsquic_packet_out_pubres(packet_out))
|
||||
LCID("sent public reset packet, size %hu", packet_out->po_data_sz);
|
||||
else if (packet_out->po_flags & PO_GQUIC)
|
||||
else if (packet_out->po_lflags & POL_GQUIC)
|
||||
LCID("sent packet %"PRIu64", size %hu, frame types: %s",
|
||||
packet_out->po_packno, packet_out->po_enc_data_sz,
|
||||
/* Frame types is a list of different frames types contained
|
||||
|
@ -176,7 +222,7 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid,
|
|||
packet_out->po_frame_types));
|
||||
else
|
||||
LCID("sent packet %"PRIu64", type %s, crypto: %s, size %hu, frame "
|
||||
"types: %s",
|
||||
"types: %s, ecn: %u, spin: %d; kp: %u, path: %hhu",
|
||||
packet_out->po_packno, lsquic_hety2str[packet_out->po_header_type],
|
||||
lsquic_enclev2str[ lsquic_packet_out_enc_level(packet_out) ],
|
||||
packet_out->po_enc_data_sz,
|
||||
|
@ -185,12 +231,17 @@ lsquic_ev_log_packet_sent (lsquic_cid_t cid,
|
|||
* printed.
|
||||
*/
|
||||
lsquic_frame_types_to_str(frames, sizeof(frames),
|
||||
packet_out->po_frame_types));
|
||||
packet_out->po_frame_types),
|
||||
lsquic_packet_out_ecn(packet_out),
|
||||
/* spin bit value is only valid for short packet headers */
|
||||
lsquic_packet_out_spin_bit(packet_out),
|
||||
lsquic_packet_out_kp(packet_out),
|
||||
packet_out->po_path->np_path_id);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_not_sent (lsquic_cid_t cid,
|
||||
lsquic_ev_log_packet_not_sent (const lsquic_cid_t *cid,
|
||||
const struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
char frames[lsquic_frame_types_str_sz];
|
||||
|
@ -205,17 +256,17 @@ lsquic_ev_log_packet_not_sent (lsquic_cid_t cid,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_http_headers_in (lsquic_cid_t cid, int is_server,
|
||||
lsquic_ev_log_http_headers_in (const lsquic_cid_t *cid, int is_server,
|
||||
const struct uncompressed_headers *uh)
|
||||
{
|
||||
const struct http1x_headers *h1h;
|
||||
const char *cr, *p;
|
||||
|
||||
if (uh->uh_flags & UH_PP)
|
||||
LCID("read push promise; stream %"PRIu32", promised stream %"PRIu32,
|
||||
LCID("read push promise; stream %"PRIu64", promised stream %"PRIu64,
|
||||
uh->uh_stream_id, uh->uh_oth_stream_id);
|
||||
else
|
||||
LCID("read %s headers; stream: %"PRIu32", depends on stream: %"PRIu32
|
||||
LCID("read %s headers; stream: %"PRIu64", depends on stream: %"PRIu64
|
||||
", weight: %hu, exclusive: %d, fin: %d",
|
||||
is_server ? "request" : "response",
|
||||
uh->uh_stream_id, uh->uh_oth_stream_id, uh->uh_weight,
|
||||
|
@ -237,7 +288,7 @@ lsquic_ev_log_http_headers_in (lsquic_cid_t cid, int is_server,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_action_stream_frame (lsquic_cid_t cid,
|
||||
lsquic_ev_log_action_stream_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *buf, size_t bufsz,
|
||||
const char *what)
|
||||
{
|
||||
|
@ -246,7 +297,7 @@ lsquic_ev_log_action_stream_frame (lsquic_cid_t cid,
|
|||
|
||||
len = pf->pf_parse_stream_frame(buf, bufsz, &frame);
|
||||
if (len > 0)
|
||||
LCID("%s STREAM frame: stream %"PRIu32", offset: %"PRIu64
|
||||
LCID("%s STREAM frame: stream %"PRIu64", offset: %"PRIu64
|
||||
", size: %"PRIu16", fin: %d", what, frame.stream_id,
|
||||
frame.data_frame.df_offset, frame.data_frame.df_size,
|
||||
frame.data_frame.df_fin);
|
||||
|
@ -256,15 +307,33 @@ lsquic_ev_log_action_stream_frame (lsquic_cid_t cid,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_ack_frame (lsquic_cid_t cid, const struct parse_funcs *pf,
|
||||
const unsigned char *ack_buf, size_t ack_buf_sz)
|
||||
lsquic_ev_log_generated_crypto_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *buf, size_t bufsz)
|
||||
{
|
||||
struct stream_frame frame;
|
||||
int len;
|
||||
|
||||
len = pf->pf_parse_crypto_frame(buf, bufsz, &frame);
|
||||
if (len > 0)
|
||||
LCID("generated CRYPTO frame: offset: %"PRIu64", size: %"PRIu16,
|
||||
frame.data_frame.df_offset, frame.data_frame.df_size);
|
||||
else
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse CRYPTO frame");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_ack_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *ack_buf,
|
||||
size_t ack_buf_sz)
|
||||
{
|
||||
struct ack_info acki;
|
||||
size_t sz;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
len = pf->pf_parse_ack_frame(ack_buf, ack_buf_sz, &acki);
|
||||
len = pf->pf_parse_ack_frame(ack_buf, ack_buf_sz, &acki,
|
||||
TP_DEF_ACK_DELAY_EXP);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse ACK frame");
|
||||
|
@ -280,7 +349,98 @@ lsquic_ev_log_generated_ack_frame (lsquic_cid_t cid, const struct parse_funcs *p
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stop_waiting_frame (lsquic_cid_t cid,
|
||||
lsquic_ev_log_generated_new_token_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *frame_buf,
|
||||
size_t frame_buf_sz)
|
||||
{
|
||||
const unsigned char *token;
|
||||
size_t sz;
|
||||
char *buf;
|
||||
int len;
|
||||
|
||||
len = pf->pf_parse_new_token_frame(frame_buf, frame_buf_sz, &token, &sz);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse NEW_TOKEN frame");
|
||||
return;
|
||||
}
|
||||
|
||||
buf = malloc(sz * 2 + 1);
|
||||
if (buf)
|
||||
{
|
||||
lsquic_hexstr(token, sz, buf, sz * 2 + 1);
|
||||
LCID("generated NEW_TOKEN frame: %s", buf);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_path_chal_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *frame_buf,
|
||||
size_t frame_buf_sz)
|
||||
{
|
||||
uint64_t chal;
|
||||
int len;
|
||||
char hexbuf[sizeof(chal) * 2 + 1];
|
||||
|
||||
len = pf->pf_parse_path_chal_frame(frame_buf, frame_buf_sz, &chal);
|
||||
if (len > 0)
|
||||
LCID("generated PATH_CHALLENGE(%s) frame",
|
||||
HEXSTR((unsigned char *) &chal, sizeof(chal), hexbuf));
|
||||
else
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse PATH_CHALLENGE frame");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_path_resp_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *frame_buf,
|
||||
size_t frame_buf_sz)
|
||||
{
|
||||
uint64_t resp;
|
||||
int len;
|
||||
char hexbuf[sizeof(resp) * 2 + 1];
|
||||
|
||||
len = pf->pf_parse_path_resp_frame(frame_buf, frame_buf_sz, &resp);
|
||||
if (len > 0)
|
||||
LCID("generated PATH_RESPONSE(%s) frame",
|
||||
HEXSTR((unsigned char *) &resp, sizeof(resp), hexbuf));
|
||||
else
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse PATH_RESPONSE frame");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_new_connection_id_frame (const lsquic_cid_t *cid,
|
||||
const struct parse_funcs *pf, const unsigned char *frame_buf,
|
||||
size_t frame_buf_sz)
|
||||
{
|
||||
const unsigned char *token;
|
||||
lsquic_cid_t new_cid;
|
||||
uint64_t seqno, retire_prior_to;
|
||||
int len;
|
||||
char token_buf[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
|
||||
char cid_buf[MAX_CID_LEN * 2 + 1];
|
||||
|
||||
len = pf->pf_parse_new_conn_id(frame_buf, frame_buf_sz, &seqno,
|
||||
&retire_prior_to, &new_cid, &token);
|
||||
if (len < 0)
|
||||
{
|
||||
LSQ_LOG2(LSQ_LOG_WARN, "cannot parse NEW_CONNECTION_ID frame");
|
||||
return;
|
||||
}
|
||||
|
||||
lsquic_hexstr(new_cid.idbuf, new_cid.len, cid_buf, sizeof(cid_buf));
|
||||
lsquic_hexstr(token, IQUIC_SRESET_TOKEN_SZ, token_buf, sizeof(token_buf));
|
||||
LCID("generated NEW_CONNECTION_ID frame: seqno: %"PRIu64"; retire prior "
|
||||
"to: %"PRIu64"; cid: %s; token: %s", seqno, retire_prior_to,
|
||||
cid_buf, token_buf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stop_waiting_frame (const lsquic_cid_t *cid,
|
||||
lsquic_packno_t lunack)
|
||||
{
|
||||
LCID("generated STOP_WAITING frame; least unacked: %"PRIu64, lunack);
|
||||
|
@ -288,16 +448,26 @@ lsquic_ev_log_generated_stop_waiting_frame (lsquic_cid_t cid,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_headers (lsquic_cid_t cid, uint32_t stream_id,
|
||||
lsquic_ev_log_generated_stop_sending_frame (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, uint16_t error_code)
|
||||
{
|
||||
LCID("generated STOP_SENDING frame; stream ID: %"PRIu64"; error code: "
|
||||
"%"PRIu16, stream_id, error_code);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_headers (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id,
|
||||
int is_server, const struct http_prio_frame *prio_frame,
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
uint32_t dep_stream_id;
|
||||
lsquic_stream_id_t dep_stream_id;
|
||||
int exclusive, i;
|
||||
unsigned short weight;
|
||||
|
||||
if (is_server)
|
||||
LCID("generated HTTP response HEADERS for stream %"PRIu32, stream_id);
|
||||
LCID("generated HTTP response HEADERS for stream %"PRIu64, stream_id);
|
||||
else
|
||||
{
|
||||
memcpy(&dep_stream_id, prio_frame->hpf_stream_id, 4);
|
||||
|
@ -305,8 +475,8 @@ lsquic_ev_log_generated_http_headers (lsquic_cid_t cid, uint32_t stream_id,
|
|||
exclusive = dep_stream_id >> 31;
|
||||
dep_stream_id &= ~(1 << 31);
|
||||
weight = prio_frame->hpf_weight + 1;
|
||||
LCID("generated HTTP request HEADERS for stream %"PRIu32
|
||||
", dep stream: %"PRIu32", weight: %hu, exclusive: %d", stream_id,
|
||||
LCID("generated HTTP request HEADERS for stream %"PRIu64
|
||||
", dep stream: %"PRIu64", weight: %hu, exclusive: %d", stream_id,
|
||||
dep_stream_id, weight, exclusive);
|
||||
}
|
||||
|
||||
|
@ -320,15 +490,15 @@ lsquic_ev_log_generated_http_headers (lsquic_cid_t cid, uint32_t stream_id,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_push_promise (lsquic_cid_t cid,
|
||||
uint32_t stream_id, uint32_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
lsquic_ev_log_generated_http_push_promise (const lsquic_cid_t *cid,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
{
|
||||
int i;
|
||||
|
||||
LCID("generated HTTP PUSH_PROMISE for stream %"PRIu32"; promised stream %"
|
||||
PRIu32, stream_id, promised_stream_id);
|
||||
LCID("generated HTTP PUSH_PROMISE for stream %"PRIu64"; promised stream %"
|
||||
PRIu64, stream_id, promised_stream_id);
|
||||
|
||||
for (i = 0; i < headers->count; ++i)
|
||||
LCID(" %.*s: %.*s",
|
||||
|
@ -346,9 +516,8 @@ lsquic_ev_log_generated_http_push_promise (lsquic_cid_t cid,
|
|||
(char *) extra_headers->headers[i].value.iov_base);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_create_connection (lsquic_cid_t cid,
|
||||
lsquic_ev_log_create_connection (const lsquic_cid_t *cid,
|
||||
const struct sockaddr *local_sa,
|
||||
const struct sockaddr *peer_sa)
|
||||
{
|
||||
|
@ -357,21 +526,21 @@ lsquic_ev_log_create_connection (lsquic_cid_t cid,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_hsk_completed (lsquic_cid_t cid)
|
||||
lsquic_ev_log_hsk_completed (const lsquic_cid_t *cid)
|
||||
{
|
||||
LCID("handshake completed");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_zero_rtt (lsquic_cid_t cid)
|
||||
lsquic_ev_log_zero_rtt (const lsquic_cid_t *cid)
|
||||
{
|
||||
LCID("zero_rtt successful");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_ev_log_check_certs (lsquic_cid_t cid, const lsquic_str_t **certs,
|
||||
lsquic_ev_log_check_certs (const lsquic_cid_t *cid, const lsquic_str_t **certs,
|
||||
size_t count)
|
||||
{
|
||||
LCID("check certs");
|
||||
|
@ -379,7 +548,7 @@ lsquic_ev_log_check_certs (lsquic_cid_t cid, const lsquic_str_t **certs,
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_version_negotiation (lsquic_cid_t cid,
|
||||
lsquic_ev_log_version_negotiation (const lsquic_cid_t *cid,
|
||||
const char *action, const char *ver)
|
||||
{
|
||||
LCID("version negotiation: %s version %s", action, ver);
|
||||
|
|
|
@ -32,7 +32,7 @@ struct uncompressed_headers;
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_in (lsquic_cid_t, const struct lsquic_packet_in *);
|
||||
lsquic_ev_log_packet_in (const lsquic_cid_t *, const struct lsquic_packet_in *);
|
||||
|
||||
#define EV_LOG_PACKET_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -40,7 +40,7 @@ lsquic_ev_log_packet_in (lsquic_cid_t, const struct lsquic_packet_in *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_ack_frame_in (lsquic_cid_t, const struct ack_info *);
|
||||
lsquic_ev_log_ack_frame_in (const lsquic_cid_t *, const struct ack_info *);
|
||||
|
||||
#define EV_LOG_ACK_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -48,7 +48,8 @@ lsquic_ev_log_ack_frame_in (lsquic_cid_t, const struct ack_info *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_stream_frame_in (lsquic_cid_t, const struct stream_frame *);
|
||||
lsquic_ev_log_stream_frame_in (const lsquic_cid_t *,
|
||||
const struct stream_frame *);
|
||||
|
||||
#define EV_LOG_STREAM_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -56,7 +57,16 @@ lsquic_ev_log_stream_frame_in (lsquic_cid_t, const struct stream_frame *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_window_update_frame_in (lsquic_cid_t, uint32_t stream_id,
|
||||
lsquic_ev_log_crypto_frame_in (const lsquic_cid_t *,
|
||||
const struct stream_frame *, unsigned enc_level);
|
||||
|
||||
#define EV_LOG_CRYPTO_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_crypto_frame_in(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_window_update_frame_in (const lsquic_cid_t *, lsquic_stream_id_t,
|
||||
uint64_t offset);
|
||||
|
||||
#define EV_LOG_WINDOW_UPDATE_FRAME_IN(...) do { \
|
||||
|
@ -65,7 +75,7 @@ lsquic_ev_log_window_update_frame_in (lsquic_cid_t, uint32_t stream_id,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_blocked_frame_in (lsquic_cid_t, uint32_t stream_id);
|
||||
lsquic_ev_log_blocked_frame_in (const lsquic_cid_t *, lsquic_stream_id_t);
|
||||
|
||||
#define EV_LOG_BLOCKED_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -73,7 +83,7 @@ lsquic_ev_log_blocked_frame_in (lsquic_cid_t, uint32_t stream_id);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_stop_waiting_frame_in (lsquic_cid_t, lsquic_packno_t);
|
||||
lsquic_ev_log_stop_waiting_frame_in (const lsquic_cid_t *, lsquic_packno_t);
|
||||
|
||||
#define EV_LOG_STOP_WAITING_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -81,8 +91,8 @@ lsquic_ev_log_stop_waiting_frame_in (lsquic_cid_t, lsquic_packno_t);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_connection_close_frame_in (lsquic_cid_t, uint32_t error_code,
|
||||
int reason_len, const char *reason);
|
||||
lsquic_ev_log_connection_close_frame_in (const lsquic_cid_t *,
|
||||
uint64_t error_code, int reason_len, const char *reason);
|
||||
|
||||
#define EV_LOG_CONNECTION_CLOSE_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -90,8 +100,8 @@ lsquic_ev_log_connection_close_frame_in (lsquic_cid_t, uint32_t error_code,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_goaway_frame_in (lsquic_cid_t, uint32_t error_code,
|
||||
uint32_t stream_id, int reason_len, const char *reason);
|
||||
lsquic_ev_log_goaway_frame_in (const lsquic_cid_t *, uint32_t error_code,
|
||||
lsquic_stream_id_t, int reason_len, const char *reason);
|
||||
|
||||
#define EV_LOG_GOAWAY_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -99,8 +109,8 @@ lsquic_ev_log_goaway_frame_in (lsquic_cid_t, uint32_t error_code,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_rst_stream_frame_in (lsquic_cid_t, uint32_t stream_id,
|
||||
uint64_t offset, uint32_t error_code);
|
||||
lsquic_ev_log_rst_stream_frame_in (const lsquic_cid_t *, lsquic_stream_id_t,
|
||||
uint64_t offset, uint64_t error_code);
|
||||
|
||||
#define EV_LOG_RST_STREAM_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -108,7 +118,16 @@ lsquic_ev_log_rst_stream_frame_in (lsquic_cid_t, uint32_t stream_id,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_padding_frame_in (lsquic_cid_t, size_t len);
|
||||
lsquic_ev_log_stop_sending_frame_in (const lsquic_cid_t *,lsquic_stream_id_t,
|
||||
uint64_t error_code);
|
||||
|
||||
#define EV_LOG_STOP_SENDING_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_stop_sending_frame_in(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_padding_frame_in (const lsquic_cid_t *, size_t len);
|
||||
|
||||
#define EV_LOG_PADDING_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -116,7 +135,7 @@ lsquic_ev_log_padding_frame_in (lsquic_cid_t, size_t len);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_ping_frame_in (lsquic_cid_t);
|
||||
lsquic_ev_log_ping_frame_in (const lsquic_cid_t *);
|
||||
|
||||
#define EV_LOG_PING_FRAME_IN(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -124,7 +143,8 @@ lsquic_ev_log_ping_frame_in (lsquic_cid_t);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_created (lsquic_cid_t, const struct lsquic_packet_out *);
|
||||
lsquic_ev_log_packet_created (const lsquic_cid_t *,
|
||||
const struct lsquic_packet_out *);
|
||||
|
||||
#define EV_LOG_PACKET_CREATED(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -132,7 +152,8 @@ lsquic_ev_log_packet_created (lsquic_cid_t, const struct lsquic_packet_out *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_sent (lsquic_cid_t, const struct lsquic_packet_out *);
|
||||
lsquic_ev_log_packet_sent (const lsquic_cid_t *,
|
||||
const struct lsquic_packet_out *);
|
||||
|
||||
#define EV_LOG_PACKET_SENT(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -140,7 +161,8 @@ lsquic_ev_log_packet_sent (lsquic_cid_t, const struct lsquic_packet_out *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_packet_not_sent (lsquic_cid_t, const struct lsquic_packet_out *);
|
||||
lsquic_ev_log_packet_not_sent (const lsquic_cid_t *,
|
||||
const struct lsquic_packet_out *);
|
||||
|
||||
#define EV_LOG_PACKET_NOT_SENT(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -148,7 +170,7 @@ lsquic_ev_log_packet_not_sent (lsquic_cid_t, const struct lsquic_packet_out *);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_http_headers_in (lsquic_cid_t, int is_server,
|
||||
lsquic_ev_log_http_headers_in (const lsquic_cid_t *, int is_server,
|
||||
const struct uncompressed_headers *);
|
||||
|
||||
#define EV_LOG_HTTP_HEADERS_IN(...) do { \
|
||||
|
@ -157,7 +179,8 @@ lsquic_ev_log_http_headers_in (lsquic_cid_t, int is_server,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_action_stream_frame (lsquic_cid_t, const struct parse_funcs *pf,
|
||||
lsquic_ev_log_action_stream_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *pf,
|
||||
const unsigned char *, size_t len, const char *action);
|
||||
|
||||
#define EV_LOG_GENERATED_STREAM_FRAME(...) do { \
|
||||
|
@ -171,8 +194,18 @@ lsquic_ev_log_action_stream_frame (lsquic_cid_t, const struct parse_funcs *pf,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_ack_frame (lsquic_cid_t, const struct parse_funcs *,
|
||||
const unsigned char *, size_t len);
|
||||
lsquic_ev_log_generated_crypto_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *pf,
|
||||
const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_CRYPTO_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_crypto_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_ack_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *, const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_ACK_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -180,7 +213,44 @@ lsquic_ev_log_generated_ack_frame (lsquic_cid_t, const struct parse_funcs *,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stop_waiting_frame (lsquic_cid_t, lsquic_packno_t);
|
||||
lsquic_ev_log_generated_new_token_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *, const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_NEW_TOKEN_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_new_token_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_path_chal_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *, const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_PATH_CHAL_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_path_chal_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_path_resp_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *, const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_PATH_RESP_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_path_resp_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_new_connection_id_frame (const lsquic_cid_t *,
|
||||
const struct parse_funcs *, const unsigned char *, size_t len);
|
||||
|
||||
#define EV_LOG_GENERATED_NEW_CONNECTION_ID_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_new_connection_id_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_stop_waiting_frame (const lsquic_cid_t *,
|
||||
lsquic_packno_t);
|
||||
|
||||
#define EV_LOG_GENERATED_STOP_WAITING_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -188,7 +258,16 @@ lsquic_ev_log_generated_stop_waiting_frame (lsquic_cid_t, lsquic_packno_t);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_headers (lsquic_cid_t, uint32_t stream_id,
|
||||
lsquic_ev_log_generated_stop_sending_frame (const lsquic_cid_t *,
|
||||
lsquic_stream_id_t, uint16_t);
|
||||
|
||||
#define EV_LOG_GENERATED_STOP_SENDING_FRAME(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
lsquic_ev_log_generated_stop_sending_frame(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_headers (const lsquic_cid_t *, lsquic_stream_id_t,
|
||||
int is_server, const struct http_prio_frame *,
|
||||
const struct lsquic_http_headers *);
|
||||
|
||||
|
@ -199,10 +278,10 @@ lsquic_ev_log_generated_http_headers (lsquic_cid_t, uint32_t stream_id,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_generated_http_push_promise (lsquic_cid_t, uint32_t stream_id,
|
||||
uint32_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers);
|
||||
lsquic_ev_log_generated_http_push_promise (const lsquic_cid_t *,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
const struct lsquic_http_headers *extra_headers);
|
||||
|
||||
#define EV_LOG_GENERATED_HTTP_PUSH_PROMISE(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -210,7 +289,7 @@ lsquic_ev_log_generated_http_push_promise (lsquic_cid_t, uint32_t stream_id,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_create_connection (lsquic_cid_t, const struct sockaddr *,
|
||||
lsquic_ev_log_create_connection (const lsquic_cid_t *, const struct sockaddr *,
|
||||
const struct sockaddr *);
|
||||
|
||||
#define EV_LOG_CREATE_CONN(...) do { \
|
||||
|
@ -221,7 +300,7 @@ lsquic_ev_log_create_connection (lsquic_cid_t, const struct sockaddr *,
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_hsk_completed (lsquic_cid_t);
|
||||
lsquic_ev_log_hsk_completed (const lsquic_cid_t *);
|
||||
|
||||
#define EV_LOG_HSK_COMPLETED(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -232,7 +311,7 @@ lsquic_ev_log_hsk_completed (lsquic_cid_t);
|
|||
|
||||
|
||||
void
|
||||
lsquic_ev_log_zero_rtt (lsquic_cid_t);
|
||||
lsquic_ev_log_zero_rtt (const lsquic_cid_t *);
|
||||
|
||||
#define EV_LOG_ZERO_RTT(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -242,7 +321,7 @@ lsquic_ev_log_zero_rtt (lsquic_cid_t);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_check_certs (lsquic_cid_t, const lsquic_str_t **, size_t);
|
||||
lsquic_ev_log_check_certs (const lsquic_cid_t *, const lsquic_str_t **, size_t);
|
||||
|
||||
#define EV_LOG_CHECK_CERTS(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
@ -252,7 +331,7 @@ lsquic_ev_log_check_certs (lsquic_cid_t, const lsquic_str_t **, size_t);
|
|||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_ev_log_version_negotiation (lsquic_cid_t, const char *, const char *);
|
||||
lsquic_ev_log_version_negotiation (const lsquic_cid_t *, const char *, const char *);
|
||||
|
||||
#define EV_LOG_VER_NEG(...) do { \
|
||||
if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT)) \
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_frab_list.c -- List of buffer for simple reading and writing
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic_frab_list.h"
|
||||
|
||||
|
||||
static void *
|
||||
fral_alloc (void *ctx, size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fral_free (void *ctx, void *obj)
|
||||
{
|
||||
free(obj);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_frab_list_init (struct frab_list *fral, unsigned short buf_size,
|
||||
void * (*alloc)(void *alloc_ctx, size_t size),
|
||||
void (*free)(void *alloc_ctx, void *obj), void *alloc_ctx)
|
||||
{
|
||||
TAILQ_INIT(&fral->fl_frabs);
|
||||
fral->fl_alloc_ctx = alloc_ctx;
|
||||
fral->fl_alloc = alloc ? alloc : fral_alloc;
|
||||
fral->fl_free = free ? free : fral_free;
|
||||
fral->fl_buf_size = buf_size;
|
||||
fral->fl_size = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_frab_list_cleanup (struct frab_list *fral)
|
||||
{
|
||||
struct frame_buf *frab, *next;
|
||||
|
||||
for (frab = TAILQ_FIRST(&fral->fl_frabs); frab; frab = next)
|
||||
{
|
||||
next = TAILQ_NEXT(frab, frab_next);
|
||||
fral->fl_free(fral->fl_alloc_ctx, frab);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct frame_buf *
|
||||
fral_get_frab (struct frab_list *fral)
|
||||
{
|
||||
struct frame_buf *frab;
|
||||
frab = fral->fl_alloc(fral->fl_alloc_ctx, fral->fl_buf_size);
|
||||
if (frab)
|
||||
{
|
||||
memset(frab, 0, sizeof(*frab));
|
||||
frab->frab_buf_size = fral->fl_buf_size;
|
||||
}
|
||||
return frab;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_frab_list_write (struct frab_list *fral, const void *buf, size_t bufsz)
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char *const end = p + bufsz;
|
||||
struct frame_buf *frab;
|
||||
unsigned ntowrite;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
frab = TAILQ_LAST(&fral->fl_frabs, frame_buf_head);
|
||||
if (!(frab && (ntowrite = frab_left_to_write(frab)) > 0))
|
||||
{
|
||||
frab = fral_get_frab(fral);
|
||||
if (!frab)
|
||||
return -1;
|
||||
TAILQ_INSERT_TAIL(&fral->fl_frabs, frab, frab_next);
|
||||
ntowrite = frab_left_to_write(frab);
|
||||
}
|
||||
if ((ptrdiff_t) ntowrite > end - p)
|
||||
ntowrite = end - p;
|
||||
memcpy(frab_write_to(frab), p, ntowrite);
|
||||
p += ntowrite;
|
||||
frab->frab_size += ntowrite;
|
||||
}
|
||||
|
||||
fral->fl_size += bufsz;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_size (void *ctx)
|
||||
{
|
||||
struct frab_list *fral = ctx;
|
||||
return fral->fl_size;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_read (void *ctx, void *buf, size_t bufsz)
|
||||
{
|
||||
struct frab_list *const fral = ctx;
|
||||
unsigned char *p = buf;
|
||||
unsigned char *const end = p + bufsz;
|
||||
struct frame_buf *frab;
|
||||
size_t ntocopy;
|
||||
|
||||
while (p < end && (frab = TAILQ_FIRST(&fral->fl_frabs)))
|
||||
{
|
||||
ntocopy = end - p;
|
||||
if (ntocopy > (size_t) frab_left_to_read(frab))
|
||||
ntocopy = frab_left_to_read(frab);
|
||||
memcpy(p, frab->frab_buf + frab->frab_off, ntocopy);
|
||||
fral->fl_size -= ntocopy;
|
||||
frab->frab_off += ntocopy;
|
||||
p += ntocopy;
|
||||
if (frab->frab_off == frab->frab_size)
|
||||
{
|
||||
TAILQ_REMOVE(&fral->fl_frabs, frab, frab_next);
|
||||
fral->fl_free(fral->fl_alloc_ctx, frab);
|
||||
}
|
||||
}
|
||||
|
||||
return p - (unsigned char *) buf;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_mem_used (const struct frab_list *fral)
|
||||
{
|
||||
struct frame_buf *frab;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*fral);
|
||||
TAILQ_FOREACH(frab, &fral->fl_frabs, frab_next)
|
||||
size += fral->fl_buf_size;
|
||||
|
||||
return size;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_frab_list.h -- List of buffer for simple reading and writing
|
||||
*
|
||||
* Useful for buffering data that cannot be packetized immediately.
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_FRAB_LIST_H
|
||||
#define LSQUIC_FRAB_LIST_H 1
|
||||
|
||||
struct frame_buf
|
||||
{
|
||||
TAILQ_ENTRY(frame_buf) frab_next;
|
||||
unsigned short frab_size,
|
||||
frab_off,
|
||||
frab_buf_size; /* Total bytes in frab_buf */
|
||||
unsigned char frab_buf[0];
|
||||
};
|
||||
|
||||
#define frab_left_to_read(f) ((f)->frab_size - (f)->frab_off)
|
||||
#define frab_left_to_write(f) ((f)->frab_buf_size - \
|
||||
(unsigned short) sizeof(*(f)) - (f)->frab_size)
|
||||
#define frab_write_to(f) ((f)->frab_buf + (f)->frab_size)
|
||||
|
||||
TAILQ_HEAD(frame_buf_head, frame_buf);
|
||||
|
||||
struct frab_list
|
||||
{
|
||||
struct frame_buf_head fl_frabs;
|
||||
void * (*fl_alloc)(void *alloc_ctx, size_t size);
|
||||
void (*fl_free)(void *alloc_ctx, void *obj);
|
||||
void *fl_alloc_ctx;
|
||||
size_t fl_size; /* Size of payload in frab_list */
|
||||
unsigned short fl_buf_size; /* Size of frame_buf */
|
||||
};
|
||||
|
||||
void
|
||||
lsquic_frab_list_init (struct frab_list *, unsigned short buf_size,
|
||||
void * (*fl_alloc)(void *alloc_ctx, size_t size),
|
||||
void (*fl_free)(void *alloc_ctx, void *obj), void *fl_alloc_ctx);
|
||||
|
||||
void
|
||||
lsquic_frab_list_cleanup (struct frab_list *);
|
||||
|
||||
int
|
||||
lsquic_frab_list_write (struct frab_list *, const void *, size_t);
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_size (void *);
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_read (void *, void *, size_t);
|
||||
|
||||
#define lsquic_frab_list_empty(fral) TAILQ_EMPTY(&(fral)->fl_frabs)
|
||||
|
||||
size_t
|
||||
lsquic_frab_list_mem_used (const struct frab_list *);
|
||||
|
||||
#endif
|
|
@ -22,10 +22,12 @@
|
|||
#include "lsquic_http1x_if.h"
|
||||
#include "lsquic_headers.h"
|
||||
#include "lsquic_ev_log.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_READER
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(fr->fr_stream))
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(lsquic_stream_conn(\
|
||||
fr->fr_stream))
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
|
@ -200,7 +202,7 @@ lsquic_frame_reader_new (enum frame_reader_flags flags,
|
|||
if (hsi_if == lsquic_http1x_if)
|
||||
{
|
||||
fr->fr_h1x_ctor_ctx = (struct http1x_ctor_ctx) {
|
||||
.cid = LSQUIC_LOG_CONN_ID,
|
||||
.conn = lsquic_stream_conn(stream),
|
||||
.max_headers_sz = fr->fr_max_headers_sz,
|
||||
.is_server = fr->fr_flags & FRF_SERVER,
|
||||
};
|
||||
|
@ -515,8 +517,9 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
|
|||
enum frame_reader_error err;
|
||||
int s;
|
||||
uint32_t name_idx;
|
||||
unsigned name_len, val_len;
|
||||
lshpack_strlen_t name_len, val_len;
|
||||
char *buf;
|
||||
uint32_t stream_id32;
|
||||
struct uncompressed_headers *uh = NULL;
|
||||
void *hset = NULL;
|
||||
|
||||
|
@ -544,6 +547,8 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
|
|||
buf, buf + 16 * 1024, &name_len, &val_len, &name_idx);
|
||||
if (s == 0)
|
||||
{
|
||||
if (name_idx > 61 /* XXX 61 */)
|
||||
name_idx = 0; /* Work around bug in ls-hpack */
|
||||
err = (enum frame_reader_error)
|
||||
fr->fr_hsi_if->hsi_process_header(hset, name_idx, buf,
|
||||
name_len, buf + name_len, val_len);
|
||||
|
@ -575,9 +580,9 @@ decode_and_pass_payload (struct lsquic_frame_reader *fr)
|
|||
goto stream_error;
|
||||
}
|
||||
|
||||
memcpy(&uh->uh_stream_id, fr->fr_state.header.hfh_stream_id,
|
||||
sizeof(uh->uh_stream_id));
|
||||
uh->uh_stream_id = ntohl(uh->uh_stream_id);
|
||||
memcpy(&stream_id32, fr->fr_state.header.hfh_stream_id,
|
||||
sizeof(stream_id32));
|
||||
uh->uh_stream_id = ntohl(stream_id32);
|
||||
uh->uh_oth_stream_id = hs->oth_stream_id;
|
||||
if (HTTP_FRAME_HEADERS == fr->fr_state.by_type.headers_state.frame_type)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ enum frame_reader_error
|
|||
FR_ERR_DUPLICATE_PSEH = LSQUIC_HDR_ERR_DUPLICATE_PSDO_HDR,
|
||||
FR_ERR_INCOMPL_REQ_PSEH = LSQUIC_HDR_ERR_INCOMPL_REQ_PSDO_HDR,
|
||||
FR_ERR_UNNEC_REQ_PSEH = LSQUIC_HDR_ERR_UNNEC_REQ_PSDO_HDR,
|
||||
FR_ERR_BAD_REQ_HEADER = LSQUIC_HDR_ERR_BAD_REQ_HEADER,
|
||||
FR_ERR_INCOMPL_RESP_PSEH = LSQUIC_HDR_ERR_INCOMPL_RESP_PSDO_HDR,
|
||||
FR_ERR_UNNEC_RESP_PSEH = LSQUIC_HDR_ERR_UNNEC_RESP_PSDO_HDR,
|
||||
FR_ERR_UNKNOWN_PSEH = LSQUIC_HDR_ERR_UNKNOWN_PSDO_HDR,
|
||||
|
@ -68,10 +69,10 @@ struct frame_reader_callbacks
|
|||
void (*frc_on_push_promise) (void *frame_cb_ctx, struct uncompressed_headers *);
|
||||
void (*frc_on_settings) (void *frame_cb_ctx, uint16_t setting_id,
|
||||
uint32_t setting_value);
|
||||
void (*frc_on_priority) (void *frame_cb_ctx, uint32_t stream_id,
|
||||
int exclusive, uint32_t dep_stream_id,
|
||||
void (*frc_on_priority) (void *frame_cb_ctx, lsquic_stream_id_t stream_id,
|
||||
int exclusive, lsquic_stream_id_t dep_stream_id,
|
||||
unsigned weight);
|
||||
void (*frc_on_error) (void *frame_cb_ctx, uint32_t stream_id,
|
||||
void (*frc_on_error) (void *frame_cb_ctx, lsquic_stream_id_t stream_id,
|
||||
enum frame_reader_error);
|
||||
};
|
||||
|
||||
|
|
|
@ -22,55 +22,30 @@
|
|||
#include "lsquic_mm.h"
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
|
||||
#include "lsquic_frame_writer.h"
|
||||
#include "lsquic_frame_common.h"
|
||||
#include "lsquic_frab_list.h"
|
||||
#include "lsquic_ev_log.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_FRAME_WRITER
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(fw->fw_stream))
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\
|
||||
lsquic_stream_conn(fw->fw_stream))
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#ifndef LSQUIC_FRAB_SZ
|
||||
# define LSQUIC_FRAB_SZ 0x1000
|
||||
#endif
|
||||
|
||||
struct frame_buf
|
||||
{
|
||||
TAILQ_ENTRY(frame_buf) frab_next;
|
||||
unsigned short frab_size,
|
||||
frab_off;
|
||||
unsigned char frab_buf[
|
||||
LSQUIC_FRAB_SZ
|
||||
- sizeof(TAILQ_ENTRY(frame_buf))
|
||||
- sizeof(unsigned short) * 2
|
||||
];
|
||||
};
|
||||
|
||||
#define frab_left_to_read(f) ((f)->frab_size - (f)->frab_off)
|
||||
#define frab_left_to_write(f) ((unsigned short) sizeof((f)->frab_buf) - (f)->frab_size)
|
||||
#define frab_write_to(f) ((f)->frab_buf + (f)->frab_size)
|
||||
|
||||
/* Make sure that frab_buf is at least five bytes long, otherwise a frame
|
||||
* won't fit into two adjacent frabs.
|
||||
*/
|
||||
typedef char three_byte_frab_buf[(sizeof(((struct frame_buf *)0)->frab_buf) >= 5) ?1 : - 1];
|
||||
|
||||
|
||||
TAILQ_HEAD(frame_buf_head, frame_buf);
|
||||
|
||||
|
||||
struct lsquic_frame_writer
|
||||
{
|
||||
struct lsquic_stream *fw_stream;
|
||||
fw_write_f fw_write;
|
||||
fw_writef_f fw_writef;
|
||||
struct lsquic_mm *fw_mm;
|
||||
struct lshpack_enc *fw_henc;
|
||||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats *fw_conn_stats;
|
||||
#endif
|
||||
struct frame_buf_head fw_frabs;
|
||||
struct frab_list fw_fral;
|
||||
unsigned fw_max_frame_sz;
|
||||
uint32_t fw_max_header_list_sz; /* 0 means unlimited */
|
||||
enum {
|
||||
|
@ -88,9 +63,16 @@ struct lsquic_frame_writer
|
|||
#define ABS_MIN_FRAME_SIZE MAX(SETTINGS_FRAME_SZ, \
|
||||
sizeof(struct http_prio_frame))
|
||||
|
||||
static void *
|
||||
fw_alloc (void *ctx, size_t size)
|
||||
{
|
||||
return lsquic_mm_get_4k(ctx);
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_frame_writer *
|
||||
lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
||||
unsigned max_frame_sz, struct lshpack_enc *henc, fw_write_f write,
|
||||
unsigned max_frame_sz, struct lshpack_enc *henc, fw_writef_f writef,
|
||||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats *conn_stats,
|
||||
#endif
|
||||
|
@ -124,17 +106,18 @@ lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
|||
fw->fw_mm = mm;
|
||||
fw->fw_henc = henc;
|
||||
fw->fw_stream = stream;
|
||||
fw->fw_write = write;
|
||||
fw->fw_writef = writef;
|
||||
fw->fw_max_frame_sz = max_frame_sz;
|
||||
fw->fw_max_header_list_sz = 0;
|
||||
if (is_server)
|
||||
fw->fw_flags = FW_SERVER;
|
||||
else
|
||||
fw->fw_flags = 0;
|
||||
TAILQ_INIT(&fw->fw_frabs);
|
||||
#if LSQUIC_CONN_STATS
|
||||
fw->fw_conn_stats = conn_stats;
|
||||
#endif
|
||||
lsquic_frab_list_init(&fw->fw_fral, 0x1000, fw_alloc,
|
||||
(void (*)(void *, void *)) lsquic_mm_put_4k, mm);
|
||||
return fw;
|
||||
}
|
||||
|
||||
|
@ -142,99 +125,34 @@ lsquic_frame_writer_new (struct lsquic_mm *mm, struct lsquic_stream *stream,
|
|||
void
|
||||
lsquic_frame_writer_destroy (struct lsquic_frame_writer *fw)
|
||||
{
|
||||
struct frame_buf *frab;
|
||||
while ((frab = TAILQ_FIRST(&fw->fw_frabs)))
|
||||
{
|
||||
TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next);
|
||||
lsquic_mm_put_4k(fw->fw_mm, frab);
|
||||
}
|
||||
lsquic_frab_list_cleanup(&fw->fw_fral);
|
||||
free(fw);
|
||||
}
|
||||
|
||||
|
||||
static struct frame_buf *
|
||||
fw_get_frab (struct lsquic_frame_writer *fw)
|
||||
{
|
||||
struct frame_buf *frab;
|
||||
frab = lsquic_mm_get_4k(fw->fw_mm);
|
||||
if (frab)
|
||||
memset(frab, 0, offsetof(struct frame_buf, frab_buf));
|
||||
return frab;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fw_put_frab (struct lsquic_frame_writer *fw, struct frame_buf *frab)
|
||||
{
|
||||
TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next);
|
||||
lsquic_mm_put_4k(fw->fw_mm, frab);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
fw_write_to_frab (struct lsquic_frame_writer *fw, const void *buf, size_t bufsz)
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char *const end = p + bufsz;
|
||||
struct frame_buf *frab;
|
||||
unsigned ntowrite;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
frab = TAILQ_LAST(&fw->fw_frabs, frame_buf_head);
|
||||
if (!(frab && (ntowrite = frab_left_to_write(frab)) > 0))
|
||||
{
|
||||
frab = fw_get_frab(fw);
|
||||
if (!frab)
|
||||
return -1;
|
||||
TAILQ_INSERT_TAIL(&fw->fw_frabs, frab, frab_next);
|
||||
ntowrite = frab_left_to_write(frab);
|
||||
}
|
||||
if (ntowrite > bufsz)
|
||||
ntowrite = bufsz;
|
||||
memcpy(frab_write_to(frab), p, ntowrite);
|
||||
p += ntowrite;
|
||||
bufsz -= ntowrite;
|
||||
frab->frab_size += ntowrite;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_frame_writer_have_leftovers (const struct lsquic_frame_writer *fw)
|
||||
{
|
||||
return !TAILQ_EMPTY(&fw->fw_frabs);
|
||||
return !lsquic_frab_list_empty(&fw->fw_fral);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_frame_writer_flush (struct lsquic_frame_writer *fw)
|
||||
{
|
||||
struct frame_buf *frab;
|
||||
struct lsquic_reader reader = {
|
||||
.lsqr_read = lsquic_frab_list_read,
|
||||
.lsqr_size = lsquic_frab_list_size,
|
||||
.lsqr_ctx = &fw->fw_fral,
|
||||
};
|
||||
ssize_t nw;
|
||||
|
||||
while ((frab = TAILQ_FIRST(&fw->fw_frabs)))
|
||||
{
|
||||
size_t ntowrite = frab_left_to_read(frab);
|
||||
ssize_t nw = fw->fw_write(fw->fw_stream,
|
||||
frab->frab_buf + frab->frab_off, ntowrite);
|
||||
if (nw > 0)
|
||||
{
|
||||
frab->frab_off += nw;
|
||||
if (frab->frab_off == frab->frab_size)
|
||||
{
|
||||
TAILQ_REMOVE(&fw->fw_frabs, frab, frab_next);
|
||||
fw_put_frab(fw, frab);
|
||||
}
|
||||
}
|
||||
else if (nw == 0)
|
||||
break;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
nw = fw->fw_writef(fw->fw_stream, &reader);
|
||||
|
||||
return 0;
|
||||
if (nw >= 0)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -249,7 +167,8 @@ struct header_framer_ctx
|
|||
unsigned hfc_max_frame_sz; /* Maximum frame size. We always fill it. */
|
||||
unsigned hfc_cur_sz; /* Number of bytes in the current frame. */
|
||||
unsigned hfc_n_frames; /* Number of frames written. */
|
||||
uint32_t hfc_stream_id; /* Stream ID */
|
||||
lsquic_stream_id_t
|
||||
hfc_stream_id; /* Stream ID */
|
||||
enum http_frame_header_flags
|
||||
hfc_first_flags;
|
||||
enum http_frame_type
|
||||
|
@ -259,8 +178,8 @@ struct header_framer_ctx
|
|||
|
||||
static void
|
||||
hfc_init (struct header_framer_ctx *hfc, struct lsquic_frame_writer *fw,
|
||||
unsigned max_frame_sz, enum http_frame_type frame_type,
|
||||
uint32_t stream_id, enum http_frame_header_flags first_flags)
|
||||
unsigned max_frame_sz, enum http_frame_type frame_type,
|
||||
lsquic_stream_id_t stream_id, enum http_frame_header_flags first_flags)
|
||||
{
|
||||
memset(hfc, 0, sizeof(*hfc));
|
||||
hfc->hfc_fw = fw;
|
||||
|
@ -275,7 +194,7 @@ hfc_init (struct header_framer_ctx *hfc, struct lsquic_frame_writer *fw,
|
|||
static void
|
||||
hfc_save_ptr (struct header_framer_ctx *hfc)
|
||||
{
|
||||
hfc->hfc_header_ptr.frab = TAILQ_LAST(&hfc->hfc_fw->fw_frabs, frame_buf_head);
|
||||
hfc->hfc_header_ptr.frab = TAILQ_LAST(&hfc->hfc_fw->fw_fral.fl_frabs, frame_buf_head);
|
||||
hfc->hfc_header_ptr.off = hfc->hfc_header_ptr.frab->frab_size;
|
||||
}
|
||||
|
||||
|
@ -339,7 +258,7 @@ hfc_write (struct header_framer_ctx *hfc, const void *buf, size_t sz)
|
|||
{
|
||||
if (hfc->hfc_n_frames > 0)
|
||||
hfc_terminate_frame(hfc, 0);
|
||||
s = fw_write_to_frab(hfc->hfc_fw, "123456789",
|
||||
s = lsquic_frab_list_write(&hfc->hfc_fw->fw_fral, "123456789",
|
||||
sizeof(struct http_frame_header));
|
||||
if (s < 0)
|
||||
return s;
|
||||
|
@ -353,7 +272,7 @@ hfc_write (struct header_framer_ctx *hfc, const void *buf, size_t sz)
|
|||
avail = sz;
|
||||
if (avail)
|
||||
{
|
||||
s = fw_write_to_frab(hfc->hfc_fw, p, avail);
|
||||
s = lsquic_frab_list_write(&hfc->hfc_fw->fw_fral, p, avail);
|
||||
if (s < 0)
|
||||
return s;
|
||||
hfc->hfc_cur_sz += avail;
|
||||
|
@ -421,6 +340,12 @@ check_headers_size (const struct lsquic_frame_writer *fw,
|
|||
|
||||
if (headers_sz <= fw->fw_max_header_list_sz)
|
||||
return 0;
|
||||
else if (fw->fw_flags & FW_SERVER)
|
||||
{
|
||||
LSQ_INFO("Sending headers larger (%u bytes) than max allowed (%u)",
|
||||
headers_sz, fw->fw_max_header_list_sz);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_INFO("Headers size %u is larger than max allowed (%u)",
|
||||
|
@ -480,9 +405,7 @@ write_headers (struct lsquic_frame_writer *fw,
|
|||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("error encoding header");
|
||||
errno = EBADMSG;
|
||||
return -1;
|
||||
/* Ignore errors, matching HTTP2 behavior in our server code */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,7 +415,7 @@ write_headers (struct lsquic_frame_writer *fw,
|
|||
|
||||
int
|
||||
lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw,
|
||||
uint32_t stream_id,
|
||||
lsquic_stream_id_t stream_id,
|
||||
const struct lsquic_http_headers *headers,
|
||||
int eos, unsigned weight)
|
||||
{
|
||||
|
@ -553,10 +476,12 @@ lsquic_frame_writer_write_headers (struct lsquic_frame_writer *fw,
|
|||
|
||||
int
|
||||
lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
|
||||
uint32_t stream_id, uint32_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *extra_headers)
|
||||
{
|
||||
uint32_t stream_id = stream_id64;
|
||||
uint32_t promised_stream_id = promised_stream_id64;
|
||||
struct header_framer_ctx hfc;
|
||||
struct http_push_promise_frame push_frame;
|
||||
lsquic_http_header_t mpas_headers[4];
|
||||
|
@ -659,7 +584,7 @@ write_settings (struct lsquic_frame_writer *fw,
|
|||
fh.hfh_length[1] = payload_length >> 8;
|
||||
fh.hfh_length[2] = payload_length;
|
||||
|
||||
s = fw_write_to_frab(fw, &fh, sizeof(fh));
|
||||
s = lsquic_frab_list_write(&fw->fw_fral, &fh, sizeof(fh));
|
||||
if (s != 0)
|
||||
return s;
|
||||
|
||||
|
@ -667,8 +592,8 @@ write_settings (struct lsquic_frame_writer *fw,
|
|||
{
|
||||
id = htons(settings->id);
|
||||
val = htonl(settings->value);
|
||||
if (0 != (s = fw_write_to_frab(fw, &id, sizeof(id))) ||
|
||||
0 != (s = fw_write_to_frab(fw, &val, sizeof(val))))
|
||||
if (0 != (s = lsquic_frab_list_write(&fw->fw_fral, &id, sizeof(id))) ||
|
||||
0 != (s = lsquic_frab_list_write(&fw->fw_fral, &val, sizeof(val))))
|
||||
return s;
|
||||
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "wrote HTTP SETTINGS frame: "
|
||||
"%s=%"PRIu32, lsquic_http_setting_id2str(settings->id),
|
||||
|
@ -680,7 +605,6 @@ write_settings (struct lsquic_frame_writer *fw,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_frame_writer_write_settings (struct lsquic_frame_writer *fw,
|
||||
const struct lsquic_http2_setting *settings, unsigned n_settings)
|
||||
|
@ -711,9 +635,11 @@ lsquic_frame_writer_write_settings (struct lsquic_frame_writer *fw,
|
|||
|
||||
int
|
||||
lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw,
|
||||
uint32_t stream_id, int exclusive, uint32_t stream_dep_id,
|
||||
unsigned weight)
|
||||
lsquic_stream_id_t stream_id64, int exclusive,
|
||||
lsquic_stream_id_t stream_dep_id64, unsigned weight)
|
||||
{
|
||||
uint32_t stream_id = stream_id64;
|
||||
uint32_t stream_dep_id = stream_dep_id64;
|
||||
unsigned char buf[ sizeof(struct http_frame_header) +
|
||||
sizeof(struct http_prio_frame) ];
|
||||
struct http_frame_header *fh = (void *) &buf[0];
|
||||
|
@ -741,7 +667,7 @@ lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw,
|
|||
memcpy(prio_frame->hpf_stream_id, &stream_id, 4);
|
||||
prio_frame->hpf_weight = weight - 1;
|
||||
|
||||
s = fw_write_to_frab(fw, buf, sizeof(buf));
|
||||
s = lsquic_frab_list_write(&fw->fw_fral, buf, sizeof(buf));
|
||||
if (s != 0)
|
||||
return s;
|
||||
|
||||
|
@ -756,12 +682,11 @@ lsquic_frame_writer_write_priority (struct lsquic_frame_writer *fw,
|
|||
size_t
|
||||
lsquic_frame_writer_mem_used (const struct lsquic_frame_writer *fw)
|
||||
{
|
||||
const struct frame_buf *frab;
|
||||
size_t size;
|
||||
|
||||
size = sizeof(*fw);
|
||||
TAILQ_FOREACH(frab, &fw->fw_frabs, frab_next)
|
||||
size += sizeof(*frab);
|
||||
size = sizeof(*fw)
|
||||
+ lsquic_frab_list_mem_used(&fw->fw_fral)
|
||||
- sizeof(fw->fw_fral);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Same as H2_TMP_HDR_BUFF_SIZE */
|
||||
#define MAX_HEADERS_SIZE (64 * 1024)
|
||||
|
||||
struct iovec;
|
||||
|
@ -16,18 +17,19 @@ struct lshpack_enc;
|
|||
struct lsquic_mm;
|
||||
struct lsquic_frame_writer;
|
||||
struct lsquic_stream;
|
||||
struct lsquic_reader;
|
||||
struct lsquic_http_headers;
|
||||
struct lsquic_http2_setting;
|
||||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats;
|
||||
#endif
|
||||
|
||||
typedef ssize_t (*fw_write_f)(struct lsquic_stream *, const void *, size_t);
|
||||
typedef ssize_t (*fw_writef_f)(struct lsquic_stream *, struct lsquic_reader *);
|
||||
|
||||
struct lsquic_frame_writer *
|
||||
lsquic_frame_writer_new (struct lsquic_mm *, struct lsquic_stream *,
|
||||
unsigned max_frame_sz, struct lshpack_enc *,
|
||||
fw_write_f,
|
||||
fw_writef_f,
|
||||
#if LSQUIC_CONN_STATS
|
||||
struct conn_stats *,
|
||||
#endif
|
||||
|
@ -44,7 +46,7 @@ lsquic_frame_writer_flush (struct lsquic_frame_writer *);
|
|||
|
||||
int
|
||||
lsquic_frame_writer_write_headers (struct lsquic_frame_writer *,
|
||||
uint32_t stream_id,
|
||||
lsquic_stream_id_t stream_id,
|
||||
const struct lsquic_http_headers *,
|
||||
int eos, unsigned weight);
|
||||
|
||||
|
@ -54,14 +56,14 @@ lsquic_frame_writer_write_settings (struct lsquic_frame_writer *,
|
|||
|
||||
int
|
||||
lsquic_frame_writer_write_priority (struct lsquic_frame_writer *,
|
||||
uint32_t stream_id, int exclusive, uint32_t stream_dep_id,
|
||||
unsigned priority);
|
||||
lsquic_stream_id_t stream_id, int exclusive,
|
||||
lsquic_stream_id_t stream_dep_id, unsigned priority);
|
||||
|
||||
int
|
||||
lsquic_frame_writer_write_promise (struct lsquic_frame_writer *,
|
||||
uint32_t stream_id, uint32_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers);
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers);
|
||||
|
||||
void
|
||||
lsquic_frame_writer_max_header_list_size (struct lsquic_frame_writer *,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,18 +3,56 @@
|
|||
#define LSQUIC_FULL_CONN_H
|
||||
|
||||
struct lsquic_conn;
|
||||
struct lsquic_stream_if;
|
||||
struct lsquic_engine_public;
|
||||
|
||||
struct lsquic_conn *
|
||||
full_conn_client_new (struct lsquic_engine_public *,
|
||||
const struct lsquic_stream_if *,
|
||||
void *stream_if_ctx,
|
||||
lsquic_gquic_full_conn_client_new (struct lsquic_engine_public *,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
int is_ipv4,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
|
||||
void
|
||||
full_conn_client_call_on_new (struct lsquic_conn *);
|
||||
struct lsquic_conn *
|
||||
lsquic_ietf_full_conn_client_new (struct lsquic_engine_public *,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
const char *hostname, unsigned short max_packet_size, int is_ipv4,
|
||||
const unsigned char *zero_rtt, size_t,
|
||||
const unsigned char *token, size_t);
|
||||
|
||||
typedef struct lsquic_conn *
|
||||
(*server_conn_ctor_f) (struct lsquic_engine_public *,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
struct lsquic_conn *mini_conn);
|
||||
|
||||
struct lsquic_conn *
|
||||
lsquic_gquic_full_conn_server_new (struct lsquic_engine_public *,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
struct lsquic_conn *mini_conn);
|
||||
|
||||
struct lsquic_conn *
|
||||
lsquic_ietf_full_conn_server_new (struct lsquic_engine_public *,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
struct lsquic_conn *mini_conn);
|
||||
|
||||
struct dcid_elem
|
||||
{
|
||||
/* This is never both in the hash and on the retirement list */
|
||||
union {
|
||||
struct lsquic_hash_elem hash_el;
|
||||
TAILQ_ENTRY(dcid_elem) next_to_ret;
|
||||
} de_u;
|
||||
#define de_hash_el de_u.hash_el
|
||||
#define de_next_to_ret de_u.next_to_ret
|
||||
lsquic_cid_t de_cid;
|
||||
unsigned de_seqno;
|
||||
enum {
|
||||
DE_SRST = 1 << 0, /* de_srst is set */
|
||||
DE_ASSIGNED = 1 << 1, /* de_cid has been assigned to a path */
|
||||
} de_flags;
|
||||
unsigned char de_srst[IQUIC_SRESET_TOKEN_SZ];
|
||||
};
|
||||
|
||||
int
|
||||
lsquic_gquic_full_conn_srej (struct lsquic_conn *);
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@
|
|||
#include "lsquic_types.h"
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_str.h"
|
||||
#include "lsquic_handshake.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_util.h"
|
||||
|
||||
|
||||
|
@ -15,12 +15,17 @@ int
|
|||
lsquic_global_init (int flags)
|
||||
{
|
||||
lsquic_init_timers();
|
||||
return lsquic_enc_session_gquic_1.esf_global_init(flags);
|
||||
if (0 != lsquic_enc_session_common_gquic_1.esf_global_init(flags))
|
||||
return -1;
|
||||
if (0 != lsquic_enc_session_common_ietf_v1.esf_global_init(flags))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_global_cleanup (void)
|
||||
{
|
||||
lsquic_enc_session_gquic_1.esf_global_cleanup();
|
||||
lsquic_enc_session_common_gquic_1.esf_global_cleanup();
|
||||
lsquic_enc_session_common_ietf_v1.esf_global_cleanup();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,854 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_h3_prio.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_PRIO
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(tree->h3pt_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
/* The tree supports up to 2^16 - 1 elements, which should suffice.
|
||||
* Zero is not a valid value (thus -1 elements).
|
||||
*/
|
||||
typedef unsigned short elem_idx_t;
|
||||
|
||||
/* Because stream IDs are 62-bit integers and we the HTTP/3 element type
|
||||
* only has four values (enum h3_elem_type), we can combine the two into
|
||||
* a single value. h3_id_t's lower 62 bits contain the ID, while the
|
||||
* high 2 bits contain element type. This makes searching faster.
|
||||
*/
|
||||
typedef uint64_t h3_id_t;
|
||||
|
||||
typedef unsigned char active_mark_t;
|
||||
|
||||
#define H3_EL_ID(type, id) ((((uint64_t) (type)) << 62) | id)
|
||||
|
||||
#define ROOT_IDX 1
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
struct h3_prio_elem
|
||||
{
|
||||
h3_id_t h3pe_id;
|
||||
struct lsquic_stream *h3pe_stream;
|
||||
|
||||
/* Time at which stream was closed: */
|
||||
lsquic_time_t h3pe_closed_at;
|
||||
|
||||
/* Tree neighbors: */
|
||||
elem_idx_t h3pe_parent,
|
||||
h3pe_first_child,
|
||||
h3pe_left,
|
||||
h3pe_right;
|
||||
|
||||
/* Closed streams are kept on a separate queue for efficient pruning: */
|
||||
elem_idx_t h3pe_next_closed;
|
||||
|
||||
/* Used as tiebreaker between elements with the same weight: streams
|
||||
* added earlier to the iterator have higher priority.
|
||||
*/
|
||||
elem_idx_t h3pe_iter_order;
|
||||
#define h3pe_taken h3pe_iter_order
|
||||
|
||||
enum {
|
||||
H3PE_FLAG_CLOSED = 1 << 0,
|
||||
} h3pe_flags:8;
|
||||
h3_weight_t h3pe_weight;
|
||||
|
||||
/* These marks are part of the iterator state */
|
||||
active_mark_t h3pe_active_self;
|
||||
active_mark_t h3pe_active_path;
|
||||
};
|
||||
|
||||
#define EL_TYPE(el) ((enum h3_elem_type)((el)->h3pe_id >> 62))
|
||||
#define EL_ID(el) ((uint64_t)((el)->h3pe_id & ((1ull << 62) - 1)))
|
||||
|
||||
#define CALC_EL_IDX(tree, el) (+((el) - (tree)->h3pt_els))
|
||||
|
||||
/* The weight and the iterator order are combined into a single value to
|
||||
* reduce the number of branches.
|
||||
*/
|
||||
typedef uint32_t iter_prio_t;
|
||||
#define EL_ITER_PRIO(el) (((uint32_t) ((el)->h3pe_weight << 16)) | \
|
||||
(el)->h3pe_iter_order)
|
||||
#define MAX_ITER_PRIO ((1u << 24) - 1)
|
||||
|
||||
#define MAX_CRIT_STREAMS (4 /* crypto streams */ \
|
||||
+ 3 /* outgoing control, encoder, and decoder */ \
|
||||
+ 3 /* incoming control, encoder, and decoder */)
|
||||
|
||||
struct h3_iter
|
||||
{
|
||||
const char *h3it_log_id;
|
||||
elem_idx_t h3it_cursor;
|
||||
elem_idx_t h3it_count;
|
||||
active_mark_t h3it_active;
|
||||
|
||||
/* Critical streams do not participate in the regular HTTP/3 priority
|
||||
* mechanism. They have an implicit priority which is higher than
|
||||
* that of the regular request or push streams. The iterator holds
|
||||
* references to them only for the duration of the iteration.
|
||||
*/
|
||||
unsigned h3it_crit_off;
|
||||
unsigned h3it_crit_count;
|
||||
struct lsquic_stream *h3it_crit_streams[MAX_CRIT_STREAMS];
|
||||
};
|
||||
|
||||
struct h3_prio_tree
|
||||
{
|
||||
const struct lsquic_conn *h3pt_conn; /* Used for logging */
|
||||
|
||||
/* Element 0 does not contain a valid value. Its only use is to store
|
||||
* the linear search sentinel.
|
||||
*/
|
||||
struct h3_prio_elem *h3pt_els;
|
||||
|
||||
struct h3_iter h3pt_iter;
|
||||
|
||||
unsigned h3pt_nalloc; /* Including element 0 */
|
||||
unsigned h3pt_nelem; /* Including element 0 */
|
||||
unsigned h3pt_max_ph; /* Maximum placeholder ID */
|
||||
|
||||
/* STAILQ analog: first element is the oldest, newly closed stream
|
||||
* elements are inserted at the end.
|
||||
*/
|
||||
elem_idx_t h3pt_closed_first,
|
||||
h3pt_closed_last;
|
||||
};
|
||||
|
||||
|
||||
struct h3_prio_tree *
|
||||
lsquic_prio_tree_new (const struct lsquic_conn *conn, unsigned n_placeholders)
|
||||
{
|
||||
struct h3_prio_tree *tree;
|
||||
struct h3_prio_elem *els;
|
||||
unsigned nalloc, nelem;
|
||||
|
||||
tree = calloc(1, sizeof(*tree));
|
||||
if (!tree)
|
||||
return NULL;
|
||||
|
||||
nelem = 1 /* element 0 */ + 1 /* root */;
|
||||
nalloc = nelem + 4;
|
||||
els = malloc(nalloc * sizeof(els[0]));
|
||||
if (!els)
|
||||
{
|
||||
free(tree);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
els[ROOT_IDX] = (struct h3_prio_elem) { .h3pe_id = H3_EL_ID(H3ET_ROOT, 0) };
|
||||
|
||||
tree->h3pt_conn = conn;
|
||||
tree->h3pt_els = els;
|
||||
tree->h3pt_nalloc = nalloc;
|
||||
tree->h3pt_nelem = nelem;
|
||||
tree->h3pt_max_ph = n_placeholders;
|
||||
LSQ_DEBUG("create tree with maximum %u placeholders", n_placeholders);
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
static struct h3_prio_elem *
|
||||
prio_tree_find_by_h3_id (struct h3_prio_tree *tree, h3_id_t h3_id)
|
||||
{
|
||||
struct h3_prio_elem *el;
|
||||
|
||||
tree->h3pt_els[0].h3pe_id = h3_id;
|
||||
for (el = &tree->h3pt_els[tree->h3pt_nelem - 1]; el->h3pe_id != h3_id; --el)
|
||||
;
|
||||
|
||||
if (el > tree->h3pt_els)
|
||||
return el;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct h3_prio_elem *
|
||||
prio_tree_find (struct h3_prio_tree *tree, enum h3_elem_type type, uint64_t id)
|
||||
{
|
||||
if (type == H3ET_ROOT)
|
||||
return &tree->h3pt_els[ROOT_IDX];
|
||||
else
|
||||
return prio_tree_find_by_h3_id(tree, H3_EL_ID(type, id));
|
||||
}
|
||||
|
||||
|
||||
static struct h3_prio_elem *
|
||||
prio_tree_alloc_elem (struct h3_prio_tree *tree)
|
||||
{
|
||||
struct h3_prio_elem *els;
|
||||
unsigned nalloc;
|
||||
|
||||
if (tree->h3pt_nalloc > tree->h3pt_nelem)
|
||||
return &tree->h3pt_els[ tree->h3pt_nelem++ ];
|
||||
|
||||
nalloc = MIN(H3_PRIO_MAX_ELEMS + 1, tree->h3pt_nalloc * 2);
|
||||
if (nalloc <= tree->h3pt_nelem)
|
||||
{
|
||||
LSQ_ERROR("number of elements reached maximum");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
els = realloc(tree->h3pt_els, nalloc * sizeof(tree->h3pt_els[0]));
|
||||
if (!els)
|
||||
{
|
||||
LSQ_WARN("memory allocation failure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->h3pt_els = els;
|
||||
tree->h3pt_nalloc = nalloc;
|
||||
return &tree->h3pt_els[ tree->h3pt_nelem++ ];
|
||||
}
|
||||
|
||||
|
||||
static struct h3_prio_elem *
|
||||
prio_tree_create_elem (struct h3_prio_tree *tree, enum h3_elem_type type,
|
||||
uint64_t id)
|
||||
{
|
||||
struct h3_prio_elem *el, *root;
|
||||
|
||||
assert(type != H3ET_ROOT);
|
||||
if (type == H3ET_PLACEHOLDER && id >= tree->h3pt_max_ph)
|
||||
{
|
||||
LSQ_INFO("invalid placeholder id %"PRIu64" is invalid (maximum "
|
||||
"is %u placeholders", id, tree->h3pt_max_ph);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
el = prio_tree_alloc_elem(tree);
|
||||
if (el)
|
||||
{
|
||||
root = &tree->h3pt_els[ROOT_IDX];
|
||||
*el = (struct h3_prio_elem) { .h3pe_id = H3_EL_ID(type, id),
|
||||
.h3pe_parent = ROOT_IDX,
|
||||
.h3pe_right = root->h3pe_first_child,
|
||||
.h3pe_weight = H3_DEFAULT_WEIGHT, };
|
||||
if (root->h3pe_first_child)
|
||||
tree->h3pt_els[ root->h3pe_first_child ].h3pe_left
|
||||
= el - tree->h3pt_els;
|
||||
root->h3pe_first_child = el - tree->h3pt_els;
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
prio_tree_reparent (struct h3_prio_tree *tree,
|
||||
struct h3_prio_elem *const child,
|
||||
struct h3_prio_elem *const parent)
|
||||
{
|
||||
struct h3_prio_elem *orig_parent;
|
||||
elem_idx_t child_idx;
|
||||
|
||||
child_idx = CALC_EL_IDX(tree, child);
|
||||
orig_parent = &tree->h3pt_els[child->h3pe_parent];
|
||||
|
||||
if (orig_parent->h3pe_first_child == child_idx)
|
||||
orig_parent->h3pe_first_child = child->h3pe_right;
|
||||
else
|
||||
tree->h3pt_els[child->h3pe_left].h3pe_right = child->h3pe_right;
|
||||
if (child->h3pe_right)
|
||||
tree->h3pt_els[child->h3pe_right].h3pe_left = child->h3pe_left;
|
||||
|
||||
child->h3pe_left = 0;
|
||||
child->h3pe_right = parent->h3pe_first_child;
|
||||
if (child->h3pe_right)
|
||||
tree->h3pt_els[child->h3pe_right].h3pe_left = child_idx;
|
||||
parent->h3pe_first_child = child_idx;
|
||||
child->h3pe_parent = CALC_EL_IDX(tree, parent);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
prio_tree_is_parent (struct h3_prio_tree *tree,
|
||||
const struct h3_prio_elem *parent, const struct h3_prio_elem *child)
|
||||
{
|
||||
elem_idx_t idx;
|
||||
|
||||
assert(parent != child);
|
||||
tree->h3pt_els[0].h3pe_id = parent->h3pe_id;
|
||||
idx = child->h3pe_parent;
|
||||
while (tree->h3pt_els[idx].h3pe_id != parent->h3pe_id)
|
||||
idx = tree->h3pt_els[idx].h3pe_parent;
|
||||
return idx > 0;
|
||||
}
|
||||
|
||||
|
||||
static const char el_type2char[] =
|
||||
{
|
||||
[H3ET_ROOT] = 'R',
|
||||
[H3ET_REQ_STREAM] = 'Q',
|
||||
[H3ET_PUSH_STREAM] = 'P',
|
||||
[H3ET_PLACEHOLDER] = 'H',
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
lsquic_prio_tree_set_rel (struct h3_prio_tree *tree,
|
||||
enum h3_elem_type child_type, uint64_t child_id, h3_weight_t child_weight,
|
||||
enum h3_elem_type parent_type, uint64_t parent_id)
|
||||
{
|
||||
struct h3_prio_elem *parent, *child;
|
||||
|
||||
parent = prio_tree_find(tree, parent_type, parent_id);
|
||||
if (!parent)
|
||||
{
|
||||
parent = prio_tree_create_elem(tree, parent_type, parent_id);
|
||||
if (!parent)
|
||||
return -1;
|
||||
}
|
||||
const elem_idx_t parent_idx = CALC_EL_IDX(tree, parent);
|
||||
|
||||
child = prio_tree_find(tree, child_type, child_id);
|
||||
if (!child)
|
||||
{
|
||||
child = prio_tree_create_elem(tree, child_type, child_id);
|
||||
if (!child)
|
||||
return -1;
|
||||
/* create() above may have realloced */
|
||||
parent = &tree->h3pt_els[ parent_idx ];
|
||||
}
|
||||
|
||||
if (child->h3pe_parent != parent_idx)
|
||||
{
|
||||
if (prio_tree_is_parent(tree, child, parent))
|
||||
prio_tree_reparent(tree, parent,
|
||||
&tree->h3pt_els[child->h3pe_parent]);
|
||||
prio_tree_reparent(tree, child, parent);
|
||||
}
|
||||
else if (child == parent)
|
||||
return -1; /* This is unlikely, so check for it last */
|
||||
|
||||
child->h3pe_weight = child_weight;
|
||||
|
||||
LSQ_DEBUG("add rel to %c:%"PRIu64" -> %c:%"PRIu64" with w=%u",
|
||||
el_type2char[ child_type ], child_id,
|
||||
el_type2char[ parent_type ], parent_id, child_weight);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Assume that unidirectional streams are push streams */
|
||||
static enum h3_elem_type
|
||||
stream_id_2_elem_type (lsquic_stream_id_t stream_id)
|
||||
{
|
||||
enum stream_dir dir;
|
||||
|
||||
dir = 1 & (stream_id >> SD_SHIFT);
|
||||
if (dir == SD_BIDI)
|
||||
return H3ET_REQ_STREAM;
|
||||
else
|
||||
return H3ET_PUSH_STREAM;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_prio_tree_add_stream (struct h3_prio_tree *tree,
|
||||
struct lsquic_stream *stream, enum h3_elem_type parent_type,
|
||||
uint64_t parent_id, h3_weight_t weight)
|
||||
{
|
||||
struct h3_prio_elem *parent, *child;
|
||||
enum h3_elem_type type;
|
||||
elem_idx_t child_idx;
|
||||
|
||||
assert(!lsquic_stream_is_critical(stream));
|
||||
|
||||
type = stream_id_2_elem_type(stream->id);
|
||||
child = prio_tree_find(tree, type, stream->id);
|
||||
if (child)
|
||||
{
|
||||
/* Prioritization information already exists: set the pointer
|
||||
* and ignore PRIORITY frame information on the request stream.
|
||||
*/
|
||||
if (!child->h3pe_stream)
|
||||
{
|
||||
child_idx = CALC_EL_IDX(tree, child);
|
||||
LSQ_DEBUG("reference stream %c:%"PRIu64" in prio element",
|
||||
el_type2char[ type ], stream->id);
|
||||
goto link;
|
||||
}
|
||||
LSQ_WARN("stream %"PRIu64" is already referenced", stream->id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
child = prio_tree_create_elem(tree, type, stream->id);
|
||||
if (!child)
|
||||
return -1;
|
||||
child_idx = CALC_EL_IDX(tree, child);
|
||||
|
||||
parent = prio_tree_find(tree, parent_type, parent_id);
|
||||
if (!parent)
|
||||
{
|
||||
parent = prio_tree_create_elem(tree, parent_type, parent_id);
|
||||
if (!parent)
|
||||
return -1;
|
||||
/* create() above may have realloced */
|
||||
child = &tree->h3pt_els[ child_idx ];
|
||||
}
|
||||
|
||||
prio_tree_reparent(tree, child, parent);
|
||||
child->h3pe_weight = weight;
|
||||
LSQ_DEBUG("add stream %c:%"PRIu64" -> %c:%"PRIu64" with w=%u",
|
||||
el_type2char[ type ], stream->id,
|
||||
el_type2char[ parent_type ], parent_id, weight);
|
||||
link:
|
||||
child->h3pe_stream = stream;
|
||||
stream->sm_h3_prio_idx = child_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_prio_tree_remove_stream (struct h3_prio_tree *tree,
|
||||
struct lsquic_stream *stream, lsquic_time_t now)
|
||||
{
|
||||
struct h3_prio_elem *el;
|
||||
|
||||
el = &tree->h3pt_els[ stream->sm_h3_prio_idx ];
|
||||
|
||||
if (stream->sm_h3_prio_idx > 0
|
||||
&& stream->sm_h3_prio_idx < tree->h3pt_nelem
|
||||
&& el->h3pe_stream == stream
|
||||
&& !(el->h3pe_flags & H3PE_FLAG_CLOSED))
|
||||
{
|
||||
assert(el->h3pe_stream == stream);
|
||||
if (tree->h3pt_closed_first)
|
||||
{
|
||||
tree->h3pt_els[ tree->h3pt_closed_last ].h3pe_next_closed
|
||||
= stream->sm_h3_prio_idx;
|
||||
tree->h3pt_closed_last = stream->sm_h3_prio_idx;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree->h3pt_closed_first = stream->sm_h3_prio_idx;
|
||||
tree->h3pt_closed_last = stream->sm_h3_prio_idx;
|
||||
}
|
||||
el->h3pe_stream = NULL;
|
||||
el->h3pe_closed_at = now;
|
||||
el->h3pe_flags |= H3PE_FLAG_CLOSED;
|
||||
stream->sm_h3_prio_idx = 0;
|
||||
LSQ_DEBUG("removed reference to stream %"PRIu64, stream->id);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("cannot remove stream %"PRIu64, stream->id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_prio_tree_drop_el (struct h3_prio_tree *tree, struct h3_prio_elem *el)
|
||||
{
|
||||
const elem_idx_t
|
||||
right = el->h3pe_right,
|
||||
left = el->h3pe_left,
|
||||
parent = el->h3pe_parent,
|
||||
el_idx = CALC_EL_IDX(tree, el);
|
||||
elem_idx_t idx, last;
|
||||
|
||||
/* Update links around the element: */
|
||||
idx = el->h3pe_first_child;
|
||||
if (idx == 0)
|
||||
{
|
||||
if (left)
|
||||
tree->h3pt_els[ left ].h3pe_right = right;
|
||||
else
|
||||
tree->h3pt_els[ parent ].h3pe_first_child = right;
|
||||
|
||||
if (right)
|
||||
tree->h3pt_els[ right ].h3pe_left = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
tree->h3pt_els[ left ].h3pe_right = idx;
|
||||
tree->h3pt_els[ idx ].h3pe_left = left;
|
||||
}
|
||||
else
|
||||
tree->h3pt_els[ parent ].h3pe_first_child = idx;
|
||||
|
||||
do
|
||||
{
|
||||
last = idx;
|
||||
tree->h3pt_els[ idx ].h3pe_parent = parent;
|
||||
idx = tree->h3pt_els[ idx ].h3pe_right;
|
||||
}
|
||||
while (idx);
|
||||
|
||||
if (right)
|
||||
{
|
||||
tree->h3pt_els[ right ].h3pe_left = last;
|
||||
tree->h3pt_els[ last ].h3pe_right = right;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move last element into its spot */
|
||||
if (--tree->h3pt_nelem > el_idx)
|
||||
{
|
||||
el = &tree->h3pt_els[ el_idx ];
|
||||
*el = tree->h3pt_els[ tree->h3pt_nelem ];
|
||||
for (idx = el->h3pe_first_child; idx;
|
||||
idx = tree->h3pt_els[ idx ].h3pe_right)
|
||||
tree->h3pt_els[ idx ].h3pe_parent = el_idx;
|
||||
if (el->h3pe_left)
|
||||
tree->h3pt_els[ el->h3pe_left ].h3pe_right = el_idx;
|
||||
if (el->h3pe_right)
|
||||
tree->h3pt_els[ el->h3pe_right ].h3pe_left = el_idx;
|
||||
if (tree->h3pt_els[ el->h3pe_parent ].h3pe_first_child
|
||||
== tree->h3pt_nelem)
|
||||
tree->h3pt_els[ el->h3pe_parent ].h3pe_first_child = el_idx;
|
||||
if (el->h3pe_stream)
|
||||
el->h3pe_stream->sm_h3_prio_idx = el_idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_prio_tree_prune (struct h3_prio_tree *tree, lsquic_time_t cutoff)
|
||||
{
|
||||
struct h3_prio_elem *el;
|
||||
unsigned count = 0;
|
||||
|
||||
while (tree->h3pt_closed_first
|
||||
&& tree->h3pt_els[ tree->h3pt_closed_first ].h3pe_closed_at < cutoff)
|
||||
{
|
||||
el = &tree->h3pt_els[ tree->h3pt_closed_first ];
|
||||
tree->h3pt_closed_first = el->h3pe_next_closed;
|
||||
if (tree->h3pt_closed_first == 0)
|
||||
tree->h3pt_closed_last = 0;
|
||||
++count;
|
||||
lsquic_prio_tree_drop_el(tree, el);
|
||||
}
|
||||
|
||||
LSQ_DEBUG("pruned %u element%.*s from the tree", count, count != 1, "s");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_prio_tree_destroy (struct h3_prio_tree *tree)
|
||||
{
|
||||
LSQ_DEBUG("destroyed");
|
||||
free(tree->h3pt_els);
|
||||
free(tree);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_prio_tree_iter_reset (struct h3_prio_tree *tree, const char *log_id)
|
||||
{
|
||||
struct h3_iter *const iter = &tree->h3pt_iter;
|
||||
unsigned i;
|
||||
|
||||
iter->h3it_log_id = log_id;
|
||||
iter->h3it_count = 0;
|
||||
iter->h3it_crit_count = 0;
|
||||
iter->h3it_crit_off = 0;
|
||||
iter->h3it_cursor = ROOT_IDX;
|
||||
iter->h3it_active++;
|
||||
if (0 == iter->h3it_active)
|
||||
{
|
||||
for (i = 0; i < tree->h3pt_nelem; ++i)
|
||||
{
|
||||
tree->h3pt_els[i].h3pe_active_self = 0;
|
||||
tree->h3pt_els[i].h3pe_active_path = 0;
|
||||
}
|
||||
iter->h3it_active++;
|
||||
}
|
||||
|
||||
LSQ_DEBUG("reset iterator; log id: `%s'; active mark: %u", log_id,
|
||||
iter->h3it_active);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
prio_tree_iter_add_critical (struct h3_prio_tree *tree,
|
||||
struct lsquic_stream *stream)
|
||||
{
|
||||
struct h3_iter *const iter = &tree->h3pt_iter;
|
||||
|
||||
if (iter->h3it_crit_count < sizeof(iter->h3it_crit_streams)
|
||||
/ sizeof(iter->h3it_crit_streams[0]))
|
||||
{
|
||||
iter->h3it_crit_streams[ iter->h3it_crit_count++ ] = stream;
|
||||
LSQ_DEBUG("%s: add critical stream %"PRIu64" at position %u",
|
||||
iter->h3it_log_id, stream->id, iter->h3it_crit_count - 1);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("could not add critical stream %"PRIu64" to the iterator: "
|
||||
"no room", stream->id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
prio_tree_iter_add_regular (struct h3_prio_tree *tree,
|
||||
struct lsquic_stream *stream)
|
||||
{
|
||||
struct h3_iter *const iter = &tree->h3pt_iter;
|
||||
struct h3_prio_elem *el;
|
||||
|
||||
if (stream->sm_h3_prio_idx > 0
|
||||
&& stream->sm_h3_prio_idx < tree->h3pt_nelem)
|
||||
{
|
||||
el = &tree->h3pt_els[stream->sm_h3_prio_idx];
|
||||
assert(el->h3pe_stream == stream);
|
||||
el->h3pe_active_self = iter->h3it_active;
|
||||
el->h3pe_iter_order = iter->h3it_count++;
|
||||
while (el->h3pe_parent)
|
||||
{
|
||||
el = &tree->h3pt_els[ el->h3pe_parent ];
|
||||
el->h3pe_active_path = iter->h3it_active;
|
||||
}
|
||||
LSQ_DEBUG("%s: added stream %"PRIu64" to the iterator",
|
||||
iter->h3it_log_id, stream->id);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSQ_WARN("%s: stream %"PRIu64" has invalid priority index value: %u",
|
||||
iter->h3it_log_id, stream->id, stream->sm_h3_prio_idx);
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_prio_tree_iter_add (struct h3_prio_tree *tree,
|
||||
struct lsquic_stream *stream)
|
||||
{
|
||||
if (lsquic_stream_is_critical(stream))
|
||||
return prio_tree_iter_add_critical(tree, stream);
|
||||
else
|
||||
return prio_tree_iter_add_regular(tree, stream);
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_prio_tree_iter_next (struct h3_prio_tree *tree)
|
||||
{
|
||||
struct h3_iter *const iter = &tree->h3pt_iter;
|
||||
struct h3_prio_elem *el_self, *el_path;
|
||||
iter_prio_t prio_self, prio_path;
|
||||
elem_idx_t idx;
|
||||
|
||||
if (iter->h3it_crit_off < iter->h3it_crit_count)
|
||||
{
|
||||
LSQ_DEBUG("%s: return critical stream %"PRIu64" at position %u",
|
||||
iter->h3it_log_id, iter->h3it_crit_streams[iter->h3it_crit_off]->id,
|
||||
iter->h3it_crit_off);
|
||||
return iter->h3it_crit_streams[ iter->h3it_crit_off++ ];
|
||||
}
|
||||
|
||||
top0:
|
||||
if (!iter->h3it_cursor)
|
||||
{
|
||||
LSQ_DEBUG("%s: out of streams", iter->h3it_log_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
top1:
|
||||
el_self = NULL, el_path = NULL;
|
||||
prio_self = MAX_ITER_PRIO + 1;
|
||||
prio_path = MAX_ITER_PRIO + 1;
|
||||
for (idx = tree->h3pt_els[ iter->h3it_cursor ].h3pe_first_child;
|
||||
idx;
|
||||
idx = tree->h3pt_els[ idx ].h3pe_right)
|
||||
{
|
||||
if (tree->h3pt_els[ idx ].h3pe_active_self == iter->h3it_active
|
||||
&& EL_ITER_PRIO(&tree->h3pt_els[ idx ]) < prio_self)
|
||||
{
|
||||
el_self = &tree->h3pt_els[ idx ];
|
||||
prio_self = EL_ITER_PRIO(el_self);
|
||||
}
|
||||
if (tree->h3pt_els[ idx ].h3pe_active_path == iter->h3it_active
|
||||
&& EL_ITER_PRIO(&tree->h3pt_els[ idx ]) < prio_path)
|
||||
{
|
||||
el_path = &tree->h3pt_els[ idx ];
|
||||
prio_path = EL_ITER_PRIO(el_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (el_self)
|
||||
{
|
||||
el_self->h3pe_active_self = 0;
|
||||
LSQ_DEBUG("%s: return %c stream %"PRIu64, iter->h3it_log_id,
|
||||
el_type2char[ EL_TYPE(el_self) ], EL_ID(el_self));
|
||||
return el_self->h3pe_stream;
|
||||
}
|
||||
else if (el_path)
|
||||
{
|
||||
iter->h3it_cursor = CALC_EL_IDX(tree, el_path);
|
||||
LSQ_DEBUG("%s: step down to %c:%"PRIu64, iter->h3it_log_id,
|
||||
el_type2char[ EL_TYPE(el_path) ], EL_ID(el_path));
|
||||
goto top1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree->h3pt_els[ iter->h3it_cursor ].h3pe_active_path = 0;
|
||||
iter->h3it_cursor = tree->h3pt_els[ iter->h3it_cursor ].h3pe_parent;
|
||||
LSQ_DEBUG("%s: step up to %c:%"PRIu64, iter->h3it_log_id,
|
||||
el_type2char[ EL_TYPE(&tree->h3pt_els[ iter->h3it_cursor ]) ],
|
||||
EL_ID(&tree->h3pt_els[ iter->h3it_cursor ]));
|
||||
goto top0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_prio_tree_highest_non_crit (struct h3_prio_tree *tree)
|
||||
{
|
||||
elem_idx_t idx, parent;
|
||||
struct h3_prio_elem *el;
|
||||
unsigned weight;
|
||||
|
||||
parent = ROOT_IDX;
|
||||
|
||||
new_level:
|
||||
/* Look for the stream */
|
||||
weight = 1u << sizeof(h3_weight_t) * 8;
|
||||
el = NULL;
|
||||
for (idx = tree->h3pt_els[ parent ].h3pe_first_child;
|
||||
idx;
|
||||
idx = tree->h3pt_els[ idx ].h3pe_right)
|
||||
if (tree->h3pt_els[ idx ].h3pe_stream
|
||||
&& tree->h3pt_els[ idx ].h3pe_weight < weight)
|
||||
{
|
||||
el = &tree->h3pt_els[ idx ];
|
||||
weight = el->h3pe_weight;
|
||||
}
|
||||
else
|
||||
/* Clear new level of crumbs */
|
||||
tree->h3pt_els[ idx ].h3pe_taken = 0;
|
||||
|
||||
if (el)
|
||||
return el->h3pe_stream;
|
||||
|
||||
old_level:
|
||||
/* Look for paths not taken */
|
||||
weight = 1u << sizeof(h3_weight_t) * 8;
|
||||
el = NULL;
|
||||
for (idx = tree->h3pt_els[ parent ].h3pe_first_child;
|
||||
idx;
|
||||
idx = tree->h3pt_els[ idx ].h3pe_right)
|
||||
if (tree->h3pt_els[ idx ].h3pe_first_child
|
||||
&& !tree->h3pt_els[ idx ].h3pe_taken
|
||||
&& tree->h3pt_els[ idx ].h3pe_weight < weight)
|
||||
{
|
||||
el = &tree->h3pt_els[ idx ];
|
||||
weight = el->h3pe_weight;
|
||||
}
|
||||
|
||||
if (el)
|
||||
{
|
||||
parent = CALC_EL_IDX(tree, el);
|
||||
goto new_level;
|
||||
}
|
||||
|
||||
tree->h3pt_els[ parent ].h3pe_taken = 1;
|
||||
parent = tree->h3pt_els[ parent ].h3pe_parent;
|
||||
if (parent)
|
||||
goto old_level;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
prio_tree_node_to_str (const struct h3_prio_tree *tree,
|
||||
const struct h3_prio_elem *el, char *const buf, char *const end)
|
||||
{
|
||||
elem_idx_t next_idx;
|
||||
char *p;
|
||||
int sz, comma;
|
||||
|
||||
if (buf >= end)
|
||||
return 0;
|
||||
|
||||
p = buf;
|
||||
sz = snprintf(p, end - p, "(t: %c; id: %"PRIu64"; w: %u",
|
||||
el_type2char[EL_TYPE(el)], EL_ID(el), el->h3pe_weight);
|
||||
if (sz > end - p)
|
||||
return end - buf;
|
||||
p += sz;
|
||||
|
||||
if (el->h3pe_first_child)
|
||||
{
|
||||
sz = snprintf(p, end - p, "; c: [");
|
||||
if (sz > end - p)
|
||||
return end - buf;
|
||||
p += sz;
|
||||
next_idx = el->h3pe_first_child;
|
||||
comma = 0;
|
||||
do
|
||||
{
|
||||
if (comma)
|
||||
{
|
||||
sz = snprintf(p, end - p, ",");
|
||||
if (sz > end - p)
|
||||
return end - buf;
|
||||
p += sz;
|
||||
}
|
||||
else
|
||||
++comma;
|
||||
el = &tree->h3pt_els[ next_idx ];
|
||||
p += prio_tree_node_to_str(tree, el, p, end);
|
||||
if (p >= end)
|
||||
return end - buf;
|
||||
}
|
||||
while ((next_idx = el->h3pe_right));
|
||||
sz = snprintf(p, end - p, "])");
|
||||
if (sz > end - p)
|
||||
return end - buf;
|
||||
p += sz;
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = snprintf(p, end - p, ")");
|
||||
if (sz > end - p)
|
||||
return end - buf;
|
||||
p += sz;
|
||||
}
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_prio_tree_to_str (const struct h3_prio_tree *tree, char *buf,
|
||||
size_t buf_sz)
|
||||
{
|
||||
return prio_tree_node_to_str(tree, &tree->h3pt_els[ROOT_IDX], buf,
|
||||
buf + buf_sz);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_prio_tree_set_ph (struct h3_prio_tree *tree, unsigned ph)
|
||||
{
|
||||
LSQ_DEBUG("set max placeholders to %u", ph);
|
||||
tree->h3pt_max_ph = ph;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_H3_PRIO_H
|
||||
#define LSQUIC_H3_PRIO_H 1
|
||||
|
||||
#define H3_PRIO_MAX_ELEMS ((1 << 16) - 1)
|
||||
|
||||
struct h3_prio_tree;
|
||||
struct lsquic_conn;
|
||||
struct lsquic_stream;
|
||||
|
||||
/* Same deal as with GQUIC priorities: lower value means higher priority */
|
||||
typedef uint8_t h3_weight_t;
|
||||
|
||||
/* This corresponds to 16: */
|
||||
#define H3_DEFAULT_WEIGHT 240
|
||||
|
||||
enum h3_elem_type
|
||||
{
|
||||
H3ET_ROOT,
|
||||
H3ET_REQ_STREAM,
|
||||
H3ET_PUSH_STREAM,
|
||||
H3ET_PLACEHOLDER,
|
||||
};
|
||||
|
||||
struct h3_prio_tree *
|
||||
lsquic_prio_tree_new (const struct lsquic_conn *, unsigned);
|
||||
|
||||
void
|
||||
lsquic_prio_tree_set_ph (struct h3_prio_tree *, unsigned);
|
||||
|
||||
void
|
||||
lsquic_prio_tree_destroy (struct h3_prio_tree *);
|
||||
|
||||
/* Call for PRIORITY frames arriving on request stream */
|
||||
int
|
||||
lsquic_prio_tree_add_stream (struct h3_prio_tree *, struct lsquic_stream *,
|
||||
enum h3_elem_type parent_type, uint64_t parent_id, h3_weight_t);
|
||||
|
||||
/* Call for PRIORITY frames on the control stream */
|
||||
int
|
||||
lsquic_prio_tree_set_rel (struct h3_prio_tree *,
|
||||
enum h3_elem_type child_type, uint64_t child_id, h3_weight_t child_weight,
|
||||
enum h3_elem_type parent_type, uint64_t parent_id);
|
||||
|
||||
int
|
||||
lsquic_prio_tree_remove_stream (struct h3_prio_tree *, struct lsquic_stream *,
|
||||
lsquic_time_t now);
|
||||
|
||||
void
|
||||
lsquic_prio_tree_prune (struct h3_prio_tree *, lsquic_time_t cutoff);
|
||||
|
||||
/* To begin to use the iterator, reset it first */
|
||||
void
|
||||
lsquic_prio_tree_iter_reset (struct h3_prio_tree *tree, const char *);
|
||||
|
||||
/* Then, add one or more stream objects */
|
||||
int
|
||||
lsquic_prio_tree_iter_add (struct h3_prio_tree *tree, struct lsquic_stream *);
|
||||
|
||||
struct lsquic_stream *
|
||||
lsquic_prio_tree_highest_non_crit (struct h3_prio_tree *);
|
||||
|
||||
/* Then, call next() until NULL is returned. It is OK to abandon the iterator
|
||||
* at any time.
|
||||
*/
|
||||
struct lsquic_stream *
|
||||
lsquic_prio_tree_iter_next (struct h3_prio_tree *tree);
|
||||
|
||||
size_t
|
||||
lsquic_prio_tree_to_str (const struct h3_prio_tree *tree, char *, size_t);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,207 +1,115 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_HANDSHAKE_SERVER_H
|
||||
#define LSQUIC_HANDSHAKE_SERVER_H
|
||||
#ifndef LSQUIC_HANDSHAKE_H
|
||||
#define LSQUIC_HANDSHAKE_H 1
|
||||
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_enc_session;
|
||||
struct stack_st_X509;
|
||||
|
||||
typedef struct lsquic_enc_session lsquic_enc_session_t;
|
||||
|
||||
#define MAX_SCFG_LENGTH 512
|
||||
#define MAX_SPUBS_LENGTH 32
|
||||
#define STK_LENGTH 60
|
||||
#define SNO_LENGTH 56
|
||||
#define SCID_LENGTH 16
|
||||
#define DNONC_LENGTH 32
|
||||
#define aes128_key_len 16
|
||||
#define aes128_iv_len 4
|
||||
#define SRST_LENGTH 16
|
||||
#define STK_LENGTH 60
|
||||
#define SCID_LENGTH 16
|
||||
|
||||
enum handshake_error /* TODO: rename this enum */
|
||||
struct lsquic_server_config;
|
||||
struct sockaddr;
|
||||
struct lsquic_str;
|
||||
struct lsquic_packet_in;
|
||||
struct lsquic_cid;
|
||||
|
||||
/* client side, certs and hashs
|
||||
*/
|
||||
typedef struct cert_hash_item_st
|
||||
{
|
||||
DATA_NOT_ENOUGH = -2,
|
||||
DATA_FORMAT_ERROR = -1,
|
||||
HS_ERROR = -1,
|
||||
DATA_NO_ERROR = 0,
|
||||
HS_SHLO = 0,
|
||||
HS_1RTT = 1,
|
||||
HS_2RTT = 2,
|
||||
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
struct lsquic_hash_elem hash_el;
|
||||
int count;
|
||||
} cert_hash_item_t;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void gen_stk(struct lsquic_server_config *, const struct sockaddr *ip_addr, uint64_t tm,
|
||||
unsigned char stk_out[STK_LENGTH]);
|
||||
enum hsk_failure_reason
|
||||
verify_stk0(struct lsquic_server_config *, const struct sockaddr *ip_addr, uint64_t tm,
|
||||
struct lsquic_str *stk,
|
||||
unsigned secs_since_stk_generated);
|
||||
enum hsk_failure_reason
|
||||
verify_stk(void *, const struct sockaddr *ip_addr,
|
||||
uint64_t tm, struct lsquic_str *stk);
|
||||
struct cert_hash_item_st* c_find_certs(const struct lsquic_str *domain);
|
||||
#endif
|
||||
|
||||
#define SNO_LENGTH 56
|
||||
|
||||
/* EVP_AEAD_CTX from boringssl pre-18d9f28f0df9f95570. */
|
||||
struct old_evp_aead_ctx_st {
|
||||
void *ptr1; /* aead */
|
||||
void *ptr2; /* aead_state */
|
||||
};
|
||||
|
||||
enum enc_level
|
||||
{
|
||||
ENC_LEV_UNSET,
|
||||
ENC_LEV_CLEAR,
|
||||
ENC_LEV_INIT,
|
||||
ENC_LEV_FORW,
|
||||
};
|
||||
|
||||
extern const char *const lsquic_enclev2str[];
|
||||
|
||||
/* client */
|
||||
typedef struct c_cert_item_st
|
||||
{
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
int count;
|
||||
} c_cert_item_t;
|
||||
|
||||
/* client side need to store 0rtt info per STK */
|
||||
typedef struct lsquic_session_cache_info_st
|
||||
/* Server need refresh SCFG once a day */
|
||||
/* can not use sizeof() to get the size */
|
||||
typedef struct SCFG_info_st
|
||||
{
|
||||
unsigned char sscid[SCID_LENGTH];
|
||||
unsigned char spubs[32]; /* server pub key for next time 0rtt */
|
||||
uint32_t ver; /* one VERSION */
|
||||
uint32_t aead;
|
||||
uint32_t kexs;
|
||||
uint32_t pdmd;
|
||||
uint64_t orbt;
|
||||
uint64_t expy;
|
||||
int scfg_flag; /* 0, no-init, 1, no parse, 2, parsed */
|
||||
struct lsquic_str sstk;
|
||||
struct lsquic_str scfg;
|
||||
struct lsquic_str sni_key; /* This is only used as key */
|
||||
unsigned char priv_key[32];
|
||||
unsigned char skt_key[16];
|
||||
uint32_t aead; /* Fixed, ONLY AESG */
|
||||
uint32_t kexs; /* Fixed, ONLY C255 */
|
||||
uint32_t pdmd; /* Fixed, ONLY X509 */
|
||||
uint64_t orbt; /* Fixed, 0 */
|
||||
uint64_t expy;
|
||||
/* Keep the hole for compatibility with older builds of LSWS: */
|
||||
struct old_evp_aead_ctx_st unused
|
||||
#if __GNUC__
|
||||
__attribute__((deprecated))
|
||||
#endif
|
||||
;
|
||||
short scfg_len;
|
||||
} SCFG_info_t;
|
||||
|
||||
} lsquic_session_cache_info_t;
|
||||
|
||||
struct lsquic_zero_rtt_storage
|
||||
struct SCFG_st
|
||||
{
|
||||
uint32_t quic_version_tag;
|
||||
uint32_t serializer_version;
|
||||
uint32_t ver;
|
||||
uint32_t aead;
|
||||
uint32_t kexs;
|
||||
uint32_t pdmd;
|
||||
uint64_t orbt;
|
||||
uint64_t expy;
|
||||
uint64_t sstk_len;
|
||||
uint64_t scfg_len;
|
||||
uint64_t scfg_flag;
|
||||
uint8_t sstk[STK_LENGTH];
|
||||
uint8_t scfg[MAX_SCFG_LENGTH];
|
||||
uint8_t sscid[SCID_LENGTH];
|
||||
uint8_t spubs[MAX_SPUBS_LENGTH];
|
||||
uint32_t cert_count;
|
||||
/*
|
||||
* uint32_t cert_len;
|
||||
* uint8_t cert_data[0];
|
||||
*/
|
||||
SCFG_info_t info;
|
||||
unsigned char scfg[]; /* whoile buffer */
|
||||
};
|
||||
typedef struct SCFG_st SCFG_t;
|
||||
/* server side need to store STK with expired time */
|
||||
|
||||
#ifndef LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
# ifndef NDEBUG
|
||||
# define LSQUIC_KEEP_ENC_SESS_HISTORY 1
|
||||
# else
|
||||
# define LSQUIC_KEEP_ENC_SESS_HISTORY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
#define ESHIST_BITS 7
|
||||
#define ESHIST_MASK ((1 << ESHIST_BITS) - 1)
|
||||
#define ESHIST_STR_SIZE ((1 << ESHIST_BITS) + 1)
|
||||
#endif
|
||||
|
||||
struct enc_session_funcs
|
||||
typedef struct lsquic_server_config
|
||||
{
|
||||
/* Global initialization: call once per implementation */
|
||||
int (*esf_global_init)(int flags);
|
||||
SCFG_t *lsc_scfg; /* This part is stored in SHM */
|
||||
EVP_AEAD_CTX lsc_stk_ctx;
|
||||
} lsquic_server_config_t;
|
||||
|
||||
/* Global cleanup: call once per implementation */
|
||||
void (*esf_global_cleanup) (void);
|
||||
/* Based on enum HandshakeFailureReason in Chromium */
|
||||
enum hsk_failure_reason
|
||||
{
|
||||
HFR_HANDSHAKE_OK = 0,
|
||||
|
||||
#if LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
/* Grab encryption session history */
|
||||
void (*esf_get_hist) (const lsquic_enc_session_t *,
|
||||
char buf[ESHIST_STR_SIZE]);
|
||||
#endif
|
||||
/* Invalid client nonce in CHLO: */
|
||||
HFR_CLIENT_NONCE_UNKNOWN = 1, /* Default nonce failure */
|
||||
HFR_CLIENT_NONCE_INVALID = 2, /* Incorrect nonce length */
|
||||
HFR_CLIENT_NONCE_NOT_UNIQ = 3,
|
||||
HFR_CLIENT_NONCE_INVALID_ORBIT = 4,
|
||||
HFR_CLIENT_NONCE_INVALID_TIME = 5,
|
||||
|
||||
/* Destroy enc session */
|
||||
void (*esf_destroy)(lsquic_enc_session_t *enc_session);
|
||||
/* Invalid server nonce in CHLO: */
|
||||
HFR_SERVER_NONCE_DECRYPTION = 8,
|
||||
HFR_SERVER_NONCE_INVALID = 9,
|
||||
HFR_SERVER_NONCE_NOT_UNIQUE = 10,
|
||||
HFR_SERVER_NONCE_INVALID_TIME = 11,
|
||||
HFR_SERVER_NONCE_REQUIRED = 20,
|
||||
|
||||
/* Return true if handshake has been completed */
|
||||
int (*esf_is_hsk_done)(lsquic_enc_session_t *enc_session);
|
||||
|
||||
/* Encrypt buffer */
|
||||
enum enc_level (*esf_encrypt)(lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version, uint8_t path_id, uint64_t pack_num,
|
||||
const unsigned char *header, size_t header_len,
|
||||
const unsigned char *data, size_t data_len,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len,
|
||||
int is_hello);
|
||||
|
||||
/** Decrypt buffer
|
||||
*
|
||||
* If decryption is successful, decryption level is returned. Otherwise,
|
||||
* the return value is -1.
|
||||
*/
|
||||
enum enc_level (*esf_decrypt)(lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version,
|
||||
uint8_t path_id, uint64_t pack_num,
|
||||
unsigned char *buf, size_t *header_len, size_t data_len,
|
||||
unsigned char *diversification_nonce,
|
||||
unsigned char *buf_out, size_t max_out_len, size_t *out_len);
|
||||
|
||||
/* Get value of setting specified by `tag' */
|
||||
int (*esf_get_peer_setting) (const lsquic_enc_session_t *, uint32_t tag,
|
||||
uint32_t *val);
|
||||
|
||||
/* Get value of peer option (that from COPT array) */
|
||||
int (*esf_get_peer_option) (const lsquic_enc_session_t *enc_session,
|
||||
uint32_t tag);
|
||||
|
||||
/* Create client session */
|
||||
lsquic_enc_session_t *
|
||||
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
/* Generate connection ID */
|
||||
lsquic_cid_t (*esf_generate_cid) (void);
|
||||
|
||||
/* -1 error, 0, OK, response in `buf' */
|
||||
int
|
||||
(*esf_gen_chlo) (lsquic_enc_session_t *, enum lsquic_version,
|
||||
uint8_t *buf, size_t *len);
|
||||
|
||||
int
|
||||
(*esf_handle_chlo_reply) (lsquic_enc_session_t *,
|
||||
const uint8_t *data, int len);
|
||||
|
||||
size_t
|
||||
(*esf_mem_used)(lsquic_enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
|
||||
size_t);
|
||||
|
||||
int
|
||||
(*esf_did_zero_rtt_succeed) (const lsquic_enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_is_zero_rtt_enabled) (const lsquic_enc_session_t *);
|
||||
|
||||
c_cert_item_t *
|
||||
(*esf_get_cert_item) (const lsquic_enc_session_t *);
|
||||
|
||||
struct stack_st_X509 *
|
||||
(*esf_get_server_cert_chain) (lsquic_enc_session_t *);
|
||||
|
||||
ssize_t
|
||||
(*esf_get_zero_rtt) (lsquic_enc_session_t *, enum lsquic_version,
|
||||
void *, size_t);
|
||||
HFR_CONFIG_INCHOATE_HELLO = 12, /* Missing SCID tag */
|
||||
HFR_CONFIG_UNKNOWN_CONFIG = 13, /* Could not find server config SCID */
|
||||
HFR_SRC_ADDR_TOKEN_INVALID = 14, /* Missing STK tag */
|
||||
HFR_SRC_ADDR_TOKEN_DECRYPTION = 15,
|
||||
HFR_SRC_ADDR_TOKEN_PARSE = 16,
|
||||
HFR_SRC_ADDR_TOKEN_DIFFERENT_IP_ADDRESS = 17,
|
||||
HFR_SRC_ADDR_TOKEN_CLOCK_SKEW = 18,
|
||||
HFR_SRC_ADDR_TOKEN_EXPIRED = 19,
|
||||
HFR_INVALID_EXPECTED_LEAF_CERTIFICATE = 21,
|
||||
};
|
||||
|
||||
extern
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
struct enc_session_funcs lsquic_enc_session_gquic_1;
|
||||
|
||||
#define select_esf_by_ver(ver) \
|
||||
(ver ? &lsquic_enc_session_gquic_1 : &lsquic_enc_session_gquic_1)
|
||||
|
||||
enum lsquic_version
|
||||
lsquic_zero_rtt_version (const unsigned char *, size_t);
|
||||
|
||||
|
|
|
@ -12,21 +12,9 @@
|
|||
#include <vc_compat.h>
|
||||
#endif
|
||||
|
||||
#include "lsquic_malo.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_xxhash.h"
|
||||
|
||||
struct lsquic_hash_elem
|
||||
{
|
||||
TAILQ_ENTRY(lsquic_hash_elem)
|
||||
qhe_next_bucket,
|
||||
qhe_next_all;
|
||||
const void *qhe_key_data;
|
||||
unsigned qhe_key_len;
|
||||
void *qhe_value;
|
||||
unsigned qhe_hash_val;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(hels_head, lsquic_hash_elem);
|
||||
|
||||
#define N_BUCKETS(n_bits) (1U << (n_bits))
|
||||
|
@ -36,7 +24,6 @@ struct lsquic_hash
|
|||
{
|
||||
struct hels_head *qh_buckets,
|
||||
qh_all;
|
||||
struct malo *qh_malo_els;
|
||||
struct lsquic_hash_elem *qh_iter_next;
|
||||
unsigned qh_count;
|
||||
unsigned qh_nbits;
|
||||
|
@ -48,7 +35,6 @@ lsquic_hash_create (void)
|
|||
{
|
||||
struct hels_head *buckets;
|
||||
struct lsquic_hash *hash;
|
||||
struct malo *malo;
|
||||
unsigned nbits = 2;
|
||||
unsigned i;
|
||||
|
||||
|
@ -63,21 +49,12 @@ lsquic_hash_create (void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
malo = lsquic_malo_create(sizeof(struct lsquic_hash_elem));
|
||||
if (!malo)
|
||||
{
|
||||
free(hash);
|
||||
free(buckets);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_BUCKETS(nbits); ++i)
|
||||
TAILQ_INIT(&buckets[i]);
|
||||
|
||||
TAILQ_INIT(&hash->qh_all);
|
||||
hash->qh_buckets = buckets;
|
||||
hash->qh_nbits = nbits;
|
||||
hash->qh_malo_els = malo;
|
||||
hash->qh_iter_next = NULL;
|
||||
hash->qh_count = 0;
|
||||
return hash;
|
||||
|
@ -87,7 +64,6 @@ lsquic_hash_create (void)
|
|||
void
|
||||
lsquic_hash_destroy (struct lsquic_hash *hash)
|
||||
{
|
||||
lsquic_malo_destroy(hash->qh_malo_els);
|
||||
free(hash->qh_buckets);
|
||||
free(hash);
|
||||
}
|
||||
|
@ -129,21 +105,16 @@ lsquic_hash_grow (struct lsquic_hash *hash)
|
|||
|
||||
struct lsquic_hash_elem *
|
||||
lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
|
||||
unsigned key_sz, void *data)
|
||||
unsigned key_sz, void *value, struct lsquic_hash_elem *el)
|
||||
{
|
||||
unsigned buckno, hash_val;
|
||||
struct lsquic_hash_elem *el;
|
||||
|
||||
el = lsquic_malo_get(hash->qh_malo_els);
|
||||
if (!el)
|
||||
if (el->qhe_flags & QHE_HASHED)
|
||||
return NULL;
|
||||
|
||||
if (hash->qh_count >= N_BUCKETS(hash->qh_nbits) / 2 &&
|
||||
0 != lsquic_hash_grow(hash))
|
||||
{
|
||||
lsquic_malo_put(el);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hash_val = XXH64(key, key_sz, (uintptr_t) hash);
|
||||
buckno = BUCKNO(hash->qh_nbits, hash_val);
|
||||
|
@ -151,8 +122,9 @@ lsquic_hash_insert (struct lsquic_hash *hash, const void *key,
|
|||
TAILQ_INSERT_TAIL(&hash->qh_buckets[buckno], el, qhe_next_bucket);
|
||||
el->qhe_key_data = key;
|
||||
el->qhe_key_len = key_sz;
|
||||
el->qhe_value = data;
|
||||
el->qhe_value = value;
|
||||
el->qhe_hash_val = hash_val;
|
||||
el->qhe_flags |= QHE_HASHED;
|
||||
++hash->qh_count;
|
||||
return el;
|
||||
}
|
||||
|
@ -178,22 +150,18 @@ lsquic_hash_find (struct lsquic_hash *hash, const void *key, unsigned key_sz)
|
|||
}
|
||||
|
||||
|
||||
void *
|
||||
lsquic_hashelem_getdata (const struct lsquic_hash_elem *el)
|
||||
{
|
||||
return el->qhe_value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_hash_erase (struct lsquic_hash *hash, struct lsquic_hash_elem *el)
|
||||
{
|
||||
unsigned buckno;
|
||||
|
||||
assert(el->qhe_flags & QHE_HASHED);
|
||||
buckno = BUCKNO(hash->qh_nbits, el->qhe_hash_val);
|
||||
if (hash->qh_iter_next == el)
|
||||
hash->qh_iter_next = TAILQ_NEXT(el, qhe_next_all);
|
||||
TAILQ_REMOVE(&hash->qh_buckets[buckno], el, qhe_next_bucket);
|
||||
TAILQ_REMOVE(&hash->qh_all, el, qhe_next_all);
|
||||
lsquic_malo_put(el);
|
||||
el->qhe_flags &= ~QHE_HASHED;
|
||||
--hash->qh_count;
|
||||
}
|
||||
|
||||
|
@ -235,6 +203,5 @@ size_t
|
|||
lsquic_hash_mem_used (const struct lsquic_hash *hash)
|
||||
{
|
||||
return sizeof(*hash)
|
||||
+ N_BUCKETS(hash->qh_nbits) * sizeof(hash->qh_buckets[0])
|
||||
+ lsquic_malo_mem_used(hash->qh_malo_els);
|
||||
+ N_BUCKETS(hash->qh_nbits) * sizeof(hash->qh_buckets[0]);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,20 @@
|
|||
#define LSQUIC_HASH_H
|
||||
|
||||
struct lsquic_hash;
|
||||
struct lsquic_hash_elem;
|
||||
|
||||
struct lsquic_hash_elem
|
||||
{
|
||||
TAILQ_ENTRY(lsquic_hash_elem)
|
||||
qhe_next_bucket,
|
||||
qhe_next_all;
|
||||
const void *qhe_key_data;
|
||||
void *qhe_value;
|
||||
unsigned qhe_key_len;
|
||||
unsigned qhe_hash_val;
|
||||
enum {
|
||||
QHE_HASHED = 1 << 0,
|
||||
} qhe_flags;
|
||||
};
|
||||
|
||||
struct lsquic_hash *
|
||||
lsquic_hash_create (void);
|
||||
|
@ -17,13 +30,12 @@ lsquic_hash_destroy (struct lsquic_hash *);
|
|||
|
||||
struct lsquic_hash_elem *
|
||||
lsquic_hash_insert (struct lsquic_hash *, const void *key, unsigned key_sz,
|
||||
void *data);
|
||||
void *value, struct lsquic_hash_elem *);
|
||||
|
||||
struct lsquic_hash_elem *
|
||||
lsquic_hash_find (struct lsquic_hash *, const void *key, unsigned key_sz);
|
||||
|
||||
void *
|
||||
lsquic_hashelem_getdata (const struct lsquic_hash_elem *);
|
||||
#define lsquic_hashelem_getdata(el) ((el)->qhe_value)
|
||||
|
||||
void
|
||||
lsquic_hash_erase (struct lsquic_hash *, struct lsquic_hash_elem *);
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_hcsi_reader.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HCSI_READER
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(reader->hr_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
void
|
||||
lsquic_hcsi_reader_init (struct hcsi_reader *reader,
|
||||
struct lsquic_conn *conn, const struct hcsi_callbacks *callbacks,
|
||||
void *ctx)
|
||||
{
|
||||
memset(reader, 0, sizeof(*reader));
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
reader->hr_conn = conn;
|
||||
reader->hr_cb = callbacks;
|
||||
reader->hr_ctx = ctx;
|
||||
LSQ_DEBUG("initialized");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_hcsi_reader_feed (struct hcsi_reader *reader, const void *buf,
|
||||
size_t bufsz)
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
const unsigned char *const end = p + bufsz;
|
||||
|
||||
const unsigned char *orig_p;
|
||||
enum h3_prio_frame_read_status prio_status;
|
||||
uint64_t len;
|
||||
int s;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
switch (reader->hr_state)
|
||||
{
|
||||
case HR_READ_FRAME_BEGIN:
|
||||
reader->hr_u.vint2_state.vr2s_state = 0;
|
||||
reader->hr_state = HR_READ_FRAME_CONTINUE;
|
||||
/* fall-through */
|
||||
case HR_READ_FRAME_CONTINUE:
|
||||
s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
|
||||
if (s < 0)
|
||||
break;
|
||||
reader->hr_frame_type = reader->hr_u.vint2_state.vr2s_one;
|
||||
reader->hr_frame_length = reader->hr_u.vint2_state.vr2s_two;
|
||||
switch (reader->hr_frame_type)
|
||||
{
|
||||
case HQFT_SETTINGS:
|
||||
if (reader->hr_frame_length)
|
||||
{
|
||||
reader->hr_state = HR_READ_SETTING_BEGIN;
|
||||
reader->hr_nread = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reader->hr_cb->on_settings_frame(reader->hr_ctx);
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
}
|
||||
break;
|
||||
case HQFT_PRIORITY:
|
||||
reader->hr_state = HR_READ_PRIORITY_BEGIN;
|
||||
break;
|
||||
case HQFT_GOAWAY:
|
||||
reader->hr_state = HR_READ_VARINT;
|
||||
break;
|
||||
case HQFT_CANCEL_PUSH:
|
||||
reader->hr_state = HR_READ_VARINT;
|
||||
break;
|
||||
case HQFT_MAX_PUSH_ID:
|
||||
reader->hr_state = HR_READ_VARINT;
|
||||
break;
|
||||
case HQFT_DATA:
|
||||
case HQFT_HEADERS:
|
||||
case HQFT_PUSH_PROMISE:
|
||||
reader->hr_cb->on_unexpected_frame(reader->hr_ctx,
|
||||
reader->hr_frame_type);
|
||||
return -1;
|
||||
default:
|
||||
if (!(reader->hr_frame_type >= 0xB &&
|
||||
(reader->hr_frame_type - 0xB) % 0x1F == 0))
|
||||
LSQ_INFO("unknown frame type 0x%"PRIX64" -- skipping",
|
||||
reader->hr_frame_type);
|
||||
reader->hr_state = HR_SKIPPING;
|
||||
LSQ_DEBUG("unknown frame 0x%"PRIX64": will skip %"PRIu64" bytes",
|
||||
reader->hr_frame_type, reader->hr_frame_length);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HR_READ_VARINT:
|
||||
reader->hr_u.vint_state.pos = 0;
|
||||
reader->hr_state = HR_READ_VARINT_CONTINUE;
|
||||
reader->hr_nread = 0;
|
||||
/* fall-through */
|
||||
case HR_READ_VARINT_CONTINUE:
|
||||
orig_p = p;
|
||||
s = lsquic_varint_read_nb(&p, end, &reader->hr_u.vint_state);
|
||||
reader->hr_nread += p - orig_p;
|
||||
if (0 == s)
|
||||
{
|
||||
if (reader->hr_nread != reader->hr_frame_length)
|
||||
{
|
||||
reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
|
||||
HEC_MALFORMED_FRAME + reader->hr_frame_type,
|
||||
"Frame length does not match actual payload length");
|
||||
reader->hr_state = HR_ERROR;
|
||||
return -1;
|
||||
}
|
||||
switch (reader->hr_frame_type)
|
||||
{
|
||||
case HQFT_GOAWAY:
|
||||
reader->hr_cb->on_goaway(reader->hr_ctx,
|
||||
reader->hr_u.vint_state.val);
|
||||
break;
|
||||
case HQFT_CANCEL_PUSH:
|
||||
reader->hr_cb->on_cancel_push(reader->hr_ctx,
|
||||
reader->hr_u.vint_state.val);
|
||||
break;
|
||||
case HQFT_MAX_PUSH_ID:
|
||||
reader->hr_cb->on_max_push_id(reader->hr_ctx,
|
||||
reader->hr_u.vint_state.val);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(p == end);
|
||||
return 0;
|
||||
}
|
||||
case HR_SKIPPING:
|
||||
len = MIN((uintptr_t) (end - p), reader->hr_frame_length);
|
||||
p += len;
|
||||
reader->hr_frame_length -= len;
|
||||
if (0 == reader->hr_frame_length)
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
break;
|
||||
case HR_READ_SETTING_BEGIN:
|
||||
reader->hr_u.vint2_state.vr2s_state = 0;
|
||||
reader->hr_state = HR_READ_SETTING_CONTINUE;
|
||||
/* fall-through */
|
||||
case HR_READ_SETTING_CONTINUE:
|
||||
orig_p = p;
|
||||
s = lsquic_varint_read_two(&p, end, &reader->hr_u.vint2_state);
|
||||
reader->hr_nread += p - orig_p;
|
||||
if (reader->hr_nread > reader->hr_frame_length)
|
||||
{
|
||||
reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
|
||||
HEC_MALFORMED_FRAME + HQFT_SETTINGS,
|
||||
"SETTING frame contents too long");
|
||||
reader->hr_state = HR_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (s < 0)
|
||||
break;
|
||||
reader->hr_cb->on_setting(reader->hr_ctx,
|
||||
reader->hr_u.vint2_state.vr2s_one,
|
||||
reader->hr_u.vint2_state.vr2s_two);
|
||||
if (reader->hr_nread >= reader->hr_frame_length)
|
||||
{
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
reader->hr_cb->on_settings_frame(reader->hr_ctx);
|
||||
}
|
||||
else
|
||||
reader->hr_state = HR_READ_SETTING_BEGIN;
|
||||
break;
|
||||
case HR_READ_PRIORITY_BEGIN:
|
||||
reader->hr_u.prio.h3pfrs_state = 0;
|
||||
reader->hr_nread = 0;
|
||||
reader->hr_state = HR_READ_PRIORITY_CONTINUE;
|
||||
/* fall-through */
|
||||
case HR_READ_PRIORITY_CONTINUE:
|
||||
orig_p = p;
|
||||
prio_status = lsquic_h3_prio_frame_read(&p, end - p,
|
||||
&reader->hr_u.prio);
|
||||
reader->hr_nread += p - orig_p;
|
||||
if (prio_status == H3PFR_STATUS_DONE)
|
||||
{
|
||||
if (reader->hr_nread != reader->hr_frame_length)
|
||||
{
|
||||
reader->hr_conn->cn_if->ci_abort_error(reader->hr_conn, 1,
|
||||
HEC_MALFORMED_FRAME + HQFT_PRIORITY, "PRIORITY frame "
|
||||
"contents size does not match frame length");
|
||||
reader->hr_state = HR_ERROR;
|
||||
return -1;
|
||||
}
|
||||
reader->hr_state = HR_READ_FRAME_BEGIN;
|
||||
reader->hr_cb->on_priority(reader->hr_ctx,
|
||||
&reader->hr_u.prio.h3pfrs_prio);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
/* fall-through */
|
||||
case HR_ERROR:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_hcsi_reader.h -- HTTP Control Stream Incoming (HCSI) reader
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_HCSI_READER_H
|
||||
#define LSQUIC_HCSI_READER_H 1
|
||||
|
||||
struct lsquic_conn;
|
||||
|
||||
|
||||
struct hcsi_callbacks
|
||||
{
|
||||
void (*on_priority)(void *ctx, const struct hq_priority *);
|
||||
void (*on_cancel_push)(void *ctx, uint64_t push_id);
|
||||
void (*on_max_push_id)(void *ctx, uint64_t push_id);
|
||||
/* Gets called at the *end* of the SETTING frame */
|
||||
void (*on_settings_frame)(void *ctx);
|
||||
void (*on_setting)(void *ctx, uint64_t setting_id, uint64_t value);
|
||||
void (*on_goaway)(void *ctx, uint64_t stream_id);
|
||||
void (*on_unexpected_frame)(void *ctx, uint64_t frame_type);
|
||||
};
|
||||
|
||||
|
||||
struct hcsi_reader
|
||||
{
|
||||
enum {
|
||||
HR_READ_FRAME_BEGIN,
|
||||
HR_READ_FRAME_CONTINUE,
|
||||
HR_SKIPPING,
|
||||
HR_READ_SETTING_BEGIN,
|
||||
HR_READ_SETTING_CONTINUE,
|
||||
HR_READ_PRIORITY_BEGIN,
|
||||
HR_READ_PRIORITY_CONTINUE,
|
||||
HR_READ_VARINT,
|
||||
HR_READ_VARINT_CONTINUE,
|
||||
HR_ERROR,
|
||||
} hr_state;
|
||||
struct lsquic_conn *hr_conn;
|
||||
uint64_t hr_frame_type;
|
||||
uint64_t hr_frame_length;
|
||||
union
|
||||
{
|
||||
struct varint_read_state vint_state;
|
||||
struct varint_read2_state vint2_state;
|
||||
struct h3_prio_frame_read_state prio;
|
||||
} hr_u;
|
||||
const struct hcsi_callbacks *hr_cb;
|
||||
void *hr_ctx;
|
||||
unsigned hr_nread; /* Used for PRIORITY and SETTINGS frames */
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
lsquic_hcsi_reader_init (struct hcsi_reader *, struct lsquic_conn *,
|
||||
const struct hcsi_callbacks *, void *cb_ctx);
|
||||
|
||||
int
|
||||
lsquic_hcsi_reader_feed (struct hcsi_reader *, const void *buf, size_t bufsz);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,367 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_hcso_writer.c - write to outgoing HTTP Control Stream
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_stream.h"
|
||||
#include "lsquic_frab_list.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_byteswap.h"
|
||||
#include "lsquic_hcso_writer.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HCSO_WRITER
|
||||
#define LSQUIC_LOG_CONN_ID \
|
||||
lsquic_conn_log_cid(lsquic_stream_conn(writer->how_stream))
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
|
||||
static int
|
||||
hcso_write_type (struct hcso_writer *writer)
|
||||
{
|
||||
int s;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (writer->how_flags & HOW_RAND_VARINT)
|
||||
{
|
||||
s = rand() & 3;
|
||||
LSQ_DEBUG("writing %d-byte stream type", 1 << s);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
s = 0;
|
||||
|
||||
switch (s)
|
||||
{
|
||||
case 0:
|
||||
return lsquic_frab_list_write(&writer->how_fral,
|
||||
(unsigned char []) { HQUST_CONTROL }, 1);
|
||||
case 1:
|
||||
return lsquic_frab_list_write(&writer->how_fral,
|
||||
(unsigned char []) { 0x40, HQUST_CONTROL }, 2);
|
||||
case 2:
|
||||
return lsquic_frab_list_write(&writer->how_fral,
|
||||
(unsigned char []) { 0x80, 0x00, 0x00, HQUST_CONTROL }, 4);
|
||||
default:
|
||||
return lsquic_frab_list_write(&writer->how_fral,
|
||||
(unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
HQUST_CONTROL }, 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static lsquic_stream_ctx_t *
|
||||
hcso_on_new (void *stream_if_ctx, struct lsquic_stream *stream)
|
||||
{
|
||||
struct hcso_writer *writer = stream_if_ctx;
|
||||
writer->how_stream = stream;
|
||||
lsquic_frab_list_init(&writer->how_fral, 0x100, NULL, NULL, NULL);
|
||||
#ifndef NDEBUG
|
||||
const char *env = getenv("LSQUIC_RND_VARINT_LEN");
|
||||
if (env && atoi(env))
|
||||
{
|
||||
writer->how_flags |= HOW_RAND_VARINT;
|
||||
LSQ_INFO("will randomize varints");
|
||||
if (0 == (rand() & 3))
|
||||
{
|
||||
writer->how_flags |= HOW_CHOP_STREAM;
|
||||
LSQ_INFO("will chop beginning of stream into tiny STREAM frames");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (0 != hcso_write_type(writer))
|
||||
{
|
||||
LSQ_INFO("cannot write to frab list");
|
||||
/* TODO: abort connection */
|
||||
}
|
||||
LSQ_DEBUG("create HTTP Control Stream Writer");
|
||||
lsquic_stream_wantwrite(stream, 1);
|
||||
return stream_if_ctx;
|
||||
}
|
||||
|
||||
|
||||
static unsigned
|
||||
hcso_setting_type2bits (struct hcso_writer *writer, unsigned setting)
|
||||
{
|
||||
unsigned bits = vint_val2bits(setting);
|
||||
|
||||
#ifndef NDEBUG
|
||||
unsigned max_bits;
|
||||
if (writer->how_flags & HOW_RAND_VARINT)
|
||||
{
|
||||
max_bits = rand() & 3;
|
||||
if (max_bits > bits)
|
||||
bits = max_bits;
|
||||
LSQ_DEBUG("writing out HTTP/3 setting %u as %d-byte varint",
|
||||
setting, 1 << bits);
|
||||
}
|
||||
#endif
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_hcso_write_settings (struct hcso_writer *writer,
|
||||
const struct lsquic_engine_settings *settings,
|
||||
int is_server)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned bits;
|
||||
int was_empty;
|
||||
#ifdef NDEBUG
|
||||
const unsigned frame_size_len = 1;
|
||||
#else
|
||||
/* Need to use two bytes for frame length, as randomization may require
|
||||
* more than 63 bytes.
|
||||
*/
|
||||
const unsigned frame_size_len = 2;
|
||||
#endif
|
||||
unsigned char buf[1 /* Frame type */ + /* Frame size */ frame_size_len
|
||||
/* There are maximum four settings that need to be written out and
|
||||
* each value can be encoded in maximum 8 bytes:
|
||||
*/
|
||||
+ 4 * (
|
||||
#ifdef NDEBUG
|
||||
1 /* Each setting needs 1-byte varint number, */
|
||||
#else
|
||||
8 /* but it can be up to 8 bytes when randomized */
|
||||
#endif
|
||||
+ 8) ];
|
||||
|
||||
p = buf;
|
||||
*p++ = HQFT_SETTINGS;
|
||||
p += frame_size_len;
|
||||
|
||||
if (is_server)
|
||||
if (settings->es_h3_placeholders != HQ_DF_NUM_PLACEHOLDERS)
|
||||
{
|
||||
/* Write out SETTINGS_NUM_PLACEHOLDERS */
|
||||
bits = hcso_setting_type2bits(writer, HQSID_NUM_PLACEHOLDERS);
|
||||
vint_write(p, HQSID_NUM_PLACEHOLDERS, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
bits = vint_val2bits(settings->es_h3_placeholders);
|
||||
vint_write(p, settings->es_h3_placeholders, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
}
|
||||
|
||||
if (settings->es_max_header_list_size != HQ_DF_MAX_HEADER_LIST_SIZE)
|
||||
{
|
||||
/* Write out SETTINGS_MAX_HEADER_LIST_SIZE */
|
||||
bits = hcso_setting_type2bits(writer, HQSID_MAX_HEADER_LIST_SIZE);
|
||||
vint_write(p, HQSID_MAX_HEADER_LIST_SIZE, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
bits = vint_val2bits(settings->es_max_header_list_size);
|
||||
vint_write(p, settings->es_max_header_list_size, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
}
|
||||
|
||||
if (settings->es_qpack_dec_max_size != HQ_DF_QPACK_MAX_TABLE_CAPACITY)
|
||||
{
|
||||
/* Write out SETTINGS_QPACK_MAX_TABLE_CAPACITY */
|
||||
bits = hcso_setting_type2bits(writer, HQSID_QPACK_MAX_TABLE_CAPACITY);
|
||||
vint_write(p, HQSID_QPACK_MAX_TABLE_CAPACITY, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
bits = vint_val2bits(settings->es_qpack_dec_max_size);
|
||||
vint_write(p, settings->es_qpack_dec_max_size, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
}
|
||||
|
||||
if (settings->es_qpack_dec_max_blocked != HQ_DF_QPACK_BLOCKED_STREAMS)
|
||||
{
|
||||
/* Write out SETTINGS_QPACK_BLOCKED_STREAMS */
|
||||
bits = hcso_setting_type2bits(writer, HQSID_QPACK_BLOCKED_STREAMS);
|
||||
vint_write(p, HQSID_QPACK_BLOCKED_STREAMS, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
bits = vint_val2bits(settings->es_qpack_dec_max_size);
|
||||
vint_write(p, settings->es_qpack_dec_max_blocked, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
buf[1] = p - buf - 2;
|
||||
#else
|
||||
vint_write(buf + 1, p - buf - 3, 1, 2);
|
||||
#endif
|
||||
|
||||
was_empty = lsquic_frab_list_empty(&writer->how_fral);
|
||||
|
||||
if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf))
|
||||
{
|
||||
LSQ_INFO("cannot write SETTINGS frame to frab list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (was_empty)
|
||||
lsquic_stream_wantwrite(writer->how_stream, 1);
|
||||
|
||||
LSQ_DEBUG("generated %u-byte SETTINGS frame", (unsigned) (p - buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
hqft2str (enum hq_frame_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HQFT_PUSH_PROMISE: return "PUSH_PROMISE";
|
||||
case HQFT_MAX_PUSH_ID: return "MAX_PUSH_ID";
|
||||
case HQFT_CANCEL_PUSH: return "CANCEL_PUSH";
|
||||
case HQFT_GOAWAY: return "GOAWAY";
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hcso_write_number_frame (struct hcso_writer *writer,
|
||||
enum hq_frame_type type, uint64_t value)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned bits;
|
||||
int was_empty;
|
||||
unsigned char buf[1 /* Frame type */ + /* Frame size */ 1 + 8 /* Value */ ];
|
||||
|
||||
p = buf;
|
||||
*p++ = type;
|
||||
|
||||
bits = vint_val2bits(value);
|
||||
*p++ = 1 << bits;
|
||||
|
||||
vint_write(p, value, bits, 1 << bits);
|
||||
p += 1 << bits;
|
||||
|
||||
was_empty = lsquic_frab_list_empty(&writer->how_fral);
|
||||
|
||||
if (0 != lsquic_frab_list_write(&writer->how_fral, buf, p - buf))
|
||||
{
|
||||
LSQ_INFO("cannot write %s frame to frab list", hqft2str(type));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (was_empty)
|
||||
lsquic_stream_wantwrite(writer->how_stream, 1);
|
||||
|
||||
LSQ_DEBUG("generated %u-byte %s frame", (unsigned) (p - buf),
|
||||
hqft2str(type));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_hcso_write_goaway (struct hcso_writer *writer,
|
||||
lsquic_stream_id_t stream_id)
|
||||
{
|
||||
return hcso_write_number_frame(writer, HQFT_GOAWAY, stream_id);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_hcso_write_max_push_id (struct hcso_writer *writer, uint64_t max_push_id)
|
||||
{
|
||||
return hcso_write_number_frame(writer, HQFT_MAX_PUSH_ID, max_push_id);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_hcso_write_cancel_push (struct hcso_writer *writer, uint64_t push_id)
|
||||
{
|
||||
return hcso_write_number_frame(writer, HQFT_CANCEL_PUSH, push_id);
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
static size_t
|
||||
one_byte_limit_read (void *ctx, void *buf, size_t bufsz)
|
||||
{
|
||||
return lsquic_frab_list_read(ctx, buf, MIN(bufsz, 1));
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
one_byte_limit_size (void *ctx)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = lsquic_frab_list_size(ctx);
|
||||
return MIN(size, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
hcso_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
struct hcso_writer *const writer = (void *) ctx;
|
||||
struct lsquic_reader reader = {
|
||||
.lsqr_read = lsquic_frab_list_read,
|
||||
.lsqr_size = lsquic_frab_list_size,
|
||||
.lsqr_ctx = &writer->how_fral
|
||||
};
|
||||
ssize_t nw;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (stream->tosend_off < 8 && (writer->how_flags & HOW_CHOP_STREAM))
|
||||
{
|
||||
reader.lsqr_read = one_byte_limit_read;
|
||||
reader.lsqr_size = one_byte_limit_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
nw = lsquic_stream_writef(stream, &reader);
|
||||
if (nw >= 0)
|
||||
{
|
||||
LSQ_DEBUG("wrote %zd bytes to stream", nw);
|
||||
(void) lsquic_stream_flush(stream);
|
||||
if (lsquic_frab_list_empty(&writer->how_fral))
|
||||
lsquic_stream_wantwrite(stream, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: abort connection */
|
||||
LSQ_WARN("cannot write to stream: %s", strerror(errno));
|
||||
lsquic_stream_wantwrite(stream, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hcso_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
struct hcso_writer *writer = (void *) ctx;
|
||||
LSQ_DEBUG("close HTTP Control Stream Writer");
|
||||
lsquic_frab_list_cleanup(&writer->how_fral);
|
||||
writer->how_stream = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hcso_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
static const struct lsquic_stream_if hcso_if =
|
||||
{
|
||||
.on_new_stream = hcso_on_new,
|
||||
.on_read = hcso_on_read,
|
||||
.on_write = hcso_on_write,
|
||||
.on_close = hcso_on_close,
|
||||
};
|
||||
|
||||
const struct lsquic_stream_if *const lsquic_hcso_writer_if = &hcso_if;
|
|
@ -0,0 +1,39 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_hcso_writer.h
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_HCSO_WRITER_H
|
||||
#define LSQUIC_HCSO_WRITER_H 1
|
||||
|
||||
struct lsquic_engine_settings;
|
||||
struct lsquic_stream;
|
||||
|
||||
struct hcso_writer
|
||||
{
|
||||
struct lsquic_stream *how_stream;
|
||||
struct frab_list how_fral;
|
||||
#ifndef NDEBUG
|
||||
enum {
|
||||
HOW_RAND_VARINT = 1 << 0,
|
||||
HOW_CHOP_STREAM = 1 << 1,
|
||||
} how_flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
lsquic_hcso_write_settings (struct hcso_writer *,
|
||||
const struct lsquic_engine_settings *, int);
|
||||
|
||||
int
|
||||
lsquic_hcso_write_goaway (struct hcso_writer *, lsquic_stream_id_t);
|
||||
|
||||
int
|
||||
lsquic_hcso_write_max_push_id (struct hcso_writer *, uint64_t max_push_id);
|
||||
|
||||
int
|
||||
lsquic_hcso_write_cancel_push (struct hcso_writer *, uint64_t push_id);
|
||||
|
||||
extern const struct lsquic_stream_if *const lsquic_hcso_writer_if;
|
||||
|
||||
#endif
|
|
@ -2,8 +2,6 @@
|
|||
#ifndef LSQUIC_HEADERS_H
|
||||
#define LSQUIC_HEADERS_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* When ea_hsi_if is not specified, the headers are converted to a C string
|
||||
* that contains HTTP/1.x-like header structure.
|
||||
*/
|
||||
|
@ -23,8 +21,8 @@ struct http1x_headers
|
|||
*/
|
||||
struct uncompressed_headers
|
||||
{
|
||||
uint32_t uh_stream_id;
|
||||
uint32_t uh_oth_stream_id; /* For HEADERS frame, the ID of the
|
||||
lsquic_stream_id_t uh_stream_id;
|
||||
lsquic_stream_id_t uh_oth_stream_id; /* For HEADERS frame, the ID of the
|
||||
* stream that this stream depends
|
||||
* on. (Zero means unset.) For
|
||||
* PUSH_PROMISE, the promised stream
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -29,7 +30,8 @@
|
|||
#define MAX_HEADER_TABLE_SIZE (512 * 1024)
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HEADERS
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(hs->hs_stream))
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(\
|
||||
lsquic_stream_conn(hs->hs_stream))
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
static const struct frame_reader_callbacks *frame_callbacks_ptr;
|
||||
|
@ -85,6 +87,7 @@ headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
|||
LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
(void) lshpack_enc_use_hist(&hs->hs_henc, 1);
|
||||
hs->hs_flags |= HS_HENC_INITED;
|
||||
hs->hs_stream = stream;
|
||||
LSQ_DEBUG("stream created");
|
||||
|
@ -103,7 +106,7 @@ headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
|
|||
return NULL;
|
||||
}
|
||||
hs->hs_fw = lsquic_frame_writer_new(&hs->hs_enpub->enp_mm, stream, 0,
|
||||
&hs->hs_henc, lsquic_stream_write,
|
||||
&hs->hs_henc, lsquic_stream_writef,
|
||||
#if LSQUIC_CONN_STATS
|
||||
hs->hs_conn_stats,
|
||||
#endif
|
||||
|
@ -161,8 +164,8 @@ headers_on_close (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
|
|||
|
||||
int
|
||||
lsquic_headers_stream_send_headers (struct headers_stream *hs,
|
||||
uint32_t stream_id, const struct lsquic_http_headers *headers, int eos,
|
||||
unsigned weight)
|
||||
lsquic_stream_id_t stream_id, const struct lsquic_http_headers *headers,
|
||||
int eos, unsigned weight)
|
||||
{
|
||||
LSQ_DEBUG("received compressed headers to send");
|
||||
int s;
|
||||
|
@ -181,7 +184,8 @@ lsquic_headers_stream_send_headers (struct headers_stream *hs,
|
|||
|
||||
int
|
||||
lsquic_headers_stream_send_priority (struct headers_stream *hs,
|
||||
uint32_t stream_id, int exclusive, uint32_t dep_stream_id, unsigned weight)
|
||||
lsquic_stream_id_t stream_id, int exclusive,
|
||||
lsquic_stream_id_t dep_stream_id, unsigned weight)
|
||||
{
|
||||
LSQ_DEBUG("received priority to send");
|
||||
int s;
|
||||
|
@ -272,8 +276,8 @@ headers_on_push_promise (void *ctx, struct uncompressed_headers *uh)
|
|||
|
||||
|
||||
static void
|
||||
headers_on_priority (void *ctx, uint32_t stream_id, int exclusive,
|
||||
uint32_t dep_stream_id, unsigned weight)
|
||||
headers_on_priority (void *ctx, lsquic_stream_id_t stream_id, int exclusive,
|
||||
lsquic_stream_id_t dep_stream_id, unsigned weight)
|
||||
{
|
||||
struct headers_stream *hs = ctx;
|
||||
hs->hs_callbacks->hsc_on_priority(hs->hs_cb_ctx, stream_id, exclusive,
|
||||
|
@ -282,7 +286,8 @@ headers_on_priority (void *ctx, uint32_t stream_id, int exclusive,
|
|||
|
||||
|
||||
static void
|
||||
headers_on_error (void *ctx, uint32_t stream_id, enum frame_reader_error err)
|
||||
headers_on_error (void *ctx, lsquic_stream_id_t stream_id,
|
||||
enum frame_reader_error err)
|
||||
{
|
||||
struct headers_stream *hs = ctx;
|
||||
switch (err)
|
||||
|
@ -290,6 +295,7 @@ headers_on_error (void *ctx, uint32_t stream_id, enum frame_reader_error err)
|
|||
case FR_ERR_DUPLICATE_PSEH:
|
||||
case FR_ERR_INCOMPL_REQ_PSEH:
|
||||
case FR_ERR_UNNEC_REQ_PSEH:
|
||||
case FR_ERR_BAD_REQ_HEADER:
|
||||
case FR_ERR_INCOMPL_RESP_PSEH:
|
||||
case FR_ERR_UNNEC_RESP_PSEH:
|
||||
case FR_ERR_UNKNOWN_PSEH:
|
||||
|
@ -299,7 +305,8 @@ headers_on_error (void *ctx, uint32_t stream_id, enum frame_reader_error err)
|
|||
case FR_ERR_DECOMPRESS:
|
||||
case FR_ERR_HEADERS_TOO_LARGE:
|
||||
case FR_ERR_SELF_DEP_STREAM:
|
||||
LSQ_INFO("error %u is a stream error (stream %u)", err, stream_id);
|
||||
LSQ_INFO("error %u is a stream error (stream %"PRIu64")", err,
|
||||
stream_id);
|
||||
hs->hs_callbacks->hsc_on_stream_error(hs->hs_cb_ctx, stream_id);
|
||||
break;
|
||||
case FR_ERR_INVALID_FRAME_SIZE:
|
||||
|
@ -308,7 +315,8 @@ headers_on_error (void *ctx, uint32_t stream_id, enum frame_reader_error err)
|
|||
case FR_ERR_ZERO_STREAM_ID:
|
||||
case FR_ERR_NOMEM:
|
||||
case FR_ERR_EXPECTED_CONTIN:
|
||||
LSQ_INFO("error %u is a connection error (stream %u)", err, stream_id);
|
||||
LSQ_INFO("error %u is a connection error (stream %"PRIu64")", err,
|
||||
stream_id);
|
||||
hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
|
||||
break;
|
||||
}
|
||||
|
@ -376,10 +384,12 @@ headers_on_settings (void *ctx, uint16_t setting_id, uint32_t setting_value)
|
|||
|
||||
int
|
||||
lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
||||
uint32_t stream_id, uint32_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers)
|
||||
lsquic_stream_id_t stream_id64, lsquic_stream_id_t promised_stream_id64,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *headers)
|
||||
{
|
||||
uint32_t stream_id = stream_id64;
|
||||
uint32_t promised_stream_id = promised_stream_id64;
|
||||
int s;
|
||||
LSQ_DEBUG("promising stream %u in response to stream %u",
|
||||
promised_stream_id, stream_id);
|
||||
|
|
|
@ -33,9 +33,9 @@ struct headers_stream_callbacks
|
|||
void (*hsc_on_enable_push) (void *hs_cb_ctx, int enable_push);
|
||||
void (*hsc_on_push_promise)
|
||||
(void *frame_cb_ctx, struct uncompressed_headers *);
|
||||
void (*hsc_on_priority) (void *hs_cb_ctx, uint32_t stream_id,
|
||||
int exclusive, uint32_t dep_stream_id, unsigned weight);
|
||||
void (*hsc_on_stream_error) (void *hs_cb_ctx, uint32_t stream_id);
|
||||
void (*hsc_on_priority) (void *hs_cb_ctx, lsquic_stream_id_t stream_id,
|
||||
int exclusive, lsquic_stream_id_t dep_stream_id, unsigned weight);
|
||||
void (*hsc_on_stream_error) (void *hs_cb_ctx, lsquic_stream_id_t stream_id);
|
||||
void (*hsc_on_conn_error) (void *hs_cb_ctx);
|
||||
};
|
||||
|
||||
|
@ -53,19 +53,20 @@ lsquic_headers_stream_destroy (struct headers_stream *);
|
|||
|
||||
int
|
||||
lsquic_headers_stream_send_headers (struct headers_stream *hs,
|
||||
uint32_t stream_id,
|
||||
lsquic_stream_id_t stream_id,
|
||||
const struct lsquic_http_headers *, int eos,
|
||||
unsigned weight);
|
||||
|
||||
int
|
||||
lsquic_headers_stream_push_promise (struct headers_stream *hs,
|
||||
uint32_t stream_id, uint32_t promised_stream_id,
|
||||
lsquic_stream_id_t stream_id, lsquic_stream_id_t promised_stream_id,
|
||||
const struct iovec *path, const struct iovec *host,
|
||||
const struct lsquic_http_headers *);
|
||||
|
||||
int
|
||||
lsquic_headers_stream_send_priority (struct headers_stream *hs,
|
||||
uint32_t stream_id, int exclusive, uint32_t dep_stream_id, unsigned weight);
|
||||
lsquic_stream_id_t stream_id, int exclusive,
|
||||
lsquic_stream_id_t dep_stream_id, unsigned weight);
|
||||
|
||||
int
|
||||
lsquic_headers_stream_send_settings (struct headers_stream *hs,
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/hkdf.h>
|
||||
|
||||
#include "lsquic_hkdf.h"
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-17] Section 5 */
|
||||
void
|
||||
lsquic_qhkdf_expand (const EVP_MD *md, const unsigned char *secret,
|
||||
unsigned secret_len, const char *label, uint8_t label_len,
|
||||
unsigned char *out, uint16_t out_len)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
int s;
|
||||
#endif
|
||||
unsigned char info[ 2 + 1 + 6 + label_len + 1];
|
||||
|
||||
info[0] = out_len >> 8;
|
||||
info[1] = out_len;
|
||||
info[2] = label_len + 6;
|
||||
info[3] = 't';
|
||||
info[4] = 'l';
|
||||
info[5] = 's';
|
||||
info[6] = '1';
|
||||
info[7] = '3';
|
||||
info[8] = ' ';
|
||||
memcpy(info + 9, label, label_len);
|
||||
info[9 + label_len] = 0;
|
||||
#ifndef NDEBUG
|
||||
s =
|
||||
#else
|
||||
(void)
|
||||
#endif
|
||||
HKDF_expand(out, out_len, md, secret, secret_len, info, sizeof(info));
|
||||
assert(s);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_HKDF_H
|
||||
#define LSQUIC_HKDF_H 1
|
||||
|
||||
/* [draft-ietf-quic-tls-22] Section 5.2 */
|
||||
#define HSK_SALT_BUF "\x7f\xbc\xdb\x0e\x7c\x66\xbb\xe9\x19\x3a" \
|
||||
"\x96\xcd\x21\x51\x9e\xbd\x7a\x02\x64\x4a"
|
||||
#define HSK_SALT ((unsigned char *) HSK_SALT_BUF)
|
||||
#define HSK_SALT_SZ (sizeof(HSK_SALT_BUF) - 1)
|
||||
|
||||
#define CLIENT_LABEL "client in"
|
||||
#define CLIENT_LABEL_SZ (sizeof(CLIENT_LABEL) - 1)
|
||||
#define SERVER_LABEL "server in"
|
||||
#define SERVER_LABEL_SZ (sizeof(SERVER_LABEL) - 1)
|
||||
|
||||
void
|
||||
lsquic_qhkdf_expand (const struct env_md_st *, const unsigned char *secret,
|
||||
unsigned secret_len, const char *label, uint8_t label_len,
|
||||
unsigned char *out, uint16_t out_len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,94 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
|
||||
const char *const lsquic_h3det2str[] =
|
||||
{
|
||||
[H3DET_REQ_STREAM] = "request stream",
|
||||
[H3DET_PUSH_STREAM] = "push stream",
|
||||
[H3DET_PLACEHOLDER] = "placeholder",
|
||||
[H3DET_ROOT] = "root of the tree",
|
||||
};
|
||||
|
||||
const char *const lsquic_h3pet2str[] =
|
||||
{
|
||||
[H3PET_REQ_STREAM] = "request stream",
|
||||
[H3PET_PUSH_STREAM] = "push stream",
|
||||
[H3PET_PLACEHOLDER] = "placeholder",
|
||||
[H3PET_CUR_STREAM] = "current stream",
|
||||
};
|
||||
|
||||
|
||||
enum h3_prio_frame_read_status
|
||||
lsquic_h3_prio_frame_read (const unsigned char **bufp, size_t bufsz,
|
||||
struct h3_prio_frame_read_state *state)
|
||||
{
|
||||
const unsigned char *p = *bufp;
|
||||
const unsigned char *const end = p + bufsz;
|
||||
int s;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
switch (state->h3pfrs_state)
|
||||
{
|
||||
case H3PFRS_STATE_TYPE:
|
||||
state->h3pfrs_prio.hqp_prio_type = (p[0] >> HQ_PT_SHIFT) & 3;
|
||||
state->h3pfrs_prio.hqp_dep_type = (p[0] >> HQ_DT_SHIFT) & 3;
|
||||
++p;
|
||||
if (state->h3pfrs_prio.hqp_prio_type == H3PET_CUR_STREAM
|
||||
&& state->h3pfrs_prio.hqp_dep_type == H3DET_ROOT)
|
||||
state->h3pfrs_state = H3PFRS_STATE_WEIGHT;
|
||||
else
|
||||
{
|
||||
state->h3pfrs_flags = 0;
|
||||
state->h3pfrs_state = H3PFRS_STATE_VINT_BEGIN;
|
||||
}
|
||||
break;
|
||||
case H3PFRS_STATE_VINT_BEGIN:
|
||||
state->h3pfrs_vint.pos = 0;
|
||||
state->h3pfrs_state = H3PFRS_STATE_VINT_CONTINUE;
|
||||
/* fall-through */
|
||||
case H3PFRS_STATE_VINT_CONTINUE:
|
||||
s = lsquic_varint_read_nb(&p, end, &state->h3pfrs_vint);
|
||||
if (0 == s)
|
||||
{
|
||||
if (state->h3pfrs_prio.hqp_prio_type == H3PET_CUR_STREAM
|
||||
|| (state->h3pfrs_flags & H3PFRS_FLAG_HAVE_PRIO_ID))
|
||||
{
|
||||
state->h3pfrs_prio.hqp_dep_id = state->h3pfrs_vint.val;
|
||||
state->h3pfrs_state = H3PFRS_STATE_WEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->h3pfrs_prio.hqp_prio_id = state->h3pfrs_vint.val;
|
||||
state->h3pfrs_flags |= H3PFRS_FLAG_HAVE_PRIO_ID;
|
||||
if (state->h3pfrs_prio.hqp_dep_type == H3DET_ROOT)
|
||||
state->h3pfrs_state = H3PFRS_STATE_WEIGHT;
|
||||
else
|
||||
state->h3pfrs_state = H3PFRS_STATE_VINT_BEGIN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(p == end);
|
||||
*bufp = p;
|
||||
return H3PFR_STATUS_NEED;
|
||||
}
|
||||
case H3PFRS_STATE_WEIGHT:
|
||||
state->h3pfrs_prio.hqp_weight = *p++;
|
||||
*bufp = p;
|
||||
return H3PFR_STATUS_DONE;
|
||||
default:
|
||||
assert(0);
|
||||
return H3PFR_STATUS_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
*bufp = p;
|
||||
return H3PFR_STATUS_NEED;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_hq.h -- HTTP over QUIC (HQ) types
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_HQ_H
|
||||
#define LSQUIC_HQ_H 1
|
||||
|
||||
/* [draft-ietf-quic-http-15] Section 4 */
|
||||
enum hq_frame_type
|
||||
{
|
||||
HQFT_DATA = 0,
|
||||
HQFT_HEADERS = 1,
|
||||
HQFT_PRIORITY = 2,
|
||||
HQFT_CANCEL_PUSH = 3,
|
||||
HQFT_SETTINGS = 4,
|
||||
HQFT_PUSH_PROMISE = 5,
|
||||
HQFT_GOAWAY = 7,
|
||||
HQFT_MAX_PUSH_ID = 0xD,
|
||||
HQFT_DUPLICATE_PUSH = 0xE,
|
||||
/* This frame is made up and its type is never written to stream.
|
||||
* Nevertheless, just to be on the safe side, give it a value as
|
||||
* described in [draft-ietf-quic-http-20] Section 4.2.10.
|
||||
*/
|
||||
HQFT_PUSH_PREAMBLE = 0x1F * 3 + 0x21,
|
||||
};
|
||||
|
||||
|
||||
enum h3_prio_el_type
|
||||
{
|
||||
H3PET_REQ_STREAM = 0,
|
||||
H3PET_PUSH_STREAM = 1,
|
||||
H3PET_PLACEHOLDER = 2,
|
||||
H3PET_CUR_STREAM = 3,
|
||||
};
|
||||
|
||||
|
||||
enum h3_dep_el_type
|
||||
{
|
||||
H3DET_REQ_STREAM = 0,
|
||||
H3DET_PUSH_STREAM = 1,
|
||||
H3DET_PLACEHOLDER = 2,
|
||||
H3DET_ROOT = 3,
|
||||
};
|
||||
|
||||
|
||||
#define HQ_PT_SHIFT 6
|
||||
#define HQ_DT_SHIFT 4
|
||||
|
||||
|
||||
enum hq_setting_id
|
||||
{
|
||||
HQSID_QPACK_MAX_TABLE_CAPACITY = 1,
|
||||
HQSID_MAX_HEADER_LIST_SIZE = 6,
|
||||
HQSID_QPACK_BLOCKED_STREAMS = 7,
|
||||
HQSID_NUM_PLACEHOLDERS = 9,
|
||||
};
|
||||
|
||||
/* As of 12/18/2018: */
|
||||
#define HQ_DF_QPACK_MAX_TABLE_CAPACITY 0
|
||||
#define HQ_DF_NUM_PLACEHOLDERS 0
|
||||
#define HQ_DF_MAX_HEADER_LIST_SIZE 0
|
||||
#define HQ_DF_QPACK_BLOCKED_STREAMS 0
|
||||
|
||||
struct hq_priority
|
||||
{
|
||||
lsquic_stream_id_t hqp_prio_id;
|
||||
lsquic_stream_id_t hqp_dep_id;
|
||||
enum h3_prio_el_type hqp_prio_type:8;
|
||||
enum h3_dep_el_type hqp_dep_type:8;
|
||||
uint8_t hqp_weight;
|
||||
};
|
||||
|
||||
#define HQP_WEIGHT(p) ((p)->hqp_weight + 1)
|
||||
|
||||
/* [draft-ietf-quic-http-19] Section 10.6,
|
||||
* [draft-ietf-quic-qpack-07] Section 8.2
|
||||
*/
|
||||
enum hq_uni_stream_type
|
||||
{
|
||||
HQUST_CONTROL = 0,
|
||||
HQUST_PUSH = 1,
|
||||
HQUST_QPACK_ENC = 2,
|
||||
HQUST_QPACK_DEC = 3,
|
||||
};
|
||||
|
||||
extern const char *const lsquic_h3det2str[];
|
||||
extern const char *const lsquic_h3pet2str[];
|
||||
|
||||
/* [draft-ietf-quic-http-22] Section 8.1 and
|
||||
* [draft-ietf-quic-qpack-08], Section 8.3
|
||||
*/
|
||||
enum http_error_code
|
||||
{
|
||||
HEC_NO_ERROR = 0x00,
|
||||
HEC_GENERAL_PROTOCOL_ERROR = 0x01,
|
||||
/* Error code 0x2 is reserved and has no meaning */
|
||||
HEC_INTERNAL_ERROR = 0x03,
|
||||
/* Error code 0x4 is reserved and has no meaning */
|
||||
HEC_REQUEST_CANCELLED = 0x05,
|
||||
HEC_INCOMPLETE_REQUEST = 0x06,
|
||||
HEC_CONNECT_ERROR = 0x07,
|
||||
HEC_EXCESSIVE_LOAD = 0x08,
|
||||
HEC_VERSION_FALLBACK = 0x09,
|
||||
HEC_WRONG_STREAM = 0x0A,
|
||||
HEC_ID_ERROR = 0x0B,
|
||||
/* Error code 0xC is reserved and has no meaning */
|
||||
HEC_STREAM_CREATION_ERROR = 0x0D,
|
||||
/* Error code 0xE is reserved and has no meaning */
|
||||
HEC_CLOSED_CRITICAL_STREAM = 0x0F,
|
||||
/* Error code 0x10 is reserved and has no meaning */
|
||||
HEC_EARLY_RESPONSE = 0x0011,
|
||||
HEC_MISSING_SETTINGS = 0x0012,
|
||||
HEC_UNEXPECTED_FRAME = 0x0013,
|
||||
HEC_REQUEST_REJECTED = 0x14,
|
||||
HEC_SETTINGS_ERROR = 0x00FF,
|
||||
HEC_MALFORMED_FRAME = 0x0100, /* add frame type */
|
||||
HEC_QPACK_DECOMPRESSION_FAILED = 0x200,
|
||||
HEC_QPACK_ENCODER_STREAM_ERROR = 0x201,
|
||||
HEC_QPACK_DECODER_STREAM_ERROR = 0x202,
|
||||
};
|
||||
|
||||
|
||||
struct h3_prio_frame_read_state
|
||||
{
|
||||
struct varint_read_state h3pfrs_vint;
|
||||
struct hq_priority h3pfrs_prio;
|
||||
enum {
|
||||
H3PFRS_STATE_TYPE = 0,
|
||||
H3PFRS_STATE_VINT_BEGIN,
|
||||
H3PFRS_STATE_VINT_CONTINUE,
|
||||
H3PFRS_STATE_WEIGHT,
|
||||
} h3pfrs_state;
|
||||
enum {
|
||||
H3PFRS_FLAG_HAVE_PRIO_ID = 1 << 0,
|
||||
} h3pfrs_flags;
|
||||
};
|
||||
|
||||
|
||||
enum h3_prio_frame_read_status
|
||||
{
|
||||
H3PFR_STATUS_DONE,
|
||||
H3PFR_STATUS_NEED,
|
||||
};
|
||||
|
||||
|
||||
/* When first called, h3pfrs_state should be set to 0 */
|
||||
enum h3_prio_frame_read_status
|
||||
lsquic_h3_prio_frame_read (const unsigned char **, size_t,
|
||||
struct h3_prio_frame_read_state *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,163 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_hspack_valid.c -- Handshake packet validator.
|
||||
*
|
||||
* We want to eliminate invalid packets as soon as we read them in and not
|
||||
* feed them to lsquic engine if we can avoid it. The handshake packet
|
||||
* possesses several characteristics which make it possible to detect
|
||||
* garbage packets.
|
||||
*/
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
#include "lsquic_packet_ietf.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_engine_public.h"
|
||||
#include "lsquic_version.h"
|
||||
#include "lsquic_parse_common.h"
|
||||
|
||||
|
||||
#define SMALLEST_GQUIC_OVERHEAD \
|
||||
1 /* Type */ \
|
||||
+ GQUIC_CID_LEN \
|
||||
+ sizeof(lsquic_ver_tag_t) \
|
||||
+ 1 /* Packet number */ \
|
||||
+ 1 /* Stream frame */ \
|
||||
+ 1 /* Stream ID */ \
|
||||
+ 2 /* Data length */ \
|
||||
+ 12 /* IV */
|
||||
|
||||
|
||||
|
||||
/* Note that we ignore nonce: even if the flag is set, we know that Chrome
|
||||
* does not actually include the 32-byte nonce.
|
||||
*/
|
||||
static int
|
||||
is_valid_gquic_hs_packet (const unsigned char *buf, size_t bufsz,
|
||||
lsquic_ver_tag_t *tag)
|
||||
{
|
||||
if (bufsz > GQUIC_MAX_PACKET_SZ ||
|
||||
/* Data: HPACKed :method GET :path / is 2 bytes */
|
||||
bufsz < SMALLEST_GQUIC_OVERHEAD + 2 ||
|
||||
/* Check maximum packet number: */
|
||||
buf[1 + GQUIC_CID_LEN + sizeof(lsquic_ver_tag_t)] > 64 ||
|
||||
/* From [draft-hamilton-quic-transport-protocol-01]:
|
||||
* 0x80 is currently unused, and must be set to 0.
|
||||
* 0x40 = MULTIPATH. This bit is reserved for multipath use.
|
||||
*
|
||||
* 0x30 = Packet number length. We expect these bits to be
|
||||
* unset.
|
||||
*
|
||||
* The reference implementation checks that two high bits are not
|
||||
* set if version flag is not set or if the version is the same.
|
||||
* For our purposes, all GQUIC version we support so far have these
|
||||
* bits set to zero.
|
||||
*
|
||||
* Incoming handshake packets must have both connection ID and
|
||||
* version bits set.
|
||||
*
|
||||
* Nonce flag is ignored: Chrome sets it erronesously, but it may
|
||||
* not be true (a) in the future or (b) in other clients.
|
||||
*/
|
||||
((buf[0] ^ (
|
||||
/* These should be unset: */
|
||||
(~(0x80|0x40|0x30|PACKET_PUBLIC_FLAGS_RST))
|
||||
&
|
||||
/* While these should be set: */
|
||||
(PACKET_PUBLIC_FLAGS_VERSION|
|
||||
PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID)
|
||||
)) & /* Ignore this bit: */ ~PACKET_PUBLIC_FLAGS_NONCE)
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(tag, buf + 1 + 8, sizeof(*tag));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lsquic_is_valid_hs_packet (struct lsquic_engine *engine,
|
||||
const unsigned char *buf, size_t bufsz)
|
||||
{
|
||||
lsquic_ver_tag_t tag;
|
||||
int is_valid;
|
||||
|
||||
if (bufsz < 1)
|
||||
return 0;
|
||||
|
||||
switch (buf[0] & 0xF8)
|
||||
{
|
||||
/* Xs vary, Gs are iGnored: */
|
||||
/* 1X11 XGGG: Q046 long header */
|
||||
case 0x80|0x40|0x20|0x10|0x08:
|
||||
case 0x80|0x00|0x20|0x10|0x08:
|
||||
case 0x80|0x40|0x20|0x10|0x00:
|
||||
case 0x80|0x00|0x20|0x10|0x00:
|
||||
is_valid = lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag);
|
||||
break;
|
||||
/* 1X00 XGGG: ID-22 long header */
|
||||
case 0x80|0x40|0x00|0x00|0x08:
|
||||
case 0x80|0x00|0x00|0x00|0x08:
|
||||
case 0x80|0x40|0x00|0x00|0x00:
|
||||
case 0x80|0x00|0x00|0x00|0x00:
|
||||
/* 1X01 XGGG: ID-22 long header */
|
||||
case 0x80|0x40|0x00|0x10|0x08:
|
||||
case 0x80|0x00|0x00|0x10|0x08:
|
||||
case 0x80|0x40|0x00|0x10|0x00:
|
||||
case 0x80|0x00|0x00|0x10|0x00:
|
||||
/* 1X10 XGGG: ID-22 long header */
|
||||
case 0x80|0x40|0x20|0x00|0x08:
|
||||
case 0x80|0x00|0x20|0x00|0x08:
|
||||
case 0x80|0x40|0x20|0x00|0x00:
|
||||
case 0x80|0x00|0x20|0x00|0x00:
|
||||
is_valid = lsquic_is_valid_ietf_v1_or_Q046_hs_packet(buf, bufsz, &tag);
|
||||
break;
|
||||
/* 01XX XGGG: ID-22 short header */
|
||||
case 0x00|0x40|0x00|0x00|0x00:
|
||||
case 0x00|0x40|0x00|0x00|0x08:
|
||||
case 0x00|0x40|0x00|0x10|0x00:
|
||||
case 0x00|0x40|0x00|0x10|0x08:
|
||||
case 0x00|0x40|0x20|0x00|0x00:
|
||||
case 0x00|0x40|0x20|0x00|0x08:
|
||||
case 0x00|0x40|0x20|0x10|0x00:
|
||||
case 0x00|0x40|0x20|0x10|0x08:
|
||||
is_valid = 0;
|
||||
break;
|
||||
/* 00XX 0GGG: Q046 short header */
|
||||
case 0x00|0x00|0x00|0x00|0x00:
|
||||
case 0x00|0x00|0x00|0x10|0x00:
|
||||
case 0x00|0x00|0x20|0x00|0x00:
|
||||
case 0x00|0x00|0x20|0x10|0x00:
|
||||
is_valid = 0;
|
||||
break;
|
||||
/* 00XX 1GGG: GQUIC */
|
||||
case 0x00|0x00|0x00|0x00|0x08:
|
||||
case 0x00|0x00|0x00|0x10|0x08:
|
||||
case 0x00|0x00|0x20|0x00|0x08:
|
||||
case 0x00|0x00|0x20|0x10|0x08:
|
||||
is_valid = is_valid_gquic_hs_packet(buf, bufsz, &tag);
|
||||
break;
|
||||
default: /* gcc thinks this is possible?! */
|
||||
assert(0);
|
||||
is_valid = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_valid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
#include "lshpack.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_HTTP1X
|
||||
#define LSQUIC_LOG_CONN_ID hwc->hwc_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(hwc->hwc_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
enum pseudo_header
|
||||
|
@ -36,7 +36,7 @@ enum pseudo_header
|
|||
|
||||
struct header_writer_ctx
|
||||
{
|
||||
lsquic_cid_t hwc_cid;
|
||||
const struct lsquic_conn *hwc_conn;
|
||||
char *buf;
|
||||
char *cookie_val;
|
||||
unsigned cookie_sz, cookie_nalloc;
|
||||
|
@ -75,7 +75,7 @@ h1h_create_header_set (void *ctx, int is_push_promise)
|
|||
if (is_push_promise)
|
||||
hwc->hwc_flags |= HWC_PUSH_PROMISE;
|
||||
hwc->max_headers_sz = hcc->max_headers_sz;
|
||||
hwc->hwc_cid = hcc->cid;
|
||||
hwc->hwc_conn = hcc->conn;
|
||||
return &hwc->hwc_h1h;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,17 @@
|
|||
#define LSQUIC_HTTP1X_IF_H 1
|
||||
|
||||
struct lsquic_hset_if;
|
||||
struct lsquic_conn;
|
||||
|
||||
struct http1x_ctor_ctx
|
||||
{
|
||||
lsquic_cid_t cid; /* Used for logging */
|
||||
const struct lsquic_conn *conn; /* Used for logging */
|
||||
unsigned max_headers_sz;
|
||||
int is_server;
|
||||
};
|
||||
|
||||
extern const struct lsquic_hset_if *const lsquic_http1x_if;
|
||||
|
||||
#define MAX_HTTP1X_HEADERS_SIZE (64 * 1024)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_IETF_H
|
||||
#define LSQUIC_IETF_H 1
|
||||
|
||||
/* Things specific to the IETF version of QUIC that do not fit anywhere else */
|
||||
|
||||
/* [draft-ietf-quic-transport-18] Section 22.3 */
|
||||
enum trans_error_code
|
||||
{
|
||||
TEC_NO_ERROR = 0x0,
|
||||
TEC_INTERNAL_ERROR = 0x1,
|
||||
TEC_SERVER_BUSY = 0x2,
|
||||
TEC_FLOW_CONTROL_ERROR = 0x3,
|
||||
TEC_STREAM_LIMIT_ERROR = 0x4,
|
||||
TEC_STREAM_STATE_ERROR = 0x5,
|
||||
TEC_FINAL_SIZE_ERROR = 0x6,
|
||||
TEC_FRAME_ENCODING_ERROR = 0x7,
|
||||
TEC_TRANSPORT_PARAMETER_ERROR = 0x8,
|
||||
TEC_VERSION_NEGOTIATION_ERROR = 0x9,
|
||||
TEC_PROTOCOL_VIOLATION = 0xA,
|
||||
TEC_INVALID_MIGRATION = 0xC,
|
||||
TEC_CRYPTO_BUFFER_EXCEEDED = 0xD,
|
||||
};
|
||||
|
||||
/* Must be at least two */
|
||||
#define MAX_IETF_CONN_DCIDS 8
|
||||
|
||||
#endif
|
|
@ -19,4 +19,13 @@ struct lsquic_packno_range {
|
|||
lsquic_packno_t low, high;
|
||||
};
|
||||
|
||||
/* RFC 3168 */
|
||||
enum ecn
|
||||
{
|
||||
ECN_NOT_ECT = 0,
|
||||
ECN_ECT1 = 1,
|
||||
ECN_ECT0 = 2,
|
||||
ECN_CE = 3,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,43 +16,34 @@
|
|||
#include <time.h>
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */
|
||||
#include "lsquic_logger.h"
|
||||
#include "lsquic_byteswap.h"
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
/* The switch to big-endian format in GQUIC also resulted in Chrome swapping
|
||||
* the CID in its log. We do the same thing in our log messages so that the
|
||||
* CIDs are easy to match. The exception is Q035, which is the last little-
|
||||
* endian GQUIC version this library supports.
|
||||
*/
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define DISP_CID(cid) bswap_64(cid)
|
||||
#else
|
||||
#define DISP_CID(cid) (cid)
|
||||
#endif
|
||||
#define MAX_LINE_LEN 8192
|
||||
#define FORMAT_PROBLEM(lb, len, max) (((ssize_t)lb < 0) || ((ssize_t)lb + (ssize_t)len >= (ssize_t)max))
|
||||
|
||||
/* TODO: display GQUIC CIDs in Chrome-compatible format */
|
||||
|
||||
static enum lsquic_logger_timestamp_style g_llts = LLTS_NONE;
|
||||
|
||||
static int
|
||||
null_vprintf (void *ctx, const char *fmt, va_list ap)
|
||||
null_log_buf (void *ctx, const char *buf, size_t len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
file_vprintf (void *ctx, const char *fmt, va_list ap)
|
||||
file_log_buf (void *ctx, const char *buf, size_t len)
|
||||
{
|
||||
return vfprintf((FILE *) ctx, fmt, ap);
|
||||
return (int)fwrite(buf, sizeof(char), len, (FILE *) ctx);
|
||||
}
|
||||
|
||||
|
||||
static const struct lsquic_logger_if file_logger_if = {
|
||||
.vprintf = file_vprintf,
|
||||
.log_buf = file_log_buf,
|
||||
};
|
||||
|
||||
static const struct lsquic_logger_if null_logger_if = {
|
||||
.vprintf = null_vprintf,
|
||||
.log_buf = null_log_buf,
|
||||
};
|
||||
|
||||
static void *logger_ctx = NULL;
|
||||
|
@ -74,18 +65,31 @@ enum lsq_log_level lsq_log_levels[N_LSQUIC_LOGGER_MODULES] = {
|
|||
[LSQLM_CRYPTO] = LSQ_LOG_WARN,
|
||||
[LSQLM_HANDSHAKE] = LSQ_LOG_WARN,
|
||||
[LSQLM_HSK_ADAPTER] = LSQ_LOG_WARN,
|
||||
[LSQLM_BBR] = LSQ_LOG_WARN,
|
||||
[LSQLM_CUBIC] = LSQ_LOG_WARN,
|
||||
[LSQLM_HEADERS] = LSQ_LOG_WARN,
|
||||
[LSQLM_FRAME_READER]= LSQ_LOG_WARN,
|
||||
[LSQLM_FRAME_WRITER]= LSQ_LOG_WARN,
|
||||
[LSQLM_CONN_HASH] = LSQ_LOG_WARN,
|
||||
[LSQLM_MINI_CONN] = LSQ_LOG_WARN,
|
||||
[LSQLM_TOKGEN] = LSQ_LOG_WARN,
|
||||
[LSQLM_ENG_HIST] = LSQ_LOG_WARN,
|
||||
[LSQLM_SPI] = LSQ_LOG_WARN,
|
||||
[LSQLM_DI] = LSQ_LOG_WARN,
|
||||
[LSQLM_PRQ] = LSQ_LOG_WARN,
|
||||
[LSQLM_PACER] = LSQ_LOG_WARN,
|
||||
[LSQLM_MIN_HEAP] = LSQ_LOG_WARN,
|
||||
[LSQLM_HTTP1X] = LSQ_LOG_WARN,
|
||||
[LSQLM_QLOG] = LSQ_LOG_WARN,
|
||||
[LSQLM_TRAPA] = LSQ_LOG_WARN,
|
||||
[LSQLM_PURGA] = LSQ_LOG_WARN,
|
||||
[LSQLM_HCSI_READER] = LSQ_LOG_WARN,
|
||||
[LSQLM_HCSO_WRITER] = LSQ_LOG_WARN,
|
||||
[LSQLM_QENC_HDL] = LSQ_LOG_WARN,
|
||||
[LSQLM_QDEC_HDL] = LSQ_LOG_WARN,
|
||||
[LSQLM_QPACK_ENC] = LSQ_LOG_WARN,
|
||||
[LSQLM_QPACK_DEC] = LSQ_LOG_WARN,
|
||||
[LSQLM_PRIO] = LSQ_LOG_WARN,
|
||||
[LSQLM_BW_SAMPLER] = LSQ_LOG_WARN,
|
||||
};
|
||||
|
||||
const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
|
||||
|
@ -104,18 +108,31 @@ const char *const lsqlm_to_str[N_LSQUIC_LOGGER_MODULES] = {
|
|||
[LSQLM_CRYPTO] = "crypto",
|
||||
[LSQLM_HANDSHAKE] = "handshake",
|
||||
[LSQLM_HSK_ADAPTER] = "hsk-adapter",
|
||||
[LSQLM_BBR] = "bbr",
|
||||
[LSQLM_CUBIC] = "cubic",
|
||||
[LSQLM_HEADERS] = "headers",
|
||||
[LSQLM_FRAME_READER]= "frame-reader",
|
||||
[LSQLM_FRAME_WRITER]= "frame-writer",
|
||||
[LSQLM_CONN_HASH] = "conn-hash",
|
||||
[LSQLM_MINI_CONN] = "mini-conn",
|
||||
[LSQLM_TOKGEN] = "tokgen",
|
||||
[LSQLM_ENG_HIST] = "eng-hist",
|
||||
[LSQLM_SPI] = "spi",
|
||||
[LSQLM_DI] = "di",
|
||||
[LSQLM_PRQ] = "prq",
|
||||
[LSQLM_PACER] = "pacer",
|
||||
[LSQLM_MIN_HEAP] = "min-heap",
|
||||
[LSQLM_HTTP1X] = "http1x",
|
||||
[LSQLM_QLOG] = "qlog",
|
||||
[LSQLM_TRAPA] = "trapa",
|
||||
[LSQLM_PURGA] = "purga",
|
||||
[LSQLM_HCSI_READER] = "hcsi-reader",
|
||||
[LSQLM_HCSO_WRITER] = "hcso-writer",
|
||||
[LSQLM_QENC_HDL] = "qenc-hdl",
|
||||
[LSQLM_QDEC_HDL] = "qdec-hdl",
|
||||
[LSQLM_QPACK_ENC] = "qpack-enc",
|
||||
[LSQLM_QPACK_DEC] = "qpack-dec",
|
||||
[LSQLM_PRIO] = "prio",
|
||||
[LSQLM_BW_SAMPLER] = "bw-sampler",
|
||||
};
|
||||
|
||||
const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = {
|
||||
|
@ -130,16 +147,6 @@ const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS] = {
|
|||
};
|
||||
|
||||
|
||||
static void
|
||||
lsquic_printf (const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logger_if->vprintf(logger_ctx, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#define DELTA_EPOCH_IN_TICKS 116444736000000000Ui64
|
||||
struct timezone
|
||||
|
@ -180,16 +187,16 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
print_timestamp (void)
|
||||
static size_t
|
||||
print_timestamp (char *buf, size_t max)
|
||||
{
|
||||
struct tm tm;
|
||||
struct timeval tv;
|
||||
size_t len = 0;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
#ifdef WIN32
|
||||
{
|
||||
|
@ -204,43 +211,66 @@ print_timestamp (void)
|
|||
localtime_r(&tv.tv_sec, &tm);
|
||||
#endif
|
||||
if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
|
||||
lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ",
|
||||
len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%06d ",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec));
|
||||
else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
|
||||
lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
|
||||
len = snprintf(buf, max, "%04d-%02d-%02d %02d:%02d:%02d.%03d ",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
|
||||
else if (g_llts == LLTS_HHMMSSMS)
|
||||
lsquic_printf("%02d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min,
|
||||
tm.tm_sec, (int) (tv.tv_usec / 1000));
|
||||
len = snprintf(buf, max, "%02d:%02d:%02d.%03d ",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) (tv.tv_usec / 1000));
|
||||
else if (g_llts == LLTS_HHMMSSUS)
|
||||
lsquic_printf("%02d:%02d:%02d.%06d ", tm.tm_hour, tm.tm_min,
|
||||
tm.tm_sec, (int) tv.tv_usec);
|
||||
len = snprintf(buf, max, "%02d:%02d:%02d.%06d ",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
|
||||
else if (g_llts == LLTS_CHROMELIKE)
|
||||
lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.tm_mon + 1,
|
||||
tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
|
||||
len = snprintf(buf, max, "%02d%02d/%02d%02d%02d.%06d ",
|
||||
tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min,
|
||||
tm.tm_sec, (int) tv.tv_usec);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_logger_log3 (enum lsq_log_level log_level,
|
||||
enum lsquic_logger_module module,
|
||||
uint64_t conn_id, uint32_t stream_id, const char *fmt, ...)
|
||||
const lsquic_cid_t *conn_id, lsquic_stream_id_t stream_id,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
const int saved_errno = errno;
|
||||
char cidbuf_[MAX_CID_LEN * 2 + 1];
|
||||
size_t len = 0;
|
||||
size_t lb;
|
||||
size_t max = MAX_LINE_LEN;
|
||||
char buf[MAX_LINE_LEN];
|
||||
|
||||
if (g_llts != LLTS_NONE)
|
||||
print_timestamp();
|
||||
|
||||
lsquic_printf("[%s] [QUIC:%"PRIu64"-%"PRIu32"] %s: ",
|
||||
lsq_loglevel2str[log_level], DISP_CID(conn_id), stream_id,
|
||||
lsqlm_to_str[module]);
|
||||
{
|
||||
lb = print_timestamp(buf, max);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
}
|
||||
lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"-%"PRIu64"] %s: ",
|
||||
lsq_loglevel2str[log_level], CID_BITS(conn_id),
|
||||
stream_id, lsqlm_to_str[module]);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logger_if->vprintf(logger_ctx, fmt, ap);
|
||||
lb = vsnprintf(buf + len, max - len, fmt, ap);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_end(ap);
|
||||
lsquic_printf("\n");
|
||||
lb = snprintf(buf + len, max - len, "\n");
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
logger_if->log_buf(logger_ctx, buf, len);
|
||||
end:
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
@ -248,20 +278,41 @@ lsquic_logger_log3 (enum lsq_log_level log_level,
|
|||
void
|
||||
lsquic_logger_log2 (enum lsq_log_level log_level,
|
||||
enum lsquic_logger_module module,
|
||||
uint64_t conn_id, const char *fmt, ...)
|
||||
const struct lsquic_cid *conn_id, const char *fmt, ...)
|
||||
{
|
||||
const int saved_errno = errno;
|
||||
char cidbuf_[MAX_CID_LEN * 2 + 1];
|
||||
size_t len = 0;
|
||||
size_t lb;
|
||||
size_t max = MAX_LINE_LEN;
|
||||
char buf[MAX_LINE_LEN];
|
||||
|
||||
if (g_llts != LLTS_NONE)
|
||||
print_timestamp();
|
||||
{
|
||||
lb = print_timestamp(buf, max);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
}
|
||||
|
||||
lsquic_printf("[%s] [QUIC:%"PRIu64"] %s: ",
|
||||
lsq_loglevel2str[log_level], DISP_CID(conn_id), lsqlm_to_str[module]);
|
||||
lb = snprintf(buf + len, max - len, "[%s] [QUIC:%"CID_FMT"] %s: ",
|
||||
lsq_loglevel2str[log_level], CID_BITS(conn_id), lsqlm_to_str[module]);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logger_if->vprintf(logger_ctx, fmt, ap);
|
||||
lb = vsnprintf(buf + len, max - len, fmt, ap);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_end(ap);
|
||||
lsquic_printf("\n");
|
||||
lb = snprintf(buf + len, max - len, "\n");
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
logger_if->log_buf(logger_ctx, buf, len);
|
||||
end:
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
@ -272,17 +323,36 @@ lsquic_logger_log1 (enum lsq_log_level log_level,
|
|||
const char *fmt, ...)
|
||||
{
|
||||
const int saved_errno = errno;
|
||||
size_t len = 0;
|
||||
size_t lb;
|
||||
size_t max = MAX_LINE_LEN;
|
||||
char buf[MAX_LINE_LEN];
|
||||
|
||||
if (g_llts != LLTS_NONE)
|
||||
print_timestamp();
|
||||
|
||||
lsquic_printf("[%s] %s: ", lsq_loglevel2str[log_level],
|
||||
{
|
||||
lb = print_timestamp(buf, max);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
}
|
||||
lb = snprintf(buf + len, max - len, "[%s] %s: ", lsq_loglevel2str[log_level],
|
||||
lsqlm_to_str[module]);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logger_if->vprintf(logger_ctx, fmt, ap);
|
||||
lb = vsnprintf(buf + len, max - len, fmt, ap);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_end(ap);
|
||||
lsquic_printf("\n");
|
||||
lb = snprintf(buf + len, max - len, "\n");
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
logger_if->log_buf(logger_ctx, buf, len);
|
||||
end:
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
@ -291,16 +361,36 @@ void
|
|||
lsquic_logger_log0 (enum lsq_log_level log_level, const char *fmt, ...)
|
||||
{
|
||||
const int saved_errno = errno;
|
||||
size_t len = 0;
|
||||
size_t lb;
|
||||
size_t max = MAX_LINE_LEN;
|
||||
char buf[MAX_LINE_LEN];
|
||||
|
||||
if (g_llts != LLTS_NONE)
|
||||
print_timestamp();
|
||||
{
|
||||
lb = print_timestamp(buf, max);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
}
|
||||
|
||||
lsquic_printf("[%s] ", lsq_loglevel2str[log_level]);
|
||||
lb = snprintf(buf + len, max - len, "[%s] ", lsq_loglevel2str[log_level]);
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
logger_if->vprintf(logger_ctx, fmt, ap);
|
||||
lb = vsnprintf(buf + len, max - len, fmt, ap);
|
||||
va_end(ap);
|
||||
lsquic_printf("\n");
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
lb = snprintf(buf + len, max - len, "\n");
|
||||
if (FORMAT_PROBLEM(lb, len, max))
|
||||
goto end;
|
||||
len += lb;
|
||||
logger_if->log_buf(logger_ctx, buf, len);
|
||||
end:
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
|
@ -406,3 +496,19 @@ lsquic_set_log_level (const char *level_str)
|
|||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* `out' must be at least MAX_CID_LEN * 2 + 1 characters long */
|
||||
void
|
||||
lsquic_cid2str (const lsquic_cid_t *cid, char *out)
|
||||
{
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int) cid->len; ++i)
|
||||
{
|
||||
*out++ = hex[ cid->idbuf[i] >> 4 ];
|
||||
*out++ = hex[ cid->idbuf[i] & 0xF ];
|
||||
}
|
||||
*out = '\0';
|
||||
}
|
||||
|
|
|
@ -61,18 +61,31 @@ enum lsquic_logger_module {
|
|||
LSQLM_CRYPTO,
|
||||
LSQLM_HANDSHAKE,
|
||||
LSQLM_HSK_ADAPTER,
|
||||
LSQLM_BBR,
|
||||
LSQLM_CUBIC,
|
||||
LSQLM_HEADERS,
|
||||
LSQLM_FRAME_WRITER,
|
||||
LSQLM_FRAME_READER,
|
||||
LSQLM_CONN_HASH,
|
||||
LSQLM_MINI_CONN,
|
||||
LSQLM_TOKGEN,
|
||||
LSQLM_ENG_HIST,
|
||||
LSQLM_SPI,
|
||||
LSQLM_DI,
|
||||
LSQLM_PRQ,
|
||||
LSQLM_PACER,
|
||||
LSQLM_MIN_HEAP,
|
||||
LSQLM_HTTP1X,
|
||||
LSQLM_QLOG,
|
||||
LSQLM_TRAPA,
|
||||
LSQLM_PURGA,
|
||||
LSQLM_HCSI_READER,
|
||||
LSQLM_HCSO_WRITER,
|
||||
LSQLM_QENC_HDL,
|
||||
LSQLM_QDEC_HDL,
|
||||
LSQLM_QPACK_ENC,
|
||||
LSQLM_QPACK_DEC,
|
||||
LSQLM_PRIO,
|
||||
LSQLM_BW_SAMPLER,
|
||||
N_LSQUIC_LOGGER_MODULES
|
||||
};
|
||||
|
||||
|
@ -89,6 +102,8 @@ extern const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS];
|
|||
|
||||
#define LSQ_LOG_ENABLED(level) LSQ_LOG_ENABLED_EXT(level, LSQUIC_LOGGER_MODULE)
|
||||
|
||||
struct lsquic_cid;
|
||||
|
||||
/* The functions that perform actual logging are void. This is an
|
||||
* optimization. In majority of cases the calls will succeed; even if
|
||||
* they fail, there is nothing (at least, nothing simple) to be done to
|
||||
|
@ -108,8 +123,8 @@ extern const char *const lsq_loglevel2str[N_LSQUIC_LOG_LEVELS];
|
|||
|
||||
void
|
||||
lsquic_logger_log3 (enum lsq_log_level, enum lsquic_logger_module,
|
||||
uint64_t conn_id, uint32_t stream_id,
|
||||
const char *format, ...)
|
||||
const struct lsquic_cid *conn_id,
|
||||
lsquic_stream_id_t stream_id, const char *format, ...)
|
||||
#if __GNUC__
|
||||
__attribute__((format(printf, 5, 6)))
|
||||
#endif
|
||||
|
@ -117,12 +132,13 @@ lsquic_logger_log3 (enum lsq_log_level, enum lsquic_logger_module,
|
|||
# define LSQ_LOG3(level, ...) do { \
|
||||
if (LSQ_LOG_ENABLED(level)) \
|
||||
lsquic_logger_log3(level, LSQUIC_LOGGER_MODULE, \
|
||||
LSQUIC_LOG_CONN_ID, LSQUIC_LOG_STREAM_ID, __VA_ARGS__); \
|
||||
LSQUIC_LOG_CONN_ID, LSQUIC_LOG_STREAM_ID, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
void
|
||||
lsquic_logger_log2 (enum lsq_log_level, enum lsquic_logger_module,
|
||||
uint64_t conn_id, const char *format, ...)
|
||||
const struct lsquic_cid *conn_id, const char *format, ...)
|
||||
#if __GNUC__
|
||||
__attribute__((format(printf, 4, 5)))
|
||||
#endif
|
||||
|
@ -130,7 +146,15 @@ lsquic_logger_log2 (enum lsq_log_level, enum lsquic_logger_module,
|
|||
# define LSQ_LOG2(level, ...) do { \
|
||||
if (LSQ_LOG_ENABLED(level)) \
|
||||
lsquic_logger_log2(level, LSQUIC_LOGGER_MODULE, \
|
||||
LSQUIC_LOG_CONN_ID, __VA_ARGS__); \
|
||||
LSQUIC_LOG_CONN_ID, __VA_ARGS__); \
|
||||
} while (0)
|
||||
# define LSQ_LOG2C(level, ...) do { \
|
||||
if (LSQ_LOG_ENABLED(level)) \
|
||||
{ \
|
||||
char cidbuf_[MAX_CID_LEN * 2 + 1]; \
|
||||
lsquic_logger_log2(level, LSQUIC_LOGGER_MODULE, \
|
||||
LSQUIC_LOG_CONN_ID, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
|
@ -144,6 +168,13 @@ lsquic_logger_log1 (enum lsq_log_level, enum lsquic_logger_module,
|
|||
if (LSQ_LOG_ENABLED(level)) \
|
||||
lsquic_logger_log1(level, LSQUIC_LOGGER_MODULE, __VA_ARGS__); \
|
||||
} while (0)
|
||||
# define LSQ_LOG1C(level, ...) do { \
|
||||
if (LSQ_LOG_ENABLED(level)) \
|
||||
{ \
|
||||
char cidbuf_[MAX_CID_LEN * 2 + 1]; \
|
||||
lsquic_logger_log1(level, LSQUIC_LOGGER_MODULE, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
lsquic_logger_log0 (enum lsq_log_level, const char *format, ...)
|
||||
|
@ -155,6 +186,13 @@ lsquic_logger_log0 (enum lsq_log_level, const char *format, ...)
|
|||
if (LSQ_LOG_ENABLED(level)) \
|
||||
lsquic_logger_log0(level, __VA_ARGS__); \
|
||||
} while (0)
|
||||
# define LSQ_LOG0C(level, ...) do { \
|
||||
if (LSQ_LOG_ENABLED(level)) \
|
||||
{ \
|
||||
char cidbuf_[MAX_CID_LEN * 2 + 1]; \
|
||||
lsquic_logger_log0(level, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if defined(LSQUIC_LOGGER_MODULE)
|
||||
#if defined(LSQUIC_LOG_CONN_ID)
|
||||
|
@ -162,12 +200,15 @@ lsquic_logger_log0 (enum lsq_log_level, const char *format, ...)
|
|||
# define LSQ_LOG LSQ_LOG3
|
||||
#else
|
||||
# define LSQ_LOG LSQ_LOG2
|
||||
# define LSQ_LOGC LSQ_LOG2C
|
||||
#endif
|
||||
#else
|
||||
# define LSQ_LOG LSQ_LOG1
|
||||
# define LSQ_LOGC LSQ_LOG1C
|
||||
#endif
|
||||
#else
|
||||
# define LSQ_LOG LSQ_LOG0
|
||||
# define LSQ_LOGC LSQ_LOG0C
|
||||
# define LSQUIC_LOGGER_MODULE LSQLM_NOMODULE
|
||||
#endif
|
||||
|
||||
|
@ -180,6 +221,15 @@ lsquic_logger_log0 (enum lsq_log_level, const char *format, ...)
|
|||
#define LSQ_INFO(...) LSQ_LOG(LSQ_LOG_INFO, __VA_ARGS__)
|
||||
#define LSQ_EMERG(...) LSQ_LOG(LSQ_LOG_EMERG, __VA_ARGS__)
|
||||
|
||||
#define LSQ_DEBUGC(...) LSQ_LOGC(LSQ_LOG_DEBUG, __VA_ARGS__)
|
||||
#define LSQ_WARNC(...) LSQ_LOGC(LSQ_LOG_WARN, __VA_ARGS__)
|
||||
#define LSQ_ALERTC(...) LSQ_LOGC(LSQ_LOG_ALERT, __VA_ARGS__)
|
||||
#define LSQ_CRITC(...) LSQ_LOGC(LSQ_LOG_CRIT, __VA_ARGS__)
|
||||
#define LSQ_ERRORC(...) LSQ_LOGC(LSQ_LOG_ERROR, __VA_ARGS__)
|
||||
#define LSQ_NOTICEC(...) LSQ_LOGC(LSQ_LOG_NOTICE, __VA_ARGS__)
|
||||
#define LSQ_INFOC(...) LSQ_LOGC(LSQ_LOG_INFO, __VA_ARGS__)
|
||||
#define LSQ_EMERGC(...) LSQ_LOGC(LSQ_LOG_EMERG, __VA_ARGS__)
|
||||
|
||||
/* Shorthand for printing to file streams using internal lsquic_logger_if
|
||||
*/
|
||||
void
|
||||
|
@ -197,6 +247,17 @@ lsquic_str_to_log_level (const char *);
|
|||
int
|
||||
lsquic_logger_lopt (const char *optarg);
|
||||
|
||||
#define CID_FMT ".*s"
|
||||
|
||||
#define CID_BITS(cid) 2 * (int) (cid)->len, \
|
||||
(lsquic_cid2str(cid, cidbuf_), cidbuf_)
|
||||
|
||||
void
|
||||
lsquic_cid2str (const struct lsquic_cid *, char *out);
|
||||
|
||||
const struct lsquic_cid *
|
||||
lsquic_conn_log_cid (const struct lsquic_conn *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
* does the following:
|
||||
*
|
||||
* 1. Allocations occur 4 KB at a time.
|
||||
* 2. No division or multiplication operations are performed.
|
||||
* 2. No division or multiplication operations are performed for
|
||||
* appropriately sized objects. (More on this below.)
|
||||
*
|
||||
* (In recent testing, malo was about 2.7 times faster than malloc for
|
||||
* 64-byte objects.)
|
||||
|
@ -18,18 +19,17 @@
|
|||
* 1. To free (put) an object, one does not need a pointer to the malo
|
||||
* object. This makes this allocator easy to use.
|
||||
* 2. A built-in iterator is provided to iterate over all allocated
|
||||
* objects (with ability to safely release objects while iterator
|
||||
* objects (with ability safely to release objects while iterator
|
||||
* is active). This may be useful in some circumstances.
|
||||
*
|
||||
* To gain all these advantages, there are trade-offs:
|
||||
*
|
||||
* 1. There are two memory penalties:
|
||||
* a. Per object overhead. To avoid division and multiplication,
|
||||
* the object sizes is rounded up to the nearest power or two,
|
||||
* starting with 64 bytes (minumum) and up to 2 KB (maximum).
|
||||
* Thus, a 104-byte object will have a 24-byte overhead; a
|
||||
* 130-byte object will have 126-byte overhead. This is
|
||||
* something to keep in mind.
|
||||
* a. Per object overhead. If an object is at least ROUNDUP_THRESH in
|
||||
* size as the next power of two, the allocator uses that power of
|
||||
* two value as the object size. This is done to avoid using
|
||||
* division and multiplication. For example, a 104-byte object
|
||||
* will have a 24-byte overhead.
|
||||
* b. Per page overhead. Page links occupy some bytes in the
|
||||
* page. To keep things fast, at least one slot per page is
|
||||
* always occupied, independent of object size. Thus, for a
|
||||
|
@ -56,17 +56,25 @@
|
|||
#include "fiu-local.h"
|
||||
#include "lsquic_malo.h"
|
||||
|
||||
#ifndef LSQUIC_USE_POOLS
|
||||
#define LSQUIC_USE_POOLS 1
|
||||
#endif
|
||||
|
||||
/* 64 slots in a 4KB page means that the smallest object is 64 bytes.
|
||||
* The largest object is 2KB.
|
||||
*/
|
||||
#define MALO_MIN_NBITS 6
|
||||
#define MALO_MAX_NBITS 11
|
||||
|
||||
#define ROUNDUP_THRESH 0.75f
|
||||
|
||||
/* A "free page" is a page with free slots available.
|
||||
*/
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
static unsigned find_free_slot (uint64_t slots);
|
||||
static unsigned size_in_bits (size_t sz);
|
||||
#endif
|
||||
|
||||
struct malo_page {
|
||||
SLIST_ENTRY(malo_page) next_page;
|
||||
|
@ -74,14 +82,25 @@ struct malo_page {
|
|||
struct malo *malo;
|
||||
uint64_t slots,
|
||||
full_slot_mask;
|
||||
unsigned nbits;
|
||||
unsigned nbits; /* If pow is zero, stores object size */
|
||||
unsigned initial_slot;
|
||||
int pow; /* True if object is power of 2 */
|
||||
};
|
||||
|
||||
typedef char malo_header_fits_in_one_slot
|
||||
[(sizeof(struct malo_page) > (1 << MALO_MAX_NBITS)) ? -1 : 1];
|
||||
[(sizeof(struct malo_page) > (1 << MALO_MIN_NBITS)) ? -1 : 1];
|
||||
|
||||
#if !LSQUIC_USE_POOLS
|
||||
struct nopool_elem
|
||||
{
|
||||
TAILQ_ENTRY(nopool_elem) next;
|
||||
struct malo *malo;
|
||||
unsigned char data[0];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct malo {
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct malo_page page_header;
|
||||
SLIST_HEAD(, malo_page) all_pages;
|
||||
LIST_HEAD(, malo_page) free_pages;
|
||||
|
@ -89,12 +108,23 @@ struct malo {
|
|||
struct malo_page *cur_page;
|
||||
unsigned next_slot;
|
||||
} iter;
|
||||
#else
|
||||
/* List of all elements: used by the iterator */
|
||||
TAILQ_HEAD(, nopool_elem) elems;
|
||||
size_t obj_size;
|
||||
struct nopool_elem *next_iter_elem;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct malo *
|
||||
lsquic_malo_create (size_t obj_size)
|
||||
{
|
||||
unsigned nbits = size_in_bits(obj_size);
|
||||
#if LSQUIC_USE_POOLS
|
||||
int pow, n_slots;
|
||||
unsigned nbits;
|
||||
|
||||
obj_size = (obj_size + 7) & -8;
|
||||
nbits = size_in_bits(obj_size);
|
||||
if (nbits < MALO_MIN_NBITS)
|
||||
nbits = MALO_MIN_NBITS;
|
||||
else if (nbits > MALO_MAX_NBITS)
|
||||
|
@ -103,6 +133,9 @@ lsquic_malo_create (size_t obj_size)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pow = obj_size <= (1 << MALO_MIN_NBITS)
|
||||
|| (float) obj_size / (1 << nbits) > ROUNDUP_THRESH;
|
||||
|
||||
struct malo *malo;
|
||||
if (0 != posix_memalign((void **) &malo, 0x1000, 0x1000))
|
||||
return NULL;
|
||||
|
@ -112,25 +145,52 @@ lsquic_malo_create (size_t obj_size)
|
|||
malo->iter.cur_page = &malo->page_header;
|
||||
malo->iter.next_slot = 0;
|
||||
|
||||
int n_slots = sizeof(*malo) / (1 << nbits)
|
||||
if (pow)
|
||||
n_slots = sizeof(*malo) / (1 << nbits)
|
||||
+ ((sizeof(*malo) % (1 << nbits)) > 0);
|
||||
else
|
||||
n_slots = sizeof(*malo) / obj_size
|
||||
+ ((sizeof(*malo) % obj_size) > 0);
|
||||
|
||||
struct malo_page *const page = &malo->page_header;
|
||||
SLIST_INSERT_HEAD(&malo->all_pages, page, next_page);
|
||||
LIST_INSERT_HEAD(&malo->free_pages, page, next_free_page);
|
||||
page->malo = malo;
|
||||
if (nbits == MALO_MIN_NBITS)
|
||||
if (!pow)
|
||||
page->full_slot_mask = (1ULL << (0x1000 / obj_size)) - 1;
|
||||
else if (nbits == MALO_MIN_NBITS)
|
||||
page->full_slot_mask = ~0ULL;
|
||||
else
|
||||
page->full_slot_mask = (1ULL << (1 << (12 - nbits))) - 1;
|
||||
page->slots = (1ULL << n_slots) - 1;
|
||||
page->nbits = nbits;
|
||||
page->pow = pow;
|
||||
page->nbits = pow ? nbits : obj_size;
|
||||
page->initial_slot = n_slots;
|
||||
|
||||
return malo;
|
||||
#else
|
||||
struct malo *malo;
|
||||
|
||||
/* Use the same sizing mechanism as in the normal version */
|
||||
if (obj_size < (1 << MALO_MIN_NBITS))
|
||||
obj_size = 1 << MALO_MIN_NBITS;
|
||||
else
|
||||
obj_size = (obj_size + 7) & -8;
|
||||
|
||||
malo = malloc(sizeof(*malo));
|
||||
if (malo)
|
||||
{
|
||||
TAILQ_INIT(&malo->elems);
|
||||
malo->obj_size = obj_size;
|
||||
return malo;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
static struct malo_page *
|
||||
allocate_page (struct malo *malo)
|
||||
{
|
||||
|
@ -142,10 +202,12 @@ allocate_page (struct malo *malo)
|
|||
page->slots = 1;
|
||||
page->full_slot_mask = malo->page_header.full_slot_mask;
|
||||
page->nbits = malo->page_header.nbits;
|
||||
page->pow = malo->page_header.pow;
|
||||
page->malo = malo;
|
||||
page->initial_slot = 1;
|
||||
return page;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define FAIL_NOMEM do { errno = ENOMEM; return NULL; } while (0)
|
||||
|
@ -154,6 +216,7 @@ allocate_page (struct malo *malo)
|
|||
void *
|
||||
lsquic_malo_get (struct malo *malo)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
fiu_do_on("malo/get", FAIL_NOMEM);
|
||||
struct malo_page *page = LIST_FIRST(&malo->free_pages);
|
||||
if (!page)
|
||||
|
@ -166,7 +229,22 @@ lsquic_malo_get (struct malo *malo)
|
|||
page->slots |= (1ULL << slot);
|
||||
if (page->full_slot_mask == page->slots)
|
||||
LIST_REMOVE(page, next_free_page);
|
||||
return (char *) page + (slot << page->nbits);
|
||||
if (page->pow)
|
||||
return (char *) page + (slot << page->nbits);
|
||||
else
|
||||
return (char *) page + (slot * page->nbits);
|
||||
#else
|
||||
struct nopool_elem *el;
|
||||
el = malloc(sizeof(*el) + malo->obj_size);
|
||||
if (el)
|
||||
{
|
||||
TAILQ_INSERT_HEAD(&malo->elems, el, next);
|
||||
el->malo = malo;
|
||||
return el->data;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,18 +252,32 @@ lsquic_malo_get (struct malo *malo)
|
|||
void
|
||||
lsquic_malo_put (void *obj)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
uintptr_t page_addr = (uintptr_t) obj & ~((1 << 12) - 1);
|
||||
struct malo_page *page = (void *) page_addr;
|
||||
unsigned slot = ((uintptr_t) obj - page_addr) >> page->nbits;
|
||||
unsigned slot;
|
||||
if (page->pow)
|
||||
slot = ((uintptr_t) obj - page_addr) >> page->nbits;
|
||||
else
|
||||
slot = ((uintptr_t) obj - page_addr) / page->nbits;
|
||||
if (page->full_slot_mask == page->slots)
|
||||
LIST_INSERT_HEAD(&page->malo->free_pages, page, next_free_page);
|
||||
page->slots &= ~(1ULL << slot);
|
||||
#else
|
||||
struct nopool_elem *el;
|
||||
el = (struct nopool_elem *) ((char *) obj - sizeof(*el));
|
||||
if (el == el->malo->next_iter_elem)
|
||||
el->malo->next_iter_elem = TAILQ_NEXT(el->malo->next_iter_elem, next);
|
||||
TAILQ_REMOVE(&el->malo->elems, el, next);
|
||||
free(el);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_malo_destroy (struct malo *malo)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct malo_page *page, *next;
|
||||
page = SLIST_FIRST(&malo->all_pages);
|
||||
while (page != &malo->page_header)
|
||||
|
@ -203,6 +295,15 @@ lsquic_malo_destroy (struct malo *malo)
|
|||
#else
|
||||
_aligned_free(page);
|
||||
#endif
|
||||
#else
|
||||
struct nopool_elem *el, *next_el;
|
||||
for (el = TAILQ_FIRST(&malo->elems); el; el = next_el)
|
||||
{
|
||||
next_el = TAILQ_NEXT(el, next);
|
||||
free(el);
|
||||
}
|
||||
free(malo);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,8 +315,12 @@ lsquic_malo_destroy (struct malo *malo)
|
|||
void *
|
||||
lsquic_malo_first (struct malo *malo)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
malo->iter.cur_page = SLIST_FIRST(&malo->all_pages);
|
||||
malo->iter.next_slot = malo->iter.cur_page->initial_slot;
|
||||
#else
|
||||
malo->next_iter_elem = TAILQ_FIRST(&malo->elems);
|
||||
#endif
|
||||
return lsquic_malo_next(malo);
|
||||
}
|
||||
|
||||
|
@ -223,13 +328,17 @@ lsquic_malo_first (struct malo *malo)
|
|||
void *
|
||||
lsquic_malo_next (struct malo *malo)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct malo_page *page;
|
||||
unsigned max_slot, slot;
|
||||
|
||||
page = malo->iter.cur_page;
|
||||
if (page)
|
||||
{
|
||||
max_slot = 1 << (12 - page->nbits); /* Same for all pages */
|
||||
if (page->pow)
|
||||
max_slot = 1 << (12 - page->nbits); /* Same for all pages */
|
||||
else
|
||||
max_slot = 0x1000 / page->nbits;
|
||||
slot = malo->iter.next_slot;
|
||||
while (1)
|
||||
{
|
||||
|
@ -239,7 +348,13 @@ lsquic_malo_next (struct malo *malo)
|
|||
{
|
||||
malo->iter.cur_page = page;
|
||||
malo->iter.next_slot = slot + 1;
|
||||
return (char *) page + (slot << page->nbits);
|
||||
if (page->pow)
|
||||
return (char *) page + (slot << page->nbits);
|
||||
else
|
||||
{
|
||||
assert(slot * (page->nbits + 1) < 0x1000);
|
||||
return (char *) page + (slot * page->nbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
page = SLIST_NEXT(page, next_page);
|
||||
|
@ -254,14 +369,27 @@ lsquic_malo_next (struct malo *malo)
|
|||
}
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
struct nopool_elem *retval;
|
||||
|
||||
if (malo->next_iter_elem)
|
||||
{
|
||||
retval = malo->next_iter_elem;
|
||||
malo->next_iter_elem = TAILQ_NEXT(malo->next_iter_elem, next);
|
||||
return retval->data;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
static unsigned
|
||||
size_in_bits (size_t sz)
|
||||
{
|
||||
#if __GNUC__
|
||||
unsigned clz = __builtin_clz(sz - 1);
|
||||
unsigned clz = sz > 1 ? __builtin_clz(sz - 1) : 31;
|
||||
return 32 - clz;
|
||||
#elif defined(WIN32)
|
||||
unsigned char s;
|
||||
|
@ -306,11 +434,13 @@ find_free_slot (uint64_t slots)
|
|||
return n;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_malo_mem_used (const struct malo *malo)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
const struct malo_page *page;
|
||||
size_t size;
|
||||
|
||||
|
@ -319,4 +449,7 @@ lsquic_malo_mem_used (const struct malo *malo)
|
|||
size += sizeof(*page);
|
||||
|
||||
return size;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#ifndef LSQUIC_MALO_H
|
||||
#define LSQUIC_MALO_H 1
|
||||
|
||||
#ifndef LSQUIC_USE_POOLS
|
||||
#define LSQUIC_USE_POOLS 1
|
||||
#endif
|
||||
|
||||
struct malo;
|
||||
|
||||
/* Create a malo allocator for objects of size `obj_size'. */
|
||||
|
@ -24,6 +28,10 @@ lsquic_malo_put (void *obj);
|
|||
void
|
||||
lsquic_malo_destroy (struct malo *);
|
||||
|
||||
/* This iterator is slow. It is only used in unit tests for verification.
|
||||
*
|
||||
* If you to iterate over all elements allocated in a pool, keep track yourself.
|
||||
*/
|
||||
/* The iterator is built-in. Usage:
|
||||
* void *obj;
|
||||
* for (obj = lsquic_malo_first(obj); obj; lsquic_malo_next(obj))
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "lsquic_min_heap.h"
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_MIN_HEAP
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#define MHE_PARENT(i) ((i - 1) / 2)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,158 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_mini_conn.h -- Mini-connection
|
||||
*
|
||||
* Before a connection is established, the server keeps a "mini" connection
|
||||
* object where it keeps track of stream 1 offsets and so on.
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_MINI_CONN_H
|
||||
#define LSQUIC_MINI_CONN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#define MAX_MINI_CONN_LIFESPAN_IN_USEC \
|
||||
((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) - 1)
|
||||
|
||||
struct lsquic_packet_in;
|
||||
struct lsquic_packet_out;
|
||||
struct lsquic_engine_public;
|
||||
|
||||
#ifndef LSQUIC_KEEP_MINICONN_HISTORY
|
||||
# ifndef NDEBUG
|
||||
# define LSQUIC_KEEP_MINICONN_HISTORY 0 /* XXX */
|
||||
# else
|
||||
# define LSQUIC_KEEP_MINICONN_HISTORY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if LSQUIC_KEEP_MINICONN_HISTORY
|
||||
|
||||
#define MCHIST_BITS 4
|
||||
#define MCHIST_MASK ((1 << MCHIST_BITS) - 1)
|
||||
typedef unsigned char mchist_idx_t;
|
||||
|
||||
enum miniconn_history_event
|
||||
{
|
||||
MCHE_EMPTY = '\0',
|
||||
MCHE_PLUS = '+',
|
||||
MCHE_HANDLE_1RTT = '1',
|
||||
MCHE_HANDLE_2RTT = '2',
|
||||
MCHE_PACKET2LARGE_IN = 'a',
|
||||
MCHE_CONN_CLOSE = 'c',
|
||||
MCHE_CREATED = 'C',
|
||||
MCHE_2HSK_1STREAM = 'd',
|
||||
MCHE_DUP_HSK = 'D',
|
||||
MCHE_HANDLE_ERROR = 'e',
|
||||
MCHE_EFRAME = 'f',
|
||||
MCHE_UNDECR_DEFER = 'F',
|
||||
MCHE_HANDLE_NOT_ENOUGH = 'g',
|
||||
MCHE_NEW_HSK = 'H',
|
||||
MCHE_INVALID_FRAME = 'I',
|
||||
MCHE_DECRYPTED = 'K',
|
||||
MCHE_PACKET_LOST = 'L',
|
||||
MCHE_HELLO_TOO_MUCH = 'm',
|
||||
MCHE_ENOMEM = 'M',
|
||||
MCHE_NEW_PACKET_OUT = 'N',
|
||||
MCHE_HELLO_HOLE = 'o',
|
||||
MCHE_PACKET_DUP_IN = 'p',
|
||||
MCHE_UNDECR_DROP = 'P',
|
||||
MCHE_PRST_IN = 'R',
|
||||
MCHE_HANDLE_SHLO = 's',
|
||||
MCHE_NEW_ENC_SESS = 'S',
|
||||
MCHE_PACKET_SENT = 'T',
|
||||
MCHE_HAHDLE_UNKNOWN = 'u',
|
||||
MCHE_UNSENT_ACKED = 'U',
|
||||
MCHE_HANDLE_DELAYED = 'y',
|
||||
MCHE_PACKET_DELAYED = 'Y',
|
||||
MCHE_PACKET0_IN = 'z',
|
||||
MCHE_OUT_OF_PACKNOS = '#',
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LSQUIC_RECORD_INORD_HIST
|
||||
# if __GNUC__
|
||||
# define LSQUIC_RECORD_INORD_HIST 0 /* XXX */
|
||||
# else
|
||||
# define LSQUIC_RECORD_INORD_HIST 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef uint64_t mconn_packno_set_t;
|
||||
|
||||
#define MINICONN_MAX_PACKETS (sizeof(mconn_packno_set_t) * 8)
|
||||
|
||||
TAILQ_HEAD(head_packet_in, lsquic_packet_in);
|
||||
|
||||
struct mini_conn {
|
||||
struct lsquic_conn mc_conn;
|
||||
struct conn_cid_elem mc_cces[1];
|
||||
struct head_packet_in mc_deferred,
|
||||
mc_packets_in;
|
||||
TAILQ_HEAD(, lsquic_packet_out)
|
||||
mc_packets_out;
|
||||
struct lsquic_engine_public
|
||||
*mc_enpub;
|
||||
lsquic_time_t mc_created;
|
||||
struct lsquic_rtt_stats
|
||||
mc_rtt_stats;
|
||||
mconn_packno_set_t mc_received_packnos,
|
||||
mc_sent_packnos,
|
||||
mc_deferred_packnos, /* Informational */
|
||||
mc_dropped_packnos, /* Informational */
|
||||
mc_lost_packnos, /* Packets that were deemed lost */ /* Informational */
|
||||
mc_acked_packnos;
|
||||
#if LSQUIC_RECORD_INORD_HIST
|
||||
unsigned long long mc_inord_hist[2]; /* Informational */
|
||||
#endif
|
||||
uint32_t mc_error_code; /* From CONNECTION_CLOSE frame */ /* Informational */
|
||||
unsigned short mc_n_ticks; /* Number of times mini conn ticked. */ /* Informational */
|
||||
unsigned short mc_read_off, /* Read offset for stream 1 */
|
||||
mc_write_off;/* Write offset for stream 1 */
|
||||
unsigned char mc_max_ack_packno,
|
||||
/* XXX: mc_max_ack_packno is never set */
|
||||
mc_cutoff,
|
||||
mc_cur_packno;
|
||||
unsigned char mc_hsk_count;
|
||||
#if LSQUIC_RECORD_INORD_HIST
|
||||
unsigned char mc_inord_idx;
|
||||
#endif
|
||||
/* mc_largest_recv is the timestamp of when packet with the largest
|
||||
* number was received; it is necessary to generate ACK frames. 24
|
||||
* bits holds about 16.5 seconds worth of microseconds, which is
|
||||
* larger than the maximum amount of time a mini connection object
|
||||
* is allowed to live. To get the timestamp, add this value to
|
||||
* mc_created.
|
||||
*/
|
||||
unsigned char mc_largest_recv[3];
|
||||
enum {
|
||||
MC_HAVE_NEW_HSK = (1 << 0),
|
||||
MC_PROMOTE = (1 << 1),
|
||||
MC_HAVE_SHLO = (1 << 2),
|
||||
MC_UNUSED_3 = (1 << 3),
|
||||
MC_ERROR = (1 << 4),
|
||||
MC_UNSENT_ACK = (1 << 5),
|
||||
MC_GEN_ACK = (1 << 6),
|
||||
MC_HSK_ERR = (1 << 7),
|
||||
MC_OO_PACKNOS = (1 << 8),
|
||||
MC_STOP_WAIT_ON = (1 << 9),
|
||||
} mc_flags:16;
|
||||
struct network_path mc_path;
|
||||
#if LSQUIC_KEEP_MINICONN_HISTORY
|
||||
mchist_idx_t mc_hist_idx;
|
||||
unsigned char mc_hist_buf[1 << MCHIST_BITS];
|
||||
#endif
|
||||
};
|
||||
|
||||
lsquic_conn_t *
|
||||
mini_conn_new (struct lsquic_engine_public *, const struct lsquic_packet_in *,
|
||||
enum lsquic_version version);
|
||||
|
||||
/* Packet numbers start with 1. By subtracting 1, we can utilize the full
|
||||
* length of the bitmask.
|
||||
*/
|
||||
#define MCONN_PACKET_MASK(packno) (1ULL << (packno - 1))
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* lsquic_mini_conn_ietf.h -- Mini connection used by the IETF QUIC
|
||||
*/
|
||||
|
||||
#ifndef LSQUIC_MINI_CONN_IETF_H
|
||||
#define LSQUIC_MINI_CONN_IETF_H 1
|
||||
|
||||
struct lsquic_conn;
|
||||
struct lsquic_engine_public;
|
||||
struct lsquic_packet_in;
|
||||
|
||||
enum { MCSBIT_WANTREAD, MCSBIT_WANTWRITE, };
|
||||
|
||||
struct mini_crypto_stream
|
||||
{
|
||||
unsigned mcs_read_off;
|
||||
unsigned mcs_write_off;
|
||||
enum {
|
||||
MCS_WANTREAD = 1 << MCSBIT_WANTREAD,
|
||||
MCS_WANTWRITE = 1 << MCSBIT_WANTWRITE,
|
||||
MCS_CREATED = 1 << 2,
|
||||
} mcs_flags:8;
|
||||
enum enc_level mcs_enc_level:8;
|
||||
};
|
||||
|
||||
typedef uint64_t packno_set_t;
|
||||
#define MAX_PACKETS ((sizeof(packno_set_t) * 8) - 1)
|
||||
|
||||
struct ietf_mini_conn
|
||||
{
|
||||
struct lsquic_conn imc_conn;
|
||||
struct conn_cid_elem imc_cces[3];
|
||||
struct lsquic_engine_public *imc_enpub;
|
||||
lsquic_time_t imc_created;
|
||||
enum {
|
||||
IMC_ENC_SESS_INITED = 1 << 0,
|
||||
IMC_QUEUED_ACK_INIT = 1 << 1,
|
||||
IMC_QUEUED_ACK_HSK = IMC_QUEUED_ACK_INIT << PNS_HSK,
|
||||
IMC_QUEUED_ACK_APP = IMC_QUEUED_ACK_INIT << PNS_APP,
|
||||
IMC_ERROR = 1 << 4,
|
||||
IMC_HSK_OK = 1 << 5,
|
||||
IMC_HSK_FAILED = 1 << 6,
|
||||
IMC_HAVE_TP = 1 << 7,
|
||||
IMC_RETRY_MODE = 1 << 8,
|
||||
IMC_RETRY_DONE = 1 << 9,
|
||||
IMC_IGNORE_INIT = 1 << 10,
|
||||
#define IMCBIT_PNS_BIT_SHIFT 11
|
||||
IMC_MAX_PNS_BIT_0 = 1 << 11,
|
||||
IMC_MAX_PNS_BIT_1 = 1 << 12,
|
||||
IMC_TLS_ALERT = 1 << 13,
|
||||
IMC_ABORT_ERROR = 1 << 14,
|
||||
IMC_ABORT_ISAPP = 1 << 15,
|
||||
IMC_BAD_TRANS_PARAMS = 1 << 16,
|
||||
IMC_ADDR_VALIDATED = 1 << 17,
|
||||
} imc_flags;
|
||||
struct mini_crypto_stream imc_streams[N_ENC_LEVS];
|
||||
void *imc_stream_ps[N_ENC_LEVS];
|
||||
struct {
|
||||
struct stream_frame *frame; /* Latest frame - on stack - be careful. */
|
||||
enum enc_level enc_level;
|
||||
} imc_last_in;
|
||||
TAILQ_HEAD(, lsquic_packet_in) imc_app_packets;
|
||||
TAILQ_HEAD(, lsquic_packet_out) imc_packets_out;
|
||||
packno_set_t imc_sent_packnos;
|
||||
packno_set_t imc_recvd_packnos[N_PNS];
|
||||
packno_set_t imc_acked_packnos[N_PNS];
|
||||
lsquic_time_t imc_largest_recvd[N_PNS];
|
||||
struct lsquic_rtt_stats imc_rtt_stats;
|
||||
unsigned imc_error_code;
|
||||
unsigned imc_bytes_in;
|
||||
unsigned imc_bytes_out;
|
||||
unsigned char imc_next_packno;
|
||||
unsigned char imc_hsk_count;
|
||||
uint8_t imc_ack_exp;
|
||||
uint8_t imc_ecn_counts_in[N_PNS][4];
|
||||
uint8_t imc_ecn_counts_out[N_PNS][4];
|
||||
uint8_t imc_incoming_ecn;
|
||||
uint8_t imc_tls_alert;
|
||||
struct network_path imc_path;
|
||||
};
|
||||
|
||||
struct lsquic_conn *
|
||||
lsquic_mini_conn_ietf_new (struct lsquic_engine_public *,
|
||||
const struct lsquic_packet_in *,
|
||||
enum lsquic_version, int is_ipv4, const struct lsquic_cid *);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,155 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
/*
|
||||
* Based on Google code released under BSD license here:
|
||||
* https://groups.google.com/forum/#!topic/bbr-dev/3RTgkzi5ZD8
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2017, Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by the following BSD-style license:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Kathleen Nichols' algorithm for tracking the minimum (or maximum)
|
||||
* value of a data stream over some fixed time interval. (E.g.,
|
||||
* the minimum RTT over the past five minutes.) It uses constant
|
||||
* space and constant time per update yet almost always delivers
|
||||
* the same minimum as an implementation that has to keep all the
|
||||
* data in the window.
|
||||
*
|
||||
* The algorithm keeps track of the best, 2nd best & 3rd best min
|
||||
* values, maintaining an invariant that the measurement time of
|
||||
* the n'th best >= n-1'th best. It also makes sure that the three
|
||||
* values are widely separated in the time window since that bounds
|
||||
* the worse case error when that data is monotonically increasing
|
||||
* over the window.
|
||||
*
|
||||
* Upon getting a new min, we can forget everything earlier because
|
||||
* it has no value - the new min is <= everything else in the window
|
||||
* by definition and it'samples the most recent. So we restart fresh on
|
||||
* every new min and overwrites 2nd & 3rd choices. The same property
|
||||
* holds for 2nd & 3rd best.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lsquic_minmax.h"
|
||||
|
||||
/* As time advances, update the 1st, 2nd, and 3rd choices. */
|
||||
static void
|
||||
minmax_subwin_update (struct minmax *minmax, const struct minmax_sample *sample)
|
||||
{
|
||||
uint64_t dt = sample->time - minmax->samples[0].time;
|
||||
|
||||
if (dt > minmax->window)
|
||||
{
|
||||
/*
|
||||
* Passed entire window without a new sample so make 2nd
|
||||
* choice the new sample & 3rd choice the new 2nd choice.
|
||||
* we may have to iterate this since our 2nd choice
|
||||
* may also be outside the window (we checked on entry
|
||||
* that the third choice was in the window).
|
||||
*/
|
||||
minmax->samples[0] = minmax->samples[1];
|
||||
minmax->samples[1] = minmax->samples[2];
|
||||
minmax->samples[2] = *sample;
|
||||
if (sample->time - minmax->samples[0].time > minmax->window) {
|
||||
minmax->samples[0] = minmax->samples[1];
|
||||
minmax->samples[1] = minmax->samples[2];
|
||||
minmax->samples[2] = *sample;
|
||||
}
|
||||
}
|
||||
else if (minmax->samples[1].time == minmax->samples[0].time
|
||||
&& dt > minmax->window / 4)
|
||||
{
|
||||
/*
|
||||
* We've passed a quarter of the window without a new sample
|
||||
* so take a 2nd choice from the 2nd quarter of the window.
|
||||
*/
|
||||
minmax->samples[2] = minmax->samples[1] = *sample;
|
||||
}
|
||||
else if (minmax->samples[2].time == minmax->samples[1].time
|
||||
&& dt > minmax->window / 2)
|
||||
{
|
||||
/*
|
||||
* We've passed half the window without finding a new sample
|
||||
* so take a 3rd choice from the last half of the window
|
||||
*/
|
||||
minmax->samples[2] = *sample;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check if new measurement updates the 1st, 2nd or 3rd choice max. */
|
||||
void
|
||||
lsquic_minmax_update_max (struct minmax *minmax, uint64_t now, uint64_t meas)
|
||||
{
|
||||
struct minmax_sample sample = { .time = now, .value = meas };
|
||||
|
||||
if (minmax->samples[0].value == 0 /* uninitialized */
|
||||
|| sample.value >= minmax->samples[0].value /* found new max? */
|
||||
|| sample.time - minmax->samples[2].time > minmax->window) /* nothing left in window? */
|
||||
{
|
||||
minmax_reset(minmax, sample); /* forget earlier samples */
|
||||
return;
|
||||
}
|
||||
|
||||
if (sample.value >= minmax->samples[1].value)
|
||||
minmax->samples[2] = minmax->samples[1] = sample;
|
||||
else if (sample.value >= minmax->samples[2].value)
|
||||
minmax->samples[2] = sample;
|
||||
|
||||
minmax_subwin_update(minmax, &sample);
|
||||
}
|
||||
|
||||
|
||||
/* Check if new measurement updates the 1st, 2nd or 3rd choice min. */
|
||||
void
|
||||
lsquic_minmax_update_min (struct minmax *minmax, uint64_t now, uint64_t meas)
|
||||
{
|
||||
struct minmax_sample sample = { .time = now, .value = meas };
|
||||
|
||||
if (minmax->samples[0].value == 0 /* uninitialized */
|
||||
|| sample.value <= minmax->samples[0].value /* found new min? */
|
||||
|| sample.time - minmax->samples[2].time > minmax->window) /* nothing left in window? */
|
||||
{
|
||||
minmax_reset(minmax, sample); /* forget earlier samples */
|
||||
return;
|
||||
}
|
||||
|
||||
if (sample.value <= minmax->samples[1].value)
|
||||
minmax->samples[2] = minmax->samples[1] = sample;
|
||||
else if (sample.value <= minmax->samples[2].value)
|
||||
minmax->samples[2] = sample;
|
||||
|
||||
minmax_subwin_update(minmax, &sample);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_MINMAX_H
|
||||
#define LSQUIC_MINMAX_H
|
||||
|
||||
/* Windowed min/max tracker by Kathleen Nichols.
|
||||
*
|
||||
* Based on Google code released under BSD license here:
|
||||
* https://groups.google.com/forum/#!topic/bbr-dev/3RTgkzi5ZD8
|
||||
*/
|
||||
|
||||
|
||||
struct minmax_sample
|
||||
{
|
||||
uint64_t time;
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
struct minmax
|
||||
{
|
||||
uint64_t window;
|
||||
struct minmax_sample samples[3];
|
||||
};
|
||||
|
||||
#define minmax_get_idx(minmax_, idx_) ((minmax_)->samples[idx_].value)
|
||||
|
||||
#define minmax_get(minmax_) minmax_get_idx(minmax_, 0)
|
||||
|
||||
#define minmax_reset(minmax_, sample_) do { \
|
||||
(minmax_)->samples[0] = (minmax_)->samples[1] \
|
||||
= (minmax_)->samples[2] = (sample_); \
|
||||
} while (0)
|
||||
|
||||
#define minmax_init(minmax_, window_) do { \
|
||||
(minmax_)->window = (window_); \
|
||||
minmax_reset(minmax_, ((struct minmax_sample) { 0, 0, })); \
|
||||
} while (0)
|
||||
|
||||
void lsquic_minmax_update_min(struct minmax *, uint64_t now, uint64_t meas);
|
||||
void lsquic_minmax_update_max(struct minmax *, uint64_t now, uint64_t meas);
|
||||
|
||||
#define minmax_upmin lsquic_minmax_update_min
|
||||
#define minmax_upmax lsquic_minmax_update_max
|
||||
|
||||
#endif
|
|
@ -14,22 +14,45 @@
|
|||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_sizes.h"
|
||||
#include "lsquic_malo.h"
|
||||
#include "lsquic_hash.h"
|
||||
#include "lsquic_conn.h"
|
||||
#include "lsquic_rtt.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_mini_conn.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_mini_conn_ietf.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
#include "lsquic_packet_in.h"
|
||||
#include "lsquic_packet_out.h"
|
||||
#include "lsquic_parse.h"
|
||||
#include "lsquic_mm.h"
|
||||
#include "lsquic_engine_public.h"
|
||||
#include "lsquic_full_conn.h"
|
||||
#include "lsquic_varint.h"
|
||||
#include "lsquic_hq.h"
|
||||
#include "lsquic_sfcw.h"
|
||||
#include "lsquic_stream.h"
|
||||
|
||||
#ifndef LSQUIC_LOG_POOL_STATS
|
||||
#define LSQUIC_LOG_POOL_STATS 0
|
||||
#endif
|
||||
|
||||
#if LSQUIC_LOG_POOL_STATS
|
||||
#include "lsquic_logger.h"
|
||||
#endif
|
||||
|
||||
#ifndef LSQUIC_USE_POOLS
|
||||
#define LSQUIC_USE_POOLS 1
|
||||
#endif
|
||||
|
||||
#define FAIL_NOMEM do { errno = ENOMEM; return NULL; } while (0)
|
||||
|
||||
|
||||
struct payload_buf
|
||||
struct packet_in_buf
|
||||
{
|
||||
SLIST_ENTRY(payload_buf) next_pb;
|
||||
SLIST_ENTRY(packet_in_buf) next_pib;
|
||||
};
|
||||
|
||||
struct packet_out_buf
|
||||
|
@ -51,21 +74,32 @@ struct sixteen_k_page
|
|||
int
|
||||
lsquic_mm_init (struct lsquic_mm *mm)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
mm->acki = malloc(sizeof(*mm->acki));
|
||||
mm->malo.stream_frame = lsquic_malo_create(sizeof(struct stream_frame));
|
||||
mm->malo.stream_rec_arr = lsquic_malo_create(sizeof(struct stream_rec_arr));
|
||||
mm->malo.mini_conn = lsquic_malo_create(sizeof(struct mini_conn));
|
||||
mm->malo.mini_conn_ietf = lsquic_malo_create(sizeof(struct ietf_mini_conn));
|
||||
mm->malo.packet_in = lsquic_malo_create(sizeof(struct lsquic_packet_in));
|
||||
mm->malo.packet_out = lsquic_malo_create(sizeof(struct lsquic_packet_out));
|
||||
mm->malo.dcid_elem = lsquic_malo_create(sizeof(struct dcid_elem));
|
||||
mm->malo.stream_hq_frame
|
||||
= lsquic_malo_create(sizeof(struct stream_hq_frame));
|
||||
#if LSQUIC_USE_POOLS
|
||||
TAILQ_INIT(&mm->free_packets_in);
|
||||
for (i = 0; i < MM_N_OUT_BUCKETS; ++i)
|
||||
SLIST_INIT(&mm->packet_out_bufs[i]);
|
||||
SLIST_INIT(&mm->payload_bufs);
|
||||
for (i = 0; i < MM_N_IN_BUCKETS; ++i)
|
||||
SLIST_INIT(&mm->packet_in_bufs[i]);
|
||||
SLIST_INIT(&mm->four_k_pages);
|
||||
SLIST_INIT(&mm->sixteen_k_pages);
|
||||
if (mm->acki && mm->malo.stream_frame && mm->malo.stream_rec_arr &&
|
||||
mm->malo.packet_in)
|
||||
#endif
|
||||
if (mm->acki && mm->malo.stream_frame && mm->malo.stream_rec_arr
|
||||
&& mm->malo.mini_conn && mm->malo.mini_conn_ietf && mm->malo.packet_in
|
||||
&& mm->malo.stream_hq_frame)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -77,18 +111,25 @@ lsquic_mm_init (struct lsquic_mm *mm)
|
|||
void
|
||||
lsquic_mm_cleanup (struct lsquic_mm *mm)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
int i;
|
||||
struct packet_out_buf *pob;
|
||||
struct payload_buf *pb;
|
||||
struct packet_in_buf *pib;
|
||||
struct four_k_page *fkp;
|
||||
struct sixteen_k_page *skp;
|
||||
#endif
|
||||
|
||||
free(mm->acki);
|
||||
lsquic_malo_destroy(mm->malo.stream_hq_frame);
|
||||
lsquic_malo_destroy(mm->malo.dcid_elem);
|
||||
lsquic_malo_destroy(mm->malo.packet_in);
|
||||
lsquic_malo_destroy(mm->malo.packet_out);
|
||||
lsquic_malo_destroy(mm->malo.stream_frame);
|
||||
lsquic_malo_destroy(mm->malo.stream_rec_arr);
|
||||
lsquic_malo_destroy(mm->malo.mini_conn);
|
||||
lsquic_malo_destroy(mm->malo.mini_conn_ietf);
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
for (i = 0; i < MM_N_OUT_BUCKETS; ++i)
|
||||
while ((pob = SLIST_FIRST(&mm->packet_out_bufs[i])))
|
||||
{
|
||||
|
@ -96,11 +137,12 @@ lsquic_mm_cleanup (struct lsquic_mm *mm)
|
|||
free(pob);
|
||||
}
|
||||
|
||||
while ((pb = SLIST_FIRST(&mm->payload_bufs)))
|
||||
{
|
||||
SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb);
|
||||
free(pb);
|
||||
}
|
||||
for (i = 0; i < MM_N_IN_BUCKETS; ++i)
|
||||
while ((pib = SLIST_FIRST(&mm->packet_in_bufs[i])))
|
||||
{
|
||||
SLIST_REMOVE_HEAD(&mm->packet_in_bufs[i], next_pib);
|
||||
free(pib);
|
||||
}
|
||||
|
||||
while ((fkp = SLIST_FIRST(&mm->four_k_pages)))
|
||||
{
|
||||
|
@ -113,6 +155,56 @@ lsquic_mm_cleanup (struct lsquic_mm *mm)
|
|||
SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp);
|
||||
free(skp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
enum {
|
||||
PACKET_IN_PAYLOAD_0 = 1370, /* common QUIC payload size upperbound */
|
||||
PACKET_IN_PAYLOAD_1 = 4096, /* payload size middleground guess */
|
||||
PACKET_IN_PAYLOAD_2 = 0xffff, /* UDP payload size upperbound */
|
||||
};
|
||||
|
||||
|
||||
static const unsigned packet_in_sizes[] = {
|
||||
PACKET_IN_PAYLOAD_0,
|
||||
PACKET_IN_PAYLOAD_1,
|
||||
PACKET_IN_PAYLOAD_2,
|
||||
};
|
||||
|
||||
|
||||
static unsigned
|
||||
packet_in_index (unsigned size)
|
||||
{
|
||||
unsigned idx = (size > PACKET_IN_PAYLOAD_0)
|
||||
+ (size > PACKET_IN_PAYLOAD_1);
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_packet_in (struct lsquic_mm *mm,
|
||||
struct lsquic_packet_in *packet_in)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
unsigned idx;
|
||||
struct packet_in_buf *pib;
|
||||
|
||||
assert(0 == packet_in->pi_refcnt);
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
{
|
||||
pib = (struct packet_in_buf *) packet_in->pi_data;
|
||||
idx = packet_in_index(packet_in->pi_data_sz);
|
||||
SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib);
|
||||
}
|
||||
TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next);
|
||||
#else
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
free(packet_in->pi_data);
|
||||
lsquic_malo_put(packet_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,6 +215,7 @@ lsquic_mm_get_packet_in (struct lsquic_mm *mm)
|
|||
|
||||
fiu_do_on("mm/packet_in", FAIL_NOMEM);
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
packet_in = TAILQ_FIRST(&mm->free_packets_in);
|
||||
if (packet_in)
|
||||
{
|
||||
|
@ -130,6 +223,7 @@ lsquic_mm_get_packet_in (struct lsquic_mm *mm)
|
|||
TAILQ_REMOVE(&mm->free_packets_in, packet_in, pi_next);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
packet_in = lsquic_malo_get(mm->malo.packet_in);
|
||||
|
||||
if (packet_in)
|
||||
|
@ -139,11 +233,14 @@ lsquic_mm_get_packet_in (struct lsquic_mm *mm)
|
|||
}
|
||||
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
/* Based on commonly used MTUs, ordered from small to large: */
|
||||
enum {
|
||||
PACKET_OUT_PAYLOAD_0 = 1280 - QUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_1 = QUIC_MAX_IPv6_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_2 = QUIC_MAX_IPv4_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_0 = 1280 - GQUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_1 = GQUIC_MAX_IPv6_PACKET_SZ - GQUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_2 = GQUIC_MAX_IPv4_PACKET_SZ - GQUIC_MIN_PACKET_OVERHEAD,
|
||||
PACKET_OUT_PAYLOAD_3 = 4096,
|
||||
PACKET_OUT_PAYLOAD_4 = 0xffff,
|
||||
};
|
||||
|
||||
|
||||
|
@ -151,6 +248,8 @@ static const unsigned packet_out_sizes[] = {
|
|||
PACKET_OUT_PAYLOAD_0,
|
||||
PACKET_OUT_PAYLOAD_1,
|
||||
PACKET_OUT_PAYLOAD_2,
|
||||
PACKET_OUT_PAYLOAD_3,
|
||||
PACKET_OUT_PAYLOAD_4,
|
||||
};
|
||||
|
||||
|
||||
|
@ -158,15 +257,120 @@ static unsigned
|
|||
packet_out_index (unsigned size)
|
||||
{
|
||||
unsigned idx = (size > PACKET_OUT_PAYLOAD_0)
|
||||
+ (size > PACKET_OUT_PAYLOAD_1);
|
||||
+ (size > PACKET_OUT_PAYLOAD_1)
|
||||
+ (size > PACKET_OUT_PAYLOAD_2)
|
||||
+ (size > PACKET_OUT_PAYLOAD_3);
|
||||
return idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
#define POOL_SAMPLE_PERIOD 1024
|
||||
|
||||
static void
|
||||
poolst_sample_max (struct pool_stats *poolst)
|
||||
{
|
||||
#define ALPHA_SHIFT 3
|
||||
#define BETA_SHIFT 2
|
||||
unsigned diff;
|
||||
|
||||
if (poolst->ps_max_avg)
|
||||
{
|
||||
poolst->ps_max_var -= poolst->ps_max_var >> BETA_SHIFT;
|
||||
if (poolst->ps_max_avg > poolst->ps_max)
|
||||
diff = poolst->ps_max_avg - poolst->ps_max;
|
||||
else
|
||||
diff = poolst->ps_max - poolst->ps_max_avg;
|
||||
poolst->ps_max_var += diff >> BETA_SHIFT;
|
||||
poolst->ps_max_avg -= poolst->ps_max_avg >> ALPHA_SHIFT;
|
||||
poolst->ps_max_avg += poolst->ps_max >> ALPHA_SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* First measurement */
|
||||
poolst->ps_max_avg = poolst->ps_max;
|
||||
poolst->ps_max_var = poolst->ps_max / 2;
|
||||
}
|
||||
|
||||
poolst->ps_calls = 0;
|
||||
poolst->ps_max = poolst->ps_objs_out;
|
||||
#if LSQUIC_LOG_POOL_STATS
|
||||
LSQ_DEBUG("new sample: max avg: %u; var: %u", poolst->ps_max_avg,
|
||||
poolst->ps_max_var);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
poolst_allocated (struct pool_stats *poolst, unsigned new)
|
||||
{
|
||||
poolst->ps_objs_out += 1;
|
||||
poolst->ps_objs_all += new;
|
||||
if (poolst->ps_objs_out > poolst->ps_max)
|
||||
poolst->ps_max = poolst->ps_objs_out;
|
||||
++poolst->ps_calls;
|
||||
if (0 == poolst->ps_calls % POOL_SAMPLE_PERIOD)
|
||||
poolst_sample_max(poolst);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
poolst_freed (struct pool_stats *poolst)
|
||||
{
|
||||
--poolst->ps_objs_out;
|
||||
++poolst->ps_calls;
|
||||
if (0 == poolst->ps_calls % POOL_SAMPLE_PERIOD)
|
||||
poolst_sample_max(poolst);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
poolst_has_new_sample (const struct pool_stats *poolst)
|
||||
{
|
||||
return poolst->ps_calls == 0;
|
||||
}
|
||||
|
||||
|
||||
/* If average maximum falls under 1/4 of all objects allocated, release
|
||||
* half of the objects allocated.
|
||||
*/
|
||||
static void
|
||||
maybe_shrink_packet_out_bufs (struct lsquic_mm *mm, unsigned idx)
|
||||
{
|
||||
struct pool_stats *poolst;
|
||||
struct packet_out_buf *pob;
|
||||
unsigned n_to_leave;
|
||||
|
||||
poolst = &mm->packet_out_bstats[idx];
|
||||
if (poolst->ps_max_avg * 4 < poolst->ps_objs_all)
|
||||
{
|
||||
n_to_leave = poolst->ps_objs_all / 2;
|
||||
while (poolst->ps_objs_all > n_to_leave
|
||||
&& (pob = SLIST_FIRST(&mm->packet_out_bufs[idx])))
|
||||
{
|
||||
SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob);
|
||||
free(pob);
|
||||
--poolst->ps_objs_all;
|
||||
}
|
||||
#if LSQUIC_LOG_POOL_STATS
|
||||
LSQ_DEBUG("pool #%u; max avg %u; shrank from %u to %u objs",
|
||||
idx, poolst->ps_max_avg, n_to_leave * 2, poolst->ps_objs_all);
|
||||
#endif
|
||||
}
|
||||
#if LSQUIC_LOG_POOL_STATS
|
||||
else
|
||||
LSQ_DEBUG("pool #%u; max avg %u; objs: %u; won't shrink",
|
||||
idx, poolst->ps_max_avg, poolst->ps_objs_all);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_packet_out (struct lsquic_mm *mm,
|
||||
struct lsquic_packet_out *packet_out)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct packet_out_buf *pob;
|
||||
unsigned idx;
|
||||
|
||||
|
@ -174,6 +378,14 @@ lsquic_mm_put_packet_out (struct lsquic_mm *mm,
|
|||
pob = (struct packet_out_buf *) packet_out->po_data;
|
||||
idx = packet_out_index(packet_out->po_n_alloc);
|
||||
SLIST_INSERT_HEAD(&mm->packet_out_bufs[idx], pob, next_pob);
|
||||
poolst_freed(&mm->packet_out_bstats[idx]);
|
||||
if (poolst_has_new_sample(&mm->packet_out_bstats[idx]))
|
||||
maybe_shrink_packet_out_bufs(mm, idx);
|
||||
if (packet_out->po_bwp_state)
|
||||
lsquic_malo_put(packet_out->po_bwp_state);
|
||||
#else
|
||||
free(packet_out->po_data);
|
||||
#endif
|
||||
lsquic_malo_put(packet_out);
|
||||
}
|
||||
|
||||
|
@ -184,9 +396,9 @@ lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
|||
{
|
||||
struct lsquic_packet_out *packet_out;
|
||||
struct packet_out_buf *pob;
|
||||
#if LSQUIC_USE_POOLS
|
||||
unsigned idx;
|
||||
|
||||
assert(size <= QUIC_MAX_PAYLOAD_SZ);
|
||||
#endif
|
||||
|
||||
fiu_do_on("mm/packet_out", FAIL_NOMEM);
|
||||
|
||||
|
@ -194,10 +406,14 @@ lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
|||
if (!packet_out)
|
||||
return NULL;
|
||||
|
||||
#if LSQUIC_USE_POOLS
|
||||
idx = packet_out_index(size);
|
||||
pob = SLIST_FIRST(&mm->packet_out_bufs[idx]);
|
||||
if (pob)
|
||||
{
|
||||
SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob);
|
||||
poolst_allocated(&mm->packet_out_bstats[idx], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pob = malloc(packet_out_sizes[idx]);
|
||||
|
@ -206,7 +422,18 @@ lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
|||
lsquic_malo_put(packet_out);
|
||||
return NULL;
|
||||
}
|
||||
poolst_allocated(&mm->packet_out_bstats[idx], 1);
|
||||
}
|
||||
if (poolst_has_new_sample(&mm->packet_out_bstats[idx]))
|
||||
maybe_shrink_packet_out_bufs(mm, idx);
|
||||
#else
|
||||
pob = malloc(size);
|
||||
if (!pob)
|
||||
{
|
||||
lsquic_malo_put(packet_out);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(packet_out, 0, sizeof(*packet_out));
|
||||
packet_out->po_n_alloc = size;
|
||||
|
@ -217,29 +444,46 @@ lsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo,
|
|||
|
||||
|
||||
void *
|
||||
lsquic_mm_get_1370 (struct lsquic_mm *mm)
|
||||
lsquic_mm_get_packet_in_buf (struct lsquic_mm *mm, size_t size)
|
||||
{
|
||||
struct payload_buf *pb = SLIST_FIRST(&mm->payload_bufs);
|
||||
fiu_do_on("mm/1370", FAIL_NOMEM);
|
||||
if (pb)
|
||||
SLIST_REMOVE_HEAD(&mm->payload_bufs, next_pb);
|
||||
struct packet_in_buf *pib;
|
||||
#if LSQUIC_USE_POOLS
|
||||
unsigned idx;
|
||||
|
||||
idx = packet_in_index(size);
|
||||
pib = SLIST_FIRST(&mm->packet_in_bufs[idx]);
|
||||
fiu_do_on("mm/packet_in_buf", FAIL_NOMEM);
|
||||
if (pib)
|
||||
SLIST_REMOVE_HEAD(&mm->packet_in_bufs[idx], next_pib);
|
||||
else
|
||||
pb = malloc(1370);
|
||||
return pb;
|
||||
pib = malloc(packet_in_sizes[idx]);
|
||||
#else
|
||||
pib = malloc(size);
|
||||
#endif
|
||||
return pib;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_1370 (struct lsquic_mm *mm, void *mem)
|
||||
lsquic_mm_put_packet_in_buf (struct lsquic_mm *mm, void *mem, size_t size)
|
||||
{
|
||||
struct payload_buf *pb = mem;
|
||||
SLIST_INSERT_HEAD(&mm->payload_bufs, pb, next_pb);
|
||||
#if LSQUIC_USE_POOLS
|
||||
unsigned idx;
|
||||
struct packet_in_buf *pib;
|
||||
|
||||
pib = (struct packet_in_buf *) mem;
|
||||
idx = packet_in_index(size);
|
||||
SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib);
|
||||
#else
|
||||
free(mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
lsquic_mm_get_4k (struct lsquic_mm *mm)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct four_k_page *fkp = SLIST_FIRST(&mm->four_k_pages);
|
||||
fiu_do_on("mm/4k", FAIL_NOMEM);
|
||||
if (fkp)
|
||||
|
@ -247,20 +491,28 @@ lsquic_mm_get_4k (struct lsquic_mm *mm)
|
|||
else
|
||||
fkp = malloc(0x1000);
|
||||
return fkp;
|
||||
#else
|
||||
return malloc(0x1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_4k (struct lsquic_mm *mm, void *mem)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct four_k_page *fkp = mem;
|
||||
SLIST_INSERT_HEAD(&mm->four_k_pages, fkp, next_fkp);
|
||||
#else
|
||||
free(mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
lsquic_mm_get_16k (struct lsquic_mm *mm)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct sixteen_k_page *skp = SLIST_FIRST(&mm->sixteen_k_pages);
|
||||
fiu_do_on("mm/16k", FAIL_NOMEM);
|
||||
if (skp)
|
||||
|
@ -268,33 +520,30 @@ lsquic_mm_get_16k (struct lsquic_mm *mm)
|
|||
else
|
||||
skp = malloc(16 * 1024);
|
||||
return skp;
|
||||
#else
|
||||
return malloc(16 * 1024);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_16k (struct lsquic_mm *mm, void *mem)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
struct sixteen_k_page *skp = mem;
|
||||
SLIST_INSERT_HEAD(&mm->sixteen_k_pages, skp, next_skp);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_mm_put_packet_in (struct lsquic_mm *mm,
|
||||
struct lsquic_packet_in *packet_in)
|
||||
{
|
||||
assert(0 == packet_in->pi_refcnt);
|
||||
if (packet_in->pi_flags & PI_OWN_DATA)
|
||||
lsquic_mm_put_1370(mm, packet_in->pi_data);
|
||||
TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next);
|
||||
#else
|
||||
free(mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
lsquic_mm_mem_used (const struct lsquic_mm *mm)
|
||||
{
|
||||
#if LSQUIC_USE_POOLS
|
||||
const struct packet_out_buf *pob;
|
||||
const struct payload_buf *pb;
|
||||
const struct packet_in_buf *pib;
|
||||
const struct four_k_page *fkp;
|
||||
const struct sixteen_k_page *skp;
|
||||
unsigned i;
|
||||
|
@ -304,6 +553,8 @@ lsquic_mm_mem_used (const struct lsquic_mm *mm)
|
|||
size += sizeof(*mm->acki);
|
||||
size += lsquic_malo_mem_used(mm->malo.stream_frame);
|
||||
size += lsquic_malo_mem_used(mm->malo.stream_rec_arr);
|
||||
size += lsquic_malo_mem_used(mm->malo.mini_conn);
|
||||
size += lsquic_malo_mem_used(mm->malo.mini_conn_ietf);
|
||||
size += lsquic_malo_mem_used(mm->malo.packet_in);
|
||||
size += lsquic_malo_mem_used(mm->malo.packet_out);
|
||||
|
||||
|
@ -311,8 +562,9 @@ lsquic_mm_mem_used (const struct lsquic_mm *mm)
|
|||
SLIST_FOREACH(pob, &mm->packet_out_bufs[i], next_pob)
|
||||
size += packet_out_sizes[i];
|
||||
|
||||
SLIST_FOREACH(pb, &mm->payload_bufs, next_pb)
|
||||
size += 1370;
|
||||
for (i = 0; i < MM_N_IN_BUCKETS; ++i)
|
||||
SLIST_FOREACH(pib, &mm->packet_in_bufs[i], next_pib)
|
||||
size += packet_in_sizes[i];
|
||||
|
||||
SLIST_FOREACH(fkp, &mm->four_k_pages, next_fkp)
|
||||
size += 0x1000;
|
||||
|
@ -321,4 +573,7 @@ lsquic_mm_mem_used (const struct lsquic_mm *mm)
|
|||
size += 0x4000;
|
||||
|
||||
return size;
|
||||
#else
|
||||
return sizeof(*mm);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -14,20 +14,38 @@ struct lsquic_packet_in;
|
|||
struct lsquic_packet_out;
|
||||
struct ack_info;
|
||||
struct malo;
|
||||
struct mini_conn;
|
||||
|
||||
#define MM_N_OUT_BUCKETS 3
|
||||
struct pool_stats
|
||||
{
|
||||
unsigned ps_calls; /* Calls to get/put */
|
||||
unsigned ps_max; /* Maximum during this sample period */
|
||||
unsigned ps_max_avg, /* Average maximum value */
|
||||
ps_max_var;
|
||||
unsigned ps_objs_all; /* Number of objects owned by the pool */
|
||||
unsigned ps_objs_out; /* Number of objects in use */
|
||||
};
|
||||
|
||||
#define MM_N_OUT_BUCKETS 5
|
||||
#define MM_N_IN_BUCKETS 3
|
||||
|
||||
struct lsquic_mm {
|
||||
struct ack_info *acki;
|
||||
struct {
|
||||
struct malo *stream_frame; /* For struct stream_frame */
|
||||
struct malo *stream_rec_arr;/* For struct stream_rec_arr */
|
||||
struct malo *mini_conn; /* For struct mini_conn */
|
||||
struct malo *mini_conn_ietf;/* For struct ietf_mini_conn */
|
||||
struct malo *retry_conn; /* For struct retry_conn */
|
||||
struct malo *packet_in; /* For struct lsquic_packet_in */
|
||||
struct malo *packet_out; /* For struct lsquic_packet_out */
|
||||
struct malo *dcid_elem; /* For struct dcid_elem */
|
||||
struct malo *stream_hq_frame; /* For struct stream_hq_frame */
|
||||
} malo;
|
||||
TAILQ_HEAD(, lsquic_packet_in) free_packets_in;
|
||||
SLIST_HEAD(, packet_out_buf) packet_out_bufs[MM_N_OUT_BUCKETS];
|
||||
SLIST_HEAD(, payload_buf) payload_bufs;
|
||||
struct pool_stats packet_out_bstats[MM_N_OUT_BUCKETS];
|
||||
SLIST_HEAD(, packet_in_buf) packet_in_bufs[MM_N_IN_BUCKETS];
|
||||
SLIST_HEAD(, four_k_page) four_k_pages;
|
||||
SLIST_HEAD(, sixteen_k_page) sixteen_k_pages;
|
||||
};
|
||||
|
@ -58,10 +76,10 @@ void
|
|||
lsquic_mm_put_packet_out (struct lsquic_mm *, struct lsquic_packet_out *);
|
||||
|
||||
void *
|
||||
lsquic_mm_get_1370 (struct lsquic_mm *);
|
||||
lsquic_mm_get_packet_in_buf (struct lsquic_mm *, size_t);
|
||||
|
||||
void
|
||||
lsquic_mm_put_1370 (struct lsquic_mm *, void *);
|
||||
lsquic_mm_put_packet_in_buf (struct lsquic_mm *, void *, size_t);
|
||||
|
||||
void *
|
||||
lsquic_mm_get_4k (struct lsquic_mm *);
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
#include "lsquic_int_types.h"
|
||||
#include "lsquic_pacer.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
#include "lsquic_packet_out.h"
|
||||
#include "lsquic_util.h"
|
||||
|
||||
#define LSQUIC_LOGGER_MODULE LSQLM_PACER
|
||||
#define LSQUIC_LOG_CONN_ID pacer->pa_cid
|
||||
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(pacer->pa_conn)
|
||||
#include "lsquic_logger.h"
|
||||
|
||||
#ifndef MAX
|
||||
|
@ -24,11 +25,12 @@
|
|||
|
||||
|
||||
void
|
||||
pacer_init (struct pacer *pacer, lsquic_cid_t cid, unsigned clock_granularity)
|
||||
pacer_init (struct pacer *pacer, const struct lsquic_conn *conn,
|
||||
unsigned clock_granularity)
|
||||
{
|
||||
memset(pacer, 0, sizeof(*pacer));
|
||||
pacer->pa_burst_tokens = 10;
|
||||
pacer->pa_cid = cid;
|
||||
pacer->pa_conn = conn;
|
||||
pacer->pa_clock_granularity = clock_granularity;
|
||||
}
|
||||
|
||||
|
@ -52,6 +54,7 @@ pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
|
|||
#ifndef NDEBUG
|
||||
++pacer->pa_stats.n_scheduled;
|
||||
#endif
|
||||
++pacer->pa_n_scheduled;
|
||||
|
||||
if (n_in_flight == 0 && !in_recovery)
|
||||
{
|
||||
|
@ -90,7 +93,7 @@ pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
|
|||
pacer->pa_next_sched = MAX(pacer->pa_next_sched + delay,
|
||||
sched_time + delay);
|
||||
LSQ_DEBUG("next_sched is set to %"PRIu64" usec from now",
|
||||
pacer->pa_next_sched - lsquic_time_now());
|
||||
pacer->pa_next_sched - pacer->pa_now);
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,8 +126,25 @@ pacer_can_schedule (struct pacer *pacer, unsigned n_in_flight)
|
|||
|
||||
|
||||
void
|
||||
pacer_tick (struct pacer *pacer, lsquic_time_t now)
|
||||
pacer_tick_in (struct pacer *pacer, lsquic_time_t now)
|
||||
{
|
||||
assert(now >= pacer->pa_now);
|
||||
pacer->pa_now = now;
|
||||
if (pacer->pa_flags & PA_LAST_SCHED_DELAYED)
|
||||
pacer->pa_flags |= PA_DELAYED_ON_TICK_IN;
|
||||
pacer->pa_n_scheduled = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pacer_tick_out (struct pacer *pacer)
|
||||
{
|
||||
if ((pacer->pa_flags & PA_DELAYED_ON_TICK_IN)
|
||||
&& pacer->pa_n_scheduled == 0
|
||||
&& pacer->pa_now > pacer->pa_next_sched)
|
||||
{
|
||||
LSQ_DEBUG("tick passed without scheduled packets: reset delayed flag");
|
||||
pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED;
|
||||
}
|
||||
pacer->pa_flags &= ~PA_DELAYED_ON_TICK_IN;
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
#ifndef LSQUIC_PACER_H
|
||||
#define LSQUIC_PACER_H 1
|
||||
|
||||
struct lsquic_conn;
|
||||
|
||||
struct pacer
|
||||
{
|
||||
lsquic_cid_t pa_cid; /* Used for logging */
|
||||
const struct lsquic_conn
|
||||
*pa_conn; /* Used for logging */
|
||||
lsquic_time_t pa_next_sched;
|
||||
lsquic_time_t pa_last_delayed;
|
||||
lsquic_time_t pa_now;
|
||||
|
@ -14,8 +17,10 @@ struct pacer
|
|||
unsigned pa_clock_granularity;
|
||||
|
||||
unsigned pa_burst_tokens;
|
||||
unsigned pa_n_scheduled; /* Within single tick */
|
||||
enum {
|
||||
PA_LAST_SCHED_DELAYED = (1 << 0),
|
||||
PA_DELAYED_ON_TICK_IN = (1 << 1),
|
||||
} pa_flags;
|
||||
#ifndef NDEBUG
|
||||
struct {
|
||||
|
@ -28,13 +33,17 @@ struct pacer
|
|||
typedef lsquic_time_t (*tx_time_f)(void *ctx);
|
||||
|
||||
void
|
||||
pacer_init (struct pacer *, lsquic_cid_t, unsigned clock_granularity);
|
||||
pacer_init (struct pacer *, const struct lsquic_conn *,
|
||||
unsigned clock_granularity);
|
||||
|
||||
void
|
||||
pacer_cleanup (struct pacer *);
|
||||
|
||||
void
|
||||
pacer_tick (struct pacer *, lsquic_time_t);
|
||||
pacer_tick_in (struct pacer *, lsquic_time_t);
|
||||
|
||||
void
|
||||
pacer_tick_out (struct pacer *);
|
||||
|
||||
int
|
||||
pacer_can_schedule (struct pacer *, unsigned n_in_flight);
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
* lsquic_packet_common.c -- some common packet-related routines
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "lsquic.h"
|
||||
#include "lsquic_types.h"
|
||||
#include "lsquic_logger.h"
|
||||
#include "lsquic_enc_sess.h"
|
||||
#include "lsquic_packet_common.h"
|
||||
|
||||
|
||||
|
@ -43,52 +47,6 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz,
|
|||
}
|
||||
|
||||
|
||||
enum packno_bits
|
||||
calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
|
||||
uint64_t n_in_flight)
|
||||
{
|
||||
uint64_t delta;
|
||||
unsigned bits;
|
||||
|
||||
delta = packno - least_unacked;
|
||||
if (n_in_flight > delta)
|
||||
delta = n_in_flight;
|
||||
|
||||
delta *= 4;
|
||||
bits = (delta > (1ULL << 8))
|
||||
+ (delta > (1ULL << 16))
|
||||
+ (delta > (1ULL << 32));
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
lsquic_packno_t
|
||||
restore_packno (lsquic_packno_t cur_packno,
|
||||
unsigned len,
|
||||
lsquic_packno_t max_packno)
|
||||
{
|
||||
lsquic_packno_t candidates[3], epoch_delta;
|
||||
int64_t diffs[3];
|
||||
unsigned min;
|
||||
|
||||
epoch_delta = 1ULL << (len << 3);
|
||||
candidates[1] = (max_packno & ~(epoch_delta - 1)) + cur_packno;
|
||||
candidates[0] = candidates[1] - epoch_delta;
|
||||
candidates[2] = candidates[1] + epoch_delta;
|
||||
|
||||
diffs[0] = llabs((int64_t) candidates[0] - (int64_t) max_packno);
|
||||
diffs[1] = llabs((int64_t) candidates[1] - (int64_t) max_packno);
|
||||
diffs[2] = llabs((int64_t) candidates[2] - (int64_t) max_packno);
|
||||
|
||||
min = diffs[1] < diffs[0];
|
||||
if (diffs[2] < diffs[min])
|
||||
min = 2;
|
||||
|
||||
return candidates[min];
|
||||
}
|
||||
|
||||
|
||||
const char *const lsquic_hety2str[] =
|
||||
{
|
||||
[HETY_NOT_SET] = "Short",
|
||||
|
@ -98,3 +56,33 @@ const char *const lsquic_hety2str[] =
|
|||
[HETY_HANDSHAKE] = "Handshake",
|
||||
[HETY_0RTT] = "0-RTT",
|
||||
};
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-14], Section 4 */
|
||||
const enum packnum_space lsquic_hety2pns[] =
|
||||
{
|
||||
[HETY_NOT_SET] = PNS_APP,
|
||||
[HETY_VERNEG] = 0,
|
||||
[HETY_INITIAL] = PNS_INIT,
|
||||
[HETY_RETRY] = 0,
|
||||
[HETY_HANDSHAKE] = PNS_HSK,
|
||||
[HETY_0RTT] = PNS_APP,
|
||||
};
|
||||
|
||||
|
||||
/* [draft-ietf-quic-tls-14], Section 4 */
|
||||
const enum packnum_space lsquic_enclev2pns[] =
|
||||
{
|
||||
[ENC_LEV_CLEAR] = PNS_INIT,
|
||||
[ENC_LEV_INIT] = PNS_HSK,
|
||||
[ENC_LEV_EARLY] = PNS_APP,
|
||||
[ENC_LEV_FORW] = PNS_APP,
|
||||
};
|
||||
|
||||
|
||||
const char *const lsquic_pns2str[] =
|
||||
{
|
||||
[PNS_INIT] = "Init PNS",
|
||||
[PNS_HSK] = "Handshake PNS",
|
||||
[PNS_APP] = "App PNS",
|
||||
};
|
||||
|
|
|
@ -2,52 +2,64 @@
|
|||
#ifndef LSQUIC_PACKET_COMMON_H
|
||||
#define LSQUIC_PACKET_COMMON_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
|
||||
enum PACKET_PUBLIC_FLAGS
|
||||
{
|
||||
PACKET_PUBLIC_FLAGS_VERSION = 1,
|
||||
PACKET_PUBLIC_FLAGS_RST = 2,
|
||||
PACKET_PUBLIC_FLAGS_NONCE = 4,
|
||||
PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID = 8,
|
||||
PACKET_PUBLIC_FLAGS_MULTIPATH = 1 << 6,
|
||||
PACKET_PUBLIC_FLAGS_TWO_OR_MORE_BYTES = 1 << 7,
|
||||
};
|
||||
|
||||
/* The list of frames contains frames both in GQUIC and in IETF QUIC.
|
||||
* They are marked as follows:
|
||||
* G Applicable to GQUIC only
|
||||
* I Applicable to IETF QUIC only
|
||||
* B Applicable to both GQUIC and IETF QUIC.
|
||||
*/
|
||||
enum quic_frame_type
|
||||
{
|
||||
QUIC_FRAME_INVALID,
|
||||
|
||||
/*Special*/
|
||||
QUIC_FRAME_STREAM,
|
||||
QUIC_FRAME_ACK,
|
||||
|
||||
/*Regular*/
|
||||
QUIC_FRAME_PADDING,
|
||||
QUIC_FRAME_RST_STREAM,
|
||||
QUIC_FRAME_CONNECTION_CLOSE,
|
||||
QUIC_FRAME_GOAWAY,
|
||||
QUIC_FRAME_WINDOW_UPDATE,
|
||||
QUIC_FRAME_BLOCKED,
|
||||
QUIC_FRAME_STOP_WAITING,
|
||||
QUIC_FRAME_PING,
|
||||
QUIC_FRAME_STREAM, /* B */
|
||||
QUIC_FRAME_ACK, /* B */
|
||||
QUIC_FRAME_PADDING, /* B */
|
||||
QUIC_FRAME_RST_STREAM, /* B */
|
||||
QUIC_FRAME_CONNECTION_CLOSE, /* B */
|
||||
QUIC_FRAME_GOAWAY, /* G */
|
||||
QUIC_FRAME_WINDOW_UPDATE, /* G */
|
||||
QUIC_FRAME_BLOCKED, /* B */
|
||||
QUIC_FRAME_STOP_WAITING, /* G */
|
||||
QUIC_FRAME_PING, /* B */
|
||||
QUIC_FRAME_MAX_DATA, /* I */
|
||||
QUIC_FRAME_MAX_STREAM_DATA, /* I */
|
||||
QUIC_FRAME_MAX_STREAMS, /* I */
|
||||
QUIC_FRAME_STREAM_BLOCKED, /* I */
|
||||
QUIC_FRAME_STREAMS_BLOCKED, /* I */
|
||||
QUIC_FRAME_NEW_CONNECTION_ID, /* I */
|
||||
QUIC_FRAME_STOP_SENDING, /* I */
|
||||
QUIC_FRAME_PATH_CHALLENGE, /* I */
|
||||
QUIC_FRAME_PATH_RESPONSE, /* I */
|
||||
QUIC_FRAME_CRYPTO, /* I */
|
||||
QUIC_FRAME_RETIRE_CONNECTION_ID,/* I */
|
||||
QUIC_FRAME_NEW_TOKEN, /* I */
|
||||
N_QUIC_FRAMES
|
||||
};
|
||||
|
||||
enum quic_ft_bit {
|
||||
QUIC_FTBIT_INVALID = 1 << QUIC_FRAME_INVALID,
|
||||
QUIC_FTBIT_STREAM = 1 << QUIC_FRAME_STREAM,
|
||||
QUIC_FTBIT_ACK = 1 << QUIC_FRAME_ACK,
|
||||
QUIC_FTBIT_PADDING = 1 << QUIC_FRAME_PADDING,
|
||||
QUIC_FTBIT_RST_STREAM = 1 << QUIC_FRAME_RST_STREAM,
|
||||
QUIC_FTBIT_CONNECTION_CLOSE = 1 << QUIC_FRAME_CONNECTION_CLOSE,
|
||||
QUIC_FTBIT_GOAWAY = 1 << QUIC_FRAME_GOAWAY,
|
||||
QUIC_FTBIT_WINDOW_UPDATE = 1 << QUIC_FRAME_WINDOW_UPDATE,
|
||||
QUIC_FTBIT_BLOCKED = 1 << QUIC_FRAME_BLOCKED,
|
||||
QUIC_FTBIT_STOP_WAITING = 1 << QUIC_FRAME_STOP_WAITING,
|
||||
QUIC_FTBIT_PING = 1 << QUIC_FRAME_PING,
|
||||
QUIC_FTBIT_INVALID = 1 << QUIC_FRAME_INVALID,
|
||||
QUIC_FTBIT_STREAM = 1 << QUIC_FRAME_STREAM,
|
||||
QUIC_FTBIT_ACK = 1 << QUIC_FRAME_ACK,
|
||||
QUIC_FTBIT_PADDING = 1 << QUIC_FRAME_PADDING,
|
||||
QUIC_FTBIT_RST_STREAM = 1 << QUIC_FRAME_RST_STREAM,
|
||||
QUIC_FTBIT_CONNECTION_CLOSE = 1 << QUIC_FRAME_CONNECTION_CLOSE,
|
||||
QUIC_FTBIT_GOAWAY = 1 << QUIC_FRAME_GOAWAY,
|
||||
QUIC_FTBIT_WINDOW_UPDATE = 1 << QUIC_FRAME_WINDOW_UPDATE,
|
||||
QUIC_FTBIT_BLOCKED = 1 << QUIC_FRAME_BLOCKED,
|
||||
QUIC_FTBIT_STOP_WAITING = 1 << QUIC_FRAME_STOP_WAITING,
|
||||
QUIC_FTBIT_PING = 1 << QUIC_FRAME_PING,
|
||||
QUIC_FTBIT_MAX_DATA = 1 << QUIC_FRAME_MAX_DATA,
|
||||
QUIC_FTBIT_MAX_STREAM_DATA = 1 << QUIC_FRAME_MAX_STREAM_DATA,
|
||||
QUIC_FTBIT_MAX_STREAMS = 1 << QUIC_FRAME_MAX_STREAMS,
|
||||
QUIC_FTBIT_STREAM_BLOCKED = 1 << QUIC_FRAME_STREAM_BLOCKED,
|
||||
QUIC_FTBIT_STREAMS_BLOCKED = 1 << QUIC_FRAME_STREAMS_BLOCKED,
|
||||
QUIC_FTBIT_NEW_CONNECTION_ID = 1 << QUIC_FRAME_NEW_CONNECTION_ID,
|
||||
QUIC_FTBIT_STOP_SENDING = 1 << QUIC_FRAME_STOP_SENDING,
|
||||
QUIC_FTBIT_PATH_CHALLENGE = 1 << QUIC_FRAME_PATH_CHALLENGE,
|
||||
QUIC_FTBIT_PATH_RESPONSE = 1 << QUIC_FRAME_PATH_RESPONSE,
|
||||
QUIC_FTBIT_CRYPTO = 1 << QUIC_FRAME_CRYPTO,
|
||||
QUIC_FTBIT_NEW_TOKEN = 1 << QUIC_FRAME_NEW_TOKEN,
|
||||
QUIC_FTBIT_RETIRE_CONNECTION_ID = 1 << QUIC_FRAME_RETIRE_CONNECTION_ID,
|
||||
};
|
||||
|
||||
static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
|
||||
|
@ -62,6 +74,18 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
|
|||
[QUIC_FRAME_BLOCKED] = "QUIC_FRAME_BLOCKED",
|
||||
[QUIC_FRAME_STOP_WAITING] = "QUIC_FRAME_STOP_WAITING",
|
||||
[QUIC_FRAME_PING] = "QUIC_FRAME_PING",
|
||||
[QUIC_FRAME_MAX_DATA] = "QUIC_FRAME_MAX_DATA",
|
||||
[QUIC_FRAME_MAX_STREAM_DATA] = "QUIC_FRAME_MAX_STREAM_DATA",
|
||||
[QUIC_FRAME_MAX_STREAMS] = "QUIC_FRAME_MAX_STREAMS",
|
||||
[QUIC_FRAME_STREAM_BLOCKED] = "QUIC_FRAME_STREAM_BLOCKED",
|
||||
[QUIC_FRAME_STREAMS_BLOCKED] = "QUIC_FRAME_STREAMS_BLOCKED",
|
||||
[QUIC_FRAME_NEW_CONNECTION_ID] = "QUIC_FRAME_NEW_CONNECTION_ID",
|
||||
[QUIC_FRAME_STOP_SENDING] = "QUIC_FRAME_STOP_SENDING",
|
||||
[QUIC_FRAME_PATH_CHALLENGE] = "QUIC_FRAME_PATH_CHALLENGE",
|
||||
[QUIC_FRAME_PATH_RESPONSE] = "QUIC_FRAME_PATH_RESPONSE",
|
||||
[QUIC_FRAME_CRYPTO] = "QUIC_FRAME_CRYPTO",
|
||||
[QUIC_FRAME_NEW_TOKEN] = "QUIC_FRAME_NEW_TOKEN",
|
||||
[QUIC_FRAME_RETIRE_CONNECTION_ID] = "QUIC_FRAME_RETIRE_CONNECTION_ID",
|
||||
};
|
||||
|
||||
#define QUIC_FRAME_PRELEN (sizeof("QUIC_FRAME_"))
|
||||
|
@ -73,92 +97,35 @@ static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
|
|||
* never a part of any frame list bitmask (e.g. po_frame_types).
|
||||
*/
|
||||
#define lsquic_frame_types_str_sz \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STREAM) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_ACK) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PADDING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_RST_STREAM) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_CONNECTION_CLOSE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_GOAWAY) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_WINDOW_UPDATE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_BLOCKED) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STOP_WAITING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PING) + 1
|
||||
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STREAM) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_ACK) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PADDING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_RST_STREAM) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_CONNECTION_CLOSE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_GOAWAY) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_WINDOW_UPDATE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_BLOCKED) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STOP_WAITING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_MAX_DATA) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_MAX_STREAM_DATA) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_MAX_STREAMS) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STREAM_BLOCKED) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STREAMS_BLOCKED) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_NEW_CONNECTION_ID) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_STOP_SENDING) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PATH_CHALLENGE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_PATH_RESPONSE) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_CRYPTO) + 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_RETIRE_CONNECTION_ID) \
|
||||
+ 1 + \
|
||||
QUIC_FRAME_SLEN(QUIC_FRAME_NEW_TOKEN) + 1 + \
|
||||
0
|
||||
|
||||
|
||||
const char *
|
||||
lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit);
|
||||
|
||||
#define QFRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \
|
||||
| (1 << QUIC_FRAME_STOP_WAITING))
|
||||
|
||||
#define QFRAME_REGENERATE(frame_type) ((1 << (frame_type)) & QFRAME_REGEN_MASK)
|
||||
|
||||
#define QFRAME_ACKABLE_MASK ( \
|
||||
(1 << QUIC_FRAME_STREAM) \
|
||||
| (1 << QUIC_FRAME_RST_STREAM) \
|
||||
| (1 << QUIC_FRAME_GOAWAY) \
|
||||
| (1 << QUIC_FRAME_WINDOW_UPDATE) \
|
||||
| (1 << QUIC_FRAME_PING) \
|
||||
| (1 << QUIC_FRAME_BLOCKED) \
|
||||
)
|
||||
|
||||
#define QFRAME_ACKABLE(frame_type) ((1 << (frame_type)) & QFRAME_ACKABLE_MASK)
|
||||
|
||||
#define QFRAME_RETRANSMITTABLE_MASK ( \
|
||||
(1 << QUIC_FRAME_STREAM) \
|
||||
| (1 << QUIC_FRAME_RST_STREAM) \
|
||||
| (1 << QUIC_FRAME_GOAWAY) \
|
||||
| (1 << QUIC_FRAME_WINDOW_UPDATE) \
|
||||
| (1 << QUIC_FRAME_BLOCKED) \
|
||||
| (1 << QUIC_FRAME_CONNECTION_CLOSE) \
|
||||
)
|
||||
|
||||
#define QFRAME_RETRANSMITTABLE(frame_type) \
|
||||
((1 << (frame_type)) & QFRAME_RETRANSMITTABLE_MASK)
|
||||
|
||||
#define GQUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \
|
||||
+ 32 /* Nonce */ + 6 /* Packet Number */ )
|
||||
|
||||
#define GQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */)
|
||||
|
||||
#define GQUIC_IETF_LONG_HEADER_SIZE (1 /* Type */ + 4 /* Version */ \
|
||||
+ 1 /* DCIL/SCIL */ + 8 /* CID */ + 4 /* Packet number */)
|
||||
|
||||
/* XXX Nonce? */
|
||||
#define IQUIC_MAX_PUBHDR_SZ GQUIC_IETF_LONG_HEADER_SIZE
|
||||
|
||||
#define IQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ \
|
||||
+ 1 /* Packet number */)
|
||||
|
||||
#define QUIC_MAX_PUBHDR_SZ (GQUIC_MAX_PUBHDR_SZ > IQUIC_MAX_PUBHDR_SZ \
|
||||
? GQUIC_MAX_PUBHDR_SZ : IQUIC_MAX_PUBHDR_SZ)
|
||||
|
||||
#define QUIC_MIN_PUBHDR_SZ (GQUIC_MIN_PUBHDR_SZ < IQUIC_MIN_PUBHDR_SZ \
|
||||
? GQUIC_MIN_PUBHDR_SZ : IQUIC_MIN_PUBHDR_SZ)
|
||||
|
||||
/* 12 bytes of FNV hash or encryption IV */
|
||||
#define QUIC_PACKET_HASH_SZ 12
|
||||
|
||||
/* [draft-hamilton-quic-transport-protocol-01], Section 7 */
|
||||
#define QUIC_MAX_IPv4_PACKET_SZ 1370
|
||||
#define QUIC_MAX_IPv6_PACKET_SZ 1350
|
||||
|
||||
#define QUIC_MAX_PACKET_SZ (QUIC_MAX_IPv4_PACKET_SZ > \
|
||||
QUIC_MAX_IPv6_PACKET_SZ ? QUIC_MAX_IPv4_PACKET_SZ : QUIC_MAX_IPv6_PACKET_SZ)
|
||||
|
||||
#define QUIC_MIN_PACKET_OVERHEAD (QUIC_PACKET_HASH_SZ + QUIC_MIN_PUBHDR_SZ)
|
||||
|
||||
#define QUIC_MAX_PAYLOAD_SZ (QUIC_MAX_PACKET_SZ - QUIC_MIN_PACKET_OVERHEAD)
|
||||
|
||||
#define QUIC_WUF_SZ 13 /* Type (1) + Stream ID (4) + Offset (8) */
|
||||
#define QUIC_BLOCKED_FRAME_SZ 5 /* Type (1) + Stream ID (4) */
|
||||
#define QUIC_RST_STREAM_SZ 17 /* Type (1) + Stream ID (4) + Offset (8) +
|
||||
Error code (4) */
|
||||
#define QUIC_GOAWAY_FRAME_SZ 11 /* Type (1) + Error code (4) + Stream ID (4) +
|
||||
Reason phrase length (2) */
|
||||
|
||||
|
||||
/* This value represents a different number of bytes used to encode the packet
|
||||
* length based on whether GQUIC or IQUIC is used.
|
||||
*/
|
||||
|
@ -203,15 +170,58 @@ enum header_type
|
|||
|
||||
extern const char *const lsquic_hety2str[];
|
||||
|
||||
enum packno_bits
|
||||
calc_packno_bits (lsquic_packno_t packno, lsquic_packno_t least_unacked,
|
||||
uint64_t n_in_flight);
|
||||
#define IQUIC_MAX_PACKNO ((1ULL << 62) - 1)
|
||||
#define IQUIC_INVALID_PACKNO (IQUIC_MAX_PACKNO + 1)
|
||||
|
||||
#define gquic_packno_bits2len(b) (((b) << 1) + !(b))
|
||||
/* IETF QUIC only: */
|
||||
#define is_valid_packno(packno) ((packno) <= IQUIC_MAX_PACKNO)
|
||||
|
||||
lsquic_packno_t
|
||||
restore_packno (lsquic_packno_t cur_packno,
|
||||
unsigned packet_len,
|
||||
lsquic_packno_t max_packno);
|
||||
enum packnum_space
|
||||
{
|
||||
PNS_INIT,
|
||||
PNS_HSK,
|
||||
PNS_APP,
|
||||
N_PNS
|
||||
};
|
||||
|
||||
extern const enum packnum_space lsquic_hety2pns[];
|
||||
extern const enum packnum_space lsquic_enclev2pns[];
|
||||
extern const char *const lsquic_pns2str[];
|
||||
|
||||
#define ALL_IQUIC_FRAMES ( \
|
||||
QUIC_FTBIT_STREAM \
|
||||
| QUIC_FTBIT_ACK \
|
||||
| QUIC_FTBIT_PADDING \
|
||||
| QUIC_FTBIT_RST_STREAM \
|
||||
| QUIC_FTBIT_CONNECTION_CLOSE \
|
||||
| QUIC_FTBIT_BLOCKED \
|
||||
| QUIC_FTBIT_PING \
|
||||
| QUIC_FTBIT_MAX_DATA \
|
||||
| QUIC_FTBIT_MAX_STREAM_DATA \
|
||||
| QUIC_FTBIT_MAX_STREAMS \
|
||||
| QUIC_FTBIT_STREAM_BLOCKED \
|
||||
| QUIC_FTBIT_STREAMS_BLOCKED \
|
||||
| QUIC_FTBIT_NEW_CONNECTION_ID \
|
||||
| QUIC_FTBIT_STOP_SENDING \
|
||||
| QUIC_FTBIT_PATH_CHALLENGE \
|
||||
| QUIC_FTBIT_PATH_RESPONSE \
|
||||
| QUIC_FTBIT_RETIRE_CONNECTION_ID \
|
||||
| QUIC_FTBIT_NEW_TOKEN \
|
||||
| QUIC_FTBIT_CRYPTO )
|
||||
|
||||
/* [draft-ietf-quic-transport-20] Section 13.1.1 */
|
||||
#define IQUIC_FRAME_ACKABLE_MASK ( \
|
||||
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_ACK|QUIC_FTBIT_PADDING))
|
||||
|
||||
/* [draft-ietf-quic-transport-20], Section 13.2 */
|
||||
/* We bend some rules and retransmit BLOCKED, MAX_DATA, MAX_STREAM_DATA,
|
||||
* MAX_STREAMS, STREAM_BLOCKED, and STREAMS_BLOCKED frames instead of
|
||||
* regenerating them. This keeps the code simple(r).
|
||||
*/
|
||||
#define IQUIC_FRAME_RETX_MASK ( \
|
||||
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \
|
||||
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK))
|
||||
|
||||
extern const enum quic_ft_bit lsquic_legal_frames_by_level[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lsquic_packet_common.h"
|
||||
#include "lsquic_packet_gquic.h"
|
||||
|
||||
|
||||
|
||||
lsquic_packno_t
|
||||
restore_packno (lsquic_packno_t cur_packno,
|
||||
unsigned len,
|
||||
lsquic_packno_t max_packno)
|
||||
{
|
||||
lsquic_packno_t candidates[3], epoch_delta;
|
||||
int64_t diffs[3];
|
||||
unsigned min;
|
||||
|
||||
epoch_delta = 1ULL << (len << 3);
|
||||
candidates[1] = (max_packno & ~(epoch_delta - 1)) + cur_packno;
|
||||
candidates[0] = candidates[1] - epoch_delta;
|
||||
candidates[2] = candidates[1] + epoch_delta;
|
||||
|
||||
diffs[0] = llabs((int64_t) candidates[0] - (int64_t) max_packno);
|
||||
diffs[1] = llabs((int64_t) candidates[1] - (int64_t) max_packno);
|
||||
diffs[2] = llabs((int64_t) candidates[2] - (int64_t) max_packno);
|
||||
|
||||
min = diffs[1] < diffs[0];
|
||||
if (diffs[2] < diffs[min])
|
||||
min = 2;
|
||||
|
||||
return candidates[min];
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_PACKET_GQUIC_H
|
||||
#define LSQUIC_PACKET_GQUIC_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lsquic_int_types.h"
|
||||
|
||||
enum PACKET_PUBLIC_FLAGS
|
||||
{
|
||||
PACKET_PUBLIC_FLAGS_VERSION = 1,
|
||||
PACKET_PUBLIC_FLAGS_RST = 2,
|
||||
PACKET_PUBLIC_FLAGS_NONCE = 4,
|
||||
PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID = 8,
|
||||
PACKET_PUBLIC_FLAGS_MULTIPATH = 1 << 6,
|
||||
PACKET_PUBLIC_FLAGS_TWO_OR_MORE_BYTES = 1 << 7,
|
||||
};
|
||||
|
||||
#define GQUIC_FRAME_REGEN_MASK ((1 << QUIC_FRAME_ACK) \
|
||||
| (1 << QUIC_FRAME_PATH_CHALLENGE) | (1 << QUIC_FRAME_PATH_RESPONSE) \
|
||||
| (1 << QUIC_FRAME_STOP_WAITING))
|
||||
|
||||
#define GQUIC_FRAME_REGENERATE(frame_type) ((1 << (frame_type)) & GQUIC_FRAME_REGEN_MASK)
|
||||
|
||||
#define GQUIC_FRAME_ACKABLE_MASK ( \
|
||||
(1 << QUIC_FRAME_STREAM) \
|
||||
| (1 << QUIC_FRAME_RST_STREAM) \
|
||||
| (1 << QUIC_FRAME_GOAWAY) \
|
||||
| (1 << QUIC_FRAME_WINDOW_UPDATE) \
|
||||
| (1 << QUIC_FRAME_PING) \
|
||||
| (1 << QUIC_FRAME_BLOCKED) \
|
||||
| (1 << QUIC_FRAME_CRYPTO) \
|
||||
)
|
||||
|
||||
#define GQUIC_FRAME_ACKABLE(frame_type) ((1 << (frame_type)) & GQUIC_FRAME_ACKABLE_MASK)
|
||||
|
||||
#define GQUIC_FRAME_RETRANSMITTABLE_MASK ( \
|
||||
(1 << QUIC_FRAME_STREAM) \
|
||||
| (1 << QUIC_FRAME_RST_STREAM) \
|
||||
| (1 << QUIC_FRAME_GOAWAY) \
|
||||
| (1 << QUIC_FRAME_WINDOW_UPDATE) \
|
||||
| (1 << QUIC_FRAME_BLOCKED) \
|
||||
| (1 << QUIC_FRAME_CONNECTION_CLOSE) \
|
||||
| (1 << QUIC_FRAME_CRYPTO) \
|
||||
| (1 << QUIC_FRAME_PING) \
|
||||
)
|
||||
|
||||
#define GQUIC_FRAME_RETRANSMITTABLE(frame_type) \
|
||||
((1 << (frame_type)) & GQUIC_FRAME_RETRANSMITTABLE_MASK)
|
||||
|
||||
#define GQUIC_MAX_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ + 4 /* Version */ \
|
||||
+ 32 /* Nonce */ + 6 /* Packet Number */ )
|
||||
|
||||
#define GQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 1 /* Packet number */)
|
||||
|
||||
#define GQUIC_IETF_LONG_HEADER_SIZE (1 /* Type */ + 4 /* Version */ \
|
||||
+ 1 /* DCIL/SCIL */ + 8 /* CID */ + 4 /* Packet number */)
|
||||
|
||||
/* XXX Nonce? */
|
||||
#define IQUIC_MAX_PUBHDR_SZ GQUIC_IETF_LONG_HEADER_SIZE
|
||||
|
||||
#define IQUIC_MIN_PUBHDR_SZ (1 /* Type */ + 8 /* CID */ \
|
||||
+ 1 /* Packet number */)
|
||||
|
||||
#define QUIC_MAX_PUBHDR_SZ (GQUIC_MAX_PUBHDR_SZ > IQUIC_MAX_PUBHDR_SZ \
|
||||
? GQUIC_MAX_PUBHDR_SZ : IQUIC_MAX_PUBHDR_SZ)
|
||||
|
||||
#define QUIC_MIN_PUBHDR_SZ (GQUIC_MIN_PUBHDR_SZ < IQUIC_MIN_PUBHDR_SZ \
|
||||
? GQUIC_MIN_PUBHDR_SZ : IQUIC_MIN_PUBHDR_SZ)
|
||||
|
||||
/* 12 bytes of FNV hash or encryption IV */
|
||||
#define GQUIC_PACKET_HASH_SZ 12
|
||||
|
||||
/* [draft-hamilton-quic-transport-protocol-01], Section 7 */
|
||||
#define GQUIC_MAX_IPv4_PACKET_SZ 1370
|
||||
#define GQUIC_MAX_IPv6_PACKET_SZ 1350
|
||||
|
||||
#define GQUIC_MAX_PACKET_SZ (GQUIC_MAX_IPv4_PACKET_SZ > \
|
||||
GQUIC_MAX_IPv6_PACKET_SZ ? GQUIC_MAX_IPv4_PACKET_SZ : GQUIC_MAX_IPv6_PACKET_SZ)
|
||||
|
||||
#define GQUIC_MIN_PACKET_OVERHEAD (GQUIC_PACKET_HASH_SZ + GQUIC_MIN_PUBHDR_SZ)
|
||||
|
||||
#define GQUIC_MAX_PAYLOAD_SZ (GQUIC_MAX_PACKET_SZ - GQUIC_MIN_PACKET_OVERHEAD)
|
||||
|
||||
#define GQUIC_WUF_SZ 13 /* Type (1) + Stream ID (4) + Offset (8) */
|
||||
#define GQUIC_BLOCKED_FRAME_SZ 5 /* Type (1) + Stream ID (4) */
|
||||
#define GQUIC_RST_STREAM_SZ 17 /* Type (1) + Stream ID (4) + Offset (8) +
|
||||
Error code (4) */
|
||||
#define GQUIC_GOAWAY_FRAME_SZ 11 /* Type (1) + Error code (4) + Stream ID (4) +
|
||||
Reason phrase length (2) */
|
||||
|
||||
#define gquic_packno_bits2len(b) (((b) << 1) + !(b))
|
||||
|
||||
lsquic_packno_t
|
||||
restore_packno (lsquic_packno_t cur_packno,
|
||||
unsigned packet_len,
|
||||
lsquic_packno_t max_packno);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
||||
#ifndef LSQUIC_PACKET_IETF_H
|
||||
#define LSQUIC_PACKET_IETF_H 1
|
||||
|
||||
#define IQUIC_MAX_IPv4_PACKET_SZ 1252
|
||||
#define IQUIC_MAX_IPv6_PACKET_SZ 1232
|
||||
|
||||
#define iquic_packno_bits2len(b) ((b) + 1)
|
||||
|
||||
/* [draft-ietf-quic-transport-22] Section 7.2:
|
||||
"
|
||||
When an Initial packet is sent by a client that has not previously
|
||||
received an Initial or Retry packet from the server, it populates the
|
||||
Destination Connection ID field with an unpredictable value. This
|
||||
MUST be at least 8 bytes in length.
|
||||
"
|
||||
* Because the server always generates 8-byte CIDs, the DCID length cannot be
|
||||
* smaller than 8 even if the client received an Initial or Retry packet from
|
||||
* us.
|
||||
*/
|
||||
#define MIN_INITIAL_DCID_LEN 8
|
||||
|
||||
#endif
|
|
@ -52,3 +52,12 @@ lsquic_packet_in_mem_used (const struct lsquic_packet_in *packet_in)
|
|||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
lsquic_scid_from_packet_in (const struct lsquic_packet_in *packet_in,
|
||||
lsquic_cid_t *scid)
|
||||
{
|
||||
scid->len = packet_in->pi_scid_len;
|
||||
memcpy(scid->idbuf, packet_in->pi_data + packet_in->pi_scid_off, scid->len);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
#ifndef LSQUIC_PACKET_IN_H
|
||||
#define LSQUIC_PACKET_IN_H 1
|
||||
|
||||
|
||||
struct lsquic_packet_in;
|
||||
struct lsquic_cid;
|
||||
|
||||
|
||||
struct data_frame
|
||||
{
|
||||
|
@ -17,6 +20,7 @@ struct data_frame
|
|||
signed char df_fin; /* FIN? */
|
||||
};
|
||||
|
||||
|
||||
typedef struct stream_frame
|
||||
{
|
||||
/* Stream frames are stored in a list inside stream. */
|
||||
|
@ -31,47 +35,74 @@ typedef struct stream_frame
|
|||
|
||||
struct data_frame data_frame;
|
||||
|
||||
uint32_t stream_id; /* Parsed from packet */
|
||||
lsquic_stream_id_t stream_id; /* Parsed from packet */
|
||||
} stream_frame_t;
|
||||
|
||||
|
||||
#define DF_OFF(frame) (frame)->data_frame.df_offset
|
||||
#define DF_ROFF(frame) (DF_OFF(frame) + (frame)->data_frame.df_read_off)
|
||||
#define DF_FIN(frame) (frame)->data_frame.df_fin
|
||||
#define DF_SIZE(frame) (frame)->data_frame.df_size
|
||||
#define DF_END(frame) (DF_OFF(frame) + DF_SIZE(frame))
|
||||
|
||||
|
||||
typedef struct lsquic_packet_in
|
||||
{
|
||||
TAILQ_ENTRY(lsquic_packet_in) pi_next;
|
||||
lsquic_time_t pi_received; /* Time received */
|
||||
lsquic_cid_t pi_conn_id;
|
||||
lsquic_cid_t pi_dcid;
|
||||
#define pi_conn_id pi_dcid
|
||||
lsquic_packno_t pi_packno;
|
||||
enum quic_ft_bit pi_frame_types;
|
||||
unsigned short pi_header_sz; /* Points to payload */
|
||||
unsigned short pi_data_sz; /* Data plus header */
|
||||
/* A packet may be referred to by one or more frames and packets_in
|
||||
* list.
|
||||
*/
|
||||
unsigned short pi_refcnt;
|
||||
enum quic_ft_bit pi_frame_types:16;
|
||||
unsigned short pi_hsk_stream; /* Offset to handshake stream
|
||||
* frame, only valid if
|
||||
* PI_HSK_STREAM is set.
|
||||
*/
|
||||
unsigned char pi_quic_ver; /* Offset to QUIC version */
|
||||
unsigned char pi_nonce; /* Offset to nonce */
|
||||
enum {
|
||||
PI_DECRYPTED = (1 << 0),
|
||||
PI_OWN_DATA = (1 << 1), /* We own pi_data */
|
||||
PI_CONN_ID = (1 << 2), /* pi_conn_id is set */
|
||||
PI_HSK_STREAM = (1 << 3), /* Has handshake data (mini only) */
|
||||
PI_FROM_MINI = (1 << 4), /* Handed off by mini connection */
|
||||
#define PIBIT_ENC_LEV_SHIFT 5
|
||||
PI_ENC_LEV_BIT_0= (1 << 5), /* Encodes encryption level */
|
||||
PI_ENC_LEV_BIT_1= (1 << 6), /* (see enum enc_level). */
|
||||
PI_GQUIC = (1 << 7),
|
||||
#define PIBIT_BITS_SHIFT 8
|
||||
PI_BITS_BIT_0 = (1 << 8),
|
||||
PI_BITS_BIT_1 = (1 << 9),
|
||||
PI_UNUSED_8 = (1 << 8), /* <-- hole, reuse me! */
|
||||
#define PIBIT_ECN_SHIFT 9
|
||||
PI_ECN_BIT_0 = (1 << 9),
|
||||
PI_ECN_BIT_1 = (1 <<10),
|
||||
#define PIBIT_SPIN_SHIFT 11
|
||||
PI_SPIN_BIT = (1 <<11),
|
||||
#define PIBIT_BITS_SHIFT 12
|
||||
PI_BITS_BIT_0 = (1 <<12),
|
||||
PI_BITS_BIT_1 = (1 <<13),
|
||||
} pi_flags:16;
|
||||
/* pi_token and pi_token_size are set in Initial and Retry packets */
|
||||
unsigned short pi_token_size; /* Size of the token */
|
||||
unsigned char pi_token; /* Offset to token */
|
||||
/* pi_odcid and pi_odcid_len are only set in Retry packets */
|
||||
unsigned char pi_odcid; /* Offset to Original DCID */
|
||||
unsigned char pi_odcid_len; /* Size of ODCID */
|
||||
unsigned char pi_scid_off; /* Offset to SCID */
|
||||
unsigned char pi_scid_len; /* Size of SCID */
|
||||
unsigned char pi_quic_ver; /* Offset to QUIC version */
|
||||
unsigned char pi_nonce; /* Offset to nonce */
|
||||
enum header_type pi_header_type:8;
|
||||
unsigned char pi_path_id;
|
||||
/* If PI_OWN_DATA flag is not set, `pi_data' points to user-supplied
|
||||
* packet data, which is NOT TO BE MODIFIED.
|
||||
*/
|
||||
unsigned char *pi_data;
|
||||
} lsquic_packet_in_t;
|
||||
|
||||
|
||||
#define lsquic_packet_in_public_flags(p) ((p)->pi_data[0])
|
||||
|
||||
#define lsquic_packet_in_is_gquic_prst(p) \
|
||||
|
@ -96,6 +127,23 @@ typedef struct lsquic_packet_in
|
|||
#define lsquic_packet_in_enc_level(p) \
|
||||
(((p)->pi_flags >> PIBIT_ENC_LEV_SHIFT) & 0x3)
|
||||
|
||||
#define lsquic_packet_in_ecn(p) \
|
||||
(((p)->pi_flags >> PIBIT_ECN_SHIFT) & 0x3)
|
||||
|
||||
#define lsquic_packet_in_spin_bit(p) (((p)->pi_flags & PI_SPIN_BIT) > 0)
|
||||
|
||||
/* PATH_CHALLENGE, PATH_RESPONSE, NEW_CONNECTION_ID, and PADDING frames
|
||||
* are "probing frames", and all other frames are "non-probing frames".
|
||||
* A packet containing only probing frames is a "probing packet", and a
|
||||
* packet containing any other frame is a "non-probing packet".
|
||||
*
|
||||
* [draft-ietf-quic-transport-20], Section 9.1
|
||||
*/
|
||||
#define lsquic_packet_in_non_probing(p) \
|
||||
(!!((p)->pi_frame_types & ~(QUIC_FTBIT_PATH_CHALLENGE \
|
||||
|QUIC_FTBIT_PATH_RESPONSE|QUIC_FTBIT_PADDING \
|
||||
|QUIC_FTBIT_NEW_CONNECTION_ID)))
|
||||
|
||||
/* The version iterator is used on a version negotiation packet only.
|
||||
* The iterator functions return 1 when next version is returned and
|
||||
* 0 when there are no more versions.
|
||||
|
@ -116,4 +164,8 @@ packet_in_ver_next (struct ver_iter *, lsquic_ver_tag_t *ver_tag);
|
|||
size_t
|
||||
lsquic_packet_in_mem_used (const struct lsquic_packet_in *);
|
||||
|
||||
void
|
||||
lsquic_scid_from_packet_in (const struct lsquic_packet_in *,
|
||||
struct lsquic_cid *);
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue