mirror of
				https://gitea.invidious.io/iv-org/litespeed-quic.git
				synced 2024-08-15 00:53:43 +00:00 
			
		
		
		
	Release 2.2.0: server included, ID-22 supported (#76)
This commit is contained in:
		
							parent
							
								
									8cba36d873
								
							
						
					
					
						commit
						5392f7a3b0
					
				
					 221 changed files with 113761 additions and 4563 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 @@
 | 
			
		|||
[](https://travis-ci.org/litespeedtech/lsquic-client)
 | 
			
		||||
[](https://cirrus-ci.com/github/litespeedtech/lsquic-client)
 | 
			
		||||
[](https://ci.appveyor.com/project/litespeedtech/lsquic-client)
 | 
			
		||||
[](https://travis-ci.org/litespeedtech/lsquic)
 | 
			
		||||
[](https://cirrus-ci.com/github/litespeedtech/lsquic)
 | 
			
		||||
[](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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										73
									
								
								patches/boringssl-meds.patch
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								patches/boringssl-meds.patch
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										122
									
								
								src/liblsquic/gen-verstrs
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										122
									
								
								src/liblsquic/gen-verstrs
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
							
								
								
									
										1
									
								
								src/liblsquic/ls-qpack
									
										
									
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								src/liblsquic/ls-qpack
									
										
									
									
									
										Submodule
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1050
									
								
								src/liblsquic/lsquic_bbr.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1050
									
								
								src/liblsquic/lsquic_bbr.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										210
									
								
								src/liblsquic/lsquic_bbr.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/liblsquic/lsquic_bbr.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										273
									
								
								src/liblsquic/lsquic_bw_sampler.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								src/liblsquic/lsquic_bw_sampler.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										111
									
								
								src/liblsquic/lsquic_bw_sampler.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/liblsquic/lsquic_bw_sampler.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										68
									
								
								src/liblsquic/lsquic_cong_ctl.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/liblsquic/lsquic_cong_ctl.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										348
									
								
								src/liblsquic/lsquic_enc_sess.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								src/liblsquic/lsquic_enc_sess.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										34
									
								
								src/liblsquic/lsquic_enc_sess_common.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/liblsquic/lsquic_enc_sess_common.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2670
									
								
								src/liblsquic/lsquic_enc_sess_ietf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2670
									
								
								src/liblsquic/lsquic_enc_sess_ietf.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												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))                    \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										148
									
								
								src/liblsquic/lsquic_frab_list.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								src/liblsquic/lsquic_frab_list.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										59
									
								
								src/liblsquic/lsquic_frab_list.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/liblsquic/lsquic_frab_list.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6976
									
								
								src/liblsquic/lsquic_full_conn_ietf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6976
									
								
								src/liblsquic/lsquic_full_conn_ietf.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												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();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										854
									
								
								src/liblsquic/lsquic_h3_prio.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										854
									
								
								src/liblsquic/lsquic_h3_prio.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								src/liblsquic/lsquic_h3_prio.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/liblsquic/lsquic_h3_prio.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										221
									
								
								src/liblsquic/lsquic_hcsi_reader.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								src/liblsquic/lsquic_hcsi_reader.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								src/liblsquic/lsquic_hcsi_reader.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/liblsquic/lsquic_hcsi_reader.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										367
									
								
								src/liblsquic/lsquic_hcso_writer.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								src/liblsquic/lsquic_hcso_writer.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
							
								
								
									
										39
									
								
								src/liblsquic/lsquic_hcso_writer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/liblsquic/lsquic_hcso_writer.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								src/liblsquic/lsquic_hkdf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/liblsquic/lsquic_hkdf.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/liblsquic/lsquic_hkdf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/liblsquic/lsquic_hkdf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										94
									
								
								src/liblsquic/lsquic_hq.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/liblsquic/lsquic_hq.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										152
									
								
								src/liblsquic/lsquic_hq.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/liblsquic/lsquic_hq.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										163
									
								
								src/liblsquic/lsquic_hspack_valid.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/liblsquic/lsquic_hspack_valid.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								src/liblsquic/lsquic_ietf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/liblsquic/lsquic_ietf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2010
									
								
								src/liblsquic/lsquic_mini_conn.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2010
									
								
								src/liblsquic/lsquic_mini_conn.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										158
									
								
								src/liblsquic/lsquic_mini_conn.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/liblsquic/lsquic_mini_conn.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										1462
									
								
								src/liblsquic/lsquic_mini_conn_ietf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1462
									
								
								src/liblsquic/lsquic_mini_conn_ietf.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										88
									
								
								src/liblsquic/lsquic_mini_conn_ietf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/liblsquic/lsquic_mini_conn_ietf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										155
									
								
								src/liblsquic/lsquic_minmax.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/liblsquic/lsquic_minmax.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								src/liblsquic/lsquic_minmax.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/liblsquic/lsquic_minmax.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								src/liblsquic/lsquic_packet_gquic.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/liblsquic/lsquic_packet_gquic.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								src/liblsquic/lsquic_packet_gquic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/liblsquic/lsquic_packet_gquic.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										23
									
								
								src/liblsquic/lsquic_packet_ietf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/liblsquic/lsquic_packet_ietf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue