diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b9665755..f30f6d2d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,10 +58,10 @@ jobs: SSL_TYPE_STR="boringssl" SSL_PATH_STR="${PWD}/third_party/boringssl" SSL_INC_PATH_STR="${PWD}/third_party/boringssl/include" - SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/ssl/libssl.a;${PWD}/third_party/boringssl/build/crypto/libcrypto.a" + SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/libssl.a;${PWD}/third_party/boringssl/build/libcrypto.a" mkdir -p build cd build - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 -DXQC_ENABLE_PKM=1 .. make -j - name: Test @@ -72,7 +72,7 @@ jobs: openssl req -newkey rsa:2048 -x509 -nodes -keyout "$keyfile" -new -out "$certfile" -subj /CN=test.xquic.com ./tests/run_tests | tee -a ../xquic_test.log ../scripts/case_test.sh | tee -a ../xquic_test.log - gcovr -r .. --xml -o ../coverage.xml + gcovr -r .. --xml --gcov-ignore-parse-errors -o ../coverage.xml - name: Check Test Result run: | @@ -141,7 +141,7 @@ jobs: SSL_TYPE_STR="boringssl" SSL_PATH_STR="${PWD}/third_party/boringssl" SSL_INC_PATH_STR="${PWD}/third_party/boringssl/include" - SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/ssl/libssl.a;${PWD}/third_party/boringssl/build/crypto/libcrypto.a" + SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/libssl.a;${PWD}/third_party/boringssl/build/libcrypto.a" mkdir -p build cd build cmake -DPLATFORM=mac -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 6445f8af7..79daf46b1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,7 +13,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 2 submodules: 'recursive' @@ -57,10 +57,10 @@ jobs: SSL_TYPE_STR="boringssl" SSL_PATH_STR="${PWD}/third_party/boringssl" SSL_INC_PATH_STR="${PWD}/third_party/boringssl/include" - SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/ssl/libssl.a;${PWD}/third_party/boringssl/build/crypto/libcrypto.a" + SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/libssl.a;${PWD}/third_party/boringssl/build/libcrypto.a" mkdir -p build cd build - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 -DXQC_ENABLE_PKM=1 .. make -j - name: Perform CodeQL Analysis diff --git a/.github/workflows/interop-docker.yml b/.github/workflows/interop-docker.yml index b923f6a69..7fa6a43c4 100644 --- a/.github/workflows/interop-docker.yml +++ b/.github/workflows/interop-docker.yml @@ -2,12 +2,13 @@ name: Build interop Docker image on: push: - branches: [ interop ] + branches: [ main, interop ] permissions: read-all jobs: build: + if: github.repository == 'alibaba/xquic' permissions: packages: write diff --git a/CMakeLists.txt b/CMakeLists.txt index 304b635d3..9ec85ab99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,80 +5,144 @@ project (xquic) set (xquic_VERSION_MAJOR 0) set (xquic_VERSION_MINOR 1) -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -option (XQC_ENABLE_BBR2 "enable bbr2" ON) -option (XQC_ENABLE_COPA "enable copa" ON) -option (XQC_ENABLE_RENO "enable reno" ON) -option (XQC_ENABLE_UNLIMITED "enable unlimited cc" ON) -option (XQC_ENABLE_MP_INTEROP "enable MPQUIC interop" ON) +set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +option (XQC_ENABLE_BBR2 "enable bbr2" OFF) +option (XQC_ENABLE_COPA "enable copa" OFF) +option (XQC_ENABLE_RENO "enable reno" OFF) +option (XQC_ENABLE_UNLIMITED "enable unlimited cc" OFF) +option (XQC_ENABLE_MP_INTEROP "enable MPQUIC interop" OFF) +option (XQC_NO_PID_PACKET_PROCESS "do not expose path_id in xqc_engine_packet_process" OFF) +option (XQC_PROTECT_POOL_MEM "enable write protection for pool memory (for debug)" OFF) +option (XQC_COMPAT_DUPLICATE "qpack compat dup" OFF) +option (XQC_ENABLE_FEC "enable fec" OFF) +option (XQC_ENABLE_XOR "enable fec scheme xor" OFF) +option (XQC_ENABLE_RSC "enable fec scheme reed-solomon code" OFF) +option (XQC_ENABLE_PKM "enable fec scheme packet mask" OFF) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() + # SSL lib type, xquic support babassl and boringssl interfaces if(NOT SSL_TYPE) set(SSL_TYPE "babassl") + message(NOTICE "-- SSL_TYPE not set, use default babassl") endif() if(${SSL_TYPE} MATCHES "babassl") - # PATH of ssl + # PATH of ssl, by default XQUIC will use babassl installed in + # /usr/local/babassl if SSL_PATH is not set if(NOT SSL_PATH) set(SSL_PATH "/usr/local/babassl") + message(NOTICE "-- SSL_PATH not set, use default ${SSL_PATH}") endif() - # ssl lib denpendency - if(NOT SSL_LIB_PATH) - set(SSL_LIB_PATH - ${SSL_PATH}/lib/libssl.a - ${SSL_PATH}/lib/libcrypto.a - ) - endif() elseif(${SSL_TYPE} MATCHES "boringssl") - # PATH of ssl + add_definitions(-DNOCRYPT=1) + # PATH of ssl, by default XQUIC will use boringssl in third_party if(NOT SSL_PATH) set(SSL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/third_party/boringssl) + message(NOTICE "-- SSL_PATH not set, use default ${SSL_PATH}") + endif() +endif() + +# Users can use both SSL_DIR or SSL_PATH to specify the ssl path to find the ssl +# module, if both are defined, SSL_DIR will be used. +if(NOT SSL_DIR) + if(NOT SSL_PATH) + # at least SSL_DIR or SSL_PATH shall be set + message(FATAL_ERROR "SSL_PATH not set") + else() + set(SSL_DIR ${SSL_PATH}) + endif() +endif() + + +# find ssl module from SSL_DIR if SSL_INC_PATH AND SSL_LIB_PATH not set. +if(NOT SSL_INC_PATH AND NOT SSL_LIB_PATH) + find_package(SSL) + + if(NOT SSL_FOUND) + message(FATAL_ERROR "ssl module not found") + endif(NOT SSL_FOUND) + + # compat with elder macros + if(SSL_DYNAMIC) + message(NOTICE "-- Building with dynamic libssl") + set(SSL_LIB_PATH ${SSL_LIBRARIES}) + else() + message(NOTICE "-- Building with static libssl") + set(SSL_LIB_PATH ${SSL_LIBRARIES_STATIC}) endif() + set(SSL_INC_PATH ${SSL_INCLUDE_DIR}) - # ssl lib denpendency - if(NOT SSL_LIB_PATH) - if(CMAKE_SYSTEM_NAME MATCHES "Windows") - add_definitions(-DNOCRYPT=1) - set(SSL_LIB_PATH - ${SSL_PATH}/build/ssl/${CMAKE_BUILD_TYPE}/ssl.lib - ${SSL_PATH}/build/crypto/${CMAKE_BUILD_TYPE}/crypto.lib - ) - else() - set(SSL_LIB_PATH - ${SSL_PATH}/build/ssl/libssl.a - ${SSL_PATH}/build/crypto/libcrypto.a - ) +else() + if(NOT EXISTS ${SSL_INC_PATH}) + message(FATAL_ERROR "ssl include path not found") + endif() + + foreach(LIB IN LISTS SSL_LIB_PATH) + if(NOT EXISTS ${LIB}) + message(FATAL_ERROR "ssl lib not found ${LIB}") endif() + endforeach() + +endif() + +MESSAGE("-- SSL_TYPE: ${SSL_TYPE}") +MESSAGE("-- SSL_PATH: ${SSL_PATH}") +MESSAGE("-- SSL_LIB_PATH: ${SSL_LIB_PATH}") +MESSAGE("-- SSL_INC_PATH: ${SSL_INC_PATH}") + + +# C_FLAGS +if(ANDROID_ABI OR PLATFORM MATCHES "mac") + if(PLATFORM STREQUAL "mac32") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") endif() endif() -# ssl include path -if(NOT SSL_INC_PATH) - set(SSL_INC_PATH - ${SSL_PATH}/include - ) +if(NOT (CMAKE_C_COMPILER_ID MATCHES "MSVC" OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")) + set(CMAKE_C_FLAGS_OPTION "-Werror -Wno-unused -Wno-pointer-sign -Wno-format-security ") +endif() + +# C_FLAGS +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -std=gnu11 -Wall ${CMAKE_C_FLAGS_OPTION} -DNDEBUG_PRINT -DNPRINT_MALLOC ") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Wall ${CMAKE_C_FLAGS_OPTION} -DNDEBUG_PRINT -DNPRINT_MALLOC -DXQC_DEBUG ") + +if(ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer") endif() -MESSAGE("SSL_TYPE= ${SSL_TYPE}") -MESSAGE("SSL_PATH= ${SSL_PATH}") -MESSAGE("SSL_LIB_PATH= ${SSL_LIB_PATH}") -MESSAGE("SSL_INC_PATH= ${SSL_INC_PATH}") + +if(CMAKE_SYSTEM_NAME MATCHES "Windows") + add_definitions(-DXQC_SYS_WINDOWS=1) + set(CMAKE_C_FLAGS_OPTION " ") +endif() + + +# configure file +configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/xqc_configure.h.in" + "${CMAKE_CURRENT_SOURCE_DIR}/include/xquic/xqc_configure.h" +) + +include_directories(include + ${CMAKE_CURRENT_SOURCE_DIR} + ${SSL_INC_PATH} + ${CMAKE_SOURCE_DIR} +) + + # print tls traffic secret in keylog if(XQC_PRINT_SECRET) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_PRINT_SECRET") endif() -if(XQC_COMPAT_DUPLICATE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_COMPAT_DUPLICATE") -endif() - +# compat with the stateless reset before version v1.6.0 if(XQC_COMPAT_GENERATE_SR_PKT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_COMPAT_GENERATE_SR_PKT") endif() @@ -98,42 +162,20 @@ if(XQC_SUPPORT_SENDMMSG_BUILD) add_definitions(-DXQC_SUPPORT_SENDMMSG) endif() -#coverity +# coverity if(GCOV STREQUAL "on") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif() -# C_FLAGS -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -std=gnu11 -Wall -DNDEBUG_PRINT -DNPRINT_MALLOC ") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Wall -DNDEBUG_PRINT -DNPRINT_MALLOC -DXQC_DEBUG ") - -if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-unused -Wno-pointer-sign -Wno-format-security ") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -Wno-unused -Wno-pointer-sign -Wno-format-security ") -else() - add_definitions(-DXQC_SYS_WINDOWS=1) -endif() - -# additional C_FLAGS on mac -if(PLATFORM STREQUAL "mac32") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") -endif() - - -# configure file -configure_file ( - "${CMAKE_CURRENT_SOURCE_DIR}/xqc_configure.h.in" - "${CMAKE_CURRENT_SOURCE_DIR}/include/xquic/xqc_configure.h" -) +# testing +if(XQC_ENABLE_TESTING) + add_subdirectory(tests) + add_subdirectory(demo) + add_subdirectory(mini) +endif(XQC_ENABLE_TESTING) -include_directories( - include - /usr/local/include - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}/include" -) # http3/qpack source set( @@ -184,12 +226,14 @@ set( "src/transport/xqc_quic_lb.c" "src/transport/xqc_timer.c" "src/transport/xqc_reinjection.c" + "src/transport/xqc_recv_timestamps_info.c" "src/transport/reinjection_control/xqc_reinj_default.c" "src/transport/reinjection_control/xqc_reinj_deadline.c" "src/transport/reinjection_control/xqc_reinj_dgram.c" "src/transport/scheduler/xqc_scheduler_minrtt.c" "src/transport/scheduler/xqc_scheduler_common.c" "src/transport/scheduler/xqc_scheduler_backup.c" + "src/transport/scheduler/xqc_scheduler_backup_fec.c" "src/transport/scheduler/xqc_scheduler_rap.c" ) @@ -201,6 +245,47 @@ if(XQC_ENABLE_MP_INTEROP) ) endif() + +# fec framework +set( + FEC_FRAMEWORK_SOURCE + "src/transport/xqc_fec.c" + "src/transport/xqc_fec_scheme.c" + "src/transport/fec_schemes/xqc_galois_calculation.c" +) + +if(XQC_ENABLE_XOR) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_xor.c" + ) +endif() + +if(XQC_ENABLE_RSC) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_reed_solomon.c" + ) +endif() + +if(XQC_ENABLE_PKM) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_packet_mask.c" + ) +endif() + +if(XQC_ENABLE_FEC) + set( + TRANSPORT_SOURCES + ${TRANSPORT_SOURCES} + ${FEC_FRAMEWORK_SOURCE} + ) +endif() + # TLS source set ( TLS_SOURCE @@ -215,17 +300,17 @@ if(${SSL_TYPE} MATCHES "boringssl") set( TLS_SOURCE ${TLS_SOURCE} - "src/tls/boringssl/xqc_hkdf.c" - "src/tls/boringssl/xqc_crypto.c" - "src/tls/boringssl/xqc_ssl_if.c" + "src/tls/boringssl/xqc_hkdf_impl.c" + "src/tls/boringssl/xqc_crypto_impl.c" + "src/tls/boringssl/xqc_ssl_if_impl.c" ) elseif(${SSL_TYPE} MATCHES "babassl") set( TLS_SOURCE ${TLS_SOURCE} - "src/tls/babassl/xqc_hkdf.c" - "src/tls/babassl/xqc_crypto.c" - "src/tls/babassl/xqc_ssl_if.c" + "src/tls/babassl/xqc_hkdf_impl.c" + "src/tls/babassl/xqc_crypto_impl.c" + "src/tls/babassl/xqc_ssl_if_impl.c" ) endif() @@ -293,6 +378,7 @@ endif() # xquic source set ( XQC_SOURCE + ${XQC_SOURCE} ${HTTP3_SOURCES} ${TRANSPORT_SOURCES} ${TLS_SOURCE} @@ -322,6 +408,7 @@ if(PLATFORM MATCHES "mac") ${SSL_LIB_PATH} "-Wl" -lpthread + -lstdc++ ) else() target_link_libraries( @@ -334,108 +421,9 @@ else() endif() - # Strip binary for release builds if(CMAKE_BUILD_TYPE STREQUAL MinSizeRel) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} libxquic.so) endif() - -include_directories(${SSL_INC_PATH}) -include_directories(${CMAKE_SOURCE_DIR}/) - - -##### build unittest, test client/server, demo client/server ##### -if (XQC_ENABLE_TESTING) - # CUnit TODO: fix test unit on windows - find_package(CUnit 2.1) - enable_testing() - set(HAVE_CUNIT ${CUNIT_FOUND}) - if(HAVE_CUNIT) - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) - endif() - - add_subdirectory(tests) - include_directories(${CMAKE_CURRENT_BINARY_DIR}/test) - - if(CMAKE_SYSTEM_NAME MATCHES "Windows") - # used wingetopt on windows - if(NOT GETOPT_INC_PATH) - set(GETOPT_INC_PATH - ${CMAKE_SOURCE_DIR}/third_party/wingetopt - ) - endif() - MESSAGE("GETOPT_INC_PATH= ${GETOPT_INC_PATH}") - - include_directories(${GETOPT_INC_PATH}/src) - set(GETOPT_SOURCES "${GETOPT_INC_PATH}/src/getopt.c") - endif() - - ### test client/server ### - add_executable(test_server tests/test_server.c ${GETOPT_SOURCES}) - add_executable(test_client tests/test_client.c ${GETOPT_SOURCES}) - - ### hq demo client/server ### - set( - HQ_SOURCES - "demo/xqc_hq_ctx.c" - "demo/xqc_hq_conn.c" - "demo/xqc_hq_request.c" - ) - - set( - DEMO_CLIENT_SOURCES - ${HQ_SOURCES} - "demo/demo_client.c" - ) - - set( - DEMO_SERVER_SOURCES - ${HQ_SOURCES} - "demo/demo_server.c" - ) - - add_executable(demo_server ${DEMO_SERVER_SOURCES} ${GETOPT_SOURCES}) - add_executable(demo_client ${DEMO_CLIENT_SOURCES} ${GETOPT_SOURCES}) - if(CMAKE_SYSTEM_NAME MATCHES "Windows") - if (NOT EVENT_LIB_DIR) - message("YOU NEED SET -DEVENT_LIB_DIR=your_event_path, eg:-DEVENT_LIB_DIR=D:/project/vcpkg/packages/libevent_x64-windows-static") - endif() - - include_directories( ${EVENT_LIB_DIR}/include ) - link_directories( ${EVENT_LIB_DIR}/lib ) - - SET(EVENT_LIB_PATH - ${EVENT_LIB_DIR}/lib/event.lib - ${EVENT_LIB_DIR}/lib/event_core.lib - ${EVENT_LIB_DIR}/lib/event_extra.lib - ) - else() - link_directories( /usr/local/lib ) - endif() - - if(PLATFORM STREQUAL "mac32") - target_link_libraries(test_server xquic-static ${SSL_LIB_PATH} -ldl -lpthread -lm ${CMAKE_CURRENT_SOURCE_DIR}/../libevent32/lib/libevent.dylib) - target_link_libraries(test_client xquic-static ${SSL_LIB_PATH} -ldl -lpthread -lm ${CMAKE_CURRENT_SOURCE_DIR}/../libevent32/lib/libevent.dylib) - target_link_libraries(demo_server xquic -lm ${CMAKE_CURRENT_SOURCE_DIR}/../libevent32/lib/libevent.dylib) - target_link_libraries(demo_client xquic -lm ${CMAKE_CURRENT_SOURCE_DIR}/../libevent32/lib/libevent.dylib) - elseif(PLATFORM STREQUAL "mac") - target_link_libraries(test_server xquic-static ${SSL_LIB_PATH} -ldl -lpthread -lm -L/usr/local/lib -levent) - target_link_libraries(test_client xquic-static ${SSL_LIB_PATH} -ldl -lpthread -lm -L/usr/local/lib -levent) - target_link_libraries(demo_server xquic -lm -L/usr/local/lib -levent) - target_link_libraries(demo_client xquic -lm -L/usr/local/lib -levent) - elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") - target_link_libraries(test_server xquic ${EVENT_LIB_PATH} -lm) - target_link_libraries(test_client xquic ${EVENT_LIB_PATH} -lm) - target_link_libraries(demo_server xquic ${EVENT_LIB_PATH} -lm) - target_link_libraries(demo_client xquic ${EVENT_LIB_PATH} -lm) - else() - target_link_libraries(test_server xquic-static ${SSL_LIB_PATH} -ldl -lpthread -levent -lm) - target_link_libraries(test_client xquic-static ${SSL_LIB_PATH} -ldl -lpthread -levent -lm) - target_link_libraries(demo_server xquic -levent -lm) - target_link_libraries(demo_client xquic -levent -lm) - endif() - -endif() - diff --git a/CMakeOptions.txt b/CMakeOptions.txt index abf493ecc..c8bff1f14 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -2,7 +2,8 @@ option(ENABLE_DEBUG "Turn on debug output" ON) option(XQC_BUILD_OPENSSL "Turn on OpenSSL" ON) -option(XQC_OPENSSL_IS_BORINGSSL "Using BoringSSL" ON) +option(SSL_TYPE "Using BoringSSL" boringssl) +option(SSL_DYNAMIC "Use dynamic libssl" OFF) option(XQC_ENABLE_TESTING "Enable Testing" OFF) option(XQC_BUILD_SAMPLE "Build Sample" OFF) option(GCOV "Test Coverage" OFF) \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6186e2e9..e3b2892f8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -221,5 +221,6 @@ In no particular order, thanks to these excellent individuals who contributed co * @ruanshanshan * @alagoutte * @MPK1 +* @tang-mouren This list will be continuously updated. Contributions are welcome! diff --git a/README.md b/README.md index c5480c2a7..15b8b780a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # XQUIC -xquic logo +xquic logo ![GitHub](https://img.shields.io/github/license/alibaba/xquic) [![Build](https://github.com/alibaba/xquic/actions/workflows/build.yml/badge.svg)](https://github.com/alibaba/xquic/actions/workflows/build.yml) @@ -16,7 +16,7 @@ XQUIC Library released by Alibaba is … … **a client and server implementation of QUIC and HTTP/3 as specified by the IETF.** Currently supported QUIC versions are v1 and draft-29. -… **OS and platform agnostic.** It currently supports Android, iOS, Linux, macOS and Windows(v1.2.0). Most of the code is used in our own products, and has been tested at scale on android, iOS apps, as well as servers. +… **OS and platform agnostic.** It currently supports Android, iOS, HarmonyOS, Linux, macOS and Windows(v1.2.0). Most of the code is used in our own products, and has been tested at scale on android, iOS apps, as well as servers. … **still in active development.** [Interoperability](https://interop.seemann.io/) is regularly tested with other QUIC implementations. @@ -27,31 +27,29 @@ XQUIC Library released by Alibaba is … [![](https://img.shields.io/static/v1?label=RFC&message=9002&color=brightgreen)](https://tools.ietf.org/html/rfc9002) [![](https://img.shields.io/static/v1?label=RFC&message=9114&color=brightgreen)](https://tools.ietf.org/html/rfc9114) [![](https://img.shields.io/static/v1?label=RFC&message=9204&color=brightgreen)](https://tools.ietf.org/html/rfc9204) +[![](https://img.shields.io/static/v1?label=RFC&message=9221&color=brightgreen)](https://datatracker.ietf.org/doc/html/rfc9221) [![](https://img.shields.io/static/v1?label=draft-13&message=QUIC-LB&color=9cf)](https://tools.ietf.org/html/draft-ietf-quic-load-balancers-13) -[![](https://img.shields.io/static/v1?label=draft-04&message=Multipath-QUIC&color=9cf)](https://tools.ietf.org/html/draft-ietf-quic-multipath-04) [![](https://img.shields.io/static/v1?label=draft-05&message=Multipath-QUIC&color=9cf)](https://tools.ietf.org/html/draft-ietf-quic-multipath-05) +[![](https://img.shields.io/static/v1?label=draft-06&message=Multipath-QUIC&color=9cf)](https://tools.ietf.org/html/draft-ietf-quic-multipath-06) +[![](https://img.shields.io/static/v1?label=draft-07&message=QUIC-Qlog&color=9cf)](https://datatracker.ietf.org/doc/html/draft-ietf-quic-qlog-main-schema-07) #### Standardized Features * All big features conforming with [RFC 9000](https://www.rfc-editor.org/rfc/rfc9000), [RFC9001](https://www.rfc-editor.org/rfc/rfc9001), [RFC9002](https://www.rfc-editor.org/rfc/rfc9002), [RFC9114](https://www.rfc-editor.org/rfc/rfc9114) and [RFC9204](https://www.rfc-editor.org/rfc/rfc9204), including the interface between QUIC and TLS, 0-RTT connection establishment, HTTP/3 and QPACK. - * ALPN Extension conforming with [RFC7301](https://www.rfc-editor.org/rfc/rfc7301) #### Not Yet Standardized Features * [Multipath QUIC](https://tools.ietf.org/html/draft-ietf-quic-multipath-04) - * [QUIC-LB](https://tools.ietf.org/html/draft-ietf-quic-load-balancers-13) #### Library Features * Pluggable congestion control: NewReno, Cubic, BBR and BBRv2, ... - * Pluggable cryptography, integration with BoringSSL and BabaSSL - -* Cross-platform implementation, support Android, iOS, Linux, macOS and Windows(v1.2.0) +* Cross-platform implementation, support Android, iOS, HarmonyOS, Linux, macOS and Windows(v1.2.0) ## Requirements @@ -65,58 +63,73 @@ To run test cases, you need ## QuickStart Guide -XQUIC can be built with Tongsuo(BabaSSL) or BoringSSL. +XQUIC can be built with BabaSSL(Tongsuo) or BoringSSL. ### Build with BoringSSL ```bash +sudo apt-get install -y build-essential libevent-dev + # get XQUIC source code -git clone https://github.com/alibaba/xquic.git -cd xquic +git clone https://github.com/alibaba/xquic.git; cd xquic # get and build BoringSSL -git clone https://github.com/google/boringssl.git ./third_party/boringssl -cd ./third_party/boringssl +git clone https://github.com/google/boringssl.git ./third_party/boringssl; cd ./third_party/boringssl mkdir -p build && cd build cmake -DBUILD_SHARED_LIBS=0 -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. -make ssl crypto +make -j ssl crypto cd .. SSL_TYPE_STR="boringssl" SSL_PATH_STR="${PWD}" -SSL_INC_PATH_STR="${PWD}/include" -SSL_LIB_PATH_STR="${PWD}/build/ssl/libssl.a;${PWD}/build/crypto/libcrypto.a" cd ../.. -## Note: if you don’t have golang in your environment, please install [golang](https://go.dev/doc/install) first. # build XQUIC with BoringSSL +# When build XQUIC with boringssl, by default XQUIC will use boringssl +# in third_party. If boringssl is deployed in other directories, SSL_PATH could be +# used to specify the search path of boringssl git submodule update --init --recursive mkdir -p build; cd build -cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +# exit if cmake error +if [ $? -ne 0 ]; then + echo "cmake failed" + exit 1 +fi + make -j ``` -### Build with BabaSSL +### Build with BabaSSL(Tongsuo) ```bash +sudo apt-get install -y build-essential libevent-dev + # get XQUIC source code -git clone https://github.com/alibaba/xquic.git -cd xquic +git clone https://github.com/alibaba/xquic.git; cd xquic -# get and build BabaSSL -git clone -b 8.3-stable https://github.com/Tongsuo-Project/Tongsuo.git ./third_party/babassl -cd ./third_party/babassl/ +# get and build BabaSSL(Tongsuo) +git clone -b 8.3-stable https://github.com/Tongsuo-Project/Tongsuo.git ./third_party/babassl; cd ./third_party/babassl/ ./config --prefix=/usr/local/babassl make -j SSL_TYPE_STR="babassl" SSL_PATH_STR="${PWD}" -SSL_INC_PATH_STR="${PWD}/include" -SSL_LIB_PATH_STR="${PWD}/libssl.a;${PWD}/libcrypto.a" cd - # build XQUIC with BabaSSL +# When build XQUIC with babassl, /usr/local/babassl directory will be searched +# as default. If babassl is deployed in other directories, SSL_PATH could be +# used to specify the search path of babassl git submodule update --init --recursive mkdir -p build; cd build -cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +# exit if cmake error +if [ $? -ne 0 ]; then + echo "cmake failed" + exit 1 +fi + make -j ``` @@ -139,7 +152,7 @@ sh ../scripts/xquic_test.sh - [draft-ietf-quic-qpack-21-zh](./docs/translation/draft-ietf-quic-qpack-21-zh.md) - [RFC9221-datagram-zh](./docs/translation/rfc9221-datagram-zh.md) -* For using event_log module, see the [Event_log module docs](./docs/docs-zh/Event_log-zh.md) +* For using quic-qlog, see the [Features: qlog](./docs/Features.md) * For testing the library, see the [Testing docs](./docs/docs-zh/Testing-zh.md). * For other frequently asked questions, see the [FAQs](./docs/docs-zh/FAQ-zh.md) and [Trouble Shooting Guide](./docs/docs-zh/Troubleshooting-zh.md). @@ -161,4 +174,4 @@ Feel free to contact us in the following ways: * Dingtalk group: 34059705 * slack channel: #xquic in quicdev group - dingtalk group + dingtalk group diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 27e951a88..7e5bce0f9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -75,6 +75,11 @@ if (XQC_ENABLE_EVENT_LOG) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_ENABLE_EVENT_LOG ") endif() +# sendmmsg +if(XQC_SUPPORT_SENDMMSG_BUILD) + add_definitions(-DXQC_SUPPORT_SENDMMSG) +endif() + if(ANDROID) set(DYMAMIC_LINK_OPTION ${DYMAMIC_LINK_OPTION} @@ -92,6 +97,10 @@ include(CMakeOptions.txt) if (XQC_BUILD_OPENSSL) if(${SSL_TYPE} MATCHES "boringssl") + if (XQC_OPENSSL_SMALL) + set(OPENSSL_SMALL "1") + endif() + add_subdirectory(${SSL_PATH}) include_directories(${SSL_PATH}/include) @@ -102,8 +111,8 @@ if (XQC_BUILD_OPENSSL) endif() else() - #set(EXTRA_CONFIGURE_OPENSSL_PARAMS "${EXTRA_CONFIGURE_OPENSSL_PARAMS} ${DYNAMIC_COMPILE_FLAGS} ") - #add_subdirectory(external/openssl-cmake) + set(EXTRA_CONFIGURE_OPENSSL_PARAMS "${EXTRA_CONFIGURE_OPENSSL_PARAMS} ${DYNAMIC_COMPILE_FLAGS} ") + add_subdirectory(external/openssl-cmake) endif() set(DYMAMIC_LINK_OPTION @@ -187,12 +196,14 @@ set( "src/transport/xqc_quic_lb.c" "src/transport/xqc_timer.c" "src/transport/xqc_reinjection.c" + "src/transport/xqc_recv_timestamps_info.c" "src/transport/reinjection_control/xqc_reinj_default.c" "src/transport/reinjection_control/xqc_reinj_deadline.c" "src/transport/reinjection_control/xqc_reinj_dgram.c" "src/transport/scheduler/xqc_scheduler_minrtt.c" "src/transport/scheduler/xqc_scheduler_common.c" "src/transport/scheduler/xqc_scheduler_backup.c" + "src/transport/scheduler/xqc_scheduler_backup_fec.c" "src/transport/scheduler/xqc_scheduler_rap.c" ) @@ -204,6 +215,47 @@ if(XQC_ENABLE_MP_INTEROP) ) endif() + +# fec framework +set( + FEC_FRAMEWORK_SOURCE + "src/transport/xqc_fec.c" + "src/transport/xqc_fec_scheme.c" + "src/transport/fec_schemes/xqc_galois_calculation.c" +) + +if(XQC_ENABLE_XOR) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_xor.c" + ) +endif() + +if(XQC_ENABLE_RSC) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_reed_solomon.c" + ) +endif() + +if(XQC_ENABLE_PKM) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_packet_mask.c" + ) +endif() + +if(XQC_ENABLE_FEC) + set( + TRANSPORT_SOURCES + ${TRANSPORT_SOURCES} + ${FEC_FRAMEWORK_SOURCE} + ) +endif() + # TLS source set ( TLS_SOURCE @@ -218,17 +270,17 @@ if(${SSL_TYPE} MATCHES "boringssl") set( TLS_SOURCE ${TLS_SOURCE} - "src/tls/boringssl/xqc_hkdf.c" - "src/tls/boringssl/xqc_crypto.c" - "src/tls/boringssl/xqc_ssl_if.c" + "src/tls/boringssl/xqc_hkdf_impl.c" + "src/tls/boringssl/xqc_crypto_impl.c" + "src/tls/boringssl/xqc_ssl_if_impl.c" ) elseif(${SSL_TYPE} MATCHES "babassl") set( TLS_SOURCE ${TLS_SOURCE} - "src/tls/babassl/xqc_hkdf.c" - "src/tls/babassl/xqc_crypto.c" - "src/tls/babassl/xqc_ssl_if.c" + "src/tls/babassl/xqc_hkdf_impl.c" + "src/tls/babassl/xqc_crypto_impl.c" + "src/tls/babassl/xqc_ssl_if_impl.c" ) endif() @@ -292,17 +344,15 @@ if(XQC_ENABLE_UNLIMITED) ) endif() - -if(XQC_ENABLE_TH3) - set(XQC_ENABLE_TUNNEL 1) +# add tunnel +if(XQC_ENABLE_TH3 OR XQC_ENABLE_TUNNEL) set( - TH3_SOURCES - "tunnel/tunnel_h3/th3_ctx.c" - "tunnel/tunnel_h3/th3_vconn.c" - ) -endif() - + XQC_SOURCE ) + if(XQC_ENABLE_TNL_DG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_ENABLE_TNL_DG ") + endif() + add_subdirectory(tunnel) endif() if (XQC_NO_SHARED) @@ -317,6 +367,7 @@ add_library( ${TLS_SOURCE} ${COMMON_SOURCES} ${CONGESTION_CONTROL_SOURCES} + ${XQC_SOURCE} ) add_dependencies(xquic xquic_global) diff --git a/cmake/FindCUnit.cmake b/cmake/FindCUnit.cmake index ef4c0f8fc..b43bd7eff 100644 --- a/cmake/FindCUnit.cmake +++ b/cmake/FindCUnit.cmake @@ -3,13 +3,24 @@ # find include dir find_path(CUNIT_INCLUDE_DIR NAMES CUnit/CUnit.h + PATHS ${CUNIT_DIR} + PATH_SUFFIXES include ) # find lib dir find_library(CUNIT_LIBRARY NAMES cunit + PATHS ${CUNIT_DIR} + PATH_SUFFIXES lib lib64 ) +if(${CUNIT_LIBRARY} MATCHES "CUNIT_LIBRARY-NOTFOUND") + find_library(CUNIT_LIBRARY + NAMES libcunit + PATHS ${CUNIT_DIR} + PATH_SUFFIXES lib lib64) +endif() + # find version if(CUNIT_INCLUDE_DIR) set(_version_regex "^#define[ \t]+CU_VERSION[ \t]+\"([^\"]+)\".*") diff --git a/cmake/FindLibEvent.cmake b/cmake/FindLibEvent.cmake new file mode 100644 index 000000000..7b2deebde --- /dev/null +++ b/cmake/FindLibEvent.cmake @@ -0,0 +1,96 @@ +# Copyright (c) 2022, Alibaba Group Holding Limited +# find the LibEvent library + +# find include dir +find_path (LIBEVENT_INCLUDE_DIR NAMES event.h + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES include) + +# find dynamic library +find_library (LIBEVENT_LIBRARY NAMES event + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES lib lib64) +find_library (LIBEVENT_SSL NAMES event_openssl + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES lib lib64) +find_library (LIBEVENT_CORE NAMES event_core + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES lib lib64) +find_library (LIBEVENT_EXTRA NAMES event_extra + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES lib lib64) +find_library (LIBEVENT_THREAD NAMES event_pthreads + PATHS ${LIBEVENT_DIR} + PATH_SUFFIXES lib lib64) + +# find version +if(LIBEVENT_INCLUDE_DIR) + set(_version_regex + "^#define[ ]+[EVENT__VERSION|_EVENT_VERSION]+[ ]+\"([^\"]+)\"") + file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event2/event-config.h" + LIBEVENT_VERSION REGEX "${_version_regex}") + + # if event-config.h not found, try find event-config-64.h + if(NOT LIBEVENT_VERSION) + file(STRINGS "${LIBEVENT_INCLUDE_DIR}/event2/event-config-64.h" + LIBEVENT_VERSION REGEX "${_version_regex}") + endif() + + string(REGEX REPLACE "${_version_regex}" "\\1" + LIBEVENT_VERSION "${LIBEVENT_VERSION}") + unset(_version_regex) +endif() + + +include (FindPackageHandleStandardArgs) +set (LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR}) + +if(NOT ${LIBEVENT_LIBRARY} MATCHES "LIBEVENT_LIBRARY-NOTFOUND") + set (LIBEVENT_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_LIBRARY} + ) +endif() + +if(NOT ${LIBEVENT_SSL} MATCHES "LIBEVENT_SSL-NOTFOUND") + set (LIBEVENT_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_SSL} + ) +endif() + +if(NOT ${LIBEVENT_CORE} MATCHES "LIBEVENT_CORE-NOTFOUND") + set (LIBEVENT_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_CORE} + ) +endif() + +if(NOT ${LIBEVENT_EXTRA} MATCHES "LIBEVENT_EXTRA-NOTFOUND") + set (LIBEVENT_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_EXTRA} + ) +endif() + +if(NOT ${LIBEVENT_THREAD} MATCHES "LIBEVENT_THREAD-NOTFOUND") + set (LIBEVENT_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_THREAD} + ) +endif() + + +find_package_handle_standard_args(LibEvent + REQUIRED_VARS + LIBEVENT_INCLUDE_DIR + LIBEVENT_LIBRARY + LIBEVENT_LIBRARIES + VERSION_VAR LIBEVENT_VERSION +) + +mark_as_advanced( + LIBEVENT_INCLUDE_DIRS + LIBEVENT_LIBRARY + LIBEVENT_LIBRARIES +) diff --git a/cmake/FindSSL.cmake b/cmake/FindSSL.cmake new file mode 100644 index 000000000..f2862f348 --- /dev/null +++ b/cmake/FindSSL.cmake @@ -0,0 +1,69 @@ +# Copyright (c) 2022, Alibaba Group Holding Limited +# find the SSL library, success when SSL_INCLUDE_DIR and SSL_LIBRARIES_STATIC is +# not empty, no matter if SSL_LIBRARIES is empty or not. + +# find include dir +find_path(SSL_INCLUDE_DIR NAMES openssl/ssl.h + PATHS ${SSL_DIR} + PATH_SUFFIXES include + NO_DEFAULT_PATH) + +# find ssl library +find_library(SSL_LIBRARY NAMES ssl + PATHS ${SSL_DIR} + PATH_SUFFIXES lib64 lib build build/ssl + NO_DEFAULT_PATH) + +# find crypto library +find_library(CRYPTO_LIBRARY NAMES crypto + PATHS ${SSL_DIR} + PATH_SUFFIXES lib64 lib build build/crypto + NO_DEFAULT_PATH) + + +if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set(SSL_LIBRARY_STATIC_NAME ssl.lib) + set(CRYPTO_LIBRARY_STATIC_NAME crypto.lib) + +else() + set(SSL_LIBRARY_STATIC_NAME libssl.a) + set(CRYPTO_LIBRARY_STATIC_NAME libcrypto.a) +endif() + +# find ssl static library +find_library(SSL_LIBRARY_STATIC NAMES ${SSL_LIBRARY_STATIC_NAME} + PATHS ${SSL_DIR} + PATH_SUFFIXES lib64 lib build build/${CMAKE_BUILD_TYPE} + NO_DEFAULT_PATH) + +# find crypto static library +find_library(CRYPTO_LIBRARY_STATIC NAMES ${CRYPTO_LIBRARY_STATIC_NAME} + PATHS ${SSL_DIR} + PATH_SUFFIXES lib64 lib build build/${CMAKE_BUILD_TYPE} + NO_DEFAULT_PATH) + +include (FindPackageHandleStandardArgs) +if(SSL_DYNAMIC) + find_package_handle_standard_args(SSL + REQUIRED_VARS + SSL_INCLUDE_DIR + SSL_LIBRARY + CRYPTO_LIBRARY + ) +else() + find_package_handle_standard_args(SSL + REQUIRED_VARS + SSL_INCLUDE_DIR + SSL_LIBRARY_STATIC + CRYPTO_LIBRARY_STATIC + ) +endif() + +set (SSL_LIBRARIES + ${SSL_LIBRARY} + ${CRYPTO_LIBRARY}) +set (SSL_LIBRARIES_STATIC + ${SSL_LIBRARY_STATIC} + ${CRYPTO_LIBRARY_STATIC}) + +mark_as_advanced(SSL_INCLUDE_DIR SSL_LIBRARIES SSL_LIBRARIES_STATIC) diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt new file mode 100644 index 000000000..b72b3aea8 --- /dev/null +++ b/demo/CMakeLists.txt @@ -0,0 +1,46 @@ +### hq demo client/server ### +set( + HQ_SOURCES + "xqc_hq_ctx.c" + "xqc_hq_conn.c" + "xqc_hq_request.c" +) + +set( + DEMO_CLIENT_SOURCES + ${HQ_SOURCES} + "demo_client.c" +) + +set( + DEMO_SERVER_SOURCES + ${HQ_SOURCES} + "demo_server.c" +) + + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(DEMO_SERVER_SOURCES + ${DEMO_SERVER_SOURCES} + ${GETOPT_SOURCES} + ) + + set(DEMO_CLIENT_SOURCES + ${DEMO_CLIENT_SOURCES} + ${GETOPT_SOURCES} + ) +endif() + +include_directories( + "${CMAKE_SOURCE_DIR}/" + "${CMAKE_SOURCE_DIR}/include" + ${CMAKE_SOURCE_DIR} + ${CUNIT_INCLUDE_DIRS} + ${LIBEVENT_INCLUDE_DIR} +) + +add_executable(demo_server ${DEMO_SERVER_SOURCES}) +add_executable(demo_client ${DEMO_CLIENT_SOURCES}) + +target_link_libraries(demo_server ${APP_DEPEND_LIBS}) +target_link_libraries(demo_client ${APP_DEPEND_LIBS}) diff --git a/demo/common.h b/demo/common.h index a6fd22808..d3bcff496 100644 --- a/demo/common.h +++ b/demo/common.h @@ -21,7 +21,8 @@ typedef enum cc_type_s { CC_TYPE_BBR, CC_TYPE_CUBIC, - CC_TYPE_RENO + CC_TYPE_RENO, + CC_TYPE_COPA } CC_TYPE; @@ -60,6 +61,10 @@ typedef enum h3_hdr_type { } H3_HDR_TYPE; +extern long xqc_random(void); +extern xqc_usec_t xqc_now(); + + int xqc_demo_read_file_data(char * data, size_t data_len, char *filename) { @@ -94,16 +99,4 @@ xqc_demo_read_file_data(char * data, size_t data_len, char *filename) return ret; } - -static inline uint64_t -xqc_demo_now() -{ - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; -} - - #endif diff --git a/demo/demo_client.c b/demo/demo_client.c index 823053a0f..a088ec00e 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -8,27 +8,38 @@ #include #include #include -#include #include -#include -#include -#include -#include #include #include #include #include #include #include -#include #include +#include #include "common.h" #include "xqc_hq.h" +#include "../tests/platform.h" + +#ifdef XQC_SYS_WINDOWS +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#pragma comment(lib, "crypt32") +#include "../tests/getopt.h" +#else +#include +#include +#include +#include +#include +#endif #define XQC_PACKET_TMP_BUF_LEN 1600 #define MAX_BUF_SIZE (100*1024*1024) -#define XQC_INTEROP_TLS_GROUPS "X25519:P-256:P-384:P-521" +#define XQC_INTEROP_TLS_GROUPS "P-256:X25519:P-384:P-521" #define MAX_PATH_CNT 2 @@ -119,6 +130,9 @@ typedef struct xqc_demo_cli_net_config_s { uint8_t rebind_p0; uint8_t rebind_p1; + uint8_t addr_specified; + uint8_t port_specified; + } xqc_demo_cli_net_config_t; /** @@ -142,6 +156,7 @@ typedef struct xqc_demo_cli_quic_config_s { /* alpn protocol of client */ xqc_demo_cli_alpn_type_t alpn_type; char alpn[16]; + int quic_version; /* 0-rtt config */ int st_len; /* session ticket len */ @@ -160,6 +175,7 @@ typedef struct xqc_demo_cli_quic_config_s { char mp_sched[32]; uint8_t mp_backup; + int backup_path_id; uint64_t close_path; @@ -171,11 +187,26 @@ typedef struct xqc_demo_cli_quic_config_s { uint8_t mp_version; + uint64_t init_max_path_id; + + /* support interop test */ + int is_interop_mode; + uint8_t send_path_standby; xqc_msec_t path_status_timer_threshold; uint64_t least_available_cid_count; + uint64_t idle_timeout; + uint8_t remove_path_flag; + + size_t max_pkt_sz; + + char co_str[XQC_CO_STR_MAX_LEN]; + + int recreate_path; + int close_path_id; + } xqc_demo_cli_quic_config_t; @@ -218,7 +249,7 @@ typedef struct xqc_demo_cli_env_config_s { * ============================================================================ */ -#define MAX_REQUEST_CNT 2048 /* client might deal MAX_REQUEST_CNT requests once */ +#define MAX_REQUEST_CNT 20480 /* client might deal MAX_REQUEST_CNT requests once */ #define MAX_REQUEST_LEN 256 /* the max length of a request */ #define g_host "" @@ -236,7 +267,6 @@ typedef struct xqc_demo_cli_request_s { /* request bundle args */ typedef struct xqc_demo_cli_requests_s { /* requests */ - char urls[MAX_REQUEST_CNT * MAX_REQUEST_LEN]; int request_cnt; /* requests cnt in urls */ xqc_demo_cli_request_t reqs[MAX_REQUEST_CNT]; @@ -253,6 +283,9 @@ typedef struct xqc_demo_cli_requests_s { int throttled_req; + int ext_reqn; + int batch_cnt; + } xqc_demo_cli_requests_t; @@ -404,6 +437,13 @@ typedef struct xqc_demo_cli_user_conn_s { int path_status; /* 0:available 1:standby */ xqc_msec_t path_status_time; xqc_msec_t path_status_timer_threshold; + + + xqc_msec_t path_create_time; + xqc_flag_t remove_path_flag; + xqc_msec_t idle_timeout; + + int recreate_path_seq; } xqc_demo_cli_user_conn_t; static void @@ -544,7 +584,7 @@ void xqc_demo_cli_set_event_timer(xqc_usec_t wake_after, void *eng_user_data) { xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t *) eng_user_data; - //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_demo_now()); + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); struct timeval tv; tv.tv_sec = wake_after / 1000000; @@ -584,12 +624,30 @@ xqc_demo_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v //printf("%s", (char *)buf); int write_len = write(ctx->log_fd, buf, size); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + } +} + +void +xqc_demo_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data) +{ + xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); return; } write_len = write(ctx->log_fd, line_break, 1); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write qlog failed, errno: %d\n", get_sys_errno()); } } @@ -634,12 +692,12 @@ xqc_demo_cli_keylog_cb(const xqc_cid_t *scid, const char *line, void *engine_use int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); return; } write_len = write(ctx->keylog_fd, line_break, 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); } } @@ -690,7 +748,7 @@ xqc_demo_cli_save_token(const unsigned char *token, uint32_t token_len, void *co { xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t*)conn_user_data; - int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, S_IRWXU); + int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, 0666); if (fd < 0) { return; } @@ -742,18 +800,18 @@ xqc_demo_cli_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t // printf("path %"PRIu64" with fd:%d\n", path_id, user_path->fd); do { - errno = 0; + set_sys_errno(0); res = sendto(user_path->fd, buf, size, 0, peer_addr, peer_addrlen); if (res < 0) { printf("xqc_demo_cli_write_socket err %zd %s, fd: %d, buf: %p, size: %zu, " - "server_addr: %s\n", res, strerror(errno), user_path->fd, buf, size, + "server_addr: %s\n", res, strerror(get_sys_errno()), user_path->fd, buf, size, user_conn->ctx->args->net_cfg.server_addr); - if (errno == EAGAIN) { + if (get_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } - user_path->last_sock_op_time = xqc_demo_now(); - } while ((res < 0) && (errno == EINTR)); + user_path->last_sock_op_time = xqc_now(); + } while ((res < 0) && (get_sys_errno() == EINTR)); return res; } @@ -766,8 +824,7 @@ xqc_demo_cli_write_socket(const unsigned char *buf, size_t size, const struct so return xqc_demo_cli_write_socket_ex(0, buf, size, peer_addr, peer_addrlen, conn_user_data); } - -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_demo_cli_write_mmsg(void *conn_user_data, struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen) @@ -791,12 +848,12 @@ xqc_demo_cli_write_mmsg(void *conn_user_data, struct iovec *msg_iov, unsigned in res = XQC_SOCKET_EAGAIN; } } - } while ((res < 0) && (errno == EINTR)); + + } while ((res < 0) && (get_sys_errno() == EINTR)); return res; } #endif - void xqc_demo_cli_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, const xqc_cid_t *new_cid, void *user_data) @@ -813,11 +870,19 @@ xqc_demo_cli_conn_create_path(const xqc_cid_t *cid, void *conn_user_data) uint64_t path_id; int ret; int backup = 0; + uint32_t path_seq; + printf("ready to create path notify: %d %d %"PRIu64"\n", + user_conn->total_path_cnt, ctx->args->net_cfg.ifcnt, + ctx->args->quic_cfg.init_max_path_id); + if (user_conn->total_path_cnt < ctx->args->net_cfg.ifcnt - && user_conn->total_path_cnt < MAX_PATH_CNT) + && user_conn->total_path_cnt < ctx->args->quic_cfg.init_max_path_id) { - if (user_conn->total_path_cnt == 1 && ctx->args->quic_cfg.mp_backup) { + if (user_conn->total_path_cnt == 1 + && ctx->args->quic_cfg.mp_backup + && ctx->args->quic_cfg.backup_path_id == 1) + { backup = 1; } @@ -831,15 +896,22 @@ xqc_demo_cli_conn_create_path(const xqc_cid_t *cid, void *conn_user_data) printf("Init No.%d path (id = %"PRIu64") to STANDBY state\n", 1, path_id); } - ret = xqc_demo_cli_init_user_path(user_conn, user_conn->total_path_cnt, path_id); + path_seq = user_conn->total_path_cnt; + if (user_conn->recreate_path_seq != -1) { + path_seq = user_conn->recreate_path_seq; + } + + ret = xqc_demo_cli_init_user_path(user_conn, path_seq, path_id); if (ret < 0) { xqc_conn_close_path(ctx->engine, &(user_conn->cid), path_id); return; } + user_conn->path_create_time = xqc_now(); + if (user_conn->total_path_cnt == 2 && ctx->args->quic_cfg.mp_backup) { - printf("set No.%d path (id = %"PRIu64") to STANDBY state\n", 1, path_id); - xqc_conn_mark_path_standby(ctx->engine, &(user_conn->cid), path_id); + printf("set path (id = %d) to STANDBY state\n", ctx->args->quic_cfg.backup_path_id); + xqc_conn_mark_path_standby(ctx->engine, &(user_conn->cid), ctx->args->quic_cfg.backup_path_id); } } @@ -873,7 +945,13 @@ xqc_demo_cli_path_removed(const xqc_cid_t *scid, uint64_t path_id, close(user_conn->paths[i].rebind_fd); } - printf("No.%d path removed id = %"PRIu64"\n", i, path_id); + printf("No.%d path removed id = %"PRIu64"\n", i, path_id); + + if (user_conn->ctx->args->quic_cfg.recreate_path) { + user_conn->total_path_cnt--; + user_conn->recreate_path_seq = user_conn->ctx->args->quic_cfg.close_path_id; + xqc_demo_cli_conn_create_path(&user_conn->cid, user_conn); + } } } @@ -924,7 +1002,7 @@ xqc_demo_cli_hq_req_send(xqc_hq_request_t *hqr, xqc_demo_cli_user_stream_t *user ssize_t ret = 0; if (user_stream->start_time == 0) { - user_stream->start_time = xqc_demo_now(); + user_stream->start_time = xqc_now(); } ret = xqc_hq_request_send_req(hqr, user_stream->send_buf); @@ -967,7 +1045,7 @@ xqc_demo_cli_hq_req_write_notify(xqc_hq_request_t *hqr, void *req_user_data) void xqc_demo_path_status_trigger(xqc_demo_cli_user_conn_t *user_conn) { - xqc_msec_t ts_now = xqc_demo_now(), path_status_time = 0; + xqc_msec_t ts_now = xqc_now(), path_status_time = 0; if (user_conn->send_path_standby) { @@ -976,23 +1054,23 @@ xqc_demo_path_status_trigger(xqc_demo_cli_user_conn_t *user_conn) && xqc_conn_available_paths(user_conn->ctx->engine, &user_conn->cid) >= 2) { if (ts_now > user_conn->path_status_time + user_conn->path_status_timer_threshold) { - xqc_conn_mark_path_standby(user_conn->ctx->engine, &user_conn->cid, 0); + xqc_conn_mark_path_standby(user_conn->ctx->engine, &user_conn->cid, user_conn->ctx->args->quic_cfg.backup_path_id); user_conn->path_status = 1; /* 1:standby */ user_conn->path_status_time = ts_now; - printf("mark_path_standby: path_id=0 path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", - user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); + printf("mark_path_standby: path_id=%d path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", + user_conn->ctx->args->quic_cfg.backup_path_id, user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); } } else if (user_conn->path_status == 1) { if (ts_now > user_conn->path_status_time + user_conn->path_status_timer_threshold) { - xqc_conn_mark_path_available(user_conn->ctx->engine, &user_conn->cid, 0); + xqc_conn_mark_path_available(user_conn->ctx->engine, &user_conn->cid, user_conn->ctx->args->quic_cfg.backup_path_id); user_conn->path_status = 0; /* 0:available */ user_conn->path_status_time = ts_now; - printf("mark_path_available: path_id=0 path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", - user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); + printf("mark_path_available: path_id=%d path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", + user_conn->ctx->args->quic_cfg.backup_path_id, user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); } } } @@ -1036,7 +1114,7 @@ xqc_demo_cli_hq_req_read_notify(xqc_hq_request_t *hqr, void *req_user_data) if (fin) { user_stream->recv_fin = 1; - xqc_msec_t now_us = xqc_demo_now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" ">>>>>>>> user_stream[%p], req: %s, send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, @@ -1070,6 +1148,7 @@ xqc_demo_cli_hq_req_close_notify(xqc_hq_request_t *hqr, void *req_user_data) stats.send_body_size, stats.recv_body_size, stats.stream_info); /* task schedule */ + xqc_demo_cli_continue_send_reqs(user_stream->user_conn); xqc_demo_cli_on_stream_fin(user_stream); free(user_stream->send_buf); @@ -1089,7 +1168,7 @@ xqc_demo_cli_h3_request_send(xqc_demo_cli_user_stream_t *user_stream) if (!user_stream->hdr_sent) { if (user_stream->start_time == 0) { - user_stream->start_time = xqc_demo_now(); + user_stream->start_time = xqc_now(); } ret = xqc_h3_request_send_headers(user_stream->h3_request, &user_stream->h3_hdrs, 1); @@ -1191,12 +1270,13 @@ xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_no user_stream->recv_fin = 1; xqc_request_stats_t stats; stats = xqc_h3_request_get_stats(h3_request); - xqc_msec_t now_us = xqc_demo_now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" - ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", + ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n" + "stream_info:%s\n", now_us - user_stream->start_time, (stats.send_body_size + stats.recv_body_size) * 1000 / (now_us - user_stream->start_time), - stats.send_body_size, stats.recv_body_size); + stats.send_body_size, stats.recv_body_size, stats.stream_info); if (user_stream->recv_body_fp) { fclose(user_stream->recv_body_fp); @@ -1205,7 +1285,8 @@ xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_no // xqc_demo_cli_on_stream_fin(user_stream); task_idx = user_stream->user_conn->task->task_idx; if (ctx->schedule.schedule_info[task_idx].req_create_cnt - < ctx->tasks[task_idx].user_conn->task->req_cnt) + < ctx->tasks[task_idx].user_conn->task->req_cnt + && user_conn->ctx->args->req_cfg.serial) { if (user_conn->ctx->args->req_cfg.idle_gap) { @@ -1250,10 +1331,10 @@ xqc_demo_cli_h3_request_close_notify(xqc_h3_request_t *h3_request, void *user_da xqc_request_stats_t stats; stats = xqc_h3_request_get_stats(h3_request); printf("send_body_size:%zu, recv_body_size:%zu, send_header_size:%zu, recv_header_size:%zu, " - "recv_fin:%d, err:%d, rate_limit:%"PRIu64", mp_state:%d, avail_send_weight:%.3lf, avail_recv_weight:%.3lf\n", + "recv_fin:%d, err:%d, rate_limit:%"PRIu64", mp_state:%d, early_data:%d, avail_send_weight:%.3lf, avail_recv_weight:%.3lf, cwnd_blk:%"PRIu64"\n", stats.send_body_size, stats.recv_body_size, stats.send_header_size, stats.recv_header_size, - user_stream->recv_fin, stats.stream_err, stats.rate_limit, stats.mp_state, - stats.mp_default_path_send_weight, stats.mp_default_path_recv_weight); + user_stream->recv_fin, stats.stream_err, stats.rate_limit, stats.mp_state, stats.early_data_state, + stats.mp_default_path_send_weight, stats.mp_default_path_recv_weight, stats.cwnd_blocked_ms); printf("\033[33m[H3-req] send_bytes:%zu, recv_bytes:%zu, path_info:%s\n\033[0m", stats.send_body_size + stats.send_header_size, @@ -1304,7 +1385,7 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn, int fd) do { recv_size = recvfrom(user_path->fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *)&addr, &addr_len); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_sys_errno() == EAGAIN) { break; } @@ -1316,25 +1397,17 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn, int fd) xqc_int_t ret = getsockname(user_path->fd, (struct sockaddr*)&user_path->local_addr, &user_path->local_addrlen); if (ret != 0) { - printf("getsockname error, errno: %d\n", errno); + printf("getsockname error, errno: %d\n", get_sys_errno()); } recv_sum += recv_size; - uint64_t recv_time = xqc_demo_now(); + uint64_t recv_time = xqc_now(); user_path->last_sock_op_time = recv_time; -#ifdef XQC_NO_PID_PACKET_PROCESS if (xqc_engine_packet_process(user_conn->ctx->engine, packet_buf, recv_size, (struct sockaddr *)(&user_path->local_addr), user_path->local_addrlen, (struct sockaddr *)(&addr), addr_len, (xqc_msec_t)recv_time, user_conn) != XQC_OK) -#else - if (xqc_engine_packet_process(user_conn->ctx->engine, packet_buf, recv_size, - (struct sockaddr *)(&user_path->local_addr), - user_path->local_addrlen, (struct sockaddr *)(&addr), - addr_len, user_path->path_id, (xqc_msec_t)recv_time, - user_conn) != XQC_OK) -#endif { return; } @@ -1371,7 +1444,7 @@ xqc_demo_cli_socket_event_callback(int fd, short what, void *arg) static void xqc_demo_cli_engine_callback(int fd, short what, void *arg) { - // printf("timer wakeup now:%"PRIu64"\n", xqc_demo_now()); + // printf("timer wakeup now:%"PRIu64"\n", xqc_now()); xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); } @@ -1384,7 +1457,7 @@ xqc_demo_cli_idle_callback(int fd, short what, void *arg) xqc_demo_cli_user_path_t *user_path = (xqc_demo_cli_user_path_t*) arg; xqc_demo_cli_user_conn_t *user_conn = user_path->user_conn; - if (xqc_demo_now() - user_path->last_sock_op_time < (uint64_t)user_conn->ctx->args->net_cfg.conn_timeout * 1000000) { + if (xqc_now() - user_path->last_sock_op_time < (uint64_t)user_conn->ctx->args->net_cfg.conn_timeout * 1000000) { struct timeval tv; tv.tv_sec = user_conn->ctx->args->net_cfg.conn_timeout; tv.tv_usec = 0; @@ -1450,12 +1523,28 @@ static void xqc_demo_cli_delayed_req_start(int fd, short what, void *arg) { xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *) arg; + int batch_cnt = user_conn->ctx->args->req_cfg.batch_cnt; int req_cnt = user_conn->task->req_cnt; - if (user_conn->ctx->args->req_cfg.serial) { - req_cnt = req_cnt > 1 ? 1 : req_cnt; + if (batch_cnt) { + req_cnt = req_cnt > batch_cnt ? batch_cnt : req_cnt; } xqc_demo_cli_send_requests(user_conn, user_conn->ctx->args, user_conn->task->reqs, req_cnt); + + if (req_cnt > user_conn->ctx->task_ctx.schedule.schedule_info[user_conn->task->task_idx].req_create_cnt + && user_conn->ctx->args->req_cfg.idle_gap + && user_conn->ctx->args->req_cfg.batch_cnt) + { + + user_conn->ev_idle_restart = event_new(user_conn->ctx->eb, -1, 0, + xqc_demo_cli_delayed_idle_restart, + user_conn); + struct timeval tv = { + .tv_sec = user_conn->ctx->args->req_cfg.idle_gap / 1000, + .tv_usec = (user_conn->ctx->args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } static void @@ -1473,7 +1562,7 @@ xqc_demo_cli_close_path_timeout(int fd, short what, void *arg) xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *) arg; if (user_conn->active_path_cnt > 1) { - xqc_conn_close_path(user_conn->ctx->engine, &(user_conn->cid), user_conn->paths[1].path_id); + xqc_conn_close_path(user_conn->ctx->engine, &(user_conn->cid), user_conn->paths[user_conn->ctx->args->quic_cfg.close_path_id].path_id); } } @@ -1574,7 +1663,7 @@ void xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, xqc_demo_cli_client_args_t *args) { - xqc_cong_ctrl_callback_t cong_ctrl; + xqc_cong_ctrl_callback_t cong_ctrl = xqc_bbr_cb; switch (args->net_cfg.cc) { case CC_TYPE_BBR: cong_ctrl = xqc_bbr_cb; @@ -1583,7 +1672,11 @@ xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, case CC_TYPE_CUBIC: cong_ctrl = xqc_cubic_cb; break; - +#ifdef XQC_ENABLE_COPA + case CC_TYPE_COPA: + cong_ctrl = xqc_copa_cb; + break; +#endif #ifdef XQC_ENABLE_RENO case CC_TYPE_RENO: cong_ctrl = xqc_reno_cb; @@ -1611,9 +1704,9 @@ xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, settings->pacing_on = args->net_cfg.pacing; settings->cong_ctrl_callback = cong_ctrl; settings->cc_params.customize_on = 1, - settings->cc_params.init_cwnd = 32, + settings->cc_params.init_cwnd = 96, settings->so_sndbuf = 1024*1024; - settings->proto_version = XQC_VERSION_V1; + settings->proto_version = args->quic_cfg.quic_version; settings->spurious_loss_detect_on = 1; settings->keyupdate_pkt_threshold = args->quic_cfg.keyupdate_pkt_threshold; settings->enable_multipath = args->net_cfg.multipath; @@ -1625,10 +1718,16 @@ xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, settings->standby_path_probe_timeout = 1000; settings->multipath_version = args->quic_cfg.mp_version; settings->mp_ping_on = 1; + settings->is_interop_mode = args->quic_cfg.is_interop_mode; + settings->max_pkt_out_size = args->quic_cfg.max_pkt_sz; + settings->max_udp_payload_size = args->quic_cfg.max_pkt_sz; + settings->adaptive_ack_frequency = 1; + settings->init_max_path_id = args->quic_cfg.init_max_path_id; if (args->req_cfg.throttled_req != -1) { settings->enable_stream_rate_limit = 1; settings->recv_rate_bytes_per_sec = 0; } + strncpy(settings->conn_option_str, args->quic_cfg.co_str, XQC_CO_STR_MAX_LEN); } /* set client args to default values */ @@ -1641,6 +1740,8 @@ xqc_demo_cli_init_args(xqc_demo_cli_client_args_t *args) args->net_cfg.conn_timeout = 30; strncpy(args->net_cfg.server_addr, "127.0.0.1", sizeof(args->net_cfg.server_addr)); args->net_cfg.server_port = 8443; + args->net_cfg.addr_specified = 0; + args->net_cfg.port_specified = 0; /* env cfg */ args->env_cfg.log_level = XQC_LOG_DEBUG; @@ -1652,8 +1753,14 @@ xqc_demo_cli_init_args(xqc_demo_cli_client_args_t *args) args->quic_cfg.alpn_type = ALPN_HQ; strncpy(args->quic_cfg.alpn, "hq-interop", sizeof(args->quic_cfg.alpn)); args->quic_cfg.keyupdate_pkt_threshold = UINT64_MAX; - /* default 04 */ - args->quic_cfg.mp_version = XQC_MULTIPATH_04; + /* default 10 */ + args->quic_cfg.mp_version = XQC_MULTIPATH_10; + args->quic_cfg.init_max_path_id = 8; + args->quic_cfg.max_pkt_sz = 1200; + args->quic_cfg.recreate_path = 0; + args->quic_cfg.close_path_id = 1; + args->quic_cfg.backup_path_id = 1; + args->quic_cfg.quic_version = XQC_VERSION_V1; args->req_cfg.throttled_req = -1; @@ -1664,42 +1771,77 @@ xqc_demo_cli_parse_server_addr(char *url, xqc_demo_cli_net_config_t *cfg) { /* get hostname and port */ char s_port[16] = {0}; - sscanf(url, "%*[^://]://%[^:]:%[^/]", cfg->host, s_port); + char tmp[256] = {0}; + sscanf(url, "%*[^://]://%[^/]", tmp); + + if (strchr(tmp, ':') != NULL) { + sscanf(url, "%*[^://]://%[^:]:%[^/]", cfg->host, s_port); + } else { + sscanf(url, "%*[^://]://%[^/]", cfg->host); + } /* parse port */ - cfg->server_port = atoi(s_port); - - /* set hint for hostname resolve */ - struct addrinfo hints = {0}; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ - hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ - hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - hints.ai_protocol = 0; /* Any protocol */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - /* resolve server's ip from hostname */ - struct addrinfo *result = NULL; - int rv = getaddrinfo(cfg->host, s_port, &hints, &result); - if (rv != 0) { - printf("get addr info from hostname: %s\n", gai_strerror(rv)); - } - memcpy(&cfg->addr, result->ai_addr, result->ai_addrlen); - cfg->addr_len = result->ai_addrlen; - - /* convert to string. */ - if (result->ai_family == AF_INET6) { - inet_ntop(result->ai_family, &(((struct sockaddr_in6*)result->ai_addr)->sin6_addr), - cfg->server_addr, sizeof(cfg->server_addr)); + if (!cfg->port_specified) { + cfg->server_port = atoi(s_port); + } + + if (!cfg->addr_specified) { + /* set hint for hostname resolve */ + struct addrinfo hints = {0}; + memset(&hints, 0, sizeof(struct addrinfo)); + if (cfg->ipv6) { + hints.ai_family = AF_INET6; /* Allow IPv4 or IPv6 */ + } else { + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + } + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + /* resolve server's ip from hostname */ + struct addrinfo *result = NULL; + int rv = getaddrinfo(cfg->host, s_port, &hints, &result); + if (rv != 0) { + printf("get addr info from hostname: %s\n", gai_strerror(rv)); + } + memcpy(&cfg->addr, result->ai_addr, result->ai_addrlen); + cfg->addr_len = result->ai_addrlen; + + /* convert to string. */ + if (result->ai_family == AF_INET6) { + inet_ntop(result->ai_family, &(((struct sockaddr_in6*)result->ai_addr)->sin6_addr), + cfg->server_addr, sizeof(cfg->server_addr)); + } else { + inet_ntop(result->ai_family, &(((struct sockaddr_in*)result->ai_addr)->sin_addr), + cfg->server_addr, sizeof(cfg->server_addr)); + } + freeaddrinfo(result); } else { - inet_ntop(result->ai_family, &(((struct sockaddr_in*)result->ai_addr)->sin_addr), - cfg->server_addr, sizeof(cfg->server_addr)); + + if (strchr(cfg->server_addr, ':') != NULL) { + struct sockaddr_in6 *addr6 = &cfg->addr; + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(cfg->server_port); + inet_pton(AF_INET6, cfg->server_addr, &addr6->sin6_addr); + cfg->ipv6 = 1; + cfg->addr_len = sizeof(struct sockaddr_in6); + + } else { + struct sockaddr_in *addr4 = (struct sockaddr_in*)&cfg->addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(cfg->server_port); + inet_pton(AF_INET, cfg->server_addr, &addr4->sin_addr); + cfg->ipv6 = 0; + cfg->addr_len = sizeof(struct sockaddr_in); + } } + printf("server[%s] addr: %s:%d.\n", cfg->host, cfg->server_addr, cfg->server_port); - freeaddrinfo(result); + } void @@ -1741,12 +1883,12 @@ xqc_demo_cli_usage(int argc, char *argv[]) "Options:\n" " -a Server addr.\n" " -p Server port.\n" - " -c Congestion Control Algorithm. r:reno b:bbr c:cubic\n" + " -c Congestion Control Algorithm. r:reno b:bbr c:cubic P:copa\n" " -C Pacing on.\n" " -t Connection timeout. Default 3 seconds.\n" " -S cipher suites\n" " -0 use 0-RTT\n" - " -A alpn selection: h3/hq\n" + " -A alpn selection: h3/h3-29/hq\n" " -D save request body directory\n" " -l Log level. e:error d:debug.\n" " -L xquic log directory.\n" @@ -1756,22 +1898,32 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -u key update packet threshold\n" " -d do not save responses to files\n" " -M enable multipath\n" + " -o use interop mode\n" " -i interface to create a path. For instance, we can use '-i lo -i lo' to create two paths via lo.\n" " -w waiting N ms to start the first request.\n" " -P enable MPQUIC to return ACK_MPs on any paths.\n" " -s multipath scheduler (interop, minrtt, backup), default: interop\n" " -b set the second path as a backup path\n" " -Z close one path after X ms\n" + " -z path id to be closed\n" + " -q create path x if closed\n" " -N No encryption (default disabled)\n" " -Q Send requests one by one (default disabled)\n" " -T Throttle recving rate (Bps)\n" " -R Reinjection (1,2,4) \n" - " -V Multipath Version (4,5,6)\n" + " -V Multipath Version\n" " -B Set initial path standby after recvd first application data, and set initial path available after X ms\n" " -I Idle interval between requests (ms)\n" " -n Throttling the {1,2,...}xn-th requests\n" " -e NAT rebinding on path 0\n" " -E NAT rebinding on path 1\n" + " -F MTU size (default: 1200)\n" + " -G Google connection options (e.g. CBBR,TBBR)\n" + " -x Extend the number of requests to X\n" + " -r Send X requests per batch\n" + " -y cid rotation after x ms\n" + " -Y cid retirement after x ms\n" + " -f max path id\n" , prog); } @@ -1779,24 +1931,30 @@ void xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args) { int ch = 0; - while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMi:w:Ps:bZ:NQT:R:V:B:I:n:eE")) != -1) { + while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMoi:w:Ps:b:Z:NQT:R:V:B:I:n:eEF:G:r:x:y:Y:f:z:q6")) != -1) { switch (ch) { /* server ip */ + case '6': + printf("option ipv6\n"); + args->net_cfg.ipv6 = 1; + break; case 'a': printf("option addr :%s\n", optarg); snprintf(args->net_cfg.server_addr, sizeof(args->net_cfg.server_addr), optarg); + args->net_cfg.addr_specified = 1; break; /* server port */ case 'p': printf("option port :%s\n", optarg); args->net_cfg.server_port = atoi(optarg); + args->net_cfg.port_specified = 1; break; /* congestion control */ case 'c': printf("option cong_ctl :%s\n", optarg); - /* r:reno b:bbr c:cubic */ + /* r:reno b:bbr c:cubic p:copa */ switch (*optarg) { case 'b': args->net_cfg.cc = CC_TYPE_BBR; @@ -1807,6 +1965,9 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args case 'r': args->net_cfg.cc = CC_TYPE_RENO; break; + case 'P': + args->net_cfg.cc = CC_TYPE_COPA; + break; default: break; } @@ -1863,6 +2024,10 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args } else if (strcmp(optarg, "hq") == 0) { args->quic_cfg.alpn_type = ALPN_HQ; strncpy(args->quic_cfg.alpn, "hq-interop", 11); + } else if (strcmp(optarg, "h3-29") == 0) { + args->quic_cfg.alpn_type = ALPN_H3; + args->quic_cfg.quic_version = XQC_IDRAFT_VER_29; + strncpy(args->quic_cfg.alpn, "h3-29", 6); } break; @@ -1921,6 +2086,10 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args args->net_cfg.multipath = 1; break; + case 'o': + printf("set interop mode\n"); + args->quic_cfg.is_interop_mode = 1; + break; case 'i': printf("option adding interface: %s\n", optarg); if (args->net_cfg.ifcnt < MAX_PATH_CNT) { @@ -1947,8 +2116,9 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args break; case 'b': - printf("option backup path on\n"); + printf("option backup path on path %s\n", optarg); args->quic_cfg.mp_backup = 1; + args->quic_cfg.backup_path_id = atoi(optarg); break; case 'Z': @@ -1956,6 +2126,16 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args args->quic_cfg.close_path = atoi(optarg); break; + case 'z': + printf("option close path id:%s\n", optarg); + args->quic_cfg.close_path_id = atoi(optarg); + break; + + case 'q': + printf("option re-create path id\n"); + args->quic_cfg.recreate_path = 1; + break; + case 'N': printf("option no encryption on\n"); args->quic_cfg.no_encryption = 1; @@ -2007,12 +2187,55 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args args->net_cfg.rebind_p1 = 1; break; + case 'F': + printf("MTU size: %s\n", optarg); + args->quic_cfg.max_pkt_sz = atoi(optarg); + break; + + case 'G': + printf("Google connection options: %s\n", optarg); + strncpy(args->quic_cfg.co_str, optarg, XQC_CO_STR_MAX_LEN); + break; + + case 'r': + printf("Request batch: %s\n", optarg); + args->req_cfg.batch_cnt = atoi(optarg); + break; + + case 'x': + printf("Extend request number: %s\n", optarg); + args->req_cfg.ext_reqn = atoi(optarg); + break; + + case 'f': + printf("max concurrent paths: %s\n", optarg); + args->quic_cfg.init_max_path_id = atoi(optarg); + break; + default: printf("other option :%c\n", ch); xqc_demo_cli_usage(argc, argv); exit(0); } } + + if (args->req_cfg.ext_reqn + && args->req_cfg.request_cnt < args->req_cfg.ext_reqn) + { + for (ch = args->req_cfg.request_cnt; + ch < args->req_cfg.ext_reqn; ch++) + { + memcpy(&args->req_cfg.reqs[ch], + &args->req_cfg.reqs[ch - 1], + sizeof(xqc_demo_cli_request_t)); + } + args->req_cfg.request_cnt = args->req_cfg.ext_reqn; + } + + if (args->req_cfg.serial) { + args->req_cfg.batch_cnt = 1; + } + } #define MAX_REQ_BUF_LEN 1500 @@ -2191,12 +2414,24 @@ xqc_demo_cli_continue_send_reqs(xqc_demo_cli_user_conn_t *user_conn) int task_idx = user_conn->task->task_idx; int req_create_cnt = ctx->task_ctx.schedule.schedule_info[task_idx].req_create_cnt; int req_cnt = user_conn->task->req_cnt - req_create_cnt; - if (ctx->args->req_cfg.serial) { - req_cnt = req_cnt > 1 ? 1 : req_cnt; + if (ctx->args->req_cfg.batch_cnt) { + req_cnt = req_cnt > ctx->args->req_cfg.batch_cnt ? ctx->args->req_cfg.batch_cnt : req_cnt; } if (req_cnt > 0) { xqc_demo_cli_request_t *reqs = user_conn->task->reqs + req_create_cnt; xqc_demo_cli_send_requests(user_conn, ctx->args, reqs, req_cnt); + + if (user_conn->task->req_cnt > req_create_cnt + && ctx->args->req_cfg.idle_gap + && ctx->args->req_cfg.batch_cnt + && !ctx->args->req_cfg.serial) + { + struct timeval tv = { + .tv_sec = ctx->args->req_cfg.idle_gap / 1000, + .tv_usec = (ctx->args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } } @@ -2229,8 +2464,12 @@ xqc_demo_cli_h3_conn_close_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *)user_data; xqc_conn_stats_t stats = xqc_conn_get_stats(user_conn->ctx->engine, cid); printf("send_count:%u, lost_count:%u, tlp_count:%u, recv_count:%u, srtt:%"PRIu64" " - "early_data_flag:%d, conn_err:%d, ack_info:%s conn_info:%s\n", stats.send_count, stats.lost_count, - stats.tlp_count, stats.recv_count, stats.srtt, stats.early_data_flag, stats.conn_err, + "standby_bytes:%"PRIu64", total_bytes:%"PRIu64" " + "early_data_flag:%d, conn_err:%d, acked_max_mtu %u, ack_info:%s, conn_info:%s\n", + stats.send_count, stats.lost_count, + stats.tlp_count, stats.recv_count, stats.srtt, + stats.standby_path_app_bytes, stats.total_app_bytes, + stats.early_data_flag, stats.conn_err, stats.max_acked_mtu, stats.ack_info, stats.conn_info); xqc_demo_cli_on_task_finish(user_conn->ctx, user_conn->task); @@ -2275,7 +2514,8 @@ xqc_demo_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t static xqc_engine_callback_t callback = { .log_callbacks = { .xqc_log_write_err = xqc_demo_cli_write_log_file, - .xqc_log_write_stat = xqc_demo_cli_write_log_file + .xqc_log_write_stat = xqc_demo_cli_write_log_file, + .xqc_qlog_event_write = xqc_demo_cli_write_qlog_file, }, .keylog_cb = xqc_demo_cli_keylog_cb, .set_event_timer = xqc_demo_cli_set_event_timer, @@ -2422,16 +2662,19 @@ xqc_demo_cli_init_xquic_connection(xqc_demo_cli_user_conn_t *user_conn, memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); } else { - user_conn->hqc_handle = xqc_hq_connect(user_conn->ctx->engine, &conn_settings, + const xqc_cid_t *cid = xqc_hq_connect(user_conn->ctx->engine, &conn_settings, args->quic_cfg.token, args->quic_cfg.token_len, args->net_cfg.host, args->quic_cfg.no_encryption, &conn_ssl_config, (struct sockaddr*)&args->net_cfg.addr, args->net_cfg.addr_len, user_conn); - if (user_conn->hqc_handle == NULL) { + + if (cid == NULL) { return -1; } + + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); } if (conn_settings.enable_multipath - && conn_settings.multipath_version >= XQC_MULTIPATH_06 + && conn_settings.multipath_version >= XQC_MULTIPATH_10 && args->quic_cfg.send_path_standby == 1) { user_conn->send_path_standby = 1; @@ -2512,13 +2755,28 @@ xqc_demo_cli_start(xqc_demo_cli_user_conn_t *user_conn, xqc_demo_cli_client_args } else { /* TODO: fix MAX_STREAMS bug */ - if (args->req_cfg.serial) { - xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt > 1 ? 1 : req_cnt); + if (args->req_cfg.batch_cnt) { + xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt > args->req_cfg.batch_cnt ? args->req_cfg.batch_cnt : req_cnt); } else { xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt); } - + + if (req_cnt > user_conn->ctx->task_ctx.schedule.schedule_info[user_conn->task->task_idx].req_create_cnt + && args->req_cfg.idle_gap + && args->req_cfg.batch_cnt + && !args->req_cfg.serial) + { + + user_conn->ev_idle_restart = event_new(user_conn->ctx->eb, -1, 0, + xqc_demo_cli_delayed_idle_restart, + user_conn); + struct timeval tv = { + .tv_sec = args->req_cfg.idle_gap / 1000, + .tv_usec = (args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } } @@ -2583,30 +2841,36 @@ xqc_demo_cli_create_socket(xqc_demo_cli_user_path_t *user_path, int size; int fd = 0; int ret; + int flags = 1; struct sockaddr *addr = (struct sockaddr*)&cfg->addr; fd = socket(addr->sa_family, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_sys_errno()); return -1; } - +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_sys_errno()); goto err; } - +#endif size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } if (cfg->ifcnt) { +#if !defined(XQC_SYS_WINDOWS) struct ifreq ifr; memset(&ifr, 0x00, sizeof(ifr)); strncpy(ifr.ifr_name, cfg->iflist[path_seq], sizeof(ifr.ifr_name) - 1); @@ -2618,10 +2882,10 @@ xqc_demo_cli_create_socket(xqc_demo_cli_user_path_t *user_path, goto err; } #endif - +#endif } - user_path->last_sock_op_time = xqc_demo_now(); + user_path->last_sock_op_time = xqc_now(); return fd; @@ -2700,6 +2964,7 @@ xqc_demo_cli_handle_task(xqc_demo_cli_ctx_t *ctx, xqc_demo_cli_task_t *task) xqc_demo_cli_user_conn_t *user_conn = calloc(1, sizeof(xqc_demo_cli_user_conn_t)); user_conn->ctx = ctx; user_conn->task = task; + user_conn->recreate_path_seq = -1; /* init the first path */ if (xqc_demo_cli_init_user_path(user_conn, 0, 0)) { @@ -2872,6 +3137,9 @@ xqc_demo_cli_free_ctx(xqc_demo_cli_ctx_t *ctx) int main(int argc, char *argv[]) { + /* init env if necessary */ + xqc_platform_init_env(); + /* get input client args */ xqc_demo_cli_client_args_t *args = calloc(1, sizeof(xqc_demo_cli_client_args_t)); xqc_demo_cli_init_args(args); diff --git a/demo/demo_server.c b/demo/demo_server.c index 9d7554655..4ce2ad4ae 100644 --- a/demo/demo_server.c +++ b/demo/demo_server.c @@ -7,22 +7,35 @@ #include #include #include -#include #include -#include #include +#include #include #include #include #include #include -#include +#include "../tests/platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include "../tests/getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#pragma comment(lib, "crypt32") +#endif + #include "common.h" #include "xqc_hq.h" + #define XQC_PACKET_TMP_BUF_LEN 1500 #define MAX_BUF_SIZE (100*1024*1024) @@ -89,6 +102,10 @@ typedef struct xqc_demo_svr_quic_config_s { /* multipath version */ int multipath_version; + + int max_initial_paths; + /* support interop test */ + int is_interop_mode; /* ack on any path */ int mp_ack_on_any_path; @@ -100,6 +117,8 @@ typedef struct xqc_demo_svr_quic_config_s { uint64_t keyupdate_pkt_threshold; uint64_t least_available_cid_count; + + size_t max_pkt_sz; } xqc_demo_svr_quic_config_t; @@ -279,15 +298,33 @@ xqc_demo_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v int write_len = write(ctx->log_fd, buf, size); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_sys_errno()); return; } write_len = write(ctx->log_fd, line_break, 1); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_sys_errno()); } } +void +xqc_demo_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *eng_user_data) +{ + xqc_demo_svr_ctx_t *ctx = (xqc_demo_svr_ctx_t*)eng_user_data; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} /** * start of server keylog functions @@ -326,12 +363,12 @@ xqc_demo_svr_keylog_cb(const xqc_cid_t *scid, const char *line, void *eng_user_d int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); return; } write_len = write(ctx->keylog_fd, line_break, 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); } } @@ -546,7 +583,11 @@ xqc_demo_svr_handle_hq_request(xqc_demo_svr_user_stream_t *user_stream, xqc_hq_r } /* get total len */ fseek(user_stream->res.fp, 0, SEEK_END); +#ifdef XQC_SYS_WINDOWS + user_stream->res.total_len = ftell(user_stream->res.fp); +#else user_stream->res.total_len = ftello(user_stream->res.fp); +#endif fseek(user_stream->res.fp, 0, SEEK_SET); } else { @@ -704,6 +745,9 @@ int xqc_demo_svr_h3_request_close_notify(xqc_h3_request_t *h3_request, void *strm_user_data) { DEBUG; + xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); + printf("cwnd_blocked:%"PRIu64"\n", stats.cwnd_blocked_ms); + xqc_demo_svr_user_stream_t *user_stream = (xqc_demo_svr_user_stream_t*)strm_user_data; xqc_demo_svr_close_user_stream_resource(user_stream); free(user_stream); @@ -737,7 +781,6 @@ xqc_demo_svr_request_send_body(xqc_demo_svr_user_stream_t *user_stream, char *da if (ret == -XQC_EAGAIN) { ret = 0; } - return ret; } @@ -839,7 +882,11 @@ xqc_demo_svr_handle_h3_request(xqc_demo_svr_user_stream_t *user_stream, } /* get total len */ fseek(user_stream->res.fp, 0, SEEK_END); +#ifdef XQC_SYS_WINDOWS + user_stream->res.total_len = ftell(user_stream->res.fp); +#else user_stream->res.total_len = ftello(user_stream->res.fp); +#endif fseek(user_stream->res.fp, 0, SEEK_SET); } else { @@ -976,15 +1023,16 @@ xqc_demo_svr_write_socket(const unsigned char *buf, size_t size, const struct so int fd = svr_ctx.current_fd; do { - errno = 0; + set_sys_errno(0); res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); if (res < 0) { - printf("xqc_demo_svr_write_socket err %zd %s, fd: %d\n", res, strerror(errno), fd); - if (errno == EAGAIN) { + printf("xqc_demo_svr_write_socket err %zd %s, fd: %d\n", + res, strerror(get_sys_errno()), fd); + if (get_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (get_sys_errno() == EINTR)); return res; } @@ -1017,28 +1065,21 @@ xqc_demo_svr_socket_read_handler(xqc_demo_svr_ctx_t *ctx, int fd) do { recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *) &peer_addr, &peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(errno)); + printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); break; } recv_sum += recv_size; - uint64_t recv_time = xqc_demo_now(); -#ifdef XQC_NO_PID_PACKET_PROCESS + uint64_t recv_time = xqc_now(); xqc_int_t ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, (struct sockaddr *)(&ctx->local_addr), ctx->local_addrlen, (struct sockaddr *)(&peer_addr), peer_addrlen, (xqc_usec_t)recv_time, ctx); -#else - xqc_int_t ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, - (struct sockaddr *)(&ctx->local_addr), ctx->local_addrlen, - (struct sockaddr *)(&peer_addr), peer_addrlen, XQC_UNKNOWN_PATH_ID, - (xqc_usec_t)recv_time, ctx); -#endif if (ret != XQC_OK) { printf("server_read_handler: packet process err, ret: %d\n", ret); return; @@ -1075,39 +1116,47 @@ xqc_demo_svr_init_socket(int family, uint16_t port, { int size; int opt_reuseaddr; + int flags = 1; int fd = socket(family, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_sys_errno()); return -1; } /* non-block */ +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_sys_errno()); goto err; } +#endif /* reuse port */ opt_reuseaddr = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt_reuseaddr, sizeof(opt_reuseaddr)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } /* send/recv buffer size */ size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } /* bind port */ if (bind(fd, local_addr, local_addrlen) < 0) { - printf("bind socket failed, family: %d, errno: %d, %s\n", family, errno, strerror(errno)); + printf("bind socket failed, family: %d, errno: %d, %s\n", family, + get_sys_errno(), strerror(get_sys_errno())); goto err; } @@ -1171,7 +1220,7 @@ xqc_demo_svr_usage(int argc, char *argv[]) "\n" "Options:\n" " -p Server port.\n" - " -c Congestion Control Algorithm. r:reno b:bbr c:cubic\n" + " -c Congestion Control Algorithm. r:reno b:bbr c:cubic P:copa \n" " -C Pacing on.\n" " -l Log level. e:error d:debug.\n" " -L xquic log directory.\n" @@ -1179,11 +1228,13 @@ xqc_demo_svr_usage(int argc, char *argv[]) " -k Key output file path\n" " -r retry\n" " -d do not read responses from files\n" + " -i use interop mode\n" " -M enable MPQUIC.\n" " -P enable MPQUIC to return ACK_MPs on any paths.\n" " -s multipath scheduler (interop, minrtt, backup), default: interop\n" " -R Reinjection (1,2,4) \n" " -u Keyupdate packet threshold\n" + " -F MTU size (default: 1200)\n" , prog); } @@ -1222,13 +1273,14 @@ xqc_demo_svr_init_args(xqc_demo_svr_args_t *args) args->quic_cfg.keyupdate_pkt_threshold = UINT64_MAX; args->quic_cfg.least_available_cid_count = 1; + args->quic_cfg.max_pkt_sz = 1200; } void xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) { int ch = 0; - while ((ch = getopt(argc, argv, "p:c:CD:l:L:6k:rdMPs:R:u:a:")) != -1) { + while ((ch = getopt(argc, argv, "p:c:CD:l:L:6k:rdMiPs:R:u:a:F:f:")) != -1) { switch (ch) { /* listen port */ case 'p': @@ -1239,7 +1291,7 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) /* congestion control */ case 'c': printf("option cong_ctl :%s\n", optarg); - /* r:reno b:bbr c:cubic */ + /* r:reno b:bbr c:cubic P:copa */ switch (*optarg) { case 'b': args->net_cfg.cc = CC_TYPE_BBR; @@ -1250,6 +1302,9 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) case 'r': args->net_cfg.cc = CC_TYPE_RENO; break; + case 'P': + args->net_cfg.cc = CC_TYPE_COPA; + break; default: break; } @@ -1303,16 +1358,16 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) args->quic_cfg.dummy_mode = 1; break; + case 'i': + printf("set interop mode\n"); + args->quic_cfg.is_interop_mode = 1; + break; + case 'M': printf("option multipath enabled\n"); args->quic_cfg.multipath = 1; break; - case 'V': - printf("option multipath version: %s\n", optarg); - args->quic_cfg.multipath_version = atoi(optarg); - break; - case 'P': printf("option ACK_MP on any path enabled\n"); args->quic_cfg.mp_ack_on_any_path = 1; @@ -1338,6 +1393,16 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) args->quic_cfg.least_available_cid_count = atoi(optarg); break; + case 'F': + printf("MTU size: %s\n", optarg); + args->quic_cfg.max_pkt_sz = atoi(optarg); + break; + + case 'f': + printf("option init_max_path_id: %s\n", optarg); + args->quic_cfg.max_initial_paths = atoi(optarg); + break; + default: printf("other option :%c\n", ch); xqc_demo_svr_usage(argc, argv); @@ -1354,7 +1419,8 @@ xqc_demo_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t .set_event_timer = xqc_demo_svr_set_event_timer, .log_callbacks = { .xqc_log_write_err = xqc_demo_svr_write_log_file, - .xqc_log_write_stat = xqc_demo_svr_write_log_file + .xqc_log_write_stat = xqc_demo_svr_write_log_file, + .xqc_qlog_event_write = xqc_demo_svr_write_qlog_file }, .keylog_cb = xqc_demo_svr_keylog_cb, }; @@ -1402,7 +1468,7 @@ xqc_demo_svr_init_ssl_config(xqc_engine_ssl_config_t *cfg, xqc_demo_svr_args_t * } void -xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) +xqc_demo_svr_init_conn_settings(xqc_engine_t *engine, xqc_demo_svr_args_t *args) { xqc_cong_ctrl_callback_t ccc = {0}; switch (args->net_cfg.cc) { @@ -1412,6 +1478,11 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) case CC_TYPE_CUBIC: ccc = xqc_cubic_cb; break; +#ifdef XQC_ENABLE_COPA + case CC_TYPE_COPA: + ccc = xqc_copa_cb; + break; +#endif #ifdef XQC_ENABLE_RENO case CC_TYPE_RENO: ccc = xqc_reno_cb; @@ -1421,7 +1492,7 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) break; } - xqc_scheduler_callback_t sched; + xqc_scheduler_callback_t sched = {0}; if (strncmp(args->quic_cfg.mp_sched, "minrtt", strlen("minrtt")) == 0) { sched = xqc_minrtt_scheduler_cb; @@ -1441,11 +1512,12 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) .cc_params = { .customize_on = 1, .init_cwnd = 32, + .bbr_enable_lt_bw = 1, }, .spurious_loss_detect_on = 1, .init_idle_time_out = 60000, .enable_multipath = args->quic_cfg.multipath, - .multipath_version = args->quic_cfg.multipath_version, + .init_max_path_id = args->quic_cfg.max_initial_paths, .mp_ack_on_any_path = args->quic_cfg.mp_ack_on_any_path, .scheduler_callback = sched, .reinj_ctl_callback = xqc_deadline_reinj_ctl_cb, @@ -1453,9 +1525,12 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) .standby_path_probe_timeout = 1000, .keyupdate_pkt_threshold = args->quic_cfg.keyupdate_pkt_threshold, .least_available_cid_count = args->quic_cfg.least_available_cid_count, + .is_interop_mode = args->quic_cfg.is_interop_mode, + .max_pkt_out_size = args->quic_cfg.max_pkt_sz, + .adaptive_ack_frequency = 1, }; - xqc_server_set_conn_settings(&conn_settings); + xqc_server_set_conn_settings(engine, &conn_settings); } @@ -1522,9 +1597,6 @@ xqc_demo_svr_init_xquic_engine(xqc_demo_svr_ctx_t *ctx, xqc_demo_svr_args_t *arg xqc_transport_callbacks_t transport_cbs; xqc_demo_svr_init_callback(&callback, &transport_cbs, args); - /* init server connection settings */ - xqc_demo_svr_init_conn_settings(args); - /* init engine config */ xqc_config_t config; if (xqc_engine_get_default_config(&config, XQC_ENGINE_CLIENT) < 0) { @@ -1559,6 +1631,9 @@ xqc_demo_svr_init_xquic_engine(xqc_demo_svr_ctx_t *ctx, xqc_demo_svr_args_t *arg return -1; } + /* init server connection settings */ + xqc_demo_svr_init_conn_settings(ctx->engine, args); + if (xqc_demo_svr_init_alpn_ctx(ctx) < 0) { printf("init alpn ctx error!"); return -1; @@ -1607,6 +1682,9 @@ th3_demo_proxy_sig_hndlr(int signo) int main(int argc, char *argv[]) { + /* init env if necessary */ + xqc_platform_init_env(); + signal(SIGTERM, th3_demo_proxy_sig_hndlr); /* get input server args */ diff --git a/demo/xqc_hq.h b/demo/xqc_hq.h index 6b302d712..95d0e5e4f 100644 --- a/demo/xqc_hq.h +++ b/demo/xqc_hq.h @@ -99,7 +99,7 @@ xqc_hq_ctx_destroy(xqc_engine_t *engine); * @brief hq connection functions */ -xqc_hq_conn_t * +const xqc_cid_t * xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const unsigned char *token, unsigned token_len, const char *server_host, int no_crypto_flag, const xqc_conn_ssl_config_t *conn_ssl_config, const struct sockaddr *peer_addr, diff --git a/demo/xqc_hq_conn.c b/demo/xqc_hq_conn.c index 035cfc231..653c25d39 100644 --- a/demo/xqc_hq_conn.c +++ b/demo/xqc_hq_conn.c @@ -11,18 +11,6 @@ #include "src/transport/xqc_conn.h" -typedef struct xqc_hq_conn_s { - xqc_hq_conn_callbacks_t *hqc_cbs; - - xqc_connection_t *conn; - - xqc_log_t *log; - - void *user_data; - -} xqc_hq_conn_s; - - xqc_hq_conn_t * xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data) { @@ -31,7 +19,12 @@ xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data return NULL; } - if (xqc_hq_ctx_get_conn_callbacks(&hqc->hqc_cbs) != XQC_OK) { + xqc_hq_callbacks_t *hq_cbs = NULL; + xqc_int_t ret; + + ret = xqc_hq_ctx_get_callbacks(conn->engine, conn->alpn, conn->alpn_len, &hq_cbs); + + if (ret != XQC_OK || hq_cbs == NULL) { PRINT_LOG("|create hq conn failed"); xqc_free(hqc); return NULL; @@ -40,6 +33,10 @@ xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data hqc->user_data = user_data; hqc->log = conn->log; hqc->conn = conn; + hqc->hqc_cbs = hq_cbs->hqc_cbs; + hqc->hqr_cbs = hq_cbs->hqr_cbs; + + xqc_conn_set_alp_user_data(conn, hqc); return hqc; } @@ -53,22 +50,7 @@ xqc_hq_conn_destroy(xqc_hq_conn_t *hqc) } } - -xqc_hq_conn_t * -xqc_hq_conn_create_passive(xqc_connection_t *conn, const xqc_cid_t *cid) -{ - xqc_hq_conn_t *hqc = xqc_hq_conn_create(conn, cid, NULL); - if (NULL == hqc) { - PRINT_LOG("|create hq conn failed"); - return NULL; - } - - xqc_conn_set_alp_user_data(conn, hqc); - return hqc; -} - - -xqc_hq_conn_t * +const xqc_cid_t* xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const unsigned char *token, unsigned token_len, const char *server_host, int no_crypto_flag, const xqc_conn_ssl_config_t *conn_ssl_config, const struct sockaddr *peer_addr, @@ -78,18 +60,8 @@ xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const xqc_cid_t *cid = xqc_connect(engine, conn_settings, token, token_len, server_host, no_crypto_flag, conn_ssl_config, peer_addr, peer_addrlen, xqc_hq_alpn[conn_settings->proto_version], user_data); - if (cid == NULL) { - return NULL; - } - - xqc_hq_conn_t *hqc = xqc_hq_conn_create(xqc_engine_conns_hash_find(engine, cid, 's'), - cid, user_data); - if (NULL == hqc) { - xqc_conn_close(engine, cid); - return NULL; - } - return hqc; + return cid; } @@ -125,12 +97,9 @@ xqc_hq_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, return -XQC_EMALLOC; } - /* set hqc as conn's application-layer-protocol user_data */ - xqc_conn_set_alp_user_data(conn, hqc); - - if (hqc->hqc_cbs->conn_create_notify) { + if (hqc->hqc_cbs.conn_create_notify) { /* NOTICE: if hqc is created passively, hqc->user_data is NULL */ - return hqc->hqc_cbs->conn_create_notify(hqc, cid, hqc->user_data); + return hqc->hqc_cbs.conn_create_notify(hqc, cid, hqc->user_data); } return XQC_OK; @@ -143,8 +112,8 @@ xqc_hq_conn_close_notify(xqc_connection_t *conn, const xqc_cid_t *cid, xqc_int_t ret = XQC_OK; xqc_hq_conn_t *hqc = (xqc_hq_conn_t *)conn_proto_data; - if (hqc->hqc_cbs->conn_close_notify) { - ret = hqc->hqc_cbs->conn_close_notify(hqc, cid, hqc->user_data); + if (hqc->hqc_cbs.conn_close_notify) { + ret = hqc->hqc_cbs.conn_close_notify(hqc, cid, hqc->user_data); if (ret != XQC_OK) { return ret; } diff --git a/demo/xqc_hq_conn.h b/demo/xqc_hq_conn.h index 722605aae..bef782e2e 100644 --- a/demo/xqc_hq_conn.h +++ b/demo/xqc_hq_conn.h @@ -7,6 +7,19 @@ #include "xqc_hq.h" +typedef struct xqc_hq_conn_s { + + xqc_hq_conn_callbacks_t hqc_cbs; + xqc_hq_request_callbacks_t hqr_cbs; + + xqc_connection_t *conn; + + xqc_log_t *log; + + void *user_data; + +} xqc_hq_conn_s; + extern const xqc_conn_callbacks_t hq_conn_callbacks; #endif \ No newline at end of file diff --git a/demo/xqc_hq_ctx.c b/demo/xqc_hq_ctx.c index efd30465a..e6b2c1cc9 100644 --- a/demo/xqc_hq_ctx.c +++ b/demo/xqc_hq_ctx.c @@ -15,9 +15,18 @@ typedef struct xqc_hq_ctx_s { xqc_hq_callbacks_t hq_cbs; } xqc_hq_ctx_t; +xqc_hq_ctx_t* +xqc_hq_ctx_create(xqc_hq_callbacks_t *hq_cbs) +{ + xqc_hq_ctx_t *hq_ctx = NULL; -xqc_hq_ctx_t *hq_ctx = NULL; + hq_ctx = xqc_malloc(sizeof(xqc_hq_callbacks_t)); + if (hq_ctx) { + hq_ctx->hq_cbs = *hq_cbs; + } + return hq_ctx; +} xqc_int_t xqc_hq_ctx_init(xqc_engine_t *engine, xqc_hq_callbacks_t *hq_cbs) @@ -26,65 +35,77 @@ xqc_hq_ctx_init(xqc_engine_t *engine, xqc_hq_callbacks_t *hq_cbs) return -XQC_EPARAM; } - if (hq_ctx == NULL) { - hq_ctx = xqc_malloc(sizeof(xqc_hq_callbacks_t)); - if (NULL == hq_ctx) { - return -XQC_EMALLOC; - } - } - - hq_ctx->hq_cbs = *hq_cbs; - + xqc_hq_ctx_t *hq_ctx; + xqc_int_t ret = XQC_OK; xqc_app_proto_callbacks_t ap_cbs = { .conn_cbs = hq_conn_callbacks, .stream_cbs = hq_stream_callbacks }; + hq_ctx = xqc_hq_ctx_create(hq_cbs); + if (hq_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + /* register ALPN and Application-Layer-Protocol callbacks */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN, &ap_cbs) != XQC_OK - || xqc_engine_register_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN, &ap_cbs) != XQC_OK) - { - xqc_hq_ctx_destroy(engine); - return -XQC_EFATAL; + if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN, &ap_cbs, hq_ctx) != XQC_OK) { + xqc_free(hq_ctx); + ret = -XQC_EFATAL; + goto error; } - return XQC_OK; + hq_ctx = xqc_hq_ctx_create(hq_cbs); + if (hq_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + + /* register ALPN and Application-Layer-Protocol callbacks */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN, &ap_cbs, hq_ctx) != XQC_OK) { + xqc_free(hq_ctx); + ret = -XQC_EFATAL; + goto error; + } + + return ret; +error: + xqc_hq_ctx_destroy(engine); + return ret; } xqc_int_t xqc_hq_ctx_destroy(xqc_engine_t *engine) { - xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); - xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); + xqc_hq_ctx_t *hq_ctx; + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); if (hq_ctx) { xqc_free(hq_ctx); - hq_ctx = NULL; } - return XQC_OK; -} - -xqc_int_t -xqc_hq_ctx_get_conn_callbacks(xqc_hq_conn_callbacks_t **hqc_cbs) -{ - if (NULL == hq_ctx || NULL == hqc_cbs) { - return -XQC_EFATAL; + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); + if (hq_ctx) { + xqc_free(hq_ctx); } - *hqc_cbs = &hq_ctx->hq_cbs.hqc_cbs; + xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); + xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); return XQC_OK; } - xqc_int_t -xqc_hq_ctx_get_request_callbacks(xqc_hq_request_callbacks_t **hqr_cbs) +xqc_hq_ctx_get_callbacks(xqc_engine_t *engine, char *alpn, size_t alpn_len, xqc_hq_callbacks_t **hq_cbs) { - if (NULL == hq_ctx || NULL == hqr_cbs) { + xqc_hq_ctx_t *hq_ctx; + + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); + + if (hq_ctx == NULL) { return -XQC_EFATAL; } - *hqr_cbs = &hq_ctx->hq_cbs.hqr_cbs; + *hq_cbs = &hq_ctx->hq_cbs; return XQC_OK; -} +} \ No newline at end of file diff --git a/demo/xqc_hq_ctx.h b/demo/xqc_hq_ctx.h index d0bf43ad7..961e6fca2 100644 --- a/demo/xqc_hq_ctx.h +++ b/demo/xqc_hq_ctx.h @@ -7,11 +7,7 @@ #include "xqc_hq.h" -xqc_int_t -xqc_hq_ctx_get_conn_callbacks(xqc_hq_conn_callbacks_t **hqc_cbs); - -xqc_int_t -xqc_hq_ctx_get_request_callbacks(xqc_hq_request_callbacks_t **hqr_cbs); +xqc_int_t xqc_hq_ctx_get_callbacks(xqc_engine_t *engine, char *alpn, size_t alpn_len, xqc_hq_callbacks_t **hq_cbs); #endif diff --git a/demo/xqc_hq_request.c b/demo/xqc_hq_request.c index a5eb915ba..8b0454ac5 100644 --- a/demo/xqc_hq_request.c +++ b/demo/xqc_hq_request.c @@ -78,11 +78,7 @@ xqc_hq_request_create(xqc_engine_t *engine, xqc_hq_conn_t *hqc, const xqc_cid_t return NULL; } - /* init app-level callbacks */ - if (xqc_hq_ctx_get_request_callbacks(&hqr->hqr_cbs) != XQC_OK) { - PRINT_LOG("get app-level request callbacks error\n"); - goto fail; - } + hqr->hqr_cbs = &hqc->hqr_cbs; /* create stream, make hqr the user_data of xqc_stream_t */ stream = xqc_stream_create(engine, cid, NULL, hqr); @@ -114,12 +110,9 @@ xqc_hq_request_create_passive(xqc_stream_t *stream) return NULL; } - /* init app-level callbacks */ - if (xqc_hq_ctx_get_request_callbacks(&hqr->hqr_cbs) != XQC_OK) { - PRINT_LOG("get app-level request callbacks error"); - xqc_hq_request_destroy(hqr); - return NULL; - } + xqc_hq_conn_t *hqc = xqc_get_conn_alp_user_data_by_stream(stream); + + hqr->hqr_cbs = &hqc->hqr_cbs; /* make hqr the user_data of xqc_stream_t */ xqc_stream_set_user_data(stream, hqr); diff --git a/docs/Features.md b/docs/Features.md new file mode 100644 index 000000000..9831f39e9 --- /dev/null +++ b/docs/Features.md @@ -0,0 +1,34 @@ +# Features +## qlog +Based on qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/), [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/) and [draft-ietf-quic-qlog-h3-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-h3-events/)),xquic implements quic event logging. + +### Activate qlog by DXQC_ENABLE_EVENT_LOG +```shell +cd build +rm -rf * +# add "-DXQC_ENABLE_EVENT_LOG=1" +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +make -j +``` +### Example +Qlog defines three event importance levels, in decreasing order of importance and expected usage: core, base, extra. The level can be set by "--qlog_importance" argument: +```shell +./tests/test_server -l e -e --qlog_importance extra + +./tests/test_client -s 10240 -l e -t 1 -E --qlog_importance extra +``` + +To disable qlog, using "--qlog_disable": +```shell +./tests/test_server -l e -e --qlog_disable + +./tests/test_client -s 10240 -l e -t 1 -E --qlog_disable +``` + +### JSON format serialization +```shell +python ../scripts/qlog_parser.py --clog clog --slog slog --qlog_path demo_qlog.json +``` + + diff --git a/docs/Platforms.md b/docs/Platforms.md index 73ddf1497..2340eba10 100644 --- a/docs/Platforms.md +++ b/docs/Platforms.md @@ -1,17 +1,17 @@ # Platforms docs -XQUIC currently supports `Android` , `iOS` , `Linux` and `macOS` . +XQUIC currently supports `Android` , `iOS` , `HarmonyOS` , `Linux` , `macOS` and `Windows` . -## Android/iOS Compile Script +## Android/iOS/HarmonyOS Compile Script -The Android and iOS use `.so` files, there is a [ `xqc_build.sh` ](../xqc_build.sh) script in the XQUIC library directory, execute the script to compile to complete the corresponding compilation. +The Android, iOS and HarmonyOS use `.so` files, there is a [ `xqc_build.sh` ](../xqc_build.sh) script in the XQUIC library directory, execute the script to compile to complete the corresponding compilation. ```bash -sh xqc_build.sh ios/android +sh xqc_build.sh ios/android/harmony ``` specially, ` can be ${PWD}/third_party/boringssl or ${PWD}/third_party/babassl` -> Note: You need to specify the IOS/android build toolchain before compiling, download and set the environment variable IOS_CMAKE_TOOLCHAIN or ANDROID_NDK, or directly modify CMAKE_TOOLCHAIN_FILE in `xqc_build.sh` . +> Note: You need to specify the IOS/android/harmony build toolchain before compiling, download and set the environment variable IOS_CMAKE_TOOLCHAIN or ANDROID_NDK or HMOS_CMAKE_PATH and HMOS_CMAKE_TOOLCHAIN, or directly modify CMAKE_TOOLCHAIN_FILE and HMOS_CMAKE_TOOLCHAIN in `xqc_build.sh` . ## Linux Release @@ -103,14 +103,13 @@ cd ../../../ # step 3:build xquic mkdir build cd build -cmake -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. +cmake -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. MSBuild.exe xquic.vcxproj # build demo && test -git clone https://github.com/alex85k/wingetopt.git third_party/wingetopt #eg: cmake -DEVENT_LIB_DIR=D:/project/vcpkg/packages/libevent_x64-windows-static .. -cmake -DXQC_ENABLE_TESTING=1 -DEVENT_LIB_DIR=your_event_path .. +cmake -DXQC_ENABLE_TESTING=1 -DLIBEVENT_DIR=your_event_path .. MSBuild.exe demo_client.vcxproj MSBuild.exe demo_server.vcxproj diff --git a/docs/docs-zh/Features-zh.md b/docs/docs-zh/Features-zh.md new file mode 100644 index 000000000..1765c56c7 --- /dev/null +++ b/docs/docs-zh/Features-zh.md @@ -0,0 +1,34 @@ +# Features +## qlog +基于 qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/)、[draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/) 和 [draft-ietf-quic-qlog-h3-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-h3-events/)),xquic 实现了 quic 事件记录。 +### 编译参数 DXQC_ENABLE_EVENT_LOG 开启 qlog +```shell +cd build +rm -rf * +# 添加 "-DXQC_ENABLE_EVENT_LOG=1" 参数 +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +make -j +``` +### 运行测试 +按重要性,qlog 将事件分为 core、base、extra 三个 importance level,可以通过 --qlog_importance 设置: +```shell +./tests/test_server -l e -e --qlog_importance extra + +./tests/test_client -s 10240 -l e -t 1 -E --qlog_importance extra +``` + +通过 --qlog_disable 关闭 qlog: +```shell +./tests/test_server -l e -e --qlog_disable + +./tests/test_client -s 10240 -l e -t 1 -E --qlog_disable +``` + +### JSON 格式转换 +执行 qlog_parser.py 脚本工具,将 xquic log 转换 json 格式 qlog. +```shell +python ../scripts/qlog_parser.py --clog clog --slog slog --qlog_path demo_qlog.json +``` + + diff --git a/docs/docs-zh/README-zh.md b/docs/docs-zh/README-zh.md index bf8393313..6babc927a 100644 --- a/docs/docs-zh/README-zh.md +++ b/docs/docs-zh/README-zh.md @@ -24,28 +24,37 @@ XQUIC 支持 BoringSSL 和 BabaSSL。 -### 使用 BabaSSL 编译 +### 使用 BabaSSL(Tongsuo) 编译 ```bash # 获取 XQUIC 源码 git clone https://github.com/alibaba/xquic.git cd xquic -# 编译 BabaSSL +# 编译 BabaSSL(Tongsuo) git clone -b 8.3-stable https://github.com/Tongsuo-Project/Tongsuo.git ./third_party/babassl cd ./third_party/babassl/ ./config --prefix=/usr/local/babassl make -j SSL_TYPE_STR="babassl" SSL_PATH_STR="${PWD}" -SSL_INC_PATH_STR="${PWD}/include" -SSL_LIB_PATH_STR="${PWD}/libssl.a;${PWD}/libcrypto.a" cd - -# 使用 BabaSSL 编译 XQUIC +# 使用 BabaSSL(Tongsuo) 编译 XQUIC +# 选择BabaSSL编译XQUIC时,会默认从/usr/local/babassl寻找头文件、依赖库,如果BabaSSL在其 +# 他位置,可以通过SSL_PATH指定位置。 +# 在编译测试程序时,依赖了libevent、CUnit,默认会从系统安装路径下寻找,如果用户部署在特定位置 +# 下,可以通过-DCUNIT_DIR、-DLIBEVENT_DIR指定目录。 git submodule update --init --recursive mkdir -p build; cd build -cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +# 如果CMake发生错误,则结束编译 +if [ $? -ne 0 ]; then + echo "cmake failed" + exit 1 +fi + make -j ``` @@ -65,14 +74,23 @@ make ssl crypto cd .. SSL_TYPE_STR="boringssl" SSL_PATH_STR="${PWD}" -SSL_INC_PATH_STR="${PWD}/include" -SSL_LIB_PATH_STR="${PWD}/build/ssl/libssl.a;${PWD}/build/crypto/libcrypto.a" cd ../.. # 使用 BoringSSL 编译 XQUIC +# 选择boringssl编译XQUIC时,会默认从源码third_party/boringssl寻找头文件、依赖库,如果 +# boringssl在其他位置,可以通过SSL_PATH指定位置。 +# 在编译测试程序时,依赖了libevent、CUnit,默认会从系统安装路径下寻找,如果用户部署在特定位置 +# 下,可以通过-DCUNIT_DIR、-DLIBEVENT_DIR指定目录。 git submodule update --init --recursive mkdir -p build; cd build -cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. +cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} .. + +# 如果CMake发生错误,则结束编译 +if [ $? -ne 0 ]; then + echo "cmake failed" + exit 1 +fi + make -j ``` diff --git a/docs/docs-zh/Testing-zh.md b/docs/docs-zh/Testing-zh.md index 7be8375be..0ae31dd63 100644 --- a/docs/docs-zh/Testing-zh.md +++ b/docs/docs-zh/Testing-zh.md @@ -35,7 +35,7 @@ openssl req -newkey rsa:2048 -x509 -nodes -keyout "$keyfile" -new -out "$certfil | -p | Server port. | | -P | Number of Parallel requests per single connection. Default 1. | | -n | Total number of requests to send. Defaults 1. | -| -c | Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ | +| -c | Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ P:copa | | -C | Pacing on. | | -t | Connection timeout. Default 3 seconds. | | -T | Transport layer. No HTTP3. | @@ -76,7 +76,7 @@ openssl req -newkey rsa:2048 -x509 -nodes -keyout "$keyfile" -new -out "$certfil | -a | Server addr. | | -p | Server port. | | -e | Echo. Send received body. | -| -c | Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ | +| -c | Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ P:copa | | -C | Pacing on. | | -L | Endless_sending on. default is off. | | -s | Body size to send. | diff --git a/docs/images/dingtalk_group.JPG b/docs/images/dingtalk_group.JPG new file mode 100644 index 000000000..0160dcfab Binary files /dev/null and b/docs/images/dingtalk_group.JPG differ diff --git a/docs/images/dingtalk_group.png b/docs/images/dingtalk_group.png deleted file mode 100644 index a6197ca21..000000000 Binary files a/docs/images/dingtalk_group.png and /dev/null differ diff --git a/include/xquic/xqc_configure.h b/include/xquic/xqc_configure.h index 5610c8b4c..fa13e49b4 100644 --- a/include/xquic/xqc_configure.h +++ b/include/xquic/xqc_configure.h @@ -2,9 +2,10 @@ #define xquic_VERSION_MAJOR 0 #define xquic_VERSION_MINOR 1 -#define XQC_ENABLE_BBR2 -#define XQC_ENABLE_RENO -#define XQC_ENABLE_COPA -#define XQC_ENABLE_UNLIMITED -#define XQC_ENABLE_MP_INTEROP +/* #undef XQC_ENABLE_BBR2 */ +/* #undef XQC_ENABLE_RENO */ +/* #undef XQC_ENABLE_COPA */ +/* #undef XQC_ENABLE_UNLIMITED */ +/* #undef XQC_ENABLE_MP_INTEROP */ /* #undef XQC_NO_PID_PACKET_PROCESS */ +/* #undef XQC_PROTECT_POOL_MEM */ diff --git a/include/xquic/xqc_errno.h b/include/xquic/xqc_errno.h index ea20d7051..fb9d32293 100644 --- a/include/xquic/xqc_errno.h +++ b/include/xquic/xqc_errno.h @@ -5,8 +5,8 @@ #ifndef _XQC_ERRNO_H_INCLUDED_ #define _XQC_ERRNO_H_INCLUDED_ -/* - * QUIC Transport Protocol error codes +/** + * @brief QUIC Transport Protocol error codes */ typedef enum { TRA_NO_ERROR = 0x0, @@ -23,17 +23,24 @@ typedef enum { TRA_INVALID_TOKEN = 0xB, TRA_APPLICATION_ERROR = 0xC, TRA_CRYPTO_BUFFER_EXCEEDED = 0xD, - TRA_0RTT_TRANS_PARAMS_ERROR = 0xE, /* MUST delete the current saved 0RTT transport parameters */ - TRA_HS_CERTIFICATE_VERIFY_FAIL = 0x1FE, /* for handshake certificate verify error */ - TRA_CRYPTO_ERROR = 0x1FF, /* 0x1XX */ - TRA_MP_PROTOCOL_VIOLATION_04 = 0xba01, - TRA_MP_PROTOCOL_VIOLATION_05 = 0x1001d76d3ded42f3, + TRA_0RTT_TRANS_PARAMS_ERROR = 0xE, /**< MUST delete the current saved 0RTT transport parameters */ + TRA_HS_CERTIFICATE_VERIFY_FAIL = 0x1FE, /**< for handshake certificate verify error */ + TRA_CRYPTO_ERROR = 0x1FF, /**< 0x1XX */ } xqc_trans_err_code_t; + +/** + * @brief Multipath error codes + */ +typedef enum { + TRA_MP_PROTOCOL_VIOLATION = 0x1001d76d3ded42f3 +} xqc_mp_err_code_t; + + #define TRA_CRYPTO_ERROR_BASE 0x100 -/* - * QUIC Http/3 Protocol error codes +/** + * @brief QUIC Http/3 Protocol error codes */ typedef enum { H3_NO_ERROR = 0x100, @@ -54,8 +61,8 @@ typedef enum { H3_VERSION_FALLBACK = 0x110, } xqc_h3_err_code_t; -/* - * QUIC QPACK protocol error codes +/** + * @brief QPACK protocol error codes */ typedef enum { QPACK_DECOMPRESSION_FAILED = 0x200, @@ -68,68 +75,78 @@ typedef enum { #define XQC_ERROR -1 -/* xquic transport internal error codes: 6xx */ +/** + * @brief xquic transport internal error codes: 6xx + */ typedef enum { - XQC_ENOBUF = 600, /* not enough buf space */ - XQC_EVINTREAD = 601, /* parse frame error */ - XQC_ENULLPTR = 602, /* empty pointer, usually a malloc failure */ - XQC_EMALLOC = 603, /* malloc failure */ - XQC_EILLPKT = 604, /* illegal packet, don't close connection, just drop it */ - XQC_ELEVEL = 605, /* incorrect encryption level */ - XQC_ECREATE_CONN = 606, /* fail to create a connection */ - XQC_CLOSING = 607, /* connection is closing, operation denied */ - XQC_ECONN_NFOUND = 608, /* fail to find the corresponding connection */ - XQC_ESYS = 609, /* system error, usually a public library interface failure */ - XQC_EAGAIN = 610, /* write blocking, similar to EAGAIN */ - XQC_EPARAM = 611, /* wrong parameters */ - XQC_ESTATE = 612, /* abnormal connection status */ - XQC_ELIMIT = 613, /* exceed cache limit */ - XQC_EPROTO = 614, /* violation of protocol */ - XQC_ESOCKET = 615, /* socket interface error */ - XQC_EFATAL = 616, /* fatal error, engine will immediately destroy the connection */ - XQC_ESTREAM_ST = 617, /* abnormal flow status */ - XQC_ESEND_RETRY = 618, /* send retry failure */ - XQC_ECONN_BLOCKED = 619, /* connection-level flow control */ - XQC_ESTREAM_BLOCKED = 620, /* stream-level flow control */ - XQC_EENCRYPT = 621, /* encryption error */ - XQC_EDECRYPT = 622, /* decryption error */ - XQC_ESTREAM_NFOUND = 623, /* fail to find the corresponding stream */ - XQC_EWRITE_PKT = 624, /* fail to create a package or write a package header */ - XQC_ECREATE_STREAM = 625, /* fail to create stream */ - XQC_ESTREAM_RESET = 626, /* stream has been reset */ - XQC_EDUP_FRAME = 627, /* duplicate frames */ - XQC_EFINAL_SIZE = 628, /* STREAM frame final size error */ - XQC_EVERSION = 629, /* this version is not supported and requires negotiation */ - XQC_EWAITING = 630, /* need to wait */ - XQC_EIGNORE_PKT = 631, /* ignore unknown packet/frame, don't close connection */ - XQC_EGENERATE_CID = 632, /* connection ID generation error */ - XQC_EANTI_AMPLIFICATION_LIMIT = 633, /* server reached the anti-amplification limit */ - XQC_ECONN_NO_AVAIL_CID = 634, /* no available connection ID */ - XQC_ECONN_CID_NOT_FOUND = 635, /* can't find cid in connection */ - XQC_EILLEGAL_FRAME = 636, /* illegal stream & frame, close connection */ - XQC_ECID_STATE = 637, /* abnormal connection ID status */ - XQC_EACTIVE_CID_LIMIT = 638, /* active cid exceed active_connection_id_limit */ - XQC_EALPN_NOT_SUPPORTED = 639, /* alpn is not supported by server */ - XQC_EALPN_NOT_REGISTERED = 640, /* alpn is not registered */ - XQC_ESTATELESS_RESET = 641, /* connection is reset by peer */ - XQC_EPACKET_FILETER_CALLBACK = 642, /* error with packet filter callback function */ - - XQC_EMP_NOT_SUPPORT_MP = 650, /* Multipath - don't support multipath */ - XQC_EMP_NO_AVAIL_PATH_ID = 651, /* Multipath - no available path id */ - XQC_EMP_CREATE_PATH = 652, /* Multipath - create path error */ - XQC_EMP_PATH_NOT_FOUND = 653, /* Multipath - can't find path in paths_list */ - XQC_EMP_PATH_STATE_ERROR = 654, /* Multipath - abnormal path status */ - XQC_EMP_SCHEDULE_PATH = 655, /* Multipath - fail to schedule path for sending */ - XQC_EMP_NO_ACTIVE_PATH = 656, /* Multipath - no another active path */ - XQC_EMP_INVALID_MP_VERTION = 657, /* Multipath - the multipath version value is invalid */ - - XQC_EENCRYPT_LB_CID = 670, /* load balance connection ID encryption error */ - XQC_EENCRYPT_AES_128_ECB = 671, /* aes_128_ecb algorithm error */ - - XQC_EDGRAM_NOT_SUPPORTED = 680, /* Datagram - not supported */ - XQC_EDGRAM_TOO_LARGE = 681, /* Datagram - payload size too large */ - - XQC_EPMTUD_PROBING_SIZE = 682, /* PMTUD - probing size error */ + XQC_ENOBUF = 600, /**< not enough buf space */ + XQC_EVINTREAD = 601, /**< parse frame error */ + XQC_ENULLPTR = 602, /**< empty pointer, usually a malloc failure */ + XQC_EMALLOC = 603, /**< malloc failure */ + XQC_EILLPKT = 604, /**< illegal packet, don't close connection, just drop it */ + XQC_ELEVEL = 605, /**< incorrect encryption level */ + XQC_ECREATE_CONN = 606, /**< fail to create a connection */ + XQC_CLOSING = 607, /**< connection is closing, operation denied */ + XQC_ECONN_NFOUND = 608, /**< fail to find the corresponding connection */ + XQC_ESYS = 609, /**< system error, usually a public library interface failure */ + XQC_EAGAIN = 610, /**< write blocking, similar to EAGAIN */ + XQC_EPARAM = 611, /**< wrong parameters */ + XQC_ESTATE = 612, /**< abnormal connection status */ + XQC_ELIMIT = 613, /**< exceed cache limit */ + XQC_EPROTO = 614, /**< violation of protocol */ + XQC_ESOCKET = 615, /**< socket interface error */ + XQC_EFATAL = 616, /**< fatal error, engine will immediately destroy the connection */ + XQC_ESTREAM_ST = 617, /**< abnormal flow status */ + XQC_ESEND_RETRY = 618, /**< send retry failure */ + XQC_ECONN_BLOCKED = 619, /**< connection-level flow control */ + XQC_ESTREAM_BLOCKED = 620, /**< stream-level flow control */ + XQC_EENCRYPT = 621, /**< encryption error */ + XQC_EDECRYPT = 622, /**< decryption error */ + XQC_ESTREAM_NFOUND = 623, /**< fail to find the corresponding stream */ + XQC_EWRITE_PKT = 624, /**< fail to create a package or write a package header */ + XQC_ECREATE_STREAM = 625, /**< fail to create stream */ + XQC_ESTREAM_RESET = 626, /**< stream has been reset */ + XQC_EDUP_FRAME = 627, /**< duplicate frames */ + XQC_EFINAL_SIZE = 628, /**< STREAM frame final size error */ + XQC_EVERSION = 629, /**< this version is not supported and requires negotiation */ + XQC_EWAITING = 630, /**< need to wait */ + XQC_EIGNORE_PKT = 631, /**< ignore unknown packet/frame, don't close connection */ + XQC_EGENERATE_CID = 632, /**< connection ID generation error */ + XQC_EANTI_AMPLIFICATION_LIMIT = 633, /**< server reached the anti-amplification limit */ + XQC_ECONN_NO_AVAIL_CID = 634, /**< no available connection ID */ + XQC_ECONN_CID_NOT_FOUND = 635, /**< can't find cid in connection */ + XQC_EILLEGAL_FRAME = 636, /**< illegal stream & frame, close connection */ + XQC_ECID_STATE = 637, /**< abnormal connection ID status */ + XQC_EACTIVE_CID_LIMIT = 638, /**< active cid exceed active_connection_id_limit */ + XQC_EALPN_NOT_SUPPORTED = 639, /**< alpn is not supported by server */ + XQC_EALPN_NOT_REGISTERED = 640, /**< alpn is not registered */ + XQC_ESTATELESS_RESET = 641, /**< connection is reset by peer */ + XQC_EPACKET_FILETER_CALLBACK = 642, /**< error with packet filter callback function */ + + XQC_EMP_NOT_SUPPORT_MP = 650, /**< Multipath - don't support multipath */ + XQC_EMP_NO_AVAIL_PATH_ID = 651, /**< Multipath - no available path id */ + XQC_EMP_CREATE_PATH = 652, /**< Multipath - create path error */ + XQC_EMP_PATH_NOT_FOUND = 653, /**< Multipath - can't find path in paths_list */ + XQC_EMP_PATH_STATE_ERROR = 654, /**< Multipath - abnormal path status */ + XQC_EMP_SCHEDULE_PATH = 655, /**< Multipath - fail to schedule path for sending */ + XQC_EMP_NO_ACTIVE_PATH = 656, /**< Multipath - no another active path */ + XQC_EMP_INVALID_MP_VERTION = 657, /**< Multipath - the multipath version value is invalid */ + XQC_EMP_NO_AVAILABLE_CID_FOR_PATH = 658, /**< Multipath - there's no available unused cid for this path */ + + XQC_EFEC_NOT_SUPPORT_FEC = 660, /**< FEC - fec not supported */ + XQC_EFEC_SCHEME_ERROR = 661, /**< FEC - no available scheme */ + XQC_EFEC_SYMBOL_ERROR = 662, /**< FEC - symbol value error */ + XQC_EFEC_TOLERABLE_ERROR = 663, /**< FEC - tolerable error */ + + XQC_EENCRYPT_LB_CID = 670, /**< load balance connection ID encryption error */ + XQC_EENCRYPT_AES_128_ECB = 671, /**< aes_128_ecb algorithm error */ + + XQC_EDGRAM_NOT_SUPPORTED = 680, /**< Datagram - not supported */ + XQC_EDGRAM_TOO_LARGE = 681, /**< Datagram - payload size too large */ + + XQC_EPMTUD_PROBING_SIZE = 682, /**< PMTUD - probing size error */ + + XQC_EACK_EXT_ABN_VAL = 690, /**< ACK Extension - abnormal value */ XQC_E_MAX, } xqc_transport_error_t; @@ -138,7 +155,9 @@ typedef enum { static const int TRANS_ERR_CNT = XQC_E_MAX - TRANS_ERR_START; -/* xquic TLS internal error codes: 7xx */ +/** + * @brief xquic TLS internal error codes: 7xx + */ typedef enum { XQC_TLS_INVALID_ARGUMENT = 700, XQC_TLS_UNKNOWN_PKT_TYPE = 701, @@ -194,42 +213,43 @@ typedef enum { static const int TLS_ERR_CNT = XQC_TLS_ERR_MAX - TLS_ERR_START; -/* xquic HTTP3/QPACK application error codes: 8xx */ +/** + * @brief xquic HTTP3/QPACK application error codes: 8xx + */ typedef enum { - /* HTTP/3 error codes */ - XQC_H3_EMALLOC = 800, /* malloc failure */ - XQC_H3_ECREATE_STREAM = 801, /* fail to create a stream */ - XQC_H3_ECREATE_REQUEST = 802, /* fail to create a request */ - XQC_H3_EGOAWAY_RECVD = 803, /* GOAWAY received, operation denied */ - XQC_H3_ECREATE_CONN = 804, /* fail to create a connection */ - XQC_H3_EQPACK_ENCODE = 805, /* QPACK - encode error */ - XQC_H3_EQPACK_DECODE = 806, /* QPACK - decode error */ - XQC_H3_EPRI_TREE = 807, /* priority tree error */ - XQC_H3_EPROC_CONTROL = 808, /* fail to process control stream */ - XQC_H3_EPROC_REQUEST = 809, /* fail to process request stream */ - XQC_H3_EPROC_PUSH = 810, /* fail to process push stream */ - XQC_H3_EPARAM = 811, /* wrong parameters */ - XQC_H3_BUFFER_EXCEED = 812, /* http send buffer exceeds the maximum */ - XQC_H3_DECODE_ERROR = 813, /* decode error */ - XQC_H3_INVALID_STREAM = 814, /* invalid stream, such as multiple control streams, etc. */ - XQC_H3_CLOSE_CRITICAL_STREAM = 815, /* illegal closure of control stream and qpack encoder/decoder stream */ - XQC_H3_STATE_ERROR = 816, /* http3 decoding status error */ - XQC_H3_CONTROL_ERROR = 817, /* control stream error, such as setting not send first or send twice */ - XQC_H3_CONTROL_DECODE_ERROR = 818, /* control stream decode error, such as encountering an unrecognized frame type */ - XQC_H3_CONTROL_DECODE_INVALID = 819, /* control stream decode invalid, eg. illegal remaining length */ - XQC_H3_PRIORITY_ERROR = 820, /* priority error */ - XQC_H3_INVALID_FRAME_TYPE = 821, /* invalid frame type */ - XQC_H3_UNSUPPORT_FRAME_TYPE = 822, /* unsupported frame type */ - XQC_H3_INVALID_HEADER = 823, /* invalid header field, such as the length exceeds the limit, etc. */ - XQC_H3_SETTING_ERROR = 824, /* SETTING error */ - XQC_H3_BLOCKED_STREAM_EXCEED = 825, /* blocked_stream exceed limit */ - XQC_H3_STREAM_RECV_ERROR = 826, /* call xqc_stream_recv error */ - XQC_H3_INVALID_PRIORITY = 827, /* invalid http priority params or values */ - XQC_H3_INVALID_BIDI_STREAM_TYPE = 828, /* invalid bidi stream type */ - XQC_H3_ECREATE_BYTESTREAM = 829, /* fail to create a bytestream */ - XQC_H3_EPROC_BYTESTREAM = 830, /* fail to process bytestream */ - XQC_H3_BYTESTREAM_FIN_SENT = 831, /* try to send data on a bytestream that already sent FIN */ - XQC_H3_BYTESTREAM_MSG_BUF_EXIST = 832, /* try to create a msg buf while it already exists */ + XQC_H3_EMALLOC = 800, /**< malloc failure */ + XQC_H3_ECREATE_STREAM = 801, /**< fail to create a stream */ + XQC_H3_ECREATE_REQUEST = 802, /**< fail to create a request */ + XQC_H3_EGOAWAY_RECVD = 803, /**< GOAWAY received, operation denied */ + XQC_H3_ECREATE_CONN = 804, /**< fail to create a connection */ + XQC_H3_EQPACK_ENCODE = 805, /**< QPACK - encode error */ + XQC_H3_EQPACK_DECODE = 806, /**< QPACK - decode error */ + XQC_H3_EPRI_TREE = 807, /**< priority tree error */ + XQC_H3_EPROC_CONTROL = 808, /**< fail to process control stream */ + XQC_H3_EPROC_REQUEST = 809, /**< fail to process request stream */ + XQC_H3_EPROC_PUSH = 810, /**< fail to process push stream */ + XQC_H3_EPARAM = 811, /**< wrong parameters */ + XQC_H3_BUFFER_EXCEED = 812, /**< http send buffer exceeds the maximum */ + XQC_H3_DECODE_ERROR = 813, /**< decode error */ + XQC_H3_INVALID_STREAM = 814, /**< invalid stream, such as multiple control streams, etc. */ + XQC_H3_CLOSE_CRITICAL_STREAM = 815, /**< illegal closure of control stream and qpack encoder/decoder stream */ + XQC_H3_STATE_ERROR = 816, /**< http3 decoding status error */ + XQC_H3_CONTROL_ERROR = 817, /**< control stream error, such as setting not send first or send twice */ + XQC_H3_CONTROL_DECODE_ERROR = 818, /**< control stream decode error, such as encountering an unrecognized frame type */ + XQC_H3_CONTROL_DECODE_INVALID = 819, /**< control stream decode invalid, eg. illegal remaining length */ + XQC_H3_PRIORITY_ERROR = 820, /**< priority error */ + XQC_H3_INVALID_FRAME_TYPE = 821, /**< invalid frame type */ + XQC_H3_UNSUPPORT_FRAME_TYPE = 822, /**< unsupported frame type */ + XQC_H3_INVALID_HEADER = 823, /**< invalid header field, such as the length exceeds the limit, etc. */ + XQC_H3_SETTING_ERROR = 824, /**< SETTING error */ + XQC_H3_BLOCKED_STREAM_EXCEED = 825, /**< blocked_stream exceed limit */ + XQC_H3_STREAM_RECV_ERROR = 826, /**< call xqc_stream_recv error */ + XQC_H3_INVALID_PRIORITY = 827, /**< invalid http priority params or values */ + XQC_H3_INVALID_BIDI_STREAM_TYPE = 828, /**< invalid bidi stream type */ + XQC_H3_ECREATE_BYTESTREAM = 829, /**< fail to create a bytestream */ + XQC_H3_EPROC_BYTESTREAM = 830, /**< fail to process bytestream */ + XQC_H3_BYTESTREAM_FIN_SENT = 831, /**< try to send data on a bytestream that already sent FIN */ + XQC_H3_BYTESTREAM_MSG_BUF_EXIST = 832, /**< try to create a msg buf while it already exists */ XQC_H3_ERR_MAX, } xqc_h3_error_t; @@ -237,25 +257,26 @@ typedef enum { #define H3_ERR_START 800 static const int H3_ERR_CNT = XQC_H3_ERR_MAX - H3_ERR_START; - +/** + * @brief xquic QPACK application error codes: 9xx + */ typedef enum { - /* QPACK error codes */ - XQC_QPACK_DECODER_VARINT_ERROR = 900, /* qpack decode variable-length integer error */ - XQC_QPACK_ENCODER_ERROR = 901, /* qpack encode error */ - XQC_QPACK_DECODER_ERROR = 902, /* qpack decode error */ - XQC_QPACK_DYNAMIC_TABLE_ERROR = 903, /* qpack dynamic table error */ - XQC_QPACK_STATIC_TABLE_ERROR = 904, /* qpack static table error */ - XQC_QPACK_SET_DTABLE_CAP_ERROR = 905, /* set dynamic table capacity error */ - XQC_QPACK_SEND_ERROR = 906, /* send data error or control message error */ - XQC_QPACK_SAVE_HEADERS_ERROR = 907, /* failed to save name-value to header structure */ - XQC_QPACK_UNKNOWN_INSTRUCTION = 908, /* unknown encoder/decoder instruction */ - XQC_QPACK_INSTRUCTION_ERROR = 909, /* error instruction */ - XQC_QPACK_DYNAMIC_TABLE_REFERRED = 910, /* dynamic table entry is still referred */ - XQC_QPACK_DYNAMIC_TABLE_VOID_ENTRY = 911, /* entry inexists in dynamic table */ - XQC_QPACK_STATE_ERROR = 912, /* state is error */ - XQC_QPACK_DYNAMIC_TABLE_NOT_ENOUGH = 913, /* dynamic table not enough */ - XQC_QPACK_HUFFMAN_DEC_ERROR = 914, /* huffman decode error */ - XQC_QPACK_HUFFMAN_DEC_STATE_ERROR = 915, /* huffman decode state error */ + XQC_QPACK_DECODER_VARINT_ERROR = 900, /**< qpack decode variable-length integer error */ + XQC_QPACK_ENCODER_ERROR = 901, /**< qpack encode error */ + XQC_QPACK_DECODER_ERROR = 902, /**< qpack decode error */ + XQC_QPACK_DYNAMIC_TABLE_ERROR = 903, /**< qpack dynamic table error */ + XQC_QPACK_STATIC_TABLE_ERROR = 904, /**< qpack static table error */ + XQC_QPACK_SET_DTABLE_CAP_ERROR = 905, /**< set dynamic table capacity error */ + XQC_QPACK_SEND_ERROR = 906, /**< send data error or control message error */ + XQC_QPACK_SAVE_HEADERS_ERROR = 907, /**< failed to save name-value to header structure */ + XQC_QPACK_UNKNOWN_INSTRUCTION = 908, /**< unknown encoder/decoder instruction */ + XQC_QPACK_INSTRUCTION_ERROR = 909, /**< error instruction */ + XQC_QPACK_DYNAMIC_TABLE_REFERRED = 910, /**< dynamic table entry is still referred */ + XQC_QPACK_DYNAMIC_TABLE_VOID_ENTRY = 911, /**< entry inexists in dynamic table */ + XQC_QPACK_STATE_ERROR = 912, /**< state is error */ + XQC_QPACK_DYNAMIC_TABLE_NOT_ENOUGH = 913, /**< dynamic table not enough */ + XQC_QPACK_HUFFMAN_DEC_ERROR = 914, /**< huffman decode error */ + XQC_QPACK_HUFFMAN_DEC_STATE_ERROR = 915, /**< huffman decode state error */ XQC_QPACK_ERR_MAX, } xqc_qpack_error_t; diff --git a/include/xquic/xqc_http3.h b/include/xquic/xqc_http3.h index f14cae4e1..28fd3adff 100644 --- a/include/xquic/xqc_http3.h +++ b/include/xquic/xqc_http3.h @@ -17,20 +17,22 @@ extern "C" { * @brief read flag of xqc_h3_request_read_notify_pt */ typedef enum { - /* nothing readable */ + /** nothing readable */ XQC_REQ_NOTIFY_READ_NULL = 0, - /* read header section flag, this will be set when the first HEADERS is processed */ + /** read header section flag, this will be set when the first HEADERS is processed */ XQC_REQ_NOTIFY_READ_HEADER = 1 << 0, - /* read body flag, this will be set when a DATA frame is processed */ + /** read body flag, this will be set when a DATA frame is processed */ XQC_REQ_NOTIFY_READ_BODY = 1 << 1, - /* read trailer section flag, this will be set when trailer HEADERS frame is processed */ + /** read trailer section flag, this will be set when trailer HEADERS frame is processed */ XQC_REQ_NOTIFY_READ_TRAILER = 1 << 2, - /* read empty fin flag, notify callback will be triggered when a single fin frame is received - while HEADERS and DATA were notified. This flag will NEVER be set with other flags */ + /** + * read empty fin flag, notify callback will be triggered when a single fin frame is received + while HEADERS and DATA were notified. This flag will NEVER be set with other flags + */ XQC_REQ_NOTIFY_READ_EMPTY_FIN = 1 << 3, } xqc_request_notify_flag_t; @@ -46,6 +48,16 @@ typedef void (*xqc_h3_handshake_finished_pt)(xqc_h3_conn_t *h3_conn, void *h3c_u typedef void (*xqc_h3_conn_ping_ack_notify_pt)(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, void *ping_user_data, void *h3c_user_data); + +typedef struct xqc_h3_conn_settings_s xqc_h3_conn_settings_t; +/** + * @brief In this callback, only operations related to modifying current_settings is allowed. + * This callback is triggered before the connection has been fully initialized. + * PLEASE DO NOT call any XQUIC APIs in this callback. + */ +typedef void (*xqc_h3_conn_init_settings_pt)(xqc_h3_conn_t *h3_conn, + xqc_h3_conn_settings_t *current_settings, void *h3c_user_data); + /** * @brief http3 request callbacks */ @@ -86,35 +98,51 @@ typedef enum xqc_http3_nv_flag_s { } xqc_http3_nv_flag_t; +typedef enum xqc_http3_nv_hit_flag_s { + XQC_NV_HIT_NONE = 0x00, /**< none is matched */ + XQC_NV_HIT_NAME = 0x01, /**< only name is matched */ + XQC_NV_HIT_BOTH = 0x02, /**< both name and value are matched */ +} xqc_http3_nv_hit_flag_t; + +typedef struct xqc_http_header_s xqc_http_header_t; typedef struct xqc_http_header_s { - /* name of http header */ + /** name of http header */ struct iovec name; - /* value of http header */ + /** value of http header */ struct iovec value; - /* flags of xqc_http3_nv_flag_t with OR operator */ + /** flags of xqc_http3_nv_flag_t with OR operator */ uint8_t flags; + + /** save the nv hit status or not (0 means do not save) */ + uint8_t save_nv_hit_flags; + + /** flags of nv hit status (used as return values) */ + uint8_t nv_hit_flags; + + /** src header (if this one is copied from another using xqc_h3_request_copy_header) */ + xqc_http_header_t *src_header; } xqc_http_header_t; typedef struct xqc_http_headers_s { - /* array of http headers */ + /** array of http headers */ xqc_http_header_t *headers; - /* count of headers */ + /** count of headers */ size_t count; - /* capacity of headers */ + /** capacity of headers */ size_t capacity; - /* total byte count of headers */ + /** total byte count of headers */ size_t total_len; } xqc_http_headers_t; -#define XQC_STREAM_INFO_LEN 100 +#define XQC_STREAM_INFO_LEN 128 /** * @brief request statistics structure @@ -122,19 +150,32 @@ typedef struct xqc_http_headers_s { typedef struct xqc_request_stats_s { size_t send_body_size; size_t recv_body_size; - size_t send_header_size; /* plaintext header size */ - size_t recv_header_size; /* plaintext header size */ - size_t send_hdr_compressed; /* compressed header size */ - size_t recv_hdr_compressed; /* compressed header size */ - int stream_err; /* QUIC layer error code, 0 for no error */ - xqc_usec_t blocked_time; /* time of h3 stream being blocked */ - xqc_usec_t unblocked_time; /* time of h3 stream being unblocked */ - xqc_usec_t stream_fin_time; /* time of receiving transport fin */ - xqc_usec_t h3r_begin_time; /* time of creating request */ - xqc_usec_t h3r_end_time; /* time of request fin */ - xqc_usec_t h3r_header_begin_time; /* time of receiving HEADERS frame */ - xqc_usec_t h3r_header_end_time; /* time of finishing processing HEADERS frame */ - xqc_usec_t h3r_body_begin_time; /* time of receiving DATA frame */ + /** plaintext header size */ + size_t send_header_size; + /** plaintext header size */ + size_t recv_header_size; + /** compressed header size */ + size_t send_hdr_compressed; + /** compressed header size */ + size_t recv_hdr_compressed; + /** QUIC layer error code, 0 for no error */ + int stream_err; + /** time of h3 stream being blocked */ + xqc_usec_t blocked_time; + /** time of h3 stream being unblocked */ + xqc_usec_t unblocked_time; + /** time of receiving transport fin */ + xqc_usec_t stream_fin_time; + /** time of creating request */ + xqc_usec_t h3r_begin_time; + /** time of request fin */ + xqc_usec_t h3r_end_time; + /** time of receiving HEADERS frame */ + xqc_usec_t h3r_header_begin_time; + /** time of finishing processing HEADERS frame */ + xqc_usec_t h3r_header_end_time; + /** time of receiving DATA frame */ + xqc_usec_t h3r_body_begin_time; xqc_usec_t h3r_header_send_time; xqc_usec_t h3r_body_send_time; xqc_usec_t stream_fin_send_time; @@ -156,7 +197,49 @@ typedef struct xqc_request_stats_s { uint64_t rate_limit; + /** + * @brief 0RTT state + * 0: no 0RTT + * 1: 0RTT accept + * 2: 0RTT reject + */ + uint8_t early_data_state; + char stream_info[XQC_STREAM_INFO_LEN]; + char extern_stream_info[XQC_STREAM_INFO_LEN]; + + xqc_usec_t stream_fst_fin_snd_time; + + /** + * @brief how long the request was blocked by congestion control (ms) + */ + xqc_msec_t cwnd_blocked_ms; + /** + * @brief the number of packet has been retransmitted + */ + uint32_t retrans_cnt; + + xqc_usec_t stream_fst_pkt_snd_time; + xqc_usec_t stream_fst_pkt_rcv_time; + + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + + /** + * @brief the number of lost/delayed packets recovered by fec module; + */ + uint32_t fec_recov_cnt; + xqc_usec_t fst_rpr_time; + xqc_usec_t last_rpr_time; + + uint8_t is_fec_protected; + uint8_t block_size_mode; + xqc_int_t fec_blk_lack_num; /* number of lack source symbol when receive last repair symbol */ + xqc_usec_t fec_blk_lack_time; /* (first block) block finish time - last received rpr (in block) time */ + xqc_usec_t fec_req_delay_time; /* request finish time - last received rpr time */ + xqc_usec_t recv_time_with_fec; + xqc_usec_t final_packet_time; + xqc_usec_t stream_close_delay; } xqc_request_stats_t; /** @@ -177,25 +260,27 @@ typedef struct xqc_h3_ext_bytestream_stats_s { xqc_usec_t first_byte_rcvd_time; } xqc_h3_ext_bytestream_stats_t; -/* connection settings for http3 */ +/** + * @brief connection settings for http3 + */ typedef struct xqc_h3_conn_settings_s { - /* MAX_FIELD_SECTION_SIZE of http3 */ + /** MAX_FIELD_SECTION_SIZE of http3 */ uint64_t max_field_section_size; - /* MAX_PUSH_STREAMS */ + /** MAX_PUSH_STREAMS */ uint64_t max_pushes; - /* ENC_MAX_DYNAMIC_TABLE_CAPACITY */ + /** ENC_MAX_DYNAMIC_TABLE_CAPACITY */ uint64_t qpack_enc_max_table_capacity; - /* DEC_MAX_DYNAMIC_TABLE_CAPACITY */ + /** DEC_MAX_DYNAMIC_TABLE_CAPACITY */ uint64_t qpack_dec_max_table_capacity; - /* MAX_BLOCKED_STREAMS */ + /** MAX_BLOCKED_STREAMS */ uint64_t qpack_blocked_streams; #ifdef XQC_COMPAT_DUPLICATE - /* compat with the original qpack encoder's duplicate strategy */ + /** compat with the original qpack encoder's duplicate strategy */ xqc_bool_t qpack_compat_duplicate; #endif @@ -284,16 +369,16 @@ typedef void (*xqc_h3_ext_datagram_mss_updated_notify_pt)(xqc_h3_conn_t *conn, typedef struct xqc_h3_ext_dgram_callbacks_s { - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_read_notify_pt dgram_read_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_write_notify_pt dgram_write_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_acked_notify_pt dgram_acked_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_lost_notify_pt dgram_lost_notify; xqc_h3_ext_datagram_mss_updated_notify_pt dgram_mss_updated_notify; @@ -303,18 +388,20 @@ typedef struct xqc_h3_ext_dgram_callbacks_s { * @brief http3 connection callbacks for application layer */ typedef struct xqc_h3_conn_callbacks_s { - /* http3 connection creation callback, REQUIRED for server, OPTIONAL for client */ + /** http3 connection creation callback, REQUIRED for server, OPTIONAL for client */ xqc_h3_conn_notify_pt h3_conn_create_notify; - /* http3 connection close callback */ + /** http3 connection close callback */ xqc_h3_conn_notify_pt h3_conn_close_notify; - /* handshake finished callback. which will be triggered when HANDSHAKE_DONE is received */ + /** handshake finished callback. which will be triggered when HANDSHAKE_DONE is received */ xqc_h3_handshake_finished_pt h3_conn_handshake_finished; - /* ping callback. which will be triggered when ping is acked */ + /** ping callback. which will be triggered when ping is acked */ xqc_h3_conn_ping_ack_notify_pt h3_conn_ping_acked; /* optional */ + xqc_h3_conn_init_settings_pt h3_conn_init_settings; + } xqc_h3_conn_callbacks_t; @@ -322,36 +409,36 @@ typedef struct xqc_h3_conn_callbacks_s { * @brief http3 request callbacks for application layer */ typedef struct xqc_h3_request_callbacks_s { - /* request creation notify. it will be triggered after a request was created, and is required + /** request creation notify. it will be triggered after a request was created, and is required for server, optional for client */ xqc_h3_request_notify_pt h3_request_create_notify; - /* request close notify. which will be triggered after a request was closed */ + /** request close notify. which will be triggered after a request was closed */ xqc_h3_request_notify_pt h3_request_close_notify; - /* request read notify callback. which will be triggered after received http headers or body */ + /** request read notify callback. which will be triggered after received http headers or body */ xqc_h3_request_read_notify_pt h3_request_read_notify; - /* request write notify callback. when triggered, users can continue to send headers or body */ + /** request write notify callback. when triggered, users can continue to send headers or body */ xqc_h3_request_notify_pt h3_request_write_notify; - /* request closing notify callback, will be triggered when request is closing */ + /** request closing notify callback, will be triggered when request is closing */ xqc_h3_request_closing_notify_pt h3_request_closing_notify; } xqc_h3_request_callbacks_t; typedef struct xqc_h3_ext_bytestream_callbacks_s { - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_bytestream_notify_pt bs_create_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_bytestream_notify_pt bs_close_notify; - /* negative return values will cause the connection to be closed */ + /** negative return values will cause the connection to be closed */ xqc_h3_ext_bytestream_read_notify_pt bs_read_notify; - /* negative return values will cause the connection to be closed */ + /** negative return values will cause the connection to be closed */ xqc_h3_ext_bytestream_notify_pt bs_write_notify; } xqc_h3_ext_bytestream_callbacks_t; @@ -359,16 +446,16 @@ typedef struct xqc_h3_ext_bytestream_callbacks_s { typedef struct xqc_h3_callbacks_s { - /* http3 connection callbacks */ + /** http3 connection callbacks */ xqc_h3_conn_callbacks_t h3c_cbs; - /* http3 request callbacks */ + /** http3 request callbacks */ xqc_h3_request_callbacks_t h3r_cbs; - /* datagram callbacks */ + /** datagram callbacks */ xqc_h3_ext_dgram_callbacks_t h3_ext_dgram_cbs; - /* bytestream callbacks */ + /** bytestream callbacks */ xqc_h3_ext_bytestream_callbacks_t h3_ext_bs_cbs; } xqc_h3_callbacks_t; @@ -389,7 +476,8 @@ xqc_int_t xqc_h3_ctx_destroy(xqc_engine_t *engine); /** - * @brief set max h3 max dynamic table capacity + * @brief set max h3 max dynamic table capacity. It MUST only be called after + * xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value capacity of dynamic table, 0 for disable dynamic table @@ -398,7 +486,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_max_dtable_capacity(xqc_engine_t *engine, size_t capacity); /** - * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead + * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value 0:disable dynamic table @@ -407,7 +496,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_dec_max_dtable_capacity(xqc_engine_t *engine, size_t value); /** - * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead + * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value 0:disable dynamic table @@ -416,7 +506,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t value); /** - * @brief set max h3 field section size + * @brief set max h3 field section size. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param size size of field section size @@ -424,17 +515,43 @@ void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t valu XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_max_field_section_size(xqc_engine_t *engine, size_t size); +/** + * @brief set the limit for qpack blocked streams. + * It MUST only be called after xqc_h3_ctx_init. + * + * @param engine + * @param value + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_engine_set_qpack_blocked_streams(xqc_engine_t *engine, size_t value); + #ifdef XQC_COMPAT_DUPLICATE +/** + * @brief It MUST only be called after xqc_h3_ctx_init. + * + * @param engine the engine handler created by xqc_engine_create + * @param cmpt value + * @return XQC_EXPORT_PUBLIC_API + */ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_qpack_compat_duplicate(xqc_engine_t *engine, xqc_bool_t cmpt); #endif + +/** + * User can set h3 settings when h3_conn_create_notify callbacks + */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_engine_set_local_settings(xqc_engine_t *engine, + const xqc_h3_conn_settings_t *h3_conn_settings); + /** * @brief create and http3 connection * * @param engine return from xqc_engine_create - * @param conn_settings connection settings + * @param conn_settings Include all the connection settings, which should be customized according to the actual needs, and will be defaultly set to internal_default_conn_settings if not specified. * @param token token receive from server, xqc_save_token_pt callback * @param token_len length of token * @param server_host server domain @@ -516,13 +633,6 @@ XQC_EXPORT_PUBLIC_API void *xqc_h3_conn_get_user_data(xqc_h3_conn_t *h3_conn); -/** - * User can set h3 settings when h3_conn_create_notify callbacks - */ -XQC_EXPORT_PUBLIC_API -void xqc_h3_conn_set_settings(xqc_h3_conn_t *h3c, - const xqc_h3_conn_settings_t *h3_conn_settings); - /** * @brief get peer address information, server should call this when h3_conn_create_notify triggers @@ -714,6 +824,9 @@ xqc_stream_id_t xqc_h3_stream_id(xqc_h3_request_t *h3_request); /** * @brief RFC 9218 HTTP Priority */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_priority_init(xqc_h3_priority_t *prio); + XQC_EXPORT_PUBLIC_API size_t xqc_write_http_priority(xqc_h3_priority_t *prio, uint8_t *dst, size_t dstcap); diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 8a1dda1e2..bfd30d78d 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -8,7 +8,10 @@ /** * Public API for using libxquic */ -#ifdef WIN32 +#include "xqc_configure.h" +#include "xquic_typedef.h" + +#if defined(XQC_SYS_WINDOWS) && !defined(XQC_ON_MINGW) #include #include #else @@ -16,8 +19,15 @@ #include #endif -#include "xqc_configure.h" -#include "xquic_typedef.h" +#if defined(__SSE2__) +// SSE2 +#include +#define XQC_ON_x86 +#elif defined(__ARM_NEON__) || defined(__ARM_NEON) +// NEON +#include +#define XQC_ON_ARM +#endif #ifdef __cplusplus extern "C" { @@ -28,8 +38,8 @@ extern "C" { * @brief engine type definition */ typedef enum { - XQC_ENGINE_SERVER, - XQC_ENGINE_CLIENT + XQC_ENGINE_SERVER = 0, + XQC_ENGINE_CLIENT = 1 } xqc_engine_type_t; @@ -37,19 +47,20 @@ typedef enum { * @brief supported versions for IETF drafts */ typedef enum xqc_proto_version_s { - /* placeholder */ - XQC_IDRAFT_INIT_VER, + /** placeholder */ + XQC_IDRAFT_INIT_VER = 0, - /* former version of QUIC RFC 9000 */ - XQC_VERSION_V1, + /** former version of QUIC RFC 9000 */ + XQC_VERSION_V1 = 1, - /* IETF Draft-29 */ - XQC_IDRAFT_VER_29, + /** IETF Draft-29 */ + XQC_IDRAFT_VER_29 = 2, - /* Special version for version negotiation. */ - XQC_IDRAFT_VER_NEGOTIATION, + /** Special version for version negotiation. */ + XQC_IDRAFT_VER_NEGOTIATION = 3, - XQC_VERSION_MAX + /** max value of proto value. */ + XQC_VERSION_MAX = 4 } xqc_proto_version_t; #define XQC_SUPPORT_VERSION_MAX 64 @@ -67,11 +78,15 @@ typedef enum xqc_proto_version_s { */ #define XQC_MAX_SEND_MSG_ONCE 32 - #define XQC_INITIAL_PATH_ID 0 #define XQC_DGRAM_RETX_ASKED_BY_APP 1 +#define XQC_CO_MAX_NUM 16 +#define XQC_CO_STR_MAX_LEN (5 * XQC_CO_MAX_NUM) + +#define XQC_FEC_MAX_SCHEME_NUM 5 + /** * @brief get timestamp callback function. this might be useful on different platforms @@ -127,7 +142,8 @@ typedef struct xqc_log_callbacks_s { * * trace log including XQC_LOG_FATAL, XQC_LOG_ERROR, XQC_LOG_WARN, XQC_LOG_STATS, XQC_LOG_INFO, * XQC_LOG_DEBUG, xquic will output logs with the level higher or equal to the level configured - * in xqc_congit_t. + * in xqc_log_init. Besides, when qlog enable and EVENT_IMPORTANCE_SELECTED importance is set, some + * event log will output log by xqc_log_write_err callback. */ void (*xqc_log_write_err)(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); @@ -139,6 +155,18 @@ typedef struct xqc_log_callbacks_s { */ void (*xqc_log_write_stat)(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); + /** + * qlog event callback function + * + * qlog event importance including EVENT_IMPORTANCE_SELECTED, EVENT_IMPORTANCE_CORE, EVENT_IMPORTANCE_BASE, + * EVENT_IMPORTANCE_EXTRA and EVENT_IMPORTANCE_REMOVED. + * EVENT_IMPORTANCE_CORE, EVENT_IMPORTANCE_BASE and EVENT_IMPORTANCE_EXTRA follow the defination of qlog draft. + * EVENT_IMPORTANCE_SELECTED works by xqc_log_write_err + * EVENT_IMPORTANCE_REMOVED exits, because the last qlog draft remove some qlog event, but the current qvis tool + * still need them. + */ + void (*xqc_qlog_event_write)(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data); + } xqc_log_callbacks_t; @@ -180,9 +208,10 @@ typedef ssize_t (*xqc_stateless_reset_pt)(const unsigned char *buf, size_t size, void *user_data); /** - * @brief connection closing notify callback function. will be triggered when a - * connection is not available and will not send/receive data any more. this - * callback is helpful to avoid attempts to send data on a closing connection. + * @brief connection closing notify callback function. + * + * This function will be triggered when a connection is not available and will not send/receive data any more. this + * callback is helpful to avoid attempts to send data on a closing connection. \n * NOTICE: this callback function will be triggered at the beginning of * connection close, while the conn_close_notify will be triggered at the end of * connection close. @@ -413,8 +442,8 @@ typedef void (*xqc_path_removed_notify_pt)(const xqc_cid_t *scid, uint64_t path_ void *conn_user_data); typedef enum { - XQC_PATH_DEGRADE, - XQC_PATH_RECOVERY, + XQC_PATH_DEGRADE = 0, + XQC_PATH_RECOVERY = 1, } xqc_path_status_change_type_t; @@ -506,6 +535,7 @@ typedef void (*xqc_datagram_write_notify_pt)(xqc_connection_t *conn, /** * @brief the callback API to notify application that a datagram is declared lost. + * * However, the datagram could also be acknowledged later, as the underlying * loss detection is not fully accurate. Applications should handle this type of * spurious loss. The return value indicates how this lost datagram is @@ -525,7 +555,7 @@ typedef xqc_int_t (*xqc_datagram_lost_notify_pt)(xqc_connection_t *conn, /** * @brief the callback API to notify application that a datagram is acked. Note, - * for every unique dgram_id, this callback will be only called once. + * for every unique dgram_id, this callback will be only called once. * * @param conn the connection handle * @param user_data the dgram_data set by xqc_datagram_set_user_data @@ -537,8 +567,8 @@ typedef void (*xqc_datagram_acked_notify_pt)(xqc_connection_t *conn, /** * @brief the callback to notify application the MSS of QUIC datagrams. Note, - * the MSS of QUIC datagrams will never shrink. If the MSS is zero, it - * means this connection does not support sending QUIC datagrams. + * the MSS of QUIC datagrams will never shrink. If the MSS is zero, it + * means this connection does not support sending QUIC datagrams. * * @param conn the connection handle * @param user_data the dgram_data set by xqc_datagram_set_user_data @@ -549,8 +579,9 @@ typedef void (*xqc_datagram_mss_updated_notify_pt)(xqc_connection_t *conn, /** - * @brief callback functions which are more related to attributes of QUIC [Transport] but not ALPN. - * In another word, these callback functions are events of QUIC Transport layer, and need to + * @brief tranport callback functions are more related to attributes of QUIC [Transport] but not ALPN. + * + * These callback functions are events of QUIC Transport layer, and need to * interact with application-layer, which have less thing to do with ALPN layer. * * These callback functions shall directly call back to application layer, with user_data from @@ -578,7 +609,7 @@ typedef void (*xqc_datagram_mss_updated_notify_pt)(xqc_connection_t *conn, */ typedef struct xqc_transport_callbacks_s { /** - * accept new connection callback. REQUIRED only for server + * accept new connection callback. REQUIRED only for server \n * NOTICE: this is the headmost callback trigger by xquic, the user_data of server_accept is * what was passed into xqc_engine_packet_process */ @@ -589,7 +620,7 @@ typedef struct xqc_transport_callbacks_s { */ xqc_server_refuse_pt server_refuse; - /* stateless reset callback */ + /** stateless reset callback */ xqc_stateless_reset_pt stateless_reset; /** @@ -711,10 +742,12 @@ typedef struct xqc_conn_callbacks_s { } xqc_conn_callbacks_t; -/* QUIC layer stream callback functions */ +/** + * @brief QUIC layer stream callback functions + */ typedef struct xqc_stream_callbacks_s { /** - * stream read callback function. REQUIRED for both client and server + * @brief stream read callback function. REQUIRED for both client and server * * this will be triggered when QUIC stream data is ready for read. application layer could read * data when xqc_stream_recv interface. @@ -722,7 +755,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_read_notify; /** - * stream write callback function. REQUIRED for both client and server + * @brief stream write callback function. REQUIRED for both client and server * * when sending data with xqc_stream_send, xquic might be blocked or send part of the data. if * this callback function is triggered, applications can continue to send the rest data. @@ -730,7 +763,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_write_notify; /** - * stream create callback function. REQUIRED for server, OPTIONAL for client. + * @brief stream create callback function. REQUIRED for server, OPTIONAL for client. * * this will be triggered when QUIC stream is created. applications can create its own stream * context in this callback function. @@ -738,7 +771,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_create_notify; /** - * stream close callback function. REQUIRED for both server and client. + * @brief stream close callback function. REQUIRED for both server and client. * * this will be triggered when QUIC stream is finally closed. xquic will close stream after * sending or receiving RESET_STREAM frame after 3 times of PTO, or when connection is closed. @@ -755,10 +788,12 @@ typedef struct xqc_stream_callbacks_s { } xqc_stream_callbacks_t; -/* QUIC layer datagram callback functions */ +/** + * @brief QUIC layer datagram callback functions + */ typedef struct xqc_datagram_callbacks_s { /** - * datagram read callback function. REQUIRED for both client and server if they want to use datagram + * @brief datagram read callback function. REQUIRED for both client and server if they want to use datagram * * this will be triggered when a QUIC datagram is received. application layer could read * data from the arguments of this callback. @@ -766,7 +801,7 @@ typedef struct xqc_datagram_callbacks_s { xqc_datagram_read_notify_pt datagram_read_notify; /** - * datagram write callback function. REQUIRED for both client and server if they want to use datagram + * @brief datagram write callback function. REQUIRED for both client and server if they want to use datagram * * when sending data with xqc_datagram_send or xqc_datagram_send_multiple, xquic might be blocked or send part of the data. if * this callback function is triggered, applications can continue to send the rest data. @@ -774,14 +809,14 @@ typedef struct xqc_datagram_callbacks_s { xqc_datagram_write_notify_pt datagram_write_notify; /** - * datagram acked callback function. OPTIONAL for server and client. + * @brief datagram acked callback function. OPTIONAL for server and client. * * this will be triggered when a QUIC packet containing a DATAGRAM frame is acked. */ xqc_datagram_acked_notify_pt datagram_acked_notify; /** - * datagram lost callback function. OPTIONAL for server and client. + * @brief datagram lost callback function. OPTIONAL for server and client. * * this will be triggered when a QUIC packet containing a DATAGRAM frame is lost. */ @@ -798,13 +833,19 @@ typedef struct xqc_datagram_callbacks_s { */ typedef struct xqc_app_proto_callbacks_s { - /* QUIC connection callback functions for Application-Layer-Protocol */ + /** + * @brief QUIC connection callback functions for Application-Layer-Protocol + */ xqc_conn_callbacks_t conn_cbs; - /* QUIC stream callback functions */ + /** + * @brief QUIC stream callback functions + */ xqc_stream_callbacks_t stream_cbs; - /* QUIC datagram callback functions */ + /** + * @brief QUIC datagram callback functions + */ xqc_datagram_callbacks_t dgram_cbs; } xqc_app_proto_callbacks_t; @@ -819,97 +860,153 @@ typedef enum { XQC_DATA_QOS_PROBING = 7, } xqc_data_qos_level_t; +/** + * @brief congestion control algorithm parameters + */ typedef struct xqc_cc_params_s { uint32_t customize_on; uint32_t init_cwnd; uint32_t min_cwnd; uint32_t expect_bw; uint32_t max_expect_bw; + uint8_t bbr_enable_lt_bw; + uint8_t bbr_ignore_app_limit; uint32_t cc_optimization_flags; - /* 0 < delta <= delta_max, default 0.05, ->0 = more throughput-oriented */ + /** 0 < delta <= delta_max, default 0.05, ->0 = more throughput-oriented */ double copa_delta_base; - /* 0 < delta_max <= 1.0, default 0.5 */ + /** 0 < delta_max <= 1.0, default 0.5 */ double copa_delta_max; - /* + /** * 1.0 <= delta_ai_unit, default 1.0, greater values mean more aggressive * when Copa competes with loss-based CCAs. */ double copa_delta_ai_unit; } xqc_cc_params_t; +/** + * @brief multipath scheduler algorithm parameters + */ typedef struct xqc_scheduler_params_u { - uint8_t customize_on; - union { - struct { - double lambda_max; - double lambda_min; - double lambda_init; - double lambda_inc; - double lambda_dec; - } blest_params; - - struct { - double beta; - } ecf_params; - }; + uint64_t rtt_us_thr_high; + uint64_t rtt_us_thr_low; + uint64_t bw_Bps_thr; + double loss_percent_thr_high; + double loss_percent_thr_low; + uint32_t pto_cnt_thr; } xqc_scheduler_params_t; +/** + * @brief FEC schemes type enum + */ +typedef enum { + XQC_REED_SOLOMON_CODE = 8, + XQC_XOR_CODE = 11, + XQC_PACKET_MASK_CODE = 12, +} xqc_fec_schemes_e; + +typedef enum { + XQC_FEC_MP_DEFAULT = 0, + XQC_FEC_MP_USE_STB = 1, +} xqc_fec_mp_mode_e; + +typedef enum { + XQC_FEC_RANDOM_TBL = 0, + XQC_FEC_BURST_TBL = 1 +} xqc_fec_tbl_mode_e; + +/** + * @brief FEC parameters on connection settings + */ +typedef struct xqc_fec_params_s { + /** code rate represents the source symbol percents in total symbols */ + float fec_code_rate; + /** element bit size of current fec finite filed */ + xqc_int_t fec_ele_bit_size; + /** frame type that should be protected by fec */ + uint64_t fec_protected_frames; + /** maximum number of block that current host can store */ + uint64_t fec_max_window_size; + /** (B) maximum symbol number of each block */ + uint64_t fec_max_symbol_num_per_block; + /** fec specific mp mode */ + xqc_fec_mp_mode_e fec_mp_mode; + + xqc_bool_t fec_log_on; + + xqc_int_t fec_encoder_schemes_num; + xqc_int_t fec_decoder_schemes_num; + /** fec schemes supported by current host as encoder */ + xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + /** fec schemes supported by current host as decoder */ + xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + + /** final fec scheme as encoder after negotiation */ + xqc_fec_schemes_e fec_encoder_scheme; + /** final fec scheme as decoder after negotiation */ + xqc_fec_schemes_e fec_decoder_scheme; + xqc_flag_t fec_blk_log_mod; + xqc_fec_tbl_mode_e fec_packet_mask_mode; +} xqc_fec_params_t; + +/** + * @brief congestion control callbacks + */ typedef struct xqc_congestion_control_callback_s { - /* Callback on initialization, for memory allocation */ + /** Callback on initialization, for memory allocation */ size_t (*xqc_cong_ctl_size)(void); - /* Callback on connection initialization, support for passing in congestion algorithm parameters */ + /** Callback on connection initialization, support for passing in congestion algorithm parameters */ void (*xqc_cong_ctl_init)(void *cong_ctl, xqc_send_ctl_t *ctl_ctx, xqc_cc_params_t cc_params); - /* Callback when packet loss is detected, reduce congestion window according to algorithm */ + /** Callback when packet loss is detected, reduce congestion window according to algorithm */ void (*xqc_cong_ctl_on_lost)(void *cong_ctl, xqc_usec_t lost_sent_time); - /* Callback when packet acked, increase congestion window according to algorithm */ + /** Callback when packet acked, increase congestion window according to algorithm */ void (*xqc_cong_ctl_on_ack)(void *cong_ctl, xqc_packet_out_t *po, xqc_usec_t now); - /* Callback when sending a packet, to determine if the packet can be sent */ + /** Callback when sending a packet, to determine if the packet can be sent */ uint64_t (*xqc_cong_ctl_get_cwnd)(void *cong_ctl); - /* Callback when all packets are detected as lost within 1-RTT, reset the congestion window */ + /** Callback when all packets are detected as lost within 1-RTT, reset the congestion window */ void (*xqc_cong_ctl_reset_cwnd)(void *cong_ctl); - /* If the connection is in slow start state */ + /** If the connection is in slow start state */ int (*xqc_cong_ctl_in_slow_start)(void *cong_ctl); - /* If the connection is in recovery state. */ + /** If the connection is in recovery state. */ int (*xqc_cong_ctl_in_recovery)(void *cong_ctl); - /* This function is used by BBR and Cubic*/ + /** This function is used by BBR and Cubic*/ void (*xqc_cong_ctl_restart_from_idle)(void *cong_ctl, uint64_t arg); - /* For BBR */ + /** For BBR */ void (*xqc_cong_ctl_on_ack_multiple_pkts)(void *cong_ctl, xqc_sample_t *sampler); - /* initialize bbr */ + /** initialize bbr */ void (*xqc_cong_ctl_init_bbr)(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params); - /* get pacing rate */ + /** get pacing rate */ uint32_t (*xqc_cong_ctl_get_pacing_rate)(void *cong_ctl); - /* get estimation of bandwidth */ + /** get estimation of bandwidth */ uint32_t (*xqc_cong_ctl_get_bandwidth_estimate)(void *cong_ctl); xqc_bbr_info_interface_t *xqc_cong_ctl_info_cb; } xqc_cong_ctrl_callback_t; #ifdef XQC_ENABLE_RENO -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_reno_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_reno_cb; #endif #ifdef XQC_ENABLE_BBR2 -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_bbr2_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_bbr2_cb; #endif -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_bbr_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_cubic_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_bbr_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_cubic_cb; #ifdef XQC_ENABLE_UNLIMITED -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_unlimited_cc_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_unlimited_cc_cb; #endif #ifdef XQC_ENABLE_COPA -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_copa_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_copa_cb; #endif typedef enum xqc_scheduler_path_event_e { @@ -921,6 +1018,9 @@ typedef enum xqc_scheduler_conn_event_e { XQC_SCHED_EVENT_CONN_ROUND_FIN = 1, } xqc_scheduler_conn_event_t; +/** + * @brief multipath scheduler callbacks + */ typedef struct xqc_scheduler_callback_s { size_t (*xqc_scheduler_size)(void); @@ -939,11 +1039,12 @@ typedef struct xqc_scheduler_callback_s { } xqc_scheduler_callback_t; -XQC_EXPORT_PUBLIC_API extern const xqc_scheduler_callback_t xqc_minrtt_scheduler_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_scheduler_callback_t xqc_backup_scheduler_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_scheduler_callback_t xqc_rap_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_minrtt_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_backup_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_rap_scheduler_cb; #ifdef XQC_ENABLE_MP_INTEROP -XQC_EXPORT_PUBLIC_API extern const xqc_scheduler_callback_t xqc_interop_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_interop_scheduler_cb; #endif typedef enum { @@ -966,50 +1067,66 @@ typedef struct xqc_reinj_ctl_callback_s { } xqc_reinj_ctl_callback_t; -XQC_EXPORT_PUBLIC_API extern const xqc_reinj_ctl_callback_t xqc_default_reinj_ctl_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_reinj_ctl_callback_t xqc_deadline_reinj_ctl_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_reinj_ctl_callback_t xqc_dgram_reinj_ctl_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_default_reinj_ctl_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_deadline_reinj_ctl_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_dgram_reinj_ctl_cb; + +typedef struct xqc_fec_code_callback_s { + void (*xqc_fec_init)(xqc_connection_t *conn); + xqc_int_t (*xqc_fec_encode)(xqc_connection_t *conn, unsigned char *unit_data, size_t un_size, unsigned char **outputs, + uint8_t fec_bm_mode); + xqc_int_t (*xqc_fec_decode)(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, size_t *size, xqc_int_t block_idx); + xqc_int_t (*xqc_fec_decode_one)(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx); + void (*xqc_fec_init_one)(xqc_connection_t *conn, uint8_t bm_idx); +} xqc_fec_code_callback_t; +XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_xor_code_cb; +XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_reed_solomon_code_cb; +XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_packet_mask_code_cb; /** * @struct xqc_config_t * QUIC config parameters */ typedef struct xqc_config_s { - /* log level */ + /** log level */ xqc_log_level_t cfg_log_level; - /* enable log based on event or not, non-zero for enable, 0 for not */ + /** enable log based on event or not, non-zero for enable, 0 for not */ xqc_flag_t cfg_log_event; - /* print timestamp in log or not, non-zero for print, 0 for not */ + /** qlog evnet importance */ + qlog_event_importance_t cfg_qlog_importance; + + /** print timestamp in log or not, non-zero for print, 0 for not */ xqc_flag_t cfg_log_timestamp; - /* print level name in log or not, non-zero for print, 0 for not */ + /** print level name in log or not, non-zero for print, 0 for not */ xqc_flag_t cfg_log_level_name; - /* connection memory pool size, which will be used for congestion control */ + /** connection memory pool size, which will be used for congestion control */ size_t conn_pool_size; - /* bucket size of stream hash table in xqc_connection_t */ + /** bucket size of stream hash table in xqc_connection_t */ size_t streams_hash_bucket_size; - /* bucket size of connection hash table in engine */ + /** bucket size of connection hash table in engine */ size_t conns_hash_bucket_size; - /* capacity of connection priority queue in engine */ + /** capacity of connection priority queue in engine */ size_t conns_active_pq_capacity; - /* capacity of wakeup connection priority queue in engine */ + /** capacity of wakeup connection priority queue in engine */ size_t conns_wakeup_pq_capacity; - /* supported quic version list, actually draft-29 and quic-v1 is supported */ + /** supported quic version list, actually draft-29 and quic-v1 is supported */ uint32_t support_version_list[XQC_SUPPORT_VERSION_MAX]; - /* supported quic version count */ + /** supported quic version count */ uint32_t support_version_count; - /* default connection id length */ + /** default connection id length */ uint8_t cid_len; /** @@ -1021,7 +1138,7 @@ typedef struct xqc_config_s { */ uint8_t cid_negotiate; - /* used to generate stateless reset token */ + /** used to generate stateless reset token */ char reset_token_key[XQC_RESET_TOKEN_MAX_KEY_LEN]; size_t reset_token_keylen; @@ -1039,6 +1156,15 @@ typedef struct xqc_config_s { * */ uint8_t enable_h3_ext; + + /** + * @brief manually call mainlogic after stream/request send + * + */ + uint8_t manually_triggered_send; + + /** for warning when the number of elements in one bucket exceeds the value of hash_conflict_threshold*/ + uint32_t hash_conflict_threshold; } xqc_config_t; @@ -1046,48 +1172,64 @@ typedef struct xqc_config_s { * @brief engine callback functions. */ typedef struct xqc_engine_callback_s { - /* timer callback for event loop */ + /** timer callback for event loop */ xqc_set_event_timer_pt set_event_timer; - /* write log file callback, REQUIRED */ + /** write log file callback, REQUIRED */ xqc_log_callbacks_t log_callbacks; - /* custom cid generator, OPTIONAL for server */ + /** custom cid generator, OPTIONAL for server */ xqc_cid_generate_pt cid_generate_cb; - /* tls secret callback, OPTIONAL */ + /** tls secret callback, OPTIONAL */ xqc_eng_keylog_pt keylog_cb; - /* get realtime timestamp callback function. if not set, xquic will get timestamp with inner + /** get realtime timestamp callback function. if not set, xquic will get timestamp with inner function xqc_now, which relies on gettimeofday */ xqc_timestamp_pt realtime_ts; - /* get monotonic increasing timestamp callback function. if not set, xquic will get timestamp + /** get monotonic increasing timestamp callback function. if not set, xquic will get timestamp with inner function xqc_now, which relies on gettimeofday */ xqc_timestamp_pt monotonic_ts; } xqc_engine_callback_t; - +/** + * @brief engine's ssl config + */ typedef struct xqc_engine_ssl_config_s { - char *private_key_file; /* For server */ - char *cert_file; /* For server */ + /** private key filefor server */ + char *private_key_file; + /** certificate file for server */ + char *cert_file; char *ciphers; char *groups; - uint32_t session_timeout; /* Session lifetime in second */ - char *session_ticket_key_data; /* For server */ - size_t session_ticket_key_len; /* For server */ + /** session lifetime in second */ + uint32_t session_timeout; + /** session ticket key for server */ + char *session_ticket_key_data; + /** session ticket key length for server */ + size_t session_ticket_key_len; } xqc_engine_ssl_config_t; - typedef enum { XQC_TLS_CERT_FLAG_NEED_VERIFY = 1 << 0, XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED = 1 << 1, } xqc_cert_verify_flag_e; +typedef enum { + XQC_RED_NOT_USE = 0, + XQC_RED_SET_CLOSE = 1, +} xqc_dgram_red_setting_e; + +typedef enum { + XQC_FEC_CONN_LEVEL = 0, + XQC_FEC_STREAM_LEVEL = 1 +} xqc_fec_level_e; + /** * @brief connection tls config for client */ @@ -1122,48 +1264,67 @@ typedef struct xqc_conn_ssl_config_s { } xqc_conn_ssl_config_t; typedef struct xqc_linger_s { - uint32_t linger_on; /* close connection after all data sent and acked, default: 0 */ - xqc_usec_t linger_timeout; /* 3*PTO if linger_timeout is 0 */ + /** close connection after all data sent and acked, default: 0 */ + uint32_t linger_on; + /** 3*PTO if linger_timeout is 0 */ + xqc_usec_t linger_timeout; } xqc_linger_t; typedef enum { XQC_ERR_MULTIPATH_VERSION = 0x00, - XQC_MULTIPATH_04 = 0x04, - XQC_MULTIPATH_05 = 0x05, - XQC_MULTIPATH_06 = 0x06, + XQC_MULTIPATH_10 = 0x0a, } xqc_multipath_version_t; +typedef enum { + XQC_ERR_FEC_VERSION = 0x00, + XQC_FEC_02 = 0x02, +} xqc_fec_version_t; + +/** + * @brief structures of connection settings + */ typedef struct xqc_conn_settings_s { - int pacing_on; /* default: 0 */ - int ping_on; /* client sends PING to keepalive, default:0 */ - xqc_cong_ctrl_callback_t cong_ctrl_callback; /* default: xqc_cubic_cb */ + /** default: 0 */ + int pacing_on; + /** client sends PING to keepalive, default:0 */ + int ping_on; + /** default: xqc_cubic_cb */ + xqc_cong_ctrl_callback_t cong_ctrl_callback; xqc_cc_params_t cc_params; - uint32_t so_sndbuf; /* socket option SO_SNDBUF, 0 for unlimited */ - uint64_t sndq_packets_used_max; /* - * default: XQC_SNDQ_PACKETS_USED_MAX. - * It should be set to buffer 2xBDP packets at least for performance consideration. - * The default value is 16000 pkts. - */ + /** socket option SO_SNDBUF, 0 for unlimited */ + uint32_t so_sndbuf; + /** + * default: XQC_SNDQ_PACKETS_USED_MAX. + * It should be set to buffer 2xBDP packets at least for performance consideration. + * The default value is 16000 pkts. + */ + uint64_t sndq_packets_used_max; xqc_linger_t linger; - xqc_proto_version_t proto_version; /* QUIC protocol version */ - xqc_msec_t init_idle_time_out; /* initial idle timeout interval, effective before handshake completion */ - xqc_msec_t idle_time_out; /* idle timeout interval, effective after handshake completion */ + /** QUIC protocol version */ + xqc_proto_version_t proto_version; + /** initial idle timeout interval, effective before handshake completion */ + xqc_msec_t init_idle_time_out; + /** idle timeout interval, effective after handshake completion */ + xqc_msec_t idle_time_out; + xqc_usec_t fec_conn_queue_rpr_timeout; int32_t spurious_loss_detect_on; - uint32_t anti_amplification_limit; /* limit of anti-amplification, default 3 */ - uint64_t keyupdate_pkt_threshold; /* packet limit of a single 1-rtt key, 0 for unlimited */ + /** limit of anti-amplification, default 5 */ + uint32_t anti_amplification_limit; + /** packet limit of a single 1-rtt key, 0 for unlimited */ + uint64_t keyupdate_pkt_threshold; size_t max_pkt_out_size; + size_t probing_pkt_out_size; - /* - * datgram option - * 0: no support for datagram mode (default) - * >0: the max size of datagrams that the local end is willing to receive - * 65535: the local end is willing to receive a datagram with any length as - * long as it fits in a QUIC packet - */ + /** + * datgram option + * 0: no support for datagram mode (default) + * >0: the max size of datagrams that the local end is willing to receive + * 65535: the local end is willing to receive a datagram with any length as long as it fits in a QUIC packet + */ uint16_t max_datagram_frame_size; - /* + /** * multipath option: * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#section-3 * 0: don't support multipath @@ -1171,9 +1332,10 @@ typedef struct xqc_conn_settings_s { */ uint64_t enable_multipath; xqc_multipath_version_t multipath_version; + uint64_t init_max_path_id; uint64_t least_available_cid_count; - /* + /** * reinjection option: * 0: default, no reinjection * bit0 = 1: @@ -1184,7 +1346,7 @@ typedef struct xqc_conn_settings_s { * reinject unacked packets after sending packets. */ int mp_enable_reinjection; - /* + /** * deadline = max(low_bound, min(hard_deadline, srtt * srtt_factor)) * default values: * low_bound = 0 @@ -1195,7 +1357,7 @@ typedef struct xqc_conn_settings_s { uint64_t reinj_hard_deadline; uint64_t reinj_deadline_lower_bound; - /* + /** * By default, XQUIC returns ACK_MPs on the path where the data * is received unless the path is not avaliable anymore. * @@ -1204,45 +1366,55 @@ typedef struct xqc_conn_settings_s { */ uint8_t mp_ack_on_any_path; - /* + /** * When sending a ping packet for connection keep-alive, we replicate the * the packet on all acitve paths to keep all paths alive (disable:0, enable:1). * The default value is 0. */ uint8_t mp_ping_on; - /* scheduler callback, default: xqc_minrtt_scheduler_cb */ + /** scheduler callback, default: xqc_minrtt_scheduler_cb */ xqc_scheduler_callback_t scheduler_callback; xqc_scheduler_params_t scheduler_params; - /* reinj_ctl callback, default: xqc_default_reinj_ctl_cb */ + /** reinj_ctl callback, default: xqc_default_reinj_ctl_cb */ xqc_reinj_ctl_callback_t reinj_ctl_callback; - /* ms */ + /** ms */ xqc_msec_t standby_path_probe_timeout; - /* params for performance tuning */ - /* max ack delay: ms */ + /** params for performance tuning */ + /** max ack delay: ms */ uint32_t max_ack_delay; - /* generate an ACK if received ack-eliciting pkts >= ack_frequency */ + /** generate an ACK if received ack-eliciting pkts >= ack_frequency */ uint32_t ack_frequency; + uint8_t adaptive_ack_frequency; uint64_t loss_detection_pkt_thresh; double pto_backoff_factor; - /* datagram redundancy: 0 disable, 1 enable, 2 only enable multipath redundancy */ + /** datagram redundancy: 0 disable, 1 enable, 2 only enable multipath redundancy */ uint8_t datagram_redundancy; uint8_t datagram_force_retrans_on; uint64_t datagram_redundant_probe; - /* enable PMTUD */ + /** + * enable PMTUD: + * 0x0 disbale, + * 0x1 enable client probing, + * 0x2 enable server probing, + * 0x3 enable both ends probing + * NOTE: This option needs to be negotiated by both ends. The final decision + * is made by the logic AND operation of both ends' options, e.g. client: + * 0x3, server: 0x1 --> 0x1 (only enable client probing). + **/ uint8_t enable_pmtud; - /* probing interval (us), default: 500000 */ + /** probing interval (us), default: 500000 */ uint64_t pmtud_probing_interval; - /* enable marking reinjected packets with reserved bits */ + /** enable marking reinjected packets with reserved bits */ uint8_t marking_reinjection; - /* + /** * The limitation on conn recv rate (only applied to stream data) in bytes per second. * NOTE: the minimal rate limitation is (63000/RTT) Bps. For instance, if RTT is 60ms, * the minimal valid rate limitation is about 1MBps. Any recv_rate_bytes_per_sec less @@ -1251,28 +1423,87 @@ typedef struct xqc_conn_settings_s { */ uint64_t recv_rate_bytes_per_sec; - /* + /** * The switch to enable stream-level recv rate throttling. Default: off (0) */ uint8_t enable_stream_rate_limit; - /* + /** * initial recv window. Default: 0 (use the internal default value) */ uint32_t init_recv_window; + /** + * initial flow control value + */ + xqc_bool_t is_interop_mode; + +#ifdef XQC_PROTECT_POOL_MEM + uint8_t protect_pool_mem; +#endif + + char conn_option_str[XQC_CO_STR_MAX_LEN]; + + /** + * @brief intial_rtt (us). Default: 0 (use the internal default value -- 250000) + * + */ + xqc_usec_t initial_rtt; + /** + * @brief initial pto duration (us). Default: 0 (use the internal default value -- 3xinitial_rtt) + * + */ + xqc_usec_t initial_pto_duration; + + /** + * fec option: + * 0: don't support fec + * 1: supports fec + */ + uint64_t enable_encode_fec; + uint64_t enable_decode_fec; + xqc_fec_params_t fec_params; + xqc_fec_code_callback_t fec_callback; + + xqc_dgram_red_setting_e close_dgram_redundancy; + + /** + * @brief disable batch sending on the connection (default:0, not disable) + */ + uint8_t disable_send_mmsg; + + /** + * @brief control PTO value + */ + uint8_t control_pto_value; + + uint64_t max_udp_payload_size; + + /** + * encode fec on connection level or stream level ? + * 0: (default) connection level + * 1: stream level, only be applied to MOQ + */ + xqc_fec_level_e fec_level; + uint64_t extended_ack_features; + uint64_t max_receive_timestamps_per_ack; + uint64_t receive_timestamps_exponent; } xqc_conn_settings_t; typedef enum { - XQC_0RTT_NONE, /* without 0-RTT */ - XQC_0RTT_ACCEPT, /* 0-RTT was accepted */ - XQC_0RTT_REJECT, /* 0-RTT was rejected */ + /** without 0-RTT */ + XQC_0RTT_NONE = 0, + /** 0-RTT was accepted */ + XQC_0RTT_ACCEPT = 1, + /** 0-RTT was rejected */ + XQC_0RTT_REJECT = 2, } xqc_0rtt_flag_t; #define XQC_MAX_PATHS_COUNT 8 #define XQC_CONN_INFO_LEN 400 +#define XQC_EXTERN_CONN_INFO_LEN 128 typedef struct xqc_path_metrics_s { uint64_t path_id; @@ -1292,16 +1523,22 @@ typedef struct xqc_path_metrics_s { uint8_t path_app_status; } xqc_path_metrics_t; - +/** + * @brief connection stats + */ typedef struct xqc_conn_stats_s { uint32_t send_count; uint32_t lost_count; uint32_t tlp_count; uint32_t spurious_loss_count; - uint32_t lost_dgram_count; /*how many datagram frames (pkts) are lost*/ - xqc_usec_t srtt; /* smoothed SRTT at present: initial value = 250000 */ - xqc_usec_t min_rtt; /* minimum RTT until now: initial value = 0xFFFFFFFF */ - uint64_t inflight_bytes; /* initial value = 0 */ + /** how many datagram frames (pkts) are lost */ + uint32_t lost_dgram_count; + /** smoothed SRTT at present: initial value = 250000 */ + xqc_usec_t srtt; + /** minimum RTT until now: initial value = 0xFFFFFFFF */ + xqc_usec_t min_rtt; + /** initial value = 0 */ + uint64_t inflight_bytes; xqc_0rtt_flag_t early_data_flag; uint32_t recv_count; int spurious_loss_detect_on; @@ -1324,12 +1561,37 @@ typedef struct xqc_conn_stats_s { */ int mp_state; + int total_rebind_count; + int total_rebind_valid; + xqc_path_metrics_t paths_info[XQC_MAX_PATHS_COUNT]; char conn_info[XQC_CONN_INFO_LEN]; char alpn[XQC_MAX_ALPN_BUF_LEN]; + + char extern_conn_info[XQC_EXTERN_CONN_INFO_LEN]; + + uint32_t send_fec_cnt; + + uint8_t enable_fec; + /** only accounts for stream and datagram packets */ + uint64_t total_app_bytes; + uint64_t standby_path_app_bytes; + + uint32_t max_acked_mtu; + + uint32_t fec_recover_pkt_cnt; + xqc_usec_t avg_close_time; } xqc_conn_stats_t; +typedef struct xqc_conn_qos_stats_s { + /** smoothed SRTT at present: initial value = 250000 */ + xqc_usec_t srtt; + /** minimum RTT until now: initial value = 0xFFFFFFFF */ + xqc_usec_t min_rtt; + /** initial value = 0 */ + uint64_t inflight_bytes; +} xqc_conn_qos_stats_t; /************************************************************* * engine layer APIs @@ -1355,7 +1617,7 @@ xqc_engine_t *xqc_engine_create(xqc_engine_type_t engine_type, /** - * @brief destroy engine. this is called after all connections are destroyed + * @brief destroy engine. this is called after all connections are destroyed \n * NOTICE: MUST NOT be called in any xquic callback functions, for this function will destroy engine * immediately, result in segmentation fault. */ @@ -1372,11 +1634,12 @@ void xqc_engine_destroy(xqc_engine_t *engine); * @param alpn Application-Layer-Protocol, for example, h3, hq-interop, or self-defined * @param alpn_len length of Application-Layer-Protocol string * @param ap_cbs connection and stream event callback functions for application-layer-protocol + * @param alp_ctx the context of the upper layer protocol (e.g. the callback functions and default settings of the upper layer protocol) * @return XQC_EXPORT_PUBLIC_API */ XQC_EXPORT_PUBLIC_API xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs); + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx); /** @@ -1390,16 +1653,41 @@ xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_ XQC_EXPORT_PUBLIC_API xqc_int_t xqc_engine_unregister_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len); +/** + * @brief get the context an application layer protocol + * + * @param engine engine handler + * @param alpn Application-Layer-Protocol, for example, h3, hq-interop, or self-defined + * @param alpn_len length of alpn + * @return the context + */ +XQC_EXPORT_PUBLIC_API +void* xqc_engine_get_alpn_ctx(xqc_engine_t *engine, const char *alpn, size_t alpn_len); + +/** + * @brief get the private context + * + * @param engine + * @return XQC_EXPORT_PUBLIC_API* + */ +XQC_EXPORT_PUBLIC_API +void* xqc_engine_get_priv_ctx(xqc_engine_t *engine); + +/** + * @brief save the private context + * + * @param engine + * @param priv_ctx + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +xqc_int_t xqc_engine_set_priv_ctx(xqc_engine_t *engine, void *priv_ctx); /** * Pass received UDP packet payload into xquic engine. * @param recv_time UDP packet received time in microsecond * @param user_data connection user_data, server is NULL - * @param path_id XQC_UNKNOWN_PATH_ID = unknown path (only use cid to identify the path) */ - -#ifdef XQC_NO_PID_PACKET_PROCESS - XQC_EXPORT_PUBLIC_API xqc_int_t xqc_engine_packet_process(xqc_engine_t *engine, const unsigned char *packet_in_buf, size_t packet_in_size, @@ -1407,17 +1695,6 @@ xqc_int_t xqc_engine_packet_process(xqc_engine_t *engine, const struct sockaddr *peer_addr, socklen_t peer_addrlen, xqc_usec_t recv_time, void *user_data); -#else - -XQC_EXPORT_PUBLIC_API -xqc_int_t xqc_engine_packet_process(xqc_engine_t *engine, - const unsigned char *packet_in_buf, size_t packet_in_size, - const struct sockaddr *local_addr, socklen_t local_addrlen, - const struct sockaddr *peer_addr, socklen_t peer_addrlen, - uint64_t path_id, xqc_usec_t recv_time, void *user_data); - -#endif - /** * @brief Process all connections, application implements MUST call this function in timer callback @@ -1447,7 +1724,7 @@ xqc_int_t xqc_engine_set_config(xqc_engine_t *engine, const xqc_config_t *engine * new created connections */ XQC_EXPORT_PUBLIC_API -void xqc_server_set_conn_settings(const xqc_conn_settings_t *settings); +void xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *settings); /** @@ -1461,11 +1738,12 @@ void xqc_engine_set_log_level(xqc_engine_t *engine, xqc_log_level_t log_level); /** * @brief enable/disable the log module of xquic + * @note This function is not thread-safe. * - * @param enable XQC_TRUE for enable, XQC_FALSE for disable + * @param enable XQC_TRUE for disable, XQC_FALSE for enable */ XQC_EXPORT_PUBLIC_API -void xqc_log_enable(xqc_bool_t enable); +void xqc_log_disable(xqc_bool_t disable); /** @@ -1475,6 +1753,17 @@ void xqc_log_enable(xqc_bool_t enable); XQC_EXPORT_PUBLIC_API void xqc_engine_finish_recv(xqc_engine_t *engine); + +/** + * @brief only useful for manually triggered send mode + * + * @param engine + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +void xqc_engine_finish_send(xqc_engine_t *engine); + + XQC_EXPORT_PUBLIC_API xqc_connection_t *xqc_engine_get_conn_by_scid(xqc_engine_t *engine, const xqc_cid_t *cid); @@ -1489,11 +1778,11 @@ xqc_connection_t *xqc_engine_get_conn_by_scid(xqc_engine_t *engine, * @param token token receive from server, xqc_save_token_pt callback * @param token_len * @param server_host server domain - * @param no_crypto_flag 1: without encryption on 0-RTT and 1-RTT packets. this flag will add - * no_crypto transport parameter when initiating a connection, which is not an official parameter + * @param no_crypto_flag 1: stop encrypt 0-RTT and 1-RTT packets. \n + * This flag will add no_crypto transport parameter when initiating a connection, which is not an official parameter * and might be modified or removed * @param conn_ssl_config For handshake - * @param user_data For connection + * @param user_data application data, for connection usage * @param peer_addr address of peer * @param peer_addrlen length of peer_addr * @param alpn Application-Layer-Protocol, MUST NOT be NULL @@ -1589,7 +1878,7 @@ XQC_EXPORT_PUBLIC_API xqc_bool_t xqc_conn_is_ready_to_send_early_data(xqc_connection_t *conn); /** - * @brief set the packet filter callback function, and replace write_socket. + * @brief set the packet filter callback function, and replace write_socket. \n * NOTICE: this function is not conflict with send_mmsg. */ XQC_EXPORT_PUBLIC_API @@ -1633,7 +1922,7 @@ void xqc_conn_set_public_remote_trans_settings(xqc_connection_t *conn, /** - * Create new stream in quic connection. + * @brief Create new stream in quic connection. * @param user_data user_data for this stream */ XQC_EXPORT_PUBLIC_API @@ -1703,12 +1992,12 @@ ssize_t xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t s /** * @brief the API to get the max length of the data that can be sent - * via a single call of xqc_datagram_send; NOTE, if the DCID length could - * be changed during the lifetime of the connection, applications is - * suggested to call xqc_datagram_get_mss every time before - * send datagram data or when getting -XQC_EDGRAM_TOO_LARGE error - * from sending datagram data. In MPQUIC cases, the DCID of all paths - * MUST be the same. Otherwise, there might be unexpected errors. + * via a single call of xqc_datagram_send; + * + * NOTE: if the DCID length could be changed during the lifetime of the connection, applications is + * suggested to call xqc_datagram_get_mss every time before send datagram data or when + * getting -XQC_EDGRAM_TOO_LARGE error from sending datagram data. In MPQUIC cases, + * the DCID of all paths MUST be the same. Otherwise, there might be unexpected errors. * * @param conn the connection handle * @return 0 = the peer does not support datagram, >0 = the max length @@ -1783,10 +2072,10 @@ xqc_int_t xqc_cid_is_equal(const xqc_cid_t *dst, const xqc_cid_t *src); * @return user should copy return buffer to your own memory if you will access in the future */ XQC_EXPORT_PUBLIC_API -unsigned char *xqc_scid_str(const xqc_cid_t *scid); +unsigned char *xqc_scid_str(xqc_engine_t *engine, const xqc_cid_t *scid); XQC_EXPORT_PUBLIC_API -unsigned char *xqc_dcid_str(const xqc_cid_t *dcid); +unsigned char *xqc_dcid_str(xqc_engine_t *engine, const xqc_cid_t *dcid); XQC_EXPORT_PUBLIC_API unsigned char *xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid); @@ -1794,7 +2083,6 @@ unsigned char *xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid) XQC_EXPORT_PUBLIC_API uint8_t xqc_engine_config_get_cid_len(xqc_engine_t *engine); - /** * User should call xqc_conn_continue_send when write event ready */ @@ -1813,6 +2101,13 @@ void xqc_conn_continue_send_by_conn(xqc_connection_t *conn); XQC_EXPORT_PUBLIC_API xqc_conn_stats_t xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid); + +/** + * User can get xqc_conn_qos_stats_t by cid + */ +XQC_EXPORT_PUBLIC_API +xqc_conn_qos_stats_t xqc_conn_get_qos_stats(xqc_engine_t *engine, const xqc_cid_t *cid); + /** * create new path for client * @param cid scid for connection diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index d429fb1fa..fc1a46d18 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -9,6 +9,48 @@ #include #include "xqc_errno.h" +#define XQC_EXTERN extern + +/* defined UNIX system default */ +#ifndef XQC_SYS_WINDOWS +# define XQC_SYS_UNIX +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(XQC_SYS_WIN32) +# if !defined(XQC_SYS_WIN32) +# define XQC_SYS_WIN32 +# endif +#endif + +#if defined(_WIN64) || defined(WIN64) || defined(XQC_SYS_WIN64) +# if !defined(XQC_SYS_WIN64) +# define XQC_SYS_WIN64 +# endif +#endif + +#if defined(XQC_SYS_WIN32) || defined(XQC_SYS_WIN64) +#undef XQC_SYS_UNIX +#define XQC_SYS_WINDOWS +#endif + +#if defined(__MINGW64__) || defined(__MINGW32__) +# if !defined(XQC_ON_MINGW) +# define XQC_ON_MINGW +# endif +#endif + +#if defined(XQC_SYS_WINDOWS) && !defined(XQC_ON_MINGW) +# undef XQC_EXTERN +# define XQC_EXTERN extern + +#ifdef XQC_SYS_WIN64 + typedef __int64 ssize_t; +#elif defined(XQC_SYS_WIN32) + typedef __int32 ssize_t; +#endif +#endif + + /* TODO: there may be problems using -o2 under Android platform */ #if defined(__GNUC__) && !defined(ANDROID) # define XQC_UNLIKELY(cond) __builtin_expect(!!(cond), 0) @@ -52,6 +94,7 @@ typedef struct xqc_path_ctx_s xqc_path_ctx_t; typedef struct xqc_timer_manager_s xqc_timer_manager_t; typedef struct xqc_h3_ext_bytestream_s xqc_h3_ext_bytestream_t; typedef struct xqc_ping_record_s xqc_ping_record_t; +typedef struct xqc_conn_qos_stats_s xqc_conn_qos_stats_t; typedef uint64_t xqc_msec_t; /* store millisecond values */ typedef uint64_t xqc_usec_t; /* store microsecond values */ @@ -68,33 +111,48 @@ typedef uint8_t xqc_bool_t; #define XQC_TRUE 1 #define XQC_FALSE 0 -/* restrictions of cid length */ +/** restrictions of cid length */ #define XQC_MAX_CID_LEN 20 #define XQC_MIN_CID_LEN 4 -/* restrictions of key length in lb cid encryption */ +/** restrictions of key length in lb cid encryption */ #define XQC_LB_CID_KEY_LEN 16 -/* length of stateless reset token */ +/** length of stateless reset token */ #define XQC_STATELESS_RESET_TOKENLEN 16 +/** + * @brief cid structure for xquic connection identification + */ typedef struct xqc_cid_s { uint8_t cid_len; uint8_t cid_buf[XQC_MAX_CID_LEN]; uint64_t cid_seq_num; uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + uint64_t path_id; /**< preallocate for multi-path */ } xqc_cid_t; typedef enum xqc_log_level_s { - XQC_LOG_REPORT, - XQC_LOG_FATAL, - XQC_LOG_ERROR, - XQC_LOG_WARN, - XQC_LOG_STATS, - XQC_LOG_INFO, - XQC_LOG_DEBUG, + XQC_LOG_REPORT = 0, + XQC_LOG_FATAL = 1, + XQC_LOG_ERROR = 2, + XQC_LOG_WARN = 3, + XQC_LOG_STATS = 4, + XQC_LOG_INFO = 5, + XQC_LOG_DEBUG = 6, } xqc_log_level_t; +/** + * @brief qlog Importance level definition + */ +typedef enum qlog_event_importance_s { + EVENT_IMPORTANCE_SELECTED = 0, /**< qlog will be emitted selectly */ + EVENT_IMPORTANCE_CORE = 1, + EVENT_IMPORTANCE_BASE = 2, + EVENT_IMPORTANCE_EXTRA = 3, + EVENT_IMPORTANCE_REMOVED = 4, /**< Currently, some events have been removed in the latest qlog draft. But old qvis need them! */ +} qlog_event_importance_t; + #define XQC_BBR_RTTVAR_COMPENSATION_ENABLED 0 typedef enum { XQC_BBR_FLAG_NONE = 0x00, @@ -112,27 +170,55 @@ typedef enum { #endif } xqc_bbr2_optimization_flag_t; -#ifdef WIN32 +#define XQC_EXPORT_PUBLIC_API __attribute__((visibility("default"))) + +#ifdef XQC_SYS_WINDOWS struct iovec { void *iov_base; /* [XSI] Base address of I/O memory region */ size_t iov_len; /* [XSI] Size of region iov_base points to */ }; + +#if !(defined __MINGW32__) && !(defined __MINGW64__) +#undef XQC_EXPORT_PUBLIC_API +#define XQC_EXPORT_PUBLIC_API _declspec(dllexport) +#endif + #endif -#define XQC_EXPORT_PUBLIC_API __attribute__((visibility("default"))) typedef enum { - XQC_CONN_TYPE_CLIENT, - XQC_CONN_TYPE_SERVER, + XQC_CONN_TYPE_CLIENT = 0, + XQC_CONN_TYPE_SERVER = 1, } xqc_conn_type_t; typedef enum { - XQC_STREAM_BIDI, - XQC_STREAM_UNI + XQC_STREAM_BIDI = 0, + XQC_STREAM_UNI = 1 } xqc_stream_direction_t; +/** + * @brief FEC priority settings decided by h3 requests size + */ +typedef enum { + XQC_FEC_DEFAULT = 0, + XQC_FEC_CLOSE = 2 * 1024, + XQC_FEC_NORMAL = 4 * 1024, + XQC_FEC_MIDDLE = 20 * 1024 +} xqc_fec_priority_t; + +/** + * @brief FEC inner priority types decided by xqc_fec_priority_t + */ +typedef enum { + XQC_DEFAULT_SIZE_REQ, + XQC_SLIM_SIZE_REQ, + XQC_NORMAL_SIZE_REQ, + XQC_MIDDLE_SIZE_REQ, + XQC_LARGE_SIZE_REQ +} xqc_stream_size_type_t; + #define XQC_DEFAULT_HTTP_PRIORITY_URGENCY 3 #define XQC_HIGHEST_HTTP_PRIORITY_URGENCY 0 #define XQC_LOWEST_HTTP_PRIORITY_URGENCY 7 @@ -142,6 +228,7 @@ typedef struct xqc_http_priority_s { uint8_t incremental; uint8_t schedule; uint8_t reinject; + uint32_t fec; } xqc_h3_priority_t; /* ALPN definition */ @@ -152,11 +239,14 @@ typedef struct xqc_http_priority_s { /* max alpn buffer length */ #define XQC_MAX_ALPN_BUF_LEN 256 +#define XQC_MAX_FEC_BUF_LEN 64 +#define XQC_MAX_COMMON_BUF_LEN 64 + #define XQC_UNKNOWN_PATH_ID ((uint64_t)-1) typedef enum xqc_conn_settings_type_e { - XQC_CONN_SETTINGS_DEFAULT, - XQC_CONN_SETTINGS_LOW_DELAY, + XQC_CONN_SETTINGS_DEFAULT = 0, + XQC_CONN_SETTINGS_LOW_DELAY = 1, } xqc_conn_settings_type_t; typedef struct xqc_conn_public_local_trans_settings_s { @@ -172,4 +262,75 @@ typedef struct xqc_stream_settings_s { uint64_t recv_rate_bytes_per_sec; } xqc_stream_settings_t; +#define XQC_CO_TAG(a, b, c, d) (uint32_t)((a << 24) + (b << 16) + (c << 8) + d) + +typedef enum xqc_conn_option_e { + XQC_CO_TBBR = XQC_CO_TAG('T', 'B', 'B', 'R'), // Reduced Buffer Bloat TCP + XQC_CO_1RTT = XQC_CO_TAG('1', 'R', 'T', 'T'), // STARTUP in BBR for 1 RTT + XQC_CO_2RTT = XQC_CO_TAG('2', 'R', 'T', 'T'), // STARTUP in BBR for 2 RTTs + XQC_CO_BBR4 = XQC_CO_TAG('B', 'B', 'R', '4'), // 20 RTT ack aggregation + XQC_CO_BBR5 = XQC_CO_TAG('B', 'B', 'R', '5'), // 40 RTT ack aggregation + XQC_CO_IW03 = XQC_CO_TAG('I', 'W', '0', '3'), // Force ICWND to 3 + XQC_CO_IW10 = XQC_CO_TAG('I', 'W', '1', '0'), // Force ICWND to 10 + XQC_CO_IW20 = XQC_CO_TAG('I', 'W', '2', '0'), // Force ICWND to 20 + XQC_CO_IW50 = XQC_CO_TAG('I', 'W', '5', '0'), // Force ICWND to 50 + XQC_CO_B2ON = XQC_CO_TAG('B', '2', 'O', 'N'), // Enable BBRv2 + XQC_CO_COPA = XQC_CO_TAG('C', 'O', 'P', 'A'), // Enable COPA + XQC_CO_C2ON = XQC_CO_TAG('C', '2', 'O', 'N'), // Enable CopaV2 + XQC_CO_QBIC = XQC_CO_TAG('Q', 'B', 'I', 'C'), // TCP Cubic + XQC_CO_RENO = XQC_CO_TAG('R', 'E', 'N', 'O'), // Enable reno + XQC_CO_SPRI = XQC_CO_TAG('S', 'P', 'R', 'I'), // enable stream priority by streamid + XQC_CO_9218 = XQC_CO_TAG('9', '2', '1', '8'), // enable stream priority by rfc9218 + XQC_CO_D218 = XQC_CO_TAG('D', '2', '1', '8'), // disable rfc9218 + XQC_CO_DRST = XQC_CO_TAG('D', 'R', 'S', 'T'), // disable cease sending stream + XQC_CO_CBBR = XQC_CO_TAG('C', 'B', 'B', 'R'), // A global option to enable all the following options (Customized BBR) + XQC_CO_BNLS = XQC_CO_TAG('B', 'N', 'L', 'S'), // Force BBR not to respond on losses during STARTUP + XQC_CO_BACG = XQC_CO_TAG('B', 'A', 'C', 'G'), // Use Adaptive CWND_GAIN in BBR + XQC_CO_CG03 = XQC_CO_TAG('C', 'G', '0', '3'), // Use 3 for CWND_GAIN in BBR + XQC_CO_CG05 = XQC_CO_TAG('C', 'G', '0', '5'), // Use 5 for CWND_GAIN in BBR + XQC_CO_CG10 = XQC_CO_TAG('C', 'G', '1', '0'), // Use 10 for CWND_GAIN in BBR + XQC_CO_CG20 = XQC_CO_TAG('C', 'G', '2', '0'), // Use 20 for CWND_GAIN in BBR + XQC_CO_PG11 = XQC_CO_TAG('P', 'G', '1', '1'), // Use 1.1 for PACING_GAIN in BBR PROBE_UP + XQC_CO_PG15 = XQC_CO_TAG('P', 'G', '1', '5'), // Use 1.5 for PACING_GAIN in BBR PROBE_UP + XQC_CO_BNLR = XQC_CO_TAG('B', 'N', 'L', 'R'), // Disable BBR's loss recovery state + XQC_CO_MW10 = XQC_CO_TAG('M', 'W', '1', '0'), // Set min CWND to 10 + XQC_CO_MW20 = XQC_CO_TAG('M', 'W', '2', '0'), // Set min CWND to 20 + XQC_CO_MW32 = XQC_CO_TAG('M', 'W', '3', '2'), // Set min CWND to 32 + XQC_CO_MW50 = XQC_CO_TAG('M', 'W', '5', '0'), // Set min CWND to 50 + XQC_CO_WL20 = XQC_CO_TAG('W', 'L', '2', '0'), // Set BW window length to 20 (RTTs) + XQC_CO_WL30 = XQC_CO_TAG('W', 'L', '3', '0'), // Set BW window length to 30 (RTTs) + XQC_CO_WL40 = XQC_CO_TAG('W', 'L', '4', '0'), // Set BW window length to 40 (RTTs) + XQC_CO_WL50 = XQC_CO_TAG('W', 'L', '5', '0'), // Set BW window length to 50 (RTTs) + XQC_CO_PR02 = XQC_CO_TAG('P', 'R', '0', '2'), // Set the target CWND in ProbeRTT to 0.2xBDP + XQC_CO_PR03 = XQC_CO_TAG('P', 'R', '0', '3'), // Set the target CWND in ProbeRTT to 0.3xBDP + XQC_CO_PR04 = XQC_CO_TAG('P', 'R', '0', '4'), // Set the target CWND in ProbeRTT to 0.4xBDP + XQC_CO_PR05 = XQC_CO_TAG('P', 'R', '0', '5'), // Set the target CWND in ProbeRTT to 0.5xBDP + XQC_CO_PR06 = XQC_CO_TAG('P', 'R', '0', '6'), // Set the target CWND in ProbeRTT to 0.6xBDP + XQC_CO_PR07 = XQC_CO_TAG('P', 'R', '0', '7'), // Set the target CWND in ProbeRTT to 0.7xBDP + XQC_CO_ENWC = XQC_CO_TAG('E', 'N', 'W', 'C'), // Enable CWND compensation according to jitter + XQC_CO_JW10 = XQC_CO_TAG('J', 'W', '1', '0'), // Set the window length of max jitter filter to 10xRTT (default) + XQC_CO_JW20 = XQC_CO_TAG('J', 'W', '2', '0'), // Set the window length of max jitter filter to 20xRTT + XQC_CO_JW30 = XQC_CO_TAG('J', 'W', '3', '0'), // Set the window length of max jitter filter to 30xRTT + XQC_CO_JW40 = XQC_CO_TAG('J', 'W', '4', '0'), // Set the window length of max jitter filter to 40xRTT + XQC_CO_JW50 = XQC_CO_TAG('J', 'W', '5', '0'), // Set the window length of max jitter filter to 50xRTT + XQC_CO_SL03 = XQC_CO_TAG('S', 'L', '0', '3'), // Set the STARTUP loss rate threshold to 0.03 + XQC_CO_SL04 = XQC_CO_TAG('S', 'L', '0', '4'), // Set the STARTUP loss rate threshold to 0.04 + XQC_CO_SL05 = XQC_CO_TAG('S', 'L', '0', '5'), // Set the STARTUP loss rate threshold to 0.05 + XQC_CO_SL10 = XQC_CO_TAG('S', 'L', '1', '0'), // Set the STARTUP loss rate threshold to 0.05 +} xqc_conn_option_t; + +/* application layer path status */ +typedef enum { + /* max */ + XQC_APP_PATH_STATUS_NONE = 0, + /* suggest that no traffic should be sent on that path if another path is available */ + XQC_APP_PATH_STATUS_STANDBY = 1, + /* allow the peer to use its own logic to split traffic among available paths */ + XQC_APP_PATH_STATUS_AVAILABLE = 2, + /* freeze a path */ + XQC_APP_PATH_STATUS_FROZEN = 3, + /* max */ + XQC_APP_PATH_STATUS_MAX, +} xqc_app_path_status_t; + #endif /*_XQUIC_TYPEDEF_H_INCLUDED_*/ diff --git a/interop/Dockerfile b/interop/Dockerfile index 4ae4417e5..e6ef04636 100644 --- a/interop/Dockerfile +++ b/interop/Dockerfile @@ -1,36 +1,27 @@ FROM martenseemann/quic-network-simulator-endpoint:latest -ENV XQC_PATH /xquic \ - SSL_PATH $XQC_PATH/third_party/boringssl \ - SSL_INC_PATH $SSL_PATH/include \ - SSL_LIB_PATH $SSL_PATH/build/ssl/libssl.a;$SSL_PATH/build/crypto/libcrypto.a - RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive \ apt-get install -y --no-install-recommends build-essential \ git cmake golang make autoconf automake libtool \ libevent-dev net-tools && \ go env -w GOPROXY=https://goproxy.cn && \ - git clone --depth 1 --branch interop https://github.com/alibaba/xquic.git && \ - git clone --depth 1 https://github.com/google/boringssl.git xquic/third_party/boringssl && \ - cd xquic/third_party/boringssl/ && \ - if [ ! -d build ]; then mkdir build; else rm -rf build; mkdir build; fi && \ - cd build && \ - cmake -DBUILD_SHARED_LIBS=0 -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. && \ - make ssl crypto && \ - cd ../../../../ && \ + git clone --depth 1 https://github.com/alibaba/xquic.git && \ + git clone --depth 1 https://github.com/Tongsuo-Project/Tongsuo.git xquic/third_party/babassl && \ + cd xquic/third_party/babassl/ && \ + ./Configure --api=1.1.1 no-deprecated && make -j && \ + cd ../../../ && \ mkdir xquic_bin && \ cd xquic_bin && \ - cmake -DSSL_TYPE="boringssl" \ - -DSSL_PATH="$SSL_PATH" \ - -DSSL_INC_PATH="$SSL_INC_PATH" \ - -DSSL_LIB_PATH="$SSL_LIB_PATH" \ + cmake -DSSL_TYPE="babassl" \ + -DSSL_PATH="/xquic/third_party/babassl" \ -DCMAKE_BUILD_TYPE=DEBUG \ -DXQC_PRINT_SECRET=1 \ -DXQC_ENABLE_TESTING=1 \ ../xquic/ && \ make -j && \ rm -rf CMake* Makefile *.cmake tests xqc_configure.h test_client test_server && \ + mv demo/demo_* . && \ cd .. && rm -rf xquic/ && \ apt-get -y purge \ git cmake golang make autoconf automake libtool && \ diff --git a/interop/run_endpoint.sh b/interop/run_endpoint.sh index 88d6f2b4f..6a64002a6 100644 --- a/interop/run_endpoint.sh +++ b/interop/run_endpoint.sh @@ -4,7 +4,7 @@ /setup.sh case $TESTCASE in - versionnegotiation|handshake|longrtt|transfer|zerortt|multiconnect|chacha20|resumption|http3|retry|keyupdate) + versionnegotiation|handshake|longrtt|transfer|zerortt|multiconnect|chacha20|resumption|http3|retry|keyupdate|mphandshake|mptransfer|mppathabandon|mppathstatus) : ;; *) @@ -20,7 +20,7 @@ if [ "$ROLE" == "client" ]; then /wait-for-it.sh sim:57832 -s -t 30 # client args - ARGS="-l d -L "$LOG_DIR/client.log" -D "/downloads" -k $SSLKEYLOGFILE -K 30" + ARGS="-l d -L "$LOG_DIR/client.log" -D "/downloads" -k $SSLKEYLOGFILE -K 30 -o" # zerortt if [ "$TESTCASE" == "zerortt" ]; then @@ -45,9 +45,9 @@ if [ "$ROLE" == "client" ]; then for REQ in $REQUESTS; do echo -e "\nstart requesty[$i]: $REQ" - echo -e "./demo_client -l d -L \"/logs/log_$i.log\" -D \"/downloads\" -k $SSLKEYLOGFILE -U \"$REQ\" -K 60\n" + echo -e "./demo_client -l d -L \"/logs/log_$i.log\" -D \"/downloads\" -k $SSLKEYLOGFILE -U \"$REQ\" -K 90 -o\n" # ./demo_client -l d -L "/logs/log_$i.log" -D "/downloads" -k $SSLKEYLOGFILE -U "$REQ" -A "h3" -0 -K 90 - ./demo_client -l d -L "/logs/log_$i.log" -D "/downloads" -k $SSLKEYLOGFILE -U "$REQ" -0 -K 90 + ./demo_client -l d -L "/logs/log_$i.log" -D "/downloads" -k $SSLKEYLOGFILE -U "$REQ" -0 -K 90 -o i=`expr $i + 1` done @@ -62,7 +62,19 @@ if [ "$ROLE" == "client" ]; then elif [ "$TESTCASE" == "keyupdate" ]; then echo "./demo_client $ARGS -U $REQUESTS -u 30" ./demo_client $ARGS -U "$REQUESTS" -u 30 + + elif [ "$TESTCASE" == "mphandshake" ] || [ "$TESTCASE" == "mptransfer" ]; then + echo "./demo_client $ARGS -U $REQUESTS -M -i eth0 -i eth0 -w 3000" + ./demo_client $ARGS -U "$REQUESTS" -M -i eth0 -i eth0 -w 3000 + elif [ "$TESTCASE" == "mppathabandon" ]; then + echo "./demo_client $ARGS -U $REQUESTS -M -i eth0 -i eth0 -w 3000 -Z 1000" + ./demo_client $ARGS -U "$REQUESTS" -M -i eth0 -i eth0 -w 3000 -Z 1000 + + elif [ "$TESTCASE" == "mppathstatus" ]; then + echo "./demo_client $ARGS -U $REQUESTS -M -i eth0 -i eth0 -w 3000 -b" + ./demo_client $ARGS -U "$REQUESTS" -M -i eth0 -i eth0 -w 3000 -b + # common testcase else echo -e "./demo_client $ARGS -U \"$REQUESTS\"\n" @@ -85,7 +97,7 @@ elif [ "$ROLE" == "server" ]; then #cp -r /www /logs - ARGS="-l d -L "$LOG_DIR/server.log" -p 443 -D "/www" -k $SSLKEYLOGFILE" + ARGS="-l d -L "$LOG_DIR/server.log" -p 443 -D "/www" -k $SSLKEYLOGFILE -i -M" echo "./demo_server $ARGS" ./demo_server $ARGS fi diff --git a/mini/CMakeLists.txt b/mini/CMakeLists.txt new file mode 100644 index 000000000..3cf4e11ec --- /dev/null +++ b/mini/CMakeLists.txt @@ -0,0 +1,50 @@ +### hq mini client/server ### +set( + HQ_SOURCES + "../demo/xqc_hq_ctx.c" + "../demo/xqc_hq_conn.c" + "../demo/xqc_hq_request.c" +) + +set( + MINI_CLIENT_SOURCES + ${HQ_SOURCES} + "common.c" + "mini_client.c" + "mini_client_cb.c" +) + +set( + MINI_SERVER_SOURCES + ${HQ_SOURCES} + "common.c" + "mini_server.c" + "mini_server_cb.c" +) + + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(MINI_SERVER_SOURCES + ${MINI_SERVER_SOURCES} + ${GETOPT_SOURCES} + ) + + set(MINI_CLIENT_SOURCES + ${MINI_CLIENT_SOURCES} + ${GETOPT_SOURCES} + ) +endif() + +include_directories( + "${CMAKE_SOURCE_DIR}/" + "${CMAKE_SOURCE_DIR}/include" + ${CMAKE_SOURCE_DIR} + ${CUNIT_INCLUDE_DIRS} + ${LIBEVENT_INCLUDE_DIR} +) + +add_executable(mini_server ${MINI_SERVER_SOURCES}) +add_executable(mini_client ${MINI_CLIENT_SOURCES}) + +target_link_libraries(mini_server ${APP_DEPEND_LIBS}) +target_link_libraries(mini_client ${APP_DEPEND_LIBS}) diff --git a/mini/common.c b/mini/common.c new file mode 100644 index 000000000..91dcc3bd3 --- /dev/null +++ b/mini/common.c @@ -0,0 +1,39 @@ +#include "common.h" + +char method_s[][16] = { + {"GET"}, + {"POST"} +}; +int +xqc_mini_read_file_data(char * data, size_t data_len, char *filename) +{ + int ret = 0; + size_t total_len, read_len; + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + ret = -1; + goto end; + } + + fseek(fp, 0 , SEEK_END); + total_len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (total_len > data_len) { + ret = -1; + goto end; + } + + read_len = fread(data, 1, total_len, fp); + if (read_len != total_len) { + ret = -1; + goto end; + } + + ret = read_len; + +end: + if (fp) { + fclose(fp); + } + return ret; +} diff --git a/mini/common.h b/mini/common.h new file mode 100644 index 000000000..ce13c89ad --- /dev/null +++ b/mini/common.h @@ -0,0 +1,71 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + + +#include +#include +#include + +/* definition for connection */ +#define DEFAULT_SERVER_ADDR "127.0.0.1" +#define DEFAULT_SERVER_PORT 8443 + +#define CIPHER_SUIT_LEN 256 +#define TLS_GROUPS_LEN 64 + +#define PATH_LEN 1024 +#define RESOURCE_LEN 1024 +#define AUTHORITY_LEN 128 +#define URL_LEN 1024 + +/* the congestion control types */ +typedef enum cc_type_s { + CC_TYPE_BBR, + CC_TYPE_CUBIC, + CC_TYPE_RENO, + CC_TYPE_COPA +} CC_TYPE; + + + +/* request method */ +typedef enum request_method_e { + REQUEST_METHOD_GET, + REQUEST_METHOD_POST, +} REQUEST_METHOD; + +extern char method_s[][16]; + + +static size_t READ_FILE_BUF_LEN = 2 *1024 * 1024; + +#define DEBUG ; +// #define DEBUG printf("%s:%d (%s)\n",__FILE__, __LINE__ ,__FUNCTION__); + + +#define RSP_HDR_BUF_LEN 32 +typedef enum h3_hdr_type { + /* rsp */ + H3_HDR_STATUS, + H3_HDR_CONTENT_TYPE, + H3_HDR_CONTENT_LENGTH, + H3_HDR_METHOD, + H3_HDR_SCHEME, + H3_HDR_HOST, + H3_HDR_PATH, + + H3_HDR_CNT +} H3_HDR_TYPE; + + +extern long xqc_random(void); +extern xqc_usec_t xqc_now(); + + +int xqc_mini_read_file_data(char * data, size_t data_len, char *filename); + +#endif diff --git a/mini/mini_client.c b/mini/mini_client.c new file mode 100644 index 000000000..4e1d716e4 --- /dev/null +++ b/mini/mini_client.c @@ -0,0 +1,745 @@ +#include "mini_client.h" + +#include + +void +xqc_mini_cli_init_engine_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_cli_args_t *args) +{ + ssl_cfg->ciphers = args->quic_cfg.ciphers; + ssl_cfg->groups = args->quic_cfg.groups; +} + + +void +xqc_mini_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, xqc_mini_cli_args_t *args) +{ + static xqc_engine_callback_t callback = { + .set_event_timer = xqc_mini_cli_set_event_timer, + .log_callbacks = { + .xqc_log_write_err = xqc_mini_cli_write_log_file, + .xqc_log_write_stat = xqc_mini_cli_write_log_file, + .xqc_qlog_event_write = xqc_mini_cli_write_qlog_file + }, + .keylog_cb = xqc_mini_cli_keylog_cb, + }; + + static xqc_transport_callbacks_t transport_cbs = { + .write_socket = xqc_mini_cli_write_socket, + .write_socket_ex = xqc_mini_cli_write_socket_ex, + .save_token = xqc_mini_cli_save_token, + .save_session_cb = xqc_mini_cli_save_session_cb, + .save_tp_cb = xqc_mini_cli_save_tp_cb, + }; + + *cb = callback; + *tcb = transport_cbs; +} + +int +xqc_mini_cli_init_xquic_engine(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + int ret; + xqc_config_t egn_cfg; + xqc_engine_callback_t callback; + xqc_engine_ssl_config_t ssl_cfg = {0}; + xqc_transport_callbacks_t transport_cbs; + + /* get default parameters of xquic engine */ + ret = xqc_engine_get_default_config(&egn_cfg, XQC_ENGINE_CLIENT); + if (ret < 0) { + return XQC_ERROR; + } + + /* init ssl config */ + xqc_mini_cli_init_engine_ssl_config(&ssl_cfg, args); + + /* init engine & transport callbacks */ + xqc_mini_cli_init_callback(&callback, &transport_cbs, args); + + /* create client engine */ + ctx->engine = xqc_engine_create(XQC_ENGINE_CLIENT, &egn_cfg, &ssl_cfg, + &callback, &transport_cbs, ctx); + if (ctx->engine == NULL) { + printf("[error] xqc_engine_create error\n"); + return XQC_ERROR; + } + + ctx->ev_engine = event_new(ctx->eb, -1, 0, xqc_mini_cli_engine_cb, ctx); + return XQC_OK; +} + +void +xqc_mini_cli_convert_text_to_sockaddr(int type, + const char *addr_text, unsigned int port, + struct sockaddr **saddr, socklen_t *saddr_len) +{ + *saddr = calloc(1, sizeof(struct sockaddr_in)); + struct sockaddr_in *addr_v4 = (struct sockaddr_in *)(*saddr); + inet_pton(type, addr_text, &(addr_v4->sin_addr.s_addr)); + addr_v4->sin_family = type; + addr_v4->sin_port = htons(port); + *saddr_len = sizeof(struct sockaddr_in); +} + +void +xqc_mini_cli_init_args(xqc_mini_cli_args_t *args) +{ + /* init network args */ + args->net_cfg.conn_timeout = 9; + + /** + * init quic config + * it's recommended to replace the constant value with option arguments according to actual needs + */ + strncpy(args->quic_cfg.ciphers, XQC_TLS_CIPHERS, CIPHER_SUIT_LEN - 1); + strncpy(args->quic_cfg.groups, XQC_TLS_GROUPS, TLS_GROUPS_LEN - 1); + args->quic_cfg.multipath = 0; + + + /* init environmen args */ + // args->env_cfg.log_level = XQC_LOG_DEBUG; + strncpy(args->env_cfg.log_path, LOG_PATH, sizeof(args->env_cfg.log_path)); + strncpy(args->env_cfg.out_file_dir, OUT_DIR, sizeof(args->env_cfg.out_file_dir)); + strncpy(args->env_cfg.key_out_path, KEY_PATH, sizeof(args->env_cfg.key_out_path)); + + /* init request args */ + args->req_cfg.method = REQUEST_METHOD_GET; // GET + strncpy(args->req_cfg.scheme, "https", sizeof(args->req_cfg.scheme)); + strncpy(args->req_cfg.url, "/", sizeof(args->req_cfg.url)); + strncpy(args->req_cfg.host, DEFAULT_HOST, sizeof(args->req_cfg.host)); +} + +int +xqc_mini_cli_init_ctx(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + memset(ctx, 0, sizeof(xqc_mini_cli_ctx_t)); + + /* init event base */ + struct event_base *eb = event_base_new(); + ctx->eb = eb; + + ctx->args = args; + + /* init log writer fd */ + ctx->log_fd = xqc_mini_cli_open_log_file(ctx); + if (ctx->log_fd < 0) { + printf("[error] open log file failed\n"); + return XQC_ERROR; + } + /* init keylog writer fd */ + ctx->keylog_fd = xqc_mini_cli_open_keylog_file(ctx); + if (ctx->keylog_fd < 0) { + printf("[error] open keylog file failed\n"); + return XQC_ERROR; + } + + return 0; +} + + +int +xqc_mini_cli_init_env(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + int ret = XQC_OK; + + /* init client args */ + xqc_mini_cli_init_args(args); + + /* init client ctx */ + ret = xqc_mini_cli_init_ctx(ctx, args); + + return ret; +} + +xqc_scheduler_callback_t +xqc_mini_cli_get_sched_cb(xqc_mini_cli_args_t *args) +{ + xqc_scheduler_callback_t sched = xqc_minrtt_scheduler_cb; + if (strncmp(args->quic_cfg.mp_sched, "minrtt", strlen("minrtt")) == 0) { + sched = xqc_minrtt_scheduler_cb; + + } if (strncmp(args->quic_cfg.mp_sched, "backup", strlen("backup")) == 0) { + sched = xqc_backup_scheduler_cb; + } + return sched; +} + +xqc_cong_ctrl_callback_t +xqc_mini_cli_get_cc_cb(xqc_mini_cli_args_t *args) +{ + xqc_cong_ctrl_callback_t ccc = xqc_bbr_cb; + switch (args->quic_cfg.cc) { + case CC_TYPE_BBR: + ccc = xqc_bbr_cb; + break; + case CC_TYPE_CUBIC: + ccc = xqc_cubic_cb; + break; + default: + break; + } + return ccc; +} + +void +xqc_mini_cli_init_conn_settings(xqc_conn_settings_t *settings, xqc_mini_cli_args_t *args) +{ + /* parse congestion control callback */ + xqc_cong_ctrl_callback_t ccc = xqc_mini_cli_get_cc_cb(args); + /* parse mp scheduler callback */ + xqc_scheduler_callback_t sched = xqc_mini_cli_get_sched_cb(args); + + /* init connection settings */ + memset(settings, 0, sizeof(xqc_conn_settings_t)); + settings->cong_ctrl_callback = ccc; + settings->cc_params.customize_on = 1; + settings->cc_params.init_cwnd = 96; + settings->so_sndbuf = 1024*1024; + settings->proto_version = XQC_VERSION_V1; + settings->spurious_loss_detect_on = 1; + settings->scheduler_callback = sched; + settings->reinj_ctl_callback = xqc_deadline_reinj_ctl_cb; + settings->adaptive_ack_frequency = 1; +} + +int +xqc_mini_cli_init_alpn_ctx(xqc_mini_cli_ctx_t *ctx) +{ + int ret = XQC_OK; + + /* init http3 callbacks */ + xqc_h3_callbacks_t h3_cbs = { + .h3c_cbs = { + .h3_conn_create_notify = xqc_mini_cli_h3_conn_create_notify, + .h3_conn_close_notify = xqc_mini_cli_h3_conn_close_notify, + .h3_conn_handshake_finished = xqc_mini_cli_h3_conn_handshake_finished, + }, + .h3r_cbs = { + .h3_request_create_notify = xqc_mini_cli_h3_request_create_notify, + .h3_request_close_notify = xqc_mini_cli_h3_request_close_notify, + .h3_request_read_notify = xqc_mini_cli_h3_request_read_notify, + .h3_request_write_notify = xqc_mini_cli_h3_request_write_notify, + } + }; + + /* init http3 context */ + ret = xqc_h3_ctx_init(ctx->engine, &h3_cbs); + if (ret != XQC_OK) { + printf("init h3 context error, ret: %d\n", ret); + return ret; + } + + return ret; +} + +int +xqc_mini_cli_init_engine_ctx(xqc_mini_cli_ctx_t *ctx) +{ + int ret; + + /* init alpn ctx */ + ret = xqc_mini_cli_init_alpn_ctx(ctx); + + return ret; +} + +void +xqc_mini_cli_free_ctx(xqc_mini_cli_ctx_t *ctx) +{ + xqc_mini_cli_close_keylog_file(ctx); + xqc_mini_cli_close_log_file(ctx); + + if (ctx->args) { + free(ctx->args); + ctx->args = NULL; + } +} + +void +xqc_mini_cli_init_0rtt(xqc_mini_cli_args_t *args) +{ + /* read session ticket */ + int ret = xqc_mini_read_file_data(args->quic_cfg.session_ticket, + SESSION_TICKET_BUF_MAX_SIZE, SESSION_TICKET_FILE); + args->quic_cfg.session_ticket_len = ret > 0 ? ret : 0; + + /* read transport params */ + ret = xqc_mini_read_file_data(args->quic_cfg.transport_parameter, + TRANSPORT_PARAMS_MAX_SIZE, TRANSPORT_PARAMS_FILE); + args->quic_cfg.transport_parameter_len = ret > 0 ? ret : 0; + + /* read token */ + ret = xqc_mini_cli_read_token( + args->quic_cfg.token, TOKEN_MAX_SIZE); + args->quic_cfg.token_len = ret > 0 ? ret : 0; +} + +void +xqc_mini_cli_init_conn_ssl_config(xqc_conn_ssl_config_t *conn_ssl_config, xqc_mini_cli_args_t *args) +{ + /* set session ticket and transport parameter args */ + if (args->quic_cfg.session_ticket_len < 0 || args->quic_cfg.transport_parameter_len < 0) { + conn_ssl_config->session_ticket_data = NULL; + conn_ssl_config->transport_parameter_data = NULL; + + } else { + conn_ssl_config->session_ticket_data = args->quic_cfg.session_ticket; + conn_ssl_config->session_ticket_len = args->quic_cfg.session_ticket_len; + conn_ssl_config->transport_parameter_data = args->quic_cfg.transport_parameter; + conn_ssl_config->transport_parameter_data_len = args->quic_cfg.transport_parameter_len; + } +} + +int +xqc_mini_cli_format_h3_req(xqc_http_header_t *headers, xqc_mini_cli_req_config_t* req_cfg) +{ + /* response header buf list */ + xqc_http_header_t req_hdr[] = { + { + .name = {.iov_base = ":method", .iov_len = 7}, + .value = {.iov_base = method_s[req_cfg->method], .iov_len = strlen(method_s[req_cfg->method])}, + .flags = 0, + }, + { + .name = {.iov_base = ":scheme", .iov_len = 7}, + .value = {.iov_base = req_cfg->scheme, .iov_len = strlen(req_cfg->scheme)}, + .flags = 0, + }, + { + .name = {.iov_base = "host", .iov_len = 4}, + .value = {.iov_base = req_cfg->host, .iov_len = strlen(req_cfg->host)}, + .flags = 0, + }, + { + .name = {.iov_base = ":path", .iov_len = 5}, + .value = {.iov_base = req_cfg->url, .iov_len = strlen(req_cfg->path)}, + .flags = 0, + }, + { + .name = {.iov_base = "content-type", .iov_len = 12}, + .value = {.iov_base = "text/plain", .iov_len = 10}, + .flags = 0, + }, + { + .name = {.iov_base = "content-length", .iov_len = 14}, + .value = {.iov_base = 0, .iov_len = 0}, + .flags = 0, + }, + }; + + size_t req_sz = sizeof(req_hdr) / sizeof(req_hdr[0]); + if (req_sz > H3_HDR_CNT) { + printf("[error] header length is too large, request_size: %zd\n", req_sz); + return XQC_ERROR; + } + + for (size_t i = 0; i < req_sz; i++) { + headers[i] = req_hdr[i]; + } + return req_sz; +} + +int +xqc_mini_cli_request_send(xqc_h3_request_t *h3_request, xqc_mini_cli_user_stream_t *user_stream) +{ + int ret, fin; + /* send packet header/body */ + xqc_http_header_t header[H3_HDR_CNT]; + xqc_mini_cli_req_config_t* req_cfg; + + req_cfg = &user_stream->user_conn->ctx->args->req_cfg; + + fin = 1; + ret = xqc_mini_cli_format_h3_req(header, req_cfg); + if (ret > 0) { + user_stream->h3_hdrs.headers = header; + user_stream->h3_hdrs.count = ret; + + if (user_stream->start_time == 0) { + user_stream->start_time = xqc_now(); + } + /* send header */ + ret = xqc_h3_request_send_headers(user_stream->h3_request, &user_stream->h3_hdrs, fin); + if (ret < 0) { + printf("[error] xqc_mini_cli_h3_request_send error %d\n", ret); + } else { + printf("[stats] xqc_mini_cli_h3_request_send success \n"); + user_stream->hdr_sent = 1; + } + } + + if (req_cfg->method == REQUEST_METHOD_GET) { + return XQC_OK; + } + + return XQC_OK; +} + +int +xqc_mini_cli_send_h3_req(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_user_stream_t *user_stream) +{ + user_stream->user_conn = user_conn; + + xqc_stream_settings_t settings = { .recv_rate_bytes_per_sec = 0 }; + user_stream->h3_request = xqc_h3_request_create(user_conn->ctx->engine, &user_conn->cid, + &settings, user_stream); + if (user_stream->h3_request == NULL) { + printf("[error] xqc_h3_request_create error\n"); + return XQC_ERROR; + } + + xqc_mini_cli_request_send(user_stream->h3_request, user_stream); + + /* generate engine main log to send packets */ + xqc_engine_main_logic(user_conn->ctx->engine); + return XQC_OK; +} + + +int +xqc_mini_cli_init_socket(xqc_mini_cli_user_conn_t *user_conn) +{ + int fd, size; + xqc_mini_cli_ctx_t *ctx = user_conn->ctx; + xqc_mini_cli_net_config_t* cfg = &ctx->args->net_cfg; + struct sockaddr *addr = user_conn->local_addr; + + fd = socket(addr->sa_family, SOCK_DGRAM, 0); + if (fd < 0) { + printf("[error] create socket failed, errno: %d\n", get_sys_errno()); + return XQC_ERROR; + } + +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + printf("[error] set socket nonblock failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + size = 1 * 1024 * 1024; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { + printf("[error] setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { + printf("[error] setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + +#if !defined(__APPLE__) + int val = IP_PMTUDISC_DO; + setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); +#endif + +#if !defined(__APPLE__) + if (connect(fd, (struct sockaddr *)user_conn->peer_addr, user_conn->peer_addrlen) < 0) { + printf("[error] connect socket failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + ctx->args->net_cfg.last_socket_time = xqc_now(); + printf("[stats] init socket succesfully \n"); + + user_conn->fd = fd; + + return XQC_OK; +err: + close(fd); + return XQC_ERROR; +} + +void +xqc_mini_cli_socket_write_handler(xqc_mini_cli_user_conn_t *user_conn, int fd) +{ + DEBUG + printf("[stats] socket write handler\n"); +} + +void +xqc_mini_cli_socket_read_handler(xqc_mini_cli_user_conn_t *user_conn, int fd) +{ + DEBUG + ssize_t recv_size, recv_sum; + uint64_t recv_time; + xqc_int_t ret; + unsigned char packet_buf[XQC_PACKET_BUF_LEN]; + xqc_mini_cli_ctx_t *ctx; + + recv_size = recv_sum = 0; + ctx = user_conn->ctx; + + do { + /* recv quic packet from server */ + recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, + user_conn->peer_addr, &user_conn->peer_addrlen); + if (recv_size < 0 && get_sys_errno() == EAGAIN) { + break; + } + + if (recv_size < 0) { + printf("recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); + break; + } + + if (user_conn->get_local_addr == 0) { + user_conn->get_local_addr = 1; + user_conn->local_addrlen = sizeof(struct sockaddr_in6); + ret = getsockname(user_conn->fd, (struct sockaddr*)user_conn->local_addr, + &user_conn->local_addrlen); + if (ret != 0) { + printf("getsockname error, errno: %d\n", get_sys_errno()); + user_conn->local_addrlen = 0; + break; + } + } + + recv_sum += recv_size; + recv_time = xqc_now(); + ctx->args->net_cfg.last_socket_time = recv_time; + + /* process quic packet with xquic engine */ + ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, + user_conn->local_addr, user_conn->local_addrlen, + user_conn->peer_addr, user_conn->peer_addrlen, + (xqc_usec_t)recv_time, user_conn); + if (ret != XQC_OK) { + printf("[error] client_read_handler: packet process err, ret: %d\n", ret); + return; + } + } while (recv_size > 0); + +finish_recv: + // printf("[stats] xqc_mini_cli_socket_read_handler, recv size:%zu\n", recv_sum); + xqc_engine_finish_recv(ctx->engine); +} + +static void +xqc_mini_cli_socket_event_callback(int fd, short what, void *arg) +{ + //DEBUG; + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)arg; + + if (what & EV_WRITE) { + xqc_mini_cli_socket_write_handler(user_conn, fd); + + } else if (what & EV_READ) { + xqc_mini_cli_socket_read_handler(user_conn, fd); + + } else { + printf("event callback: fd=%d, what=%d\n", fd, what); + exit(1); + } +} +int +xqc_mini_cli_init_xquic_connection(xqc_mini_cli_user_conn_t *user_conn) +{ + xqc_conn_ssl_config_t conn_ssl_config = {0}; + xqc_conn_settings_t conn_settings = {0}; + xqc_mini_cli_ctx_t *ctx; + xqc_mini_cli_args_t *args; + + ctx = user_conn->ctx; + args = ctx->args; + + /* load 0-rtt args */ + xqc_mini_cli_init_0rtt(ctx->args); + + /* init connection settings */ + xqc_mini_cli_init_conn_settings(&conn_settings, ctx->args); + + /* init connection ssl config */ + xqc_mini_cli_init_conn_ssl_config(&conn_ssl_config, ctx->args); + + /* build connection */ + const xqc_cid_t *cid = xqc_h3_connect(ctx->engine, &conn_settings, args->quic_cfg.token, + args->quic_cfg.token_len, args->req_cfg.host, args->quic_cfg.no_encryption, &conn_ssl_config, + user_conn->peer_addr, user_conn->peer_addrlen, user_conn); + if (cid == NULL) { + return XQC_ERROR; + } + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); + printf("[stats] init xquic connection success \n"); + + return XQC_OK; +} +void +xqc_mini_cli_on_socket_created(xqc_mini_cli_user_conn_t *user_conn) +{ + xqc_mini_cli_ctx_t *ctx; + + ctx = user_conn->ctx; + + /* init callback function for READ/PERSIST EVENT */ + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_cli_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); +} +int +xqc_mini_cli_main_process(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_ctx_t *ctx) +{ + int ret; + xqc_mini_cli_args_t *args; + + user_conn->ctx = ctx; + args = ctx->args; + + ret = xqc_mini_cli_init_xquic_connection(user_conn); + if (ret < 0) { + printf("[error] mini socket init xquic connection failed\n"); + return XQC_ERROR; + } + + xqc_mini_cli_user_stream_t *user_stream = calloc(1, sizeof(xqc_mini_cli_user_stream_t)); + ret = xqc_mini_cli_send_h3_req(user_conn, user_stream); + if (ret < 0) { + return XQC_ERROR; + } + + return XQC_OK; +} + +void +xqc_mini_cli_init_local_addr(struct sockaddr *local_addr) +{ + char s_port[16] = "8443"; + struct addrinfo hints = {0}; + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + /* resolve server's ip from hostname */ + struct addrinfo *result = NULL; + int rv = getaddrinfo(DEFAULT_IP, s_port, &hints, &result); + if (rv != 0) { + printf("get addr info from hostname: %s\n", gai_strerror(rv)); + } + memcpy(local_addr, result->ai_addr, result->ai_addrlen); +} + +xqc_mini_cli_user_conn_t * +xqc_mini_cli_user_conn_create(xqc_mini_cli_ctx_t *ctx) +{ + int ret; + xqc_mini_cli_user_conn_t *user_conn = calloc(1, sizeof(xqc_mini_cli_user_conn_t)); + + user_conn->ctx = ctx; + + /* set connection timeout */ + struct timeval tv; + tv.tv_sec = ctx->args->net_cfg.conn_timeout; + tv.tv_usec = 0; + user_conn->ev_timeout = event_new(ctx->eb, -1, 0, xqc_mini_cli_timeout_callback, user_conn); + event_add(user_conn->ev_timeout, &tv); + + user_conn->local_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); + xqc_mini_cli_init_local_addr(user_conn->local_addr); + user_conn->local_addrlen = sizeof(struct sockaddr_in); + + xqc_mini_cli_convert_text_to_sockaddr(AF_INET, DEFAULT_IP, DEFAULT_PORT, + &(user_conn->peer_addr), &(user_conn->peer_addrlen)); + + /* init socket fd */ + ret = xqc_mini_cli_init_socket(user_conn); + if (ret < 0) { + printf("[error] mini socket init socket failed\n"); + return NULL; + } + + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_cli_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); + + return user_conn; +} + +void +xqc_mini_cli_free_user_conn(xqc_mini_cli_user_conn_t *user_conn) +{ + free(user_conn->peer_addr); + free(user_conn->local_addr); + free(user_conn); +} + +void +xqc_mini_cli_on_connection_finish(xqc_mini_cli_user_conn_t *user_conn) +{ + if (user_conn->ev_timeout) { + event_del(user_conn->ev_timeout); + user_conn->ev_timeout = NULL; + } + + if (user_conn->ev_socket) { + event_del(user_conn->ev_socket); + user_conn->ev_timeout = NULL; + } + + close(user_conn->fd); +} + +int main(int argc, char *argv[]) +{ + int ret; + xqc_mini_cli_ctx_t cli_ctx = {0}, *ctx = &cli_ctx; + xqc_mini_cli_args_t *args = NULL; + xqc_mini_cli_user_conn_t *user_conn = NULL; + + args = calloc(1, sizeof(xqc_mini_cli_args_t)); + if (args == NULL) { + printf("[error] calloc args failed\n"); + goto exit; + } + + /* init env (for windows) */ + xqc_platform_init_env(); + + /* init client environment (ctx & args) */ + ret = xqc_mini_cli_init_env(ctx, args); + if (ret < 0) { + goto exit; + } + + /* init client engine */ + ret = xqc_mini_cli_init_xquic_engine(ctx, args); + if (ret < 0) { + printf("[error] init xquic engine failed\n"); + goto exit; + } + + /* init engine ctx */ + ret = xqc_mini_cli_init_engine_ctx(ctx); + if (ret < 0) { + printf("[error] init engine ctx failed\n"); + goto exit; + } + + user_conn = xqc_mini_cli_user_conn_create(ctx); + if (user_conn == NULL) { + printf("[error] init user_conn failed.\n"); + goto exit; + } + + /* cli main process: build connection, process request, etc. */ + xqc_mini_cli_main_process(user_conn, ctx); + + /* start event loop */ + event_base_dispatch(ctx->eb); + +exit: + xqc_engine_destroy(ctx->engine); + xqc_mini_cli_on_connection_finish(user_conn); + xqc_mini_cli_free_ctx(ctx); + xqc_mini_cli_free_user_conn(user_conn); + + return 0; +} \ No newline at end of file diff --git a/mini/mini_client.h b/mini/mini_client.h new file mode 100644 index 000000000..e33654bd0 --- /dev/null +++ b/mini/mini_client.h @@ -0,0 +1,261 @@ +#ifndef XQC_MINI_CLIENT_H +#define XQC_MINI_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef XQC_SYS_WINDOWS +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#include "../tests/getopt.h" +#else +#include +#include +#include +#include +#include +#endif + + +#include "../tests/platform.h" +#include "common.h" +#include "mini_client_cb.h" + + +#define DEFAULT_IP "127.0.0.1" +#define DEFAULT_PORT 8443 +#define DEFAULT_HOST "test.xquic.com" + +#define SESSION_TICKET_BUF_MAX_SIZE 8192 +#define TRANSPORT_PARAMS_MAX_SIZE 8192 +#define TOKEN_MAX_SIZE 8192 +#define MAX_PATH_CNT 2 +#define XQC_PACKET_BUF_LEN 1500 + +#define SESSION_TICKET_FILE "session_ticket" +#define TRANSPORT_PARAMS_FILE "transport_params" +#define TOKEN_FILE "token" + +#define LOG_PATH "clog.log" +#define KEY_PATH "ckeys.log" +#define OUT_DIR "." + +/** + * net config definition + * net config is those arguments about socket information + * all configuration on net should be put under this section + */ + +typedef struct xqc_mini_cli_net_config_s { + int conn_timeout; + xqc_usec_t last_socket_time; + + // /* server addr info */ + // struct sockaddr *addr; + // socklen_t addr_len; + // char server_addr[64]; + // short server_port; +} xqc_mini_cli_net_config_t; + +/** + * quic config definition + * quic config is those arguments required by quic features, including connection settings, ssl configs, etc. + * all configuration on quic should be put under this section + */ + +typedef struct xqc_mini_cli_quic_config_s { + /* cipher config */ + char ciphers[CIPHER_SUIT_LEN]; + char groups[TLS_GROUPS_LEN]; + + /* connection ssl config */ + char session_ticket[SESSION_TICKET_BUF_MAX_SIZE]; + int session_ticket_len; + char transport_parameter[TRANSPORT_PARAMS_MAX_SIZE]; + int transport_parameter_len; + + char token[TOKEN_MAX_SIZE]; + int token_len; + + int no_encryption; + + /* multipath */ + int multipath; // mp option, 0: disable, 1: enable + char mp_sched[32]; // mp scheduler, minrtt/backup + + /* congestion control */ + CC_TYPE cc; // cc algrithm, bbr/cubic +} xqc_mini_cli_quic_config_t; + +/** + * the environment config definition + * environment config is those arguments about IO inputs and outputs + * all configuration on environment should be put under this section + */ + +typedef struct xqc_mini_cli_env_config_s { + /* log config */ + char log_path[PATH_LEN]; + + /* tls certificates */ + char private_key_file[PATH_LEN]; + char cert_file[PATH_LEN]; + + /* key export */ + char key_out_path[PATH_LEN]; + + /* output file */ + char out_file_dir[PATH_LEN]; +} xqc_mini_cli_env_config_t; + + +/** + * the request config definition + * request config is those arguments about request information + * all configuration on request should be put under this section + */ +typedef struct xqc_mini_cli_req_config_s { + char path[RESOURCE_LEN]; /* request path */ + char scheme[8]; /* request scheme, http/https */ + REQUEST_METHOD method; + char host[256]; /* request host */ + // char auth[AUTHORITY_LEN]; + char url[URL_LEN]; /* original url */ +} xqc_mini_cli_req_config_t; + + +typedef struct xqc_mini_cli_args_s { + /* network args */ + xqc_mini_cli_net_config_t net_cfg; + + /* xquic args */ + xqc_mini_cli_quic_config_t quic_cfg; + + /* environment args */ + xqc_mini_cli_env_config_t env_cfg; + + /* request args */ + xqc_mini_cli_req_config_t req_cfg; +} xqc_mini_cli_args_t; + + +typedef struct xqc_mini_cli_ctx_s { + struct event_base *eb; + + xqc_mini_cli_args_t *args; // server arguments for current context + + xqc_engine_t *engine; // xquic engine for current context + struct event *ev_engine; + + int log_fd; + int keylog_fd; +} xqc_mini_cli_ctx_t; + + +typedef struct xqc_mini_cli_user_conn_s { + xqc_cid_t cid; + xqc_h3_conn_t *h3_conn; + + xqc_mini_cli_ctx_t *ctx; + + /* ipv4 server */ + int fd; + int get_local_addr; + struct sockaddr *local_addr; + socklen_t local_addrlen; + struct sockaddr *peer_addr; + socklen_t peer_addrlen; + + struct event *ev_socket; + struct event *ev_timeout; + +} xqc_mini_cli_user_conn_t; + +typedef struct xqc_mini_cli_user_stream_s { + xqc_mini_cli_user_conn_t *user_conn; + + /* save file */ + // char file_name[RESOURCE_LEN]; + // FILE *recv_body_fp; + + /* stat for IO */ + size_t send_body_len; + size_t recv_body_len; + int recv_fin; + xqc_msec_t start_time; + + + /* h3 request content */ + xqc_h3_request_t *h3_request; + + xqc_http_headers_t h3_hdrs; + uint8_t hdr_sent; + + char *send_body_buff; + int send_body_size; + size_t send_offset; + +} xqc_mini_cli_user_stream_t; + + + +void xqc_mini_cli_init_engine_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_cli_args_t *args); + +void xqc_mini_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_xquic_engine(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +void xqc_mini_cli_convert_text_to_sockaddr(int type, + const char *addr_text, unsigned int port, + struct sockaddr **saddr, socklen_t *saddr_len); + +void xqc_mini_cli_init_args(xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_ctx(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_env(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +xqc_scheduler_callback_t xqc_mini_cli_get_sched_cb(xqc_mini_cli_args_t *args); +xqc_cong_ctrl_callback_t xqc_mini_cli_get_cc_cb(xqc_mini_cli_args_t *args); +void xqc_mini_cli_init_conn_settings(xqc_conn_settings_t *settings, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_alpn_ctx(xqc_mini_cli_ctx_t *ctx); +int xqc_mini_cli_init_engine_ctx(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_free_ctx(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_init_0rtt(xqc_mini_cli_args_t *args); + +void xqc_mini_cli_init_conn_ssl_config(xqc_conn_ssl_config_t *conn_ssl_config, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_format_h3_req(xqc_http_header_t *headers, xqc_mini_cli_req_config_t* req_cfg); + +int xqc_mini_cli_request_send(xqc_h3_request_t *h3_request, xqc_mini_cli_user_stream_t *user_stream); + +int xqc_mini_cli_send_h3_req(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_user_stream_t *user_stream); + +int xqc_mini_cli_init_socket(xqc_mini_cli_user_conn_t *user_conn); + +void xqc_mini_cli_socket_write_handler(xqc_mini_cli_user_conn_t *user_conn, int fd); + +void xqc_mini_cli_socket_read_handler(xqc_mini_cli_user_conn_t *user_conn, int fd); + +static void xqc_mini_cli_socket_event_callback(int fd, short what, void *arg); +int xqc_mini_cli_init_xquic_connection(xqc_mini_cli_user_conn_t *user_conn); + +int xqc_mini_cli_main_process(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_ctx_t *ctx); +xqc_mini_cli_user_conn_t *xqc_mini_cli_user_conn_create(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_free_user_conn(xqc_mini_cli_user_conn_t *user_conn); +void xqc_mini_cli_on_connection_finish(xqc_mini_cli_user_conn_t *user_conn); +#endif \ No newline at end of file diff --git a/mini/mini_client_cb.c b/mini/mini_client_cb.c new file mode 100644 index 000000000..045d3edc7 --- /dev/null +++ b/mini/mini_client_cb.c @@ -0,0 +1,405 @@ +/** + * @file mini_server_cb.c contains callbacks definitions for mini_server, including: + * 1. engine callbacks + * 2. hq callbacks + * 3. h3 callbacks + */ +#include "mini_client_cb.h" +/** + * @brief engine callbacks to trigger engine main logic + */ +const char *line_break = "\n"; +void +xqc_mini_cli_engine_cb(int fd, short what, void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t *) arg; + + xqc_engine_main_logic(ctx->engine); +} + +int +xqc_mini_cli_open_log_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + return open(ctx->args->env_cfg.log_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_cli_close_log_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + if (ctx->log_fd > 0) { + close(ctx->log_fd); + ctx->log_fd = 0; + } +} + +void +xqc_mini_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + //printf("%s", (char *)buf); + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + } +} + + +int +xqc_mini_cli_open_keylog_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + return open(ctx->args->env_cfg.key_out_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_cli_close_keylog_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + if (ctx->keylog_fd > 0) { + close(ctx->keylog_fd); + ctx->keylog_fd = 0; + } +} + +void +xqc_mini_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} + + +void +xqc_mini_cli_keylog_cb(const xqc_cid_t *scid, const char *line, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + + if (ctx->keylog_fd <= 0) { + printf("write keys error!\n"); + return; + } + + int write_len = write(ctx->keylog_fd, line, strlen(line)); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->keylog_fd, line_break, 1); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + } +} +int +xqc_mini_cli_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + + user_conn->h3_conn = conn; + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); + + return XQC_OK; +} + +int +xqc_mini_cli_h3_conn_close_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + + event_base_loopbreak(user_conn->ctx->eb); + printf("[stats] xqc_mini_cli_h3_conn_close_notify success \n"); + return XQC_OK; +} + +void +xqc_mini_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) +{ + return; +} +int +xqc_mini_cli_h3_request_create_notify(xqc_h3_request_t *h3_request, void *h3s_user_data) +{ + return 0; +} + +int +xqc_mini_cli_h3_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) +{ + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)user_data; + xqc_mini_cli_user_conn_t *user_conn = user_stream->user_conn; + xqc_mini_cli_ctx_t *conn_ctx = user_conn->ctx; + xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); + + xqc_h3_conn_close(conn_ctx->engine, &user_conn->cid); + free(user_stream); + + printf("[stats] xqc_mini_cli_h3_request_close_notify success, cwnd_blocked:%"PRIu64"\n", stats.cwnd_blocked_ms); + return 0; +} +int +xqc_mini_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, + xqc_request_notify_flag_t flag, void *h3s_user_data) +{ + char recv_buff[XQC_MAX_BUFF_SIZE] = {0}; + size_t recv_buff_size; + ssize_t read, read_sum; + unsigned char fin = 0; + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)h3s_user_data; + xqc_mini_cli_user_conn_t *user_conn = user_stream->user_conn; + + if (flag & XQC_REQ_NOTIFY_READ_HEADER) { + xqc_http_headers_t *headers; + headers = xqc_h3_request_recv_headers(h3_request, &fin); + if (headers == NULL) { + printf("[error] xqc_h3_request_recv_headers error\n"); + return XQC_ERROR; + } + + for (int i = 0; i < headers->count; i++) { + printf("[receive report] %s = %s\n", (char *)headers->headers[i].name.iov_base, + (char *)headers->headers[i].value.iov_base); + } + + if (fin) { + /* only header in request */ + user_stream->recv_fin = 1; + printf("[stats] h3 request read header finish \n"); + return XQC_OK; + } + } + + /* continue to recv body */ + if (!(flag & XQC_REQ_NOTIFY_READ_BODY)) { + return XQC_OK; + } + + recv_buff_size = XQC_MAX_BUFF_SIZE; + read = read_sum = 0; + + do { + read = xqc_h3_request_recv_body(h3_request, recv_buff, recv_buff_size, &fin); + if (read == -XQC_EAGAIN) { + break; + + } else if (read < 0) { + printf("xqc_h3_request_recv_body error %zd\n", read); + return XQC_OK; + } + + read_sum += read; + user_stream->recv_body_len += read; + } while (read > 0 && !fin); + + printf("[report] xqc_h3_request_recv_body size %zd, fin:%d\n", read, fin); + + if (fin) { + printf("[stats] read h3 request finish. \n"); + } + + return XQC_OK; +} + +int +xqc_mini_cli_h3_request_write_notify(xqc_h3_request_t *h3_request, void *h3s_user_data) +{ + int ret = 0; + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)h3s_user_data; + + ret = xqc_mini_cli_request_send(h3_request, user_stream); + + printf("[stats] finish h3 request write notify!:%"PRIu64"\n", xqc_h3_stream_id(h3_request)); + + return ret; +} + +void +xqc_mini_cli_set_event_timer(xqc_usec_t wake_after, void *user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t *) user_data; + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); + + struct timeval tv; + tv.tv_sec = wake_after / 1000000; + tv.tv_usec = wake_after % 1000000; + event_add(ctx->ev_engine, &tv); +} + +ssize_t +xqc_mini_cli_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data) +{ + return xqc_mini_cli_write_socket_ex(0, buf, size, peer_addr, peer_addrlen, conn_user_data); +} + +ssize_t +xqc_mini_cli_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *conn_user_data) +{ + int fd; + ssize_t res; + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)conn_user_data; + + fd = user_conn->fd; + res = 0; + + do { + set_sys_errno(0); + res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); + if (res < 0) { + printf("xqc_mini_cli_write_socket err %zd %s, fd: %d, buf: %p, size: %zu, " + "server_addr: %s\n", res, strerror(get_sys_errno()), fd, buf, size, + user_conn->peer_addr->sa_data); + if (get_sys_errno() == EAGAIN) { + res = XQC_SOCKET_EAGAIN; + } + } + } while ((res < 0) && (get_sys_errno() == EINTR)); + + // printf("[report] xqc_mini_cli_write_socket_ex success size=%lu\n", size); + + return res; +} + +int +xqc_mini_cli_read_token(unsigned char *token, unsigned token_len) +{ + int fd = open(TOKEN_FILE, O_RDONLY); + if (fd < 0) { + return -1; + } + + ssize_t n = read(fd, token, token_len); + close(fd); + return n; +} + +void +xqc_mini_cli_save_token(const unsigned char *token, unsigned token_len, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start xqc_mini_cli_save_token, use client ip as the key.\n"); + + int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, 0666); + if (fd < 0) { + printf("save token error %s\n", strerror(get_sys_errno())); + return; + } + + ssize_t n = write(fd, token, token_len); + if (n < token_len) { + printf("save token error %s\n", strerror(get_sys_errno())); + close(fd); + return; + } + close(fd); +} + +void +xqc_mini_cli_save_session_cb(const char * data, size_t data_len, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start save_session_cb. \n"); + + FILE * fp = fopen(SESSION_TICKET_FILE, "wb"); + if (fp < 0) { + printf("save session error %s\n", strerror(get_sys_errno())); + return; + } + + int write_size = fwrite(data, 1, data_len, fp); + if (data_len != write_size) { + printf("save _session_cb error\n"); + fclose(fp); + return; + } + fclose(fp); + return; +} + + +void +xqc_mini_cli_save_tp_cb(const char * data, size_t data_len, void * user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start save_tp_cb\n"); + + FILE * fp = fopen(TRANSPORT_PARAMS_FILE, "wb"); + if (fp < 0) { + printf("save transport callback error %s\n", strerror(get_sys_errno())); + return; + } + + int write_size = fwrite(data, 1, data_len, fp); + if (data_len != write_size) { + printf("save _tp_cb error\n"); + fclose(fp); + return; + } + + fclose(fp); + return; +} + + +void +xqc_mini_cli_timeout_callback(int fd, short what, void *arg) +{ + int conn_timeout, last_socket_time, ret; + xqc_usec_t socket_idle_time; + struct timeval tv; + xqc_mini_cli_ctx_t *ctx; + xqc_mini_cli_user_conn_t *user_conn; + + user_conn = (xqc_mini_cli_user_conn_t *)arg; + ctx = user_conn->ctx; + conn_timeout = ctx->args->net_cfg.conn_timeout; + last_socket_time = ctx->args->net_cfg.last_socket_time; + socket_idle_time = xqc_now() - last_socket_time; + + if (socket_idle_time < conn_timeout * 1000000) { + tv.tv_sec = conn_timeout; + tv.tv_usec = 0; + event_add(user_conn->ev_timeout, &tv); + return; + } + +conn_close: + printf("[stats] client process timeout, connection closing... \n"); + ret = xqc_h3_conn_close(ctx->engine, &user_conn->cid); + if (ret) { + printf("[error] xqc_conn_close error:%d\n", ret); + return; + } +} + +int +xqc_mini_cli_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data, void *conn_proto_data) +{ + DEBUG; + + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *) user_data; + xqc_conn_set_alp_user_data(conn, user_conn); + + printf("[stats] xqc_conn_is_ready_to_send_early_data:%d\n", xqc_conn_is_ready_to_send_early_data(conn)); + return XQC_OK; +} \ No newline at end of file diff --git a/mini/mini_client_cb.h b/mini/mini_client_cb.h new file mode 100644 index 000000000..730d95154 --- /dev/null +++ b/mini/mini_client_cb.h @@ -0,0 +1,65 @@ +#ifndef XQC_MINI_CLIENT_CB_H +#define XQC_MINI_CLIENT_CB_H +#include +#include +#include "mini_client.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include "../tests/getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#endif + +#define XQC_MAX_BUFF_SIZE 4096 + +void xqc_mini_cli_engine_cb(int fd, short what, void *arg); + +int xqc_mini_cli_open_log_file(void *arg); +void xqc_mini_cli_close_log_file(void *arg); +void xqc_mini_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); + +int xqc_mini_cli_open_keylog_file(void *arg); +void xqc_mini_cli_close_keylog_file(void *arg); + +void xqc_mini_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data); + +void xqc_mini_cli_keylog_cb(const xqc_cid_t *scid, const char *line, void *engine_user_data); + +int xqc_mini_cli_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data); +int xqc_mini_cli_h3_conn_close_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data); +void xqc_mini_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data); + +int xqc_mini_cli_h3_request_create_notify(xqc_h3_request_t *h3_request, void *h3s_user_data); +void xqc_mini_cli_h3_request_closing_notify(xqc_h3_request_t *h3_request, + xqc_int_t err, void *h3s_user_data); +int xqc_mini_cli_h3_request_close_notify(xqc_h3_request_t *h3_request, void *user_data); +int xqc_mini_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, + xqc_request_notify_flag_t flag, void *h3s_user_data); +int xqc_mini_cli_h3_request_write_notify(xqc_h3_request_t *h3_request, void *h3s_user_data); + +void xqc_mini_cli_set_event_timer(xqc_usec_t wake_after, void *user_data); + +ssize_t xqc_mini_cli_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data); + +ssize_t xqc_mini_cli_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *conn_user_data); + +int xqc_mini_cli_read_token(unsigned char *token, unsigned token_len); + +void xqc_mini_cli_save_token(const unsigned char *token, unsigned token_len, void *user_data); + +void xqc_mini_cli_save_session_cb(const char * data, size_t data_len, void *user_data); + +void xqc_mini_cli_save_tp_cb(const char * data, size_t data_len, void * user_data); + +void xqc_mini_cli_timeout_callback(int fd, short what, void *arg); + +int xqc_mini_cli_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data, void *conn_proto_data); + +#endif \ No newline at end of file diff --git a/mini/mini_server.c b/mini/mini_server.c new file mode 100644 index 000000000..8efa4f752 --- /dev/null +++ b/mini/mini_server.c @@ -0,0 +1,544 @@ +#include "mini_server.h" + +void +xqc_mini_svr_init_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_svr_args_t *args) +{ + ssl_cfg->private_key_file = args->env_cfg.private_key_file; + ssl_cfg->cert_file = args->env_cfg.cert_file; + ssl_cfg->ciphers = args->quic_cfg.ciphers; + ssl_cfg->groups = args->quic_cfg.groups; + + /* for server, load session ticket key if there exists */ + if (args->quic_cfg.session_ticket_key_len <= 0) { + ssl_cfg->session_ticket_key_data = NULL; + ssl_cfg->session_ticket_key_len = 0; + + } else { + ssl_cfg->session_ticket_key_data = args->quic_cfg.session_ticket_key_data; + ssl_cfg->session_ticket_key_len = args->quic_cfg.session_ticket_key_len; + } +} + +void +xqc_mini_svr_init_args(xqc_mini_svr_args_t *args) +{ + int ret; + char *p = NULL; + + /* init network args */ + strncpy(args->net_cfg.ip, DEFAULT_IP, sizeof(args->net_cfg.ip) - 1); + args->net_cfg.port = DEFAULT_PORT; + + /** + * init quic config + * it's recommended to replace the constant value with option arguments according to actual needs + */ + p = args->quic_cfg.session_ticket_key_data; + ret = xqc_mini_read_file_data(p, + SESSION_TICKET_KEY_BUF_LEN, SESSION_TICKET_KEY_FILE); + args->quic_cfg.session_ticket_key_len = ret > 0 ? ret : 0; + args->quic_cfg.cc = CC_TYPE_BBR; + args->quic_cfg.multipath = 1; + strncpy(args->quic_cfg.mp_sched, "minrtt", 32); + strncpy(args->quic_cfg.ciphers, XQC_TLS_CIPHERS, CIPHER_SUIT_LEN - 1); + strncpy(args->quic_cfg.groups, XQC_TLS_GROUPS, TLS_GROUPS_LEN - 1); + + /* init env config */ + strncpy(args->env_cfg.log_path, LOG_PATH, TLS_GROUPS_LEN - 1); + strncpy(args->env_cfg.key_out_path, KEY_PATH, PATH_LEN - 1); + strncpy(args->env_cfg.private_key_file, PRIV_KEY_PATH, PATH_LEN - 1); + strncpy(args->env_cfg.cert_file, CERT_PEM_PATH, PATH_LEN - 1); +} + +int +xqc_mini_svr_init_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + memset(ctx, 0, sizeof(xqc_mini_svr_ctx_t)); + + /* init event base */ + struct event_base *eb = event_base_new(); + ctx->eb = eb; + + ctx->args = args; + /* init log writer fd */ + ctx->log_fd = xqc_mini_svr_open_log_file(ctx); + if (ctx->log_fd < 0) { + printf("[error] open log file failed\n"); + return XQC_ERROR; + } + /* init keylog writer fd */ + ctx->keylog_fd = xqc_mini_svr_open_keylog_file(ctx); + if (ctx->keylog_fd < 0) { + printf("[error] open keylog file failed\n"); + return XQC_ERROR; + } + return XQC_OK; +} + +/** + * @brief init engine & transport callbacks + */ +void +xqc_mini_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, + xqc_mini_svr_args_t *args) +{ + static xqc_engine_callback_t callback = { + .set_event_timer = xqc_mini_svr_set_event_timer, + .log_callbacks = { + .xqc_log_write_err = xqc_mini_svr_write_log_file, + .xqc_log_write_stat = xqc_mini_svr_write_log_file, + .xqc_qlog_event_write = xqc_mini_svr_write_qlog_file + }, + .keylog_cb = xqc_mini_svr_keylog_cb, + }; + + static xqc_transport_callbacks_t transport_cbs = { + .server_accept = xqc_mini_svr_accept, + .write_socket = xqc_mini_svr_write_socket, + .write_socket_ex = xqc_mini_svr_write_socket_ex, + .conn_update_cid_notify = xqc_mini_svr_conn_update_cid_notify, + }; + + *cb = callback; + *tcb = transport_cbs; +} + +/** + * @brief init xquic server engine + */ +int +xqc_mini_svr_init_xquic_engine(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret; + xqc_config_t egn_cfg; + xqc_engine_callback_t callback; + xqc_engine_ssl_config_t ssl_cfg = {0}; + xqc_transport_callbacks_t transport_cbs; + + /* get default parameters of xquic engine */ + ret = xqc_engine_get_default_config(&egn_cfg, XQC_ENGINE_SERVER); + if (ret < 0) { + return XQC_ERROR; + } + + /* init ssl config */ + xqc_mini_svr_init_ssl_config(&ssl_cfg, args); + + /* init engine & transport callbacks */ + xqc_mini_svr_init_callback(&callback, &transport_cbs, args); + + /* create server engine */ + ctx->engine = xqc_engine_create(XQC_ENGINE_SERVER, &egn_cfg, &ssl_cfg, + &callback, &transport_cbs, ctx); + if (ctx->engine == NULL) { + printf("[error] xqc_engine_create error\n"); + return XQC_ERROR; + } + + ctx->ev_engine = event_new(ctx->eb, -1, 0, xqc_mini_svr_engine_cb, ctx); + + return XQC_OK; +} + +int +xqc_mini_svr_init_env(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret = XQC_OK; + + /* init server args */ + xqc_mini_svr_init_args(args); + + /* init server ctx */ + ret = xqc_mini_svr_init_ctx(ctx, args); + + return ret; +} + +xqc_cong_ctrl_callback_t +xqc_mini_svr_get_cc_cb(xqc_mini_svr_args_t *args) +{ + xqc_cong_ctrl_callback_t ccc = xqc_bbr_cb; + switch (args->quic_cfg.cc) { + case CC_TYPE_BBR: + ccc = xqc_bbr_cb; + break; + case CC_TYPE_CUBIC: + ccc = xqc_cubic_cb; + break; + default: + break; + } + return ccc; +} + +xqc_scheduler_callback_t +xqc_mini_svr_get_sched_cb(xqc_mini_svr_args_t *args) +{ + xqc_scheduler_callback_t sched = xqc_minrtt_scheduler_cb; + if (strncmp(args->quic_cfg.mp_sched, "minrtt", strlen("minrtt")) == 0) { + sched = xqc_minrtt_scheduler_cb; + + } if (strncmp(args->quic_cfg.mp_sched, "backup", strlen("backup")) == 0) { + sched = xqc_backup_scheduler_cb; + } + return sched; +} + +void +xqc_mini_svr_init_conn_settings(xqc_engine_t *engine, xqc_mini_svr_args_t *args) +{ + /* parse congestion control callback */ + xqc_cong_ctrl_callback_t ccc = xqc_mini_svr_get_cc_cb(args); + /* parse mp scheduler callback */ + xqc_scheduler_callback_t sched = xqc_mini_svr_get_sched_cb(args); + + /* init connection settings */ + xqc_conn_settings_t conn_settings = { + .cong_ctrl_callback = ccc, + .cc_params = { + .customize_on = 1, + .init_cwnd = 32, + .bbr_enable_lt_bw = 1, + }, + .spurious_loss_detect_on = 1, + .init_idle_time_out = 60000, + .enable_multipath = args->quic_cfg.multipath, + .scheduler_callback = sched, + .standby_path_probe_timeout = 1000, + .adaptive_ack_frequency = 1, + .anti_amplification_limit = 4, + }; + + /* set customized connection settings to engine ctx */ + xqc_server_set_conn_settings(engine, &conn_settings); +} + +/* create socket and bind port */ +static int +xqc_mini_svr_init_socket(int family, uint16_t port, + struct sockaddr *local_addr, socklen_t local_addrlen) +{ + int size; + int opt_reuseaddr; + int flags = 1; + int fd = socket(family, SOCK_DGRAM, 0); + if (fd < 0) { + printf("create socket failed, errno: %d\n", get_sys_errno()); + return XQC_ERROR; + } + + /* non-block */ +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + printf("set socket nonblock failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + /* reuse port */ + opt_reuseaddr = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt_reuseaddr, sizeof(opt_reuseaddr)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + /* send/recv buffer size */ + size = 1 * 1024 * 1024; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + /* bind port */ + if (bind(fd, local_addr, local_addrlen) < 0) { + printf("bind socket failed, family: %d, errno: %d, %s\n", family, + get_sys_errno(), strerror(get_sys_errno())); + goto err; + } + + return fd; + +err: + close(fd); + return -1; +} + +static int +xqc_mini_svr_create_socket(xqc_mini_svr_user_conn_t *user_conn, xqc_mini_svr_net_config_t* cfg) +{ + /* ipv4 socket */ + user_conn->local_addr->sin_family = AF_INET; + user_conn->local_addr->sin_port = htons(cfg->port); + user_conn->local_addr->sin_addr.s_addr = htonl(INADDR_ANY); + user_conn->local_addrlen = sizeof(struct sockaddr_in); + user_conn->fd = xqc_mini_svr_init_socket(AF_INET, cfg->port, (struct sockaddr*)user_conn->local_addr, + user_conn->local_addrlen); + printf("[stats] create ipv4 socket fd: %d success, bind socket to ip: %s, port: %d\n", user_conn->fd, cfg->ip, cfg->port); + + if (!user_conn->fd) { + return -1; + } + + return 0; +} + +int +xqc_mini_svr_init_alpn_ctx(xqc_engine_t *engine) +{ + int ret = 0; + + /* init http3 callbacks */ + xqc_h3_callbacks_t h3_cbs = { + .h3c_cbs = { + .h3_conn_create_notify = xqc_mini_svr_h3_conn_create_notify, + .h3_conn_close_notify = xqc_mini_svr_h3_conn_close_notify, + .h3_conn_handshake_finished = xqc_mini_svr_h3_conn_handshake_finished, + }, + .h3r_cbs = { + .h3_request_create_notify = xqc_mini_svr_h3_request_create_notify, + .h3_request_close_notify = xqc_mini_svr_h3_request_close_notify, + .h3_request_read_notify = xqc_mini_svr_h3_request_read_notify, + .h3_request_write_notify = xqc_mini_svr_h3_request_write_notify, + } + }; + + /* init http3 context */ + ret = xqc_h3_ctx_init(engine, &h3_cbs); + if (ret != XQC_OK) { + printf("init h3 context error, ret: %d\n", ret); + return ret; + } + + return ret; +} + +int +xqc_mini_svr_init_engine_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret; + + /* init connection settings */ + xqc_mini_svr_init_conn_settings(ctx->engine, args); + + /* init alpn ctx */ + ret = xqc_mini_svr_init_alpn_ctx(ctx->engine); + + return ret; +} + +void +xqc_mini_svr_socket_write_handler(xqc_mini_svr_user_conn_t *user_conn, int fd) +{ + DEBUG + printf("[stats] socket write handler\n"); +} + +void +xqc_mini_svr_socket_read_handler(xqc_mini_svr_user_conn_t *user_conn, int fd) +{ + DEBUG; + ssize_t recv_size, recv_sum; + struct sockaddr_in peer_addr = {0}; + socklen_t peer_addrlen = sizeof(peer_addr); + uint64_t recv_time; + xqc_int_t ret; + unsigned char packet_buf[XQC_PACKET_BUF_LEN] = {0}; + xqc_mini_svr_ctx_t *ctx; + + ctx = user_conn->ctx; + ctx->current_fd = fd; + recv_size = recv_sum = 0; + + do { + /* recv quic packet from client */ + recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, + (struct sockaddr *) &peer_addr, &peer_addrlen); + if (recv_size < 0 && get_sys_errno() == EAGAIN) { + break; + } + memcpy(user_conn->peer_addr, &peer_addr, peer_addrlen); + user_conn->peer_addrlen = peer_addrlen; + + if (recv_size < 0) { + printf("recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); + break; + } + + user_conn->local_addrlen = sizeof(struct sockaddr_in6); + ret = getsockname(user_conn->fd, (struct sockaddr *)user_conn->local_addr, + &user_conn->local_addrlen); + if (ret != 0) { + printf("[error] getsockname error, errno: %d\n", get_sys_errno()); + } + // printf("[stats] get sock name %d\n", user_conn->local_addr->sin_family); + + recv_sum += recv_size; + recv_time = xqc_now(); + /* process quic packet with xquic engine */ + ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, + (struct sockaddr *)(user_conn->local_addr), user_conn->local_addrlen, + (struct sockaddr *)(user_conn->peer_addr), user_conn->peer_addrlen, + (xqc_usec_t)recv_time, user_conn); + if (ret != XQC_OK) { + printf("[error] server_read_handler: packet process err, ret: %d\n", ret); + return; + } + } while (recv_size > 0); + +finish_recv: + // printf("[stats] xqc_mini_svr_socket_read_handler, recv size:%zu\n", recv_sum); + xqc_engine_finish_recv(ctx->engine); +} + +static void +xqc_mini_svr_socket_event_callback(int fd, short what, void *arg) +{ + //DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)arg; + if (what & EV_WRITE) { + xqc_mini_svr_socket_write_handler(user_conn, fd); + + } else if (what & EV_READ) { + xqc_mini_svr_socket_read_handler(user_conn, fd); + + } else { + printf("event callback: fd=%d, what=%d\n", fd, what); + exit(1); + } +} + +void +xqc_mini_svr_free_ctx(xqc_mini_svr_ctx_t *ctx) +{ + xqc_mini_svr_close_keylog_file(ctx); + xqc_mini_svr_close_log_file(ctx); + + if (ctx->args) { + free(ctx->args); + ctx->args = NULL; + } + +} + +void +xqc_mini_svr_free_user_conn(xqc_mini_svr_user_conn_t *user_conn) +{ + if (user_conn->local_addr) { + free(user_conn->local_addr); + user_conn->local_addr = NULL; + } + if (user_conn->peer_addr) { + free(user_conn->peer_addr); + user_conn->peer_addr = NULL; + } + if (user_conn) { + free(user_conn); + user_conn = NULL; + } +} + +xqc_mini_svr_user_conn_t * +xqc_mini_svr_create_user_conn(xqc_mini_svr_ctx_t *ctx) +{ + int ret; + xqc_mini_svr_user_conn_t *user_conn = calloc(1, sizeof(xqc_mini_svr_user_conn_t)); + + user_conn->ctx = ctx; + + user_conn->local_addr = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in)); + user_conn->peer_addr = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in)); + + /* init server socket and save to ctx->fd */ + ret = xqc_mini_svr_create_socket(user_conn, &ctx->args->net_cfg); + if (ret < 0) { + printf("[error] xqc_create_socket error\n"); + goto error; + } + + /* bind socket event callback to fd event */ + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_svr_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); + + return user_conn; +error: + xqc_mini_svr_free_user_conn(user_conn); + return NULL; +} + +void +xqc_mini_cli_on_connection_finish(xqc_mini_svr_user_conn_t *user_conn) +{ + if (user_conn->ev_timeout) { + event_del(user_conn->ev_timeout); + user_conn->ev_timeout = NULL; + } + + if (user_conn->ev_socket) { + event_del(user_conn->ev_socket); + user_conn->ev_timeout = NULL; + } +} + +int +main(int argc, char *argv[]) +{ + int ret; + xqc_mini_svr_ctx_t svr_ctx = {0}, *ctx = &svr_ctx; + xqc_mini_svr_args_t *args = NULL; + xqc_mini_svr_user_conn_t *user_conn = NULL; + + args = calloc(1, sizeof(xqc_mini_svr_args_t)); + if (args == NULL) { + printf("[error] calloc args failed\n"); + goto exit; + } + + /* init env (for windows) */ + xqc_platform_init_env(); + + /* init server environment */ + ret = xqc_mini_svr_init_env(ctx, args); + if (ret < 0) { + printf("[error] init server environment failed\n"); + goto exit; + } + + /* create & init engine to ctx->engine */ + ret = xqc_mini_svr_init_xquic_engine(ctx, args); + if (ret < 0) { + printf("[error] init xquic engine failed\n"); + goto exit; + } + + /* init engine ctx */ + ret = xqc_mini_svr_init_engine_ctx(ctx, args); + if (ret < 0) { + printf("[error] init engine ctx failed\n"); + goto exit; + } + + /* initiate user_conn */ + user_conn = xqc_mini_svr_create_user_conn(ctx); + + /* start event loop */ + event_base_dispatch(ctx->eb); + +exit: + xqc_engine_destroy(ctx->engine); + xqc_mini_svr_free_ctx(ctx); + if (user_conn) { + xqc_mini_svr_free_user_conn(user_conn); + } + + return 0; +} \ No newline at end of file diff --git a/mini/mini_server.h b/mini/mini_server.h new file mode 100644 index 000000000..b7e2a3905 --- /dev/null +++ b/mini/mini_server.h @@ -0,0 +1,160 @@ +#ifndef XQC_MINI_SERVER_H +#define XQC_MINI_SERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../demo/xqc_hq.h" +#include "../tests/platform.h" +#include "mini_server_cb.h" + +#define DEFAULT_IP "127.0.0.1" +#define DEFAULT_PORT 8443 +#define XQC_PACKET_BUF_LEN 1500 + +/** + * net config definition + * net config is those arguments about socket information + * all configuration on net should be put under this section + */ +typedef struct xqc_mini_svr_net_config_s +{ + /* server addr info */ + char ip[64]; + short port; + + /* idle persist timeout */ + int conn_timeout; +} xqc_mini_svr_net_config_t; + +/** + * quic config definition + * quic config is those arguments required by quic features, including connection settings, ssl configs, etc. + * all configuration on quic should be put under this section + */ +#define SESSION_TICKET_KEY_FILE "session_ticket.key" +#define SESSION_TICKET_KEY_BUF_LEN 2048 + +typedef struct xqc_mini_svr_quic_config_s +{ + /* cipher config */ + char ciphers[CIPHER_SUIT_LEN]; + char groups[TLS_GROUPS_LEN]; + + /* multipath */ + int multipath; // mp option, 0: disable, 1: enable + char mp_sched[32]; // mp scheduler, minrtt/backup + + /* congestion control */ + CC_TYPE cc; // cc algrithm, bbr/cubic + + + /* server should load session ticket key to enable 0-RTT */ + char session_ticket_key_data[SESSION_TICKET_KEY_BUF_LEN]; + size_t session_ticket_key_len; + +} xqc_mini_svr_quic_config_t; + +/** + * the environment config definition + * environment config is those arguments about IO inputs and outputs + * all configuration on environment should be put under this section + */ + +#define LOG_PATH "slog.log" +#define KEY_PATH "skeys.log" +#define SOURCE_DIR "." +#define PRIV_KEY_PATH "server.key" +#define CERT_PEM_PATH "server.crt" + +typedef struct xqc_mini_svr_env_config_s { + /* log config */ + char log_path[PATH_LEN]; + + /* tls certificates */ + char private_key_file[PATH_LEN]; + char cert_file[PATH_LEN]; + + /* key export */ + char key_out_path[PATH_LEN]; + +} xqc_mini_svr_env_config_t; + +typedef struct xqc_mini_svr_args_s { + /* network args */ + xqc_mini_svr_net_config_t net_cfg; + + /* xquic args */ + xqc_mini_svr_quic_config_t quic_cfg; + + /* environment args */ + xqc_mini_svr_env_config_t env_cfg; + +} xqc_mini_svr_args_t; + +typedef struct xqc_mini_svr_ctx_s { + struct event_base *eb; + + /* used to remember fd type to send stateless reset */ + int current_fd; + + xqc_engine_t *engine; // xquic engine for current context + struct event *ev_engine; + + xqc_mini_svr_args_t *args; // server arguments for current context + + int log_fd; + int keylog_fd; +} xqc_mini_svr_ctx_t; + + +typedef struct xqc_mini_svr_user_conn_s { + struct event *ev_timeout; + xqc_cid_t cid; + xqc_mini_svr_ctx_t *ctx; + + /* ipv4 server */ + int fd; + struct sockaddr_in *local_addr; + socklen_t local_addrlen; + struct event *ev_socket; + struct sockaddr_in *peer_addr; + socklen_t peer_addrlen; + +} xqc_mini_svr_user_conn_t; + + +void xqc_mini_svr_init_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_svr_args_t *args); + +void xqc_mini_svr_init_args(xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); +/** + * @brief init engine & transport callbacks + */ +void xqc_mini_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, + xqc_mini_svr_args_t *args); +/** + * @brief init xquic server engine + */ +int xqc_mini_svr_init_xquic_engine(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_env(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_engine_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +void xqc_mini_svr_init_conn_settings(xqc_engine_t *engine, xqc_mini_svr_args_t *args); + +static int xqc_mini_svr_init_socket(int family, uint16_t port, struct sockaddr *local_addr, + socklen_t local_addrlen); + +static void xqc_mini_svr_socket_event_callback(int fd, short what, void *arg); +#endif \ No newline at end of file diff --git a/mini/mini_server_cb.c b/mini/mini_server_cb.c new file mode 100644 index 000000000..178fa4ded --- /dev/null +++ b/mini/mini_server_cb.c @@ -0,0 +1,350 @@ +/** + * @file mini_server_cb.c contains callbacks definitions for mini_server, including: + * 1. engine callbacks + * 2. hq callbacks + * 3. h3 callbacks + */ + +#include "mini_server_cb.h" +/* engine callbacks */ + + +const char *line_break = "\n"; + +/** + * @brief engine callbacks to trigger engine main logic + */ +void +xqc_mini_svr_engine_cb(int fd, short what, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t *) arg; + + xqc_engine_main_logic(ctx->engine); +} + +/** + * @brief callbacks to set timer of engine callbacks + */ +void +xqc_mini_svr_set_event_timer(xqc_msec_t wake_after, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t *)arg; + + struct timeval tv; + tv.tv_sec = wake_after / 1000000; + tv.tv_usec = wake_after % 1000000; + event_add(ctx->ev_engine, &tv); +} + +int +xqc_mini_svr_open_log_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + return open(ctx->args->env_cfg.log_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} +void +xqc_mini_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + } +} + + +void +xqc_mini_svr_close_log_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd > 0) { + close(ctx->log_fd); + ctx->log_fd = 0; + } +} + +void +xqc_mini_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} + +int +xqc_mini_svr_open_keylog_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + return open(ctx->args->env_cfg.key_out_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_svr_keylog_cb(const xqc_cid_t *scid, const char *line, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->keylog_fd <= 0) { + printf("write keys error!\n"); + return; + } + + int write_len = write(ctx->keylog_fd, line, strlen(line)); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->keylog_fd, line_break, 1); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + } +} + +void +xqc_mini_svr_close_keylog_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->keylog_fd > 0) { + close(ctx->keylog_fd); + ctx->keylog_fd = 0; + } +} +int +xqc_mini_svr_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t *cid, + void *arg) +{ + DEBUG; + + return 0; +} + + +ssize_t +xqc_mini_svr_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *arg) +{ + ssize_t res = XQC_OK; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)arg; + int fd = user_conn->ctx->current_fd; + + do { + set_sys_errno(0); + res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); + if (res < 0) { + printf("[error] xqc_mini_svr_write_socket err %zd %s, fd: %d\n", + res, strerror(get_sys_errno()), fd); + if (get_sys_errno() == EAGAIN) { + res = XQC_SOCKET_EAGAIN; + } + } + } while ((res < 0) && (get_sys_errno() == EINTR)); + + // printf("[report] xqc_mini_svr_write_socket success size=%lu\n", size); + return res; +} + +ssize_t +xqc_mini_svr_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr,socklen_t peer_addrlen, void *conn_user_data) +{ + return xqc_mini_svr_write_socket(buf, size, peer_addr, peer_addrlen, conn_user_data); +} + +void +xqc_mini_svr_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, + const xqc_cid_t *new_cid, void *user_data) +{ + DEBUG; + // xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)user_data; + // memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); +} + +/* h3 callbacks */ +int +xqc_mini_svr_h3_conn_create_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)conn_user_data; + xqc_h3_conn_set_user_data(h3_conn, user_conn); + xqc_h3_conn_get_peer_addr(h3_conn, (struct sockaddr *)user_conn->peer_addr, + sizeof(struct sockaddr_in), &user_conn->peer_addrlen); + memcpy(&user_conn->cid, cid, sizeof(*cid)); + + printf("[stats] xqc_mini_svr_h3_conn_create_notify \n"); + return 0; +} + + +int +xqc_mini_svr_h3_conn_close_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t*)conn_user_data; + + printf("[stats] xqc_mini_svr_h3_conn_close_notify success \n"); + return 0; +} + + +void +xqc_mini_svr_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)conn_user_data; + xqc_conn_stats_t stats = xqc_conn_get_stats(user_conn->ctx->engine, &user_conn->cid); +} + + +int +xqc_mini_svr_h3_request_create_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_mini_svr_user_stream_t *user_stream = calloc(1, sizeof(*user_stream)); + user_stream->h3_request = h3_request; + + xqc_h3_request_set_user_data(h3_request, user_stream); + user_stream->recv_buf = calloc(1, REQ_BUF_SIZE); + + printf("[stats] xqc_mini_svr_h3_request_create_notify success \n"); + return 0; +} + +int +xqc_mini_svr_h3_request_close_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); + printf("[stats] xqc_mini_svr_h3_request_close_notify success, cwnd_blocked:%"PRIu64"\n", stats.cwnd_blocked_ms); + + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t*)strm_user_data; + free(user_stream); + + return 0; +} +int +xqc_mini_cli_handle_h3_request(xqc_mini_svr_user_stream_t *user_stream) +{ + DEBUG; + ssize_t ret = 0; + + /* response header buf list */ + xqc_http_header_t rsp_hdr[] = { + { + .name = {.iov_base = "content-type", .iov_len = 12}, + .value = {.iov_base = "text/plain", .iov_len = 10}, + .flags = 0, + } + }; + /* response header */ + xqc_http_headers_t rsp_hdrs; + rsp_hdrs.headers = rsp_hdr; + rsp_hdrs.count = sizeof(rsp_hdr) / sizeof(rsp_hdr[0]); + + if (user_stream->header_sent == 0) { + ret = xqc_h3_request_send_headers(user_stream->h3_request, &rsp_hdrs, 0); + if (ret < 0) { + printf("[error] xqc_h3_request_send_headers error %zd\n", ret); + return ret; + } else { + printf("[stats] xqc_h3_request_send_headers success \n"); + user_stream->header_sent = 1; + } + } + + ret = xqc_mini_svr_send_body(user_stream); + return ret; +} + +int +xqc_mini_svr_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_flag_t flag, + void *strm_user_data) +{ + DEBUG; + int ret; + char recv_buff[4096] = {0}; + ssize_t recv_buff_size, read, read_sum; + unsigned char fin = 0; + xqc_http_headers_t *headers = NULL; + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t *)strm_user_data; + + read = read_sum = 0; + recv_buff_size = 4096; + + /* recv headers */ + if (flag & XQC_REQ_NOTIFY_READ_HEADER) { + headers = xqc_h3_request_recv_headers(h3_request, &fin); + if (headers == NULL) { + printf("[error] xqc_h3_request_recv_headers error\n"); + return XQC_ERROR; + } + + /* TODO: if recv headers once for all? */ + user_stream->header_recvd = 1; + + } else if (flag & XQC_REQ_NOTIFY_READ_BODY) { /* recv body */ + do { + read = xqc_h3_request_recv_body(h3_request, recv_buff, recv_buff_size, &fin); + if (read == -XQC_EAGAIN) { + break; + + } else if (read < 0) { + printf("[error] xqc_h3_request_recv_body error %zd\n", read); + return XQC_OK; + } + + read_sum += read; + user_stream->recv_body_len += read; + } while (read > 0 && !fin); + } + if (fin) { + printf("[stats] read h3 request finish. \n"); + xqc_mini_cli_handle_h3_request(user_stream); + } + return 0; +} + +int +xqc_mini_svr_send_body(xqc_mini_svr_user_stream_t *user_stream) +{ + int fin = 1, send_buf_size, ret; + char send_buf[REQ_BUF_SIZE]; + + send_buf_size = REQ_BUF_SIZE; + memset(send_buf, 'D', send_buf_size); + + ret = xqc_h3_request_send_body(user_stream->h3_request, send_buf, send_buf_size, fin); + + printf("[reports] xqc_mini_svr_send_body success, size:%d \n", ret); + return ret; +} + +int +xqc_mini_svr_h3_request_write_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t *)strm_user_data; + int ret = xqc_mini_svr_send_body(user_stream); + + printf("[stats] write h3 request notify finish \n"); + return ret; +} diff --git a/mini/mini_server_cb.h b/mini/mini_server_cb.h new file mode 100644 index 000000000..262603096 --- /dev/null +++ b/mini/mini_server_cb.h @@ -0,0 +1,85 @@ +#ifndef XQC_MINI_SERVER_CB_H +#define XQC_MINI_SERVER_CB_H + +#include +#include + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include "../tests/getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#endif + +#include "mini_server.h" +#include + +#define REQ_BUF_SIZE 2048 + +typedef struct xqc_mini_svr_user_stream_s { + xqc_h3_request_t *h3_request; + + // uint64_t send_offset; + int header_sent; + int header_recvd; + size_t send_body_len; + size_t recv_body_len; + char *recv_buf; +} xqc_mini_svr_user_stream_t; + + +/* engine callbacks */ +void xqc_mini_svr_engine_cb(int fd, short what, void *arg); + +void xqc_mini_svr_set_event_timer(xqc_msec_t wake_after, void *arg); + +int xqc_mini_svr_open_log_file(void *arg); + +void xqc_mini_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *arg); + +void xqc_mini_svr_close_log_file(void *arg); + +void xqc_mini_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *arg); + +int xqc_mini_svr_open_keylog_file(void *arg); + +void xqc_mini_svr_keylog_cb(const xqc_cid_t *scid, const char *line, void *arg); + +void xqc_mini_svr_close_keylog_file(void *arg); + +int xqc_mini_svr_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t *cid, + void *eng_user_data); + +ssize_t xqc_mini_svr_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *arg); + +ssize_t xqc_mini_svr_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr,socklen_t peer_addrlen, void *arg); + +void xqc_mini_svr_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, + const xqc_cid_t *new_cid, void *user_data); + +/* h3 callbacks */ +int xqc_mini_svr_h3_conn_create_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data); + +int xqc_mini_svr_h3_conn_close_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data); + +void xqc_mini_svr_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *conn_user_data); + +int xqc_mini_svr_h3_request_create_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_h3_request_close_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_flag_t flag, + void *strm_user_data); + +int xqc_mini_svr_h3_request_write_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_send_body(xqc_mini_svr_user_stream_t *user_stream); +#endif \ No newline at end of file diff --git a/scripts/case_test.sh b/scripts/case_test.sh index 9d939f0ea..ab217ade6 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -10,10 +10,9 @@ LOCAL_TEST=0 cd ../build -# start test_server -killall test_server 2> /dev/null -./test_server -l d -e > /dev/null & -sleep 1 +CLIENT_BIN="tests/test_client" +SERVER_BIN="tests/test_server" + clear_log() { >clog @@ -38,10 +37,16 @@ function case_print_result() { } +# start test_server +rm -rf tp_localhost test_session xqc_token +killall test_server 2> /dev/null +${SERVER_BIN} -l d -e > /dev/null & +sleep 1 + clear_log echo -e "log switch off ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 44 >> stdlog -log_size=`wc -c clog | awk -F ' ' '{print $1}'` +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 44 >> stdlog +log_size=`wc -l clog | awk -F ' ' '{print $1}'` if [ $log_size -eq 0 ]; then echo ">>>>>>>> pass:1" case_print_result "log_switch_off" "pass" @@ -50,14 +55,27 @@ else case_print_result "log_switch_off" "fail" fi + +echo -e "server refuse ...\c" +${CLIENT_BIN} -x 46 -t 10 >> stdlog +result=`grep "conn close notified by refuse" slog` +if [ -n "$result" ]; then + echo ">>>>>>>> pass:1" + case_print_result "server_refuse" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "server_refuse" "fail" +fi + + rm -f test_session tp_localhost xqc_token killall test_server 2> /dev/null -./test_server -l d -e -x 17 > /dev/null & +${SERVER_BIN} -l d -e -x 17 > /dev/null & clear_log echo -e "server-inited stream ...\c" -./test_client -l d -E -t 3 >> stdlog +${CLIENT_BIN} -l d -E -t 3 >> stdlog client_refuse=`grep "ignore server initiated bidi-streams at client" clog` client_discard=`grep "data discarded" clog` client_check=`grep "xqc_h3_stream_close_notify" clog | grep "|stream_id:1|"` @@ -74,14 +92,14 @@ fi killall test_server 2> /dev/null -./test_server -l d -e -x 99 > /dev/null & +${SERVER_BIN} -l d -e -x 99 > /dev/null & sleep 1 rm -f test_session tp_localhost xqc_token clear_log echo -e "stream send pure fin ...\c" -./test_client -s 1024 -l d -t 1 -E -x 99 -T 1 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 99 -T 1 >> clog errlog=`grep_err_log` clog_res=`cat clog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:0|read_bytes:0|recv_bytes:0|stream_len:0|"` slog_res=`cat slog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:0|read_bytes:0|recv_bytes:0|stream_len:0|"` @@ -97,7 +115,7 @@ rm -f test_session clear_log echo -e "h3 stream send pure fin ...\c" -./test_client -s 1024 -l d -t 1 -E -x 99 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 99 >> clog errlog=`grep_err_log | grep -v "send data after fin sent"` clog_res=`cat clog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:0|read_bytes:0|recv_bytes:0|stream_len:0|"` slog_res=`cat slog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:0|read_bytes:0|recv_bytes:0|stream_len:0|"` @@ -113,7 +131,7 @@ rm -f test_session clear_log echo -e "h3_ext_bytestream send pure fin ...\c" -./test_client -s 1024 -l d -t 1 -E -x 310 -T 2 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 310 -T 2 >> clog errlog=`grep_err_log` clog_res=`cat clog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:5|read_bytes:2|recv_bytes:2|stream_len:2|"` slog_res=`cat slog | grep "|send_state:3|recv_state:3|stream_id:0|stream_type:0|send_bytes:2|read_bytes:5|recv_bytes:5|stream_len:5|"` @@ -128,12 +146,12 @@ fi rm -rf test_session killall test_server 2> /dev/null -./test_server -l d -e > /dev/null & +${SERVER_BIN} -l d -e > /dev/null & sleep 1 clear_log echo -e "stream read notify fail ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 12 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 12 >> clog result=`grep_err_log|grep -v xqc_h3_request_on_recv|grep -v xqc_h3_stream_process_in|grep -v xqc_h3_stream_read_notify|grep -v xqc_process_read_streams|grep -v xqc_process_conn_close_frame|grep -v xqc_h3_stream_process_request` if [ -z "$result" ]; then echo ">>>>>>>> pass:1" @@ -146,7 +164,7 @@ fi clear_log echo -e "create stream fail ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 11 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 11 >> clog result=`grep_err_log|grep -v xqc_stream_create` if [ -z "$result" ]; then echo ">>>>>>>> pass:1" @@ -158,7 +176,7 @@ fi clear_log echo -e "illegal packet ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E -x 10|grep ">>>>>>>> pass" ` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 10|grep ">>>>>>>> pass" ` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -170,7 +188,7 @@ fi clear_log echo -e "duplicate packet ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E -x 9|grep ">>>>>>>> pass" ` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 9|grep ">>>>>>>> pass" ` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -182,7 +200,7 @@ fi clear_log echo -e "packet with wrong cid ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E -x 8|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 8|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -194,7 +212,7 @@ fi clear_log echo -e "create connection fail ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 7 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 7 >> clog result=`grep_err_log|grep -v xqc_client_connect` if [ -z "$result" ]; then echo ">>>>>>>> pass:1" @@ -206,7 +224,7 @@ fi clear_log echo -e "socket recv fail ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E -x 6|grep ">>>>>>>> pass" ` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 6|grep ">>>>>>>> pass" ` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -218,7 +236,7 @@ fi clear_log echo -e "socket send fail ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E -x 5|grep ">>>>>>>> pass" ` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 5|grep ">>>>>>>> pass" ` errlog=`grep_err_log|grep -v "write_socket error"` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -231,7 +249,7 @@ fi clear_log echo -e "verify Token fail ...\c" rm -f xqc_token -result=`./test_client -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log|grep -v xqc_conn_check_token` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -243,7 +261,7 @@ fi clear_log echo -e "verify Token success ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -256,7 +274,7 @@ fi clear_log echo -e "test application delay ...\c" rm -f xqc_token -./test_client -s 5120 -l d -t 1 -E -x 16 >> clog +${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 16 >> clog if test "$(grep -e "|====>|.*NEW_TOKEN" clog |wc -l)" -gt 1 >/dev/null && grep ">>>>>>>> pass:1" clog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "test_application_delay" "pass" @@ -268,7 +286,7 @@ grep_err_log clear_log echo -e "fin only ...\c" -result=`./test_client -s 5120 -l d -t 1 -E -x 4 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 4 |grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -280,7 +298,7 @@ fi clear_log echo -e "send data after fin ...\c" -result=`./test_client -s 5120 -l d -t 1 -E -x 50 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 50 |grep ">>>>>>>> pass"` errlog=`grep_err_log | grep -v "send data after fin sent"` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -292,7 +310,7 @@ fi clear_log echo -e "send header after fin ...\c" -result=`./test_client -s 5120 -l d -t 1 -E -x 51 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 51 |grep ">>>>>>>> pass"` errlog=`grep_err_log | grep -v "send data after fin sent"` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -304,7 +322,7 @@ fi clear_log echo -e "send fin after fin ...\c" -result=`./test_client -s 5120 -l d -t 1 -E -x 52 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 52 |grep ">>>>>>>> pass"` errlog=`grep_err_log | grep -v "send data after fin sent"` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -317,7 +335,7 @@ fi clear_log echo -e "header header data ...\c" -./test_client -s 5120 -l d -t 1 -E -x 30 >> clog +${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 30 >> clog header_res=`grep "recv header" slog` trailer_res=`grep "recv tailer header" slog` if [ -n "$header_res" ] && [ -n "$trailer_res" ]; then @@ -331,7 +349,7 @@ grep_err_log clear_log echo -e "header data header ...\c" -./test_client -s 5120 -l d -t 1 -E -x 31 >> clog +${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 31 >> clog header_res=`grep "recv header" slog` trailer_res=`grep "recv tailer header" slog` if [ -n "$header_res" ] && [ -n "$trailer_res" ]; then @@ -346,7 +364,7 @@ grep_err_log clear_log echo -e "header data fin ...\c" -./test_client -l d -t 2 -s 100 -E -x 35 >> clog +${CLIENT_BIN} -l d -t 2 -s 100 -E -x 35 >> clog result=`grep ">>>>>>>> pass" clog` sres=`grep "|recv_fin|" slog` errlog=`grep_err_log` @@ -362,7 +380,7 @@ grep_err_log clear_log echo -e "header data immediate fin ...\c" -./test_client -l d -t 2 -s 100 -E -x 36 >> clog +${CLIENT_BIN} -l d -t 2 -s 100 -E -x 36 >> clog result=`grep ">>>>>>>> pass" clog` sres=`grep "h3 fin only received" slog` errlog=`grep_err_log` @@ -378,7 +396,7 @@ grep_err_log clear_log echo -e "header fin ...\c" -./test_client -l d -t 2 -x 37 >> clog +${CLIENT_BIN} -l d -t 2 -x 37 >> clog sres=`grep "|recv_fin|" slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$sres" ]; then @@ -393,7 +411,7 @@ grep_err_log clear_log echo -e "header immediate fin ...\c" -./test_client -l d -t 2 -x 38 >> clog +${CLIENT_BIN} -l d -t 2 -x 38 >> clog sres=`grep "h3 fin only received" slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -z "$sres" ]; then @@ -409,7 +427,7 @@ grep_err_log clear_log echo -e "uppercase header ...\c" -./test_client -s 5120 -l d -t 1 -E -x 34 >> clog +${CLIENT_BIN} -s 5120 -l d -t 1 -E -x 34 >> clog result=`grep ">>>>>>>> pass" clog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -423,7 +441,7 @@ fi clear_log echo -e "user close connection ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 2 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 2 >> clog if grep "<==.*CONNECTION_CLOSE" clog >/dev/null && grep "==>.*CONNECTION_CLOSE" clog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "user_close_connection" "pass" @@ -437,7 +455,7 @@ grep_err_log clear_log echo -e "close connection with error ...\c" -./test_client -s 1024000 -l d -t 1 -E -x 3 >> stdlog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 3 >> stdlog if grep "<==.*CONNECTION_CLOSE" clog >/dev/null && grep "==>.*CONNECTION_CLOSE" clog >/dev/null && grep "conn closing: 1" stdlog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "close_connection_with_error" "pass" @@ -451,7 +469,7 @@ grep_err_log|grep -v xqc_process_write_streams|grep -v xqc_h3_stream_write_notif clear_log echo -e "Reset stream when sending...\c" -./test_client -s 1024000 -l d -t 1 -E -x 1 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 1 >> clog if grep "send_state:5|recv_state:5" clog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "reset_stream" "pass" @@ -464,7 +482,7 @@ grep_err_log|grep -v stream clear_log echo -e "Reset stream when receiving...\c" -./test_client -s 1024000 -l d -t 1 -E -x 21 > stdlog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 21 > stdlog result=`grep "xqc_send_queue_drop_stream_frame_packets" slog` flag=`grep "send_state:5|recv_state:5" clog` errlog=`grep_err_log|grep -v stream` @@ -480,7 +498,7 @@ fi clear_log echo -e "Send header after reset stream...\c" -./test_client -s 1024000 -l d -t 1 -E -x 28 > stdlog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 28 > stdlog result=`grep "xqc_conn_destroy.*err:0x0" clog` flag=`grep "send_state:5|recv_state:5" clog` errlog=`grep_err_log|grep -v stream` @@ -496,7 +514,7 @@ fi clear_log -./test_client -s 1024000 -l e -t 1 -E -1 -V 1 > stdlog +${CLIENT_BIN} -s 1024000 -l e -t 1 -E -1 -V 1 > stdlog echo -e "Cert verify ...\c" result=`grep ">>>>>>>> pass:" stdlog` echo "$result" @@ -511,7 +529,7 @@ fi clear_log echo -e "1RTT ...\c" -./test_client -s 1024000 -l e -t 1 -E -1 > stdlog +${CLIENT_BIN} -s 1024000 -l e -t 1 -E -1 > stdlog result=`grep ">>>>>>>> pass:" stdlog` echo "$result" flag=`grep "early_data_flag:0" stdlog` @@ -528,7 +546,7 @@ fi clear_log echo -e "alp negotiation failure ...\c" rm -f test_session -./test_client -l e -t 1 -T 1 -x 43 > stdlog +${CLIENT_BIN} -l e -t 1 -T 1 -x 43 > stdlog alpn_res=`grep "xqc_ssl_alpn_select_cb|select proto error" slog` if [ -n "$alpn_res" ]; then echo ">>>>>>>> pass:1" @@ -542,7 +560,7 @@ fi clear_log echo -e "without session ticket ...\c" rm -f test_session -./test_client -s 1024000 -l e -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l e -t 1 -E > stdlog result=`grep ">>>>>>>> pass:" stdlog` echo "$result" flag=`grep "early_data_flag:0" stdlog` @@ -559,7 +577,7 @@ fi clear_log rm -f test_session xqc_token tp_localhost echo -e "transport ping ...\c" -./test_client -s 1024 -l d -E -x 28 -T 1 >> clog +${CLIENT_BIN} -s 1024 -l d -E -x 28 -T 1 >> clog ret_ping_id=`grep "====>ping_id:" clog` ret_no_ping_id=`grep "====>no ping_id" clog` if [ -n "$ret_ping_id" ] && [ -n "$ret_no_ping_id" ]; then @@ -574,7 +592,7 @@ fi clear_log rm -f test_session xqc_token tp_localhost echo -e "h3 ping ...\c" -./test_client -s 1024 -l d -E -x 28 >> clog +${CLIENT_BIN} -s 1024 -l d -E -x 28 >> clog ret_ping_id=`grep "====>ping_id:" clog` ret_no_ping_id=`grep "====>no ping_id" clog` if [ -n "$ret_ping_id" ] && [ -n "$ret_no_ping_id" ]; then @@ -588,7 +606,7 @@ fi clear_log echo -e "0RTT accept ...\c" -./test_client -s 1024000 -l e -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l e -t 1 -E > stdlog result=`grep ">>>>>>>> pass:" stdlog` echo "$result" flag=`grep "early_data_flag:1" stdlog` @@ -605,9 +623,9 @@ fi clear_log echo -e "0RTT reject. restart server ....\c" killall test_server -./test_server -l i -e > /dev/null & +${SERVER_BIN} -l i -e > /dev/null & sleep 1 -./test_client -s 1024000 -l d -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E > stdlog result=`grep ">>>>>>>> pass:" stdlog` echo "$result" flag=`grep "early_data_flag:2" stdlog` @@ -623,7 +641,7 @@ fi clear_log echo -e "transport only ...\c" rm -f test_session -result=`./test_client -s 1024000 -l d -T 1 -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -T 1 -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -635,7 +653,7 @@ fi clear_log echo -e "transport 0RTT ...\c" -./test_client -s 1024000 -l e -T 1 -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l e -T 1 -t 1 -E > stdlog result=`grep ">>>>>>>> pass:" stdlog` echo "$result" flag=`grep "early_data_flag:1" stdlog` @@ -653,7 +671,7 @@ rm -f test_session clear_log echo -e "no crypto without 0RTT ...\c" rm -f test_session -result=`./test_client -s 1024000 -l d -N -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -N -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -666,7 +684,7 @@ fi clear_log echo -e "no crypto with 0RTT ...\c" -./test_client -s 1024000 -l d -N -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l d -N -t 1 -E > stdlog if grep "early_data_flag:1" stdlog >/dev/null && grep ">>>>>>>> pass:1" stdlog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "no_crypto_with_0RTT" "pass" @@ -679,7 +697,7 @@ grep_err_log clear_log echo -e "no crypto with 0RTT twice ...\c" -./test_client -s 1024000 -l d -N -t 1 -E > stdlog +${CLIENT_BIN} -s 1024000 -l d -N -t 1 -E > stdlog if grep "early_data_flag:1" stdlog >/dev/null && grep ">>>>>>>> pass:1" stdlog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "no_crypto_with_0RTT_twice" "pass" @@ -692,7 +710,7 @@ grep_err_log clear_log echo -e "0RTT buffer limit before Initial ...\c" -./test_client -l d -t 1 -x 39 -E >> clog +${CLIENT_BIN} -l d -t 1 -x 39 -E >> clog limit_log=`grep "0RTT reach buffer limit before DCID confirmed" slog` clog_res=`grep ">>>>>>>> pass:1" clog` errlog=`grep_err_log` @@ -706,13 +724,29 @@ fi grep_err_log +clear_log +echo -e "empty header value ...\c" +${CLIENT_BIN} -x 47 -1 -n 10 >> stdlog +result=`grep -E "test_result_speed:.*request_cnt: 10." stdlog` +errlog=`grep_err_log` +if [ -n "$result" ] && [ -z "$errlog" ]; then + echo ">>>>>>>> pass:1" + case_print_result "empty_header_value" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "empty_header_value" "fail" + exit 1 +fi +grep_err_log + + clear_log rm -f test_session echo -e "NULL stream callback ...\c" killall test_server -./test_server -l i -e -x 2 > /dev/null & +${SERVER_BIN} -l i -e -x 2 > /dev/null & sleep 1 -./test_client -l d -T 1 -E >> clog +${CLIENT_BIN} -l d -T 1 -E >> clog if grep "stream_read_notify is NULL" slog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "NULL_stream_callback" "pass" @@ -726,9 +760,9 @@ rm -f test_session clear_log echo -e "server cid negotiate ...\c" killall test_server -./test_server -l d -e -x 1 > /dev/null & +${SERVER_BIN} -l d -e -x 1 > /dev/null & sleep 1 -./test_client -s 1024000 -l d -t 1 -E >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 -E >> clog result=`grep ">>>>>>>> pass:1" clog` dcid=`grep "====>DCID" clog | awk -F ":" '{print $2}'` dcid_res=`grep "new:$dcid" clog` @@ -744,9 +778,9 @@ fi clear_log echo -e "GET request ...\c" -result=`./test_client -l d -t 1 -E -G|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -l d -t 1 -E -G|grep ">>>>>>>> pass"` errlog=`grep_err_log` -alpn_res=`grep "|select alpn|h3|" slog` +alpn_res=`grep "|selected_alpn:h3|" slog` echo "$result" if [ -z "$errlog" ] && [ -n "$alpn_res" ] && [ "$result" == ">>>>>>>> pass:1" ]; then case_print_result "GET_request" "pass" @@ -758,8 +792,8 @@ fi clear_log rm -f test_session xqc_token tp_localhost echo -e "new client 29 - new server ...\c" -result=`./test_client -s 1024 -l d -t 1 -E -x 17 |grep ">>>>>>>> pass"` -alpn_res=`grep "select alpn|h3-29|" slog` +result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 17 |grep ">>>>>>>> pass"` +alpn_res=`grep "selected_alpn:h3-29" slog` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ -n "$alpn_res" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -773,7 +807,7 @@ rm -f test_session xqc_token tp_localhost clear_log echo -e "set h3 settings ...\c" -./test_client -s 1024 -l d -t 1 -E -x 18 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 18 >> clog if grep ">>>>>>>> pass:1" clog >/dev/null && \ grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog >/dev/null && \ grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog >/dev/null && \ @@ -789,7 +823,7 @@ grep_err_log clear_log echo -e "header size constraints ...\c" -./test_client -s 1024 -l d -t 1 -E -x 19 -n 2 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 19 -n 2 >> clog if grep -e "xqc_h3_stream_send_headers.*fields_size.*exceed.*SETTINGS_MAX_FIELD_SECTION_SIZE.*" slog >/dev/null; then echo ">>>>>>>> pass:1" case_print_result "header_size_constraints" "pass" @@ -800,9 +834,36 @@ fi grep_err_log|grep -v xqc_h3_stream_send_headers +clear_log +echo -e "no h3 init settings callback ...\c" +result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E |grep ">>>>>>>> pass"` +clog_res=`grep "new_h3_local_settings" clog` +errlog=`grep_err_log` +echo "$result" +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -z "$clog_res" ]; then + case_print_result "no_h3_init_settings_cb" "pass" +else + case_print_result "no_h3_init_settings_cb" "fail" + echo "$errlog" +fi + +clear_log +echo -e "set h3 init settings callback ...\c" +result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 502|grep ">>>>>>>> pass"` +clog_res=`grep -E "new_h3_local_settings.*qpack_dec_max_table_capacity:65536" clog` +errlog=`grep_err_log` +echo "$result" +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$clog_res" ]; then + case_print_result "set_h3_init_settings_cb" "pass" +else + case_print_result "set_h3_init_settings_cb" "fail" + echo "$errlog" +fi + + clear_log echo -e "send 1K data ...\c" -result=`./test_client -s 1024 -l d -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E --conn_options CBBR|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -814,7 +875,7 @@ fi clear_log echo -e "send 1M data ...\c" -result=`./test_client -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -826,7 +887,7 @@ fi clear_log echo -e "send 10M data ...\c" -result=`./test_client -s 10240000 -l e -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -836,9 +897,21 @@ else echo "$errlog" fi +clear_log +echo -e "send 10M data (mempool protected) ...\c" +result=`${CLIENT_BIN} -s 10240000 -l e -E -x 600 |grep ">>>>>>>> pass"` +errlog=`grep_err_log` +echo "$result" +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then + case_print_result "send_10M_data_mempool_protected" "pass" +else + case_print_result "send_10M_data_mempool_protected" "fail" + echo "$errlog" +fi + clear_log echo -e "send 4K every time ...\c" -result=`./test_client -s 10240000 -l e -E -x 49|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -x 49|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -850,7 +923,7 @@ fi clear_log echo -e "BBR ...\c" -result=`./test_client -s 10240000 -l e -E -c bbr|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c bbr|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -862,7 +935,7 @@ fi clear_log echo -e "BBR with cwnd compensation ...\c" -result=`./test_client -s 10240000 -l e -E -c bbr+|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c bbr+|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -874,7 +947,7 @@ fi clear_log echo -e "BBRv2 ...\c" -result=`./test_client -s 10240000 -l e -E -c bbr2|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c bbr2|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -886,7 +959,7 @@ fi clear_log echo -e "BBRv2+ ...\c" -result=`./test_client -s 10240000 -l e -E -c bbr2+|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c bbr2+|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -898,7 +971,7 @@ fi clear_log echo -e "Reno with pacing ...\c" -result=`./test_client -s 10240000 -l e -E -c reno -C|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c reno -C|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -910,7 +983,7 @@ fi clear_log echo -e "Reno without pacing ...\c" -result=`./test_client -s 10240000 -l e -E -c reno|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c reno|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -923,7 +996,7 @@ fi clear_log echo -e "Cubic with pacing ...\c" -result=`./test_client -s 10240000 -l e -E -c cubic -C|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c cubic -C|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -935,7 +1008,7 @@ fi clear_log echo -e "Cubic without pacing ...\c" -result=`./test_client -s 10240000 -l e -E -c cubic|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -c cubic|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -947,7 +1020,7 @@ fi clear_log echo -e "unlimited_cc...\c" -result=`./test_client -s 102400 -l e -t 1 -E -c u|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 102400 -l e -t 1 -E -c u|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -959,7 +1032,7 @@ fi clear_log echo -e "Copa with default parameters (delta=0.05, ai_unit=1.0) ...\c" -result=`./test_client -s 10240000 -l e -t 1 -E -c P|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -t 1 -E -c P|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -971,7 +1044,7 @@ fi clear_log echo -e "Copa with customized parameters (delta=0.5, ai_unit=5.0) ...\c" -result=`./test_client -s 10240000 -l e -t 1 -E -c P --copa_delta 0.5 --copa_ai_unit 5.0 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -t 1 -E -c P --copa_delta 0.5 --copa_ai_unit 5.0 |grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -984,7 +1057,7 @@ fi clear_log echo -e "low_delay_settings...\c" -result=`./test_client -s 102400 -l e -t 1 -E -x 400|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 102400 -l e -t 1 -E -x 400|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -996,7 +1069,7 @@ fi clear_log -result=`./test_client -s 10240000 -l e -t 1 -E -x 26|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -t 1 -E -x 26|grep ">>>>>>>> pass"` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then case_print_result "spurious_loss_detect_on" "pass" @@ -1010,7 +1083,7 @@ echo "$result" clear_log echo -e "stream level flow control ...\c" -result=`./test_client -s 10240000 -l e -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1022,7 +1095,7 @@ fi clear_log echo -e "connection level flow control ...\c" -./test_client -s 512000 -l e -E -n 10 > stdlog +${CLIENT_BIN} -s 512000 -l e -E -n 10 > stdlog sleep 1 if [[ `grep ">>>>>>>> pass:1" stdlog|wc -l` -eq 10 ]]; then echo ">>>>>>>> pass:1" @@ -1035,7 +1108,7 @@ grep_err_log clear_log echo -e "stream concurrency flow control ...\c" -./test_client -s 1 -l e -t 1 -E -P 1025 -G > ccfc.log +${CLIENT_BIN} -s 1 -l e -t 1 -E -P 1025 -G > ccfc.log if [[ `grep ">>>>>>>> pass:1" ccfc.log|wc -l` -eq 1024 ]]; then echo ">>>>>>>> pass:1" case_print_result "stream_concurrency_flow_control" "pass" @@ -1048,7 +1121,7 @@ rm -f ccfc.log clear_log echo -e "1% loss ...\c" -result=`./test_client -s 10240000 -l e -E -d 10|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -d 10|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1060,7 +1133,7 @@ fi clear_log echo -e "3% loss ...\c" -result=`./test_client -s 10240000 -l e -E -d 30|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -l e -E -d 30|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1071,7 +1144,7 @@ else fi clear_log -result=`./test_client -s 10240000 -t 5 -l e -E -d 100|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -t 5 -l e -E -d 100|grep ">>>>>>>> pass"` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then case_print_result "10_percent_loss" "pass" @@ -1084,12 +1157,12 @@ echo "$result" killall test_server 2> /dev/null -./test_server -l e -e > /dev/null & +${SERVER_BIN} -l e -e > /dev/null & sleep 1 clear_log echo -e "sendmmsg with 10% loss ...\c" -result=`./test_client -s 10240000 -t 5 -l e -E -d 100 -x 20 -c c|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 10240000 -t 5 -l e -E -d 100 -x 20 -c c|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1101,7 +1174,7 @@ fi clear_log -result=`./test_client -s 2048000 -l e -t 5 -E -d 300|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 2048000 -l e -t 5 -E -d 300|grep ">>>>>>>> pass"` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then case_print_result "large_ack_range_with_30_percent_loss" "pass" @@ -1115,7 +1188,7 @@ echo "$result" clear_log echo -e "test client long header ...\c" -./test_client -l d -x 29 >> clog +${CLIENT_BIN} -l d -x 29 >> clog #clog_res=`grep "xqc_process_conn_close_frame|with err:" clog` #slog_res=`grep "READ_VALUE error" slog` slog_res=`grep -a "large nv|conn" slog` @@ -1128,13 +1201,13 @@ fi killall test_server 2> /dev/null -./test_server -l d -x 9 > /dev/null & +${SERVER_BIN} -l d -x 9 > /dev/null & sleep 1 clear_log echo -e "test server long header ...\c" -./test_client -l d >> clog +${CLIENT_BIN} -l d >> clog #slog_res=`grep "xqc_process_conn_close_frame|with err:" slog` #clog_res=`grep "READ_VALUE error" clog` slog_res=`grep "large nv|conn" slog` @@ -1149,12 +1222,13 @@ fi clear_log killall test_server echo -e "client Initial dcid corruption ...\c" -./test_server -l d -e > /dev/null & sleep 1 -client_print_res=`./test_client -s 1024000 -l d -t 1 -x 22 -E | grep ">>>>>>>> pass"` +${SERVER_BIN} -l d -e > /dev/null & +sleep 1 +client_print_res=`${CLIENT_BIN} -s 1024000 -l d -t 1 -x 22 -E | grep ">>>>>>>> pass"` errlog=`grep_err_log` server_log_res=`grep "decrypt payload error" slog` -server_conn_cnt=`grep "xqc_conn_create" slog | grep -v "tra_parameters_set" | wc -l` +server_conn_cnt=`grep "xqc_conn_create" slog | grep -v "tra_parameters_set" | grep -v "mempool" | grep -v "connection_state_updated" | grep -v "path_assigned" | wc -l` echo "$client_print_res" if [ "$client_print_res" != "" ] && [ "$server_log_res" != "" ] && [ $server_conn_cnt -eq 2 ]; then case_print_result "client_initial_dcid_corruption" "pass" @@ -1167,9 +1241,9 @@ fi clear_log killall test_server echo -e "client Initial scid corruption ...\c" -./test_server -l d -e > /dev/null & +${SERVER_BIN} -l d -e > /dev/null & sleep 1 -client_print_res=`./test_client -s 1024000 -l d -t 1 -x 23 -E | grep ">>>>>>>> pass"` +client_print_res=`${CLIENT_BIN} -s 1024000 -l d -t 1 -x 23 -E | grep ">>>>>>>> pass"` errlog=`grep_err_log` server_log_res=`grep "decrypt data error" slog` server_dcid_res=`grep "dcid change" slog` @@ -1185,9 +1259,9 @@ fi clear_log killall test_server echo -e "server Initial dcid corruption ...\c" -./test_server -l d -e -x 3 > /dev/null & +${SERVER_BIN} -l d -e -x 3 > /dev/null & sleep 1 -client_print_res=`./test_client -s 1024000 -l d -t 1 -E |grep ">>>>>>>> pass"` +client_print_res=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E |grep ">>>>>>>> pass"` client_log_res=`grep "fail to find connection" clog` echo "$client_print_res" if [ "$client_print_res" != "" ] && [ "$client_log_res" != "" ]; then @@ -1201,9 +1275,9 @@ fi clear_log killall test_server echo -e "server Initial scid corruption ...\c" -./test_server -l d -e -x 4 > /dev/null & +${SERVER_BIN} -l d -e -x 4 > /dev/null & sleep 1 -client_print_res=`./test_client -s 1024000 -l d -t 1 -E |grep ">>>>>>>> pass"` +client_print_res=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E |grep ">>>>>>>> pass"` client_log_res=`grep "decrypt data error" clog` echo "$client_print_res" if [ "$client_print_res" != "" ] && [ "$client_log_res" != "" ]; then @@ -1216,9 +1290,9 @@ fi clear_log killall test_server echo -e "server odcid hash ...\c" -./test_server -l d -e -x 5 > /dev/null & +${SERVER_BIN} -l d -e -x 5 > /dev/null & sleep 1 -result=`./test_client -s 1024000 -l d -t 1 -E | grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -t 1 -E | grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1228,13 +1302,13 @@ else echo "$errlog" fi -# ./test_server should be killed after this case, since some of the test case requires ./test_server without param `-E` +# ${SERVER_BIN} should be killed after this case, since some of the test case requires ${SERVER_BIN} without param `-E` clear_log killall test_server 2> /dev/null echo -e "load balancer cid generate with encryption...\c" -./test_server -l d -e -S "server_id_0" -E > /dev/null & +${SERVER_BIN} -l d -e -S "server_id_0" -E > /dev/null & sleep 1 -./test_client -s 1024000 -l d -t 1 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 >> clog result=`grep "|lb cid encrypted|" slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" != "" ]; then @@ -1248,9 +1322,9 @@ fi clear_log killall test_server 2> /dev/null echo -e "load balancer cid generate ...\c" -./test_server -l d -e -S "server_id_0" > /dev/null & +${SERVER_BIN} -l d -e -S "server_id_0" > /dev/null & sleep 1 -./test_client -s 1024000 -l d -t 1 >> clog +${CLIENT_BIN} -s 1024000 -l d -t 1 >> clog result=`grep "|xqc_conn_confirm_cid|dcid change|" clog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" != "" ]; then @@ -1263,7 +1337,7 @@ fi clear_log echo -e "set cipher suites ...\c" -./test_client -s 1024 -l d -t 1 -x 27 >> clog +${CLIENT_BIN} -s 1024 -l d -t 1 -x 27 >> clog result=`grep "set cipher suites suc|ciphers:TLS_CHACHA20_POLY1305_SHA256" clog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" != "" ]; then @@ -1276,13 +1350,13 @@ fi killall test_server 2> /dev/null -./test_server -l d -e -x 8 > /dev/null & +${SERVER_BIN} -l d -e -x 8 > /dev/null & sleep 1 clear_log rm -f test_session xqc_token tp_localhost echo -e "server amplification limit ...\c" -./test_client -s 1024 -l d -t 3 -x 25 -1 >> clog +${CLIENT_BIN} -s 1024 -l d -t 3 -x 25 -1 >> clog enter_aal=`grep "amplification limit" slog` aal=`grep "blocked by anti amplification limit" slog` leave_aal=`grep "anti-amplification state unlock" slog` @@ -1296,12 +1370,12 @@ fi killall test_server 2> /dev/null -./test_server -l e -e -x 10 > /dev/null & +${SERVER_BIN} -l e -e -x 10 > /dev/null & sleep 1 clear_log echo -e "massive requests with massive header ...\c" -./test_client -l e -q 50 -n 100 -x 32 -E >> clog -result=`grep ">>>>>>>> pass:1" clog` +${CLIENT_BIN} -l e -q 50 -n 100 -x 32 -E > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" != "" ]; then echo ">>>>>>>> pass:1" @@ -1309,15 +1383,16 @@ if [ -z "$errlog" ] && [ "$result" != "" ]; then else echo ">>>>>>>> pass:0" case_print_result "massive_requests_with_massive_header" "fail" + echo "$result" fi killall test_server 2> /dev/null -./test_server -l d -e -b > /dev/null & +${SERVER_BIN} -l d -e -b > /dev/null & sleep 1 clear_log echo -e "version negotiation ...\c" -./test_client -l d -E -x 33 >> clog +${CLIENT_BIN} -l d -E -x 33 >> clog result=`grep -e "|====>|.*VERSION_NEGOTIATION" clog` if [ -n "$result" ]; then echo ">>>>>>>> pass:1" @@ -1329,12 +1404,12 @@ fi killall test_server -./test_server -l d -e -x 11 > /dev/null & +${SERVER_BIN} -l d -e -x 11 > /dev/null & sleep 1 clear_log echo -e "server refuse connection ...\c" -./test_client -l d -E >> clog +${CLIENT_BIN} -l d -E >> clog svr_result=`grep "server_accept callback return error" slog` if [ -n "$svr_result" ] ; then echo ">>>>>>>> pass:1" @@ -1345,13 +1420,13 @@ else fi killall test_server -./test_server -l e -e -x 12 > /dev/null & +${SERVER_BIN} -l e -e -x 12 > /dev/null & sleep 1 clear_log echo -e "linger close transport ...\c" rm -f test_session xqc_token tp_localhost -result=`./test_client -l e -T 1 -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -l e -T 1 -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1364,7 +1439,7 @@ rm -f test_session xqc_token tp_localhost clear_log echo -e "linger close h3 ...\c" -result=`./test_client -l e -t 1 -E|grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -l e -t 1 -E|grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1375,12 +1450,12 @@ else fi killall test_server -./test_server -l d -e > /dev/null & +${SERVER_BIN} -l d -e > /dev/null & sleep 1 clear_log echo -e "key update ...\c" -./test_client -s 102400 -l d -E -x 40 >> clog +${CLIENT_BIN} -s 102400 -l d -E -x 40 >> clog result=`grep ">>>>>>>> pass" clog` svr_res=`grep "key phase changed to" slog` cli_res=`grep "key phase changed to" clog` @@ -1396,7 +1471,7 @@ grep_err_log clear_log echo -e "key update 0RTT...\c" -./test_client -s 102400 -l d -E -x 40 >> clog +${CLIENT_BIN} -s 102400 -l d -E -x 40 >> clog result=`grep ">>>>>>>> pass" clog` svr_res=`grep "key phase changed to" slog` cli_res=`grep "key phase changed to" clog` @@ -1412,7 +1487,7 @@ grep_err_log echo -e "max pkt out size...\c" -./test_client -l d -x 42 -1 -E > stdlog +${CLIENT_BIN} -l d -x 42 -1 -E > stdlog result=`grep ">>>>>>>> pass" stdlog` if [ -n "$result" ]; then echo ">>>>>>>> pass:1" @@ -1424,11 +1499,11 @@ fi killall test_server -./test_server -l d -x 13 > /dev/null & +${SERVER_BIN} -l d -x 13 > /dev/null & sleep 1 clear_log echo -e "stateless reset...\c" -./test_client -l d -x 41 -1 -t 5 > stdlog +${CLIENT_BIN} -l d -x 41 -1 -t 5 > stdlog result=`grep "|====>|receive stateless reset" clog` cloing_notify=`grep "conn closing: 641" stdlog` if [ -n "$result" ] && [ -n "$cloing_notify" ]; then @@ -1442,7 +1517,7 @@ fi clear_log echo -e "stateless reset during hsk...\c" -./test_client -l d -t 5 -x 45 -1 -s 100 -G > stdlog +${CLIENT_BIN} -l d -t 5 -x 45 -1 -s 100 -G > stdlog result=`grep "|====>|receive stateless reset" clog` cloing_notify=`grep "conn closing: 641" stdlog` svr_hsk=`grep "handshake_time:0" slog` @@ -1456,13 +1531,13 @@ else fi killall test_server -./test_server -l d -e -M > /dev/null & +${SERVER_BIN} -l d -e -M > /dev/null & sleep 1 clear_log echo -e "MPNS enable multipath negotiate ...\c" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo > stdlog result=` grep "enable_multipath=1" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" != "" ]; then @@ -1476,7 +1551,7 @@ grep_err_log clear_log echo -e "MPNS send 1M data on multiple paths ...\c" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo -i lo -E > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E > stdlog result=`grep ">>>>>>>> pass" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1490,7 +1565,7 @@ grep_err_log clear_log echo -e "MPNS multipath 30 percent loss ...\c" -sudo ./test_client -s 10240000 -t 5 -l e -E -d 300 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 10240000 -t 5 -l e -E -d 300 -M -i lo -i lo > stdlog result=`grep ">>>>>>>> pass" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1504,12 +1579,12 @@ grep_err_log clear_log echo -e "MPNS multipath close initial path ...\c" -sudo ./test_client -s 1024000 -l d -t 3 -M -i lo -i lo -E -x 100 > stdlog +sudo ${CLIENT_BIN} -s 10240 -l d -t 5 -M -i lo -i lo -E -x 100 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:0|" slog` cli_res=`grep "|path closed|path:0|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_close_initial_path" "pass" else @@ -1520,12 +1595,12 @@ grep_err_log clear_log echo -e "MPNS multipath 30 percent loss close initial path ...\c" -sudo ./test_client -s 10240000 -t 5 -l d -E -d 300 -M -i lo -i lo -x 100 > stdlog +sudo ${CLIENT_BIN} -s 10240 -t 6 -l d -E -d 300 -M -i lo -i lo -x 100 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:0|" slog` cli_res=`grep "|path closed|path:0|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_30_percent_loss_close_initial_path" "pass" else @@ -1534,14 +1609,16 @@ else fi grep_err_log + + clear_log echo -e "MPNS multipath close new path ...\c" -sudo ./test_client -s 1024000 -l d -t 3 -M -A -i lo -i lo -E -x 101 >> clog +sudo ${CLIENT_BIN} -s 10240 -l d -t 5 -M -A -i lo -i lo -E -x 101 -e 10 --epoch_timeout 1000000 >> clog result=`grep ">>>>>>>> pass" clog` svr_res=`grep "|path closed|path:1|" slog` cli_res=`grep "|path closed|path:1|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_close_new_path" "pass" else @@ -1552,12 +1629,12 @@ grep_err_log clear_log echo -e "MPNS multipath 30 percent loss close new path ...\c" -sudo ./test_client -s 10240000 -t 5 -l d -E -d 300 -M -i lo -i lo -x 101 > stdlog +sudo ${CLIENT_BIN} -s 10240 -t 6 -l d -E -d 300 -M -i lo -i lo -x 101 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:1|" slog` cli_res=`grep "|path closed|path:1|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_30_percent_loss_close_new_path" "pass" else @@ -1567,43 +1644,30 @@ fi grep_err_log killall test_server -./test_server -l d -e -M > /dev/null & +${SERVER_BIN} -l d -e -M > /dev/null & sleep 1 clear_log -echo -e "send 1M data on multiple paths with multipath vertion 04" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 4 > stdlog -cli_result=`grep "multipath version negotiation succeed on multipath 04" clog` +echo -e "send 1M data on multiple paths with multipath version 10" +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 10 > stdlog +cli_result=`grep "multipath version negotiation succeed on multipath 010" clog` if [ -n "$cli_result" ]; then echo ">>>>>>>> pass:1" - case_print_result "MPNS_send_data_with_multipath_04" "pass" + case_print_result "MPNS_send_data_with_multipath_10" "pass" else echo ">>>>>>>> pass:0" - case_print_result "MPNS_send_data_with_multipath_04" "fail" -fi -rm -f test_session tp_localhost xqc_token - -clear_log -echo -e "send 1M data on multiple paths with multipath vertion 05" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 5 > stdlog -cli_result=`grep "multipath version negotiation succeed on multipath 05" clog` -if [ -n "$cli_result" ]; then - echo ">>>>>>>> pass:1" - case_print_result "MPNS_send_data_with_multipath_05" "pass" -else - echo ">>>>>>>> pass:0" - case_print_result "MPNS_send_data_with_multipath_05" "fail" + case_print_result "MPNS_send_data_with_multipath_10" "fail" fi rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l d -e -M -R 1 > /dev/null & +${SERVER_BIN} -l d -e -M -R 1 > /dev/null & sleep 1 clear_log echo -e "MPNS reinject unack packets by capacity ...\c" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo -i lo -E -R 1 > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -R 1 > stdlog result=`grep ">>>>>>>> pass" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1617,12 +1681,12 @@ grep_err_log killall test_server -./test_server -l d -e -M -R 2 > /dev/null & +${SERVER_BIN} -l d -e -M -R 2 > /dev/null & sleep 1 clear_log echo -e "MPNS reinject unack packets by deadline ...\c" -sudo ./test_client -s 1024000 -l d -t 1 -M -i lo -i lo -E -R 2 > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -R 2 > stdlog result=`grep ">>>>>>>> pass" stdlog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1636,12 +1700,12 @@ grep_err_log killall test_server -./test_server -l d -e -M > /dev/null & +${SERVER_BIN} -l d -e -M > /dev/null & sleep 1 clear_log echo -e "NAT rebinding path 0 ...\c" -sudo ./test_client -s 102400 -l d -t 3 -M -i lo -i lo -E -n 2 -x 103 > stdlog +sudo ${CLIENT_BIN} -s 102400 -l d -t 3 -M -i lo -i lo -E -n 2 -x 103 > stdlog result=`grep ">>>>>>>> pass:0" stdlog` errlog=`grep_err_log` rebind=`grep "|path:0|REBINDING|validate NAT rebinding addr|" slog` @@ -1659,7 +1723,7 @@ grep_err_log clear_log echo -e "NAT rebinding path 1 ...\c" -sudo ./test_client -s 1024000 -l d -t 3 -M -i lo -i lo -E -n 2 -x 104 > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -t 3 -M -i lo -i lo -E -n 2 -x 104 > stdlog result=`grep ">>>>>>>> pass:0" stdlog` errlog=`grep_err_log` rebind=`grep "|path:1|REBINDING|validate NAT rebinding addr|" slog` @@ -1673,12 +1737,12 @@ fi grep_err_log killall test_server -./test_server -l d -e -M -y > /dev/null & +${SERVER_BIN} -l d -e -M -y > /dev/null & sleep 1 clear_log echo -e "Multipath Compensate and Accelerate ...\c" -sudo ./test_client -s 102400 -l d -t 3 -M -A -i lo -i lo -E -P 2 -y > ccfc.log +sudo ${CLIENT_BIN} -s 102400 -l d -t 3 -M -A -i lo -i lo -E -P 2 -y > ccfc.log errlog=`grep_err_log` svr_res=`grep "path_status:2->1" slog` cli_res=`grep "path_status:2->1" clog` @@ -1693,7 +1757,7 @@ grep_err_log clear_log echo -e "Multipath Compensate but not Accelerate ...\c" -sudo ./test_client -s 102400 -l d -t 3 -M -i lo -i lo -E -P 2 -y > ccfc.log +sudo ${CLIENT_BIN} -s 102400 -l d -t 3 -M -i lo -i lo -E -P 2 -y > ccfc.log errlog=`grep_err_log` svr_res=`grep "path_status:2->1" slog` cli_res=`grep "path_status:2->1" clog` @@ -1720,11 +1784,12 @@ fi if [ -f stdlog ]; then rm -f stdlog fi -./test_server -l d -Q 9000 > /dev/null & + +${SERVER_BIN} -l d -Q 9000 > /dev/null & sleep 1 clear_log echo -e "datagram frame size negotiation...\c" -./test_client -l d -Q 9000 >> stdlog +${CLIENT_BIN} -l d -Q 9000 >> stdlog cli_result=`grep "|1RTT_transport_params|max_datagram_frame_size:9000|" clog` svr_result=`grep "|1RTT_transport_params|max_datagram_frame_size:9000|" slog` errlog=`grep_err_log` @@ -1738,7 +1803,7 @@ fi clear_log echo -e "0RTT max_datagram_frame_size is valid...\c" -./test_client -l d >> stdlog +${CLIENT_BIN} -l d >> stdlog cli_result=`grep "|0RTT_transport_params|max_datagram_frame_size:9000|" clog` cli_result2=`grep "|1RTT_transport_params|max_datagram_frame_size:9000|" clog` errlog=`grep_err_log` @@ -1751,11 +1816,11 @@ else fi killall test_server -./test_server -l d -Q 8000 > /dev/null & +${SERVER_BIN} -l d -Q 8000 > /dev/null & sleep 1 clear_log echo -e "0RTT max_datagram_frame_size is invalid...\c" -./test_client -l d >> stdlog +${CLIENT_BIN} -l d >> stdlog cli_result=`grep "|0RTT_transport_params|max_datagram_frame_size:9000|" clog` cli_err=`grep "[error].*err:0xe" clog` svr_err=`grep "[error].*err:0xe" slog` @@ -1778,11 +1843,11 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 1000 -x 200 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 1000 -x 200 > svr_stdlog & sleep 1 clear_log echo -e "datagram_get_mss(no_saved_transport_params)...\c" -./test_client -l d -T 1 -x 200 -Q 1000 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 1 -x 200 -Q 1000 -s 1 -U 1 > stdlog cli_res1=`grep "\[dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -1798,7 +1863,7 @@ fi > svr_stdlog clear_log echo -e "datagram_get_mss(saved_transport_params)...\c" -./test_client -l d -T 1 -x 200 -Q 1000 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 1 -x 200 -Q 1000 -s 1 -U 1 > stdlog cli_res1=`grep "\[dgram-200\]|.*|initial_mss:997|" stdlog` cli_res2=`grep "\[dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -1821,11 +1886,11 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 65535 -x 201 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 201 > svr_stdlog & sleep 1 clear_log echo -e "datagram_mss_limited_by_MTU...\c" -./test_client -l d -T 1 -x 201 -Q 65535 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 1 -x 201 -Q 65535 -s 1 -U 1 > stdlog cli_res1=`grep "\[dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[dgram-200\]|.*|updated_mss:1200|" stdlog` svr_res=`grep -a "\[dgram-200\]|.*|initial_mss:1200|" svr_stdlog` @@ -1850,11 +1915,11 @@ if [ -f xqc_token ]; then fi # timer-based dgram probe -stdbuf -oL ./test_server -l d -Q 65535 -x 209 -e -U 2 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 209 -e -U 2 > svr_stdlog & sleep 1 clear_log echo -e "timer_based_dgram_probe...\c" -./test_client -l d -T 1 -x 209 -s 1000 -U 1 -Q 65535 -x 209 > stdlog +${CLIENT_BIN} -l d -T 1 -x 209 -s 1000 -U 1 -Q 65535 -x 209 > stdlog killall test_server cli_res1=(`grep "|recv_dgram_bytes:" stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) svr_res=(`grep "|recv_dgram_bytes:" svr_stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) @@ -1878,11 +1943,11 @@ if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 1000 -x 200 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 1000 -x 200 > svr_stdlog & sleep 1 clear_log echo -e "datagram_mss_limited_by_max_datagram_frame_size...\c" -./test_client -l d -T 1 -x 200 -s 1 -U 1 -Q 1000 > stdlog +${CLIENT_BIN} -l d -T 1 -x 200 -s 1 -U 1 -Q 1000 > stdlog cli_res1=`grep "\[dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -1898,14 +1963,14 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log #generate 0rtt data -./test_client -l e -T 1 -s 1 -U 1 -Q 65535 > stdlog +${CLIENT_BIN} -l e -T 1 -s 1 -U 1 -Q 65535 > stdlog clear_log echo -e "send_0RTT_datagram_100KB...\c" -./test_client -l e -T 1 -s 102400 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l e -T 1 -s 102400 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1919,7 +1984,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_1MB...\c" - ./test_client -l e -T 1 -s 1048576 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 1048576 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1932,7 +1997,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_10MB...\c" - ./test_client -l e -T 1 -s 10485760 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 10485760 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1945,7 +2010,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_100MB...\c" - ./test_client -l e -T 1 -s 104857600 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 104857600 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1962,14 +2027,14 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 2 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 2 > /dev/null & sleep 1 clear_log #generate 0rtt data -./test_client -l e -T 1 -s 1 -U 2 -Q 65535 > stdlog +${CLIENT_BIN} -l e -T 1 -s 1 -U 2 -Q 65535 > stdlog clear_log echo -e "send_0RTT_datagram_100KB_batch...\c" -./test_client -l e -T 1 -s 102400 -U 2 -Q 65535 -E > stdlog +${CLIENT_BIN} -l e -T 1 -s 102400 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1983,7 +2048,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_1MB_batch...\c" - ./test_client -l e -T 1 -s 1048576 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 1048576 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -1996,7 +2061,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_10MB_batch...\c" - ./test_client -l e -T 1 -s 10485760 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 10485760 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2009,7 +2074,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_datagram_100MB_batch...\c" - ./test_client -l e -T 1 -s 104857600 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 1 -s 104857600 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2025,11 +2090,11 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "send_1RTT_datagram_100KB...\c" -./test_client -l e -T 1 -s 102400 -U 1 -Q 65535 -E -1 > stdlog +${CLIENT_BIN} -l e -T 1 -s 102400 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2043,7 +2108,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_1MB...\c" - ./test_client -l e -T 1 -s 1048576 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 1048576 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2056,7 +2121,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_10MB...\c" - ./test_client -l e -T 1 -s 10485760 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 10485760 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2069,7 +2134,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_100MB...\c" - ./test_client -l e -T 1 -s 104857600 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 104857600 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2084,11 +2149,11 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 2 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 2 > /dev/null & sleep 1 clear_log echo -e "send_1RTT_datagram_100KB_batch...\c" -./test_client -l e -T 1 -s 102400 -U 2 -Q 65535 -E -1 > stdlog +${CLIENT_BIN} -l e -T 1 -s 102400 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2102,7 +2167,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_1MB_batch...\c" - ./test_client -l e -T 1 -s 1048576 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 1048576 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2115,7 +2180,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_10MB_batch...\c" - ./test_client -l e -T 1 -s 10485760 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 10485760 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2128,7 +2193,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_datagram_100MB_batch...\c" - ./test_client -l e -T 1 -s 104857600 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 1 -s 104857600 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2142,11 +2207,11 @@ fi rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_queue_full...\c" -./test_client -l d -T 1 -s 40000000 -U 1 -Q 65535 -1 > stdlog +${CLIENT_BIN} -l d -T 1 -s 40000000 -U 1 -Q 65535 -1 > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|too many packets used|ctl_packets_used:" clog` cli_res3=`grep "\[dgram\]|dgram_write|" stdlog` @@ -2161,7 +2226,7 @@ fi clear_log echo -e "send_queue_full_batch...\c" -./test_client -l d -T 1 -s 40000000 -U 2 -Q 65535 -1 > stdlog +${CLIENT_BIN} -l d -T 1 -s 40000000 -U 2 -Q 65535 -1 > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|too many packets used|ctl_packets_used:" clog` cli_res3=`grep "\[dgram\]|dgram_write|" stdlog` @@ -2176,7 +2241,7 @@ fi clear_log echo -e "send_0rtt_datagram_without_saved_datagram_tp...\c" -./test_client -l d -T 1 -s 999 -U 1 -Q 65535 -1 -E -x 202 > stdlog +${CLIENT_BIN} -l d -T 1 -s 999 -U 1 -Q 65535 -1 -E -x 202 > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|waiting_for_max_datagram_frame_size_from_peer|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2192,7 +2257,7 @@ fi clear_log echo -e "send_0rtt_datagram_without_saved_datagram_tp_batch...\c" -./test_client -l d -T 1 -s 999 -U 2 -Q 65535 -1 -E -x 202 > stdlog +${CLIENT_BIN} -l d -T 1 -s 999 -U 2 -Q 65535 -1 -E -x 202 > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|waiting_for_max_datagram_frame_size_from_peer|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2209,7 +2274,7 @@ fi clear_log echo -e "send_too_many_0rtt_datagrams...\c" -./test_client -l d -T 1 -s 40000 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 1 -s 40000 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2225,7 +2290,7 @@ fi clear_log echo -e "send_too_many_0rtt_datagrams_batch...\c" -./test_client -l d -T 1 -s 40000 -U 2 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 1 -s 40000 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2240,11 +2305,11 @@ else fi killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_0rtt_datagram_reject...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "xqc_conn_early_data_reject" clog` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` @@ -2258,11 +2323,11 @@ fi killall test_server -./test_server -l d -Q 1000 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 1000 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_oversized_datagram...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E -1 -x 203 > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E -1 -x 203 > stdlog cli_res1=`grep "datagram_is_too_large" clog` cli_res2=`grep "trying_to_send_an_oversized_datagram" stdlog` errlog=`grep_err_log` @@ -2276,7 +2341,7 @@ fi clear_log echo -e "send_oversized_datagram_batch...\c" -./test_client -l d -T 1 -s 4800 -U 2 -Q 65535 -E -1 -x 203 > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 2 -Q 65535 -E -1 -x 203 > stdlog cli_res1=`grep "datagram_is_too_large" clog` cli_res2=`grep "trying_to_send_an_oversized_datagram" stdlog` cli_res3=`grep "|partially_sent_pkts_in_a_batch|cnt:1|" stdlog` @@ -2291,11 +2356,11 @@ fi rm -rf tp_localhost test_session xqc_token killall test_server -./test_server -l d -Q 0 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 0 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_datagram_while_peer_does_not_support...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E -1 -x 204 > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E -1 -x 204 > stdlog cli_res1=`grep "|does not support datagram|" clog` cli_res2=`grep "\[dgram\]|send_datagram_error|" stdlog` errlog=`grep_err_log` @@ -2309,7 +2374,7 @@ fi clear_log echo -e "send_datagram_batch_while_peer_does_not_support...\c" -./test_client -l d -T 1 -s 4800 -U 2 -Q 65535 -E -1 -x 204 > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 2 -Q 65535 -E -1 -x 204 > stdlog cli_res1=`grep "|does not support datagram|" clog` cli_res2=`grep "\[dgram\]|send_datagram_multiple_error|" stdlog` errlog=`grep_err_log` @@ -2322,12 +2387,12 @@ else fi killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 -./test_client -l d -T 1 -s 1 -U 1 -Q 65535 -E -N > stdlog +${CLIENT_BIN} -l d -T 1 -s 1 -U 1 -Q 65535 -E -N > stdlog clear_log echo -e "send_0rtt_datagram_dgram1_lost...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E -x 205 -N > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E -x 205 -N > stdlog cli_res1=`grep "\[dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2340,7 +2405,7 @@ fi clear_log echo -e "send_1rtt_datagram_dgram1_lost...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog cli_res1=`grep "\[dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2353,7 +2418,7 @@ fi clear_log echo -e "send_0rtt_datagram_reorder...\c" -./test_client -l d -T 1 -s 1800 -U 1 -Q 65535 -E -x 206 -N > stdlog +${CLIENT_BIN} -l d -T 1 -s 1800 -U 1 -Q 65535 -E -x 206 -N > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2366,7 +2431,7 @@ fi clear_log echo -e "send_1rtt_datagram_reorder...\c" -./test_client -l d -T 1 -s 1800 -U 1 -Q 65535 -E -x 206 -N -1 > stdlog +${CLIENT_BIN} -l d -T 1 -s 1800 -U 1 -Q 65535 -E -x 206 -N -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2379,7 +2444,7 @@ fi clear_log echo -e "datagram_lost_callback...\c" -./test_client -l d -T 1 -s 1000 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog +${CLIENT_BIN} -l d -T 1 -s 1000 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog cli_res1=`grep "\[dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2392,7 +2457,7 @@ fi clear_log echo -e "datagram_acked_callback...\c" -./test_client -l d -T 1 -s 1000 -U 1 -Q 65535 -E -x 207 > stdlog +${CLIENT_BIN} -l d -T 1 -s 1000 -U 1 -Q 65535 -E -x 207 > stdlog cli_res1=`grep "\[dgram\]|dgram_acked|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2413,12 +2478,12 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 65535 -x 208 -e -U 1 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 208 -e -U 1 > svr_stdlog & sleep 1 clear_log echo -e "1RTT_datagram_send_redundancy...\c" -./test_client -l d -T 1 -s 2000 -U 1 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 1 -s 2000 -U 1 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2435,7 +2500,7 @@ fi clear_log echo -e "1RTT_datagram_send_multiple_redundancy...\c" -./test_client -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2449,7 +2514,7 @@ fi clear_log echo -e "0RTT_datagram_send_redundancy...\c" -./test_client -l d -T 1 -s 2000 -U 1 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 1 -s 2000 -U 1 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2462,7 +2527,7 @@ fi clear_log echo -e "0RTT_datagram_send_multiple_redundancy...\c" -./test_client -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2473,15 +2538,34 @@ else case_print_result "0RTT_datagram_send_multiple_redundancy" "fail" fi +killall test_server +rm -rf tp_localhost test_session xqc_token +clear_log +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 208 -e -U 1 > svr_stdlog & +sleep 1 + +echo -e "stop_datagram_send_redundancy_after_negotiation...\c" +${CLIENT_BIN} -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 --close_dg_red 1 > stdlog +cli_res=`grep "|stop sending datagram redundancy." clog` +svr_res=`grep "|stop sending datagram redundancy." slog` +errlog=`grep_err_log` +if [ -n "$cli_res" ] && [ -n "$svr_res" ] && [ -z "$errlog" ]; then + echo ">>>>>>>> pass:1" + case_print_result "stop_datagram_send_redundancy_after_negotiation" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "stop_datagram_send_redundancy_after_negotiation" "fail" +fi + killall test_server -./test_server -l d -e -x 208 -Q 65535 -U 1 --dgram_qos 3 > /dev/null & +${SERVER_BIN} -l d -e -x 208 -Q 65535 -U 1 --dgram_qos 3 > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "No reinjection for normal datagrams...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 --dgram_qos 3 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 --dgram_qos 3 > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:0" clog` errlog=`grep_err_log` @@ -2497,7 +2581,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "No reinjection for normal h3-ext datagrams...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 --dgram_qos 3 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 --dgram_qos 3 > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:0" clog` errlog=`grep_err_log` @@ -2523,11 +2607,11 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 1000 -x 200 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 1000 -x 200 > svr_stdlog & sleep 1 clear_log echo -e "h3_ext_datagram_get_mss(no_saved_transport_params)...\c" -./test_client -l d -T 2 -x 200 -Q 1000 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 2 -x 200 -Q 1000 -s 1 -U 1 > stdlog cli_res1=`grep "\[h3-dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[h3-dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[h3-dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -2543,7 +2627,7 @@ fi > svr_stdlog clear_log echo -e "h3_ext_datagram_get_mss(saved_transport_params)...\c" -./test_client -l d -T 2 -x 200 -Q 1000 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 2 -x 200 -Q 1000 -s 1 -U 1 > stdlog cli_res1=`grep "\[h3-dgram-200\]|.*|initial_mss:997|" stdlog` cli_res2=`grep "\[h3-dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[h3-dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -2566,11 +2650,11 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 65535 -x 201 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 201 > svr_stdlog & sleep 1 clear_log echo -e "h3_ext_datagram_mss_limited_by_MTU...\c" -./test_client -l d -T 2 -x 201 -Q 65535 -s 1 -U 1 > stdlog +${CLIENT_BIN} -l d -T 2 -x 201 -Q 65535 -s 1 -U 1 > stdlog cli_res1=`grep "\[h3-dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[h3-dgram-200\]|.*|updated_mss:1200|" stdlog` svr_res=`grep -a "\[h3-dgram-200\]|.*|initial_mss:1200|" svr_stdlog` @@ -2593,11 +2677,11 @@ fi if [ -f xqc_token ]; then rm -f xqc_token fi -stdbuf -oL ./test_server -l d -Q 1000 -x 200 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -Q 1000 -x 200 > svr_stdlog & sleep 1 clear_log echo -e "h3_ext_datagram_mss_limited_by_max_datagram_frame_size...\c" -./test_client -l d -T 2 -x 200 -s 1 -U 1 -Q 1000 > stdlog +${CLIENT_BIN} -l d -T 2 -x 200 -s 1 -U 1 -Q 1000 > stdlog cli_res1=`grep "\[h3-dgram-200\]|.*|initial_mss:0|" stdlog` cli_res2=`grep "\[h3-dgram-200\]|.*|updated_mss:997|" stdlog` svr_res=`grep -a "\[h3-dgram-200\]|.*|initial_mss:997|" svr_stdlog` @@ -2613,14 +2697,14 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log #generate 0rtt data -./test_client -l e -T 2 -s 1 -U 1 -Q 65535 > stdlog +${CLIENT_BIN} -l e -T 2 -s 1 -U 1 -Q 65535 > stdlog clear_log echo -e "send_0RTT_h3_ext_datagram_100KB...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2634,7 +2718,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_1MB...\c" - ./test_client -l e -T 2 -s 1048576 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 1048576 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2647,7 +2731,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_10MB...\c" - ./test_client -l e -T 2 -s 10485760 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 10485760 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2660,7 +2744,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_100MB...\c" - ./test_client -l e -T 2 -s 104857600 -U 1 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 104857600 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2677,14 +2761,14 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 2 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 2 > /dev/null & sleep 1 clear_log #generate 0rtt data -./test_client -l e -T 2 -s 1 -U 2 -Q 65535 > stdlog +${CLIENT_BIN} -l e -T 2 -s 1 -U 2 -Q 65535 > stdlog clear_log echo -e "send_0RTT_h3_ext_datagram_100KB_batch...\c" -./test_client -l e -T 2 -s 102400 -U 2 -Q 65535 -E > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2698,7 +2782,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_1MB_batch...\c" - ./test_client -l e -T 2 -s 1048576 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 1048576 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2711,7 +2795,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_10MB_batch...\c" - ./test_client -l e -T 2 -s 10485760 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 10485760 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2724,7 +2808,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_0RTT_h3_ext_datagram_100MB_batch...\c" - ./test_client -l e -T 2 -s 104857600 -U 2 -Q 65535 -E > stdlog + ${CLIENT_BIN} -l e -T 2 -s 104857600 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2740,11 +2824,11 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "send_1RTT_h3_ext_datagram_100KB...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2758,7 +2842,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_1MB...\c" - ./test_client -l e -T 2 -s 1048576 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 1048576 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2771,7 +2855,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_10MB...\c" - ./test_client -l e -T 2 -s 10485760 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 10485760 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2784,7 +2868,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_100MB...\c" - ./test_client -l e -T 2 -s 104857600 -U 1 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 104857600 -U 1 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2799,11 +2883,11 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 2 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 2 > /dev/null & sleep 1 clear_log echo -e "send_1RTT_h3_ext_datagram_100KB_batch...\c" -./test_client -l e -T 2 -s 102400 -U 2 -Q 65535 -E -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2817,7 +2901,7 @@ fi if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_1MB_batch...\c" - ./test_client -l e -T 2 -s 1048576 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 1048576 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2830,7 +2914,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_10MB_batch...\c" - ./test_client -l e -T 2 -s 10485760 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 10485760 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2843,7 +2927,7 @@ if [ $LOCAL_TEST -ne 0 ]; then clear_log echo -e "send_1RTT_h3_ext_datagram_100MB_batch...\c" - ./test_client -l e -T 2 -s 104857600 -U 2 -Q 65535 -E -1 > stdlog + ${CLIENT_BIN} -l e -T 2 -s 104857600 -U 2 -Q 65535 -E -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -2857,11 +2941,11 @@ fi rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext_dgram_send_queue_full...\c" -./test_client -l d -T 2 -s 40000000 -U 1 -Q 65535 -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 40000000 -U 1 -Q 65535 -1 > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|too many packets used|ctl_packets_used:" clog` cli_res3=`grep "\[h3-dgram\]|dgram_write|" stdlog` @@ -2876,7 +2960,7 @@ fi clear_log echo -e "h3_ext_dgram_send_queue_full_batch...\c" -./test_client -l d -T 2 -s 40000000 -U 2 -Q 65535 -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 40000000 -U 2 -Q 65535 -1 > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|too many packets used|ctl_packets_used:" clog` cli_res3=`grep "\[h3-dgram\]|dgram_write|" stdlog` @@ -2891,7 +2975,7 @@ fi clear_log echo -e "send_0rtt_h3_ext_datagram_without_saved_datagram_tp...\c" -./test_client -l d -T 2 -s 999 -U 1 -Q 65535 -1 -E -x 202 > stdlog +${CLIENT_BIN} -l d -T 2 -s 999 -U 1 -Q 65535 -1 -E -x 202 > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|waiting_for_max_datagram_frame_size_from_peer|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2907,7 +2991,7 @@ fi clear_log echo -e "send_0rtt_h3_ext_datagram_without_saved_datagram_tp_batch...\c" -./test_client -l d -T 2 -s 999 -U 2 -Q 65535 -1 -E -x 202 > stdlog +${CLIENT_BIN} -l d -T 2 -s 999 -U 2 -Q 65535 -1 -E -x 202 > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|waiting_for_max_datagram_frame_size_from_peer|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2924,7 +3008,7 @@ fi clear_log echo -e "send_too_many_0rtt_h3_ext_datagrams...\c" -./test_client -l d -T 2 -s 40000 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 2 -s 40000 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_later|" stdlog` cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2940,7 +3024,7 @@ fi clear_log echo -e "send_too_many_0rtt_h3_ext_datagrams_batch...\c" -./test_client -l d -T 2 -s 40000 -U 2 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 2 -s 40000 -U 2 -Q 65535 -E > stdlog cli_res1=`grep "\[h3-dgram\]|retry_datagram_send_multiple_later|" stdlog` cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` @@ -2955,11 +3039,11 @@ else fi killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_0rtt_h3_ext_datagram_reject...\c" -./test_client -l d -T 2 -s 4800 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 1 -Q 65535 -E > stdlog cli_res1=`grep "xqc_conn_early_data_reject" clog` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` @@ -2973,11 +3057,11 @@ fi killall test_server -./test_server -l d -Q 1000 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 1000 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_oversized_h3_ext_datagram...\c" -./test_client -l d -T 2 -s 4800 -U 1 -Q 65535 -E -1 -x 203 > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 1 -Q 65535 -E -1 -x 203 > stdlog cli_res1=`grep "datagram_is_too_large" clog` cli_res2=`grep "trying_to_send_an_oversized_datagram" stdlog` #errlog=`grep_err_log` @@ -2991,7 +3075,7 @@ fi clear_log echo -e "send_oversized_h3_ext_datagram_batch...\c" -./test_client -l d -T 2 -s 4800 -U 2 -Q 65535 -E -1 -x 203 > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 2 -Q 65535 -E -1 -x 203 > stdlog cli_res1=`grep "datagram_is_too_large" clog` cli_res2=`grep "trying_to_send_an_oversized_datagram" stdlog` cli_res3=`grep "|partially_sent_pkts_in_a_batch|cnt:1|" stdlog` @@ -3006,11 +3090,11 @@ fi rm -rf tp_localhost test_session xqc_token killall test_server -./test_server -l d -Q 0 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 0 -e -U 1 -s 1 > /dev/null & sleep 1 clear_log echo -e "send_h3_ext_datagram_while_peer_does_not_support...\c" -./test_client -l d -T 2 -s 4800 -U 1 -Q 65535 -E -1 -x 204 > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 1 -Q 65535 -E -1 -x 204 > stdlog cli_res1=`grep "|does not support datagram|" clog` cli_res2=`grep "\[h3-dgram\]|send_datagram_error|" stdlog` #errlog=`grep_err_log` @@ -3024,7 +3108,7 @@ fi clear_log echo -e "send_h3_ext_datagram_batch_while_peer_does_not_support...\c" -./test_client -l d -T 2 -s 4800 -U 2 -Q 65535 -E -1 -x 204 > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 2 -Q 65535 -E -1 -x 204 > stdlog cli_res1=`grep "|does not support datagram|" clog` cli_res2=`grep "\[h3-dgram\]|send_datagram_multiple_error|" stdlog` #errlog=`grep_err_log` @@ -3037,12 +3121,12 @@ else fi killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 -./test_client -l d -T 2 -s 1 -U 1 -Q 65535 -E -N > stdlog +${CLIENT_BIN} -l d -T 2 -s 1 -U 1 -Q 65535 -E -N > stdlog clear_log echo -e "send_0rtt_h3_ext_datagram_dgram1_lost...\c" -./test_client -l d -T 2 -s 4800 -U 1 -Q 65535 -E -x 205 -N > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 1 -Q 65535 -E -x 205 -N > stdlog cli_res1=`grep "\[h3-dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3055,7 +3139,7 @@ fi clear_log echo -e "send_1rtt_h3_ext_datagram_dgram1_lost...\c" -./test_client -l d -T 2 -s 4800 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 4800 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog cli_res1=`grep "\[h3-dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3068,7 +3152,7 @@ fi clear_log echo -e "send_0rtt_h3_ext_datagram_reorder...\c" -./test_client -l d -T 2 -s 1800 -U 1 -Q 65535 -E -x 206 -N > stdlog +${CLIENT_BIN} -l d -T 2 -s 1800 -U 1 -Q 65535 -E -x 206 -N > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3081,7 +3165,7 @@ fi clear_log echo -e "send_1rtt_h3_ext_datagram_reorder...\c" -./test_client -l d -T 2 -s 1800 -U 1 -Q 65535 -E -x 206 -N -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 1800 -U 1 -Q 65535 -E -x 206 -N -1 > stdlog cli_res1=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3094,7 +3178,7 @@ fi clear_log echo -e "h3_ext_datagram_lost_callback...\c" -./test_client -l d -T 2 -s 1000 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 1000 -U 1 -Q 65535 -E -x 205 -N -1 > stdlog cli_res1=`grep "\[h3-dgram\]|dgram_lost|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3107,7 +3191,7 @@ fi clear_log echo -e "h3_ext_datagram_acked_callback...\c" -./test_client -l d -T 2 -s 1000 -U 1 -Q 65535 -E -x 207 > stdlog +${CLIENT_BIN} -l d -T 2 -s 1000 -U 1 -Q 65535 -E -x 207 > stdlog cli_res1=`grep "\[h3-dgram\]|dgram_acked|dgram_id:0|" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3122,12 +3206,12 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 -x 208 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 -x 208 > /dev/null & sleep 1 clear_log echo -e "1RTT_h3_ext_datagram_send_redundancy...\c" -./test_client -l d -T 2 -s 2000 -U 1 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 2 -s 2000 -U 1 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[h3-dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3142,7 +3226,7 @@ rm -f test_session tp_localhost xqc_token clear_log echo -e "1RTT_h3_ext_datagram_send_multiple_redundancy...\c" -./test_client -l d -T 2 -s 2000 -U 2 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 2 -s 2000 -U 2 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[h3-dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3155,7 +3239,7 @@ fi clear_log echo -e "0RTT_h3_ext_datagram_send_redundancy...\c" -./test_client -l d -T 2 -s 2000 -U 1 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 2 -s 2000 -U 1 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[h3-dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3168,7 +3252,7 @@ fi clear_log echo -e "0RTT_h3_ext_datagram_send_multiple_redundancy...\c" -./test_client -l d -T 2 -s 2000 -U 2 -Q 65535 -x 208 > stdlog +${CLIENT_BIN} -l d -T 2 -s 2000 -U 2 -Q 65535 -x 208 > stdlog cli_res1=`grep "\[h3-dgram\]|recv_dgram_bytes:8000" stdlog` errlog=`grep_err_log` if [ -n "$cli_res1" ] && [ -z "$errlog" ]; then @@ -3186,14 +3270,14 @@ rm -f test_session tp_localhost xqc_token killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 ## 1RTT clear_log echo -e "h3_ext_1RTT_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 -1 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3212,7 +3296,7 @@ fi ## 0RTT clear_log echo -e "h3_ext_0RTT_accept_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3232,12 +3316,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext_0RTT_reject_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 300 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3258,7 +3342,7 @@ fi ## 1RTT clear_log echo -e "h3_ext_1RTT_concurrent_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 -1 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3278,7 +3362,7 @@ fi ## 0RTT clear_log echo -e "h3_ext_0RTT_accept_concurrent_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3299,12 +3383,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext_0RTT_reject_concurrent_send_test...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 301 -P 2 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3328,7 +3412,7 @@ fi clear_log echo -e "h3_ext_1RTT_send_pure_fin1...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 -1 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3347,7 +3431,7 @@ fi clear_log echo -e "h3_ext_1RTT_send_pure_fin2...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 -1 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 -1 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3368,7 +3452,7 @@ fi clear_log echo -e "h3_ext_0RTT_accept_send_pure_fin1...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3387,7 +3471,7 @@ fi clear_log echo -e "h3_ext_0RTT_accept_send_pure_fin2...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3408,12 +3492,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext_0RTT_reject_send_pure_fin1...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 302 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3432,12 +3516,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext_0RTT_reject_send_pure_fin2...\c" -./test_client -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 > stdlog +${CLIENT_BIN} -l e -T 2 -s 102400 -U 1 -Q 65535 -E -x 303 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` cli_res3=`grep "\[h3-dgram\]|recv_dgram_bytes:102400|sent_dgram_bytes:102400|lost_dgram_bytes:0|lost_cnt:0|" stdlog` @@ -3458,41 +3542,33 @@ fi clear_log echo -e "h3_ext_finish_bytestream_during_transmission...\c" -./test_client -l d -T 2 -s 102400 -U 1 -Q 65535 -E -x 304 > stdlog +${CLIENT_BIN} -l d -T 2 -s 102400 -U 1 -Q 65535 -E -x 304 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` -cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` -cli_res3=(`grep "\[h3-dgram\]|recv_dgram_bytes:" stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) cli_res4=(`grep "\[bytestream\]|bytes_sent:" stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) cli_res5=`grep "\[bytestream\]|same_content:yes|" stdlog | wc -l` cli_res6=`grep "send pure fin" clog` errlog=`grep_err_log | grep -v "send data after fin sent"` -if [ "$cli_res1" == "1" ] && [ -n "$cli_res2" ] \ - && [ ${cli_res3[0]} -ge 102400 ] && [ ${cli_res3[1]} -ge 102400 ] \ - && [ ${cli_res4[0]} -ge 102400 ] && [ ${cli_res4[1]} -ge 102400 ] \ +if [ "$cli_res1" == "1" ] \ + && [ ${cli_res4[0]} -eq 102400 ] && [ ${cli_res4[1]} -eq 102400 ] \ && [ "$cli_res5" == "1" ] && [ -n "$cli_res6" ] && [ -z "$errlog" ]; then echo ">>>>>>>> pass:1" case_print_result "h3_ext_finish_bytestream_during_transmission" "pass" else echo ">>>>>>>> pass:0" case_print_result "h3_ext_finish_bytestream_during_transmission" "fail" - exit fi # close bytestream during transmission (-x 305) clear_log echo -e "h3_ext_close_bytestream_during_transmission...\c" -./test_client -l d -T 2 -s 102400 -U 1 -Q 65535 -E -x 305 > stdlog +${CLIENT_BIN} -l d -T 2 -s 102400 -U 1 -Q 65535 -E -x 305 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` -cli_res2=`grep "\[dgram\]|echo_check|same_content:yes|" stdlog` -cli_res3=(`grep "\[h3-dgram\]|recv_dgram_bytes:" stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) cli_res4=(`grep "\[bytestream\]|bytes_sent:" stdlog | egrep -o ':[0-9]+' | egrep -o '[0-9]+'`) cli_res5=`grep "\[bytestream\]|same_content:.*|" stdlog | wc -l` cli_res6=`grep "xqc_h3_ext_bytestream_close|success" clog` errlog=`grep_err_log | grep -v "xqc_h3_stream_process_data|xqc_stream_recv"` -if [ "$cli_res1" == "1" ] && [ -n "$cli_res2" ] \ - && [ ${cli_res3[0]} -ge 102400 ] && [ ${cli_res3[1]} -ge 102400 ] \ - && [ ${cli_res4[0]} -ge 102400 ] \ +if [ "$cli_res1" == "1" ] && [ ${cli_res4[0]} -ge 102400 ] \ && [ "$cli_res5" == "1" ] && [ -n "$cli_res6" ] && [ -z "$errlog" ]; then echo ">>>>>>>> pass:1" case_print_result "h3_ext_close_bytestream_during_transmission" "pass" @@ -3505,7 +3581,7 @@ fi clear_log echo -e "h3_ext_bytestream_blocked_by_stream_flowctl...\c" -./test_client -l d -T 2 -s 32000000 -U 1 -Q 65535 -E -x 306 > stdlog +${CLIENT_BIN} -l d -T 2 -s 32000000 -U 1 -Q 65535 -E -x 306 > stdlog cli_res2=`grep "|xqc_stream_send|exceed max_stream_data" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:32000000|bytes_rcvd:32000000|recv_fin:1|" stdlog` @@ -3523,7 +3599,7 @@ fi clear_log echo -e "h3_ext_bytestream_blocked_by_0RTT_limit...\c" -./test_client -l d -T 2 -s 10000000 -U 1 -Q 65535 -E -x 307 > stdlog +${CLIENT_BIN} -l d -T 2 -s 10000000 -U 1 -Q 65535 -E -x 307 > stdlog cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:10000000|bytes_rcvd:10000000|recv_fin:1|" stdlog` @@ -3541,7 +3617,7 @@ fi clear_log echo -e "h3_ext_bytestream_blocked_by_no_0RTT_support...\c" -./test_client -l d -T 2 -s 1024 -U 1 -Q 65535 -E -x 308 -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 1024 -U 1 -Q 65535 -E -x 308 -1 > stdlog cli_res2=`grep "|blocked by no 0RTT support|" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:1024|bytes_rcvd:1024|recv_fin:1|" stdlog` @@ -3559,7 +3635,7 @@ fi clear_log echo -e "h3_ext_bytestream_blocked_by_sndq_full...\c" -./test_client -l e -T 2 -s 16000000 -U 1 -Q 65535 -E -x 309 > stdlog +${CLIENT_BIN} -l e -T 2 -s 16000000 -U 1 -Q 65535 -E -x 309 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:.*|" stdlog` cli_res4=`grep "\[bytestream\]|bytes_sent:16000000|bytes_rcvd:16000000|recv_fin:1|" stdlog` @@ -3578,7 +3654,7 @@ fi clear_log echo -e "h3_ext_bytestream_full_message_flow_ctrl...\c" -./test_client -l d -T 2 -s 32000000 -U 1 -Q 65535 -E -x 311 > stdlog +${CLIENT_BIN} -l d -T 2 -s 32000000 -U 1 -Q 65535 -E -x 311 > stdlog cli_res2=`grep "|xqc_stream_send|exceed max_stream_data" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:32001000|bytes_rcvd:32001000|recv_fin:1|snd_times:2|rcv_times:2|" stdlog` @@ -3594,7 +3670,7 @@ fi clear_log echo -e "h3_ext_bytestream_full_message_0RTT_blocking...\c" -./test_client -l d -T 2 -s 10000000 -U 1 -Q 65535 -E -x 312 > stdlog +${CLIENT_BIN} -l d -T 2 -s 10000000 -U 1 -Q 65535 -E -x 312 > stdlog cli_res2=`grep "|too many 0rtt packets|" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:10001000|bytes_rcvd:10001000|recv_fin:1|snd_times:2|rcv_times:2|" stdlog` @@ -3610,7 +3686,7 @@ fi clear_log echo -e "h3_ext_bytestream_full_message_no_0RTT_suppport...\c" -./test_client -l d -T 2 -s 1024 -U 1 -Q 65535 -E -x 313 -1 > stdlog +${CLIENT_BIN} -l d -T 2 -s 1024 -U 1 -Q 65535 -E -x 313 -1 > stdlog cli_res2=`grep "|blocked by no 0RTT support|" clog` cli_res3=`grep "|h3_ext_bytestream_write_notify|success|" clog` cli_res4=`grep "\[bytestream\]|bytes_sent:2024|bytes_rcvd:2024|recv_fin:1|snd_times:2|rcv_times:2|" stdlog` @@ -3626,7 +3702,7 @@ fi clear_log echo -e "h3_ext_bytestream_full_message_sndq_full...\c" -./test_client -l e -T 2 -s 16000000 -U 1 -Q 65535 -E -x 314 > stdlog +${CLIENT_BIN} -l e -T 2 -s 16000000 -U 1 -Q 65535 -E -x 314 > stdlog cli_res1=`grep ">>>>>>>> pass:1" stdlog | wc -l` cli_res2=`grep "\[dgram\]|echo_check|same_content:.*|" stdlog` cli_res4=`grep "\[bytestream\]|bytes_sent:16001000|bytes_rcvd:16001000|recv_fin:1|snd_times:2|rcv_times:2|" stdlog` @@ -3643,12 +3719,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 -H > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 -H > /dev/null & sleep 1 clear_log echo -e "connect to an h3_ext disabled server...\c" -./test_client -l e -T 2 -s 1024 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l e -T 2 -s 1024 -U 1 -Q 65535 -E > stdlog svr_log=`grep "select proto error" slog` if [ -n "$svr_log" ]; then @@ -3661,12 +3737,12 @@ fi killall test_server -./test_server -l e -Q 65535 -e -U 1 > /dev/null & +${SERVER_BIN} -l e -Q 65535 -e -U 1 > /dev/null & sleep 1 clear_log echo -e "h3_ext is disabled on the client...\c" -./test_client -l e -T 2 -s 1024 -U 1 -Q 65535 -E -x 315 > stdlog +${CLIENT_BIN} -l e -T 2 -s 1024 -U 1 -Q 65535 -E -x 315 > stdlog cli_res1=`grep "can't get application layer callback" clog` if [ -n "$cli_res1" ]; then @@ -3681,15 +3757,15 @@ rm -rf tp_localhost test_session xqc_token killall test_server -./test_server -l d -Q 65535 -e -U 1 -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 > /dev/null & sleep 1 -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E &> /dev/null #generate 0rtt ticket +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E &> /dev/null #generate 0rtt ticket killall test_server -./test_server -l d -e -s 1 > /dev/null & #disable datagram +${SERVER_BIN} -l d -e -s 1 > /dev/null & #disable datagram sleep 1 clear_log echo -e "check_clear_0rtt_ticket_flag_in_close_notify...\c" -./test_client -l d -T 1 -s 4800 -U 1 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -T 1 -s 4800 -U 1 -Q 65535 -E > stdlog cli_res2=`grep "should_clear_0rtt_ticket, conn_err:14, clear_0rtt_ticket:1" stdlog` errlog=`grep_err_log` if [ -n "$cli_res2" ] && [ -n "$errlog" ]; then @@ -3703,15 +3779,15 @@ fi rm -rf tp_localhost test_session xqc_token killall test_server -./test_server -l d -Q 65535 -e -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -s 1 > /dev/null & sleep 1 -./test_client -l d -s 4800 -Q 65535 -E &> /dev/null #generate 0rtt ticket +${CLIENT_BIN} -l d -s 4800 -Q 65535 -E &> /dev/null #generate 0rtt ticket killall test_server -./test_server -l d -e -s 1 > /dev/null & #disable datagram +${SERVER_BIN} -l d -e -s 1 > /dev/null & #disable datagram sleep 1 clear_log echo -e "check_clear_0rtt_ticket_flag_in_h3_close_notify...\c" -./test_client -l d -s 4800 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -s 4800 -Q 65535 -E > stdlog cli_res2=`grep "should_clear_0rtt_ticket, conn_err:14, clear_0rtt_ticket:1" stdlog` errlog=`grep_err_log` if [ -n "$cli_res2" ] && [ -n "$errlog" ]; then @@ -3725,15 +3801,15 @@ fi rm -rf tp_localhost test_session xqc_token killall test_server -./test_server -l d -Q 65535 -e -s 1 > /dev/null & +${SERVER_BIN} -l d -Q 65535 -e -s 1 > /dev/null & sleep 1 -./test_client -l d -s 4800 -Q 65535 -E &> /dev/null #generate 0rtt ticket +${CLIENT_BIN} -l d -s 4800 -Q 65535 -E &> /dev/null #generate 0rtt ticket killall test_server -./test_server -l d -e -s 1 > /dev/null & #disable datagram +${SERVER_BIN} -l d -e -s 1 > /dev/null & #disable datagram sleep 1 clear_log echo -e "check_clear_0rtt_ticket_flag_in_h3_close_notify...\c" -./test_client -l d -s 4800 -Q 65535 -E > stdlog +${CLIENT_BIN} -l d -s 4800 -Q 65535 -E > stdlog cli_res2=`grep "should_clear_0rtt_ticket, conn_err:14, clear_0rtt_ticket:1" stdlog` errlog=`grep_err_log` if [ -n "$cli_res2" ] && [ -n "$errlog" ]; then @@ -3749,9 +3825,9 @@ killall test_server clear_log echo -e "request_closing_notify...\c" -./test_server -l d -x 14 > /dev/null & +${SERVER_BIN} -l d -x 14 > /dev/null & sleep 1 -./test_client -l d >> stdlog +${CLIENT_BIN} -l d >> stdlog res=`grep "request closing notify triggered" stdlog` if [ -n "$res" ]; then echo ">>>>>>>> pass:1" @@ -3763,13 +3839,13 @@ fi killall test_server -./test_server -l d -e -M -R 3 -Q 65535 -U 1 > /dev/null & +${SERVER_BIN} -l d -e -M -R 3 -Q 65535 -U 1 > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "SP reinject datagrams ...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 1 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 1 > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:0" clog` errlog=`grep_err_log` @@ -3785,7 +3861,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "SP reinject h3-ext datagrams ...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 2 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 2 > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:0" clog` errlog=`grep_err_log` @@ -3802,7 +3878,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP reinject datagrams ...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 1 -M -i lo -i lo > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3818,7 +3894,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP reinject h3-ext datagrams ...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 2 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -R 3 -Q 65535 -U 1 -T 2 -M -i lo -i lo > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3833,14 +3909,14 @@ grep_err_log killall test_server -./test_server -l d -e -M -x 208 -Q 65535 -U 1 > /dev/null & +${SERVER_BIN} -l d -e -M -x 208 -Q 65535 -U 1 > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP datagrams redundancy...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 -M -i lo -i lo > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3856,7 +3932,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP h3-ext datagrams redundancy...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 -M -i lo -i lo > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:4096|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3871,14 +3947,14 @@ grep_err_log killall test_server -./test_server -l d -e -M -x 208 -Q 65535 -U 1 --dgram_qos 3 > /dev/null & +${SERVER_BIN} -l d -e -M -x 208 -Q 65535 -U 1 --dgram_qos 3 > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP no reinjection for normal datagrams...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 -M -i lo -i lo --dgram_qos 3 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 1 -M -i lo -i lo --dgram_qos 3 > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3894,7 +3970,7 @@ grep_err_log rm -rf tp_localhost test_session xqc_token clear_log echo -e "MP no reinjection for normal h3-ext datagrams...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 -M -i lo -i lo --dgram_qos 3 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 208 -Q 65535 -U 1 -T 2 -M -i lo -i lo --dgram_qos 3 > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` cli_res=`grep -E "xqc_conn_destroy.*mp_enable:1" clog` errlog=`grep_err_log` @@ -3909,14 +3985,14 @@ grep_err_log killall test_server -stdbuf -oL ./test_server -l d -e -M -Q 65535 -U 1 --pmtud 1 -x 200 > svr_stdlog & +stdbuf -oL ${SERVER_BIN} -l d -e -M -Q 65535 -U 1 --pmtud 1 -x 200 > svr_stdlog & sleep 1 rm -rf tp_localhost test_session xqc_token > svr_stdlog clear_log echo -e "SP datagram PMTUD 1RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[dgram\]|mss_callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -3934,7 +4010,7 @@ grep_err_log > svr_stdlog clear_log echo -e "SP datagram PMTUD 0RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[dgram\]|mss_callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -3953,7 +4029,7 @@ rm -rf tp_localhost test_session xqc_token > svr_stdlog clear_log echo -e "SP h3-ext datagram PMTUD 1RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[h3-dgram\]|callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[h3-dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -3971,7 +4047,7 @@ grep_err_log > svr_stdlog clear_log echo -e "SP h3-ext datagram PMTUD 0RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[h3-dgram\]|callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[h3-dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -3991,7 +4067,7 @@ rm -rf tp_localhost test_session xqc_token > svr_stdlog clear_log echo -e "MP datagram PMTUD 1RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 -M -i lo -i lo > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[dgram\]|mss_callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -4009,7 +4085,7 @@ grep_err_log > svr_stdlog clear_log echo -e "MP datagram PMTUD 0RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 1 --pmtud 1 -M -i lo -i lo > stdlog result=`grep "\[dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[dgram\]|mss_callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -4028,7 +4104,7 @@ rm -rf tp_localhost test_session xqc_token > svr_stdlog clear_log echo -e "MP h3-ext datagram PMTUD 1RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 -M -i lo -i lo > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[h3-dgram\]|callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[h3-dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -4046,7 +4122,7 @@ grep_err_log > svr_stdlog clear_log echo -e "MP h3-ext datagram PMTUD 0RTT...\c" -sudo ./test_client -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 -M -i lo -i lo > stdlog +sudo ${CLIENT_BIN} -s 1024 -l d -t 1 -E -Q 65535 -U 1 -T 2 --pmtud 1 -M -i lo -i lo > stdlog result=`grep "\[h3-dgram\]|recv_dgram_bytes:1024|sent_dgram_bytes:1024|" stdlog` mtu_res1=`grep "\[h3-dgram\]|callback|updated_mss:1404|" stdlog` mtu_res2=`grep -a "\[h3-dgram\]|1RTT|updated_mss:1404|" svr_stdlog` @@ -4063,13 +4139,13 @@ grep_err_log killall test_server -stdbuf -oL ./test_server -l d -e -M > /dev/null & +stdbuf -oL ${SERVER_BIN} -l d -e -M > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "transport MP ping ...\c" -sudo ./test_client -s 1024 -l d -E -T 1 -e 1 --epoch_timeout 2000000 -t 3 --mp_ping 1 -M -i lo -i lo >> clog +sudo ${CLIENT_BIN} -s 1024 -l d -E -T 1 -e 1 --epoch_timeout 2000000 -t 3 --mp_ping 1 -M -i lo -i lo >> clog ret_ping_id=`grep "====>ping_id:" clog` ret_no_ping_id=`grep "====>no ping_id" clog` path0_ping=`grep -E "xqc_send_packet_with_pn.*path:0.*PING" clog` @@ -4086,7 +4162,7 @@ fi rm -rf tp_localhost test_session xqc_token clear_log echo -e "h3 MP ping ...\c" -sudo ./test_client -s 1024 -l d -E -e 1 --epoch_timeout 2000000 -t 3 --mp_ping 1 -M -i lo -i lo >> clog +sudo ${CLIENT_BIN} -s 1024 -l d -E -e 1 --epoch_timeout 2000000 -t 3 --mp_ping 1 -M -i lo -i lo >> clog ret_ping_id=`grep "====>ping_id:" clog` ret_no_ping_id=`grep "====>no ping_id" clog` path0_ping=`grep -E "xqc_send_packet_with_pn.*path:0.*PING" clog` @@ -4103,14 +4179,12 @@ fi rm -rf tp_localhost test_session xqc_token clear_log echo -e "freeze path0 ...\c" -sudo ./test_client -s 1024000 -l d -E -e 4 -T 2 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 107 > stdlog -stream_info3=`grep "stream_info:" stdlog | head -n 3 | tail -n 1 | grep -v "#0" | grep "#1"` -stream_info5=`grep "stream_info:" stdlog | tail -n 1 | grep -E "#0.*#1"` +sudo ${CLIENT_BIN} -s 1024000 -l d -E -e 4 -T 2 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 107 > stdlog clog_res1=`grep -E "path:0.*app_path_status:2->3" clog` clog_res2=`grep -E "path:0.*app_path_status:3->1" clog` slog_res1=`grep -E "path:0.*app_path_status:2->3" slog` slog_res2=`grep -E "path:0.*app_path_status:3->1" slog` -if [ -n "$stream_info3" ] && [ -n "$stream_info5" ] && [ -n "$clog_res1" ] && [ -n "$clog_res2" ] && [ -n "$slog_res1" ] && [ -n "$slog_res2" ] ; then +if [ -n "$clog_res1" ] && [ -n "$clog_res2" ] && [ -n "$slog_res1" ] && [ -n "$slog_res2" ] ; then echo ">>>>>>>> pass:1" case_print_result "freeze_path0" "pass" else @@ -4121,14 +4195,12 @@ fi rm -rf tp_localhost test_session xqc_token clear_log echo -e "freeze path1 ...\c" -sudo ./test_client -s 1024000 -l d -E -e 4 -T 2 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 108 > stdlog -stream_info3=`grep "stream_info:" stdlog | head -n 3 | tail -n 1 | grep -v "#1" | grep "#0"` -stream_info5=`grep "stream_info:" stdlog | tail -n 1 | grep -E "#0.*#1"` +sudo ${CLIENT_BIN} -s 1024000 -l d -E -e 4 -T 2 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 108 > stdlog clog_res1=`grep -E "path:1.*app_path_status:2->3" clog` clog_res2=`grep -E "path:1.*app_path_status:3->1" clog` slog_res1=`grep -E "path:1.*app_path_status:2->3" slog` slog_res2=`grep -E "path:1.*app_path_status:3->1" slog` -if [ -n "$stream_info3" ] && [ -n "$stream_info5" ] && [ -n "$clog_res1" ] && [ -n "$clog_res2" ] && [ -n "$slog_res1" ] && [ -n "$slog_res2" ] ; then +if [ -n "$clog_res1" ] && [ -n "$clog_res2" ] && [ -n "$slog_res1" ] && [ -n "$slog_res2" ] ; then echo ">>>>>>>> pass:1" case_print_result "freeze_path1" "pass" else @@ -4137,13 +4209,13 @@ else fi killall test_server -stdbuf -oL ./test_server -l d -e -M > /dev/null & +stdbuf -oL ${SERVER_BIN} -l d -e -M > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token clear_log echo -e "probing standby paths ...\c" -sudo ./test_client -s 1024000 -l d -E -e 1 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 501 -y > stdlog +sudo ${CLIENT_BIN} -s 1024000 -l d -E -e 1 --epoch_timeout 2000000 -t 4 -M -i lo -i lo -x 501 -y > stdlog clog_res1=`grep -E "|xqc_path_standby_probe|PING|path:1|" clog` if [ -n "$clog_res1" ] ; then echo ">>>>>>>> pass:1" @@ -4157,7 +4229,7 @@ fi sudo rm -rf tp_localhost test_session xqc_token clog stdlog ckeys.log clear_log echo -e "conn_rate_throttling ...\c" -result=`./test_client -s 1024000 -l d -E --rate_limit 1000000 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -E --rate_limit 1000000 |grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -4169,7 +4241,7 @@ fi clear_log echo -e "stream_rate_throttling ...\c" -result=`./test_client -s 1024000 -l d -E -x 109 |grep ">>>>>>>> pass"` +result=`${CLIENT_BIN} -s 1024000 -l d -E -x 109 |grep ">>>>>>>> pass"` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -4179,6 +4251,675 @@ else echo "$errlog" fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 150 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3 ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 150 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 151 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 151 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_more" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 152 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_29 ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 152 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_29" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_29" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 153 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_29_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 153 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_29_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_29_more" "fail" +fi + + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log killall test_server +${SERVER_BIN} -l d -e -x 150 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_ext ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 150 -T 2 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_ext" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_ext" "fail" +fi + + +sudo rm -rf tp_localhost test_session xqc_token stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 151 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_ext_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 151 -T 2 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_ext_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_ext_more" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token +killall test_server 2> /dev/null +${SERVER_BIN} -l d -e -f > /dev/null & +sleep 1 + +clear_log +echo -e "negotiate_encoder_fec_schemes ...\c" +sudo ${CLIENT_BIN} -l d -g > stdlog +clog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" clog` +slog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res1" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "negotiate_encoder_fec_scheme" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "negotiate_encoder_fec_scheme" "fail" +fi + + +clear_log +echo -e "negotiate_decoder_fec_schemes ...\c" +sudo ${CLIENT_BIN} -l d -g > stdlog +clog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" clog` +slog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res2" ] && [ -n "$slog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "negotiate_decoder_fec_scheme" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "negotiate_decoder_fec_scheme" "fail" +fi + + +clear_log +killall test_server 2> /dev/null +stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + +rm -rf tp_localhost test_session xqc_token +echo -e "check fec recovery function of stream using XOR ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo > stdlog +slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_stream_xor" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_stream_xor" "fail" +fi + +clear_log +killall test_server 2> /dev/null +stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + +rm -rf tp_localhost test_session xqc_token +echo -e "check fec recovery function of stream using RSC ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 > stdlog +slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_stream_rsc" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_stream_rsc" "fail" +fi + +clear_log +killall test_server 2> /dev/null +stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + +rm -rf tp_localhost test_session xqc_token +echo -e "check fec recovery function of stream using PM ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 > stdlog +slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_stream_pm" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_stream_pm" "fail" +fi + +rm -rf tp_localhost test_session xqc_token +echo -e "check fec recovery when send repair packets ahead ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l d -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 --fec_timeout 20 > stdlog +clog_res=`grep '|send repair packets ahead finished' clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_send_repair_ahead" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_send_repair_ahead" "fail" + echo "$errlog" + echo "$clog_res" +fi + + + +killall test_server 2> /dev/null +${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 --dgram_qos 3 -f > /dev/null & +sleep 1 + +rm -rf tp_localhost test_session xqc_token + +clear_log +echo -e "check fec recovery function of datagram with XOR fec scheme ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_xor" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_xor" "fail" +fi + +clear_log +echo -e "check fec recovery function of datagram with RSC fec scheme ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 8 > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_rsc" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_rsc" "fail" +fi + +clear_log +echo -e "check fec recovery function of datagram with Packet Mask scheme ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 12 --fec_decoder 12 > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_pm" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_pm" "fail" +fi + +clear_log +echo -e "check fec recovery function of datagram with XOR(encoder) and RSC(decoder) fec schemes ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 11 > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_xor_and_rsc" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_xor_and_rsc" "fail" +fi + + +clear_log +echo -e "check fec recovery function of datagram with XOR(decoder) and RSC(encoder) fec schemes ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 8 > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_rsc_and_xor" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_rsc_and_xor" "fail" +fi + + +clear_log +rm -rf tp_localhost test_session xqc_token +echo -e "qlog disable ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_disable > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_disable > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[packet_sent\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[packet_sent\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -z "$svr_qlog_res1" ] && [ -z "$svr_qlog_res2" ] \ + && [ -z "$cli_qlog_res1" ] && [ -z "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_disable" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_disable" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance selected 1 ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance s > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance s > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[connection_started\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[connection_started\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_selected_1" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_selected_1" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance selected 2 ...\c" +killall test_server +${SERVER_BIN} -l i -e -x 1 --qlog_importance s > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l i -t 1 -E --qlog_importance s > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[connection_started\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[connection_started\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -z "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -z "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_selected_2" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_selected_2" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance removed ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance r > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance r > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$svr_qlog_res3" ] && [ -n "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -n "$cli_qlog_res3" ] && [ -n "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_removed" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_removed" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance extra ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance e > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance e > stdlog +result=`grep ">>>>>>>> pass:1" stdlog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -n "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_extra" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_extra" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance base ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance b > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance b > stdlog +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -z "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -z "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_base" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_base" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance core ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance c > /dev/null & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance c > /dev/null +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -z "$svr_qlog_res2" ] \ + && [ -z "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -z "$cli_qlog_res2" ] \ + && [ -z "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_core" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_core" "fail" + echo "$errlog" +fi + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server enable, 0 < max_ts_per_ack < 64 and client enable, 0 < max_ts_per_ack < 64 ...\c" +${SERVER_BIN} -l d -e -x 450 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 450 > stdlog +cli_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" clog | wc -l` +cli_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" clog | wc -l` + +svr_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" slog | wc -l` +svr_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" slog | wc -l` + +if [ "$cli_res1" -gt 0 ] && [ "$cli_res2" -gt 0 ] && [ "$svr_res1" -gt 0 ] && [ "$svr_res2" -gt 0 ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_1" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_1" "fail" +fi + + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server enable, 0 < max_ts_per_ack < 64 and client disable, 0 < max_ts_per_ack < 64 ...\c" +${SERVER_BIN} -l d -e -x 450 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 451 > stdlog +cli_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" clog | wc -l` +cli_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" clog | wc -l` + +svr_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" slog | wc -l` +svr_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" slog | wc -l` + +echo -e "$cli_res1 $cli_res2 $svr_res1 $svr_res2" + +if [ "$cli_res1" -eq 0 ] && [ "$cli_res2" -eq 0 ] && [ "$svr_res1" -eq 0 ] && [ "$svr_res2" -eq 0 ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_2" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_2" "fail" +fi + + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server enable, 0 < max_ts_per_ack < 64 and client enable, max_ts_per_ack >= 64 ...\c" +${SERVER_BIN} -l d -e -x 450 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 452 > stdlog +cli_res1=`grep "conn errno" stdlog` + +svr_res1=`grep "[error]" slog | grep "xqc_conn_tls_transport_params_cb" | wc -l` + +if [ -n "$cli_res1" ] && [ -n "$svr_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_3" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_3" "fail" +fi + + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server enable, 0 < max_ts_per_ack < 64 and client enable, max_ts_per_ack = 0 ...\c" +${SERVER_BIN} -l d -e -x 450 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 453 > stdlog +cli_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" clog | wc -l` +cli_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" clog | wc -l` + +svr_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" slog | wc -l` +svr_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" slog | wc -l` + +if [ "$cli_res1" -gt 0 ] && [ "$cli_res2" -eq 0 ] && [ "$svr_res1" -eq 0 ] && [ "$svr_res2" -gt 0 ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_4" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_4" "fail" +fi + + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server disable, 0 < max_ts_per_ack < 64 and client enable, 0 < max_ts_per_ack < 64 ...\c" +${SERVER_BIN} -l d -e -x 451 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 450 > stdlog +cli_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" clog | wc -l` +cli_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" clog | wc -l` + +svr_res1=`grep "xqc_write_packet_receive_timestamps_into_buf|ts_info_len" slog | wc -l` +svr_res2=`grep "xqc_parse_timestamps_in_ack_ext|report_num:" slog | wc -l` + +if [ "$cli_res1" -eq 0 ] && [ "$cli_res2" -eq 0 ] && [ "$svr_res1" -eq 0 ] && [ "$svr_res2" -eq 0 ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_5" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_5" "fail" +fi + + +killall test_server +clear_log +echo -e "ack_timestamp_frame: server enable, max_ts_per_ack > 64 and client enable, 0 < max_ts_per_ack < 64 ...\c" +${SERVER_BIN} -l d -e -x 452 > /dev/null & +sleep 1 +${CLIENT_BIN} -s 102400 -l d -t 1 -E -x 450 > stdlog +cli_res1=`grep "[error]" clog | grep "xqc_conn_tls_transport_params_cb" | wc -l` + +svr_res1=`grep "[error]" slog | grep "xqc_process_conn_close_frame" | wc -l` + + +if [ "$cli_res1" -gt 0 ] && [ "$svr_res1" -gt 0 ]; then + echo ">>>>>>>> pass:1" + case_print_result "ack_timestamp_frame_case_6" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "ack_timestamp_frame_case_6" "fail" +fi -cd - +cd - \ No newline at end of file diff --git a/scripts/qlog_parser.py b/scripts/qlog_parser.py new file mode 100644 index 000000000..b6b073b13 --- /dev/null +++ b/scripts/qlog_parser.py @@ -0,0 +1,984 @@ +import argparse +import os +import sys +import json +import re +import datetime + +connectivity_event_list_ = ["server_listening", "connection_started", "connection_closed", + "connection_id_updated", "spin_bit_updated", "connection_state_updated", + "path_assigned", "mtu_updated"] + +quic_event_list_ = ["version_information", "alpn_information", "parameters_set", + "parameters_restored", "packet_sent", "packet_received", + "packets_acked", "datagrams_sent", "datagrams_received", + "datagram_dropped", "stream_state_updated", "frames_processed", + "stream_data_moved", "datagram_data_moved", "migration_state_updated", + "packet_dropped", "packet_buffered"] + +security_event_list_ = ["key_updated" , "key_discarded"] + +recovery_event_list_ = ["rec_parameters_set", "rec_metrics_updated", "congestion_state_updated", + "loss_timer_updated", "packet_lost", "marked_for_retransmit", + "ecn_state_updated"] + +http_event_list_ = ["http_parameters_set", "http_parameters_restored", "http_stream_type_set", + "http_frame_created", "http_frame_parsed", "push_resolved", "http_setting_parsed"] + +qpack_event_list_ = ["qpack_state_updated", "qpack_stream_state_updated", "dynamic_table_updated","headers_encoded", + "headers_decoded", "instruction_created", "instruction_parsed"] + +packet_type_ = {0: "initial", 1: "0RTT", 2: "handshake" , + 3: "retry", 4: "short_header", 5: "version_negotiation", 6: "unknown"} + +packet_number_namespace_ = {0: "initial", 1: "handshake", 2: "application data", 3: "negotiation"} + +packet_type_ = {0: "initial", 1: "0RTT", 2: "handshake" , + 3: "retry", 4: "short_header", 5: "version_negotiation", 6: "unknown"} + +packet_number_namespace_ = {0: "initial", 1: "handshake", 2: "application data", 3: "negotiation"} + +send_stream_states_ = ["ready", "send", "data_sent", "reset_sent", "reset_received"] + +recv_stream_states_ = ["receive", "size_known", "data_read", "reset_read", "reset_received", "reset_received"] + +frame_type_ = ["PADDING", "PING", "ACK", "RESET_STREAM", "STOP_SENDING", "CRYPTO", "NEW_TOKEN", + "STREAM", "MAX_DATA", "MAX_STREAM_DATA", "MAX_STREAMS", "DATA_BLOCKED", "STREAM_DATA_BLOCKED", "STREAMS_BLOCKED", + "NEW_CONNECTION_ID", "RETIRE_CONNECTION_ID", "PATH_CHALLENGE", "PATH_RESPONSE", "CONNECTION_CLOSE", "HANDSHAKE_DONE", + "ACK_MP", "PATH_ABANDON", "PATH_STATUS", "DATAGRAM", "Extension"] + +h3_stream_type_ = ["control", "push", "qpack_encode", "qpack_decode", "request", "bytestream", "unknown"] + +h3_frame_type_ = ["data", "headers", "bidi_stream_type", "cancel_push", "settings", "push_promise", "goaway", "max_push_id", "unknown"] + +last_scid_ = "initcid" + +def get_path_id(line): + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "path_id": + return int(item[1]) + raise ValueError("no path_id") + +def parse_line(line): + event = {} + event_scid = "" + pattern = r'\[(.*?)\]' + matches = re.findall(pattern, line) + matches = [segment.strip() for segment in matches] + if(len(matches) != 2): + return None, event_scid + time_str = matches[0] + dt_object = datetime.datetime.strptime(time_str, "%Y/%m/%d %H:%M:%S %f") + + event["time"] = dt_object.timestamp() * 1000 + event["name"] = matches[1] + + if event["name"] in connectivity_event_list_: + event["name"] = "connectivity:" + event["name"] + elif event["name"] in quic_event_list_: + event["name"] = "quic:" + event["name"] + elif event["name"] in security_event_list_: + event["name"] = "security:" + event["name"] + elif event["name"] in recovery_event_list_: + if event["name"] == "rec_parameters_set" or event["name"] == "rec_metrics_updated": + event["name"] = event["name"][4:] + event["name"] = "recovery:" + event["name"] + elif event["name"] in http_event_list_: + if event["name"] == "push_resolved": + event["name"] = "h3:push_resolved" + else: + event["name"] = "h3:" + event["name"][5:] + else: + return None, event_scid + + if matches[1] in ["packet_sent", "packet_received", "mtu_updated", "datagrams_sent", "datagrams_received", "packets_acked"]: + event["path"] = get_path_id(line) + + if matches[1] == "packet_sent" or matches[1] == "packet_received": + event["data"], event_scid = parse_packet_sent_and_recv(line) + return event, event_scid + + if matches[1] == "datagrams_sent" or matches[1] == "datagrams_received": + event["data"], event_scid = parse_datagrams_sent_or_recv(line) + return event, event_scid + + if matches[1] in ["server_listening", "connection_started", "connection_close", "connection_state_updated", + "path_assigned", "mtu_updated", "alpn_information","parameters_set", "packet_buffered", "packets_acked", "stream_state_updated", + "frames_processed", "stream_data_moved", "rec_parameters_set", "rec_metrics_updated", "congestion_state_updated", + "packet_lost", "http_parameters_set", "http_frame_created", "http_frame_parse"]: + function_name = "parse_" + matches[1] + func = globals()[function_name] + (event["data"], event_scid) = func(line) + return event, event_scid + else: + return None, None + + + +def endpoint_events_extraction(file_name, vantagepoint): + assert(vantagepoint == "server" or vantagepoint == "client") + conn_events = { + "vantage_point" : {"name": vantagepoint + "-view", + "type": vantagepoint + }, + "title": "xquic qlog", + "description": "", + "common_fields": { "ODCID": "", "time_format": "absolute" }, + "events": [] + } + count = 0 + last_scid_ = "initcid" + traces_log = {} + with open(file_name, 'r',encoding='utf-8', errors='ignore') as file: + for line in file: + event, scid = parse_line(line) + if (event is None): + continue + if (event is not None) and (scid != last_scid_): + if count > 0: + if(scid in traces_log): + traces_log[scid]['events'] += conn_events['events'] + else: + traces_log[last_scid_] = conn_events + last_scid_ = scid + conn_events = { + "title": "xquic-qlog json: " + vantagepoint, + "description": "", + "common_fields": { "ODCID": scid, "time_format": "absolute" }, + "vantage_point" : {"name": vantagepoint + "-view", + "type": vantagepoint + }, + "events": [] + } + count = 1 + conn_events["events"].append(event) + else: + count += 1 + conn_events["events"].append(event) + if(count > 1): + scid = conn_events["common_fields"]["ODCID"] + if(scid in traces_log): + traces_log[scid]['events'] += conn_events['events'] + else: + traces_log[scid] = conn_events + return list(traces_log.values()) + + +def parse_packet_sent_and_recv(line): + data = { + "header": { + "packet_number": "unknown", + "packet_type": "unknown" + }, + "raw": { + "length": 1280 + } + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "pkt_type"): + data["header"]["packet_type"] = item[1] + elif(item[0] == "pkt_num"): + data["header"]["packet_number"] = int(item[1]) + elif(item[0] == "size"): + data["raw"]["length"] = int(item[1]) + return (data, event_scid) + +def parse_server_listening(line): + data = { + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + else: + if item[0].startswith("port"): + data[item[0]] = int(item[1]) + else: + data[item[0]] = item[1] + return (data, event_scid) + +def parse_connection_started(line): + # [2024/05/14 11:34:11 641605] [connection_started] |scid:b59e52a51185db48|xqc_engine_packet_process|local|src_ip:127.0.0.1|src_port:35148| + data = { + "src_ip": "127.0.0.1", + "dst_ip": "127.0.0.1", + "src_port": 0, + "dst_port": 0 + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "src_ip"): + data["src_ip"] = item[1] + elif(item[0] == "dst_ip"): + data["dst_ip"] = item[1] + elif(item[0] == "src_port"): + data["src_port"] = int(item[1]) + elif(item[0] == "dst_port"): + data["dst_port"] = int(item[1]) + return (data, event_scid) + +def parse_connection_closed(line): + # [2024/05/14 11:34:26 672332] [connection_closed] |scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_conn_destroy|err_code:0| + data = { + "connection_code": 0 + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "err_code": + data["connection_code"] = int(item[1]) + break + return (data, event_scid) + +def parse_connection_state_updated(line): + data = { + "new": "unknow" + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "new": + data["new"] = item[1] + break + return (data, event_scid) + +def parse_path_assigned(line): + data = { + "path_id": "unknow" + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "path_id": + data["path_id"] = item[1] + break + return (data, event_scid) + + +def parse_mtu_updated(line): + data = { + "new": 0, + "done": False + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "new": + data["path_id"] = int(item[1]) + elif item[0] == "done": + data["done"] = False + if int(item[1]): + data["done"] = True + return (data, event_scid) + +def parse_alpn_information(line): + #[2024/05/14 11:34:11 548027] [alpn_information] + #|scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_ssl_alpn_select_cb|client_alpn:h3 |server_alpn:h3 h3-29 h3-ext transport |selected_alpn:h3| + data = { + "server_alpns": [], + "client_alpns": [], + "chosen_alpn": {"string_value" : "unknown"} + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "client_alpn": + alpns = item[1].split(' ') + for alpn in alpns: + temp = {"string_value" : alpn} + data["client_alpns"].append(temp) + elif item[0] == "server_alpn": + alpns = item[1].split(' ') + for alpn in alpns: + temp = {"string_value" : alpn} + data["server_alpns"].append(temp) + elif item[0] == "selected_alpn": + data["chosen_alpn"]["string_value"] = item[1] + return (data, event_scid) + + +def parse_parameters_set(line): + # [2024/05/14 11:34:11 547473] [tra_parameters_set] |scid:007cc254f81be8e78d765a2e63339fc99a66320d| + # xqc_conn_create|local|migration:1|max_idle_timeout:120000|max_udp_payload_size:1500|active_connection_id_limit:8|max_data:0| + data = { + "max_idle_timeout": 0, + "max_udp_payload_size": 0, + "active_connection_id_limit": 0 + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] in data.keys: + data[item[0]] = int(item[1]) + return (data, event_scid) + +def parse_packet_buffered(line): + # [2024/05/14 11:34:11 693524] [packet_buffered] |scid:007cc254f81be8e78d765a2e63339fc99a66320d| + # xqc_conn_buff_undecrypt_packet_in|pkt_pns:2|pkt_type:4|len:1216| + data = { + "header": { + "packet_number": "unknown", + "packet_type": "unknown" + }, + "raw": { + "length": 1280 + } + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "pkt_type"): + data["header"]["packet_type"] = packet_type_[int(item[1])] + elif(item[0] == "pkt_num"): + data["header"]["packet_number"] = int(item[1]) + elif(item[0] == "len"): + data["raw"]["length"] = int(item[1]) + return (data, event_scid) + +def parse_packets_acked(line): + # [2024/05/14 11:34:11 642140] [packets_acked] |scid:007cc254f81be8e78d765a2e63339fc99a66320d| + # xqc_process_ack_frame|pkt_space:0|high:0|low:0|path_id:0| + data = { + "packet_number_space": "unknown", + "packet_numbers": [] + } + event_scid = "unknown" + low = 0 + high = -1 + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "pkt_space"): + data["packet_number_space"] = packet_number_namespace_[int(item[1])] + elif(item[0] == "low"): + low = int(item[1]) + elif(item[0] == "high"): + high = int(item[1]) + if(low > high): + return (None, event_scid) + for i in range(low, high + 1): + data["packet_numbers"].append(i) + return (data, event_scid) + +def parse_datagrams_sent_or_recv(line): + # [2024/05/14 11:34:11 552331] [datagrams_sent] |scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_send|size:1216| + data = { + "raw": { + "length": 1280 + } + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "size"): + data["raw"]["length"] = int(item[1]) + return (data, event_scid) + +def parse_stream_state_updated(line): + # [2024/05/14 11:34:11 552613] [stream_state_updated] + # |scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_stream_send_state_update|stream_id:3|send_stream|old:0|new:1| + data = { + "StreamType" : "bidirectional", + "new": "unknown", + "stream_side": "sending" + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) == 1): + if item[0] == "send_stream": + data["stream_side"] = "sending" + if item[0] == "recv_stream": + data["stream_side"] = "receiving" + if len(item) != 2: + continue + if item[0] == "scid": + event_scid = item[1] + if item[0] == "new": + state = int(item[1]) + if data["stream_side"] == "sending": + data["new"] = send_stream_states_[state] + else: + data["new"] = recv_stream_states_[state] + return (data, event_scid) + + +def parse_frames_processed(line): + data = { + "frames":[{"frame_type" : "unknow"}] + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + frame_type = -1 + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if len(item) == 2 and item[0] == "scid": + event_scid = item[1] + if(len(item) == 2 and item[0] == "type"): + frame_type = int(item[1]) + break + data["frames"][0]["frame_type"] = frame_type_[frame_type].lower() + type_str = frame_type_[frame_type] + + if type_str == "PADDING": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "length": + data["frames"][0]["payload_length"] = int(item[1]) + return (data, event_scid) + elif type_str == "PING": + return (data, event_scid) + + elif type_str == "ACK": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "ack_range": + s_clean = item[1].strip("{}") + pairs = s_clean.split(", ") + result = [list(map(int, pair.split(" - "))) for pair in pairs] + for i in range(len(result)): + if result[i][0] == result[i][1]: + result[i] = [result[i][0]] + data["frames"][0]["acked_ranges"] = result + return (data, event_scid) + + elif type_str == "RESET_STREAM" or type_str == "STOP_SENDING": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "stream_id": + data["frames"][0]["stream_id"] = int(item[1]) + elif item[0] == "err_code": + data["frames"][0]["error_code"] = int(item[1]) + elif item[0] == "final_size": + data["frames"][0]["final_size"] = int(item[1]) + return (data, event_scid) + + elif type_str == "CRYPTO": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "offset": + data["frames"][0]["offset"] = int(item[1]) + elif item[0] == "length": + data["frames"][0]["length"] = int(item[1]) + return (data, event_scid) + + elif type_str == "NEW_TOKEN": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "token": + data["frames"][0]["token"] = item[1] + return (data, event_scid) + + elif type_str == "STREAM": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "data_length": + data["frames"][0]["length"] = int(item[1]) + elif item[0] == "data_offset": + data["frames"][0]["offset"] = int(item[1]) + elif item[0] == "fin": + data["frames"][0]["fin"] = False + if int(item[1]): + data["frames"][0]["offset"] = True + return (data, event_scid) + + elif type_str == "MAX_DATA": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "max_data": + data["frames"][0]["maximum"] = int(item[1]) + return (data, event_scid) + + elif type_str == "MAX_STREAM_DATA": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "stream_id": + data["frames"][0]["stream_id"] = int(item[1]) + elif item[0] == "max_stream_data": + data["frames"][0]["maximum"] = int(item[1]) + return (data, event_scid) + + elif type_str == "MAX_STREAMS": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "stream_type": + data["frames"][0]["stream_type"] = item[1] + elif item[0] == "maximum": + data["frames"][0]["maximum"] = int(item[1]) + return (data, event_scid) + + elif type_str == "DATA_BLOCKED": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "limit": + data["frames"][0]["limit"] = int(item[1]) + return (data, event_scid) + + elif type_str == "STREAM_DATA_BLOCKED": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "stream_id": + data["frames"][0]["stream_id"] = int(item[1]) + elif item[0] == "limit": + data["frames"][0]["limit"] = int(item[1]) + return (data, event_scid) + + elif type_str == "STREAMS_BLOCKED": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "stream_type": + data["frames"][0]["stream_type"] = item[1] + elif item[0] == "limit": + data["frames"][0]["limit"] = int(item[1]) + return (data, event_scid) + + elif type_str == "NEW_CONNECTION_ID": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] in ["sequence_number", "retire_prior_to", "connection_id_length"]: + data["frames"][0][item[0]] = int(item[1]) + elif item[0] == "connection_id": + data["frames"][0]["connection_id"] = item[1] + return (data, event_scid) + + elif type_str == "CONNECTION_CLOSE": + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "err_code": + data["frames"][0]["error_code"] = int(item[1]) + return (data, event_scid) + else: + return (data, event_scid) + +def parse_stream_data_moved(line): + # [2024/05/14 11:34:11 547904] [stream_data_moved] |scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_stream_send|ret:-610|stream_id:3|stream_send_offset:0|pkt_type:SHORT_HEADER|buff_1rtt:0|send_data_size:1|offset:0|fin:0| + # stream_flag:17|conn:0000000002354F7C|conn_state:S_INIT|flag:TICKING TOKEN_OK UPPER_CONN_EXIST INIT_RECVD |from:application|to:transport| + data = { + "stream_id" : "unknown", + "offset": 0, + "length": 0, + "from": "unknown", + "to": "unknown" + + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) == 1): + continue + if item[0] == "stream_id": + data["stream_id"] = int(item[1]) + elif item[0] == "stream_send_offset": + data["offset"] = int(item[1]) + elif item[0] in ["from", "to"]: + data[item[0]] = item[1] + elif item[0] == "send_data_size": + data["length"] = int(item[1]) + elif item[0] == "scid": + event_scid = item[1] + + return (data, event_scid) + + +def parse_rec_parameters_set(line): + data = {} + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + else: + data[item[0]] = int(item[1]) + return (data, event_scid) + +def parse_rec_metrics_updated(line): + # [2024/05/14 11:34:11 642348] [rec_metrics_updated] + # |scid:007cc254f81be8e78d765a2e63339fc99a66320d|xqc_send_ctl_on_ack_received| + # cwnd:47152|inflight:1384|mode:0|applimit:0|pacing_rate:1477151|bw:13370|srtt:89748|latest_rtt:89748|ctl_rttvar:0|pto_count:89748|min_rtt:6|send:0|lost:0|tlp:29|recv:47152| + data = {} + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "cwnd": + data["congestion_window"] = int(item[1]) + elif item[0] == "inflight": + data["bytes_in_flight"] = int(item[1]) + elif item[0] == "pacing_rate": + data["pacing_rate"] = int(item[1]) + elif item[0] == "pto_count": + data["pto_count"] = int(item[1]) + elif item[0] == "ctl_rttvar": + data["rtt_variance"] = int(item[1]) + elif item[0] == "min_rtt": + data["min_rtt"] = int(item[1]) + elif item[0] == "latest_rtt": + data["latest_rtt"] = int(item[1]) + + return (data, event_scid) + +def parse_congestion_state_updated(line): + data = {"new" : "unknown"} + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif item[0] == "new_state": + data["new"] = item[1] + return (data, event_scid) + +def parse_packet_lost(line): + data = { + "header": { + "packet_number": "unknown", + "packet_type": "unknown" + } + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "pkt_type"): + data["header"]["packet_type"] = packet_type_[int(item[1])] + elif(item[0] == "pkt_num"): + data["header"]["packet_number"] = int(item[1]) + return (data, event_scid) + +def parse_http_parameters_set(line): + data = {} + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "owner"): + data["owner"] = item[1] + else: + data[item[0]] = int(item[1]) + return (data, event_scid) + +def parse_http_stream_type_set(line): + data = {"stream_id": "unknown", + "stream_type": "unknown" + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "stream_id"): + data["stream_id"] = int(item[1]) + elif item[0] == "stream_type": + data["stream_type"] = h3_stream_type_[int(item[1])] + return (data, event_scid) + +def parse_http_frame_created(line): + data = {"stream_id": "unknown", + "frame": {"frame_type": "unknown"} + } + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + h3_frame_type = "unknown" + kv = {} + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + if item[0] == "type": + h3_frame_type = h3_frame_type_[int(item[1])] + else: + kv[item[0]] = item[1] + data["frame"]["frame_type"] = h3_frame_type + data["stream_id"] = kv["stream_id"] + if h3_frame_type == "data": + return (data, event_scid) + elif h3_frame_type == "headers": + header_list = [] + for i in range(1,len(segments)): + if segments[i].startswith("{name"): + match_header = re.findall(r'\{(.*?)\}', segments[i]) + temp_header = {"name": "unknown", "value": "/"} + temp_header["name"] = match_header[0][5:] + if len(match_header) == 2: + temp_header["value"] = match_header[0][6:] + header_list.append(temp_header) + data["frame"]["headers"] = header_list + return (data, event_scid) + + elif h3_frame_type == "cancel_push" or h3_frame_type == "push_promise": + data["frame"]["push_id"] = kv["push_id"] + return (data, event_scid) + + elif h3_frame_type == "settings": + temp_set = [] + for set_i in ["max_field_section_size", "max_pushes", + "qpack_max_table_capacity", "qpack_blocked_streams"]: + temp_set.append({set_i: int(kv[set_i])}) + data["frame"]["settings"] = temp_set + return (data, event_scid) + else: + return (data, event_scid) + +def parse_http_frame_parsed(line): + data = {} + event_scid = "unknown" + segments = line.split('|') + segments = [segment.strip() for segment in segments] + assert(len(segments) > 1) + for i in range(1,len(segments)): + item = segments[i].split(':') + item = [i.strip() for i in item] + if(len(item) != 2): + continue + if item[0] == "scid": + event_scid = item[1] + elif(item[0] == "stream_id"): + data["stream_id"] = packet_type_[int(item[1])] + elif(item[0] == "push_id"): + data["push_id"] = int(item[1]) + return (data, event_scid) + + +def main(): + global last_scid_ + parser = argparse.ArgumentParser() + parser.add_argument("--clog", help="xquic client log file") + parser.add_argument("--slog", help="xquic server log file") + parser.add_argument("--qlog_path", help="output json file, endswith .json", default="demo_qlog.json") + args = parser.parse_args() + if (args.clog is None) and (args.slog is None): + print("Usage: must provide either --clog or --slog argument") + sys.exit(1) + if (args.clog is not None) and (not os.path.isfile(args.clog)): + print(f"Error: The log '{args.clog}' does not exist.") + sys.exit(1) + if (args.slog is not None) and (not os.path.isfile(args.slog)): + print(f"Error: The log '{args.slog}' does not exist.") + sys.exit(1) + if (args.qlog_path is not None) and (not args.qlog_path.endswith(".json")): + print(f"Error: The qlog_path should endswith .json.") + sys.exit(1) + + data = { "qlog_version": "0.4", + "qlog_format": "JSON", + "title": "xquic qlog", + "description": "this is a demo qlog json of qlog-draft-07", + "traces": [] + } + if(args.slog is not None): + server_traces = endpoint_events_extraction(args.slog, "server") + data["traces"] += server_traces + + if(args.clog is not None): + client_traces = endpoint_events_extraction(args.clog, "client") + data["traces"] += client_traces + + json_output = json.dumps(data, indent=4) + + with open(args.qlog_path, 'w') as out_file: + out_file.write(json_output) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/xquic.lds b/scripts/xquic.lds index a971851c2..529413d9d 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -4,6 +4,8 @@ XQUIC_VERS_1.0 { xqc_server_set_conn_settings; xqc_engine_create; xqc_engine_destroy; + xqc_engine_set_priv_ctx; + xqc_engine_get_priv_ctx; xqc_h3_connect; xqc_h3_conn_close; xqc_scid_str; @@ -18,7 +20,7 @@ XQUIC_VERS_1.0 { xqc_h3_request_get_stats; xqc_h3_request_stats_print; xqc_h3_request_set_user_data; - xqc_h3_conn_set_settings; + xqc_h3_engine_set_local_settings; xqc_h3_get_conn_user_data_by_request; xqc_h3_stream_id; xqc_h3_request_close; @@ -26,6 +28,7 @@ XQUIC_VERS_1.0 { xqc_h3_request_send_body; xqc_h3_request_recv_headers; xqc_h3_request_recv_body; + xqc_h3_priority_init; xqc_write_http_priority; xqc_parse_http_priority; xqc_h3_request_set_priority; @@ -33,6 +36,7 @@ XQUIC_VERS_1.0 { xqc_h3_engine_set_enc_max_dtable_capacity; xqc_h3_engine_set_max_dtable_capacity; xqc_h3_engine_set_max_field_section_size; + xqc_h3_engine_set_qpack_blocked_streams; xqc_connect; xqc_conn_close; xqc_conn_get_errno; @@ -49,6 +53,7 @@ XQUIC_VERS_1.0 { xqc_stream_send; xqc_engine_packet_process; xqc_engine_finish_recv; + xqc_engine_finish_send; xqc_engine_recv_batch; xqc_engine_main_logic; xqc_engine_get_default_config; @@ -65,6 +70,7 @@ XQUIC_VERS_1.0 { xqc_minrtt_scheduler_cb; xqc_interop_scheduler_cb; xqc_backup_scheduler_cb; + xqc_backup_fec_scheduler_cb; xqc_rap_scheduler_cb; xqc_conn_is_ready_to_send_early_data; xqc_h3_conn_send_ping; @@ -81,6 +87,7 @@ XQUIC_VERS_1.0 { xqc_h3_ctx_destroy; xqc_engine_register_alpn; xqc_engine_unregister_alpn; + xqc_engine_get_alpn_ctx; xqc_conn_set_alp_user_data; xqc_h3_request_finish; xqc_conn_close_with_error; @@ -115,9 +122,12 @@ XQUIC_VERS_1.0 { xqc_copa_cb; xqc_conn_get_conn_settings_template; xqc_conn_get_lastest_rtt; - xqc_log_enable; - xqc_h3_request_update_settings; - xqc_stream_update_settings; + xqc_log_disable; + xqc_h3_request_update_settings; + xqc_stream_update_settings; + xqc_reed_solomon_code_cb; + xqc_xor_code_cb; + xqc_packet_mask_code_cb; local: *; }; diff --git a/scripts/xquic_test.sh b/scripts/xquic_test.sh index 31df14314..ed71fc533 100644 --- a/scripts/xquic_test.sh +++ b/scripts/xquic_test.sh @@ -26,32 +26,28 @@ function install_go() { } function build_babassl() { - git clone https://github.com/BabaSSL/BabaSSL.git ../third_party/babassl + git clone https://github.com/Tongsuo-Project/Tongsuo.git ../third_party/babassl cd ../third_party/babassl/ - ./config --prefix=/usr/local/babassl + ./config --prefix=/usr/local/babassl --api=1.1.1 no-deprecated make -j SSL_PATH_STR="${PWD}" - SSL_INC_PATH_STR="${PWD}/include" - SSL_LIB_PATH_STR="${PWD}/libssl.a;${PWD}/libcrypto.a" cd - } function build_boringssl() { git clone https://github.com/google/boringssl.git ../third_party/boringssl mkdir -p ../third_party/boringssl/build - cd ../third_party/boringssl//build + cd ../third_party/boringssl/build cmake -DBUILD_SHARED_LIBS=0 -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. make ssl crypto cd .. SSL_PATH_STR="${PWD}" - SSL_INC_PATH_STR="${PWD}/include" - SSL_LIB_PATH_STR="${PWD}/build/ssl/libssl.a;${PWD}/build/crypto/libcrypto.a" cd ../../build/ } function do_compile() { rm -f CMakeCache.txt - if [[ $1 == "XQC_OPENSSL_IS_BORINGSSL" ]]; then + if [[ $1 == "boringssl" ]]; then build_boringssl SSL_TYPE_STR="boringssl" @@ -61,9 +57,13 @@ function do_compile() { fi #turn on Code Coverage - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 .. make -j + if [ $? -ne 0 ]; then + echo "cmake failed" + exit 1 + fi rm -f CMakeCache.txt } @@ -111,7 +111,7 @@ install_cunit install_go #run boringssl -do_compile "XQC_OPENSSL_IS_BORINGSSL" +do_compile "boringssl" run_test_case #run babassl diff --git a/src/common/utils/ringarray/xqc_ring_array.c b/src/common/utils/ringarray/xqc_ring_array.c index 45d8bc037..90d8cba88 100644 --- a/src/common/utils/ringarray/xqc_ring_array.c +++ b/src/common/utils/ringarray/xqc_ring_array.c @@ -239,3 +239,11 @@ xqc_rarray_resize(xqc_rarray_t *ra, uint64_t cap) return XQC_OK; } + +void +xqc_rarray_reinit(xqc_rarray_t *ra) +{ + xqc_memzero(ra->buf, ra->cap * ra->esize); + ra->count = 0; + ra->offset = 0; +} \ No newline at end of file diff --git a/src/common/utils/ringarray/xqc_ring_array.h b/src/common/utils/ringarray/xqc_ring_array.h index e495cf5ce..41ad2d683 100644 --- a/src/common/utils/ringarray/xqc_ring_array.h +++ b/src/common/utils/ringarray/xqc_ring_array.h @@ -84,4 +84,6 @@ xqc_int_t xqc_rarray_pop_from(xqc_rarray_t *ra, uint64_t idx); */ xqc_int_t xqc_rarray_resize(xqc_rarray_t *ra, uint64_t cap); +void xqc_rarray_reinit(xqc_rarray_t *ra); + #endif diff --git a/src/common/utils/ringmem/xqc_ring_mem.c b/src/common/utils/ringmem/xqc_ring_mem.c index 4ab6921f2..9fa4b85bd 100644 --- a/src/common/utils/ringmem/xqc_ring_mem.c +++ b/src/common/utils/ringmem/xqc_ring_mem.c @@ -267,7 +267,7 @@ xqc_ring_mem_undo(xqc_ring_mem_t *rmem, xqc_ring_mem_idx_t idx, size_t len) int xqc_ring_mem_cmp(xqc_ring_mem_t *rmem, xqc_ring_mem_idx_t idx, uint8_t *data, size_t len) { - if (idx < rmem->sidx || idx + len > rmem->eidx) { + if (idx < rmem->sidx || idx + len > rmem->eidx || len == 0) { return -XQC_EPARAM; } diff --git a/src/common/utils/vint/xqc_variable_len_int.h b/src/common/utils/vint/xqc_variable_len_int.h index 640b1f527..ef6d68170 100644 --- a/src/common/utils/vint/xqc_variable_len_int.h +++ b/src/common/utils/vint/xqc_variable_len_int.h @@ -7,7 +7,11 @@ #include #include "src/common/xqc_str.h" +#ifdef XQC_SYS_WINDOWS +#include +#else #include +#endif #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) #include @@ -19,7 +23,7 @@ #define bswap_16 OSSwapInt16 #define bswap_32 OSSwapInt32 #define bswap_64 OSSwapInt64 -#elif defined(WIN32) +#elif (defined XQC_SYS_WINDOWS) #include #define bswap_16 _byteswap_ushort #define bswap_32 _byteswap_ulong diff --git a/src/common/xqc_algorithm.h b/src/common/xqc_algorithm.h index 9474f9324..15e270b1d 100644 --- a/src/common/xqc_algorithm.h +++ b/src/common/xqc_algorithm.h @@ -20,4 +20,16 @@ xqc_uint32_list_find(const uint32_t *list, size_t count, uint32_t target) return -1; } +static inline uint64_t +xqc_uint64_bounded_subtract(uint64_t a, uint64_t b) +{ + return a > b ? a - b : 0; +} + +static inline uint32_t +xqc_uint32_bounded_subtract(uint32_t a, uint32_t b) +{ + return a > b ? a - b : 0; +} + #endif /* XQC_ALGORITHM_H_INCLUDED */ diff --git a/src/common/xqc_config.h b/src/common/xqc_config.h index 1dca67037..6f4ed5e45 100644 --- a/src/common/xqc_config.h +++ b/src/common/xqc_config.h @@ -5,17 +5,27 @@ #ifndef _XQC_H_CONFIG_INCLUDED_ #define _XQC_H_CONFIG_INCLUDED_ +#include + #define xqc_min(a, b) ((a) < (b) ? (a) : (b)) #define xqc_max(a, b) ((a) > (b) ? (a) : (b)) #define xqc_sub_abs(a, b) ((a) > (b) ? ((a) - (b)): ((b) - (a))) #define xqc_clamp(a, min, max) xqc_max(xqc_min(a, max), min) +#ifdef XQC_SYS_WINDOWS +static const unsigned char LF = '\n'; +static const unsigned char CR = '\r'; +#else #define LF (unsigned char) '\n' #define CR (unsigned char) '\r' +#endif + #define CRLF "\r\n" #define XQC_PTR_SIZE 8 +#define XQC_DECIMAL 10 + #define XQC_INT32_LEN (sizeof("-2147483648") - 1) #define XQC_INT64_LEN (sizeof("-9223372036854775808") - 1) diff --git a/src/common/xqc_id_hash.h b/src/common/xqc_id_hash.h index ade6a9052..6cd193841 100644 --- a/src/common/xqc_id_hash.h +++ b/src/common/xqc_id_hash.h @@ -31,25 +31,11 @@ typedef struct xqc_id_hash_table_s { } xqc_id_hash_table_t; -/* make n to 2 pow */ -static inline int -xqc_pow2(unsigned int n) -{ - int clz , power = sizeof(n); - if (__builtin_popcount(n) <= 1) { - return n ; - } - clz = __builtin_clz(n); - power = (power << 3) - clz ; - return pow(2 , power); -} - - static inline xqc_int_t xqc_id_hash_init(xqc_id_hash_table_t *hash_tab, xqc_allocator_t allocator, size_t bucket_num) { hash_tab->allocator = allocator; - bucket_num = xqc_pow2(bucket_num); + bucket_num = xqc_pow2_upper(bucket_num); hash_tab->list = allocator.malloc(allocator.opaque, sizeof(xqc_id_hash_node_t *) * bucket_num); if (hash_tab->list == NULL) { return XQC_ERROR; diff --git a/src/common/xqc_log.c b/src/common/xqc_log.c index a69210864..8aca1315f 100644 --- a/src/common/xqc_log.c +++ b/src/common/xqc_log.c @@ -3,18 +3,18 @@ */ #include "xqc_log.h" +#include "src/transport/xqc_engine.h" #ifdef PRINT_MALLOC FILE *g_malloc_info_fp; #endif - -static xqc_bool_t xqc_log_switch = XQC_TRUE; +static xqc_bool_t log_disable = XQC_FALSE; void -xqc_log_enable(xqc_bool_t enable) +xqc_log_disable(xqc_bool_t disable) { - xqc_log_switch = enable; + log_disable = disable; } void @@ -58,58 +58,145 @@ xqc_log_type_2_level(xqc_log_type_t type) return XQC_LOG_ERROR; case GEN_WARN: return XQC_LOG_WARN; + case GEN_STATS: + return XQC_LOG_STATS; + case GEN_INFO: + return XQC_LOG_INFO; + case GEN_DEBUG: + return XQC_LOG_DEBUG; + default: + return XQC_LOG_DEBUG; + } +} + +qlog_event_importance_t +xqc_qlog_event_2_level(xqc_log_type_t type) +{ + switch (type) { + /* draft-ietf-quic-qlog-quic-events */ case CON_SERVER_LISTENING: + return EVENT_IMPORTANCE_EXTRA; case CON_CONNECTION_STARTED: case CON_CONNECTION_CLOSED: - case GEN_STATS: - return XQC_LOG_STATS; case CON_CONNECTION_ID_UPDATED: + case CON_SPIN_BIM_UPDATED: case CON_CONNECTION_STATE_UPDATED: - case SEC_KEY_UPDATED: - case SEC_KEY_RETIRED: + case CON_PATH_ASSIGNED: + return EVENT_IMPORTANCE_BASE; + + case CON_MTU_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + case TRA_VERSION_INFORMATION: case TRA_ALPN_INFORMATION: case TRA_PARAMETERS_SET: + return EVENT_IMPORTANCE_CORE; + case TRA_PARAMETERS_RESTORED: + return EVENT_IMPORTANCE_BASE; + + case TRA_PACKET_SENT: + case TRA_PACKET_RECEIVED: + return EVENT_IMPORTANCE_CORE; + + case TRA_PACKET_DROPPED: + case TRA_PACKET_BUFFERED: + return EVENT_IMPORTANCE_BASE; + + case TRA_PACKETS_ACKED: + case TRA_DATAGRAM_DROPPED: case TRA_DATAGRAMS_SENT: case TRA_DATAGRAMS_RECEIVED: + return EVENT_IMPORTANCE_EXTRA; + case TRA_STREAM_STATE_UPDATED: - case TRA_STATELESS_RESET: + return EVENT_IMPORTANCE_BASE; + + case TRA_FRAMES_PROCESSED: + return EVENT_IMPORTANCE_EXTRA; + + case TRA_STREAM_DATA_MOVED: + case TRA_DATAGRAM_DATA_MOVED: + return EVENT_IMPORTANCE_BASE; + case REC_METRICS_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + + case SEC_KEY_UPDATED: + case SEC_KEY_RETIRED: + return EVENT_IMPORTANCE_BASE; + case REC_PARAMETERS_SET: + return EVENT_IMPORTANCE_BASE; + case REC_CONGESTION_STATE_UPDATED: + return EVENT_IMPORTANCE_BASE; + + case REC_LOSS_TIMER_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + + case REC_PACKET_LOST: + return EVENT_IMPORTANCE_CORE; + + case REC_MARKED_FOR_RETRANSMIT: + return EVENT_IMPORTANCE_EXTRA; + + /* draft-ietf-quic-qlog-h3-events */ case HTTP_PARAMETERS_SET: case HTTP_PARAMETERS_RESTORED: - case HTTP_SETTING_PARSED: case HTTP_STREAM_TYPE_SET: + case HTTP_PRIORITY_UPDATED: + return EVENT_IMPORTANCE_BASE; + case HTTP_FRAME_PARSED: + case HTTP_FRAME_CREATED: + return EVENT_IMPORTANCE_CORE; + + case HTTP_PUSH_RESOLVED: + return EVENT_IMPORTANCE_EXTRA; + + /* quic-qlog-h3-events have removed all qpack event definitions since draft 05*/ case QPACK_STATE_UPDATED: case QPACK_STREAM_STATE_UPDATED: - case GEN_INFO: - return XQC_LOG_INFO; - case CON_SPIN_BIM_UPDATED: - case TRA_PACKET_SENT: - case TRA_PACKET_RECEIVED: - case TRA_PACKET_DROPPED: - case TRA_PACKET_BUFFERED: + case QPACK_DYNAMIC_TABLE_UPDATED: + case QPACK_HEADERS_ENCODED: + case QPACK_HEADERS_DECODED: + case QPACK_INSTRUCTION_CREATED: + case QPACK_INSTRUCTION_PARSED: + return EVENT_IMPORTANCE_REMOVED; + default: + return EVENT_IMPORTANCE_EXTRA; + } +} + +xqc_log_level_t +qlog_importance_2_log_level(xqc_log_type_t type){ + if (type >= GEN_REPORT){ + return xqc_log_type_2_level(type); + } + switch (type) + { + /* datagrame, packet, frame level event should be xqc_log_debug */ + case HTTP_FRAME_PARSED: + case HTTP_FRAME_CREATED: case TRA_PACKETS_ACKED: case TRA_DATAGRAM_DROPPED: + case TRA_DATAGRAMS_SENT: + case TRA_DATAGRAMS_RECEIVED: + case TRA_PACKET_SENT: + case TRA_PACKET_RECEIVED: case TRA_FRAMES_PROCESSED: - case TRA_DATA_MOVED: + case TRA_STREAM_DATA_MOVED: + case TRA_DATAGRAM_DATA_MOVED: case REC_LOSS_TIMER_UPDATED: case REC_PACKET_LOST: case REC_MARKED_FOR_RETRANSMIT: - case HTTP_FRAME_CREATED: - case HTTP_PUSH_RESOLVED: - case QPACK_DYNAMIC_TABLE_UPDATED: - case QPACK_INSTRUCTION_CREATED: - case QPACK_INSTRUCTION_PARSED: - case QPACK_HEADERS_ENCODED: - case QPACK_HEADERS_DECODED: - case GEN_DEBUG: + case TRA_PACKET_DROPPED: + case TRA_PACKET_BUFFERED: return XQC_LOG_DEBUG; + default: - return XQC_LOG_DEBUG; + return XQC_LOG_INFO; } } @@ -123,6 +210,8 @@ xqc_log_type_str(xqc_log_type_t type) [CON_CONNECTION_ID_UPDATED] = "connection_id_updated", [CON_SPIN_BIM_UPDATED] = "spin_bin_updated", [CON_CONNECTION_STATE_UPDATED] = "connection_state_updated", + [CON_PATH_ASSIGNED] = "path_assigned", + [CON_MTU_UPDATED] = "mtu_updated", [SEC_KEY_UPDATED] = "key_updated", [SEC_KEY_RETIRED] = "key_retired", [TRA_VERSION_INFORMATION] = "version_information", @@ -139,7 +228,8 @@ xqc_log_type_str(xqc_log_type_t type) [TRA_DATAGRAM_DROPPED] = "datagram_dropped", [TRA_STREAM_STATE_UPDATED] = "stream_state_updated", [TRA_FRAMES_PROCESSED] = "frames_processed", - [TRA_DATA_MOVED] = "data_moved", + [TRA_STREAM_DATA_MOVED] = "stream_data_moved", + [TRA_DATAGRAM_DATA_MOVED] = "datagram_data_moved", [TRA_STATELESS_RESET] = "stateless_reset", [REC_PARAMETERS_SET] = "rec_parameters_set", [REC_METRICS_UPDATED] = "rec_metrics_updated", @@ -150,10 +240,10 @@ xqc_log_type_str(xqc_log_type_t type) [HTTP_PARAMETERS_SET] = "http_parameters_set", [HTTP_PARAMETERS_RESTORED] = "http_parameters_restored", [HTTP_STREAM_TYPE_SET] = "http_stream_type_set", + [HTTP_PRIORITY_UPDATED] = "http_priority_updated", [HTTP_FRAME_CREATED] = "http_frame_created", [HTTP_FRAME_PARSED] = "http_frame_parsed", [HTTP_PUSH_RESOLVED] = "push_resolved", - [HTTP_SETTING_PARSED] = "http_setting_parsed", [QPACK_STATE_UPDATED] = "qpack_state_updated", [QPACK_STREAM_STATE_UPDATED] = "qpack_stream_state_updated", [QPACK_DYNAMIC_TABLE_UPDATED] = "dynamic_table_updated", @@ -177,7 +267,7 @@ void xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) { /* do nothing if switch is off */ - if (!xqc_log_switch) { + if (log_disable) { return; } @@ -233,6 +323,73 @@ xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const c /* if didn't set log callback, just return */ } +void +xqc_qlog_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) +{ + /* do nothing if switch is off */ + if (log_disable) { + return; + } + + if (!log->log_event){ + return; + } + + qlog_event_importance_t event_imp = xqc_qlog_event_2_level(type); + /* EVENT_IMPORTANCE_SELECTED: events will be emitted based on their map log level and cur log level */ + xqc_log_level_t level = XQC_LOG_DEBUG; + if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { + level = qlog_importance_2_log_level(type); + if (level > log->log_level) { + return; + } + } + + unsigned char buf[XQC_MAX_LOG_LEN] = {0}; + unsigned char *p = buf; + unsigned char *last = buf + sizeof(buf); + + /* do not need time & level if use outside log format */ + if (log->log_timestamp) { + /* time */ + char time[64]; + xqc_log_time(time, sizeof(time)); + p = xqc_sprintf(p, last, "[%s] ", time); + } + + if (log->log_level_name) { + /* qlog event */ + p = xqc_sprintf(p, last, "[%s] ", xqc_log_type_str(type)); + } + + if (log->scid != NULL) { + p = xqc_sprintf(p, last, "|scid:%s|%s", log->scid, func); + } else { + p = xqc_sprintf(p, last, "|%s", func); + } + + /* log */ + va_list args; + va_start(args, fmt); + p = xqc_vsprintf(p, last, fmt, args); + va_end(args); + + if (p + 1 < last) { + /* may use printf("%s") outside, add '\0' and don't count into size */ + *p = '\0'; + } + /* EVENT_IMPORTANCE_SELECTED: event logs output with xqc_log via xqc_log_write_err callback */ + if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { + if (log->log_callbacks->xqc_log_write_err) { + log->log_callbacks->xqc_log_write_err(level, buf, p - buf, log->user_data); + } + } + else if(log->log_callbacks->xqc_qlog_event_write) { + log->log_callbacks->xqc_qlog_event_write(event_imp, buf, p - buf, log->user_data); + } +} + + void xqc_log_time(char *buf, size_t buf_len) { @@ -241,7 +398,7 @@ xqc_log_time(char *buf, size_t buf_len) struct tm tm; -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS time_t t = tv.tv_sec; #ifdef _USE_32BIT_TIME_T _localtime32_s(&tm, &t); diff --git a/src/common/xqc_log.h b/src/common/xqc_log.h index 465d17bd5..63a99d52a 100644 --- a/src/common/xqc_log.h +++ b/src/common/xqc_log.h @@ -13,14 +13,18 @@ #include #include #include -#include #include +#include #include "src/common/xqc_config.h" #include "src/common/xqc_malloc.h" #include "src/common/xqc_str.h" #include "src/common/xqc_time.h" +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + /* max length for log buffer */ #define XQC_MAX_LOG_LEN 2048 @@ -53,6 +57,9 @@ typedef enum { CON_CONNECTION_ID_UPDATED, CON_SPIN_BIM_UPDATED, CON_CONNECTION_STATE_UPDATED, + CON_PATH_ASSIGNED, + CON_MTU_UPDATED, + /* security event */ SEC_KEY_UPDATED, @@ -73,7 +80,8 @@ typedef enum { TRA_DATAGRAM_DROPPED, TRA_STREAM_STATE_UPDATED, TRA_FRAMES_PROCESSED, - TRA_DATA_MOVED, + TRA_STREAM_DATA_MOVED, + TRA_DATAGRAM_DATA_MOVED, TRA_STATELESS_RESET, /* recovery event */ @@ -88,10 +96,10 @@ typedef enum { HTTP_PARAMETERS_SET, HTTP_PARAMETERS_RESTORED, HTTP_STREAM_TYPE_SET, + HTTP_PRIORITY_UPDATED, HTTP_FRAME_CREATED, HTTP_FRAME_PARSED, HTTP_PUSH_RESOLVED, - HTTP_SETTING_PARSED, /* qpack event */ QPACK_STATE_UPDATED, @@ -115,17 +123,19 @@ typedef enum { typedef struct xqc_log_s { xqc_log_level_t log_level; + qlog_event_importance_t qlog_importance; xqc_flag_t log_event; /* 1:enable log event, 0:disable log event */ xqc_flag_t log_timestamp; /* 1:add timestamp before log, 0:don't need timestamp */ xqc_flag_t log_level_name; /* 1:add level name before log, 0:don't need level name */ unsigned char *scid; + xqc_engine_t *engine; xqc_log_callbacks_t *log_callbacks; void *user_data; } xqc_log_t; static inline xqc_log_t * -xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, xqc_flag_t log_timestamp, xqc_flag_t log_level_name, - xqc_log_callbacks_t *log_callbacks, void *user_data) +xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, qlog_event_importance_t qlog_imp, xqc_flag_t log_timestamp, xqc_flag_t log_level_name, + xqc_engine_t *engine, xqc_log_callbacks_t *log_callbacks, void *user_data) { xqc_log_t* log = xqc_malloc(sizeof(xqc_log_t)); if (log == NULL) { @@ -139,6 +149,8 @@ xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, xqc_flag_t log_tim log->log_timestamp = log_timestamp; log->log_level_name = log_level_name; log->log_callbacks = log_callbacks; + log->qlog_importance = qlog_imp; + log->engine = engine; return log; } @@ -155,6 +167,12 @@ xqc_log_level_set(xqc_log_t *log, xqc_log_level_t level); xqc_log_level_t xqc_log_type_2_level(xqc_log_type_t type); +qlog_event_importance_t +xqc_qlog_event_2_level(xqc_log_type_t type); + +xqc_log_level_t +qlog_importance_2_log_level(xqc_log_type_t type); + xqc_log_type_t xqc_log_event_type(xqc_log_level_t level); @@ -167,6 +185,8 @@ xqc_log_time(char *buf, size_t buf_len); void xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...); +void +xqc_qlog_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...); #ifndef XQC_DISABLE_LOG #ifndef XQC_ONLY_ERROR_LOG @@ -189,7 +209,9 @@ xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const c #define xqc_log_event(log, type, ...) \ do { \ if ((log)->log_event) { \ - if ((log)->log_level >= xqc_log_type_2_level(type)) { \ + if ((log)->qlog_importance >= xqc_qlog_event_2_level(type) || \ + ((log)->qlog_importance == EVENT_IMPORTANCE_SELECTED && \ + (log)->log_level >= qlog_importance_2_log_level(type))) { \ xqc_log_##type##_callback(log, __FUNCTION__, __VA_ARGS__); \ } \ } \ diff --git a/src/common/xqc_log_event_callback.c b/src/common/xqc_log_event_callback.c index 66af99906..8b2c60134 100644 --- a/src/common/xqc_log_event_callback.c +++ b/src/common/xqc_log_event_callback.c @@ -9,30 +9,75 @@ #include "src/congestion_control/xqc_bbr_common.h" #include "src/http3/xqc_h3_conn.h" +void +xqc_log_CON_SERVER_LISTENING_callback(xqc_log_t *log, const char *func, const struct sockaddr *peer_addr, + socklen_t peer_addrlen) +{ + struct sockaddr_in *sa_peer = (struct sockaddr_in *)peer_addr; + if(peer_addr->sa_family == AF_INET){ + xqc_qlog_implement(log, CON_SERVER_LISTENING, func, + "|ip_v4:%s|port_v4:%d|", + xqc_peer_addr_str(log->engine, (struct sockaddr*)sa_peer, peer_addrlen), + ntohs(sa_peer->sin_port)); + } + else{ + xqc_qlog_implement(log, CON_SERVER_LISTENING, func, + "|ip_v6:%s|port_v6:%d|", + xqc_peer_addr_str(log->engine, (struct sockaddr*)sa_peer, peer_addrlen), + ntohs(sa_peer->sin_port)); + } +} + void xqc_log_CON_CONNECTION_STARTED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local) { if (local == XQC_LOG_LOCAL_EVENT) { struct sockaddr_in *sa_local = (struct sockaddr_in *)conn->local_addr; - xqc_log_implement(log, CON_CONNECTION_STARTED, func, + xqc_qlog_implement(log, CON_CONNECTION_STARTED, func, "|local|src_ip:%s|src_port:%d|", - xqc_local_addr_str((struct sockaddr*)sa_local, conn->local_addrlen), + xqc_local_addr_str(conn->engine, (struct sockaddr*)sa_local, conn->local_addrlen), ntohs(sa_local->sin_port)); } else { struct sockaddr_in *sa_peer = (struct sockaddr_in *)conn->peer_addr; - xqc_log_implement(log, CON_CONNECTION_STARTED, func, + xqc_qlog_implement(log, CON_CONNECTION_STARTED, func, "|remote|dst_ip:%s|dst_port:%d|scid:%s|dcid:%s|", - xqc_peer_addr_str((struct sockaddr*)sa_peer, conn->peer_addrlen), - ntohs(sa_peer->sin_port), log->scid, xqc_dcid_str(&conn->dcid_set.current_dcid)); + xqc_peer_addr_str(conn->engine, (struct sockaddr*)sa_peer, conn->peer_addrlen), + ntohs(sa_peer->sin_port), log->scid, xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid)); } } void xqc_log_CON_CONNECTION_CLOSED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, CON_CONNECTION_CLOSED, func, - "|err_code:%d|", conn->conn_err); + if (conn->conn_err != 0){ + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path = NULL; + unsigned char log_buf[500]; + unsigned char *p = log_buf; + unsigned char *last = log_buf + sizeof(log_buf); + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + uint8_t idx = path->path_send_ctl->ctl_cwndlim_update_idx; + p = xqc_sprintf(p, last, "", + path->path_id, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[idx], conn->conn_create_time) / 1000, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[(idx + 1) % 3], conn->conn_create_time) / 1000, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[(idx + 2) % 3], conn->conn_create_time) / 1000 + ); + if (p != last) { + *p = '\0'; + } + } + xqc_qlog_implement(log, CON_CONNECTION_CLOSED, func, + "|err_code:%d|mtu_updatad_count:%d|pkt_dropped:%d|recent_congestion:%s|", + conn->conn_err, conn->MTU_updated_count, conn->packet_dropped_count, log_buf); + } + else{ + xqc_qlog_implement(log, CON_CONNECTION_CLOSED, func, + "|err_code:%d|mtu_updatad_count:%d|pkt_dropped:%d|", + conn->conn_err, conn->MTU_updated_count, conn->packet_dropped_count); + } } void @@ -41,26 +86,43 @@ xqc_log_CON_CONNECTION_ID_UPDATED_callback(xqc_log_t *log, const char *func, xqc unsigned char scid_str[XQC_MAX_CID_LEN * 2 + 1]; xqc_hex_dump(scid_str, conn->scid_set.user_scid.cid_buf, conn->scid_set.user_scid.cid_len); scid_str[conn->scid_set.user_scid.cid_len * 2] = '\0'; - xqc_log_implement(log, CON_CONNECTION_ID_UPDATED, func, + xqc_qlog_implement(log, CON_CONNECTION_ID_UPDATED, func, "|scid:%s|dcid:%s|", scid_str, conn->dcid_set.current_dcid_str); } void xqc_log_CON_CONNECTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, CON_CONNECTION_STATE_UPDATED, func, - "|state:%d|", conn->conn_state); + xqc_qlog_implement(log, CON_CONNECTION_STATE_UPDATED, func, + "|new:%s|", xqc_conn_state_2_str(conn->conn_state)); +} + +void +xqc_log_CON_PATH_ASSIGNED_callback(xqc_log_t *log, const char *func, + xqc_path_ctx_t *path, xqc_connection_t *conn) +{ + xqc_qlog_implement(log, CON_PATH_ASSIGNED, func, + "|path_id:%ui|local_addr:%s|peer_addr:%s|dcid:%s|scid:%s|", + path->path_id, xqc_conn_addr_str(conn), xqc_path_addr_str(path), + xqc_dcid_str(log->engine, &path->path_dcid), xqc_scid_str(log->engine, &path->path_scid)); +} + +void +xqc_log_CON_MTU_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, int32_t is_done) +{ + xqc_qlog_implement(log, CON_MTU_UPDATED, func, + "|new:%uz|done:%d|max:%uz|", conn->pkt_out_size, is_done, conn->max_pkt_out_size); } void xqc_log_SEC_KEY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_engine_ssl_config_t ssl_config, xqc_int_t local) { if (local == XQC_LOG_LOCAL_EVENT) { - xqc_log_implement(log, SEC_KEY_UPDATED, func, + xqc_qlog_implement(log, SEC_KEY_UPDATED, func, "|local|ciphers:%s|", ssl_config.ciphers); } else { - xqc_log_implement(log, SEC_KEY_UPDATED, func, + xqc_qlog_implement(log, SEC_KEY_UPDATED, func, "|remote|ciphers:%s|", ssl_config.ciphers); } } @@ -87,35 +149,42 @@ xqc_log_TRA_VERSION_INFORMATION_callback(xqc_log_t *log, const char *func, uint3 *p = '\0'; } - xqc_log_implement(log, TRA_VERSION_INFORMATION, func, + xqc_qlog_implement(log, TRA_VERSION_INFORMATION, func, "|%s|choose:%d|", log_buf, choose); } void -xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, size_t local_count, uint8_t *local_alpn, - size_t remote_count, const uint8_t *remote_alpn, size_t alpn_len, const unsigned char *alpn) +xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, const unsigned char * server_alpn_list, + unsigned int server_alpn_list_len, const unsigned char *client_alpn_list, unsigned int client_alpn_list_len, + const char *selected_alpn, size_t selected_alpn_len) { unsigned char log_buf[XQC_MAX_LOG_LEN]; unsigned char *p = log_buf; unsigned char *last = log_buf + sizeof(log_buf); + p = xqc_sprintf(p, last, "client_alpn:"); - p = xqc_sprintf(p, last, "local_alpn:"); - for (size_t i = 0; i < local_count; ++i) { - p = xqc_sprintf(p, last, " %d", local_alpn[i]); - } + uint8_t alpn_len; + size_t alpn_write_len; - p = xqc_sprintf(p, last, "|remote_alpn:"); - for (size_t i = 0; i < remote_count; ++i) { - p = xqc_sprintf(p, last, " %d", remote_alpn[i]); + for (unsigned i = 0; i < client_alpn_list_len;) { + alpn_len = client_alpn_list[i]; + alpn_write_len = alpn_len; + p = xqc_sprintf(p, last, "%*s ", alpn_write_len, &client_alpn_list[i + 1]); + i += alpn_len; + i++; } + p = xqc_sprintf(p, last, "|server_alpn:"); - if (p != last) { - *p = '\0'; + for (unsigned i = 0; i < server_alpn_list_len;) { + alpn_len = server_alpn_list[i]; + alpn_write_len = alpn_len; + p = xqc_sprintf(p, last, "%*s ", alpn_write_len, &server_alpn_list[i + 1]); + i += alpn_len; + i++; } - - xqc_log_implement(log, TRA_ALPN_INFORMATION, func, - "|%s|choose:%*s|", log_buf, alpn_len, alpn); -} + xqc_qlog_implement(log, TRA_ALPN_INFORMATION, func, + "|%s|selected_alpn:%*s|", log_buf, selected_alpn_len, selected_alpn); + } void xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local) @@ -128,7 +197,7 @@ xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connec setting = &conn->remote_settings; } - xqc_log_implement(log, TRA_PARAMETERS_SET, func, + xqc_qlog_implement(log, TRA_PARAMETERS_SET, func, "|%s|migration:%d|max_idle_timeout:%d|max_udp_payload_size:%d|" "active_connection_id_limit:%d|max_data:%d|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", setting->disable_active_migration, @@ -139,50 +208,71 @@ xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connec void xqc_log_TRA_PACKET_RECEIVED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in) { - xqc_log_implement(log, TRA_PACKET_RECEIVED, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|len:%d|frame_flag:%s|", - packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->pi_pkt.pkt_num, - packet_in->buf_size, xqc_frame_type_2_str(packet_in->pi_frame_types)); + xqc_qlog_implement(log, TRA_PACKET_RECEIVED, func, + "|pkt_pns:%d|pkt_type:%s|pkt_num:%ui|len:%uz|frame_flag:%s|path_id:%ui|", + packet_in->pi_pkt.pkt_pns, xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num, + packet_in->buf_size, xqc_frame_type_2_str(log->engine, packet_in->pi_frame_types), packet_in->pi_path_id); } void -xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out) +xqc_log_TRA_PACKET_DROPPED_callback(xqc_log_t *log, const char *func, const char *trigger, xqc_int_t ret, + const char* pi_pkt_type, xqc_packet_number_t pi_pkt_num) { - xqc_log_implement(log, TRA_PACKET_SENT, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|size:%d|frame_flag:%s|", - packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, - packet_out->po_used_size, xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_qlog_implement(log, TRA_PACKET_DROPPED, func, + "|trigger:%s|ret:%d|pkt_type:%s|pkt_num:%ui|", + trigger, ret, pi_pkt_type, pi_pkt_num); +} + +void +xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, xqc_path_ctx_t *path, xqc_usec_t send_time, ssize_t sent, xqc_bool_t with_pn) +{ + if (with_pn) { + xqc_qlog_implement(log, TRA_PACKET_SENT, func, + "|<==|conn:%p|path_id:%ui|pkt_pns:%d|pkt_type:%s|pkt_num:%ui|size:%d|frame_flag:%s|" + "sent:%z|inflight:%ud|now:%ui|stream_id:%ui|stream_offset:%ui|", + conn, path->path_id, packet_out->po_pkt.pkt_pns, + xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), packet_out->po_pkt.pkt_num, + packet_out->po_used_size, xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), + sent, path->path_send_ctl->ctl_bytes_in_flight, send_time, + packet_out->po_stream_id, packet_out->po_stream_offset); + } else { + xqc_qlog_implement(log, TRA_PACKET_SENT, func, + "|<==|conn:%p|path_id:%ui|pkt_type:%s|pkt_pns:%d|frame_flag:%s|size:%ud|sent:%z|", + conn, path->path_id, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), packet_out->po_pkt.pkt_pns, + xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), packet_out->po_used_size, sent); + } } void xqc_log_TRA_PACKET_BUFFERED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in) { - xqc_log_implement(log, TRA_PACKET_BUFFERED, func, - "|pkt_pns:%d|pkt_type:%d|len:%d|", - packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->buf_size); + xqc_qlog_implement(log, TRA_PACKET_BUFFERED, func, + "|pkt_num:%ui|pkt_pns:%d|pkt_type:%d|len:%d|", + packet_in->pi_pkt.pkt_num, packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->buf_size); } void xqc_log_TRA_PACKETS_ACKED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in, - xqc_packet_number_t high, xqc_packet_number_t low) + xqc_packet_number_t high, xqc_packet_number_t low, uint64_t path_id) { - xqc_log_implement(log, TRA_PACKETS_ACKED, func, - "|pkt_space:%d|high:%d|low:%d|", - packet_in->pi_pkt.pkt_pns, high, low); + xqc_qlog_implement(log, TRA_PACKETS_ACKED, func, + "|pkt_space:%d|high:%d|low:%d|path_id:%ui|", + packet_in->pi_pkt.pkt_pns, high, low, path_id); } void -xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size) +xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id) { - xqc_log_implement(log, TRA_DATAGRAMS_SENT, func, - "|size:%d|", size); + xqc_qlog_implement(log, TRA_DATAGRAMS_SENT, func, + "|size:%z|path_id:%ui|", size, path_id); } void -xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size) +xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id) { - xqc_log_implement(log, TRA_DATAGRAMS_RECEIVED, func, - "|size:%d|", size); + xqc_qlog_implement(log, TRA_DATAGRAMS_RECEIVED, func, + "|size:%d|path_id:%ui|", size, path_id); } void @@ -190,11 +280,11 @@ xqc_log_TRA_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_ xqc_int_t stream_type, xqc_int_t state) { if (stream_type == XQC_LOG_STREAM_SEND) { - xqc_log_implement(log, TRA_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, TRA_STREAM_STATE_UPDATED, func, "|stream_id:%d|send_stream|old:%d|new:%d|", stream->stream_id, stream->stream_state_send, state); } else { - xqc_log_implement(log, TRA_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, TRA_STREAM_STATE_UPDATED, func, "|stream_id:%d|recv_stream|old:%d|new:%d|", stream->stream_id, stream->stream_state_recv, state); } @@ -209,13 +299,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) switch (frame_type) { case XQC_FRAME_PADDING: { uint32_t length = va_arg(args, uint32_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|length:%ui|", frame_type, length); break; } case XQC_FRAME_PING: - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|", frame_type); break; @@ -239,7 +329,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) *p = '\0'; } - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|ack_delay:%ui|ack_range:%s|", frame_type, ack_info->ack_delay, buf); break; @@ -249,7 +339,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t err_code = va_arg(args, uint64_t); uint64_t final_size = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|err_code:%ui|final_size:%ui|", frame_type, stream_id, err_code, final_size); break; @@ -258,7 +348,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_STOP_SENDING: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t err_code = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|err_code:%ui|", frame_type, stream_id, err_code); break; } @@ -266,7 +356,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_CRYPTO: { uint64_t offset = va_arg(args, uint64_t); uint64_t length = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|offset:%ui|length:%ui|", frame_type, offset, length); break; } @@ -274,14 +364,14 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_NEW_TOKEN: { uint64_t length = va_arg(args, uint64_t); unsigned char *token = va_arg(args, unsigned char *); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|token_length:%ui|token:%s|", frame_type, length, token); break; } case XQC_FRAME_STREAM: { xqc_stream_frame_t *frame = va_arg(args, xqc_stream_frame_t*); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|data_offset:%ui|data_length:%d|fin:%d|", frame_type, frame->data_offset, frame->data_length, frame->fin); break; @@ -289,14 +379,14 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_DATAGRAM: { uint64_t length = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|data_length:%ui|", frame_type, length); break; } case XQC_FRAME_MAX_DATA: { uint64_t max_data = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|max_data:%ui|", frame_type, max_data); break; } @@ -304,7 +394,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_MAX_STREAM_DATA: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t max_stream_data = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|max_stream_data:%ui|", frame_type, stream_id, max_stream_data); break; @@ -313,13 +403,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) int bidirectional = va_arg(args, int); uint64_t max_streams = va_arg(args, uint64_t); if (bidirectional) { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|max_stream_data:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:bidirectional|maximum:%ui|", frame_type, max_streams); } else { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|unidirectional|max_stream_data:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:unidirectional|maximum:%ui|", frame_type, max_streams); } break; @@ -327,8 +417,8 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_DATA_BLOCKED: { uint64_t data_limit = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|data_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|bidirectional|limit:%ui|", frame_type, data_limit); break; } @@ -336,8 +426,8 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_STREAM_DATA_BLOCKED: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t stream_data_limit = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|stream_id:%ui|stream_data_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|bidirectional|stream_id:%ui|limit:%ui|", frame_type, stream_id, stream_data_limit); break; } @@ -346,13 +436,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) int bidirectional = va_arg(args, int); uint64_t stream_limit = va_arg(args, uint64_t); if (bidirectional) { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|stream_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:bidirectional|limit:%ui|", frame_type, stream_limit); } else { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|unidirectional|stream_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:unidirectional|limit:%ui|", frame_type, stream_limit); } break; @@ -364,21 +454,21 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) unsigned char scid_str[XQC_MAX_CID_LEN * 2 + 1]; xqc_hex_dump(scid_str, new_cid->cid_buf, new_cid->cid_len); scid_str[new_cid->cid_len * 2] = '\0'; - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|seq_num:%ui|retire_prior_to:%ui|cid_len:%d|cid:%s|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|sequence_number:%ui|retire_prior_to:%ui|connection_id_length:%d|connection_id:%s|", frame_type, new_cid->cid_seq_num, retire_prior_to, new_cid->cid_len, scid_str); break; } case XQC_FRAME_CONNECTION_CLOSE: { uint64_t err_code = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|err_code:%ui|", frame_type, err_code); break; } case XQC_FRAME_HANDSHAKE_DONE: - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|", frame_type); break; @@ -399,19 +489,56 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) } +void +xqc_log_TRA_STREAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + xqc_bool_t is_recv, size_t read_or_write_size, size_t recv_buf_size, + uint8_t fin, int ret, int pkt_type, int buff_1rtt, size_t offset) +{ + if (is_recv) { + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|stream_id:%ui|read:%uz|recv_buf_size:%uz|fin:%d|stream_length:%ui|next_read_offset:%ui|conn:%p" + "|from:transport|to:application|", + stream->stream_id, read_or_write_size, recv_buf_size, fin, + stream->stream_data_in.stream_length, stream->stream_data_in.next_read_offset, + stream->stream_conn); + } + else{ + xqc_connection_t *conn = stream->stream_conn; + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|ret:%d|stream_id:%ui|stream_send_offset:%ui|pkt_type:%s|buff_1rtt:%d" + "|send_data_size:%uz|offset:%uz|fin:%d|stream_flag:%d|conn:%p|conn_state:%s|flag:%s" + "|from:application|to:transport|", + ret, stream->stream_id, stream->stream_send_offset, xqc_pkt_type_2_str(pkt_type), + buff_1rtt, read_or_write_size, offset, fin, stream->stream_flag, conn, + xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag)); + } +} + +void +xqc_log_TRA_DATAGRAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + size_t moved_data_len, const char *from, const char *to) +{ + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|stream_id:%ui|length:%uz|from:%s|to:%s|", + stream->stream_id, moved_data_len, from, to); +} + void xqc_log_TRA_STATELESS_RESET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, TRA_DATAGRAMS_SENT, func, "|stateless reset|cid:%s", + xqc_qlog_implement(log, TRA_STATELESS_RESET, func, "|stateless reset|cid:%s|", log->scid); } void -xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl) +xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl, uint8_t timer_granularity, + xqc_cc_params_t cc_params) { - xqc_log_implement(log, REC_PARAMETERS_SET, func, - "|reordering_packet_threshold:%d|reordering_time_threshold_shift:%d|", - send_ctl->ctl_reordering_packet_threshold, send_ctl->ctl_reordering_time_threshold_shift); + xqc_qlog_implement(log, REC_PARAMETERS_SET, func, + "|reordering_threshold:%ui|time_threshold:%d|timer_granularity:%d|initial_rtt:%ui|" + "initial_congestion_window:%d|minimum_congestion_window:%d|", + send_ctl->ctl_reordering_packet_threshold, send_ctl->ctl_reordering_time_threshold_shift, timer_granularity, send_ctl->ctl_srtt / 1000, + cc_params.init_cwnd, cc_params.min_cwnd); } void @@ -430,7 +557,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ xqc_cong_ctl_get_pacing_rate(send_ctl->ctl_cong); mode = send_ctl->ctl_cong_callback->xqc_cong_ctl_info_cb->mode(send_ctl->ctl_cong); min_rtt = send_ctl->ctl_cong_callback-> xqc_cong_ctl_info_cb->min_rtt(send_ctl->ctl_cong); - xqc_log_implement(log, REC_METRICS_UPDATED, func, + xqc_qlog_implement(log, REC_METRICS_UPDATED, func, "|cwnd:%ui|inflight:%ud|mode:%ud|applimit:%ud|pacing_rate:%ui|bw:%ui|srtt:%ui|" "latest_rtt:%ui|ctl_rttvar:%ui|pto_count:%ud|min_rtt:%ui|send:%ud|lost:%ud|tlp:%ud|recv:%ud|", cwnd, send_ctl->ctl_bytes_in_flight, mode, send_ctl->ctl_app_limited, pacing_rate, bw, send_ctl->ctl_srtt, @@ -438,7 +565,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ send_ctl->ctl_tlp_count, send_ctl->ctl_recv_count); } else { - xqc_log_implement(log, REC_METRICS_UPDATED, func, + xqc_qlog_implement(log, REC_METRICS_UPDATED, func, "|cwnd:%ui|inflight:%ud|applimit:%ud|srtt:%ui|latest_rtt:%ui|pto_count:%ud|" "send:%ud|lost:%ud|tlp:%ud|recv:%ud|", cwnd, send_ctl->ctl_bytes_in_flight, send_ctl->ctl_app_limited, send_ctl->ctl_srtt, send_ctl->ctl_latest_rtt, send_ctl->ctl_pto_count, @@ -449,7 +576,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ void xqc_log_REC_CONGESTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, char *new_state) { - xqc_log_implement(log, REC_CONGESTION_STATE_UPDATED, func, + xqc_qlog_implement(log, REC_CONGESTION_STATE_UPDATED, func, "|new_state:%s|", new_state); } @@ -457,28 +584,36 @@ void xqc_log_REC_LOSS_TIMER_UPDATED_callback(xqc_log_t *log, const char *func, xqc_timer_manager_t *timer_manager, xqc_usec_t inter_time, xqc_int_t type, xqc_int_t event) { + if (type != XQC_TIMER_LOSS_DETECTION){ + return ; + } if (event == XQC_LOG_TIMER_SET) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|set|type:%s|expire:%ui|interv:%ui|", + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:set|type:%s|expire:%ui|interv:%ui|", xqc_timer_type_2_str(type), timer_manager->timer[type].expire_time, inter_time); } else if (event == XQC_LOG_TIMER_EXPIRE) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|expired|type:%s|expire_time:%ui|", + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:expired|type:%s|expire_time:%ui|", xqc_timer_type_2_str(type), timer_manager->timer[type].expire_time); } else if (event == XQC_LOG_TIMER_CANCEL) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|cancel|type:%s|", xqc_timer_type_2_str(type)); + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:cancel|type:%s|", xqc_timer_type_2_str(type)); } } void -xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out) +xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out, + xqc_packet_number_t lost_pn, xqc_usec_t lost_send_time, xqc_usec_t loss_delay) { - xqc_log_implement(log, REC_PACKET_LOST, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|", - packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num); + xqc_qlog_implement(log, REC_PACKET_LOST, func, + "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|lost_pn:%ui|po_sent_time:%ui|" + "lost_send_time:%ui|loss_delay:%ui|frame:%s|repair:%d|path_id:%ui|", + packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, + lost_pn, packet_out->po_sent_time, lost_send_time, loss_delay, + xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), XQC_NEED_REPAIR(packet_out->po_frame_types), + packet_out->po_path_id); } void @@ -491,8 +626,8 @@ xqc_log_HTTP_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_h3_co } else { setting = &h3_conn->peer_h3_conn_settings; } - xqc_log_implement(log, HTTP_PARAMETERS_SET, func, - "|%s|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", + xqc_qlog_implement(log, HTTP_PARAMETERS_SET, func, + "|owner:%s|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", setting->max_field_section_size, setting->qpack_dec_max_table_capacity, setting->qpack_blocked_streams); } @@ -501,7 +636,7 @@ void xqc_log_HTTP_PARAMETERS_RESTORED_callback(xqc_log_t *log, const char *func, xqc_h3_conn_t *h3_conn) { xqc_h3_conn_settings_t *setting = &h3_conn->local_h3_conn_settings; - xqc_log_implement(log, HTTP_PARAMETERS_RESTORED, func, + xqc_qlog_implement(log, HTTP_PARAMETERS_RESTORED, func, "|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", setting->max_field_section_size, setting->qpack_dec_max_table_capacity, setting->qpack_blocked_streams); @@ -510,7 +645,7 @@ xqc_log_HTTP_PARAMETERS_RESTORED_callback(xqc_log_t *log, const char *func, xqc_ void xqc_log_HTTP_STREAM_TYPE_SET_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream, xqc_int_t local) { - xqc_log_implement(log, HTTP_STREAM_TYPE_SET, func, + xqc_qlog_implement(log, HTTP_STREAM_TYPE_SET, func, "|%s|stream_id:%ui|stream_type:%d|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", h3_stream->stream_id, h3_stream->type); } @@ -527,7 +662,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) switch (type) { case XQC_H3_FRM_DATA: { uint64_t size = va_arg(args, uint64_t); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|size:%ui|", stream_id, type, size); break; } @@ -544,7 +679,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) p = xqc_sprintf(p, last, "{name:%*s}|", (size_t) header->name.iov_len, header->name.iov_base); } } - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|%s", stream_id, type, log_buf); break; } @@ -552,13 +687,13 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) case XQC_H3_FRM_GOAWAY: case XQC_H3_FRM_MAX_PUSH_ID: { uint64_t push_id = va_arg(args, uint64_t); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|push_id:%ui|", stream_id, type, push_id); break; } case XQC_H3_FRM_SETTINGS: { xqc_h3_conn_settings_t *settings = va_arg(args, xqc_h3_conn_settings_t*); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|max_field_section_size:%ui|max_pushes:%ui|" "|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", stream_id, type, settings->max_field_section_size, settings->max_pushes, @@ -568,7 +703,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) case XQC_H3_FRM_PUSH_PROMISE: { uint64_t push_id = va_arg(args, uint64_t); xqc_http_headers_t *headers = va_arg(args, xqc_http_headers_t*); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|push_id:%ui|", stream_id, type, push_id); break; } @@ -587,29 +722,29 @@ xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stre case XQC_H3_FRM_DATA: case XQC_H3_FRM_HEADERS: case XQC_H3_FRM_SETTINGS: - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|", stream_id, frame->type, frame->len); break; case XQC_H3_FRM_CANCEL_PUSH: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.cancel_push.push_id.vi); break; } case XQC_H3_FRM_PUSH_PROMISE: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.push_promise.push_id.vi); break; } case XQC_H3_FRM_GOAWAY: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.goaway.stream_id.vi); break; } case XQC_H3_FRM_MAX_PUSH_ID: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.max_push_id.push_id.vi); break; @@ -620,15 +755,18 @@ xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stre } void -xqc_log_HTTP_SETTING_PARSED_callback(xqc_log_t *log, const char *func, uint64_t identifier, uint64_t value) +xqc_log_HTTP_PRIORITY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_priority_t *prio, xqc_h3_stream_t *h3s) { - xqc_log_implement(log, HTTP_SETTING_PARSED, func, "|id:%ui|value:%d|", identifier, value); + xqc_qlog_implement(log, HTTP_PRIORITY_UPDATED, func, "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|fec_bm_mode:%ui|" + "stream_id:%ui|conn:%p|", + prio->urgency, prio->incremental, prio->schedule, prio->reinject, h3s->stream->stream_fec_blk_mode, + h3s->stream_id, h3s->h3c->conn); } void xqc_log_QPACK_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream) { - xqc_log_implement(log, QPACK_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, QPACK_STREAM_STATE_UPDATED, func, "|stream_id:%ui|%s|", h3_stream->stream_id, h3_stream->flags & XQC_HTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED ? "blocked" : "unblocked"); } @@ -641,7 +779,7 @@ xqc_log_QPACK_DYNAMIC_TABLE_UPDATED_callback(xqc_log_t *log, const char *func, . xqc_int_t type = va_arg(args, xqc_int_t); uint64_t index = va_arg(args, uint64_t); if (type == XQC_LOG_DTABLE_EVICTED) { - xqc_log_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, + xqc_qlog_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, "|evicted|index:%ui|", index); } else { @@ -649,7 +787,7 @@ xqc_log_QPACK_DYNAMIC_TABLE_UPDATED_callback(xqc_log_t *log, const char *func, . char *name = va_arg(args, char *); uint64_t vlen = va_arg(args, uint64_t); char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, + xqc_qlog_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, "|inserted|index:%ui|name:%*s|value:%*s|", index, (size_t) nlen, name, (size_t) vlen, value); } va_end(args); @@ -666,33 +804,34 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... switch (type) { case XQC_INS_TYPE_ENC_SET_DTABLE_CAP: { uint64_t cap = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|set_dynamic_table_capacity|capacity:%ui|", cap); break; } case XQC_INS_TYPE_ENC_INSERT_NAME_REF: { - xqc_int_t table_type = va_arg(args, xqc_int_t); - uint64_t name_index = va_arg(args, uint64_t); - uint64_t value_len = va_arg(args, uint64_t); - char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_flag_t table_type = va_arg(args, xqc_flag_t); + uint64_t name_index = va_arg(args, uint64_t); + size_t value_len = va_arg(args, size_t); + char *value = va_arg(args, char *); + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_with_name_reference|%s|name_index:%ui|value:%*s|", - table_type == XQC_DTABLE_FLAG ? "dtable" : "stable", name_index, (size_t) value_len, value); + table_type == XQC_DTABLE_FLAG ? "dtable" : "stable", + name_index, (size_t) value_len, value); break; } case XQC_INS_TYPE_ENC_INSERT_LITERAL: { - uint64_t name_len = va_arg(args, uint64_t); - char *name = va_arg(args, char *); - uint64_t value_len = va_arg(args, uint64_t); - char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + size_t name_len = va_arg(args, size_t); + char *name = va_arg(args, char *); + size_t value_len = va_arg(args, size_t); + char *value = va_arg(args, char *); + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_without_name_reference|name:%*s|value:%*s|", (size_t) name_len, name, (size_t) value_len, value); break; } case XQC_INS_TYPE_ENC_DUP: { uint64_t index = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|duplicate|index:%ui|", index); break; } @@ -705,19 +844,19 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... switch (type) { case XQC_INS_TYPE_DEC_SECTION_ACK: { uint64_t stream_id = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|header_acknowledgement|stream_id:%ui|", stream_id); break; } case XQC_INS_TYPE_DEC_STREAM_CANCEL: { uint64_t stream_id = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|stream_cancellation|stream_id:%ui|", stream_id); break; } case XQC_INS_TYPE_DEC_INSERT_CNT_INC: { uint64_t increment = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_count_increment|increment:%ui|", increment); break; } @@ -738,22 +877,22 @@ xqc_log_QPACK_INSTRUCTION_PARSED_callback(xqc_log_t *log, const char *func, ...) xqc_ins_enc_ctx_t *ctx = va_arg(args, xqc_ins_enc_ctx_t*); switch (ctx->type) { case XQC_INS_TYPE_ENC_SET_DTABLE_CAP: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|set_dynamic_table_capacity|capacity:%ui|", ctx->capacity.value); break; case XQC_INS_TYPE_ENC_INSERT_NAME_REF: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_with_name_reference|name_index:%ui|value:%*s|", ctx->name_index.value, (size_t) ctx->value->value->data_len, ctx->value->value->data); break; case XQC_INS_TYPE_ENC_INSERT_LITERAL: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_without_name_reference|name:%*s|value:%*s|", (size_t) ctx->name->value->data_len, ctx->name->value->data, (size_t) ctx->value->value->data_len, ctx->value->value->data); break; case XQC_INS_TYPE_ENC_DUP: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|duplicate|index:%ui|", ctx->name_index.value); break; } @@ -762,15 +901,15 @@ xqc_log_QPACK_INSTRUCTION_PARSED_callback(xqc_log_t *log, const char *func, ...) xqc_ins_dec_ctx_t *ctx = va_arg(args, xqc_ins_dec_ctx_t*); switch (ctx->type) { case XQC_INS_TYPE_DEC_SECTION_ACK: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|header_acknowledgement|stream_id:%ui|", ctx->stream_id.value); break; case XQC_INS_TYPE_DEC_STREAM_CANCEL: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|stream_cancellation|stream_id:%ui|", ctx->stream_id.value); break; case XQC_INS_TYPE_DEC_INSERT_CNT_INC: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_count_increment|increment:%ui|", ctx->increment.value); break; } diff --git a/src/common/xqc_log_event_callback.h b/src/common/xqc_log_event_callback.h index ff0cf9d0e..b53ee3249 100644 --- a/src/common/xqc_log_event_callback.h +++ b/src/common/xqc_log_event_callback.h @@ -7,6 +7,8 @@ #include "src/common/xqc_log.h" +void xqc_log_CON_SERVER_LISTENING_callback(xqc_log_t *log, const char *func, const struct sockaddr *peer_addr, + socklen_t peer_addrlen); void xqc_log_CON_CONNECTION_STARTED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local); @@ -20,6 +22,12 @@ void xqc_log_CON_CONNECTION_ID_UPDATED_callback(xqc_log_t *log, const char *func void xqc_log_CON_CONNECTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn); +void xqc_log_CON_PATH_ASSIGNED_callback(xqc_log_t *log, const char *func, + xqc_path_ctx_t *path, xqc_connection_t *conn); + +void xqc_log_CON_MTU_UPDATED_callback(xqc_log_t *log, const char *func, + xqc_connection_t *conn, int32_t is_done); + void xqc_log_SEC_KEY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_engine_ssl_config_t ssl_config, xqc_int_t local); @@ -27,37 +35,48 @@ void xqc_log_TRA_VERSION_INFORMATION_callback(xqc_log_t *log, const char *func, uint32_t local_count, uint32_t *local_version, uint32_t remote_count, uint32_t *remote_version, uint32_t choose); -void xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, size_t local_count, - uint8_t *local_alpn, size_t remote_count, const uint8_t *remote_alpn, size_t alpn_len, - const unsigned char *alpn); +void xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, const unsigned char * server_alpn_list, + unsigned int server_alpn_list_len, const unsigned char *client_alpn_list, unsigned int client_alpn_list_len, + const char *selected_alpn, size_t selected_alpn_len); void xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local); +void xqc_log_TRA_PACKET_DROPPED_callback(xqc_log_t *log, const char *func, const char *trigger, xqc_int_t ret, + const char * pi_pkt_type, xqc_packet_number_t pi_pkt_num); + void xqc_log_TRA_PACKET_RECEIVED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in); -void xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, - xqc_packet_out_t *packet_out); +void xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, xqc_path_ctx_t *path, xqc_usec_t send_time, ssize_t sent, xqc_bool_t with_pn); void xqc_log_TRA_PACKET_BUFFERED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in); void xqc_log_TRA_PACKETS_ACKED_callback(xqc_log_t *log, const char *func, - xqc_packet_in_t *packet_in, xqc_packet_number_t high, xqc_packet_number_t low); + xqc_packet_in_t *packet_in, xqc_packet_number_t high, xqc_packet_number_t low, uint64_t path_id); -void xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size); +void xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id); -void xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size); +void xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id); void xqc_log_TRA_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, xqc_int_t stream_type, xqc_int_t state); void xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...); +void xqc_log_TRA_STREAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + xqc_bool_t is_recv, size_t read_or_write_size, size_t recv_buf_size, uint8_t fin, int ret, + int pkt_type, int buff_1rtt, size_t offset); + +void xqc_log_TRA_DATAGRAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + size_t moved_data_len, const char *from, const char *to); + void xqc_log_TRA_STATELESS_RESET_callback(xqc_log_t *log, const char *func, xqc_connection_t *c); -void xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl); +void xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl, + uint8_t timer_granularity, xqc_cc_params_t cc_params); void xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl); @@ -67,8 +86,8 @@ void xqc_log_REC_CONGESTION_STATE_UPDATED_callback(xqc_log_t *log, const char *f void xqc_log_REC_LOSS_TIMER_UPDATED_callback(xqc_log_t *log, const char *func, xqc_timer_manager_t *timer_manager, xqc_usec_t inter_time, xqc_int_t type, xqc_int_t event); -void xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, - xqc_packet_out_t *packet_out); +void xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out, + xqc_packet_number_t lost_pn, xqc_usec_t lost_send_time, xqc_usec_t loss_delay); void xqc_log_HTTP_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_h3_conn_t *h3_conn, xqc_int_t local); @@ -84,8 +103,8 @@ void xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...); void xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream); -void xqc_log_HTTP_SETTING_PARSED_callback(xqc_log_t *log, const char *func, uint64_t identifier, - uint64_t value); +void +xqc_log_HTTP_PRIORITY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_priority_t *prio, xqc_h3_stream_t *h3s); void xqc_log_QPACK_STATE_UPDATED_callback(xqc_log_t *log, const char *func, ...); diff --git a/src/common/xqc_malloc.h b/src/common/xqc_malloc.h index eb77d7252..a33c9abf0 100644 --- a/src/common/xqc_malloc.h +++ b/src/common/xqc_malloc.h @@ -52,11 +52,21 @@ xqc_calloc(size_t count, size_t size) } #endif +#ifdef PRINT_MALLOC +#define xqc_realloc(ptr, size) ({\ + xqc_init_print();\ + void *p = realloc(ptr, size); \ + fprintf(g_malloc_info_fp, "PRINT_FREE %p\n", ptr); \ + fprintf(g_malloc_info_fp, "PRINT_MALLOC %p %zu %s:%d\n", p, size, __FILE__, __LINE__);\ + (p);\ + }) +#else static inline void * xqc_realloc(void *ptr, size_t size) { return realloc(ptr, size); } +#endif static inline void xqc_free(void *ptr) diff --git a/src/common/xqc_memory_pool.h b/src/common/xqc_memory_pool.h index 325948cbb..ef4e2eaf7 100644 --- a/src/common/xqc_memory_pool.h +++ b/src/common/xqc_memory_pool.h @@ -7,9 +7,19 @@ #include #include +#include #include "src/common/xqc_malloc.h" +#ifdef XQC_PROTECT_POOL_MEM +#ifndef XQC_SYS_WINDOWS +#include +#include +#include +#include +#endif +#endif + /* Interfaces: * xqc_memory_pool_t *xqc_create_pool(size_t size) * void xqc_destroy_pool(xqc_memory_pool_t* pool) @@ -36,19 +46,78 @@ typedef struct xqc_memory_pool_s { xqc_memory_block_t *current; xqc_memory_large_t *large; /* large chunk list */ size_t max; +#ifdef XQC_PROTECT_POOL_MEM + xqc_bool_t protect_block; + size_t page_size; +#endif } xqc_memory_pool_t; #define XQC_MAX_MALLOC_FROM_POOL (4096) +#ifdef XQC_PROTECT_POOL_MEM +static inline void * +xqc_mempool_malloc_protected(size_t size, size_t page_sz) +{ +#ifndef XQC_SYS_WINDOWS + int ret; + void *ptr = NULL; + ret = posix_memalign(&ptr, page_sz, page_sz + size); + if (ret != 0) { + return NULL; + } + ret = mprotect(ptr, page_sz, PROT_READ); + if (ret != 0) { + xqc_free(ptr); + return NULL; + } + return (void*)((char*)ptr + page_sz); +#else + return xqc_malloc(size); +#endif +} + +static inline void +xqc_mempool_free_protected(void* ptr, size_t page_sz) { +#ifndef XQC_SYS_WINDOWS + void *start; + int ret; + start = (void*)((char*)ptr - page_sz); + ret = mprotect(start, page_sz, PROT_READ | PROT_WRITE | PROT_EXEC); + assert(ret == 0); + xqc_free(start); +#else + xqc_free(ptr); +#endif +} +#endif +#ifdef XQC_PROTECT_POOL_MEM +static inline xqc_memory_pool_t * +xqc_create_pool(size_t size, xqc_bool_t protect_block) +#else static inline xqc_memory_pool_t * xqc_create_pool(size_t size) +#endif { if (size <= sizeof(xqc_memory_pool_t)) { return NULL; } +#ifdef XQC_PROTECT_POOL_MEM + char *m; +#ifndef XQC_SYS_WINDOWS + size_t page_sz = sysconf(_SC_PAGESIZE); +#else + size_t page_sz = 4096; +#endif + if (protect_block) { + m = xqc_mempool_malloc_protected(size, page_sz); + } else { + m = xqc_malloc(size); + } +#else char *m = xqc_malloc(size); +#endif if (m == NULL) { return NULL; } @@ -58,6 +127,10 @@ xqc_create_pool(size_t size) pool->block.end = m + size; pool->block.failed = 0; pool->block.next = NULL; +#ifdef XQC_PROTECT_POOL_MEM + pool->protect_block = protect_block; + pool->page_size = page_sz; +#endif pool->current = &pool->block; pool->large = NULL; @@ -76,23 +149,61 @@ xqc_destroy_pool(xqc_memory_pool_t *pool) while (block) { xqc_memory_block_t *p = block; block = block->next; +#ifdef XQC_PROTECT_POOL_MEM + if (pool->protect_block) { + xqc_mempool_free_protected(p, pool->page_size); + + } else { + xqc_free(p); + } +#else xqc_free(p); +#endif } xqc_memory_large_t *large = pool->large; while (large) { xqc_memory_large_t * p = large; large = large->next; +#ifdef XQC_PROTECT_POOL_MEM + if (pool->protect_block) { + xqc_mempool_free_protected(p, pool->page_size); + + } else { + xqc_free(p); + } +#else xqc_free(p); +#endif } - xqc_free(pool); +#ifdef XQC_PROTECT_POOL_MEM + if (pool->protect_block) { + xqc_mempool_free_protected(pool, pool->page_size); + + } else { + xqc_free(pool); + } +#else + xqc_free(pool); +#endif } static inline void * xqc_palloc_large(xqc_memory_pool_t *pool, size_t size) { +#ifdef XQC_PROTECT_POOL_MEM + xqc_memory_large_t *p; + if (pool->protect_block) { + p = xqc_mempool_malloc_protected(size + sizeof(xqc_memory_large_t), pool->page_size); + + } else { + p = xqc_malloc(size + sizeof(xqc_memory_large_t)); + } +#else xqc_memory_large_t *p = xqc_malloc(size + sizeof(xqc_memory_large_t)); +#endif + if (p == NULL) { return NULL; } @@ -112,7 +223,18 @@ xqc_palloc_block(xqc_memory_pool_t *pool, size_t size) { size_t psize = pool->block.end - (char *)pool; +#ifdef XQC_PROTECT_POOL_MEM + char *m; + if (pool->protect_block) { + m = xqc_mempool_malloc_protected(psize, pool->page_size); + + } else { + m = xqc_malloc(psize); + } +#else char *m = xqc_malloc(psize); +#endif + if (m == NULL) { return NULL; } diff --git a/src/common/xqc_priority_q.h b/src/common/xqc_priority_q.h index 098113062..1e172ff6e 100644 --- a/src/common/xqc_priority_q.h +++ b/src/common/xqc_priority_q.h @@ -2,25 +2,28 @@ * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ -#ifndef _NGX_H_PRIORITY_Q_INCLUDED_ -#define _NGX_H_PRIORITY_Q_INCLUDED_ +#ifndef _XQC_H_PRIORITY_Q_INCLUDED_ +#define _XQC_H_PRIORITY_Q_INCLUDED_ #include #include #include "src/common/xqc_malloc.h" +#include "src/common/xqc_str.h" /* Priority Queue based on Binary Heap * * Interfaces: - * xqc_pq_init(), xqc_pq_init_default(capacity=xqc_pq_default_capacity) + * xqc_pq_init() * xqc_pq_push() * xqc_pq_pop() * xqc_pq_top() * xqc_pq_empty() + * xqc_pq_remove() */ typedef uint64_t xqc_pq_key_t; +typedef struct xqc_priority_queue_s xqc_pq_t; typedef struct xqc_priority_queue_element_s { xqc_pq_key_t key; @@ -29,6 +32,7 @@ typedef struct xqc_priority_queue_element_s { /* element compare function */ typedef int (*xqc_pq_compare_ptr)(xqc_pq_key_t a, xqc_pq_key_t b); +typedef int (*xqc_pq_element_op_t)(xqc_pq_t *pq, xqc_pq_element_t *e); /* default element compare function, priority: a < b */ static inline int @@ -51,14 +55,25 @@ typedef struct xqc_priority_queue_s { size_t capacity; /* capacity */ xqc_allocator_t a; /* memory allocator */ xqc_pq_compare_ptr cmp; /* compare function */ + xqc_pq_element_op_t eop; /* callback function to operate element */ } xqc_pq_t; #define xqc_pq_element(pq, index) ((xqc_pq_element_t *)&(pq)->elements[(index) * (pq)->element_size]) -#define xqc_pq_element_copy(pq, dst, src) memcpy(xqc_pq_element((pq), (dst)), xqc_pq_element((pq), (src)), (pq)->element_size) +#define xqc_pq_element_index(pq, elem) ((((char*)elem) - pq->elements) / pq->element_size) +#define xqc_pq_element_copy(pq, dst, src) (xqc_memcpy(xqc_pq_element((pq), (dst)), xqc_pq_element((pq), (src)), (pq)->element_size)) +#define xqc_pq_element_init(pq, elem, key, data) \ + xqc_memzero(elem, pq->element_size); \ + elem->key = key; \ + if (data != NULL) { \ + xqc_memcpy(elem->data, (char*)data, pq->element_size - sizeof(elem->key)); \ + } + #define xqc_pq_default_capacity 16 static inline int -xqc_pq_init(xqc_pq_t *pq, size_t element_size, size_t capacity, xqc_allocator_t a, xqc_pq_compare_ptr cmp) +xqc_pq_init(xqc_pq_t *pq, size_t element_size, + size_t capacity, xqc_allocator_t a, xqc_pq_compare_ptr cmp, + xqc_pq_element_op_t eop) { if (element_size < sizeof(xqc_pq_element_t) || capacity == 0) { return -1; @@ -74,16 +89,11 @@ xqc_pq_init(xqc_pq_t *pq, size_t element_size, size_t capacity, xqc_allocator_t pq->capacity = capacity; pq->a = a; pq->cmp = cmp; + pq->eop = eop; return 0; } -static inline int -xqc_pq_init_default(xqc_pq_t *pq, size_t element_size, xqc_allocator_t a, xqc_pq_compare_ptr cmp) -{ - return xqc_pq_init(pq, element_size, xqc_pq_default_capacity, a, cmp); -} - static inline void xqc_pq_destroy(xqc_pq_t *pq) { @@ -92,19 +102,68 @@ xqc_pq_destroy(xqc_pq_t *pq) pq->element_size = 0; pq->count = 0; pq->capacity = 0; + pq->cmp = NULL; + pq->eop = NULL; } static inline void xqc_pq_element_swap(xqc_pq_t *pq, size_t i, size_t j) { +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) char buf[pq->element_size]; +#else + char *buf = (char *)_alloca(pq->element_size); +#endif + memcpy(buf, xqc_pq_element(pq, j), pq->element_size); memcpy(xqc_pq_element(pq, j), xqc_pq_element(pq, i), pq->element_size); memcpy(xqc_pq_element(pq, i), buf, pq->element_size); + + if (pq->eop) { + pq->eop(pq, xqc_pq_element(pq, i)); + pq->eop(pq, xqc_pq_element(pq, j)); + } +} + +static inline uint32_t +xqc_pq_move_towards_top(xqc_pq_t *pq, uint32_t i) +{ + uint32_t j; + while (i != 0) { + j = (i - 1) / 2; + + if (!pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, i)->key)) + break; + + xqc_pq_element_swap(pq, i, j); + + i = j; + } + return i; +} + +static inline void +xqc_pq_move_towards_bottom(xqc_pq_t *pq, uint32_t i) +{ + uint32_t j = 2 * i + 1; + while (j <= pq->count - 1) { + if (j < pq->count - 1 && pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, j+1)->key)) { + ++j; + } + + if (!pq->cmp(xqc_pq_element(pq, i)->key, xqc_pq_element(pq, j)->key)) { + break; + } + + xqc_pq_element_swap(pq, i, j); + + i = j; + j = 2 * i + 1; + } } static inline xqc_pq_element_t * -xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key) +xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key, const void *data) { if (pq->count == pq->capacity) { size_t capacity = pq->capacity * 2; @@ -121,19 +180,15 @@ xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key) } xqc_pq_element_t *p = xqc_pq_element(pq, pq->count); - p->key = key; + xqc_pq_element_init(pq, p, key, data); - size_t i = pq->count++; - while (i != 0) { - int j = (i - 1) / 2; - if (!pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, i)->key)) - break; - - xqc_pq_element_swap(pq, i, j); - - i = j; + if (pq->eop) { + pq->eop(pq, p); } + size_t i = pq->count++; + i = xqc_pq_move_towards_top(pq, i); + return xqc_pq_element(pq, i); } @@ -160,25 +215,31 @@ xqc_pq_pop(xqc_pq_t *pq) } xqc_pq_element_copy(pq, 0, pq->count); + + if (pq->eop) { + pq->eop(pq, xqc_pq_element(pq, 0)); + } - int i = 0, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, j+1)->key)) { - ++j; - } + xqc_pq_move_towards_bottom(pq, 0); +} - if (!pq->cmp(xqc_pq_element(pq, i)->key, xqc_pq_element(pq, j)->key)) { - break; - } - xqc_pq_element_swap(pq, i, j); +static inline void +xqc_pq_remove(xqc_pq_t *pq, uint32_t index) +{ + if (index >= pq->count || pq->count == 0 || --pq->count == 0) { + return; + } - i = j; - j = 2 * i + 1; + xqc_pq_element_copy(pq, index, pq->count); + xqc_pq_element_t *p = xqc_pq_element(pq, index); + + if (pq->eop) { + pq->eop(pq, p); } -} -#undef xqc_pq_element -#undef xqc_pq_element_copy + xqc_pq_move_towards_bottom(pq, index); + xqc_pq_move_towards_top(pq, index); +} -#endif /*_NGX_H_PRIORITY_Q_INCLUDED_*/ +#endif /*_XQC_H_PRIORITY_Q_INCLUDED_*/ diff --git a/src/common/xqc_random.c b/src/common/xqc_random.c index 1bf01fb9a..a44c74a75 100644 --- a/src/common/xqc_random.c +++ b/src/common/xqc_random.c @@ -1,20 +1,39 @@ /** * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ - +#if (defined _WIN32) || (defined _WIN64) +#define _CRT_RAND_S +#endif #include #include #include -#include #include #include +#include #include "src/common/xqc_random.h" #include "src/common/xqc_str.h" #include "src/common/xqc_log.h" +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + #define XQC_RANDOM_BUFFER_SIZE 4096 +long xqc_random(void) { +#ifdef XQC_SYS_WINDOWS + unsigned int val; + if (rand_s(&val)) { + val = rand(); + } + return (long)val && 0xFFFFFFFF; +#else + return random(); +#endif + +} + xqc_random_generator_t * xqc_random_generator_create(xqc_log_t *log) { @@ -32,7 +51,7 @@ xqc_random_generator_create(xqc_log_t *log) rand_gen->rand_buf_size = XQC_RANDOM_BUFFER_SIZE; rand_gen->rand_fd = -1; rand_gen->log = log; -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS rand_gen->hProvider = 0; int res = CryptAcquireContextW(&rand_gen->hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); assert(res); @@ -43,7 +62,7 @@ xqc_random_generator_create(xqc_log_t *log) void xqc_random_generator_destroy(xqc_random_generator_t *rand_gen) { -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS CryptReleaseContext(rand_gen->hProvider, 0); #else if (rand_gen->rand_fd != -1) { @@ -57,7 +76,7 @@ xqc_random_generator_destroy(xqc_random_generator_t *rand_gen) xqc_int_t xqc_get_random(xqc_random_generator_t *rand_gen, u_char *buf, size_t need_len) { -#ifndef WIN32 +#ifndef XQC_SYS_WINDOWS size_t total_read = 0; ssize_t bytes_read = 0; diff --git a/src/common/xqc_random.h b/src/common/xqc_random.h index fa5a13e5c..9bcb6c1ce 100644 --- a/src/common/xqc_random.h +++ b/src/common/xqc_random.h @@ -11,8 +11,12 @@ #include "src/common/xqc_str.h" #include "src/common/xqc_log.h" #include "src/common/xqc_common.h" -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS #include +#undef PKCS7_SIGNER_INFO +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef X509_NAME #endif @@ -24,8 +28,7 @@ typedef struct xqc_random_generator_s { xqc_str_t rand_buf; /* buffer for random bytes*/ xqc_log_t *log; - -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS HCRYPTPROV hProvider; #endif } xqc_random_generator_t; @@ -33,6 +36,7 @@ typedef struct xqc_random_generator_s { xqc_int_t xqc_get_random(xqc_random_generator_t *rand_gen, u_char *buf, size_t need_len); xqc_random_generator_t *xqc_random_generator_create(xqc_log_t *log); void xqc_random_generator_destroy(xqc_random_generator_t *rand_gen); +long xqc_random(void); #endif /* _XQC_RANDOM_H_INCLUDED_ */ diff --git a/src/common/xqc_siphash.h b/src/common/xqc_siphash.h new file mode 100644 index 000000000..48e85cff8 --- /dev/null +++ b/src/common/xqc_siphash.h @@ -0,0 +1,190 @@ +/** + * @copyright Copyright (c) 2025, Alibaba Group Holding Limited + */ + +#ifndef _XQC_SIPHASH_H_INCLUDED_ +#define _XQC_SIPHASH_H_INCLUDED_ + +#include +#include +#include +#include "src/common/xqc_common.h" + +#define XQC_SIPHASH_KEY_SIZE 16 +#define XQC_SIPHASH_C_ROUNDS 2 +#define XQC_SIPHASH_D_ROUNDS 4 +#define XQC_DEFAULT_HASH_SIZE 8 + +/* save siphash context */ +typedef struct xqc_siphash_ctx { + /* v0 v1 v2 v3 */ + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + int hash_size; /* save sizeof(hash), only 8 or 16 */ + /* SipHash-2-4 */ + int crounds; + int drounds; +} xqc_siphash_ctx_t; + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; \ + v3 = ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL(v2, 32); \ + } while (0) + +static inline int +xqc_siphash_init(xqc_siphash_ctx_t *ctx, const unsigned char *k, size_t key_len, + size_t hash_size, int crounds, int drounds) +{ + uint64_t k0, k1; + if (key_len != XQC_SIPHASH_KEY_SIZE) { + return XQC_ERROR; + } + /* hash_size must be 8 or 16 */ + if (hash_size != 8 && hash_size != 16) { + return XQC_ERROR; + } + k0 = U8TO64_LE(k); + k1 = U8TO64_LE(k + 8); + + ctx->v0 = 0x736f6d6570736575ULL ^ k0; + ctx->v1 = 0x646f72616e646f6dULL ^ k1; + ctx->v2 = 0x6c7967656e657261ULL ^ k0; + ctx->v3 = 0x7465646279746573ULL ^ k1; + + ctx->hash_size = hash_size; + if (hash_size == 16) { + ctx->v1 ^= 0xee; + } + /* default: SipHash-2-4 */ + if (crounds == 0) { + ctx->crounds = XQC_SIPHASH_C_ROUNDS; + } else { + ctx->crounds = crounds; + } + if (drounds == 0) { + ctx->drounds = XQC_SIPHASH_D_ROUNDS; + } else { + ctx->drounds = drounds; + } + return XQC_OK; +} + + +/* + Computes a SipHash value + *ctx: point to siphash context + *in: pointer to input data (read-only) + inlen: input data length in bytes (any size_t value) + *out: pointer to output data (write-only), outlen bytes must be allocated + outlen: length of the output in bytes, must be 8 or 16 +*/ + +static inline int +xqc_siphash(xqc_siphash_ctx_t *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen) +{ + uint64_t b = (uint64_t)inlen << 56, m; + const uint8_t *pi = in, *end = in + inlen - (inlen % sizeof(uint64_t)); + int left = inlen & 7; + int i = 0; + uint64_t v0 = ctx->v0; + uint64_t v1 = ctx->v1; + uint64_t v2 = ctx->v2; + uint64_t v3 = ctx->v3; + + if (outlen != ctx->hash_size) { + return XQC_ERROR; + } + + for(; pi != end; pi += 8) { + m = U8TO64_LE(pi); + v3 ^= m; + for (i = 0; i < ctx->crounds; i++) { + SIPROUND; + } + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t)pi[6]) << 48; + case 6: + b |= ((uint64_t)pi[5]) << 40; + case 5: + b |= ((uint64_t)pi[4]) << 32; + case 4: + b |= ((uint64_t)pi[3]) << 24; + case 3: + b |= ((uint64_t)pi[2]) << 16; + case 2: + b |= ((uint64_t)pi[1]) << 8; + case 1: + b |= ((uint64_t)pi[0]); + break; + case 0: + break; + } + + v3 ^= b; + for (i = 0; i < ctx->crounds; ++i) + SIPROUND; + v0 ^= b; + + if (outlen == 16) { + v2 ^= 0xee; + } else { + v2 ^= 0xff; + } + + for (i = 0; i < ctx->drounds; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + if (outlen == 8) { + return XQC_OK; + } + v1 ^= 0xdd; + for (i = 0; i < ctx->drounds; ++i) + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + return XQC_OK; +} + + + + +#endif /* _XQC_SIPHASH_H_INCLUDED_ */ diff --git a/src/common/xqc_str.c b/src/common/xqc_str.c index d4b156a61..cd17fb7ff 100644 --- a/src/common/xqc_str.c +++ b/src/common/xqc_str.c @@ -218,7 +218,7 @@ xqc_vsprintf(unsigned char *buf, unsigned char *last, const char *fmt, va_list a fmt++; continue; -#ifndef WIN32 +#ifndef XQC_SYS_WINDOWS case 'r': i64 = (int64_t) va_arg(args, rlim_t); sign = 1; @@ -283,13 +283,13 @@ xqc_sprintf_num(unsigned char *buf, unsigned char *last, uint64_t ui64, unsigned { unsigned char *p, temp[XQC_INT64_LEN + 1]; /* - * we need temp[NGX_INT64_LEN] only, + * we need temp[XQC_INT64_LEN] only, * but icc issues the warning */ size_t len; uint32_t ui32; - static unsigned char hex[] = "0123456789abcdef"; - static unsigned char HEX[] = "0123456789ABCDEF"; + static const unsigned char hex[] = "0123456789abcdef"; + static const unsigned char HEX[] = "0123456789ABCDEF"; p = temp + XQC_INT64_LEN; diff --git a/src/common/xqc_str.h b/src/common/xqc_str.h index 6c4b6f036..9ea4612f2 100644 --- a/src/common/xqc_str.h +++ b/src/common/xqc_str.h @@ -9,15 +9,15 @@ #include #include #include -#ifndef WIN32 -#include -#endif #include #include +#include #include "src/common/xqc_config.h" -#include "include/xquic/xquic_typedef.h" +#ifndef XQC_SYS_WINDOWS +#include +#endif typedef struct xqc_str_s { size_t len; @@ -95,5 +95,46 @@ xqc_memeq(const void *s1, const void *s2, size_t n) return n == 0 || memcmp(s1, s2, n) == 0; } +inline static xqc_bool_t +xqc_char_is_letter_or_number(char c) +{ + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9')) + { + return XQC_TRUE; + } + return XQC_FALSE; +} + +static inline void +xqc_int_2_str(char *output, uint32_t val, xqc_int_t val_len) +{ + xqc_int_t i, tail; + i = val_len - 1; + while (val > 0 && i >= 0) { + tail = val % 10; + output[i] = '0' + tail; + i--; + val /= 10; + } + for (i; i >= 0; i--) { + output[i] = '0'; + } +} + +static inline uint32_t +xqc_str_2_int(char *str, xqc_int_t str_len) +{ + xqc_int_t i, tmp, result; + result = 0; + + for (i = 0; i < str_len; i++) { + result *= 10; + tmp = str[i] - '0'; + result += tmp; + } + + return result; +} #endif /*_XQC_STR_H_INCLUDED_*/ diff --git a/src/common/xqc_str_hash.h b/src/common/xqc_str_hash.h index 21eec2151..9126fb742 100644 --- a/src/common/xqc_str_hash.h +++ b/src/common/xqc_str_hash.h @@ -6,8 +6,21 @@ #define _XQC_STR_HASH_INCLUDED_ #include +#include #include "src/common/xqc_str.h" +#include "src/common/xqc_siphash.h" +#include "src/common/xqc_log.h" + +/* + * default log threshold of number of element in on bucket + * test result of max conflict (default 1024*1024 hash buckets) in one bucket: + * 100000 connections, the max conflict is 5 + * 1000000 connections, the max conflict is 24 + */ +#define XQC_HASH_DEFAULT_CONFLICT_THRESHOLD 50 +/* 10 second, log interval must not less then 10 second */ +#define XQC_HASH_CONFLICT_LOG_INTERVAL 10 typedef struct xqc_str_hash_element_s { uint64_t hash; @@ -24,12 +37,44 @@ typedef struct xqc_str_hash_table_s { xqc_str_hash_node_t **list; size_t count; xqc_allocator_t allocator; /* memory allocator */ + uint8_t *conflict_stat; /* statistic the number of elements in every bucket */ + xqc_siphash_ctx_t siphash_ctx; /* siphash context */ + uint32_t conflict_thres; /* conflict threshold in one bucket, warning if exceeded */ + time_t last_log_time; /* last timestamp(second) for logging the max conflict value*/ + xqc_log_t *log; /* pointer to engine's log*/ } xqc_str_hash_table_t; +/* calculate the hash value using the siphash algorithm */ +static inline uint64_t +xqc_siphash_get_hash(xqc_siphash_ctx_t *ctx, const uint8_t *data, size_t len) +{ + uint64_t hash_value; + if (xqc_siphash(ctx, data, len, (uint8_t *)(&hash_value), sizeof(hash_value)) == XQC_OK) { + return hash_value; + } + /* + * impossible, we set hash_size value 8 when we call xqc_siphash_init, sizeof(hash_value) is always 8 + * xqc_siphash return XQC_ERROR only when hash_size not equal sizeof(hash_value), it is impossible here + */ + return 0; +} static inline int -xqc_str_hash_init(xqc_str_hash_table_t *hash_tab, xqc_allocator_t allocator, size_t bucket_num) +xqc_str_hash_init(xqc_str_hash_table_t *hash_tab, + xqc_allocator_t allocator, size_t bucket_num, + uint32_t conflict_thres, uint8_t *key, + size_t key_len, xqc_log_t *log) { + if (bucket_num == 0) { /* impossible */ + return XQC_ERROR; + } + if (key_len != XQC_SIPHASH_KEY_SIZE) { /* siphash key length must be 16 */ + return XQC_ERROR; + } + if (log == NULL) { + return XQC_ERROR; + } + xqc_memzero(hash_tab, sizeof(xqc_str_hash_table_t)); hash_tab->allocator = allocator; hash_tab->list = allocator.malloc(allocator.opaque, sizeof(xqc_str_hash_node_t *) * bucket_num); if (hash_tab->list == NULL) { @@ -37,7 +82,34 @@ xqc_str_hash_init(xqc_str_hash_table_t *hash_tab, xqc_allocator_t allocator, si } xqc_memzero(hash_tab->list, sizeof(xqc_str_hash_node_t *) * bucket_num); hash_tab->count = bucket_num; + hash_tab->conflict_stat = allocator.malloc(allocator.opaque, sizeof(uint8_t) * bucket_num); + if (hash_tab->conflict_stat == NULL) { + goto fail; + } + xqc_memzero(hash_tab->conflict_stat, sizeof(uint8_t) * bucket_num); + if (conflict_thres > 0) { + hash_tab->conflict_thres = conflict_thres; + } else { + hash_tab->conflict_thres = XQC_HASH_DEFAULT_CONFLICT_THRESHOLD; + } + hash_tab->last_log_time = 0; + hash_tab->log = log; + if (xqc_siphash_init(&hash_tab->siphash_ctx, key, key_len, + XQC_DEFAULT_HASH_SIZE, XQC_SIPHASH_C_ROUNDS, + XQC_SIPHASH_D_ROUNDS) != XQC_OK) + { + goto fail; + } return XQC_OK; + +fail: + if (hash_tab->list) { + allocator.free(allocator.opaque, hash_tab->list); + } + if (hash_tab->conflict_stat) { + allocator.free(allocator.opaque, hash_tab->conflict_stat); + } + return XQC_ERROR; } static inline void @@ -53,6 +125,7 @@ xqc_str_hash_release(xqc_str_hash_table_t *hash_tab) } } a->free(a->opaque, hash_tab->list); + a->free(a->opaque, hash_tab->conflict_stat); } static inline void * @@ -90,6 +163,16 @@ xqc_str_hash_add(xqc_str_hash_table_t *hash_tab, xqc_str_hash_element_t e) node->next = hash_tab->list[index]; hash_tab->list[index] = node; + hash_tab->conflict_stat[index] += 1; + if (hash_tab->conflict_stat[index] > hash_tab->conflict_thres) { + time_t now_sec = time(NULL); + if (now_sec >= hash_tab->last_log_time + XQC_HASH_CONFLICT_LOG_INTERVAL) { + xqc_log(hash_tab->log, XQC_LOG_WARN, + "|xqc conn hash conflict exceed|index:%ui, number of elements:%d|", + index, hash_tab->conflict_stat[index]); + hash_tab->last_log_time = now_sec; + } + } return XQC_OK; } @@ -104,6 +187,9 @@ xqc_str_hash_delete(xqc_str_hash_table_t *hash_tab, uint64_t hash, xqc_str_t str while (node) { if (node->element.hash == hash && xqc_str_equal(str, node->element.str)) { *pp = node->next; + if (hash_tab->conflict_stat[index] > 0) { + hash_tab->conflict_stat[index] -= 1; + } a->free(a->opaque, node->element.str.data); a->free(a->opaque, node); return XQC_OK; diff --git a/src/common/xqc_time.c b/src/common/xqc_time.c index dc2fb29a3..be210a77a 100644 --- a/src/common/xqc_time.c +++ b/src/common/xqc_time.c @@ -4,8 +4,13 @@ #include "xqc_time.h" -#ifdef WIN32 -#define DELTA_EPOCH_IN_TICKS 116444736000000000ULL +#ifdef XQC_SYS_WINDOWS +#ifndef _GETTIMEOFDAY_DEFINED + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of DST correction */ +}; int gettimeofday(struct timeval *tv, struct timezone *tz) @@ -13,15 +18,13 @@ gettimeofday(struct timeval *tv, struct timezone *tz) FILETIME ft; uint64_t tmpres; static int tzflag; - if (NULL != tv) { GetSystemTimeAsFileTime(&ft); - tmpres = ((uint64_t) ft.dwHighDateTime << 32) | (ft.dwLowDateTime); - - tmpres -= DELTA_EPOCH_IN_TICKS; - tv->tv_sec = tmpres / 10000000; + tmpres /= 10; /* Convert from 100-nanosecond intervals to microseconds */ + tmpres -= 11644473600000000ULL; /* Convert from Windows epoch (1601-01-01) to Unix epoch (1970-01-01) */ + tv->tv_sec = tmpres / 1000000; tv->tv_usec = tmpres % 1000000; } @@ -37,8 +40,9 @@ gettimeofday(struct timeval *tv, struct timezone *tz) return 0; } #endif +#endif -static xqc_usec_t +xqc_usec_t xqc_now() { /* get microsecond unit time */ diff --git a/src/common/xqc_time.h b/src/common/xqc_time.h index 604e02752..dfbc756fa 100644 --- a/src/common/xqc_time.h +++ b/src/common/xqc_time.h @@ -5,18 +5,19 @@ #ifndef _XQC_TIME_H_INCLUDED_ #define _XQC_TIME_H_INCLUDED_ -#ifndef WIN32 -#include -#endif -#ifdef MINGW_HAS_SECURE_API -#include -#endif #include #include +#include -#ifdef WIN32 +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + +#ifdef XQC_SYS_WINDOWS +#ifndef _GETTIMEOFDAY_DEFINED int gettimeofday(struct timeval *tv, struct timezone *tz); #endif +#endif /** diff --git a/src/congestion_control/xqc_bbr.c b/src/congestion_control/xqc_bbr.c index c497abb6d..6392c7520 100644 --- a/src/congestion_control/xqc_bbr.c +++ b/src/congestion_control/xqc_bbr.c @@ -2,12 +2,18 @@ * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ + #include #include #include +#include +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif #include "src/congestion_control/xqc_bbr.h" #include "src/congestion_control/xqc_sample.h" #include "src/common/xqc_time.h" +#include "src/common/xqc_random.h" #include "src/common/xqc_config.h" #include "src/transport/xqc_send_ctl.h" #include "src/transport/xqc_packet.h" @@ -50,19 +56,19 @@ const float xqc_bbr_fullbw_thresh = 1.1; /* After 3 rounds bandwidth less than (1.25x), estimate the pipe is full */ const uint32_t xqc_bbr_fullbw_cnt = 3; const float xqc_bbr_probe_rtt_gain = 0.75; -const uint32_t xqc_bbr_extra_ack_gain = 1; -const float xqc_bbr_max_extra_ack_time = 0.1; -const uint32_t xqc_bbr_ack_epoch_acked_reset_thresh = 1 << 20; +const uint32_t xqc_bbr_extra_ack_gain = 2; +const float xqc_bbr_max_extra_ack_time = 0.2; +const uint32_t xqc_bbr_ack_epoch_acked_reset_thresh = (1 << 20) * XQC_BBR_MAX_DATAGRAMSIZE; const float xqc_bbr_pacing_rate_margin_percent = 0; /* BBRv2 parameters */ const float xqc_bbr2_drain_gain = 0.75; -const float xqc_bbr2_startup_cwnd_gain = 2.885 + 2; +const float xqc_bbr2_startup_cwnd_gain = 2.885; /* keep minrtt valid for 10s if it has not been changed */ -const uint32_t xqc_bbr2_minrtt_win_size_us = 3000000; +const uint32_t xqc_bbr2_minrtt_win_size_us = 10000000; /* probe new minrtt in 2.5s*/ -const uint32_t xqc_bbr2_probertt_win_size_us = 2500000; +const uint32_t xqc_bbr2_probertt_win_size_us = 10000000; const bool xqc_bbr2_extra_ack_in_startup = 1; /* 10 packet-timed rtt */ const uint32_t xqc_bbr2_extra_ack_win_rtt = 5; @@ -72,6 +78,13 @@ const uint32_t xqc_bbr2_extra_ack_win_rtt_in_startup = 1; const float xqc_bbr2_startup_pacing_gain_on_lost = 1.5; const bool xqc_bbr2_slow_down_startup_on_lost = 0; +const uint32_t xqc_bbr_lt_bw_interval_min_rtts = 4; +const float xqc_bbr_lt_bw_loss_thresh = 0.2; // 20% +const float xqc_bbr_lt_bw_ratio = 0.125; // 1/8 +const uint32_t xqc_bbr_lt_bw_diff = 4000; // 4000 B/s +const uint32_t xqc_bbr_lt_bw_interval_max_rtts = 16; +const uint32_t xqc_bbr_lt_bw_max_rtts = 48; // use lt_bw for 48xRTT at maximum + /* 5RTT */ #if XQC_BBR_RTTVAR_COMPENSATION_ENABLED static const float xqc_bbr_windowed_max_rtt_win_size = 5; @@ -80,6 +93,8 @@ static const float xqc_bbr_rtt_compensation_thresh = 1; static const float xqc_bbr_rtt_compensation_cwnd_factor = 1; #endif +static void xqc_bbr_enter_probe_bw(xqc_bbr_t *bbr, xqc_sample_t *sampler); + size_t xqc_bbr_size() { @@ -109,6 +124,112 @@ xqc_bbr_init_pacing_rate(xqc_bbr_t *bbr, xqc_sample_t *sampler) bbr->pacing_rate = bbr->pacing_gain * bandwidth; } +static void +xqc_bbr_reset_lt_bw_sampling(xqc_bbr_t *bbr) +{ + bbr->lt_is_sampling = 0; + bbr->lt_bw = 0; + bbr->lt_use_bw = 0; + bbr->lt_last_lost_pkt = 0; + bbr->lt_last_delivered_bytes = 0; + bbr->lt_last_stamp = 0; + bbr->lt_rtt_cnt = 0; +} + +static void +xqc_bbr_new_lt_bw_interval(xqc_bbr_t *bbr, xqc_sample_t *sampler) +{ + bbr->lt_rtt_cnt = 0; + bbr->lt_last_delivered_bytes = sampler->total_acked; + bbr->lt_last_lost_pkt = sampler->total_lost_pkts; + bbr->lt_last_stamp = sampler->now; +} + +static void +xqc_bbr_finish_lt_bw_interval(xqc_bbr_t *bbr, + xqc_sample_t *sampler, uint64_t bw) +{ + uint64_t diff = 0; + if (bbr->lt_bw) { + diff = bbr->lt_bw > bw ? bbr->lt_bw - bw : bw - bbr->lt_bw; + /* the observed policing rate is consistent */ + if (diff <= (uint64_t)(bbr->lt_bw * xqc_bbr_lt_bw_ratio) + || diff <= (xqc_bbr_lt_bw_diff)) + { + bbr->lt_bw = (bw + bbr->lt_bw) >> 1; + bbr->lt_use_bw = 1; + bbr->lt_rtt_cnt = 0; + bbr->pacing_gain = 1.0; + return; + } + } + bbr->lt_bw = bw; + xqc_bbr_new_lt_bw_interval(bbr, sampler); +} + +static void +xqc_bbr_update_lt_bw_sampling(xqc_bbr_t *bbr, xqc_sample_t *sampler) +{ + if (bbr->lt_use_bw) { + if (bbr->mode == BBR_PROBE_BW && bbr->round_start + && ++bbr->lt_rtt_cnt >= xqc_bbr_lt_bw_max_rtts) + { + xqc_bbr_reset_lt_bw_sampling(bbr); + xqc_bbr_enter_probe_bw(bbr, sampler); + return; + } + } + + if (!bbr->lt_is_sampling) { + if (sampler->loss == 0) { + return; + } + bbr->lt_is_sampling = XQC_TRUE; + xqc_bbr_new_lt_bw_interval(bbr, sampler); + } + + if (sampler->is_app_limited) { + xqc_bbr_reset_lt_bw_sampling(bbr); + return; + } + + if (bbr->round_start) { + bbr->lt_rtt_cnt++; + } + + if (bbr->lt_rtt_cnt < xqc_bbr_lt_bw_interval_min_rtts) { + return; // wait a bit for sampling + } + + if (bbr->lt_rtt_cnt > xqc_bbr_lt_bw_interval_max_rtts) { + xqc_bbr_reset_lt_bw_sampling(bbr); + return; // stop sampling as the interval is too long + } + + if (sampler->loss == 0) { + return; // wait for losses + } + + uint64_t lost_bytes = (sampler->total_lost_pkts - bbr->lt_last_lost_pkt) * XQC_BBR_MAX_DATAGRAMSIZE; + uint64_t acked_bytes = sampler->total_acked - bbr->lt_last_delivered_bytes; + + if (acked_bytes == 0 + || lost_bytes < (uint64_t)(acked_bytes * xqc_bbr_lt_bw_loss_thresh)) + { + return; // wait for more losses + } + + xqc_usec_t interval = sampler->now - bbr->lt_last_stamp; + + if (interval < 1000) { + return; // interval is too small. let's wait. + } + + uint64_t policing_rate = acked_bytes * 1000000 / interval; + + xqc_bbr_finish_lt_bw_interval(bbr, sampler, policing_rate); +} + static void xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) { @@ -142,7 +263,7 @@ xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) bbr->packet_conservation = FALSE; bbr->prior_cwnd = 0; bbr->initial_congestion_window = XQC_BBR_INITIAL_WINDOW; - bbr->congestion_window = bbr->initial_congestion_window; + bbr->min_cwnd = xqc_bbr_min_cwnd; bbr->has_srtt = 0; bbr->idle_restart = 0; bbr->packet_conservation = 0; @@ -161,13 +282,19 @@ xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) bbr->extra_ack_win_len_in_startup = xqc_bbr2_extra_ack_win_rtt_in_startup; bbr->full_bandwidth_cnt = 0; bbr->full_bandwidth_reached = FALSE; + bbr->lt_bw_enabled = XQC_FALSE; + bbr->ignore_app_limit = XQC_FALSE; if (cc_params.customize_on) { cc_params.init_cwnd *= XQC_BBR_MAX_DATAGRAMSIZE; + cc_params.min_cwnd *= XQC_BBR_MAX_DATAGRAMSIZE; bbr->initial_congestion_window = cc_params.init_cwnd >= XQC_BBR_MIN_WINDOW && cc_params.init_cwnd <= XQC_BBR_MAX_WINDOW ? cc_params.init_cwnd : XQC_BBR_INITIAL_WINDOW; + bbr->min_cwnd = cc_params.min_cwnd >= XQC_BBR_MIN_WINDOW + && cc_params.min_cwnd <= XQC_BBR_MAX_WINDOW + ? cc_params.min_cwnd : xqc_bbr_min_cwnd; if (cc_params.expect_bw > 0) { bbr->enable_expect_bw = TRUE; @@ -177,8 +304,16 @@ xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) bbr->enable_max_expect_bw = TRUE; bbr->max_expect_bw = cc_params.max_expect_bw; } + if (cc_params.bbr_enable_lt_bw) { + bbr->lt_bw_enabled = XQC_TRUE; + } + if (cc_params.bbr_ignore_app_limit) { + bbr->ignore_app_limit = XQC_TRUE; + } } + bbr->congestion_window = bbr->initial_congestion_window; + xqc_bbr_reset_lt_bw_sampling(bbr); xqc_bbr_enter_startup(bbr); xqc_bbr_init_pacing_rate(bbr, sampler); } @@ -189,6 +324,12 @@ xqc_bbr_max_bw(xqc_bbr_t *bbr) return xqc_win_filter_get(&bbr->bandwidth); } +static uint32_t +xqc_bbr_bw(xqc_bbr_t *bbr) +{ + return bbr->lt_use_bw && bbr->lt_bw_enabled ? bbr->lt_bw : xqc_bbr_max_bw(bbr); +} + static void xqc_bbr_update_bandwidth(xqc_bbr_t *bbr, xqc_sample_t *sampler) { @@ -212,11 +353,14 @@ xqc_bbr_update_bandwidth(xqc_bbr_t *bbr, xqc_sample_t *sampler) "|BBRv1: RTT round update %ud -> %ud|", bbr->round_cnt - 1, bbr->round_cnt); } - /* FIXED: It may reduce the est. bw due to network instability. */ - /* if (sampler->lagest_ack_time > bbr->last_round_trip_time) { - bbr->round_cnt++; - bbr->last_round_trip_time = xqc_monotonic_timestamp(); - } */ + + if (bbr->lt_bw_enabled + && bbr->mode != BBR_STARTUP + && bbr->mode != BBR_DRAIN) + { + xqc_bbr_update_lt_bw_sampling(bbr, sampler); + } + uint32_t bandwidth; /* Calculate the new bandwidth, bytes per second */ bandwidth = 1.0 * sampler->delivered / sampler->interval * MSEC2SEC; @@ -224,8 +368,12 @@ xqc_bbr_update_bandwidth(xqc_bbr_t *bbr, xqc_sample_t *sampler) if (bbr->enable_max_expect_bw && bandwidth >= bbr->max_expect_bw) { bandwidth = bbr->max_expect_bw; } - - if (!sampler->is_app_limited || bandwidth >= xqc_bbr_max_bw(bbr)) { + + /* + * In a live video scenario, the applimit state often occurs, + * causing the detection bandwidth increases but does not decrease. + */ + if (bbr->ignore_app_limit || !sampler->is_app_limited || bandwidth >= xqc_bbr_max_bw(bbr)) { xqc_win_filter_max(&bbr->bandwidth, xqc_bbr_bw_win_size, bbr->round_cnt, bandwidth); xqc_log(sampler->send_ctl->ctl_conn->log, XQC_LOG_DEBUG, @@ -235,9 +383,9 @@ xqc_bbr_update_bandwidth(xqc_bbr_t *bbr, xqc_sample_t *sampler) } static uint32_t -xqc_bbr_bdp(xqc_bbr_t *bbr) +xqc_bbr_bdp(xqc_bbr_t *bbr, uint64_t bw) { - return bbr->min_rtt * xqc_win_filter_get(&bbr->bandwidth) / MSEC2SEC; + return bbr->min_rtt * bw / MSEC2SEC; } #if XQC_BBR_RTTVAR_COMPENSATION_ENABLED @@ -267,13 +415,13 @@ xqc_bbr_compensate_cwnd_for_rttvar(xqc_bbr_t *bbr, xqc_sample_t *sampler) #endif static uint32_t -xqc_bbr_target_cwnd(xqc_bbr_t *bbr, float gain) +xqc_bbr_target_cwnd(xqc_bbr_t *bbr, float gain, uint64_t bw) { if (bbr->min_rtt == XQC_BBR_INF) { return bbr->initial_congestion_window; } - uint32_t cwnd = gain * xqc_bbr_bdp(bbr); - return xqc_max(cwnd, XQC_BBR_MIN_WINDOW); + uint32_t cwnd = gain * xqc_bbr_bdp(bbr, bw); + return xqc_max(cwnd, bbr->min_cwnd); } static bool @@ -285,12 +433,14 @@ xqc_bbr_is_next_cycle_phase(xqc_bbr_t *bbr, xqc_sample_t *sampler) if (bbr->pacing_gain > 1.0) { should_advance_gain_cycling = is_full_length && (sampler->loss - || inflight >= xqc_bbr_target_cwnd(bbr, bbr->pacing_gain)); + || inflight >= xqc_bbr_target_cwnd(bbr, + bbr->pacing_gain, + xqc_bbr_max_bw(bbr))); } /* Drain to target: 1xBDP */ if (bbr->pacing_gain < 1.0) { should_advance_gain_cycling = is_full_length - || (inflight <= xqc_bbr_target_cwnd(bbr, 1.0)); + || (inflight <= xqc_bbr_target_cwnd(bbr, 1.0, xqc_bbr_max_bw(bbr))); } return should_advance_gain_cycling; } @@ -298,9 +448,14 @@ xqc_bbr_is_next_cycle_phase(xqc_bbr_t *bbr, xqc_sample_t *sampler) static float xqc_bbr_get_pacing_gain(xqc_bbr_t *bbr, uint32_t cycle_idx) { + if (bbr->lt_use_bw && bbr->lt_bw_enabled) { + return 1.0; + } + if (bbr->enable_expect_bw && xqc_bbr_max_bw(bbr) >= bbr->expect_bw) { return xqc_bbr_low_pacing_gain[cycle_idx]; } + return xqc_bbr_pacing_gain[cycle_idx]; } @@ -329,7 +484,7 @@ xqc_bbr_ack_aggregation_cwnd(xqc_bbr_t *bbr) if (xqc_bbr_extra_ack_gain && (bbr->full_bandwidth_reached || bbr->extra_ack_in_startup)) { - max_aggr_cwnd = xqc_bbr_max_bw(bbr) * xqc_bbr_max_extra_ack_time; + max_aggr_cwnd = xqc_bbr_bw(bbr) * xqc_bbr_max_extra_ack_time; aggr_cwnd = xqc_bbr_extra_ack_gain * xqc_bbr_extra_ack(bbr); aggr_cwnd = xqc_min(aggr_cwnd, max_aggr_cwnd); } @@ -360,7 +515,7 @@ xqc_update_ack_aggregation(xqc_bbr_t *bbr, xqc_sample_t *sampler) } epoch = sampler->now - bbr->extra_ack_stamp; - expected_ack = ((uint64_t)xqc_bbr_max_bw(bbr) * epoch) / MSEC2SEC; + expected_ack = ((uint64_t)xqc_bbr_bw(bbr) * epoch) / MSEC2SEC; if (bbr->epoch_ack <= expected_ack || (bbr->epoch_ack + sampler->acked @@ -389,8 +544,12 @@ xqc_bbr_check_full_bw_reached(xqc_bbr_t *bbr, xqc_sample_t *sampler) * Otherwise, startup may end too early due to multiple ACKs arrive in a RTT. */ if (!bbr->round_start || bbr->full_bandwidth_reached - || sampler->is_app_limited) + || (!bbr->ignore_app_limit && sampler->is_app_limited)) { + /* + * In a live video scenario, the applimit state often occurs, + * causing the startup state to persist for a long time. + */ return; } @@ -422,7 +581,7 @@ xqc_bbr_enter_probe_bw(xqc_bbr_t *bbr, xqc_sample_t *sampler) { bbr->mode = BBR_PROBE_BW; bbr->cwnd_gain = xqc_bbr_cwnd_gain; - bbr->cycle_idx = random() % (XQC_BBR_CYCLE_LENGTH - 1); + bbr->cycle_idx = xqc_random() % (XQC_BBR_CYCLE_LENGTH - 1); bbr->cycle_idx = bbr->cycle_idx == 0 ? bbr->cycle_idx : bbr->cycle_idx + 1; bbr->pacing_gain = xqc_bbr_get_pacing_gain(bbr, bbr->cycle_idx); bbr->cycle_start_stamp = sampler->now; @@ -435,14 +594,17 @@ xqc_bbr_check_drain(xqc_bbr_t *bbr, xqc_sample_t *sampler) if (bbr->mode == BBR_STARTUP && bbr->full_bandwidth_reached) { xqc_bbr_enter_drain(bbr); } + if (bbr->mode == BBR_DRAIN - && sampler->bytes_inflight <= xqc_bbr_target_cwnd(bbr, 1.0)) { + && sampler->bytes_inflight <= xqc_bbr_target_cwnd(bbr, + 1.0, + xqc_bbr_max_bw(bbr))) + { #if XQC_BBR_RTTVAR_COMPENSATION_ENABLED bbr->rtt_compensation_thresh = xqc_bbr_rtt_compensation_thresh; #endif xqc_bbr_enter_probe_bw(bbr, sampler); } - } static void @@ -500,9 +662,13 @@ static uint32_t xqc_bbr_probe_rtt_cwnd(xqc_bbr_t *bbr) { if (xqc_bbr_probe_rtt_gain == 0) { - return xqc_bbr_min_cwnd; + return bbr->min_cwnd; } - return xqc_max(xqc_bbr_min_cwnd, xqc_bbr_target_cwnd(bbr, xqc_bbr_probe_rtt_gain)); + + return xqc_max(bbr->min_cwnd, + xqc_bbr_target_cwnd(bbr, + xqc_bbr_probe_rtt_gain, + xqc_bbr_max_bw(bbr))); } static void @@ -561,7 +727,8 @@ xqc_bbr_update_min_rtt(xqc_bbr_t *bbr, xqc_sample_t *sampler) /* Ignore low rate samples during this mode. */ xqc_send_ctl_t *send_ctl = sampler->send_ctl; send_ctl->ctl_app_limited = (send_ctl->ctl_delivered - + send_ctl->ctl_bytes_in_flight)? : 1; + + send_ctl->ctl_bytes_in_flight)? (send_ctl->ctl_delivered + + send_ctl->ctl_bytes_in_flight) : 1; xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|BBR PROBE_RTT|inflight:%ud|done_stamp:%ui|done:%ud|" "round_start:%ud|", @@ -602,7 +769,7 @@ static void _xqc_bbr_set_pacing_rate_helper(xqc_bbr_t *bbr, float pacing_gain) { uint32_t bandwidth, rate; - bandwidth = xqc_bbr_max_bw(bbr); + bandwidth = xqc_bbr_bw(bbr); rate = bandwidth * pacing_gain * (1.0 - xqc_bbr_pacing_rate_margin_percent); if (bbr->full_bandwidth_reached || rate > bbr->pacing_rate) { bbr->pacing_rate = rate; @@ -634,6 +801,12 @@ xqc_bbr_modulate_cwnd_for_recovery(xqc_bbr_t *bbr, xqc_sample_t *sampler) bbr->congestion_window, sampler->loss, sampler->acked, sampler->po_sent_time, bbr->recovery_mode, bbr->recovery_start_time, bbr->packet_conservation, bbr->next_round_delivered); + + /* + * No need react to losses. + * It hurts throughput under shallow-buffered networks + */ +#if 0 if (sampler->loss > 0) { /* to avoid underflow of unsigned numbers */ if (bbr->congestion_window @@ -647,6 +820,8 @@ xqc_bbr_modulate_cwnd_for_recovery(xqc_bbr_t *bbr, xqc_sample_t *sampler) bbr->congestion_window = xqc_max(bbr->congestion_window, XQC_BBR_MAX_DATAGRAMSIZE); } +#endif + if (bbr->just_enter_recovery_mode) { bbr->just_enter_recovery_mode = FALSE; bbr->packet_conservation = 1; @@ -685,7 +860,7 @@ xqc_bbr_reset_cwnd(void *cong_ctl) xqc_bbr_t *bbr = (xqc_bbr_t *)cong_ctl; xqc_bbr_save_cwnd(bbr); /* reduce cwnd to the minimal value */ - bbr->congestion_window = XQC_BBR_MIN_WINDOW; + bbr->congestion_window = bbr->min_cwnd; /* cancel recovery state */ if (bbr->recovery_mode == BBR_IN_RECOVERY) { bbr->recovery_mode = BBR_NOT_IN_RECOVERY; @@ -694,6 +869,11 @@ xqc_bbr_reset_cwnd(void *cong_ctl) } /* reset recovery start time in any case */ bbr->recovery_start_time = 0; + + if (bbr->lt_bw_enabled) { + xqc_bbr_reset_lt_bw_sampling(bbr); + } + #ifndef XQC_BBR_DISABLE_CWND_AI /* If losses happened, we do not increase cwnd beyond target_cwnd. */ bbr->snd_cwnd_cnt_bytes = 0; @@ -737,7 +917,7 @@ xqc_bbr_set_cwnd(xqc_bbr_t *bbr, xqc_sample_t *sampler) xqc_send_ctl_t *send_ctl = sampler->send_ctl; uint32_t target_cwnd, extra_cwnd; - target_cwnd = xqc_bbr_target_cwnd(bbr, bbr->cwnd_gain); + target_cwnd = xqc_bbr_target_cwnd(bbr, bbr->cwnd_gain, xqc_bbr_bw(bbr)); extra_cwnd = xqc_bbr_ack_aggregation_cwnd(bbr); xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|xqc_bbr_set_cwnd|target_cwnd:%ud|extra_cwnd:%ud|", @@ -786,7 +966,7 @@ xqc_bbr_set_cwnd(xqc_bbr_t *bbr, xqc_sample_t *sampler) bbr->congestion_window += sampler->acked; } } - bbr->congestion_window = xqc_max(bbr->congestion_window, xqc_bbr_min_cwnd); + bbr->congestion_window = xqc_max(bbr->congestion_window, bbr->min_cwnd); } if (bbr->mode == BBR_PROBE_RTT) { bbr->congestion_window = xqc_min(bbr->congestion_window, @@ -798,6 +978,12 @@ static void xqc_bbr_on_lost(void *cong_ctl, xqc_usec_t lost_sent_time) { xqc_bbr_t *bbr = (xqc_bbr_t *)cong_ctl; + + if (bbr->mode == BBR_STARTUP) { + /* do not enter loss recovery state during startup */ + return; + } + /* * Unlike the definition of "recovery epoch" for loss-based CCs, * for the sake of resistance to losses, we MUST refresh the end of a @@ -805,8 +991,10 @@ xqc_bbr_on_lost(void *cong_ctl, xqc_usec_t lost_sent_time) * ability of BBR to sustain network where high loss rate presents * is hampered because of frequently entering packet conservation state. */ + xqc_bbr_save_cwnd(bbr); bbr->recovery_start_time = xqc_monotonic_timestamp(); + #ifndef XQC_BBR_DISABLE_CWND_AI /* If losses happened, we do not increase cwnd beyond target_cwnd. */ bbr->snd_cwnd_cnt_bytes = 0; @@ -898,15 +1086,16 @@ static uint32_t xqc_bbr_get_pacing_rate(void *cong_ctl) { xqc_bbr_t *bbr = (xqc_bbr_t *)(cong_ctl); - - return bbr->pacing_rate; + xqc_usec_t min_rtt = (bbr->min_rtt && (bbr->min_rtt != XQC_BBR_INF) ? bbr->min_rtt : 10000); + uint32_t min_pacing_rate = bbr->min_cwnd * (uint64_t)MSEC2SEC / min_rtt; + return xqc_max(bbr->pacing_rate, bbr->pacing_gain * min_pacing_rate); } static uint32_t xqc_bbr_get_bandwidth(void *cong_ctl) { xqc_bbr_t *bbr = (xqc_bbr_t *)(cong_ctl); - return xqc_bbr_max_bw(bbr); + return xqc_bbr_bw(bbr); } static void @@ -920,6 +1109,10 @@ xqc_bbr_restart_from_idle(void *cong_ctl, uint64_t conn_delivered) bbr->epoch_ack = 0; xqc_sample_t sampler = {.now = now, .total_acked = conn_delivered}; + if (bbr->lt_bw_enabled) { + xqc_bbr_reset_lt_bw_sampling(bbr); + } + if (bbr->mode == BBR_PROBE_BW) { _xqc_bbr_set_pacing_rate_helper(bbr, 1.0); if (bbr->pacing_rate == 0) { diff --git a/src/congestion_control/xqc_bbr.h b/src/congestion_control/xqc_bbr.h index 2ec5ec0ff..7c1a89408 100644 --- a/src/congestion_control/xqc_bbr.h +++ b/src/congestion_control/xqc_bbr.h @@ -29,7 +29,7 @@ typedef enum { } xqc_bbr_mode; typedef enum { - BBR_NOT_IN_RECOVERY=0, + BBR_NOT_IN_RECOVERY = 0, BBR_IN_RECOVERY, } xqc_bbr_recovery_mode; @@ -62,6 +62,7 @@ typedef struct xqc_bbr_s { uint32_t prior_cwnd; /* Initial congestion window of connection */ uint32_t initial_congestion_window; + uint32_t min_cwnd; /* Current pacing rate */ uint32_t pacing_rate; /* Gain currently applied to pacing rate */ @@ -142,6 +143,19 @@ typedef struct xqc_bbr_s { uint32_t rtt_compensation_thresh; uint8_t rttvar_compensation_on; #endif + + /* for long-term bw sampling */ + xqc_bool_t lt_bw_enabled; + uint64_t lt_last_lost_pkt; + uint64_t lt_last_delivered_bytes; + xqc_usec_t lt_last_stamp; + uint64_t lt_bw; + xqc_bool_t lt_is_sampling; + xqc_bool_t lt_use_bw; + uint16_t lt_rtt_cnt; + + xqc_bool_t ignore_app_limit; + } xqc_bbr_t; extern const xqc_cong_ctrl_callback_t xqc_bbr_cb; diff --git a/src/congestion_control/xqc_bbr2.c b/src/congestion_control/xqc_bbr2.c index f2ccaee17..3778669fc 100644 --- a/src/congestion_control/xqc_bbr2.c +++ b/src/congestion_control/xqc_bbr2.c @@ -8,6 +8,7 @@ #include "src/congestion_control/xqc_bbr2.h" #include "src/congestion_control/xqc_sample.h" #include "src/common/xqc_time.h" +#include "src/common/xqc_random.h" #include "src/common/xqc_config.h" #include "src/transport/xqc_send_ctl.h" #include "src/transport/xqc_packet.h" @@ -871,19 +872,19 @@ xqc_bbr2_enter_drain(xqc_bbr2_t *bbr2) static void xqc_bbr2_pick_probe_wait(xqc_bbr2_t *bbr2) { - bbr2->rounds_since_probe = random() % xqc_bbr2_bw_probe_rand_rounds; + bbr2->rounds_since_probe = xqc_random() % xqc_bbr2_bw_probe_rand_rounds; #if XQC_BBR2_PLUS_ENABLED if (bbr2->fast_convergence_on) { - uint32_t rand_rtt_rounds = random() % + uint32_t rand_rtt_rounds = xqc_random() % xqc_bbr2_fast_convergence_probe_round_rand; rand_rtt_rounds += (1 + xqc_bbr2_fast_convergence_probe_round_base); } else { bbr2->probe_wait_us = xqc_bbr2_bw_probe_base_us + - (random() % xqc_bbr2_bw_probe_rand_us); + (xqc_random() % xqc_bbr2_bw_probe_rand_us); } #else bbr2->probe_wait_us = xqc_bbr2_bw_probe_base_us + - (random() % xqc_bbr2_bw_probe_rand_us); + (xqc_random() % xqc_bbr2_bw_probe_rand_us); #endif } @@ -991,7 +992,8 @@ xqc_bbr2_update_min_rtt(xqc_bbr2_t *bbr2, xqc_sample_t *sampler) /* Ignore low rate samples during this mode. */ xqc_send_ctl_t *send_ctl = sampler->send_ctl; send_ctl->ctl_app_limited = (send_ctl->ctl_delivered - + send_ctl->ctl_bytes_in_flight)? : 1; + + send_ctl->ctl_bytes_in_flight) + ? (send_ctl->ctl_delivered + send_ctl->ctl_bytes_in_flight) : 1; xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|BBR PROBE_RTT|inflight:%ud|done_stamp:%ui|done:%ud|" "round_start:%ud|", diff --git a/src/congestion_control/xqc_copa.c b/src/congestion_control/xqc_copa.c index 0f6a96dcc..c39cf5ac9 100644 --- a/src/congestion_control/xqc_copa.c +++ b/src/congestion_control/xqc_copa.c @@ -27,7 +27,7 @@ #define XQC_COPA_MAX_DELTA (1.0) #define XQC_COPA_INF_U64 (~0ULL) #define XQC_COPA_INIT_VELOCITY (1.0) -#define XQC_COPA_MAX_RATE (1.0 * (~0ULL)) +#define XQC_COPA_MAX_RATE (1.8E19) #define XQC_COPA_USEC2SEC (1000000) #define XQC_COPA_DEFAULT_DELTA_AI_UNIT (1.0) @@ -62,6 +62,7 @@ xqc_copa_set_pacing_rate(xqc_copa_t *copa) { /* 2*cwnd / rtt_standing */ xqc_usec_t rtt_standing = xqc_win_filter_get(&copa->rtt_standing); + xqc_usec_t initial_rtt = copa->ctl_ctx->ctl_conn->conn_settings.initial_rtt; if (rtt_standing == XQC_COPA_INF_U64) { /* initialization */ rtt_standing = copa->ctl_ctx->ctl_srtt; @@ -70,7 +71,7 @@ xqc_copa_set_pacing_rate(xqc_copa_t *copa) xqc_log(copa->ctl_ctx->ctl_conn->log, XQC_LOG_WARN, "|copa|rtt_standing_error:%ui|", rtt_standing); /* initialization */ - rtt_standing = XQC_kInitialRtt * 1000; + rtt_standing = initial_rtt; xqc_win_filter_reset(&copa->rtt_standing, 0, XQC_COPA_INF_U64); } copa->pacing_rate = ((copa->cwnd_bytes) * XQC_COPA_USEC2SEC) << 1; diff --git a/src/congestion_control/xqc_cubic.c b/src/congestion_control/xqc_cubic.c index d9307d2a5..66e81fe61 100644 --- a/src/congestion_control/xqc_cubic.c +++ b/src/congestion_control/xqc_cubic.c @@ -121,13 +121,7 @@ static void xqc_cubic_init(void *cong_ctl, xqc_send_ctl_t *ctl_ctx, xqc_cc_params_t cc_params) { xqc_cubic_t *cubic = (xqc_cubic_t *)(cong_ctl); - cubic->epoch_start = 0; - cubic->cwnd = XQC_CUBIC_INIT_WIN; - cubic->tcp_cwnd = XQC_CUBIC_INIT_WIN; - cubic->tcp_cwnd_cnt = 0; - cubic->last_max_cwnd = XQC_CUBIC_INIT_WIN; - cubic->ssthresh = XQC_CUBIC_MAX_SSTHRESH; - cubic->congestion_recovery_start_time = 0; + cubic->init_cwnd = XQC_CUBIC_INIT_WIN; cubic->min_cwnd = XQC_CUBIC_MIN_WIN; @@ -141,6 +135,14 @@ xqc_cubic_init(void *cong_ctl, xqc_send_ctl_t *ctl_ctx, xqc_cc_params_t cc_param cc_params.min_cwnd >= XQC_CUBIC_MIN_WIN && cc_params.min_cwnd <= XQC_CUBIC_MAX_MIN_WIN ? cc_params.min_cwnd : XQC_CUBIC_MIN_WIN; } + + cubic->epoch_start = 0; + cubic->cwnd = cubic->init_cwnd; + cubic->tcp_cwnd = cubic->init_cwnd; + cubic->tcp_cwnd_cnt = 0; + cubic->last_max_cwnd = cubic->init_cwnd; + cubic->ssthresh = XQC_CUBIC_MAX_SSTHRESH; + cubic->congestion_recovery_start_time = 0; } diff --git a/src/congestion_control/xqc_sample.c b/src/congestion_control/xqc_sample.c index c54070913..1c7538b12 100644 --- a/src/congestion_control/xqc_sample.c +++ b/src/congestion_control/xqc_sample.c @@ -51,6 +51,7 @@ xqc_generate_sample(xqc_sample_t *sampler, xqc_send_ctl_t *send_ctl, sampler->bytes_inflight = send_ctl->ctl_bytes_in_flight; sampler->prior_inflight = send_ctl->ctl_prior_bytes_in_flight; sampler->total_acked = send_ctl->ctl_delivered; + sampler->total_lost_pkts = send_ctl->ctl_lost_pkts_number; /* * Normally we expect interval >= MinRTT. @@ -71,9 +72,10 @@ xqc_generate_sample(xqc_sample_t *sampler, xqc_send_ctl_t *send_ctl, xqc_log(sampler->send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|sampler: send_elapse %ui, ack_elapse %ui, " - "delivered %ud|", + "delivered %ud|rate %ui|lost %ud|", sampler->send_elapse, sampler->ack_elapse, - sampler->delivered); + sampler->delivered, sampler->delivery_rate, + sampler->total_lost_pkts); return XQC_RATE_SAMPLE_VALID; } @@ -102,7 +104,14 @@ xqc_update_sample(xqc_sample_t *sampler, xqc_packet_out_t *packet, sampler->tx_in_flight = packet->po_tx_in_flight; sampler->prior_delivered = packet->po_delivered; sampler->prior_time = packet->po_delivered_time; - sampler->is_app_limited = packet->po_is_app_limited; + + if (xqc_conn_is_handshake_confirmed(send_ctl->ctl_conn)) { + sampler->is_app_limited = packet->po_is_app_limited; + + } else { + sampler->is_app_limited = 1; + } + sampler->send_elapse = packet->po_sent_time - packet->po_first_sent_time; sampler->ack_elapse = send_ctl->ctl_delivered_time - diff --git a/src/congestion_control/xqc_sample.h b/src/congestion_control/xqc_sample.h index 988bf0632..b81212c99 100644 --- a/src/congestion_control/xqc_sample.h +++ b/src/congestion_control/xqc_sample.h @@ -45,6 +45,8 @@ typedef struct xqc_sample_s { uint64_t tx_in_flight; uint32_t lost_pkts; + uint32_t total_lost_pkts; + } xqc_sample_t; void xqc_init_sample_before_ack(xqc_sample_t *sampler); diff --git a/src/http3/frame/xqc_h3_frame_defs.h b/src/http3/frame/xqc_h3_frame_defs.h index 74f9f367d..8c14e6b13 100644 --- a/src/http3/frame/xqc_h3_frame_defs.h +++ b/src/http3/frame/xqc_h3_frame_defs.h @@ -25,9 +25,11 @@ typedef enum xqc_h3_frm_type_s { typedef struct xqc_h3_frm_data_s { + char reserved; } xqc_h3_frame_data_t; typedef struct xqc_h3_frm_headers_s { + char reserved; } xqc_h3_frame_headers_t; typedef struct xqc_h3_frm_cancel_push_s { diff --git a/src/http3/qpack/xqc_encoder.c b/src/http3/qpack/xqc_encoder.c index a1056b22c..c38a6a55d 100644 --- a/src/http3/qpack/xqc_encoder.c +++ b/src/http3/qpack/xqc_encoder.c @@ -682,6 +682,10 @@ xqc_encoder_prepare(xqc_encoder_t *enc, xqc_http_headers_t *hdrs, xqc_field_sect xqc_hdr_enc_rule_t *info = &fs->reps[i]; info->hdr = hdr; + if (hdr->save_nv_hit_flags && hdr->src_header) { + hdr->src_header->nv_hit_flags = 0; + } + /* * if XQC_HTTP_HEADER_FLAG_NEVER_INDEX is set, header will be sent as Literal Filed Line * With Literal Name, regardless of lookup or insertion operation with stable and dtable @@ -745,6 +749,11 @@ xqc_encoder_prepare(xqc_encoder_t *enc, xqc_http_headers_t *hdrs, xqc_field_sect { fs->rqrd_insert_cnt = info->index + 1; } + + if (hdr->save_nv_hit_flags && info->ref != XQC_NV_ERROR + && hdr->src_header) { + hdr->src_header->nv_hit_flags = info->ref; + } } return XQC_OK; @@ -1216,5 +1225,6 @@ void xqc_encoder_compat_dup(xqc_encoder_t *enc, xqc_bool_t compat) { enc->compat_dup = compat; + xqc_log(enc->log, XQC_LOG_DEBUG, "|qpack_enc_compat_dup:%d|", compat); } #endif diff --git a/src/http3/xqc_h3_conn.c b/src/http3/xqc_h3_conn.c index 70400c382..482626ce3 100644 --- a/src/http3/xqc_h3_conn.c +++ b/src/http3/xqc_h3_conn.c @@ -11,7 +11,7 @@ #include "src/transport/xqc_defs.h" -xqc_h3_conn_settings_t default_local_h3_conn_settings = { +const xqc_h3_conn_settings_t default_local_h3_conn_settings = { .max_pushes = 0, .max_field_section_size = XQC_H3_MAX_FIELD_SECTION_SIZE, .qpack_blocked_streams = XQC_QPACK_MAX_BLOCK_STREAM, @@ -22,7 +22,7 @@ xqc_h3_conn_settings_t default_local_h3_conn_settings = { #endif }; -xqc_h3_conn_settings_t default_peer_h3_conn_settings = { +const xqc_h3_conn_settings_t default_peer_h3_conn_settings = { .max_pushes = XQC_H3_SETTINGS_UNSET, .max_field_section_size = XQC_H3_SETTINGS_UNSET, .qpack_blocked_streams = XQC_H3_SETTINGS_UNSET, @@ -74,33 +74,125 @@ xqc_h3_conn_destroy_blocked_stream_list(xqc_h3_conn_t *h3c); void xqc_h3_engine_set_dec_max_dtable_capacity(xqc_engine_t *engine, size_t value) { - default_local_h3_conn_settings.qpack_dec_max_table_capacity = value; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + } } void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t value) { - default_local_h3_conn_settings.qpack_enc_max_table_capacity = value; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + } } void xqc_h3_engine_set_max_dtable_capacity(xqc_engine_t *engine, size_t capacity) { - default_local_h3_conn_settings.qpack_dec_max_table_capacity = capacity; - default_local_h3_conn_settings.qpack_enc_max_table_capacity = capacity; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + } } void xqc_h3_engine_set_max_field_section_size(xqc_engine_t *engine, size_t size) { - default_local_h3_conn_settings.max_field_section_size = size; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + } +} + +void +xqc_h3_engine_set_qpack_blocked_streams(xqc_engine_t *engine, size_t value) +{ + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + } } #ifdef XQC_COMPAT_DUPLICATE void xqc_h3_engine_set_qpack_compat_duplicate(xqc_engine_t *engine, xqc_bool_t cmpt) { - default_local_h3_conn_settings.qpack_compat_duplicate = cmpt; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + } } #endif @@ -166,37 +258,25 @@ xqc_h3_conn_set_user_data(xqc_h3_conn_t *h3_conn, } -void -xqc_h3_conn_set_settings(xqc_h3_conn_t *h3_conn, const xqc_h3_conn_settings_t *h3_conn_settings) +void +xqc_h3_engine_set_local_settings(xqc_engine_t *engine, + const xqc_h3_conn_settings_t *h3_conn_settings) { - xqc_h3_conn_settings_t *settings = &h3_conn->local_h3_conn_settings; - - if (h3_conn_settings->max_field_section_size) { - settings->max_field_section_size = h3_conn_settings->max_field_section_size; - } - - if (h3_conn_settings->max_pushes) { - settings->max_pushes = h3_conn_settings->max_pushes; - } + xqc_h3_conn_settings_t *settings; - if (h3_conn_settings->qpack_enc_max_table_capacity) { - settings->qpack_enc_max_table_capacity = h3_conn_settings->qpack_enc_max_table_capacity; + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + *settings = *h3_conn_settings; } - if (h3_conn_settings->qpack_dec_max_table_capacity) { - settings->qpack_dec_max_table_capacity = h3_conn_settings->qpack_dec_max_table_capacity; + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + *settings = *h3_conn_settings; } - if (h3_conn_settings->qpack_blocked_streams) { - settings->qpack_blocked_streams = h3_conn_settings->qpack_blocked_streams; + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + *settings = *h3_conn_settings; + } } - -#ifdef XQC_COMPAT_DUPLICATE - settings->qpack_compat_duplicate = h3_conn_settings->qpack_compat_duplicate; - xqc_qpack_set_compat_dup(h3_conn->qpack, settings->qpack_compat_duplicate); -#endif - - xqc_log_event(h3_conn->log, HTTP_PARAMETERS_SET, h3_conn, XQC_LOG_LOCAL_EVENT); } @@ -303,21 +383,50 @@ const xqc_qpack_ins_cb_t xqc_h3_qpack_ins_cb = { xqc_int_t xqc_h3_conn_init_callbacks(xqc_h3_conn_t *h3c) { + if (h3c->conn->alpn == NULL) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|alpn is null|"); + return -XQC_EFATAL; + } + xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); + xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(h3c->conn->engine, h3c->conn->alpn, h3c->conn->alpn_len, &h3_cbs); if (XQC_OK != ret || h3_cbs == NULL) { xqc_log(h3c->log, XQC_LOG_ERROR, "|can't get app callbacks, not initialized?"); return -XQC_EFATAL; } h3c->h3_conn_callbacks = h3_cbs->h3c_cbs; + h3c->h3_request_callbacks = h3_cbs->h3r_cbs; + if (h3c->flags & XQC_H3_CONN_FLAG_EXT_ENABLED) { + h3c->h3_ext_bs_callbacks = h3_cbs->h3_ext_bs_cbs; h3c->h3_ext_dgram_callbacks = h3_cbs->h3_ext_dgram_cbs; } return XQC_OK; } +xqc_int_t +xqc_h3_conn_init_settings(xqc_h3_conn_t *h3c) +{ + if (h3c->conn->alpn == NULL) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|alpn is null|"); + return -XQC_EFATAL; + } + + xqc_h3_conn_settings_t *local_settings = NULL; + xqc_int_t ret = xqc_h3_ctx_get_default_conn_settings(h3c->conn->engine, h3c->conn->alpn, h3c->conn->alpn_len, &local_settings); + if (XQC_OK != ret) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|can't get the default local h3 conn settings|"); + return -XQC_EFATAL; + } + + h3c->local_h3_conn_settings = *local_settings; + h3c->peer_h3_conn_settings = default_peer_h3_conn_settings; + + return XQC_OK; +} + xqc_h3_conn_t * xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) @@ -334,6 +443,14 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) h3c->control_stream_out = NULL; + /* avoid error handling in this function leads to crash */ + h3c->qdec_stream = NULL; + h3c->qenc_stream = NULL; + + /* blocked streams list */ + xqc_init_list_head(&h3c->block_stream_head); + h3c->block_stream_count = 0; + if (conn->engine->config->enable_h3_ext) { h3c->flags |= XQC_H3_CONN_FLAG_EXT_ENABLED; } @@ -341,10 +458,44 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) /* set callback functions from application layer to http3 layer */ if (xqc_h3_conn_init_callbacks(h3c) != XQC_OK) { h3c->flags &= ~XQC_H3_CONN_FLAG_EXT_ENABLED; + goto fail; } - h3c->local_h3_conn_settings = default_local_h3_conn_settings; - h3c->peer_h3_conn_settings = default_peer_h3_conn_settings; + + if (xqc_h3_conn_init_settings(h3c) != XQC_OK) { + h3c->flags &= ~XQC_H3_CONN_FLAG_EXT_ENABLED; + goto fail; + } + + if (h3c->h3_conn_callbacks.h3_conn_init_settings) { + h3c->h3_conn_callbacks.h3_conn_init_settings(h3c, + &h3c->local_h3_conn_settings, user_data); +#ifdef XQC_COMPAT_DUPLICATE + xqc_log(h3c->log, XQC_LOG_DEBUG, "|new_h3_local_settings|" + "max_field_section_size:%ui|max_pushes:%ui|" + "qpack_enc_max_table_capacity:%ui|" + "qpack_dec_max_table_capacity:%ui|" + "qpack_blocked_streams:%ui|" + "qpack_compat_duplicate:%ui|", + h3c->local_h3_conn_settings.max_field_section_size, + h3c->local_h3_conn_settings.max_pushes, + h3c->local_h3_conn_settings.qpack_enc_max_table_capacity, + h3c->local_h3_conn_settings.qpack_dec_max_table_capacity, + h3c->local_h3_conn_settings.qpack_blocked_streams, + h3c->local_h3_conn_settings.qpack_compat_duplicate); +#else + xqc_log(h3c->log, XQC_LOG_DEBUG, "|new_h3_local_settings|" + "max_field_section_size:%ui|max_pushes:%ui|" + "qpack_enc_max_table_capacity:%ui|" + "qpack_dec_max_table_capacity:%ui|" + "qpack_blocked_streams:%ui|", + h3c->local_h3_conn_settings.max_field_section_size, + h3c->local_h3_conn_settings.max_pushes, + h3c->local_h3_conn_settings.qpack_enc_max_table_capacity, + h3c->local_h3_conn_settings.qpack_dec_max_table_capacity, + h3c->local_h3_conn_settings.qpack_blocked_streams); +#endif + } /* create qpack */ h3c->qpack = xqc_qpack_create(h3c->local_h3_conn_settings.qpack_enc_max_table_capacity, @@ -359,12 +510,7 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) xqc_qpack_set_compat_dup(h3c->qpack, h3c->local_h3_conn_settings.qpack_compat_duplicate); #endif - h3c->qdec_stream = NULL; - h3c->qenc_stream = NULL; - - /* blocked streams list */ - xqc_init_list_head(&h3c->block_stream_head); - h3c->block_stream_count = 0; + xqc_log_event(h3c->log, HTTP_PARAMETERS_SET, h3c, XQC_LOG_LOCAL_EVENT); /* creation callback */ if (h3c->h3_conn_callbacks.h3_conn_create_notify) { @@ -538,7 +684,6 @@ xqc_h3_conn_on_settings_entry_received(uint64_t identifier, uint64_t value, void xqc_h3_conn_t *h3c = (xqc_h3_conn_t *) user_data; xqc_log(h3c->log, XQC_LOG_DEBUG, "|id:%ui|value:%ui|", identifier, value); - xqc_log_event(h3c->log, HTTP_SETTING_PARSED, identifier, value); switch (identifier) { case XQC_H3_SETTINGS_MAX_FIELD_SECTION_SIZE: diff --git a/src/http3/xqc_h3_conn.h b/src/http3/xqc_h3_conn.h index 30f63fe6e..6969ee474 100644 --- a/src/http3/xqc_h3_conn.h +++ b/src/http3/xqc_h3_conn.h @@ -73,7 +73,8 @@ typedef struct xqc_h3_conn_s { /* h3 connection callback functions for user */ xqc_h3_conn_callbacks_t h3_conn_callbacks; - + xqc_h3_request_callbacks_t h3_request_callbacks; + xqc_h3_ext_bytestream_callbacks_t h3_ext_bs_callbacks; /* h3 datagram callback functions for user */ xqc_h3_ext_dgram_callbacks_t h3_ext_dgram_callbacks; diff --git a/src/http3/xqc_h3_ctx.c b/src/http3/xqc_h3_ctx.c index 59a72c392..e02fb65cd 100644 --- a/src/http3/xqc_h3_ctx.c +++ b/src/http3/xqc_h3_ctx.c @@ -9,13 +9,22 @@ #include "xqc_h3_ext_dgram.h" #include "src/transport/xqc_engine.h" -/* 应用层注册回调,放到engine */ -typedef struct xqc_h3_ctx_s { - xqc_h3_callbacks_t h3_cbs; -} xqc_h3_ctx_t; +xqc_h3_ctx_t* +xqc_h3_ctx_create(xqc_h3_callbacks_t *h3_cbs) +{ + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_calloc(1, sizeof(xqc_h3_ctx_t)); -xqc_h3_ctx_t *h3_ctx = NULL; + if (h3_ctx) { + /* save h3 callbacks */ + h3_ctx->h3_cbs = *h3_cbs; + h3_ctx->h3c_def_local_settings = default_local_h3_conn_settings; + } + + return h3_ctx; +} xqc_int_t xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) @@ -24,15 +33,8 @@ xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) return -XQC_EPARAM; } - if (NULL == h3_ctx) { - h3_ctx = xqc_malloc(sizeof(xqc_h3_ctx_t)); - if (NULL == h3_ctx) { - return -XQC_EMALLOC; - } - } - - /* save h3 callbacks */ - h3_ctx->h3_cbs = *h3_cbs; + xqc_h3_ctx_t *h3_ctx = NULL; + xqc_int_t ret = XQC_OK; /* init http3 layer callbacks */ xqc_app_proto_callbacks_t ap_cbs = { @@ -40,53 +42,120 @@ xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) .stream_cbs = h3_stream_callbacks, }; - /* register ALPN and transport layer callbacks */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &ap_cbs) != XQC_OK - || xqc_engine_register_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &ap_cbs) != XQC_OK) - { - xqc_h3_ctx_destroy(engine); - return -XQC_EFATAL; + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + return -XQC_EMALLOC; + } + + /* register H3 */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; + } + + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + + /* register H3-29 */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; } if (engine->config->enable_h3_ext) { ap_cbs.dgram_cbs = h3_ext_datagram_callbacks; + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + /* register h3-ext ALPN */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &ap_cbs) != XQC_OK) - { - xqc_h3_ctx_destroy(engine); - return -XQC_EFATAL; + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; } } - return XQC_OK; + return ret; + +error: + xqc_h3_ctx_destroy(engine); + return ret; } xqc_int_t xqc_h3_ctx_destroy(xqc_engine_t *engine) { - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + xqc_h3_ctx_t *h3_ctx; + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); if (h3_ctx) { xqc_free(h3_ctx); - h3_ctx = NULL; } + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); + if (h3_ctx) { + xqc_free(h3_ctx); + } + + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + if (h3_ctx) { + xqc_free(h3_ctx); + } + + + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + return XQC_OK; } xqc_int_t -xqc_h3_ctx_get_app_callbacks(xqc_h3_callbacks_t **h3_cbs) +xqc_h3_ctx_get_app_callbacks(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_callbacks_t **h3_cbs) { - if (NULL == h3_ctx) { + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_engine_get_alpn_ctx(engine, alpn, alpn_len); + + if (h3_ctx == NULL) { return -XQC_EFATAL; } *h3_cbs = &h3_ctx->h3_cbs; + return XQC_OK; } + +xqc_int_t +xqc_h3_ctx_get_default_conn_settings(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_conn_settings_t **settings) +{ + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_engine_get_alpn_ctx(engine, alpn, alpn_len); + + if (h3_ctx == NULL) { + return -XQC_EFATAL; + } + + *settings = &h3_ctx->h3c_def_local_settings; + + return XQC_OK; +} \ No newline at end of file diff --git a/src/http3/xqc_h3_ctx.h b/src/http3/xqc_h3_ctx.h index ed9dfdae1..c78dbd62f 100644 --- a/src/http3/xqc_h3_ctx.h +++ b/src/http3/xqc_h3_ctx.h @@ -8,7 +8,17 @@ #include -xqc_int_t xqc_h3_ctx_get_app_callbacks(xqc_h3_callbacks_t **h3_cbs); +/* 应用层注册回调,放到engine */ +typedef struct xqc_h3_ctx_s { + xqc_h3_callbacks_t h3_cbs; + xqc_h3_conn_settings_t h3c_def_local_settings; +} xqc_h3_ctx_t; + +xqc_int_t xqc_h3_ctx_get_app_callbacks(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_callbacks_t **h3_cbs); + +xqc_int_t xqc_h3_ctx_get_default_conn_settings(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_conn_settings_t **settings); #endif diff --git a/src/http3/xqc_h3_ext_bytestream.c b/src/http3/xqc_h3_ext_bytestream.c index 070d46acf..3582f06b3 100644 --- a/src/http3/xqc_h3_ext_bytestream.c +++ b/src/http3/xqc_h3_ext_bytestream.c @@ -156,16 +156,9 @@ xqc_h3_ext_bytestream_data_buf_merge(xqc_h3_ext_bytestream_data_buf_t *buf) } xqc_int_t -xqc_h3_ext_bytestream_init_callbacks(xqc_h3_ext_bytestream_t *bs) +xqc_h3_ext_bytestream_init_callbacks(xqc_h3_conn_t *h3c, xqc_h3_ext_bytestream_t *bs) { - xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); - if (XQC_OK != ret || h3_cbs == NULL) { - xqc_log(bs->h3_stream->log, XQC_LOG_ERROR, "|can't get app callbacks, not registered ?|"); - return ret; - } - - bs->bs_callbacks = &h3_cbs->h3_ext_bs_cbs; + bs->bs_callbacks = &h3c->h3_ext_bs_callbacks; return XQC_OK; } @@ -180,7 +173,7 @@ xqc_h3_ext_bytestream_create_inner(xqc_h3_conn_t *h3_conn, return NULL; } - if (xqc_h3_ext_bytestream_init_callbacks(bs) != XQC_OK) { + if (xqc_h3_ext_bytestream_init_callbacks(h3_conn, bs) != XQC_OK) { xqc_free(bs); return NULL; } @@ -266,7 +259,7 @@ xqc_h3_ext_bytestream_create(xqc_engine_t *engine, xqc_log(engine->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3_stream->stream_id, h3_conn->conn, xqc_conn_state_2_str(h3_conn->conn->conn_state), - xqc_conn_flag_2_str(h3_conn->conn->conn_flag)); + xqc_conn_flag_2_str(h3_conn->conn, h3_conn->conn->conn_flag)); return h3_ext_bs; } @@ -310,7 +303,7 @@ xqc_h3_ext_bytestream_destroy(xqc_h3_ext_bytestream_t *bs) xqc_log(h3s->log, XQC_LOG_REPORT, "|stream_id:%ui|close_msg:%s|err:%d" "|bytes_sent:%uz|bytes_rcvd:%uz|create_time:%ui|fb_sent_delay:%ui|fb_rcvd_delay:%ui" "|fin_sent_delay:%ui|fin_acked_delay:%ui|fin_rcvd_delay:%ui|", - xqc_h3_ext_bytestream_id(bs), stats.stream_close_msg ? : "", + xqc_h3_ext_bytestream_id(bs), stats.stream_close_msg ? stats.stream_close_msg : "", stats.stream_err, stats.bytes_sent, stats.bytes_rcvd, stats.create_time, xqc_calc_delay(stats.first_byte_sent_time, stats.create_time), @@ -350,13 +343,13 @@ xqc_h3_ext_bytestream_close(xqc_h3_ext_bytestream_t *h3_ext_bs) if (ret) { xqc_log(conn->log, XQC_LOG_ERROR, "|fail|ret:%d|stream_id:%ui|conn:%p|conn_state:%s|" "flag:%s|", ret, h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return ret; } xqc_log(conn->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return XQC_OK; } diff --git a/src/http3/xqc_h3_request.c b/src/http3/xqc_h3_request.c index 7c6e74e4f..1c820f620 100644 --- a/src/http3/xqc_h3_request.c +++ b/src/http3/xqc_h3_request.c @@ -41,10 +41,17 @@ xqc_h3_request_create(xqc_engine_t *engine, xqc_log(engine->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3_stream->stream_id, h3_conn->conn, xqc_conn_state_2_str(h3_conn->conn->conn_state), - xqc_conn_flag_2_str(h3_conn->conn->conn_flag)); + xqc_conn_flag_2_str(h3_conn->conn, h3_conn->conn->conn_flag)); return h3_request; } +xqc_usec_t +xqc_get_fec_fin_delay(xqc_usec_t stream_fin_time, xqc_usec_t last_rpr_time) +{ + return (last_rpr_time == 0 || last_rpr_time > stream_fin_time) ? 0 : xqc_calc_delay(stream_fin_time, last_rpr_time); +} + + void xqc_h3_request_destroy(xqc_h3_request_t *h3_request) { @@ -59,8 +66,14 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) "|rcvd_bdy_sz:%uz|snd_bdy_sz:%uz|rcvd_hdr_sz:%uz|snd_hdr_sz:%uz" "|create:%ui|blkd:%ui|nblkd:%ui|hdr_b:%ui|hdr_e:%ui|bdy_b:%ui|fin:%ui|recv_end:%ui" "|hrd_send:%ui|bdy_send:%ui|fin_send:%ui|fin_ack:%ui|last_send:%ui|last_recv:%ui" - "|mp_state:%d|path_info:%s|comp_hdr_s:%uz|comp_hdr_r:%uz|", - h3s->stream_id, stats.stream_close_msg ? : "", + "|mp_state:%d|path_info:%s|comp_hdr_s:%uz|comp_hdr_r:%uz|fst_fin_snd:%ui|" + "sched_blk:%ud|sched_blk_time:%ui|" + "cwnd_blk:%ud|cwnd_blk_time:%ui|" + "pacing_blk:%ud|pacing_blk_time:%ui|begin_state:%s|end_state:%s|" + "is_fec_protected:%ud|fec_reco_pkt_cnt:%ud|fec_block_size_mode:%ud|" + "fst_rpr_ts:%ui|last_rpr_ts:%ui|fec_fin_delay:%ui|" + "external_stream_info:%s|", + h3s->stream_id, stats.stream_close_msg ? stats.stream_close_msg : "", stats.stream_err, stats.recv_body_size, stats.send_body_size, stats.recv_header_size, stats.send_header_size, create_time, @@ -78,7 +91,21 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) xqc_calc_delay(h3_request->h3_stream->h3c->conn->conn_last_send_time, create_time), xqc_calc_delay(h3_request->h3_stream->h3c->conn->conn_last_recv_time, create_time), stats.mp_state, stats.stream_info, stats.send_hdr_compressed, - stats.recv_hdr_compressed); + stats.recv_hdr_compressed, + xqc_calc_delay(stats.stream_fst_fin_snd_time, create_time), + h3_request->sched_cwnd_blk_cnt, + h3_request->sched_cwnd_blk_duration / 1000, + h3_request->send_cwnd_blk_cnt, + h3_request->send_cwnd_blk_duration/ 1000, + h3_request->send_pacing_blk_cnt, + h3_request->send_pacing_blk_duration / 1000, + h3s->begin_trans_state, + h3s->end_trans_state, + stats.is_fec_protected, stats.fec_recov_cnt, h3_request->block_size_mode, + stats.fst_rpr_time, stats.last_rpr_time, + stats.fec_req_delay_time, + stats.extern_stream_info + ); if (h3_request->request_if->h3_request_close_notify) { h3_request->request_if->h3_request_close_notify(h3_request, h3_request->user_data); @@ -102,13 +129,13 @@ xqc_h3_request_close(xqc_h3_request_t *h3_request) if (ret) { xqc_log(conn->log, XQC_LOG_ERROR, "|fail|ret:%d|stream_id:%ui|conn:%p|conn_state:%s|" "flag:%s|", ret, h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return ret; } xqc_log(conn->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return XQC_OK; } @@ -122,17 +149,9 @@ xqc_h3_request_header_initial(xqc_h3_request_t *h3_request) xqc_int_t -xqc_h3_request_init_callbacks(xqc_h3_request_t *h3r) +xqc_h3_request_init_callbacks(xqc_h3_conn_t *h3c, xqc_h3_request_t *h3r) { - xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); - if (XQC_OK != ret || h3_cbs == NULL) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|can't get app callbacks, not initialized ?"); - return ret; - } - - h3r->request_if = &h3_cbs->h3r_cbs; - + h3r->request_if = &h3c->h3_request_callbacks; return XQC_OK; } @@ -157,7 +176,7 @@ xqc_h3_request_create_inner(xqc_h3_conn_t *h3_conn, xqc_h3_stream_t *h3_stream, xqc_init_list_head(&h3_request->body_buf); h3_request->body_buf_count = 0; - xqc_h3_request_init_callbacks(h3_request); + xqc_h3_request_init_callbacks(h3_conn, h3_request); if (h3_request->request_if->h3_request_create_notify) { h3_request->request_if->h3_request_create_notify(h3_request, h3_request->user_data); @@ -168,6 +187,37 @@ xqc_h3_request_create_inner(xqc_h3_conn_t *h3_conn, xqc_h3_stream_t *h3_stream, return h3_request; } +void +xqc_h3_request_encode_rtts(xqc_h3_request_t *h3r, char *buff, size_t buff_size) +{ + xqc_h3_stream_t *h3_stream = h3r->h3_stream; + size_t cursor = 0; + int ret, i; + + for (int i = 0; i < XQC_MAX_PATHS_COUNT; ++i) { + if ((h3_stream->paths_info[i].path_send_bytes > 0) + || (h3_stream->paths_info[i].path_recv_bytes > 0)) + { + ret = snprintf(buff + cursor, buff_size - cursor, + "%"PRIu64"-", h3_stream->paths_info[i].path_srtt / 1000); + cursor += ret; + + if (cursor >= buff_size) { + break; + } + } + } + + cursor = xqc_min(cursor, buff_size); + for (i = cursor - 1; i >= 0; i--) { + if (buff[i] == '-') { + buff[i] = '\0'; + break; + } + } + buff[buff_size - 1] = '\0'; +} + void xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) { @@ -177,7 +227,8 @@ xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) size_t cursor = 0, ret = 0; int i; int flag = 0; - uint32_t mp_settings = 0; + char mp_settings[XQC_MP_SETTINGS_STR_LEN] = {0}; + xqc_usec_t hsk_time; if (h3c->conn->handshake_complete_time > 0) { flag = 1; @@ -187,32 +238,17 @@ xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) flag |= 1 << 1; } - if (h3c->conn->enable_multipath) { - mp_settings |= 1; - } + hsk_time = (h3c->conn->handshake_complete_time > h3c->conn->conn_create_time) ? + (h3c->conn->handshake_complete_time - h3c->conn->conn_create_time) : + 0; - if (h3c->conn->local_settings.enable_multipath) { - mp_settings |= (1 << 1); - } + xqc_conn_encode_mp_settings(h3c->conn, mp_settings, XQC_MP_SETTINGS_STR_LEN); - if (h3c->conn->remote_settings.enable_multipath) { - mp_settings |= (1 << 2); - } - - if (h3c->conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 3); - } - - if (h3c->conn->local_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 4); - } - - if (h3c->conn->remote_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 5); - } - - ret = snprintf(buff, buff_size, "(%d,%"PRIu64",%d)#", - flag, h3_stream->recv_rate_limit, mp_settings); + ret = snprintf(buff, buff_size, "(%d,%"PRIu64",%s,%"PRIu64",%"PRIu64",%"PRIu64",%u,%"PRIu64")#", + flag, h3_stream->recv_rate_limit, mp_settings, + h3_stream->send_offset, h3_stream->recv_offset, + stats->cwnd_blocked_ms, stats->retrans_cnt, + hsk_time / 1000); cursor += ret; @@ -252,6 +288,89 @@ xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) buff[buff_size - 1] = '\0'; } +#ifdef XQC_ENABLE_FEC +void +xqc_fec_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats, + char *output, size_t output_size) +{ + int32_t i, ret; + size_t curr_size; + xqc_h3_conn_t *h3c = h3_stream->h3c; + + i = ret = 0; + curr_size = 0; + xqc_memset(output, 0, output_size); +#define __calc_delay(a, b) ((a > b && b)? (a) - (b) : 0) + ret = snprintf(output, output_size, "%d,%u,%d,%u,%u,%"PRIu64",%"PRIu64",%s,%s,%"PRIu64",%"PRIu64",", + stats->is_fec_protected, + h3c->conn->fec_neg_fail_reason, + stats->block_size_mode, + stats->fec_recov_cnt, + stats->fec_blk_lack_num, + stats->fec_blk_lack_time, + stats->fec_req_delay_time, + xqc_get_fec_scheme_str(h3c->conn->conn_settings.fec_params.fec_encoder_scheme), + xqc_get_fec_scheme_str(h3c->conn->conn_settings.fec_params.fec_decoder_scheme), + __calc_delay(stats->final_packet_time, stats->recv_time_with_fec), + stats->stream_close_delay + ); +#undef __calc_delay + curr_size += ret; + + if (curr_size >= output_size) { + goto full; + } + +full: + curr_size = xqc_min(curr_size, output_size); + for (i = curr_size - 1; i >= 0; i--) { + if (output[i] == ',') { + output[i] = '\0'; + break; + } + } + output[output_size - 1] = '\0'; +} +#endif + + +void +xqc_extern_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) +{ + int32_t i, ret; + xqc_h3_conn_t *h3c = h3_stream->h3c; + char *buff = stats->extern_stream_info; + size_t buff_size, curr_size; + +#ifdef XQC_ENABLE_FEC + char fec_buf[XQC_MAX_FEC_BUF_LEN]; + xqc_fec_stream_info_print(h3_stream, stats, fec_buf, XQC_MAX_FEC_BUF_LEN); +#endif + i = ret = 0; + curr_size = 0; + buff_size = XQC_STREAM_INFO_LEN; + + /* stream info */ + ret = snprintf(buff, buff_size, + "{" +#ifdef XQC_ENABLE_FEC + "\"fec\": \"%s\"," +#endif + "}" +#ifdef XQC_ENABLE_FEC + , + fec_buf +#endif + ); + curr_size += ret; + if (curr_size >= buff_size) { + goto full; + } + +full: + curr_size = xqc_min(curr_size, buff_size); + buff[curr_size] = '\0'; +} xqc_int_t xqc_h3_request_update_settings(xqc_h3_request_t *h3_request, @@ -277,6 +396,9 @@ xqc_h3_request_get_stats(xqc_h3_request_t *h3_request) xqc_request_stats_t stats; xqc_memzero(&stats, sizeof(stats)); + /* try to update stats */ + xqc_h3_stream_update_stats(h3_request->h3_stream); + uint64_t conn_err = h3_request->h3_stream->h3c->conn->conn_err; stats.recv_body_size = h3_request->body_recvd; stats.send_body_size = h3_request->body_sent; @@ -294,16 +416,35 @@ xqc_h3_request_get_stats(xqc_h3_request_t *h3_request) stats.h3r_header_send_time = h3_request->h3r_header_send_time; stats.h3r_body_send_time = h3_request->h3r_body_send_time; stats.stream_fin_send_time = h3_request->stream_fin_send_time; + stats.stream_fst_fin_snd_time = h3_request->stream_fst_fin_snd_time; stats.stream_fin_ack_time = h3_request->stream_fin_ack_time; stats.stream_close_msg = h3_request->stream_close_msg; stats.send_hdr_compressed = h3_request->compressed_header_sent; stats.recv_hdr_compressed = h3_request->compressed_header_recvd; stats.rate_limit = h3_request->h3_stream->recv_rate_limit; - + stats.cwnd_blocked_ms = (h3_request->sched_cwnd_blk_duration + h3_request->send_cwnd_blk_duration) / 1000; + stats.early_data_state = h3_request->h3_stream->early_data_state; + stats.retrans_cnt = h3_request->retrans_pkt_cnt; + stats.stream_fst_pkt_snd_time = h3_request->stream_fst_pkt_snd_time; + stats.stream_fst_pkt_rcv_time = h3_request->stream_fst_pkt_rcv_time; + stats.sent_pkt_cnt = h3_request->sent_pkt_cnt; + stats.max_pto_backoff = h3_request->max_pto_backoff; + stats.fec_recov_cnt = h3_request->recov_pkt_cnt; + stats.fst_rpr_time = h3_request->fst_rpr_time; + stats.last_rpr_time = h3_request->last_rpr_time; + stats.is_fec_protected = h3_request->block_size_mode != XQC_SLIM_SIZE_REQ && h3_request->h3_stream->h3c->conn->conn_settings.fec_params.fec_encoder_scheme != 0 ? 1 : 0; + stats.block_size_mode = h3_request->block_size_mode; + stats.fec_blk_lack_num = h3_request->fec_blk_lack_num; + stats.fec_blk_lack_time = h3_request->fec_blk_lack_time; + stats.fec_req_delay_time = xqc_get_fec_fin_delay(stats.stream_fin_time, stats.last_rpr_time); + stats.recv_time_with_fec = h3_request->recv_time_with_fec; + stats.final_packet_time = h3_request->final_packet_time; + stats.stream_close_delay = h3_request->stream_close_delay; xqc_h3_stream_get_path_info(h3_request->h3_stream); xqc_request_path_metrics_print(h3_request->h3_stream->h3c->conn, h3_request->h3_stream, &stats); xqc_stream_info_print(h3_request->h3_stream, &stats); + xqc_extern_stream_info_print(h3_request->h3_stream, &stats); return stats; } @@ -313,8 +454,11 @@ xqc_h3_request_stats_print(xqc_h3_request_t *h3_request, char *str, size_t size) { xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); xqc_usec_t create_time = h3_request->h3r_begin_time; + char rtt_str[32] = {0}; + xqc_h3_request_encode_rtts(h3_request, rtt_str, 32); return snprintf(str, size, "%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64 - ",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64, + ",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",cc:%"PRIu64 + ",rtx:%u,rtt:%s", h3_request->h3_stream->stream_id, xqc_calc_delay(stats.h3r_header_begin_time, create_time) / 1000, xqc_calc_delay(stats.h3r_header_end_time, create_time) / 1000, @@ -324,7 +468,8 @@ xqc_h3_request_stats_print(xqc_h3_request_t *h3_request, char *str, size_t size) xqc_calc_delay(stats.h3r_header_send_time, create_time) / 1000, xqc_calc_delay(stats.h3r_body_send_time, create_time) / 1000, xqc_calc_delay(stats.stream_fin_send_time, create_time) / 1000, - xqc_calc_delay(stats.stream_fin_ack_time, create_time) / 1000); + xqc_calc_delay(stats.stream_fin_ack_time, create_time) / 1000, + stats.cwnd_blocked_ms, stats.retrans_cnt, rtt_str); } void @@ -394,11 +539,12 @@ xqc_h3_request_copy_header(xqc_http_header_t *dst, xqc_http_header_t *src, xqc_v dst->value = src->value; dst->flags = src->flags; + dst->save_nv_hit_flags = src->save_nv_hit_flags; + dst->src_header = src; return XQC_OK; } - ssize_t xqc_h3_request_send_headers(xqc_h3_request_t *h3_request, xqc_http_headers_t *headers, uint8_t fin) { @@ -446,7 +592,6 @@ xqc_h3_request_send_headers(xqc_h3_request_t *h3_request, xqc_http_headers_t *he sent = ret; goto end; } - headers_in->total_len += (headers->headers[pt].name.iov_len + headers->headers[pt].value.iov_len); pt++; @@ -641,8 +786,18 @@ xqc_h3_request_on_recv_header(xqc_h3_request_t *h3r) XQC_REQ_NOTIFY_READ_TRAILER }; + xqc_int_t ret; xqc_http_headers_t *headers; + if (h3r->current_header == 1) { + /* notify data before trailer headers*/ + ret = xqc_h3_request_on_recv_body(h3r); + if (ret != XQC_OK) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|recv body error|%d|", ret); + return ret; + } + } + /* header section and trailer section are all processed */ if (h3r->current_header >= XQC_H3_REQUEST_MAX_HEADERS_CNT) { xqc_log(h3r->h3_stream->log, XQC_LOG_WARN, "|headers count exceed 2|" @@ -674,12 +829,14 @@ xqc_h3_request_on_recv_header(xqc_h3_request_t *h3r) h3r->current_header++; /* header notify callback */ - xqc_int_t ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + if (h3r->request_if->h3_request_read_notify) { + ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } return XQC_OK; @@ -688,19 +845,18 @@ xqc_h3_request_on_recv_header(xqc_h3_request_t *h3r) xqc_int_t xqc_h3_request_on_recv_body(xqc_h3_request_t *h3r) { - /* there might be a fin only operation, which shall be notified to user */ - if (!xqc_list_empty(&h3r->body_buf) || (h3r->fin_flag == XQC_TRUE)) { - - if (!xqc_list_empty(&h3r->body_buf)) { - h3r->read_flag |= XQC_REQ_NOTIFY_READ_BODY; - } - - xqc_int_t ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + /* Note, the case of empty fin is already handled at another place. */ + if (!xqc_list_empty(&h3r->body_buf)) { + + h3r->read_flag |= XQC_REQ_NOTIFY_READ_BODY; + if (h3r->request_if->h3_request_read_notify) { + xqc_int_t ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } } @@ -730,14 +886,16 @@ xqc_h3_request_on_recv_empty_fin(xqc_h3_request_t *h3r) return XQC_OK; } - /* if all header and content were received by application, notify empty fin */ - ret = h3r->request_if->h3_request_read_notify(h3r, XQC_REQ_NOTIFY_READ_EMPTY_FIN, - h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + if (h3r->request_if->h3_request_read_notify) { + /* if all header and content were received by application, notify empty fin */ + ret = h3r->request_if->h3_request_read_notify(h3r, XQC_REQ_NOTIFY_READ_EMPTY_FIN, + h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } xqc_log(h3r->h3_stream->h3c->log, XQC_LOG_DEBUG, "|stream_id:%ui|recv_fin|conn:%p|", @@ -856,6 +1014,10 @@ xqc_h3_request_closing(xqc_h3_request_t *h3r, xqc_int_t err) #define XQC_PRIORITY_REINJECT ", r=" #define XQC_PRIORITY_REINJECT_LEN 4 +#define XQC_PRIORITY_FEC ", f=" +#define XQC_PRIORITY_FEC_LEN 4 +#define XQC_PRIORITY_FEC_VAL_LEN 8 + void xqc_h3_priority_init(xqc_h3_priority_t *prio) { @@ -863,6 +1025,7 @@ xqc_h3_priority_init(xqc_h3_priority_t *prio) prio->incremental = XQC_FALSE; prio->schedule = 0; prio->reinject = 0; + prio->fec = XQC_DEFAULT_SIZE_REQ; } size_t @@ -870,11 +1033,13 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, uint8_t *dst, size_t dstcap) { uint8_t *begin = dst; + char *fec_str = xqc_calloc(1, XQC_PRIORITY_FEC_VAL_LEN); size_t need = XQC_PRIORITY_URGENCY_LEN + 1 + XQC_PRIORITY_INCREMENTAL_LEN + XQC_PRIORITY_SCHEDULE_LEN + 1 - + XQC_PRIORITY_REINJECT_LEN + 1; + + XQC_PRIORITY_REINJECT_LEN + 1 + + XQC_PRIORITY_FEC_LEN + XQC_PRIORITY_FEC_VAL_LEN; if (need > dstcap) { return -XQC_H3_BUFFER_EXCEED; } @@ -896,6 +1061,14 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, dst += XQC_PRIORITY_REINJECT_LEN; *dst++ = '0' + prio->reinject; + xqc_memcpy(dst, XQC_PRIORITY_FEC, XQC_PRIORITY_FEC_LEN); + dst += XQC_PRIORITY_FEC_LEN; + xqc_int_2_str(fec_str, prio->fec, XQC_PRIORITY_FEC_VAL_LEN); + xqc_memcpy(dst, fec_str, XQC_PRIORITY_FEC_VAL_LEN); + dst += XQC_PRIORITY_FEC_VAL_LEN; + + xqc_free(fec_str); + return dst - begin; } @@ -920,7 +1093,7 @@ xqc_parse_http_priority(xqc_h3_priority_t *dst, if (strncmp(p, "u=", xqc_lengthof("u=")) == 0) { p += xqc_lengthof("u="); - prio.urgency = strtoul(p, NULL, 10); + prio.urgency = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "i", xqc_lengthof("i")) == 0) { v = strchr(p, '='); @@ -932,7 +1105,7 @@ xqc_parse_http_priority(xqc_h3_priority_t *dst, } else if (strncmp(p, "i=?", xqc_lengthof("i=?")) == 0) { p += xqc_lengthof("i=?"); - prio.incremental = strtoul(p, NULL, 10); + prio.incremental = strtoul(p, NULL, XQC_DECIMAL); } else { return -XQC_H3_INVALID_PRIORITY; @@ -940,12 +1113,20 @@ xqc_parse_http_priority(xqc_h3_priority_t *dst, } else if (strncmp(p, "s=", xqc_lengthof("s=")) == 0) { p += xqc_lengthof("s="); - prio.schedule = strtoul(p, NULL, 10); + prio.schedule = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "r=", xqc_lengthof("r=")) == 0) { p += xqc_lengthof("r="); - prio.reinject = strtoul(p, NULL, 10); + prio.reinject = strtoul(p, NULL, XQC_DECIMAL); + } else if (strncmp(p, "f=", xqc_lengthof("f=")) == 0) { + p += xqc_lengthof("f="); + // when encounter invalid priority length, set prio.fec to close stats + if (p + XQC_PRIORITY_FEC_VAL_LEN > e) { + prio.fec = XQC_FEC_CLOSE; + goto end; + } + prio.fec = strtoul(p, NULL, XQC_DECIMAL); } p = strchr(p, ','); @@ -988,11 +1169,6 @@ xqc_h3_request_set_priority(xqc_h3_request_t *h3r, xqc_h3_priority_t *prio) } xqc_h3_stream_set_priority(h3r->h3_stream, prio); - xqc_log(h3r->h3_stream->log, XQC_LOG_INFO, - "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|" - "stream_id:%ui|conn:%p|", - prio->urgency, prio->incremental, prio->schedule, prio->reinject, - h3r->h3_stream->stream_id, h3r->h3_stream->h3c->conn); - + xqc_log_event(h3r->h3_stream->log, HTTP_PRIORITY_UPDATED, prio, h3r->h3_stream); return XQC_OK; } \ No newline at end of file diff --git a/src/http3/xqc_h3_request.h b/src/http3/xqc_h3_request.h index c76c18ca1..8b8307ea5 100644 --- a/src/http3/xqc_h3_request.h +++ b/src/http3/xqc_h3_request.h @@ -61,8 +61,32 @@ typedef struct xqc_h3_request_s { xqc_usec_t h3r_body_send_time; xqc_usec_t stream_fin_send_time; xqc_usec_t stream_fin_ack_time; + xqc_usec_t stream_fst_fin_snd_time; + xqc_usec_t stream_fst_pkt_snd_time; + xqc_usec_t stream_fst_pkt_rcv_time; + xqc_usec_t stream_close_delay; const char *stream_close_msg; + uint32_t sched_cwnd_blk_cnt; + uint32_t send_cwnd_blk_cnt; + uint32_t send_pacing_blk_cnt; + xqc_usec_t sched_cwnd_blk_duration; + xqc_usec_t send_cwnd_blk_duration; + xqc_usec_t send_pacing_blk_duration; + + uint32_t retrans_pkt_cnt; + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + + /* fec */ + uint32_t recov_pkt_cnt; + uint8_t block_size_mode; + xqc_usec_t fst_rpr_time; + xqc_usec_t last_rpr_time; + xqc_int_t fec_blk_lack_num; /* number of lack source symbol when receive last repair symbol */ + xqc_usec_t fec_blk_lack_time; /* (first block) block finish time - last received rpr (in block) time */ + xqc_usec_t recv_time_with_fec; + xqc_usec_t final_packet_time; } xqc_h3_request_t; xqc_h3_request_t *xqc_h3_request_create_inner(xqc_h3_conn_t *h3_conn, xqc_h3_stream_t *h3_stream, diff --git a/src/http3/xqc_h3_stream.c b/src/http3/xqc_h3_stream.c index 9c960b062..3c84c928a 100644 --- a/src/http3/xqc_h3_stream.c +++ b/src/http3/xqc_h3_stream.c @@ -86,6 +86,7 @@ xqc_h3_stream_destroy(xqc_h3_stream_t *h3s) } if (h3s->h3r && h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { + xqc_h3_stream_update_stats(h3s); xqc_h3_request_destroy(h3s->h3r); } @@ -388,12 +389,14 @@ xqc_h3_stream_send_headers(xqc_h3_stream_t *h3s, xqc_http_headers_t *headers, ui h3s->h3r->header_sent += headers->total_len; xqc_log(h3c->log, XQC_LOG_DEBUG, "|write:%z|stream_id:%ui|fin:%ud|conn:%p|flag:%s|", write, - h3s->stream_id, (unsigned int)fin, h3c->conn, xqc_conn_flag_2_str(h3c->conn->conn_flag)); + h3s->stream_id, (unsigned int)fin, h3c->conn, xqc_conn_flag_2_str(h3c->conn, h3c->conn->conn_flag)); h3s->flags &= ~XQC_HTTP3_STREAM_NEED_WRITE_NOTIFY; - xqc_engine_main_logic_internal(h3c->conn->engine); - + if (!h3c->conn->engine->config->manually_triggered_send) { + xqc_engine_conn_logic(h3c->conn->engine, h3c->conn); + } + return write; } @@ -526,7 +529,9 @@ xqc_h3_stream_send_data(xqc_h3_stream_t *h3s, unsigned char *data, size_t data_s xqc_log(h3s->log, XQC_LOG_DEBUG, "|stream_id:%ui|data_size:%uz|write:%z|fin:%ud|conn:%p|", h3s->stream_id, data_size, write, (unsigned int)fin, h3s->h3c->conn); - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + if (!h3s->h3c->conn->engine->config->manually_triggered_send) { + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); + } return write; } @@ -570,7 +575,7 @@ xqc_h3_stream_send_finish(xqc_h3_stream_t *h3s) return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -630,7 +635,7 @@ xqc_h3_stream_send_goaway(xqc_h3_stream_t *h3s, uint64_t push_id, uint8_t fin) return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -644,7 +649,7 @@ xqc_h3_stream_send_bidi_stream_type(xqc_h3_stream_t *h3s, return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -682,13 +687,15 @@ xqc_h3_stream_write_notify(xqc_stream_t *stream, void *user_data) if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST && (h3s->flags & XQC_HTTP3_STREAM_NEED_WRITE_NOTIFY)) { - ret = h3s->h3r->request_if->h3_request_write_notify(h3s->h3r, h3s->h3r->user_data); - if (ret < 0) { - xqc_log(stream->stream_conn->log, XQC_LOG_ERROR, - "|h3_request_write_notify error|%d|", ret); - return ret; + if (h3s->h3r->request_if->h3_request_write_notify) { + ret = h3s->h3r->request_if->h3_request_write_notify(h3s->h3r, h3s->h3r->user_data); + if (ret < 0) { + xqc_log(stream->stream_conn->log, XQC_LOG_ERROR, + "|h3_request_write_notify error|%d|", ret); + return ret; + } + xqc_log(h3s->log, XQC_LOG_DEBUG, "|h3_request_write_notify|success|"); } - xqc_log(h3s->log, XQC_LOG_DEBUG, "|h3_request_write_notify|success|"); } //TODO: implement the notification of bytestream writable event @@ -763,6 +770,12 @@ xqc_h3_stream_process_control(xqc_h3_stream_t *h3s, unsigned char *data, size_t break; case XQC_H3_FRM_GOAWAY: + + if (!(h3s->h3c->flags & XQC_H3_CONN_FLAG_GOAWAY_RECVD)) { + h3c->goaway_stream_id = pl->goaway.stream_id.vi; + h3s->h3c->flags |= XQC_H3_CONN_FLAG_GOAWAY_RECVD; + } + if (h3c->goaway_stream_id > pl->goaway.stream_id.vi) { h3c->goaway_stream_id = pl->goaway.stream_id.vi; @@ -771,9 +784,11 @@ xqc_h3_stream_process_control(xqc_h3_stream_t *h3s, unsigned char *data, size_t " receive bigger push id|push_id:%ui|", pl->goaway.stream_id.vi); } - h3s->h3c->flags |= XQC_H3_CONN_FLAG_GOAWAY_RECVD; + xqc_log(h3c->log, XQC_LOG_DEBUG, "|H3_GOAWAY|stream_id:%ui|", pl->goaway.stream_id.vi); + break; + case XQC_H3_FRM_MAX_PUSH_ID: /* PUSH related is not implemented yet */ h3c->max_stream_id_recvd = pl->max_push_id.push_id.vi; @@ -1014,17 +1029,6 @@ xqc_h3_stream_process_request(xqc_h3_stream_t *h3s, unsigned char *data, size_t if (fin_flag && processed == data_len) { h3s->h3r->fin_flag = fin_flag; } - - /* - * when all bytes of DATA frame is read, notify to - * application to make sure it is notified before Trailer - */ - ret = xqc_h3_request_on_recv_body(h3s->h3r); - if (ret != XQC_OK) { - xqc_log(h3s->log, XQC_LOG_ERROR, "|recv body error|%d|", ret); - return ret; - } - xqc_log(h3s->log, XQC_LOG_DEBUG, "|notify body on DATA frame end"); } break; @@ -1549,6 +1553,10 @@ xqc_h3_stream_get_buf(xqc_h3_stream_t *h3s, xqc_list_head_t *head, size_t expect { xqc_var_buf_t *buf = NULL; + if (head->prev == NULL || head->next == NULL) { + return NULL; + } + if (!xqc_list_empty(head)) { /* the last in list */ xqc_list_buf_t *list_buf = xqc_list_entry(head->prev, xqc_list_buf_t, list_head); @@ -1654,6 +1662,7 @@ xqc_h3_stream_process_data(xqc_stream_t *stream, xqc_h3_stream_t *h3s, xqc_bool_ if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { /* only request stream will be blocked */ xqc_h3_request_stream_fin(h3s->h3r); + xqc_h3_stream_update_stats(h3s); } } @@ -1678,8 +1687,10 @@ xqc_h3_stream_process_data(xqc_stream_t *stream, xqc_h3_stream_t *h3s, xqc_bool_ } else if (h3s->type == XQC_H3_STREAM_TYPE_BYTESTEAM) { //TODO: mark the fin flag of the bytestream and record time - xqc_h3_ext_bytestream_fin_rcvd(h3s->h3_ext_bs); - xqc_h3_ext_bytestream_set_fin_rcvd_flag(h3s->h3_ext_bs); + if (h3s->h3_ext_bs) { + xqc_h3_ext_bytestream_fin_rcvd(h3s->h3_ext_bs); + xqc_h3_ext_bytestream_set_fin_rcvd_flag(h3s->h3_ext_bs); + } } } @@ -1873,6 +1884,7 @@ xqc_h3_stream_read_notify(xqc_stream_t *stream, void *user_data) /* TODO: BYTESTRAM: notify DATA to application ASAP */ if (h3s->type == XQC_H3_STREAM_TYPE_BYTESTEAM + && h3s->h3_ext_bs && xqc_h3_ext_bytestream_should_notify_read(h3s->h3_ext_bs)) { ret = xqc_h3_ext_bytestream_notify_read(h3s->h3_ext_bs); @@ -1889,6 +1901,65 @@ xqc_h3_stream_read_notify(xqc_stream_t *stream, void *user_data) return XQC_OK; } +void +xqc_h3_stream_update_stats(xqc_h3_stream_t *h3s) +{ + if (h3s->stream == NULL) { + return; + } +#define __calc_delay(a, b) (a? (a) - (b) : 0) + if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { + h3s->h3r->stream_fin_send_time = h3s->stream->stream_stats.local_fin_snd_time; + h3s->h3r->stream_fst_fin_snd_time = h3s->stream->stream_stats.local_fst_fin_snd_time; + h3s->h3r->stream_fin_ack_time = h3s->stream->stream_stats.first_fin_ack_time; + h3s->h3r->send_cwnd_blk_cnt = h3s->stream->stream_stats.send_cwnd_blk_cnt; + h3s->h3r->sched_cwnd_blk_cnt = h3s->stream->stream_stats.sched_cwnd_blk_cnt; + h3s->h3r->send_pacing_blk_cnt = h3s->stream->stream_stats.send_pacing_blk_cnt; + h3s->h3r->send_cwnd_blk_duration = h3s->stream->stream_stats.send_cwnd_blk_duration; + h3s->h3r->sched_cwnd_blk_duration = h3s->stream->stream_stats.sched_cwnd_blk_duration; + h3s->h3r->send_pacing_blk_duration = h3s->stream->stream_stats.send_pacing_blk_duration; + h3s->h3r->retrans_pkt_cnt = h3s->stream->stream_stats.retrans_pkt_cnt; + h3s->h3r->stream_fst_pkt_snd_time = h3s->stream->stream_stats.first_snd_time; + h3s->h3r->stream_fst_pkt_rcv_time = h3s->stream->stream_stats.first_rcv_time; + h3s->h3r->sent_pkt_cnt = h3s->stream->stream_stats.sent_pkt_cnt; + h3s->h3r->max_pto_backoff = h3s->stream->stream_stats.max_pto_backoff; + h3s->h3r->recov_pkt_cnt = h3s->stream->stream_stats.recov_pkt_cnt; + h3s->h3r->fst_rpr_time = h3s->stream->stream_stats.fst_rpr_time; + h3s->h3r->last_rpr_time = h3s->stream->stream_stats.last_rpr_time; + h3s->h3r->fec_blk_lack_num = h3s->stream->stream_stats.fec_blk_lack_num; + h3s->h3r->fec_blk_lack_time = h3s->stream->stream_stats.fec_blk_lack_time; + h3s->h3r->recv_time_with_fec = h3s->stream->stream_stats.recv_time_with_fec; + h3s->h3r->final_packet_time = h3s->stream->stream_stats.final_packet_time; + h3s->h3r->stream_close_delay = __calc_delay(h3s->stream->stream_stats.close_time, h3s->stream->stream_stats.create_time); + } +#undef __calc_delay + h3s->send_offset = h3s->stream->stream_send_offset; + h3s->recv_offset = h3s->stream->stream_data_in.merged_offset_end; + + if (h3s->h3c == NULL) { + return; + } + + xqc_connection_t *conn = xqc_h3_conn_get_xqc_conn(h3s->h3c); + + if (conn == NULL) { + return; + } + + if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { + h3s->stream->stream_stats.max_pto_backoff = xqc_max(h3s->stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); + h3s->h3r->max_pto_backoff = h3s->stream->stream_stats.max_pto_backoff; + } + + if (h3s->stream->stream_flag & XQC_STREAM_FLAG_HAS_0RTT) { + if (conn->conn_flag & XQC_CONN_FLAG_0RTT_OK) { + h3s->early_data_state = 1; + + } else { + h3s->early_data_state = 2; + } + } +} int xqc_h3_stream_close_notify(xqc_stream_t *stream, void *user_data) @@ -1905,9 +1976,8 @@ xqc_h3_stream_close_notify(xqc_stream_t *stream, void *user_data) xqc_h3_stream_get_path_info(h3s); if (h3s->h3r && h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { - h3s->h3r->stream_fin_send_time = h3s->stream->stream_stats.local_fin_snd_time; - h3s->h3r->stream_fin_ack_time = h3s->stream->stream_stats.first_fin_ack_time; h3s->h3r->stream_close_msg = h3s->stream->stream_close_msg; + xqc_h3_stream_update_stats(h3s); } if (h3s->h3_ext_bs && h3s->type == XQC_H3_STREAM_TYPE_BYTESTEAM) { @@ -1915,6 +1985,9 @@ xqc_h3_stream_close_notify(xqc_stream_t *stream, void *user_data) xqc_h3_ext_bytestream_save_stats_from_stream(h3s->h3_ext_bs, h3s->stream); } + xqc_memcpy(h3s->begin_trans_state, stream->begin_trans_state, XQC_STREAM_TRANSPORT_STATE_SZ); + xqc_memcpy(h3s->end_trans_state, stream->end_trans_state, XQC_STREAM_TRANSPORT_STATE_SZ); + h3s->stream = NULL; /* stream closed, MUST NOT use it any more */ /* @@ -2013,6 +2086,26 @@ xqc_h3_stream_get_path_info(xqc_h3_stream_t *h3s) } } +uint8_t +xqc_set_stream_fec_block_mode(uint32_t fec_size) +{ + if (fec_size == XQC_FEC_DEFAULT) { + return XQC_DEFAULT_SIZE_REQ; + + } else if (fec_size <= XQC_FEC_CLOSE) { + return XQC_SLIM_SIZE_REQ; + + } else if (fec_size <= XQC_FEC_NORMAL) { + return XQC_NORMAL_SIZE_REQ; + + } else if (fec_size <= XQC_FEC_MIDDLE) { + return XQC_MIDDLE_SIZE_REQ; + + } else { + return XQC_LARGE_SIZE_REQ; + } +} + void xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) { @@ -2023,6 +2116,7 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) h3s->priority.incremental = prio->incremental; h3s->priority.schedule = prio->schedule; h3s->priority.reinject = prio->reinject; + h3s->priority.fec = prio->fec; if (h3s->stream == NULL) { xqc_log(h3s->log, XQC_LOG_ERROR, "|transport stream was NULL|stream_id:%ui|", h3s->stream_id); @@ -2030,5 +2124,7 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) } xqc_stream_set_multipath_usage(h3s->stream, h3s->priority.schedule, h3s->priority.reinject); + h3s->stream->stream_fec_blk_mode = xqc_set_stream_fec_block_mode(h3s->priority.fec); + h3s->h3r->block_size_mode = h3s->stream->stream_fec_blk_mode; } } diff --git a/src/http3/xqc_h3_stream.h b/src/http3/xqc_h3_stream.h index b1a151149..61400acd2 100644 --- a/src/http3/xqc_h3_stream.h +++ b/src/http3/xqc_h3_stream.h @@ -9,6 +9,7 @@ #include "src/http3/xqc_h3_defs.h" #include "src/http3/qpack/xqc_qpack.h" #include "src/http3/frame/xqc_h3_frame.h" +#include "src/transport/xqc_stream.h" typedef struct xqc_h3_conn_s xqc_h3_conn_t; typedef struct xqc_h3_stream_s xqc_h3_stream_t; @@ -148,6 +149,13 @@ typedef struct xqc_h3_stream_s { uint32_t ref_cnt; uint64_t recv_rate_limit; + uint64_t send_offset; + uint64_t recv_offset; + + uint8_t early_data_state; + + char begin_trans_state[XQC_STREAM_TRANSPORT_STATE_SZ]; + char end_trans_state[XQC_STREAM_TRANSPORT_STATE_SZ]; } xqc_h3_stream_t; @@ -155,6 +163,8 @@ typedef struct xqc_h3_stream_s { /* transport layer callback hook */ extern const xqc_stream_callbacks_t h3_stream_callbacks; +void xqc_h3_stream_update_stats(xqc_h3_stream_t *h3s); + xqc_h3_stream_t *xqc_h3_stream_create(xqc_h3_conn_t *h3c, xqc_stream_t *stream, xqc_h3_stream_type_t type, void *user_data); diff --git a/src/tls/babassl/xqc_aead_impl.h b/src/tls/babassl/xqc_aead_impl.h index e977b94ec..57100d099 100644 --- a/src/tls/babassl/xqc_aead_impl.h +++ b/src/tls/babassl/xqc_aead_impl.h @@ -25,46 +25,46 @@ #define XQC_AEAD_OVERHEAD_IMPL(obj, cln) (0) + (obj)->taglen /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_AEAD_INIT(obj, a, tgl) ({ \ +#define DO_NOT_CALL_XQC_AEAD_INIT(obj, a, tgl) do { \ obj->aead = a; \ obj->keylen = EVP_CIPHER_key_length(obj->aead); \ obj->noncelen = EVP_CIPHER_iv_length(obj->aead); \ obj->taglen = (tgl); \ obj->encrypt = xqc_ossl_aead_encrypt; \ obj->decrypt = xqc_ossl_aead_decrypt; \ -}) +} while(0) /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) ({ \ +#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) do { \ obj->cipher = c; \ obj->keylen = EVP_CIPHER_key_length(obj->cipher); \ obj->noncelen = EVP_CIPHER_iv_length(obj->cipher); \ obj->hp_mask = xqc_ossl_hp_mask; \ -}) +} while(0) /* aes gcm initialization */ -#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d, ...) ({ \ +#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aes_##d##_gcm(), EVP_GCM_TLS_TAG_LEN); \ -}) +} while(0) /* chacha20 initialization */ -#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, ...) ({ \ +#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_chacha20_poly1305(), EVP_CHACHAPOLY_TLS_TAG_LEN); \ -}) +} while(0) /* aes cipher initialization */ -#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d, ...) ({ \ +#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_aes_##d##_ctr()); \ -}) +} while(0) /* chacha20 cipher initialization */ -#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj, ...) ({ \ +#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_chacha20()); \ -}) +} while(0) xqc_int_t xqc_ossl_aead_encrypt(const xqc_pkt_protect_aead_t *pp_aead, void *aead_ctx, diff --git a/src/tls/babassl/xqc_crypto.c b/src/tls/babassl/xqc_crypto_impl.c similarity index 100% rename from src/tls/babassl/xqc_crypto.c rename to src/tls/babassl/xqc_crypto_impl.c diff --git a/src/tls/babassl/xqc_hkdf.c b/src/tls/babassl/xqc_hkdf_impl.c similarity index 100% rename from src/tls/babassl/xqc_hkdf.c rename to src/tls/babassl/xqc_hkdf_impl.c diff --git a/src/tls/babassl/xqc_ssl_if.c b/src/tls/babassl/xqc_ssl_if_impl.c similarity index 82% rename from src/tls/babassl/xqc_ssl_if.c rename to src/tls/babassl/xqc_ssl_if_impl.c index 0fd24816b..28672a336 100644 --- a/src/tls/babassl/xqc_ssl_if.c +++ b/src/tls/babassl/xqc_ssl_if_impl.c @@ -6,6 +6,7 @@ #include #include "src/tls/xqc_ssl_if.h" #include "src/tls/xqc_tls_common.h" +#include "src/transport/xqc_conn.h" void @@ -114,9 +115,23 @@ xqc_ssl_session_is_early_data_enabled(SSL_SESSION *session) xqc_ssl_handshake_res_t -xqc_ssl_do_handshake(SSL *ssl) +xqc_ssl_do_handshake(SSL *ssl, xqc_connection_t *conn, xqc_log_t *log) { int rv = SSL_do_handshake(ssl); + + xqc_log(log, XQC_LOG_DEBUG, "|ssl_do_handshake|SSL_quic_read_level:%d|SSL_quic_write_level:%d|rv:%d|", + (int) SSL_quic_read_level(ssl), + (int) SSL_quic_write_level(ssl), + rv); + + /* check if client hello is received completely */ + if (SSL_quic_read_level(ssl) > 0 + && conn != NULL + && !(conn->conn_flag & XQC_CONN_FLAG_TLS_CH_RECVD)) + { + conn->conn_flag |= XQC_CONN_FLAG_TLS_CH_RECVD; + } + if (rv <= 0) { int err = SSL_get_error(ssl, rv); switch (err) { diff --git a/src/tls/boringssl/xqc_aead_impl.h b/src/tls/boringssl/xqc_aead_impl.h index 36981e004..5f7096603 100644 --- a/src/tls/boringssl/xqc_aead_impl.h +++ b/src/tls/boringssl/xqc_aead_impl.h @@ -25,49 +25,51 @@ #define XQC_AEAD_OVERHEAD_IMPL(obj,cln) (0) + (obj)->taglen /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_AEAD_INIT(obj,a) ({ \ +#define DO_NOT_CALL_XQC_AEAD_INIT(obj,a) do { \ obj->aead = a; \ obj->taglen = EVP_AEAD_max_tag_len(obj->aead); \ obj->keylen = EVP_AEAD_key_length(obj->aead); \ obj->noncelen = EVP_AEAD_nonce_length(obj->aead); \ obj->encrypt = xqc_bssl_aead_encrypt; \ obj->decrypt = xqc_bssl_aead_decrypt; \ - 0;}) + } while (0) + /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) ({ \ +#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) do { \ obj->cipher = c; \ obj->keylen = EVP_CIPHER_key_length(obj->cipher); \ obj->noncelen = EVP_CIPHER_iv_length(obj->cipher); \ - 0;}) + } while (0) + /* aes gcm initialization */ -#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d, ...) ({ \ +#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aead_aes_##d##_gcm()); \ - 0;}) + } while (0) /* chacha20 initialization */ -#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, ...) ({ \ +#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aead_chacha20_poly1305()); \ - 0;}) + } while(0) /* aes cipher initialization */ -#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d, ...) ({ \ +#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_aes_##d##_ctr()); \ ___cipher->hp_mask = xqc_bssl_hp_mask; \ - 0;}) + } while(0) /* chacha20 follow openssl impl */ -#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj, ...) ({ \ +#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ ___cipher->cipher = NULL; \ ___cipher->keylen = 32; \ ___cipher->noncelen = 16; \ ___cipher->hp_mask = xqc_bssl_hp_mask_chacha20; \ - 0;}) + } while(0) /* extern */ diff --git a/src/tls/boringssl/xqc_crypto.c b/src/tls/boringssl/xqc_crypto_impl.c similarity index 100% rename from src/tls/boringssl/xqc_crypto.c rename to src/tls/boringssl/xqc_crypto_impl.c diff --git a/src/tls/boringssl/xqc_hkdf.c b/src/tls/boringssl/xqc_hkdf_impl.c similarity index 100% rename from src/tls/boringssl/xqc_hkdf.c rename to src/tls/boringssl/xqc_hkdf_impl.c diff --git a/src/tls/boringssl/xqc_ssl_if.c b/src/tls/boringssl/xqc_ssl_if_impl.c similarity index 82% rename from src/tls/boringssl/xqc_ssl_if.c rename to src/tls/boringssl/xqc_ssl_if_impl.c index fa29bfc7f..558df1387 100644 --- a/src/tls/boringssl/xqc_ssl_if.c +++ b/src/tls/boringssl/xqc_ssl_if_impl.c @@ -6,6 +6,7 @@ #include #include "src/tls/xqc_ssl_if.h" #include "src/tls/xqc_tls_common.h" +#include "src/transport/xqc_conn.h" void @@ -83,13 +84,27 @@ xqc_ssl_is_early_data_accepted(SSL *ssl) xqc_ssl_handshake_res_t -xqc_ssl_do_handshake(SSL *ssl) +xqc_ssl_do_handshake(SSL *ssl, xqc_connection_t *conn, xqc_log_t *log) { int ret; again: ERR_clear_error(); ret = SSL_do_handshake(ssl); + + /* check if client hello is received completely */ + if (SSL_quic_read_level(ssl) > 0 + && conn != NULL + && !(conn->conn_flag & XQC_CONN_FLAG_TLS_CH_RECVD)) + { + conn->conn_flag |= XQC_CONN_FLAG_TLS_CH_RECVD; + } + + xqc_log(log, XQC_LOG_DEBUG, "|ssl_do_handshake|SSL_quic_read_level:%d|SSL_quic_write_level:%d|rv:%d|", + (int) SSL_quic_read_level(ssl), + (int) SSL_quic_write_level(ssl), + ret); + if (ret <= 0) { switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_WANT_READ: diff --git a/src/tls/xqc_crypto.c b/src/tls/xqc_crypto.c index 02b5300fb..56e709a93 100644 --- a/src/tls/xqc_crypto.c +++ b/src/tls/xqc_crypto.c @@ -661,9 +661,13 @@ xqc_crypto_derive_updated_keys(xqc_crypto_t *crypto, xqc_key_type_t type) /* update application traffic secret */ static uint8_t LABEL[] = "quic ku"; - uint8_t dest_buf[INITIAL_SECRET_MAX_LEN]; + uint8_t dest_buf[XQC_MAX_KNP_LEN]; - ret = xqc_hkdf_expand_label(dest_buf, INITIAL_SECRET_MAX_LEN, + if (current_ckm->secret.len > XQC_MAX_KNP_LEN) { + return -XQC_TLS_UPDATE_KEY_ERROR; + } + + ret = xqc_hkdf_expand_label(dest_buf, current_ckm->secret.len, current_ckm->secret.base, current_ckm->secret.len, LABEL, xqc_lengthof(LABEL), &crypto->md); if (ret != XQC_OK) { diff --git a/src/tls/xqc_crypto.h b/src/tls/xqc_crypto.h index 52f1b701f..cb150583c 100644 --- a/src/tls/xqc_crypto.h +++ b/src/tls/xqc_crypto.h @@ -27,16 +27,16 @@ typedef struct xqc_hdr_protect_cipher_s xqc_hdr_protect_cipher_t; /* aes_d_gcm d is the length of key */ -#define xqc_aead_init_aes_gcm(aead, d, ...) XQC_AEAD_INIT_AES_GCM_IMPL(aead, d, __VA_ARGS__) +#define xqc_aead_init_aes_gcm(aead, d) XQC_AEAD_INIT_AES_GCM_IMPL(aead, d) /* chacha20_poly1305 */ -#define xqc_aead_init_chacha20_poly1305(obj, ...) XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, __VA_ARGS__) +#define xqc_aead_init_chacha20_poly1305(obj) XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) /* aes_d_ctr */ -#define xqc_cipher_init_aes_ctr(cipher, d, ...) XQC_CIPHER_INIT_AES_CTR_IMPL(cipher, d, __VA_ARGS__) +#define xqc_cipher_init_aes_ctr(cipher, d) XQC_CIPHER_INIT_AES_CTR_IMPL(cipher, d) /* chacha20 */ -#define xqc_cipher_init_chacha20(cipher, ...) XQC_CIPHER_INIT_CHACHA20_IMPL(cipher, __VA_ARGS__) +#define xqc_cipher_init_chacha20(cipher) XQC_CIPHER_INIT_CHACHA20_IMPL(cipher) /* length of aead overhead */ #define xqc_aead_overhead(obj, cln) (XQC_AEAD_OVERHEAD_IMPL((obj), cln)) diff --git a/src/tls/xqc_ssl_if.h b/src/tls/xqc_ssl_if.h index b774e5457..fadf731bc 100644 --- a/src/tls/xqc_ssl_if.h +++ b/src/tls/xqc_ssl_if.h @@ -37,6 +37,6 @@ xqc_int_t xqc_ssl_get_certs_array(SSL *ssl, X509_STORE_CTX *store_ctx, unsigned size_t array_cap, size_t *certs_array_len, size_t *certs_len); void xqc_ssl_free_certs_array(unsigned char **certs_array, size_t certs_array_len); -xqc_ssl_handshake_res_t xqc_ssl_do_handshake(SSL *ssl); +xqc_ssl_handshake_res_t xqc_ssl_do_handshake(SSL *ssl, xqc_connection_t *conn, xqc_log_t *log); #endif \ No newline at end of file diff --git a/src/tls/xqc_tls.c b/src/tls/xqc_tls.c index 5f1f20078..66c3256ca 100644 --- a/src/tls/xqc_tls.c +++ b/src/tls/xqc_tls.c @@ -391,7 +391,10 @@ xqc_tls_process_trans_param(xqc_tls_t *tls) xqc_int_t xqc_tls_do_handshake(xqc_tls_t *tls) { - xqc_ssl_handshake_res_t res = xqc_ssl_do_handshake(tls->ssl); + xqc_ssl_handshake_res_t res = xqc_ssl_do_handshake(tls->ssl, tls->user_data, tls->log); + + xqc_log(tls->log, XQC_LOG_DEBUG, "|TLS handshake|ret:%d|", res); + if (res == XQC_SSL_HSK_RES_FAIL) { xqc_log(tls->log, XQC_LOG_ERROR, "|TLS handshake error:%s|", ERR_error_string(ERR_get_error(), NULL)); @@ -555,6 +558,8 @@ xqc_tls_process_crypto_data(xqc_tls_t *tls, xqc_encrypt_level_t level, int ret; int err; + xqc_log(tls->log, XQC_LOG_DEBUG, "|xqc_tls_process_crypto_data|level:%d|%zu|", level, data_len); + if (SSL_provide_quic_data(ssl, (enum ssl_encryption_level_t)level, crypto_data, data_len) != XQC_SSL_SUCCESS) { @@ -686,7 +691,7 @@ xqc_tls_is_key_ready(xqc_tls_t *tls, xqc_encrypt_level_t level, xqc_key_type_t k } uint32_t -xqc_tls_get_cipher_id(SSL *ssl, xqc_encrypt_level_t level, xqc_bool_t no_crypto) +xqc_tls_get_cipher_id(SSL *ssl, const SSL_CIPHER *cipher, xqc_encrypt_level_t level, xqc_bool_t no_crypto) { if (no_crypto == XQC_TRUE && (level == XQC_ENC_LEV_0RTT || level == XQC_ENC_LEV_1RTT)) @@ -694,6 +699,10 @@ xqc_tls_get_cipher_id(SSL *ssl, xqc_encrypt_level_t level, xqc_bool_t no_crypto) return NID_undef; } + if (cipher != NULL) { + return SSL_CIPHER_get_id(cipher); + } + return SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)); } @@ -857,8 +866,8 @@ xqc_ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outle if (XQC_OK != ret) { return SSL_TLSEXT_ERR_ALERT_FATAL; } - - xqc_log(tls->log, XQC_LOG_DEBUG, "|select alpn|%*s|", alpn_len, alpn); + xqc_log_event(tls->log, TRA_ALPN_INFORMATION, alpn_list, alpn_list_len, in, + inlen, alpn, alpn_len); return SSL_TLSEXT_ERR_OK; } @@ -1063,7 +1072,7 @@ xqc_ssl_cert_cb(SSL *ssl, void *arg) hostname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (NULL == hostname) { - xqc_log(tls->log, XQC_LOG_ERROR, "hostname is NULL"); + xqc_log(tls->log, XQC_LOG_ERROR, "|hostname is NULL"); return XQC_SSL_FAIL; } @@ -1154,7 +1163,7 @@ xqc_tls_set_read_secret(SSL *ssl, enum ssl_encryption_level_t level, /* create crypto instance if not created */ if (NULL == tls->crypto[level]) { tls->crypto[level] = xqc_crypto_create( - xqc_tls_get_cipher_id(ssl, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); + xqc_tls_get_cipher_id(ssl, cipher, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); if (NULL == tls->crypto[level]) { xqc_log(tls->log, XQC_LOG_ERROR, "|create crypto error"); return XQC_SSL_FAIL; @@ -1197,7 +1206,7 @@ xqc_tls_set_write_secret(SSL *ssl, enum ssl_encryption_level_t level, /* create crypto instance if not created */ if (NULL == tls->crypto[level]) { tls->crypto[level] = xqc_crypto_create( - xqc_tls_get_cipher_id(ssl, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); + xqc_tls_get_cipher_id(ssl, cipher, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); if (NULL == tls->crypto[level]) { xqc_log(tls->log, XQC_LOG_ERROR, "|create crypto error"); return XQC_SSL_FAIL; diff --git a/src/tls/xqc_tls.h b/src/tls/xqc_tls.h index b3f7a4dc0..71364b96e 100644 --- a/src/tls/xqc_tls.h +++ b/src/tls/xqc_tls.h @@ -6,10 +6,28 @@ #define XQC_TLS_H #include -#include "xqc_tls_defs.h" #include + +#include "src/tls/xqc_tls_defs.h" #include "src/transport/xqc_packet.h" + + +#ifdef XQC_SYS_WINDOWS +// wincrypt.h defines macros which conflict with OpenSSL's types. This header +// includes wincrypt and undefines the OpenSSL macros which conflict. +#define WIN32_LEAN_AND_MEAN +#include +#include +// Undefine the macros which conflict with OpenSSL and define replacements. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx +#undef PKCS7_SIGNER_INFO +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef X509_NAME +#endif + + /** * @brief init tls context. MUST be called before any creation of xqc_tls_t */ diff --git a/src/transport/fec_schemes/xqc_galois_calculation.c b/src/transport/fec_schemes/xqc_galois_calculation.c new file mode 100644 index 000000000..896c17f28 --- /dev/null +++ b/src/transport/fec_schemes/xqc_galois_calculation.c @@ -0,0 +1,254 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_conn.h" +#include + + +unsigned char +xqc_galois_multiply(unsigned char a, unsigned char b) +{ + if (a == 0 || b == 0) { + return 0; + } + + unsigned char log_a = xqc_rs_log_table[a]; + unsigned char log_b = xqc_rs_log_table[b]; + + return xqc_rs_exp_table[log_a + log_b]; +} + +unsigned char +xqc_galois_exp(unsigned char a, unsigned char n) +{ + unsigned char log_a, log_r; + if (n == 0) { + return 1; + } + + if (a == 0) { + return 0; + } + + log_a = xqc_rs_log_table[a]; + log_r = (log_a * n) % 255; + + return xqc_rs_exp_table[log_r]; +} + +xqc_int_t +xqc_galois_divide(unsigned char a, unsigned char b, unsigned char *res) +{ + if (a == 0) { + *res = 0; + return XQC_OK; + } + + if (b == 0) { + return -XQC_EPARAM; + } + + unsigned char log_a = xqc_rs_log_table[a]; + unsigned char log_b = xqc_rs_log_table[b]; + unsigned char log_r = 0; + + if (log_a < log_b) { + log_r += 255; + } + + log_r += log_a - log_b; + *res = xqc_rs_exp_table[log_r]; + + return XQC_OK; +} + +unsigned char +xqc_galois_inversion(unsigned char a) +{ + int i = 0; + if (a == 0) { + return 0; + } + for (i = 1; i < 256; i++) { + if (xqc_galois_multiply(a, i) == 1) { + return i; + } + } + return 0; +} + + +void +xqc_submatrix(int row_min, int row_max, + int col_min, int col_max, + int col_max_sub, int col_max_matrix, + unsigned char *submatrix, unsigned char *matrix) +{ + xqc_memset(submatrix, 0, col_max_sub * row_max); + for (int row_i = row_min; row_i < row_max; row_i++) { + for (int col_i = col_min; col_i < col_max; col_i++) { + *(submatrix + (row_i - row_min) * col_max_sub + col_i - col_min) = *(matrix + row_i * col_max_matrix + col_i); + } + } +} + +void +xqc_build_vandermonde_matrix(unsigned char rows, unsigned char cols, + unsigned char (*Vandermonde)[XQC_RSM_COL]) +{ + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + Vandermonde[i][j] = (unsigned char)xqc_galois_exp(i, j); + } + } +} + + + +/* Generate a identity matrix with given size */ +xqc_int_t +xqc_identity_matrix(unsigned char size, int output_col, unsigned char (*output)[XQC_RSM_COL]) +{ + for (int i = 0; i < size; i++) { + xqc_memset(output[i], 0, output_col); + output[i][i] = 1; + } + return XQC_OK; +} + +/* concatenate 2 matrices horizontally */ +xqc_int_t +xqc_concatenate_matrix(unsigned char left_rows, unsigned char right_rows, + unsigned char left_cols, unsigned char right_cols, + unsigned char (*left)[XQC_RSM_COL], unsigned char (*right)[XQC_RSM_COL], + unsigned char (*output)[2 * XQC_RSM_COL]) +{ + if (left_rows != right_rows) { + return -XQC_EPARAM; + } + + for (int row_i = 0; row_i < left_rows; row_i++) { + for (int col_i = 0; col_i < left_cols; col_i++) { + output[row_i][col_i] = left[row_i][col_i]; + } + for (int col_i = 0; col_i < right_cols; col_i++) { + output[row_i][left_cols + col_i] = right[row_i][col_i]; + } + } + return XQC_OK; +} + + +xqc_int_t +xqc_gaussian_elimination(unsigned char rows, unsigned char cols, + unsigned char (*output)[2 * XQC_RSM_COL]) +{ + int row_i, col_i, max_row, i, tmp, inv, row_above; + unsigned char ratio = 0; + for (row_i = 0; row_i < rows; row_i++) { + max_row = row_i; + for (i = row_i + 1; i < rows; i++) { + if (output[i][row_i] > output[max_row][row_i]) { + max_row = i; + } + } + + for (col_i = row_i; col_i < cols; col_i++) { + tmp = output[max_row][col_i]; + output[max_row][col_i] = output[row_i][col_i]; + output[row_i][col_i] = tmp; + } + + if (output[row_i][row_i] == 0) { + return -XQC_EFEC_SCHEME_ERROR; + } + + inv = xqc_galois_inversion(output[row_i][row_i]); + for (col_i = row_i; col_i < cols; col_i++) { + output[row_i][col_i] = xqc_galois_multiply(output[row_i][col_i], inv); + } + + for (i = row_i + 1; i < rows; i++) { + tmp = output[i][row_i]; + for (col_i = row_i; col_i < cols; col_i++) { + output[i][col_i] ^= xqc_galois_multiply(tmp, output[row_i][col_i]); + } + } + } + + for (row_i = 0; row_i < rows; row_i++) { + for (row_above = 0; row_above < row_i; row_above++) { + if (output[row_above][row_i] != 0) { + ratio = output[row_above][row_i]; + for (col_i = 0; col_i < cols; col_i++) { + output[row_above][col_i] ^= xqc_galois_multiply(ratio, output[row_i][col_i]); + } + } + } + } + return XQC_OK; +} + +xqc_int_t +xqc_invert_matrix(unsigned char rows, unsigned char cols, unsigned char (*output)[XQC_RSM_COL]) +{ + if (rows != cols) { + return -XQC_EPARAM; + } + + int id_mt_col, out_mt_col, tmp_mt_col; + xqc_int_t ret; + unsigned char identity_matrix[XQC_RSM_COL][XQC_RSM_COL], tmp_matrix[XQC_RSM_COL][2 * XQC_RSM_COL]; + + id_mt_col = out_mt_col = XQC_RSM_COL; + tmp_mt_col = 2 * XQC_RSM_COL; + + if (xqc_identity_matrix(rows, id_mt_col, identity_matrix) != XQC_OK) { + return -XQC_EPARAM; + } + + if (xqc_concatenate_matrix(rows, rows, cols, rows, output, identity_matrix, tmp_matrix) != XQC_OK) { + return -XQC_EPARAM; + } + + ret = xqc_gaussian_elimination(rows, rows + cols, tmp_matrix); + if (ret != XQC_OK) { + return ret; + } + + xqc_submatrix(0, rows, cols, 2 * cols, out_mt_col, tmp_mt_col, &output[0][0], &tmp_matrix[0][0]); + + return XQC_OK; +} + +xqc_int_t +xqc_matrix_time(unsigned char left_row, unsigned char left_col, + unsigned char (*left)[XQC_RSM_COL], + unsigned char right_row, unsigned char right_col, + unsigned char (*right)[XQC_RSM_COL], + unsigned char output_row, unsigned char output_col, + unsigned char (*output)[XQC_RSM_COL]) +{ + unsigned char value = 0; + if (left_col != right_row + || left_row > output_row + || right_col > output_col) + { + /* invalid matrix multiplication. */ + return -XQC_EPARAM; + } + for (int row_i = 0; row_i < left_row; row_i++) { + for(int col_i = 0; col_i < right_col; col_i++) { + value = 0; + for (int i = 0; i < left_col; i++) { + value ^= xqc_galois_multiply(left[row_i][i], right[i][col_i]); + } + output[row_i][col_i] = value; + } + } + return XQC_OK; +} + diff --git a/src/transport/fec_schemes/xqc_galois_calculation.h b/src/transport/fec_schemes/xqc_galois_calculation.h new file mode 100644 index 000000000..e66b41c63 --- /dev/null +++ b/src/transport/fec_schemes/xqc_galois_calculation.h @@ -0,0 +1,162 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_GALOIS_CACULATION_H_ +#define _XQC_GALOIS_CACULATION_H_ + + +#include +#include +#include +#include "src/transport/xqc_defs.h" + +/** + * The following table stands for log_a(x) and exp_a(x), + * where a is the polynomial(here we use 29, (2^8 +) 2^4 + 2^3 + 2^2 + 1) used to generate a Galois field of 256 elements. + * and x is in [0, 255]. + */ +static const unsigned char xqc_rs_log_table[256] = { + -1, 0, 1, 25, 2, 50, 26, 198, + 3, 223, 51, 238, 27, 104, 199, 75, + 4, 100, 224, 14, 52, 141, 239, 129, + 28, 193, 105, 248, 200, 8, 76, 113, + 5, 138, 101, 47, 225, 36, 15, 33, + 53, 147, 142, 218, 240, 18, 130, 69, + 29, 181, 194, 125, 106, 39, 249, 185, + 201, 154, 9, 120, 77, 228, 114, 166, + 6, 191, 139, 98, 102, 221, 48, 253, + 226, 152, 37, 179, 16, 145, 34, 136, + 54, 208, 148, 206, 143, 150, 219, 189, + 241, 210, 19, 92, 131, 56, 70, 64, + 30, 66, 182, 163, 195, 72, 126, 110, + 107, 58, 40, 84, 250, 133, 186, 61, + 202, 94, 155, 159, 10, 21, 121, 43, + 78, 212, 229, 172, 115, 243, 167, 87, + 7, 112, 192, 247, 140, 128, 99, 13, + 103, 74, 222, 237, 49, 197, 254, 24, + 227, 165, 153, 119, 38, 184, 180, 124, + 17, 68, 146, 217, 35, 32, 137, 46, + 55, 63, 209, 91, 149, 188, 207, 205, + 144, 135, 151, 178, 220, 252, 190, 97, + 242, 86, 211, 171, 20, 42, 93, 158, + 132, 60, 57, 83, 71, 109, 65, 162, + 31, 45, 67, 216, 183, 123, 164, 118, + 196, 23, 73, 236, 127, 12, 111, 246, + 108, 161, 59, 82, 41, 157, 85, 170, + 251, 96, 134, 177, 187, 204, 62, 90, + 203, 89, 95, 176, 156, 169, 160, 81, + 11, 245, 22, 235, 122, 117, 44, 215, + 79, 174, 213, 233, 230, 231, 173, 232, + 116, 214, 244, 234, 168, 80, 88, 175 +}; + +static const unsigned char xqc_rs_exp_table[510] = { + 1, 2, 4, 8, 16, 32, 64, -128, + 29, 58, 116, -24, -51, -121, 19, 38, + 76, -104, 45, 90, -76, 117, -22, -55, + -113, 3, 6, 12, 24, 48, 96, -64, + -99, 39, 78, -100, 37, 74, -108, 53, + 106, -44, -75, 119, -18, -63, -97, 35, + 70, -116, 5, 10, 20, 40, 80, -96, + 93, -70, 105, -46, -71, 111, -34, -95, + 95, -66, 97, -62, -103, 47, 94, -68, + 101, -54, -119, 15, 30, 60, 120, -16, + -3, -25, -45, -69, 107, -42, -79, 127, + -2, -31, -33, -93, 91, -74, 113, -30, + -39, -81, 67, -122, 17, 34, 68, -120, + 13, 26, 52, 104, -48, -67, 103, -50, + -127, 31, 62, 124, -8, -19, -57, -109, + 59, 118, -20, -59, -105, 51, 102, -52, + -123, 23, 46, 92, -72, 109, -38, -87, + 79, -98, 33, 66, -124, 21, 42, 84, + -88, 77, -102, 41, 82, -92, 85, -86, + 73, -110, 57, 114, -28, -43, -73, 115, + -26, -47, -65, 99, -58, -111, 63, 126, + -4, -27, -41, -77, 123, -10, -15, -1, + -29, -37, -85, 75, -106, 49, 98, -60, + -107, 55, 110, -36, -91, 87, -82, 65, + -126, 25, 50, 100, -56, -115, 7, 14, + 28, 56, 112, -32, -35, -89, 83, -90, + 81, -94, 89, -78, 121, -14, -7, -17, + -61, -101, 43, 86, -84, 69, -118, 9, + 18, 36, 72, -112, 61, 122, -12, -11, + -9, -13, -5, -21, -53, -117, 11, 22, + 44, 88, -80, 125, -6, -23, -49, -125, + 27, 54, 108, -40, -83, 71, -114, + // Repeat the table a second time, so multiply() + // does not have to check bounds. + 1, 2, 4, 8, 16, 32, 64, -128, + 29, 58, 116, -24, -51, -121, 19, 38, + 76, -104, 45, 90, -76, 117, -22, -55, + -113, 3, 6, 12, 24, 48, 96, -64, + -99, 39, 78, -100, 37, 74, -108, 53, + 106, -44, -75, 119, -18, -63, -97, 35, + 70, -116, 5, 10, 20, 40, 80, -96, + 93, -70, 105, -46, -71, 111, -34, -95, + 95, -66, 97, -62, -103, 47, 94, -68, + 101, -54, -119, 15, 30, 60, 120, -16, + -3, -25, -45, -69, 107, -42, -79, 127, + -2, -31, -33, -93, 91, -74, 113, -30, + -39, -81, 67, -122, 17, 34, 68, -120, + 13, 26, 52, 104, -48, -67, 103, -50, + -127, 31, 62, 124, -8, -19, -57, -109, + 59, 118, -20, -59, -105, 51, 102, -52, + -123, 23, 46, 92, -72, 109, -38, -87, + 79, -98, 33, 66, -124, 21, 42, 84, + -88, 77, -102, 41, 82, -92, 85, -86, + 73, -110, 57, 114, -28, -43, -73, 115, + -26, -47, -65, 99, -58, -111, 63, 126, + -4, -27, -41, -77, 123, -10, -15, -1, + -29, -37, -85, 75, -106, 49, 98, -60, + -107, 55, 110, -36, -91, 87, -82, 65, + -126, 25, 50, 100, -56, -115, 7, 14, + 28, 56, 112, -32, -35, -89, 83, -90, + 81, -94, 89, -78, 121, -14, -7, -17, + -61, -101, 43, 86, -84, 69, -118, 9, + 18, 36, 72, -112, 61, 122, -12, -11, + -9, -13, -5, -21, -53, -117, 11, 22, + 44, 88, -80, 125, -6, -23, -49, -125, + 27, 54, 108, -40, -83, 71, -114 +}; + +unsigned char xqc_galois_multiply(unsigned char a, unsigned char b); +unsigned char xqc_galois_exp(unsigned char a, unsigned char n); + +xqc_int_t xqc_galois_divide(unsigned char a, unsigned char b, unsigned char *res); + + +void xqc_build_vandermonde_matrix(unsigned char rows, unsigned char cols, + unsigned char (*Vandermonde)[XQC_RSM_COL]); + +void xqc_submatrix(int row_min, int row_max, + int col_min, int col_max, + int row_max_sub, int row_max_matrix, + unsigned char *submatrix, unsigned char *matrix); + +xqc_int_t xqc_matrix_time(unsigned char left_row, unsigned char left_col, + unsigned char (*left)[XQC_RSM_COL], + unsigned char right_row, unsigned char right_col, + unsigned char (*right)[XQC_RSM_COL], + unsigned char output_row, unsigned char output_col, + unsigned char (*output)[XQC_RSM_COL]); + + +xqc_int_t xqc_identity_matrix(unsigned char size, int output_col, unsigned char (*output)[XQC_RSM_COL]); + +xqc_int_t +xqc_concatenate_matrix(unsigned char left_rows, unsigned char right_rows, + unsigned char left_cols, unsigned char right_cols, + unsigned char (*left)[XQC_RSM_COL], unsigned char (*right)[XQC_RSM_COL], + unsigned char (*output)[2 * XQC_RSM_COL]); + + +xqc_int_t xqc_gaussian_elimination(unsigned char rows, unsigned char cols, + unsigned char (*output)[2 * XQC_RSM_COL]); + +xqc_int_t xqc_invert_matrix(unsigned char rows, unsigned char cols, unsigned char (*output)[XQC_RSM_COL]); + + +#endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_packet_mask.c b/src/transport/fec_schemes/xqc_packet_mask.c new file mode 100644 index 000000000..4faac7a9c --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask.c @@ -0,0 +1,305 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + +#include "src/transport/fec_schemes/xqc_packet_mask.h" +#include "src/transport/fec_schemes/xqc_xor.h" +#include "src/transport/fec_schemes/xqc_packet_mask_value.h" +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_conn.h" + +const uint8_t * +xqc_get_mask_tbl(xqc_connection_t *conn) +{ + if (conn->conn_settings.fec_params.fec_packet_mask_mode == XQC_FEC_BURST_TBL) + { + return xqc_bst_pm_tbl; + } + return xqc_rnd_pm_tbl; +} + +void +xqc_lookup_pkm(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t rpr_symbol_num, uint8_t *output) +{ + const uint8_t *table = NULL, *mask_entry = NULL; + uint8_t increment, count; + uint16_t tbl_len; + + table = xqc_get_mask_tbl(conn); + + if (src_symbol_num > XQC_MAX_LOOKUP_MASK_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|invalid symbol number for constant mask tbl|src num:%d|rpr num:%d", src_symbol_num, rpr_symbol_num); + return; + } + + tbl_len = table[0]; + increment = 2; + mask_entry = &table[1]; + + // skip entries before src_symbol_num'th one; + for (uint32_t i = 0; i < src_symbol_num - 1; i++) { + count = mask_entry[0]; + mask_entry = &mask_entry[1]; + for (uint32_t j = 0; j < count; j++) { + mask_entry += increment * (j + 1); + } + } + + count = mask_entry[0]; + mask_entry = &mask_entry[1]; + // skip entries before repair_num; + for (uint32_t i = 0; i < rpr_symbol_num - 1; i++) { + mask_entry += increment * (i + 1); + } + + xqc_memcpy(output, mask_entry, increment * rpr_symbol_num); +} + +void +xqc_get_packet_mask(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t rpr_symbol_num, uint8_t *tbl) +{ + size_t tbl_size, increment; + uint32_t i, j; + + xqc_memset(tbl, 0, XQC_MAX_PM_SIZE); + if (src_symbol_num <= XQC_MAX_LOOKUP_MASK_SIZE) { + xqc_lookup_pkm(conn, src_symbol_num, rpr_symbol_num, tbl); + return; + } + + tbl_size = src_symbol_num; + increment = src_symbol_num > 16 ? 6 : 2; + for(i = 0; i < rpr_symbol_num; i++) { + for (j = 0; j < increment; j++) { + tbl[i * increment + j] = + ((j * 8) % rpr_symbol_num == i && (j * 8) < src_symbol_num ? 0x80: 0x00) | + ((j * 8 + 1) % rpr_symbol_num == i && (j * 8 + 1) < src_symbol_num ? 0x40: 0x00) | + ((j * 8 + 2) % rpr_symbol_num == i && (j * 8 + 2) < src_symbol_num ? 0x20: 0x00) | + ((j * 8 + 3) % rpr_symbol_num == i && (j * 8 + 3) < src_symbol_num ? 0x10: 0x00) | + ((j * 8 + 4) % rpr_symbol_num == i && (j * 8 + 4) < src_symbol_num ? 0x08: 0x00) | + ((j * 8 + 5) % rpr_symbol_num == i && (j * 8 + 5) < src_symbol_num ? 0x04: 0x00) | + ((j * 8 + 6) % rpr_symbol_num == i && (j * 8 + 6) < src_symbol_num ? 0x02: 0x00) | + ((j * 8 + 7) % rpr_symbol_num == i && (j * 8 + 7) < src_symbol_num ? 0x01: 0x00); + } + } +} + +void +xqc_packet_mask_init_one(xqc_connection_t *conn, uint8_t bm_idx) +{ + // init packet mask with default block size and code rate + uint8_t k, *output = NULL, table[XQC_MAX_PM_SIZE]; + uint16_t repair_num, increment; + const uint8_t *tbl_p = table; + + repair_num = conn->fec_ctl->fec_send_required_repair_num[bm_idx]; + k = xqc_get_fec_blk_size(conn, bm_idx); + increment = k > 16 ? 6 : 2; + + if (k > 48 || repair_num <= 0 || repair_num > xqc_min(k, XQC_REPAIR_LEN)) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + return; + } + + xqc_get_packet_mask(conn, k, repair_num, table); + + for (uint32_t j = 0; j < repair_num; j++) { + output = conn->fec_ctl->fec_send_decode_matrix[bm_idx][j]; + xqc_memset(output, 0, increment); + xqc_memcpy(output, tbl_p, increment); + tbl_p += increment; + } + + return; +} + +void +xqc_packet_mask_init(xqc_connection_t *conn) +{ + // init packet mask with default block size and code rate + uint8_t i, k, *output = NULL, table[XQC_MAX_PM_SIZE]; + uint16_t repair_num, increment; + const uint8_t *tbl_p = table; + + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; + } + repair_num = conn->fec_ctl->fec_send_required_repair_num[i]; + k = xqc_get_fec_blk_size(conn, i); + increment = k > 16 ? 6 : 2; + + if (k > 48 || repair_num <= 0 || repair_num > xqc_min(k, XQC_REPAIR_LEN)) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + return; + } + + xqc_get_packet_mask(conn, k, repair_num, table); + tbl_p = table; + + for (uint32_t j = 0; j < repair_num; j++) { + output = conn->fec_ctl->fec_send_decode_matrix[i][j]; + xqc_memset(output, 0, increment); + xqc_memcpy(output, tbl_p, increment); + tbl_p += increment; + } + } + + return; +} + +xqc_int_t +xqc_pm_code_symbols(xqc_connection_t *conn, unsigned char *input, size_t in_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + size_t tmp_size; + uint32_t src_syb_num, repair_num, symbol_idx; + unsigned char pm_size, pm_offset, symbol_flag, *output_p = NULL, *pm_p = NULL, *rpr_key_p = NULL; + xqc_int_t ret = XQC_OK; + + if (fec_bm_mode >= XQC_BLOCK_MODE_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|invalid fec_bm_mode:%d|", fec_bm_mode); + return -XQC_EPARAM; + } + src_syb_num = xqc_get_fec_blk_size(conn, fec_bm_mode); + repair_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + symbol_idx = conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]; + symbol_flag = 1 << (7 - symbol_idx % 8); + pm_offset = symbol_idx / 8; + pm_size = src_syb_num > 16 ? 6 : 2; + + if (repair_num > XQC_REPAIR_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair number exceeds buff size"); + return -XQC_EPARAM; + } + + if (pm_offset >= pm_size) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol index"); + return -XQC_EPARAM; + } + + for (uint32_t i = 0; i < repair_num; i++) { + pm_p = conn->fec_ctl->fec_send_decode_matrix[fec_bm_mode][i]; + rpr_key_p = conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i].payload; + if (*(rpr_key_p + pm_offset) & symbol_flag) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|source symbol already been calculated"); + + } else if (symbol_flag & *(pm_p + pm_offset)) { + output_p = outputs[i]; + ret = xqc_xor_code_one_symbol(input, output_p, in_size); + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(in_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i], 1, output_p, + tmp_size); + if (ret == XQC_OK) { + // update repair key value with symbol flag + *(rpr_key_p + pm_offset) |= symbol_flag; + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i], 1, rpr_key_p, pm_size); + } + } + } + return ret; +} + +/** + * TODOfec: maybe need a function to update block size/ code rate, + * for packet mask can be changed according to network conditions; + */ + +xqc_int_t +xqc_packet_mask_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + xqc_int_t ret; + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_packet_mask_encode|invalid input size:%d|", st_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + + ret = xqc_pm_code_symbols(conn, stream, st_size, outputs, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_packet_mask_encode|code symbols failed with errno: %d|", ret); + return -XQC_EFEC_SCHEME_ERROR; + } + + return ret; +} + +xqc_int_t +xqc_packet_mask_decode_one(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx) +{ + xqc_int_t ret, src_block_id, src_symbol_idx, src_mask_offset; + xqc_list_head_t *pos, *next, *src_list, *rpr_list; + xqc_fec_rpr_syb_t *rpr_symbol; + + if (recovered_symbols_buff == NULL) { + return -XQC_EPARAM; + } + + src_list = &conn->fec_ctl->fec_recv_src_syb_list; + rpr_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + rpr_symbol = xqc_get_rpr_symbol(rpr_list, block_id, symbol_idx); + if (rpr_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|no such repair symbol|"); + return -XQC_EPARAM; + } + + if (rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|pkm decoder can't process rpr symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(rpr_symbol->payload, recovered_symbols_buff, rpr_symbol->payload_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_mask calculate xor error"); + return -XQC_EFEC_SCHEME_ERROR; + } + + xqc_list_for_each_safe(pos, next, src_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + + if (src_symbol->block_id > block_id) { + break; + } + src_block_id = src_symbol->block_id; + src_symbol_idx = src_symbol->symbol_idx; + src_mask_offset = src_symbol_idx / 8; + if (src_mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + return -XQC_EFEC_SCHEME_ERROR; + } + + if (src_block_id == block_id + && *(rpr_symbol->recv_mask + src_mask_offset) & (1 << (7 - src_symbol_idx % 8))) + { + if (src_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|pkm decoder can't process src symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(src_symbol->payload, recovered_symbols_buff, src_symbol->payload_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_mask calculate xor error"); + return -XQC_EFEC_SCHEME_ERROR; + } + } + } + + return ret; +} + +const xqc_fec_code_callback_t xqc_packet_mask_code_cb = { + .xqc_fec_init = xqc_packet_mask_init, + .xqc_fec_init_one = xqc_packet_mask_init_one, + .xqc_fec_encode = xqc_packet_mask_encode, + .xqc_fec_decode_one = xqc_packet_mask_decode_one + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_packet_mask.h b/src/transport/fec_schemes/xqc_packet_mask.h new file mode 100644 index 000000000..8d3afa532 --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask.h @@ -0,0 +1,31 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_PACKET_MASK_H_ +#define _XQC_FEC_PACKET_MASK_H_ + +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include +#include +#include + +// TODOfec: might needed change according to the draft +#define XQC_MAX_MASK_SIZE 48 +#define XQC_MAX_LOOKUP_MASK_SIZE 12 + +extern const xqc_fec_code_callback_t xqc_packet_mask_code_cb; + +void xqc_packet_mask_init(xqc_connection_t *conn); + +void +xqc_packet_mask_init_one(xqc_connection_t *conn, uint8_t bm_idx); + +xqc_int_t xqc_packet_mask_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); + +xqc_int_t xqc_packet_mask_decode_one(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx); +#endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_packet_mask_value.h b/src/transport/fec_schemes/xqc_packet_mask_value.h new file mode 100644 index 000000000..cad478615 --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask_value.h @@ -0,0 +1,1278 @@ +#define RandomMask1_1 \ + 0x80, 0x00 + +#define RandomMask2_1 \ + 0xc0, 0x00 + +#define RandomMask2_2 \ + 0xc0, 0x00, \ + 0x80, 0x00 + +#define RandomMask3_1 \ + 0xe0, 0x00 + +#define RandomMask3_2 \ + 0xc0, 0x00, \ + 0xa0, 0x00 + +#define RandomMask3_3 \ + 0xc0, 0x00, \ + 0xa0, 0x00, \ + 0x60, 0x00 + +#define RandomMask4_1 \ + 0xf0, 0x00 + +#define RandomMask4_2 \ + 0xc0, 0x00, \ + 0xb0, 0x00 + +#define RandomMask4_3 \ + 0xc0, 0x00, \ + 0xb0, 0x00, \ + 0x60, 0x00 + +#define RandomMask4_4 \ + 0xc0, 0x00, \ + 0xa0, 0x00, \ + 0x30, 0x00, \ + 0x50, 0x00 + +#define RandomMask5_1 \ + 0xf8, 0x00 + +#define RandomMask5_2 \ + 0xa8, 0x00, \ + 0xd0, 0x00 + +#define RandomMask5_3 \ + 0xb0, 0x00, \ + 0xc8, 0x00, \ + 0x50, 0x00 + +#define RandomMask5_4 \ + 0xc8, 0x00, \ + 0xb0, 0x00, \ + 0x50, 0x00, \ + 0x28, 0x00 + +#define RandomMask5_5 \ + 0xc0, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0xa0, 0x00, \ + 0x48, 0x00 + +#define RandomMask6_1 \ + 0xfc, 0x00 + +#define RandomMask6_2 \ + 0xa8, 0x00, \ + 0xd4, 0x00 + +#define RandomMask6_3 \ + 0xd0, 0x00, \ + 0x68, 0x00, \ + 0xa4, 0x00 + +#define RandomMask6_4 \ + 0xa8, 0x00, \ + 0x58, 0x00, \ + 0x64, 0x00, \ + 0x94, 0x00 + +#define RandomMask6_5 \ + 0xa8, 0x00, \ + 0x84, 0x00, \ + 0x64, 0x00, \ + 0x90, 0x00, \ + 0x58, 0x00 + +#define RandomMask6_6 \ + 0x98, 0x00, \ + 0x64, 0x00, \ + 0x50, 0x00, \ + 0x14, 0x00, \ + 0xa8, 0x00, \ + 0xe0, 0x00 + +#define RandomMask7_1 \ + 0xfe, 0x00 + +#define RandomMask7_2 \ + 0xd4, 0x00, \ + 0xaa, 0x00 + +#define RandomMask7_3 \ + 0xd0, 0x00, \ + 0xaa, 0x00, \ + 0x64, 0x00 + +#define RandomMask7_4 \ + 0xd0, 0x00, \ + 0xaa, 0x00, \ + 0x64, 0x00, \ + 0x1c, 0x00 + +#define RandomMask7_5 \ + 0x0c, 0x00, \ + 0xb0, 0x00, \ + 0x1a, 0x00, \ + 0xc4, 0x00, \ + 0x62, 0x00 + +#define RandomMask7_6 \ + 0x8c, 0x00, \ + 0x4a, 0x00, \ + 0x64, 0x00, \ + 0xd0, 0x00, \ + 0xa0, 0x00, \ + 0x32, 0x00 + +#define RandomMask7_7 \ + 0x4a, 0x00, \ + 0x94, 0x00, \ + 0x1a, 0x00, \ + 0xc4, 0x00, \ + 0x28, 0x00, \ + 0xc2, 0x00, \ + 0x34, 0x00 + +#define RandomMask8_1 \ + 0xff, 0x00 + +#define RandomMask8_2 \ + 0xaa, 0x00, \ + 0xd5, 0x00 + +#define RandomMask8_3 \ + 0xc5, 0x00, \ + 0x92, 0x00, \ + 0x6a, 0x00 + +#define RandomMask8_4 \ + 0x45, 0x00, \ + 0xb4, 0x00, \ + 0x6a, 0x00, \ + 0x89, 0x00 + +#define RandomMask8_5 \ + 0x8c, 0x00, \ + 0x92, 0x00, \ + 0x2b, 0x00, \ + 0x51, 0x00, \ + 0x64, 0x00 + +#define RandomMask8_6 \ + 0xa1, 0x00, \ + 0x52, 0x00, \ + 0x91, 0x00, \ + 0x2a, 0x00, \ + 0xc4, 0x00, \ + 0x4c, 0x00 + +#define RandomMask8_7 \ + 0x15, 0x00, \ + 0xc2, 0x00, \ + 0x25, 0x00, \ + 0x62, 0x00, \ + 0x58, 0x00, \ + 0x8c, 0x00, \ + 0xa3, 0x00 + +#define RandomMask8_8 \ + 0x25, 0x00, \ + 0x8a, 0x00, \ + 0x91, 0x00, \ + 0x68, 0x00, \ + 0x32, 0x00, \ + 0x43, 0x00, \ + 0xc4, 0x00, \ + 0x1c, 0x00 + +#define RandomMask9_1 \ + 0xff, 0x80 + +#define RandomMask9_2 \ + 0xaa, 0x80, \ + 0xd5, 0x00 + +#define RandomMask9_3 \ + 0xa5, 0x00, \ + 0xc8, 0x00, \ + 0x52, 0x80 + +#define RandomMask9_4 \ + 0xa2, 0x00, \ + 0xc9, 0x00, \ + 0x52, 0x80, \ + 0x24, 0x80 + +#define RandomMask9_5 \ + 0x8c, 0x00, \ + 0x25, 0x00, \ + 0x92, 0x80, \ + 0x41, 0x80, \ + 0x58, 0x00 + +#define RandomMask9_6 \ + 0x84, 0x80, \ + 0x27, 0x00, \ + 0x51, 0x80, \ + 0x1a, 0x00, \ + 0x68, 0x00, \ + 0x89, 0x00 + +#define RandomMask9_7 \ + 0x8c, 0x00, \ + 0x47, 0x00, \ + 0x81, 0x80, \ + 0x12, 0x80, \ + 0x58, 0x00, \ + 0x28, 0x80, \ + 0xb4, 0x00 + +#define RandomMask9_8 \ + 0x2c, 0x00, \ + 0x91, 0x00, \ + 0x40, 0x80, \ + 0x06, 0x80, \ + 0xc8, 0x00, \ + 0x45, 0x00, \ + 0x30, 0x80, \ + 0xa2, 0x00 + +#define RandomMask9_9 \ + 0x4c, 0x00, \ + 0x62, 0x00, \ + 0x91, 0x00, \ + 0x42, 0x80, \ + 0xa4, 0x00, \ + 0x13, 0x00, \ + 0x30, 0x80, \ + 0x88, 0x80, \ + 0x09, 0x00 + +#define RandomMask10_1 \ + 0xff, 0xc0 + +#define RandomMask10_10 \ + 0x4c, 0x00, \ + 0x51, 0x00, \ + 0xa0, 0x40, \ + 0x04, 0xc0, \ + 0x03, 0x80, \ + 0x86, 0x00, \ + 0x29, 0x00, \ + 0x42, 0x40, \ + 0x98, 0x00, \ + 0x30, 0x80 + +#define RandomMask10_2 \ + 0xaa, 0x80, \ + 0xd5, 0x40 + +#define RandomMask10_3 \ + 0xa4, 0x40, \ + 0xc9, 0x00, \ + 0x52, 0x80 + +#define RandomMask10_4 \ + 0xca, 0x00, \ + 0x32, 0x80, \ + 0xa1, 0x40, \ + 0x55, 0x00 + +#define RandomMask10_5 \ + 0xca, 0x00, \ + 0x32, 0x80, \ + 0xa1, 0x40, \ + 0x55, 0x00, \ + 0x08, 0xc0 + +#define RandomMask10_6 \ + 0x0e, 0x00, \ + 0x33, 0x00, \ + 0x10, 0xc0, \ + 0x45, 0x40, \ + 0x88, 0x80, \ + 0xe0, 0x00 + +#define RandomMask10_7 \ + 0x46, 0x00, \ + 0x33, 0x00, \ + 0x80, 0xc0, \ + 0x0c, 0x40, \ + 0x28, 0x80, \ + 0x94, 0x00, \ + 0xc1, 0x00 + +#define RandomMask10_8 \ + 0x2c, 0x00, \ + 0x81, 0x80, \ + 0xa0, 0x40, \ + 0x05, 0x40, \ + 0x18, 0x80, \ + 0xc2, 0x00, \ + 0x22, 0x80, \ + 0x50, 0x40 + +#define RandomMask10_9 \ + 0x4c, 0x00, \ + 0x23, 0x00, \ + 0x88, 0xc0, \ + 0x21, 0x40, \ + 0x52, 0x80, \ + 0x94, 0x00, \ + 0x26, 0x00, \ + 0x48, 0x40, \ + 0x91, 0x80 + +#define RandomMask11_1 \ + 0xff, 0xe0 + +#define RandomMask11_10 \ + 0x64, 0x40, \ + 0x51, 0x40, \ + 0xa9, 0x00, \ + 0x04, 0xc0, \ + 0xd0, 0x00, \ + 0x82, 0x40, \ + 0x21, 0x20, \ + 0x0c, 0x20, \ + 0x4a, 0x00, \ + 0x12, 0xa0 + +#define RandomMask11_11 \ + 0x46, 0x40, \ + 0x33, 0x20, \ + 0x99, 0x00, \ + 0x05, 0x80, \ + 0x80, 0xa0, \ + 0x84, 0x40, \ + 0x40, 0x60, \ + 0x0a, 0x80, \ + 0x68, 0x00, \ + 0x10, 0x20, \ + 0x30, 0x40 + +#define RandomMask11_2 \ + 0xec, 0xc0, \ + 0x9b, 0xa0 + +#define RandomMask11_3 \ + 0xca, 0xc0, \ + 0xf1, 0x40, \ + 0xb6, 0x20 + +#define RandomMask11_4 \ + 0xc4, 0xc0, \ + 0x31, 0x60, \ + 0x4b, 0x20, \ + 0x2c, 0xa0 + +#define RandomMask11_5 \ + 0x86, 0x80, \ + 0x23, 0x20, \ + 0x16, 0x20, \ + 0x4c, 0x20, \ + 0x41, 0xc0 + +#define RandomMask11_6 \ + 0x64, 0x40, \ + 0x51, 0x40, \ + 0x0c, 0xa0, \ + 0xa1, 0x20, \ + 0x12, 0xa0, \ + 0x8a, 0x40 + +#define RandomMask11_7 \ + 0x46, 0x40, \ + 0x33, 0x20, \ + 0x91, 0x80, \ + 0xa4, 0x20, \ + 0x50, 0xa0, \ + 0x84, 0xc0, \ + 0x09, 0x60 + +#define RandomMask11_8 \ + 0x0c, 0x80, \ + 0x80, 0x60, \ + 0xa0, 0x80, \ + 0x05, 0x40, \ + 0x43, 0x00, \ + 0x1a, 0x00, \ + 0x60, 0x20, \ + 0x14, 0x20 + +#define RandomMask11_9 \ + 0x46, 0x40, \ + 0x62, 0x60, \ + 0x8c, 0x00, \ + 0x01, 0x60, \ + 0x07, 0x80, \ + 0xa0, 0x80, \ + 0x18, 0xa0, \ + 0x91, 0x00, \ + 0x78, 0x00 + +#define RandomMask12_1 \ + 0xff, 0xf0 + +#define RandomMask12_10 \ + 0x51, 0x40, \ + 0x45, 0x10, \ + 0x80, 0xd0, \ + 0x24, 0x20, \ + 0x0a, 0x20, \ + 0x00, 0xe0, \ + 0xb8, 0x00, \ + 0x09, 0x10, \ + 0x56, 0x00, \ + 0xa2, 0x80 + +#define RandomMask12_11 \ + 0x53, 0x60, \ + 0x21, 0x30, \ + 0x10, 0x90, \ + 0x00, 0x70, \ + 0x0c, 0x10, \ + 0x40, 0xc0, \ + 0x6a, 0x00, \ + 0x86, 0x00, \ + 0x24, 0x80, \ + 0x89, 0x00, \ + 0xc0, 0x20 + +#define RandomMask12_12 \ + 0x10, 0x60, \ + 0x02, 0x30, \ + 0x40, 0x50, \ + 0x21, 0x80, \ + 0x81, 0x10, \ + 0x14, 0x80, \ + 0x98, 0x00, \ + 0x08, 0x90, \ + 0x62, 0x00, \ + 0x24, 0x20, \ + 0x8a, 0x00, \ + 0x84, 0x40 + +#define RandomMask12_2 \ + 0xec, 0xc0, \ + 0x93, 0xb0 + +#define RandomMask12_3 \ + 0x9b, 0x80, \ + 0x4f, 0x10, \ + 0x3c, 0x60 + +#define RandomMask12_4 \ + 0x8b, 0x20, \ + 0x14, 0xb0, \ + 0x22, 0xd0, \ + 0x45, 0x50 + +#define RandomMask12_5 \ + 0x53, 0x60, \ + 0x64, 0x20, \ + 0x0c, 0xc0, \ + 0x82, 0xa0, \ + 0x09, 0x30 + +#define RandomMask12_6 \ + 0x51, 0x40, \ + 0xc5, 0x10, \ + 0x21, 0x80, \ + 0x12, 0x30, \ + 0x08, 0xe0, \ + 0x2e, 0x00 + +#define RandomMask12_7 \ + 0x53, 0x60, \ + 0x21, 0x30, \ + 0x90, 0x90, \ + 0x02, 0x50, \ + 0x06, 0xa0, \ + 0x2c, 0x00, \ + 0x88, 0x60 + +#define RandomMask12_8 \ + 0x20, 0x60, \ + 0x80, 0x30, \ + 0x42, 0x40, \ + 0x01, 0x90, \ + 0x14, 0x10, \ + 0x0a, 0x80, \ + 0x38, 0x00, \ + 0xc5, 0x00 + +#define RandomMask12_9 \ + 0x53, 0x60, \ + 0xe4, 0x20, \ + 0x24, 0x40, \ + 0xa1, 0x10, \ + 0x18, 0x30, \ + 0x03, 0x90, \ + 0x8a, 0x10, \ + 0x04, 0x90, \ + 0x00, 0xe0 + +// choose second idx of packet mask according to n-k value (repair number) +#define RandomPacketMask1 1, \ + RandomMask1_1 + +#define RandomPacketMask2 2, \ + RandomMask2_1, \ + RandomMask2_2 + +#define RandomPacketMask3 3, \ + RandomMask3_1, \ + RandomMask3_2, \ + RandomMask3_3 + +#define RandomPacketMask4 4, \ + RandomMask4_1, \ + RandomMask4_2, \ + RandomMask4_3, \ + RandomMask4_4 + +#define RandomPacketMask5 5, \ + RandomMask5_1, \ + RandomMask5_2, \ + RandomMask5_3, \ + RandomMask5_4, \ + RandomMask5_5 + +#define RandomPacketMask6 6, \ + RandomMask6_1, \ + RandomMask6_2, \ + RandomMask6_3, \ + RandomMask6_4, \ + RandomMask6_5, \ + RandomMask6_6 + +#define RandomPacketMask7 7, \ + RandomMask7_1, \ + RandomMask7_2, \ + RandomMask7_3, \ + RandomMask7_4, \ + RandomMask7_5, \ + RandomMask7_6, \ + RandomMask7_7 + +#define RandomPacketMask8 8, \ + RandomMask8_1, \ + RandomMask8_2, \ + RandomMask8_3, \ + RandomMask8_4, \ + RandomMask8_5, \ + RandomMask8_6, \ + RandomMask8_7, \ + RandomMask8_8 + +#define RandomPacketMask9 9, \ + RandomMask9_1, \ + RandomMask9_2, \ + RandomMask9_3, \ + RandomMask9_4, \ + RandomMask9_5, \ + RandomMask9_6, \ + RandomMask9_7, \ + RandomMask9_8, \ + RandomMask9_9 + +#define RandomPacketMask10 10, \ + RandomMask10_1, \ + RandomMask10_2, \ + RandomMask10_3, \ + RandomMask10_4, \ + RandomMask10_5, \ + RandomMask10_6, \ + RandomMask10_7, \ + RandomMask10_8, \ + RandomMask10_9, \ + RandomMask10_10 + +#define RandomPacketMask11 11, \ + RandomMask11_1, \ + RandomMask11_2, \ + RandomMask11_3, \ + RandomMask11_4, \ + RandomMask11_5, \ + RandomMask11_6, \ + RandomMask11_7, \ + RandomMask11_8, \ + RandomMask11_9, \ + RandomMask11_10, \ + RandomMask11_11 + +#define RandomPacketMask12 12, \ + RandomMask12_1, \ + RandomMask12_2, \ + RandomMask12_3, \ + RandomMask12_4, \ + RandomMask12_5, \ + RandomMask12_6, \ + RandomMask12_7, \ + RandomMask12_8, \ + RandomMask12_9, \ + RandomMask12_10, \ + RandomMask12_11, \ + RandomMask12_12 + + +#define BurstMask1_1 \ + 0x80, 0x00 + +#define BurstMask2_1 \ + 0xc0, 0x00 + +#define BurstMask2_2 \ + 0x80, 0x00, \ + 0xc0, 0x00 + +#define BurstMask3_1 \ + 0xe0, 0x00 + +#define BurstMask3_2 \ + 0xc0, 0x00, \ + 0xa0, 0x00 + +#define BurstMask3_3 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00 + +#define BurstMask4_1 \ + 0xf0, 0x00 + +#define BurstMask4_2 \ + 0xa0, 0x00, \ + 0xd0, 0x00 + +#define BurstMask4_3 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x90, 0x00 + +#define BurstMask4_4 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00 + +#define BurstMask5_1 \ + 0xf8, 0x00 + +#define BurstMask5_2 \ + 0xd0, 0x00, \ + 0xa8, 0x00 + +#define BurstMask5_3 \ + 0x70, 0x00, \ + 0x90, 0x00, \ + 0xc8, 0x00 + +#define BurstMask5_4 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x88, 0x00 + +#define BurstMask5_5 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00 + +#define BurstMask6_1 \ + 0xfc, 0x00 + +#define BurstMask6_2 \ + 0xa8, 0x00, \ + 0xd4, 0x00 + +#define BurstMask6_3 \ + 0x94, 0x00, \ + 0xc8, 0x00, \ + 0x64, 0x00 + +#define BurstMask6_4 \ + 0x60, 0x00, \ + 0x38, 0x00, \ + 0x88, 0x00, \ + 0xc4, 0x00 + +#define BurstMask6_5 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x84, 0x00 + +#define BurstMask6_6 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00 + +#define BurstMask7_1 \ + 0xfe, 0x00 + +#define BurstMask7_2 \ + 0xd4, 0x00, \ + 0xaa, 0x00 + +#define BurstMask7_3 \ + 0xc8, 0x00, \ + 0x74, 0x00, \ + 0x92, 0x00 + +#define BurstMask7_4 \ + 0x38, 0x00, \ + 0x8a, 0x00, \ + 0xc4, 0x00, \ + 0x62, 0x00 + +#define BurstMask7_5 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x1c, 0x00, \ + 0x84, 0x00, \ + 0xc2, 0x00 + +#define BurstMask7_6 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x82, 0x00 + +#define BurstMask7_7 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00 + +#define BurstMask8_1 \ + 0xff, 0x00 + +#define BurstMask8_2 \ + 0xaa, 0x00, \ + 0xd5, 0x00 + +#define BurstMask8_3 \ + 0x74, 0x00, \ + 0x92, 0x00, \ + 0xc9, 0x00 + +#define BurstMask8_4 \ + 0x8a, 0x00, \ + 0xc5, 0x00, \ + 0x62, 0x00, \ + 0x31, 0x00 + +#define BurstMask8_5 \ + 0x30, 0x00, \ + 0x1c, 0x00, \ + 0x85, 0x00, \ + 0xc2, 0x00, \ + 0x61, 0x00 + +#define BurstMask8_6 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0e, 0x00, \ + 0x82, 0x00, \ + 0xc1, 0x00 + +#define BurstMask8_7 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x81, 0x00 + +#define BurstMask8_8 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00 + +#define BurstMask9_1 \ + 0xff, 0x80 + +#define BurstMask9_2 \ + 0xd5, 0x00, \ + 0xaa, 0x80 + +#define BurstMask9_3 \ + 0x92, 0x00, \ + 0xc9, 0x00, \ + 0x74, 0x80 + +#define BurstMask9_4 \ + 0xc5, 0x00, \ + 0x62, 0x00, \ + 0x39, 0x00, \ + 0x8a, 0x80 + +#define BurstMask9_5 \ + 0x1c, 0x00, \ + 0x85, 0x00, \ + 0xc2, 0x80, \ + 0x61, 0x00, \ + 0x30, 0x80 + +#define BurstMask9_6 \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0e, 0x00, \ + 0x82, 0x80, \ + 0xc1, 0x00, \ + 0x60, 0x80 + +#define BurstMask9_7 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x07, 0x00, \ + 0x81, 0x00, \ + 0xc0, 0x80 + +#define BurstMask9_8 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x80, 0x80 + +#define BurstMask9_9 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80 + +#define BurstMask10_1 \ + 0xff, 0xc0 + +#define BurstMask10_2 \ + 0xaa, 0x80, \ + 0xd5, 0x40 + +#define BurstMask10_3 \ + 0xc9, 0x00, \ + 0x74, 0x80, \ + 0x92, 0x40 + +#define BurstMask10_4 \ + 0x62, 0x00, \ + 0x39, 0x00, \ + 0x8a, 0x80, \ + 0xc5, 0x40 + +#define BurstMask10_5 \ + 0x85, 0x00, \ + 0xc2, 0x80, \ + 0x61, 0x40, \ + 0x30, 0x80, \ + 0x18, 0x40 + +#define BurstMask10_6 \ + 0x18, 0x00, \ + 0x0e, 0x00, \ + 0x82, 0x80, \ + 0xc1, 0x40, \ + 0x60, 0x80, \ + 0x30, 0x40 + +#define BurstMask10_7 \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x07, 0x00, \ + 0x81, 0x40, \ + 0xc0, 0x80, \ + 0x60, 0x40 + +#define BurstMask10_8 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x80, 0x80, \ + 0xc0, 0x40 + +#define BurstMask10_9 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x80, 0x40 + +#define BurstMask10_10 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0 + +#define BurstMask11_1 \ + 0xff, 0xe0 + +#define BurstMask11_2 \ + 0xd5, 0x40, \ + 0xaa, 0xa0 + +#define BurstMask11_3 \ + 0x74, 0x80, \ + 0x92, 0x40, \ + 0xc9, 0x20 + +#define BurstMask11_4 \ + 0x39, 0x00, \ + 0x8a, 0x80, \ + 0xc5, 0x40, \ + 0x62, 0x20 + +#define BurstMask11_5 \ + 0xc2, 0xc0, \ + 0x61, 0x00, \ + 0x30, 0xa0, \ + 0x1c, 0x40, \ + 0x85, 0x20 + +#define BurstMask11_6 \ + 0x0e, 0x00, \ + 0x82, 0x80, \ + 0xc1, 0x40, \ + 0x60, 0xa0, \ + 0x30, 0x40, \ + 0x18, 0x20 + +#define BurstMask11_7 \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x07, 0x00, \ + 0x81, 0x40, \ + 0xc0, 0xa0, \ + 0x60, 0x40, \ + 0x30, 0x20 + +#define BurstMask11_8 \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x40, \ + 0x80, 0xa0, \ + 0xc0, 0x40, \ + 0x60, 0x20 + +#define BurstMask11_9 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x80, 0x40, \ + 0xc0, 0x20 + +#define BurstMask11_10 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0, \ + 0x80, 0x20 + +#define BurstMask11_11 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0, \ + 0x00, 0x60 + +#define BurstMask12_1 \ + 0xff, 0xf0 + +#define BurstMask12_2 \ + 0xaa, 0xa0, \ + 0xd5, 0x50 + +#define BurstMask12_3 \ + 0x92, 0x40, \ + 0xc9, 0x20, \ + 0x74, 0x90 + +#define BurstMask12_4 \ + 0x8a, 0x80, \ + 0xc5, 0x40, \ + 0x62, 0x20, \ + 0x39, 0x10 + +#define BurstMask12_5 \ + 0x61, 0x00, \ + 0x30, 0xa0, \ + 0x1c, 0x50, \ + 0x85, 0x20, \ + 0xc2, 0x90 + +#define BurstMask12_6 \ + 0x82, 0x90, \ + 0xc1, 0x40, \ + 0x60, 0xa0, \ + 0x30, 0x50, \ + 0x18, 0x20, \ + 0x0c, 0x10 + +#define BurstMask12_7 \ + 0x0c, 0x00, \ + 0x07, 0x00, \ + 0x81, 0x40, \ + 0xc0, 0xa0, \ + 0x60, 0x50, \ + 0x30, 0x20, \ + 0x18, 0x10 + +#define BurstMask12_8 \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x80, 0xa0, \ + 0xc0, 0x50, \ + 0x60, 0x20, \ + 0x30, 0x10 + +#define BurstMask12_9 \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x80, 0x50, \ + 0xc0, 0x20, \ + 0x60, 0x10 + +#define BurstMask12_10 \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0, \ + 0x80, 0x20, \ + 0xc0, 0x10 + +#define BurstMask12_11 \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0, \ + 0x00, 0x60, \ + 0x80, 0x10 + +#define BurstMask12_12 \ + 0x80, 0x00, \ + 0xc0, 0x00, \ + 0x60, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0x0c, 0x00, \ + 0x06, 0x00, \ + 0x03, 0x00, \ + 0x01, 0x80, \ + 0x00, 0xc0, \ + 0x00, 0x60, \ + 0x00, 0x30 + +#define kPacketMaskBursty1 1, \ + BurstMask1_1 + +#define kPacketMaskBursty2 2, \ + BurstMask2_1, \ + BurstMask2_2 + +#define kPacketMaskBursty3 3, \ + BurstMask3_1, \ + BurstMask3_2, \ + BurstMask3_3 + +#define kPacketMaskBursty4 4, \ + BurstMask4_1, \ + BurstMask4_2, \ + BurstMask4_3, \ + BurstMask4_4 + +#define kPacketMaskBursty5 5, \ + BurstMask5_1, \ + BurstMask5_2, \ + BurstMask5_3, \ + BurstMask5_4, \ + BurstMask5_5 + +#define kPacketMaskBursty6 6, \ + BurstMask6_1, \ + BurstMask6_2, \ + BurstMask6_3, \ + BurstMask6_4, \ + BurstMask6_5, \ + BurstMask6_6 + +#define kPacketMaskBursty7 7, \ + BurstMask7_1, \ + BurstMask7_2, \ + BurstMask7_3, \ + BurstMask7_4, \ + BurstMask7_5, \ + BurstMask7_6, \ + BurstMask7_7 + +#define kPacketMaskBursty8 8, \ + BurstMask8_1, \ + BurstMask8_2, \ + BurstMask8_3, \ + BurstMask8_4, \ + BurstMask8_5, \ + BurstMask8_6, \ + BurstMask8_7, \ + BurstMask8_8 + +#define kPacketMaskBursty9 9, \ + BurstMask9_1, \ + BurstMask9_2, \ + BurstMask9_3, \ + BurstMask9_4, \ + BurstMask9_5, \ + BurstMask9_6, \ + BurstMask9_7, \ + BurstMask9_8, \ + BurstMask9_9 + +#define kPacketMaskBursty10 10, \ + BurstMask10_1, \ + BurstMask10_2, \ + BurstMask10_3, \ + BurstMask10_4, \ + BurstMask10_5, \ + BurstMask10_6, \ + BurstMask10_7, \ + BurstMask10_8, \ + BurstMask10_9, \ + BurstMask10_10 + +#define kPacketMaskBursty11 11, \ + BurstMask11_1, \ + BurstMask11_2, \ + BurstMask11_3, \ + BurstMask11_4, \ + BurstMask11_5, \ + BurstMask11_6, \ + BurstMask11_7, \ + BurstMask11_8, \ + BurstMask11_9, \ + BurstMask11_10, \ + BurstMask11_11 + +#define kPacketMaskBursty12 12, \ + BurstMask12_1, \ + BurstMask12_2, \ + BurstMask12_3, \ + BurstMask12_4, \ + BurstMask12_5, \ + BurstMask12_6, \ + BurstMask12_7, \ + BurstMask12_8, \ + BurstMask12_9, \ + BurstMask12_10, \ + BurstMask12_11, \ + BurstMask12_12 + +// choose first idx of packet mask according to k value (source number) +const uint8_t xqc_rnd_pm_tbl[] = { + 12, + RandomPacketMask1, // 2 byte entries. + RandomPacketMask2, + RandomPacketMask3, + RandomPacketMask4, + RandomPacketMask5, + RandomPacketMask6, + RandomPacketMask7, + RandomPacketMask8, + RandomPacketMask9, + RandomPacketMask10, + RandomPacketMask11, + RandomPacketMask12, +}; + +const uint8_t xqc_bst_pm_tbl[] = { + 12, + kPacketMaskBursty1, + kPacketMaskBursty2, + kPacketMaskBursty3, + kPacketMaskBursty4, + kPacketMaskBursty5, + kPacketMaskBursty6, + kPacketMaskBursty7, + kPacketMaskBursty8, + kPacketMaskBursty9, + kPacketMaskBursty10, + kPacketMaskBursty11, + kPacketMaskBursty12, +}; diff --git a/src/transport/fec_schemes/xqc_reed_solomon.c b/src/transport/fec_schemes/xqc_reed_solomon.c new file mode 100644 index 000000000..39136fa76 --- /dev/null +++ b/src/transport/fec_schemes/xqc_reed_solomon.c @@ -0,0 +1,277 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + + +#include "src/transport/fec_schemes/xqc_reed_solomon.h" +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_conn.h" + + +void +xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char total_symbol_num, + unsigned char (*GM)[XQC_RSM_COL]) +{ + int tmp_gm_col, invert_gm_col; + unsigned char tmp_GM[XQC_RSM_COL * 2][XQC_RSM_COL] = {{0}}, invert_GM[XQC_RSM_COL][XQC_RSM_COL] = {{0}}; + + tmp_gm_col = invert_gm_col = XQC_RSM_COL; + + xqc_build_vandermonde_matrix(total_symbol_num, src_symbol_num, tmp_GM); + /* invert GM rows corresponds to src symbols */ + xqc_submatrix(0, src_symbol_num, 0, src_symbol_num, invert_gm_col, tmp_gm_col, &invert_GM[0][0], &tmp_GM[0][0]); + + xqc_invert_matrix(src_symbol_num, src_symbol_num, invert_GM); + + xqc_matrix_time(total_symbol_num, src_symbol_num, tmp_GM, + src_symbol_num, src_symbol_num, invert_GM, + total_symbol_num, src_symbol_num, GM); +} + +void +xqc_reed_solomon_init_one(xqc_connection_t *conn, uint8_t bm_idx) +{ + return; +} + +void +xqc_reed_solomon_init(xqc_connection_t *conn) +{ + xqc_int_t i, j, ret, max_src_symbol_num, repair_symbol_num, symbol_idx; + unsigned char *key_p; + + max_src_symbol_num = xqc_get_fec_blk_size(conn, XQC_DEFAULT_SIZE_REQ); + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ]; + + if (max_src_symbol_num > XQC_REPAIR_LEN) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + conn->conn_settings.fec_params.fec_encoder_scheme = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec| reed-solomon code init error"); + return; + } + + xqc_build_generator_matrix(max_src_symbol_num, max_src_symbol_num + repair_symbol_num, conn->fec_ctl->decode_matrix); + + /* If it's the last symbol in block, save it's key; */ + for (i = 0 ; i < repair_symbol_num; i++) { + key_p = conn->fec_ctl->fec_send_repair_key[XQC_DEFAULT_SIZE_REQ][i].payload; + if (key_p == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_encode|malloc key failed"); + return; + } + xqc_memset(key_p, 0, max_src_symbol_num); + xqc_memcpy(key_p, conn->fec_ctl->decode_matrix[max_src_symbol_num + i], max_src_symbol_num); + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_key[XQC_DEFAULT_SIZE_REQ][i], 1, key_p, max_src_symbol_num); + } + +} + +xqc_int_t +xqc_rs_code_one_symbol(unsigned char (*GM_rows)[XQC_RSM_COL], unsigned char *input, unsigned char **outputs, + xqc_int_t outputs_rows_num, xqc_int_t item_size, xqc_int_t input_idx) +{ + xqc_int_t output_i, j; + unsigned char *output_p, *gm_p; + output_i = 0; + + if (input_idx > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + return -XQC_EFEC_SCHEME_ERROR; + } + + for (output_i = 0; output_i < outputs_rows_num; output_i++) { + /* symbol_length is the length of a repair key unit */ + if (outputs[output_i] == NULL) { + if (input_idx != 0) { + return -XQC_EFEC_SCHEME_ERROR; + } + return -XQC_EMALLOC; + } + + if (input_idx == 0) { + xqc_memset(outputs[output_i], 0, item_size); + } + output_p = outputs[output_i]; + gm_p = GM_rows[output_i]; + for (j = 0; j < item_size; j++) { + *(output_p + j) ^= xqc_galois_multiply(*(gm_p + input_idx), *(input + j)); + } + } + return XQC_OK; +} + +xqc_int_t +xqc_rs_code_symbols(unsigned char (*GM_rows)[XQC_RSM_COL], unsigned char **inputs, xqc_int_t inputs_rows_num, + unsigned char **outputs, xqc_int_t outputs_rows_num, xqc_int_t item_size) +{ + xqc_int_t input_i, output_i, ret; + unsigned char *input_p, *output_p, *gm_p; + input_i = output_i = 0; + + /** + * outputs[i][byte j] = GM_rows[i][0]*Inputs[0][bytej] + GM_rows[i][1]*Inputs[1][bytej] + ... + * The "+" is equal to XOR in galois fields + */ + for (input_i = 0; input_i < inputs_rows_num; input_i++) { + input_p = inputs[input_i]; + ret = xqc_rs_code_one_symbol(GM_rows, input_p, outputs, outputs_rows_num, item_size, input_i); + if (ret != XQC_OK) { + return ret; + } + } + + return XQC_OK; +} + +xqc_int_t +xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + size_t tmp_size; + xqc_int_t i, ret, max_src_symbol_num, repair_symbol_num, symbol_idx; + unsigned char *key_p, *output_p; + /* Record multiplication result in galois field. */ + + max_src_symbol_num = xqc_get_fec_blk_size(conn, XQC_DEFAULT_SIZE_REQ); + symbol_idx = conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]; + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + + ret = xqc_rs_code_one_symbol(conn->fec_ctl->decode_matrix + max_src_symbol_num, stream, outputs, + repair_symbol_num, st_size, symbol_idx); + for (i = 0; i < repair_symbol_num; i++) { + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(st_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + output_p = outputs[i]; + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i], 1, output_p, + tmp_size); + } + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_encode|xqc_rs_code_one_symbol failed"); + return -XQC_EFEC_SCHEME_ERROR; + } + + return XQC_OK; +} + +void +xqc_gen_invert_GM(xqc_connection_t *conn, int row, int col, unsigned char (*GM)[XQC_RSM_COL], xqc_int_t block_idx, xqc_int_t symbol_flag) +{ + xqc_int_t i, j, k, symbol_num, repair_symbol_num, src_symbol_num, symbol_idx, ret; + xqc_list_head_t *pos, *next; + xqc_fec_rpr_syb_t *rpr_symbol; + + src_symbol_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_idx); + repair_symbol_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_idx); + symbol_num = src_symbol_num + repair_symbol_num; + symbol_idx = 0; + rpr_symbol = NULL; + + xqc_memset(GM, 0, col * sizeof(*GM)); + + for (i = 0; i < row; i++) { + for (k = symbol_idx; k < col; k++) { + if (symbol_flag & (1 << k)) { + symbol_idx = k; + GM[i][symbol_idx] = 1; + symbol_idx++; + break; + } + } + } + + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_idx) { + break; + } + if (rpr_symbol->block_id == block_idx) { + xqc_memcpy(GM[i], rpr_symbol->repair_key, rpr_symbol->repair_key_size); + i++; + } + } + + xqc_invert_matrix(col, col, GM); +} + +xqc_int_t +xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx) +{ + /** + * 根据fec_recv_symbols_buff和fec_recv_repair_key复原丢失的srcsymbol: + * 1. 生成GM的逆矩阵 + * 2. 将recv symbols格式化 + * 3. 逆矩阵 * recv symbols + */ + xqc_int_t i, j, ret, recv_symbols_num, recv_source_symbols_num, symbol_flag, max_src_symbol_num, loss_src_num; + unsigned char GM[XQC_RSM_COL][XQC_RSM_COL] = {{0}}, *recv_symbols_buff[XQC_RSM_COL], *recovered_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK]; + xqc_int_t loss_symbol_idx[XQC_RSM_COL] = {-1}; + + *output_size = loss_src_num = 0; + recv_source_symbols_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_idx); + recv_symbols_num = recv_source_symbols_num + xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_idx); + symbol_flag = xqc_get_symbol_flag(conn, block_idx); + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + + for (i = 0; i < recv_symbols_num; i++) { + recv_symbols_buff[i] = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + recovered_symbols_buff[i] = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + } + + for (i = 0; i < max_src_symbol_num; i++) { + if ((symbol_flag & (1 << i)) == 0) { + loss_symbol_idx[loss_src_num] = i; + loss_src_num++; + } + } + + xqc_gen_invert_GM(conn, recv_source_symbols_num, recv_symbols_num, GM, block_idx, symbol_flag); + + // get symbols and make them into matrix according to block idx; + i = xqc_get_symbols_buff(recv_symbols_buff, conn->fec_ctl, block_idx, output_size); + if (i < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_get_symbols_buff|recv invalid symbols"); + return -XQC_EFEC_SCHEME_ERROR; + } + if (i != recv_symbols_num) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_reed_solomon_decode|recv symbols not enouph to recover lost symbols"); + return -XQC_EFEC_SCHEME_ERROR; + } + + ret = xqc_rs_code_symbols(GM, recv_symbols_buff, recv_symbols_num, + recovered_symbols_buff, recv_symbols_num, + *output_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_decode|reed solomon decode symbols failed"); + } + + for (i = 0; i < loss_src_num; i++) { + xqc_fec_ctl_save_symbol(&outputs[i], recovered_symbols_buff[loss_symbol_idx[i]], *output_size); + } + + for (i = 0; i < recv_symbols_num; i++) { + if (recv_symbols_buff[i] != NULL) { + xqc_free(recv_symbols_buff[i]); + } + if (recovered_symbols_buff[i] != NULL) { + xqc_free(recovered_symbols_buff[i]); + } + } + + return ret; +} + + +const xqc_fec_code_callback_t xqc_reed_solomon_code_cb = { + .xqc_fec_init = xqc_reed_solomon_init, + .xqc_fec_init_one = xqc_reed_solomon_init_one, + .xqc_fec_decode = xqc_reed_solomon_decode, + .xqc_fec_encode = xqc_reed_solomon_encode, + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_reed_solomon.h b/src/transport/fec_schemes/xqc_reed_solomon.h new file mode 100644 index 000000000..1c3620b17 --- /dev/null +++ b/src/transport/fec_schemes/xqc_reed_solomon.h @@ -0,0 +1,33 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_REED_SOLOMON_H_ +#define _XQC_FEC_REED_SOLOMON_H_ + + +#include +#include +#include +#include "src/transport/xqc_defs.h" + +extern const xqc_fec_code_callback_t xqc_reed_solomon_code_cb; + +xqc_int_t xqc_rs_code_one_symbol(unsigned char (*GM_rows)[XQC_RSM_COL], unsigned char *input, unsigned char **outputs, + xqc_int_t outputs_rows_num, xqc_int_t item_size, xqc_int_t input_idx); + +void xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char total_symbol_num, + unsigned char (*GM)[XQC_RSM_COL]); + +xqc_int_t xqc_rs_code_symbols(unsigned char (*GM_rows)[XQC_RSM_COL], unsigned char **inputs, xqc_int_t inputs_rows_num, + unsigned char **outputs, xqc_int_t outputs_rows_num, xqc_int_t item_size); + +void xqc_reed_solomon_init(xqc_connection_t *conn); +void xqc_reed_solomon_init_one(xqc_connection_t *conn, uint8_t bm_idx); +xqc_int_t xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx); +xqc_int_t xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); + +#endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_xor.c b/src/transport/fec_schemes/xqc_xor.c new file mode 100644 index 000000000..d51bc0958 --- /dev/null +++ b/src/transport/fec_schemes/xqc_xor.c @@ -0,0 +1,209 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + + +#include "src/transport/fec_schemes/xqc_xor.h" +#include "src/transport/xqc_conn.h" + +void +xqc_xor_init(xqc_connection_t *conn) +{ + if (conn->fec_ctl == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fail to malloc space for fec_ctl"); + return; + } + conn->fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = 1; + return; +} + +void +xqc_xor_init_one(xqc_connection_t *conn, uint8_t bm_idx) +{ + return; +} + +#ifdef XQC_ON_x86 +void +xqc_xor_string_simd_x86(unsigned char *input, unsigned char *outputs, + xqc_int_t item_size) +{ + size_t i = 0; + size_t aligned_len = item_size & ~(size_t)15; + + for (i = 0; i < aligned_len; i += 16) { + __m128i output_unit = _mm_loadu_si128((__m128i *)(outputs + i)); + __m128i input_unit = _mm_loadu_si128((__m128i *)(input + i)); + __m128i result = _mm_xor_si128(output_unit, input_unit); + _mm_storeu_si128((__m128i *)(outputs + i), result); + } + + for (; i < item_size; ++i) { + outputs[i] ^= input[i]; + } +} +#endif + +#ifdef XQC_ON_ARM +void +xqc_xor_string_simd_arm(unsigned char *input, unsigned char *outputs, + xqc_int_t item_size) +{ + size_t i = 0; + size_t aligned_len = item_size & ~(size_t)15; + + for (i = 0; i < aligned_len; i += 16) { + uint8x16_t out_data = vld1q_u8(outputs + i); + uint8x16_t in_data = vld1q_u8(input + i); + uint8x16_t result = veorq_u8(out_data, in_data); + vst1q_u8(outputs + i, result); + } + + for (; i < item_size; ++i) { + outputs[i] ^= input[i]; + } +} +#endif + +void +xqc_xor_string(unsigned char *input, unsigned char *outputs, + xqc_int_t item_size) +{ + size_t i = 0; + unsigned char *output_p; + + output_p = outputs; + for (i = 0; i < item_size; i++) { + *(output_p + i) ^= *(input + i); + } +} + + +xqc_int_t +xqc_xor_code_one_symbol(unsigned char *input, unsigned char *outputs, + xqc_int_t item_size) +{ + if (outputs == NULL) { + return -XQC_EMALLOC; + } + +#if defined(XQC_ON_x86) + xqc_xor_string_simd_x86(input, outputs, item_size); +#else + xqc_xor_string(input, outputs, item_size); +#endif + + return XQC_OK; +} + +xqc_int_t +xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx) +{ + xqc_int_t i, j, ret, recv_repair_symbols_num, output_len, block_mod; + xqc_usec_t now, diff_time; + xqc_stream_t *stream; + xqc_list_head_t *pos, *next, *fec_recv_src_syb_list, *fec_recv_rpr_syb_list; + xqc_fec_rpr_syb_t *symbol = NULL; + + *output_size = 0; + ret = -XQC_EFEC_SYMBOL_ERROR; + fec_recv_src_syb_list = &conn->fec_ctl->fec_recv_src_syb_list; + fec_recv_rpr_syb_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + block_mod = conn->conn_settings.fec_params.fec_blk_log_mod; + + xqc_list_for_each_safe(pos, next, fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_syb = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_syb->block_id < block_idx) { + continue; + } + if (rpr_syb->block_id == block_idx) { + if (rpr_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xor decoder can't process rpr symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(rpr_syb->payload, outputs[0], rpr_syb->payload_size); + if (ret != XQC_OK) { + return ret; + } + *output_size = rpr_syb->payload_size; + symbol = rpr_syb; + break; + } + if (rpr_syb->block_id > block_idx) { + return -XQC_EFEC_SCHEME_ERROR; + } + } + xqc_list_for_each_safe(pos, next, fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_syb = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_syb->block_id < block_idx) { + continue; + } + if (src_syb->block_id == block_idx) { + if (src_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xor decoder can't process src symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(src_syb->payload, outputs[0], src_syb->payload_size); + if (ret != XQC_OK) { + return ret; + } + } + if (src_syb->block_id > block_idx) { + break; + } + } + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_decode|xor decode symbols failed"); + return ret; + } + + // log the time it cost between recovered and rpr symbol received, control log rate + if (conn->conn_settings.fec_params.fec_log_on && symbol && symbol->block_id % block_mod == 0) { + now = xqc_monotonic_timestamp(); + diff_time = xqc_calc_delay(now, symbol->recv_time); + xqc_log(conn->log, XQC_LOG_REPORT, "|fec_stats|XOR|current block: %d|recovered %ui ms after rpr received", symbol->block_id, diff_time / 1000); + } + + return XQC_OK; +} + +xqc_int_t +xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + size_t tmp_size; + xqc_int_t ret; + + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_encode|invalid input size:%d|", st_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + + ret = xqc_xor_code_one_symbol(stream, outputs[0], st_size); + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(st_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][0].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][0], 1, outputs[0], + tmp_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_encode|code one symbol failed"); + return -XQC_EFEC_SCHEME_ERROR; + } + + return XQC_OK; +} + +const xqc_fec_code_callback_t xqc_xor_code_cb = { + .xqc_fec_init = xqc_xor_init, + .xqc_fec_init_one = xqc_xor_init_one, + .xqc_fec_decode = xqc_xor_decode, + .xqc_fec_encode = xqc_xor_encode, + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_xor.h b/src/transport/fec_schemes/xqc_xor.h new file mode 100644 index 000000000..083a4430e --- /dev/null +++ b/src/transport/fec_schemes/xqc_xor.h @@ -0,0 +1,26 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_XOR_H_ +#define _XQC_FEC_XOR_H_ + + +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include +#include +#include + +extern const xqc_fec_code_callback_t xqc_xor_code_cb; + +xqc_int_t xqc_xor_code_one_symbol(unsigned char *input, unsigned char *outputs, xqc_int_t item_size); + +void xqc_xor_init(xqc_connection_t *conn); +void xqc_xor_init_one(xqc_connection_t *conn, uint8_t bm_idx); +xqc_int_t xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx); +xqc_int_t xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); + +#endif \ No newline at end of file diff --git a/src/transport/reinjection_control/xqc_reinj_deadline.c b/src/transport/reinjection_control/xqc_reinj_deadline.c index 60d29a716..7703cd157 100644 --- a/src/transport/reinjection_control/xqc_reinj_deadline.c +++ b/src/transport/reinjection_control/xqc_reinj_deadline.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" @@ -42,10 +41,37 @@ xqc_deadline_reinj_ctl_init(void *reinj_ctl, xqc_connection_t *conn) rctl->conn = conn; } +static inline xqc_bool_t +xqc_deadline_reinj_check_packet(xqc_packet_out_t *po) +{ + if (((po->po_frame_types & XQC_FRAME_BIT_STREAM) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAM_DATA) + || (po->po_frame_types & XQC_FRAME_BIT_RESET_STREAM) + || (po->po_frame_types & XQC_FRAME_BIT_STOP_SENDING) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAMS) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_DATA) + || (po->po_frame_types & XQC_FRAME_BIT_DATA_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_STREAM_DATA_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_STREAMS_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_CONNECTION_CLOSE)) + && !(po->po_flag & XQC_POF_NOT_REINJECT) + && !(XQC_MP_PKT_REINJECTED(po)) + && (po->po_flag & XQC_POF_IN_FLIGHT)) + { + return XQC_TRUE; + } + + return XQC_FALSE; +} + static xqc_bool_t xqc_deadline_reinj_can_reinject_before_sched(xqc_deadline_reinj_ctl_t *rctl, xqc_packet_out_t *po) { + if (!xqc_deadline_reinj_check_packet(po)) { + return XQC_FALSE; + } + xqc_connection_t *conn = rctl->conn; xqc_usec_t now = xqc_monotonic_timestamp(); xqc_usec_t min_srtt = xqc_conn_get_min_srtt(conn, 0); @@ -56,22 +82,47 @@ xqc_deadline_reinj_can_reinject_before_sched(xqc_deadline_reinj_ctl_t *rctl, uint64_t lower_bound = conn->conn_settings.reinj_deadline_lower_bound; double deadline = xqc_max(xqc_min(flexible, (double)hard), (double)lower_bound); - xqc_log(conn->log, XQC_LOG_DEBUG, "|deadline:%f|factor:%.4f|min_srtt:%ui|flexible:%f|hard:%ui|lower_bound:%ui|now:%ui|sent_time:%ui|frame:%s|", - deadline, factor, min_srtt, flexible, hard, lower_bound, now, po->po_sent_time, xqc_frame_type_2_str(po->po_frame_types)); + xqc_log(conn->log, XQC_LOG_DEBUG, + "|deadline:%f|factor:%.4f|min_srtt:%ui|flexible:%f|hard:%ui|" + "lower_bound:%ui|now:%ui|sent_time:%ui|frame:%s|", + deadline, factor, min_srtt, flexible, hard, + lower_bound, now, po->po_sent_time, + xqc_frame_type_2_str(conn->engine, po->po_frame_types)); - if (((po->po_frame_types & XQC_FRAME_BIT_STREAM) - || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAM_DATA)) - && !(po->po_flag & XQC_POF_NOT_REINJECT) - && !(XQC_MP_PKT_REINJECTED(po)) - && (po->po_flag & XQC_POF_IN_FLIGHT) - && ((double)(now - po->po_sent_time) >= deadline)) - { + if ((double)(now - po->po_sent_time) >= deadline) { return XQC_TRUE; } return XQC_FALSE; } + +static xqc_bool_t +xqc_deadline_reinj_can_reinject_after_send(xqc_deadline_reinj_ctl_t *rctl, + xqc_packet_out_t *po) +{ + if (!xqc_deadline_reinj_check_packet(po)) { + return XQC_FALSE; + } + + xqc_connection_t *conn = rctl->conn; + xqc_path_ctx_t *path = NULL; + xqc_path_perf_class_t path_class; + + path = xqc_conn_find_path_by_path_id(conn, po->po_path_id); + + if (path) { + path_class = xqc_path_get_perf_class(path); + if (path_class == XQC_PATH_CLASS_STANDBY_LOW + || path_class == XQC_PATH_CLASS_AVAILABLE_LOW) + { + return XQC_TRUE; + } + } + + return XQC_FALSE; +} + static xqc_bool_t xqc_deadline_reinj_can_reinject(void *ctl, xqc_packet_out_t *po, xqc_reinjection_mode_t mode) @@ -83,6 +134,9 @@ xqc_deadline_reinj_can_reinject(void *ctl, case XQC_REINJ_UNACK_BEFORE_SCHED: can_reinject = xqc_deadline_reinj_can_reinject_before_sched(rctl, po); break; + case XQC_REINJ_UNACK_AFTER_SEND: + can_reinject = xqc_deadline_reinj_can_reinject_after_send(rctl, po); + break; default: can_reinject = XQC_FALSE; break; diff --git a/src/transport/reinjection_control/xqc_reinj_default.c b/src/transport/reinjection_control/xqc_reinj_default.c index 265ada8b1..15e213929 100644 --- a/src/transport/reinjection_control/xqc_reinj_default.c +++ b/src/transport/reinjection_control/xqc_reinj_default.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" @@ -50,7 +49,15 @@ xqc_default_reinj_can_reinject_after_sched(xqc_default_reinj_ctl_t *rctl, if (xqc_list_empty(&conn->conn_send_queue->sndq_send_packets) && ((po->po_frame_types & XQC_FRAME_BIT_STREAM) - || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAM_DATA)) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAM_DATA) + || (po->po_frame_types & XQC_FRAME_BIT_RESET_STREAM) + || (po->po_frame_types & XQC_FRAME_BIT_STOP_SENDING) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_STREAMS) + || (po->po_frame_types & XQC_FRAME_BIT_MAX_DATA) + || (po->po_frame_types & XQC_FRAME_BIT_DATA_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_STREAM_DATA_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_STREAMS_BLOCKED) + || (po->po_frame_types & XQC_FRAME_BIT_CONNECTION_CLOSE)) && !(po->po_flag & XQC_POF_NOT_REINJECT) && !(XQC_MP_PKT_REINJECTED(po)) && (po->po_flag & XQC_POF_IN_FLIGHT)) diff --git a/src/transport/reinjection_control/xqc_reinj_dgram.c b/src/transport/reinjection_control/xqc_reinj_dgram.c index dba910e9b..d8741f493 100644 --- a/src/transport/reinjection_control/xqc_reinj_dgram.c +++ b/src/transport/reinjection_control/xqc_reinj_dgram.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" @@ -48,7 +47,7 @@ xqc_dgram_reinj_can_reinject_after_send(xqc_dgram_reinj_ctl_t *rctl, { xqc_connection_t *conn = rctl->conn; - if ((po->po_frame_types & XQC_FRAME_BIT_DATAGRAM) + if ((po->po_frame_types & (XQC_FRAME_BIT_DATAGRAM | XQC_FRAME_BIT_CONNECTION_CLOSE)) && !(po->po_flag & XQC_POF_NOT_REINJECT) && !(XQC_MP_PKT_REINJECTED(po)) && (po->po_flag & XQC_POF_IN_FLIGHT)) diff --git a/src/transport/scheduler/xqc_scheduler_backup.c b/src/transport/scheduler/xqc_scheduler_backup.c index a6950779e..604644c6b 100644 --- a/src/transport/scheduler/xqc_scheduler_backup.c +++ b/src/transport/scheduler/xqc_scheduler_backup.c @@ -22,47 +22,48 @@ xqc_backup_scheduler_init(void *scheduler, xqc_log_t *log, xqc_scheduler_params_ xqc_path_ctx_t * -xqc_backup_scheduler_get_path(void *scheduler, - xqc_connection_t *conn, xqc_packet_out_t *packet_out, int check_cwnd, int reinject, +xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, int check_cwnd, int reinject, xqc_bool_t *cc_blocked) { - xqc_path_ctx_t *best_path = NULL; - xqc_path_ctx_t *best_standby_path = NULL; + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_bool_t has_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_path_perf_class_t path_class; + xqc_bool_t available_path_exists; xqc_list_head_t *pos, *next; xqc_path_ctx_t *path; xqc_send_ctl_t *send_ctl; + xqc_bool_t path_can_send = XQC_FALSE; /* min RTT */ - uint64_t min_rtt = XQC_MAX_UINT64_VALUE; - uint64_t min_rtt_standby = XQC_MAX_UINT64_VALUE; - uint64_t path_srtt; - uint32_t avail_path_cnt = 0; + uint64_t path_srtt = 0; xqc_bool_t reached_cwnd_check = XQC_FALSE; if (cc_blocked) { *cc_blocked = XQC_FALSE; } + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + has_path[path_class] = XQC_FALSE; + } + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - /* skip inactive paths */ - if (path->path_state != XQC_PATH_STATE_ACTIVE) { - continue; - } + path_class = xqc_path_get_perf_class(path); + /* skip inactive paths */ /* skip frozen paths */ - if (path->app_path_status == XQC_APP_PATH_STATUS_FROZEN) { - continue; - } - - if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - avail_path_cnt++; - } - - if (reinject && (packet_out->po_path_id == path->path_id)) { - continue; + if (path->path_state != XQC_PATH_STATE_ACTIVE + || path->app_path_status == XQC_APP_PATH_STATUS_FROZEN + || (reinject && (packet_out->po_path_id == path->path_id))) + { + goto skip_path; } if (!reached_cwnd_check) { @@ -72,8 +73,11 @@ xqc_backup_scheduler_get_path(void *scheduler, } } - if (!xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd)) { - continue; + has_path[path_class] = XQC_TRUE; + path_can_send = xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd); + + if (!path_can_send) { + goto skip_path; } if (cc_blocked) { @@ -81,41 +85,62 @@ xqc_backup_scheduler_get_path(void *scheduler, } path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); - xqc_log(conn->log, XQC_LOG_DEBUG, "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|", - conn, path->path_id, path_srtt); - - if (path_srtt < min_rtt) { - if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - best_path = path; - min_rtt = path_srtt; - - } else { - best_standby_path = path; - min_rtt_standby = path_srtt; - } + + if (best_path[path_class] == NULL + || path_srtt < best_path[path_class]->path_send_ctl->ctl_srtt) + { + best_path[path_class] = path; } - } +skip_path: + xqc_log(conn->log, XQC_LOG_DEBUG, + "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|path_class:%d|" + "can_send:%d|path_status:%d|path_state:%d|reinj:%d|" + "pkt_path_id:%ui|best_path:%i|", + conn, path->path_id, path_srtt, path_class, path_can_send, + path->app_path_status, path->path_state, reinject, + packet_out->po_path_id, + best_path[path_class] ? best_path[path_class]->path_id : -1); + } - if (best_path == NULL) { - if (best_standby_path != NULL - && (avail_path_cnt == 0 || reinject)) - { - best_path = best_standby_path; + available_path_exists = XQC_FALSE; - } else { - xqc_log(conn->log, XQC_LOG_DEBUG, "|No available paths to schedule|conn:%p|", conn); + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (has_path[path_class] && ((path_class & 1) == 0)) { + available_path_exists = XQC_TRUE; } - } + /* + * do not use a standby path if there + * is an available path with higher performence level + */ + if (best_path[path_class] != NULL) { + + if (available_path_exists && (path_class & 1) && !reinject) { + /* skip standby path*/ + xqc_log(conn->log, XQC_LOG_DEBUG, + "|skip_standby_path|path_class:%d|path_id:%ui|", + path_class, best_path[path_class]->path_id); + continue; - if (best_path) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|app_status:%d|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types), - best_path->app_path_status); + } else { + xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" + "pn:%ui|size:%ud|reinj:%d|path_class:%d|", + best_path[path_class]->path_id, + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), + packet_out->po_pkt.pkt_num, + packet_out->po_used_size, reinject, path_class); + return best_path[path_class]; + } + } } - return best_path; + xqc_log(conn->log, XQC_LOG_DEBUG, + "|No available paths to schedule|conn:%p|", conn); + return NULL; } void diff --git a/src/transport/scheduler/xqc_scheduler_backup_fec.c b/src/transport/scheduler/xqc_scheduler_backup_fec.c new file mode 100644 index 000000000..4c871a29a --- /dev/null +++ b/src/transport/scheduler/xqc_scheduler_backup_fec.c @@ -0,0 +1,243 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/scheduler/xqc_scheduler_backup_fec.h" +#include "src/transport/scheduler/xqc_scheduler_common.h" +#include "src/transport/xqc_send_ctl.h" + + +static size_t +xqc_backup_fec_scheduler_size() +{ + return 0; +} + +static void +xqc_backup_fec_scheduler_init(void *scheduler, xqc_log_t *log, xqc_scheduler_params_t *param) +{ + return; +} + +xqc_path_ctx_t * +xqc_send_on_standby_path(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *has_path, + xqc_path_ctx_t **best_path) +{ + xqc_bool_t available_path_exists; + xqc_path_ctx_t *ret_path; + xqc_path_perf_class_t path_class; + + ret_path = NULL; + + available_path_exists = XQC_FALSE; + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (has_path[path_class] && (path_class & 1)) { + available_path_exists = XQC_TRUE; + } + if (best_path[path_class] != NULL) { + if (ret_path == NULL && (path_class & 1) == 0) { + ret_path = best_path[path_class]; + continue; + } else { + return best_path[path_class]; + } + } + } + return ret_path; +} + +xqc_path_ctx_t * +xqc_send_on_normal_path(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *has_path, + xqc_path_ctx_t **best_path, int reinject) +{ + xqc_path_perf_class_t path_class; + xqc_bool_t available_path_exists; + + available_path_exists = XQC_FALSE; + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (has_path[path_class] && ((path_class & 1) == 0)) { + available_path_exists = XQC_TRUE; + } + + /* + * do not use a standby path if there + * is an available path with higher performence level + */ + if (best_path[path_class] != NULL) { + if (available_path_exists && (path_class & 1) && !reinject) { + /* skip standby path*/ + xqc_log(conn->log, XQC_LOG_DEBUG, + "|skip_standby_path|path_class:%d|path_id:%ui|", + path_class, best_path[path_class]->path_id); + continue; + + } else { + return best_path[path_class]; + } + } + } + return NULL; +} + +xqc_path_ctx_t * +xqc_backup_fec_scheduler_get_path(void *scheduler, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, int check_cwnd, int reinject, + xqc_bool_t *cc_blocked) +{ + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_bool_t has_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_path_perf_class_t path_class; + xqc_bool_t available_path_exists; + + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path, *ret_path; + xqc_send_ctl_t *send_ctl; + xqc_bool_t path_can_send = XQC_FALSE; + + /* min RTT */ + uint64_t path_srtt = 0; + xqc_bool_t reached_cwnd_check = XQC_FALSE; + + if (cc_blocked) { + *cc_blocked = XQC_FALSE; + } + + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + has_path[path_class] = XQC_FALSE; + } + + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + + path_class = xqc_path_get_perf_class(path); + + /* skip inactive paths */ + /* skip frozen paths */ + if (path->path_state != XQC_PATH_STATE_ACTIVE + || path->app_path_status == XQC_APP_PATH_STATUS_FROZEN + || (reinject && (packet_out->po_path_id == path->path_id))) + { + goto skip_path; + } + + if (!reached_cwnd_check) { + reached_cwnd_check = XQC_TRUE; + if (cc_blocked) { + *cc_blocked = XQC_TRUE; + } + } + + has_path[path_class] = XQC_TRUE; + path_can_send = xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd); + + if (!path_can_send) { + goto skip_path; + } + + if (cc_blocked) { + *cc_blocked = XQC_FALSE; + } + + path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); + + if (best_path[path_class] == NULL + || path_srtt < best_path[path_class]->path_send_ctl->ctl_srtt) + { + best_path[path_class] = path; + } + +skip_path: + xqc_log(conn->log, XQC_LOG_DEBUG, + "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|path_class:%d|" + "can_send:%d|path_status:%d|path_state:%d|reinj:%d|" + "pkt_path_id:%ui|best_path:%i|", + conn, path->path_id, path_srtt, path_class, path_can_send, + path->app_path_status, path->path_state, reinject, + packet_out->po_path_id, + best_path[path_class] ? best_path[path_class]->path_id : -1); + } + + available_path_exists = XQC_FALSE; +#ifdef XQC_ENABLE_FEC + if (conn->fec_ctl && conn->fec_ctl->fec_mp_mode == XQC_FEC_MP_USE_STB && packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL) { + ret_path = xqc_send_on_standby_path(conn, packet_out, has_path, best_path); + + } else { + ret_path = xqc_send_on_normal_path(conn, packet_out, has_path, best_path, reinject); + } + +#else + ret_path = xqc_send_on_normal_path(conn, packet_out, has_path, best_path, reinject); +#endif + + if (ret_path != NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" + "pn:%ui|size:%ud|reinj:%d|path_class:%d|", + ret_path->path_id, + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), + packet_out->po_pkt.pkt_num, + packet_out->po_used_size, reinject, path_class); + return ret_path; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|No available paths to schedule|conn:%p|", conn); + return NULL; +} + +void +xqc_backup_fec_scheduler_handle_conn_event(void *scheduler, + xqc_connection_t *conn, xqc_scheduler_conn_event_t event, void *event_arg) +{ + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path; + xqc_send_ctl_t *send_ctl; + xqc_usec_t now = 0, deadline; + + if (event == XQC_SCHED_EVENT_CONN_ROUND_START + && conn->conn_settings.standby_path_probe_timeout + && conn->enable_multipath + && (conn->conn_state == XQC_CONN_STATE_ESTABED)) + { + /* check if we need to probe standby paths */ + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + if (path->path_state == XQC_PATH_STATE_ACTIVE + && path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) + { + if (!now) { + now = xqc_monotonic_timestamp(); + } + + send_ctl = path->path_send_ctl; + + deadline = send_ctl->ctl_time_of_last_sent_ack_eliciting_packet[XQC_PNS_APP_DATA] + conn->conn_settings.standby_path_probe_timeout * 1000; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|standby_probe|path:%ui|deadline:%ui|now:%ui|now>=deadline:%d|last_send:%ui|", + path->path_id, deadline, now, now >= deadline, send_ctl->ctl_time_of_last_sent_ack_eliciting_packet[XQC_PNS_APP_DATA]); + + if (now >= deadline) { + xqc_path_standby_probe(path); + } + } + } + } +} + +const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb = { + .xqc_scheduler_size = xqc_backup_fec_scheduler_size, + .xqc_scheduler_init = xqc_backup_fec_scheduler_init, + .xqc_scheduler_get_path = xqc_backup_fec_scheduler_get_path, + .xqc_scheduler_handle_conn_event = xqc_backup_fec_scheduler_handle_conn_event, +}; \ No newline at end of file diff --git a/src/transport/scheduler/xqc_scheduler_backup_fec.h b/src/transport/scheduler/xqc_scheduler_backup_fec.h new file mode 100644 index 000000000..e32dc77b6 --- /dev/null +++ b/src/transport/scheduler/xqc_scheduler_backup_fec.h @@ -0,0 +1,13 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ +#define _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ + +#include +#include + +extern const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb; + +#endif /* _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ */ diff --git a/src/transport/scheduler/xqc_scheduler_common.c b/src/transport/scheduler/xqc_scheduler_common.c index eb12b1f44..d7124d392 100644 --- a/src/transport/scheduler/xqc_scheduler_common.c +++ b/src/transport/scheduler/xqc_scheduler_common.c @@ -10,7 +10,7 @@ xqc_scheduler_check_path_can_send(xqc_path_ctx_t *path, xqc_packet_out_t *packet uint32_t schedule_bytes = path->path_schedule_bytes; /* normal packets in send list will be blocked by cc */ - if (check_cwnd && (!xqc_send_packet_cwnd_allows(send_ctl, packet_out, schedule_bytes))) + if (check_cwnd && (!xqc_send_packet_cwnd_allows(send_ctl, packet_out, schedule_bytes, 0))) { xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|path:%ui|blocked by cwnd|", path->path_id); return XQC_FALSE; diff --git a/src/transport/scheduler/xqc_scheduler_interop.c b/src/transport/scheduler/xqc_scheduler_interop.c index 1d207a79b..49e46caa6 100644 --- a/src/transport/scheduler/xqc_scheduler_interop.c +++ b/src/transport/scheduler/xqc_scheduler_interop.c @@ -101,7 +101,7 @@ xqc_interop_scheduler_get_path(void *scheduler, if (best_path) { xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|app_status:%d|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types), + best_path->path_id, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), best_path->app_path_status); } diff --git a/src/transport/scheduler/xqc_scheduler_minrtt.c b/src/transport/scheduler/xqc_scheduler_minrtt.c index ea2783734..faa5c00f4 100644 --- a/src/transport/scheduler/xqc_scheduler_minrtt.c +++ b/src/transport/scheduler/xqc_scheduler_minrtt.c @@ -25,16 +25,24 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_connection_t *conn, xqc_packet_out_t *packet_out, int check_cwnd, int reinject, xqc_bool_t *cc_blocked) { - xqc_path_ctx_t *best_path = NULL; + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_path_perf_class_t path_class; xqc_list_head_t *pos, *next; xqc_path_ctx_t *path; xqc_send_ctl_t *send_ctl; /* min RTT */ - uint64_t min_rtt = XQC_MAX_UINT64_VALUE; - uint64_t path_srtt; + uint64_t path_srtt = 0; xqc_bool_t reached_cwnd_check = XQC_FALSE; + xqc_bool_t path_can_send = XQC_FALSE; + + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + } if (cc_blocked) { *cc_blocked = XQC_FALSE; @@ -43,17 +51,15 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - if (path->path_state != XQC_PATH_STATE_ACTIVE) { - continue; - } - - /* skip the frozen path */ - if (path->app_path_status == XQC_APP_PATH_STATUS_FROZEN) { - continue; - } - - if (reinject && (packet_out->po_path_id == path->path_id)) { - continue; + path_class = xqc_path_get_perf_class(path); + + /* skip inactive paths */ + /* skip frozen paths */ + if (path->path_state != XQC_PATH_STATE_ACTIVE + || path->app_path_status == XQC_APP_PATH_STATUS_FROZEN + || (reinject && (packet_out->po_path_id == path->path_id))) + { + goto skip_path; } if (!reached_cwnd_check) { @@ -64,12 +70,14 @@ xqc_minrtt_scheduler_get_path(void *scheduler, } /* @TODO: It is not correct for BBR/BBRv2, as they do not used cwnd to decide - * how much data can be sent in one RTT. But, currently, BBR does not - * work well for MPQUIC due to the problem of applimit. We may adapt this - * to BBR in the future, if we manage to fix the applimit problem of BBR. - */ - if (!xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd)) { - continue; + * how much data can be sent in one RTT. But, currently, BBR does not + * work well for MPQUIC due to the problem of applimit. We may adapt this + * to BBR in the future, if we manage to fix the applimit problem of BBR. + */ + path_can_send = xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd); + + if (!path_can_send) { + goto skip_path; } if (cc_blocked) { @@ -77,24 +85,42 @@ xqc_minrtt_scheduler_get_path(void *scheduler, } path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); - xqc_log(conn->log, XQC_LOG_DEBUG, "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|", - conn, path->path_id, path_srtt); - - if (path_srtt < min_rtt) { - best_path = path; - min_rtt = path_srtt; + + if (best_path[path_class] == NULL + || path_srtt < best_path[path_class]->path_send_ctl->ctl_srtt) + { + best_path[path_class] = path; } + +skip_path: + xqc_log(conn->log, XQC_LOG_DEBUG, + "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|path_class:%d|" + "can_send:%d|path_status:%d|path_state:%d|reinj:%d|" + "pkt_path_id:%ui|best_path:%i|", + conn, path->path_id, path_srtt, path_class, path_can_send, + path->app_path_status, path->path_state, reinject, + packet_out->po_path_id, + best_path[path_class] ? best_path[path_class]->path_id : -1); } - if (best_path == NULL) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|No available paths to schedule|conn:%p|", conn); - } else { - xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types)); + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (best_path[path_class] != NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" + "pn:%ui|size:%ud|reinj:%d|path_class:%d|", + best_path[path_class]->path_id, + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), + packet_out->po_pkt.pkt_num, + packet_out->po_used_size, reinject, path_class); + return best_path[path_class]; + } } - return best_path; + xqc_log(conn->log, XQC_LOG_DEBUG, "|No available paths to schedule|conn:%p|", conn); + return NULL; } const xqc_scheduler_callback_t xqc_minrtt_scheduler_cb = { diff --git a/src/transport/scheduler/xqc_scheduler_rap.c b/src/transport/scheduler/xqc_scheduler_rap.c index 96a13373d..9aea931b0 100644 --- a/src/transport/scheduler/xqc_scheduler_rap.c +++ b/src/transport/scheduler/xqc_scheduler_rap.c @@ -99,7 +99,7 @@ xqc_rap_scheduler_get_path(void *scheduler, } else { xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types)); + best_path->path_id, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); } return best_path; diff --git a/src/transport/xqc_cid.c b/src/transport/xqc_cid.c index 68a9d3ff0..d9eea4b4c 100644 --- a/src/transport/xqc_cid.c +++ b/src/transport/xqc_cid.c @@ -35,6 +35,8 @@ xqc_generate_cid(xqc_engine_t *engine, xqc_cid_t *ori_cid, xqc_cid_t *cid, return -XQC_EGENERATE_CID; } + cid->path_id = XQC_INITIAL_PATH_ID; /* default initial path_id = 0 */ + return XQC_OK; } @@ -64,6 +66,7 @@ xqc_cid_copy(xqc_cid_t *dst, xqc_cid_t *src) xqc_memcpy(dst->cid_buf, src->cid_buf, dst->cid_len); dst->cid_seq_num = src->cid_seq_num; xqc_memcpy(dst->sr_token, src->sr_token, XQC_STATELESS_RESET_TOKENLEN); + dst->path_id = src->path_id; } void @@ -71,6 +74,7 @@ xqc_cid_init_zero(xqc_cid_t *cid) { cid->cid_len = 0; cid->cid_seq_num = 0; + cid->path_id = 0; } void @@ -82,32 +86,30 @@ xqc_cid_set(xqc_cid_t *cid, const unsigned char *data, uint8_t len) } } -static unsigned char g_scid_buf[XQC_MAX_CID_LEN * 2 + 1]; -static unsigned char g_dcid_buf[XQC_MAX_CID_LEN * 2 + 1]; static unsigned char g_sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2 + 1]; unsigned char * -xqc_dcid_str(const xqc_cid_t *dcid) +xqc_dcid_str(xqc_engine_t *engine, const xqc_cid_t *dcid) { - xqc_hex_dump(g_dcid_buf, dcid->cid_buf, dcid->cid_len); - g_dcid_buf[dcid->cid_len * 2] = '\0'; - return g_dcid_buf; + xqc_hex_dump(engine->dcid_buf, dcid->cid_buf, dcid->cid_len); + engine->dcid_buf[dcid->cid_len * 2] = '\0'; + return engine->dcid_buf; } unsigned char * -xqc_scid_str(const xqc_cid_t *scid) +xqc_scid_str(xqc_engine_t *engine, const xqc_cid_t *scid) { - xqc_hex_dump(g_scid_buf, scid->cid_buf, scid->cid_len); - g_scid_buf[scid->cid_len * 2] = '\0'; - return g_scid_buf; + xqc_hex_dump(engine->scid_buf, scid->cid_buf, scid->cid_len); + engine->scid_buf[scid->cid_len * 2] = '\0'; + return engine->scid_buf; } unsigned char * -xqc_sr_token_str(const char *sr_token) +xqc_sr_token_str(xqc_engine_t *engine, const char *sr_token) { - xqc_hex_dump(g_sr_token_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); - g_sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2] = '\0'; - return g_sr_token_buf; + xqc_hex_dump(engine->sr_token_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); + engine->sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2] = '\0'; + return engine->sr_token_buf; } unsigned char * @@ -130,93 +132,205 @@ xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid) void xqc_init_cid_set(xqc_cid_set_t *cid_set) { - xqc_init_list_head(&cid_set->list_head); - cid_set->unused_cnt = 0; - cid_set->used_cnt = 0; - cid_set->retired_cnt = 0; + xqc_memzero(cid_set, sizeof(xqc_cid_set_t)); + xqc_init_list_head(&cid_set->cid_set_list); } -void -xqc_init_scid_set(xqc_scid_set_t *scid_set) +void +xqc_cid_set_inner_init(xqc_cid_set_inner_t *cid_set_inner) { - xqc_init_cid_set(&scid_set->cid_set); - xqc_cid_init_zero(&scid_set->user_scid); - scid_set->largest_scid_seq_num = 0; + xqc_memzero(cid_set_inner, sizeof(xqc_cid_set_inner_t)); + xqc_init_list_head(&cid_set_inner->cid_list); + xqc_init_list_head(&cid_set_inner->next); } -void -xqc_init_dcid_set(xqc_dcid_set_t *dcid_set) +void +xqc_cid_set_inner_destroy(xqc_cid_set_inner_t *cid_set_inner) { - xqc_init_cid_set(&dcid_set->cid_set); - xqc_cid_init_zero(&dcid_set->current_dcid); - dcid_set->largest_retire_prior_to = 0; + xqc_cid_inner_t *cid = NULL; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &cid_set_inner->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_list_del(pos); + xqc_free(cid); + } + + xqc_cid_set_inner_init(cid_set_inner); } void xqc_destroy_cid_set(xqc_cid_set_t *cid_set) { - xqc_cid_inner_t *cid = NULL; + xqc_cid_set_inner_t *cid_set_inner = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); xqc_list_del(pos); - xqc_free(cid); + xqc_cid_set_inner_destroy(cid_set_inner); + xqc_free(cid_set_inner); } xqc_init_cid_set(cid_set); } +xqc_cid_set_inner_t* +xqc_get_path_cid_set(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *cid_set_inner = NULL; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (cid_set_inner->path_id == path_id) { + return cid_set_inner; + } + } + + return NULL; +} + +xqc_cid_set_inner_t* +xqc_get_next_unused_path_cid_set(xqc_cid_set_t *cid_set) +{ + xqc_cid_set_inner_t *cid_set_inner = NULL; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (cid_set_inner->set_state == XQC_CID_SET_UNUSED) { + return cid_set_inner; + } + } + + return NULL; +} + +int64_t +xqc_cid_set_get_unused_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->unused_cnt; + } + return XQC_ERROR; +} + +int64_t +xqc_cid_set_get_used_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->used_cnt; + } + return XQC_ERROR; +} + +int64_t +xqc_cid_set_get_retired_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->retired_cnt; + } + return XQC_ERROR; +} + +int64_t +xqc_cid_set_get_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->largest_scid_seq_num; + } + return XQC_ERROR; +} + +xqc_int_t +xqc_cid_set_set_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t val) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + inner_set->largest_scid_seq_num = val; + return XQC_OK; + } + return XQC_ERROR; +} + xqc_int_t -xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit) +xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit, uint64_t path_id) { - if (cid_set->unused_cnt + cid_set->used_cnt > limit) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (!inner_set) { + return -XQC_ECONN_CID_NOT_FOUND; + } + + if ((inner_set->unused_cnt + inner_set->used_cnt) > limit) { return -XQC_EACTIVE_CID_LIMIT; } - xqc_cid_inner_t *inner_cid = xqc_malloc(sizeof(xqc_cid_inner_t)); + xqc_cid_inner_t *inner_cid = xqc_calloc(1, sizeof(xqc_cid_inner_t)); if (inner_cid == NULL) { return -XQC_EMALLOC; } + cid->path_id = path_id; xqc_cid_copy(&inner_cid->cid, cid); inner_cid->state = state; inner_cid->retired_ts = XQC_MAX_UINT64_VALUE; xqc_init_list_head(&inner_cid->list); - xqc_list_add_tail(&inner_cid->list, &cid_set->list_head); + xqc_list_add_tail(&inner_cid->list, &inner_set->cid_list); if (state == XQC_CID_UNUSED) { - cid_set->unused_cnt++; + inner_set->unused_cnt++; } else if (state == XQC_CID_USED) { - cid_set->used_cnt++; + inner_set->used_cnt++; } else if (state == XQC_CID_RETIRED) { - cid_set->retired_cnt++; + inner_set->retired_cnt++; } return XQC_OK; } xqc_int_t -xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) +xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return XQC_ERROR; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { if (inner_cid->state == XQC_CID_UNUSED) { - cid_set->unused_cnt--; + inner_set->unused_cnt--; + if (inner_cid->acked == XQC_CID_ACKED) { + inner_set->acked_unused--; + } } else if (inner_cid->state == XQC_CID_USED) { - cid_set->used_cnt--; + inner_set->used_cnt--; } else if (inner_cid->state == XQC_CID_RETIRED) { - cid_set->retired_cnt--; + inner_set->retired_cnt--; } xqc_list_del(pos); @@ -227,17 +341,50 @@ xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) return XQC_ERROR; } +xqc_cid_inner_t * +xqc_cid_set_search_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid) +{ + xqc_cid_inner_t *inner_cid; + xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; + + xqc_list_for_each_safe(pos_set, next_set, &cid_set->cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + + if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { + cid->cid_seq_num = inner_cid->cid.cid_seq_num; + cid->path_id = inner_cid->cid.path_id; + return inner_cid; + } + } + } + + return NULL; +} xqc_cid_inner_t * -xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid) +xqc_cid_in_cid_set(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return NULL; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { cid->cid_seq_num = inner_cid->cid.cid_seq_num; + cid->path_id = inner_cid->cid.path_id; return inner_cid; } } @@ -247,9 +394,9 @@ xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid) xqc_int_t -xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t next_state) +xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t next_state, uint64_t path_id) { - if (xqc_cid_in_cid_set(cid_set, &cid->cid) == NULL) { + if (xqc_cid_in_cid_set(cid_set, &cid->cid, path_id) == NULL) { return -XQC_ECONN_CID_NOT_FOUND; } @@ -262,82 +409,148 @@ xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_c return -XQC_ECID_STATE; } - /* current_state < next_state */ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return -XQC_ECONN_CID_NOT_FOUND; + } if (current_state == XQC_CID_UNUSED) { - cid_set->unused_cnt--; + inner_set->unused_cnt--; + if (cid->acked == XQC_CID_ACKED) { + inner_set->acked_unused--; + } } else if (current_state == XQC_CID_USED) { - cid_set->used_cnt--; + inner_set->used_cnt--; } else if (current_state == XQC_CID_RETIRED) { - cid_set->retired_cnt--; + inner_set->retired_cnt--; } cid->state = next_state; if (next_state == XQC_CID_USED) { - cid_set->used_cnt++; + inner_set->used_cnt++; } else if (next_state == XQC_CID_RETIRED) { - cid_set->retired_cnt++; + inner_set->retired_cnt++; } return XQC_OK; } xqc_int_t -xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) -{ - if (cid_set->unused_cnt == 0) { +xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return -XQC_ECONN_NO_AVAIL_CID; + } + + if (inner_set->unused_cnt == 0) { return -XQC_ECONN_NO_AVAIL_CID; } xqc_cid_inner_t *inner_cid; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (inner_cid->state == XQC_CID_UNUSED) { xqc_cid_copy(cid, &inner_cid->cid); - return xqc_cid_switch_to_next_state(cid_set, inner_cid, XQC_CID_USED); + return xqc_cid_switch_to_next_state(cid_set, inner_cid, XQC_CID_USED, path_id); } } return -XQC_ECONN_NO_AVAIL_CID; } -xqc_cid_t * -xqc_get_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num) +xqc_cid_inner_t * +xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return NULL; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (inner_cid->cid.cid_seq_num == seq_num) { - return &inner_cid->cid; + return inner_cid; } } return NULL; } -xqc_cid_inner_t * -xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num) +xqc_int_t +xqc_cid_set_add_path(xqc_cid_set_t *cid_set, uint64_t path_id) { - xqc_cid_inner_t *inner_cid = NULL; - xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { - inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (inner_set) { + return XQC_OK; + } - if (inner_cid->cid.cid_seq_num == seq_num) { - return inner_cid; - } + /* Note: the memory of inner_set will only be released on conn_destroy */ + inner_set = xqc_calloc(1, sizeof(xqc_cid_set_inner_t)); + if (!inner_set) { + return -XQC_EMALLOC; } - return NULL; + xqc_cid_set_inner_init(inner_set); + xqc_list_add_tail(&inner_set->next, &cid_set->cid_set_list); + inner_set->path_id = path_id; + cid_set->set_cnt[XQC_CID_SET_UNUSED]++; + return XQC_OK; +} + +void +xqc_cid_set_update_state(xqc_cid_set_t *cid_set, + uint64_t path_id, xqc_cid_set_state_t state) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (inner_set && inner_set->set_state != state) { + cid_set->set_cnt[inner_set->set_state]--; + cid_set->set_cnt[state]++; + inner_set->set_state = state; + } } + +void +xqc_cid_set_on_cid_acked(xqc_cid_set_t *cid_set, uint64_t path_id, + uint64_t cid_seq) +{ + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos, *next; + xqc_cid_inner_t *inner_cid; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (inner_set) { + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (inner_cid->cid.cid_seq_num == cid_seq) { + if (inner_cid->acked == XQC_CID_UNACKED + && inner_cid->state == XQC_CID_UNUSED) + { + inner_set->acked_unused++; + } + inner_cid->acked = XQC_CID_ACKED; + } + } + } +} \ No newline at end of file diff --git a/src/transport/xqc_cid.h b/src/transport/xqc_cid.h index 9acfe4a76..39dbdf984 100644 --- a/src/transport/xqc_cid.h +++ b/src/transport/xqc_cid.h @@ -8,7 +8,6 @@ #include #include "src/common/xqc_list.h" - #define XQC_DEFAULT_CID_LEN 8 typedef enum { @@ -18,61 +17,101 @@ typedef enum { XQC_CID_REMOVED, } xqc_cid_state_t; +typedef enum { + XQC_CID_SET_UNUSED, + XQC_CID_SET_USED, + XQC_CID_SET_ABANDONED, + XQC_CID_SET_MAX_STATE, +} xqc_cid_set_state_t; + +typedef enum { + XQC_CID_UNACKED = 0, + XQC_CID_ACKED = 1 +} xqc_cid_flag_t; typedef struct xqc_cid_inner_s { xqc_list_head_t list; - xqc_cid_t cid; xqc_cid_state_t state; xqc_usec_t retired_ts; + xqc_cid_flag_t acked; } xqc_cid_inner_t; -typedef struct xqc_cid_set_s { - xqc_list_head_t list_head; - uint64_t unused_cnt; - uint64_t used_cnt; - uint64_t retired_cnt; -} xqc_cid_set_t; +typedef struct xqc_cid_set_inner_s { + xqc_list_head_t next; /* a list of cid inner structures */ + xqc_list_head_t cid_list; + uint64_t unused_cnt; + uint64_t used_cnt; + uint64_t retired_cnt; + uint64_t path_id; + union { + uint64_t largest_scid_seq_num; /* for scid set */ + uint64_t largest_retire_prior_to; /* for dcid set */ + }; + xqc_cid_set_state_t set_state; + uint32_t acked_unused; +} xqc_cid_set_inner_t; -typedef struct xqc_scid_set_s { - xqc_cid_t user_scid; /* one of the USED SCIDs, for create/close notify */ - xqc_cid_set_t cid_set; /* a set of SCID, includes used/unused/retired SCID */ - uint64_t largest_scid_seq_num; +typedef struct xqc_cid_set_s { + xqc_list_head_t cid_set_list; /* a list of xqc_cid_set_inner_t */ + union { unsigned char original_scid_str[XQC_MAX_CID_LEN * 2 + 1]; -} xqc_scid_set_t; - -typedef struct xqc_dcid_set_s { - xqc_cid_t current_dcid; /* one of the USED DCIDs, for send packets */ - xqc_cid_set_t cid_set; /* a set of DCID, includes used/unused/retired DCID */ - uint64_t largest_retire_prior_to; unsigned char current_dcid_str[XQC_MAX_CID_LEN * 2 + 1]; -} xqc_dcid_set_t; + }; + union { + xqc_cid_t user_scid; /* one of the USED SCIDs, for create/close notify */ + xqc_cid_t current_dcid; /* one of the USED DCIDs, for send packets */ + }; + uint32_t set_cnt[XQC_CID_SET_MAX_STATE]; +} xqc_cid_set_t; xqc_int_t xqc_generate_cid(xqc_engine_t *engine, xqc_cid_t *ori_cid, xqc_cid_t *cid, uint64_t cid_seq_num); - void xqc_cid_copy(xqc_cid_t *dst, xqc_cid_t *src); void xqc_cid_init_zero(xqc_cid_t *cid); void xqc_cid_set(xqc_cid_t *cid, const unsigned char *data, uint8_t len); -void xqc_init_scid_set(xqc_scid_set_t *scid_set); -void xqc_init_dcid_set(xqc_dcid_set_t *dcid_set); +void xqc_init_cid_set(xqc_cid_set_t *cid_set); void xqc_destroy_cid_set(xqc_cid_set_t *cid_set); -xqc_int_t xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit); -xqc_int_t xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid); +xqc_int_t xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, + xqc_cid_state_t state, uint64_t limit, uint64_t path_id); +xqc_int_t xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); + +xqc_cid_inner_t *xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, + uint64_t seq_num, uint64_t path_id); +xqc_cid_inner_t *xqc_cid_in_cid_set(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); +xqc_cid_inner_t *xqc_cid_set_search_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid); + +xqc_int_t xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, + xqc_cid_inner_t *cid, xqc_cid_state_t state, uint64_t path_id); + +xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); + +void xqc_cid_set_inner_init(xqc_cid_set_inner_t *cid_set_inner); +void xqc_cid_set_inner_destroy(xqc_cid_set_inner_t *cid_set_inner); +xqc_cid_set_inner_t* xqc_get_path_cid_set(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_unused_cnt(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_used_cnt(xqc_cid_set_t *cid_set, uint64_t path_id);\ +int64_t xqc_cid_set_get_retired_cnt(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id); +xqc_int_t xqc_cid_set_set_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t val); + +unsigned char *xqc_sr_token_str(xqc_engine_t *engine, const char *sr_token); -xqc_cid_t *xqc_get_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num); -xqc_cid_inner_t *xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num); -xqc_cid_inner_t *xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid); +xqc_int_t xqc_cid_set_add_path(xqc_cid_set_t *cid_set, uint64_t path_id); -xqc_int_t xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t state); -xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid); +void xqc_cid_set_update_state(xqc_cid_set_t *cid_set, uint64_t path_id, xqc_cid_set_state_t state); +xqc_cid_set_inner_t* xqc_get_next_unused_path_cid_set(xqc_cid_set_t *cid_set); +void xqc_cid_set_on_cid_acked(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t cid_seq); -unsigned char *xqc_sr_token_str(const char *sr_token); #endif /* _XQC_CID_H_INCLUDED_ */ diff --git a/src/transport/xqc_client.c b/src/transport/xqc_client.c index 48c2609a8..905249ed6 100644 --- a/src/transport/xqc_client.c +++ b/src/transport/xqc_client.c @@ -68,7 +68,6 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting return NULL; } - xqc_log(engine->log, XQC_LOG_DEBUG, "|xqc_connect|"); xqc_log_event(xc->log, CON_CONNECTION_STARTED, xc, XQC_LOG_REMOTE_EVENT); /* conn_create callback */ @@ -83,15 +82,13 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting xc->conn_flag |= XQC_CONN_FLAG_UPPER_CONN_EXIST; } - /* xqc_conn_destroy must be called before the connection is inserted into conns_active_pq */ - if (!(xc->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(engine->conns_active_pq, xc, 0)) { - return NULL; - } - xc->conn_flag |= XQC_CONN_FLAG_TICKING; + xqc_engine_remove_wakeup_queue(engine, xc); + + if (xqc_engine_add_active_queue(engine, xc) != XQC_OK) { + return NULL; } - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, xc); /* when the connection is destroyed in the main logic, we should return error to upper level */ if (xqc_engine_conns_hash_find(engine, &scid, 's') == NULL) { diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index 8155b7fff..c45d9130a 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -17,6 +17,7 @@ #include "src/transport/xqc_defs.h" #include "src/transport/xqc_conn.h" #include "src/transport/xqc_send_ctl.h" +#include "src/transport/xqc_recv_timestamps_info.h" #include "src/transport/xqc_send_queue.h" #include "src/transport/xqc_engine.h" #include "src/transport/xqc_cid.h" @@ -24,15 +25,17 @@ #include "src/transport/xqc_frame_parser.h" #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_multipath.h" #include "src/transport/xqc_reinjection.h" -#include "src/tls/xqc_tls.h" #include "src/transport/xqc_datagram.h" +#include "src/transport/xqc_packet.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/tls/xqc_tls.h" #include -xqc_conn_settings_t default_conn_settings = { +xqc_conn_settings_t internal_default_conn_settings = { .pacing_on = 0, .ping_on = 0, .so_sndbuf = 0, @@ -42,11 +45,12 @@ xqc_conn_settings_t default_conn_settings = { .init_idle_time_out = XQC_CONN_INITIAL_IDLE_TIMEOUT, .idle_time_out = XQC_CONN_DEFAULT_IDLE_TIMEOUT, .enable_multipath = 0, - .multipath_version = XQC_MULTIPATH_04, + .multipath_version = XQC_MULTIPATH_10, .spurious_loss_detect_on = 0, .anti_amplification_limit = XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT, .keyupdate_pkt_threshold = 0, .max_pkt_out_size = XQC_PACKET_OUT_SIZE, + .probing_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE, .max_datagram_frame_size = 0, .mp_enable_reinjection = 0, .mp_ack_on_any_path = 0, @@ -64,12 +68,53 @@ xqc_conn_settings_t default_conn_settings = { .reinj_deadline_lower_bound = 20000, /* 20ms */ .standby_path_probe_timeout = 0, + .fec_conn_queue_rpr_timeout = 0, .enable_pmtud = 0, .pmtud_probing_interval = 500000, .marking_reinjection = 0, .recv_rate_bytes_per_sec = 0, .enable_stream_rate_limit = 0, + .close_dgram_redundancy= XQC_RED_NOT_USE, + + .scheduler_params = { + .bw_Bps_thr = 375000, + .loss_percent_thr_high = 30, + .loss_percent_thr_low = 10, + .pto_cnt_thr = 2, + .rtt_us_thr_high = 2000000, + .rtt_us_thr_low = 500000 + }, + .is_interop_mode = 0, +#ifdef XQC_PROTECT_POOL_MEM + .protect_pool_mem = 0, +#endif + .fec_level = XQC_FEC_CONN_LEVEL, /** 0: connection level; 1: stream level */ + .enable_encode_fec = 0, + .enable_decode_fec = 0, + .fec_params = { + .fec_code_rate = 0, + .fec_ele_bit_size = XQC_FEC_ELE_BIT_SIZE_DEFAULT, + .fec_protected_frames = XQC_FRAME_BIT_DATAGRAM | XQC_FRAME_BIT_STREAM, + .fec_max_window_size = XQC_SYMBOL_CACHE_LEN, + .fec_mp_mode = XQC_FEC_MP_DEFAULT, + .fec_max_symbol_num_per_block = 10, + .fec_encoder_schemes_num = 0, + .fec_decoder_schemes_num = 0, + .fec_encoder_scheme = 0, + .fec_decoder_scheme = 0, + .fec_blk_log_mod = 1000, + .fec_packet_mask_mode = 0, + .fec_log_on = 0, + }, + .disable_send_mmsg = 0, + .init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID, + .control_pto_value = 0, + .max_udp_payload_size = XQC_CONN_MAX_UDP_PAYLOAD_SIZE, + + .extended_ack_features = 0, + .max_receive_timestamps_per_ack = 0, + .receive_timestamps_exponent = 0 }; @@ -87,120 +132,237 @@ xqc_conn_dgram_probe_timeout(xqc_gp_timer_id_t gp_timer_id, } } +void +xqc_conn_set_default_sched_params(xqc_conn_settings_t *src_settings, xqc_conn_settings_t *settings) +{ + if (settings->scheduler_params.bw_Bps_thr == 0) { + settings->scheduler_params.bw_Bps_thr = src_settings->scheduler_params.bw_Bps_thr; + } + + if (settings->scheduler_params.loss_percent_thr_high == 0) { + settings->scheduler_params.loss_percent_thr_high = src_settings->scheduler_params.loss_percent_thr_high; + } + + if (settings->scheduler_params.loss_percent_thr_low == 0) { + settings->scheduler_params.loss_percent_thr_low = src_settings->scheduler_params.loss_percent_thr_low; + } + + if (settings->scheduler_params.pto_cnt_thr == 0) { + settings->scheduler_params.pto_cnt_thr = src_settings->scheduler_params.pto_cnt_thr; + } + + if (settings->scheduler_params.rtt_us_thr_high == 0) { + settings->scheduler_params.rtt_us_thr_high = src_settings->scheduler_params.rtt_us_thr_high; + } + + if (settings->scheduler_params.rtt_us_thr_low == 0) { + settings->scheduler_params.rtt_us_thr_low = src_settings->scheduler_params.rtt_us_thr_low; + } +} + void -xqc_server_set_conn_settings(const xqc_conn_settings_t *settings) -{ - default_conn_settings.cong_ctrl_callback = settings->cong_ctrl_callback; - default_conn_settings.cc_params = settings->cc_params; - default_conn_settings.scheduler_params = settings->scheduler_params; - default_conn_settings.pacing_on = settings->pacing_on; - default_conn_settings.ping_on = settings->ping_on; - default_conn_settings.so_sndbuf = settings->so_sndbuf; - default_conn_settings.sndq_packets_used_max = settings->sndq_packets_used_max; - default_conn_settings.linger = settings->linger; - default_conn_settings.spurious_loss_detect_on = settings->spurious_loss_detect_on; - default_conn_settings.datagram_force_retrans_on = settings->datagram_force_retrans_on; - default_conn_settings.enable_pmtud = settings->enable_pmtud; - default_conn_settings.marking_reinjection = settings->marking_reinjection; - default_conn_settings.mp_ack_on_any_path = settings->mp_ack_on_any_path; - default_conn_settings.mp_ping_on = settings->mp_ping_on; - default_conn_settings.recv_rate_bytes_per_sec = settings->recv_rate_bytes_per_sec; - default_conn_settings.enable_stream_rate_limit = settings->enable_stream_rate_limit; - default_conn_settings.init_recv_window = settings->init_recv_window; - - if (default_conn_settings.init_recv_window) { - default_conn_settings.init_recv_window = xqc_max(default_conn_settings.init_recv_window, XQC_QUIC_MAX_MSS); +xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *settings) +{ + engine->default_conn_settings.cong_ctrl_callback = settings->cong_ctrl_callback; + engine->default_conn_settings.cc_params = settings->cc_params; + engine->default_conn_settings.pacing_on = settings->pacing_on; + engine->default_conn_settings.ping_on = settings->ping_on; + engine->default_conn_settings.so_sndbuf = settings->so_sndbuf; + engine->default_conn_settings.sndq_packets_used_max = settings->sndq_packets_used_max; + engine->default_conn_settings.linger = settings->linger; + engine->default_conn_settings.spurious_loss_detect_on = settings->spurious_loss_detect_on; + engine->default_conn_settings.datagram_force_retrans_on = settings->datagram_force_retrans_on; + engine->default_conn_settings.enable_pmtud = settings->enable_pmtud; + engine->default_conn_settings.marking_reinjection = settings->marking_reinjection; + engine->default_conn_settings.mp_ack_on_any_path = settings->mp_ack_on_any_path; + engine->default_conn_settings.mp_ping_on = settings->mp_ping_on; + engine->default_conn_settings.recv_rate_bytes_per_sec = settings->recv_rate_bytes_per_sec; + engine->default_conn_settings.enable_stream_rate_limit = settings->enable_stream_rate_limit; + engine->default_conn_settings.init_recv_window = settings->init_recv_window; + engine->default_conn_settings.initial_rtt = settings->initial_rtt; + engine->default_conn_settings.initial_pto_duration = settings->initial_pto_duration; + engine->default_conn_settings.disable_send_mmsg = settings->disable_send_mmsg; +#ifdef XQC_PROTECT_POOL_MEM + engine->default_conn_settings.protect_pool_mem = settings->protect_pool_mem; +#endif + engine->default_conn_settings.adaptive_ack_frequency = settings->adaptive_ack_frequency; + + engine->default_conn_settings.scheduler_params = settings->scheduler_params; + xqc_conn_set_default_sched_params(&internal_default_conn_settings, &engine->default_conn_settings); + + if (settings->max_udp_payload_size != 0) { + engine->default_conn_settings.max_udp_payload_size = settings->max_udp_payload_size; + } + + if (engine->default_conn_settings.init_recv_window) { + engine->default_conn_settings.init_recv_window = xqc_max(engine->default_conn_settings.init_recv_window, XQC_QUIC_MAX_MSS); } if (settings->pmtud_probing_interval) { - default_conn_settings.pmtud_probing_interval = settings->pmtud_probing_interval; + engine->default_conn_settings.pmtud_probing_interval = settings->pmtud_probing_interval; } if (settings->max_ack_delay) { - default_conn_settings.max_ack_delay = xqc_min(settings->max_ack_delay, XQC_DEFAULT_MAX_ACK_DELAY); + engine->default_conn_settings.max_ack_delay = xqc_min(settings->max_ack_delay, XQC_DEFAULT_MAX_ACK_DELAY); } if (settings->datagram_redundant_probe) { - default_conn_settings.datagram_redundant_probe = xqc_max(settings->datagram_redundant_probe, + engine->default_conn_settings.datagram_redundant_probe = xqc_max(settings->datagram_redundant_probe, XQC_MIN_DATAGRAM_REDUNDANT_PROBE_INTERVAL); } if (settings->datagram_redundancy <= XQC_MAX_DATAGRAM_REDUNDANCY) { - default_conn_settings.datagram_redundancy = settings->datagram_redundancy; + engine->default_conn_settings.datagram_redundancy = settings->datagram_redundancy; } if (settings->init_idle_time_out > 0) { - default_conn_settings.init_idle_time_out = settings->init_idle_time_out; + engine->default_conn_settings.init_idle_time_out = settings->init_idle_time_out; + } + + if (settings->fec_conn_queue_rpr_timeout > 0) { + engine->default_conn_settings.fec_conn_queue_rpr_timeout = settings->fec_conn_queue_rpr_timeout; } if (settings->idle_time_out > 0) { - default_conn_settings.idle_time_out = settings->idle_time_out; + engine->default_conn_settings.idle_time_out = settings->idle_time_out; } - if (settings->anti_amplification_limit > XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT) { - default_conn_settings.anti_amplification_limit = settings->anti_amplification_limit; + if (settings->anti_amplification_limit > 0) { + engine->default_conn_settings.anti_amplification_limit = settings->anti_amplification_limit; } if (xqc_check_proto_version_valid(settings->proto_version)) { - default_conn_settings.proto_version = settings->proto_version; + engine->default_conn_settings.proto_version = settings->proto_version; } - default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; - default_conn_settings.max_datagram_frame_size = settings->max_datagram_frame_size; + engine->default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; + engine->default_conn_settings.max_datagram_frame_size = settings->max_datagram_frame_size; - if (settings->max_pkt_out_size > default_conn_settings.max_pkt_out_size) { - default_conn_settings.max_pkt_out_size = settings->max_pkt_out_size; + if (settings->max_pkt_out_size != 0) { + engine->default_conn_settings.max_pkt_out_size = settings->max_pkt_out_size; } - if (default_conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { - default_conn_settings.max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; + if (engine->default_conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { + engine->default_conn_settings.max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; } - default_conn_settings.enable_multipath = settings->enable_multipath; + engine->default_conn_settings.enable_multipath = settings->enable_multipath; + engine->default_conn_settings.is_interop_mode = settings->is_interop_mode; if (xqc_conn_is_current_mp_version_supported(settings->multipath_version) == XQC_OK) { - default_conn_settings.multipath_version = settings->multipath_version; + engine->default_conn_settings.multipath_version = settings->multipath_version; + + } else { + engine->default_conn_settings.multipath_version = XQC_MULTIPATH_10; + } + if (settings->init_max_path_id == 0) { + engine->default_conn_settings.init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID; + } else { - default_conn_settings.multipath_version = XQC_MULTIPATH_04; + engine->default_conn_settings.init_max_path_id = settings->init_max_path_id; + } + + engine->default_conn_settings.close_dgram_redundancy = settings->close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + engine->default_conn_settings.enable_encode_fec = settings->enable_encode_fec; + if (engine->default_conn_settings.enable_encode_fec) { + xqc_set_fec_schemes(settings->fec_params.fec_encoder_schemes, settings->fec_params.fec_encoder_schemes_num, + engine->default_conn_settings.fec_params.fec_encoder_schemes, &engine->default_conn_settings.fec_params.fec_encoder_schemes_num); + /* if no fec scheme was negotiated succesfully, set enable_encode_fec to 0 */ + engine->default_conn_settings.enable_encode_fec = engine->default_conn_settings.fec_params.fec_encoder_schemes_num == 0 ? 0 : settings->enable_encode_fec; + if (settings->fec_params.fec_code_rate) { + engine->default_conn_settings.fec_params.fec_code_rate = settings->fec_params.fec_code_rate; + } + if (settings->fec_params.fec_max_symbol_num_per_block) { + engine->default_conn_settings.fec_params.fec_max_symbol_num_per_block = settings->fec_params.fec_max_symbol_num_per_block; + } + if (settings->fec_params.fec_mp_mode) { + engine->default_conn_settings.fec_params.fec_mp_mode = settings->fec_params.fec_mp_mode; + } + if (settings->fec_level) { + engine->default_conn_settings.fec_level = settings->fec_level; + } } - default_conn_settings.scheduler_callback = settings->scheduler_callback; - default_conn_settings.reinj_ctl_callback = settings->reinj_ctl_callback; - default_conn_settings.mp_enable_reinjection = settings->mp_enable_reinjection; + engine->default_conn_settings.enable_decode_fec = settings->enable_decode_fec; + if (engine->default_conn_settings.enable_decode_fec) { + xqc_set_fec_schemes(settings->fec_params.fec_decoder_schemes, settings->fec_params.fec_decoder_schemes_num, + engine->default_conn_settings.fec_params.fec_decoder_schemes, &engine->default_conn_settings.fec_params.fec_decoder_schemes_num); + /* if no fec scheme was negotiated succesfully, set enable_decode_fec to 0 */ + engine->default_conn_settings.enable_decode_fec = engine->default_conn_settings.fec_params.fec_decoder_schemes_num == 0 ? 0 : settings->enable_decode_fec; + if (settings->fec_params.fec_max_window_size) { + engine->default_conn_settings.fec_params.fec_max_window_size = xqc_min(settings->fec_params.fec_max_window_size, XQC_SYMBOL_CACHE_LEN); + } + if (settings->fec_params.fec_blk_log_mod) { + engine->default_conn_settings.fec_params.fec_blk_log_mod = settings->fec_params.fec_blk_log_mod; + } + if (settings->fec_params.fec_log_on) { + engine->default_conn_settings.fec_params.fec_log_on = settings->fec_params.fec_log_on; + } + if (settings->fec_params.fec_packet_mask_mode) { + engine->default_conn_settings.fec_params.fec_packet_mask_mode = settings->fec_params.fec_packet_mask_mode; + } + } + +#endif + + engine->default_conn_settings.scheduler_callback = settings->scheduler_callback; + engine->default_conn_settings.reinj_ctl_callback = settings->reinj_ctl_callback; + engine->default_conn_settings.mp_enable_reinjection = settings->mp_enable_reinjection; + + if ((settings->extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) + && !settings->enable_multipath) + { + /* + * Bit 1 indicates whether Receive Timestamps are enabled. + * Currently, we only use receive_timestamps features, so set extended_ack_features = XQC_ACK_EXT_FEATURE_BIT_RECV_TS. + * + * Besides, multipath-quic and ack_ext are incompatible right now, disable ack_ext when enable multipath. + * TODO: coordinate them in the future. + */ + engine->default_conn_settings.extended_ack_features = XQC_ACK_EXT_FEATURE_BIT_RECV_TS; + engine->default_conn_settings.max_receive_timestamps_per_ack = settings->max_receive_timestamps_per_ack; + engine->default_conn_settings.receive_timestamps_exponent = settings->receive_timestamps_exponent; + } if (settings->ack_frequency > 0) { - default_conn_settings.ack_frequency = settings->ack_frequency; + engine->default_conn_settings.ack_frequency = settings->ack_frequency; } if (settings->pto_backoff_factor > 0) { - default_conn_settings.pto_backoff_factor = settings->pto_backoff_factor; + engine->default_conn_settings.pto_backoff_factor = settings->pto_backoff_factor; } if (settings->loss_detection_pkt_thresh > 0) { - default_conn_settings.loss_detection_pkt_thresh = settings->loss_detection_pkt_thresh; + engine->default_conn_settings.loss_detection_pkt_thresh = settings->loss_detection_pkt_thresh; } if (settings->reinj_flexible_deadline_srtt_factor > 0) { - default_conn_settings.reinj_flexible_deadline_srtt_factor = settings->reinj_flexible_deadline_srtt_factor; + engine->default_conn_settings.reinj_flexible_deadline_srtt_factor = settings->reinj_flexible_deadline_srtt_factor; } if (settings->reinj_hard_deadline > 0) { - default_conn_settings.reinj_hard_deadline = settings->reinj_hard_deadline; + engine->default_conn_settings.reinj_hard_deadline = settings->reinj_hard_deadline; } if (settings->reinj_deadline_lower_bound > 0) { - default_conn_settings.reinj_deadline_lower_bound = settings->reinj_deadline_lower_bound; + engine->default_conn_settings.reinj_deadline_lower_bound = settings->reinj_deadline_lower_bound; } if (settings->standby_path_probe_timeout > 0) { /* no less than 500ms */ - default_conn_settings.standby_path_probe_timeout = xqc_max(settings->standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); + engine->default_conn_settings.standby_path_probe_timeout = xqc_max(settings->standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); } if (settings->keyupdate_pkt_threshold != UINT64_MAX) { - default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; + engine->default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; + } + + if (settings->probing_pkt_out_size > 0) { + engine->default_conn_settings.probing_pkt_out_size = settings->probing_pkt_out_size; } } @@ -209,9 +371,6 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT] = "HSK_DONE", [XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT] = "CAN_SEND_1RTT", [XQC_CONN_FLAG_TICKING_SHIFT] = "TICKING", - [XQC_CONN_FLAG_SHOULD_ACK_INIT_SHIFT] = "ACK_INIT", - [XQC_CONN_FLAG_SHOULD_ACK_HSK_SHIFT] = "ACK_HSK", - [XQC_CONN_FLAG_SHOULD_ACK_01RTT_SHIFT] = "ACK_01RTT", [XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT] = "HAS_GAP", [XQC_CONN_FLAG_TIME_OUT_SHIFT] = "TIME_OUT", [XQC_CONN_FLAG_ERROR_SHIFT] = "ERROR", @@ -233,7 +392,6 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT] = "HSK_CONFIRMED", [XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT] = "HSK_DONE_ACKED", [XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT] = "ADDR_VALIDATED", - [XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT] = "NEW_CID_ACKED", [XQC_CONN_FLAG_LINGER_CLOSING_SHIFT] = "LINGER_CLOSING", [XQC_CONN_FLAG_RETRY_RECVD_SHIFT] = "RETRY_RECVD", [XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT] = "TLS_HSK_CMPTD", @@ -246,31 +404,30 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_PMTUD_PROBING_SHIFT] = "PMTUD_PROBING", [XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT] = "NO_DGRAM_NOTIFIED", [XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT] = "DGRAM_MSS_NOTIFY", - [XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT] = "MP_WAIT_SCID", - [XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT] = "MP_WAIT_DCID", - [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY", + [XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT] = "MP_WAIT_MP_READY", + [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY_NOTIFY", }; -unsigned char g_conn_flag_buf[1024]; const char * -xqc_conn_flag_2_str(xqc_conn_flag_t conn_flag) +xqc_conn_flag_2_str(xqc_connection_t *conn, xqc_conn_flag_t conn_flag) { - g_conn_flag_buf[0] = '\0'; + xqc_engine_t *engine = conn->engine; + engine->conn_flag_str_buf[0] = '\0'; size_t pos = 0; int wsize; for (int i = 0; i < XQC_CONN_FLAG_SHIFT_NUM; i++) { if (conn_flag & 1ULL << i) { - wsize = snprintf(g_conn_flag_buf + pos, sizeof(g_conn_flag_buf) - pos, "%s ", + wsize = snprintf(engine->conn_flag_str_buf + pos, sizeof(engine->conn_flag_str_buf) - pos, "%s ", xqc_conn_flag_to_str[i]); - if (wsize < 0 || wsize >= sizeof(g_conn_flag_buf) - pos) { + if (wsize < 0 || wsize >= sizeof(engine->conn_flag_str_buf) - pos) { break; } pos += wsize; } } - return g_conn_flag_buf; + return engine->conn_flag_str_buf; } static const char * const xqc_conn_state_to_str[XQC_CONN_STATE_N] = { @@ -321,13 +478,24 @@ xqc_conn_init_trans_settings(xqc_connection_t *conn) /* set local and remote settings to default */ xqc_trans_settings_t *ls = &conn->local_settings; xqc_trans_settings_t *rs = &conn->remote_settings; + uint32_t i, co_bytes; + char *co_str = conn->conn_settings.conn_option_str; + xqc_conn_set_default_settings(ls); xqc_conn_set_default_settings(rs); /* set local default setting values */ - ls->max_streams_bidi = 1024; - ls->max_stream_data_bidi_remote = XQC_MAX_RECV_WINDOW; + if (conn->conn_settings.is_interop_mode) { + ls->max_streams_bidi = 128; + ls->max_streams_uni = 128; + } else { + ls->max_streams_bidi = 1024; + ls->max_streams_uni = 1024; + } + ls->max_stream_data_bidi_remote = XQC_MAX_RECV_WINDOW; + ls->max_stream_data_uni = XQC_MAX_RECV_WINDOW; + if (conn->conn_settings.enable_stream_rate_limit) { ls->max_stream_data_bidi_local = conn->conn_settings.init_recv_window; @@ -335,34 +503,84 @@ xqc_conn_init_trans_settings(xqc_connection_t *conn) ls->max_stream_data_bidi_local = XQC_MAX_RECV_WINDOW; } - ls->max_streams_uni = 1024; - ls->max_stream_data_uni = XQC_MAX_RECV_WINDOW; - - if (conn->conn_settings.recv_rate_bytes_per_sec) { - ls->max_data = conn->conn_settings.recv_rate_bytes_per_sec * XQC_FC_INIT_RTT / 1000000; - ls->max_data = xqc_max(XQC_MIN_RECV_WINDOW, ls->max_data); - ls->max_data = xqc_min(XQC_MAX_RECV_WINDOW, ls->max_data); - + if (conn->conn_settings.is_interop_mode) { + ls->max_data = 1024 * 1024; + } else { - /* max_data is the sum of stream_data on all uni and bidi streams */ - ls->max_data = ls->max_streams_bidi * ls->max_stream_data_bidi_local - + ls->max_streams_uni * ls->max_stream_data_uni; + if (conn->conn_settings.recv_rate_bytes_per_sec) { + ls->max_data = conn->conn_settings.recv_rate_bytes_per_sec * XQC_FC_INIT_RTT / 1000000; + ls->max_data = xqc_max(XQC_MIN_RECV_WINDOW, ls->max_data); + ls->max_data = xqc_min(XQC_MAX_RECV_WINDOW, ls->max_data); + + } else { + /* max_data is the sum of stream_data on all uni and bidi streams */ + ls->max_data = ls->max_streams_bidi * ls->max_stream_data_bidi_local + + ls->max_streams_uni * ls->max_stream_data_uni; + } } ls->max_idle_timeout = conn->conn_settings.idle_time_out; - ls->max_udp_payload_size = XQC_CONN_MAX_UDP_PAYLOAD_SIZE; + ls->max_udp_payload_size = conn->conn_settings.max_udp_payload_size; ls->active_connection_id_limit = XQC_CONN_ACTIVE_CID_LIMIT; ls->enable_multipath = conn->conn_settings.enable_multipath; ls->multipath_version = conn->conn_settings.multipath_version; + ls->init_max_path_id = conn->conn_settings.init_max_path_id; + ls->enable_pmtud = conn->conn_settings.enable_pmtud; ls->max_datagram_frame_size = conn->conn_settings.max_datagram_frame_size; ls->disable_active_migration = ls->enable_multipath ? 0 : 1; ls->max_ack_delay = conn->conn_settings.max_ack_delay; + + /* init local conn options */ + for (i = 0, co_bytes = 0; i < XQC_CO_STR_MAX_LEN; i++) { + if (co_bytes == 4) { + if ((co_str[i] != ',' && co_str[i] != '\0')) { + // invalid CO. Stop decoding. + break; + + } else { + ls->conn_options[ls->conn_option_num++] = XQC_CO_TAG(co_str[i - 4], co_str[i - 3], co_str[i - 2], co_str[i - 1]); + } + + co_bytes = 0; + + } else { + if (xqc_char_is_letter_or_number(co_str[i])) { + co_bytes++; + + } else { + // invalid CO. Stop decoding. + break; + } + } + } + + ls->close_dgram_redundancy = conn->conn_settings.close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + /* init FEC transport params */ + if (conn->conn_settings.enable_encode_fec) { + ls->enable_encode_fec = conn->conn_settings.enable_encode_fec; + ls->fec_max_symbols_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; + ls->fec_encoder_schemes_num = conn->conn_settings.fec_params.fec_encoder_schemes_num; + for (xqc_int_t i = 0; i < conn->conn_settings.fec_params.fec_encoder_schemes_num; i++) { + ls->fec_encoder_schemes[i] = conn->conn_settings.fec_params.fec_encoder_schemes[i]; + } + } + if (conn->conn_settings.enable_decode_fec) { + ls->enable_decode_fec = conn->conn_settings.enable_decode_fec; + ls->fec_decoder_schemes_num = conn->conn_settings.fec_params.fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < conn->conn_settings.fec_params.fec_decoder_schemes_num; i++) { + ls->fec_decoder_schemes[i] = conn->conn_settings.fec_params.fec_decoder_schemes[i]; + } + } +#endif + } @@ -371,6 +589,8 @@ xqc_conn_init_flow_ctl(xqc_connection_t *conn) { xqc_conn_flow_ctl_t *flow_ctl = &conn->conn_flow_ctl; xqc_trans_settings_t * settings = & conn->local_settings; + + /* TODO: send params are inited to be zero, until zerortt inited or handshake done */ flow_ctl->fc_max_data_can_send = settings->max_data; /* replace with the value specified by peer after handshake */ flow_ctl->fc_max_data_can_recv = settings->max_data; flow_ctl->fc_max_streams_bidi_can_send = settings->max_streams_bidi; /* replace with the value specified by peer after handshake */ @@ -413,14 +633,15 @@ xqc_conn_init_timer_manager(xqc_connection_t *conn) { xqc_timer_set(timer_manager, XQC_TIMER_PING, now, XQC_PING_TIMEOUT * 1000); } +} - if (conn->conn_settings.enable_pmtud) { - if (conn->conn_settings.enable_multipath) { - xqc_timer_set(timer_manager, XQC_TIMER_PMTUD_PROBING, now, XQC_PMTUD_START_DELAY * 1000); - - } else { - xqc_timer_set(timer_manager, XQC_TIMER_PMTUD_PROBING, now, 1); - } +static void +xqc_conn_set_ack_ext_local_settings(xqc_trans_settings_t *local_settings, const xqc_conn_settings_t *settings) +{ + if (settings->extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) { + local_settings->extended_ack_features = 2; + local_settings->max_receive_timestamps_per_ack = settings->max_receive_timestamps_per_ack; + local_settings->receive_timestamps_exponent = settings->receive_timestamps_exponent; } } @@ -429,11 +650,20 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, const xqc_conn_settings_t *settings, void *user_data, xqc_conn_type_t type) { xqc_connection_t *xc = NULL; +#ifdef XQC_PROTECT_POOL_MEM + xqc_memory_pool_t *pool = xqc_create_pool(engine->config->conn_pool_size, settings->protect_pool_mem); +#else xqc_memory_pool_t *pool = xqc_create_pool(engine->config->conn_pool_size); +#endif if (pool == NULL) { return NULL; } +#ifdef XQC_PROTECT_POOL_MEM + xqc_log(engine->log, XQC_LOG_DEBUG, "|mempool|protect:%d|page_sz:%z|", + pool->protect_block, pool->page_size); +#endif + xc = xqc_pcalloc(pool, sizeof(xqc_connection_t)); if (xc == NULL) { goto fail; @@ -441,6 +671,17 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_settings = *settings; + xqc_memcpy(xc->conn_settings.conn_option_str, settings->conn_option_str, XQC_CO_STR_MAX_LEN); + xqc_conn_set_default_sched_params(&engine->default_conn_settings, &xc->conn_settings); + + if (xc->conn_settings.max_udp_payload_size == 0) { + xc->conn_settings.max_udp_payload_size = engine->default_conn_settings.max_udp_payload_size; + } + + if (xc->conn_settings.initial_rtt == 0) { + xc->conn_settings.initial_rtt = XQC_kInitialRtt_us; + } + if (xc->conn_settings.max_ack_delay == 0) { xc->conn_settings.max_ack_delay = XQC_DEFAULT_MAX_ACK_DELAY; } @@ -451,6 +692,11 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, XQC_MIN_DATAGRAM_REDUNDANT_PROBE_INTERVAL); } + if (xc->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_BEFORE_SCHED) { + xc->conn_settings.mp_enable_reinjection |= XQC_REINJ_UNACK_AFTER_SEND; + } + + if (xc->conn_settings.datagram_redundancy > XQC_MAX_DATAGRAM_REDUNDANCY) { xc->conn_settings.datagram_redundancy = XQC_MAX_DATAGRAM_REDUNDANCY; } @@ -464,7 +710,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, /* do not reinject packets on the same path */ xc->conn_settings.scheduler_callback = xqc_minrtt_scheduler_cb; } - + xc->conn_settings.reinj_ctl_callback = xqc_dgram_reinj_ctl_cb; xc->conn_settings.mp_enable_reinjection |= XQC_REINJ_UNACK_AFTER_SEND; } @@ -480,8 +726,8 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_settings.standby_path_probe_timeout = xqc_max(xc->conn_settings.standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); } - if (xc->conn_settings.max_pkt_out_size < default_conn_settings.max_pkt_out_size) { - xc->conn_settings.max_pkt_out_size = default_conn_settings.max_pkt_out_size; + if (xc->conn_settings.max_pkt_out_size == 0) { + xc->conn_settings.max_pkt_out_size = engine->default_conn_settings.max_pkt_out_size; } if (xc->conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { @@ -489,19 +735,19 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, } if (xc->conn_settings.pmtud_probing_interval == 0) { - xc->conn_settings.pmtud_probing_interval = default_conn_settings.pmtud_probing_interval; + xc->conn_settings.pmtud_probing_interval = engine->default_conn_settings.pmtud_probing_interval; } if (xc->conn_settings.ack_frequency == 0) { - xc->conn_settings.ack_frequency = default_conn_settings.ack_frequency; + xc->conn_settings.ack_frequency = engine->default_conn_settings.ack_frequency; } if (xc->conn_settings.pto_backoff_factor == 0) { - xc->conn_settings.pto_backoff_factor = default_conn_settings.pto_backoff_factor; + xc->conn_settings.pto_backoff_factor = engine->default_conn_settings.pto_backoff_factor; } if (xc->conn_settings.loss_detection_pkt_thresh == 0) { - xc->conn_settings.loss_detection_pkt_thresh = default_conn_settings.loss_detection_pkt_thresh; + xc->conn_settings.loss_detection_pkt_thresh = engine->default_conn_settings.loss_detection_pkt_thresh; } xc->version = (type == XQC_CONN_TYPE_CLIENT) ? settings->proto_version : XQC_IDRAFT_INIT_VER; @@ -522,55 +768,137 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_settings.idle_time_out = XQC_CONN_DEFAULT_IDLE_TIMEOUT; } - if (xc->conn_settings.anti_amplification_limit < XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT) { + if (xc->conn_settings.anti_amplification_limit == 0) { xc->conn_settings.anti_amplification_limit = XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT; } if (xc->conn_settings.reinj_flexible_deadline_srtt_factor == 0) { - xc->conn_settings.reinj_flexible_deadline_srtt_factor = default_conn_settings.reinj_flexible_deadline_srtt_factor; + xc->conn_settings.reinj_flexible_deadline_srtt_factor = engine->default_conn_settings.reinj_flexible_deadline_srtt_factor; } if (xc->conn_settings.reinj_hard_deadline == 0) { - xc->conn_settings.reinj_hard_deadline = default_conn_settings.reinj_hard_deadline; + xc->conn_settings.reinj_hard_deadline = engine->default_conn_settings.reinj_hard_deadline; } if (xqc_conn_is_current_mp_version_supported(xc->conn_settings.multipath_version) != XQC_OK) { - xc->conn_settings.multipath_version = XQC_MULTIPATH_04; + xc->conn_settings.multipath_version = XQC_MULTIPATH_10; + } + + if (xc->conn_settings.init_max_path_id == 0) { + xc->conn_settings.init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID; + } + + if (xc->conn_settings.probing_pkt_out_size == 0) { + xc->conn_settings.probing_pkt_out_size = engine->default_conn_settings.probing_pkt_out_size; + } + + xc->conn_settings.extended_ack_features = 0; + xc->conn_settings.max_receive_timestamps_per_ack = 0; + xc->conn_settings.receive_timestamps_exponent = 0; + +#ifdef XQC_ENABLE_FEC + xc->fec_neg_fail_reason = 0; + + if (xc->conn_settings.enable_encode_fec) { + if (xc->conn_settings.fec_params.fec_code_rate == 0) { + xc->conn_settings.fec_params.fec_code_rate = engine->default_conn_settings.fec_params.fec_code_rate; + } + if (xc->conn_settings.fec_params.fec_ele_bit_size == 0) { + xc->conn_settings.fec_params.fec_ele_bit_size = engine->default_conn_settings.fec_params.fec_ele_bit_size; + } + if (xc->conn_settings.fec_params.fec_protected_frames == 0) { + xc->conn_settings.fec_params.fec_protected_frames = engine->default_conn_settings.fec_params.fec_protected_frames; + } + if (xc->conn_settings.fec_params.fec_max_symbol_num_per_block == 0) { + xc->conn_settings.fec_params.fec_max_symbol_num_per_block = engine->default_conn_settings.fec_params.fec_max_symbol_num_per_block; + } + if (xc->conn_settings.fec_params.fec_mp_mode == 0) { + xc->conn_settings.fec_params.fec_mp_mode = engine->default_conn_settings.fec_params.fec_mp_mode; + } + if (xc->conn_settings.fec_level == 0) { + xc->conn_settings.fec_level = engine->default_conn_settings.fec_level; + } + } + if (xc->conn_settings.enable_decode_fec) { + if (xc->conn_settings.fec_params.fec_max_window_size) { + xc->conn_settings.fec_params.fec_max_window_size = xqc_min(xc->conn_settings.fec_params.fec_max_window_size, XQC_SYMBOL_CACHE_LEN); + + } else { + xc->conn_settings.fec_params.fec_max_window_size = engine->default_conn_settings.fec_params.fec_max_window_size; + } + if (xc->conn_settings.fec_params.fec_blk_log_mod == 0) { + xc->conn_settings.fec_params.fec_blk_log_mod = engine->default_conn_settings.fec_params.fec_blk_log_mod; + } + if (xc->conn_settings.fec_params.fec_log_on == 0) { + xc->conn_settings.fec_params.fec_log_on = engine->default_conn_settings.fec_params.fec_log_on; + } + + if (xc->conn_settings.fec_params.fec_packet_mask_mode == 0) { + xc->conn_settings.fec_params.fec_packet_mask_mode = engine->default_conn_settings.fec_params.fec_packet_mask_mode; + } + } + if (xc->conn_settings.fec_conn_queue_rpr_timeout == 0) { + xc->conn_settings.fec_conn_queue_rpr_timeout = engine->default_conn_settings.fec_conn_queue_rpr_timeout; + } + + if (xc->conn_settings.enable_encode_fec + || xc->conn_settings.enable_decode_fec) + { + xc->fec_ctl = xqc_fec_ctl_create(xc); + if (xc->fec_ctl == NULL) { + xc->conn_settings.enable_encode_fec = 0; + xc->conn_settings.enable_decode_fec = 0; + } } +#endif xqc_conn_init_trans_settings(xc); + xqc_conn_set_ack_ext_local_settings(&xc->local_settings, settings); + xqc_conn_init_flow_ctl(xc); xqc_conn_init_key_update_ctx(xc); xc->conn_pool = pool; - xqc_init_dcid_set(&xc->dcid_set); - xqc_init_scid_set(&xc->scid_set); + xqc_init_cid_set(&xc->dcid_set); + xqc_init_cid_set(&xc->scid_set); + + if (xqc_cid_set_add_path(&xc->dcid_set, XQC_INITIAL_PATH_ID) != XQC_OK) { + goto fail; + } + + if (xqc_cid_set_add_path(&xc->scid_set, XQC_INITIAL_PATH_ID) != XQC_OK) { + goto fail; + } + xqc_cid_set_update_state(&xc->dcid_set, XQC_INITIAL_PATH_ID, XQC_CID_SET_USED); + xqc_cid_set_update_state(&xc->scid_set, XQC_INITIAL_PATH_ID, XQC_CID_SET_USED); + + if (xqc_cid_set_insert_cid(&xc->dcid_set, dcid, XQC_CID_USED, + xc->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID)) + { + goto fail; + } xqc_cid_copy(&(xc->dcid_set.current_dcid), dcid); xqc_hex_dump(xc->dcid_set.current_dcid_str, dcid->cid_buf, dcid->cid_len); xc->dcid_set.current_dcid_str[dcid->cid_len * 2] = '\0'; - if (xqc_cid_set_insert_cid(&xc->dcid_set.cid_set, dcid, XQC_CID_USED, - xc->local_settings.active_connection_id_limit)) + + if (xqc_cid_set_insert_cid(&xc->scid_set, scid, XQC_CID_USED, + xc->remote_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID)) { goto fail; } - xqc_cid_copy(&(xc->scid_set.user_scid), scid); xqc_hex_dump(xc->scid_set.original_scid_str, scid->cid_buf, scid->cid_len); xc->scid_set.original_scid_str[scid->cid_len * 2] = '\0'; - xc->scid_set.largest_scid_seq_num = scid->cid_seq_num; - if (xqc_cid_set_insert_cid(&xc->scid_set.cid_set, scid, XQC_CID_USED, - xc->remote_settings.active_connection_id_limit)) - { - goto fail; - } - + xqc_cid_set_set_largest_seq_or_rpt(&xc->scid_set, XQC_INITIAL_PATH_ID, scid->cid_seq_num); xqc_cid_copy(&(xc->initial_scid), scid); xc->engine = engine; - xc->log = xqc_log_init(engine->log->log_level, engine->log->log_event, engine->log->log_timestamp, - engine->log->log_level_name, engine->log->log_callbacks, engine->log->user_data); + xc->log = xqc_log_init(engine->log->log_level, engine->log->log_event, engine->log->qlog_importance, engine->log->log_timestamp, + engine->log->log_level_name, engine, engine->log->log_callbacks, engine->log->user_data); xc->log->scid = xc->scid_set.original_scid_str; xc->transport_cbs = engine->transport_cbs; xc->user_data = user_data; @@ -578,6 +906,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_type = type; xc->conn_flag = 0; xc->conn_state = (type == XQC_CONN_TYPE_SERVER) ? XQC_CONN_STATE_SERVER_INIT : XQC_CONN_STATE_CLIENT_INIT; + xqc_log_event(xc->log, CON_CONNECTION_STATE_UPDATED, xc); xc->zero_rtt_count = 0; xc->conn_create_time = xqc_monotonic_timestamp(); xc->handshake_complete_time = 0; @@ -585,9 +914,9 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->max_stream_id_bidi_remote = -1; xc->max_stream_id_uni_remote = -1; xc->last_dgram = NULL; - xc->pkt_out_size = xc->conn_settings.max_pkt_out_size; - xc->max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; - xc->probing_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; + xc->pkt_out_size = xqc_min(xc->conn_settings.max_pkt_out_size, xc->conn_settings.max_udp_payload_size - XQC_PACKET_OUT_EXT_SPACE); + xc->max_pkt_out_size = xc->conn_settings.probing_pkt_out_size; + xc->probing_pkt_out_size = xc->conn_settings.probing_pkt_out_size; xc->probing_cnt = 0; for (xqc_encrypt_level_t encrypt_level = XQC_ENC_LEV_INIT; encrypt_level < XQC_ENC_LEV_MAX; encrypt_level++) { @@ -664,10 +993,6 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, goto fail; } - if (xqc_conn_init_paths_list(xc) != XQC_OK) { - goto fail; - } - /* set scheduler callback (default: minRTT) */ if (xc->conn_settings.scheduler_callback.xqc_scheduler_init) { xc->scheduler_callback = &xc->conn_settings.scheduler_callback; @@ -677,6 +1002,9 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, } xc->scheduler = xqc_pcalloc(xc->conn_pool, xc->scheduler_callback->xqc_scheduler_size()); + if (xc->scheduler == NULL) { + goto fail; + } xc->scheduler_callback->xqc_scheduler_init(xc->scheduler, xc->log, &xc->conn_settings.scheduler_params); /* set reinject control callback if reinjection enabled */ @@ -689,6 +1017,14 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->reinj_callback->xqc_reinj_ctl_init(xc->reinj_ctl, xc); } + + /* + * Init paths after the scheduler and the reinjection controller are initialized. + */ + if (xqc_conn_init_paths_list(xc) != XQC_OK) { + goto fail; + } + xc->pkt_filter_cb = NULL; /* for datagram */ @@ -697,7 +1033,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xqc_init_list_head(&xc->ping_notification_list); xqc_log(xc->log, XQC_LOG_DEBUG, "|success|scid:%s|dcid:%s|conn:%p|", - xqc_scid_str(&xc->scid_set.user_scid), xqc_dcid_str(&xc->dcid_set.current_dcid), xc); + xqc_scid_str(engine, &xc->scid_set.user_scid), xqc_dcid_str(engine, &xc->dcid_set.current_dcid), xc); xqc_log_event(xc->log, TRA_PARAMETERS_SET, xc, XQC_LOG_LOCAL_EVENT); return xc; @@ -805,7 +1141,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, xqc_cid_copy(&conn->original_dcid, scid); - if (xqc_cid_in_cid_set(&conn->scid_set.cid_set, &conn->original_dcid) == NULL) { + if (xqc_cid_in_cid_set(&conn->scid_set, &conn->original_dcid, XQC_INITIAL_PATH_ID) == NULL) { /* * if server choose it's own cid, then if server Initial is lost, * and if client Initial retransmit, server might use odcid to @@ -819,7 +1155,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, } xqc_log(conn->log, XQC_LOG_INFO, "|hash odcid conn|odcid:%s|conn:%p|", - xqc_dcid_str(&conn->original_dcid), conn); + xqc_dcid_str(engine, &conn->original_dcid), conn); } ret = xqc_memcpy_with_cap(conn->local_addr, sizeof(conn->local_addr), @@ -858,7 +1194,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, goto fail; } - xqc_log(engine->log, XQC_LOG_DEBUG, "|server accept new conn|"); + xqc_log_event(conn->log, CON_CONNECTION_STARTED, conn, XQC_LOG_REMOTE_EVENT); if (conn->transport_cbs.server_accept) { if (conn->transport_cbs.server_accept(engine, conn, &conn->scid_set.user_scid, user_data) < 0) { @@ -869,7 +1205,6 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, conn->conn_flag |= XQC_CONN_FLAG_UPPER_CONN_EXIST; } - xqc_log_event(conn->log, CON_CONNECTION_STARTED, conn, XQC_LOG_REMOTE_EVENT); return conn; fail: @@ -883,9 +1218,22 @@ xqc_conn_client_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ { xqc_int_t ret; + /* save alpn */ + conn->alpn = xqc_calloc(1, alpn_len + 1); + if (conn->alpn == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|malloc alpn buffer error|"); + return -XQC_EMALLOC; + } + + xqc_memcpy(conn->alpn, alpn, alpn_len); + conn->alpn_len = alpn_len; + /* set quic callbacks to quic connection */ ret = xqc_engine_get_alpn_callbacks(conn->engine, alpn, alpn_len, &conn->app_proto_cbs); if (ret != XQC_OK) { + xqc_free(conn->alpn); + conn->alpn = NULL; + conn->alpn_len = 0; xqc_log(conn->log, XQC_LOG_ERROR, "|can't get application layer callback|ret:%d", ret); return ret; } @@ -899,9 +1247,22 @@ xqc_conn_server_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ { xqc_int_t ret; + /* save alpn */ + conn->alpn = xqc_calloc(1, alpn_len + 1); + if (conn->alpn == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|malloc alpn buffer error|"); + return -XQC_EMALLOC; + } + + xqc_memcpy(conn->alpn, alpn, alpn_len); + conn->alpn_len = alpn_len; + /* set quic callbacks to quic connection */ ret = xqc_engine_get_alpn_callbacks(conn->engine, alpn, alpn_len, &conn->app_proto_cbs); if (ret != XQC_OK) { + xqc_free(conn->alpn); + conn->alpn = NULL; + conn->alpn_len = 0; xqc_log(conn->log, XQC_LOG_ERROR, "|can't get application layer callback|ret:%d", ret); return ret; } @@ -923,7 +1284,7 @@ xqc_conn_server_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ if (conn->conn_flag & XQC_CONN_FLAG_LOCAL_TP_UPDATED) { ret = xqc_conn_encode_local_tp(conn, tp_buf, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); + XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|server encode tp error|ret:%d|", ret); goto err; @@ -949,6 +1310,142 @@ xqc_conn_server_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ return -TRA_INTERNAL_ERROR; } +#ifdef XQC_ENABLE_FEC +void +xqc_fec_conn_info_print(xqc_connection_t *conn, char *output, size_t output_size) +{ + int32_t i, ret; + size_t curr_size; + + i = ret = 0; + curr_size = 0; + xqc_memset(output, 0, output_size); + + if (conn->fec_ctl == NULL) { + goto full; + } + + /* fec info, must be ended with ',' */ + ret = snprintf(output, output_size, + "%u,%u,%u,%u,%u,%u,%u,%u,%u,%s,%s,%d,%"PRIu64",%"PRIu64"," + , + conn->conn_settings.fec_params.fec_encoder_scheme ? 1 : 0, + conn->conn_settings.fec_params.fec_decoder_scheme ? 1 : 0, + conn->fec_ctl->fec_processed_blk_num > 0 ? 1 : 0, + conn->fec_ctl->fec_recover_pkt_cnt, + conn->fec_ctl->fec_recover_failed_cnt, + conn->fec_ctl->fec_flush_blk_cnt, + conn->fec_ctl->fec_recv_repair_num_total, + conn->fec_neg_fail_reason, + conn->fec_ctl->fec_send_ahead, + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_encoder_scheme), + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_decoder_scheme), + conn->fec_ctl->fec_enable_stream_num, + conn->fec_ctl->conn_avg_recv_delay / 1000, + conn->fec_ctl->fec_avg_opt_time / 1000 + ); + + curr_size += ret; + + if (curr_size >= output_size) { + goto full; + } + +full: + curr_size = xqc_min(curr_size, output_size); + for (i = curr_size - 1; i >= 0; i--) { + if (output[i] == ',') { + output[i] = '\0'; + break; + } + } + output[output_size - 1] = '\0'; +} + +#endif +void +xqc_common_conn_info_print(xqc_connection_t *conn, char *output, size_t output_size) +{ + int32_t i, ret; + size_t curr_size;; + + i = ret = 0; + curr_size = 0; + xqc_memset(output, 0, output_size); + + /* common info, must be ended with ',' */ + ret = snprintf(output, output_size, + "%d,%"PRIu64",%"PRIu64",%"PRIu64",%d," + , + conn->conn_video_frames, + conn->conn_avg_close_delay / 1000, + conn->conn_avg_recv_delay / 1000, + conn->conn_latest_close_delay / 1000, + conn->burst_loss_cnt + ); + + curr_size += ret; + + if (curr_size >= output_size) { + goto full; + } + +full: + curr_size = xqc_min(curr_size, output_size); + for (i = curr_size - 1; i >= 0; i--) { + if (output[i] == ',') { + output[i] = '\0'; + break; + } + } + output[output_size - 1] = '\0'; +} + +void +xqc_extern_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) +{ + int32_t i, ret; + char *buff = conn_stats->extern_conn_info; + size_t curr_size, buff_size; + +#ifdef XQC_ENABLE_FEC + char fec_buf[XQC_MAX_FEC_BUF_LEN]; + xqc_fec_conn_info_print(conn, fec_buf, XQC_MAX_FEC_BUF_LEN); +#endif + + char common_buf[XQC_MAX_COMMON_BUF_LEN]; + xqc_common_conn_info_print(conn, common_buf, XQC_MAX_COMMON_BUF_LEN); + + i = ret = 0; + curr_size = 0; + buff_size = XQC_EXTERN_CONN_INFO_LEN; + + /* conn info */ + ret = snprintf(buff, buff_size, + "{" +#ifdef XQC_ENABLE_FEC + "\"fec\": \"%s\"," +#endif + "\"common\": \"%s\"," + "}" +#ifdef XQC_ENABLE_FEC + , + fec_buf +#endif + , + common_buf + ); + + curr_size += ret; + + if (curr_size >= buff_size) { + goto full; + } + +full: + curr_size = xqc_min(curr_size, buff_size); + buff[curr_size] = '\0'; +} void xqc_conn_destroy(xqc_connection_t *xc) @@ -964,11 +1461,28 @@ xqc_conn_destroy(xqc_connection_t *xc) if (xc->conn_flag & XQC_CONN_FLAG_TICKING) { xqc_log(xc->log, XQC_LOG_ERROR, "|in XQC_CONN_FLAG_TICKING|%p|", xc); xc->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(xc->log, CON_CONNECTION_STATE_UPDATED, xc); return; } + uint8_t fec_flag; xqc_conn_stats_t conn_stats; + xqc_fec_schemes_e ensch, desch; + unsigned char *ensch_str, *desch_str, *fec_mpm_str; + + fec_flag = 0; + ensch = xc->conn_settings.fec_params.fec_encoder_scheme; + desch = xc->conn_settings.fec_params.fec_decoder_scheme; + ensch_str = desch_str = fec_mpm_str = "NO_FEC"; + + xqc_memzero(&conn_stats, sizeof(xqc_conn_stats_t)); xqc_conn_get_stats_internal(xc, &conn_stats); +#ifdef XQC_ENABLE_FEC + fec_flag = 1; + ensch_str = xqc_get_fec_scheme_str(ensch); + desch_str = xqc_get_fec_scheme_str(desch); + fec_mpm_str = xqc_get_fec_mp_mode_str(xc->fec_ctl); +#endif if (xc->tls) { xqc_tls_get_selected_alpn(xc->tls, &out_alpn, &out_alpn_len); @@ -983,7 +1497,16 @@ xqc_conn_destroy(xqc_connection_t *xc) "has_0rtt:%d|0rtt_accept:%d|token_ok:%d|handshake_time:%ui|" "first_send_delay:%ui|conn_persist:%ui|keyupdate_cnt:%d|err:0x%xi|close_msg:%s|%s|" "hsk_recv:%ui|close_recv:%ui|close_send:%ui|last_recv:%ui|last_send:%ui|" - "mp_enable:%ud|create:%ud|validated:%ud|active:%ud|path_info:%s|alpn:%*s", + "mp_enable:%ud|create:%ud|validated:%ud|active:%ud|path_info:%s|alpn:%*s|rebind_count:%d|" + "rebind_valid:%d|rtx_pkt:%ud|tlp_pkt:%ud|" + "snd_pkt:%ud|spurious_loss:%ud|detected_loss:%ud|" + "max_pto:%ud|finished_streams:%ud|cli_bidi_s:%ud|svr_bidi_s:%ud|" + "fec_exist:%ud|" + "fec_ensch:%s|fec_desch:%s|fec_neg_fail:%ud|" + "fec_mp_mode:%s|send_fec_pkts:%ud|recovered_fec_num:%ud|" + "max_po_size:%uz|max_probing_size:%uz|ppo_size:%uz|" + "ext_conn_info:%s|max_acked_po_size:%uz|enable_pmtud:%ui|avg_closed_time:%ui|" + , xc, xc->conn_flag & XQC_CONN_FLAG_HAS_0RTT ? 1:0, xc->conn_flag & XQC_CONN_FLAG_0RTT_OK ? 1:0, @@ -991,20 +1514,28 @@ xqc_conn_destroy(xqc_connection_t *xc) (xc->handshake_complete_time > xc->conn_create_time) ? (xc->handshake_complete_time - xc->conn_create_time) : 0, (xc->first_data_send_time > xc->conn_create_time) ? (xc->first_data_send_time - xc->conn_create_time) : 0, xqc_monotonic_timestamp() - xc->conn_create_time, xc->key_update_ctx.key_update_cnt, - xc->conn_err, xc->conn_close_msg ? : "", xqc_conn_addr_str(xc), + xc->conn_err, xc->conn_close_msg ? xc->conn_close_msg : "", xqc_conn_addr_str(xc), xqc_calc_delay(xc->conn_hsk_recv_time, xc->conn_create_time), xqc_calc_delay(xc->conn_close_recv_time, xc->conn_create_time), xqc_calc_delay(xc->conn_close_send_time, xc->conn_create_time), xqc_calc_delay(xc->conn_last_recv_time, xc->conn_create_time), xqc_calc_delay(xc->conn_last_send_time, xc->conn_create_time), xc->enable_multipath, xc->create_path_count, xc->validated_path_count, xc->active_path_count, - conn_stats.conn_info, out_alpn_len, out_alpn); + conn_stats.conn_info, out_alpn_len, out_alpn, conn_stats.total_rebind_count, + conn_stats.total_rebind_valid, + conn_stats.lost_count, conn_stats.tlp_count, + conn_stats.send_count, conn_stats.spurious_loss_count, xc->detected_loss_cnt, + xc->max_pto_cnt, xc->finished_streams, xc->cli_bidi_streams, xc->svr_bidi_streams, + fec_flag, + ensch_str, desch_str, xc->fec_neg_fail_reason, + fec_mpm_str, conn_stats.send_fec_cnt, xc->fec_ctl ? xc->fec_ctl->fec_recover_pkt_cnt : 0, + xc->pkt_out_size, xc->max_pkt_out_size, xc->probing_pkt_out_size, + conn_stats.extern_conn_info, xc->max_acked_po_size, + xc->local_settings.enable_pmtud & xc->remote_settings.enable_pmtud, xc->conn_avg_close_delay + ); xqc_log_event(xc->log, CON_CONNECTION_CLOSED, xc); - if (xc->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP) { - xqc_wakeup_pq_remove(xc->engine->conns_wait_wakeup_pq, xc); - xc->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - } + xqc_engine_remove_wakeup_queue(xc->engine, xc); xqc_list_head_t *pos, *next; xqc_stream_t *stream; @@ -1055,7 +1586,11 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_timer_destroy_gp_timer_list(&xc->conn_timer_manager); xqc_send_queue_destroy(xc->conn_send_queue); - +#ifdef XQC_ENABLE_FEC + if (xc->fec_ctl) { + xqc_fec_ctl_destroy(xc->fec_ctl); + } +#endif /* free streams hash */ if (xc->streams_hash) { xqc_id_hash_release(xc->streams_hash); @@ -1100,6 +1635,10 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_log_release(xc->log); + if (xc->alpn) { + xqc_free(xc->alpn); + } + /* free pool, must be the last thing to do */ if (xc->conn_pool) { xqc_destroy_pool(xc->conn_pool); @@ -1144,22 +1683,80 @@ xqc_conn_get_local_addr(xqc_connection_t *conn, struct sockaddr *addr, socklen_t return XQC_OK; } +void +xqc_conn_encode_transport_state(xqc_connection_t *conn, char *buf, size_t buf_sz) +{ + xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; + xqc_send_ctl_t *send_ctl; + int ret, i; + size_t cursor; + uint64_t cwnd, inflight, sched_queue, pacing_rate, est_bw; + xqc_usec_t srtt_ms; + + cursor = 0; + + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + send_ctl = path->path_send_ctl; + if (path->path_state == XQC_PATH_STATE_ACTIVE) { + //KB + cwnd = send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong) >> 10; + //KBps + est_bw = xqc_send_ctl_get_est_bw(send_ctl) >> 10; + srtt_ms = send_ctl->ctl_srtt / 1000; + //KB + inflight = send_ctl->ctl_bytes_in_flight >> 10; + //KB + sched_queue = path->path_schedule_bytes >> 10; + //KBps + pacing_rate = xqc_send_ctl_get_pacing_rate(send_ctl) >> 10; + ret = snprintf(buf + cursor, buf_sz - cursor, + "(%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64"),", + path->path_id, cwnd, inflight, sched_queue, est_bw, pacing_rate, srtt_ms); + + cursor += ret; + + if (cursor >= buf_sz) { + break; + } + } + } + + cursor = xqc_min(cursor, buf_sz); + for (i = cursor - 1; i >= 0; i--) { + if (buf[i] == ',') { + buf[i] = '\0'; + break; + } + } + buf[buf_sz - 1] = '\0'; +} + xqc_int_t xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_data, xqc_bool_t notify) { - xqc_int_t ret = XQC_OK; + xqc_int_t ret; + xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; + xqc_bool_t has_ping; + xqc_ping_record_t *pr; + + ret = XQC_OK; if (conn->conn_state >= XQC_CONN_STATE_CLOSING) { return ret; } - if (conn->enable_multipath && conn->conn_settings.mp_ping_on) { + pr = xqc_conn_create_ping_record(conn); - xqc_path_ctx_t *path; - xqc_list_head_t *pos, *next; - xqc_bool_t has_ping = XQC_FALSE; - xqc_ping_record_t *pr = xqc_conn_create_ping_record(conn); + if (pr == NULL) { + return -XQC_EMALLOC; + } + + has_ping = XQC_FALSE; + if (conn->enable_multipath && conn->conn_settings.mp_ping_on) { xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); if (path->path_state == XQC_PATH_STATE_ACTIVE) { @@ -1173,19 +1770,21 @@ xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_data, xqc_bo } } - if (!has_ping) { - xqc_conn_destroy_ping_record(pr); - return ret; - } - } else { - ret = xqc_write_ping_to_packet(conn, NULL, ping_user_data, notify, NULL); + ret = xqc_write_ping_to_packet(conn, NULL, ping_user_data, notify, pr); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|write ping error|"); - return ret; + + } else { + has_ping = XQC_TRUE; } } + if (!has_ping) { + xqc_conn_destroy_ping_record(pr); + return ret; + } + return XQC_OK; } @@ -1198,7 +1797,7 @@ xqc_conn_send_ping(xqc_engine_t *engine, const xqc_cid_t *cid, void *ping_user_d conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } @@ -1207,13 +1806,10 @@ xqc_conn_send_ping(xqc_engine_t *engine, const xqc_cid_t *cid, void *ping_user_d return ret; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, conn); return XQC_OK; } @@ -1247,7 +1843,6 @@ xqc_conn_try_to_update_mss(xqc_connection_t *conn) xqc_list_head_t *pos, *next; size_t min_pkt_out_size = 0; size_t max_pkt_out_size = 0; - xqc_usec_t probing_interval = conn->conn_settings.pmtud_probing_interval; /* try to update conn MTU */ xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { @@ -1281,40 +1876,74 @@ xqc_conn_try_to_update_mss(xqc_connection_t *conn) ssize_t xqc_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, struct iovec *iov, int cnt) { - ssize_t sent = 0; + ssize_t sent_size = 0; + int sent_cnt = 0; + + if (conn->pkt_filter_cb) { + + for (sent_cnt = 0; sent_cnt < cnt; sent_cnt++) { + sent_size = conn->pkt_filter_cb(iov[sent_cnt].iov_base, + iov[sent_cnt].iov_len, + (struct sockaddr *)conn->peer_addr, + conn->peer_addrlen, + conn->pkt_filter_cb_user_data); + if (sent_size < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|pkt_filter_cb error|conn:%p|" + "size:%ud|sent:%z|sent_cnt:%d|", + conn, iov[sent_cnt].iov_len, sent_size, + sent_cnt); + + sent_size = sent_size == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; + break; + } + } - if (conn->transport_cbs.write_mmsg_ex) { - sent = conn->transport_cbs.write_mmsg_ex(path->path_id, iov, cnt, + if (sent_size == -XQC_EAGAIN && sent_cnt == 0) { + sent_cnt = -XQC_EAGAIN; + + } else if (sent_size == -XQC_ESOCKET) { + sent_cnt = -XQC_EPACKET_FILETER_CALLBACK; + } + + } else if (conn->transport_cbs.write_mmsg_ex) { + sent_cnt = conn->transport_cbs.write_mmsg_ex(path->path_id, iov, cnt, (struct sockaddr *)path->peer_addr, path->peer_addrlen, xqc_conn_get_user_data(conn)); - if (sent < 0) { + if (sent_cnt < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|error send mmsg|"); - if (sent == XQC_SOCKET_ERROR) { + if (sent_cnt == XQC_SOCKET_ERROR) { path->path_flag |= XQC_PATH_FLAG_SOCKET_ERROR; if (xqc_conn_should_close(conn, path)) { xqc_log(conn->log, XQC_LOG_ERROR, "|socket exception, close connection|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } } + + sent_cnt = sent_cnt == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } else { - sent = conn->transport_cbs.write_mmsg(iov, cnt, + sent_cnt = conn->transport_cbs.write_mmsg(iov, cnt, (struct sockaddr *)conn->peer_addr, conn->peer_addrlen, xqc_conn_get_user_data(conn)); - if (sent < 0) { + if (sent_cnt < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|error send mmsg|"); - if (sent == XQC_SOCKET_ERROR) { + if (sent_cnt == XQC_SOCKET_ERROR) { xqc_log(conn->log, XQC_LOG_ERROR, "|socket exception, close connection|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } + + sent_cnt = sent_cnt == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } - return sent; + return sent_cnt; } xqc_int_t @@ -1334,7 +1963,7 @@ xqc_check_acked_or_dropped_pkt(xqc_connection_t *conn, "|conn:%p|pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); return XQC_FALSE; } @@ -1345,30 +1974,30 @@ xqc_conn_schedule_packets(xqc_connection_t *conn, xqc_list_head_t *head, xqc_bool_t packets_are_limited_by_cc, xqc_send_type_t send_type) { ssize_t ret; - - xqc_list_head_t *pos, *next; + uint32_t send_repair_num, src_syb_num; + uint64_t stream_id; + xqc_bool_t cc_blocked, reset_rpr_timer; + xqc_usec_t now, cq_fin_timeout; xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; xqc_packet_out_t *packet_out; - xqc_bool_t cc_blocked; + xqc_stream_t *stream; + + now = xqc_monotonic_timestamp(); + reset_rpr_timer = 0; xqc_list_for_each_safe(pos, next, head) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - - /* 1. connection level not support schedule multipath */ - if (conn->enable_multipath == XQC_CONN_NOT_SUPPORT_MULTIPATH) { - path = conn->conn_initial_path; - - /* 2. 已设置特定路径发送的包,例如:PATH_CHALLENGE PATH_RESPONSE MP_ACK(原路径ACK) */ - } else if (xqc_packet_out_on_specific_path(conn, packet_out, &path)) { - + /* 1. 已设置特定路径发送的包,例如:PATH_CHALLENGE PATH_RESPONSE MP_ACK(原路径ACK) */ + if (xqc_packet_out_on_specific_path(conn, packet_out, &path)) { if (path == NULL) { continue; } xqc_log(conn->log, XQC_LOG_DEBUG, "|specify|path:%ui|state:%d|frame_type:%s|stream_id:%ui|stream_offset:%ui|", - path->path_id, path->path_state, xqc_frame_type_2_str(packet_out->po_frame_types), + path->path_id, path->path_state, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), packet_out->po_stream_id, packet_out->po_stream_offset); - /* 3. schedule packet multipath */ + /* 2. schedule packet multipath */ } else { path = conn->scheduler_callback-> xqc_scheduler_get_path(conn->scheduler, @@ -1378,13 +2007,44 @@ xqc_conn_schedule_packets(xqc_connection_t *conn, xqc_list_head_t *head, if (path == NULL) { if (cc_blocked) { conn->sched_cc_blocked++; + if (packet_out->po_sched_cwnd_blk_ts == 0) { + packet_out->po_sched_cwnd_blk_ts = now; + } + } + if (xqc_timer_is_set(&conn->conn_timer_manager, XQC_TIMER_QUEUE_FIN)) { + reset_rpr_timer = 1; } break; } } +#ifdef XQC_ENABLE_FEC + /* FEC encode packets */ + if (conn->conn_settings.enable_encode_fec + && conn->conn_settings.fec_params.fec_encoder_scheme + && !(packet_out->po_frame_types & XQC_FRAME_BIT_SID + || packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL)) + { + if (xqc_is_packet_fec_protected(conn, packet_out) == XQC_OK) { + xqc_process_fec_protected_packet(conn, packet_out); + /* if insert repair packet after current po, update next pointer; */ + next = pos->next; + reset_rpr_timer = 1; + } + } +#endif + xqc_path_send_buffer_append(path, packet_out, &path->path_schedule_buf[send_type]); } + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE + && send_type == XQC_SEND_TYPE_NORMAL + && reset_rpr_timer) + { + cq_fin_timeout = xqc_conn_get_queue_fin_timeout(conn); + if (cq_fin_timeout) { + xqc_timer_set(&conn->conn_timer_manager, XQC_TIMER_QUEUE_FIN, now, cq_fin_timeout * 1000); + } + } } static inline void @@ -1445,7 +2105,7 @@ xqc_on_packets_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, ssize_t "|<==|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), send_ctl->ctl_bytes_in_flight, now); } else { @@ -1505,7 +2165,7 @@ xqc_convert_pkt_0rtt_2_1rtt(xqc_connection_t *conn, xqc_packet_out_t *packet_out xqc_log(conn->log, XQC_LOG_DEBUG, "|0RTT to 1RTT|conn:%p|type:%d|pkt_num:%ui|pns:%d|frame:%s|", conn, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, packet_out->po_pkt.pkt_pns, - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); } @@ -1545,7 +2205,7 @@ xqc_path_send_burst_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, /* check cc limit */ if (congest - && !xqc_send_packet_check_cc(send_ctl, packet_out, total_bytes_to_send)) + && !xqc_send_packet_check_cc(send_ctl, packet_out, total_bytes_to_send, now)) { send_ctl->ctl_conn->send_cc_blocked++; break; @@ -1612,7 +2272,8 @@ xqc_path_send_packets_batch(xqc_connection_t *conn, xqc_path_ctx_t *path, } } - if (send_burst_count < 0) { + /* @FIXME: in the case of EAGAIN, we should not reschedule packets. */ + if (send_burst_count < 0 && send_burst_count != -XQC_EAGAIN) { xqc_path_send_buffer_clear(conn, path, head, send_type); } @@ -1655,6 +2316,8 @@ xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_send_ctl_t *send_ctl = path->path_send_ctl; xqc_send_queue_t *send_queue = conn->conn_send_queue; + xqc_usec_t now = xqc_monotonic_timestamp(); + xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[send_type]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); @@ -1673,7 +2336,7 @@ xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, /* check cc limit */ if (congest - && !xqc_send_packet_check_cc(send_ctl, packet_out, 0)) + && !xqc_send_packet_check_cc(send_ctl, packet_out, 0, now)) { send_ctl->ctl_conn->send_cc_blocked++; break; @@ -1707,12 +2370,14 @@ xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, } } - if (ret < 0) { + /* @FIXME: in the case of EAGAIN, we should not reschedule packets. */ + if (ret < 0 && ret != -XQC_EAGAIN) { xqc_path_send_buffer_clear(conn, path, head, send_type); } } + void xqc_conn_send_packets(xqc_connection_t *conn) { @@ -1788,6 +2453,7 @@ xqc_conn_enc_packet(xqc_connection_t *conn, xqc_gen_padding_frame(conn, packet_out); } + /* generate packet number and update packet length, might do packet number encoding here */ xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); packet_out->po_pkt.pkt_num = pn_ctl->ctl_packet_number[packet_out->po_pkt.pkt_pns]++; @@ -1803,6 +2469,7 @@ xqc_conn_enc_packet(xqc_connection_t *conn, if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|encrypt packet error|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return -XQC_EENCRYPT; } @@ -1823,7 +2490,8 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (sent < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|pkt_filter_cb error|conn:%p|" "size:%ud|sent:%z|", conn, len, sent); - return -XQC_EPACKET_FILETER_CALLBACK; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_EPACKET_FILETER_CALLBACK; } sent = len; @@ -1845,9 +2513,11 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (xqc_conn_should_close(conn, path)) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn:%p|socket exception, close connection|", conn); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } } - return -XQC_ESOCKET; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } else { @@ -1863,12 +2533,14 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (sent == XQC_SOCKET_ERROR) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn:%p|socket exception, close connection|", conn); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } - return -XQC_ESOCKET; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } - xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent); + xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent, path->path_id); return sent; } @@ -1881,10 +2553,9 @@ xqc_process_packet_without_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_ ssize_t sent = xqc_send(conn, path, packet_out->po_buf, packet_out->po_used_size); xqc_log(conn->log, XQC_LOG_INFO, "|<==|conn:%p|size:%ud|sent:%z|pkt_type:%s|", conn, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type)); - + xqc_log_event(conn->log, TRA_PACKET_SENT, conn, packet_out, path, 0, sent, 0); if (sent > 0) { xqc_conn_log_sent_packet(conn, packet_out, xqc_monotonic_timestamp()); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); } return sent; } @@ -1905,7 +2576,7 @@ xqc_send_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet "|write_socket error|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|now:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), now); return sent; } else { @@ -1913,8 +2584,8 @@ xqc_send_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet "|<==|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|stream_id:%ui|stream_offset:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now, packet_out->po_stream_id, packet_out->po_stream_offset); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now, packet_out->po_stream_id, packet_out->po_stream_offset); + xqc_log_event(conn->log, TRA_PACKET_SENT, conn, packet_out, path, now, sent, 1); } /* deliver packet to send control */ @@ -1961,6 +2632,7 @@ xqc_enc_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet_ if (xqc_packet_encrypt(conn, packet_out) < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|encrypt packet error|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return -XQC_EENCRYPT; } @@ -2211,11 +2883,12 @@ xqc_path_send_ping_to_probe(xqc_path_ctx_t *path, xqc_pkt_num_space_t pns, return XQC_OK; } -void +int xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, xqc_packet_out_t *packet_out) { xqc_reinjection_mode_t mode; + int reinject = 0; mode = c->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_BEFORE_SCHED; @@ -2224,7 +2897,7 @@ xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, packet_out->po_path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(c->engine, packet_out->po_frame_types), xqc_conn_state_2_str(c->conn_state)); /* reinjection */ @@ -2239,10 +2912,15 @@ xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(c->engine, packet_out->po_frame_types)); + reinject = 1; } } + if (packet_out->po_flag & XQC_POF_IN_FLIGHT) { + c->detected_loss_cnt++; + } + xqc_send_ctl_decrease_inflight(c, packet_out); xqc_send_queue_copy_to_probe(packet_out, c->conn_send_queue, path); @@ -2251,6 +2929,8 @@ xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, if (packet_out->po_frame_types & XQC_FRAME_BIT_DATAGRAM) { path->path_send_ctl->ctl_lost_dgram_cnt++; } + + return reinject; } void @@ -2266,7 +2946,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, xqc_list_head_t *sndq; xqc_int_t probe_num; xqc_bool_t send_hsd; - xqc_bool_t send_hsd_next; + int has_reinjection = 0; c = path->parent_conn; sndq = &c->conn_send_queue->sndq_unacked_packets[pns]; @@ -2275,7 +2955,6 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, shall send HANDSHAKE_DONE on PTO as it has not been acknowledged. */ probe_num = XQC_CONN_PTO_PKT_CNT_MAX; send_hsd = XQC_FALSE; - send_hsd_next = XQC_FALSE; packet_out_last_sent = NULL; packet_out_later_send = NULL; @@ -2283,9 +2962,11 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, xqc_log(c->log, XQC_LOG_DEBUG, "|send two ack-eliciting pkts" "|path:%ui|pns:%d|", path->path_id, pns); - /* if server's HANDSHAKE_DONE frame has not been acked, try to send it */ + /* if server's HANDSHAKE_DONE frame was sent and has not been acked, try to + send it */ if ((c->conn_type == XQC_CONN_TYPE_SERVER) - && !(c->conn_flag & XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED)) + && !(c->conn_flag & XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED) + && c->conn_flag & XQC_CONN_FLAG_HANDSHAKE_DONE_SENT) { send_hsd = XQC_TRUE; } @@ -2303,6 +2984,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, if (XQC_IS_ACK_ELICITING(packet_out->po_frame_types) && (XQC_NEED_REPAIR(packet_out->po_frame_types) + || (packet_out->po_flag & XQC_POF_NOTIFY) || (packet_out->po_frame_types & XQC_FRAME_BIT_DATAGRAM && c->conn_settings.datagram_force_retrans_on))) { @@ -2321,7 +3003,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, continue; } - xqc_conn_send_probe_pkt(c, path, packet_out); + has_reinjection = has_reinjection || xqc_conn_send_probe_pkt(c, path, packet_out); packet_out_last_sent = packet_out; if (--probe_num == 0) { @@ -2338,7 +3020,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, /* try to send the first ack-eliciting pkt do not contain HSK_DONE frame */ if (packet_out_later_send) { - xqc_conn_send_probe_pkt(c, path, packet_out_later_send); + has_reinjection = has_reinjection || xqc_conn_send_probe_pkt(c, path, packet_out_later_send); packet_out_last_sent = packet_out_later_send; packet_out_later_send = NULL; @@ -2357,7 +3039,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, while (probe_num > 0) { xqc_log(c->log, XQC_LOG_DEBUG, "|dup pkt on PTO, pkt_num:%ui|", packet_out_last_sent->po_pkt.pkt_num); - xqc_conn_send_probe_pkt(c, path, packet_out_last_sent); + has_reinjection = has_reinjection || xqc_conn_send_probe_pkt(c, path, packet_out_last_sent); probe_num--; } @@ -2370,6 +3052,15 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, } } } + + if (has_reinjection) { + xqc_path_ctx_t *path; + xqc_list_for_each_safe(pos, next, &c->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + xqc_list_splice_tail_init(&path->path_reinj_tmp_buf, + &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); + } + } } @@ -2403,12 +3094,12 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } xqc_log(conn->log, XQC_LOG_INFO, "|conn:%p|state:%s|flag:%s|", conn, - xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag)); XQC_CONN_CLOSE_MSG(conn, "local close"); @@ -2419,10 +3110,12 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) /* close connection after all data sent and acked or XQC_TIMER_LINGER_CLOSE timeout */ xqc_usec_t now = xqc_monotonic_timestamp(); xqc_usec_t pto = xqc_conn_get_max_pto(conn); + if (conn->conn_settings.linger.linger_on && !xqc_send_queue_out_queue_empty(conn->conn_send_queue)) { conn->conn_flag |= XQC_CONN_FLAG_LINGER_CLOSING; + xqc_usec_t linger_timeout = conn->conn_settings.linger.linger_timeout; xqc_timer_set(&conn->conn_timer_manager, XQC_TIMER_LINGER_CLOSE, now, - (conn->conn_settings.linger.linger_timeout ? : 3 * pto)); + (linger_timeout ? linger_timeout : 3 * pto)); goto end; } @@ -2433,13 +3126,10 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) } end: - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_wakeup_once(conn->engine); + xqc_engine_wakeup_once(engine); return XQC_OK; } @@ -2506,6 +3196,7 @@ xqc_conn_immediate_close(xqc_connection_t *conn) && conn->conn_type == XQC_CONN_TYPE_SERVER) { conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); xqc_conn_log(conn, XQC_LOG_ERROR, "|server cannot send CONNECTION_CLOSE before initial pkt received|"); return XQC_OK; } @@ -2516,8 +3207,9 @@ xqc_conn_immediate_close(xqc_connection_t *conn) /* convert state to CLOSING */ xqc_log(conn->log, XQC_LOG_INFO, "|state to closing|state:%s|flags:%s", xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); conn->conn_state = XQC_CONN_STATE_CLOSING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } /* @@ -2655,11 +3347,8 @@ xqc_conn_send_version_negotiation(xqc_connection_t *c) packet_out->po_used_size = p - packet_out->po_buf; /* push to conns queue */ - if (!(c->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(c->engine->conns_active_pq, c, c->last_ticked_time)) { - c->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(c->engine, c); + xqc_engine_add_active_queue(c->engine, c); c->conn_flag &= ~XQC_CONN_FLAG_VERSION_NEGOTIATION; return XQC_OK; @@ -2668,32 +3357,16 @@ xqc_conn_send_version_negotiation(xqc_connection_t *c) void xqc_conn_continue_send_by_conn(xqc_connection_t *conn) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); if (!conn) { - xqc_log(conn->engine->log, XQC_LOG_ERROR, "|can not find connection|conn:%p|", conn); - return ; + return; } - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - - xqc_conn_schedule_packets_to_paths(conn); - - if (xqc_engine_is_sendmmsg_on(conn->engine)) { - xqc_conn_transmit_pto_probe_packets_batch(conn); - xqc_conn_retransmit_lost_packets_batch(conn); - xqc_conn_send_packets_batch(conn); - } else { - xqc_conn_transmit_pto_probe_packets(conn); - xqc_conn_retransmit_lost_packets(conn); - xqc_conn_send_packets(conn); - } + xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - if (conn->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_AFTER_SEND) { - xqc_conn_reinject_unack_packets(conn, XQC_REINJ_UNACK_AFTER_SEND); - xqc_conn_send_packets(conn); - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } int @@ -2702,15 +3375,55 @@ xqc_conn_continue_send(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_connection_t *conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - xqc_engine_main_logic_internal(conn->engine); + xqc_conn_continue_send_by_conn(conn); return XQC_OK; } +void +xqc_conn_encode_mp_settings(xqc_connection_t *conn, char *buf, size_t buf_sz) +{ + size_t len = 0; + uint8_t encode_val = 0; + + if (buf_sz < XQC_MP_SETTINGS_STR_LEN) { + return; + } + + if (conn->enable_multipath) { + encode_val = 1; + } + //len: 1 + len = snprintf(buf, buf_sz, "%d", encode_val); + + encode_val = 0; + if (conn->local_settings.enable_multipath) { + encode_val = 1; + } + //len: 3 + len += snprintf(buf + len, buf_sz - len, "/%d", encode_val); + + encode_val = 0; + if (conn->remote_settings.enable_multipath) { + encode_val = 1; + } + //len: 5 + len += snprintf(buf + len, buf_sz - len, "/%d", encode_val); + + //len: 9 + encode_val = conn->local_settings.multipath_version; + len += snprintf(buf + len, buf_sz - len, "/%x", encode_val); + + //len: 13 + encode_val = conn->remote_settings.multipath_version; + len += snprintf(buf + len, buf_sz - len, "/%x", encode_val); + + buf[len] = 0; +} + void xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) { @@ -2718,41 +3431,22 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) size_t buff_size = XQC_CONN_INFO_LEN; size_t curr_size = 0; int ret = 0; - int record_cnt = 0; int i = 0; xqc_list_head_t *pos, *next; xqc_path_ctx_t *path = NULL; xqc_path_info_t path_info; - uint32_t mp_settings = 0; + char mp_settings[XQC_MP_SETTINGS_STR_LEN] = {0}; uint32_t sock_err_flag = 0; + uint32_t init_cwnd = 0; - if (conn->enable_multipath) { - mp_settings |= 1; - } - - if (conn->local_settings.enable_multipath) { - mp_settings |= (1 << 1); - } - - if (conn->remote_settings.enable_multipath) { - mp_settings |= (1 << 2); - } - - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 3); - } + xqc_conn_encode_mp_settings(conn, mp_settings, XQC_MP_SETTINGS_STR_LEN); - if (conn->local_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 4); - } - - if (conn->remote_settings.multipath_version == XQC_MULTIPATH_05) { - mp_settings |= (1 << 5); - } + init_cwnd = conn->conn_settings.cc_params.customize_on ? conn->conn_settings.cc_params.init_cwnd : 0; /* conn info */ - ret = snprintf(buff, buff_size, "%u,%u,%u,%u,%u,%u,%u," - "%u,%u,%u,%u,%u,%u,%u,%"PRIu64",%"PRIu64",%"PRIu64",", + ret = snprintf(buff, buff_size, "%s,%u,%u,%u,%u,%u,%u," + "%u,%u,%u,%u,%u,%u,%u,%"PRIu64",%"PRIu64",%"PRIu64",i%u," + , mp_settings, conn->create_path_count, conn->validated_path_count, @@ -2769,7 +3463,9 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) conn->rcv_pkt_stats.conn_udp_pkts, conn->stream_stats.send_bytes, conn->stream_stats.reinjected_bytes, - conn->stream_stats.recv_bytes); + conn->stream_stats.recv_bytes, + init_cwnd + ); curr_size += ret; @@ -2781,15 +3477,15 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) for (i = 0; i < 3; i++) { ret = snprintf(buff + curr_size, buff_size - curr_size, - "%u,%u,%u,%"PRIu64",%"PRIu64"," - "%"PRIu64",%"PRIu64",", + "%u,%u,%u,%"PRIx64",%"PRIu64"," + "%"PRIu64",%d,", (uint32_t)conn->rcv_pkt_stats.pkt_types[i], conn->rcv_pkt_stats.pkt_size[i], conn->rcv_pkt_stats.pkt_udp_size[i], (uint64_t)conn->rcv_pkt_stats.pkt_frames[i], (uint64_t)conn->rcv_pkt_stats.pkt_pn[i], (uint64_t)conn->rcv_pkt_stats.pkt_timestamp[i], - (uint64_t)conn->rcv_pkt_stats.pkt_err[i]); + conn->rcv_pkt_stats.pkt_err[i]); curr_size += ret; @@ -2801,7 +3497,7 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) /* send_stats */ for (i = 0; i < 3; i++) { ret = snprintf(buff + curr_size, buff_size - curr_size, - "%u,%u,%"PRIu64",%"PRIu64"," + "%u,%u,%"PRIx64",%"PRIu64"," "%"PRIu64",", (uint32_t)conn->snd_pkt_stats.pkt_types[i], conn->snd_pkt_stats.pkt_size[i], @@ -2831,13 +3527,14 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) "%d-%u,%d-%u," "%d-%u,%d-%u," "%d-%u,%d-%u," + "%d-%u,%d-%u," "%d-%u,%d-%u,", (int)path_info.path_id, path_info.path_state, (int)path_info.path_id, path_info.app_path_status, (int)path_info.path_id, sock_err_flag, (int)path_info.path_id, path_info.path_create_time, (int)path_info.path_id, path_info.path_destroy_time, - (int)path_info.path_id, path_info.srtt, + (int)path_info.path_id, path_info.srtt / 1000, (int)path_info.path_id, path_info.path_bytes_send, (int)path_info.path_id, path_info.path_bytes_recv, (int)path_info.path_id, path_info.pkt_send_cnt, @@ -2847,7 +3544,9 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) (int)path_info.path_id, path_info.dgram_send_cnt, (int)path_info.path_id, path_info.dgram_recv_cnt, (int)path_info.path_id, path_info.red_dgram_send_cnt, - (int)path_info.path_id, path_info.red_dgram_recv_cnt); + (int)path_info.path_id, path_info.red_dgram_recv_cnt, + (int)path_info.path_id, path->rebinding_count, + (int)path_info.path_id, path->rebinding_valid); curr_size += ret; @@ -2890,7 +3589,9 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats conn_stats->conn_err = (int)conn->conn_err; conn_stats->early_data_flag = XQC_0RTT_NONE; conn_stats->enable_multipath = conn->enable_multipath; + conn_stats->enable_fec = conn->conn_settings.fec_params.fec_encoder_scheme ? 1 : 0; conn_stats->spurious_loss_detect_on = conn->conn_settings.spurious_loss_detect_on; + conn_stats->max_acked_mtu = conn->max_acked_po_size; if (conn->conn_flag & XQC_CONN_FLAG_HAS_0RTT) { if (conn->conn_flag & XQC_CONN_FLAG_0RTT_OK) { conn_stats->early_data_flag = XQC_0RTT_ACCEPT; @@ -2905,7 +3606,7 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats && conn->conn_initial_path->path_send_ctl && conn->conn_initial_path->path_pn_ctl) { - if (conn_stats->min_rtt == XQC_MAX_UINT32_VALUE) { + if (conn->conn_initial_path->path_send_ctl->ctl_first_rtt_sample_time == 0) { conn_stats->srtt = 0; conn_stats->min_rtt = 0; @@ -2918,6 +3619,11 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats conn_stats->ack_info, sizeof(conn_stats->ack_info)); } + if (conn->fec_ctl) { + conn_stats->send_fec_cnt = conn->fec_ctl->fec_send_repair_num_total; + conn_stats->fec_recover_pkt_cnt = conn->fec_ctl->fec_recover_pkt_cnt; + } + /* 3. 遍历路径,获取各个路径count加和 */ xqc_list_head_t *pos, *next; @@ -2943,6 +3649,8 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats conn_stats->recv_count += send_ctl->ctl_recv_count; conn_stats->lost_dgram_count += send_ctl->ctl_lost_dgram_cnt; conn_stats->inflight_bytes += send_ctl->ctl_bytes_in_flight; + conn_stats->total_rebind_count += path->rebinding_count; + conn_stats->total_rebind_valid += path->rebinding_valid; } /* 路径信息 */ @@ -2950,6 +3658,8 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats /* 自定义信息 */ xqc_conn_info_print(conn, conn_stats); + + xqc_extern_conn_info_print(conn, conn_stats); } xqc_conn_stats_t @@ -2960,12 +3670,13 @@ xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_memzero(&conn_stats, sizeof(conn_stats)); for (int i = 0; i < XQC_MAX_PATHS_COUNT; ++i) { conn_stats.paths_info[i].path_id = XQC_MAX_UINT64_VALUE; + conn_stats.paths_info[i].path_app_status = 0; } conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return conn_stats; } @@ -2974,6 +3685,55 @@ xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid) return conn_stats; } +xqc_conn_qos_stats_t +xqc_conn_get_qos_stats(xqc_engine_t *engine, const xqc_cid_t *cid) +{ + xqc_connection_t *conn; + xqc_conn_qos_stats_t qos_stats; + xqc_memzero(&qos_stats, sizeof(qos_stats)); + + conn = xqc_engine_conns_hash_find(engine, cid, 's'); + if (!conn) { + xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", + xqc_scid_str(engine, cid)); + return qos_stats; + } + + /* 2. srtt 和 ack_info 使用主路信息 (TODO: 有问题,后续需要修改) */ + if (conn->conn_initial_path + && conn->conn_initial_path->path_send_ctl + && conn->conn_initial_path->path_pn_ctl) + { + if (conn->conn_initial_path->path_send_ctl->ctl_first_rtt_sample_time == 0) { + qos_stats.srtt = 0; + qos_stats.min_rtt = 0; + + } else { + qos_stats.srtt = conn->conn_initial_path->path_send_ctl->ctl_srtt; + qos_stats.min_rtt = conn->conn_initial_path->path_send_ctl->ctl_minrtt; + } + } + + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path = NULL; + xqc_send_ctl_t *send_ctl; + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + if (path == NULL) { + continue; + } + + send_ctl = path->path_send_ctl; + if (send_ctl == NULL) { + continue; + } + + qos_stats.inflight_bytes += send_ctl->ctl_bytes_in_flight; + } + + return qos_stats; +} + xqc_usec_t xqc_conn_get_lastest_rtt(xqc_engine_t *engine, const xqc_cid_t *cid) @@ -2984,14 +3744,14 @@ xqc_conn_get_lastest_rtt(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return 0; } path = conn->conn_initial_path; if (!path) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find initial path|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return 0; } @@ -3235,43 +3995,74 @@ xqc_conn_update_flow_ctl_settings(xqc_connection_t *conn) } xqc_int_t -xqc_conn_handshake_complete(xqc_connection_t *conn) +xqc_conn_add_path_cid_sets(xqc_connection_t *conn, uint32_t start, uint32_t end) { - xqc_int_t ret; + if (conn->enable_multipath) { + uint32_t path_id; + xqc_int_t ret; + /* add cid_set_inner for all paths */ + for (path_id = start; path_id <= end; path_id++) { + ret = xqc_cid_set_add_path(&conn->scid_set, path_id); + if (ret != XQC_OK) { + return ret; + } - xqc_list_head_t *pos, *next; - xqc_stream_t *stream; - xqc_multipath_version_t mp_version_ret; - /* update flow control */ - xqc_conn_update_flow_ctl_settings(conn); + ret = xqc_cid_set_add_path(&conn->dcid_set, path_id); + if (ret != XQC_OK) { + return ret; + } + } + } + return XQC_OK; +} - xqc_list_for_each_safe(pos, next, &conn->conn_all_streams) { - stream = xqc_list_entry(pos, xqc_stream_t, all_stream_list); - xqc_stream_update_flow_ctl(stream); +void +xqc_conn_try_to_enable_pmtud(xqc_connection_t *conn) +{ + uint64_t pmtud_check_bit = conn->conn_type == XQC_CONN_TYPE_SERVER ? 0x2 : 0x1; + xqc_usec_t now; + if (((conn->remote_settings.enable_pmtud & conn->local_settings.enable_pmtud) & pmtud_check_bit) != 0) { + conn->enable_pmtud = 1; + now = xqc_monotonic_timestamp(); + if (conn->enable_multipath) { + xqc_timer_set(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING, now, XQC_PMTUD_START_DELAY * 1000); + + } else { + xqc_timer_set(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING, now, 1); + } } +} + +xqc_int_t +xqc_conn_try_to_enable_multipath(xqc_connection_t *conn) +{ + xqc_int_t ret = XQC_OK; + uint64_t path_id = 0; /* determine multipath mode */ conn->enable_multipath = xqc_conn_enable_multipath(conn); - - if (!conn->enable_multipath - && xqc_timer_is_set(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING)) - { - conn->probing_cnt = 0; - conn->conn_flag |= XQC_CONN_FLAG_PMTUD_PROBING; - xqc_timer_unset(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING); - } - - mp_version_ret = xqc_conn_multipath_version_negotiation(conn); - if (mp_version_ret == XQC_ERR_MULTIPATH_VERSION) { + conn->conn_settings.multipath_version = xqc_conn_multipath_version_negotiation(conn); + if (conn->conn_settings.multipath_version == XQC_ERR_MULTIPATH_VERSION) { xqc_log(conn->log, XQC_LOG_WARN, "|multipath_version_negotiation err|"); conn->enable_multipath = 0; } - conn->conn_settings.multipath_version = mp_version_ret; if (conn->enable_multipath) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_SCID; + conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_MP_READY; } + return xqc_conn_add_path_cid_sets(conn, XQC_INITIAL_PATH_ID + 1, conn->curr_max_path_id); +} + +xqc_int_t +xqc_conn_handshake_complete(xqc_connection_t *conn) +{ + xqc_int_t ret; + + xqc_list_head_t *pos, *next; + xqc_stream_t *stream; + xqc_multipath_version_t mp_version_ret; + /* conn's handshake is complete when TLS stack has reported handshake complete */ conn->conn_flag |= XQC_CONN_FLAG_HANDSHAKE_COMPLETED; @@ -3384,13 +4175,10 @@ xqc_conn_process_undecrypt_packet_in(xqc_connection_t *conn, xqc_encrypt_level_t xqc_int_t ret; xqc_list_for_each_safe(pos, next, &conn->undecrypt_packet_in[encrypt_level]) { packet_in = xqc_list_entry(pos, xqc_packet_in_t, pi_list); + xqc_log_event(conn->log, TRA_DATAGRAMS_RECEIVED, packet_in->buf_size, packet_in->pi_path_id); xqc_log(conn->log, XQC_LOG_DEBUG, "|delay|undecrypt_count:%ud|encrypt_level:%d|", conn->undecrypt_count[encrypt_level], encrypt_level); -#ifdef XQC_NO_PID_PACKET_PROCESS - ret = xqc_conn_process_packet(conn, packet_in->buf, packet_in->buf_size, packet_in->pkt_recv_time); -#else - ret = xqc_conn_process_packet(conn, packet_in->buf, packet_in->buf_size, XQC_UNKNOWN_PATH_ID, packet_in->pkt_recv_time); -#endif + ret = xqc_conn_process_packet(conn, packet_in->buf, packet_in->buf_size, packet_in->pkt_recv_time); if (ret) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_packet_process error|ret:%d|", ret); return ret; @@ -3404,6 +4192,15 @@ xqc_conn_process_undecrypt_packet_in(xqc_connection_t *conn, xqc_encrypt_level_t return XQC_OK; } +void +xqc_conn_buff_1rtt_packet(xqc_connection_t *conn, xqc_packet_out_t *po) +{ + xqc_send_queue_remove_send(&po->po_list); + xqc_send_queue_insert_buff(&po->po_list, &conn->conn_send_queue->sndq_buff_1rtt_packets); + if (!(conn->conn_flag & XQC_CONN_FLAG_DCID_OK)) { + po->po_flag |= XQC_POF_DCID_NOT_DONE; + } +} void xqc_conn_buff_1rtt_packets(xqc_connection_t *conn) @@ -3495,54 +4292,54 @@ static char g_local_addr_str[INET6_ADDRSTRLEN]; static char g_peer_addr_str[INET6_ADDRSTRLEN]; char * -xqc_local_addr_str(const struct sockaddr *local_addr, socklen_t local_addrlen) +xqc_local_addr_str(xqc_engine_t *engine, const struct sockaddr *local_addr, socklen_t local_addrlen) { if (local_addrlen == 0 || local_addr == NULL) { - g_local_addr_str[0] = '\0'; - return g_local_addr_str; + engine->local_addr_str[0] = '\0'; + return engine->local_addr_str; } struct sockaddr_in *sa_local = (struct sockaddr_in *)local_addr; if (sa_local->sin_family == AF_INET) { - if (inet_ntop(sa_local->sin_family, &sa_local->sin_addr, g_local_addr_str, local_addrlen) == NULL) { - g_local_addr_str[0] = '\0'; + if (inet_ntop(sa_local->sin_family, &sa_local->sin_addr, engine->local_addr_str, local_addrlen) == NULL) { + engine->local_addr_str[0] = '\0'; } } else { if (inet_ntop(sa_local->sin_family, &((struct sockaddr_in6*)sa_local)->sin6_addr, - g_local_addr_str, local_addrlen) == NULL) + engine->local_addr_str, local_addrlen) == NULL) { - g_local_addr_str[0] = '\0'; + engine->local_addr_str[0] = '\0'; } } - return g_local_addr_str; + return engine->local_addr_str; } char * -xqc_peer_addr_str(const struct sockaddr *peer_addr, socklen_t peer_addrlen) +xqc_peer_addr_str(xqc_engine_t *engine, const struct sockaddr *peer_addr, socklen_t peer_addrlen) { if (peer_addrlen == 0 || peer_addr == NULL) { - g_peer_addr_str[0] = '\0'; - return g_peer_addr_str; + engine->peer_addr_str[0] = '\0'; + return engine->peer_addr_str; } struct sockaddr_in *sa_peer = (struct sockaddr_in *)peer_addr; if (sa_peer->sin_family == AF_INET) { - if (inet_ntop(sa_peer->sin_family, &sa_peer->sin_addr, g_peer_addr_str, peer_addrlen) == NULL) { - g_peer_addr_str[0] = '\0'; + if (inet_ntop(sa_peer->sin_family, &sa_peer->sin_addr, engine->peer_addr_str, peer_addrlen) == NULL) { + engine->peer_addr_str[0] = '\0'; } } else { if (inet_ntop(sa_peer->sin_family, &((struct sockaddr_in6*)sa_peer)->sin6_addr, - g_peer_addr_str, peer_addrlen) == NULL) + engine->peer_addr_str, peer_addrlen) == NULL) { - g_peer_addr_str[0] = '\0'; + engine->peer_addr_str[0] = '\0'; } } - return g_peer_addr_str; + return engine->peer_addr_str; } @@ -3560,10 +4357,10 @@ xqc_conn_addr_str(xqc_connection_t *conn) struct sockaddr_in *sa_peer = (struct sockaddr_in *)conn->peer_addr; conn->addr_str_len = snprintf(conn->addr_str, sizeof(conn->addr_str), "l-%s-%d-%s p-%s-%d-%s", - xqc_local_addr_str((struct sockaddr*)sa_local, conn->local_addrlen), - ntohs(sa_local->sin_port), xqc_scid_str(&conn->scid_set.user_scid), - xqc_peer_addr_str((struct sockaddr*)sa_peer, conn->peer_addrlen), - ntohs(sa_peer->sin_port), xqc_dcid_str(&conn->dcid_set.current_dcid)); + xqc_local_addr_str(conn->engine, (struct sockaddr*)sa_local, conn->local_addrlen), + ntohs(sa_local->sin_port), xqc_scid_str(conn->engine, &conn->scid_set.user_scid), + xqc_peer_addr_str(conn->engine, (struct sockaddr*)sa_peer, conn->peer_addrlen), + ntohs(sa_peer->sin_port), xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid)); } return conn->addr_str; @@ -3583,10 +4380,10 @@ xqc_path_addr_str(xqc_path_ctx_t *path) struct sockaddr_in *sa_peer = (struct sockaddr_in *)path->peer_addr; path->addr_str_len = snprintf(path->addr_str, sizeof(path->addr_str), "l-%s-%d-%s p-%s-%d-%s", - xqc_local_addr_str((struct sockaddr*)sa_local, path->local_addrlen), - ntohs(sa_local->sin_port), xqc_scid_str(&path->path_scid), - xqc_peer_addr_str((struct sockaddr*)sa_peer, path->peer_addrlen), - ntohs(sa_peer->sin_port), xqc_dcid_str(&path->path_dcid)); + xqc_local_addr_str(path->parent_conn->engine, (struct sockaddr*)sa_local, path->local_addrlen), + ntohs(sa_local->sin_port), xqc_scid_str(path->parent_conn->engine, &path->path_scid), + xqc_peer_addr_str(path->parent_conn->engine, (struct sockaddr*)sa_peer, path->peer_addrlen), + ntohs(sa_peer->sin_port), xqc_dcid_str(path->parent_conn->engine, &path->path_dcid)); } return path->addr_str; @@ -3602,7 +4399,6 @@ xqc_conn_record_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) xqc_path_ctx_t *path; if (c->enable_multipath) { - //TODO: MPQUIC fix migration path = xqc_conn_find_path_by_path_id(c, packet_in->pi_path_id); } else { @@ -3614,6 +4410,11 @@ xqc_conn_record_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) return; } + /* update path stats */ + if (packet_in->pi_frame_types & (XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_DATAGRAM)) { + path->path_send_ctl->ctl_app_bytes_recv += packet_in->buf_size; + } + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(c, path); xqc_send_ctl_t *send_ctl = path->path_send_ctl; @@ -3622,6 +4423,13 @@ xqc_conn_record_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) xqc_pkt_num_space_t pns = packet_in->pi_pkt.pkt_pns; xqc_packet_number_t pkt_num = packet_in->pi_pkt.pkt_num; + /* only recording the receive timestamp of pkt in app data space */ + if ((c->conn_settings.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) + && pns == XQC_PNS_APP_DATA) + { + xqc_recv_timestamps_info_add_pkt(path->recv_ts_info, pkt_num, packet_in->pkt_recv_time); + } + range_status = xqc_recv_record_add(&pn_ctl->ctl_recv_record[pns], pkt_num); if (range_status == XQC_PKTRANGE_OK) { if (XQC_IS_ACK_ELICITING(packet_in->pi_frame_types)) { @@ -3659,22 +4467,23 @@ xqc_conn_confirm_cid(xqc_connection_t *c, xqc_packet_t *pkt) if (!(c->conn_flag & XQC_CONN_FLAG_DCID_OK)) { - if (xqc_cid_in_cid_set(&c->dcid_set.cid_set, &pkt->pkt_scid) == NULL) { - ret = xqc_cid_set_insert_cid(&c->dcid_set.cid_set, &pkt->pkt_scid, XQC_CID_USED, - c->local_settings.active_connection_id_limit); + if (xqc_cid_in_cid_set(&c->dcid_set, &pkt->pkt_scid, XQC_INITIAL_PATH_ID) == NULL) { + ret = xqc_cid_set_insert_cid(&c->dcid_set, &pkt->pkt_scid, XQC_CID_USED, + c->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { xqc_log(c->log, XQC_LOG_ERROR, - "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|", + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", c->local_settings.active_connection_id_limit, - c->dcid_set.cid_set.unused_cnt, c->dcid_set.cid_set.used_cnt); + xqc_cid_set_get_unused_cnt(&c->dcid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&c->dcid_set, XQC_INITIAL_PATH_ID)); return ret; } } if (XQC_OK != xqc_cid_is_equal(&c->dcid_set.current_dcid, &pkt->pkt_scid)) { xqc_log(c->log, XQC_LOG_INFO, "|dcid change|ori:%s|new:%s|", - xqc_dcid_str(&c->dcid_set.current_dcid), xqc_scid_str(&pkt->pkt_scid)); - // TODO: DCID changes + xqc_dcid_str(c->engine, &c->dcid_set.current_dcid), xqc_scid_str(c->engine, &pkt->pkt_scid)); xqc_cid_copy(&c->dcid_set.current_dcid, &pkt->pkt_scid); xqc_cid_copy(&c->conn_initial_path->path_dcid, &pkt->pkt_scid); xqc_datagram_record_mss(c); @@ -3729,8 +4538,8 @@ xqc_conn_server_validate_address(xqc_connection_t *c, xqc_packet_in_t *pi) * client MAY send an Initial packet with PING/PADDING on PTO with server's CID */ if (c->scid_set.user_scid.cid_len >= XQC_CONN_ADDR_VALIDATION_CID_ENTROPY - && xqc_cid_in_cid_set(&c->scid_set.cid_set, &c->original_dcid) == NULL - && xqc_cid_in_cid_set(&c->scid_set.cid_set, &pi->pi_pkt.pkt_dcid) != NULL) + && xqc_cid_in_cid_set(&c->scid_set, &c->original_dcid, XQC_INITIAL_PATH_ID) == NULL + && xqc_cid_in_cid_set(&c->scid_set, &pi->pi_pkt.pkt_dcid, XQC_INITIAL_PATH_ID) != NULL) { xqc_conn_addr_validated(c); } @@ -3853,15 +4662,17 @@ xqc_conn_on_pkt_processed(xqc_connection_t *c, xqc_packet_in_t *pi, xqc_usec_t n /* record packet */ xqc_conn_record_single(c, pi); - if (pi->pi_frame_types & (~(XQC_FRAME_BIT_STREAM|XQC_FRAME_BIT_DATAGRAM|XQC_FRAME_BIT_PADDING))) { + if (pi->pi_frame_types & (~(XQC_FRAME_BIT_STREAM|XQC_FRAME_BIT_DATAGRAM|XQC_FRAME_BIT_PADDING|XQC_FRAME_BIT_SID|XQC_FRAME_BIT_REPAIR_SYMBOL))) { c->conn_flag |= XQC_CONN_FLAG_NEED_RUN; } c->conn_last_recv_time = now; - xqc_log(c->log, XQC_LOG_INFO, "|====>|conn:%p|path:%ui|size:%uz|pkt_type:%s|pkt_num:%ui|frame:%s|recv_time:%ui|", + xqc_log(c->log, XQC_LOG_INFO, "|====>|conn:%p|path:%ui|size:%uz|pkt_type:%s|pkt_num:%ui|frame:%s|recv_time:%ui|dcid:%s|dcid_seq:%ui|", c, pi->pi_path_id, pi->buf_size, xqc_pkt_type_2_str(pi->pi_pkt.pkt_type), pi->pi_pkt.pkt_num, - xqc_frame_type_2_str(pi->pi_frame_types), pi->pkt_recv_time); + xqc_frame_type_2_str(c->engine, pi->pi_frame_types), pi->pkt_recv_time, + xqc_dcid_str(c->engine, &pi->pi_pkt.pkt_dcid), + pi->pi_pkt.pkt_dcid.cid_seq_num); return ret; } @@ -3896,17 +4707,11 @@ xqc_conn_log_recvd_packet(xqc_connection_t *c, xqc_packet_in_t *pi, c->rcv_pkt_stats.curr_index = (index + 1) % 3; } -#ifdef XQC_NO_PID_PACKET_PROCESS + xqc_int_t xqc_conn_process_packet(xqc_connection_t *c, const unsigned char *packet_in_buf, size_t packet_in_size, xqc_usec_t recv_time) -#else -xqc_int_t -xqc_conn_process_packet(xqc_connection_t *c, - const unsigned char *packet_in_buf, size_t packet_in_size, - uint64_t path_id, xqc_usec_t recv_time) -#endif { xqc_int_t ret = XQC_OK; const unsigned char *last_pos = NULL; @@ -3923,11 +4728,8 @@ xqc_conn_process_packet(xqc_connection_t *c, xqc_packet_in_t *packet_in = &packet; memset(packet_in, 0, sizeof(*packet_in)); xqc_packet_in_init(packet_in, pos, end - pos, decrypt_payload, XQC_MAX_PACKET_IN_LEN, recv_time); -#ifndef XQC_NO_PID_PACKET_PROCESS - packet_in->pi_path_id = path_id; -#else + packet_in->pi_path_id = XQC_UNKNOWN_PATH_ID; -#endif /* packet_in->pos will update inside */ ret = xqc_packet_process_single(c, packet_in); @@ -3961,30 +4763,21 @@ xqc_conn_process_packet(xqc_connection_t *c, return ret; } -#ifdef XQC_NO_PID_PACKET_PROCESS + void xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid, size_t packet_in_size, xqc_usec_t recv_time) -#else -void -xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid, - uint64_t path_id, size_t packet_in_size, xqc_usec_t recv_time) -#endif { xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { path = xqc_conn_find_path_by_scid(conn, scid); -#ifndef XQC_NO_PID_PACKET_PROCESS - if (path == NULL && path_id != XQC_UNKNOWN_PATH_ID) { - path = xqc_conn_find_path_by_path_id(conn, path_id); - } -#endif + } else { path = conn->conn_initial_path; } if (path == NULL) { - xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|scid:%s|", xqc_scid_str(scid)); + xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|scid:%s|", xqc_scid_str(conn->engine, scid)); return; } @@ -4031,24 +4824,38 @@ xqc_conn_check_handshake_complete(xqc_connection_t *conn) } -/* should have at lease one unused dcid & one unused scid */ xqc_int_t -xqc_conn_check_unused_cids(xqc_connection_t *conn) +xqc_conn_get_available_path_id(xqc_connection_t *conn, uint64_t *path_id) { - if (conn->dcid_set.cid_set.unused_cnt == 0 || conn->scid_set.cid_set.unused_cnt == 0) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|don't have available unused cid|%ui|%ui|", - conn->dcid_set.cid_set.unused_cnt, conn->scid_set.cid_set.unused_cnt); - return -XQC_EMP_NO_AVAIL_PATH_ID; + if (conn->enable_multipath + && conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) + { + /* principle: the next unused path ID has at least one unused DCID and one acked unused SCID */ + xqc_cid_set_inner_t *scid_inner_set = xqc_get_next_unused_path_cid_set(&conn->scid_set); + if (scid_inner_set) { + xqc_cid_set_inner_t *dcid_inner_set = xqc_get_path_cid_set(&conn->dcid_set, scid_inner_set->path_id); + if (dcid_inner_set) { + if (dcid_inner_set->unused_cnt > 0 && scid_inner_set->acked_unused > 0) { + if (path_id) { + *path_id = scid_inner_set->path_id; + } + return XQC_OK; + } + } + + } } - return XQC_OK; + + return -XQC_EMP_NO_AVAIL_PATH_ID; } - void xqc_conn_destroy_cids(xqc_connection_t *conn) { xqc_cid_inner_t *cid = NULL; xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set = NULL; + xqc_list_head_t *pos_set, *next_set; if (conn->engine->conns_hash) { if (xqc_find_conns_hash(conn->engine->conns_hash, conn, @@ -4059,69 +4866,111 @@ xqc_conn_destroy_cids(xqc_connection_t *conn) conn->original_dcid.cid_buf, conn->original_dcid.cid_len); } + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); - xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - if (xqc_find_conns_hash(conn->engine->conns_hash, conn, - cid->cid.cid_buf, cid->cid.cid_len)) - { - xqc_remove_conns_hash(conn->engine->conns_hash, conn, - cid->cid.cid_buf, cid->cid.cid_len); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (xqc_find_conns_hash(conn->engine->conns_hash, conn, + cid->cid.cid_buf, cid->cid.cid_len)) + { + xqc_remove_conns_hash(conn->engine->conns_hash, conn, + cid->cid.cid_buf, cid->cid.cid_len); + } } } } - if (conn->engine->conns_hash_dcid && (conn->conn_flag & XQC_CONN_FLAG_DCID_OK)) { - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { + xqc_list_for_each_safe(pos_set, next_set, &conn->dcid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (conn->engine->conns_hash_dcid) { + /* delete relationship from conns_hash_dcid */ + if (xqc_find_conns_hash(conn->engine->conns_hash_dcid, conn, + cid->cid.cid_buf, cid->cid.cid_len)) + { + xqc_remove_conns_hash(conn->engine->conns_hash_dcid, conn, + cid->cid.cid_buf, cid->cid.cid_len); + } - /* delete relationship from conns_hash_dcid */ - if (xqc_find_conns_hash(conn->engine->conns_hash_dcid, conn, - cid->cid.cid_buf, cid->cid.cid_len)) - { - xqc_remove_conns_hash(conn->engine->conns_hash_dcid, conn, - cid->cid.cid_buf, cid->cid.cid_len); } - - /* delete relationship from conns_hash_sr_token */ - if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, - cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN)) - { - xqc_remove_conns_hash(conn->engine->conns_hash_sr_token, conn, - cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN); + if (conn->engine->conns_hash_sr_token) { + /* delete relationship from conns_hash_sr_token */ + if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN)) + { + xqc_remove_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + } } } } - xqc_destroy_cid_set(&conn->scid_set.cid_set); - xqc_destroy_cid_set(&conn->dcid_set.cid_set); + xqc_destroy_cid_set(&conn->scid_set); + xqc_destroy_cid_set(&conn->dcid_set); } - xqc_int_t xqc_conn_try_add_new_conn_id(xqc_connection_t *conn, uint64_t retire_prior_to) { - uint64_t active_cid_cnt = conn->scid_set.cid_set.unused_cnt + conn->scid_set.cid_set.used_cnt; -#ifdef XQC_NO_PID_PACKET_PROCESS - uint64_t unused_limit = 1; -#else - uint64_t unused_limit = conn->enable_multipath ? 2 : 1; - if (conn->enable_multipath) { - unused_limit = xqc_max(unused_limit, conn->conn_settings.least_available_cid_count); - } -#endif + xqc_int_t ret = XQC_OK; + uint8_t unused_limit = 2; + xqc_cid_set_inner_t *inner_set; + if (xqc_conn_is_handshake_confirmed(conn)) { - while (active_cid_cnt < conn->remote_settings.active_connection_id_limit - && conn->scid_set.cid_set.unused_cnt < unused_limit) + if (conn->enable_multipath && conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { - xqc_int_t ret = xqc_write_new_conn_id_frame_to_packet(conn, retire_prior_to); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_conn_id_frame_to_packet error|"); - return ret; + /* principle #1 there are two CIDs for the next path ID */ + inner_set = xqc_get_next_unused_path_cid_set(&conn->scid_set); + while (inner_set + && (inner_set->unused_cnt + inner_set->used_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_mp_new_conn_id_frame_to_packet(conn, retire_prior_to, inner_set->path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_write_mp_new_conn_id_frame_to_packet error|path_id:%ui|", + inner_set->path_id); + return ret; + } + } + + /* principle #2 there are two CIDs for every in-use path ID */ + xqc_list_head_t *pos, *next; + xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (inner_set->set_state == XQC_CID_SET_USED) { + while (inner_set + && (inner_set->unused_cnt + inner_set->used_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_mp_new_conn_id_frame_to_packet(conn, retire_prior_to, inner_set->path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_write_mp_new_conn_id_frame_to_packet error|path_id:%ui|", + inner_set->path_id); + return ret; + } + } + } + } + + } else { + + inner_set = xqc_get_path_cid_set(&conn->scid_set, XQC_INITIAL_PATH_ID); + /* origin logic for new connection id */ + while ((inner_set->used_cnt + inner_set->unused_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_new_conn_id_frame_to_packet(conn, retire_prior_to); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_conn_id_frame_to_packet error|"); + return ret; + } } - active_cid_cnt++; } } @@ -4170,11 +5019,13 @@ xqc_conn_ptmud_probing(xqc_connection_t *conn) /* stop probing if the range is less than 10B */ if ((conn->max_pkt_out_size - conn->pkt_out_size) < 10) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|stop pmtud probing|max:%z|curr:%z|", - conn->max_pkt_out_size, conn->pkt_out_size); + xqc_log_event(conn->log, CON_MTU_UPDATED, conn, 1); conn->conn_flag &= ~XQC_CONN_FLAG_PMTUD_PROBING; return; } + xqc_log_event(conn->log, CON_MTU_UPDATED, conn, 0); + conn->MTU_updated_count ++; + size_t probing_size = conn->probing_pkt_out_size; xqc_list_head_t *pos, *next; @@ -4251,16 +5102,16 @@ xqc_conn_check_dcid(xqc_connection_t *conn, xqc_cid_t *dcid) { xqc_int_t ret; - xqc_cid_inner_t *scid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, dcid); + xqc_cid_inner_t *scid = xqc_cid_set_search_cid(&conn->scid_set, dcid); if (scid == NULL) { return -XQC_ECONN_CID_NOT_FOUND; } if (scid->state == XQC_CID_UNUSED) { - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, scid, XQC_CID_USED); + ret = xqc_cid_switch_to_next_state(&conn->scid_set, scid, XQC_CID_USED, scid->cid.path_id); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|scid:%s|", - xqc_scid_str(&scid->cid)); + xqc_scid_str(conn->engine, &scid->cid)); return ret; } } @@ -4273,7 +5124,7 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) { xqc_int_t ret = XQC_OK; - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, inner_cid, XQC_CID_RETIRED); + ret = xqc_cid_switch_to_next_state(&conn->scid_set, inner_cid, XQC_CID_RETIRED, inner_cid->cid.path_id); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|set cid retired error|"); return ret; @@ -4281,7 +5132,7 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) xqc_log(conn->log, XQC_LOG_DEBUG, "|retired|cid:%s|seq:%ui|len:%d|", - xqc_scid_str(&inner_cid->cid), + xqc_scid_str(conn->engine, &inner_cid->cid), inner_cid->cid.cid_seq_num, inner_cid->cid.cid_len); @@ -4301,26 +5152,32 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) /* switch another used scid to replace user_scid */ xqc_int_t -xqc_conn_update_user_scid(xqc_connection_t *conn, xqc_scid_set_t *scid_set) +xqc_conn_update_user_scid(xqc_connection_t *conn) { xqc_cid_inner_t *scid; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &scid_set->cid_set.list_head) { - scid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; - if (scid->state == XQC_CID_USED - && xqc_cid_is_equal(&scid_set->user_scid, &scid->cid) != XQC_OK) - { - if (conn->transport_cbs.conn_update_cid_notify) { - conn->transport_cbs.conn_update_cid_notify(conn, &scid_set->user_scid, &scid->cid, - xqc_conn_get_user_data(conn)); - } + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + scid = xqc_list_entry(pos, xqc_cid_inner_t, list); - // TODO: SCID changes - xqc_cid_copy(&scid_set->user_scid, &scid->cid); - xqc_datagram_record_mss(conn); - return XQC_OK; + if (scid->state == XQC_CID_USED + && xqc_cid_is_equal(&conn->scid_set.user_scid, &scid->cid) != XQC_OK) + { + if (conn->transport_cbs.conn_update_cid_notify) { + conn->transport_cbs.conn_update_cid_notify(conn, &conn->scid_set.user_scid, &scid->cid, + xqc_conn_get_user_data(conn)); + } + + xqc_cid_copy(&conn->scid_set.user_scid, &scid->cid); + xqc_datagram_record_mss(conn); + return XQC_OK; + } } } @@ -4414,7 +5271,7 @@ xqc_conn_reassemble_packet(xqc_connection_t *conn, xqc_packet_out_t *ori_po) xqc_log(conn->log, XQC_LOG_DEBUG, "|pkt_num:%ui|ptype:%d|frames:%s|", new_po->po_pkt.pkt_num, new_po->po_pkt.pkt_type, - xqc_frame_type_2_str(new_po->po_frame_types)); + xqc_frame_type_2_str(conn->engine, new_po->po_frame_types)); return XQC_OK; } @@ -4468,7 +5325,6 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) conn->conn_flag |= XQC_CONN_FLAG_RETRY_RECVD; /* change the DCID it uses for sending packets in response to Retry packet. */ - // TODO: DCID changes xqc_cid_copy(&conn->dcid_set.current_dcid, retry_scid); xqc_datagram_record_mss(conn); @@ -4477,7 +5333,7 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_tls_reset_initial error|retry_scid:%s|ret:%d|", - xqc_scid_str(retry_scid), ret); + xqc_scid_str(conn->engine, retry_scid), ret); return ret; } @@ -4559,7 +5415,50 @@ xqc_conn_set_remote_transport_params(xqc_connection_t *conn, settings->enable_multipath = params->enable_multipath; settings->multipath_version = params->multipath_version; + settings->init_max_path_id = params->init_max_path_id; settings->max_datagram_frame_size = params->max_datagram_frame_size; + settings->close_dgram_redundancy = params->close_dgram_redundancy; + settings->enable_pmtud = params->enable_pmtud; + +#ifdef XQC_ENABLE_FEC + /* + * set fec params to remote_settings + */ + + settings->fec_version = params->fec_version; + if (params->fec_version != XQC_ERR_FEC_VERSION) { + + // if current host enable fec encode, set decoder params of remote settings + if (conn->conn_settings.enable_encode_fec) { + settings->enable_decode_fec = params->enable_decode_fec; + settings->fec_decoder_schemes_num = params->fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_decoder_schemes_num; i++) { + settings->fec_decoder_schemes[i] = params->fec_decoder_schemes[i]; + } + } + // if current host enable fec decode, set encoder params of remote settings + if (conn->conn_settings.enable_decode_fec) { + settings->enable_encode_fec = params->enable_encode_fec; + settings->fec_max_symbols_num = params->fec_max_symbols_num; + settings->fec_encoder_schemes_num = params->fec_encoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_encoder_schemes_num; i++) { + settings->fec_encoder_schemes[i] = params->fec_encoder_schemes[i]; + } + } + } else { + settings->enable_encode_fec = 0; + settings->enable_decode_fec = 0; + } +#endif + + settings->extended_ack_features = params->extended_ack_features; + settings->max_receive_timestamps_per_ack = params->max_receive_timestamps_per_ack; + settings->receive_timestamps_exponent = params->receive_timestamps_exponent; + + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && settings->max_udp_payload_size >= XQC_PACKET_OUT_SIZE) { + conn->pkt_out_size = xqc_min(conn->pkt_out_size, settings->max_udp_payload_size - XQC_PACKET_OUT_EXT_SPACE); + } return XQC_OK; } @@ -4596,8 +5495,31 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->no_crypto = settings->no_crypto; params->enable_multipath = settings->enable_multipath; params->multipath_version = settings->multipath_version; + params->init_max_path_id = settings->init_max_path_id; params->max_datagram_frame_size = settings->max_datagram_frame_size; + params->enable_pmtud = settings->enable_pmtud; + params->close_dgram_redundancy = settings->close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + if (conn->conn_settings.enable_encode_fec) { + params->enable_encode_fec = settings->enable_encode_fec; + params->fec_max_symbols_num = settings->fec_max_symbols_num; + params->fec_encoder_schemes_num = settings->fec_encoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_encoder_schemes_num; i++) { + params->fec_encoder_schemes[i] = settings->fec_encoder_schemes[i]; + } + } + if (conn->conn_settings.enable_decode_fec) { + params->enable_decode_fec = settings->enable_decode_fec; + params->fec_decoder_schemes_num = settings->fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_decoder_schemes_num; i++) { + params->fec_decoder_schemes[i] = settings->fec_decoder_schemes[i]; + } + } + +#endif + /* set other transport parameters */ if (conn->conn_type == XQC_CONN_TYPE_SERVER && conn->original_dcid.cid_len > 0) @@ -4614,8 +5536,8 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->stateless_reset_token_present = 1; xqc_log(conn->log, XQC_LOG_INFO, "|generate sr_token[%s] for cid[%s]", - xqc_sr_token_str(params->stateless_reset_token), - xqc_scid_str(&conn->original_dcid)); + xqc_sr_token_str(conn->engine, params->stateless_reset_token), + xqc_scid_str(conn->engine, &conn->original_dcid)); } else { params->original_dest_connection_id_present = 0; @@ -4628,6 +5550,14 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->retry_source_connection_id.cid_len = 0; params->retry_source_connection_id_present = 0; + params->conn_option_num = settings->conn_option_num; + xqc_memcpy(params->conn_options, settings->conn_options, + sizeof(uint32_t) * settings->conn_option_num); + + params->extended_ack_features = settings->extended_ack_features; + params->max_receive_timestamps_per_ack = settings->max_receive_timestamps_per_ack; + params->receive_timestamps_exponent = settings->receive_timestamps_exponent; + return XQC_OK; } @@ -4670,14 +5600,52 @@ xqc_conn_check_transport_params(xqc_connection_t *conn, const xqc_transport_para return XQC_OK; } +void +xqc_update_neg_info(xqc_connection_t *conn, xqc_transport_params_t params) +{ + xqc_trans_settings_t *ls = &conn->local_settings; + if (!ls->enable_encode_fec) { + conn->fec_neg_fail_reason |= XQC_LOCAL_NOT_SUPPORT_ENC; + } + if (!ls->enable_decode_fec) { + conn->fec_neg_fail_reason |= XQC_LOCAL_NOT_SUPPORT_DEC; + } + if (!params.enable_encode_fec) { + conn->fec_neg_fail_reason |= XQC_REMOTE_NOT_SUPPORT_ENC; + } + if (!params.enable_decode_fec) { + conn->fec_neg_fail_reason |= XQC_REMOTE_NOT_SUPPORT_DEC; + } +} + +void +xqc_check_fec_trans_param(xqc_connection_t *conn, xqc_transport_params_t params) +{ + if (params.enable_encode_fec) { + if (params.fec_max_symbols_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + conn->conn_settings.enable_decode_fec = 0; + conn->local_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_REMOTE_PARAM_ERR; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|remote_setting's max_symbol_number is too large to be decoded"); + } + if (params.fec_max_symbols_num == 0) { + conn->conn_settings.enable_decode_fec = 0; + conn->local_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_REMOTE_PARAM_ERR; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|remote_setting's max_symbol_number is zero"); + } + } +} + void xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) { - xqc_int_t ret; - xqc_transport_params_t params; - xqc_list_head_t *node; - xqc_cid_inner_t *cid_node; + xqc_int_t ret, re_encode_local_tp_flag = 0; xqc_cid_t *cid; + xqc_list_head_t *node, *pos, *next; + xqc_cid_inner_t *cid_node; + xqc_transport_params_t params; + xqc_stream_t *stream; xqc_connection_t *conn = (xqc_connection_t *)user_data; xqc_transport_params_type_t tp_type = (conn->conn_type == XQC_CONN_TYPE_CLIENT @@ -4719,6 +5687,16 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) xqc_log(conn->log, XQC_LOG_DEBUG, "|1RTT_transport_params|max_datagram_frame_size:%ud|", conn->remote_settings.max_datagram_frame_size); + if ((conn->local_settings.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) + && (conn->remote_settings.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) + && conn->remote_settings.max_receive_timestamps_per_ack > 0) + { + conn->conn_settings.extended_ack_features = 2; + conn->conn_settings.max_receive_timestamps_per_ack = + conn->remote_settings.max_receive_timestamps_per_ack; + conn->conn_settings.receive_timestamps_exponent = + conn->remote_settings.receive_timestamps_exponent; + } /* save no crypto flag */ if (params.no_crypto == 1) { @@ -4733,22 +5711,29 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) if (params.stateless_reset_token_present) { /* it is supposed to be only one existing cid in the dcid set, find the first node and copy the sr token to that cid */ - node = conn->dcid_set.cid_set.list_head.next; + xqc_cid_set_inner_t *inner_set = xqc_get_path_cid_set(&conn->dcid_set, XQC_INITIAL_PATH_ID); + node = inner_set->cid_list.next; if (NULL != node) { cid_node = xqc_list_entry(node, xqc_cid_inner_t, list); xqc_memcpy(cid_node->cid.sr_token, params.stateless_reset_token, XQC_STATELESS_RESET_TOKENLEN); xqc_log(conn->log, XQC_LOG_INFO, "|store sr_token with cid: %s" - "|token:%s", xqc_dcid_str(&cid_node->cid), - xqc_sr_token_str(params.stateless_reset_token)); - + "|token:%s", xqc_dcid_str(conn->engine, &cid_node->cid), + xqc_sr_token_str(conn->engine, params.stateless_reset_token)); - if (xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, - cid_node->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN)) + if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid_node->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN) == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|insert sr conn hash error"); + if (xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid_node->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN)) + { + xqc_log(conn->log, XQC_LOG_ERROR, "|insert sr conn hash error"); + } + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|sr_token conflict:%s", xqc_sr_token_str(conn->engine, cid_node->cid.sr_token)); } } else { @@ -4762,9 +5747,75 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) && params.multipath_version != conn->local_settings.multipath_version && xqc_conn_is_current_mp_version_supported(params.multipath_version) == XQC_OK) { + conn->local_settings.multipath_version = params.multipath_version; + re_encode_local_tp_flag = 1; + } + + ret = xqc_conn_try_to_enable_multipath(conn); + if(ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|enable multipath error|ret:%d|", ret); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return; + } + + /* must be called after xqc_conn_try_to_enable_multipath */ + xqc_conn_try_to_enable_pmtud(conn); + + /* update flow control */ + xqc_conn_update_flow_ctl_settings(conn); + + xqc_list_for_each_safe(pos, next, &conn->conn_all_streams) { + stream = xqc_list_entry(pos, xqc_stream_t, all_stream_list); + xqc_stream_update_flow_ctl(stream); + } + + /** Negotiate on whether send datagram redundancy on 1RTT packet; + * on XQC_RED_NOT_USE(default): + * No need to negotiate, and whether to send redundancy is + * completely decided by server's config; + * on XQC_RED_SET_CLOSE: + * The client's signal to close datagram redundancy, thus stop + * sending dgram redundancy. + * + */ + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && params.close_dgram_redundancy != XQC_RED_NOT_USE) + { + if (params.close_dgram_redundancy == XQC_RED_SET_CLOSE) { + conn->local_settings.close_dgram_redundancy = XQC_RED_SET_CLOSE; + conn->conn_settings.datagram_redundancy = 0; + } + re_encode_local_tp_flag = 1; + } + + if (conn->local_settings.close_dgram_redundancy == XQC_RED_SET_CLOSE) { + conn->conn_settings.mp_enable_reinjection = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|stop sending datagram redundancy."); + } + + +#ifdef XQC_ENABLE_FEC + xqc_update_neg_info(conn, params); + if (conn->conn_settings.enable_encode_fec + || conn->conn_settings.enable_decode_fec) + { + // update fec settings according to remote params + xqc_check_fec_trans_param(conn, params); + ret = xqc_negotiate_fec_schemes(conn, params); + if (ret == XQC_OK) { + xqc_on_fec_negotiate_success(conn, params); + } + if (conn->conn_type == XQC_CONN_TYPE_SERVER) { + re_encode_local_tp_flag = 1; + } + } +#endif + // if local_settings needs to be updated, reencode local transport parameters + if (re_encode_local_tp_flag) { uint8_t tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; size_t tp_len = 0; - conn->local_settings.multipath_version = params.multipath_version; + ret = xqc_conn_encode_local_tp(conn, tp_buf, XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); if (ret != XQC_OK) { @@ -4896,7 +5947,9 @@ xqc_settings_copy_from_transport_params(xqc_trans_settings_t *dest, dest->active_connection_id_limit = src->active_connection_id_limit; dest->enable_multipath = src->enable_multipath; + dest->init_max_path_id = src->init_max_path_id; dest->max_datagram_frame_size = src->max_datagram_frame_size; + dest->enable_pmtud = src->enable_pmtud; } xqc_int_t @@ -5025,6 +6078,11 @@ xqc_conn_get_idle_timeout(xqc_connection_t *conn) } } +xqc_msec_t +xqc_conn_get_queue_fin_timeout(xqc_connection_t *conn) +{ + return conn->conn_settings.fec_conn_queue_rpr_timeout; +} void xqc_conn_decrease_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *packet_out) @@ -5057,7 +6115,7 @@ xqc_conn_decrease_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *p /* Update stream state */ if (stream->stream_unacked_pkt == 0 && stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_SENT) { xqc_stream_send_state_update(stream, XQC_SEND_STREAM_ST_DATA_RECVD); - xqc_log(conn->log, XQC_LOG_DEBUG, "|stream enter DATA RECVD|"); + xqc_log(conn->log, XQC_LOG_DEBUG, "|stream enter DATA RECVD|stream_id:%d", stream->stream_id); xqc_stream_maybe_need_close(stream); } } @@ -5100,29 +6158,62 @@ xqc_conn_increase_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *p void -xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now) +xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_send_ctl_t *ctl, + xqc_packet_out_t *packet_out, xqc_usec_t now) { xqc_stream_id_t stream_id; - xqc_stream_t *stream; - if (packet_out->po_frame_types & XQC_FRAME_BIT_STREAM) { - for (int i = 0; i < XQC_MAX_STREAM_FRAME_IN_PO; i++) { + xqc_stream_t *stream[XQC_MAX_STREAM_FRAME_IN_PO] = {0}; + int stream_cnt = 0; + int i, j; + + if (packet_out->po_frame_types & (XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_RESET_STREAM)) { + for (i = 0; i < XQC_MAX_STREAM_FRAME_IN_PO; i++) { if (packet_out->po_stream_frames[i].ps_is_used == 0) { break; } stream_id = packet_out->po_stream_frames[i].ps_stream_id; - stream = xqc_find_stream_by_id(stream_id, conn->streams_hash); - if (stream) { - if (stream->stream_stats.first_snd_time == 0) { - stream->stream_stats.first_snd_time = now; + stream[stream_cnt] = xqc_find_stream_by_id(stream_id, conn->streams_hash); + for (j = 0; j < stream_cnt; j++) { + if (stream[j] == stream[stream_cnt]) { + break; + } + } + + if (stream[stream_cnt]) { + if (stream[stream_cnt]->stream_stats.first_snd_time == 0) { + stream[stream_cnt]->stream_stats.first_snd_time = now; } if (packet_out->po_stream_frames[i].ps_has_fin) { - stream->stream_stats.local_fin_snd_time = now; + stream[stream_cnt]->stream_stats.local_fin_snd_time = now; + if (stream[stream_cnt]->stream_stats.local_fst_fin_snd_time == 0) { + stream[stream_cnt]->stream_stats.local_fst_fin_snd_time = now; + } } if (packet_out->po_stream_frames[i].ps_is_reset) { - stream->stream_stats.local_reset_time = now; + stream[stream_cnt]->stream_stats.local_reset_time = now; } - } - + // do not repeatedly count + if (j == stream_cnt) { + if (packet_out->po_sched_cwnd_blk_ts) { + stream[stream_cnt]->stream_stats.sched_cwnd_blk_duration += now - packet_out->po_sched_cwnd_blk_ts; + stream[stream_cnt]->stream_stats.sched_cwnd_blk_cnt++; + } + if (packet_out->po_send_cwnd_blk_ts) { + stream[stream_cnt]->stream_stats.send_cwnd_blk_duration += now - packet_out->po_send_cwnd_blk_ts; + stream[stream_cnt]->stream_stats.send_cwnd_blk_cnt++; + } + if (packet_out->po_send_pacing_blk_ts) { + stream[stream_cnt]->stream_stats.send_pacing_blk_duration += now - packet_out->po_send_pacing_blk_ts; + stream[stream_cnt]->stream_stats.send_pacing_blk_cnt++; + } + if (packet_out->po_flag & (XQC_POF_TLP | XQC_POF_LOST)) { + stream[stream_cnt]->stream_stats.retrans_pkt_cnt++; + } + stream[stream_cnt]->stream_stats.sent_pkt_cnt++; + stream[stream_cnt]->stream_stats.max_pto_backoff = xqc_max(stream[stream_cnt]->stream_stats.max_pto_backoff, ctl->ctl_pto_count); + stream_cnt++; + } + } } } } @@ -5147,6 +6238,31 @@ xqc_conn_get_max_pto(xqc_connection_t *conn) return max_pto; } +uint32_t +xqc_conn_get_max_pto_backoff(xqc_connection_t *conn, uint8_t available_only) +{ + xqc_path_ctx_t *path = NULL; + uint32_t max_pto = 0; + + xqc_list_head_t *pos, *next; + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + if (path->path_state != XQC_PATH_STATE_ACTIVE) { + continue; + } + + if (available_only + && path->app_path_status != XQC_APP_PATH_STATUS_AVAILABLE) + { + continue; + } + + max_pto = xqc_max(path->path_send_ctl->ctl_pto_count, max_pto); + } + + return max_pto; +} + xqc_usec_t xqc_conn_get_min_srtt(xqc_connection_t *conn, xqc_bool_t available_only) { @@ -5306,7 +6422,7 @@ xqc_conn_send_path_challenge(xqc_connection_t *conn, xqc_path_ctx_t *path) "|write_socket error|conn:%p|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|now:%ui|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), now); ret = -XQC_ESOCKET; goto end; @@ -5315,9 +6431,7 @@ xqc_conn_send_path_challenge(xqc_connection_t *conn, xqc_path_ctx_t *path) "|<==|conn:%p|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now); - xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, ret); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now); } pn_ctl = xqc_get_pn_ctl(conn, path); @@ -5448,7 +6562,7 @@ xqc_conn_should_clear_0rtt_ticket(xqc_int_t conn_err) xqc_conn_settings_t xqc_conn_get_conn_settings_template(xqc_conn_settings_type_t settings_type) { - xqc_conn_settings_t conn_settings = default_conn_settings; + xqc_conn_settings_t conn_settings = internal_default_conn_settings; if (settings_type == XQC_CONN_SETTINGS_LOW_DELAY) { conn_settings.ack_frequency = 1; @@ -5549,6 +6663,7 @@ xqc_conn_reset(xqc_connection_t *conn) /* set error code and close message, notify to application */ conn->conn_state = XQC_CONN_STATE_DRAINING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); conn->conn_err = XQC_ESTATELESS_RESET; XQC_CONN_CLOSE_MSG(conn, "stateless reset"); xqc_conn_closing(conn); @@ -5558,10 +6673,12 @@ xqc_int_t xqc_conn_handle_stateless_reset(xqc_connection_t *conn, const uint8_t *sr_token) { - xqc_int_t ret; - int res; - xqc_list_head_t *pos, *next; - xqc_cid_inner_t *cid; + xqc_int_t ret; + int res; + xqc_list_head_t *pos, *next; + xqc_cid_inner_t *cid; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; if (NULL == conn || NULL == sr_token) { return -XQC_EPARAM; @@ -5573,20 +6690,31 @@ xqc_conn_handle_stateless_reset(xqc_connection_t *conn, } /* compare received stateless reset token with the ones peer sent */ - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - - res = xqc_memcmp(sr_token, cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN); - if (0 == res) { - xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" - "|cid:%s", xqc_dcid_str(&cid->cid)); - xqc_log_event(conn->log, TRA_STATELESS_RESET, conn); + xqc_list_for_each_safe(pos_set, next_set, &conn->dcid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - /* stateless reset received, close connection */ - xqc_conn_reset(conn); + res = xqc_memcmp(sr_token, cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + if (0 == res) { + xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" + "|cid:%s|sr_token:%s|", + xqc_dcid_str(conn->engine, &cid->cid), + xqc_sr_token_str(conn->engine, sr_token)); + xqc_log_event(conn->log, TRA_STATELESS_RESET, conn); + + if (inner_set->set_state < XQC_CID_SET_ABANDONED + && cid->state < XQC_CID_RETIRED) + { + /* only responds for non-retired CIDs */ + /* stateless reset received, close connection */ + xqc_conn_reset(conn); + } - goto end; + goto end; + } } } @@ -5625,7 +6753,6 @@ xqc_conn_available_paths(xqc_engine_t *engine, const xqc_cid_t *cid) return available_paths; } - #ifdef XQC_COMPAT_GENERATE_SR_PKT xqc_int_t @@ -5642,7 +6769,7 @@ xqc_conn_handle_deprecated_stateless_reset(xqc_connection_t *conn, } xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" - "|deprecated|cid:%s", xqc_dcid_str(scid)); + "|deprecated|cid:%s", xqc_dcid_str(conn->engine, scid)); /* reset state of connection */ xqc_conn_reset(conn); diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index 7fe56dce3..a92b5e522 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -19,6 +19,8 @@ #include "src/transport/xqc_transport_params.h" #include "src/transport/xqc_timer.h" #include "src/transport/xqc_multipath.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" #include "src/tls/xqc_tls.h" #include "src/common/xqc_list.h" @@ -36,6 +38,8 @@ #define XQC_MAX_RECV_WINDOW (16 * 1024 * 1024) +#define XQC_MP_SETTINGS_STR_LEN (30) + static const uint32_t MAX_RSP_CONN_CLOSE_CNT = 3; /* for debugging, will be deleted later */ @@ -62,84 +66,77 @@ static const uint32_t MAX_RSP_CONN_CLOSE_CNT = 3; } \ } while(0) \ -extern xqc_conn_settings_t default_conn_settings; +extern xqc_conn_settings_t internal_default_conn_settings; extern const xqc_tls_callbacks_t xqc_conn_tls_cbs; /* !!WARNING: to add state, please update conn_state_2_str */ typedef enum { /* server */ XQC_CONN_STATE_SERVER_INIT = 0, - XQC_CONN_STATE_SERVER_INITIAL_RECVD, - XQC_CONN_STATE_SERVER_INITIAL_SENT, - XQC_CONN_STATE_SERVER_HANDSHAKE_SENT, - XQC_CONN_STATE_SERVER_HANDSHAKE_RECVD, + XQC_CONN_STATE_SERVER_INITIAL_RECVD = 1, + XQC_CONN_STATE_SERVER_INITIAL_SENT = 2, + XQC_CONN_STATE_SERVER_HANDSHAKE_SENT = 3, + XQC_CONN_STATE_SERVER_HANDSHAKE_RECVD = 4, /* client */ XQC_CONN_STATE_CLIENT_INIT = 5, - XQC_CONN_STATE_CLIENT_INITIAL_SENT, - XQC_CONN_STATE_CLIENT_INITIAL_RECVD, - XQC_CONN_STATE_CLIENT_HANDSHAKE_RECVD, - XQC_CONN_STATE_CLIENT_HANDSHAKE_SENT, + XQC_CONN_STATE_CLIENT_INITIAL_SENT = 6, + XQC_CONN_STATE_CLIENT_INITIAL_RECVD = 7, + XQC_CONN_STATE_CLIENT_HANDSHAKE_RECVD = 8, + XQC_CONN_STATE_CLIENT_HANDSHAKE_SENT = 9, /* client & server */ XQC_CONN_STATE_ESTABED = 10, - XQC_CONN_STATE_CLOSING, - XQC_CONN_STATE_DRAINING, - XQC_CONN_STATE_CLOSED, - XQC_CONN_STATE_N, + XQC_CONN_STATE_CLOSING = 11, + XQC_CONN_STATE_DRAINING = 12, + XQC_CONN_STATE_CLOSED = 13, + XQC_CONN_STATE_N = 14, } xqc_conn_state_t; -#define XQC_CONN_FLAG_SHOULD_ACK (XQC_CONN_FLAG_SHOULD_ACK_INIT \ - | XQC_CONN_FLAG_SHOULD_ACK_HSK \ - | XQC_CONN_FLAG_SHOULD_ACK_01RTT) \ - #define XQC_CONN_IMMEDIATE_CLOSE_FLAGS (XQC_CONN_FLAG_ERROR) /* !!WARNING: to add flag, please update conn_flag_2_str */ typedef enum { - XQC_CONN_FLAG_WAIT_WAKEUP_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT, - XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT, - XQC_CONN_FLAG_TICKING_SHIFT, - XQC_CONN_FLAG_SHOULD_ACK_INIT_SHIFT, - XQC_CONN_FLAG_SHOULD_ACK_HSK_SHIFT = (XQC_CONN_FLAG_SHOULD_ACK_INIT_SHIFT + XQC_PNS_HSK), - XQC_CONN_FLAG_SHOULD_ACK_01RTT_SHIFT = (XQC_CONN_FLAG_SHOULD_ACK_INIT_SHIFT + XQC_PNS_APP_DATA), - XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT, - XQC_CONN_FLAG_TIME_OUT_SHIFT, - XQC_CONN_FLAG_ERROR_SHIFT, - XQC_CONN_FLAG_DATA_BLOCKED_SHIFT, - XQC_CONN_FLAG_DCID_OK_SHIFT, - XQC_CONN_FLAG_TOKEN_OK_SHIFT, - XQC_CONN_FLAG_HAS_0RTT_SHIFT, - XQC_CONN_FLAG_0RTT_OK_SHIFT, - XQC_CONN_FLAG_0RTT_REJ_SHIFT, - XQC_CONN_FLAG_UPPER_CONN_EXIST_SHIFT, - XQC_CONN_FLAG_INIT_RECVD_SHIFT, - XQC_CONN_FLAG_NEED_RUN_SHIFT, - XQC_CONN_FLAG_PING_SHIFT, - XQC_CONN_FLAG_HSK_ACKED_SHIFT, - XQC_CONN_FLAG_RESERVE_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_DONE_RECVD_SHIFT, - XQC_CONN_FLAG_UPDATE_NEW_TOKEN_SHIFT, - XQC_CONN_FLAG_VERSION_NEGOTIATION_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT, - XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT, - XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT, - XQC_CONN_FLAG_LINGER_CLOSING_SHIFT, - XQC_CONN_FLAG_RETRY_RECVD_SHIFT, - XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT, - XQC_CONN_FLAG_RECV_NEW_PATH_SHIFT, - XQC_CONN_FLAG_VALIDATE_REBINDING_SHIFT, - XQC_CONN_FLAG_CONN_CLOSING_NOTIFY_SHIFT, - XQC_CONN_FLAG_CONN_CLOSING_NOTIFIED_SHIFT, - XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT_SHIFT, - XQC_CONN_FLAG_LOCAL_TP_UPDATED_SHIFT, - XQC_CONN_FLAG_PMTUD_PROBING_SHIFT, - XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT, - XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT, - XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT, - XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT, - XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, - XQC_CONN_FLAG_SHIFT_NUM, + XQC_CONN_FLAG_WAIT_WAKEUP_SHIFT = 0, + XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT = 1, + XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT = 2, + XQC_CONN_FLAG_TICKING_SHIFT = 3, + XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT = 4, + XQC_CONN_FLAG_TIME_OUT_SHIFT = 5, + XQC_CONN_FLAG_ERROR_SHIFT = 6, + XQC_CONN_FLAG_DATA_BLOCKED_SHIFT = 7, + XQC_CONN_FLAG_DCID_OK_SHIFT = 8, + XQC_CONN_FLAG_TOKEN_OK_SHIFT = 9, + XQC_CONN_FLAG_HAS_0RTT_SHIFT = 10, + XQC_CONN_FLAG_0RTT_OK_SHIFT = 11, + XQC_CONN_FLAG_0RTT_REJ_SHIFT = 12, + XQC_CONN_FLAG_UPPER_CONN_EXIST_SHIFT = 13, + XQC_CONN_FLAG_INIT_RECVD_SHIFT = 14, + XQC_CONN_FLAG_NEED_RUN_SHIFT = 15, + XQC_CONN_FLAG_PING_SHIFT = 16, + XQC_CONN_FLAG_HSK_ACKED_SHIFT = 17, + XQC_CONN_FLAG_RESERVE_SHIFT = 18, + XQC_CONN_FLAG_HANDSHAKE_DONE_RECVD_SHIFT = 19, + XQC_CONN_FLAG_UPDATE_NEW_TOKEN_SHIFT = 20, + XQC_CONN_FLAG_VERSION_NEGOTIATION_SHIFT = 21, + XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT = 22, + XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT = 23, + XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT = 24, + XQC_CONN_FLAG_LINGER_CLOSING_SHIFT = 25, + XQC_CONN_FLAG_RETRY_RECVD_SHIFT = 26, + XQC_CONN_FLAG_TLS_CH_SHIFT = 27, + XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT = 28, + XQC_CONN_FLAG_RECV_NEW_PATH_SHIFT = 29, + XQC_CONN_FLAG_VALIDATE_REBINDING_SHIFT = 30, + XQC_CONN_FLAG_CONN_CLOSING_NOTIFY_SHIFT = 31, + XQC_CONN_FLAG_CONN_CLOSING_NOTIFIED_SHIFT = 32, + XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT_SHIFT = 33, + XQC_CONN_FLAG_LOCAL_TP_UPDATED_SHIFT = 34, + XQC_CONN_FLAG_PMTUD_PROBING_SHIFT = 35, + XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT = 36, + XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT = 37, + XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT = 38, + XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT = 39, + XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT = 40, + XQC_CONN_FLAG_SHIFT_NUM = 41, } xqc_conn_flag_shift_t; typedef enum { @@ -147,9 +144,6 @@ typedef enum { XQC_CONN_FLAG_HANDSHAKE_COMPLETED = 1ULL << XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT, XQC_CONN_FLAG_CAN_SEND_1RTT = 1ULL << XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT, XQC_CONN_FLAG_TICKING = 1ULL << XQC_CONN_FLAG_TICKING_SHIFT, - XQC_CONN_FLAG_SHOULD_ACK_INIT = 1ULL << XQC_CONN_FLAG_SHOULD_ACK_INIT_SHIFT, - XQC_CONN_FLAG_SHOULD_ACK_HSK = 1ULL << XQC_CONN_FLAG_SHOULD_ACK_HSK_SHIFT, - XQC_CONN_FLAG_SHOULD_ACK_01RTT = 1ULL << XQC_CONN_FLAG_SHOULD_ACK_01RTT_SHIFT, XQC_CONN_FLAG_ACK_HAS_GAP = 1ULL << XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT, XQC_CONN_FLAG_TIME_OUT = 1ULL << XQC_CONN_FLAG_TIME_OUT_SHIFT, XQC_CONN_FLAG_ERROR = 1ULL << XQC_CONN_FLAG_ERROR_SHIFT, @@ -171,9 +165,9 @@ typedef enum { XQC_CONN_FLAG_HANDSHAKE_CONFIRMED = 1ULL << XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED = 1ULL << XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT, XQC_CONN_FLAG_ADDR_VALIDATED = 1ULL << XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT, - XQC_CONN_FLAG_NEW_CID_ACKED = 1ULL << XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT, XQC_CONN_FLAG_LINGER_CLOSING = 1ULL << XQC_CONN_FLAG_LINGER_CLOSING_SHIFT, XQC_CONN_FLAG_RETRY_RECVD = 1ULL << XQC_CONN_FLAG_RETRY_RECVD_SHIFT, + XQC_CONN_FLAG_TLS_CH_RECVD = 1ULL << XQC_CONN_FLAG_TLS_CH_SHIFT, XQC_CONN_FLAG_TLS_HSK_COMPLETED = 1ULL << XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT, XQC_CONN_FLAG_RECV_NEW_PATH = 1ULL << XQC_CONN_FLAG_RECV_NEW_PATH_SHIFT, XQC_CONN_FLAG_VALIDATE_REBINDING = 1ULL << XQC_CONN_FLAG_VALIDATE_REBINDING_SHIFT, @@ -184,9 +178,9 @@ typedef enum { XQC_CONN_FLAG_PMTUD_PROBING = 1ULL << XQC_CONN_FLAG_PMTUD_PROBING_SHIFT, XQC_CONN_FLAG_NO_DGRAM_NOTIFIED = 1ULL << XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT, XQC_CONN_FLAG_DGRAM_MSS_NOTIFY = 1ULL << XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT, - XQC_CONN_FLAG_MP_WAIT_SCID = 1ULL << XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT, - XQC_CONN_FLAG_MP_WAIT_DCID = 1ULL << XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT, + XQC_CONN_FLAG_MP_WAIT_MP_READY = 1ULL << XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT, XQC_CONN_FLAG_MP_READY_NOTIFY = 1ULL << XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, + XQC_CONN_FLAG_HANDSHAKE_DONE_SENT = 1ULL << XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT, } xqc_conn_flag_t; @@ -211,8 +205,28 @@ typedef struct { uint64_t enable_multipath; xqc_multipath_version_t multipath_version; uint16_t max_datagram_frame_size; + uint32_t conn_options[XQC_CO_MAX_NUM]; + uint8_t conn_option_num; + + xqc_fec_version_t fec_version; + uint64_t enable_encode_fec; + uint64_t enable_decode_fec; + uint64_t fec_max_symbols_num; + xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + xqc_int_t fec_encoder_schemes_num; + xqc_int_t fec_decoder_schemes_num; + + xqc_dgram_red_setting_e close_dgram_redundancy; + uint64_t init_max_path_id; + + uint64_t extended_ack_features; + /* Currently, max_receive_timestamps_per_ack must be less than or equal to 63. */ + uint64_t max_receive_timestamps_per_ack; + uint64_t receive_timestamps_exponent; + uint64_t enable_pmtud; } xqc_trans_settings_t; - + typedef struct { /* flow control limit */ @@ -271,8 +285,8 @@ struct xqc_connection_s { /* initial source connection id, RFC 9000, Section 7.3 */ xqc_cid_t initial_scid; - xqc_dcid_set_t dcid_set; - xqc_scid_set_t scid_set; + xqc_cid_set_t dcid_set; + xqc_cid_set_t scid_set; unsigned char peer_addr[sizeof(struct sockaddr_in6)]; socklen_t peer_addrlen; @@ -313,6 +327,9 @@ struct xqc_connection_s { xqc_trans_settings_t local_settings; xqc_trans_settings_t remote_settings; + + /* a bitmap to record if ACKs should be generated for path[pns] */ + uint64_t ack_flag; xqc_conn_flag_t conn_flag; xqc_conn_type_t conn_type; @@ -321,6 +338,8 @@ struct xqc_connection_s { void *user_data; /* user_data for application layer */ /* callback function and user_data to application-layer-protocol layer */ + char *alpn; + size_t alpn_len; xqc_app_proto_callbacks_t app_proto_cbs; void *proto_data; @@ -361,6 +380,15 @@ struct xqc_connection_s { uint32_t create_path_count; uint32_t validated_path_count; uint32_t active_path_count; + + uint64_t curr_max_path_id; + uint64_t local_max_path_id; + uint64_t remote_max_path_id; + + /* for qlog */ + uint32_t MTU_updated_count; + uint32_t packet_dropped_count; + const xqc_scheduler_callback_t *scheduler_callback; @@ -412,6 +440,7 @@ struct xqc_connection_s { size_t max_pkt_out_size; size_t probing_pkt_out_size; uint32_t probing_cnt; + size_t max_acked_po_size; /* pending ping notification */ xqc_list_head_t ping_notification_list; @@ -420,13 +449,27 @@ struct xqc_connection_s { uint32_t sched_cc_blocked; uint32_t send_cc_blocked; + /* internal loss detection stats */ + uint32_t detected_loss_cnt; + + /* max consecutive PTO cnt among all paths */ + uint16_t max_pto_cnt; + uint32_t finished_streams; + uint32_t cli_bidi_streams; + uint32_t svr_bidi_streams; + + /* for fec */ + xqc_fec_ctl_t *fec_ctl; + uint32_t fec_neg_fail_reason; + + /* receved pkts stats */ struct { xqc_pkt_type_t pkt_types[3]; xqc_frame_type_bit_t pkt_frames[3]; uint32_t pkt_size[3]; uint32_t pkt_udp_size[3]; - uint64_t pkt_err[3]; + int pkt_err[3]; xqc_usec_t pkt_timestamp[3]; xqc_packet_number_t pkt_pn[3]; uint8_t curr_index; @@ -443,9 +486,18 @@ struct xqc_connection_s { uint8_t curr_index; uint32_t conn_sent_pkts; } snd_pkt_stats; + + uint8_t enable_pmtud; + uint32_t burst_loss_cnt; + xqc_usec_t conn_avg_close_delay; + xqc_usec_t conn_avg_recv_delay; + xqc_usec_t conn_latest_close_delay; + uint32_t conn_video_frames; }; -const char *xqc_conn_flag_2_str(xqc_conn_flag_t conn_flag); +extern const xqc_h3_conn_settings_t default_local_h3_conn_settings; + +const char *xqc_conn_flag_2_str(xqc_connection_t *conn, xqc_conn_flag_t conn_flag); const char *xqc_conn_state_2_str(xqc_conn_state_t state); void xqc_conn_init_flow_ctl(xqc_connection_t *conn); @@ -496,12 +548,13 @@ xqc_int_t xqc_conn_handshake_complete(xqc_connection_t *conn); xqc_int_t xqc_conn_buff_undecrypt_packet_in(xqc_packet_in_t *packet_in, xqc_connection_t *conn, xqc_encrypt_level_t encrypt_level); xqc_int_t xqc_conn_process_undecrypt_packet_in(xqc_connection_t *conn, xqc_encrypt_level_t encrypt_level); +void xqc_conn_buff_1rtt_packet(xqc_connection_t *conn, xqc_packet_out_t *po); void xqc_conn_buff_1rtt_packets(xqc_connection_t *conn); void xqc_conn_write_buffed_1rtt_packets(xqc_connection_t *conn); xqc_usec_t xqc_conn_next_wakeup_time(xqc_connection_t *conn); -char *xqc_local_addr_str(const struct sockaddr *local_addr, socklen_t local_addrlen); -char *xqc_peer_addr_str(const struct sockaddr *peer_addr, socklen_t peer_addrlen); +char *xqc_local_addr_str(xqc_engine_t *engine, const struct sockaddr *local_addr, socklen_t local_addrlen); +char *xqc_peer_addr_str(xqc_engine_t *engine, const struct sockaddr *peer_addr, socklen_t peer_addrlen); char *xqc_conn_addr_str(xqc_connection_t *conn); char *xqc_path_addr_str(xqc_path_ctx_t *path); @@ -538,42 +591,21 @@ xqc_conn_has_undecrypt_packets(xqc_connection_t *conn) || conn->undecrypt_count[XQC_ENC_LEV_HSK]; } -static inline xqc_int_t -xqc_conn_should_ack(xqc_connection_t *conn) -{ - if (conn->conn_flag & XQC_CONN_FLAG_SHOULD_ACK) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|should_generate_ack yes|flag:%s|", - xqc_conn_flag_2_str(conn->conn_flag)); - return 1; - } - return 0; -} - /* process an UDP datagram */ -#ifdef XQC_NO_PID_PACKET_PROCESS xqc_int_t xqc_conn_process_packet(xqc_connection_t *c, const unsigned char *packet_in_buf, size_t packet_in_size, xqc_usec_t recv_time); -#else -xqc_int_t xqc_conn_process_packet(xqc_connection_t *c, const unsigned char *packet_in_buf, - size_t packet_in_size, uint64_t path_id, xqc_usec_t recv_time); -#endif -#ifdef XQC_NO_PID_PACKET_PROCESS void xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid, size_t packet_in_size, xqc_usec_t recv_time); -#else -void xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid, - uint64_t path_id, size_t packet_in_size, xqc_usec_t recv_time); -#endif xqc_int_t xqc_conn_check_handshake_complete(xqc_connection_t *conn); -xqc_int_t xqc_conn_check_unused_cids(xqc_connection_t *conn); +xqc_int_t xqc_conn_get_available_path_id(xqc_connection_t *conn, uint64_t *path_id); xqc_int_t xqc_conn_try_add_new_conn_id(xqc_connection_t *conn, uint64_t retire_prior_to); xqc_int_t xqc_conn_check_dcid(xqc_connection_t *conn, xqc_cid_t *dcid); void xqc_conn_destroy_cids(xqc_connection_t *conn); -xqc_int_t xqc_conn_update_user_scid(xqc_connection_t *conn, xqc_scid_set_t *scid_set); +xqc_int_t xqc_conn_update_user_scid(xqc_connection_t *conn); xqc_int_t xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid); xqc_bool_t xqc_conn_peer_complete_address_validation(xqc_connection_t *c); @@ -599,7 +631,8 @@ xqc_int_t xqc_conn_confirm_key_update(xqc_connection_t *conn); /* from send_ctl */ void xqc_conn_decrease_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *packet_out); void xqc_conn_increase_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now); +void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_send_ctl_t *ctl, + xqc_packet_out_t *packet_out, xqc_usec_t now); /* 选择所有path的PTO中最大的那个,作为conn的PTO,用于连接级别的定时器触发: * - XQC_TIMER_LINGER_CLOSE @@ -609,6 +642,8 @@ void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out */ xqc_usec_t xqc_conn_get_max_pto(xqc_connection_t *conn); +uint32_t xqc_conn_get_max_pto_backoff(xqc_connection_t *conn, uint8_t available_only); + void xqc_conn_ptmud_probing(xqc_connection_t *conn); /* 用于流控 */ @@ -643,6 +678,8 @@ xqc_int_t xqc_conn_gp_timer_get_info(xqc_connection_t *conn, xqc_gp_timer_id_t g void xqc_conn_schedule_packets_to_paths(xqc_connection_t *conn); +void xqc_conn_encode_transport_state(xqc_connection_t *conn, char *buf, size_t buf_sz); + static inline xqc_uint_t xqc_conn_get_mss(xqc_connection_t *conn) { return conn->pkt_out_size + XQC_ACK_SPACE; @@ -666,5 +703,14 @@ void xqc_conn_destroy_ping_notification_list(xqc_connection_t *conn); xqc_int_t xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_data, xqc_bool_t notify); +void xqc_conn_encode_mp_settings(xqc_connection_t *conn, char *buf, size_t buf_sz); + +void xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, + xqc_list_head_t *head, int congest, xqc_send_type_t send_type); + +xqc_int_t xqc_conn_try_to_enable_multipath(xqc_connection_t *conn); +xqc_int_t xqc_conn_add_path_cid_sets(xqc_connection_t *conn, uint32_t start, uint32_t end); +xqc_msec_t xqc_conn_get_queue_fin_timeout(xqc_connection_t *conn); +void xqc_conn_try_to_enable_pmtud(xqc_connection_t *conn); #endif /* _XQC_CONN_H_INCLUDED_ */ diff --git a/src/transport/xqc_datagram.c b/src/transport/xqc_datagram.c index e39ec96d1..23f4cb646 100644 --- a/src/transport/xqc_datagram.c +++ b/src/transport/xqc_datagram.c @@ -70,6 +70,11 @@ xqc_datagram_record_mss(xqc_connection_t *conn) } headroom = XQC_ACK_SPACE + XQC_TLS_AEAD_OVERHEAD_MAX_LEN + quic_header_size + XQC_DATAGRAM_HEADER_BYTES; + + if (conn->conn_settings.fec_params.fec_encoder_scheme) { + headroom += XQC_FEC_SPACE; + } + if (conn->remote_settings.max_udp_payload_size >= headroom) { udp_payload_limit = conn->remote_settings.max_udp_payload_size - headroom; @@ -78,6 +83,9 @@ xqc_datagram_record_mss(xqc_connection_t *conn) } headroom = quic_header_size + XQC_DATAGRAM_HEADER_BYTES; + if (conn->conn_settings.fec_params.fec_encoder_scheme) { + headroom += XQC_FEC_SPACE; + } if (conn->pkt_out_size >= headroom) { mtu_limit = conn->pkt_out_size - headroom; @@ -231,11 +239,8 @@ xqc_int_t xqc_datagram_send(xqc_connection_t *conn, void *data, *dgram_id = dg_id; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); if (conn->conn_settings.datagram_redundant_probe && conn->dgram_probe_timer >= 0 @@ -250,7 +255,7 @@ xqc_int_t xqc_datagram_send(xqc_connection_t *conn, void *data, } /* call main logic to send packets out */ - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); return XQC_OK; } @@ -406,11 +411,8 @@ xqc_datagram_send_multiple_internal(xqc_connection_t *conn, } if (*sent_cnt > 0) { - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); data = iov[*sent_cnt - 1].iov_base; data_len = iov[*sent_cnt - 1].iov_len; @@ -428,7 +430,7 @@ xqc_datagram_send_multiple_internal(xqc_connection_t *conn, } /* call main logic to send packets out */ - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } return ret < 0 ? ret : XQC_OK; diff --git a/src/transport/xqc_defs.h b/src/transport/xqc_defs.h index ef36e09af..1a406b082 100644 --- a/src/transport/xqc_defs.h +++ b/src/transport/xqc_defs.h @@ -66,6 +66,9 @@ extern const unsigned char xqc_proto_version_field[][XQC_PROTO_VERSION_LEN]; #define XQC_MAX_ALPN_LEN 255 /* limit of anti-amplification */ -#define XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT 3 +#define XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT 5 +#define XQC_MAX_MT_ROW 256 + +#define XQC_RSM_COL 48 #endif \ No newline at end of file diff --git a/src/transport/xqc_engine.c b/src/transport/xqc_engine.c index 7f8b2a6d7..896cbb6cc 100644 --- a/src/transport/xqc_engine.c +++ b/src/transport/xqc_engine.c @@ -18,7 +18,6 @@ #include "src/transport/xqc_packet_in.h" #include "src/transport/xqc_packet.h" #include "src/transport/xqc_cid.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_utils.h" #include "src/transport/xqc_timer.h" #include "src/transport/xqc_datagram.h" @@ -34,11 +33,13 @@ extern const xqc_qpack_ins_cb_t xqc_h3_qpack_ins_cb; xqc_config_t default_client_config = { .cfg_log_level = XQC_LOG_WARN, .cfg_log_event = 1, + .cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA, .cfg_log_timestamp = 1, .cfg_log_level_name = 1, .conn_pool_size = 4096, .streams_hash_bucket_size = 1024, .conns_hash_bucket_size = 1024, + .hash_conflict_threshold = XQC_HASH_DEFAULT_CONFLICT_THRESHOLD, .conns_active_pq_capacity = 128, .conns_wakeup_pq_capacity = 128, .support_version_count = 1, @@ -49,17 +50,20 @@ xqc_config_t default_client_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, + .manually_triggered_send = 0, }; xqc_config_t default_server_config = { .cfg_log_level = XQC_LOG_WARN, .cfg_log_event = 1, + .cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA, .cfg_log_timestamp = 1, .cfg_log_level_name = 1, .conn_pool_size = 4096, .streams_hash_bucket_size = 1024, .conns_hash_bucket_size = 1024*1024, /* too many connections will affect lookup performance */ + .hash_conflict_threshold = XQC_HASH_DEFAULT_CONFLICT_THRESHOLD, .conns_active_pq_capacity = 1024, .conns_wakeup_pq_capacity = 16*1024, .support_version_count = 2, @@ -70,6 +74,7 @@ xqc_config_t default_server_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, + .manually_triggered_send = 0, }; @@ -91,6 +96,9 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) if (src->conns_hash_bucket_size > 0) { dst->conns_hash_bucket_size = src->conns_hash_bucket_size; } + if (src->hash_conflict_threshold > 0) { + dst->hash_conflict_threshold = src->hash_conflict_threshold; + } if (src->conns_active_pq_capacity > 0) { dst->conns_active_pq_capacity = src->conns_active_pq_capacity; @@ -128,6 +136,7 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) dst->cid_negotiate = src->cid_negotiate; dst->cfg_log_level = src->cfg_log_level; dst->cfg_log_event = src->cfg_log_event; + dst->cfg_qlog_importance = src->cfg_qlog_importance; dst->cfg_log_timestamp = src->cfg_log_timestamp; dst->cfg_log_level_name = src->cfg_log_level_name; dst->sendmmsg_on = src->sendmmsg_on; @@ -192,14 +201,17 @@ xqc_engine_set_log_level(xqc_engine_t *engine, xqc_log_level_t log_level) xqc_str_hash_table_t * -xqc_engine_conns_hash_create(xqc_config_t *config) +xqc_engine_conns_hash_create(xqc_config_t *config, uint8_t *key, size_t key_len, xqc_log_t *log) { xqc_str_hash_table_t *hash_table = xqc_malloc(sizeof(xqc_str_hash_table_t)); if (hash_table == NULL) { return NULL; } - if (xqc_str_hash_init(hash_table, xqc_default_allocator, config->conns_hash_bucket_size)) { + if (xqc_str_hash_init(hash_table, xqc_default_allocator, + config->conns_hash_bucket_size, config->hash_conflict_threshold, + key, key_len, log)) + { goto fail; } @@ -219,42 +231,32 @@ xqc_engine_conns_hash_destroy(xqc_str_hash_table_t *hash_table) } -xqc_pq_t * -xqc_engine_conns_pq_create(xqc_config_t *config) +int xqc_engine_conn_pq_operator(xqc_pq_t *pq, xqc_pq_element_t *e) { - xqc_pq_t *q = xqc_malloc(sizeof(xqc_pq_t)); - if (q == NULL) { - return NULL; + xqc_connection_t **conn; + conn = (xqc_connection_t**)e->data; + if (conn && *conn) { + (*conn)->wakeup_pq_index = xqc_pq_element_index(pq, e); } - - xqc_memzero(q, sizeof(xqc_pq_t)); - if (xqc_pq_init(q, sizeof(xqc_conns_pq_elem_t), - config->conns_active_pq_capacity, xqc_default_allocator, xqc_pq_revert_cmp)) - { - goto fail; - } - - return q; - -fail: - xqc_pq_destroy(q); - xqc_free(q); - return NULL; + return XQC_OK; } - -xqc_wakeup_pq_t * -xqc_engine_wakeup_pq_create(xqc_config_t *config) +xqc_pq_t * +xqc_engine_conns_pq_create(xqc_config_t *config, uint8_t is_wakeup) { - xqc_wakeup_pq_t *q = xqc_malloc(sizeof(xqc_wakeup_pq_t)); + xqc_pq_t *q = xqc_malloc(sizeof(xqc_pq_t)); if (q == NULL) { return NULL; } - xqc_memzero(q, sizeof(xqc_wakeup_pq_t)); + size_t capacity = is_wakeup == 1 ? + config->conns_wakeup_pq_capacity : + config->conns_active_pq_capacity; - if (xqc_wakeup_pq_init(q, config->conns_wakeup_pq_capacity, - xqc_default_allocator, xqc_wakeup_pq_revert_cmp)) + xqc_memzero(q, sizeof(xqc_pq_t)); + if (xqc_pq_init(q, sizeof(xqc_conns_pq_elem_t), + capacity, xqc_default_allocator, + xqc_pq_revert_cmp, xqc_engine_conn_pq_operator)) { goto fail; } @@ -262,7 +264,7 @@ xqc_engine_wakeup_pq_create(xqc_config_t *config) return q; fail: - xqc_wakeup_pq_destroy(q); + xqc_pq_destroy(q); xqc_free(q); return NULL; } @@ -271,22 +273,30 @@ xqc_engine_wakeup_pq_create(xqc_config_t *config) xqc_connection_t * xqc_engine_conns_hash_find(xqc_engine_t *engine, const xqc_cid_t *cid, char type) { + xqc_connection_t *xqc_conn; if (cid == NULL || cid->cid_len == 0) { return NULL; } - uint64_t hash = xqc_hash_string(cid->cid_buf, cid->cid_len); + uint64_t hash; xqc_str_t str; str.data = (unsigned char *)cid->cid_buf; str.len = cid->cid_len; if (type == 's') { /* search by endpoint's cid */ + hash = xqc_siphash_get_hash(&engine->conns_hash->siphash_ctx, cid->cid_buf, cid->cid_len); return xqc_str_hash_find(engine->conns_hash, hash, str); } else { /* search by peer's cid */ - return xqc_str_hash_find(engine->conns_hash_dcid, hash, str); + hash = xqc_siphash_get_hash(&engine->conns_hash_dcid->siphash_ctx, cid->cid_buf, cid->cid_len); + xqc_conn = xqc_str_hash_find(engine->conns_hash_dcid, hash, str); + if (xqc_conn == NULL) { + xqc_log(engine->log, XQC_LOG_ERROR, "|xquic find dcid error|dcid:%s|", + xqc_dcid_str(engine, cid)); + } + return xqc_conn; } } @@ -303,23 +313,19 @@ xqc_engine_conns_pq_destroy(xqc_pq_t *q) xqc_free(q); } -void -xqc_engine_wakeup_pq_destroy(xqc_wakeup_pq_t *q) -{ - xqc_wakeup_pq_destroy(q); - xqc_free(q); -} - - xqc_usec_t xqc_engine_wakeup_after(xqc_engine_t *engine) { - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(engine->conns_wait_wakeup_pq); if (el) { xqc_usec_t now = xqc_monotonic_timestamp(); - return el->wakeup_time > now ? el->wakeup_time - now : 1; + xqc_log(engine->log, XQC_LOG_DEBUG, "|wakeup:%ui|now:%ui|diff:%ui|", + el->time_us, now, el->time_us - now); + return el->time_us > now ? el->time_us - now : 1; + } + xqc_log(engine->log, XQC_LOG_DEBUG, "|NULL wakeup top|"); return 0; } @@ -379,8 +385,8 @@ xqc_bool_t xqc_engine_check_config(xqc_engine_type_t engine_type, const xqc_config_t *engine_config, const xqc_engine_ssl_config_t *ssl_config, const xqc_transport_callbacks_t *transport_cbs) { - /* mismatch of sendmmsg_on enable and write_mmsg callback function */ - if (engine_config && engine_config->sendmmsg_on && transport_cbs->write_mmsg == NULL) { + /* mismatch of sendmmsg_on enable and write_mmsg & write_mmsg_ex callback function */ + if (engine_config && engine_config->sendmmsg_on && transport_cbs->write_mmsg == NULL && transport_cbs->write_mmsg_ex == NULL) { return XQC_FALSE; } @@ -400,6 +406,7 @@ xqc_engine_create(xqc_engine_type_t engine_type, void *user_data) { xqc_engine_t *engine = NULL; + uint8_t sipkey[XQC_SIPHASH_KEY_SIZE]; /* check input parameter */ if (xqc_engine_check_config(engine_type, engine_config, ssl_config, transport_cbs) @@ -432,11 +439,11 @@ xqc_engine_create(xqc_engine_type_t engine_type, xqc_engine_set_callback(engine, engine_callback, transport_cbs); engine->user_data = user_data; - engine->log = xqc_log_init(engine->config->cfg_log_level, engine->config->cfg_log_event, + engine->config->cfg_qlog_importance, engine->config->cfg_log_timestamp, - engine->config->cfg_log_level_name, + engine->config->cfg_log_level_name, engine, &engine->eng_callback.log_callbacks, engine->user_data); if (engine->log == NULL) { goto fail; @@ -446,28 +453,30 @@ xqc_engine_create(xqc_engine_type_t engine_type, if (engine->rand_generator == NULL) { goto fail; } + xqc_get_random(engine->rand_generator, sipkey, sizeof(sipkey)); + - engine->conns_hash = xqc_engine_conns_hash_create(engine->config); + engine->conns_hash = xqc_engine_conns_hash_create(engine->config, sipkey, sizeof(sipkey), engine->log); if (engine->conns_hash == NULL) { goto fail; } - engine->conns_hash_dcid = xqc_engine_conns_hash_create(engine->config); + engine->conns_hash_dcid = xqc_engine_conns_hash_create(engine->config, sipkey, sizeof(sipkey), engine->log); if (engine->conns_hash_dcid == NULL) { goto fail; } - engine->conns_hash_sr_token = xqc_engine_conns_hash_create(engine->config); + engine->conns_hash_sr_token = xqc_engine_conns_hash_create(engine->config, sipkey, sizeof(sipkey), engine->log); if (engine->conns_hash_sr_token == NULL) { goto fail; } - engine->conns_active_pq = xqc_engine_conns_pq_create(engine->config); + engine->conns_active_pq = xqc_engine_conns_pq_create(engine->config, 0); if (engine->conns_active_pq == NULL) { goto fail; } - engine->conns_wait_wakeup_pq = xqc_engine_wakeup_pq_create(engine->config); + engine->conns_wait_wakeup_pq = xqc_engine_conns_pq_create(engine->config, 1); if (engine->conns_wait_wakeup_pq == NULL) { goto fail; } @@ -485,6 +494,8 @@ xqc_engine_create(xqc_engine_type_t engine_type, goto fail; } + engine->default_conn_settings = internal_default_conn_settings; + return engine; fail: @@ -493,22 +504,6 @@ xqc_engine_create(xqc_engine_type_t engine_type, } -xqc_connection_t * -xqc_conns_pq_pop_top_conn(xqc_pq_t *pq) -{ - /* used to traverse conns_pq */ - xqc_conns_pq_elem_t *el = xqc_conns_pq_top(pq); - if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { - xqc_conns_pq_pop(pq); - return NULL; - } - - xqc_connection_t *conn = el->conn; - xqc_conns_pq_pop(pq); - return conn; -} - - void xqc_engine_destroy(xqc_engine_t *engine) { @@ -536,32 +531,21 @@ xqc_engine_destroy(xqc_engine_t *engine) } conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - } - + /* active connections should never present in the wakeup queue */ xqc_conn_destroy(conn); } } if (engine->conns_wait_wakeup_pq) { - while (!xqc_wakeup_pq_empty(engine->conns_wait_wakeup_pq)) { + while (!xqc_pq_empty(engine->conns_wait_wakeup_pq)) { /* get conn from pq top and pop */ - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); - if (el == NULL || el->conn == NULL) { + conn = xqc_conns_pq_pop_top_conn(engine->conns_wait_wakeup_pq); + if (conn == NULL) { if (engine->log) { xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); } - - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); continue; } - - /* get conn first then pop */ - conn = el->conn; - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; xqc_conn_destroy(conn); } @@ -573,7 +557,7 @@ xqc_engine_destroy(xqc_engine_t *engine) } if (engine->conns_wait_wakeup_pq) { - xqc_engine_wakeup_pq_destroy(engine->conns_wait_wakeup_pq); + xqc_engine_conns_pq_destroy(engine->conns_wait_wakeup_pq); engine->conns_wait_wakeup_pq = NULL; } @@ -678,7 +662,7 @@ void xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) { xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|state:%s|flag:%s|now:%ui|", - conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag), now); + conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag), now); int ret; xqc_bool_t wait_scid, wait_dcid; @@ -690,6 +674,7 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) if (XQC_UNLIKELY(conn->conn_flag & XQC_CONN_FLAG_TIME_OUT)) { conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return; } XQC_CHECK_IMMEDIATE_CLOSE(); @@ -745,13 +730,14 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) } XQC_CHECK_IMMEDIATE_CLOSE(); - if (xqc_conn_should_ack(conn)) { - ret = xqc_write_ack_or_mp_ack_to_packets(conn); + if (conn->ack_flag) { + ret = xqc_write_ack_or_mp_ack_or_ext_ack_to_packets(conn); if (ret) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_ack_or_mp_ack_to_packets error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_ack_or_mp_ack_or_ext_ack_to_packets error|"); XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); } } + XQC_CHECK_IMMEDIATE_CLOSE(); ret = xqc_conn_try_add_new_conn_id(conn, 0); @@ -760,27 +746,16 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) } if (conn->enable_multipath) { - - if (conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_SCID) { - if (conn->conn_flag & XQC_CONN_FLAG_NEW_CID_ACKED) { - conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_SCID; - conn->conn_flag &= ~XQC_CONN_FLAG_NEW_CID_ACKED; - conn->conn_flag |= XQC_CONN_FLAG_MP_READY_NOTIFY; - } - } - - if (conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_DCID - && !(conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_SCID)) + if ((conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_MP_READY) + && xqc_conn_get_available_path_id(conn, NULL) == XQC_OK) { - conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_DCID; conn->conn_flag |= XQC_CONN_FLAG_MP_READY_NOTIFY; - } + conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_MP_READY; + } } /* for multi-path */ - if ((conn->conn_flag & XQC_CONN_FLAG_MP_READY_NOTIFY) - && xqc_conn_check_unused_cids(conn) == XQC_OK) - { + if (conn->conn_flag & XQC_CONN_FLAG_MP_READY_NOTIFY) { if (conn->transport_cbs.ready_to_create_path_notify) { conn->transport_cbs.ready_to_create_path_notify(&conn->scid_set.user_scid, xqc_conn_get_user_data(conn)); @@ -821,6 +796,10 @@ void xqc_engine_finish_recv (xqc_engine_t *engine) { xqc_engine_main_logic_internal(engine); } +void xqc_engine_finish_send (xqc_engine_t *engine) { + xqc_engine_main_logic_internal(engine); +} + void xqc_engine_main_logic_internal(xqc_engine_t *engine) { if (engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY) { @@ -832,6 +811,72 @@ void xqc_engine_main_logic_internal(xqc_engine_t *engine) { engine->eng_flag &= ~XQC_ENG_FLAG_NO_DESTROY; } +void +xqc_engine_conn_logic(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if (engine->eng_flag & XQC_ENG_FLAG_RUNNING) { + xqc_log(conn->log, XQC_LOG_DEBUG, + "|engine is running on conn:%s|", xqc_conn_addr_str(conn)); + return; + } + + engine->eng_flag |= XQC_ENG_FLAG_RUNNING; + + xqc_usec_t now = xqc_monotonic_timestamp(); + xqc_usec_t wake_after; + xqc_engine_process_conn(conn, now); + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->last_ticked_time = now; + xqc_conn_schedule_packets_to_paths(conn); + + if (xqc_engine_is_sendmmsg_on(engine, conn)) { + xqc_conn_transmit_pto_probe_packets_batch(conn); + xqc_conn_retransmit_lost_packets_batch(conn); + xqc_conn_send_packets_batch(conn); + + } else { + xqc_conn_transmit_pto_probe_packets(conn); + xqc_conn_retransmit_lost_packets(conn); + xqc_conn_send_packets(conn); + } + + if (conn->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_AFTER_SEND) { + xqc_conn_reinject_unack_packets(conn, XQC_REINJ_UNACK_AFTER_SEND); + xqc_conn_send_packets(conn); + } + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->next_tick_time = xqc_conn_next_wakeup_time(conn); + if (XQC_LIKELY(conn->next_tick_time != 0)) { + xqc_engine_remove_active_queue(engine, conn); + xqc_engine_add_wakeup_queue(engine, conn); + goto finish; + } + } + } + + conn->next_tick_time = 0; + xqc_engine_remove_active_queue(engine, conn); + xqc_engine_add_wakeup_queue(engine, conn); + +finish: + if (!xqc_pq_empty(engine->conns_active_pq)) { + /* If there are other acitve connections, we must wakeup immediately. */ + xqc_engine_wakeup_once(engine); + + } else { + wake_after = xqc_engine_wakeup_after(engine); + if (wake_after > 0) { + engine->eng_callback.set_event_timer(wake_after, engine->user_data); + } + } + + engine->eng_flag &= ~XQC_ENG_FLAG_RUNNING; + xqc_log(engine->log, XQC_LOG_DEBUG, "|END|"); + return; +} + /** * Process all connections @@ -845,33 +890,25 @@ xqc_engine_main_logic(xqc_engine_t *engine) } engine->eng_flag |= XQC_ENG_FLAG_RUNNING; - xqc_log(engine->log, XQC_LOG_DEBUG, "|BEGIN|"); - xqc_usec_t now = xqc_monotonic_timestamp(); xqc_connection_t *conn; - while (!xqc_wakeup_pq_empty(engine->conns_wait_wakeup_pq)) { - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); + xqc_log(engine->log, XQC_LOG_DEBUG, "|BEGIN|now:%ui|", now); + + while (!xqc_pq_empty(engine->conns_wait_wakeup_pq)) { + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(engine->conns_wait_wakeup_pq); if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { - xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); /* no push between top and pop */ + xqc_log(engine->log, XQC_LOG_ERROR, "|wakeup|NULL ptr, skip|"); + xqc_conns_pq_pop(engine->conns_wait_wakeup_pq); /* no push between top and pop */ continue; } conn = el->conn; - /* xqc_log(conn->log, XQC_LOG_DEBUG, "|wakeup|conn:%p|state:%s|flag:%s|now:%ui|wakeup:%ui|", - conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag), now, el->wakeup_time); */ - if (el->wakeup_time <= now) { - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - - } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|"); - } + if (el->time_us <= now) { + xqc_engine_remove_wakeup_queue(engine, conn); + if (xqc_engine_add_active_queue(engine, conn) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|"); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); } } else { @@ -881,36 +918,20 @@ xqc_engine_main_logic(xqc_engine_t *engine) while (!xqc_pq_empty(engine->conns_active_pq)) { conn = xqc_conns_pq_pop_top_conn(engine->conns_active_pq); + if (XQC_UNLIKELY(conn == NULL)) { - xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); + xqc_log(engine->log, XQC_LOG_ERROR, "|active|NULL ptr, skip|"); continue; } now = xqc_monotonic_timestamp(); xqc_engine_process_conn(conn, now); - - if (XQC_UNLIKELY(conn->conn_state == XQC_CONN_STATE_CLOSED)) { - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(engine->log, XQC_LOG_INFO, "|destroy conn from conns_active_pq while closed|" - "conn:%p|%s", conn, xqc_conn_addr_str(conn)); - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - continue; - - } else { + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { conn->last_ticked_time = now; - xqc_conn_schedule_packets_to_paths(conn); - if (xqc_engine_is_sendmmsg_on(engine)) { + if (xqc_engine_is_sendmmsg_on(engine, conn)) { xqc_conn_transmit_pto_probe_packets_batch(conn); xqc_conn_retransmit_lost_packets_batch(conn); xqc_conn_send_packets_batch(conn); @@ -926,63 +947,29 @@ xqc_engine_main_logic(xqc_engine_t *engine) xqc_conn_send_packets(conn); } - if (XQC_UNLIKELY(conn->conn_state == XQC_CONN_STATE_CLOSED)) { - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(engine->log, XQC_LOG_INFO, "|destroy conn from conns_active_pq after sending|" - "conn:%p|%s", conn, xqc_conn_addr_str(conn)); - - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - continue; - } - - conn->next_tick_time = xqc_conn_next_wakeup_time(conn); - if (conn->next_tick_time) { - if (!(conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, conn->next_tick_time, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - - } else { - /* remove from pq then push again, update wakeup time */ - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, conn->next_tick_time, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - - } else { - /* it's unexpected that conn's tick timer is unset */ - xqc_log(conn->log, XQC_LOG_ERROR, "|destroy_connection|"); - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(conn->log, XQC_LOG_ERROR, "|destroy unexpected conn with tick timer unset|"); - - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->next_tick_time = xqc_conn_next_wakeup_time(conn); + if (XQC_LIKELY(conn->next_tick_time != 0)) { + conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + xqc_engine_add_wakeup_queue(engine, conn); + continue; } - continue; } } - /* - * xqc_engine_process_conn may insert conns_active_pq, XQC_CONN_FLAG_TICKING prevents - * duplicate insertions and must be placed after xqc_engine_process_conn. - */ + /* conn should be destroyed ( closed or next_tick_time = 0) */ conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { + xqc_log(engine->log, XQC_LOG_INFO, "|conn:%p|%s|" + "conn_state:%ud|next_tick_time:%ui", + conn, xqc_conn_addr_str(conn), + conn->conn_state, conn->next_tick_time); + xqc_conn_destroy(conn); + + } else { + conn->next_tick_time = 0; + xqc_engine_add_wakeup_queue(engine, conn); + } } xqc_usec_t wake_after = xqc_engine_wakeup_after(engine); @@ -992,7 +979,7 @@ xqc_engine_main_logic(xqc_engine_t *engine) engine->eng_flag &= ~XQC_ENG_FLAG_RUNNING; - xqc_log(engine->log, XQC_LOG_DEBUG, "|END|"); + xqc_log(engine->log, XQC_LOG_DEBUG, "|END|now:%ui|", now); return; } @@ -1022,7 +1009,8 @@ xqc_engine_handle_stateless_reset(xqc_engine_t *engine, return -XQC_ERROR; } - hash = xqc_hash_string(sr_token, XQC_STATELESS_RESET_TOKENLEN); + hash = xqc_siphash_get_hash(&engine->conns_hash_sr_token->siphash_ctx, + sr_token, XQC_STATELESS_RESET_TOKENLEN); str.data = (unsigned char *)sr_token; str.len = XQC_STATELESS_RESET_TOKENLEN; @@ -1031,7 +1019,7 @@ xqc_engine_handle_stateless_reset(xqc_engine_t *engine, if (NULL == conn) { /* can't find connection with sr_token */ xqc_log(engine->log, XQC_LOG_DEBUG, "|can't find conn with sr|sr:%s", - xqc_sr_token_str(sr_token)); + xqc_sr_token_str(engine, sr_token)); return -XQC_ERROR; } @@ -1107,25 +1095,18 @@ xqc_engine_process_sr_pkt(xqc_engine_t *engine, const unsigned char *buf, * Pass received UDP packet payload into xquic engine. * @param recv_time UDP packet received time in microsecond */ -#ifdef XQC_NO_PID_PACKET_PROCESS xqc_int_t xqc_engine_packet_process(xqc_engine_t *engine, const unsigned char *packet_in_buf, size_t packet_in_size, const struct sockaddr *local_addr, socklen_t local_addrlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen, xqc_usec_t recv_time, void *user_data) -#else -xqc_int_t -xqc_engine_packet_process(xqc_engine_t *engine, - const unsigned char *packet_in_buf, size_t packet_in_size, - const struct sockaddr *local_addr, socklen_t local_addrlen, - const struct sockaddr *peer_addr, socklen_t peer_addrlen, - uint64_t path_id, xqc_usec_t recv_time, void *user_data) -#endif { xqc_int_t ret; xqc_connection_t *conn = NULL; xqc_cid_t dcid, scid; /* dcid: cid of peer; scid: cid of endpoint */ + xqc_log_level_t lvl; + xqc_cid_init_zero(&dcid); xqc_cid_init_zero(&scid); @@ -1133,7 +1114,7 @@ xqc_engine_packet_process(xqc_engine_t *engine, ret = xqc_packet_parse_cid(&scid, &dcid, engine->config->cid_len, (unsigned char *)packet_in_buf, packet_in_size); if (XQC_UNLIKELY(ret != XQC_OK)) { - xqc_log(engine->log, XQC_LOG_INFO, "|fail to parse cid|ret:%d|", ret); + xqc_log_event(engine->log, TRA_PACKET_DROPPED, "fail to parse cid", ret, "unknown", 0); return -XQC_EILLPKT; } @@ -1151,7 +1132,8 @@ xqc_engine_packet_process(xqc_engine_t *engine, { conn = xqc_conn_server_create(engine, local_addr, local_addrlen, peer_addr, peer_addrlen, &dcid, &scid, - &default_conn_settings, user_data); + &engine->default_conn_settings, user_data); + xqc_log_event(engine->log, CON_SERVER_LISTENING, peer_addr, peer_addrlen); if (conn == NULL) { xqc_log(engine->log, XQC_LOG_ERROR, "|fail to create connection|"); return -XQC_ECREATE_CONN; @@ -1179,8 +1161,16 @@ xqc_engine_packet_process(xqc_engine_t *engine, return -XQC_ECONN_NFOUND; } - xqc_log(engine->log, XQC_LOG_STATS, "|fail to find connection, send " - "reset|size:%uz|scid:%s|", packet_in_size, xqc_scid_str(&scid)); + lvl = XQC_LOG_STATS; + if (engine->eng_type == XQC_ENGINE_CLIENT) { + lvl = XQC_LOG_REPORT; + } + + xqc_log(engine->log, lvl, "|fail to find connection, send reset|" + "size:%uz|scid:%s|recv_time:%ui|peer_addr:%s|local_addr:%s", + packet_in_size, xqc_scid_str(engine, &scid), recv_time, + xqc_peer_addr_str(engine, peer_addr, peer_addrlen), + xqc_local_addr_str(engine, local_addr, local_addrlen)); ret = xqc_engine_send_reset(engine, &scid, peer_addr, peer_addrlen, local_addr, local_addrlen, packet_in_size, @@ -1193,7 +1183,6 @@ xqc_engine_packet_process(xqc_engine_t *engine, } process: - xqc_log_event(conn->log, TRA_DATAGRAMS_RECEIVED, packet_in_size); xqc_log(engine->log, XQC_LOG_INFO, "|==>|conn:%p|size:%uz|state:%s|recv_time:%ui|", conn, packet_in_size, xqc_conn_state_2_str(conn->conn_state), recv_time); @@ -1257,11 +1246,7 @@ xqc_engine_packet_process(xqc_engine_t *engine, } /* process packets */ -#ifdef XQC_NO_PID_PACKET_PROCESS ret = xqc_conn_process_packet(conn, packet_in_buf, packet_in_size, recv_time); -#else - ret = xqc_conn_process_packet(conn, packet_in_buf, packet_in_size, path_id, recv_time); -#endif conn->rcv_pkt_stats.conn_udp_pkts++; @@ -1288,26 +1273,20 @@ xqc_engine_packet_process(xqc_engine_t *engine, goto after_process; } } -#ifdef XQC_NO_PID_PACKET_PROCESS + xqc_conn_process_packet_recved_path(conn, &scid, packet_in_size, recv_time); -#else - xqc_conn_process_packet_recved_path(conn, &scid, path_id, packet_in_size, recv_time); -#endif xqc_timer_set(&conn->conn_timer_manager, XQC_TIMER_CONN_IDLE, recv_time, xqc_conn_get_idle_timeout(conn) * 1000); after_process: - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - - } else { - xqc_log(engine->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|conn:%p|", conn); - XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); - xqc_conn_destroy(conn); - return -XQC_EFATAL; - } + xqc_engine_remove_wakeup_queue(engine, conn); + + if (xqc_engine_add_active_queue(engine, conn) != XQC_OK) { + xqc_log(engine->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|conn:%p|", conn); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + xqc_conn_destroy(conn); + return -XQC_EFATAL; } /* main logic */ @@ -1340,7 +1319,7 @@ xqc_engine_config_get_cid_len(xqc_engine_t *engine) xqc_int_t xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs) + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx) { /* register alpn in tls context */ xqc_int_t ret = xqc_tls_ctx_register_alpn(engine->tls_ctx, alpn, alpn_len); @@ -1348,7 +1327,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, return ret; } - xqc_alpn_registration_t *registration = xqc_malloc(sizeof(xqc_alpn_registration_t)); + xqc_alpn_registration_t *registration = xqc_calloc(1, sizeof(xqc_alpn_registration_t)); if (NULL == registration) { xqc_log(engine->log, XQC_LOG_ERROR, "|create alpn registration error!"); return -XQC_EMALLOC; @@ -1366,6 +1345,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, registration->alpn[alpn_len] = '\0'; registration->alpn_len = alpn_len; registration->ap_cbs = *ap_cbs; + registration->alp_ctx = alp_ctx; xqc_list_add_tail(®istration->head, &engine->alpn_reg_list); @@ -1376,7 +1356,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs) + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx) { xqc_list_head_t *pos, *next; xqc_alpn_registration_t *alpn_reg; @@ -1393,12 +1373,31 @@ xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len { /* if found registration, update */ alpn_reg->ap_cbs = *ap_cbs; + alpn_reg->alp_ctx = alp_ctx; return XQC_OK; } } /* not registered, add into alpn_reg_list */ - return xqc_engine_add_alpn(engine, alpn, alpn_len, ap_cbs); + return xqc_engine_add_alpn(engine, alpn, alpn_len, ap_cbs, alp_ctx); +} + +void* +xqc_engine_get_alpn_ctx(xqc_engine_t *engine, const char *alpn, size_t alpn_len) +{ + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + + xqc_list_for_each_safe(pos, next, &engine->alpn_reg_list) { + alpn_reg = xqc_list_entry(pos, xqc_alpn_registration_t, head); + if (alpn_reg && alpn_len == alpn_reg->alpn_len + && xqc_memcmp(alpn, alpn_reg->alpn, alpn_len) == 0) + { + return alpn_reg->alp_ctx; + } + } + + return NULL; } @@ -1476,8 +1475,83 @@ xqc_engine_free_alpn_list(xqc_engine_t *engine) } xqc_bool_t -xqc_engine_is_sendmmsg_on(xqc_engine_t *engine) +xqc_engine_is_sendmmsg_on(xqc_engine_t *engine, xqc_connection_t *conn) { return engine->config->sendmmsg_on - && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex); + && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex) + && (!conn->conn_settings.disable_send_mmsg); +} + + +void* +xqc_engine_get_priv_ctx(xqc_engine_t *engine) +{ + return engine->priv_ctx; +} + + +xqc_int_t +xqc_engine_set_priv_ctx(xqc_engine_t *engine, void *priv_ctx) +{ + if (engine->priv_ctx) { + return -XQC_ESTATE; + } + + engine->priv_ctx = priv_ctx; + return XQC_OK; +} + + +xqc_int_t +xqc_engine_add_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if (!(conn->conn_flag & (XQC_CONN_FLAG_WAIT_WAKEUP | XQC_CONN_FLAG_TICKING))) { + if(xqc_conns_pq_push(engine->conns_wait_wakeup_pq, + conn, conn->next_tick_time) != XQC_OK) + { + return -XQC_EMALLOC; + } + xqc_log(conn->log, XQC_LOG_DEBUG, "|next_tick_time:%ui|", conn->next_tick_time); + conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; + } + return XQC_OK; +} + +xqc_int_t +xqc_engine_remove_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|next_tick_time:%ui|pq_index:%ud|", conn->next_tick_time, conn->wakeup_pq_index); + xqc_conns_pq_remove(engine->conns_wait_wakeup_pq, conn); + + conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; + } + return XQC_OK; +} + +xqc_int_t +xqc_engine_add_active_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + xqc_int_t ret = XQC_OK; + if (!(conn->conn_flag & (XQC_CONN_FLAG_WAIT_WAKEUP | XQC_CONN_FLAG_TICKING))) { + ret = xqc_conns_pq_push(engine->conns_active_pq, + conn, conn->last_ticked_time); + if (ret == 0) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|last_ticked_time:%ui|", conn->last_ticked_time); + conn->conn_flag |= XQC_CONN_FLAG_TICKING; + ret = XQC_OK; + } + } + return ret; +} + +xqc_int_t +xqc_engine_remove_active_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if ((conn->conn_flag & XQC_CONN_FLAG_TICKING)) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|last_ticked_time:%ui|pd_index:%ud|", conn->last_ticked_time, conn->wakeup_pq_index); + xqc_conns_pq_remove(engine->conns_active_pq, conn); + conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + } + return XQC_OK; } diff --git a/src/transport/xqc_engine.h b/src/transport/xqc_engine.h index 6f1a6b974..fc8d8ef45 100644 --- a/src/transport/xqc_engine.h +++ b/src/transport/xqc_engine.h @@ -33,6 +33,8 @@ typedef struct xqc_alpn_registration_s { /* Application-Layer-Protocol callback functions */ xqc_app_proto_callbacks_t ap_cbs; + void *alp_ctx; + } xqc_alpn_registration_t; @@ -48,14 +50,13 @@ typedef struct xqc_engine_s { xqc_str_hash_table_t *conns_hash_dcid; /* For reset packet */ xqc_str_hash_table_t *conns_hash_sr_token; /* For stateless reset */ xqc_pq_t *conns_active_pq; /* In process */ - xqc_wakeup_pq_t *conns_wait_wakeup_pq; /* Need wakeup after next tick time */ + xqc_pq_t *conns_wait_wakeup_pq; /* Need wakeup after next tick time */ uint8_t reset_sent_cnt[XQC_RESET_CNT_ARRAY_LEN]; /* remote addr hash */ xqc_usec_t reset_sent_cnt_cleared; /* tls context */ xqc_tls_ctx_t *tls_ctx; - /* common */ xqc_log_t *log; xqc_random_generator_t *rand_generator; @@ -68,6 +69,18 @@ typedef struct xqc_engine_s { /* list of xqc_alpn_registration_t */ xqc_list_head_t alpn_reg_list; + xqc_conn_settings_t default_conn_settings; + + char scid_buf[XQC_MAX_CID_LEN * 2 + 1]; + char dcid_buf[XQC_MAX_CID_LEN * 2 + 1]; + char sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2 + 1]; + char conn_flag_str_buf[1024]; + char frame_type_buf[128]; + char local_addr_str[INET6_ADDRSTRLEN]; + char peer_addr_str[INET6_ADDRSTRLEN]; + + void *priv_ctx; + } xqc_engine_t; @@ -97,9 +110,19 @@ void xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now); void xqc_engine_main_logic_internal(xqc_engine_t *engine); +void xqc_engine_conn_logic(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_add_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_remove_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_add_active_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_remove_active_queue(xqc_engine_t *engine, xqc_connection_t *conn); + xqc_int_t xqc_engine_get_alpn_callbacks(xqc_engine_t *engine, const char *alpn, size_t alpn_len, xqc_app_proto_callbacks_t *cbs); -xqc_bool_t xqc_engine_is_sendmmsg_on(xqc_engine_t *engine); +xqc_bool_t xqc_engine_is_sendmmsg_on(xqc_engine_t *engine, xqc_connection_t *conn); #endif diff --git a/src/transport/xqc_fec.c b/src/transport/xqc_fec.c new file mode 100644 index 000000000..24346b278 --- /dev/null +++ b/src/transport/xqc_fec.c @@ -0,0 +1,1574 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_conn.h" +#include "src/transport/xqc_send_queue.h" +#include "src/transport/xqc_packet_out.h" + + +#define XQC_FEC_MAX_SCHEME_VAL 32 +#define MAX_FEC_CODE_RATE (20) + +xqc_int_t +xqc_set_valid_encoder_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) +{ + switch (scheme) { +#ifdef XQC_ENABLE_RSC + case XQC_REED_SOLOMON_CODE: + callback->xqc_fec_init = xqc_reed_solomon_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_reed_solomon_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_reed_solomon_code_cb.xqc_fec_encode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_XOR + case XQC_XOR_CODE: + callback->xqc_fec_init = xqc_xor_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_xor_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_xor_code_cb.xqc_fec_encode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_PKM + case XQC_PACKET_MASK_CODE: + callback->xqc_fec_init = xqc_packet_mask_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_packet_mask_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_packet_mask_code_cb.xqc_fec_encode; + return XQC_OK; +#endif + } + + return -XQC_EFEC_SCHEME_ERROR; +} + +xqc_int_t +xqc_set_valid_decoder_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) +{ + switch (scheme) { +#ifdef XQC_ENABLE_RSC + case XQC_REED_SOLOMON_CODE: + callback->xqc_fec_decode = xqc_reed_solomon_code_cb.xqc_fec_decode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_XOR + case XQC_XOR_CODE: + callback->xqc_fec_decode = xqc_xor_code_cb.xqc_fec_decode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_PKM + case XQC_PACKET_MASK_CODE: + callback->xqc_fec_decode_one = xqc_packet_mask_code_cb.xqc_fec_decode_one; + return XQC_OK; +#endif + } + + return -XQC_EFEC_SCHEME_ERROR; +} + +unsigned char * +xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme) +{ + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + return "Reed-Solomon"; + case XQC_XOR_CODE: + return "XOR"; + case XQC_PACKET_MASK_CODE: + return "Packet-Mask"; + default: + return "NO_FEC"; + } +} + +unsigned char* +xqc_get_fec_enc_level_str(xqc_fec_level_e fec_level) +{ + switch (fec_level) { + case XQC_FEC_CONN_LEVEL: + return "FEC_CONN_LEVEL"; + case XQC_FEC_STREAM_LEVEL: + return "FEC_STREAM_LEVEL"; + default: + return "UNDEFINED"; + } +} + +unsigned char * +xqc_get_fec_mp_mode_str(xqc_fec_ctl_t *fec_ctl) +{ + if (fec_ctl == NULL) { + return "NO_FEC"; + } + if (fec_ctl->fec_mp_mode == XQC_FEC_MP_USE_STB) { + if (fec_ctl->fec_rep_path_id != XQC_MAX_UINT64_VALUE) { + return "USE_STB_PATH"; + } else { + return "NO_AVAI_STB_PATH"; + } + } + return "DEFAULT"; +} + +xqc_int_t +xqc_set_final_scheme(xqc_connection_t *conn, xqc_fec_schemes_e *local_fec_schemes_buff, xqc_int_t *local_fec_schemes_buff_len, + xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len) +{ + uint32_t p, schemes_flag; + xqc_int_t i, ret; + + if (*local_fec_schemes_buff_len == 0 || remote_fec_schemes_buff_len == 0) { + return 0; + } + + p = schemes_flag = 0; + ret = 0; + + for (i = 0; i < remote_fec_schemes_buff_len; i++) { + if (remote_fec_schemes_buff[i] > XQC_FEC_MAX_SCHEME_VAL) { + continue; + } + p = 1 << remote_fec_schemes_buff[i]; + schemes_flag |= p; + } + + /* 初始化schemes_flag */ + for (i = 0; i < *local_fec_schemes_buff_len; i++) { + if (schemes_flag & (1 << local_fec_schemes_buff[i])) { + ret = local_fec_schemes_buff[i]; + break; + } + } + + return ret; +} + +xqc_int_t +xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) +{ + switch (in) { + case XQC_REED_SOLOMON_CODE: + *out = XQC_REED_SOLOMON_CODE; + return XQC_OK; + case XQC_XOR_CODE: + *out = XQC_XOR_CODE; + return XQC_OK; + case XQC_PACKET_MASK_CODE: + *out = XQC_PACKET_MASK_CODE; + return XQC_OK; + default: + break; + } + + return -XQC_EFEC_SCHEME_ERROR; +} + +xqc_int_t +xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, + xqc_fec_schemes_e *fec_schemes_buff, xqc_int_t *fec_schemes_buff_len) +{ + xqc_int_t i = 0, j = 0; + + for (i = 0; i < XQC_FEC_MAX_SCHEME_NUM; i++) + { + fec_schemes_buff[i] = 0; + } + + *fec_schemes_buff_len = 0; + for (i = 0, j = 0; i < schemes_len && j < XQC_FEC_MAX_SCHEME_NUM; i++) { + switch (schemes[i]) { + case XQC_XOR_CODE: + fec_schemes_buff[j] = XQC_XOR_CODE; + j++; + break; + case XQC_REED_SOLOMON_CODE: + fec_schemes_buff[j] = XQC_REED_SOLOMON_CODE; + j++; + break; + case XQC_PACKET_MASK_CODE: + fec_schemes_buff[j] = XQC_PACKET_MASK_CODE; + j++; + break; + default: + break; + } + + if (j != *fec_schemes_buff_len) { + *fec_schemes_buff_len = j; + } + } + return XQC_OK; +} + +/** + * @brief + * return XQC_TRUE if obj and cmp_buff has SAME payload content, + * otherwise return XQC_FALSE + * @param obj + * @param cmp_buff + * @return xqc_bool_t + */ +xqc_bool_t +xqc_fec_object_compare(xqc_fec_object_t *obj, unsigned char *cmp_buff) +{ + size_t obj_size; + unsigned char *obj_buff; + + if (!obj->is_valid) { + return XQC_FALSE; + } + obj_size = obj->payload_size; + obj_buff = obj->payload; + return xqc_memcmp(obj_buff, cmp_buff, obj_size) == 0 ? XQC_TRUE : XQC_FALSE; +} + +xqc_int_t +xqc_send_repair_packets_ahead(xqc_connection_t *conn, xqc_list_head_t *prev, uint8_t fec_bm_mode) +{ + uint32_t i, fss_esi, repair_num, cur_syb_num, tmp_repair_num; + xqc_int_t ret; + unsigned char *repair_key_p; + + if (fec_bm_mode >= XQC_BLOCK_MODE_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|invalid fec_bm_mode:%d|", fec_bm_mode); + return -XQC_EPARAM; + } + + cur_syb_num = conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]; + fss_esi = conn->fec_ctl->fec_send_block_num[fec_bm_mode]; + repair_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + tmp_repair_num = 0; + + if (cur_syb_num <= 1) { + /* TODO: whether protect if only one src syb? */ + return XQC_OK; + } + + for (i = 0; i < repair_num; i++) { + if (!conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i].is_valid) { + continue; + } + + xqc_packet_out_t *packet_out = xqc_write_one_repair_packet(conn, fss_esi, tmp_repair_num, fec_bm_mode); + if (packet_out == NULL) { + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|generate one repair packet error"); + return -XQC_EFEC_SYMBOL_ERROR; + } + tmp_repair_num++; + conn->fec_ctl->fec_send_ahead++; + xqc_send_queue_move_to_head(&packet_out->po_list, prev); + prev = &packet_out->po_list; + } + + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); + + return XQC_OK; +} + +xqc_int_t +xqc_send_repair_packets(xqc_connection_t *conn, xqc_fec_schemes_e scheme, xqc_list_head_t *prev, + uint8_t fec_bm_mode) +{ + uint32_t i, fss_esi, repair_num, pm_size, tmp_repair_num; + xqc_int_t ret; + unsigned char *pm_p; + + if (fec_bm_mode >= XQC_BLOCK_MODE_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|invalid fec_bm_mode:%d|", fec_bm_mode); + return -XQC_EPARAM; + } + + repair_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + fss_esi = conn->fec_ctl->fec_send_block_num[fec_bm_mode]; + tmp_repair_num = 0; + + if (repair_num > XQC_REPAIR_LEN) { + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|repair number exceeds buff size"); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (repair_num > conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]) { + xqc_log(conn->log, XQC_LOG_ERROR, "|source symbols number or repair symbol number invalid|src:%d|rpr:%d|", conn->fec_ctl->fec_send_symbol_num[fec_bm_mode], repair_num); + return -XQC_EFEC_SYMBOL_ERROR; + } + + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + case XQC_XOR_CODE: + /* Generate repair packets */ + ret = xqc_write_repair_packets(conn, fss_esi, prev, repair_num, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_gen_repair_packet error|"); + return -XQC_EWRITE_PKT; + } + break; + case XQC_PACKET_MASK_CODE: + for (i = 0; i < repair_num; i++) { + pm_p = conn->fec_ctl->fec_send_decode_matrix[fec_bm_mode][i]; + if (xqc_fec_object_compare(&conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i], pm_p)) { + xqc_packet_out_t *packet_out = xqc_write_one_repair_packet(conn, fss_esi, tmp_repair_num, fec_bm_mode); + if (packet_out == NULL) { + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|generate one repair packet error"); + continue; + } + + tmp_repair_num++; + xqc_send_queue_move_to_head(&packet_out->po_list, prev); + prev = &packet_out->po_list; + } + } + break; + default: + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|error type of fec scheme"); + return -XQC_EFEC_SCHEME_ERROR; + } + + return XQC_OK; +} + +xqc_int_t +xqc_is_packet_fec_protected(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + if (packet_out->po_flag & XQC_POF_USE_FEC + && packet_out->po_frame_types & conn->conn_settings.fec_params.fec_protected_frames) + { + return XQC_OK; + } + + return -XQC_EFEC_NOT_SUPPORT_FEC; +} + +xqc_int_t +xqc_check_fec_params(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t repair_symbol_num, + xqc_int_t max_window_size, xqc_int_t symbol_size) +{ + if (repair_symbol_num < 0 || repair_symbol_num > XQC_REPAIR_LEN || repair_symbol_num > src_symbol_num) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid fec repair symbol:%d|src_num:%d|", repair_symbol_num, src_symbol_num); + return -XQC_EFEC_SCHEME_ERROR; + } + if (repair_symbol_num == 0) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|current code rate is too low to generate repair packets."); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (src_symbol_num <= 0 || src_symbol_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|src_symbol_num invalid|%d|", src_symbol_num); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (max_window_size <= 0 || max_window_size > XQC_SYMBOL_CACHE_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|max_window_size invalid|%d|", max_window_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (symbol_size < 0 || symbol_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|symbol_size invalid|%d|", symbol_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + + return XQC_OK; +} + +/* process fec protected packet with stream mode */ +xqc_int_t +xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + uint8_t fec_bm_mode; + xqc_int_t i, ret, fss_esi, header_len, payload_len, max_src_symbol_num, repair_symbol_num; + xqc_fec_schemes_e encoder_scheme; + unsigned char *p; + + header_len = packet_out->po_payload - packet_out->po_buf; + payload_len = packet_out->po_used_size - header_len; + fec_bm_mode = packet_out->po_stream_fec_blk_mode; + max_src_symbol_num = xqc_get_fec_blk_size(conn, fec_bm_mode); + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + encoder_scheme = conn->conn_settings.fec_params.fec_encoder_scheme; + + ret = xqc_check_fec_params(conn, max_src_symbol_num, repair_symbol_num, conn->conn_settings.fec_params.fec_max_window_size, payload_len); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_is_fec_params_valid|fec params invalid|"); + return -XQC_EPARAM; + } + + /* attach sid frame to current packet */ + ret = xqc_write_sid_frame_to_one_packet(conn, packet_out); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + + } else if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_write_sid_frame_to_one_packet error|"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + /* FEC encoder */ + ret = xqc_fec_encoder(conn, packet_out->po_payload, payload_len, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder error|"); + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); + return ret; + } + + conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] += 1; + /* Try to generate repair packets, only succeed when send_symbol_numbers satisfy the limits */ + if (conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] == max_src_symbol_num) { + ret = xqc_send_repair_packets(conn, conn->conn_settings.fec_params.fec_encoder_scheme, &packet_out->po_list, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_send_repair_packets error: %d|", ret); + } + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); + } + + return XQC_OK; +} +void +xqc_stream_fec_init(xqc_stream_t *stream) +{ + double fec_code_rate; + xqc_connection_t *conn; + + conn = stream->stream_conn; + + // if FEC negotiation success, set current block size + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE) { + // set fec symbol number in trans stream in the first round + if (stream->stream_fec_ctl.stream_fec_syb_num != 0) { + conn->conn_settings.fec_params.fec_code_rate = stream->stream_fec_ctl.fec_code_rate; + xqc_fec_on_stream_size_changed(stream); + } + } +} + + +xqc_int_t +xqc_process_fec_protected_packet_moq(xqc_stream_t *stream) +{ + uint8_t fec_bm_mode; + xqc_int_t ret, header_len, payload_len, max_src_symbol_num, repair_symbol_num; + xqc_list_head_t *pos, *next; + xqc_list_head_t *fec_enc_pkts; + xqc_packet_out_t *packet_out; + xqc_connection_t *conn; + xqc_send_queue_t *send_queue; + + fec_bm_mode = 0; + conn = stream->stream_conn; + send_queue = conn->conn_send_queue; + // fec_enc_pkts = &stream->stream_fec_ctl.stream_fec_send_packets; + fec_enc_pkts = stream->stream_fec_ctl.stream_fec_head; + + + xqc_stream_fec_init(stream); + max_src_symbol_num = stream->stream_fec_ctl.stream_fec_syb_num; + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + + ret = xqc_check_fec_params(conn, xqc_min(max_src_symbol_num, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK), repair_symbol_num, conn->conn_settings.fec_params.fec_max_window_size, 0); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_is_fec_params_valid|fec params invalid|"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + xqc_list_for_each_safe(pos, next, fec_enc_pkts) { + packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); + header_len = packet_out->po_payload - packet_out->po_buf; + payload_len = packet_out->po_used_size - header_len; + if (payload_len < 0 || payload_len > XQC_MAX_SYMBOL_SIZE) { + continue; + } + /* attach sid frame to current packet */ + ret = xqc_write_sid_frame_to_one_packet(conn, packet_out); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + + } else if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_write_sid_frame_to_one_packet error|"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + /* FEC encoder */ + ret = xqc_fec_encoder(conn, packet_out->po_payload, payload_len, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder error|"); + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); + return ret; + } + + conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] += 1; + /* if source symbols number GT max symbol number(48), generate repair packets in ahead */ + if (conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] == XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + ret = xqc_send_repair_packets(conn, XQC_PACKET_MASK_CODE, (&conn->conn_send_queue->sndq_send_packets)->prev, 0); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_send_repair_packets error: %d|", ret); + break; + } + + stream->stream_stats.fec_send_rpr_cnt += repair_symbol_num; + + xqc_fec_ctl_init_send_params(conn, 0); + stream->stream_fec_ctl.stream_fec_syb_num -= XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; + if (stream->stream_fec_ctl.stream_fec_syb_num != 0) { + xqc_fec_on_stream_size_changed(stream); + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + } + } + + if (pos == stream->stream_fec_ctl.stream_fec_tail) { + break; + } + } + + if (stream->stream_fec_ctl.stream_fec_syb_num != 0) { + /* Try to generate repair packets, only succeed when send_symbol_numbers satisfy the limits */ + ret = xqc_send_repair_packets(conn, XQC_PACKET_MASK_CODE, (&conn->conn_send_queue->sndq_send_packets)->prev, 0); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_send_repair_packets error: %d|", ret); + + } else { + stream->stream_stats.fec_send_rpr_cnt += repair_symbol_num; + } + } + + ret = xqc_fec_ctl_init_send_params(conn, 0); + + stream->stream_fec_ctl.stream_fec_syb_num = 0; + stream->stream_fec_ctl.stream_fec_head = stream->stream_fec_ctl.stream_fec_tail = NULL; + + return XQC_OK; +} + + +xqc_int_t +xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id, uint8_t bm_idx) +{ + xqc_connection_t *conn = fec_ctl->conn; + + if (fec_ctl->fec_send_block_num[bm_idx] > XQC_FEC_MAX_BLOCK_NUM || fec_ctl->fec_send_symbol_num[bm_idx] > XQC_FEC_MAX_SYMBOL_NUM) { + return -XQC_EFEC_SYMBOL_ERROR; + } + *payload_id = fec_ctl->fec_send_block_num[bm_idx] << 8 | fec_ctl->fec_send_symbol_num[bm_idx]; + return XQC_OK; +} + +xqc_fec_ctl_t * +xqc_fec_ctl_create(xqc_connection_t *conn) +{ + xqc_int_t i, j; + uint32_t repair_num; + xqc_fec_ctl_t *fec_ctl = NULL; + + fec_ctl = xqc_calloc(1, sizeof(xqc_fec_ctl_t)); + if (fec_ctl == NULL) { + return NULL; + } + + fec_ctl->conn = conn; + if (conn->conn_settings.fec_params.fec_code_rate == 0) { + fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = 1; + + } else { + repair_num = xqc_max(1, conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate); + fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = xqc_min(repair_num, XQC_REPAIR_LEN); + } + + if (conn->conn_settings.enable_multipath) { + fec_ctl->fec_mp_mode = conn->conn_settings.fec_params.fec_mp_mode; + } + fec_ctl->fec_rep_path_id = XQC_MAX_UINT64_VALUE; + + for (i = 0; i < XQC_REPAIR_LEN; i++) { + unsigned char *recv_syb_p = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (recv_syb_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_gen_repair_symbols_buff[i], 0, recv_syb_p, 0); + } + + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; + } + fec_ctl->fec_send_block_num[i] = i; + for (j = 0; j < XQC_REPAIR_LEN; j++) { + unsigned char *key_p = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + if (key_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_send_repair_key[i][j], 0, key_p, 0); + + unsigned char *syb_p = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (syb_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_send_repair_symbols_buff[i][j], 0, syb_p, 0); + } + } + + for (i = 0; i < XQC_FEC_BLOCK_NUM; i++) { + fec_ctl->latest_stream_id[i] = -1; + } + + // FEC 2.0: init repair symbols list and source symbols list + fec_ctl->fec_src_syb_num = 0; + fec_ctl->fec_rpr_syb_num = 0; + xqc_init_list_head(&fec_ctl->fec_recv_rpr_syb_list); + xqc_init_list_head(&fec_ctl->fec_recv_src_syb_list); + xqc_init_list_head(&fec_ctl->fec_free_src_list); + xqc_init_list_head(&fec_ctl->fec_free_rpr_list); + + return fec_ctl; +process_emalloc: + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|create_fec_ctl fail to malloc for params"); + xqc_fec_ctl_destroy(fec_ctl); + return NULL; +} + +void +xqc_fec_ctl_destroy(xqc_fec_ctl_t *fec_ctl) +{ + xqc_int_t i, j; + xqc_list_head_t *pos, *next; + + fec_ctl->fec_flow_id = 0; + for (i = 0; i < XQC_REPAIR_LEN; i++) { + if (fec_ctl->fec_gen_repair_symbols_buff[i].payload != NULL) { + xqc_free(fec_ctl->fec_gen_repair_symbols_buff[i].payload); + fec_ctl->fec_gen_repair_symbols_buff[i].is_valid = 0; + } + } + + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; + } + fec_ctl->fec_send_symbol_num[i] = 0; + fec_ctl->fec_send_block_num[i] = 0; + for (j = 0; j < XQC_REPAIR_LEN; j++) { + if (fec_ctl->fec_send_repair_key[i][j].payload != NULL) { + xqc_free(fec_ctl->fec_send_repair_key[i][j].payload); + fec_ctl->fec_send_repair_key[i][j].is_valid = 0; + } + if (fec_ctl->fec_send_repair_symbols_buff[i][j].payload != NULL) { + xqc_free(fec_ctl->fec_send_repair_symbols_buff[i][j].payload); + fec_ctl->fec_send_repair_symbols_buff[i][j].is_valid = 0; + } + } + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_free_src_list) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_free_rpr_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol->repair_key); + xqc_free(symbol->recv_mask); + xqc_free(symbol); + } + + xqc_free(fec_ctl); +} + +void +xqc_set_fec_blk_size(xqc_connection_t *conn, xqc_transport_params_t params) +{ + switch (params.fec_version) { + case XQC_FEC_02: + xqc_memcpy(conn->fec_ctl->fec_send_block_mode_size, fec_blk_size_v2, XQC_BLOCK_MODE_LEN); + break; + + default: + break; + } +} + +uint8_t +xqc_get_fec_blk_size(xqc_connection_t *conn, uint8_t blk_md) { + if (blk_md == XQC_DEFAULT_SIZE_REQ) { + return xqc_min(XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, xqc_max(0, conn->conn_settings.fec_params.fec_max_symbol_num_per_block)); + } + return conn->fec_ctl->fec_send_block_mode_size[blk_md]; +} + +xqc_int_t +xqc_fec_ctl_save_symbol(unsigned char **symbol_buff_addr, const unsigned char *data, + xqc_int_t data_len) +{ + if (*symbol_buff_addr == NULL) { + return -XQC_EMALLOC; + } + xqc_memset(*symbol_buff_addr, 0, data_len); + xqc_memcpy(*symbol_buff_addr, data, data_len); + return XQC_OK; +} + +xqc_int_t +xqc_fec_ctl_init_send_params(xqc_connection_t *conn, uint8_t bm_idx) +{ + double loss_rate; + uint32_t send_repair_num; + xqc_int_t i, symbol_size, key_size; + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + + symbol_size = key_size = 0; + fec_ctl->fec_send_symbol_num[bm_idx] = 0; + + for (i = 0 ; i < XQC_REPAIR_LEN; i++) { + if (conn->conn_settings.fec_params.fec_encoder_scheme != XQC_REED_SOLOMON_CODE) { + if (fec_ctl->fec_send_repair_key[bm_idx][i].is_valid) { + fec_ctl->fec_send_repair_key[bm_idx][i].payload_size = XQC_MAX_RPR_KEY_SIZE; + xqc_init_object_value(&fec_ctl->fec_send_repair_key[bm_idx][i]); + } + } + if (fec_ctl->fec_send_repair_symbols_buff[bm_idx][i].is_valid) { + fec_ctl->fec_send_repair_symbols_buff[bm_idx][i].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&fec_ctl->fec_send_repair_symbols_buff[bm_idx][i]); + } + } + // each time init send param, add 1 to send_block_num, so that symbol from different block won't be mixed + if (conn->fec_ctl->fec_send_block_num[bm_idx] >= XQC_FEC_MAX_BLOCK_NUM - XQC_BLOCK_MODE_LEN) { + conn->fec_ctl->fec_send_block_num[bm_idx] = bm_idx; + + } else { + conn->fec_ctl->fec_send_block_num[bm_idx] += XQC_BLOCK_MODE_LEN; + } + + if (conn->conn_settings.fec_params.fec_code_rate == 0 && conn->conn_settings.fec_params.fec_encoder_scheme != XQC_XOR_CODE) { + loss_rate = xqc_conn_recent_loss_rate(conn); + send_repair_num = xqc_min(XQC_REPAIR_LEN, xqc_max(1, (int)(loss_rate * xqc_get_fec_blk_size(conn, bm_idx) / 100))); + if (conn->fec_ctl->fec_send_required_repair_num[bm_idx] != send_repair_num) { + // edit encode repair key + conn->fec_ctl->fec_send_required_repair_num[bm_idx] = send_repair_num; + conn->conn_settings.fec_callback.xqc_fec_init_one(conn, bm_idx); + } + } + return XQC_OK; +} + +void +xqc_set_object_value(xqc_fec_object_t *object, xqc_int_t is_valid, + unsigned char *payload, size_t size) +{ + object->is_valid = is_valid; + object->payload = payload; + object->payload_size = xqc_min(XQC_MAX_SYMBOL_SIZE, size); +} + +void +xqc_init_object_value(xqc_fec_object_t *object) +{ + object->is_valid = 0; + xqc_memset(object->payload, 0, object->payload_size); + object->payload_size = 0; +} + +void +xqc_init_src_symbol_value(xqc_fec_src_syb_t *symbol) +{ + symbol->block_id = 0; + symbol->symbol_idx = 0; + xqc_memset(symbol->payload, 0, xqc_min(XQC_MAX_SYMBOL_SIZE, symbol->payload_size)); + symbol->payload_size = 0; +} + +void +xqc_init_rpr_symbol_value(xqc_fec_rpr_syb_t *symbol) +{ + symbol->block_id = 0; + symbol->symbol_idx = 0; + xqc_memset(symbol->payload, 0, XQC_MAX_SYMBOL_SIZE); + symbol->payload_size = 0; + xqc_memset(symbol->repair_key, 0, XQC_MAX_RPR_KEY_SIZE); + xqc_memset(symbol->recv_mask, 0, XQC_MAX_RPR_KEY_SIZE); + symbol->repair_key_size = 0; +} + +void +xqc_remove_src_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_src_syb_t *src_symbol) +{ + xqc_list_del_init(&src_symbol->fec_list); + xqc_init_src_symbol_value(src_symbol); + // save payload for further uses + xqc_list_add_tail(&src_symbol->fec_list, &fec_ctl->fec_free_src_list); + fec_ctl->fec_src_syb_num--; +} + +void +xqc_remove_rpr_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_rpr_syb_t *rpr_symbol) +{ + xqc_list_del_init(&rpr_symbol->fec_list); + xqc_init_rpr_symbol_value(rpr_symbol); + // save payload for further uses + xqc_list_add_tail(&rpr_symbol->fec_list, &fec_ctl->fec_free_rpr_list); + fec_ctl->fec_rpr_syb_num--; +} + +xqc_int_t +xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t j, symbol_size, key_size; + xqc_list_head_t *pos, *next; + + + // FEC 2.0 update symbols list + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + xqc_remove_src_symbol_from_list(fec_ctl, src_symbol); + } + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + xqc_remove_rpr_symbol_from_list(fec_ctl, rpr_symbol); + } + } + + return XQC_OK; +} + +xqc_int_t +xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params) +{ + xqc_int_t ret, encode_scheme, decode_scheme; + xqc_trans_settings_t *ls = &conn->local_settings; + ret = -XQC_EFEC_NOT_SUPPORT_FEC; + /* + * 如果对端发来了多种FEC schemes选择,接收端需要选择其中的一种FEC schemes并重新encode local_settings + * AS Server: + * 如果FEC协商成功 且 收到的FEC schemes列表长度大于1,需要进行选择; + * 随后需要进行重新设置并encode选择完成后的schemes list,其长度必须为1; + * AS Client: + * 需要设置服务端选择的FEC Scheme至conn_settings + */ + if (params.fec_version == XQC_ERR_FEC_VERSION) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|remote fec version is not supported."); + conn->fec_neg_fail_reason |= XQC_OLD_FEC_VERSION; + return ret; + } + + if (ls->enable_encode_fec && params.enable_decode_fec) { + // server should provide only 1 scheme if negotiation success; + if (conn->conn_type == XQC_CONN_TYPE_CLIENT + && params.fec_decoder_schemes_num > 1) + { + conn->fec_neg_fail_reason |= XQC_CLIENT_RECEIVE_INV_DEC; + goto set_decoder; + } + + encode_scheme = xqc_set_final_scheme(conn, ls->fec_encoder_schemes, &ls->fec_encoder_schemes_num, + params.fec_decoder_schemes, params.fec_decoder_schemes_num); + if (encode_scheme == 0) { + ls->enable_encode_fec = 0; + conn->conn_settings.enable_encode_fec = 0; + conn->fec_neg_fail_reason |= XQC_NO_COMMON_FEC_ENC; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec encoder schemes failed."); + goto set_decoder; + } + // set valid encoder scheme + ret = xqc_set_valid_encoder_scheme_cb(&conn->conn_settings.fec_callback, encode_scheme); + if (ret != XQC_OK) { + ls->enable_encode_fec = 0; + conn->conn_settings.enable_encode_fec = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set fec encoder cb failed with scheme num: %d", encode_scheme); + goto set_decoder; + } + conn->conn_settings.fec_params.fec_encoder_scheme = encode_scheme; + // change fec scheme in local_settings + ls->fec_encoder_schemes[0] = conn->conn_settings.fec_params.fec_encoder_scheme; + ls->fec_encoder_schemes_num = 1; + xqc_log(conn->log, XQC_LOG_INFO, "|set final encoder fec scheme: %s|fec_level: %s|", + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_encoder_scheme), xqc_get_fec_enc_level_str(conn->conn_settings.fec_level)); + ret = XQC_OK; + } + +set_decoder: + if (ls->enable_decode_fec && params.enable_encode_fec) { + // server should provide only 1 scheme if negotiation success; + if (conn->conn_type == XQC_CONN_TYPE_CLIENT + && params.fec_encoder_schemes_num > 1) + { + conn->fec_neg_fail_reason |= XQC_CLIENT_RECEIVE_INV_ENC; + goto end; + } + + decode_scheme = xqc_set_final_scheme(conn, ls->fec_decoder_schemes, &ls->fec_decoder_schemes_num, + params.fec_encoder_schemes, params.fec_encoder_schemes_num); + if (decode_scheme == 0) { + ls->enable_decode_fec = 0; + conn->conn_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_NO_COMMON_FEC_DEC; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec decoder schemes failed."); + goto end; + } + // set valid encoder scheme + ret = xqc_set_valid_decoder_scheme_cb(&conn->conn_settings.fec_callback, decode_scheme); + if (ret != XQC_OK) { + ls->enable_decode_fec = 0; + conn->conn_settings.enable_decode_fec = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set fec decoder cb failed with scheme num: %d", decode_scheme); + goto end; + } + conn->conn_settings.fec_params.fec_decoder_scheme = decode_scheme; + // change fec scheme in local_settings + ls->fec_decoder_schemes[0] = conn->conn_settings.fec_params.fec_decoder_scheme; + ls->fec_decoder_schemes_num = 1; + xqc_log(conn->log, XQC_LOG_INFO, "|set final decoder fec scheme: %s", + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_decoder_scheme)); + ret = XQC_OK; + } +end: + if (conn->conn_type == XQC_CONN_TYPE_CLIENT) { + if (conn->conn_settings.fec_params.fec_encoder_scheme == 0) { + conn->conn_settings.enable_encode_fec = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec encoder schemes failed."); + } + if (conn->conn_settings.fec_params.fec_decoder_scheme == 0) { + conn->conn_settings.enable_decode_fec = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec decoder schemes failed."); + } + } + return ret; +} +xqc_int_t +xqc_insert_src_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + uint64_t block_id, uint64_t symbol_idx, xqc_int_t *blk_output, + unsigned char *symbol, xqc_int_t symbol_size) +{ + xqc_list_head_t *pos, *next; + xqc_int_t ret, blk_num_flag; + xqc_fec_src_syb_t *src_symbol; + + ret = 0; + blk_num_flag = 1; + src_symbol = NULL; + + xqc_list_for_each_reverse_safe(pos, next, symbol_list) { + xqc_fec_src_syb_t *cur_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (block_id < cur_symbol->block_id) { + continue; + } + if (block_id == cur_symbol->block_id) { + if (symbol_idx < cur_symbol->symbol_idx) { + continue; + + } else if (cur_symbol->symbol_idx == symbol_idx) { + // current symbol already exists. + return -XQC_EFEC_TOLERABLE_ERROR; + } + } + break; + + } + + // push into src symbol list; + src_symbol = xqc_build_src_symbol(conn, block_id, symbol_idx, symbol, symbol_size); + if (src_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|build source symbol error|block_id:%d|symbol_idx:%d|symbol_size:%d", block_id, symbol_idx, symbol_size); + return -XQC_EMALLOC; + } + + // insert into proper position + xqc_list_add(&src_symbol->fec_list, pos); + *blk_output += 1; + return XQC_OK; +} + +xqc_int_t +xqc_insert_rpr_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + xqc_fec_rpr_syb_t *tmp_rpr_symbol, xqc_int_t *blk_output, xqc_fec_rpr_syb_t **rpr_symbol) +{ + xqc_list_head_t *pos, *next; + xqc_int_t ret, blk_num_flag, window_limit, block_id, symbol_idx; + + ret = 0; + blk_num_flag = 1; + window_limit = conn->conn_settings.fec_params.fec_max_window_size; + *rpr_symbol = NULL; + block_id = tmp_rpr_symbol->block_id; + symbol_idx = tmp_rpr_symbol->symbol_idx; + + if (block_id < 0) { + return -XQC_EFEC_SYMBOL_ERROR; + } + + xqc_list_for_each_reverse_safe(pos, next, symbol_list) { + xqc_fec_rpr_syb_t *cur_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (block_id < cur_symbol->block_id) { + continue; + } + + if (block_id == cur_symbol->block_id) { + if (symbol_idx < cur_symbol->symbol_idx) { + continue; + + } else if (cur_symbol->symbol_idx == symbol_idx) { + // current symbol already exists. + return -XQC_EFEC_TOLERABLE_ERROR; + } + } + break; + } + + // insert into rpr symbol list; + *rpr_symbol = xqc_build_rpr_symbol(conn, tmp_rpr_symbol); + if (*rpr_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|build repair symbol error|block_id:%d|symbol_idx:%d|symbol_size:%d", block_id, symbol_idx, tmp_rpr_symbol->payload_size); + return -XQC_EMALLOC; + } + + // insert into proper position + xqc_list_add(&(*rpr_symbol)->fec_list, pos); + *blk_output += 1; + return XQC_OK; +} + + +xqc_fec_src_syb_t * +xqc_create_src_symbol() +{ + xqc_fec_src_syb_t *src_symbol = (xqc_fec_src_syb_t *)xqc_calloc(1, sizeof(xqc_fec_src_syb_t)); + if (src_symbol == NULL) { + return NULL; + } + + src_symbol->payload = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (src_symbol->payload == NULL) { + xqc_free(src_symbol); + return NULL; + } + + return src_symbol; +} + +xqc_fec_rpr_syb_t * +xqc_create_rpr_symbol() +{ + xqc_fec_rpr_syb_t *rpr_symbol = (xqc_fec_rpr_syb_t *)xqc_calloc(1, sizeof(xqc_fec_rpr_syb_t)); + if (rpr_symbol == NULL) { + return NULL; + } + rpr_symbol->payload = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + rpr_symbol->repair_key = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + rpr_symbol->recv_mask = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + if (rpr_symbol->payload == NULL || rpr_symbol->repair_key == NULL || rpr_symbol->recv_mask == NULL) { + if (rpr_symbol->payload != NULL) { + xqc_free(rpr_symbol->payload); + } + if (rpr_symbol->repair_key != NULL) { + xqc_free(rpr_symbol->repair_key); + } + if (rpr_symbol->recv_mask != NULL) { + xqc_free(rpr_symbol->recv_mask); + } + xqc_free(rpr_symbol); + return NULL; + } + return rpr_symbol; +} + +xqc_fec_src_syb_t * +xqc_new_src_symbol(xqc_list_head_t *fec_free_list) +{ + // try to fetch an available symbol in free list, otherwise malloc a new space + xqc_list_head_t *pos, *next; + xqc_fec_src_syb_t *src_symbol; + + xqc_list_for_each_safe(pos, next, fec_free_list) { + src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_list_del_init(&src_symbol->fec_list); + if (src_symbol->payload == NULL) { + xqc_free(src_symbol); + return NULL; + } + return src_symbol; + } + return xqc_create_src_symbol(); +} + +xqc_fec_rpr_syb_t * +xqc_new_rpr_symbol(xqc_list_head_t *fec_free_list) +{ + // try to fetch an available symbol in free list, otherwise malloc a new space + xqc_list_head_t *pos, *next; + xqc_fec_rpr_syb_t *rpr_symbol; + + xqc_list_for_each_safe(pos, next, fec_free_list) { + rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_list_del_init(&rpr_symbol->fec_list); + return rpr_symbol; + } + return xqc_create_rpr_symbol(); +} + +xqc_fec_rpr_syb_t * +xqc_get_rpr_symbol(xqc_list_head_t *head, uint64_t block_id, uint64_t symbol_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (symbol->block_id > block_id) { + break; + } + if (symbol->block_id == block_id) { + if (symbol->symbol_idx > symbol_id) { + break; + } + if (symbol->symbol_idx == symbol_id){ + return symbol; + } + } + } + return NULL; +} + +void +xqc_update_rpr_symbol_mask_on_src(xqc_list_head_t *head, xqc_int_t block_id, + xqc_int_t pi_sym_idx) +{ + xqc_list_head_t *pos, *next; + xqc_int_t mask_offset; + + mask_offset = pi_sym_idx / 8; + + if (mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + return; + } + + // traverse rpr list + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (symbol->block_id > block_id) { + break; + } + + if (symbol->block_id == block_id + && *(symbol->repair_key + mask_offset) & (1 << (7 - pi_sym_idx % 8))) + { + *(symbol->recv_mask + mask_offset) |= (1 << (7 - pi_sym_idx % 8)); + } + } +} + +void +xqc_update_rpr_symbol_mask_on_rpr(xqc_list_head_t *head, xqc_fec_rpr_syb_t *rpr_symbol) +{ + xqc_list_head_t *pos, *next; + + // traverse src list + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_int_t block_id, symbol_idx, mask_offset; + + block_id = symbol->block_id; + symbol_idx = symbol->symbol_idx; + mask_offset = symbol_idx / 8; + + if (mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + continue; + } + + if (block_id > rpr_symbol->block_id) { + break; + } + + if (block_id == rpr_symbol->block_id + && *(rpr_symbol->repair_key + mask_offset) & (1 << (7 - symbol_idx % 8))) + { + *(rpr_symbol->recv_mask + mask_offset) |= (1 << (7 - symbol_idx % 8)); + } + } +} + + +xqc_fec_src_syb_t * +xqc_build_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size) +{ + xqc_int_t is_repair_symbol = 0, ret; + xqc_list_head_t *fec_free_src_list; + xqc_fec_src_syb_t *src_symbol = NULL; + + if (symbol_size > XQC_MAX_SYMBOL_SIZE) { + return src_symbol; + } + + fec_free_src_list = &conn->fec_ctl->fec_free_src_list; + src_symbol = xqc_new_src_symbol(fec_free_src_list); + if (src_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|get src symbol error|"); + return NULL; + } + src_symbol->block_id = block_id; + src_symbol->symbol_idx = symbol_idx; + xqc_memcpy(src_symbol->payload, symbol, symbol_size); + src_symbol->payload_size = symbol_size; + xqc_init_list_head(&src_symbol->fec_list); + + return src_symbol; +} + + +xqc_fec_rpr_syb_t * +xqc_build_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol) +{ + size_t symbol_size, repair_key_size; + xqc_int_t is_repair_symbol = 1, ret; + xqc_list_head_t *fec_free_rpr_list; + xqc_fec_rpr_syb_t *rpr_symbol = NULL; + + symbol_size = tmp_rpr_symbol->payload_size; + repair_key_size = tmp_rpr_symbol->repair_key_size; + + if (symbol_size > XQC_MAX_SYMBOL_SIZE || repair_key_size > XQC_MAX_RPR_KEY_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol params|symbol_size:%d|symbol_key_size:%d|", symbol_size, repair_key_size); + return rpr_symbol; + } + + fec_free_rpr_list = &conn->fec_ctl->fec_free_rpr_list; + rpr_symbol = xqc_new_rpr_symbol(fec_free_rpr_list); + + if (rpr_symbol == NULL || rpr_symbol->payload == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|get rpr symbol error|"); + return rpr_symbol; + } + rpr_symbol->block_id = tmp_rpr_symbol->block_id; + rpr_symbol->symbol_idx = tmp_rpr_symbol->symbol_idx; + xqc_memcpy(rpr_symbol->payload, tmp_rpr_symbol->payload, symbol_size); + rpr_symbol->payload_size = symbol_size; + xqc_memcpy(rpr_symbol->repair_key, tmp_rpr_symbol->repair_key, repair_key_size); + rpr_symbol->repair_key_size = repair_key_size; + xqc_init_list_head(&rpr_symbol->fec_list); + + return rpr_symbol; +} + +xqc_int_t +xqc_get_min_src_blk_num(xqc_connection_t *conn) +{ + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + if (!xqc_list_empty(&fec_ctl->fec_recv_src_syb_list)) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(fec_ctl->fec_recv_src_syb_list.next, xqc_fec_src_syb_t, fec_list); + return src_symbol->block_id; + } + return -1; +} + +xqc_int_t +xqc_get_min_rpr_blk_num(xqc_connection_t *conn) +{ + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + if (!xqc_list_empty(&fec_ctl->fec_recv_rpr_syb_list)) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(fec_ctl->fec_recv_rpr_syb_list.next, xqc_fec_rpr_syb_t, fec_list); + return rpr_symbol->block_id; + } + return -1; +} + + +xqc_bool_t +xqc_if_src_blk_exists(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id == block_id) { + return XQC_TRUE; + } + } + return XQC_FALSE; +} + +xqc_bool_t +xqc_if_rpr_blk_exists(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id == block_id) { + return XQC_TRUE; + } + } + return XQC_FALSE; +} + + +xqc_int_t +xqc_process_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size) +{ + xqc_int_t ret, window_size, min_block_id; + xqc_fec_ctl_t *fec_ctl; + xqc_list_head_t *symbol_list, *rpr_list; + xqc_fec_src_syb_t *src_symbol; + + window_size = conn->conn_settings.fec_params.fec_max_window_size; + fec_ctl = conn->fec_ctl; + symbol_list = &conn->fec_ctl->fec_recv_src_syb_list; + src_symbol = NULL; + + if (block_id != 0 + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id) + && block_id <= conn->fec_ctl->fec_max_fin_blk_id) + { + return -XQC_EFEC_TOLERABLE_ERROR; + } + + if (conn->fec_ctl->fec_src_syb_num > window_size + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id)) + { + while (conn->fec_ctl->fec_src_syb_num > window_size) { + min_block_id = xqc_get_min_src_blk_num(conn); + if (min_block_id == -1) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|window_size and src_symbol_list length is not match"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + // flush the smallest old block + xqc_fec_ctl_init_recv_params(conn->fec_ctl, min_block_id); + } + } + + // insert into src symbol_list according to block id and symbol idx + ret = xqc_insert_src_symbol_by_seq(conn, symbol_list, block_id, symbol_idx, &conn->fec_ctl->fec_src_syb_num, symbol, symbol_size); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|current symbol is already exists|block_id:%d|symbol_idx:%d", block_id, symbol_idx); + return ret; + } + + // update repair symbol recv_mask + if (conn->conn_settings.fec_params.fec_decoder_scheme == XQC_PACKET_MASK_CODE) { + rpr_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + xqc_update_rpr_symbol_mask_on_src(rpr_list, block_id, symbol_idx); + } + + return XQC_OK; +} + + +xqc_int_t +xqc_process_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol) +{ + xqc_int_t ret, window_size, min_block_id, block_id; + xqc_fec_ctl_t *fec_ctl; + xqc_list_head_t *symbol_list, *src_list; + xqc_fec_rpr_syb_t *rpr_symbol; + + window_size = conn->conn_settings.fec_params.fec_max_window_size; + fec_ctl = conn->fec_ctl; + symbol_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + rpr_symbol = NULL; + min_block_id = xqc_get_min_rpr_blk_num(conn); + block_id = tmp_rpr_symbol->block_id; + + if (block_id != 0 + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id) + && block_id <= conn->fec_ctl->fec_max_fin_blk_id) + { + return -XQC_EFEC_TOLERABLE_ERROR; + } + + if (conn->fec_ctl->fec_rpr_syb_num > window_size + && !xqc_if_rpr_blk_exists(conn->fec_ctl, block_id)) + { + while (conn->fec_ctl->fec_rpr_syb_num > window_size) { + min_block_id = xqc_get_min_rpr_blk_num(conn); + if (min_block_id == -1) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|window_size and rpr_symbol_list length is not match"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + // flush the smallest old block + xqc_fec_ctl_init_recv_params(conn->fec_ctl, min_block_id); + } + } + + // insert into src symbol_list according to block id and symbol idx + ret = xqc_insert_rpr_symbol_by_seq(conn, symbol_list, tmp_rpr_symbol, &conn->fec_ctl->fec_rpr_syb_num, &rpr_symbol); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|current symbol is already exists|block_id:%d|symbol_idx:%d", block_id, tmp_rpr_symbol->symbol_idx); + return ret; + } + + // link src symbols to the rpr symbols using pkt mask + if (conn->conn_settings.fec_params.fec_decoder_scheme == XQC_PACKET_MASK_CODE) { + src_list = &conn->fec_ctl->fec_recv_src_syb_list; + xqc_update_rpr_symbol_mask_on_rpr(src_list, rpr_symbol); + tmp_rpr_symbol->recv_mask = rpr_symbol->recv_mask; + } + rpr_symbol->recv_time = xqc_monotonic_timestamp(); + + return XQC_OK; +} + +xqc_int_t +xqc_get_symbol_flag(xqc_connection_t *conn, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + xqc_int_t symbol_flag, max_src_symbol_num; + + symbol_flag = 0; + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + symbol_flag |= (1 << src_symbol->symbol_idx); + } + } + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + symbol_flag |= (1 << (rpr_symbol->symbol_idx + max_src_symbol_num)); + } + } + return symbol_flag; +} + +xqc_int_t +xqc_get_symbols_buff(unsigned char **output, xqc_fec_ctl_t *fec_ctl, uint64_t block_id, size_t *size) +{ + xqc_list_head_t *pos, *next, *fec_recv_src_syb_list, *fec_recv_rpr_syb_list; + xqc_int_t i = 0; + + fec_recv_src_syb_list = &fec_ctl->fec_recv_src_syb_list; + fec_recv_rpr_syb_list = &fec_ctl->fec_recv_rpr_syb_list; + *size = 0; + + // check 一下当前block idx能否成功被flush + + xqc_list_for_each_safe(pos, next, fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_syb = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_syb->block_id == block_id) { + xqc_memcpy(output[i++], src_syb->payload, xqc_min(XQC_MAX_SYMBOL_SIZE, src_syb->payload_size)); + } + } + + xqc_list_for_each_safe(pos, next, fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_syb = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_syb->block_id == block_id) { + if (rpr_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + return -XQC_EPARAM; + } + xqc_memcpy(output[i++], rpr_syb->payload, xqc_min(XQC_MAX_SYMBOL_SIZE, rpr_syb->payload_size)); + if (rpr_syb->payload_size > *size) { + *size = rpr_syb->payload_size; + } + } + } + return i; +} + + +xqc_int_t +xqc_cnt_src_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t ret = 0; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + ret++; + } + } + return ret; +} + +xqc_int_t +xqc_cnt_rpr_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t ret = 0; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + ret++; + } + } + return ret; +} + +void +xqc_on_fec_negotiate_success(xqc_connection_t *conn, xqc_transport_params_t params) +{ + uint8_t i; + if (conn->conn_settings.enable_encode_fec) { + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE) { + xqc_set_fec_blk_size(conn, params); + for (i = XQC_NORMAL_SIZE_REQ; i < XQC_BLOCK_MODE_LEN; i++) { + if (conn->conn_settings.fec_params.fec_code_rate == 0) { + conn->fec_ctl->fec_send_required_repair_num[i] = 1; + + } else { + conn->fec_ctl->fec_send_required_repair_num[i] = xqc_min(xqc_max(1, conn->fec_ctl->fec_send_block_mode_size[i] * conn->conn_settings.fec_params.fec_code_rate), XQC_REPAIR_LEN); + } + } + } + if (conn->conn_settings.fec_callback.xqc_fec_init != NULL) { + conn->conn_settings.fec_callback.xqc_fec_init(conn); + } + } +} + +xqc_int_t +xqc_get_fec_rpr_num(float fec_code_rate, xqc_int_t src_syb_num) +{ + return xqc_min(XQC_REPAIR_LEN, xqc_max(1, xqc_min(src_syb_num, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) * fec_code_rate + 1)); +} + +void +xqc_fec_on_stream_size_changed(xqc_stream_t *quic_stream) +{ + float fec_code_rate; + xqc_connection_t *conn; + uint32_t src_syb_num, rpr_syb_num; + + conn = quic_stream->stream_conn; + src_syb_num = xqc_min(quic_stream->stream_fec_ctl.stream_fec_syb_num, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK); + // fec_code_rate should be pre-set in bitrate_allocator + fec_code_rate = conn->conn_settings.fec_params.fec_code_rate; + rpr_syb_num = xqc_get_fec_rpr_num(fec_code_rate, src_syb_num); + + // if fec block size or repair number is different, init fec parameters + if (conn->fec_ctl->fec_send_required_repair_num[0] != rpr_syb_num + || conn->conn_settings.fec_params.fec_max_symbol_num_per_block != src_syb_num) + { + conn->fec_ctl->fec_send_required_repair_num[0] = rpr_syb_num; + conn->conn_settings.fec_params.fec_max_symbol_num_per_block = src_syb_num; + conn->conn_settings.fec_callback.xqc_fec_init_one(conn, 0); + } +} \ No newline at end of file diff --git a/src/transport/xqc_fec.h b/src/transport/xqc_fec.h new file mode 100644 index 000000000..29c39262a --- /dev/null +++ b/src/transport/xqc_fec.h @@ -0,0 +1,223 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_H_INCLUDED_ +#define _XQC_FEC_H_INCLUDED_ + + +#include +#include +#include +#include "src/transport/xqc_packet_out.h" +// #include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_transport_params.h" +#include "src/common/xqc_str.h" +#include "src/transport/xqc_stream.h" + + +#define XQC_FEC_BLOCK_NUM 10 +#define XQC_FEC_ELE_BIT_SIZE_DEFAULT 8 +#define XQC_FEC_MAX_SYMBOL_NUM_TOTAL 256 +#define XQC_FEC_MAX_SYMBOL_PAYLOAD_ID 0xffffffff - XQC_FEC_MAX_SYMBOL_NUM_TOTAL +#define XQC_FEC_MAX_BLOCK_NUM 0x00ffffff +#define XQC_FEC_MAX_SYMBOL_NUM 0x000000ff +#define XQC_FEC_MAX_SYMBOL_NUM_PBLOCK 48 /* 2^XQC_FEC_ELE_BIT_SIZE_DEFAULT */ +#define XQC_FEC_CODE_RATE_DEFAULT 0.95 +#define XQC_REPAIR_LEN 10 /* (1-XQC_FEC_CODE_RATE_DEFAULT) * XQC_FEC_MAX_SYMBOL_NUM_PBLOCK */ +#define XQC_BLOCK_MODE_LEN 5 +#define XQC_SYMBOL_CACHE_LEN 96 +#define XQC_MAX_RPR_KEY_SIZE 10 +#define XQC_MAX_SYMBOL_SIZE XQC_MAX_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_FEC_SPACE +#define XQC_MAX_PM_SIZE 288 + +static const uint8_t fec_blk_size_v2[XQC_BLOCK_MODE_LEN] = {0, 0, 4, 10, 20}; +typedef struct xqc_fec_object_s { + size_t payload_size; + xqc_int_t is_valid; + unsigned char *payload; +} xqc_fec_object_t; + +// FEC 2.0 params + +typedef struct xqc_fec_src_syb_s { + size_t payload_size; + unsigned char *payload; + xqc_list_head_t fec_list; + xqc_int_t block_id; + xqc_int_t symbol_idx; + xqc_stream_id_t stream_id; +} xqc_fec_src_syb_t; + +typedef struct xqc_fec_rpr_syb_s { + size_t payload_size; + unsigned char *payload; + size_t repair_key_size; + unsigned char *repair_key; + unsigned char *recv_mask; + xqc_list_head_t fec_list; + xqc_int_t block_id; + xqc_int_t symbol_idx; + xqc_usec_t recv_time; +} xqc_fec_rpr_syb_t; + +typedef struct xqc_fec_payload_s { + unsigned char *payload; + xqc_list_head_t pld_list; +} xqc_fec_payload_t; + +typedef enum { + XQC_LOCAL_NOT_SUPPORT_ENC = 1 << 0, + XQC_LOCAL_NOT_SUPPORT_DEC = 1 << 1, + XQC_REMOTE_NOT_SUPPORT_ENC = 1 << 2, + XQC_REMOTE_NOT_SUPPORT_DEC = 1 << 3, + XQC_NO_COMMON_FEC_ENC = 1 << 4, + XQC_NO_COMMON_FEC_DEC = 1 << 5, + XQC_OLD_FEC_VERSION = 1 << 6, + XQC_CLIENT_RECEIVE_INV_ENC = 1 << 7, + XQC_CLIENT_RECEIVE_INV_DEC = 1 << 8, + XQC_REMOTE_PARAM_ERR = 1 << 9 +} xqc_fec_neg_fail_reason_e; + + + +typedef struct xqc_fec_ctl_s { + xqc_connection_t *conn; + + xqc_int_t fec_flow_id; + uint32_t fec_recover_pkt_cnt; + uint32_t fec_processed_blk_num; + uint32_t fec_flush_blk_cnt; + uint32_t fec_recover_failed_cnt; + uint32_t fec_recv_repair_num_total; + uint32_t fec_send_repair_num_total; + uint32_t fec_send_ahead; + xqc_int_t fec_max_fin_blk_id; + xqc_stream_id_t latest_stream_id[XQC_FEC_BLOCK_NUM]; + + xqc_fec_mp_mode_e fec_mp_mode; + uint64_t fec_rep_path_id; + + uint32_t fec_send_block_num[XQC_BLOCK_MODE_LEN]; + uint8_t fec_send_block_mode_size[XQC_BLOCK_MODE_LEN]; + uint32_t fec_send_required_repair_num[XQC_BLOCK_MODE_LEN]; + uint32_t fec_send_symbol_num[XQC_BLOCK_MODE_LEN]; /* src symbols number for current fec process */ + xqc_fec_object_t fec_send_repair_key[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN]; + xqc_fec_object_t fec_send_repair_symbols_buff[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN]; + uint8_t fec_send_decode_matrix[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN][XQC_MAX_RPR_KEY_SIZE]; + unsigned char decode_matrix[2 * XQC_RSM_COL][XQC_RSM_COL]; + + // FEC 2.0 params + xqc_list_head_t fec_free_src_list; + xqc_list_head_t fec_free_rpr_list; + xqc_list_head_t fec_recv_src_syb_list; /* source symbols (including recovered source symbols) list */ + xqc_list_head_t fec_recv_rpr_syb_list; /* repair symbols list */ + + xqc_int_t fec_src_syb_num; + xqc_int_t fec_rpr_syb_num; + xqc_fec_object_t fec_gen_repair_symbols_buff[XQC_REPAIR_LEN]; + + xqc_int_t fec_enable_stream_num; /* number of stream that enables fec */ + xqc_msec_t conn_avg_recv_delay; /* fec averaged one way receive delay time */ + xqc_msec_t fec_avg_opt_time; /* fec averaged one way receive delay time */ +} xqc_fec_ctl_t; + +xqc_int_t xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out); +/* + * @desc + * copy fec schemes from schemes to fec_schemes_buff, filtered by xqc_fec_schemes_e + */ +xqc_int_t xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, + xqc_fec_schemes_e *fec_schemes_buff, xqc_int_t *fec_schemes_buff_len); + + +/* + * @desc + * server set the final fec scheme + */ +xqc_int_t xqc_set_final_scheme(xqc_connection_t *conn, xqc_fec_schemes_e *local_fec_schemes_buff, xqc_int_t *local_fec_schemes_buff_len, + xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len); + + +xqc_int_t xqc_is_packet_fec_protected(xqc_connection_t *conn, xqc_packet_out_t *packet_out); + + + +xqc_fec_ctl_t *xqc_fec_ctl_create(xqc_connection_t *conn); + +void xqc_fec_ctl_destroy(xqc_fec_ctl_t *fec_ctl); + +xqc_int_t xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id, uint8_t bm_idx); + +xqc_int_t xqc_fec_ctl_save_symbol(unsigned char **symbol_buff, const unsigned char *data, + xqc_int_t data_len); + +xqc_int_t xqc_fec_ctl_init_send_params(xqc_connection_t *conn, uint8_t bm_idx); + +xqc_int_t xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); + +unsigned char *xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme); + +unsigned char *xqc_get_fec_mp_mode_str(xqc_fec_ctl_t *fec_ctl); + +xqc_int_t xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params); + +xqc_int_t xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out); + +void xqc_set_object_value(xqc_fec_object_t *object, xqc_int_t is_valid, + unsigned char *payload, size_t size); + +void xqc_init_object_value(xqc_fec_object_t *object); + +xqc_int_t xqc_process_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size); + +xqc_int_t xqc_process_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol); + + +xqc_int_t xqc_get_symbols_buff(unsigned char **output, xqc_fec_ctl_t *fec_ctl, uint64_t block_idx, size_t *size); + +xqc_fec_rpr_syb_t *xqc_get_rpr_symbol(xqc_list_head_t *head, uint64_t block_id, uint64_t symbol_id); + + +xqc_int_t xqc_cnt_src_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); + +xqc_int_t xqc_cnt_rpr_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); + +xqc_int_t xqc_get_symbol_flag(xqc_connection_t *conn, uint64_t block_id); + +xqc_fec_src_syb_t *xqc_build_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size); + +xqc_int_t xqc_insert_src_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + uint64_t block_id, uint64_t symbol_idx, xqc_int_t *blk_output, + unsigned char *symbol, xqc_int_t symbol_size); + +xqc_int_t xqc_insert_rpr_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + xqc_fec_rpr_syb_t *tmp_rpr_symbol, xqc_int_t *blk_output, xqc_fec_rpr_syb_t **rpr_symbol); + +void xqc_remove_rpr_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_rpr_syb_t *rpr_symbol); + +xqc_int_t xqc_check_fec_params(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t total_symbol_num, + xqc_int_t max_window_size, xqc_int_t symbol_size); + +xqc_fec_rpr_syb_t *xqc_build_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol); + +void xqc_set_fec_blk_size(xqc_connection_t *conn, xqc_transport_params_t params); + +uint8_t xqc_get_fec_blk_size(xqc_connection_t *conn, uint8_t blk_md); + +void xqc_on_fec_negotiate_success(xqc_connection_t *conn, xqc_transport_params_t params); + +xqc_int_t xqc_send_repair_packets_ahead(xqc_connection_t *conn, xqc_list_head_t *prev, uint8_t fec_bm_mode); + + +xqc_int_t xqc_send_repair_packets(xqc_connection_t *conn, xqc_fec_schemes_e scheme, xqc_list_head_t *prev, + uint8_t fec_bm_mode); + +xqc_int_t xqc_process_fec_protected_packet_moq(xqc_stream_t *stream); + +void xqc_fec_on_stream_size_changed(xqc_stream_t *quic_stream); +#endif /* _XQC_FEC_H_INCLUDED_ */ \ No newline at end of file diff --git a/src/transport/xqc_fec_scheme.c b/src/transport/xqc_fec_scheme.c new file mode 100644 index 000000000..7af5b7181 --- /dev/null +++ b/src/transport/xqc_fec_scheme.c @@ -0,0 +1,233 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_conn.h" + +xqc_int_t +xqc_fec_encoder_check_params(xqc_connection_t *conn, xqc_int_t repair_symbol_num, xqc_fec_schemes_e encoder_scheme, size_t st_size) +{ + if (encoder_scheme == XQC_XOR_CODE) { + if (repair_symbol_num > 1) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|xor fec scheme can only maintain one repair symbol"); + return -XQC_EPARAM; + } + } + + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|stream size is too large to get fec encode|st_size:%zu|", st_size); + return -XQC_EPARAM; + } + + return XQC_OK; +} + +xqc_int_t +xqc_fec_encoder(xqc_connection_t *conn, unsigned char *input, size_t st_size, uint8_t fec_bm_mode) +{ + xqc_int_t i, ret; + unsigned char *repair_symbols_payload_buff[XQC_REPAIR_LEN] = {0}; + xqc_int_t repair_symbol_num; + + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + + // validate encode params + ret = xqc_fec_encoder_check_params(conn, repair_symbol_num, conn->conn_settings.fec_params.fec_encoder_scheme, st_size); + if (ret != XQC_OK) { + return ret; + } + + if (conn->conn_settings.fec_callback.xqc_fec_encode) { + // encode stream value into fec_send_repair_symbols_buff + for (i = 0; i < repair_symbol_num; i++) { + repair_symbols_payload_buff[i] = conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload; + if (repair_symbols_payload_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fail to malloc memory for fec_send_repair_symbols_buff"); + return -XQC_EMALLOC; + } + } + + ret = conn->conn_settings.fec_callback.xqc_fec_encode(conn, input, st_size, repair_symbols_payload_buff, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|fec scheme encode_uni error"); + return -XQC_EFEC_SCHEME_ERROR; + } + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder|fec encode_uni callback is NULL"); + return -XQC_EFEC_SCHEME_ERROR; + } + + return XQC_OK; +} + +xqc_int_t +xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char *recovered_payload, size_t symbol_size, xqc_usec_t rpr_recv_time) +{ + xqc_int_t i, ret, res; + + res = XQC_OK; + xqc_packet_in_t *new_packet = xqc_calloc(1, sizeof(xqc_packet_in_t)); + if (new_packet == NULL) { + return -XQC_EMALLOC; + } + + new_packet->decode_payload = recovered_payload; + new_packet->decode_payload_len = symbol_size; + new_packet->pos = new_packet->decode_payload; + new_packet->last = new_packet->decode_payload + symbol_size; + new_packet->pkt_recv_time = xqc_monotonic_timestamp(); + new_packet->pi_path_id = 0; + new_packet->pi_flag |= XQC_PIF_FEC_RECOVERED; + new_packet->pi_fec_process_time = rpr_recv_time; + + ret = xqc_process_frames(conn, new_packet); + xqc_free(new_packet); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process recovered packet failed|ret:%d", ret); + res = -XQC_EFEC_SCHEME_ERROR; + + } else { + conn->fec_ctl->fec_recover_pkt_cnt++; + } + return res; +} + + +xqc_int_t +xqc_fec_cc_decoder(xqc_connection_t *conn, xqc_fec_rpr_syb_t *rpr_symbol, uint8_t lack_syb_id) +{ + xqc_int_t ret, block_id, symbol_idx, mask_offset; + unsigned char *payload_p; + + ret = -XQC_EFEC_SYMBOL_ERROR; + block_id = rpr_symbol->block_id; + symbol_idx = rpr_symbol->symbol_idx; + payload_p = conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload; + + if (payload_p == NULL || (rpr_symbol->payload_size <= 0 && rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE)) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol payload"); + goto cc_decoder_end; + } + if (conn->conn_settings.fec_callback.xqc_fec_decode_one == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_decode_one doesn't exists"); + goto cc_decoder_end; + } + + ret = conn->conn_settings.fec_callback.xqc_fec_decode_one(conn, payload_p, block_id, symbol_idx); + xqc_set_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[0], 1, payload_p, rpr_symbol->payload_size); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_decode_one error"); + goto cc_decoder_end; + } + ret = xqc_process_recovered_packet(conn, payload_p, rpr_symbol->payload_size, rpr_symbol->recv_time); + if (ret == XQC_OK) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|process packet of block %d successfully.", block_id); + // insert into source list + ret = xqc_process_src_symbol(conn, block_id, lack_syb_id, payload_p, rpr_symbol->payload_size); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + ret = XQC_OK; + } + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process source symbol error|ret:%d", ret); + } + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process recovered packet error|ret:%d|bid:%d|symbol_size:%d", ret, block_id, rpr_symbol->payload_size); + } + +cc_decoder_end: + if (conn->fec_ctl->fec_gen_repair_symbols_buff[0].is_valid) { + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[0]); + } + conn->fec_ctl->fec_processed_blk_num++; + + if (ret == XQC_OK) { + return XQC_OK; + } + + conn->fec_ctl->fec_recover_failed_cnt++; + return ret; +} + +/** + * @brief fec block code decoder; + * + * @param conn + * @param block_id + * @return xqc_int_t + */ +xqc_int_t +xqc_fec_bc_decoder(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t loss_src_num, xqc_usec_t rpr_time) +{ + size_t symbol_size; + xqc_int_t i, ret, symbol_flag, rpr_syb_num, src_syb_num, symbol_idx; + unsigned char *recovered_symbols_buff[XQC_REPAIR_LEN]; + xqc_list_head_t *pos, *next; + + ret = symbol_size = 0; + /* proceeds if there's no loss src symbol */ + if (loss_src_num == 0) { + ret = XQC_OK; + goto bc_decoder_end; + } + + for (i = 0; i < loss_src_num; i++) { + recovered_symbols_buff[i] = conn->fec_ctl->fec_gen_repair_symbols_buff[i].payload; + if (recovered_symbols_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec_gen_repair_symbols_buff is NULL"); + ret = -XQC_EMALLOC; + goto bc_decoder_end; + } + } + + /* generate loss packets payload */ + if (conn->conn_settings.fec_callback.xqc_fec_decode) { + ret = conn->conn_settings.fec_callback.xqc_fec_decode(conn, recovered_symbols_buff, &symbol_size, block_id); + for (i = 0; i < loss_src_num; i++) { + xqc_set_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[i], 1, recovered_symbols_buff[i], + symbol_size); + } + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|fec scheme decode error"); + ret = -XQC_EFEC_SCHEME_ERROR; + goto bc_decoder_end; + } + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_bc_decoder|fec decode callback is NULL"); + ret = -XQC_EFEC_SCHEME_ERROR; + goto bc_decoder_end; + } + + for (i = 0; i < loss_src_num; i++) { + if (recovered_symbols_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_process_recovered_packet|symbol %d recover failed", i); + break; + } + ret = xqc_process_recovered_packet(conn, recovered_symbols_buff[i], symbol_size, rpr_time); + if (ret == XQC_OK) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|process packet of block %d successfully.", block_id); + } + } + +bc_decoder_end: + conn->fec_ctl->fec_processed_blk_num++; + /* free recovered symbols buff */ + for (i = 0; i < loss_src_num; i++) { + if (conn->fec_ctl->fec_gen_repair_symbols_buff[i].is_valid) { + conn->fec_ctl->fec_gen_repair_symbols_buff[i].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[i]); + } + } + if (ret == XQC_OK) { + return XQC_OK; + } + + conn->fec_ctl->fec_recover_failed_cnt++; + return ret; +} \ No newline at end of file diff --git a/src/transport/xqc_fec_scheme.h b/src/transport/xqc_fec_scheme.h new file mode 100644 index 000000000..e536a44b8 --- /dev/null +++ b/src/transport/xqc_fec_scheme.h @@ -0,0 +1,33 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_SCHEME_H_INCLUDED_ +#define _XQC_FEC_SCHEME_H_INCLUDED_ + + +#include +#include +#include "src/transport/xqc_fec.h" +#include "src/transport/fec_schemes/xqc_reed_solomon.h" + + +typedef enum { + XQC_FEC_ENCODE_TYPE_NORMAL, + XQC_FEC_ENCODE_TYPE_UNI, +} xqc_fec_encode_type_t; + + +xqc_int_t xqc_fec_encoder(xqc_connection_t *conn, unsigned char *input, size_t st_size, uint8_t fec_bm_mode); + +xqc_int_t xqc_fec_bc_decoder(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t loss_src_num, xqc_usec_t rpr_time); + +xqc_int_t xqc_fec_cc_decoder(xqc_connection_t *conn, xqc_fec_rpr_syb_t *rpr_symbol, uint8_t lack_syb_id); + +xqc_int_t xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char *recovered_payload, size_t symbol_size, xqc_usec_t rpr_recv_time); + +xqc_int_t xqc_fec_encoder_check_params(xqc_connection_t *conn, xqc_int_t repair_symbol_num, xqc_fec_schemes_e encoder_scheme, size_t st_size); + +#endif /* _XQC_FEC_SCHEME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index 55b12288c..82a55cd3e 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -45,29 +45,35 @@ static const char * const frame_type_2_str[XQC_FRAME_NUM] = { [XQC_FRAME_ACK_MP] = "ACK_MP", [XQC_FRAME_PATH_ABANDON] = "PATH_ABANDON", [XQC_FRAME_PATH_STATUS] = "PATH_STATUS", + [XQC_FRAME_PATH_AVAILABLE] = "PATH_AVAILABLE", + [XQC_FRAME_PATH_STANDBY] = "PATH_STANDBY", + [XQC_FRAME_MP_NEW_CONNECTION_ID] = "MP_NEW_CONN_ID", + [XQC_FRAME_MP_RETIRE_CONNECTION_ID] = "MP_RETIRE_CONN_ID", + [XQC_FRAME_MAX_PATH_ID] = "MAX_PATH_ID", + [XQC_FRAME_PATH_FROZEN] = "PATH_FROZEN", [XQC_FRAME_DATAGRAM] = "DATAGRAM", [XQC_FRAME_Extension] = "Extension", + [XQC_FRAME_SID] = "FEC_SID", + [XQC_FRAME_REPAIR_SYMBOL] = "FEC_REPAIR", }; -static char g_frame_type_buf[128]; - const char * -xqc_frame_type_2_str(xqc_frame_type_bit_t type_bit) +xqc_frame_type_2_str(xqc_engine_t *engine, xqc_frame_type_bit_t type_bit) { - g_frame_type_buf[0] = '\0'; + engine->frame_type_buf[0] = '\0'; size_t pos = 0; int wsize; for (int i = 0; i < XQC_FRAME_NUM; i++) { if (type_bit & 1 << i) { - wsize = snprintf(g_frame_type_buf + pos, sizeof(g_frame_type_buf) - pos, "%s ", + wsize = snprintf(engine->frame_type_buf + pos, sizeof(engine->frame_type_buf) - pos, "%s ", frame_type_2_str[i]); - if (wsize < 0 || wsize >= sizeof(g_frame_type_buf) - pos) { + if (wsize < 0 || wsize >= sizeof(engine->frame_type_buf) - pos) { break; } pos += wsize; } } - return g_frame_type_buf; + return engine->frame_type_buf; } unsigned int @@ -185,10 +191,13 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } if (conn->conn_state == XQC_CONN_STATE_CLOSING) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|closing state|frame_type:%ui|", + xqc_log(conn->log, XQC_LOG_DEBUG, "|closing state|frame_type:%xL|", frame_type); - /* respond connection close when recv any packet */ - if (frame_type != 0x1c && frame_type != 0x1d) { + /* respond connection close when recv any packet except conn_close and ack / ack_mp */ + if (frame_type != 0x1c && frame_type != 0x1d + && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK0 + && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK1) + { xqc_conn_immediate_close(conn); packet_in->pos = packet_in->last; return XQC_OK; @@ -201,7 +210,7 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return XQC_OK; } - xqc_log(conn->log, XQC_LOG_DEBUG, "|frame_type:%ui|", frame_type); + xqc_log(conn->log, XQC_LOG_DEBUG, "|frame_type:%xL|", frame_type); switch (frame_type) { @@ -211,7 +220,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x01: ret = xqc_process_ping_frame(conn, packet_in); break; - case 0x02 ... 0x03: + case 0x02: + case 0x03: ret = xqc_process_ack_frame(conn, packet_in); break; case 0x04: @@ -226,7 +236,14 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x07: ret = xqc_process_new_token_frame(conn, packet_in); break; - case 0x08 ... 0x0f: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: ret = xqc_process_stream_frame(conn, packet_in); break; case 0x10: @@ -235,7 +252,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x11: ret = xqc_process_max_stream_data_frame(conn, packet_in); break; - case 0x12 ... 0x13: + case 0x12: + case 0x13: ret = xqc_process_max_streams_frame(conn, packet_in); break; case 0x14: @@ -244,7 +262,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x15: ret = xqc_process_stream_data_blocked_frame(conn, packet_in); break; - case 0x16 ... 0x17: + case 0x16: + case 0x17: ret = xqc_process_streams_blocked_frame(conn, packet_in); break; case 0x18: @@ -259,84 +278,111 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x1b: ret = xqc_process_path_response_frame(conn, packet_in); break; - case 0x1c ... 0x1d: + case 0x1c: + case 0x1d: ret = xqc_process_conn_close_frame(conn, packet_in); break; case 0x1e: ret = xqc_process_handshake_done_frame(conn, packet_in); break; - case 0x30 ... 0x31: + case 0x30: + case 0x31: ret = xqc_process_datagram_frame(conn, packet_in); break; - case 0xbaba00 ... 0xbaba01: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { + case XQC_TRANS_FRAME_TYPE_ACK_EXT: + ret = xqc_process_ack_ext_frame(conn, packet_in); + break; + case XQC_TRANS_FRAME_TYPE_MP_ACK0: + case XQC_TRANS_FRAME_TYPE_MP_ACK1: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_ack_mp_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version mp_ack frame or cannot process frame in mp version 04|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c00 ... 0x15228c01: - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { - ret = xqc_process_ack_mp_frame(conn, packet_in); + case XQC_TRANS_FRAME_TYPE_MP_ABANDON: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_path_abandon_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version mp_ack frame or cannot process frame in mp version 05|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0xbaba05: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - ret = xqc_process_path_abandon_frame(conn, packet_in); + + case XQC_TRANS_FRAME_TYPE_MP_STANDBY: + case XQC_TRANS_FRAME_TYPE_MP_AVAILABLE: + case XQC_TRANS_FRAME_TYPE_MP_FROZEN: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_path_status_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_abandon frame or cannot process frame in mp version 04|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c05: - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { - ret = xqc_process_path_abandon_frame(conn, packet_in); + + case XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_mp_new_conn_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_abandon frame or cannot process frame in mp version 05|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0xbaba06: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - ret = xqc_process_path_status_frame(conn, packet_in); + case XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_mp_retire_conn_id_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 04|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c06: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - ret = xqc_process_path_status_frame(conn, packet_in); - + case XQC_TRANS_FRAME_TYPE_MAX_PATH_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_max_path_id_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 05|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c07: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_06) { - ret = xqc_process_path_standby_frame(conn, packet_in); +#ifdef XQC_ENABLE_FEC + case 0xfec5: + if (conn->conn_settings.enable_decode_fec + && conn->conn_settings.fec_params.fec_decoder_scheme != 0) + { + ret = xqc_process_sid_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 06|"); - ret = -XQC_EMP_INVALID_MP_VERTION; + xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); + return -XQC_EIGNORE_PKT; } break; - case 0x15228c08: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_06) { - ret = xqc_process_path_available_frame(conn, packet_in); + + case 0xfec6: + if (conn->conn_settings.enable_decode_fec + && conn->conn_settings.fec_params.fec_decoder_scheme != 0) + { + ret = xqc_process_repair_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 06|"); - ret = -XQC_EMP_INVALID_MP_VERTION; + xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); + return -XQC_EIGNORE_PKT; } break; +#endif default: xqc_log(conn->log, XQC_LOG_ERROR, "|unknown frame type|"); return -XQC_EIGNORE_PKT; @@ -353,6 +399,16 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } + /* + * An endpoint MUST treat receipt of a packet containing no frames as a + * connection error of type PROTOCOL_VIOLATION + */ + if (packet_in->pi_frame_types == 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|receive packet with no frame, close" + "with PROTOCOL_VIOLATION|"); + XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); + } + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); if (path != NULL && (packet_in->pi_frame_types & XQC_FRAME_BIT_DATAGRAM)) @@ -408,6 +464,7 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_log(conn->log, XQC_LOG_DEBUG, "|offset:%ui|data_length:%ud|fin:%ud|stream_id:%ui|path:%ui|", stream_frame->data_offset, stream_frame->data_length, stream_frame->fin, stream_id, packet_in->pi_path_id); + stream = xqc_find_stream_by_id(stream_id, conn->streams_hash); if (!stream) { if ((conn->conn_type == XQC_CONN_TYPE_SERVER && (stream_type == XQC_CLI_BID || stream_type == XQC_CLI_UNI)) @@ -425,12 +482,31 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } + packet_in->stream_id = stream_id; + + if (!stream->stream_stats.first_rcv_time) { + if (packet_in->pkt_recv_time) { + stream->stream_stats.first_rcv_time = packet_in->pkt_recv_time; + + } else { + stream->stream_stats.first_rcv_time = xqc_monotonic_timestamp(); + } + } + conn->stream_stats.recv_bytes += stream_frame->data_length; - xqc_stream_path_metrics_on_recv(conn, stream, packet_in); + if (packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) { + stream->stream_stats.recov_pkt_cnt++; + if (stream->stream_stats.fec_blk_lack_time == 0) { + stream->stream_stats.fec_blk_lack_time = xqc_calc_delay(xqc_monotonic_timestamp(), packet_in->pi_fec_process_time); + } + } - if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { - stream->paths_info[packet_in->pi_path_id].path_recv_bytes += stream_frame->data_length; + if (!(packet_in->pi_flag & XQC_PIF_FEC_RECOVERED)) { + xqc_stream_path_metrics_on_recv(conn, stream, packet_in); + if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { + stream->paths_info[packet_in->pi_path_id].path_recv_bytes += stream_frame->data_length; + } } if (stream->stream_state_recv >= XQC_RECV_STREAM_ST_RESET_RECVD) { @@ -439,6 +515,7 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) goto free; } + stream->stream_stats.final_packet_time = xqc_monotonic_timestamp(); if (stream_frame->data_offset + stream_frame->data_length <= stream->stream_data_in.merged_offset_end) { if (!(stream_frame->fin && stream_frame->data_length == 0 && stream->stream_data_in.stream_length == 0)) { xqc_log(conn->log, XQC_LOG_DEBUG, "|already recvd|data_offset:%ui|data_length:%ud|merged_offset_end:%ui|", @@ -532,6 +609,10 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_stream_recv_state_update(stream, XQC_RECV_STREAM_ST_DATA_RECVD); } xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_stream_ready_to_read all recvd|"); + if (stream->stream_stats.recov_pkt_cnt != 0) { + stream->stream_stats.recv_time_with_fec = xqc_monotonic_timestamp(); + } + stream->stream_stats.stream_recv_time = xqc_monotonic_timestamp(); xqc_stream_ready_to_read(stream); } @@ -540,7 +621,9 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_stream_ready_to_read(stream); } - if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { + if (!(packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) + && packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) + { stream->paths_info[packet_in->pi_path_id].path_recv_effective_bytes += stream_frame->data_length; } @@ -556,6 +639,15 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return ret; } +xqc_int_t +xqc_check_crypto_frame_data_buffer_exceed(xqc_stream_t *stream, xqc_stream_frame_t *stream_frame, uint64_t threshold) +{ + if (stream_frame->data_offset + stream_frame->data_length > stream->stream_data_in.next_read_offset + threshold) { + return -XQC_ELIMIT; + } + + return XQC_OK; +} xqc_int_t xqc_insert_crypto_frame(xqc_connection_t *conn, xqc_stream_t *stream, xqc_stream_frame_t *stream_frame) @@ -563,6 +655,14 @@ xqc_insert_crypto_frame(xqc_connection_t *conn, xqc_stream_t *stream, xqc_stream unsigned char inserted = 0; xqc_list_head_t *pos; xqc_stream_frame_t *frame; + xqc_int_t ret; + ret = xqc_check_crypto_frame_data_buffer_exceed(stream, stream_frame, XQC_CONN_MAX_CRYPTO_DATA_TOTAL_LEN); + if (ret != XQC_OK) { + XQC_CONN_ERR(conn, TRA_CRYPTO_BUFFER_EXCEEDED); + xqc_log(conn->log, XQC_LOG_ERROR, + "|crypto frame data buffer exceed|"); + return ret; + } xqc_list_for_each_reverse(pos, &stream->stream_data_in.frames_tailq) { frame = xqc_list_entry(pos, xqc_stream_frame_t, sf_list); @@ -602,6 +702,17 @@ xqc_process_crypto_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } + if (conn->conn_state == XQC_CONN_STATE_SERVER_INIT + && !(conn->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) + { + conn->conn_flag |= XQC_CONN_FLAG_INIT_RECVD; + + } else if (conn->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT + && !(conn->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) + { + conn->conn_flag |= XQC_CONN_FLAG_INIT_RECVD; + } + xqc_stream_frame_t *stream_frame = xqc_calloc(1, sizeof(xqc_stream_frame_t)); if (stream_frame == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_calloc error|"); @@ -626,13 +737,15 @@ xqc_process_crypto_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } + xqc_log(conn->log, XQC_LOG_DEBUG, "|level:%d|", encrypt_level); + xqc_stream_t *stream = conn->crypto_stream[encrypt_level]; ret = xqc_insert_crypto_frame(conn, stream, stream_frame); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_insert_crypto_frame error|"); xqc_destroy_stream_frame(stream_frame); - return -1; + return ret; } ret = xqc_read_crypto_stream(stream); @@ -670,18 +783,21 @@ xqc_process_ack_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_ack_frame error|"); return ret; } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } for (int i = 0; i < ack_info.n_ranges; i++) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|high:%ui|low:%ui|pkt_pns:%d|", - ack_info.ranges[i].high, ack_info.ranges[i].low, packet_in->pi_pkt.pkt_pns); - xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, ack_info.ranges[i].low); + xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, + ack_info.ranges[i].low, packet_in->pi_path_id); } /* 对端还不支持MP,或还未握手确认时,使用 initial path */ xqc_path_ctx_t *path = conn->conn_initial_path; xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); ret = xqc_send_ctl_on_ack_received(path->path_send_ctl, pn_ctl, conn->conn_send_queue, - &ack_info, packet_in->pkt_recv_time, 1); + &ack_info, packet_in->pkt_recv_time, + packet_in->pi_path_id == path->path_id); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_send_ctl_on_ack_received error|"); @@ -691,11 +807,60 @@ xqc_process_ack_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return XQC_OK; } +xqc_int_t +xqc_process_ack_ext_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + xqc_int_t parse_ack_recv_ts_ret; + + xqc_ack_info_t ack_info; + xqc_ack_timestamp_info_t ack_ts_info; + ack_ts_info.report_num = 0; + parse_ack_recv_ts_ret = xqc_parse_ack_ext_frame(packet_in, conn, &ack_info, &ack_ts_info); + if (parse_ack_recv_ts_ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_process_ack_ext_frame error|"); + return parse_ack_recv_ts_ret; + } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + + for (int i = 0; i < ack_info.n_ranges; i++) { + xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, + ack_info.ranges[i].low, packet_in->pi_path_id); + } + + /* 对端还不支持MP,或还未握手确认时,使用 initial path */ + xqc_path_ctx_t *path = conn->conn_initial_path; + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); + xqc_int_t ret = xqc_send_ctl_on_ack_received(path->path_send_ctl, pn_ctl, conn->conn_send_queue, + &ack_info, packet_in->pkt_recv_time, + packet_in->pi_path_id == path->path_id); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_send_ctl_on_ack_received error|"); + return ret; + } + /* + * TODO: There will be an interface that passes receive timestamps information to sent_ctl. + * Temporarily, the client does not receive ack_with_timestamps_frame. So we will complete + * the interface after verification in moq server. + */ + return XQC_OK; +} + xqc_int_t xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret; - + + /* ping frame should not be the first frame in the first initial packet */ + if (conn->conn_state == XQC_CONN_STATE_SERVER_INIT + && !(conn->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) + { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_process_ping_frame error: ping frame shoud not be the first frame|"); + return XQC_ERROR; + } ret = xqc_parse_ping_frame(packet_in, conn); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, @@ -712,10 +877,11 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in { xqc_int_t ret = XQC_ERROR; xqc_cid_t new_conn_cid; - uint64_t retire_prior_to; + uint64_t retire_prior_to, curr_rpi; xqc_cid_inner_t *inner_cid; xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; ret = xqc_parse_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, conn); if (ret != XQC_OK) { @@ -725,7 +891,8 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in } xqc_log(conn->log, XQC_LOG_DEBUG, "|new_conn_id|%s|sr_token:%s", - xqc_scid_str(&new_conn_cid), xqc_sr_token_str(new_conn_cid.sr_token)); + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); if (retire_prior_to > new_conn_cid.cid_seq_num) { /* @@ -739,9 +906,15 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return -XQC_EPROTO; } - /* TODO: write_retire_conn_id_frame 可能涉及到 替换 path.dcid (当前无 retire_prior_to 因此不涉及) */ + curr_rpi = xqc_cid_set_get_largest_seq_or_rpt(&conn->dcid_set, XQC_INITIAL_PATH_ID); + if (curr_rpi < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current retire_prior_to error:%i|", + curr_rpi); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } - if (new_conn_cid.cid_seq_num < conn->dcid_set.largest_retire_prior_to) { + if (new_conn_cid.cid_seq_num < curr_rpi) { /* * An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller * than the Retire Prior To field of a previously received NEW_CONNECTION_ID frame @@ -749,7 +922,7 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in * connection ID, unless it has already done so for that sequence number. */ xqc_log(conn->log, XQC_LOG_DEBUG, "|seq_num:%ui smaller than largest_retire_prior_to:%ui|", - new_conn_cid.cid_seq_num, conn->dcid_set.largest_retire_prior_to); + new_conn_cid.cid_seq_num, curr_rpi); ret = xqc_write_retire_conn_id_frame_to_packet(conn, new_conn_cid.cid_seq_num); if (ret != XQC_OK) { @@ -760,18 +933,18 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return XQC_OK; } - if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) { + if (retire_prior_to > curr_rpi) { /* * Upon receipt of an increased Retire Prior To field, the peer MUST stop using the * corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before * adding the newly provided connection ID to the set of active connection IDs. */ - - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { + inner_set = xqc_get_path_cid_set(&conn->dcid_set, XQC_INITIAL_PATH_ID); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); uint64_t seq_num = inner_cid->cid.cid_seq_num; if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED) - && (seq_num >= conn->dcid_set.largest_retire_prior_to && seq_num < retire_prior_to)) + && (seq_num >= curr_rpi && seq_num < retire_prior_to)) { ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num); if (ret != XQC_OK) { @@ -781,13 +954,13 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in } } - conn->dcid_set.largest_retire_prior_to = retire_prior_to; xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to|%ui|", - conn->dcid_set.largest_retire_prior_to, retire_prior_to); + curr_rpi, retire_prior_to); + xqc_cid_set_set_largest_seq_or_rpt(&conn->dcid_set, XQC_INITIAL_PATH_ID, retire_prior_to); } /* store dcid & add unused_dcid_count */ - if (xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &new_conn_cid) != NULL) { + if (xqc_cid_in_cid_set(&conn->dcid_set, &new_conn_cid, XQC_INITIAL_PATH_ID) != NULL) { return XQC_OK; } @@ -803,19 +976,34 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in /* insert into sr_token-connection hash, for processing stateless reset packet */ - ret = xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, - new_conn_cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN); + if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, + new_conn_cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN) == NULL) + { + ret = xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, + new_conn_cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|sr_token conflict:%s", xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); + /* ignore this error, as it is not fatal. */ + ret = XQC_OK; + } + if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|insert new_cid into conns_hash_sr_token failed|"); return ret; } - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &new_conn_cid, + XQC_CID_UNUSED, + conn->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|", - conn->local_settings.active_connection_id_limit, conn->dcid_set.cid_set.unused_cnt, conn->dcid_set.cid_set.used_cnt); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", + conn->local_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->dcid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&conn->dcid_set, XQC_INITIAL_PATH_ID)); return ret; } @@ -827,7 +1015,7 @@ xqc_int_t xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; - uint64_t seq_num; + uint64_t seq_num = 0, largest_scid_seq_num = 0; ret = xqc_parse_retire_conn_id_frame(packet_in, &seq_num); if (ret != XQC_OK) { @@ -835,24 +1023,40 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet "|xqc_parse_retire_conn_id_frame error|"); return ret; } + + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + + largest_scid_seq_num = xqc_cid_set_get_largest_seq_or_rpt(&conn->scid_set, XQC_INITIAL_PATH_ID); + if (largest_scid_seq_num < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current largest_scid_seq_num error:%i|", + largest_scid_seq_num); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } - if (seq_num > conn->scid_set.largest_scid_seq_num) { + if (seq_num > largest_scid_seq_num) { /* * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number * greater than any previously sent to the peer MUST be treated as a * connection error of type PROTOCOL_VIOLATION. */ - xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|seq:%ui|", seq_num); XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); return -XQC_EPROTO; } - xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set.cid_set, seq_num); + xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set, seq_num, XQC_INITIAL_PATH_ID); if (inner_cid == NULL) { xqc_log(conn->log, XQC_LOG_DEBUG, "|can't find scid with seq_num:%ui|", seq_num); return XQC_OK; } + if (inner_cid->state >= XQC_CID_RETIRED) { + return XQC_OK; + } + if (XQC_OK == xqc_cid_is_equal(&inner_cid->cid, &packet_in->pi_pkt.pkt_dcid)) { /* * The sequence number specified in a RETIRE_CONNECTION_ID frame MUST NOT refer to @@ -872,7 +1076,7 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet /* update SCID */ if (XQC_OK == xqc_cid_is_equal(&conn->scid_set.user_scid, &inner_cid->cid)) { - ret = xqc_conn_update_user_scid(conn, &conn->scid_set); + ret = xqc_conn_update_user_scid(conn); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have other used scid, can't retire user_scid|"); return ret; @@ -881,12 +1085,6 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet xqc_log(conn->log, XQC_LOG_DEBUG, "|switch scid to %ui|", conn->scid_set.user_scid.cid_seq_num); } - /* TODO: 如果对应 “Active” Path 则需要替换 CID */ - // xqc_path_ctx_t *path = xqc_conn_find_path_by_scid(conn, &inner_cid->cid); - // if (path != NULL) { - // xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|state:%d|", path->path_id, path->path_state); - // } - return XQC_OK; } @@ -925,6 +1123,7 @@ xqc_process_conn_close_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } conn->conn_state = XQC_CONN_STATE_DRAINING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); xqc_conn_closing(conn); return XQC_OK; @@ -1041,7 +1240,7 @@ xqc_int_t xqc_process_data_blocked_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret; - uint64_t data_limit; + uint64_t data_limit, new_limit; ret = xqc_parse_data_blocked_frame(packet_in, &data_limit, conn); if (ret != XQC_OK) { @@ -1056,16 +1255,20 @@ xqc_process_data_blocked_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_i return XQC_OK; } - conn->conn_flow_ctl.fc_max_data_can_recv = conn->conn_flow_ctl.fc_data_read + conn->conn_flow_ctl.fc_recv_windows_size; + new_limit = conn->conn_flow_ctl.fc_data_read + conn->conn_flow_ctl.fc_recv_windows_size; - ret = xqc_write_max_data_to_packet(conn, conn->conn_flow_ctl.fc_max_data_can_recv); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_max_data_to_packet error|"); - return ret; - } + if (new_limit > conn->conn_flow_ctl.fc_max_data_can_recv) { + conn->conn_flow_ctl.fc_max_data_can_recv = new_limit; + ret = xqc_write_max_data_to_packet(conn, conn->conn_flow_ctl.fc_max_data_can_recv); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_max_data_to_packet error|"); + return ret; + } - xqc_log(conn->log, XQC_LOG_DEBUG, "|data_limit:%ui|new_limit:%ui|", - data_limit, conn->conn_flow_ctl.fc_max_data_can_recv); + xqc_log(conn->log, XQC_LOG_DEBUG, "|data_limit:%ui|new_limit:%ui|", + data_limit, conn->conn_flow_ctl.fc_max_data_can_recv); + } + return XQC_OK; } @@ -1073,7 +1276,7 @@ xqc_int_t xqc_process_stream_data_blocked_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret; - uint64_t stream_data_limit; + uint64_t stream_data_limit, new_limit; xqc_stream_id_t stream_id; xqc_stream_t *stream; @@ -1108,16 +1311,21 @@ xqc_process_stream_data_blocked_frame(xqc_connection_t *conn, xqc_packet_in_t *p return XQC_OK; } - stream->stream_flow_ctl.fc_max_stream_data_can_recv = stream->stream_data_in.next_read_offset + stream->stream_flow_ctl.fc_stream_recv_window_size; + new_limit = stream->stream_data_in.next_read_offset + stream->stream_flow_ctl.fc_stream_recv_window_size; - ret = xqc_write_max_stream_data_to_packet(conn, stream_id, stream->stream_flow_ctl.fc_max_stream_data_can_recv, XQC_PTYPE_SHORT_HEADER); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_max_stream_data_to_packet error|"); - return ret; - } + if (new_limit > stream->stream_flow_ctl.fc_max_stream_data_can_recv) { + stream->stream_flow_ctl.fc_max_stream_data_can_recv = new_limit; - xqc_log(conn->log, XQC_LOG_DEBUG, "|stream_data_limit:%ui|new_limit:%ui|", - stream_data_limit, stream->stream_flow_ctl.fc_max_stream_data_can_recv); + ret = xqc_write_max_stream_data_to_packet(conn, stream_id, stream->stream_flow_ctl.fc_max_stream_data_can_recv, XQC_PTYPE_SHORT_HEADER); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_max_stream_data_to_packet error|"); + return ret; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|stream_data_limit:%ui|new_limit:%ui|", + stream_data_limit, stream->stream_flow_ctl.fc_max_stream_data_can_recv); + } + return XQC_OK; } @@ -1379,40 +1587,44 @@ xqc_process_path_challenge_frame(xqc_connection_t *conn, xqc_packet_in_t *packet return ret; } - //TODO: MPQUIC fix migration + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { - path = xqc_conn_find_path_by_scid(conn, &packet_in->pi_pkt.pkt_dcid); + path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); } else { path = conn->conn_initial_path; } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|path_id=%ui|", packet_in->pi_path_id); if (path == NULL) { if (conn->conn_type == XQC_CONN_TYPE_SERVER) { /* try to create new path */ - path = xqc_conn_create_path_inner(conn, &packet_in->pi_pkt.pkt_dcid, NULL, XQC_APP_PATH_STATUS_AVAILABLE); + path = xqc_conn_create_path_inner(conn, &packet_in->pi_pkt.pkt_dcid, NULL, XQC_APP_PATH_STATUS_AVAILABLE, packet_in->pi_path_id); if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner err|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner err|%ui|", packet_in->pi_path_id); return -XQC_EMP_CREATE_PATH; } - packet_in->pi_path_id = path->path_id; conn->validating_path_id = path->path_id; conn->conn_flag |= XQC_CONN_FLAG_RECV_NEW_PATH; } else { xqc_log(conn->log, XQC_LOG_ERROR, "|no path to challenge|dcid:%s|path_id:%ui|", - xqc_dcid_str(&packet_in->pi_pkt.pkt_dcid), + xqc_dcid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid), packet_in->pi_path_id); return XQC_OK; } } xqc_log(conn->log, XQC_LOG_DEBUG, - "|path:%ui|state:%d|RECV path_challenge_data:%s|cid:%s|", - path->path_id, path->path_state, - path_challenge_data, xqc_dcid_str(&packet_in->pi_pkt.pkt_dcid)); + "|path:%ui|state:%d|RECV path_challenge_data:%*s|cid:%s|", + path->path_id, path->path_state, XQC_PATH_CHALLENGE_DATA_LEN, + path_challenge_data, xqc_dcid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid)); ret = xqc_write_path_response_frame_to_packet(conn, path, path_challenge_data); if (ret != XQC_OK) { @@ -1436,14 +1648,17 @@ xqc_process_path_response_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_ return ret; } - //TODO: MPQUIC fix migration + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { - path = xqc_conn_find_path_by_scid(conn, &packet_in->pi_pkt.pkt_dcid); + path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|ingnore path response|pkt_dcid:%s|path_id:%ui|", - xqc_scid_str(&packet_in->pi_pkt.pkt_dcid), + xqc_scid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid), packet_in->pi_path_id); return XQC_OK; } @@ -1512,16 +1727,27 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_int_t ret; xqc_ack_info_t ack_info; - uint64_t dcid_seq_num; - ret = xqc_parse_ack_mp_frame(packet_in, conn, &dcid_seq_num, &ack_info); + uint64_t path_id = 0; + ret = xqc_parse_ack_mp_frame(packet_in, conn, &path_id, &ack_info); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_ack_mp_frame error|"); return ret; } - xqc_path_ctx_t *path_to_be_acked = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + + xqc_path_ctx_t *path_to_be_acked = xqc_conn_find_path_by_path_id(conn, path_id); if (path_to_be_acked == NULL) { - xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|dcid_seq:%ui|", dcid_seq_num); + xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|path:%ui|", path_id); return XQC_OK; } @@ -1533,9 +1759,8 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } for (int i = 0; i < ack_info.n_ranges; i++) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|high:%ui|low:%ui|pkt_pns:%d|", path_to_be_acked->path_id, - ack_info.ranges[i].high, ack_info.ranges[i].low, packet_in->pi_pkt.pkt_pns); - xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, ack_info.ranges[i].low); + xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, + ack_info.ranges[i].low, path_to_be_acked->path_id); } xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path_to_be_acked); @@ -1556,21 +1781,31 @@ xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_i { xqc_int_t ret = XQC_ERROR; - uint64_t dcid_seq_num; + uint64_t path_id = 0; uint64_t error_code; - ret = xqc_parse_path_abandon_frame(packet_in, &dcid_seq_num, &error_code); + ret = xqc_parse_path_abandon_frame(packet_in, &path_id, &error_code); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_abandon_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path abandon|path_id:%ui|", path_id); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + //MPQUIC: path associated cid resources should be released and path id should be consumed anyway + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); + "|no context for abandoned path|path_id:%ui|pi_path_id:%ui|", + path_id, packet_in->pi_path_id); + xqc_cid_set_update_state(&conn->dcid_set, path_id, XQC_CID_SET_ABANDONED); + xqc_cid_set_update_state(&conn->scid_set, path_id, XQC_CID_SET_ABANDONED); return XQC_OK; /* ignore */ } @@ -1597,34 +1832,42 @@ xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_i return XQC_OK; } -xqc_int_t +xqc_int_t xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; - - uint64_t dcid_seq_num; + uint64_t path_id = 0; uint64_t path_status_seq_num; uint64_t path_status; - ret = xqc_parse_path_status_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + ret = xqc_parse_path_status_frame(packet_in, &path_id, &path_status_seq_num, &path_status); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path status:%ui|path_id:%ui|", path_status, path_id); + + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); + "|invalid path|path_id:%ui|pi_path_id:%ui|", + path_id, packet_in->pi_path_id); return XQC_OK; /* ignore */ } if (path_status_seq_num > path->app_path_status_recv_seq_num) { path->app_path_status_recv_seq_num = path_status_seq_num; path->next_app_path_state = path_status; - + if (path->path_state < XQC_PATH_STATE_ACTIVE) { path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; @@ -1636,81 +1879,388 @@ xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return XQC_OK; } + xqc_int_t -xqc_process_path_standby_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_process_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; + xqc_cid_t new_conn_cid; + uint64_t retire_prior_to, curr_rpi; - uint64_t dcid_seq_num; - uint64_t path_status_seq_num; - uint64_t path_status; + xqc_cid_inner_t *inner_cid; + xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + uint64_t path_id; - ret = xqc_parse_path_standby_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + ret = xqc_parse_mp_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, &path_id, conn); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_parse_new_conn_id_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); - return XQC_OK; /* ignore */ + xqc_log(conn->log, XQC_LOG_DEBUG, "|new_conn_id|%s|sr_token:%s", + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); + + if (retire_prior_to > new_conn_cid.cid_seq_num) { + /* + * The Retire Prior To field MUST be less than or equal to the Sequence Number field. + * Receiving a value greater than the Sequence Number MUST be treated as a connection + * error of type FRAME_ENCODING_ERROR. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|path:%ui|retire_prior_to:%ui greater than seq_num:%ui|", + path_id, retire_prior_to, new_conn_cid.cid_seq_num); + XQC_CONN_ERR(conn, TRA_FRAME_ENCODING_ERROR); + return -XQC_EPROTO; } - if (path_status_seq_num > path->app_path_status_recv_seq_num) { - path->app_path_status_recv_seq_num = path_status_seq_num; - path->next_app_path_state = path_status; + curr_rpi = xqc_cid_set_get_largest_seq_or_rpt(&conn->dcid_set, path_id); + if (curr_rpi < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current retire_prior_to error:%i|path:%ui|", + curr_rpi, path_id); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } - if (path->path_state < XQC_PATH_STATE_ACTIVE) { - path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; + if (new_conn_cid.cid_seq_num < curr_rpi) { + /* + * An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller + * than the Retire Prior To field of a previously received NEW_CONNECTION_ID frame + * MUST send a corresponding RETIRE_CONNECTION_ID frame that retires the newly received + * connection ID, unless it has already done so for that sequence number. + */ + xqc_log(conn->log, XQC_LOG_DEBUG, "|seq_num:%ui smaller than largest_retire_prior_to:%ui|", + new_conn_cid.cid_seq_num, curr_rpi); - } else { - xqc_set_application_path_status(path, path->next_app_path_state, XQC_FALSE); + ret = xqc_write_mp_retire_conn_id_frame_to_packet(conn, new_conn_cid.cid_seq_num, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|xqc_write_mp_retire_conn_id_frame_to_packet error|", path_id); + return ret; } + + return XQC_OK; + } + + if (retire_prior_to > curr_rpi) { + /* + * Upon receipt of an increased Retire Prior To field, the peer MUST stop using the + * corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before + * adding the newly provided connection ID to the set of active connection IDs. + */ + inner_set = xqc_get_path_cid_set(&conn->dcid_set, path_id); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + uint64_t seq_num = inner_cid->cid.cid_seq_num; + if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED) + && (seq_num >= curr_rpi && seq_num < retire_prior_to)) + { + ret = xqc_write_mp_retire_conn_id_frame_to_packet(conn, seq_num, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id:%ui|xqc_write_mp_retire_conn_id_frame_to_packet error|", + path_id); + return ret; + } + } + } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|retire_prior_to|%ui|increase to|%ui|", + path_id, curr_rpi, retire_prior_to); + xqc_cid_set_set_largest_seq_or_rpt(&conn->dcid_set, path_id, retire_prior_to); + } + + /* store dcid & add unused_dcid_count */ + if (xqc_cid_in_cid_set(&conn->dcid_set, &new_conn_cid, path_id) != NULL) { + return XQC_OK; + } + + /* insert into dcid-connection hash, for processing the deprecated stateless + reset packet */ + ret = xqc_insert_conns_hash(conn->engine->conns_hash_dcid, conn, + new_conn_cid.cid_buf, new_conn_cid.cid_len); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|insert new_cid into conns_hash_dcid failed|"); + return ret; + } + + /* insert into sr_token-connection hash, for processing stateless reset + packet */ + if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, + new_conn_cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN) == NULL) + { + ret = xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, + new_conn_cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|sr_token conflict:%s", xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); + /* ignore this error, as it is not fatal. */ + ret = XQC_OK; + } + + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|insert new_cid into conns_hash_sr_token failed|"); + return ret; + } + + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &new_conn_cid, + XQC_CID_UNUSED, + conn->local_settings.active_connection_id_limit, + path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|path:%ui|", + conn->local_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->dcid_set, path_id), + xqc_cid_set_get_used_cnt(&conn->dcid_set, path_id), + path_id); + return ret; } return XQC_OK; } - xqc_int_t -xqc_process_path_available_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_process_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; + uint64_t seq_num = 0, largest_scid_seq_num = 0, path_id; - uint64_t dcid_seq_num; - uint64_t path_status_seq_num; - uint64_t path_status; + ret = xqc_parse_mp_retire_conn_id_frame(packet_in, &seq_num, &path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_parse_retire_conn_id_frame error|"); + return ret; + } + + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + + largest_scid_seq_num = xqc_cid_set_get_largest_seq_or_rpt(&conn->scid_set, path_id); + if (largest_scid_seq_num < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current largest_scid_seq_num error:%i|path:%ui|", + largest_scid_seq_num, path_id); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } + + if (seq_num > largest_scid_seq_num) { + /* + * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number + * greater than any previously sent to the peer MUST be treated as a + * connection error of type PROTOCOL_VIOLATION. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|seq:%ui|path:%ui|", seq_num, path_id); + XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); + return -XQC_EPROTO; + } + + xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set, seq_num, path_id); + if (inner_cid == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, + "|can't find scid with seq_num:%ui|path:%ui|", + seq_num, path_id); + return XQC_OK; + } - ret = xqc_parse_path_available_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + if (inner_cid->state >= XQC_CID_RETIRED) { + return XQC_OK; + } + + if (XQC_OK == xqc_cid_is_equal(&inner_cid->cid, &packet_in->pi_pkt.pkt_dcid)) { + /* + * The sequence number specified in a RETIRE_CONNECTION_ID frame MUST NOT refer to + * the Destination Connection ID field of the packet in which the frame is contained. + * The peer MAY treat this as a connection error of type PROTOCOL_VIOLATION. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|seq_num refer to pkt_dcid|"); + XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); + return -XQC_EPROTO; + } + + ret = xqc_conn_set_cid_retired_ts(conn, inner_cid); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_set_cid_retired_ts error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + /* update SCID */ + if (XQC_OK == xqc_cid_is_equal(&conn->scid_set.user_scid, &inner_cid->cid)) { + ret = xqc_conn_update_user_scid(conn); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have other used scid, can't retire user_scid|"); + return ret; + } - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); - return XQC_OK; /* ignore */ + xqc_log(conn->log, XQC_LOG_DEBUG, "|switch scid to %ui|", conn->scid_set.user_scid.cid_seq_num); } - if (path_status_seq_num > path->app_path_status_recv_seq_num) { - path->app_path_status_recv_seq_num = path_status_seq_num; - path->next_app_path_state = path_status; + return XQC_OK; +} - if (path->path_state < XQC_PATH_STATE_ACTIVE) { - path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; +xqc_int_t +xqc_process_max_path_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + xqc_int_t ret = XQC_ERROR; + uint64_t max_path_id, new_max_path_id; + + ret = xqc_parse_max_path_id_frame(packet_in, &max_path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_process_max_paths_frame error|"); + return ret; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|max_path_id:%ui|prev_max_path_id:%ui|", max_path_id, conn->remote_max_path_id); + + if (conn->remote_max_path_id < max_path_id) { + conn->remote_max_path_id = max_path_id; + new_max_path_id = xqc_min(conn->local_max_path_id, conn->remote_max_path_id); + if (new_max_path_id > conn->curr_max_path_id) { + if (xqc_conn_add_path_cid_sets(conn, conn->curr_max_path_id + 1, new_max_path_id) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|add_path_cid_sets_error|"); + return -XQC_EMALLOC; + } + conn->curr_max_path_id = new_max_path_id; + } + } + + return ret; +} + +#ifdef XQC_ENABLE_FEC + +uint32_t +xqc_parse_block_number(uint64_t payload_id) +{ + return payload_id >> 8; +} + +uint32_t +xqc_parse_symbol_number(uint64_t payload_id) +{ + return payload_id & 0xff; +} + + +xqc_int_t +xqc_process_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + uint64_t src_payload_id, symbol_idx, block_id; + xqc_int_t ret, remain_frame_len, symbol_size; + + ret = xqc_parse_sid_frame(conn, packet_in, &src_payload_id, &symbol_size); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_sid_frame err|ret:%d|", ret); + return -XQC_EFEC_SYMBOL_ERROR; + } + // If current packet is fec recovered, should not be used in fec decoder + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + if (symbol_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|received source symbol size is too large"); + return XQC_OK; + } + + block_id = xqc_parse_block_number(src_payload_id); + symbol_idx = xqc_parse_symbol_number(src_payload_id); + // update buffered symbols according to received symbol. + ret = xqc_process_src_symbol(conn, block_id, symbol_idx, packet_in->decode_payload, symbol_size); + if (ret != XQC_OK) { + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; } else { - xqc_set_application_path_status(path, path->next_app_path_state, XQC_FALSE); + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process source symbol error"); + return ret; } } + conn->fec_ctl->latest_stream_id[block_id % XQC_FEC_BLOCK_NUM] = packet_in->stream_id; + + xqc_try_process_fec_decode(conn, block_id); return XQC_OK; } + +xqc_int_t +xqc_process_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + uint8_t lack_syb_num, fst_lack_syb_id; + xqc_int_t ret, block_mod, i; + xqc_fec_rpr_syb_t tmp_rpr_syb; + + xqc_stream_t *stream = NULL; + + conn->fec_ctl->fec_recv_repair_num_total++; + xqc_memset(&tmp_rpr_syb, 0, sizeof(xqc_fec_rpr_syb_t)); + block_mod = conn->conn_settings.fec_params.fec_blk_log_mod; + + ret = xqc_parse_repair_frame(conn, packet_in, &tmp_rpr_syb); + if (ret != XQC_OK) { + if (ret != -XQC_EFEC_TOLERABLE_ERROR) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_repair_frame error|err:%d", ret); + return ret; + } + return XQC_OK; + } + + // update buffered symbols according to received symbol. + ret = xqc_process_rpr_symbol(conn, &tmp_rpr_syb); + if (ret != XQC_OK) { + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + } + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_repair_frame error|err:%d", ret); + return ret; + } + + // temp log logic + if (conn->conn_settings.fec_params.fec_log_on && tmp_rpr_syb.block_id % block_mod == 0) { + xqc_fec_schemes_e fec_scheme = conn->conn_settings.fec_params.fec_decoder_scheme; + if (fec_scheme == XQC_PACKET_MASK_CODE) { + lack_syb_num = fst_lack_syb_id = 0; + xqc_get_lack_src_syb(tmp_rpr_syb.repair_key, tmp_rpr_syb.recv_mask, tmp_rpr_syb.repair_key_size, + &fst_lack_syb_id, &lack_syb_num); + if (lack_syb_num > 1) { + xqc_log(conn->log, XQC_LOG_REPORT, "|fec_stats|PM|current block: %d|lack %d src_syb|", tmp_rpr_syb.block_id, lack_syb_num - 1); + } + + } else { + xqc_int_t max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + xqc_int_t recv_rpr_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, tmp_rpr_syb.block_id); + xqc_int_t recv_src_num = xqc_cnt_src_symbols_num(conn->fec_ctl, tmp_rpr_syb.block_id); + if (recv_rpr_num + recv_src_num < max_src_symbol_num && recv_src_num > 0) { + // receive some repair symbols, but the received source symbol are too little to perform recover. + lack_syb_num = max_src_symbol_num - recv_src_num - recv_rpr_num; + xqc_log(conn->log, XQC_LOG_REPORT, "|fec_stats|XOR|current block: %d|lack %d src_syb|total_syb:%d", tmp_rpr_syb.block_id, max_src_symbol_num - recv_src_num - recv_rpr_num, max_src_symbol_num); + } + } + } + + xqc_try_process_fec_decode(conn, tmp_rpr_syb.block_id); + return XQC_OK; +} + +#endif diff --git a/src/transport/xqc_frame.h b/src/transport/xqc_frame.h index f39482836..24c887a32 100644 --- a/src/transport/xqc_frame.h +++ b/src/transport/xqc_frame.h @@ -7,6 +7,14 @@ #include +/* + * draft-smith-quic-receive-ts-01: + * enable ECN counts (if bit 0 is set in Features) + * enable Receive Timestamps (if bit 1 is set in Features) + */ +#define XQC_ACK_EXT_FEATURE_BIT_ENC_COUNT 1 +#define XQC_ACK_EXT_FEATURE_BIT_RECV_TS 2 + typedef enum { XQC_FRAME_PADDING, XQC_FRAME_PING, @@ -33,40 +41,52 @@ typedef enum { XQC_FRAME_PATH_STATUS, XQC_FRAME_PATH_STANDBY, XQC_FRAME_PATH_AVAILABLE, + XQC_FRAME_MP_NEW_CONNECTION_ID, + XQC_FRAME_MP_RETIRE_CONNECTION_ID, + XQC_FRAME_MAX_PATH_ID, + XQC_FRAME_PATH_FROZEN, XQC_FRAME_DATAGRAM, XQC_FRAME_Extension, + XQC_FRAME_SID, + XQC_FRAME_REPAIR_SYMBOL, XQC_FRAME_NUM, } xqc_frame_type_t; typedef enum { - XQC_FRAME_BIT_PADDING = 1 << XQC_FRAME_PADDING, - XQC_FRAME_BIT_PING = 1 << XQC_FRAME_PING, - XQC_FRAME_BIT_ACK = 1 << XQC_FRAME_ACK, - XQC_FRAME_BIT_RESET_STREAM = 1 << XQC_FRAME_RESET_STREAM, - XQC_FRAME_BIT_STOP_SENDING = 1 << XQC_FRAME_STOP_SENDING, - XQC_FRAME_BIT_CRYPTO = 1 << XQC_FRAME_CRYPTO, - XQC_FRAME_BIT_NEW_TOKEN = 1 << XQC_FRAME_NEW_TOKEN, - XQC_FRAME_BIT_STREAM = 1 << XQC_FRAME_STREAM, - XQC_FRAME_BIT_MAX_DATA = 1 << XQC_FRAME_MAX_DATA, - XQC_FRAME_BIT_MAX_STREAM_DATA = 1 << XQC_FRAME_MAX_STREAM_DATA, - XQC_FRAME_BIT_MAX_STREAMS = 1 << XQC_FRAME_MAX_STREAMS, - XQC_FRAME_BIT_DATA_BLOCKED = 1 << XQC_FRAME_DATA_BLOCKED, - XQC_FRAME_BIT_STREAM_DATA_BLOCKED = 1 << XQC_FRAME_STREAM_DATA_BLOCKED, - XQC_FRAME_BIT_STREAMS_BLOCKED = 1 << XQC_FRAME_STREAMS_BLOCKED, - XQC_FRAME_BIT_NEW_CONNECTION_ID = 1 << XQC_FRAME_NEW_CONNECTION_ID, - XQC_FRAME_BIT_RETIRE_CONNECTION_ID = 1 << XQC_FRAME_RETIRE_CONNECTION_ID, - XQC_FRAME_BIT_PATH_CHALLENGE = 1 << XQC_FRAME_PATH_CHALLENGE, - XQC_FRAME_BIT_PATH_RESPONSE = 1 << XQC_FRAME_PATH_RESPONSE, - XQC_FRAME_BIT_CONNECTION_CLOSE = 1 << XQC_FRAME_CONNECTION_CLOSE, - XQC_FRAME_BIT_HANDSHAKE_DONE = 1 << XQC_FRAME_HANDSHAKE_DONE, - XQC_FRAME_BIT_ACK_MP = 1 << XQC_FRAME_ACK_MP, - XQC_FRAME_BIT_PATH_ABANDON = 1 << XQC_FRAME_PATH_ABANDON, - XQC_FRAME_BIT_PATH_STATUS = 1 << XQC_FRAME_PATH_STATUS, - XQC_FRAME_BIT_PATH_STANDBY = 1 << XQC_FRAME_PATH_STANDBY, - XQC_FRAME_BIT_PATH_AVAILABLE = 1 << XQC_FRAME_PATH_AVAILABLE, - XQC_FRAME_BIT_DATAGRAM = 1 << XQC_FRAME_DATAGRAM, - XQC_FRAME_BIT_Extension = 1 << XQC_FRAME_Extension, - XQC_FRAME_BIT_NUM = 1 << XQC_FRAME_NUM, + XQC_FRAME_BIT_PADDING = 1ULL << XQC_FRAME_PADDING, + XQC_FRAME_BIT_PING = 1ULL << XQC_FRAME_PING, + XQC_FRAME_BIT_ACK = 1ULL << XQC_FRAME_ACK, + XQC_FRAME_BIT_RESET_STREAM = 1ULL << XQC_FRAME_RESET_STREAM, + XQC_FRAME_BIT_STOP_SENDING = 1ULL << XQC_FRAME_STOP_SENDING, + XQC_FRAME_BIT_CRYPTO = 1ULL << XQC_FRAME_CRYPTO, + XQC_FRAME_BIT_NEW_TOKEN = 1ULL << XQC_FRAME_NEW_TOKEN, + XQC_FRAME_BIT_STREAM = 1ULL << XQC_FRAME_STREAM, + XQC_FRAME_BIT_MAX_DATA = 1ULL << XQC_FRAME_MAX_DATA, + XQC_FRAME_BIT_MAX_STREAM_DATA = 1ULL << XQC_FRAME_MAX_STREAM_DATA, + XQC_FRAME_BIT_MAX_STREAMS = 1ULL << XQC_FRAME_MAX_STREAMS, + XQC_FRAME_BIT_DATA_BLOCKED = 1ULL << XQC_FRAME_DATA_BLOCKED, + XQC_FRAME_BIT_STREAM_DATA_BLOCKED = 1ULL << XQC_FRAME_STREAM_DATA_BLOCKED, + XQC_FRAME_BIT_STREAMS_BLOCKED = 1ULL << XQC_FRAME_STREAMS_BLOCKED, + XQC_FRAME_BIT_NEW_CONNECTION_ID = 1ULL << XQC_FRAME_NEW_CONNECTION_ID, + XQC_FRAME_BIT_RETIRE_CONNECTION_ID = 1ULL << XQC_FRAME_RETIRE_CONNECTION_ID, + XQC_FRAME_BIT_PATH_CHALLENGE = 1ULL << XQC_FRAME_PATH_CHALLENGE, + XQC_FRAME_BIT_PATH_RESPONSE = 1ULL << XQC_FRAME_PATH_RESPONSE, + XQC_FRAME_BIT_CONNECTION_CLOSE = 1ULL << XQC_FRAME_CONNECTION_CLOSE, + XQC_FRAME_BIT_HANDSHAKE_DONE = 1ULL << XQC_FRAME_HANDSHAKE_DONE, + XQC_FRAME_BIT_ACK_MP = 1ULL << XQC_FRAME_ACK_MP, + XQC_FRAME_BIT_PATH_ABANDON = 1ULL << XQC_FRAME_PATH_ABANDON, + XQC_FRAME_BIT_PATH_STATUS = 1ULL << XQC_FRAME_PATH_STATUS, + XQC_FRAME_BIT_PATH_STANDBY = 1ULL << XQC_FRAME_PATH_STANDBY, + XQC_FRAME_BIT_PATH_AVAILABLE = 1ULL << XQC_FRAME_PATH_AVAILABLE, + XQC_FRAME_BIT_MP_NEW_CONNECTION_ID = 1ULL << XQC_FRAME_MP_NEW_CONNECTION_ID, + XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID = 1ULL << XQC_FRAME_MP_RETIRE_CONNECTION_ID, + XQC_FRAME_BIT_MAX_PATH_ID = 1ULL << XQC_FRAME_MAX_PATH_ID, + XQC_FRAME_BIT_PATH_FROZEN = 1ULL << XQC_FRAME_PATH_FROZEN, + XQC_FRAME_BIT_DATAGRAM = 1ULL << XQC_FRAME_DATAGRAM, + XQC_FRAME_BIT_Extension = 1ULL << XQC_FRAME_Extension, + XQC_FRAME_BIT_SID = 1ULL << XQC_FRAME_SID, + XQC_FRAME_BIT_REPAIR_SYMBOL = 1ULL << XQC_FRAME_REPAIR_SYMBOL, + XQC_FRAME_BIT_NUM = 1ULL << XQC_FRAME_NUM, } xqc_frame_type_bit_t; @@ -97,10 +117,10 @@ typedef enum { * PING and PADDING frames contain no information, so lost PING or * PADDING frames do not require repair */ -#define XQC_NEED_REPAIR(types) ((types) & ~(XQC_FRAME_BIT_ACK| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_PING | XQC_FRAME_BIT_CONNECTION_CLOSE | XQC_FRAME_BIT_DATAGRAM)) +#define XQC_NEED_REPAIR(types) ((types) & ~(XQC_FRAME_BIT_ACK| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_PING | XQC_FRAME_BIT_CONNECTION_CLOSE | XQC_FRAME_BIT_DATAGRAM | XQC_FRAME_BIT_SID | XQC_FRAME_BIT_REPAIR_SYMBOL)) -const char *xqc_frame_type_2_str(xqc_frame_type_bit_t type_bit); +const char *xqc_frame_type_2_str(xqc_engine_t *engine, xqc_frame_type_bit_t type_bit); unsigned int xqc_stream_frame_header_size(xqc_stream_id_t stream_id, uint64_t offset, size_t length); @@ -118,6 +138,9 @@ xqc_int_t xqc_process_crypto_frame(xqc_connection_t *conn, xqc_packet_in_t *pack xqc_int_t xqc_process_ack_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +/* draft-smith-quic-receive-ts-01: QUIC Extended Acknowledgement for Reporting Packet Receive Timestamps */ +xqc_int_t xqc_process_ack_ext_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + xqc_int_t xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); xqc_int_t xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); @@ -156,10 +179,16 @@ xqc_int_t xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t xqc_int_t xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); -xqc_int_t xqc_process_path_standby_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +xqc_int_t xqc_process_datagram_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); -xqc_int_t xqc_process_path_available_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +xqc_int_t xqc_process_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); -xqc_int_t xqc_process_datagram_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +xqc_int_t xqc_process_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + +xqc_int_t xqc_process_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + +xqc_int_t xqc_process_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + +xqc_int_t xqc_process_max_path_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); #endif /* _XQC_FRAME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame_parser.c b/src/transport/xqc_frame_parser.c index d7e3edf7f..5413b0e8f 100644 --- a/src/transport/xqc_frame_parser.c +++ b/src/transport/xqc_frame_parser.c @@ -8,16 +8,22 @@ #include "src/common/utils/vint/xqc_variable_len_int.h" #include "src/common/xqc_log.h" #include "src/common/xqc_log_event_callback.h" +#include "src/common/xqc_str.h" #include "src/transport/xqc_conn.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_reinjection.h" +#include "src/transport/xqc_fec_scheme.h" + +static size_t xqc_write_packet_receive_timestamps_into_buf(xqc_connection_t *conn, unsigned char *dst_buf, size_t dst_buf_len, + xqc_recv_timestamps_info_t *recv_timestamps, uint64_t po_largest_ack); /** * generate datagram frame */ -xqc_int_t xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, +xqc_int_t +xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, const unsigned char *payload, size_t size) { if (packet_out == NULL) { @@ -25,7 +31,7 @@ xqc_int_t xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, } unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); unsigned char *p = dst_buf + 1; if ((size + 1 + XQC_DATAGRAM_LENGTH_FIELD_BYTES) > dst_buf_len) { @@ -125,7 +131,7 @@ xqc_gen_stream_frame(xqc_packet_out_t *packet_out, */ unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); *written_size = 0; /* variable length integer's most significant 2 bits */ @@ -254,6 +260,8 @@ xqc_gen_stream_frame(xqc_packet_out_t *packet_out, if (length_len) { *p++ = 0; + } else { + packet_out->po_flag |= XQC_POF_STREAM_NO_LEN; } } @@ -314,6 +322,7 @@ xqc_parse_stream_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, p += vlen; if (length > end - p) { + xqc_log(conn->log, XQC_LOG_ERROR, "|parse stream frame error|stream length:%d|packet length:%d",length, end - p); return -XQC_EILLEGAL_FRAME; } frame->data_length = length; @@ -365,7 +374,7 @@ xqc_gen_crypto_frame(xqc_packet_out_t *packet_out, uint64_t offset, const unsigned char *payload, uint64_t payload_size, size_t *written_size) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); unsigned char offset_bits, length_bits; unsigned offset_vlen, length_vlen; @@ -449,9 +458,9 @@ xqc_parse_crypto_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, void xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) { - size_t total_len = XQC_PACKET_INITIAL_MIN_LENGTH; - - if (conn->conn_settings.enable_pmtud) { + size_t total_len = XQC_PACKET_INITIAL_MIN_LENGTH - XQC_TLS_AEAD_OVERHEAD_MAX_LEN; + + if (conn->enable_pmtud) { if ((packet_out->po_frame_types & (XQC_FRAME_BIT_PATH_CHALLENGE | XQC_FRAME_BIT_PATH_RESPONSE)) || (packet_out->po_flag & XQC_POF_PMTUD_PROBING)) { @@ -467,6 +476,27 @@ xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) } } +xqc_int_t +xqc_gen_padding_frame_with_len(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + size_t padding_len, size_t limit) +{ + unsigned char *p; + + /* fec模式padding长度 */ + if (packet_out->po_used_size + padding_len > limit) { + xqc_log(conn->log, XQC_LOG_WARN, "|packet_out too large|"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + if (packet_out->po_used_size < limit) { + packet_out->po_padding = packet_out->po_buf + packet_out->po_used_size; + memset(packet_out->po_padding, 0, padding_len); + packet_out->po_used_size += padding_len; + packet_out->po_frame_types |= XQC_FRAME_BIT_PADDING; + } + return XQC_OK; +} + xqc_int_t xqc_parse_padding_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn) { @@ -491,7 +521,7 @@ xqc_gen_ping_frame(xqc_packet_out_t *packet_out) unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; unsigned need = 1; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } *dst_buf++ = 0x01; @@ -510,7 +540,429 @@ xqc_parse_ping_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn) return XQC_OK; } +#ifdef XQC_ENABLE_FEC + + +void +xqc_get_lack_src_syb(unsigned char* pm, unsigned char* recv_mask, xqc_int_t m_size, + uint8_t *syb_idx, uint8_t *syb_num) +{ + uint8_t i, flag, cur_syb_id; + + *syb_idx = XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; + *syb_num = 0; + flag = 0x80; + cur_syb_id = 0; + + if (m_size > XQC_MAX_RPR_KEY_SIZE) { + return; + } + + for (i = 0; i < m_size; i++) { + while (1) { + if ((flag & (*(pm + i) ^ *(recv_mask + i)))) { + *syb_num = *syb_num + 1; + if (*syb_idx == XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + *syb_idx = cur_syb_id; + } + } + cur_syb_id++; + if (flag == 0x01) { + break; + } + flag = flag >> 1; + } + flag = 0x80; + } +} + +xqc_fec_rpr_syb_t * +xqc_get_rpr_syb(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + return rpr_symbol; + } + } + return NULL; +} + +void +xqc_try_process_fec_decode(xqc_connection_t *conn, xqc_int_t block_id) +{ + xqc_int_t ret, max_src_symbol_num, recv_src_num, recv_rpr_num, block_mod; + xqc_usec_t rpr_time; + xqc_list_head_t *pos, *next; + xqc_fec_schemes_e fec_scheme; + + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + fec_scheme = conn->conn_settings.fec_params.fec_decoder_scheme; + recv_src_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_id); + recv_rpr_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_id); + block_mod = conn->conn_settings.fec_params.fec_blk_log_mod; + + switch (fec_scheme) { + case XQC_REED_SOLOMON_CODE: + case XQC_XOR_CODE: + if (recv_src_num + recv_rpr_num >= max_src_symbol_num) { + /* FEC decode/flush buffer */ + if (recv_src_num >= max_src_symbol_num) { + xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_id); + goto after_decoder; + + } else if (recv_rpr_num > 0) { + xqc_fec_rpr_syb_t *rpr_syb = xqc_get_rpr_syb(conn->fec_ctl, block_id); + rpr_time = rpr_syb->recv_time; + ret = xqc_fec_bc_decoder(conn, block_id, max_src_symbol_num - recv_src_num, rpr_time); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec xqc_fec_bc_decoder error|ret:%d|", ret); + } + xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_id); + goto after_decoder; + } + } + return; + case XQC_PACKET_MASK_CODE: + // check each recv mask in rpr symbol, if only lack one src symbol + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + uint8_t lack_syb_num, fst_lack_syb_id; + lack_syb_num = fst_lack_syb_id = 0; + + if (symbol->block_id < block_id) { + continue; + } + if (symbol->block_id > block_id) { + break; + } + xqc_get_lack_src_syb(symbol->repair_key, symbol->recv_mask, symbol->repair_key_size, + &fst_lack_syb_id, &lack_syb_num); + if (lack_syb_num == 0) { + xqc_remove_rpr_symbol_from_list(conn->fec_ctl, symbol); + + } else if (lack_syb_num == 1) { + // current repair packet satisfy the conditions of decoding + ret = xqc_fec_cc_decoder(conn, symbol, fst_lack_syb_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec xqc_fec_cc_decoder error|ret:%d|", ret); + + } else { + // log the time it cost between recovered and rpr symbol received, control log rate + if (conn->conn_settings.fec_params.fec_log_on && block_id % block_mod == 0) { + xqc_log(conn->log, XQC_LOG_REPORT, "|fec_stats|PM|current block: %d|recovered %ui ms after rpr received", block_id, xqc_calc_delay(xqc_monotonic_timestamp(), symbol->recv_time)/1000); + } + } + xqc_remove_rpr_symbol_from_list(conn->fec_ctl, symbol); + } + } + return; + default: + return; + } +after_decoder: + if (block_id > conn->fec_ctl->fec_max_fin_blk_id) { + conn->fec_ctl->fec_max_fin_blk_id = block_id; + } +} +xqc_int_t +xqc_check_gen_sid_param(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + xqc_int_t po_remained_size; + + if (packet_out->po_flag & XQC_POF_STREAM_NO_LEN) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|packet_out stream frame have no LEN bit, cannot support superaddition of other frame.|"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + + po_remained_size = packet_out->po_buf_size - packet_out->po_used_size + (packet_out->po_frame_types & XQC_FRAME_BIT_ACK ? XQC_ACK_SPACE : 0); + if (po_remained_size < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|po_used_size exceeds po_buf_size|po_used_size:%d|po_buf_size:%d|", packet_out->po_used_size, packet_out->po_buf_size); + return -XQC_EPARAM; + } + + if (po_remained_size < packet_out->po_reserved_size || packet_out->po_reserved_size == 0) { + if (packet_out->po_reserved_size != 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_out reserved buff are taken|po_frame:%d|po_buf_size:%d|po_used_size:%d|po_reserved_size:%d", + packet_out->po_frame_types, packet_out->po_buf_size, packet_out->po_used_size, packet_out->po_reserved_size); + + } else if (conn->conn_settings.fec_params.fec_encoder_scheme != 0){ + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|reserved size is zero"); + } + return -XQC_EFEC_TOLERABLE_ERROR; + } + return XQC_OK; +} + +ssize_t +xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + size_t dst_buf_len = packet_out->po_reserved_size; + uint64_t flow_id = 0, src_payload_id = 0, frame_type = 0xfec5; + unsigned need, frame_type_bits, flow_id_bits, src_payload_id_bits; + xqc_int_t ret = 0; + unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; + const unsigned char *begin = dst_buf, *end = dst_buf + dst_buf_len; + + ret = xqc_check_gen_sid_param(conn, packet_out); + if (ret != XQC_OK) { + return ret; + } + + /* gen src_payload_id and save src symbol */ + ret = xqc_gen_src_payload_id(conn->fec_ctl, &src_payload_id, packet_out->po_stream_fec_blk_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|generate source payload id error."); + return -XQC_EFEC_SYMBOL_ERROR; + } + frame_type_bits = xqc_vint_get_2bit(frame_type); + flow_id_bits = xqc_vint_get_2bit(flow_id); + src_payload_id_bits = xqc_vint_get_2bit(src_payload_id); + + need = xqc_vint_len(frame_type_bits) /* type: 0xfec5 */ + + xqc_vint_len(flow_id_bits) + + xqc_vint_len(src_payload_id_bits); /* Explicit Source Payload ID */ + + if (dst_buf + need > end) { + xqc_log(conn->log, XQC_LOG_ERROR, "|data length exceed packetout buffer."); + return -XQC_ENOBUF; + } + + xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); + + xqc_vint_write(dst_buf, flow_id, flow_id_bits, xqc_vint_len(flow_id_bits)); + dst_buf += xqc_vint_len(flow_id_bits); + + xqc_vint_write(dst_buf, src_payload_id, src_payload_id_bits, xqc_vint_len(src_payload_id_bits)); + dst_buf += xqc_vint_len(src_payload_id_bits); + + packet_out->po_frame_types |= XQC_FRAME_BIT_SID; + return dst_buf - begin; +} + +xqc_int_t +xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, uint64_t *src_payload_id, xqc_int_t *symbol_size) +{ + int vlen; + uint64_t frame_type, flow_id; + xqc_int_t ret, remain_frame_len, tmp_len; + unsigned char *p = packet_in->pos, *tmp_payload_p; + const unsigned char *end = packet_in->last; + + ret = *symbol_size = *src_payload_id = 0; + remain_frame_len = packet_in->last - packet_in->pos; + + vlen = xqc_vint_read(p, end, &frame_type); + if (vlen < 0 || frame_type != 0xfec5) { + return -XQC_EVINTREAD; + } + p += vlen; + + // TODOfec: flow_id is to be connected to stream + vlen = xqc_vint_read(p, end, &flow_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, src_payload_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + *symbol_size = packet_in->decode_payload_len - remain_frame_len; + +end_parse: + packet_in->pos = (unsigned char *)p; + packet_in->pi_frame_types |= XQC_FRAME_BIT_SID; + return ret; +} + +xqc_int_t +xqc_gen_repair_frame_check_param(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + xqc_int_t repair_idx, uint8_t bm_idx, xqc_int_t repair_key_size, xqc_int_t repair_symbol_size) +{ + if (packet_out == NULL + || repair_idx < 0 + || repair_idx >= XQC_REPAIR_LEN + || repair_key_size < 0 + || repair_symbol_size <= 0 + || repair_symbol_size >= XQC_MAX_SYMBOL_SIZE) + { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|fec parameter error|repair_idx:%d|repair_key_size:%d|repair_symbol_size:%d|", repair_idx, repair_key_size, repair_symbol_size); + return -XQC_EPARAM; + } + + if (conn->conn_settings.fec_params.fec_ele_bit_size <= 0 + || (!conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].is_valid && conn->conn_settings.fec_params.fec_encoder_scheme != XQC_XOR_CODE) + || !conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].is_valid) + { + xqc_log(conn->log, XQC_LOG_WARN, "No available repair key or repair symbol"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + return XQC_OK; +} + +xqc_int_t +xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, + xqc_int_t repair_idx, uint8_t bm_idx) +{ + size_t dst_buf_len; + uint64_t flow_id, frame_type, repair_payload_id; + unsigned need, frame_type_bits, flow_id_bits, fss_esi_bits, repair_key_bits, repair_payload_id_bits, repair_key_size_bits, repair_symbol_size_bits; + xqc_int_t ret, repair_symbol_size, repair_key_size; + unsigned char *dst_buf, *repair_symbol_p, *repair_key_p; + const unsigned char *begin, *end; + + repair_key_p = conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].payload; + repair_key_size = conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].payload_size; + repair_symbol_p = conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].payload; + repair_symbol_size = conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].payload_size; + + ret = xqc_gen_repair_frame_check_param(conn, packet_out, repair_idx, bm_idx, repair_key_size, repair_symbol_size); + if (ret != XQC_OK) { + return ret; + } + + dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out) + XQC_FEC_SPACE; + dst_buf = packet_out->po_buf + packet_out->po_used_size; + begin = dst_buf; end = dst_buf + dst_buf_len; + + frame_type = 0xfec6; + flow_id = conn->fec_ctl->fec_flow_id; + repair_payload_id = repair_idx; + + frame_type_bits = xqc_vint_get_2bit(frame_type); + flow_id_bits = xqc_vint_get_2bit(flow_id); + fss_esi_bits = xqc_vint_get_2bit(fss_esi); + repair_payload_id_bits = xqc_vint_get_2bit(repair_payload_id); + repair_key_size_bits = xqc_vint_get_2bit(repair_key_size); + repair_symbol_size_bits = xqc_vint_get_2bit(repair_symbol_size); + + need = xqc_vint_len(frame_type_bits) + + xqc_vint_len(flow_id_bits) + + xqc_vint_len(fss_esi_bits) + + xqc_vint_len(repair_payload_id_bits) + + xqc_vint_len(repair_key_size_bits) + + repair_key_size + + xqc_vint_len(repair_symbol_size_bits) + + repair_symbol_size; + + if (dst_buf + need > end) { + return -XQC_ENOBUF; + } + + xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); + + xqc_vint_write(dst_buf, flow_id, flow_id_bits, xqc_vint_len(flow_id_bits)); + dst_buf += xqc_vint_len(flow_id_bits); + + xqc_vint_write(dst_buf, fss_esi, fss_esi_bits, xqc_vint_len(fss_esi_bits)); + dst_buf += xqc_vint_len(fss_esi_bits); + + xqc_vint_write(dst_buf, repair_payload_id, repair_payload_id_bits, xqc_vint_len(repair_payload_id_bits)); + dst_buf += xqc_vint_len(repair_payload_id_bits); + + xqc_vint_write(dst_buf, repair_key_size, repair_key_size_bits, xqc_vint_len(repair_key_size_bits)); + dst_buf += xqc_vint_len(repair_key_size_bits); + + xqc_memcpy(dst_buf, repair_key_p, repair_key_size); + dst_buf += repair_key_size; + + xqc_vint_write(dst_buf, repair_symbol_size, repair_symbol_size_bits, xqc_vint_len(repair_symbol_size_bits)); + dst_buf += xqc_vint_len(repair_symbol_size_bits); + + xqc_memcpy(dst_buf, repair_symbol_p, repair_symbol_size); + dst_buf += repair_symbol_size; + + packet_out->po_frame_types |= XQC_FRAME_BIT_REPAIR_SYMBOL; + packet_out->po_used_size += dst_buf - begin; + return XQC_OK; +} + +xqc_int_t +xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, + xqc_fec_rpr_syb_t *rpr_symbol) +{ + int vlen = 0; + uint64_t frame_type, flow_id, fss_esi, repair_payload_id, repair_symbol_size, repair_key_size; + xqc_int_t ret; + unsigned char *p = packet_in->pos, *end = packet_in->last, *tmp_payload_p, *repair_key_p, *repair_symbol_p; + + frame_type = flow_id = fss_esi = repair_payload_id = 0; + ret = 0; + + vlen = xqc_vint_read(p, end, &frame_type); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, &flow_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, &fss_esi); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + rpr_symbol->block_id = fss_esi; + + vlen = xqc_vint_read(p, end, &repair_payload_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + rpr_symbol->symbol_idx = repair_payload_id; + + vlen = xqc_vint_read(p, end, &repair_key_size); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + rpr_symbol->repair_key_size = repair_key_size; + rpr_symbol->repair_key = p; + + p = p + rpr_symbol->repair_key_size; + vlen = xqc_vint_read(p, end, &repair_symbol_size); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + rpr_symbol->payload_size = repair_symbol_size; + rpr_symbol->payload = p; + + p += rpr_symbol->payload_size; + + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + ret = -XQC_EFEC_TOLERABLE_ERROR; + goto end_parse_repair; + } + if (rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|received repair symbol size is too large"); + ret = -XQC_EIGNORE_PKT; + goto end_parse_repair; + } + +end_parse_repair: + packet_in->pos = (unsigned char *) p; + packet_in->pi_frame_types |= XQC_FRAME_BIT_REPAIR_SYMBOL; + return ret; +} +#endif /* * 0 1 2 3 @@ -547,9 +999,9 @@ xqc_gen_ack_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec int *has_gap, xqc_packet_number_t *largest_ack) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size + XQC_ACK_SPACE; + size_t dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out); - xqc_packet_number_t lagest_recv, prev_low; + xqc_packet_number_t largest_recv, prev_low; xqc_usec_t ack_delay; const unsigned char *begin = dst_buf; @@ -572,21 +1024,21 @@ xqc_gen_ack_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec } ack_delay = (now - largest_pkt_recv_time); - lagest_recv = first_range->pktno_range.high; - first_ack_range = lagest_recv - first_range->pktno_range.low; + largest_recv = first_range->pktno_range.high; + first_ack_range = largest_recv - first_range->pktno_range.low; prev_low = first_range->pktno_range.low; - xqc_log(conn->log, XQC_LOG_DEBUG, "|lagest_recv:%ui|ack_delay:%ui|first_ack_range:%ud|largest_pkt_recv_time:%ui|", - lagest_recv, ack_delay, first_ack_range, largest_pkt_recv_time); + xqc_log(conn->log, XQC_LOG_DEBUG, "|largest_recv:%ui|ack_delay:%ui|first_ack_range:%ud|largest_pkt_recv_time:%ui|", + largest_recv, ack_delay, first_ack_range, largest_pkt_recv_time); ack_delay = ack_delay >> ack_delay_exponent; - unsigned lagest_recv_bits = xqc_vint_get_2bit(lagest_recv); + unsigned largest_recv_bits = xqc_vint_get_2bit(largest_recv); unsigned ack_delay_bits = xqc_vint_get_2bit(ack_delay); unsigned first_ack_range_bits = xqc_vint_get_2bit(first_ack_range); need = 1 /* type */ - + xqc_vint_len(lagest_recv_bits) + + xqc_vint_len(largest_recv_bits) + xqc_vint_len(ack_delay_bits) + 1 /* range_count */ + xqc_vint_len(first_ack_range_bits); @@ -597,10 +1049,10 @@ xqc_gen_ack_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec *dst_buf++ = 0x02; - xqc_vint_write(dst_buf, lagest_recv, lagest_recv_bits, xqc_vint_len(lagest_recv_bits)); - dst_buf += xqc_vint_len(lagest_recv_bits); + xqc_vint_write(dst_buf, largest_recv, largest_recv_bits, xqc_vint_len(largest_recv_bits)); + dst_buf += xqc_vint_len(largest_recv_bits); - *largest_ack = lagest_recv; + *largest_ack = largest_recv; xqc_vint_write(dst_buf, ack_delay, ack_delay_bits, xqc_vint_len(ack_delay_bits)); dst_buf += xqc_vint_len(ack_delay_bits); @@ -667,9 +1119,14 @@ xqc_parse_ack_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, xqc_ack_ { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; - const unsigned char first_byte = *p++; int vlen; + uint64_t frame_type; + vlen = xqc_vint_read(p, end, &frame_type); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; uint64_t largest_acked; uint64_t ack_range_count; /* the actual range cnt */ uint64_t first_ack_range; @@ -682,7 +1139,7 @@ xqc_parse_ack_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, xqc_ack_ * negotiated, ACK frames in 1-RTT packets acknowledge packets sent * with the Connection ID having sequence number 0. */ - ack_info->dcid_seq_num = 0; + ack_info->path_id = 0; ack_info->pns = packet_in->pi_pkt.pkt_pns; vlen = xqc_vint_read(p, end, &largest_acked); @@ -690,6 +1147,7 @@ xqc_parse_ack_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, xqc_ack_ return -XQC_EVINTREAD; } p += vlen; + ack_info->largest_acked = largest_acked; vlen = xqc_vint_read(p, end, &ack_info->ack_delay); if (vlen < 0) { @@ -786,7 +1244,7 @@ xqc_gen_conn_close_frame(xqc_packet_out_t *packet_out, + xqc_vint_len(frame_type_bits) + xqc_vint_len(reason_len_bits) + reason_len; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -891,7 +1349,7 @@ xqc_gen_reset_stream_frame(xqc_packet_out_t *packet_out, xqc_stream_id_t stream_ + xqc_vint_len(err_code_bits) + xqc_vint_len(final_size_bits) ; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -972,7 +1430,7 @@ xqc_gen_stop_sending_frame(xqc_packet_out_t *packet_out, xqc_stream_id_t stream_ + xqc_vint_len(stream_id_bits) + xqc_vint_len(err_code_bits) ; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1381,11 +1839,10 @@ xqc_gen_new_token_frame(xqc_packet_out_t *packet_out, const unsigned char *token xqc_vint_write(dst_buf, token_len, token_len_bits, xqc_vint_len(token_len_bits)); dst_buf += xqc_vint_len(token_len_bits); - if (packet_out->po_used_size - + 1 + if (1 + xqc_vint_len(token_len_bits) + token_len - > packet_out->po_buf_size) + > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1443,7 +1900,7 @@ xqc_gen_handshake_done_frame(xqc_packet_out_t *packet_out) const unsigned char *begin = dst_buf; unsigned need = 1; /* only need 1 byte */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } *dst_buf++ = 0x1e; @@ -1487,8 +1944,6 @@ xqc_gen_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, *dst_buf++ = 0x18; - unsigned char stateless_reset_token[XQC_STATELESS_RESET_TOKENLEN] = {0}; - unsigned sequence_number_bits = xqc_vint_get_2bit(new_cid->cid_seq_num); unsigned retire_prior_to_bits = xqc_vint_get_2bit(retire_prior_to); uint64_t cid_len = new_cid->cid_len; @@ -1665,7 +2120,7 @@ xqc_gen_path_challenge_frame(xqc_packet_out_t *packet_out, unsigned char *data) need = xqc_vint_len(frame_type_bits) + XQC_PATH_CHALLENGE_DATA_LEN; /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1725,7 +2180,7 @@ xqc_gen_path_response_frame(xqc_packet_out_t *packet_out, unsigned char *data) need = xqc_vint_len(frame_type_bits) + XQC_PATH_CHALLENGE_DATA_LEN; /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1768,7 +2223,7 @@ xqc_parse_path_response_frame(xqc_packet_in_t *packet_in, unsigned char *data) * * ACK_MP Frame { * Type (i) = TBD-00..TBD-01 , - * Destination Connection ID Sequence Number (i), + * Path ID (i), * Largest Acknowledged (i), * ACK Delay (i), * ACK Range Count (i), @@ -1781,27 +2236,24 @@ xqc_parse_path_response_frame(xqc_packet_in_t *packet_in, unsigned char *data) */ ssize_t -xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, +xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t path_id, xqc_packet_out_t *packet_out, xqc_usec_t now, int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, int *has_gap, xqc_packet_number_t *largest_ack) { uint64_t frame_type; - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba00; - - } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { - /* 06 is the same with 05 */ - frame_type = 0x15228c00; + + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + frame_type = XQC_TRANS_FRAME_TYPE_MP_ACK0; } else { return -XQC_EMP_INVALID_MP_VERTION; } unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size + XQC_ACK_SPACE; + size_t dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out); - xqc_packet_number_t lagest_recv, prev_low; + xqc_packet_number_t largest_recv, prev_low; xqc_usec_t ack_delay; const unsigned char *begin = dst_buf; @@ -1832,24 +2284,24 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, ack_delay = 0; } - lagest_recv = first_range->pktno_range.high; - first_ack_range = lagest_recv - first_range->pktno_range.low; + largest_recv = first_range->pktno_range.high; + first_ack_range = largest_recv - first_range->pktno_range.low; prev_low = first_range->pktno_range.low; - xqc_log(conn->log, XQC_LOG_DEBUG, "|lagest_recv:%ui|ack_delay:%ui|first_ack_range:%ud|largest_pkt_recv_time:%ui|", - lagest_recv, ack_delay, first_ack_range, largest_pkt_recv_time); + xqc_log(conn->log, XQC_LOG_DEBUG, "|largest_recv:%ui|ack_delay:%ui|first_ack_range:%ud|largest_pkt_recv_time:%ui|", + largest_recv, ack_delay, first_ack_range, largest_pkt_recv_time); ack_delay = ack_delay >> ack_delay_exponent; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_bits = xqc_vint_get_2bit(dcid_seq); - unsigned lagest_recv_bits = xqc_vint_get_2bit(lagest_recv); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); + unsigned largest_recv_bits = xqc_vint_get_2bit(largest_recv); unsigned ack_delay_bits = xqc_vint_get_2bit(ack_delay); unsigned first_ack_range_bits = xqc_vint_get_2bit(first_ack_range); need = + xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_bits) - + xqc_vint_len(lagest_recv_bits) + + xqc_vint_len(path_id_bits) + + xqc_vint_len(largest_recv_bits) + xqc_vint_len(ack_delay_bits) + 1 /* range_count */ + xqc_vint_len(first_ack_range_bits); @@ -1861,13 +2313,13 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - xqc_vint_write(dst_buf, dcid_seq, dcid_seq_bits, xqc_vint_len(dcid_seq_bits)); - dst_buf += xqc_vint_len(dcid_seq_bits); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); - xqc_vint_write(dst_buf, lagest_recv, lagest_recv_bits, xqc_vint_len(lagest_recv_bits)); - dst_buf += xqc_vint_len(lagest_recv_bits); + xqc_vint_write(dst_buf, largest_recv, largest_recv_bits, xqc_vint_len(largest_recv_bits)); + dst_buf += xqc_vint_len(largest_recv_bits); - *largest_ack = lagest_recv; + *largest_ack = largest_recv; xqc_vint_write(dst_buf, ack_delay, ack_delay_bits, xqc_vint_len(ack_delay_bits)); dst_buf += xqc_vint_len(ack_delay_bits); @@ -1930,7 +2382,7 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, xqc_int_t xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, - uint64_t *dcid_seq_num, xqc_ack_info_t *ack_info) + uint64_t *path_id, xqc_ack_info_t *ack_info) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; @@ -1950,13 +2402,13 @@ xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, } p += vlen; - vlen = xqc_vint_read(p, end, dcid_seq_num); + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - ack_info->dcid_seq_num = *dcid_seq_num; + ack_info->path_id = *path_id; ack_info->pns = packet_in->pi_pkt.pkt_pns; vlen = xqc_vint_read(p, end, &largest_acked); @@ -2028,34 +2480,30 @@ xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, /* - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#name-path_abandon-frame - * * PATH_ABANDON Frame { * Type (i) = TBD-03, - * DCID Sequence Number (i), + * Path ID (i), * Error Code (i), * Reason Phrase Length (i), * Reason Phrase (..), * } * - * Figure 6: PATH_ABANDON Frame Format */ ssize_t xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, uint64_t error_code) + uint64_t path_id, uint64_t error_code) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; + unsigned need, po_remained_size; uint64_t frame_type; - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba05; - - } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { + need = po_remained_size = 0; + + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { /* same frame type in 05 and 06 */ - frame_type = 0x15228c05; + frame_type = XQC_TRANS_FRAME_TYPE_MP_ABANDON; } else { return -XQC_EMP_INVALID_MP_VERTION; @@ -2065,18 +2513,20 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint8_t *reason = NULL; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); unsigned error_code_bits = xqc_vint_get_2bit(error_code); unsigned reason_len_bits = xqc_vint_get_2bit(reason_len); need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) + + xqc_vint_len(path_id_bits) + xqc_vint_len(error_code_bits) + xqc_vint_len(reason_len_bits) + reason_len; + po_remained_size = xqc_get_po_remained_size(packet_out); + /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > po_remained_size) { return -XQC_ENOBUF; } @@ -2084,9 +2534,9 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + /* Path ID (i) */ + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); /* Error Code (i) */ xqc_vint_write(dst_buf, error_code, error_code_bits, xqc_vint_len(error_code_bits)); @@ -2109,7 +2559,7 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, uint64_t *error_code) + uint64_t *path_id, uint64_t *error_code) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; @@ -2124,8 +2574,8 @@ xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } @@ -2158,52 +2608,52 @@ xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, } -/* - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#name-path_status-frame - * - * PATH_STATUS Frame { - * Type (i) = TBD-03, - * DCID Sequence Number (i), - * Path Status sequence number (i), - * Path Status (i), - * } - * - * Figure 7: PATH_STATUS Frame Format - */ - -ssize_t +ssize_t xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num, uint64_t path_status) + uint64_t path_id, + uint64_t path_status_seq_num, + xqc_app_path_status_t status) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; unsigned need = 0; uint64_t frame_type; - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba06; + uint64_t ft_flag; - } else if (conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - frame_type = 0x15228c06; + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + switch (status) { + case XQC_APP_PATH_STATUS_STANDBY: + frame_type = XQC_TRANS_FRAME_TYPE_MP_STANDBY; + ft_flag = XQC_FRAME_BIT_PATH_STANDBY; + break; + case XQC_APP_PATH_STATUS_AVAILABLE: + frame_type = XQC_TRANS_FRAME_TYPE_MP_AVAILABLE; + ft_flag = XQC_FRAME_BIT_PATH_AVAILABLE; + break; + case XQC_APP_PATH_STATUS_FROZEN: + frame_type = XQC_TRANS_FRAME_TYPE_MP_FROZEN; + ft_flag = XQC_FRAME_BIT_PATH_FROZEN; + break; + default: + return -XQC_EMP_PATH_STATE_ERROR; + } } else { return -XQC_EMP_INVALID_MP_VERTION; } unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); - unsigned path_status_bits = xqc_vint_get_2bit(path_status); need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits) - + xqc_vint_len(path_status_bits); + + xqc_vint_len(path_id_bits) + + xqc_vint_len(path_status_seq_num_bits); /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -2211,27 +2661,22 @@ xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + /* Path ID (i) */ + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); /* Path Status sequence number (i) */ xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); dst_buf += xqc_vint_len(path_status_seq_num_bits); - /* Path Status (i) */ - xqc_vint_write(dst_buf, path_status, path_status_bits, xqc_vint_len(path_status_bits)); - dst_buf += xqc_vint_len(path_status_bits); - - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_STATUS; + packet_out->po_frame_types |= ft_flag; return dst_buf - begin; - } -xqc_int_t +xqc_int_t xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, + uint64_t *path_id, uint64_t *path_status_seq_num, uint64_t *path_status) { unsigned char *p = packet_in->pos; @@ -2246,8 +2691,8 @@ xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } @@ -2260,86 +2705,105 @@ xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* Path Status (i) */ - vlen = xqc_vint_read(p, end, path_status); - if (vlen < 0) { - return -XQC_EVINTREAD; - } - p += vlen; - packet_in->pos = p; - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STATUS; + switch (frame_type) { + case XQC_TRANS_FRAME_TYPE_MP_STANDBY: + *path_status = XQC_APP_PATH_STATUS_STANDBY; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + break; + case XQC_TRANS_FRAME_TYPE_MP_AVAILABLE: + *path_status = XQC_APP_PATH_STATUS_AVAILABLE; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; + break; + case XQC_TRANS_FRAME_TYPE_MP_FROZEN: + *path_status = XQC_APP_PATH_STATUS_FROZEN; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_FROZEN; + break; + default: + return -XQC_EILLEGAL_FRAME; + } return XQC_OK; } /* - * PATH_STANDBY Frame { - * Type (i) = TBD-03 (experiments use 0x15228c07) - * Destination Connection ID Sequence Number (i), - * Path Status sequence number (i), - * } * - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-06#section-8.3 + * MP_NEW_CONNECTION_ID Frame { + * Type (i) = 0x15228c09, + * Path Identifier (i), + * Sequence Number (i), + * Retire Prior To (i), + * Length (8), + * Connection ID (8..160), + * Stateless Reset Token (128), + * } + * + * Figure 39: MP_NEW_CONNECTION_ID Frame Format * */ ssize_t -xqc_gen_path_standby_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num) +xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, + uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; - - uint64_t frame_type; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - frame_type = 0x15228c07; - } else { - return -XQC_EMP_INVALID_MP_VERTION; - } + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); - unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); - - need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits); - - /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { - return -XQC_ENOBUF; - } - - /* Type(i) */ xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + /* Path ID (i) */ + unsigned path_id_bits = xqc_vint_get_2bit(path_id); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); - /* Path Status sequence number (i) */ - xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); - dst_buf += xqc_vint_len(path_status_seq_num_bits); + unsigned sequence_number_bits = xqc_vint_get_2bit(new_cid->cid_seq_num); + unsigned retire_prior_to_bits = xqc_vint_get_2bit(retire_prior_to); + uint64_t cid_len = new_cid->cid_len; + uint8_t cid_len_bits = xqc_vint_get_2bit(cid_len); - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + /* make sure cid_len won't exceed XQC_MAX_CID_LEN */ + if (cid_len > XQC_MAX_CID_LEN) { + return -XQC_EPARAM; + } + + xqc_vint_write(dst_buf, new_cid->cid_seq_num, + sequence_number_bits, xqc_vint_len(sequence_number_bits)); + dst_buf += xqc_vint_len(sequence_number_bits); + + + xqc_vint_write(dst_buf, retire_prior_to, retire_prior_to_bits, xqc_vint_len(retire_prior_to_bits)); + dst_buf += xqc_vint_len(retire_prior_to_bits); + + xqc_vint_write(dst_buf, cid_len, cid_len_bits, xqc_vint_len(cid_len_bits)); + dst_buf += xqc_vint_len(cid_len_bits); + + xqc_memcpy(dst_buf, new_cid->cid_buf, new_cid->cid_len); + dst_buf += new_cid->cid_len; + + if (sr_token) { + xqc_memcpy(dst_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); + dst_buf += XQC_STATELESS_RESET_TOKENLEN; + } + + packet_out->po_frame_types |= XQC_FRAME_BIT_MP_NEW_CONNECTION_ID; return dst_buf - begin; } + xqc_int_t -xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status) +xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, + xqc_cid_t *new_cid, uint64_t *retire_prior_to, uint64_t *path_id, + xqc_connection_t *conn) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; - int vlen; + /* frame type */ uint64_t frame_type = 0; vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ if (vlen < 0) { @@ -2347,97 +2811,166 @@ xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } + new_cid->path_id = *path_id; p += vlen; - /* Path Status sequence number (i) */ - vlen = xqc_vint_read(p, end, path_status_seq_num); + /* Sequence Number (i) */ + vlen = xqc_vint_read(p, end, &new_cid->cid_seq_num); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + /* Retire Prior To (i) */ + vlen = xqc_vint_read(p, end, retire_prior_to); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - *path_status = 1; /* 1 - Standby */ + /* Length (8) */ + if (p >= end) { + return -XQC_EPROTO; + } + new_cid->cid_len = *p++; + if (new_cid->cid_len > XQC_MAX_CID_LEN) { + return -XQC_EPROTO; + } + + /* Connection ID (8..160) */ + if (p + new_cid->cid_len > end) { + return -XQC_EPROTO; + } + xqc_memcpy(new_cid->cid_buf, p, new_cid->cid_len); + p += new_cid->cid_len; + + /* Stateless Reset Token (128) */ + if (p + XQC_STATELESS_RESET_TOKENLEN > end) { + return -XQC_EPROTO; + } + xqc_memcpy(new_cid->sr_token, p, XQC_STATELESS_RESET_TOKENLEN); + p += XQC_STATELESS_RESET_TOKENLEN; packet_in->pos = p; - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + packet_in->pi_frame_types |= XQC_FRAME_BIT_MP_NEW_CONNECTION_ID; + xqc_log_event(conn->log, TRA_FRAMES_PROCESSED, XQC_FRAME_NEW_CONNECTION_ID, new_cid, retire_prior_to); return XQC_OK; } /* - * - * PATH_AVAILABLE Frame { - * Type (i) = TBD-03 (experiments use 0x15228c08), - * Destination Connection ID Sequence Number (i), - * Path Status sequence number (i), - * } - * - * - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-06#section-8.4 + * MP_RETIRE_CONNECTION_ID Frame { + * Type (i) = 0x15228c0a, + * Path ID (i), + * Sequence Number (i), + * } * */ ssize_t -xqc_gen_path_available_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num) +xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; - - uint64_t frame_type; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - frame_type = 0x15228c08; - } else { - return -XQC_EMP_INVALID_MP_VERTION; - } + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); - unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); + xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); - need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); - /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { - return -XQC_ENOBUF; + unsigned sequence_number_bits = xqc_vint_get_2bit(seq_num); + xqc_vint_write(dst_buf, seq_num, sequence_number_bits, xqc_vint_len(sequence_number_bits)); + dst_buf += xqc_vint_len(sequence_number_bits); + + packet_out->po_frame_types |= XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID; + + return dst_buf - begin; +} + + +xqc_int_t +xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, uint64_t *path_id) +{ + unsigned char *p = packet_in->pos; + const unsigned char *end = packet_in->last; + int vlen; + + /* frame type */ + uint64_t frame_type = 0; + vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ + if (vlen < 0) { + return -XQC_EVINTREAD; } + p += vlen; - /* Type(i) */ + vlen = xqc_vint_read(p, end, path_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, seq_num); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + packet_in->pos = p; + + packet_in->pi_frame_types |= XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID; + + return XQC_OK; +} + + +/* + * + * MAX_PATH_ID Frame { + * Type (i) = 0x15228c0c, + * Maximum Path Identifier (i), + * } + * + * Figure: MAX_PATH_ID Frame Format + * */ +ssize_t +xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id) +{ + unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; + const unsigned char *begin = dst_buf; + + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MAX_PATH_ID; + unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); - - /* Path Status sequence number (i) */ - xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); - dst_buf += xqc_vint_len(path_status_seq_num_bits); + unsigned max_paths_bits = xqc_vint_get_2bit(max_path_id); + xqc_vint_write(dst_buf, max_path_id, max_paths_bits, xqc_vint_len(max_paths_bits)); + dst_buf += xqc_vint_len(max_paths_bits); - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; + packet_out->po_frame_types |= XQC_FRAME_BIT_MAX_PATH_ID; return dst_buf - begin; } + xqc_int_t -xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status) +xqc_parse_max_path_id_frame(xqc_packet_in_t *packet_in, uint64_t *max_path_id) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; - int vlen; + /* frame type */ uint64_t frame_type = 0; vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ if (vlen < 0) { @@ -2445,25 +2978,432 @@ xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + vlen = xqc_vint_read(p, end, max_path_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - *path_status = 2; /* 2 - available */ + packet_in->pos = p; - /* Path Status sequence number (i) */ - vlen = xqc_vint_read(p, end, path_status_seq_num); + packet_in->pi_frame_types |= XQC_FRAME_BIT_MAX_PATH_ID; + + return XQC_OK; +} + +/* + * + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Largest Acknowledged (i) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ACK Delay (i) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ACK Range Count (i) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | First ACK Range (i) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ACK Ranges (*) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Extended Ack Features (i) ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | // Optional ECN counts (if bit 0 is set in Features) + | [ECN Counts (..)] ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | // Optional Receive Timestamps (if bit 1 is set in Features) + | [Receive Timestamps (..)] ... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Figure: ACK_EXTENDED Frame Format +*/ +ssize_t +xqc_gen_ack_ext_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now, + int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, + int *has_gap, xqc_packet_number_t *largest_ack, xqc_recv_timestamps_info_t *recv_ts_info) +{ + unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out); + + xqc_packet_number_t largest_recv, prev_low; + xqc_usec_t ack_delay; + + const unsigned char *begin = dst_buf; + const unsigned char *end = dst_buf + dst_buf_len; + unsigned char *p_range_count; + unsigned range_count = 0, first_ack_range, gap, acks, gap_bits, acks_bits, need; + + xqc_list_head_t *pos, *next; + xqc_pktno_range_node_t *range_node; + + xqc_pktno_range_node_t *first_range = NULL; + xqc_list_for_each_safe(pos, next, &recv_record->list_head) { + first_range = xqc_list_entry(pos, xqc_pktno_range_node_t, list); + break; + } + + if (first_range == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|recv_record empty|"); + return -XQC_ENULLPTR; + } + + ack_delay = (now - largest_pkt_recv_time); + largest_recv = first_range->pktno_range.high; + first_ack_range = largest_recv - first_range->pktno_range.low; + prev_low = first_range->pktno_range.low; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|largest_recv:%ui|ack_delay:%ui|first_ack_range:%ud|largest_pkt_recv_time:%ui|", + largest_recv, ack_delay, first_ack_range, largest_pkt_recv_time); + + ack_delay = ack_delay >> ack_delay_exponent; + + unsigned largest_recv_bits = xqc_vint_get_2bit(largest_recv); + unsigned ack_delay_bits = xqc_vint_get_2bit(ack_delay); + unsigned first_ack_range_bits = xqc_vint_get_2bit(first_ack_range); + unsigned frame_type_bits = xqc_vint_get_2bit(XQC_TRANS_FRAME_TYPE_ACK_EXT); + unsigned ts_range_need = xqc_recv_timestamps_info_need_bytes_estimate(recv_ts_info); + + need = xqc_vint_len(frame_type_bits) /* type */ + + xqc_vint_len(largest_recv_bits) + + xqc_vint_len(ack_delay_bits) + + 1 /* range_count */ + + xqc_vint_len(first_ack_range_bits) + + 1 /* ext ack features */ + + ts_range_need; + + if (dst_buf + need > end) { + return -XQC_ENOBUF; + } + + /* ack_with_timestamps frame using a different frame type */ + xqc_vint_write(dst_buf, XQC_TRANS_FRAME_TYPE_ACK_EXT, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); + + xqc_vint_write(dst_buf, largest_recv, largest_recv_bits, xqc_vint_len(largest_recv_bits)); + dst_buf += xqc_vint_len(largest_recv_bits); + + *largest_ack = largest_recv; + + xqc_vint_write(dst_buf, ack_delay, ack_delay_bits, xqc_vint_len(ack_delay_bits)); + dst_buf += xqc_vint_len(ack_delay_bits); + + p_range_count = dst_buf; + dst_buf += 1; /* max range_count 63, 1 byte */ + + xqc_vint_write(dst_buf, first_ack_range, first_ack_range_bits, xqc_vint_len(first_ack_range_bits)); + dst_buf += xqc_vint_len(first_ack_range_bits); + + int is_first = 1; + xqc_list_for_each_safe(pos, next, &recv_record->list_head) { /* from second node */ + range_node = xqc_list_entry(pos, xqc_pktno_range_node_t, list); + + xqc_log(conn->log, XQC_LOG_DEBUG, "|high:%ui|low:%ui|pkt_pns:%d|", + range_node->pktno_range.high, range_node->pktno_range.low, packet_out->po_pkt.pkt_pns); + if (is_first) { + is_first = 0; + continue; + } + + gap = prev_low - range_node->pktno_range.high - 2; + acks = range_node->pktno_range.high - range_node->pktno_range.low; + + gap_bits = xqc_vint_get_2bit(gap); + acks_bits = xqc_vint_get_2bit(acks); + + need = xqc_vint_len(gap_bits) + xqc_vint_len(acks_bits); + if (dst_buf + need > end) { + return -XQC_ENOBUF; + } + + xqc_vint_write(dst_buf, gap, gap_bits, xqc_vint_len(gap_bits)); + dst_buf += xqc_vint_len(gap_bits); + + xqc_vint_write(dst_buf, acks, acks_bits, xqc_vint_len(acks_bits)); + dst_buf += xqc_vint_len(acks_bits); + + prev_low = range_node->pktno_range.low; + + ++range_count; + if (range_count >= XQC_MAX_ACK_RANGE_CNT - 1) { + break; + } + } + + if (range_count > 0) { + *has_gap = 1; + + } else { + *has_gap = 0; + } + xqc_vint_write(p_range_count, range_count, 0, 1); + + packet_out->po_frame_types |= XQC_FRAME_BIT_ACK; + /* write base ack range finish */ + + /* + * Write Extended Ack Features: A variable-length integer whose bit-wise + * value indicates which optional fields are included in the ACK. Bit 0 + * indicates whether ECN count fields are included in the frame. + * Bit 1 indicates whether Receive Timestamps are included in the frame. + * XQUIC doesn't send ECN count currently, But Receive Timestamps is enabled + */ + int64_t ext_ack_features = 2; + if (dst_buf + 1 > end) { + return -XQC_ENOBUF; + } + /* if write ack ext features fail, set ext_ack_features = 0 */ + unsigned char *ext_ack_features_pos = dst_buf; + xqc_vint_write(dst_buf, ext_ack_features, 0, 1); + dst_buf += 1; + + size_t left_buf_len = end - dst_buf; + if (left_buf_len < ts_range_need) { + xqc_vint_write(ext_ack_features_pos, 0, 0, 1); + xqc_recv_timestamps_info_set_nobuf_flag(recv_ts_info, 1); + return dst_buf - begin; + } + size_t fill_ts_ret = xqc_write_packet_receive_timestamps_into_buf(conn, dst_buf, left_buf_len, recv_ts_info, largest_recv); + xqc_recv_timestamps_info_set_nobuf_flag(recv_ts_info, 0); + xqc_recv_timestamps_info_clear(recv_ts_info); + return dst_buf - begin + fill_ts_ret; +} + +/* return: the number of bytes written to dst_buf */ +static size_t +xqc_write_packet_receive_timestamps_into_buf(xqc_connection_t *conn, unsigned char *dst_buf, size_t dst_buf_len, + xqc_recv_timestamps_info_t *recv_ts_info, uint64_t po_largest_ack) +{ + /* + * step 1: fill Timestamp Ranges + * step 2: set Timestamp Range Count + * step 3: update packet_out used size + */ + unsigned char *end = dst_buf + dst_buf_len; + unsigned char *begin = dst_buf; + + uint32_t timestamp_range_count = 0; + uint32_t timestamp_exponent = conn->conn_settings.receive_timestamps_exponent; + + unsigned char *timestamp_range_count_pos = dst_buf; + unsigned char *cur_range_delta_count_pos = NULL; + /* currently, only using one byte to write timestamp range count, which means the max count is 1 << 6 - 1 = 63 */ + dst_buf += 1; + + uint32_t cur_range_gap, cur_range_delta_count = 0; + uint64_t cur_timestamp_delta; + uint32_t total_report_num = 0; + uint8_t is_first_pkt_in_cur_range = 1, is_first_range = 1; + + uint32_t need_for_cur_pkt; + unsigned cur_range_gap_bits, cur_timestamp_delta_bits; + xqc_packet_number_t cur_pkt_num, last_pkt_num = 0; + xqc_usec_t cur_pkt_recv_time, last_pkt_recv_time = 0; + uint32_t total_ts_len = xqc_recv_timestamps_info_length(recv_ts_info); + int cur_idx = total_ts_len - 1; + xqc_recv_timestamps_info_fetch(recv_ts_info, cur_idx, &cur_pkt_num, &cur_pkt_recv_time); + while(cur_idx >= 0) { + total_report_num += 1; + /* + * 1. num of reporting timestamp should not exceed max_receive_timestamps_per_ack + * 2. currently, using one byte to write timestamp range count, + * so timestamp_range_count need be small than 1 << 6 - 1 + */ + if (total_report_num > conn->conn_settings.max_receive_timestamps_per_ack) { + break; + } + if (is_first_pkt_in_cur_range) { + if (is_first_range) { + /* + * for first pkt in first range: + * gap = largest_ack - cur_pkt_num + * time_delta = cur_pkt_recv_time - conn_create_time + */ + cur_range_gap = po_largest_ack - cur_pkt_num; + cur_timestamp_delta = ((cur_pkt_recv_time - conn->conn_create_time) / 1000) >> timestamp_exponent; + is_first_range = 0; + } else { + /* + * for first pkt other ranges: + * gap = last_pkt_num - cur_pkt_num + * time_delta = last_pkt_recv_time - cur_pkt_recv_time + */ + cur_range_gap = last_pkt_num - cur_pkt_num; + cur_timestamp_delta = ((last_pkt_recv_time - cur_pkt_recv_time) / 1000) >> timestamp_exponent; + } + /* + * 1. write cur_range:gap + * 2. save buf pos of cur_range:cur_range_delta_count + * 3. write first time delta of cur_range + */ + cur_range_gap_bits = xqc_vint_get_2bit(cur_range_gap); + cur_timestamp_delta_bits = xqc_vint_get_2bit(cur_timestamp_delta); + need_for_cur_pkt = xqc_vint_len(cur_range_gap_bits) + + 1 /* cur_range:delta_count */ + + xqc_vint_len(cur_timestamp_delta_bits); + if (dst_buf + need_for_cur_pkt > end) { + break; + } + xqc_vint_write(dst_buf, cur_range_gap, cur_range_gap_bits, xqc_vint_len(cur_range_gap_bits)); + dst_buf += xqc_vint_len(cur_range_gap_bits); + + /* cur_range:delta_count */ + cur_range_delta_count_pos = dst_buf; + dst_buf += 1; + + xqc_vint_write(dst_buf, cur_timestamp_delta, cur_timestamp_delta_bits, xqc_vint_len(cur_timestamp_delta_bits)); + dst_buf += xqc_vint_len(cur_timestamp_delta_bits); + is_first_pkt_in_cur_range = 0; + cur_range_delta_count = 1; + } else { + if (cur_pkt_num + 1 != last_pkt_num) { + /* + * new timestamp range: + * 1. write cur_range_delta_count + * 2. set is_first_pkt_in_cur_range + */ + xqc_vint_write(cur_range_delta_count_pos, cur_range_delta_count, 0, 1); + cur_range_delta_count_pos = NULL; + is_first_pkt_in_cur_range = 1; + timestamp_range_count += 1; + continue; + } + cur_timestamp_delta = ((last_pkt_recv_time - cur_pkt_recv_time) / 1000) >> timestamp_exponent; + cur_timestamp_delta_bits = xqc_vint_get_2bit(cur_timestamp_delta); + need_for_cur_pkt = xqc_vint_len(cur_timestamp_delta_bits); + if (dst_buf + need_for_cur_pkt > end) { + break; + } + xqc_vint_write(dst_buf, cur_timestamp_delta, cur_timestamp_delta_bits, xqc_vint_len(cur_timestamp_delta_bits)); + dst_buf += need_for_cur_pkt; + cur_range_delta_count += 1; + } + last_pkt_num = cur_pkt_num; + last_pkt_recv_time = cur_pkt_recv_time; + cur_idx -= 1; + xqc_recv_timestamps_info_fetch(recv_ts_info, cur_idx, &cur_pkt_num, &cur_pkt_recv_time); + } + /* write cur_range:delta_count and timestamp_range_count */ + if (cur_range_delta_count_pos != NULL) { + xqc_vint_write(cur_range_delta_count_pos, cur_range_delta_count, 0, 1); + timestamp_range_count += 1; + } + xqc_vint_write(timestamp_range_count_pos, timestamp_range_count, 0, 1); + xqc_log(conn->log, XQC_LOG_DEBUG, "|ts_info_len:%ud|range_count:%ud|", total_ts_len, timestamp_range_count); + return dst_buf - begin; +} + +static xqc_int_t +xqc_parse_timestamps_in_ack_ext(xqc_packet_in_t *packet_in, xqc_connection_t *conn, + xqc_ack_timestamp_info_t *ack_ts_info, xqc_packet_number_t largest_acked) +{ + unsigned char *p = packet_in->pos; + const unsigned char *end = packet_in->last; + uint64_t timestamp_range_count, cur_range_gap, cur_time_delta, cur_range_length; + uint64_t timestamp_delta_exponent = conn->local_settings.receive_timestamps_exponent; + xqc_packet_number_t pkt_num_base = largest_acked; + uint8_t is_first_range = 1, is_first_pkt_in_range = 1; + int vlen; + + vlen = xqc_vint_read(p, end, ×tamp_range_count); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; + if (timestamp_range_count >= XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH) { + return -XQC_EACK_EXT_ABN_VAL; + } + + for (int i = 0; i < timestamp_range_count; ++i) { + vlen = xqc_vint_read(p, end, &cur_range_gap); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, &cur_range_length); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + is_first_pkt_in_range = 1; + if (cur_range_length >= XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH) { + return -XQC_EACK_EXT_ABN_VAL; + } + for (int j = 0; j < cur_range_length; ++j) { + vlen = xqc_vint_read(p, end, &cur_time_delta); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + if (is_first_pkt_in_range) { + if (is_first_range) { + ack_ts_info->pkt_nums[ack_ts_info->report_num] = largest_acked - cur_range_gap; + /* + * The base of first timestamp delta is conn_create_time in sender side, + * the receiver cannnot access it. But due to clock synchronization reason, + * it's meaningless to acess the base. + */ + ack_ts_info->recv_ts[ack_ts_info->report_num] = + (cur_time_delta << timestamp_delta_exponent) + conn->conn_create_time / 1000; + is_first_range = 0; + } else { + ack_ts_info->pkt_nums[ack_ts_info->report_num] = + ack_ts_info->pkt_nums[ack_ts_info->report_num - 1] - cur_range_gap; + ack_ts_info->recv_ts[ack_ts_info->report_num] = + ack_ts_info->recv_ts[ack_ts_info->report_num - 1] - (cur_time_delta << timestamp_delta_exponent); + } + is_first_pkt_in_range = 0; + } else { + ack_ts_info->pkt_nums[ack_ts_info->report_num] = + ack_ts_info->pkt_nums[ack_ts_info->report_num - 1] - 1; + ack_ts_info->recv_ts[ack_ts_info->report_num] = + ack_ts_info->recv_ts[ack_ts_info->report_num - 1] - (cur_time_delta << timestamp_delta_exponent); + } + ack_ts_info->report_num += 1; + if (ack_ts_info->report_num > conn->local_settings.max_receive_timestamps_per_ack) { + return -XQC_EACK_EXT_ABN_VAL; + } + } + is_first_range = 0; + } packet_in->pos = p; + xqc_log(conn->log, XQC_LOG_DEBUG, "|report_num:%d|", ack_ts_info->report_num); + return XQC_OK; +} - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; +xqc_int_t +xqc_parse_ack_ext_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, + xqc_ack_info_t *ack_info, xqc_ack_timestamp_info_t *ack_ts_info) +{ + int ack_parse_ret = xqc_parse_ack_frame(packet_in, conn, ack_info); + if (ack_parse_ret != XQC_OK) { + return ack_parse_ret; + } + /* parse ack_ext feature */ + uint64_t ack_ext_feature = 0; + unsigned char *p = packet_in->pos; + const unsigned char *end = packet_in->last; + int vlen; + vlen = xqc_vint_read(p, end, &ack_ext_feature); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + packet_in->pos = p; + /* parse ENC count */ + /* + * if (ack_ext_feature & XQC_ACK_EXT_FEATURE_BIT_ENC_COUNT) { + * xqc_parse_enc_count_in_ack_ext(packet_in, conn, ack_ts_info, ack_info->largest_acked); + * } + */ + /* parse timestamps */ + if (ack_ext_feature & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) { + int recv_ts_parse_ret = xqc_parse_timestamps_in_ack_ext(packet_in, conn, ack_ts_info, ack_info->largest_acked); + if (recv_ts_parse_ret != XQC_OK) { + return recv_ts_parse_ret; + } + } return XQC_OK; } \ No newline at end of file diff --git a/src/transport/xqc_frame_parser.h b/src/transport/xqc_frame_parser.h index 19aa56430..17e14eafe 100644 --- a/src/transport/xqc_frame_parser.h +++ b/src/transport/xqc_frame_parser.h @@ -6,15 +6,29 @@ #define _XQC_FRAME_PARSER_H_INCLUDED_ #include +#include "src/transport/xqc_fec.h" #include "src/transport/xqc_frame.h" #include "src/transport/xqc_packet_in.h" #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_recv_record.h" +#include "src/transport/xqc_recv_timestamps_info.h" #define XQC_PATH_CHALLENGE_DATA_LEN 8 #define XQC_DATAGRAM_LENGTH_FIELD_BYTES 2 #define XQC_DATAGRAM_HEADER_BYTES (XQC_DATAGRAM_LENGTH_FIELD_BYTES + 1) +#define XQC_TRANS_FRAME_TYPE_MP_ACK0 0x15228c00 +#define XQC_TRANS_FRAME_TYPE_MP_ACK1 0x15228c01 +#define XQC_TRANS_FRAME_TYPE_MP_ABANDON 0x15228c05 +#define XQC_TRANS_FRAME_TYPE_MP_STANDBY 0x15228c07 +#define XQC_TRANS_FRAME_TYPE_MP_AVAILABLE 0x15228c08 +#define XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID 0x15228c09 +#define XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID 0x15228c0a +#define XQC_TRANS_FRAME_TYPE_MAX_PATH_ID 0x15228c0c +#define XQC_TRANS_FRAME_TYPE_MP_FROZEN 0x15228cff + +#define XQC_TRANS_FRAME_TYPE_ACK_EXT 0xB1 + /** * generate datagram frame */ @@ -43,6 +57,9 @@ xqc_int_t xqc_parse_crypto_frame(xqc_packet_in_t *packet_in, xqc_connection_t *c void xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); +xqc_int_t xqc_gen_padding_frame_with_len(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + size_t padding_len, size_t limit); + xqc_int_t xqc_parse_padding_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn); ssize_t xqc_gen_ping_frame(xqc_packet_out_t *packet_out); @@ -123,39 +140,58 @@ ssize_t xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t path_id, xqc_packe int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, int *has_gap, xqc_packet_number_t *largest_ack); xqc_int_t xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, - uint64_t *dcid_seq_num, xqc_ack_info_t *ack_info); + uint64_t *path_id, xqc_ack_info_t *ack_info); ssize_t xqc_gen_path_abandon_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, uint64_t dcid_seq_num, uint64_t error_code); + xqc_packet_out_t *packet_out, uint64_t path_id, uint64_t error_code); xqc_int_t xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, uint64_t *error_code); + uint64_t *path_id, uint64_t *error_code); ssize_t xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num, uint64_t path_status); + uint64_t path_id, + uint64_t path_status_seq_num, + xqc_app_path_status_t status); xqc_int_t xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); + uint64_t *path_id, + uint64_t *path_status_seq_num, uint64_t *path_status); -ssize_t xqc_gen_path_standby_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num); +ssize_t xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -xqc_int_t xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); +xqc_int_t xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, uint64_t *src_payload_id, xqc_int_t *symbol_size); -ssize_t xqc_gen_path_available_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num); +xqc_int_t xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, + xqc_int_t repair_idx, uint8_t bm_idx); + +xqc_int_t xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, + xqc_fec_rpr_syb_t *rpr_symbol); + +ssize_t xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, + uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id); + +xqc_int_t xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, + xqc_cid_t *new_cid, uint64_t *retire_prior_to, uint64_t *path_id, xqc_connection_t *conn); + +ssize_t xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id); + +xqc_int_t xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, uint64_t *path_id); + +ssize_t xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id); +xqc_int_t xqc_parse_max_path_id_frame(xqc_packet_in_t *packet_in, uint64_t *max_path_id); + +void xqc_try_process_fec_decode(xqc_connection_t *conn, xqc_int_t block_id); + + +void xqc_get_lack_src_syb(unsigned char* pm, unsigned char* recv_mask, xqc_int_t m_size, + uint8_t *syb_idx, uint8_t *syb_num); + +ssize_t xqc_gen_ack_ext_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now, + int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, int *has_gap, + xqc_packet_number_t *largest_ack, xqc_recv_timestamps_info_t *recv_ts_info); -xqc_int_t xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); +xqc_int_t xqc_parse_ack_ext_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, + xqc_ack_info_t *ack_info, xqc_ack_timestamp_info_t *ack_ts_info); #endif /*_XQC_FRAME_PARSER_H_INCLUDED_*/ diff --git a/src/transport/xqc_multipath.c b/src/transport/xqc_multipath.c index 46e5dbf85..fbe17e26e 100644 --- a/src/transport/xqc_multipath.c +++ b/src/transport/xqc_multipath.c @@ -9,11 +9,11 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_frame_parser.h" #include "src/transport/xqc_datagram.h" +#include "src/transport/xqc_recv_timestamps_info.h" #include "src/common/xqc_common.h" #include "src/common/xqc_malloc.h" @@ -66,16 +66,24 @@ xqc_path_destroy(xqc_path_ctx_t *path) path->path_pn_ctl = NULL; } + xqc_recv_timestamps_info_destroy(path->recv_ts_info); + xqc_path_schedule_buf_destroy(path); xqc_free((void *)path); } xqc_path_ctx_t * -xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) +xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid, uint64_t path_id) { xqc_path_ctx_t *path = NULL; + if (conn->create_path_count >= XQC_MAX_PATHS_COUNT) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|too many paths|current maximum:%d|", XQC_MAX_PATHS_COUNT); + return NULL; + } + path = xqc_calloc(1, sizeof(xqc_path_ctx_t)); if (path == NULL) { return NULL; @@ -87,11 +95,15 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) path->app_path_status = XQC_APP_PATH_STATUS_AVAILABLE; path->app_path_status_send_seq_num = 0; path->app_path_status_recv_seq_num = 0; + path->path_id = path_id; path->path_pn_ctl = xqc_pn_ctl_create(conn); if (path->path_pn_ctl == NULL) { goto err; } + if (conn->local_settings.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) { + path->recv_ts_info = xqc_recv_timestamps_info_create(); + } path->path_send_ctl = xqc_send_ctl_create(path); if (path->path_send_ctl == NULL) { @@ -104,18 +116,17 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) xqc_init_list_head(&path->path_reinj_tmp_buf); /* cid & path_id init */ - if (scid == NULL) { - if (xqc_get_unused_cid(&conn->scid_set.cid_set, &path->path_scid) != XQC_OK) { + if (xqc_get_unused_cid(&conn->scid_set, &path->path_scid, path_id) != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available scid|"); goto err; } } else { /* already have scid */ - xqc_cid_inner_t *inner_cid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, scid); + xqc_cid_inner_t *inner_cid = xqc_cid_in_cid_set(&conn->scid_set, scid, path_id); if (inner_cid == NULL) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid scid:%s|", xqc_scid_str(scid)); + xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid scid:%s|", xqc_scid_str(conn->engine, scid)); goto err; } @@ -123,7 +134,7 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) } if (dcid == NULL) { - if (xqc_get_unused_cid(&(conn->dcid_set.cid_set), &(path->path_dcid)) != XQC_OK) { + if (xqc_get_unused_cid(&conn->dcid_set, &(path->path_dcid), path_id) != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|MP|conn don't have available dcid|"); goto err; } @@ -133,8 +144,9 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) xqc_cid_copy(&(path->path_dcid), dcid); } - //TODO: MPQUIC fix migration - path->path_id = conn->create_path_count; + xqc_cid_set_update_state(&conn->dcid_set, path_id, XQC_CID_SET_USED); + xqc_cid_set_update_state(&conn->scid_set, path_id, XQC_CID_SET_USED); + path->path_create_time = xqc_monotonic_timestamp(); path->curr_pkt_out_size = conn->pkt_out_size; path->path_max_pkt_out_size = conn->max_pkt_out_size; @@ -144,7 +156,7 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) conn->create_path_count++; xqc_log(conn->engine->log, XQC_LOG_DEBUG, "|path:%ui|dcid:%s|scid:%s|create_path_count:%ud|", - path->path_id, xqc_dcid_str(&path->path_dcid), xqc_scid_str(&path->path_scid), conn->create_path_count); + path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), xqc_scid_str(conn->engine, &path->path_scid), conn->create_path_count); return path; @@ -206,7 +218,9 @@ xqc_path_init(xqc_path_ctx_t *path, xqc_connection_t *conn) xqc_path_addr_str(path), path->peer_addrlen); xqc_log(conn->engine->log, XQC_LOG_DEBUG, "|path:%ui|dcid:%s|scid:%s|state:%d|", - path->path_id, xqc_dcid_str(&path->path_dcid), xqc_scid_str(&path->path_scid), path->path_state); + path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), + xqc_scid_str(conn->engine, &path->path_scid), + path->path_state); return XQC_OK; } @@ -243,9 +257,10 @@ xqc_path_move_unack_packets_from_conn(xqc_path_ctx_t *path, xqc_connection_t *co } if (XQC_NEED_REPAIR(po->po_frame_types) + || (po->po_flag & XQC_POF_NOTIFY) || repair_dgram == XQC_DGRAM_RETX_ASKED_BY_APP) { - xqc_send_queue_copy_to_lost(po, conn->conn_send_queue); + xqc_send_queue_copy_to_lost(po, conn->conn_send_queue, XQC_FALSE); } else { /* for datagram, we should remove all copies in the unacked list */ @@ -309,7 +324,7 @@ xqc_path_immediate_close(xqc_path_ctx_t *path) } /* try to update MSS */ - if (conn->conn_settings.enable_pmtud) { + if (conn->enable_pmtud) { xqc_conn_try_to_update_mss(conn); } @@ -319,6 +334,9 @@ xqc_path_immediate_close(xqc_path_ctx_t *path) xqc_timer_set(&path->path_send_ctl->path_timer_manager, XQC_TIMER_PATH_DRAINING, now, 3 * pto); } + xqc_cid_set_update_state(&conn->scid_set, path->path_id, XQC_CID_SET_ABANDONED); + xqc_cid_set_update_state(&conn->dcid_set, path->path_id, XQC_CID_SET_ABANDONED); + return XQC_OK; } @@ -344,7 +362,6 @@ xqc_path_closed(xqc_path_ctx_t *path) xqc_conn_get_user_data(conn)); } - /* TODO: releadse path recource */ return XQC_OK; } @@ -365,20 +382,20 @@ xqc_conn_enable_multipath(xqc_connection_t *conn) if (conn->dcid_set.current_dcid.cid_len == 0 || conn->scid_set.user_scid.cid_len == 0) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|mutlipath is not possible for connections" - " with zero-length DCID|"); - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - XQC_CONN_ERR(conn, TRA_TRANSPORT_PARAMETER_ERROR); - - } else { - XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION_05); - } - return XQC_CONN_NOT_SUPPORT_MULTIPATH; + xqc_log(conn->log, XQC_LOG_ERROR, "|zero-length DCID|"); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return XQC_CONN_MP_DISABLED; } - return XQC_CONN_MULTIPATH_MULTIPLE_PNS; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|1RTT_transport_params|max_path_id:local:%ui|max_path_id:remote:%ui|", + conn->local_settings.init_max_path_id, conn->remote_settings.init_max_path_id); + conn->local_max_path_id = conn->local_settings.init_max_path_id; + conn->remote_max_path_id = conn->remote_settings.init_max_path_id; + conn->curr_max_path_id = xqc_min(conn->local_max_path_id, conn->remote_max_path_id); + + return XQC_CONN_MP_ENABLED; } - return XQC_CONN_NOT_SUPPORT_MULTIPATH; + return XQC_CONN_MP_DISABLED; } xqc_multipath_version_t @@ -399,13 +416,7 @@ xqc_conn_is_current_mp_version_supported(xqc_multipath_version_t mp_version) { xqc_int_t ret; switch (mp_version) { - case XQC_MULTIPATH_04: - ret = XQC_OK; - break; - case XQC_MULTIPATH_05: - ret = XQC_OK; - break; - case XQC_MULTIPATH_06: + case XQC_MULTIPATH_10: ret = XQC_OK; break; default: @@ -421,6 +432,7 @@ xqc_conn_create_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t *new_ xqc_connection_t *conn = NULL; xqc_path_ctx_t *path = NULL; xqc_app_path_status_t ps_inner = XQC_APP_PATH_STATUS_AVAILABLE; + uint64_t path_id = 0; conn = xqc_engine_conns_hash_find(engine, scid, 's'); if (!conn) { @@ -438,36 +450,30 @@ xqc_conn_create_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t *new_ return -XQC_EMP_NOT_SUPPORT_MP; } - /* must have at least one available unused scid & dcid */ - if (xqc_conn_check_unused_cids(conn) != XQC_OK) { - if (conn->dcid_set.cid_set.unused_cnt == 0) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_DCID; - } - - if (conn->scid_set.cid_set.unused_cnt == 0) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_SCID; - } - + if (xqc_conn_get_available_path_id(conn, &path_id) != XQC_OK) { + conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_MP_READY; xqc_log(conn->log, XQC_LOG_WARN, "|don't have available cid for new path|"); return -XQC_EMP_NO_AVAIL_PATH_ID; } + xqc_log(conn->log, XQC_LOG_DEBUG, + "|find available path_id:%ui|", path_id); + if (path_status == XQC_APP_PATH_STATUS_STANDBY) { ps_inner = XQC_APP_PATH_STATUS_STANDBY; } - path = xqc_conn_create_path_inner(conn, NULL, NULL, ps_inner); + path = xqc_conn_create_path_inner(conn, NULL, NULL, ps_inner, path_id); if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_create error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_create error|%ui|", path_id); return -XQC_EMP_CREATE_PATH; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); + + xqc_engine_wakeup_once(engine); *new_path_id = path->path_id; @@ -519,13 +525,10 @@ xqc_conn_close_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t closed return ret; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, conn); return XQC_OK; } @@ -538,7 +541,7 @@ xqc_conn_init_paths_list(xqc_connection_t *conn) conn->conn_initial_path = xqc_conn_create_path_inner(conn, &conn->scid_set.user_scid, &conn->dcid_set.current_dcid, - XQC_APP_PATH_STATUS_AVAILABLE); + XQC_APP_PATH_STATUS_AVAILABLE, 0); if (conn->conn_initial_path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner fail|"); return -XQC_EMP_CREATE_PATH; @@ -559,24 +562,6 @@ xqc_conn_destroy_paths_list(xqc_connection_t *conn) } } -xqc_path_ctx_t * -xqc_conn_find_path_by_dcid_seq(xqc_connection_t *conn, uint64_t dcid_seq_num) -{ - xqc_path_ctx_t *path = NULL; - xqc_list_head_t *pos, *next; - - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (path->path_dcid.cid_seq_num == dcid_seq_num) { - return path; - } - } - - return NULL; -} - - xqc_path_ctx_t * xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id) { @@ -594,54 +579,37 @@ xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id) return NULL; } + xqc_path_ctx_t * xqc_conn_find_path_by_scid(xqc_connection_t *conn, xqc_cid_t *scid) { xqc_path_ctx_t *path = NULL; xqc_list_head_t *pos, *next; + xqc_cid_inner_t *inner_cid = NULL; - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (xqc_cid_is_equal(&path->path_scid, scid) == XQC_OK) { - return path; - } + inner_cid = xqc_cid_set_search_cid(&conn->scid_set, scid); + if (inner_cid != NULL) { + return xqc_conn_find_path_by_path_id(conn, inner_cid->cid.path_id); } - if (xqc_cid_is_equal(&conn->original_dcid, scid) == XQC_OK) { + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && xqc_cid_is_equal(&conn->original_dcid, scid) == XQC_OK) + { return conn->conn_initial_path; } return NULL; } -xqc_path_ctx_t * -xqc_conn_find_path_by_dcid(xqc_connection_t *conn, xqc_cid_t *dcid) -{ - xqc_path_ctx_t *path = NULL; - xqc_list_head_t *pos, *next; - - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (xqc_cid_is_equal(&path->path_dcid, dcid) == XQC_OK) { - return path; - } - } - - return NULL; -} - - xqc_path_ctx_t * xqc_conn_create_path_inner(xqc_connection_t *conn, - xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status) + xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status, uint64_t path_id) { xqc_int_t ret = XQC_ERROR; xqc_path_ctx_t *path = NULL; - path = xqc_path_create(conn, scid, dcid); + path = xqc_path_create(conn, scid, dcid, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_create error|"); return NULL; @@ -654,7 +622,7 @@ xqc_conn_create_path_inner(xqc_connection_t *conn, xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_init error|%d|", ret); return NULL; } - + xqc_log_event(conn->log, CON_PATH_ASSIGNED, path, conn); return path; } @@ -674,19 +642,24 @@ xqc_conn_path_metrics_print(xqc_connection_t *conn, xqc_conn_stats_t *stats) xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - if (path->path_state >= XQC_PATH_STATE_VALIDATING && paths_num < XQC_MAX_PATHS_COUNT) { + if (path->path_state >= XQC_PATH_STATE_ACTIVE && paths_num < XQC_MAX_PATHS_COUNT) { if (path == NULL || path->path_send_ctl == NULL) { continue; } - if (path->path_send_ctl->ctl_recv_count == 0) { - continue; - } - stats->paths_info[paths_num].path_id = path->path_id; stats->paths_info[paths_num].path_pkt_recv_count = path->path_send_ctl->ctl_recv_count; stats->paths_info[paths_num].path_pkt_send_count = path->path_send_ctl->ctl_send_count; + stats->paths_info[paths_num].path_send_bytes = path->path_send_ctl->ctl_app_bytes_send; + stats->paths_info[paths_num].path_recv_bytes = path->path_send_ctl->ctl_app_bytes_recv; + stats->paths_info[paths_num].path_app_status = path->app_path_status; + + if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { + stats->standby_path_app_bytes += path->path_send_ctl->ctl_app_bytes_send + path->path_send_ctl->ctl_app_bytes_recv; + } + + stats->total_app_bytes += path->path_send_ctl->ctl_app_bytes_send + path->path_send_ctl->ctl_app_bytes_recv; paths_num++; } @@ -772,7 +745,7 @@ xqc_stream_path_metrics_print(xqc_connection_t *conn, xqc_stream_t *stream, char if (!conn->enable_multipath) { snprintf(buff, buff_size, "mp is not supported in connection scid:%s", - xqc_scid_str(&conn->scid_set.user_scid)); + xqc_scid_str(conn->engine, &conn->scid_set.user_scid)); return; } @@ -837,10 +810,10 @@ xqc_stream_path_metrics_on_send(xqc_connection_t *conn, xqc_packet_out_t *po) if (stream != NULL && po->po_path_id < XQC_MAX_PATHS_COUNT) { stream->paths_info[po->po_path_id].path_id = po->po_path_id; stream->paths_info[po->po_path_id].path_pkt_send_count += 1; - stream->paths_info[po->po_path_id].path_send_bytes += po->po_used_size; + stream->paths_info[po->po_path_id].path_send_bytes += po->po_stream_frames[i].ps_length; if (po->po_flag & XQC_POF_REINJECTED_REPLICA) { - stream->paths_info[po->po_path_id].path_send_reinject_bytes += po->po_used_size; + stream->paths_info[po->po_path_id].path_send_reinject_bytes += po->po_stream_frames[i].ps_length; } } @@ -862,49 +835,6 @@ xqc_stream_path_metrics_on_recv(xqc_connection_t *conn, xqc_stream_t *stream, xq } -void -xqc_path_metrics_print(xqc_connection_t *conn, char *buff, unsigned buff_size) -{ - xqc_list_head_t *pos, *next; - xqc_path_ctx_t *path; - - int cursor = 0; - int ret = 0; - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - if (path->path_state >= XQC_PATH_STATE_VALIDATING) { - if (cursor >= (buff_size - 100)) { // enough space - break; - } - - // TODO 关于数据抓取说明 - ret = snprintf(buff + cursor, buff_size - cursor, - "#%"PRIu64"-%d-%d-%"PRIu64"-%.4f-%"PRIu32"-%"PRIu32"-%"PRIu32"-%"PRIu32"-%"PRIu32"" - "-%"PRIu32"-%"PRIu32"-%"PRIu32"-%"PRIu64"-%"PRIu64"-%"PRIu32"-%"PRIu32, - path->path_id, - path->path_state, - path->app_path_status, - xqc_send_ctl_get_srtt(path->path_send_ctl), - xqc_send_ctl_get_retrans_rate(path->path_send_ctl), - path->path_send_ctl->ctl_send_count, - path->path_send_ctl->ctl_lost_count, - path->path_send_ctl->ctl_tlp_count, - path->path_send_ctl->ctl_spurious_loss_count, - path->path_send_ctl->ctl_recv_count, - path->path_send_ctl->ctl_update_latest_rtt_count, - path->rebinding_count, - path->rebinding_valid, - path->path_send_ctl->ctl_bytes_send, - path->path_send_ctl->ctl_bytes_recv, - path->standby_probe_count, - path->app_path_status_changed_count); - - cursor += ret; - } - } -} - - void xqc_path_send_buffer_append(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out, xqc_list_head_t *head) { @@ -960,7 +890,7 @@ xqc_path_send_buffer_clear(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_lis if (packet_out->po_flag & XQC_POF_TLP) { xqc_send_queue_move_to_head(&packet_out->po_list, &send_queue->sndq_pto_probe_packets); - } else if (packet_out->po_flag & XQC_POF_RETRANSED) { + } else if (packet_out->po_flag & XQC_POF_LOST) { xqc_send_queue_move_to_head(&packet_out->po_list, &send_queue->sndq_lost_packets); } else { @@ -1093,10 +1023,11 @@ xqc_conn_server_init_path_addr(xqc_connection_t *conn, uint64_t path_id, /* check if ip address is same with sub-connections created */ if (xqc_is_same_addr(peer_addr, (struct sockaddr *)active_path->peer_addr)) { xqc_path_immediate_close(path); - xqc_log(conn->engine->log, XQC_LOG_STATS, "|MP|path:%ui|conn:%s|cannot activate this path, due to the same IP|curIP:%s|conflictIP:%s|", + xqc_log(conn->engine->log, XQC_LOG_STATS, "|MP|path:%ui|conn:%s|" + "cannot activate this path, due to the same IP|curIP:%s|conflictIP:%s|", path_id, xqc_conn_addr_str(conn), - xqc_peer_addr_str((struct sockaddr*)peer_addr, conn->peer_addrlen), - xqc_local_addr_str((struct sockaddr*)active_path->peer_addr, active_path->peer_addrlen)); + xqc_peer_addr_str(conn->engine, (struct sockaddr*)peer_addr, conn->peer_addrlen), + xqc_local_addr_str(conn->engine, (struct sockaddr*)active_path->peer_addr, active_path->peer_addrlen)); return XQC_OK; } } @@ -1165,7 +1096,7 @@ xqc_path_validate(xqc_path_ctx_t *path) path->path_flag &= ~XQC_PATH_FLAG_SEND_STATUS; xqc_int_t ret = xqc_set_application_path_status(path, path->next_app_path_state, XQC_TRUE); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_status_frame_to_packet error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|"); } } @@ -1175,7 +1106,7 @@ xqc_path_validate(xqc_path_ctx_t *path) } /* PMTUD: launch probing immediately */ - if (conn->conn_settings.enable_pmtud) { + if (conn->enable_pmtud) { conn->probing_cnt = 0; conn->conn_flag |= XQC_CONN_FLAG_PMTUD_PROBING; xqc_timer_unset(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING); @@ -1290,18 +1221,16 @@ xqc_set_application_path_status(xqc_path_ctx_t *path, xqc_app_path_status_t stat if (is_tx) { xqc_int_t ret = XQC_ERROR; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - ret = xqc_write_path_standby_or_available_frame_to_packet(conn, path); - } else { - ret = xqc_write_path_status_frame_to_packet(conn, path); - } + + ret = xqc_write_path_status_frame_to_packet(conn, path); if (ret != XQC_OK) { path->app_path_status = last_status; - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_status_frame_to_packet error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|%d|", ret); return ret; } } + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|app_path_status:%d->%d|", path->path_id, last_status, status); path->app_path_status_changed_count++; path->last_app_path_status_changed_time = xqc_monotonic_timestamp(); @@ -1318,11 +1247,12 @@ xqc_set_application_path_status(xqc_path_ctx_t *path, xqc_app_path_status_t stat } + xqc_int_t xqc_conn_mark_path_standby(xqc_engine_t *engine, const xqc_cid_t *cid, uint64_t path_id) { - xqc_connection_t *conn = NULL; xqc_path_ctx_t *path = NULL; + xqc_connection_t *conn = NULL; conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { @@ -1466,4 +1396,99 @@ xqc_path_standby_probe(xqc_path_ctx_t *path) xqc_log(conn->log, XQC_LOG_DEBUG, "|PING|path:%ui|", path->path_id); path->standby_probe_count++; return XQC_OK; +} + +xqc_path_perf_class_t +xqc_path_get_perf_class(xqc_path_ctx_t *path) +{ + xqc_connection_t *conn = path->parent_conn; + xqc_scheduler_params_t *param = &conn->conn_settings.scheduler_params; + xqc_usec_t path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); + xqc_usec_t min_srtt = xqc_conn_get_min_srtt(path->parent_conn, 0); + uint64_t path_bw = xqc_send_ctl_get_est_bw(path->path_send_ctl); + double loss_rate = xqc_path_recent_loss_rate(path); + + xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|path_id:%ui|" + "path_srtt:%ui|min_srtt:%ui|path_bw:%ui|loss_rate:%.2f|" + "path_pto:%ud|", + conn, path->path_id, path_srtt, min_srtt, path_bw, loss_rate, + path->path_send_ctl->ctl_pto_count); + + // low + if (path_srtt > param->rtt_us_thr_high + || path->path_send_ctl->ctl_pto_count >= param->pto_cnt_thr + || loss_rate > param->loss_percent_thr_high) + { + if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { + return XQC_PATH_CLASS_AVAILABLE_LOW; + + } else { + return XQC_PATH_CLASS_STANDBY_LOW; + } + } + + // mid + if ((path_srtt <= param->rtt_us_thr_high && (path_srtt > xqc_min(param->rtt_us_thr_low, 3 * min_srtt))) + || path_bw < param->bw_Bps_thr + || (loss_rate <= param->loss_percent_thr_high && loss_rate > param->loss_percent_thr_low)) + { + if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { + return XQC_PATH_CLASS_AVAILABLE_MID; + + } else { + return XQC_PATH_CLASS_STANDBY_MID; + } + } + + // high + if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { + return XQC_PATH_CLASS_AVAILABLE_HIGH; + } + + return XQC_PATH_CLASS_STANDBY_HIGH; +} + +double +xqc_conn_recent_loss_rate(xqc_connection_t *conn) +{ + double loss_rate0 = 0, loss_rate1 = 0; + unsigned lost_cnt0, lost_cnt1, send_cnt0, send_cnt1; + xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; + + lost_cnt0 = lost_cnt1 = send_cnt0 = send_cnt1 = 0; + + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + lost_cnt0 += path->path_send_ctl->ctl_recent_lost_count[0]; + send_cnt0 += path->path_send_ctl->ctl_recent_send_count[0]; + lost_cnt1 += path->path_send_ctl->ctl_recent_lost_count[1]; + send_cnt1 += path->path_send_ctl->ctl_recent_send_count[1]; + } + + if (send_cnt0) { + loss_rate0 = 100.0 * lost_cnt0 / send_cnt0; + } + + if (send_cnt1) { + loss_rate1 = 100.0 * lost_cnt1 / send_cnt1; + } + + return xqc_max(loss_rate0, loss_rate1); +} + +double +xqc_path_recent_loss_rate(xqc_path_ctx_t *path) +{ + double loss_rate0 = 0, loss_rate1 = 0; + + if (path->path_send_ctl->ctl_recent_send_count[0]) { + loss_rate0 = 100.0 * path->path_send_ctl->ctl_recent_lost_count[0] / path->path_send_ctl->ctl_recent_send_count[0]; + } + + if (path->path_send_ctl->ctl_recent_send_count[1]) { + loss_rate1 = 100.0 * path->path_send_ctl->ctl_recent_lost_count[1] / path->path_send_ctl->ctl_recent_send_count[1]; + } + + return xqc_max(loss_rate0, loss_rate1); } \ No newline at end of file diff --git a/src/transport/xqc_multipath.h b/src/transport/xqc_multipath.h index 7ddb220bb..0d2d37bdc 100644 --- a/src/transport/xqc_multipath.h +++ b/src/transport/xqc_multipath.h @@ -9,6 +9,7 @@ #include #include #include +#include "src/transport/xqc_cid.h" #include "src/common/xqc_common.h" #include "src/transport/xqc_packet.h" #include "src/transport/xqc_recv_record.h" @@ -17,8 +18,8 @@ /* enable multipath */ typedef enum { - XQC_CONN_NOT_SUPPORT_MULTIPATH = 0, /* 00 */ - XQC_CONN_MULTIPATH_MULTIPLE_PNS = 1, /* 01 */ + XQC_CONN_MP_DISABLED = 0, /* 00 */ + XQC_CONN_MP_ENABLED = 1, /* 01 */ } xqc_multipath_mode_t; /* path state */ @@ -30,21 +31,6 @@ typedef enum { XQC_PATH_STATE_CLOSED = 4, /* PATH_ABANDONED acked or draining timeout */ } xqc_path_state_t; -/* application layer path status */ -typedef enum { - /* max */ - XQC_APP_PATH_STATUS_NONE, - /* suggest that no traffic should be sent on that path if another path is available */ - XQC_APP_PATH_STATUS_STANDBY = 1, - /* allow the peer to use its own logic to split traffic among available paths */ - XQC_APP_PATH_STATUS_AVAILABLE = 2, - /* freeze a path */ - XQC_APP_PATH_STATUS_FROZEN = 3, - /* max */ - XQC_APP_PATH_STATUS_MAX, -} xqc_app_path_status_t; - - /* path close mode: passive & proactive */ typedef enum { XQC_PATH_CLOSE_PASSIVE = 0, @@ -60,9 +46,21 @@ typedef enum { } xqc_send_type_t; typedef enum { - XQC_PATH_FLAG_SEND_STATUS = 1 << 0, - XQC_PATH_FLAG_RECV_STATUS = 1 << 1, - XQC_PATH_FLAG_SOCKET_ERROR = 1 << 2, + XQC_PATH_FLAG_SEND_STATUS_SHIFT, + XQC_PATH_FLAG_RECV_STATUS_SHIFT, + XQC_PATH_FLAG_SOCKET_ERROR_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_INIT_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_HSK_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_01RTT_SHIFT, +} xqc_path_flag_shift_t; + +typedef enum { + XQC_PATH_FLAG_SEND_STATUS = 1 << XQC_PATH_FLAG_SEND_STATUS_SHIFT, + XQC_PATH_FLAG_RECV_STATUS = 1 << XQC_PATH_FLAG_RECV_STATUS_SHIFT, + XQC_PATH_FLAG_SOCKET_ERROR = 1 << XQC_PATH_FLAG_SOCKET_ERROR_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_INIT = 1 << XQC_PATH_FLAG_SHOULD_ACK_INIT_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_HSK = 1 << XQC_PATH_FLAG_SHOULD_ACK_HSK_SHIFT, + XQC_PATH_FLAG_SHOULD_ACK_01RTT = 1 << XQC_PATH_FLAG_SHOULD_ACK_01RTT_SHIFT, } xqc_path_flag_t; typedef enum { @@ -73,8 +71,19 @@ typedef enum { XQC_PATH_SPECIFIED_BY_PTMUD = 1 << 4, /* PMTUD Probe */ XQC_PATH_SPECIFIED_BY_KAP = 1 << 5, /* Keepalive Probe */ XQC_PATH_SPECIFIED_BY_PQP = 1 << 6, /* Path Quality Probe */ + XQC_PATH_SPECIFIED_BY_FEC = 1 << 7, /* FEC repair symbol */ } xqc_path_specified_flag_t; +typedef enum { + XQC_PATH_CLASS_AVAILABLE_HIGH, + XQC_PATH_CLASS_STANDBY_HIGH, + XQC_PATH_CLASS_AVAILABLE_MID, + XQC_PATH_CLASS_STANDBY_MID, + XQC_PATH_CLASS_AVAILABLE_LOW, + XQC_PATH_CLASS_STANDBY_LOW, + XQC_PATH_CLASS_PERF_CLASS_SIZE, +} xqc_path_perf_class_t; + /* path context */ struct xqc_path_ctx_s { @@ -82,7 +91,6 @@ struct xqc_path_ctx_s { uint64_t path_id; /* path identifier */ xqc_cid_t path_scid; xqc_cid_t path_dcid; - xqc_cid_t path_last_scid; /* Path_address: 4-tuple */ unsigned char peer_addr[sizeof(struct sockaddr_in6)], @@ -120,6 +128,7 @@ struct xqc_path_ctx_s { xqc_send_ctl_t *path_send_ctl; xqc_pn_ctl_t *path_pn_ctl; + /* path send buffer, used to store packets scheduled to this path */ xqc_list_head_t path_schedule_buf[XQC_SEND_TYPE_N]; uint32_t path_schedule_bytes; @@ -141,6 +150,12 @@ struct xqc_path_ctx_s { /* PTMUD */ size_t curr_pkt_out_size; size_t path_max_pkt_out_size; + + /* + * Record pkt receive timestamp info. Null if local + * conn_setting.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS == 0 + */ + xqc_recv_timestamps_info_t *recv_ts_info; }; /* 埋点路径信息 */ @@ -167,8 +182,7 @@ typedef struct { uint32_t red_dgram_recv_cnt; uint32_t standby_probe_count; - uint32_t app_path_status_changed_count; - + uint32_t app_path_status_changed_count; } xqc_path_info_t; xqc_bool_t xqc_is_same_addr(const struct sockaddr *sa1, const struct sockaddr *sa2); @@ -193,7 +207,7 @@ void xqc_path_schedule_buf_pre_destroy(xqc_send_queue_t *send_queue, xqc_path_ct /* create path inner */ xqc_path_ctx_t *xqc_conn_create_path_inner(xqc_connection_t *conn, - xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status); + xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status, uint64_t path_id); /* server update client addr when recv path_challenge frame */ xqc_int_t xqc_conn_server_init_path_addr(xqc_connection_t *conn, uint64_t path_id, @@ -213,8 +227,6 @@ xqc_int_t xqc_path_closed(xqc_path_ctx_t *path); /* find path */ xqc_path_ctx_t *xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id); xqc_path_ctx_t *xqc_conn_find_path_by_scid(xqc_connection_t *conn, xqc_cid_t *scid); -xqc_path_ctx_t *xqc_conn_find_path_by_dcid(xqc_connection_t *conn, xqc_cid_t *dcid); -xqc_path_ctx_t *xqc_conn_find_path_by_dcid_seq(xqc_connection_t *conn, uint64_t dcid_seq); void xqc_path_send_buffer_append(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out, xqc_list_head_t *head); void xqc_path_send_buffer_remove(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out); @@ -230,8 +242,6 @@ void xqc_stream_path_metrics_print(xqc_connection_t *conn, xqc_stream_t *stream, void xqc_stream_path_metrics_on_send(xqc_connection_t *conn, xqc_packet_out_t *po); void xqc_stream_path_metrics_on_recv(xqc_connection_t *conn, xqc_stream_t *stream, xqc_packet_in_t *pi); -void xqc_path_metrics_print(xqc_connection_t *conn, char *buff, unsigned buff_size); - xqc_msec_t xqc_path_get_idle_timeout(xqc_path_ctx_t *path); void xqc_path_validate(xqc_path_ctx_t *path); @@ -246,6 +256,12 @@ xqc_bool_t xqc_path_is_full(xqc_path_ctx_t *path); xqc_int_t xqc_path_standby_probe(xqc_path_ctx_t *path); +xqc_path_perf_class_t xqc_path_get_perf_class(xqc_path_ctx_t *path); + +double xqc_path_recent_loss_rate(xqc_path_ctx_t *path); + +double xqc_conn_recent_loss_rate(xqc_connection_t *conn); + #endif /* XQC_MULTIPATH_H */ diff --git a/src/transport/xqc_pacing.c b/src/transport/xqc_pacing.c index 0d34f06bd..276cc24a8 100644 --- a/src/transport/xqc_pacing.c +++ b/src/transport/xqc_pacing.c @@ -13,7 +13,7 @@ #define FALSE 0 #define XQC_CLOCK_GRANULARITY_US 1000 /* 1ms */ #define XQC_PACING_DELAY_US XQC_CLOCK_GRANULARITY_US -#define XQC_DEFAULT_PACING_RATE (((2 * XQC_MSS * 1000000ULL)/(XQC_kInitialRtt * 1000))) +#define XQC_DEFAULT_PACING_RATE(init_rtt) (((2 * XQC_MSS * 1000000ULL)/(init_rtt))) void xqc_pacing_init(xqc_pacing_t *pacing, int pacing_on, xqc_send_ctl_t *send_ctl) @@ -45,13 +45,13 @@ xqc_pacing_rate_calc(xqc_pacing_t *pacing) xqc_usec_t srtt = send_ctl->ctl_srtt; if (srtt == 0) { - srtt = XQC_kInitialRtt * 1000; + srtt = send_ctl->ctl_conn->conn_settings.initial_rtt; } /* bytes can be sent per second */ pacing_rate = cwnd * 1000000 / srtt; if (pacing_rate == 0) { - pacing_rate = XQC_DEFAULT_PACING_RATE; + pacing_rate = XQC_DEFAULT_PACING_RATE(srtt); xqc_log(pacing->ctl_ctx->ctl_conn->log, XQC_LOG_ERROR, "|pacing_rate zero|cwnd:%ui|srtt:%ui|", cwnd, srtt); } @@ -141,7 +141,7 @@ xqc_pacing_can_write(xqc_pacing_t *pacing, uint32_t total_bytes) } uint64_t delay = xqc_pacing_time_until_send(pacing, total_bytes); - xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|pacing_delay: %ui|", delay); + xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|pacing_delay:%ui|", delay); if (delay != 0) { xqc_timer_update(&send_ctl->path_timer_manager, XQC_TIMER_PACING, xqc_monotonic_timestamp(), delay); diff --git a/src/transport/xqc_pacing.h b/src/transport/xqc_pacing.h index 8f4929f49..5c17d2d4e 100644 --- a/src/transport/xqc_pacing.h +++ b/src/transport/xqc_pacing.h @@ -27,4 +27,6 @@ void xqc_pacing_on_app_limit(xqc_pacing_t *pacing); int xqc_pacing_can_write(xqc_pacing_t *pacing, uint32_t total_bytes); +uint64_t xqc_pacing_rate_calc(xqc_pacing_t *pacing); + #endif /* _XQC_PACING_H_INCLUDED_ */ diff --git a/src/transport/xqc_packet.c b/src/transport/xqc_packet.c index 308cb4c55..543fe52ff 100644 --- a/src/transport/xqc_packet.c +++ b/src/transport/xqc_packet.c @@ -95,6 +95,31 @@ xqc_packet_need_decrypt(xqc_packet_t *pkt) return xqc_has_packet_number(pkt); } +/* + * a client MUST discard Initial keys when it first sends a Handshake packet + * and a server MUST discard Initial keys when it first successfully processes a Handshake packet + * we should ignore initial packet if xqc_conn_check_initial_packet_from_cur_state return XQC_FALSE + */ +static inline xqc_int_t +xqc_conn_check_initial_packet_from_cur_state(xqc_conn_state_t cur_state) +{ + switch(cur_state) { + case XQC_CONN_STATE_CLIENT_INIT: + case XQC_CONN_STATE_CLIENT_INITIAL_SENT: + case XQC_CONN_STATE_CLIENT_INITIAL_RECVD: + case XQC_CONN_STATE_SERVER_INIT: + case XQC_CONN_STATE_SERVER_INITIAL_RECVD: + case XQC_CONN_STATE_SERVER_INITIAL_SENT: + case XQC_CONN_STATE_SERVER_HANDSHAKE_SENT: + case XQC_CONN_STATE_SERVER_HANDSHAKE_RECVD: + return XQC_TRUE; + default: + return XQC_FALSE; + + } + return XQC_TRUE; +} + xqc_int_t xqc_packet_parse_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) { @@ -144,6 +169,12 @@ xqc_packet_parse_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) xqc_log(c->log, XQC_LOG_INFO, "|delay|buff HSK before hs_rx_key_ready|"); xqc_conn_buff_undecrypt_packet_in(packet_in, c, XQC_ENC_LEV_HSK); return -XQC_EWAITING; + } else if (XQC_PTYPE_INIT == XQC_PACKET_LONG_HEADER_GET_TYPE(packet_in->pos)) { + if (XQC_UNLIKELY(xqc_conn_check_initial_packet_from_cur_state(c->conn_state) == XQC_FALSE)) { + xqc_log(c->log, XQC_LOG_INFO, "|initial packet should be discarded" + "|curr_stat:%d|", c->conn_state); + return -XQC_EIGNORE_PKT; + } } /* parse packet */ @@ -192,8 +223,9 @@ xqc_packet_decrypt_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) ret = -XQC_EIGNORE_PKT; } else { - xqc_log(c->log, XQC_LOG_WARN, "|decrypt data error, return|%d|pkt_type:%s|pkt_num:%ui|", - ret, xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num); + xqc_log_event(c->log, TRA_PACKET_DROPPED, "decrypt data error", ret, + xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num); + c->packet_dropped_count ++; ret = -XQC_EDECRYPT; /* don't close connection, just drop the packet */ } diff --git a/src/transport/xqc_packet.h b/src/transport/xqc_packet.h index 3427e6af7..70036a326 100644 --- a/src/transport/xqc_packet.h +++ b/src/transport/xqc_packet.h @@ -10,8 +10,10 @@ #include "src/tls/xqc_tls_defs.h" #define XQC_ACK_SPACE 16 +#define XQC_FEC_SPACE 12 +#define XQC_HEADER_SPACE 28 #define XQC_QUIC_MIN_MSS 1200 -/* 1500 - 40 (IPv6) - 8 (UDP) - 16 (ACK) - 16 (AEAD)*/ +/* 1500 - 40 (IPv6) - 8 (UDP) - 16 (ACK) - 16 (AEAD) */ #define XQC_QUIC_MAX_MSS 1420 #define XQC_MSS (XQC_QUIC_MAX_MSS + XQC_ACK_SPACE) diff --git a/src/transport/xqc_packet_in.h b/src/transport/xqc_packet_in.h index f5a341766..f5c1713f7 100644 --- a/src/transport/xqc_packet_in.h +++ b/src/transport/xqc_packet_in.h @@ -14,6 +14,7 @@ typedef enum { XQC_PIF_REINJECTED_REPLICA = 1 << 0, + XQC_PIF_FEC_RECOVERED = 1 << 1, } xqc_packet_in_flag_t; struct xqc_packet_in_s { @@ -31,6 +32,9 @@ struct xqc_packet_in_s { uint64_t pi_path_id; xqc_packet_in_flag_t pi_flag; + + xqc_usec_t pi_fec_process_time; + xqc_stream_id_t stream_id; }; diff --git a/src/transport/xqc_packet_out.c b/src/transport/xqc_packet_out.c index 73f2ac37a..f0fe12bfa 100644 --- a/src/transport/xqc_packet_out.c +++ b/src/transport/xqc_packet_out.c @@ -17,6 +17,7 @@ #include "src/transport/xqc_datagram.h" #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_packet_out.h" +#include "src/transport/xqc_cid.h" xqc_packet_out_t * @@ -74,7 +75,7 @@ xqc_packet_out_create(size_t po_buf_size) || ((*path)->path_state >= XQC_PATH_STATE_CLOSING) || (*path)->app_path_status == XQC_APP_PATH_STATUS_FROZEN) { - po->po_path_flag &= ~(XQC_PATH_SPECIFIED_BY_ACK | XQC_PATH_SPECIFIED_BY_PTO | XQC_PATH_SPECIFIED_BY_REINJ); + po->po_path_flag &= ~(XQC_PATH_SPECIFIED_BY_ACK | XQC_PATH_SPECIFIED_BY_PTO | XQC_PATH_SPECIFIED_BY_REINJ | XQC_PATH_SPECIFIED_BY_FEC); if (po->po_path_flag) { if ((*path == NULL) @@ -104,7 +105,7 @@ xqc_packet_out_can_attach_ack(xqc_packet_out_t *po, return XQC_FALSE; } - if (po->po_frame_types & (XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP)) { + if (po->po_frame_types & (XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP | XQC_FRAME_BIT_REPAIR_SYMBOL)) { return XQC_FALSE; } @@ -112,6 +113,10 @@ xqc_packet_out_can_attach_ack(xqc_packet_out_t *po, return XQC_FALSE; } + if (po->po_flag & XQC_POF_STREAM_NO_LEN) { + return XQC_FALSE; + } + return XQC_TRUE; } @@ -166,9 +171,20 @@ xqc_packet_out_copy(xqc_packet_out_t *dst, xqc_packet_out_t *src) dst->po_user_data = src->po_user_data; dst->po_path_id = src->po_path_id; + dst->po_reserved_size = src->po_reserved_size; dst->po_flag &= ~XQC_POF_IN_UNACK_LIST; dst->po_flag &= ~XQC_POF_IN_PATH_BUF_LIST; + + dst->po_pr = src->po_pr; + + if (dst->po_pr) { + dst->po_pr->ref_cnt++; + } + + dst->po_send_cwnd_blk_ts = 0; + dst->po_sched_cwnd_blk_ts = 0; + dst->po_send_pacing_blk_ts = 0; } @@ -177,12 +193,11 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) { xqc_packet_out_t *packet_out; unsigned int buf_size; - size_t buf_cap; + size_t buf_cap, reserved_size; xqc_list_head_t *pos, *next; xqc_list_for_each_safe(pos, next, &send_queue->sndq_free_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - xqc_send_queue_remove_free(pos, send_queue); unsigned char *tmp = packet_out->po_buf; @@ -192,7 +207,7 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) packet_out->po_buf = tmp; packet_out->po_buf_size = buf_size; packet_out->po_buf_cap = buf_cap; - return packet_out; + goto return_po; } packet_out = xqc_packet_out_create(send_queue->sndq_conn->pkt_out_size); @@ -200,6 +215,12 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) return NULL; } +return_po: + reserved_size = 0; + if (send_queue->sndq_conn->conn_settings.fec_params.fec_encoder_scheme) { + reserved_size += XQC_FEC_SPACE; + } + packet_out->po_reserved_size = reserved_size; return packet_out; } @@ -247,7 +268,7 @@ xqc_write_packet_header(xqc_connection_t *conn, xqc_packet_out_t *packet_out) return XQC_OK; } - int ret = XQC_OK; + ssize_t ret = XQC_OK; xqc_pkt_type_t pkt_type = packet_out->po_pkt.pkt_type; @@ -266,7 +287,7 @@ xqc_write_packet_header(xqc_connection_t *conn, xqc_packet_out_t *packet_out) } if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|gen header error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|gen header error|%z|", ret); return ret; } packet_out->po_used_size += ret; @@ -409,7 +430,10 @@ xqc_write_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out } else { conn->conn_flag &= ~XQC_CONN_FLAG_ACK_HAS_GAP; } - conn->conn_flag &= ~(XQC_CONN_FLAG_SHOULD_ACK_INIT << pns); + path->path_flag &= ~(XQC_PATH_FLAG_SHOULD_ACK_INIT << pns); + conn->ack_flag &= ~(1 << (pns + path->path_id * XQC_PNS_N)); + + path->path_send_ctl->ctl_ack_sent_cnt++; return XQC_OK; @@ -418,20 +442,111 @@ xqc_write_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out return ret; } +#ifdef XQC_ENABLE_FEC xqc_int_t -xqc_write_ack_or_mp_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns, xqc_path_ctx_t *path, xqc_bool_t is_mp_ack) +xqc_write_sid_frame_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + ssize_t ret; + + ret = xqc_gen_sid_frame(conn, packet_out); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return ret; + + } else if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_gen_sid_frame error|"); + return -XQC_EWRITE_PKT; + } + + packet_out->po_used_size += ret; + packet_out->po_reserved_size -= ret; + + return XQC_OK; +} + +xqc_packet_out_t * +xqc_write_one_repair_packet(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_int_t repair_idx, + uint8_t bm_idx) +{ + uint64_t path_id; + xqc_int_t ret; + xqc_packet_out_t *packet_out; + xqc_send_queue_t *send_queue = conn->conn_send_queue; + + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_write_new_packet error|"); + return NULL; + } + + ret = xqc_gen_repair_frame(conn, packet_out, fss_esi, repair_idx, bm_idx); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_gen_repair_frame error|"); + xqc_send_queue_remove_send(&packet_out->po_list); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); + return NULL; + } + + conn->fec_ctl->fec_send_repair_num_total++; + + return packet_out; +} + +xqc_int_t +xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev, xqc_int_t repair_packet_num, + uint8_t bm_idx) +{ + xqc_int_t ret, curr_repair_idx, insert_flag; + xqc_path_ctx_t *path; + xqc_list_head_t *head; + xqc_packet_out_t *packet_out; + + curr_repair_idx = insert_flag = 0; + + if (repair_packet_num <= 0) { + xqc_log(conn->log, XQC_LOG_WARN, "|current code rate is too low to generate repair packets."); + return XQC_OK; + } + + for (xqc_int_t i = 0; i < repair_packet_num; i++) { + packet_out = xqc_write_one_repair_packet(conn, fss_esi, curr_repair_idx, bm_idx); + if (packet_out == NULL) { + continue; + } + curr_repair_idx++; + // move to the next position of current src symbol + xqc_send_queue_move_to_head(&packet_out->po_list, prev); + prev = &packet_out->po_list; + insert_flag = 1; + } + + if (insert_flag) { + return XQC_OK; + } + + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec| no repair packets inserted."); + return -XQC_EFEC_SCHEME_ERROR; +} +#endif +xqc_int_t +xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns, + xqc_path_ctx_t *path, xqc_bool_t is_mp_ack, xqc_bool_t is_ext_ack, xqc_bool_t is_new_pkt) { int ret; if (is_mp_ack) { ret = xqc_write_ack_mp_to_one_packet(conn, path, packet_out, pns); } else { - ret = xqc_write_ack_to_one_packet(conn, packet_out, pns); + if (is_ext_ack) { + ret = xqc_write_ack_ext_to_one_packet(conn, packet_out, pns, is_new_pkt); + } else { + ret = xqc_write_ack_to_one_packet(conn, packet_out, pns); + } } return ret; } xqc_int_t -xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) +xqc_write_ack_or_mp_ack_or_ext_ack_to_packets(xqc_connection_t *conn) { XQC_DEBUG_PRINT xqc_pkt_num_space_t pns; @@ -439,22 +554,24 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) xqc_pkt_type_t pkt_type; xqc_list_head_t *pos, *next; xqc_bool_t is_mp_ack = 0; /* Send ack in default case */ - - int ret; - + xqc_bool_t is_ext_ack = 0; + int ret = XQC_OK; xqc_path_ctx_t *path; xqc_list_head_t *path_pos, *path_next; - for (pns = 0; pns < XQC_PNS_N; ++pns) { - - /* If there's no such pns in the connection, continue the loop */ - if (!(conn->conn_flag & (XQC_CONN_FLAG_SHOULD_ACK_INIT << pns))) { + xqc_list_for_each_safe(path_pos, path_next, &conn->conn_paths_list) { + path = xqc_list_entry(path_pos, xqc_path_ctx_t, path_list); + + if (path->path_state < XQC_PATH_STATE_VALIDATING + || path->path_state >= XQC_PATH_STATE_CLOSED) + { continue; } - xqc_list_for_each_safe(path_pos, path_next, &conn->conn_paths_list) { - path = xqc_list_entry(path_pos, xqc_path_ctx_t, path_list); - if (path->path_state < XQC_PATH_STATE_VALIDATING) { + for (pns = 0; pns < XQC_PNS_N; ++pns) { + + /* If there's no such pns in the connection, continue the loop */ + if (!(path->path_flag & (XQC_PATH_FLAG_SHOULD_ACK_INIT << pns))) { continue; } @@ -466,6 +583,7 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) first_range = xqc_list_entry(tmp_pos, xqc_pktno_range_node_t, list); break; } + if (first_range == NULL) { continue; } @@ -479,19 +597,25 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) } /* Acknowledgements of Initial and Handshake packets MUST be carried using ACK frames */ - if (pkt_type > XQC_PTYPE_HSK && conn->enable_multipath == XQC_CONN_MULTIPATH_MULTIPLE_PNS) { + if (pkt_type > XQC_PTYPE_HSK && conn->enable_multipath == XQC_CONN_MP_ENABLED) { is_mp_ack = 1; + } else if ((conn->conn_settings.extended_ack_features & XQC_ACK_EXT_FEATURE_BIT_RECV_TS) + && pns == XQC_PNS_APP_DATA + && xqc_recv_timestamps_info_length(path->recv_ts_info) > 0) + { + /* ENC count is not supported */ + is_ext_ack = 1; } path_buffer: /* Try to attach ack or mp_ack to packet_out in path_buffer */ xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - + if (xqc_packet_out_can_attach_ack(packet_out, path, pkt_type)) { - ret = xqc_write_ack_or_mp_ack_to_one_packet(conn, packet_out, pns, path, is_mp_ack); + ret = xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet(conn, packet_out, pns, path, is_mp_ack, is_ext_ack, 0); if (ret == -XQC_ENOBUF) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_write_ack_or_mp_ack_to_one_packet try new packet|"); + xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet try new packet|"); goto write_new; } else if (ret == XQC_OK) { goto done; @@ -506,9 +630,13 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) if (!is_mp_ack) { xqc_list_for_each_safe(pos, next, &conn->conn_send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - + if (xqc_packet_out_can_attach_ack(packet_out, path, pkt_type)) { - ret = xqc_write_ack_to_one_packet(conn, packet_out, pns); + if (is_ext_ack) { + ret = xqc_write_ack_ext_to_one_packet(conn, packet_out, pns, 0); + } else { + ret = xqc_write_ack_to_one_packet(conn, packet_out, pns); + } if (ret == -XQC_ENOBUF) { xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_write_ack_to_one_packet try new packet|"); goto write_new; @@ -528,10 +656,10 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); return -XQC_EWRITE_PKT; } - ret = xqc_write_ack_or_mp_ack_to_one_packet(conn, packet_out, pns, path, is_mp_ack); + ret = xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet(conn, packet_out, pns, path, is_mp_ack, is_ext_ack, 1); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_ack_or_mp_ack_to_one_packet write to new packet error|ret:%d|is_mp_ack:%d|", - ret, is_mp_ack); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet write to new packet error|ret:%d|is_mp_ack:%d|is_ext_ack:%d|", + ret, is_mp_ack, is_ext_ack); return ret; } @@ -541,13 +669,9 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) done: xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|pns:%d|", path->path_id, pns); - - /* Ack frame should only be sent on initial path */ - if (!is_mp_ack) { - break; - } } } + return XQC_OK; } @@ -653,10 +777,18 @@ xqc_write_conn_close_to_packet(xqc_connection_t *conn, uint64_t err_code) xqc_packet_out_t *packet_out; xqc_pkt_type_t pkt_type = XQC_PTYPE_INIT; + /* select packet type */ + if (xqc_tls_is_key_ready(conn->tls, XQC_ENC_LEV_HSK, XQC_KEY_TYPE_TX_WRITE)) { + pkt_type = XQC_PTYPE_HSK; + } + /* peer may not have received the handshake packet */ - if (conn->conn_flag & XQC_CONN_FLAG_HANDSHAKE_COMPLETED && conn->conn_flag & XQC_CONN_FLAG_HSK_ACKED) { + if ((conn->conn_flag & XQC_CONN_FLAG_HANDSHAKE_COMPLETED && conn->conn_flag & XQC_CONN_FLAG_HSK_ACKED) + || (conn->conn_flag & XQC_CONN_FLAG_HANDSHAKE_CONFIRMED)) + { pkt_type = XQC_PTYPE_SHORT_HEADER; } + packet_out = xqc_write_new_packet(conn, pkt_type); if (packet_out == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); @@ -686,8 +818,25 @@ xqc_write_reset_stream_to_packet(xqc_connection_t *conn, xqc_stream_t *stream, { ssize_t ret; xqc_packet_out_t *packet_out; + xqc_pkt_type_t pkt_type = XQC_PTYPE_SHORT_HEADER; + int support_0rtt = xqc_conn_is_ready_to_send_early_data(conn); + xqc_bool_t buff_reset = XQC_FALSE; + + if (!(conn->conn_flag & XQC_CONN_FLAG_CAN_SEND_1RTT)) { + if ((conn->conn_type == XQC_CONN_TYPE_CLIENT) + && (conn->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT) + && support_0rtt) + { + pkt_type = XQC_PTYPE_0RTT; + conn->conn_flag |= XQC_CONN_FLAG_HAS_0RTT; + stream->stream_flag |= XQC_STREAM_FLAG_HAS_0RTT; - packet_out = xqc_write_new_packet(conn, XQC_PTYPE_NUM); + } else { + buff_reset = XQC_TRUE; + } + } + + packet_out = xqc_write_new_packet(conn, pkt_type); if (packet_out == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); return -XQC_EWRITE_PKT; @@ -715,6 +864,10 @@ xqc_write_reset_stream_to_packet(xqc_connection_t *conn, xqc_stream_t *stream, stream->stream_stats.app_reset_time = xqc_monotonic_timestamp(); } + if (buff_reset) { + xqc_conn_buff_1rtt_packet(conn, packet_out); + } + xqc_log(conn->log, XQC_LOG_DEBUG, "|stream_id:%ui|stream_state_send:%d|", stream->stream_id, stream->stream_state_send); return XQC_OK; @@ -739,7 +892,25 @@ xqc_write_stop_sending_to_packet(xqc_connection_t *conn, xqc_stream_t *stream, return XQC_OK; } - packet_out = xqc_write_new_packet(conn, XQC_PTYPE_NUM); + xqc_pkt_type_t pkt_type = XQC_PTYPE_SHORT_HEADER; + int support_0rtt = xqc_conn_is_ready_to_send_early_data(conn); + xqc_bool_t buff_pkt = XQC_FALSE; + + if (!(conn->conn_flag & XQC_CONN_FLAG_CAN_SEND_1RTT)) { + if ((conn->conn_type == XQC_CONN_TYPE_CLIENT) + && (conn->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT) + && support_0rtt) + { + pkt_type = XQC_PTYPE_0RTT; + conn->conn_flag |= XQC_CONN_FLAG_HAS_0RTT; + stream->stream_flag |= XQC_STREAM_FLAG_HAS_0RTT; + + } else { + buff_pkt = XQC_TRUE; + } + } + + packet_out = xqc_write_new_packet(conn, pkt_type); if (packet_out == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); return -XQC_EWRITE_PKT; @@ -753,6 +924,10 @@ xqc_write_stop_sending_to_packet(xqc_connection_t *conn, xqc_stream_t *stream, packet_out->po_used_size += ret; + if (buff_pkt) { + xqc_conn_buff_1rtt_packet(conn, packet_out); + } + return XQC_OK; error: @@ -969,6 +1144,7 @@ xqc_write_new_token_to_packet(xqc_connection_t *conn) } packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); return XQC_OK; @@ -977,6 +1153,20 @@ xqc_write_new_token_to_packet(xqc_connection_t *conn) return ret; } + +void +xqc_fec_encode_queue_insert_send(xqc_packet_out_t *po, xqc_stream_t *stream) +{ + // xqc_list_add_tail(&po->po_list, &stream->stream_fec_ctl.stream_fec_send_packets); + if (stream->stream_fec_ctl.stream_fec_head == NULL) { + stream->stream_fec_ctl.stream_fec_head = po->po_list.prev; + } + stream->stream_fec_ctl.stream_fec_tail = &po->po_list; + // count encode list number + stream->stream_fec_ctl.stream_fec_syb_num++; +} + + int xqc_write_stream_frame_to_packet(xqc_connection_t *conn, xqc_stream_t *stream, xqc_pkt_type_t pkt_type, uint8_t fin, @@ -990,6 +1180,7 @@ xqc_write_stream_frame_to_packet(xqc_connection_t *conn, xqc_usec_t max_srtt = 0; uint64_t old_fc_win = 0; uint64_t available_window; + xqc_int_t ret; if (conn->conn_settings.enable_stream_rate_limit && stream->stream_send_offset == 0 @@ -1054,6 +1245,27 @@ xqc_write_stream_frame_to_packet(xqc_connection_t *conn, packet_out->po_stream_id = stream->stream_id; packet_out->po_stream_offset = stream->stream_send_offset; +#ifdef XQC_ENABLE_FEC + // FEC process source packet on stream level + if (conn->conn_settings.fec_level == XQC_FEC_STREAM_LEVEL) { + // if current stream requires fec encode, save it to encode_list + if (stream->stream_fec_ctl.enable_fec + && conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE + && !(packet_out->po_frame_types & XQC_FRAME_BIT_SID + || packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL)) + { + xqc_fec_encode_queue_insert_send(packet_out, stream); + } + + } else if (stream->stream_fec_blk_mode != XQC_SLIM_SIZE_REQ && conn->conn_settings.fec_params.fec_encoder_scheme) { + // FEC tag source packet to be processed on connection level + packet_out->po_flag |= XQC_POF_USE_FEC; + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE) { + packet_out->po_stream_fec_blk_mode = stream->stream_fec_blk_mode; + } + } +#endif + if (fin && *send_data_written == payload_size) { stream->stream_flag |= XQC_STREAM_FLAG_FIN_WRITE; stream->stream_stats.local_fin_write_time = xqc_monotonic_timestamp(); @@ -1106,6 +1318,7 @@ xqc_write_datagram_frame_to_packet(xqc_connection_t *conn, xqc_pkt_type_t pkt_ty packet_out->po_flag |= XQC_POF_QOS_PROBING; } else { + packet_out->po_flag |= XQC_POF_USE_FEC; packet_out->po_flag |= XQC_POF_NOT_REINJECT; } @@ -1134,6 +1347,7 @@ xqc_write_handshake_done_frame_to_packet(xqc_connection_t *conn) } packet_out->po_used_size += n_written; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); return XQC_OK; } @@ -1146,11 +1360,18 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr xqc_packet_out_t *packet_out = NULL; xqc_cid_t new_conn_cid; uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + xqc_cid_set_inner_t *inner_set; + + inner_set = xqc_get_path_cid_set(&conn->scid_set, XQC_INITIAL_PATH_ID); + + if (!inner_set) { + return -XQC_EGENERATE_CID; + } /* only reserve bits for server side */ - ++conn->scid_set.largest_scid_seq_num; + inner_set->largest_scid_seq_num++; if (XQC_OK != xqc_generate_cid(conn->engine, &conn->scid_set.user_scid, &new_conn_cid, - conn->scid_set.largest_scid_seq_num)) + inner_set->largest_scid_seq_num)) { xqc_log(conn->log, XQC_LOG_WARN, "|generate cid error|"); return -XQC_EGENERATE_CID; @@ -1162,13 +1383,15 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr conn->engine->config->reset_token_keylen); /* insert to scid_set & add scid_unused_cnt */ - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &new_conn_cid, XQC_CID_UNUSED, - conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &new_conn_cid, XQC_CID_UNUSED, + conn->remote_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, - "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|", + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", conn->remote_settings.active_connection_id_limit, - conn->scid_set.cid_set.unused_cnt, conn->scid_set.cid_set.used_cnt); + xqc_cid_set_get_unused_cnt(&conn->scid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&conn->scid_set, XQC_INITIAL_PATH_ID)); return ret; } @@ -1192,9 +1415,11 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr goto error; } packet_out->po_used_size += ret; + packet_out->po_new_cid_seq = new_conn_cid.cid_seq_num; + packet_out->po_new_cid_path = XQC_INITIAL_PATH_ID; xqc_log(conn->log, XQC_LOG_DEBUG, "|gen_new_scid|cid:%s|sr_token:%s|seq_num:%ui", - xqc_scid_str(&new_conn_cid), xqc_sr_token_str(new_conn_cid.sr_token), + xqc_scid_str(conn->engine, &new_conn_cid), xqc_sr_token_str(conn->engine, new_conn_cid.sr_token), new_conn_cid.cid_seq_num); xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); @@ -1210,19 +1435,28 @@ xqc_int_t xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num) { xqc_int_t ret = XQC_ERROR; + xqc_path_ctx_t *path = conn->conn_initial_path; - /* select new current_dcid to replace the cid to be retired */ - if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) { - // TODO: DCID changes - ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid); + /* change path_dcid */ + if (path->path_dcid.cid_seq_num == seq_num) { + ret = xqc_get_unused_cid(&conn->dcid_set, &path->path_dcid, XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|conn have no available dcid|"); return ret; } - xqc_datagram_record_mss(conn); - } + xqc_datagram_record_mss(conn); + } + + /* replace conn current_dcid */ + if (seq_num == conn->dcid_set.current_dcid.cid_seq_num + && conn->dcid_set.current_dcid.path_id == XQC_INITIAL_PATH_ID) + { + xqc_cid_copy(&conn->dcid_set.current_dcid, &path->path_dcid); + } + xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|", - xqc_dcid_str(&conn->dcid_set.current_dcid), conn->dcid_set.current_dcid.cid_seq_num); + xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid), + conn->dcid_set.current_dcid.cid_seq_num); xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); if (packet_out == NULL) { @@ -1238,6 +1472,7 @@ xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_nu } packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); return XQC_OK; } @@ -1268,34 +1503,18 @@ xqc_write_path_challenge_frame_to_packet(xqc_connection_t *conn, if (attach_path_status) { path->app_path_status_send_seq_num++; - //TODO: MPQUIC fix migration - - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { - ret = xqc_gen_path_standby_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - ret = xqc_gen_path_available_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else { - ret = -XQC_EMP_PATH_STATE_ERROR; - xqc_log(conn->log, XQC_LOG_DEBUG, - "|xqc_write_path_challenge_frame_to_packet path_status didn't set|%d|", path->app_path_status); - } - } else { - ret = xqc_gen_path_status_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num, (uint64_t)path->app_path_status); - } - + ret = xqc_gen_path_status_frame(conn, packet_out, path->path_id, + path->app_path_status_send_seq_num, + path->app_path_status); if (ret < 0) { /* ignore */ - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_status_frame error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|attach status error|%d|", ret); } else { xqc_log(conn->log, XQC_LOG_DEBUG, "|initial_path_status|status:%d|frames:%s|", path->app_path_status, - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); packet_out->po_used_size += ret; } } @@ -1356,8 +1575,7 @@ xqc_write_ack_mp_to_one_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); - //TODO: MPQUIC fix migration - ret = xqc_gen_ack_mp_frame(conn, path->path_scid.cid_seq_num, packet_out, now, + ret = xqc_gen_ack_mp_frame(conn, path->path_id, packet_out, now, conn->local_settings.ack_delay_exponent, &pn_ctl->ctl_recv_record[packet_out->po_pkt.pkt_pns], path->path_send_ctl->ctl_largest_recv_time[pns], @@ -1381,7 +1599,10 @@ xqc_write_ack_mp_to_one_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, } else { conn->conn_flag &= ~XQC_CONN_FLAG_ACK_HAS_GAP; } - conn->conn_flag &= ~(XQC_CONN_FLAG_SHOULD_ACK_INIT << pns); + path->path_flag &= ~(XQC_PATH_FLAG_SHOULD_ACK_INIT << pns); + conn->ack_flag &= ~(1 << (pns + path->path_id * XQC_PNS_N)); + + path->path_send_ctl->ctl_ack_sent_cnt++; return XQC_OK; @@ -1402,11 +1623,9 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p return -XQC_EWRITE_PKT; } - /* dcid_seq_num = path->scid.cid_seq_num */ - //TODO: MPQUIC fix migration - uint64_t dcid_seq_num = path->path_scid.cid_seq_num; + uint64_t path_id = path->path_id; - ret = xqc_gen_path_abandon_frame(conn, packet_out, dcid_seq_num, 0); + ret = xqc_gen_path_abandon_frame(conn, packet_out, path_id, 0); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_abandon_frame error|%d|", ret); goto error; @@ -1416,8 +1635,8 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); - xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|dcid_seq_num:%ui|", - path->path_id, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|path_id:%ui|", + path->path_id, path_id); return XQC_OK; @@ -1426,6 +1645,7 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p return ret; } + xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path) { @@ -1438,17 +1658,119 @@ xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *pa } path->app_path_status_send_seq_num++; - //TODO: MPQUIC fix migration - ret = xqc_gen_path_status_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num, (uint64_t)path->app_path_status); + + ret = xqc_gen_path_status_frame(conn, packet_out, path->path_id, + path->app_path_status_send_seq_num, + path->app_path_status); if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_status_frame error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|%d|", ret); goto error; } packet_out->po_used_size += ret; xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + xqc_log(conn->log, XQC_LOG_DEBUG, "|status=%d|", path->app_path_status); + + return XQC_OK; + + error: + xqc_maybe_recycle_packet_out(packet_out, conn); + return ret; +} + +size_t +xqc_get_po_remained_size(xqc_packet_out_t *po) +{ + size_t res; + + res = po->po_buf_size - po->po_used_size - po->po_reserved_size; + + return xqc_max(res, 0); +} + +size_t +xqc_get_po_remained_size_with_ack_spc(xqc_packet_out_t *po) +{ + return xqc_get_po_remained_size(po) + XQC_ACK_SPACE; +} + +xqc_int_t +xqc_write_mp_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_prior_to, uint64_t path_id) +{ + xqc_int_t ret = XQC_ERROR; + xqc_packet_out_t *packet_out = NULL; + xqc_cid_t new_conn_cid; + uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + xqc_cid_set_inner_t *inner_set; + + inner_set = xqc_get_path_cid_set(&conn->scid_set, path_id); + + if (!inner_set) { + return -XQC_EGENERATE_CID; + } + + if (path_id == XQC_INITIAL_PATH_ID + || ((inner_set->unused_cnt + inner_set->used_cnt + inner_set->retired_cnt) > 0)) + { + inner_set->largest_scid_seq_num++; + } + + if (XQC_OK != xqc_generate_cid(conn->engine, &conn->scid_set.user_scid, &new_conn_cid, + inner_set->largest_scid_seq_num)) + { + xqc_log(conn->log, XQC_LOG_WARN, "|generate cid error|"); + return -XQC_EGENERATE_CID; + } + + /* generate stateless reset token */ + xqc_gen_reset_token(&new_conn_cid, sr_token, XQC_STATELESS_RESET_TOKENLEN, + conn->engine->config->reset_token_key, + conn->engine->config->reset_token_keylen); + + /* insert to scid_set & add scid_unused_cnt */ + ret = xqc_cid_set_insert_cid(&conn->scid_set, &new_conn_cid, XQC_CID_UNUSED, + conn->remote_settings.active_connection_id_limit, + path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", + conn->remote_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->scid_set, path_id), + xqc_cid_set_get_used_cnt(&conn->scid_set, path_id)); + return ret; + } + + ret = xqc_insert_conns_hash(conn->engine->conns_hash, conn, + new_conn_cid.cid_buf, new_conn_cid.cid_len); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|insert new_cid into conns_hash failed|"); + return ret; + } + + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return -XQC_EWRITE_PKT; + } + + ret = xqc_gen_mp_new_conn_id_frame(packet_out, &new_conn_cid, retire_prior_to, + sr_token, path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_new_conn_id_frame error|"); + goto error; + } + packet_out->po_used_size += ret; + packet_out->po_new_cid_seq = new_conn_cid.cid_seq_num; + packet_out->po_new_cid_path = path_id; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|path_id:%ui|cid:%s|sr_token:%s|seq_num:%ui", + path_id, + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token), + new_conn_cid.cid_seq_num); + + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); return XQC_OK; error: @@ -1458,9 +1780,48 @@ xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *pa xqc_int_t -xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path) +xqc_write_mp_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num, uint64_t path_id) { xqc_int_t ret = XQC_ERROR; + xqc_path_ctx_t *path; + + path = xqc_conn_find_path_by_path_id(conn, path_id); + + /* replace path's dcid */ + if (path && path->path_dcid.cid_seq_num == seq_num) { + ret = xqc_get_unused_cid(&conn->dcid_set, &path->path_dcid, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|don't have available dcid|", + path_id); + return ret; + } + xqc_datagram_record_mss(conn); + } + + /* select new current_dcid to replace the cid to be retired */ + if (seq_num == conn->dcid_set.current_dcid.cid_seq_num + && path_id == conn->dcid_set.current_dcid.path_id) + { + if (!path) { + ret = xqc_get_unused_cid(&conn->dcid_set, &conn->dcid_set.current_dcid, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|don't have available dcid|", + path_id); + return ret; + } + xqc_datagram_record_mss(conn); + + } else { + xqc_cid_copy(&conn->dcid_set.current_dcid, &path->path_dcid); + } + + } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|path_id:%ui|", + xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid), + conn->dcid_set.current_dcid.cid_seq_num, path_id); xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); if (packet_out == NULL) { @@ -1468,33 +1829,95 @@ xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_ return -XQC_EWRITE_PKT; } - path->app_path_status_send_seq_num++; + ret = xqc_gen_mp_retire_conn_id_frame(packet_out, seq_num, path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_retire_conn_id_frame error|"); + xqc_maybe_recycle_packet_out(packet_out, conn); + return ret; + } - if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { - ret = xqc_gen_path_standby_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - ret = xqc_gen_path_available_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else { - xqc_log(conn->log, XQC_LOG_WARN, "|xqc_write_path_standby_or_available_frame_to_packet status error|%d|", path->app_path_status); - ret = -XQC_EMP_PATH_STATE_ERROR; + packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + + return XQC_OK; +} + +int +xqc_write_max_path_id_to_packet(xqc_connection_t *conn, uint64_t max_path_id) +{ + ssize_t ret = XQC_ERROR; + xqc_packet_out_t *packet_out; + xqc_log(conn->log, XQC_LOG_DEBUG, "|set max_path_id:%ui|", max_path_id); + + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return -XQC_EWRITE_PKT; + } + + ret = xqc_gen_max_path_id_frame(packet_out, max_path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_max_streams_frame error|"); goto error; } + packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + xqc_log(conn->log, XQC_LOG_DEBUG, "|max_path_id:%ui|", max_path_id); + return XQC_OK; + +error: + xqc_maybe_recycle_packet_out(packet_out, conn); + return -XQC_EWRITE_PKT; +} + +int +xqc_write_ack_ext_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + xqc_pkt_num_space_t pns, xqc_bool_t is_new_pkt) +{ + ssize_t ret; + int has_gap; + xqc_packet_number_t largest_ack; + xqc_usec_t now = xqc_monotonic_timestamp(); + + xqc_path_ctx_t *path = conn->conn_initial_path; + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); + + if (path->recv_ts_info->nobuf_for_ts_in_last_ext_ack && !is_new_pkt) { + return -XQC_ENOBUF; + } + ret = xqc_gen_ack_ext_frame(conn, packet_out, now, conn->local_settings.ack_delay_exponent, + &pn_ctl->ctl_recv_record[pns], path->path_send_ctl->ctl_largest_recv_time[pns], + &has_gap, &largest_ack, path->recv_ts_info); if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_standby_or_available_frame_to_packet error|%d|", ret); goto error; } + xqc_log(conn->log, XQC_LOG_DEBUG, "|ack_size:%ui|path:%ui|path_largest_recv:%ui|frame_largest_recv:%ui|", + ret, path->path_id, path->path_send_ctl->ctl_largest_received[pns], xqc_recv_record_largest(&pn_ctl->ctl_recv_record[pns])); + + packet_out->po_ack_offset = packet_out->po_used_size; packet_out->po_used_size += ret; - xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + packet_out->po_largest_ack = largest_ack; - xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_write_path_standby_or_available_frame_to_packet|status=%d|", path->app_path_status); + packet_out->po_path_flag |= XQC_PATH_SPECIFIED_BY_ACK; + packet_out->po_path_id = path->path_id; + + path->path_send_ctl->ctl_ack_eliciting_pkt[pns] = 0; + if (has_gap) { + conn->conn_flag |= XQC_CONN_FLAG_ACK_HAS_GAP; + + } else { + conn->conn_flag &= ~XQC_CONN_FLAG_ACK_HAS_GAP; + } + path->path_flag &= ~(XQC_PATH_FLAG_SHOULD_ACK_INIT << pns); + conn->ack_flag &= ~(1 << (pns + path->path_id * XQC_PNS_N)); + + path->path_send_ctl->ctl_ack_sent_cnt++; return XQC_OK; - error: +error: xqc_maybe_recycle_packet_out(packet_out, conn); return ret; -} \ No newline at end of file +} diff --git a/src/transport/xqc_packet_out.h b/src/transport/xqc_packet_out.h index aff345178..160a484fa 100644 --- a/src/transport/xqc_packet_out.h +++ b/src/transport/xqc_packet_out.h @@ -17,7 +17,7 @@ */ /* without XQC_EXTRA_SPACE & XQC_ACK_SPACE */ #define XQC_MAX_PACKET_OUT_SIZE XQC_QUIC_MAX_MSS -#define XQC_PACKET_OUT_SIZE XQC_QUIC_MIN_MSS +#define XQC_PACKET_OUT_SIZE XQC_QUIC_MIN_MSS #define XQC_PACKET_OUT_EXT_SPACE (XQC_TLS_AEAD_OVERHEAD_MAX_LEN + XQC_ACK_SPACE) #define XQC_PACKET_OUT_BUF_CAP (XQC_MAX_PACKET_OUT_SIZE + XQC_PACKET_OUT_EXT_SPACE) @@ -44,6 +44,9 @@ typedef enum { XQC_POF_PMTUD_PROBING = 1 << 17, XQC_POF_QOS_HIGH = 1 << 18, XQC_POF_QOS_PROBING = 1 << 19, + XQC_POF_SPURIOUS_LOSS = 1 << 20, + XQC_POF_USE_FEC = 1 << 21, + XQC_POF_STREAM_NO_LEN = 1 << 22, /* for stream without LEN bit, shouldn't attach different frame to it */ } xqc_packet_out_flag_t; typedef struct xqc_po_stream_frame_s { @@ -72,6 +75,7 @@ typedef struct xqc_packet_out_s { size_t po_buf_cap; /* capcacity of po_buf */ unsigned int po_buf_size; /* size of po_buf can be used */ unsigned int po_used_size; + unsigned int po_enc_size; /* size of po after being encrypted */ unsigned int po_ack_offset; xqc_packet_out_flag_t po_flag; /* Largest Acknowledged in ACK frame, initiated to be 0 */ @@ -82,6 +86,7 @@ typedef struct xqc_packet_out_s { /* the stream related to stream frame */ xqc_po_stream_frame_t po_stream_frames[XQC_MAX_STREAM_FRAME_IN_PO]; unsigned int po_stream_frames_idx; + uint8_t po_stream_fec_blk_mode; uint32_t po_origin_ref_cnt; /* reference count of original packet */ uint32_t po_acked; @@ -111,8 +116,17 @@ typedef struct xqc_packet_out_s { /* PMTUD Probing */ size_t po_max_pkt_out_size; + size_t po_reserved_size; + /* ping notification */ xqc_ping_record_t *po_pr; + + xqc_usec_t po_sched_cwnd_blk_ts; + xqc_usec_t po_send_cwnd_blk_ts; + xqc_usec_t po_send_pacing_blk_ts; + + uint64_t po_new_cid_seq; + uint32_t po_new_cid_path; } xqc_packet_out_t; xqc_bool_t xqc_packet_out_on_specific_path(xqc_connection_t *conn, @@ -146,10 +160,10 @@ xqc_packet_out_t *xqc_write_packet_for_stream(xqc_connection_t *conn, xqc_pkt_ty int xqc_write_packet_header(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -xqc_int_t xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn); +xqc_int_t xqc_write_ack_or_mp_ack_or_ext_ack_to_packets(xqc_connection_t *conn); -xqc_int_t xqc_write_ack_or_mp_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - xqc_pkt_num_space_t pns, xqc_path_ctx_t *path, xqc_bool_t is_mp_ack); +xqc_int_t xqc_write_ack_or_mp_ack_or_ext_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + xqc_pkt_num_space_t pns, xqc_path_ctx_t *path, xqc_bool_t is_mp_ack, xqc_bool_t is_ext_ack, xqc_bool_t is_new_pkt); int xqc_write_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns); @@ -203,9 +217,32 @@ xqc_int_t xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_pat xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); -xqc_int_t xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); +xqc_int_t xqc_write_sid_frame_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out); + +xqc_int_t xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev, xqc_int_t repair_packet_num, + uint8_t bm_idx); + +xqc_packet_out_t *xqc_write_one_repair_packet(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_int_t repair_idx, + uint8_t bm_idx); int xqc_write_pmtud_ping_to_packet(xqc_path_ctx_t *path, size_t probing_size, xqc_pkt_type_t pkt_type); +xqc_int_t xqc_write_mp_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_prior_to, uint64_t path_id); + +xqc_int_t xqc_write_mp_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num, uint64_t path_id); + +int xqc_write_max_path_id_to_packet(xqc_connection_t *conn, uint64_t max_path_id); + +/** + * @brief Get remained space size in packet out buff. + * + * @param conn + * @param po + * @return size_t + */ +size_t xqc_get_po_remained_size(xqc_packet_out_t *po); +size_t xqc_get_po_remained_size_with_ack_spc(xqc_packet_out_t *po); + +int xqc_write_ack_ext_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns, xqc_bool_t is_new_pkt); #endif /* _XQC_PACKET_OUT_H_INCLUDED_ */ diff --git a/src/transport/xqc_packet_parser.c b/src/transport/xqc_packet_parser.c index a55ed8e28..cce022959 100644 --- a/src/transport/xqc_packet_parser.c +++ b/src/transport/xqc_packet_parser.c @@ -3,6 +3,9 @@ */ #include +#ifdef XQC_SYS_WINDOWS +#include +#endif #include #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_cid.h" @@ -195,7 +198,7 @@ xqc_gen_short_packet_header(xqc_packet_out_t *packet_out, unsigned char *dcid, u unsigned int need = 1 + dcid_len + packet_number_len; unsigned char *dst_buf = packet_out->po_buf; - size_t dst_buf_size = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_size = xqc_get_po_remained_size(packet_out); packet_out->po_pkt.pkt_type = XQC_PTYPE_SHORT_HEADER; @@ -268,49 +271,14 @@ xqc_packet_parse_short_header(xqc_connection_t *c, xqc_packet_in_t *packet_in) if (xqc_conn_check_dcid(c, &(packet->pkt_dcid)) != XQC_OK) { /* log & ignore, the pkt might be corrupted or stateless reset */ xqc_log(c->log, XQC_LOG_WARN, "|parse short header|invalid destination cid, pkt dcid: %s, conn scid: %s|", - xqc_dcid_str(&packet->pkt_dcid), xqc_scid_str(&c->scid_set.user_scid)); + xqc_dcid_str(c->engine, &packet->pkt_dcid), xqc_scid_str(c->engine, &c->scid_set.user_scid)); return -XQC_EILLPKT; } - //TODO: MPQUIC fix migration - if (c->enable_multipath) { - /* try to find the path */ - path = xqc_conn_find_path_by_scid(c, &packet_in->pi_pkt.pkt_dcid); -#ifndef XQC_NO_PID_PACKET_PROCESS - /* Note: to handle the case in which the server changes CID upon NAT rebinding */ - if (path == NULL && packet_in->pi_path_id != XQC_UNKNOWN_PATH_ID) { - path = xqc_conn_find_path_by_path_id(c, packet_in->pi_path_id); - - if (path == NULL) { - xqc_log(c->log, XQC_LOG_ERROR, "|can not find path|dcid:%s|path_id:%ui|", - xqc_dcid_str(&packet_in->pi_pkt.pkt_dcid), packet_in->pi_path_id); - return -XQC_EILLPKT; - } - - /* update the cid to a newer one */ - if (xqc_cid_is_equal(&path->path_last_scid, &packet_in->pi_pkt.pkt_dcid) != XQC_OK) { - xqc_cid_copy(&path->path_last_scid, &path->path_scid); - xqc_cid_copy(&path->path_scid, &packet_in->pi_pkt.pkt_dcid); - xqc_log(c->log, XQC_LOG_DEBUG, "|update_path_scid|%s->%s|", - xqc_scid_str(&path->path_last_scid), - xqc_dcid_str(&path->path_scid)); - } - } -#endif - - } else { - path = c->conn_initial_path; - } - - if (path != NULL) { - packet_in->pi_path_id = path->path_id; - - } else { - packet_in->pi_path_id = XQC_UNKNOWN_PATH_ID; - } + packet_in->pi_path_id = packet_in->pi_pkt.pkt_dcid.path_id; xqc_log(c->log, XQC_LOG_DEBUG, "|parse short header|path:%ui|pkt_dcid:%s|spin_bit:%ud|", - packet_in->pi_path_id, xqc_scid_str(&(packet->pkt_dcid)), spin_bit); + packet_in->pi_path_id, xqc_scid_str(c->engine, &(packet->pkt_dcid)), spin_bit); /* packet number */ packet_in->pi_pkt.length = packet_in->last - pos; @@ -382,7 +350,7 @@ void xqc_packet_update_reserved_bits(xqc_packet_out_t *packet_out) } } -int +ssize_t xqc_gen_long_packet_header (xqc_packet_out_t *packet_out, const unsigned char *dcid, unsigned char dcid_len, const unsigned char *scid, unsigned char scid_len, @@ -391,7 +359,7 @@ xqc_gen_long_packet_header (xqc_packet_out_t *packet_out, unsigned char pktno_bits) { unsigned char *dst_buf = packet_out->po_buf; - size_t dst_buf_size = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_size = xqc_get_po_remained_size(packet_out); xqc_pkt_type_t type = packet_out->po_pkt.pkt_type; xqc_packet_number_t packet_number = packet_out->po_pkt.pkt_num; @@ -493,21 +461,14 @@ xqc_packet_parse_initial(xqc_connection_t *c, xqc_packet_in_t *packet_in) packet_in->pi_pkt.pkt_type = XQC_PTYPE_INIT; packet_in->pi_pkt.pkt_pns = XQC_PNS_INIT; - if (c->conn_state == XQC_CONN_STATE_SERVER_INIT - && !(c->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) - { + /* The smallest length of udp datagrams carrying initial packet frome client is 1200 */ + if (c->conn_type == XQC_CONN_TYPE_SERVER) { if (XQC_BUFF_LEFT_SIZE(packet_in->buf, end) < XQC_PACKET_INITIAL_MIN_LENGTH) { xqc_log(c->log, XQC_LOG_ERROR, "|initial size too small|%z|", (size_t)XQC_BUFF_LEFT_SIZE(packet_in->buf, end)); XQC_CONN_ERR(c, TRA_PROTOCOL_VIOLATION); return -XQC_EILLPKT; } - c->conn_flag |= XQC_CONN_FLAG_INIT_RECVD; - - } else if (c->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT - && !(c->conn_flag & XQC_CONN_FLAG_INIT_RECVD)) - { - c->conn_flag |= XQC_CONN_FLAG_INIT_RECVD; } /* Token Length(i) & Token */ @@ -658,9 +619,10 @@ xqc_packet_encrypt_buf(xqc_connection_t *conn, xqc_packet_out_t *packet_out, } /* do packet protection */ - //TODO: MPQUIC fix migration uint32_t nonce_path_id = (conn->enable_multipath) ? - (uint32_t)path->path_dcid.cid_seq_num : 0; + (uint32_t)path->path_id : 0; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|encryption nonce|path_id:%ui|pn:%ui|", nonce_path_id, packet_out->po_pkt.pkt_num); ret = xqc_tls_encrypt_payload(conn->tls, level, packet_out->po_pkt.pkt_num, nonce_path_id, dst_header, header_len, payload, payload_len, @@ -714,6 +676,7 @@ xqc_packet_encrypt_buf(xqc_connection_t *conn, xqc_packet_out_t *packet_out, } } + packet_out->po_enc_size = *enc_pkt_len; return XQC_OK; } @@ -779,16 +742,9 @@ xqc_packet_decrypt(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_packet_parse_packet_number(pktno, pktno_len, &truncated_pn); /* decode packet number */ - // TODO: MPQUIC fix migration xqc_packet_number_t largest_pn = 0; - if (packet_in->pi_path_id != XQC_UNKNOWN_PATH_ID) { - xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|canno find the path|path_id:%ui|", - packet_in->pi_path_id); - return -XQC_EMP_PATH_NOT_FOUND; - } + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); + if (path) { xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); xqc_pkt_num_space_t pns = packet_in->pi_pkt.pkt_pns; largest_pn = xqc_recv_record_largest(&pn_ctl->ctl_recv_record[pns]); @@ -814,9 +770,10 @@ xqc_packet_decrypt(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } /* decrypt packet payload */ - // TODO: MPQUIC fix migration uint32_t nonce_path_id = (conn->enable_multipath) ? - (uint32_t)packet_in->pi_pkt.pkt_dcid.cid_seq_num : 0; + (uint32_t)packet_in->pi_path_id : 0; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|decryption nonce|path_id:%ui|pn:%ui|", nonce_path_id, packet_in->pi_pkt.pkt_num); ret = xqc_tls_decrypt_payload(conn->tls, level, packet_in->pi_pkt.pkt_num, nonce_path_id, header, header_len, payload, payload_len, @@ -1064,8 +1021,8 @@ xqc_packet_parse_retry(xqc_connection_t *c, xqc_packet_in_t *packet_in) */ if (xqc_cid_is_equal(&c->original_dcid, &packet_in->pi_pkt.pkt_scid) == XQC_OK) { xqc_log(c->log, XQC_LOG_DEBUG, "|discard|packet SCID error|odcid:%s|scid:%s|", - xqc_dcid_str(&c->original_dcid), - xqc_scid_str(&packet_in->pi_pkt.pkt_scid)); + xqc_dcid_str(c->engine, &c->original_dcid), + xqc_scid_str(c->engine, &packet_in->pi_pkt.pkt_scid)); return -XQC_EILLPKT; } @@ -1159,7 +1116,7 @@ xqc_packet_parse_version_negotiation(xqc_connection_t *c, xqc_packet_in_t *packe /* check original DCID */ if (xqc_cid_is_equal(&c->original_dcid, &packet_in->pi_pkt.pkt_scid) != XQC_OK) { xqc_log(c->log, XQC_LOG_ERROR, "|version negotiation pkt SCID error|original_dcid:%s|scid:%s|", - xqc_dcid_str(&c->original_dcid), xqc_scid_str(&packet_in->pi_pkt.pkt_scid)); + xqc_dcid_str(c->engine, &c->original_dcid), xqc_scid_str(c->engine, &packet_in->pi_pkt.pkt_scid)); return -XQC_EILLPKT; } @@ -1300,6 +1257,10 @@ xqc_packet_parse_long_header(xqc_connection_t *c, uint32_t version = xqc_parse_uint32(pos); if (version == 0) { /* version negotiation */ + if (c->conn_type == XQC_CONN_TYPE_SERVER) { + xqc_log(c->log, XQC_LOG_DEBUG, "|server receive version negotiation packet|"); + return -XQC_EILLPKT; + } type = XQC_PTYPE_VERSION_NEGOTIATION; } pos += XQC_PACKET_VERSION_LENGTH; @@ -1321,6 +1282,7 @@ xqc_packet_parse_long_header(xqc_connection_t *c, XQC_BUFF_LEFT_SIZE(pos, end), dcid->cid_len + 1); return -XQC_EILLPKT; } + dcid->path_id = XQC_INITIAL_PATH_ID; xqc_memcpy(dcid->cid_buf, pos, dcid->cid_len); pos += dcid->cid_len; @@ -1335,6 +1297,7 @@ xqc_packet_parse_long_header(xqc_connection_t *c, XQC_BUFF_LEFT_SIZE(pos, end), scid->cid_len); return -XQC_EILLPKT; } + scid->path_id = XQC_INITIAL_PATH_ID; xqc_memcpy(scid->cid_buf, pos, scid->cid_len); pos += scid->cid_len; @@ -1345,8 +1308,8 @@ xqc_packet_parse_long_header(xqc_connection_t *c, && XQC_CONN_FLAG_DCID_OK & c->conn_flag) { /* check cid */ - if (xqc_cid_in_cid_set(&c->scid_set.cid_set, &(packet->pkt_dcid)) == NULL - || xqc_cid_in_cid_set(&c->dcid_set.cid_set, &(packet->pkt_scid)) == NULL) + if (xqc_cid_set_search_cid(&c->scid_set, &(packet->pkt_dcid)) == NULL + || xqc_cid_set_search_cid(&c->dcid_set, &(packet->pkt_scid)) == NULL) { /* log & ignore packet */ xqc_log(c->log, XQC_LOG_ERROR, "|invalid dcid or scid|"); @@ -1357,7 +1320,9 @@ xqc_packet_parse_long_header(xqc_connection_t *c, /* check protocol version */ if (xqc_conn_version_check(c, version) != XQC_OK) { xqc_log(c->log, XQC_LOG_INFO, "|version not supported|v:%ui|", version); - c->conn_flag |= XQC_CONN_FLAG_VERSION_NEGOTIATION; + if (c->conn_type == XQC_CONN_TYPE_SERVER) { /* version negotiation only send by server */ + c->conn_flag |= XQC_CONN_FLAG_VERSION_NEGOTIATION; + } return -XQC_EVERSION; } @@ -1516,4 +1481,4 @@ xqc_is_deprecated_reset_packet(xqc_cid_t *cid, const unsigned char *buf, } return 0; } -#endif \ No newline at end of file +#endif diff --git a/src/transport/xqc_packet_parser.h b/src/transport/xqc_packet_parser.h index a90b4db60..056865054 100644 --- a/src/transport/xqc_packet_parser.h +++ b/src/transport/xqc_packet_parser.h @@ -33,7 +33,7 @@ void xqc_short_packet_update_dcid(xqc_packet_out_t *packet_out, xqc_cid_t dcid); void xqc_packet_update_reserved_bits(xqc_packet_out_t *packet_out); -int xqc_gen_long_packet_header(xqc_packet_out_t *packet_out, +ssize_t xqc_gen_long_packet_header(xqc_packet_out_t *packet_out, const unsigned char *dcid, unsigned char dcid_len, const unsigned char *scid, unsigned char scid_len, const unsigned char *token, uint32_t token_len, diff --git a/src/transport/xqc_recv_record.c b/src/transport/xqc_recv_record.c index 630d98267..525fde8b3 100644 --- a/src/transport/xqc_recv_record.c +++ b/src/transport/xqc_recv_record.c @@ -197,6 +197,7 @@ xqc_recv_record_destroy(xqc_recv_record_t *recv_record) xqc_free(pnode); } recv_record->node_count = 0; + recv_record->rr_del_from = 0; } /* 把src的链表逐个节点移动到dst */ @@ -240,6 +241,20 @@ xqc_recv_record_largest(xqc_recv_record_t *recv_record) } } +uint32_t +xqc_get_ack_frequency(xqc_connection_t *conn, xqc_path_ctx_t *path) +{ + if(xqc_conn_is_handshake_confirmed(conn) + && conn->conn_settings.adaptive_ack_frequency + && path->path_send_ctl->ctl_ack_sent_cnt >= 100) + { + // slow down ack rate if we have sent more than 100 ACKs + return xqc_max(conn->conn_settings.ack_frequency, 10); + } + + return conn->conn_settings.ack_frequency; +} + void xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t *pn_ctl, xqc_pkt_num_space_t pns, int out_of_order, xqc_usec_t now) { @@ -247,7 +262,7 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t * Generating Acknowledgements */ - if (conn->conn_flag & (XQC_CONN_FLAG_SHOULD_ACK_INIT << pns)) { + if (path->path_flag & (XQC_PATH_FLAG_SHOULD_ACK_INIT << pns)) { xqc_log(conn->log, XQC_LOG_DEBUG, "|already yes|"); return; } @@ -264,12 +279,14 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t } xqc_send_ctl_t *send_ctl = path->path_send_ctl; + uint32_t ack_frequency = xqc_get_ack_frequency(conn, path); - if (send_ctl->ctl_ack_eliciting_pkt[pns] >= conn->conn_settings.ack_frequency + if (send_ctl->ctl_ack_eliciting_pkt[pns] >= ack_frequency || (pns <= XQC_PNS_HSK && send_ctl->ctl_ack_eliciting_pkt[pns] >= 1) || (out_of_order && send_ctl->ctl_ack_eliciting_pkt[pns] >= 1)) { - conn->conn_flag |= XQC_CONN_FLAG_SHOULD_ACK_INIT << pns; + path->path_flag |= XQC_PATH_FLAG_SHOULD_ACK_INIT << pns; + conn->ack_flag |= (1 << (pns + path->path_id * XQC_PNS_N)); xqc_timer_unset(&send_ctl->path_timer_manager, XQC_TIMER_ACK_INIT + pns); @@ -277,8 +294,8 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t "pns:%d|flag:%s|ack_freq:%ud|", path->path_id, out_of_order, send_ctl->ctl_ack_eliciting_pkt[pns], - pns, xqc_conn_flag_2_str(conn->conn_flag), - conn->conn_settings.ack_frequency); + pns, xqc_conn_flag_2_str(conn, conn->conn_flag), + ack_frequency); } else if (send_ctl->ctl_ack_eliciting_pkt[pns] > 0 && !xqc_timer_is_set(&send_ctl->path_timer_manager, XQC_TIMER_ACK_INIT + pns)) @@ -289,7 +306,7 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|set ack timer|ack_eliciting_pkt:%ud|pns:%d|flag:%s|now:%ui|max_ack_delay:%ui|", path->path_id, - send_ctl->ctl_ack_eliciting_pkt[pns], pns, xqc_conn_flag_2_str(conn->conn_flag), + send_ctl->ctl_ack_eliciting_pkt[pns], pns, xqc_conn_flag_2_str(conn, conn->conn_flag), now, conn->local_settings.max_ack_delay * 1000); } } @@ -305,6 +322,13 @@ xqc_ack_sent_record_init(xqc_ack_sent_record_t *record) return XQC_OK; } +void +xqc_ack_sent_record_reset(xqc_ack_sent_record_t *record) +{ + record->last_add_time = 0; + xqc_rarray_reinit(record->ack_sent); +} + void xqc_ack_sent_record_destroy(xqc_ack_sent_record_t *record) { diff --git a/src/transport/xqc_recv_record.h b/src/transport/xqc_recv_record.h index af1091508..75fd65b88 100644 --- a/src/transport/xqc_recv_record.h +++ b/src/transport/xqc_recv_record.h @@ -33,10 +33,11 @@ typedef struct xqc_recv_record_s { typedef struct xqc_ack_info_s { xqc_pkt_num_space_t pns; - uint64_t dcid_seq_num; + uint64_t path_id; unsigned n_ranges; /* must > 0 */ xqc_pktno_range_t ranges[XQC_MAX_ACK_RANGE_CNT]; xqc_usec_t ack_delay; + xqc_packet_number_t largest_acked; } xqc_ack_info_t; typedef struct xqc_ack_sent_entry_s { @@ -67,6 +68,8 @@ void xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_c int xqc_ack_sent_record_init(xqc_ack_sent_record_t *record); +void xqc_ack_sent_record_reset(xqc_ack_sent_record_t *record); + void xqc_ack_sent_record_destroy(xqc_ack_sent_record_t *record); int xqc_ack_sent_record_add(xqc_ack_sent_record_t *record, xqc_packet_out_t *packet_out, xqc_usec_t srtt, xqc_usec_t now); diff --git a/src/transport/xqc_recv_timestamps_info.c b/src/transport/xqc_recv_timestamps_info.c new file mode 100644 index 000000000..a7e3d49c1 --- /dev/null +++ b/src/transport/xqc_recv_timestamps_info.c @@ -0,0 +1,125 @@ +#include "src/transport/xqc_recv_timestamps_info.h" +#include "src/common/xqc_malloc.h" + +#define RECV_TIMESTAMPS_INFO_NEXT_IDX(pkt_num) ((pkt_num + 1) & (XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH - 1)) + +static unsigned int +xqc_popcountll(uint64_t num) +{ +#if defined(__GNUC__) || defined(__clang__) + return __builtin_popcountll(num); +#elif defined(_MSC_VER) + return __popcnt64(num); +#else + unsigned int count = 0; + while (num) { + count += num & 1; + num >>= 1; + } + return count; +#endif +} + +xqc_recv_timestamps_info_t * +xqc_recv_timestamps_info_create() +{ + xqc_recv_timestamps_info_t *ts_info = + xqc_calloc(1, sizeof(xqc_recv_timestamps_info_t)); + ts_info->is_first_pkt = 1; + return ts_info; +} + +void +xqc_recv_timestamps_info_destroy(xqc_recv_timestamps_info_t *ts_info) +{ + if (ts_info) { + xqc_free(ts_info); + } +} + +void +xqc_recv_timestamps_info_add_pkt(xqc_recv_timestamps_info_t *ts_info, + xqc_packet_number_t pkt_num, xqc_usec_t recv_time) +{ + if (ts_info->is_first_pkt) { + ts_info->is_first_pkt = 0; + ts_info->expected_next_pkt_num = pkt_num; + } + /* don't support reporting out-of-order packet */ + if (pkt_num < ts_info->expected_next_pkt_num) { + return; + } else if (pkt_num > ts_info->expected_next_pkt_num) { + ts_info->new_range_flag |= 1 << (ts_info->end_idx); + } else { + ts_info->new_range_flag &= ~(1 << (ts_info->end_idx)); + } + ts_info->pkt_nums[ts_info->end_idx] = pkt_num; + ts_info->recv_timestamps[ts_info->end_idx] = recv_time; + ts_info->end_idx = RECV_TIMESTAMPS_INFO_NEXT_IDX(ts_info->end_idx); + if (ts_info->end_idx == ts_info->start_idx) { + ts_info->start_idx = RECV_TIMESTAMPS_INFO_NEXT_IDX(ts_info->start_idx); + } + ts_info->expected_next_pkt_num = pkt_num + 1; + ts_info->cur_len += 1; +} + +void +xqc_recv_timestamps_info_clear(xqc_recv_timestamps_info_t *ts_info) +{ + ts_info->start_idx = 0; + ts_info->end_idx = 0; + ts_info->cur_len = 0; + ts_info->new_range_flag = 0; +} + +int +xqc_recv_timestamps_info_length(xqc_recv_timestamps_info_t *ts_info) +{ + if (ts_info == NULL) { + return 0; + } + return ts_info->cur_len; +} + +int +xqc_recv_timestamps_info_fetch(xqc_recv_timestamps_info_t *ts_info, uint32_t idx, + xqc_packet_number_t *pkt_num, xqc_usec_t *recv_time) +{ + if (idx > ts_info->cur_len) { + return 0; + } + int inner_idx = ((idx + ts_info->start_idx) & (XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH - 1)); + *pkt_num = ts_info->pkt_nums[inner_idx]; + *recv_time = ts_info->recv_timestamps[inner_idx]; + return 1; +} + +/* +* Additional fields for ACK_RECEIVE_TIMESTAMPS { +* Timestamp Range Count (i), +* Timestamp Ranges (..) ..., +* } +* here, Timestamp Range { +* Gap (i), +* Timestamp Delta Count (i), +* Timestamp Delta (i) ..., +* } +* estimated_bytes = 1 (Timestamp Range Count) + 2 (gap and timestamp_delta_count for one TS_Range) * range_count + +* 4 (TS Delta for the first pkt in first range) + 1 (TS Delta for left pkts) +*/ +size_t +xqc_recv_timestamps_info_need_bytes_estimate(xqc_recv_timestamps_info_t *ts_info){ + if (ts_info->cur_len == 0) { + /* for no timestamp reporting */ + return 1; + } + int range_count = xqc_popcountll(ts_info->new_range_flag) + 1; + int est_byte = 1 + range_count * 2 + 4 + (ts_info->cur_len - 1); + return est_byte; +} + +void +xqc_recv_timestamps_info_set_nobuf_flag(xqc_recv_timestamps_info_t *ts_info, uint8_t nobuf_for_ts) +{ + ts_info->nobuf_for_ts_in_last_ext_ack = nobuf_for_ts; +} \ No newline at end of file diff --git a/src/transport/xqc_recv_timestamps_info.h b/src/transport/xqc_recv_timestamps_info.h new file mode 100644 index 000000000..5d7661d9d --- /dev/null +++ b/src/transport/xqc_recv_timestamps_info.h @@ -0,0 +1,53 @@ +#ifndef _XQC_RECV_TIMESTAMPS_INFO_H_INCLUDED_ +#define _XQC_RECV_TIMESTAMPS_INFO_H_INCLUDED_ + +#include + +#define XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH 64 + +/* + * xqc_recv_timestamps_info_t: using a circular deque with fix length + * to save packet receive timestamp in ascending order of pkt num. If + * one packet arrives out of order, just discard and don't report it. +*/ +typedef struct xqc_recv_timestamps_info_s { + uint32_t start_idx; + uint32_t end_idx; + uint32_t cur_len; + xqc_packet_number_t expected_next_pkt_num; + xqc_usec_t recv_timestamps[XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH]; + xqc_packet_number_t pkt_nums[XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH]; + /* + * if XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH > 64, + * new_range_flag should be implemented in another way. + */ + uint64_t new_range_flag; + uint8_t is_first_pkt; + uint8_t nobuf_for_ts_in_last_ext_ack; +} xqc_recv_timestamps_info_t; + +typedef struct xqc_ack_timestamp_info_s { + uint32_t report_num; + xqc_packet_number_t pkt_nums[XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH]; + uint64_t recv_ts[XQC_RECV_TIMESTAMPS_INFO_MAX_LENGTH]; +} xqc_ack_timestamp_info_t; + +xqc_recv_timestamps_info_t *xqc_recv_timestamps_info_create(); + +void xqc_recv_timestamps_info_destroy(xqc_recv_timestamps_info_t *ts_info); + +void xqc_recv_timestamps_info_add_pkt(xqc_recv_timestamps_info_t *ts_info, + xqc_packet_number_t pkt_num, xqc_usec_t recv_time); + +void xqc_recv_timestamps_info_clear(xqc_recv_timestamps_info_t *ts_info); + +int xqc_recv_timestamps_info_length(xqc_recv_timestamps_info_t *ts_info); + +int xqc_recv_timestamps_info_fetch(xqc_recv_timestamps_info_t *ts_info, uint32_t idx, + xqc_packet_number_t *pkt_num, xqc_usec_t *recv_time); + +size_t xqc_recv_timestamps_info_need_bytes_estimate(xqc_recv_timestamps_info_t *ts_info); + +void xqc_recv_timestamps_info_set_nobuf_flag(xqc_recv_timestamps_info_t *ts_info, uint8_t has_ts_in_ack_ext); + +#endif /* _XQC_RECV_TIMESTAMPS_INFO_H_INCLUDED_ */ \ No newline at end of file diff --git a/src/transport/xqc_reinjection.c b/src/transport/xqc_reinjection.c index ab07de1a2..178c3d1fd 100644 --- a/src/transport/xqc_reinjection.c +++ b/src/transport/xqc_reinjection.c @@ -10,7 +10,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" @@ -66,6 +65,9 @@ xqc_packet_out_replicate(xqc_packet_out_t *dst, xqc_packet_out_t *src) dst->po_flag &= ~XQC_POF_IN_UNACK_LIST; dst->po_flag &= ~XQC_POF_IN_PATH_BUF_LIST; dst->po_user_data = src->po_user_data; + dst->po_sched_cwnd_blk_ts = 0; + dst->po_send_cwnd_blk_ts = 0; + dst->po_send_pacing_blk_ts = 0; } xqc_int_t @@ -92,6 +94,9 @@ xqc_conn_try_reinject_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_ou po_copy->po_path_flag &= ~XQC_PATH_SPECIFIED_BY_PTO; } + po_copy->po_flag &= ~XQC_POF_RETRANSED; + po_copy->po_flag &= ~XQC_POF_SPURIOUS_LOSS; + xqc_associate_packet_with_reinjection(packet_out, po_copy); xqc_send_queue_insert_send(po_copy, &send_queue->sndq_send_packets, send_queue); @@ -101,7 +106,7 @@ xqc_conn_try_reinject_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_ou "path:%ui|stream_id:%ui|stream_offset:%ui|" "pkt_type:%s|origin_pkt_path:%ui|origin_pkt_num:%ui|", po_copy->po_path_id, po_copy->po_stream_id, po_copy->po_stream_offset, - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), packet_out->po_path_id, packet_out->po_pkt.pkt_num); return XQC_OK; @@ -126,10 +131,11 @@ xqc_conn_reinject_unack_packets(xqc_connection_t *conn, xqc_reinjection_mode_t m } xqc_log(conn->log, XQC_LOG_DEBUG, "|MP|REINJ|reinject unacked packets|" - "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", + "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|mode:%d|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), + mode); } } diff --git a/src/transport/xqc_send_ctl.c b/src/transport/xqc_send_ctl.c index b9f9e3037..539742832 100644 --- a/src/transport/xqc_send_ctl.c +++ b/src/transport/xqc_send_ctl.c @@ -15,6 +15,7 @@ #include "src/transport/xqc_conn.h" #include "src/transport/xqc_stream.h" #include "src/common/xqc_memory_pool.h" +#include "src/common/xqc_algorithm.h" #include "src/congestion_control/xqc_sample.h" #include "src/transport/xqc_pacing.h" #include "src/transport/xqc_utils.h" @@ -122,12 +123,13 @@ xqc_send_ctl_create(xqc_path_ctx_t *path) send_ctl->ctl_pto_count = 0; send_ctl->ctl_minrtt = XQC_MAX_UINT32_VALUE; - send_ctl->ctl_srtt = XQC_kInitialRtt * 1000; - send_ctl->ctl_rttvar = XQC_kInitialRtt * 1000 / 2; + send_ctl->ctl_srtt = conn->conn_settings.initial_rtt; + send_ctl->ctl_rttvar = send_ctl->ctl_srtt / 2; send_ctl->ctl_latest_rtt = 0; send_ctl->ctl_max_bytes_in_flight = 0; send_ctl->ctl_reordering_packet_threshold = conn->conn_settings.loss_detection_pkt_thresh; send_ctl->ctl_reordering_time_threshold_shift = XQC_kTimeThresholdShift; + send_ctl->ctl_first_rtt_sample_time = 0; for (size_t i = 0; i < XQC_PNS_N; i++) { send_ctl->ctl_largest_acked[i] = XQC_MAX_UINT64_VALUE; @@ -182,7 +184,7 @@ xqc_send_ctl_create(xqc_path_ctx_t *path) send_ctl->sampler.send_ctl = send_ctl; - xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl); + xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl, XQC_kGranularity, conn->conn_settings.cc_params); return send_ctl; } @@ -207,11 +209,13 @@ xqc_send_ctl_reset(xqc_send_ctl_t *send_ctl) send_ctl->ctl_pto_count = 0; send_ctl->ctl_minrtt = XQC_MAX_UINT32_VALUE; - send_ctl->ctl_srtt = XQC_kInitialRtt * 1000; - send_ctl->ctl_rttvar = XQC_kInitialRtt * 1000 / 2; + send_ctl->ctl_srtt = conn->conn_settings.initial_rtt; + send_ctl->ctl_rttvar = send_ctl->ctl_srtt / 2; send_ctl->ctl_max_bytes_in_flight = 0; send_ctl->ctl_reordering_packet_threshold = XQC_kPacketThreshold; send_ctl->ctl_reordering_time_threshold_shift = XQC_kTimeThresholdShift; + send_ctl->ctl_ack_sent_cnt = 0; + send_ctl->ctl_first_rtt_sample_time = 0; for (size_t i = 0; i < XQC_PNS_N; i++) { send_ctl->ctl_largest_acked[i] = XQC_MAX_UINT64_VALUE; @@ -281,7 +285,7 @@ xqc_send_ctl_reset(xqc_send_ctl_t *send_ctl) xqc_send_queue_move_to_tail(pos, &send_queue->sndq_send_packets); } - xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl); + xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl, XQC_kGranularity, conn->conn_settings.cc_params); } xqc_pn_ctl_t * @@ -438,7 +442,7 @@ xqc_send_ctl_can_send(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, ui xqc_bool_t xqc_send_packet_cwnd_allows(xqc_send_ctl_t *send_ctl, - xqc_packet_out_t *packet_out, uint32_t schedule_bytes) + xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now) { xqc_connection_t *conn = send_ctl->ctl_conn; @@ -447,6 +451,9 @@ xqc_send_packet_cwnd_allows(xqc_send_ctl_t *send_ctl, if (!xqc_send_ctl_can_send(send_ctl, packet_out, schedule_bytes)) { xqc_log(conn->log, XQC_LOG_DEBUG, "|blocked by congestion control|po_sz:%ud|", packet_out->po_used_size); + if (packet_out->po_send_cwnd_blk_ts == 0) { + packet_out->po_send_cwnd_blk_ts = now; + } return XQC_FALSE; } } @@ -456,7 +463,7 @@ xqc_send_packet_cwnd_allows(xqc_send_ctl_t *send_ctl, xqc_bool_t xqc_send_packet_pacer_allows(xqc_send_ctl_t *send_ctl, - xqc_packet_out_t *packet_out, uint32_t schedule_bytes) + xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now) { xqc_connection_t *conn = send_ctl->ctl_conn; @@ -467,6 +474,9 @@ xqc_send_packet_pacer_allows(xqc_send_ctl_t *send_ctl, schedule_bytes + packet_out->po_used_size)) { xqc_log(conn->log, XQC_LOG_DEBUG, "|pacing blocked|"); + if (packet_out->po_send_pacing_blk_ts == 0) { + packet_out->po_send_pacing_blk_ts = now; + } return XQC_FALSE; } } @@ -477,10 +487,10 @@ xqc_send_packet_pacer_allows(xqc_send_ctl_t *send_ctl, xqc_bool_t xqc_send_packet_check_cc(xqc_send_ctl_t *send_ctl, - xqc_packet_out_t *po, uint32_t schedule_bytes) + xqc_packet_out_t *po, uint32_t schedule_bytes, xqc_usec_t now) { - return xqc_send_packet_cwnd_allows(send_ctl, po, schedule_bytes) - && xqc_send_packet_pacer_allows(send_ctl, po, schedule_bytes); + return xqc_send_packet_cwnd_allows(send_ctl, po, schedule_bytes, now) + && xqc_send_packet_pacer_allows(send_ctl, po, schedule_bytes, now); } @@ -562,15 +572,8 @@ xqc_send_ctl_decrease_inflight(xqc_connection_t *conn, xqc_packet_out_t *packet_ xqc_send_ctl_t *send_ctl = path->path_send_ctl; if (packet_out->po_flag & XQC_POF_IN_FLIGHT) { if (XQC_IS_ACK_ELICITING(packet_out->po_frame_types)) { - if (send_ctl->ctl_bytes_ack_eliciting_inflight[packet_out->po_pkt.pkt_pns] < packet_out->po_used_size) { - xqc_log(conn->log, XQC_LOG_ERROR, "|ctl_bytes_in_flight too small|"); - send_ctl->ctl_bytes_ack_eliciting_inflight[packet_out->po_pkt.pkt_pns] = 0; - send_ctl->ctl_bytes_in_flight = 0; - - } else { - send_ctl->ctl_bytes_ack_eliciting_inflight[packet_out->po_pkt.pkt_pns] -= packet_out->po_used_size; - send_ctl->ctl_bytes_in_flight -= packet_out->po_used_size; - } + send_ctl->ctl_bytes_ack_eliciting_inflight[packet_out->po_pkt.pkt_pns] = xqc_uint32_bounded_subtract(send_ctl->ctl_bytes_ack_eliciting_inflight[packet_out->po_pkt.pkt_pns], packet_out->po_used_size); + send_ctl->ctl_bytes_in_flight = xqc_uint32_bounded_subtract(send_ctl->ctl_bytes_in_flight, packet_out->po_used_size); packet_out->po_flag &= ~XQC_POF_IN_FLIGHT; } } @@ -588,7 +591,7 @@ xqc_send_ctl_on_pns_discard(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns) static void -xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl) +xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl, xqc_usec_t now) { if (send_ctl->ctl_bytes_in_flight > send_ctl->ctl_max_bytes_in_flight) { send_ctl->ctl_max_bytes_in_flight = send_ctl->ctl_bytes_in_flight; @@ -602,6 +605,9 @@ xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl) uint32_t actual_mss = xqc_conn_get_mss(send_ctl->ctl_conn); if ((send_ctl->ctl_bytes_in_flight + actual_mss) > cwnd_bytes) { send_ctl->ctl_is_cwnd_limited = 1; + /* record the time of cwnd limited */ + send_ctl->ctl_recent_cwnd_limitation_time[send_ctl->ctl_cwndlim_update_idx] = now; + send_ctl->ctl_cwndlim_update_idx = (send_ctl->ctl_cwndlim_update_idx + 1) % 3; } } @@ -618,13 +624,15 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ xqc_packet_number_t orig_pktnum = packet_out->po_origin ? packet_out->po_origin->po_pkt.pkt_num : 0; xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, - "|conn:%p|path:%ui|pkt_num:%ui|origin_pktnum:%ui|size:%ud|pkt_type:%s|frame:%s|conn_state:%s|po_in_flight:%d|", - send_ctl->ctl_conn, send_ctl->ctl_path->path_id, packet_out->po_pkt.pkt_num, orig_pktnum, packet_out->po_used_size, + "|conn:%p|path:%ui|pkt_num:%ui|origin_pktnum:%ui|size:%ud|enc_size:%ud|pkt_type:%s|frame:%s|conn_state:%s|po_in_flight:%d|" + "|retrans:%d|", + send_ctl->ctl_conn, send_ctl->ctl_path->path_id, packet_out->po_pkt.pkt_num, orig_pktnum, packet_out->po_used_size, packet_out->po_enc_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(send_ctl->ctl_conn->conn_state), - packet_out->po_flag & XQC_POF_IN_FLIGHT ? 1: 0); - + packet_out->po_flag & XQC_POF_IN_FLIGHT ? 1: 0, + packet_out->po_flag & (XQC_POF_LOST | XQC_POF_TLP)); + if (packet_out->po_frame_types & (XQC_FRAME_BIT_DATA_BLOCKED | XQC_FRAME_BIT_STREAM_DATA_BLOCKED @@ -637,7 +645,7 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ send_ctl->ctl_conn, send_ctl->ctl_path->path_id, packet_out->po_pkt.pkt_num, orig_pktnum, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(send_ctl->ctl_conn->conn_state), packet_out->po_flag & XQC_POF_IN_FLIGHT ? 1: 0); } @@ -646,7 +654,10 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ pn_ctl->ctl_largest_sent[pns] = packet_out->po_pkt.pkt_num; } - send_ctl->ctl_bytes_send += packet_out->po_used_size; + send_ctl->ctl_bytes_send += packet_out->po_enc_size; + if (packet_out->po_frame_types & (XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_DATAGRAM)) { + send_ctl->ctl_app_bytes_send += packet_out->po_enc_size; + } if (packet_out->po_largest_ack > 0) { xqc_ack_sent_record_add(&pn_ctl->ack_sent_record[pns], packet_out, send_ctl->ctl_srtt, now); @@ -660,39 +671,23 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ send_ctl->ctl_last_sent_ack_eliciting_packet_number[pns] = packet_out->po_pkt.pkt_num; } - xqc_conn_update_stream_stats_on_sent(send_ctl->ctl_conn, packet_out, now); + + xqc_conn_update_stream_stats_on_sent(send_ctl->ctl_conn, send_ctl, packet_out, now); xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|path:%ui|inflight:%ud|applimit:%ui|", send_ctl->ctl_path->path_id, send_ctl->ctl_bytes_in_flight, send_ctl->ctl_app_limited); + if (send_ctl->ctl_bytes_in_flight == 0) { + if (send_ctl->ctl_cong_callback->xqc_cong_ctl_init_bbr && send_ctl->ctl_app_limited > 0) { - uint8_t mode, idle_restart; - mode = send_ctl->ctl_cong_callback-> - xqc_cong_ctl_info_cb->mode(send_ctl->ctl_cong); - idle_restart = send_ctl->ctl_cong_callback-> - xqc_cong_ctl_info_cb-> - idle_restart(send_ctl->ctl_cong); - xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, - "|BeforeRestartFromIdle|mode %ud|idle %ud" - "|bw %ud|pacing rate %ud|", - (unsigned int)mode, (unsigned int)idle_restart, send_ctl->ctl_cong_callback-> - xqc_cong_ctl_get_bandwidth_estimate(send_ctl->ctl_cong), - send_ctl->ctl_cong_callback-> - xqc_cong_ctl_get_pacing_rate(send_ctl->ctl_cong)); send_ctl->ctl_cong_callback->xqc_cong_ctl_restart_from_idle(send_ctl->ctl_cong, send_ctl->ctl_delivered); xqc_log_event(send_ctl->ctl_conn->log, REC_CONGESTION_STATE_UPDATED, "restart"); - - xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, - "|AfterRestartFromIdle|mode %ud|" - "idle %ud|bw %ud|pacing rate %ud|", - (unsigned int)mode, (unsigned int)idle_restart, send_ctl->ctl_cong_callback-> - xqc_cong_ctl_get_bandwidth_estimate(send_ctl->ctl_cong), - send_ctl->ctl_cong_callback->xqc_cong_ctl_get_pacing_rate(send_ctl->ctl_cong)); } + if (!send_ctl->ctl_cong_callback->xqc_cong_ctl_init_bbr) { xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|Restart from idle|"); send_ctl->ctl_cong_callback->xqc_cong_ctl_restart_from_idle(send_ctl->ctl_cong, send_ctl->ctl_last_inflight_pkt_sent_time); @@ -705,18 +700,23 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ xqc_conn_increase_unacked_stream_ref(send_ctl->ctl_conn, packet_out); } - if (XQC_IS_ACK_ELICITING(packet_out->po_frame_types)) { + if (XQC_IS_ACK_ELICITING(packet_out->po_frame_types) + /* do not set loss detection timer for PMTUD probing */ + && !(packet_out->po_flag & XQC_POF_PMTUD_PROBING)) + { xqc_send_ctl_set_loss_detection_timer(send_ctl); } if (packet_out->po_flag & XQC_POF_LOST) { ++send_ctl->ctl_lost_count; + send_ctl->ctl_recent_lost_count[0]++; packet_out->po_flag &= ~XQC_POF_LOST; } if (packet_out->po_flag & XQC_POF_TLP) { ++send_ctl->ctl_tlp_count; + send_ctl->ctl_recent_lost_count[0]++; packet_out->po_flag &= ~XQC_POF_TLP; } @@ -746,10 +746,11 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ } ++send_ctl->ctl_send_count; + send_ctl->ctl_recent_send_count[0]++; xqc_stream_path_metrics_on_send(send_ctl->ctl_conn, packet_out); send_ctl->ctl_last_inflight_pkt_sent_time = now; - xqc_send_ctl_update_cwnd_limited(send_ctl); + xqc_send_ctl_update_cwnd_limited(send_ctl, now); } if (packet_out->po_frame_types & XQC_FRAME_BIT_CONNECTION_CLOSE) { @@ -758,8 +759,23 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ } } + if (packet_out->po_frame_types & XQC_FRAME_BIT_HANDSHAKE_DONE) { + send_ctl->ctl_conn->conn_flag |= XQC_CONN_FLAG_HANDSHAKE_DONE_SENT; + } + send_ctl->ctl_conn->conn_last_send_time = now; + if (!send_ctl->ctl_recent_stats_timestamp) { + send_ctl->ctl_recent_stats_timestamp = now; + } + + if (now >= send_ctl->ctl_recent_stats_timestamp + (5 * send_ctl->ctl_srtt)) { + send_ctl->ctl_recent_stats_timestamp = now; + send_ctl->ctl_recent_lost_count[1] = send_ctl->ctl_recent_lost_count[0]; + send_ctl->ctl_recent_send_count[1] = send_ctl->ctl_recent_send_count[0]; + send_ctl->ctl_recent_lost_count[0] = 0; + send_ctl->ctl_recent_send_count[0] = 0; + } } /** @@ -779,7 +795,7 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc xqc_pkt_num_space_t pns = ack_info->pns; /* 标记ack info里是否有这条路径发出的包 */ - unsigned char has_acked = 0, update_largest_ack = 0; + unsigned char has_acked = 0, update_largest_ack = 0, ignore_rtt = 0; unsigned char has_ack_eliciting = 0, spurious_loss_detected = 0; xqc_packet_number_t frame_largest_ack = ack_info->ranges[0].high; xqc_packet_number_t spurious_loss_pktnum = 0; @@ -843,8 +859,12 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc send_ctl->ctl_largest_acked[pns] == XQC_MAX_UINT64_VALUE) { update_largest_ack = 1; + ignore_rtt = 0; send_ctl->ctl_largest_acked[pns] = packet_out->po_pkt.pkt_num; send_ctl->ctl_largest_acked_sent_time[pns] = packet_out->po_sent_time; + if (packet_out->po_flag & XQC_POF_PMTUD_PROBING) { + ignore_rtt = 1; + } } // 更新 largest_ack_both @@ -859,7 +879,7 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc (xqc_packet_number_t)packet_out->po_origin ? packet_out->po_origin->po_pkt.pkt_num : 0, packet_out->po_used_size, pns, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(conn->conn_state), frame_largest_ack, send_ctl->ctl_largest_acked[pns]); @@ -867,13 +887,14 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc xqc_update_sample(&send_ctl->sampler, packet_out, send_ctl, ack_recv_time); /* Packet previously declared lost gets acked */ - if (!packet_out->po_acked && (packet_out->po_flag & XQC_POF_RETRANSED)) { + if (!(packet_out->po_flag & XQC_POF_SPURIOUS_LOSS) && (packet_out->po_flag & XQC_POF_RETRANSED)) { ++send_ctl->ctl_spurious_loss_count; if (!spurious_loss_detected) { spurious_loss_detected = 1; spurious_loss_pktnum = packet_out->po_pkt.pkt_num; spurious_loss_sent_time = packet_out->po_sent_time; } + packet_out->po_flag |= XQC_POF_SPURIOUS_LOSS; } if (packet_out->po_frame_types & XQC_FRAME_BIT_DATAGRAM) { @@ -881,6 +902,11 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc } xqc_send_ctl_on_packet_acked(send_ctl, packet_out, ack_recv_time, 1); + + if (packet_out->po_used_size > conn->max_acked_po_size) { + conn->max_acked_po_size = packet_out->po_used_size + XQC_TLS_AEAD_OVERHEAD_MAX_LEN; + } + xqc_send_queue_maybe_remove_unacked(packet_out, send_queue, NULL); @@ -899,10 +925,16 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc } if (update_largest_ack && has_ack_eliciting && ack_on_same_path) { - /* 更新 ctl_latest_rtt */ - send_ctl->ctl_latest_rtt = ack_recv_time - send_ctl->ctl_largest_acked_sent_time[pns]; - /* 更新rtt */ - xqc_send_ctl_update_rtt(send_ctl, &send_ctl->ctl_latest_rtt, ack_info->ack_delay); + if (!ignore_rtt) { + /* 更新 ctl_latest_rtt */ + send_ctl->ctl_latest_rtt = ack_recv_time - send_ctl->ctl_largest_acked_sent_time[pns]; + /* 更新rtt */ + xqc_send_ctl_update_rtt(send_ctl, &send_ctl->ctl_latest_rtt, ack_info->ack_delay); + + } else { + xqc_log(conn->log, XQC_LOG_DEBUG, "|ignore_rtt:%ui|", ack_recv_time - send_ctl->ctl_largest_acked_sent_time[pns]); + } + } /* TODO: ECN */ @@ -1201,6 +1233,7 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, xqc_int_t repair_dgram = 0; xqc_reinjection_mode_t mode = conn->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_BEFORE_SCHED; + int has_reinjection = 0; xqc_list_for_each_safe(pos, next, &send_queue->sndq_unacked_packets[pns]) { po = xqc_list_entry(pos, xqc_packet_out_t, po_list); @@ -1237,7 +1270,8 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", po->po_pkt.pkt_num, po->po_used_size, xqc_pkt_type_2_str(po->po_pkt.pkt_type), - xqc_frame_type_2_str(po->po_frame_types)); + xqc_frame_type_2_str(conn->engine, po->po_frame_types)); + has_reinjection = 1; } } @@ -1252,9 +1286,10 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, } if (XQC_NEED_REPAIR(po->po_frame_types) + || (po->po_flag & XQC_POF_NOTIFY) || repair_dgram == XQC_DGRAM_RETX_ASKED_BY_APP) { - xqc_send_queue_copy_to_lost(po, send_queue); + xqc_send_queue_copy_to_lost(po, send_queue, XQC_TRUE); } else { if (po->po_frame_types & XQC_FRAME_BIT_DATAGRAM) { @@ -1268,13 +1303,14 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, } } + conn->detected_loss_cnt++; lost_n++; xqc_log(conn->log, XQC_LOG_DEBUG, "|mark lost|pns:%d|pkt_num:%ui|" "lost_pn:%ui|po_sent_time:%ui|lost_send_time:%ui|loss_delay:%ui|frame:%s|repair:%d|", pns, po->po_pkt.pkt_num, lost_pn, po->po_sent_time, lost_send_time, loss_delay, - xqc_frame_type_2_str(po->po_frame_types), XQC_NEED_REPAIR(po->po_frame_types)); - xqc_log_event(conn->log, REC_PACKET_LOST, po); + xqc_frame_type_2_str(conn->engine, po->po_frame_types), XQC_NEED_REPAIR(po->po_frame_types)); + xqc_log_event(conn->log, REC_PACKET_LOST, po, lost_pn, lost_send_time, loss_delay); } else { xqc_log(conn->log, XQC_LOG_DEBUG, "|it's a copy of origin pkt|acked:%d|origin_acked:%d|origin_ref_cnt:%d|", @@ -1300,6 +1336,15 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, } } + if (has_reinjection) { + xqc_path_ctx_t *path; + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + xqc_list_splice_tail_init(&path->path_reinj_tmp_buf, + &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); + } + } + /* update statistic */ send_ctl->ctl_lost_pkts_number += lost_n; send_ctl->sampler.loss = lost_n; @@ -1519,11 +1564,11 @@ xqc_send_ctl_on_packet_acked(xqc_send_ctl_t *send_ctl, } } - /* TODO: fix NEW_CID_RECEIVED */ - if (packet_out->po_frame_types & XQC_FRAME_BIT_NEW_CONNECTION_ID) { - packet_out->po_frame_types &= ~XQC_FRAME_BIT_NEW_CONNECTION_ID; - conn->conn_flag |= XQC_CONN_FLAG_NEW_CID_ACKED; + + if (packet_out->po_frame_types & (XQC_FRAME_BIT_NEW_CONNECTION_ID | XQC_FRAME_BIT_MP_NEW_CONNECTION_ID)) { + xqc_cid_set_on_cid_acked(&conn->scid_set, packet_out->po_new_cid_path, packet_out->po_new_cid_seq); } + if (do_cc) { xqc_send_ctl_cc_on_ack(send_ctl, packet_out, now); @@ -1540,7 +1585,7 @@ xqc_send_ctl_on_packet_acked(xqc_send_ctl_t *send_ctl, xqc_usec_t xqc_send_ctl_get_pto_time_and_space(xqc_send_ctl_t *send_ctl, xqc_usec_t now, xqc_pkt_num_space_t *pns_ret) { - xqc_usec_t t; + xqc_usec_t t, duration; xqc_usec_t pto_timeout = XQC_MAX_UINT64_VALUE; xqc_connection_t *c = send_ctl->ctl_conn; xqc_int_t pto_cnt = send_ctl->ctl_pto_count; @@ -1550,8 +1595,22 @@ xqc_send_ctl_get_pto_time_and_space(xqc_send_ctl_t *send_ctl, xqc_usec_t now, xq backoff = xqc_min(backoff, 1 << 16); /* get pto duration */ - xqc_usec_t duration = (send_ctl->ctl_srtt - + xqc_max(4 * send_ctl->ctl_rttvar, XQC_kGranularity * 1000)) * backoff; + if (c->conn_settings.control_pto_value) { + duration = send_ctl->ctl_srtt + send_ctl->ctl_srtt / 4; + + } else { + duration = (send_ctl->ctl_srtt + + xqc_max(4 * send_ctl->ctl_rttvar, XQC_kGranularity * 1000)); + } + + /* RTT has not been measured yet*/ + if (send_ctl->ctl_first_rtt_sample_time == 0 + && c->conn_settings.initial_pto_duration != 0) + { + duration = c->conn_settings.initial_pto_duration; + } + + duration *= backoff; xqc_log(c->log, XQC_LOG_DEBUG, "|srtt:%ud|rtt_var:%ud|pto_duration:%ud|backoff_factor:%.2f|backoff:%.2f|pto_cnt:%d|max_ack_delay:%d|", @@ -1783,3 +1842,25 @@ xqc_send_ctl_get_pkt_num_gap(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns, { return back - front; } + +uint64_t +xqc_send_ctl_get_est_bw(xqc_send_ctl_t *send_ctl) +{ + if (send_ctl->ctl_cong && send_ctl->ctl_cong_callback) { + if (send_ctl->ctl_cong_callback->xqc_cong_ctl_get_bandwidth_estimate) { + return send_ctl->ctl_cong_callback->xqc_cong_ctl_get_bandwidth_estimate(send_ctl->ctl_cong); + + } else if (send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd) { + uint64_t cwnd = send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong); + xqc_usec_t srtt = send_ctl->ctl_srtt ? send_ctl->ctl_srtt : send_ctl->ctl_conn->conn_settings.initial_rtt; + return (cwnd * 1000000) / srtt; + } + } + + return 0; +} + +uint64_t +xqc_send_ctl_get_pacing_rate(xqc_send_ctl_t *send_ctl) { + return xqc_pacing_rate_calc(&send_ctl->ctl_pacing); +} diff --git a/src/transport/xqc_send_ctl.h b/src/transport/xqc_send_ctl.h index 7ca18f30b..024a97fa4 100644 --- a/src/transport/xqc_send_ctl.h +++ b/src/transport/xqc_send_ctl.h @@ -25,7 +25,7 @@ */ #define XQC_kGranularity 2 -#define XQC_kInitialRtt 250 +#define XQC_kInitialRtt_us 250000 /* 2^n */ #define xqc_send_ctl_pow(n) (1 << n) @@ -112,6 +112,10 @@ typedef struct xqc_send_ctl_s { unsigned ctl_spurious_loss_count; unsigned ctl_lost_dgram_cnt; + /* record time for last three cwnd limitation and rtt mutation*/ + xqc_msec_t ctl_recent_cwnd_limitation_time[3]; + uint8_t ctl_cwndlim_update_idx; + unsigned ctl_recv_count; /* for QUIC datagrams */ @@ -130,6 +134,10 @@ typedef struct xqc_send_ctl_s { uint64_t ctl_bytes_send; uint64_t ctl_bytes_recv; + /* only accounts for stream and datagram packets */ + uint64_t ctl_app_bytes_send; + uint64_t ctl_app_bytes_recv; + const xqc_cong_ctrl_callback_t *ctl_cong_callback; void *ctl_cong; @@ -150,6 +158,13 @@ typedef struct xqc_send_ctl_s { xqc_sample_t sampler; xqc_send_ctl_info_t ctl_info; + + unsigned ctl_recent_send_count[2]; + unsigned ctl_recent_lost_count[2]; + xqc_usec_t ctl_recent_stats_timestamp; + + uint64_t ctl_ack_sent_cnt; + } xqc_send_ctl_t; @@ -182,12 +197,12 @@ xqc_pn_ctl_t *xqc_get_pn_ctl(xqc_connection_t *conn, xqc_path_ctx_t *path); int xqc_send_ctl_can_send(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes); xqc_bool_t xqc_send_packet_cwnd_allows(xqc_send_ctl_t *send_ctl, - xqc_packet_out_t *packet_out, uint32_t schedule_bytes); + xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); xqc_bool_t xqc_send_packet_pacer_allows(xqc_send_ctl_t *send_ctl, - xqc_packet_out_t *packet_out, uint32_t schedule_bytes); + xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); -xqc_bool_t xqc_send_packet_check_cc(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes); +xqc_bool_t xqc_send_packet_check_cc(xqc_send_ctl_t *send_ctl, xqc_packet_out_t *packet_out, uint32_t schedule_bytes, xqc_usec_t now); void xqc_send_ctl_increase_inflight(xqc_connection_t *conn, xqc_packet_out_t *packet_out); @@ -254,4 +269,8 @@ xqc_packet_number_t xqc_send_ctl_get_lost_sent_pn(xqc_send_ctl_t *send_ctl, xqc_ xqc_packet_number_t xqc_send_ctl_get_pkt_num_gap(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns, xqc_packet_number_t front, xqc_packet_number_t back); +/* bytes per second */ +uint64_t xqc_send_ctl_get_est_bw(xqc_send_ctl_t *send_ctl); +uint64_t xqc_send_ctl_get_pacing_rate(xqc_send_ctl_t *send_ctl); + #endif /* _XQC_SEND_CTL_H_INCLUDED_ */ diff --git a/src/transport/xqc_send_queue.c b/src/transport/xqc_send_queue.c index 082224416..1e61e0273 100644 --- a/src/transport/xqc_send_queue.c +++ b/src/transport/xqc_send_queue.c @@ -116,7 +116,7 @@ xqc_send_queue_get_packet_out(xqc_send_queue_t *send_queue, unsigned need, xqc_p xqc_list_for_each_reverse(pos, &send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); if (packet_out->po_pkt.pkt_type == pkt_type - && packet_out->po_buf_size >= packet_out->po_used_size + need) + && xqc_get_po_remained_size(packet_out) >= need) { return packet_out; } @@ -136,15 +136,21 @@ xqc_send_queue_get_packet_out_for_stream(xqc_send_queue_t *send_queue, unsigned { xqc_packet_out_t *packet_out; xqc_list_head_t *pos; + xqc_list_head_t *list = &send_queue->sndq_send_packets; + if (stream->stream_priority == XQC_STREAM_PRI_HIGH) { + list = &send_queue->sndq_send_packets_high_pri; + } - xqc_list_for_each_reverse(pos, &send_queue->sndq_send_packets) { + xqc_list_for_each_reverse(pos, list) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); if (packet_out->po_pkt.pkt_type == pkt_type - && packet_out->po_buf_size >= packet_out->po_used_size + need + && xqc_get_po_remained_size(packet_out) >= need && packet_out->po_stream_frames_idx < XQC_MAX_STREAM_FRAME_IN_PO && packet_out->po_stream_frames_idx > 0 /* Avoid Head-of-Line blocking. */ - && packet_out->po_stream_frames[packet_out->po_stream_frames_idx - 1].ps_stream_id == stream->stream_id) + && packet_out->po_stream_frames[packet_out->po_stream_frames_idx - 1].ps_stream_id == stream->stream_id + && !(packet_out->po_frame_types & XQC_FRAME_BIT_SID) + && !(packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL)) { return packet_out; } @@ -156,6 +162,10 @@ xqc_send_queue_get_packet_out_for_stream(xqc_send_queue_t *send_queue, unsigned if (packet_out == NULL) { return NULL; } + + if (stream->stream_priority == XQC_STREAM_PRI_HIGH) { + xqc_send_queue_move_to_high_pri(&packet_out->po_list, send_queue); + } if (pkt_type == XQC_PTYPE_0RTT) { send_queue->sndq_conn->zero_rtt_count++; @@ -203,7 +213,7 @@ xqc_send_queue_insert_send(xqc_packet_out_t *po, xqc_list_head_t *head, xqc_send { xqc_list_add_tail(&po->po_list, head); send_queue->sndq_packets_used++; - } +} void xqc_send_queue_remove_send(xqc_list_head_t *pos) @@ -275,10 +285,19 @@ xqc_send_queue_remove_probe(xqc_list_head_t *pos) void xqc_send_queue_insert_unacked(xqc_packet_out_t *packet_out, xqc_list_head_t *head, xqc_send_queue_t *send_queue) { + xqc_connection_t *conn = send_queue->sndq_conn; xqc_list_add_tail(&packet_out->po_list, head); if (!(packet_out->po_flag & XQC_POF_IN_UNACK_LIST)) { send_queue->sndq_packets_in_unacked_list++; packet_out->po_flag |= XQC_POF_IN_UNACK_LIST; + if (send_queue->sndq_packets_in_unacked_list > XQC_SNDQ_MAX_UNACK_PACKETS_LIMIT) { + if (conn) { + XQC_CONN_ERR(conn, XQC_ELIMIT); + xqc_log(conn->log, XQC_LOG_ERROR, + "|sndq unack packets exceed|sndq_packets_in_unacked_list:%ui|", + send_queue->sndq_packets_in_unacked_list); + } + } } } @@ -336,7 +355,7 @@ xqc_send_queue_move_to_high_pri(xqc_list_head_t *pos, xqc_send_queue_t *send_que void -xqc_send_queue_copy_to_lost(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue) +xqc_send_queue_copy_to_lost(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue, xqc_bool_t mark_retrans) { xqc_connection_t *conn = send_queue->sndq_conn; @@ -355,7 +374,11 @@ xqc_send_queue_copy_to_lost(xqc_packet_out_t *packet_out, xqc_send_queue_t *send xqc_send_queue_insert_lost(&new_po->po_list, &send_queue->sndq_lost_packets); send_queue->sndq_packets_used++; - packet_out->po_flag |= XQC_POF_RETRANSED; + if (mark_retrans) { + packet_out->po_flag |= XQC_POF_RETRANSED; + } + new_po->po_flag &= ~XQC_POF_RETRANSED; + new_po->po_flag &= ~XQC_POF_SPURIOUS_LOSS; } void @@ -378,6 +401,8 @@ xqc_send_queue_copy_to_probe(xqc_packet_out_t *packet_out, xqc_send_queue_t *sen xqc_send_queue_insert_probe(&new_po->po_list, &send_queue->sndq_pto_probe_packets); send_queue->sndq_packets_used++; packet_out->po_flag |= XQC_POF_RETRANSED; + new_po->po_flag &= ~XQC_POF_RETRANSED; + new_po->po_flag &= ~XQC_POF_SPURIOUS_LOSS; } /* Called when conn is ready to close */ @@ -502,7 +527,7 @@ xqc_send_queue_drop_packets_from_list_with_type(xqc_send_ctl_t *send_ctl, xqc_se xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|drop pkt from %s list|inflight:%ud|cwnd:%ui|" "pkt_num:%ui|ptype:%d|frames:%s|len:%ud|", list_name, send_ctl->ctl_bytes_in_flight, send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong), packet_out->po_pkt.pkt_num, - packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(packet_out->po_frame_types), + packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), packet_out->po_used_size); } } @@ -528,10 +553,10 @@ xqc_send_queue_drop_packets_with_type(xqc_send_ctl_t *send_ctl, xqc_send_queue_t xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|drop pkt from unacked|inflight:%ui|cwnd:%ui|" + xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|drop pkt from unacked|inflight:%ud|cwnd:%ui|" "pkt_num:%ui|ptype:%d|frames:%s|", send_ctl->ctl_bytes_in_flight, send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong), packet_out->po_pkt.pkt_num, - packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(packet_out->po_frame_types)); + packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types)); } xqc_send_queue_drop_packets_from_list_with_type(send_ctl, send_queue, type, &send_queue->sndq_send_packets_high_pri, "high_pri", XQC_FALSE); @@ -558,6 +583,7 @@ void xqc_send_queue_drop_initial_packets(xqc_connection_t *conn) xqc_send_queue_t *send_queue = conn->conn_send_queue; xqc_send_queue_drop_packets_with_type(send_ctl, send_queue, XQC_PTYPE_INIT); xqc_send_ctl_on_pns_discard(send_ctl, XQC_PNS_INIT); + conn->max_acked_po_size = XQC_QUIC_MIN_MSS; } @@ -575,7 +601,19 @@ int xqc_send_ctl_stream_frame_can_drop(xqc_packet_out_t *packet_out, xqc_stream_id_t stream_id) { int drop = 0; - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { + /* + * Attached ACK could lead to a situation + * where an original packet (w/o ACK) can be removed but the corresponding + * replicated packet (w/ ACK) cannot be removed. This + * ultimately causes that the po_origin of the replicated packet (R) points to a new + * packet (N) to which the buffer of the original packet is reallocated. This is + * very rare but may lead to a infinite loop or crash when the unacked list + * in xqc_send_ctl_detect_lost is traversed. For example, when N is next to R in the unacked list, + * removing R may also free N via xqc_send_ctl_indirectly_ack_or_drop_po. If that + * happens, an infinite loop that traversing the free_packets list is triggered. + */ + uint64_t mask = ~(XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP | XQC_FRAME_BIT_SID); + if ((packet_out->po_frame_types & mask) == 0) { drop = 0; for (int i = 0; i < XQC_MAX_STREAM_FRAME_IN_PO; i++) { if (packet_out->po_stream_frames[i].ps_is_used == 0) { @@ -612,50 +650,42 @@ xqc_send_queue_drop_stream_frame_packets(xqc_connection_t *conn, xqc_stream_id_t xqc_list_for_each_safe(pos, next, &send_queue->sndq_unacked_packets[XQC_PNS_APP_DATA]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_send_ctl_decrease_inflight(conn, packet_out); - xqc_send_queue_remove_unacked(packet_out, send_queue); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_send_ctl_decrease_inflight(conn, packet_out); + xqc_send_queue_remove_unacked(packet_out, send_queue); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } xqc_list_for_each_safe(pos, next, &send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_send_queue_remove_send(pos); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_send_queue_remove_send(pos); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } xqc_list_for_each_safe(pos, next, &send_queue->sndq_lost_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_send_queue_remove_lost(pos); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_send_queue_remove_lost(pos); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } xqc_list_for_each_safe(pos, next, &send_queue->sndq_pto_probe_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_send_queue_remove_probe(pos); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_send_queue_remove_probe(pos); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } @@ -666,37 +696,31 @@ xqc_send_queue_drop_stream_frame_packets(xqc_connection_t *conn, xqc_stream_id_t xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_path_send_buffer_remove(path, packet_out); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_path_send_buffer_remove(path, packet_out); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[XQC_SEND_TYPE_RETRANS]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_path_send_buffer_remove(path, packet_out); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_path_send_buffer_remove(path, packet_out); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[XQC_SEND_TYPE_PTO_PROBE]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (packet_out->po_frame_types == XQC_FRAME_BIT_STREAM) { - drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); - if (drop) { - count++; - xqc_path_send_buffer_remove(path, packet_out); - xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); - } + drop = xqc_send_ctl_stream_frame_can_drop(packet_out, stream_id); + if (drop) { + count++; + xqc_path_send_buffer_remove(path, packet_out); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); } } } @@ -704,4 +728,4 @@ xqc_send_queue_drop_stream_frame_packets(xqc_connection_t *conn, xqc_stream_id_t if (count > 0) { xqc_log(conn->log, XQC_LOG_DEBUG, "|stream_id:%ui|to_drop: %d|count:%d|", stream_id, to_drop, count); } -} \ No newline at end of file +} diff --git a/src/transport/xqc_send_queue.h b/src/transport/xqc_send_queue.h index 596dd1afa..0267dff0e 100644 --- a/src/transport/xqc_send_queue.h +++ b/src/transport/xqc_send_queue.h @@ -7,6 +7,7 @@ #define XQC_SNDQ_PACKETS_USED_MAX 18000 #define XQC_SNDQ_RELEASE_ENOUGH_SPACE_TH 10 /* 1 / 10*/ +#define XQC_SNDQ_MAX_UNACK_PACKETS_LIMIT (100 * 1000) /* limit unack packets to avoid ddos attack */ typedef struct xqc_send_queue_s { @@ -86,7 +87,7 @@ void xqc_send_queue_move_to_head(xqc_list_head_t *pos, xqc_list_head_t *head); void xqc_send_queue_move_to_tail(xqc_list_head_t *pos, xqc_list_head_t *head); void xqc_send_queue_move_to_high_pri(xqc_list_head_t *pos, xqc_send_queue_t *send_queue); -void xqc_send_queue_copy_to_lost(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue); +void xqc_send_queue_copy_to_lost(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue, xqc_bool_t mark_retrans); void xqc_send_queue_copy_to_probe(xqc_packet_out_t *packet_out, xqc_send_queue_t *send_queue, xqc_path_ctx_t *path); diff --git a/src/transport/xqc_stream.c b/src/transport/xqc_stream.c index d2517c594..0477192f2 100644 --- a/src/transport/xqc_stream.c +++ b/src/transport/xqc_stream.c @@ -43,14 +43,8 @@ xqc_stream_ready_to_write(xqc_stream_t *stream) stream->stream_flag |= XQC_STREAM_FLAG_READY_TO_WRITE; } - if (!(stream->stream_conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(stream->stream_conn->engine->conns_active_pq, - stream->stream_conn, stream->stream_conn->last_ticked_time) != 0) { - return; - } - - stream->stream_conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } + xqc_engine_remove_wakeup_queue(stream->stream_conn->engine, stream->stream_conn); + xqc_engine_add_active_queue(stream->stream_conn->engine, stream->stream_conn); } void @@ -74,14 +68,8 @@ xqc_stream_ready_to_read(xqc_stream_t *stream) stream->stream_flag |= XQC_STREAM_FLAG_READY_TO_READ; } - if (!(stream->stream_conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(stream->stream_conn->engine->conns_active_pq, - stream->stream_conn, stream->stream_conn->last_ticked_time) != 0) { - return; - } - - stream->stream_conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } + xqc_engine_remove_wakeup_queue(stream->stream_conn->engine, stream->stream_conn); + xqc_engine_add_active_queue(stream->stream_conn->engine, stream->stream_conn); } void @@ -95,6 +83,40 @@ xqc_stream_shutdown_read(xqc_stream_t *stream) } } +xqc_bool_t +xqc_stream_is_terminal_state(xqc_stream_t *stream) +{ + xqc_bool_t check_send_state, check_recv_state; + xqc_conn_type_t conn_type = stream->stream_conn->conn_type; + + if (stream->stream_type == XQC_CLI_BID || stream->stream_type == XQC_SVR_BID) { + check_send_state = XQC_TRUE; + check_recv_state = XQC_TRUE; + } else if ((stream->stream_type == XQC_CLI_UNI && conn_type == XQC_CONN_TYPE_CLIENT) + || (stream->stream_type == XQC_SVR_UNI && conn_type == XQC_CONN_TYPE_SERVER)) { + /* Uni Stream Send side */ + check_send_state = XQC_TRUE; + check_recv_state = XQC_FALSE; + } else { + /* Uni Stream Recv side */ + check_send_state = XQC_FALSE; + check_recv_state = XQC_TRUE; + } + + if (check_send_state && check_recv_state) { + return (stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD + || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD) + && (stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ + || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ); + } else if (check_send_state) { + return stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD + || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD; + } else { + return stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ + || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ; + } +} + void xqc_stream_maybe_need_close(xqc_stream_t *stream) { @@ -108,8 +130,15 @@ xqc_stream_maybe_need_close(xqc_stream_t *stream) stream->stream_stats.all_data_acked_time = xqc_monotonic_timestamp(); } - if ((stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD) - && (stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ)) + if (stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD + || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD) + { + xqc_stream_record_trans_state(stream, XQC_FALSE); + } + + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(stream->stream_conn, 1)); + + if (xqc_stream_is_terminal_state(stream)) { xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, "|stream_id:%ui|stream_type:%d|", stream->stream_id, stream->stream_type); stream->stream_flag |= XQC_STREAM_FLAG_NEED_CLOSE; @@ -507,7 +536,7 @@ xqc_stream_create(xqc_engine_t *engine, const xqc_cid_t *cid, xqc_stream_setting conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return NULL; } @@ -517,6 +546,8 @@ xqc_stream_create(xqc_engine_t *engine, const xqc_cid_t *cid, xqc_stream_setting return NULL; } + conn->cli_bidi_streams++; + return stream; } @@ -558,7 +589,7 @@ xqc_create_stream_with_conn(xqc_connection_t *conn, xqc_stream_id_t stream_id, if (conn->conn_state >= XQC_CONN_STATE_CLOSING) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn closing, cannot create stream|type:%d|state:%d|flag:%s|", - conn->conn_type, conn->conn_state, xqc_conn_flag_2_str(conn->conn_flag)); + conn->conn_type, conn->conn_state, xqc_conn_flag_2_str(conn, conn->conn_flag)); return NULL; } @@ -644,6 +675,12 @@ xqc_create_stream_with_conn(xqc_connection_t *conn, xqc_stream_id_t stream_id, return NULL; } +void +xqc_stream_set_priority(xqc_stream_t *stream, xqc_stream_priority_t priority) +{ + stream->stream_priority = priority; +} + void xqc_stream_set_user_data(xqc_stream_t *stream, void *user_data) { @@ -668,12 +705,85 @@ xqc_stream_id(xqc_stream_t *stream) return stream->stream_id; } +xqc_usec_t +xqc_update_avg_time(xqc_usec_t new_time, xqc_usec_t ori_time, xqc_int_t ori_time_num) +{ + return (xqc_usec_t)(1.0 * new_time / (ori_time_num + 1) + 1.0 * ori_time / (ori_time_num + 1) * ori_time_num); +} + +xqc_bool_t +xqc_is_stream_finished(xqc_stream_t *stream) +{ + xqc_bool_t check_send_state, check_recv_state; + xqc_conn_type_t conn_type = stream->stream_conn->conn_type; + + if (stream->stream_type == XQC_CLI_BID || stream->stream_type == XQC_SVR_BID) { + check_send_state = XQC_TRUE; + check_recv_state = XQC_TRUE; + } else if ((stream->stream_type == XQC_CLI_UNI && conn_type == XQC_CONN_TYPE_CLIENT) + || (stream->stream_type == XQC_SVR_UNI && conn_type == XQC_CONN_TYPE_SERVER)) { + /* Uni Stream Send side */ + check_send_state = XQC_TRUE; + check_recv_state = XQC_FALSE; + } else { + /* Uni Stream Recv side */ + check_send_state = XQC_FALSE; + check_recv_state = XQC_TRUE; + } + + if (check_send_state && check_recv_state) { + return (stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD) + && (stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ); + } else if (check_send_state) { + return stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD; + } else { + return stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ; + } +} + void xqc_destroy_stream(xqc_stream_t *stream) { + xqc_int_t finished_streams, enable_stream_num, video_frames; + xqc_usec_t curr_recv_delay, curr_fec_recv_opt; + +#define __calc_delay(a, b) ((a && b && (a > b))? (a) - (b) : 0) + xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, "|send_state:%d|recv_state:%d|stream_id:%ui|stream_type:%d|", stream->stream_state_send, stream->stream_state_recv, stream->stream_id, stream->stream_type); + if (xqc_is_stream_finished(stream)) { + if(stream->stream_conn) { + finished_streams = stream->stream_conn->finished_streams++; + if (stream->stream_fec_ctl.is_video_frame) { + video_frames = stream->stream_conn->conn_video_frames++; + xqc_usec_t curr_close_delay; + curr_close_delay = __calc_delay(stream->stream_stats.close_time, stream->stream_stats.create_time); + curr_recv_delay = __calc_delay(stream->stream_stats.stream_recv_time, stream->stream_stats.create_time); + stream->stream_conn->conn_avg_close_delay = xqc_update_avg_time(curr_close_delay, stream->stream_conn->conn_avg_close_delay, video_frames); + stream->stream_conn->conn_latest_close_delay = curr_close_delay; + stream->stream_conn->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->conn_avg_recv_delay, video_frames); + if (stream->stream_conn->fec_ctl) { + if (stream->stream_fec_ctl.enable_fec + || stream->stream_stats.recov_pkt_cnt > 0) + { + enable_stream_num = stream->stream_conn->fec_ctl->fec_enable_stream_num++; + curr_recv_delay = __calc_delay(stream->stream_stats.recv_time_with_fec, stream->stream_stats.create_time); + curr_fec_recv_opt = __calc_delay(stream->stream_stats.final_packet_time, stream->stream_stats.recv_time_with_fec); + stream->stream_conn->fec_ctl->conn_avg_recv_delay = xqc_update_avg_time(curr_recv_delay, stream->stream_conn->fec_ctl->conn_avg_recv_delay, enable_stream_num); + stream->stream_conn->fec_ctl->fec_avg_opt_time = xqc_update_avg_time(curr_fec_recv_opt, stream->stream_conn->fec_ctl->fec_avg_opt_time, enable_stream_num); + } + } + } + } + } + + xqc_stream_record_trans_state(stream, XQC_FALSE); + + if (stream->stream_stats.retrans_pkt_cnt > stream->stream_stats.fec_send_rpr_cnt) { + stream->stream_conn->burst_loss_cnt += 1; + } + if (stream->stream_if->stream_close_notify && !(stream->stream_flag & XQC_STREAM_FLAG_DISCARDED)) { @@ -704,8 +814,6 @@ xqc_destroy_stream(xqc_stream_t *stream) stream->stream_flag |= XQC_STREAM_FLAG_CLOSED; -#define __calc_delay(a, b) (a? (a) - (b) : 0) - char path_info_buff[200 * XQC_MAX_PATHS_COUNT] = {'\0'}; xqc_stream_path_metrics_print(stream->stream_conn, stream, path_info_buff, 50 * XQC_MAX_PATHS_COUNT); @@ -718,8 +826,8 @@ xqc_destroy_stream(xqc_stream_t *stream) "finrcv_delay:%ui|finread_delay:%ui|all_acked_delay:%ui|" "firstfinack_dely:%ui|close_delay:%ui|" "apprst_delay:%ui|rstsnd_delay:%ui|rstrcv_delay:%ui|%s|" - "path_info:%s|", - stream->stream_err, stream->stream_close_msg ? : "", + "path_info:%s|fec_recv_delay:%"PRIu64"|fec_send_rpr_cnt:%d|retrans:%d|", + stream->stream_err, stream->stream_close_msg ? stream->stream_close_msg : "", stream->stream_conn->enable_multipath ? 1:0, stream->stream_state_send, stream->stream_state_recv, stream->stream_id, stream->stream_type, @@ -741,12 +849,30 @@ xqc_destroy_stream(xqc_stream_t *stream) __calc_delay(stream->stream_stats.local_reset_time, stream->stream_stats.create_time), __calc_delay(stream->stream_stats.peer_reset_time, stream->stream_stats.create_time), xqc_conn_addr_str(stream->stream_conn), - path_info_buff); + path_info_buff, + (stream->stream_stats.recv_time_with_fec == 0 || (stream->stream_stats.final_packet_time < stream->stream_stats.recv_time_with_fec)) ? 0 : (stream->stream_stats.final_packet_time - stream->stream_stats.recv_time_with_fec), + stream->stream_stats.fec_send_rpr_cnt, + stream->stream_stats.retrans_pkt_cnt + ); #undef __calc_delay xqc_free(stream); } +void +xqc_stream_record_trans_state(xqc_stream_t *stream, xqc_bool_t begin) +{ + xqc_connection_t *conn = stream->stream_conn; + + if (begin && stream->begin_trans_state[0] == 0) { + xqc_conn_encode_transport_state(conn, stream->begin_trans_state, XQC_STREAM_TRANSPORT_STATE_SZ); + } + + if (!begin && stream->end_trans_state[0] == 0) { + xqc_conn_encode_transport_state(conn, stream->end_trans_state, XQC_STREAM_TRANSPORT_STATE_SZ); + } +} + xqc_int_t xqc_stream_close(xqc_stream_t *stream) { @@ -783,13 +909,13 @@ xqc_stream_close(xqc_stream_t *stream) } } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); + + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); + xqc_stream_shutdown_write(stream); - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); return XQC_OK; } @@ -839,6 +965,16 @@ xqc_passive_create_stream(xqc_connection_t *conn, xqc_stream_id_t stream_id, voi return NULL; } + xqc_stream_type_t stream_type; + stream_type = xqc_get_stream_type(stream_id); + + if (stream_type == XQC_CLI_BID) { + conn->cli_bidi_streams++; + + } else if (stream_type == XQC_SVR_BID) { + conn->svr_bidi_streams++; + } + return stream; } @@ -888,6 +1024,8 @@ xqc_read_crypto_stream(xqc_stream_t *stream) xqc_stream_frame_t *stream_frame = NULL; xqc_connection_t *conn = stream->stream_conn; + xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_read_crypto_stream|level:%d|", stream->stream_encrypt_level); + xqc_list_head_t *pos, *next; xqc_list_for_each_safe(pos, next, &stream->stream_data_in.frames_tailq) { stream_frame = xqc_list_entry(pos, xqc_stream_frame_t, sf_list); @@ -934,6 +1072,7 @@ xqc_crypto_stream_on_read(xqc_stream_t *stream, void *user_data) if (encrypt_level == XQC_ENC_LEV_INIT) { switch (cur_state) { case XQC_CONN_STATE_CLIENT_INITIAL_SENT: + xqc_stream_ready_to_write(stream); next_state = XQC_CONN_STATE_CLIENT_INITIAL_RECVD; break; case XQC_CONN_STATE_SERVER_INIT: @@ -984,8 +1123,8 @@ xqc_crypto_stream_on_read(xqc_stream_t *stream, void *user_data) encrypt_level); return -XQC_ELEVEL; } - conn->conn_state = next_state; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); int ret = xqc_conn_check_handshake_complete(conn); if (ret < 0) { return ret; @@ -1047,7 +1186,7 @@ xqc_crypto_stream_send(xqc_stream_t *stream, "|crypto send data|pkt_num:%ui|size:%ud|sent:%d|pkt_type:%s|frame:%s|now:%ui|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, n_written, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(stream->stream_conn->engine, packet_out->po_frame_types), now); xqc_send_queue_move_to_high_pri(&packet_out->po_list, stream->stream_conn->conn_send_queue); } @@ -1076,18 +1215,34 @@ xqc_crypto_stream_on_write(xqc_stream_t *stream, void *user_data) xqc_connection_t *conn = stream->stream_conn; xqc_list_head_t *crypto_data_list = NULL; + xqc_log(conn->log, XQC_LOG_DEBUG, "|enc_level|%d|", encrypt_level); + if (encrypt_level == XQC_ENC_LEV_INIT) { pns = XQC_PNS_INIT; pkt_type = XQC_PTYPE_INIT; switch (cur_state) { case XQC_CONN_STATE_CLIENT_INIT: + crypto_data_list = &conn->initial_crypto_data_list; next_state = XQC_CONN_STATE_CLIENT_INITIAL_SENT; break; + + case XQC_CONN_STATE_CLIENT_INITIAL_RECVD: + crypto_data_list = &conn->initial_crypto_data_list; + next_state = XQC_CONN_STATE_CLIENT_INITIAL_RECVD; + break; case XQC_CONN_STATE_SERVER_INIT: case XQC_CONN_STATE_SERVER_INITIAL_RECVD: + + xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, "|cur_state:%d|switch|", cur_state); + + /* haven't recved enough data for client hello */ + if (conn->conn_type == XQC_CONN_TYPE_SERVER && !(conn->conn_flag & XQC_CONN_FLAG_TLS_CH_RECVD)) { + return XQC_OK; + } + crypto_data_list = &conn->initial_crypto_data_list; if (conn->crypto_stream[XQC_ENC_LEV_HSK] != NULL) { xqc_stream_ready_to_write(conn->crypto_stream[XQC_ENC_LEV_HSK]); @@ -1155,7 +1310,8 @@ xqc_crypto_stream_on_write(xqc_stream_t *stream, void *user_data) xqc_stream_shutdown_write(stream); conn->conn_state = next_state; - + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); + ret = xqc_conn_check_handshake_complete(conn); if (ret < 0) { return ret; @@ -1298,11 +1454,8 @@ xqc_stream_recv(xqc_stream_t *stream, unsigned char *recv_buf, size_t recv_buf_s stream->stream_conn->conn_flow_ctl.fc_data_read += read; - xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, - "|stream_id:%ui|read:%z|recv_buf_size:%uz|fin:%d|stream_length:%ui|next_read_offset:%ui|conn:%p|", - stream->stream_id, read, recv_buf_size, *fin, stream->stream_data_in.stream_length, - stream->stream_data_in.next_read_offset, stream->stream_conn); - + xqc_log_event(stream->stream_conn->log, TRA_STREAM_DATA_MOVED, stream, 1, read, + recv_buf_size, *fin, 0, 0, 0, 0); xqc_stream_shutdown_read(stream); int ret = xqc_stream_do_recv_flow_ctl(stream); @@ -1314,7 +1467,6 @@ xqc_stream_recv(xqc_stream_t *stream, unsigned char *recv_buf, size_t recv_buf_s return (read == 0 && *fin == 0) ? -XQC_EAGAIN : read; } - ssize_t xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data_size, uint8_t fin) { @@ -1347,9 +1499,8 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data if (!(conn->conn_flag & XQC_CONN_FLAG_CAN_SEND_1RTT)) { - if ((conn->conn_type == XQC_CONN_TYPE_CLIENT) - && (conn->conn_state == XQC_CONN_STATE_CLIENT_INITIAL_SENT) - && support_0rtt) + if ((conn->conn_type == XQC_CONN_TYPE_CLIENT) && support_0rtt + && xqc_conn_is_ready_to_send_early_data(conn)) { pkt_type = XQC_PTYPE_0RTT; conn->conn_flag |= XQC_CONN_FLAG_HAS_0RTT; @@ -1361,7 +1512,6 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data goto do_buff; } } - while (offset < send_data_size || fin_only) { if (pkt_type == XQC_PTYPE_SHORT_HEADER) { @@ -1411,6 +1561,17 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data xqc_stream_shutdown_write(stream); +#ifdef XQC_ENABLE_FEC + + // FEC encode process on stream level + if (conn->conn_settings.fec_level == XQC_FEC_STREAM_LEVEL + && stream->stream_fec_ctl.enable_fec + && conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE + && stream->stream_fec_ctl.stream_fec_syb_num > 0) + { + ret = xqc_process_fec_protected_packet_moq(stream); + } +#endif do_buff: /* 0RTT failure requires fallback to 1RTT, save the original send data */ if (pkt_type == XQC_PTYPE_0RTT) { @@ -1434,17 +1595,21 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data "send_data_size:%uz|offset:%uz|fin:%d|stream_flag:%d|conn:%p|conn_state:%s|flag:%s|", ret, stream->stream_id, stream->stream_send_offset, xqc_pkt_type_2_str(pkt_type), buff_1rtt, send_data_size, offset, fin, stream->stream_flag, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); + xqc_log_event(conn->log, TRA_STREAM_DATA_MOVED, stream, 0, send_data_size, 0, fin, ret, pkt_type, + buff_1rtt, offset); - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); + + xqc_stream_record_trans_state(stream, XQC_TRUE); + + /* update max_pto stats */ + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); /* application layer call the main logic */ if (!(stream->stream_flag & XQC_STREAM_FLAG_HAS_H3)) { - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } if (offset == 0 && !fin_only_done) { diff --git a/src/transport/xqc_stream.h b/src/transport/xqc_stream.h index e68de280e..245bae956 100644 --- a/src/transport/xqc_stream.h +++ b/src/transport/xqc_stream.h @@ -11,6 +11,7 @@ #include "src/transport/xqc_packet.h" #define XQC_UNDEFINE_STREAM_ID XQC_MAX_UINT64_VALUE +#define XQC_STREAM_TRANSPORT_STATE_SZ 128 #define XQC_STREAM_CLOSE_MSG(stream, msg) do { \ if ((stream)->stream_close_msg == NULL) { \ @@ -40,23 +41,29 @@ typedef enum { } xqc_stream_flag_t; typedef enum { - XQC_SEND_STREAM_ST_READY, - XQC_SEND_STREAM_ST_SEND, - XQC_SEND_STREAM_ST_DATA_SENT, - XQC_SEND_STREAM_ST_DATA_RECVD, - XQC_SEND_STREAM_ST_RESET_SENT, - XQC_SEND_STREAM_ST_RESET_RECVD, + XQC_SEND_STREAM_ST_READY = 0, + XQC_SEND_STREAM_ST_SEND = 1, + XQC_SEND_STREAM_ST_DATA_SENT = 2, + XQC_SEND_STREAM_ST_DATA_RECVD = 3, + XQC_SEND_STREAM_ST_RESET_SENT = 4, + XQC_SEND_STREAM_ST_RESET_RECVD = 5, } xqc_send_stream_state_t; typedef enum { - XQC_RECV_STREAM_ST_RECV, - XQC_RECV_STREAM_ST_SIZE_KNOWN, - XQC_RECV_STREAM_ST_DATA_RECVD, - XQC_RECV_STREAM_ST_DATA_READ, - XQC_RECV_STREAM_ST_RESET_RECVD, - XQC_RECV_STREAM_ST_RESET_READ, + XQC_RECV_STREAM_ST_RECV = 0, + XQC_RECV_STREAM_ST_SIZE_KNOWN = 1, + XQC_RECV_STREAM_ST_DATA_RECVD = 2, + XQC_RECV_STREAM_ST_DATA_READ = 3, + XQC_RECV_STREAM_ST_RESET_RECVD = 4, + XQC_RECV_STREAM_ST_RESET_READ = 5, } xqc_recv_stream_state_t; +typedef enum { + XQC_STREAM_PRI_DEFAULT = 0, + XQC_STREAM_PRI_HIGH = 1, + XQC_STREAM_PRI_NORMAL = 2, +} xqc_stream_priority_t; + typedef struct { uint64_t fc_max_stream_data_can_send; uint64_t fc_max_stream_data_can_recv; @@ -136,6 +143,7 @@ struct xqc_stream_s { xqc_usec_t peer_fin_read_time; /* app read fin */ xqc_usec_t local_fin_write_time; /* app send fin */ xqc_usec_t local_fin_snd_time; /* socket send fin */ + xqc_usec_t local_fst_fin_snd_time; xqc_usec_t first_write_time; /* app send data */ xqc_usec_t first_snd_time; /* socket send data */ xqc_usec_t first_fin_ack_time; @@ -144,13 +152,52 @@ struct xqc_stream_s { xqc_usec_t app_reset_time; /* app snd reset */ xqc_usec_t local_reset_time; /* socket snd reset */ xqc_usec_t peer_reset_time; /* quic stack rcv reset */ + xqc_usec_t first_rcv_time; /* recv the first udp packet */ + uint32_t sched_cwnd_blk_cnt; + uint32_t send_cwnd_blk_cnt; + uint32_t send_pacing_blk_cnt; + xqc_usec_t sched_cwnd_blk_duration; + xqc_usec_t send_cwnd_blk_duration; + xqc_usec_t send_pacing_blk_duration; + uint32_t retrans_pkt_cnt; + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + uint32_t recov_pkt_cnt; + xqc_usec_t fst_rpr_time; + xqc_usec_t last_rpr_time; + xqc_int_t fec_blk_lack_num; /* number of lack source symbol when receive last repair symbol */ + xqc_usec_t fec_blk_lack_time; /* (first block) block finish time - last received rpr (in block) time */ + xqc_usec_t recv_time_with_fec; /* stream received time with fec recovered packets */ + xqc_usec_t final_packet_time; /* final arrived packets of current stream */ + xqc_usec_t stream_recv_time; /* stream received time */ + uint32_t fec_send_rpr_cnt; /* FEC repair packets sent on current stream */ } stream_stats; xqc_path_metrics_t paths_info[XQC_MAX_PATHS_COUNT]; uint8_t stream_mp_usage_schedule; uint8_t stream_mp_usage_reinject; + uint8_t stream_fec_blk_mode; uint64_t recv_rate_bytes_per_sec; + + char begin_trans_state[XQC_STREAM_TRANSPORT_STATE_SZ]; + char end_trans_state[XQC_STREAM_TRANSPORT_STATE_SZ]; + + xqc_stream_priority_t stream_priority; + struct { + xqc_flag_t enable_fec; + + /** current fec code rate */ + float fec_code_rate; + /** symbol number in current stream */ + xqc_int_t stream_fec_syb_num; + + xqc_list_head_t *stream_fec_head; + xqc_list_head_t *stream_fec_tail; + + uint16_t is_video_frame; + + } stream_fec_ctl; }; static inline xqc_stream_type_t @@ -171,9 +218,13 @@ xqc_stream_is_uni(xqc_stream_id_t stream_id) return stream_id & 0x02; } +void xqc_stream_set_priority(xqc_stream_t *stream, xqc_stream_priority_t priority); + xqc_stream_t *xqc_create_stream_with_conn (xqc_connection_t *conn, xqc_stream_id_t stream_id, xqc_stream_type_t stream_type, xqc_stream_settings_t *settings, void *user_data); +void xqc_stream_record_trans_state(xqc_stream_t *stream, xqc_bool_t begin); + void xqc_destroy_stream(xqc_stream_t *stream); void xqc_process_write_streams(xqc_connection_t *conn); @@ -192,6 +243,8 @@ void xqc_stream_ready_to_read(xqc_stream_t *stream); void xqc_stream_shutdown_read(xqc_stream_t *stream); +xqc_bool_t xqc_stream_is_terminal_state(xqc_stream_t *stream); + void xqc_stream_maybe_need_close(xqc_stream_t *stream); xqc_stream_t *xqc_find_stream_by_id(xqc_stream_id_t stream_id, xqc_id_hash_table_t *streams_hash); diff --git a/src/transport/xqc_timer.c b/src/transport/xqc_timer.c index cc4e66e1d..129dc6742 100644 --- a/src/transport/xqc_timer.c +++ b/src/transport/xqc_timer.c @@ -28,6 +28,7 @@ static const char * const timer_type_2_str[XQC_TIMER_N] = { [XQC_TIMER_LINGER_CLOSE] = "LINGER_CLOSE", [XQC_TIMER_KEY_UPDATE] = "KEY_UPDATE", [XQC_TIMER_PMTUD_PROBING] = "PMTUD_PROBING", + [XQC_TIMER_QUEUE_FIN] = "CONN_QUEUE_FINISH" }; const char * @@ -44,7 +45,8 @@ xqc_timer_ack_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_data) xqc_connection_t *conn = send_ctl->ctl_conn; xqc_pkt_num_space_t pns = type - XQC_TIMER_ACK_INIT; - conn->conn_flag |= XQC_CONN_FLAG_SHOULD_ACK_INIT << pns; + send_ctl->ctl_path->path_flag |= XQC_PATH_FLAG_SHOULD_ACK_INIT << pns; + conn->ack_flag |= (1 << (pns + send_ctl->ctl_path->path_id * XQC_PNS_N)); xqc_log(conn->log, XQC_LOG_DEBUG, "|pns:%d|path:%ui|", pns, send_ctl->ctl_path->path_id); } @@ -102,6 +104,7 @@ xqc_timer_loss_detection_timeout(xqc_timer_type_t type, xqc_usec_t now, void *us } send_ctl->ctl_pto_count++; + conn->max_pto_cnt = xqc_max(send_ctl->ctl_pto_count, conn->max_pto_cnt); xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_send_ctl_set_loss_detection_timer|PTO|conn:%p|pto_count:%ud", conn, send_ctl->ctl_pto_count); xqc_send_ctl_set_loss_detection_timer(send_ctl); @@ -226,6 +229,37 @@ xqc_timer_ping_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_data) } } +void +xqc_timer_fec_conn_queue_rpr_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_data) +{ + uint8_t fec_bm_mode; + xqc_int_t ret; + xqc_usec_t cq_fin_timeout; + xqc_list_head_t *head; + xqc_connection_t *conn = (xqc_connection_t *)user_data; + xqc_fec_schemes_e encoder_scheme; + +#if defined(XQC_ENABLE_FEC) && defined(XQC_ENABLE_PKM) + encoder_scheme = conn->conn_settings.fec_params.fec_encoder_scheme; + head = &conn->conn_send_queue->sndq_send_packets; + /* if connection sendq has no fec protected packet, try to send repair packets in ahead */ + if (conn->conn_settings.enable_encode_fec + && encoder_scheme == XQC_PACKET_MASK_CODE) + { + for (fec_bm_mode = 0; fec_bm_mode < XQC_BLOCK_MODE_LEN; fec_bm_mode++) { + if (fec_bm_mode == XQC_SLIM_SIZE_REQ) { + continue; + } + ret = xqc_send_repair_packets_ahead(conn, head, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_send_repair_packets_ahead error: %d|", ret); + } + } + xqc_log(conn->log, XQC_LOG_DEBUG, "|send repair packets ahead finished"); + } +#endif +} + void xqc_timer_retire_cid_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_data) { @@ -238,48 +272,44 @@ xqc_timer_retire_cid_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_d xqc_usec_t next_time = XQC_MAX_UINT64_VALUE; xqc_usec_t interval = 0; - xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set.list_head) { - inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - - if (inner_cid->state == XQC_CID_RETIRED) { - - if (inner_cid->retired_ts < now) { - /* MP关闭主路后如果删除对应的cid映射,对外接口通过engine和cid无法找到conn,暂时注释掉 */ - /* TODO: 1. MP切换主路后通知上层更换cid; 2. 重新设计接口,改用conn而不是engine和cid */ - // /* switch state to REMOVED & delete from cid_set */ - // if (xqc_find_conns_hash(conn->engine->conns_hash, conn, - // inner_cid->cid.cid_buf, inner_cid->cid.cid_len)) - // { - // xqc_remove_conns_hash(conn->engine->conns_hash, conn, - // inner_cid->cid.cid_buf, inner_cid->cid.cid_len); - // } - - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, inner_cid, XQC_CID_REMOVED); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|"); - return; - } - - xqc_log(conn->log, XQC_LOG_DEBUG, - "|retired->removed|cid:%s|seq:%ui|len:%d|", - xqc_scid_str(&inner_cid->cid), - inner_cid->cid.cid_seq_num, - inner_cid->cid.cid_len); - - // xqc_list_del(pos); - // xqc_free(inner_cid); - - } else { - /* record the earliest time that has not yet expired */ - if (inner_cid->retired_ts < next_time) { - next_time = inner_cid->retired_ts; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; + uint32_t to_be_retired_cnt = 0; + + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + + if (inner_cid->state == XQC_CID_RETIRED) { + + if (inner_cid->retired_ts < now) { + /* CID related resources will be released when the connection is destroyed */ + ret = xqc_cid_switch_to_next_state(&conn->scid_set, inner_cid, XQC_CID_REMOVED, inner_cid->cid.path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|"); + continue; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|retired->removed|cid:%s|seq:%ui|len:%d|", + xqc_scid_str(conn->engine, &inner_cid->cid), + inner_cid->cid.cid_seq_num, + inner_cid->cid.cid_len); + + } else { + /* record the earliest time that has not yet expired */ + if (inner_cid->retired_ts < next_time) { + next_time = inner_cid->retired_ts; + } + to_be_retired_cnt++; } - } } } - if (conn->scid_set.cid_set.retired_cnt > 0) { + if (to_be_retired_cnt > 0) { if (next_time == XQC_MAX_UINT64_VALUE) { xqc_log(conn->log, XQC_LOG_ERROR, "|next_time is not assigned a value|"); return; @@ -385,6 +415,9 @@ xqc_timer_init(xqc_timer_manager_t *manager, xqc_log_t *log, void *user_data) } else if (type == XQC_TIMER_PMTUD_PROBING) { timer->timeout_cb = xqc_timer_pmtud_probing_timeout; timer->user_data = user_data; + } else if (type == XQC_TIMER_QUEUE_FIN) { + timer->timeout_cb = xqc_timer_fec_conn_queue_rpr_timeout; + timer->user_data = user_data; } } diff --git a/src/transport/xqc_timer.h b/src/transport/xqc_timer.h index f2604c02a..fc2a473c9 100644 --- a/src/transport/xqc_timer.h +++ b/src/transport/xqc_timer.h @@ -17,7 +17,7 @@ */ #define XQC_PING_TIMEOUT 15000 -#define XQC_PMTUD_START_DELAY 10000 +#define XQC_PMTUD_START_DELAY 5000 typedef enum xqc_timer_level { XQC_PATH_LEVEL_TIMER, @@ -46,6 +46,7 @@ typedef enum xqc_timer_type { XQC_TIMER_LINGER_CLOSE, XQC_TIMER_KEY_UPDATE, XQC_TIMER_PMTUD_PROBING, + XQC_TIMER_QUEUE_FIN, XQC_TIMER_N, diff --git a/src/transport/xqc_transport_params.c b/src/transport/xqc_transport_params.c index 312e4ace7..20f955c39 100644 --- a/src/transport/xqc_transport_params.c +++ b/src/transport/xqc_transport_params.c @@ -7,6 +7,7 @@ #include "src/common/xqc_str.h" #include "src/transport/xqc_defs.h" #include "src/transport/xqc_cid.h" +#include "src/transport/xqc_fec.h" #include #include #include @@ -20,6 +21,10 @@ /* ack_delay_exponent above 20 is invalid */ #define XQC_MAX_ACK_DELAY_EXPONENT 20 +/* draft-smith-quic-receive-ts-01: receive_timestamps_exponent above 20 is invalid */ +#define XQC_MAX_RECEIVE_TIMESTAMPS_EXPONENT 20 +#define XQC_MAX_RECEIVE_TIMESTAMPS_PER_ACK 63 + static inline uint16_t xqc_get_uint16(const uint8_t *p) { @@ -34,7 +39,7 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, xqc_transport_params_type_t exttype) { size_t len = 0; - size_t preferred_addrlen = 0; + size_t preferred_addrlen = 0, preferred_fec_paramslen = 0; if (params->original_dest_connection_id_present) { len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ORIGINAL_DEST_CONNECTION_ID) + @@ -157,20 +162,80 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, } if (params->enable_multipath) { - if (params->multipath_version == XQC_MULTIPATH_06) { - /* enable_multipath (-draft06) is zero-length transport parameter */ - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06) + - xqc_put_varint_len(0); - - } else if (params->multipath_version == XQC_MULTIPATH_05) { - /* enable_multipath (-draft05) is zero-length transport parameter */ - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05) + - xqc_put_varint_len(0); - - } else { - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04) + - xqc_put_varint_len(xqc_put_varint_len(params->enable_multipath)) + - xqc_put_varint_len(params->enable_multipath); + if (params->multipath_version == XQC_MULTIPATH_10) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10) + + xqc_put_varint_len(xqc_put_varint_len(params->init_max_path_id)) + + xqc_put_varint_len(params->init_max_path_id); + + } + } + + if (params->enable_pmtud > 0) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_PMTUD_OPTIONS) + + xqc_put_varint_len(xqc_put_varint_len(params->enable_pmtud)) + + xqc_put_varint_len(params->enable_pmtud); + } + + if (params->close_dgram_redundancy == XQC_RED_SET_CLOSE) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY) + + xqc_put_varint_len(xqc_put_varint_len(params->close_dgram_redundancy)) + + xqc_put_varint_len(params->close_dgram_redundancy); + } + +#ifdef XQC_ENABLE_FEC + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_VERSION_02) + + xqc_put_varint_len(0); + + /* + * if enable_encode_fec, add fec related params' length: + * max_symbol_size; max_src_symbol_len; max_encoder_schemes; + */ + if (params->enable_encode_fec + && params->fec_encoder_schemes_num > 0 + && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes_num); + + for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes[i]); + } + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES) + + xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM) + + xqc_put_varint_len(xqc_put_varint_len(params->fec_max_symbols_num)) + + xqc_put_varint_len(params->fec_max_symbols_num); + } + /* + * if enable_decode_fec, add fec related params' length: + * max_decoder_schemes; + */ + if (params->enable_decode_fec + && params->fec_decoder_schemes_num > 0 + && params->fec_decoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes[i]); + } + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES) + + xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; + } +#endif + + if (params->extended_ack_features) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_EXTENDED_ACK_FEATURES) + + xqc_put_varint_len(xqc_put_varint_len(params->extended_ack_features)) + + xqc_put_varint_len(params->extended_ack_features); + if (params->max_receive_timestamps_per_ack) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_MAX_RECEIVE_TIMESTAMPS_PER_ACK) + + xqc_put_varint_len(xqc_put_varint_len(params->max_receive_timestamps_per_ack)) + + xqc_put_varint_len(params->max_receive_timestamps_per_ack); + } + if (params->receive_timestamps_exponent) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_RECEIVE_TIMESTAMPS_EXPONENT) + + xqc_put_varint_len(xqc_put_varint_len(params->receive_timestamps_exponent)) + + xqc_put_varint_len(params->receive_timestamps_exponent); } } @@ -180,6 +245,12 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, xqc_put_varint_len(params->max_datagram_frame_size); } + if (params->conn_option_num) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_GOOGLE_CO) + + xqc_put_varint_len(params->conn_option_num * sizeof(uint32_t)) + + params->conn_option_num * sizeof(uint32_t); + } + return len; } @@ -214,7 +285,8 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, { uint8_t *p = out; size_t len = 0; - size_t preferred_addrlen = 0; + size_t preferred_addrlen = 0, preferred_fec_paramslen = 0; + int i; /* calculate encoding length */ len += xqc_transport_params_calc_length(params, exttype); @@ -344,14 +416,84 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, } if (params->enable_multipath) { - if (params->multipath_version == XQC_MULTIPATH_06) { - p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06); + if (params->multipath_version == XQC_MULTIPATH_10) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10, params->init_max_path_id); + + } + } + + if (params->enable_pmtud) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_PMTUD_OPTIONS, params->enable_pmtud); + } + + if (params->close_dgram_redundancy == XQC_RED_SET_CLOSE) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY, + params->close_dgram_redundancy); + } - } else if (params->multipath_version == XQC_MULTIPATH_05) { - p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05); - } else { - p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04, params->enable_multipath); + if (params->conn_option_num) { + p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_GOOGLE_CO); + p = xqc_put_varint(p, sizeof(uint32_t) * params->conn_option_num); + for (i = 0; i < params->conn_option_num; i++) { + p = xqc_put_uint32be(p, params->conn_options[i]); + } + } + +#ifdef XQC_ENABLE_FEC + p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_FEC_VERSION_02); + + if (params->enable_encode_fec + && params->fec_encoder_schemes_num > 0 + && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES); + preferred_fec_paramslen = xqc_put_varint_len(params->fec_encoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes[i]); + } + p = xqc_put_varint(p, preferred_fec_paramslen); + + p = xqc_put_varint(p, params->fec_encoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { + p = xqc_put_varint(p, params->fec_encoder_schemes[i]); + } + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM, + params->fec_max_symbols_num); + } + + if (params->enable_decode_fec + && params->fec_decoder_schemes_num > 0 + && params->fec_decoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + if (params->fec_decoder_schemes_num > 0 && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) { + p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES); + preferred_fec_paramslen = xqc_put_varint_len(params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes[i]); + } + p = xqc_put_varint(p, preferred_fec_paramslen); + + p = xqc_put_varint(p, params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + p = xqc_put_varint(p, params->fec_decoder_schemes[i]); + } + } + } +#endif + + if (params->extended_ack_features) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_EXTENDED_ACK_FEATURES, + params->extended_ack_features); + if (params->max_receive_timestamps_per_ack) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_MAX_RECEIVE_TIMESTAMPS_PER_ACK, + params->max_receive_timestamps_per_ack); + } + if (params->receive_timestamps_exponent) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_RECEIVE_TIMESTAMPS_EXPONENT, + params->receive_timestamps_exponent); } } @@ -595,22 +737,157 @@ static xqc_int_t xqc_decode_enable_multipath(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) { - if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06) { - /* enable_multipath param is a zero-length value, presentation means enable */ - params->enable_multipath = 1; - params->multipath_version = XQC_MULTIPATH_06; - return XQC_OK; - } else if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05) { - /* enable_multipath param is a zero-length value, presentation means enable */ + if (param_type == XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10) { params->enable_multipath = 1; - params->multipath_version = XQC_MULTIPATH_05; + params->multipath_version = XQC_MULTIPATH_10; + XQC_DECODE_VINT_VALUE(¶ms->init_max_path_id, p, end); return XQC_OK; - } else if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04) { - if (params->multipath_version > XQC_MULTIPATH_04) { - return XQC_OK; + } + return XQC_OK; +} + +static xqc_int_t +xqc_decode_enable_pmtud(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + XQC_DECODE_VINT_VALUE(¶ms->enable_pmtud, p, end); +} + +static xqc_int_t +xqc_decode_close_dgram_redundancy(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + uint64_t ret = 0; + ssize_t nread = xqc_vint_read(p, end, &ret); + + switch (ret) { + case XQC_RED_SET_CLOSE: + params->close_dgram_redundancy = XQC_RED_SET_CLOSE; + break; + + default: + params->close_dgram_redundancy = XQC_RED_NOT_USE; + break; + } + return XQC_OK; +} + +#ifdef XQC_ENABLE_FEC +static xqc_int_t +xqc_decode_fec_version(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + switch (param_type) { + case XQC_TRANSPORT_PARAM_FEC_VERSION_02: + params->fec_version = XQC_FEC_02; + break; + + default: + params->fec_version = XQC_ERR_FEC_VERSION; + break; + } + + return XQC_OK; +} + + +static xqc_int_t +xqc_decode_fec_max_symbols_num(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + XQC_DECODE_VINT_VALUE(¶ms->fec_max_symbols_num, p, end); +} + +static xqc_int_t +xqc_decode_encoder_schemes(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + int vlen; + uint64_t schemes_len, curr_scheme; + xqc_int_t i, tmp_len; + + tmp_len = 0; + schemes_len = curr_scheme = 0; + vlen = xqc_vint_read(p, end, &schemes_len); + + if (schemes_len < 0 || schemes_len > XQC_FEC_MAX_SCHEME_NUM) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; + } + + params->fec_encoder_schemes_num = schemes_len; + p += vlen; + + for (i = 0; i < schemes_len; i++) { + vlen = xqc_vint_read(p, end, &curr_scheme); + if (xqc_set_fec_scheme(curr_scheme, ¶ms->fec_encoder_schemes[tmp_len]) == XQC_OK) { + tmp_len++; } - params->multipath_version = XQC_MULTIPATH_04; - XQC_DECODE_VINT_VALUE(¶ms->enable_multipath, p, end); + p += vlen; + } + + params->enable_encode_fec = 1; + params->fec_encoder_schemes_num = tmp_len; + return XQC_OK; +} + +static xqc_int_t +xqc_decode_decoder_schemes(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + int vlen; + uint64_t schemes_len, curr_scheme; + xqc_int_t i, tmp_len; + + tmp_len = 0; + schemes_len = curr_scheme = 0; + vlen = xqc_vint_read(p, end, &schemes_len); + + if (schemes_len < 0 || schemes_len > XQC_FEC_MAX_SCHEME_NUM) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; + } + + params->fec_decoder_schemes_num = schemes_len; + p += vlen; + + for (i = 0; i < schemes_len; i++) { + vlen = xqc_vint_read(p, end, &curr_scheme); + if (xqc_set_fec_scheme(curr_scheme, ¶ms->fec_decoder_schemes[tmp_len]) == XQC_OK) { + tmp_len++; + } + p += vlen; + } + + params->enable_decode_fec = 1; + params->fec_decoder_schemes_num = tmp_len; + + return XQC_OK; +} +#endif + +static xqc_int_t xqc_decode_extended_ack_features(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + XQC_DECODE_VINT_VALUE(¶ms->extended_ack_features, p, end); +} + +static xqc_int_t xqc_decode_max_receive_timestamps_per_ack(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + ssize_t nread = xqc_vint_read(p, end, ¶ms->max_receive_timestamps_per_ack); + /* [TRANSPORT] Values above 20 are invalid */ + if (nread < 0 || params->max_receive_timestamps_per_ack > XQC_MAX_RECEIVE_TIMESTAMPS_PER_ACK) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; + } + return XQC_OK; +} + +static xqc_int_t xqc_decode_receive_timestamps_exponent(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + size_t nread = xqc_vint_read(p, end, ¶ms->receive_timestamps_exponent); + /* [TRANSPORT] Values above 20 are invalid */ + if (nread < 0 || params->receive_timestamps_exponent > XQC_MAX_RECEIVE_TIMESTAMPS_EXPONENT) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; } return XQC_OK; } @@ -622,6 +899,44 @@ xqc_decode_max_datagram_frame_size(xqc_transport_params_t *params, xqc_transport XQC_DECODE_VINT_VALUE(¶ms->max_datagram_frame_size, p, end); } +typedef enum { + XQC_TP_DECODER_ORIGINAL_DEST_CONNECTION_ID = 0x0000, + XQC_TP_DECODER_MAX_IDLE_TIMEOUT , + XQC_TP_DECODER_STATELESS_RESET_TOKEN , + XQC_TP_DECODER_MAX_UDP_PAYLOAD_SIZE , + XQC_TP_DECODER_INITIAL_MAX_DATA , + XQC_TP_DECODER_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL , + XQC_TP_DECODER_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE , + XQC_TP_DECODER_INITIAL_MAX_STREAM_DATA_UNI , + XQC_TP_DECODER_INITIAL_MAX_STREAMS_BIDI , + XQC_TP_DECODER_INITIAL_MAX_STREAMS_UNI , + XQC_TP_DECODER_ACK_DELAY_EXPONENT , + XQC_TP_DECODER_MAX_ACK_DELAY , + XQC_TP_DECODER_DISABLE_ACTIVE_MIGRATION , + XQC_TP_DECODER_PREFERRED_ADDRESS , + XQC_TP_DECODER_ACTIVE_CONNECTION_ID_LIMIT , + XQC_TP_DECODER_INITIAL_SOURCE_CONNECTION_ID , + XQC_TP_DECODER_RETRY_SOURCE_CONNECTION_ID , + + XQC_TP_DECODER_ENABLE_MULTIPATH , + XQC_TP_DECODER_MAX_DATAGRAM_FRAME_SIZE , + + /* whether enable datagram reduncy */ + XQC_TP_DECODER_CLOSE_DGRAM_REDUNDANCY , +#ifdef XQC_ENABLE_FEC + /* fec attributes' parser */ + XQC_TP_DECODER_FEC_VERSION_PARSER , + XQC_TP_DECODER_FEC_ENCODER_SCHEMES_PARSER , + XQC_TP_DECODER_FEC_DECODER_SCHEMES_PARSER , + XQC_TP_DECODER_FEC_MAX_SYMBOL_NUM_PARSER , +#endif + XQC_TP_EXTENDED_ACK_FEATURES_PARSER , + XQC_TP_MAX_RECEIVE_TIMESTAMPS_PER_ACK_PARSER , + XQC_TP_RECEIVE_TIMESTAMPS_EXPONENT_PARSER , + XQC_TP_DECODER_NO_CRYPTO , + XQC_TP_DECODER_PMTUD_OPTIONS , + XQC_TP_DECODER_UNKNOWN +} xqc_tp_decoder_index_t; /* decode value from p, and store value in the input params */ typedef xqc_int_t (*xqc_trans_param_decode_func)( @@ -646,9 +961,20 @@ xqc_trans_param_decode_func xqc_trans_param_decode_func_list[] = { xqc_decode_active_cid_limit, xqc_decode_initial_scid, xqc_decode_retry_scid, - xqc_decode_no_crypto, xqc_decode_enable_multipath, xqc_decode_max_datagram_frame_size, + xqc_decode_close_dgram_redundancy, +#ifdef XQC_ENABLE_FEC + xqc_decode_fec_version, + xqc_decode_encoder_schemes, + xqc_decode_decoder_schemes, + xqc_decode_fec_max_symbols_num, +#endif + xqc_decode_extended_ack_features, + xqc_decode_max_receive_timestamps_per_ack, + xqc_decode_receive_timestamps_exponent, + xqc_decode_no_crypto, + xqc_decode_enable_pmtud, }; @@ -675,24 +1001,53 @@ xqc_trans_param_get_index(uint64_t param_type) case XQC_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT: case XQC_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID: case XQC_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: - return param_type; - - case XQC_TRANSPORT_PARAM_NO_CRYPTO: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX; + return (xqc_tp_decoder_index_t)param_type; - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04: - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05: - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX + 1; + case XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10: + return XQC_TP_DECODER_ENABLE_MULTIPATH; case XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX + 2; + return XQC_TP_DECODER_MAX_DATAGRAM_FRAME_SIZE; + + case XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY: + return XQC_TP_DECODER_CLOSE_DGRAM_REDUNDANCY; + +#ifdef XQC_ENABLE_FEC + case XQC_TRANSPORT_PARAM_FEC_VERSION: + case XQC_TRANSPORT_PARAM_FEC_VERSION_02: + return XQC_TP_DECODER_FEC_VERSION_PARSER; + + case XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES: + return XQC_TP_DECODER_FEC_ENCODER_SCHEMES_PARSER; + + case XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES: + return XQC_TP_DECODER_FEC_DECODER_SCHEMES_PARSER; + + case XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM: + return XQC_TP_DECODER_FEC_MAX_SYMBOL_NUM_PARSER; + +#endif + + case XQC_TRANSPORT_PARAM_EXTENDED_ACK_FEATURES: + return XQC_TP_EXTENDED_ACK_FEATURES_PARSER; + + case XQC_TRANSPORT_PARAM_MAX_RECEIVE_TIMESTAMPS_PER_ACK: + return XQC_TP_MAX_RECEIVE_TIMESTAMPS_PER_ACK_PARSER; + + case XQC_TRANSPORT_PARAM_RECEIVE_TIMESTAMPS_EXPONENT: + return XQC_TP_RECEIVE_TIMESTAMPS_EXPONENT_PARSER; + + case XQC_TRANSPORT_PARAM_NO_CRYPTO: + return XQC_TP_DECODER_NO_CRYPTO; + + case XQC_TRANSPORT_PARAM_PMTUD_OPTIONS: + return XQC_TP_DECODER_PMTUD_OPTIONS; default: break; } - return XQC_TRANSPORT_PARAM_UNKNOWN; + return XQC_TP_DECODER_UNKNOWN; } @@ -726,7 +1081,7 @@ xqc_decode_one_transport_param(xqc_transport_params_t *params, * for example, disable_active_migration. */ uint64_t param_index = xqc_trans_param_get_index(param_type); - if (param_index != XQC_TRANSPORT_PARAM_UNKNOWN) { + if (param_index != XQC_TP_DECODER_UNKNOWN) { xqc_int_t ret = xqc_trans_param_decode_func_list[param_index](params, exttype, p, end, param_type, param_len); if (ret < 0) { @@ -780,6 +1135,22 @@ xqc_decode_transport_params(xqc_transport_params_t *params, params->enable_multipath = 0; params->multipath_version = XQC_ERR_MULTIPATH_VERSION; + params->init_max_path_id = 0; + + /* init fec params value */ + params->enable_encode_fec = 0; + params->enable_decode_fec = 0; + params->fec_version = XQC_ERR_FEC_VERSION; + params->fec_max_symbols_num = 0; + params->fec_encoder_schemes_num = 0; + params->fec_decoder_schemes_num = 0; + + params->extended_ack_features = 0; + params->max_receive_timestamps_per_ack = 0; + params->receive_timestamps_exponent = 0; + + params->close_dgram_redundancy = XQC_RED_NOT_USE; + params->enable_pmtud = 0; while (p < end) { ret = xqc_decode_one_transport_param(params, exttype, &p, end); @@ -810,43 +1181,43 @@ xqc_read_transport_params(char *tp_data, size_t tp_data_len, xqc_transport_param xqc_lengthof("initial_max_streams_bidi=")) == 0) { p += xqc_lengthof("initial_max_streams_bidi="); - params->initial_max_streams_bidi = strtoul(p, NULL, 10); + params->initial_max_streams_bidi = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "initial_max_streams_uni=", xqc_lengthof("initial_max_streams_uni=")) == 0) { p += xqc_lengthof("initial_max_streams_uni="); - params->initial_max_streams_uni = strtoul(p, NULL, 10); + params->initial_max_streams_uni = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "initial_max_stream_data_bidi_local=", xqc_lengthof("initial_max_stream_data_bidi_local=")) == 0) { p += xqc_lengthof("initial_max_stream_data_bidi_local="); - params->initial_max_stream_data_bidi_local = strtoul(p, NULL, 10); + params->initial_max_stream_data_bidi_local = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "initial_max_stream_data_bidi_remote=", xqc_lengthof("initial_max_stream_data_bidi_remote=")) == 0) { p += xqc_lengthof("initial_max_stream_data_bidi_remote="); - params->initial_max_stream_data_bidi_remote = strtoul(p, NULL, 10); + params->initial_max_stream_data_bidi_remote = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "initial_max_stream_data_uni=", xqc_lengthof("initial_max_stream_data_uni=")) == 0) { p += xqc_lengthof("initial_max_stream_data_uni="); - params->initial_max_stream_data_uni = strtoul(p, NULL, 10); + params->initial_max_stream_data_uni = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "initial_max_data=", xqc_lengthof("initial_max_data=")) == 0) { p += xqc_lengthof("initial_max_data="); - params->initial_max_data = strtoul(p, NULL, 10); + params->initial_max_data = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "max_ack_delay=", xqc_lengthof("max_ack_delay=")) == 0) { p += xqc_lengthof("max_ack_delay="); - params->max_ack_delay = strtoul(p, NULL, 10); + params->max_ack_delay = strtoul(p, NULL, XQC_DECIMAL); } else if (strncmp(p, "max_datagram_frame_size=", xqc_lengthof("max_datagram_frame_size=")) == 0) { p += xqc_lengthof("max_datagram_frame_size="); - params->max_datagram_frame_size = strtoul(p, NULL, 10); + params->max_datagram_frame_size = strtoul(p, NULL, XQC_DECIMAL); } p = strchr(p, '\n'); diff --git a/src/transport/xqc_transport_params.h b/src/transport/xqc_transport_params.h index 2abbf6897..e572f6ad7 100644 --- a/src/transport/xqc_transport_params.h +++ b/src/transport/xqc_transport_params.h @@ -23,6 +23,9 @@ /* max buffer length of encoded transport parameter */ #define XQC_MAX_TRANSPORT_PARAM_BUF_LEN 512 +/* default value for max_path_id */ +#define XQC_DEFAULT_INIT_MAX_PATH_ID 8 + /** @@ -59,9 +62,9 @@ typedef enum { XQC_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT = 0x000e, XQC_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f, XQC_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010, - - /* upper limit of params defined in [Transport] */ - XQC_TRANSPORT_PARAM_PROTOCOL_MAX, + + /* whether enable datagram reduncy */ + XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY = 0x0013, /* max datagram frame size */ XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE = 0x0020, @@ -70,12 +73,24 @@ typedef enum { XQC_TRANSPORT_PARAM_NO_CRYPTO = 0x1000, /* multipath quic attributes */ - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04 = 0x0f739bbc1b666d04, - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05 = 0x0f739bbc1b666d05, - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06 = 0x0f739bbc1b666d06, - - /* upper limit of params defined by xquic */ - XQC_TRANSPORT_PARAM_UNKNOWN, + XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10 = 0x0f739bbc1b666d09, + + /* google connection options */ + XQC_TRANSPORT_PARAM_GOOGLE_CO = 0x3128, + + /* PTMUD negotiation */ + XQC_TRANSPORT_PARAM_PMTUD_OPTIONS = 0x0e08a234ff112300, +#ifdef XQC_ENABLE_FEC + /* fec attributes */ + XQC_TRANSPORT_PARAM_FEC_VERSION = 0xfec001, + XQC_TRANSPORT_PARAM_FEC_VERSION_02 = 0xfec002, + XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES = 0xfece01, + XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES = 0xfecd02, + XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM = 0xfecb02, +#endif + XQC_TRANSPORT_PARAM_EXTENDED_ACK_FEATURES = 0xff0a004, + XQC_TRANSPORT_PARAM_MAX_RECEIVE_TIMESTAMPS_PER_ACK = 0xff0a002, + XQC_TRANSPORT_PARAM_RECEIVE_TIMESTAMPS_EXPONENT = 0xff0a003, } xqc_transport_param_id_t; @@ -144,13 +159,39 @@ typedef struct { * NOTICE: enable_multipath MIGHT be modified or removed as it is not an official parameter */ uint64_t enable_multipath; + xqc_multipath_version_t multipath_version; + uint64_t init_max_path_id; - xqc_multipath_version_t multipath_version; - -} xqc_transport_params_t; + uint32_t conn_options[XQC_CO_MAX_NUM]; + uint8_t conn_option_num; + xqc_fec_version_t fec_version; + uint64_t enable_encode_fec; + uint64_t enable_decode_fec; + uint64_t fec_max_symbols_num; + xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + xqc_int_t fec_encoder_schemes_num; + xqc_int_t fec_decoder_schemes_num; + xqc_dgram_red_setting_e close_dgram_redundancy; + uint64_t enable_pmtud; + + /* + * draft-smith-quic-receive-ts-01: QUIC Extended Acknowledgement for Reporting Packet Receive Timestamps + * extended_ack_features: a bit-wise value indicates which optional fields are included. + * Bit 0 indicates whether ECN count fields are included in the frame. + * Bit 1 indicates whether Receive Timestamps are included in the frame. + * + * max_receive_timestamps_per_ack: max number of timestamps in a extended ack frame. + * ack_receive_timestamps: all time delta values are decoded by mulitplying the + * value in the field by 2 to the power of the receive_timestamps_exponent. + */ + uint64_t extended_ack_features; + uint64_t max_receive_timestamps_per_ack; + uint64_t receive_timestamps_exponent; +} xqc_transport_params_t; /** * encode transport parameters. diff --git a/src/transport/xqc_utils.c b/src/transport/xqc_utils.c index b1ae87e1b..bc482f944 100644 --- a/src/transport/xqc_utils.c +++ b/src/transport/xqc_utils.c @@ -9,18 +9,17 @@ #include "src/common/xqc_log.h" #include "src/transport/xqc_utils.h" #include "src/transport/xqc_conn.h" - +#include "src/common/xqc_time.h" int -xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_ms) +xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_us) { - xqc_conns_pq_elem_t *elem = (xqc_conns_pq_elem_t *)xqc_pq_push(pq, time_ms); + xqc_conns_pq_elem_t *elem = (xqc_conns_pq_elem_t *)xqc_pq_push(pq, time_us, &conn); if (!elem) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_pq_push error|count:%uz|capacity:%uz|", pq->count, pq->capacity); return -XQC_EMALLOC; } - elem->conn = conn; - return 0; + return XQC_OK; } void @@ -35,12 +34,32 @@ xqc_conns_pq_top(xqc_pq_t *pq) return (xqc_conns_pq_elem_t *)xqc_pq_top(pq); } +xqc_connection_t * +xqc_conns_pq_pop_top_conn(xqc_pq_t *pq) +{ + /* used to traverse conns_pq */ + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(pq); + if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { + xqc_conns_pq_pop(pq); + return NULL; + } + + xqc_connection_t *conn = el->conn; + xqc_conns_pq_pop(pq); + return conn; +} + +void +xqc_conns_pq_remove(xqc_pq_t *pq, xqc_connection_t *conn) +{ + xqc_pq_remove(pq, conn->wakeup_pq_index); +} + int xqc_insert_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len) { - uint64_t hash = xqc_hash_string(data, len); - + uint64_t hash = xqc_siphash_get_hash(&conns_hash->siphash_ctx, data, len); xqc_str_hash_element_t c = { .str = { .data = (unsigned char *)data, @@ -49,18 +68,19 @@ xqc_insert_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, .hash = hash, .value = conn }; - - if (xqc_str_hash_add(conns_hash, c)) { + + if (xqc_str_hash_add(conns_hash, c) != XQC_OK) { return -XQC_EMALLOC; } - return 0; + + return XQC_OK; } int xqc_remove_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len) { - uint64_t hash = xqc_hash_string(data, len); + uint64_t hash = xqc_siphash_get_hash(&conns_hash->siphash_ctx, data, len); xqc_str_t str = { .data = (unsigned char *)data, .len = len, @@ -77,7 +97,7 @@ int xqc_insert_conns_addr_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const struct sockaddr *addr, socklen_t addrlen) { - uint64_t hash = xqc_hash_string((unsigned char *)addr, addrlen); + uint64_t hash = xqc_siphash_get_hash(&conns_hash->siphash_ctx, (const uint8_t *)addr, addrlen); xqc_str_hash_element_t c = { .str = { .data = (unsigned char *)addr, @@ -87,7 +107,7 @@ xqc_insert_conns_addr_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *c .value = conn }; - if (xqc_str_hash_add(conns_hash, c)) { + if (xqc_str_hash_add(conns_hash, c) != XQC_OK) { return -XQC_EMALLOC; } return 0; @@ -98,11 +118,11 @@ void * xqc_find_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len) { - uint64_t hash = xqc_hash_string(data, len); + uint64_t hash = xqc_siphash_get_hash(&conns_hash->siphash_ctx, data, len); xqc_str_t str = { .data = (unsigned char *)data, .len = len, }; return xqc_str_hash_find(conns_hash, hash, str); -} \ No newline at end of file +} diff --git a/src/transport/xqc_utils.h b/src/transport/xqc_utils.h index 0a4be3770..d60839344 100644 --- a/src/transport/xqc_utils.h +++ b/src/transport/xqc_utils.h @@ -9,16 +9,20 @@ #include "src/common/xqc_priority_q.h" typedef struct xqc_conns_pq_elem_s { - xqc_pq_key_t time_ms; + xqc_pq_key_t time_us; xqc_connection_t *conn; } xqc_conns_pq_elem_t; -int xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_ms); +int xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_us); void xqc_conns_pq_pop(xqc_pq_t *pq); xqc_conns_pq_elem_t *xqc_conns_pq_top(xqc_pq_t *pq); +xqc_connection_t *xqc_conns_pq_pop_top_conn(xqc_pq_t *pq); + +void xqc_conns_pq_remove(xqc_pq_t *pq, xqc_connection_t *conn); + int xqc_insert_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len); diff --git a/src/transport/xqc_wakeup_pq.h b/src/transport/xqc_wakeup_pq.h deleted file mode 100644 index 2e18bffc6..000000000 --- a/src/transport/xqc_wakeup_pq.h +++ /dev/null @@ -1,230 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#ifndef _XQC_WAKEUP_PQ_H_INCLUDED_ -#define _XQC_WAKEUP_PQ_H_INCLUDED_ - -#include "src/transport/xqc_conn.h" -#include "src/common/xqc_malloc.h" -#include - -typedef uint64_t xqc_pq_wakeup_time_t; - -typedef struct { - xqc_pq_wakeup_time_t wakeup_time; - struct xqc_connection_s *conn; -} xqc_wakeup_pq_elem_t; - -/* element compare function */ -typedef int (*xqc_wakeup_pq_compare_ptr)(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b); - -/* - * default element compare function, priority: a < b - * higher priority first - */ -static inline int -xqc_wakeup_pq_default_cmp(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b) -{ - return (a < b) ? 1 : 0; -} - -/* - * inverse element compare function, priority: a > b - * lower priority first - */ -static inline int -xqc_wakeup_pq_revert_cmp(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b) -{ - return (b < a) ? 1 : 0; -} - -typedef struct xqc_wakeup_pq_s { - char *elements; /* elements */ - size_t element_size; /* memory size of element objects */ - size_t count; /* number of elements */ - size_t capacity; /* element capacity */ - xqc_allocator_t a; /* memory allocator */ - xqc_wakeup_pq_compare_ptr cmp; /* compare function */ -} xqc_wakeup_pq_t; - - -#define xqc_wakeup_pq_element(pq, index) ((xqc_wakeup_pq_elem_t*)&(pq)->elements[(index) * (pq)->element_size]) -#define xqc_wakeup_pq_element_copy(pq, dst, src) memmove(xqc_wakeup_pq_element((pq), (dst)), xqc_wakeup_pq_element((pq), (src)), (pq)->element_size) -#define xqc_wakeup_pq_default_capacity 16 - -static inline int -xqc_wakeup_pq_init(xqc_wakeup_pq_t *pq, size_t capacity, xqc_allocator_t a, xqc_wakeup_pq_compare_ptr cmp) -{ - size_t element_size = sizeof(xqc_wakeup_pq_elem_t); - if (capacity == 0) { - return -1; - } - - pq->elements = a.malloc(a.opaque, element_size * capacity); - if (pq->elements == NULL) { - return -2; - } - - pq->element_size = element_size; - pq->count = 0; - pq->capacity = capacity; - pq->a = a; - pq->cmp = cmp; - - return 0; -} - -static inline int -xqc_wakeup_pq_init_default(xqc_wakeup_pq_t *pq, xqc_allocator_t a, xqc_wakeup_pq_compare_ptr cmp) -{ - return xqc_wakeup_pq_init(pq, xqc_wakeup_pq_default_capacity, a, cmp); -} - -static inline void -xqc_wakeup_pq_destroy(xqc_wakeup_pq_t *pq) -{ - pq->a.free(pq->a.opaque, pq->elements); - pq->elements = NULL; - pq->element_size = 0; - pq->count = 0; - pq->capacity = 0; -} - -static inline void -xqc_wakeup_pq_element_swap(xqc_wakeup_pq_t *pq, size_t i, size_t j) -{ - char buf[pq->element_size]; - xqc_wakeup_pq_elem_t* p; - p = xqc_wakeup_pq_element(pq, i); - p->conn->wakeup_pq_index = j; - p = xqc_wakeup_pq_element(pq, j); - p->conn->wakeup_pq_index = i; - - memcpy(buf, xqc_wakeup_pq_element(pq, j), pq->element_size); - memcpy(xqc_wakeup_pq_element(pq, j), xqc_wakeup_pq_element(pq, i), pq->element_size); - memcpy(xqc_wakeup_pq_element(pq, i), buf, pq->element_size); -} - -static inline xqc_wakeup_pq_elem_t * -xqc_wakeup_pq_push(xqc_wakeup_pq_t *pq, xqc_pq_wakeup_time_t wakeup_time, struct xqc_connection_s *conn) -{ - if (pq->count == pq->capacity) { - size_t capacity = pq->capacity * 2; - size_t size = capacity * pq->element_size; - void* buf = pq->a.malloc(pq->a.opaque, size); - if (buf == NULL) { - return NULL; - } - memcpy(buf, pq->elements, pq->capacity * pq->element_size); - pq->a.free(pq->a.opaque, pq->elements); - pq->elements = buf; - pq->capacity = capacity; - } - - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, pq->count); - p->wakeup_time = wakeup_time; - p->conn = conn; - conn->wakeup_pq_index = pq->count; - - size_t i = pq->count++; - while (i != 0) { - int j = (i - 1) / 2; - if (!pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, i)->wakeup_time)) - break; - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - } - - return xqc_wakeup_pq_element(pq, i); -} - -static inline xqc_wakeup_pq_elem_t * -xqc_wakeup_pq_top(xqc_wakeup_pq_t *pq) -{ - if (pq->count == 0) { - return NULL; - } - return xqc_wakeup_pq_element(pq, 0); -} - -static inline int -xqc_wakeup_pq_empty(xqc_wakeup_pq_t *pq) -{ - return pq->count == 0 ? 1 : 0; -} - -static inline void -xqc_wakeup_pq_pop(xqc_wakeup_pq_t *pq) -{ - if (pq->count == 0 || --pq->count == 0) { - return; - } - - xqc_wakeup_pq_element_copy(pq, 0, pq->count); - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, 0); - p->conn->wakeup_pq_index = 0; - - int i = 0, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, j+1)->wakeup_time)) { - ++j; - } - - if (!pq->cmp(xqc_wakeup_pq_element(pq, i)->wakeup_time, xqc_wakeup_pq_element(pq, j)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - j = 2 * i + 1; - } -} - -static inline void -xqc_wakeup_pq_remove(xqc_wakeup_pq_t *pq, struct xqc_connection_s *conn) -{ - unsigned pq_index = conn->wakeup_pq_index; - if (pq_index >= pq->count || pq->count == 0 || --pq->count == 0) { - return; - } - - xqc_wakeup_pq_element_copy(pq, pq_index, pq->count); - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, pq_index); - p->conn->wakeup_pq_index = pq_index; - - int i = pq_index, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, j+1)->wakeup_time)) { - ++j; - } - - if (!pq->cmp(xqc_wakeup_pq_element(pq, i)->wakeup_time, xqc_wakeup_pq_element(pq, j)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - j = 2 * i + 1; - } - - i = pq_index; - while (i != 0) { - j = (i - 1)/2; - if (!pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, i)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - i = j; - } -} - -#undef xqc_wakeup_pq_element -#undef xqc_wakeup_pq_element_copy - -#endif /* _XQC_WAKEUP_PQ_H_INCLUDED_ */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 80673e074..b4cb157ac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,82 @@ +##### build test_client/test_server, demo_client/demo_server ##### +# CUnit TODO: fix test unit on windows +find_package(CUnit 2.1) +enable_testing() +set(HAVE_CUNIT ${CUNIT_FOUND}) if(HAVE_CUNIT) - include_directories( - ${CMAKE_SOURCE_DIR} - ${CUNIT_INCLUDE_DIRS} + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) +endif() + +# find LibEvent include and library path +find_package(LibEvent 2.0.21) +if(NOT LIBEVENT_FOUND) + message(FATAL_ERROR "libevent with required version not found") +endif() + +include_directories( + "${CMAKE_SOURCE_DIR}/" + "${CMAKE_SOURCE_DIR}/include" + ${CMAKE_SOURCE_DIR} + ${CUNIT_INCLUDE_DIRS} + ${LIBEVENT_INCLUDE_DIR} +) + +set(TEST_SERVER_SOURCES + test_server.c +) + +set(TEST_CLIENT_SOURCES + test_client.c +) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(GETOPT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/getopt.c + CACHE STRING "xquic windows getopt source") + + set(TEST_SERVER_SOURCES + ${TEST_SERVER_SOURCES} + ${GETOPT_SOURCES} ) + set(TEST_CLIENT_SOURCES + ${TEST_CLIENT_SOURCES} + ${GETOPT_SOURCES} + ) +endif() + + +### test client/server ### +add_executable(test_server ${TEST_SERVER_SOURCES}) +add_executable(test_client ${TEST_CLIENT_SOURCES}) + +# link libraries +if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set(APP_DEPEND_LIBS + xquic-static + ${SSL_LIB_PATH} + ${LIBEVENT_LIBRARY} + -lm + CACHE STRING "xquic app depend libs") +else() + set(APP_DEPEND_LIBS + xquic-static + ${SSL_LIB_PATH} + ${LIBEVENT_LIBRARY} + m + dl + stdc++ + pthread + CACHE STRING "xquic app depend libs") +endif() + +target_link_libraries(test_server ${APP_DEPEND_LIBS}) +target_link_libraries(test_client ${APP_DEPEND_LIBS}) + + +# build run_tests +if(HAVE_CUNIT) + set (UNIT_TEST_DIR unittest) set(test_SOURCES @@ -20,7 +93,6 @@ if(HAVE_CUNIT) ${UNIT_TEST_DIR}/xqc_reno_test.c ${UNIT_TEST_DIR}/xqc_cubic_test.c ${UNIT_TEST_DIR}/xqc_stream_frame_test.c - ${UNIT_TEST_DIR}/xqc_wakeup_pq_test.c ${UNIT_TEST_DIR}/xqc_process_frame_test.c ${UNIT_TEST_DIR}/xqc_tp_test.c ${UNIT_TEST_DIR}/xqc_tls_test.c @@ -40,25 +112,52 @@ if(HAVE_CUNIT) ${UNIT_TEST_DIR}/xqc_retry_test.c ${UNIT_TEST_DIR}/xqc_datagram_test.c ${UNIT_TEST_DIR}/xqc_h3_ext_test.c + ${UNIT_TEST_DIR}/xqc_ack_with_timestamp_test.c ) + if(XQC_ENABLE_FEC) + set( + test_SOURCES + ${test_SOURCES} + ${UNIT_TEST_DIR}/xqc_galois_test.c + ${UNIT_TEST_DIR}/xqc_fec_scheme_test.c + ${UNIT_TEST_DIR}/xqc_fec_test.c + ) + endif() add_executable(run_tests ${test_SOURCES} ) - target_include_directories(run_tests PRIVATE ${CUNIT_INCLUDE_DIRS}) + target_include_directories(run_tests + PRIVATE + ${INCLUDE_DIRECTORIES} + ${CUNIT_INCLUDE_DIRS}) + + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CUTEST_DEPEND_LIBS + xquic-static + ${CUNIT_LIBRARIES} + ${SSL_LIB_PATH} + m + CACHE STRING "xquic unit test depend libs") + else() + set(CUTEST_DEPEND_LIBS + xquic-static + ${CUNIT_LIBRARIES} + ${SSL_LIB_PATH} + m + stdc++ + dl + pthread + CACHE STRING "xquic unit test depend libs") + endif() + target_link_libraries(run_tests - xquic-static - ${CUNIT_LIBRARIES} - ${SSL_LIB_PATH} - m - dl - pthread + ${CUTEST_DEPEND_LIBS} ) add_test(run_tests run_tests) add_dependencies(check run_tests) - include_directories(${SSL_INC_PATH}) - endif() + diff --git a/tests/getopt.c b/tests/getopt.c new file mode 100644 index 000000000..da00d91fe --- /dev/null +++ b/tests/getopt.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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 + */ + +#include +#include +#include "getopt.h" + +/* + * On some versions of Solaris, opterr and friends are defined in core libc + * rather than in a separate getopt module. Define these variables only + * if configure found they aren't there by default. (We assume that testing + * opterr is sufficient for all of these.) + */ +#ifndef HAVE_INT_OPTERR +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt; /* character checked for validity */ +char *optarg; /* argument associated with option */ +#endif + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt + * Parse argc/argv argument vector. + * + * This implementation does not use optreset. Instead, we guarantee that + * it can be restarted on a new argv array after a previous call returned -1, + * if the caller resets optind to 1 before the first call of the new series. + * (Internally, this means we must be sure to reset "place" to EMSG before + * returning -1.) + */ +int getopt(int nargc, char *const *nargv, const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (!*place) + { /* update scanning pointer */ + if (optind >= nargc || *(place = nargv[optind]) != '-') + { + place = EMSG; + return -1; + } + if (place[1] && *++place == '-' && place[1] == '\0') + { /* found "--" */ + ++optind; + place = EMSG; + return -1; + } + } /* option letter okay? */ + if ((optopt = (int) *place++) == (int) ':' || + !(oli = strchr(ostr, optopt))) + { + /* + * if the user didn't specify '-' as an option, assume it means -1. + */ + if (optopt == (int) '-') + { + place = EMSG; + return -1; + } + if (!*place) + ++optind; + if (opterr && *ostr != ':') + fprintf(stderr, "illegal option -- %c\n", optopt); + return BADCH; + } + if (*++oli != ':') + { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) + { /* no arg */ + place = EMSG; + if (*ostr == ':') + return BADARG; + if (opterr) + fprintf(stderr,"option requires an argument -- %c\n", optopt); + return BADCH; + } else { + /* white space */ + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + return optopt; /* dump back option letter */ +} + +/* + * getopt_long + * Parse argc/argv argument vector, with long options. + * + * This implementation does not use optreset. Instead, we guarantee that + * it can be restarted on a new argv array after a previous call returned -1, + * if the caller resets optind to 1 before the first call of the new series. + * (Internally, this means we must be sure to reset "place" to EMSG before + * returning -1.) + */ +int +getopt_long(int argc, char *const argv[], + const char *optstring, + const struct option * longopts, int *longindex) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (!*place) + { /* update scanning pointer */ + if (optind >= argc) { + place = EMSG; + return -1; + } + + place = argv[optind]; + if (place[0] != '-') { + place = EMSG; + return -1; + } + + place++; + if (place[0] && place[0] == '-' && place[1] == '\0') + { + ++optind; + place = EMSG; + return -1; + } + + if (place[0] && place[0] == '-' && place[1]) + { + /* long option */ + size_t namelen; + int i; + + place++; + namelen = strcspn(place, "="); + for (i = 0; longopts[i].name != NULL; i++) + { + if (strlen(longopts[i].name) == namelen + && strncmp(place, longopts[i].name, namelen) == 0) + { + int has_arg = longopts[i].has_arg; + if (has_arg != no_argument) + { + if (place[namelen] == '=') { + optarg = place + namelen + 1; + } else if (optind < argc - 1 && has_arg == required_argument) + { + optind++; + optarg = argv[optind]; + } else { + if (optstring[0] == ':') { + return BADARG; + } + if (opterr && has_arg == required_argument) { + fprintf(stderr, "%s: option requires an argument -- %s\n", + argv[0], place); + } + place = EMSG; + optind++; + if (has_arg == required_argument) + return BADCH; + optarg = NULL; + } + } else { + optarg = NULL; + if (place[namelen] != 0) { + /* XXX error? */ + fprintf(stderr, "XXX error? \n"); + } + } + + optind++; + if (longindex) + *longindex = i; + + place = EMSG; + if (longopts[i].flag == NULL) + return longopts[i].val; + else { + *longopts[i].flag = longopts[i].val; + return 0; + } + } + } + + if (opterr && optstring[0] != ':') + fprintf(stderr, "%s: illegal option -- %s\n", argv[0], place); + place = EMSG; + optind++; + return BADCH; + } + } + + /* short option */ + optopt = (int) *place++; + oli = strchr(optstring, optopt); + if (!oli) + { + if (!*place) + ++optind; + if (opterr && *optstring != ':') + fprintf(stderr, "%s: illegal option -- %c\n", argv[0], optopt); + return BADCH; + } + + if (oli[1] != ':') + { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (argc <= ++optind) + { /* no arg */ + place = EMSG; + if (*optstring == ':') + return BADARG; + if (opterr) + fprintf(stderr, "%s: option requires an argument -- %c\n", + argv[0], optopt); + return BADCH; + } else { + /* white space */ + optarg = argv[optind]; + } + place = EMSG; + ++optind; + } + return optopt; +} diff --git a/tests/getopt.h b/tests/getopt.h new file mode 100644 index 000000000..10e5bdd7d --- /dev/null +++ b/tests/getopt.h @@ -0,0 +1,48 @@ +/* + * Portions Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + */ +#ifndef GETOPT_H +#define GETOPT_H + +/* rely on the system's getopt.h if present */ +#ifdef HAVE_GETOPT_H +#include +#endif + +/* + * If we have , assume it declares these variables, else do that + * ourselves. (We used to just declare them unconditionally, but Cygwin + * doesn't like that.) + */ +#ifndef HAVE_GETOPT_H +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; +#endif /* HAVE_GETOPT_H */ + +#ifndef HAVE_STRUCT_OPTION +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 +#endif /* HAVE_STRUCT_OPTION */ + +#ifndef HAVE_GETOPT +extern int getopt(int nargc, char *const * nargv, const char *ostr); +#endif + +#ifndef HAVE_GETOPT_LONG +extern int getopt_long(int argc, char *const argv[], + const char *optstring, + const struct option * longopts, int *longindex); +#endif +#endif + diff --git a/tests/platform.h b/tests/platform.h new file mode 100644 index 000000000..d3435932d --- /dev/null +++ b/tests/platform.h @@ -0,0 +1,61 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) +#define XQC_SYS_WINDOWS +#endif + +#ifdef XQC_SYS_WINDOWS +# define EAGAIN WSAEWOULDBLOCK +# define EINTR WSAEINTR +#endif + + +/** + * @brief get system last errno + * + * @return int + */ +static inline int get_sys_errno() +{ + int err = 0; +#ifdef XQC_SYS_WINDOWS + err = WSAGetLastError(); +#else + err = errno; +#endif + return err; +} + +static inline void set_sys_errno(int err) +{ +#ifdef XQC_SYS_WINDOWS + WSASetLastError(err); +#else + errno = err; +#endif +} + +/** + * @brief init platform env if necessary + * + */ +static inline void xqc_platform_init_env() +{ + int result = 0; + + #ifdef XQC_SYS_WINDOWS + // Initialize Winsock + WSADATA wsaData; + if ((result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { + printf("WSAStartup failed with error %d\n", result); + exit(1); + } +#endif + +} +#endif diff --git a/tests/test_client.c b/tests/test_client.c index 536e04083..79de8511c 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -15,12 +13,26 @@ #include #include #include -#include -#include #include #include #include +#include "platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#include +#include #include +#else +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#include "getopt.h" +#endif + +extern long xqc_random(void); +extern xqc_usec_t xqc_now(); int printf_null(const char *format, ...) @@ -31,7 +43,6 @@ printf_null(const char *format, ...) #define XQC_ALPN_TRANSPORT "transport" #define XQC_ALPN_TRANSPORT_TEST "transport-test" - //#define printf printf_null #define DEBUG printf("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__); @@ -94,12 +105,12 @@ typedef struct user_stream_s { size_t recv_body_len; FILE *recv_body_fp; int recv_fin; - xqc_msec_t start_time; - xqc_msec_t first_frame_time; /* first frame download time */ - xqc_msec_t last_read_time; + xqc_usec_t start_time; + xqc_usec_t first_frame_time; /* first frame download time */ + xqc_usec_t last_read_time; int abnormal_count; int body_read_notify_cnt; - xqc_msec_t last_recv_log_time; + xqc_usec_t last_recv_log_time; uint64_t recv_log_bytes; xqc_h3_ext_bytestream_t *h3_ext_bs; @@ -211,6 +222,7 @@ int g_send_body_size_from_cdf; cdf_entry_t *cdf_list; int cdf_list_size; int g_req_paral = 1; +int g_req_per_time = 0; int g_recovery = 0; int g_save_body; int g_read_body; @@ -243,7 +255,8 @@ char g_headers[MAX_HEADER][256]; int g_header_cnt = 0; int g_ping_id = 1; int g_enable_multipath = 0; -xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_04; +xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_10; +int g_enable_fec = 0; int g_enable_reinjection = 0; int g_verify_cert = 0; int g_verify_cert_allow_self_sign = 0; @@ -262,7 +275,6 @@ char g_header_value[MAX_HEADER_VALUE_LEN]; char g_multi_interface[XQC_DEMO_MAX_PATH_COUNT][64]; xqc_user_path_t g_client_path[XQC_DEMO_MAX_PATH_COUNT]; int g_multi_interface_cnt = 0; -int mp_has_closed = 0; int mp_has_recved = 0; char g_priority[64] = {'\0'}; @@ -342,21 +354,24 @@ get_val_from_cdf_by_p(double p) static int get_random_from_cdf() { - int r = 1 + (random() % 1000); + int r = 1 + (xqc_random() % 1000); double p = r * 1.0 / 1000; // 0.001 ~ 1 return get_val_from_cdf_by_p(p); } - -static inline uint64_t -now() +#ifdef XQC_SYS_WINDOWS +static void usleep(unsigned long usec) { - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; + HANDLE timer; + LARGE_INTEGER interval; + interval.QuadPart = -(10 * usec); + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); } +#endif static void xqc_client_socket_event_callback(int fd, short what, void *arg); @@ -412,7 +427,7 @@ xqc_client_datagram_send(user_conn_t *user_conn) if (ret == -XQC_EAGAIN) { printf("[dgram]|retry_datagram_send_later|\n"); return; - } else if (ret == -XQC_EDGRAM_TOO_LARGE ) { + } else if (ret == -XQC_EDGRAM_TOO_LARGE) { printf("[dgram]|trying_to_send_an_oversized_datagram|recorded_mss:%zu|send_size:%zu|current_mss:%zu|\n", user_conn->dgram_mss, dgram_size, xqc_datagram_get_mss(user_conn->quic_conn)); xqc_conn_close(ctx.engine, &user_conn->cid); return; @@ -459,6 +474,7 @@ xqc_client_datagram_send(user_conn_t *user_conn) printf("[dgram]|partially_sent_pkts_in_a_batch|cnt:%zu|\n", succ_sent); xqc_conn_close(ctx.engine, &user_conn->cid); return; + } else if (ret < 0 && ret != -XQC_EAGAIN) { printf("[dgram]|send_datagram_multiple_error|err_code:%d|\n", ret); xqc_conn_close(ctx.engine, &user_conn->cid); @@ -593,7 +609,7 @@ xqc_client_h3_ext_datagram_send(user_conn_t *user_conn) } dgram_blk->data[dgram_blk->data_sent] = 0x32; *(uint32_t*)(dgram_blk->data + dgram_blk->data_sent + 1) = dgram_blk->dgram_id++; - *(uint64_t*)(dgram_blk->data + dgram_blk->data_sent + 5) = now(); + *(uint64_t*)(dgram_blk->data + dgram_blk->data_sent + 5) = xqc_now(); } else { dgram_blk->data[dgram_blk->data_sent] = 0x31; @@ -745,10 +761,10 @@ static void xqc_client_timeout_multi_process_callback(int fd, short what, void * void -xqc_client_set_event_timer(xqc_msec_t wake_after, void *user_data) +xqc_client_set_event_timer(xqc_usec_t wake_after, void *user_data) { client_ctx_t *ctx = (client_ctx_t *) user_data; - //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, now()); + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); struct timeval tv; tv.tv_sec = wake_after / 1000000; @@ -801,15 +817,15 @@ xqc_client_save_token(const unsigned char *token, unsigned token_len, void *user if (g_test_case == 16) { /* test application delay */ usleep(300*1000); } - int fd = open("./xqc_token", O_TRUNC | O_CREAT | O_WRONLY, S_IRWXU); + int fd = open("./xqc_token", O_TRUNC | O_CREAT | O_WRONLY, 0666); if (fd < 0) { - printf("save token error %s\n", strerror(errno)); + printf("save token error %s\n", strerror(get_sys_errno())); return; } ssize_t n = write(fd, token, token_len); if (n < token_len) { - printf("save token error %s\n", strerror(errno)); + printf("save token error %s\n", strerror(get_sys_errno())); close(fd); return; } @@ -821,7 +837,7 @@ xqc_client_read_token(unsigned char *token, unsigned token_len) { int fd = open("./xqc_token", O_RDONLY); if (fd < 0) { - printf("read token error %s\n", strerror(errno)); + printf("read token error %s\n", strerror(get_sys_errno())); return -1; } @@ -897,16 +913,16 @@ xqc_client_write_socket(const unsigned char *buf, size_t size, } do { - errno = 0; + set_sys_errno(0); - g_last_sock_op_time = now(); + g_last_sock_op_time = xqc_now(); if (TEST_DROP) { return send_buf_size; } if (g_test_case == 5) { /* socket send fail */ g_test_case = -1; - errno = EAGAIN; + set_sys_errno(EAGAIN); return XQC_SOCKET_EAGAIN; } @@ -964,8 +980,8 @@ xqc_client_write_socket(const unsigned char *buf, size_t size, res = sendto(fd, send_buf, send_buf_size, 0, peer_addr, peer_addrlen); if (res < 0) { - printf("xqc_client_write_socket err %zd %s\n", res, strerror(errno)); - if (errno == EAGAIN) { + printf("xqc_client_write_socket err %zd %s\n", res, strerror(get_sys_errno())); + if (get_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } if (errno == EMSGSIZE) { @@ -998,7 +1014,7 @@ xqc_client_write_socket(const unsigned char *buf, size_t size, sock_op_buffer_len = 0; } } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (get_sys_errno() == EINTR)); return res; } @@ -1022,6 +1038,7 @@ xqc_client_get_path_fd_by_id(user_conn_t *user_conn, uint64_t path_id) return fd; } + /* 多路必须保证传正确的path id,因为conn_fd写死了,跟initial path不一定匹配 */ ssize_t xqc_client_write_socket_ex(uint64_t path_id, @@ -1032,7 +1049,7 @@ xqc_client_write_socket_ex(uint64_t path_id, user_conn_t *user_conn = (user_conn_t *)user_data; ssize_t res; int fd = 0; - + int header_type; /* test stateless reset after handshake completed */ if (g_test_case == 41) { @@ -1043,7 +1060,7 @@ xqc_client_write_socket_ex(uint64_t path_id, } else { /* delay short header packet to make server idle timeout */ - uint64_t nowtime = now(); + uint64_t nowtime = xqc_now(); if (user_conn->black_hole_start_time == 0) { user_conn->black_hole_start_time = nowtime; @@ -1063,7 +1080,7 @@ xqc_client_write_socket_ex(uint64_t path_id, /* test stateless rset during handshake */ if (g_test_case == 45) { - uint64_t nowtime = now(); + uint64_t nowtime = xqc_now(); if (user_conn->black_hole_start_time == 0) { if ((((buf[0] & 0x80) == 0x80) && ((buf[0] & 0x30) >> 4) == 2) @@ -1099,7 +1116,7 @@ xqc_client_write_socket_ex(uint64_t path_id, /* COPY to run corruption test cases */ unsigned char send_buf[XQC_PACKET_TMP_BUF_LEN]; size_t send_buf_size = 0; - + if (size > XQC_PACKET_TMP_BUF_LEN) { printf("xqc_client_write_socket err: size=%zu is too long\n", size); return XQC_SOCKET_ERROR; @@ -1119,6 +1136,19 @@ xqc_client_write_socket_ex(uint64_t path_id, return size; } + if (g_test_case == 46) { + /* drop all initial packets to make server buffer 0rtt packets */ + header_type = send_buf[0] & 0x80; + + /* initial packet */ + uint8_t fixed_bit = send_buf[0] & 0x40; + xqc_uint_t type = (send_buf[0] & 0x30) >> 4; + if (type == 0) { + printf("... drop initial pkt, len: %zd\n", size); + return size; + } + } + if (g_enable_multipath) { g_client_path[path_id].send_size += size; } @@ -1135,7 +1165,7 @@ xqc_client_write_socket_ex(uint64_t path_id, do { errno = 0; - g_last_sock_op_time = now(); + g_last_sock_op_time = xqc_now(); if (TEST_DROP) { return send_buf_size; @@ -1164,7 +1194,7 @@ xqc_client_write_socket_ex(uint64_t path_id, // drop the first datagram packet if ((g_test_case == 205 || g_test_case == 206) && g_no_crypt && !dgram_drop_pkt1) { - int header_type = send_buf[0] & 0x80; + header_type = send_buf[0] & 0x80; if (header_type == 0x80) { // long header: 29B + 3B (frame header) int lp_type = send_buf[0] & 0x30; @@ -1258,7 +1288,7 @@ xqc_client_conn_closing_notify(xqc_connection_t *conn, } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_client_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *user) @@ -1274,7 +1304,7 @@ xqc_client_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, mmsg[i].msg_hdr.msg_iovlen = 1; } do { - errno = 0; + set_sys_errno(0); if (TEST_DROP) return vlen; if (g_test_case == 5) { /* socket send fail */ @@ -1340,23 +1370,20 @@ xqc_client_mp_write_mmsg(uint64_t path_id, } #endif - static int -xqc_client_bind_to_interface(int fd, - const char *interface_name) +xqc_client_bind_to_interface(int fd, const char *interface_name) { +#if !defined(XQC_SYS_WINDOWS) struct ifreq ifr; memset(&ifr, 0x00, sizeof(ifr)); strncpy(ifr.ifr_name, interface_name, sizeof(ifr.ifr_name) - 1); - #if !defined(__APPLE__) -// #if (XQC_TEST_MP) printf("fd: %d. bind to nic: %s\n", fd, interface_name); if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0) { printf("bind to nic error: %d, try use sudo\n", errno); return XQC_ERROR; } -// #endif +#endif #endif return XQC_OK; @@ -1364,31 +1391,38 @@ xqc_client_bind_to_interface(int fd, static int xqc_client_create_socket(int type, - const struct sockaddr *saddr, socklen_t saddr_len, char *interface) + const struct sockaddr *saddr, socklen_t saddr_len, char *interface_type) { int size; int fd = -1; + int flags; /* create fd & set socket option */ fd = socket(type, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_sys_errno()); return -1; } +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_sys_errno()); goto err; } +#endif size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } @@ -1397,10 +1431,10 @@ xqc_client_create_socket(int type, setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); #endif - g_last_sock_op_time = now(); + g_last_sock_op_time = xqc_now(); - if (interface != NULL - && xqc_client_bind_to_interface(fd, interface) < 0) + if (interface_type != NULL + && xqc_client_bind_to_interface(fd, interface_type) < 0) { printf("|xqc_client_bind_to_interface error|"); goto err; @@ -1409,7 +1443,7 @@ xqc_client_create_socket(int type, /* connect to peer addr */ #if !defined(__APPLE__) if (connect(fd, (struct sockaddr *)saddr, saddr_len) < 0) { - printf("connect socket failed, errno: %d\n", errno); + printf("connect socket failed, errno: %d\n", get_sys_errno()); goto err; } #endif @@ -1469,26 +1503,33 @@ xqc_client_init_addr(user_conn_t *user_conn, } } - static int xqc_client_create_path_socket(xqc_user_path_t *path, char *path_interface) { path->path_fd = xqc_client_create_socket((g_ipv6 ? AF_INET6 : AF_INET), - path->peer_addr, path->peer_addrlen, path_interface); + path->peer_addr, path->peer_addrlen, path_interface); if (path->path_fd < 0) { printf("|xqc_client_create_path_socket error|"); return XQC_ERROR; } +#ifndef XQC_SYS_WINDOWS + if (path_interface != NULL + && xqc_client_bind_to_interface(path->path_fd, path_interface) < 0) + { + printf("|xqc_client_bind_to_interface error|"); + return XQC_ERROR; + } if (g_test_case == 103 || g_test_case == 104) { path->rebinding_path_fd = xqc_client_create_socket((g_ipv6 ? AF_INET6 : AF_INET), - path->peer_addr, path->peer_addrlen, path_interface); + path->peer_addr, path->peer_addrlen, path_interface); if (path->rebinding_path_fd < 0) { printf("|xqc_client_create_path_socket error|"); return XQC_ERROR; } } +#endif return XQC_OK; } @@ -1588,7 +1629,7 @@ xqc_client_user_conn_create(const char *server_addr, int server_port, } - user_conn->conn_create_time = now(); + user_conn->conn_create_time = xqc_now(); int ip_type = (g_ipv6 ? AF_INET6 : AF_INET); xqc_client_init_addr(user_conn, server_addr, server_port); @@ -1734,8 +1775,8 @@ xqc_client_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1752,7 +1793,7 @@ xqc_client_conn_handshake_finished(xqc_connection_t *conn, void *user_data, void } printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, &user_conn->cid)); - printf("====>SCID:%s\n", xqc_scid_str(&user_conn->cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, &user_conn->cid)); } hsk_completed = 1; @@ -1780,32 +1821,6 @@ xqc_client_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void DEBUG; user_conn_t *user_conn = (user_conn_t *) user_data; - if (g_test_case == 18) { /* test h3 settings */ - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 512, - .qpack_enc_max_table_capacity = 4096, - .qpack_dec_max_table_capacity = 4096, - .qpack_blocked_streams = 32, - }; - xqc_h3_conn_set_settings(conn, &settings); - } - - if (g_test_case == 32) { - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 10000000, - .qpack_enc_max_table_capacity = 4096, - .qpack_dec_max_table_capacity = 4096, - .qpack_blocked_streams = 32, - }; - xqc_h3_conn_set_settings(conn, &settings); - } - - if (g_test_case == 19) { /* test header size constraints */ - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 100, - }; - xqc_h3_conn_set_settings(conn, &settings); - } user_conn->dgram_mss = xqc_h3_ext_datagram_get_mss(conn); user_conn->h3_conn = conn; @@ -1883,7 +1898,7 @@ xqc_client_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) } printf("====>DCID:%s\n", xqc_dcid_str_by_scid(p_ctx->engine, &user_conn->cid)); - printf("====>SCID:%s\n", xqc_scid_str(&user_conn->cid)); + printf("====>SCID:%s\n", xqc_scid_str(p_ctx->engine, &user_conn->cid)); hsk_completed = 1; @@ -1917,6 +1932,13 @@ xqc_client_h3_conn_ping_acked_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, } } +void +xqc_client_h3_conn_init_settings_notify(xqc_h3_conn_t *h3_conn, + xqc_h3_conn_settings_t *current_settings, void *h3c_user_data) +{ + current_settings->qpack_dec_max_table_capacity = 64 * 1024; +} + void xqc_client_h3_conn_update_cid_notify(xqc_h3_conn_t *conn, const xqc_cid_t *retire_cid, const xqc_cid_t *new_cid, void *user_data) { @@ -1926,8 +1948,8 @@ xqc_client_h3_conn_update_cid_notify(xqc_h3_conn_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1947,7 +1969,7 @@ xqc_client_stream_send(xqc_stream_t *stream, void *user_data) user_stream_t *user_stream = (user_stream_t *) user_data; if (user_stream->start_time == 0) { - user_stream->start_time = now(); + user_stream->start_time = xqc_now(); } if (user_stream->send_body == NULL) { @@ -2079,7 +2101,7 @@ xqc_client_stream_read_notify(xqc_stream_t *stream, void *user_data) user_stream->recv_body_len += read; user_stream->recv_log_bytes += read; - xqc_msec_t curr_time = now(); + xqc_usec_t curr_time = xqc_now(); if ((curr_time - user_stream->last_recv_log_time) >= 200000) { printf("[qperf]|ts:%"PRIu64"|recv_size:%"PRIu64"|\n", curr_time, user_stream->recv_log_bytes); user_stream->last_recv_log_time = curr_time; @@ -2093,12 +2115,12 @@ xqc_client_stream_read_notify(xqc_stream_t *stream, void *user_data) /* test first frame rendering time */ if (g_test_case == 14 && user_stream->first_frame_time == 0 && user_stream->recv_body_len >= 98*1024) { - user_stream->first_frame_time = now(); + user_stream->first_frame_time = xqc_now(); } /* test abnormal rate */ if (g_test_case == 14) { - xqc_msec_t tmp = now(); + xqc_usec_t tmp = xqc_now(); if (tmp - user_stream->last_read_time > 150*1000 && user_stream->last_read_time != 0 ) { user_stream->abnormal_count++; printf("\033[33m!!!!!!!!!!!!!!!!!!!!abnormal!!!!!!!!!!!!!!!!!!!!!!!!\033[0m\n"); @@ -2108,15 +2130,15 @@ xqc_client_stream_read_notify(xqc_stream_t *stream, void *user_data) if (fin) { user_stream->recv_fin = 1; - xqc_msec_t now_us = now(); - printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" + xqc_usec_t now_us = xqc_now(); + printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" Kbit/s \n" ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, - (user_stream->send_body_len + user_stream->recv_body_len)*1000/(now_us - user_stream->start_time), + (user_stream->send_body_len + user_stream->recv_body_len)*8000/(now_us - user_stream->start_time), user_stream->send_body_len, user_stream->recv_body_len); - printf("test_result_speed: %"PRIu64" K/s\n", - (user_stream->send_body_len + user_stream->recv_body_len)*1000/(now_us - user_stream->start_time)); + printf("test_result_speed: %"PRIu64" Kbit/s\n", + (user_stream->send_body_len + user_stream->recv_body_len)*8000/(now_us - user_stream->start_time)); printf("[rr_benchmark]|request_time:%"PRIu64"|" "request_size:%zu|response_size:%zu|\n", @@ -2161,7 +2183,7 @@ xqc_client_stream_close_notify(xqc_stream_t *stream, void *user_data) /* test first frame rendering time */ if (g_test_case == 14) { printf("first_frame_time: %"PRIu64", start_time: %"PRIu64"\n", user_stream->first_frame_time, user_stream->start_time); - xqc_msec_t t = user_stream->first_frame_time - user_stream->start_time + 200000 /* server-side time consumption */; + xqc_usec_t t = user_stream->first_frame_time - user_stream->start_time + 200000 /* server-side time consumption */; printf("\033[33m>>>>>>>> first_frame pass:%d time:%"PRIu64"\033[0m\n", t <= 1000000 ? 1 : 0, t); } @@ -2179,7 +2201,7 @@ int xqc_client_bytestream_send(xqc_h3_ext_bytestream_t *h3_bs, user_stream_t *user_stream) { if (user_stream->start_time == 0) { - user_stream->start_time = now(); + user_stream->start_time = xqc_now(); } ssize_t ret = 0; char content_len[10]; @@ -2367,7 +2389,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream } if (user_stream->start_time == 0) { - user_stream->start_time = now(); + user_stream->start_time = xqc_now(); } ssize_t ret = 0; char content_len[10]; @@ -2453,6 +2475,36 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream }, }; + if (g_test_case == 47) { + header[header_size].name.iov_base = "test_null_hdr"; + header[header_size].name.iov_len = 13; + header[header_size].value.iov_base = ""; + header[header_size].value.iov_len = 0; + header_size++; + } + + if (g_enable_fec) { + xqc_h3_priority_t h3_prio = { + .fec = 4 * 1024 + }; + xqc_h3_request_set_priority(h3_request, &h3_prio); + + h3_prio.fec = 20 * 1024; + + ret = xqc_write_http_priority(&h3_prio, g_priority, 64); + if (ret < 0) { + printf("xqc_write_http_priority error %zd\n", ret); + return ret; + } + xqc_http_header_t priority_hdr = { + .name = {.iov_base = "priority", .iov_len = 8}, + .value = {.iov_base = g_priority, .iov_len = 63}, + .flags = 0, + }; + header[header_size] = priority_hdr; + header_size++; + } + if (g_mp_request_accelerate) { /* set local h3 priority */ xqc_h3_priority_t h3_prio = { @@ -2460,6 +2512,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream .incremental = 1, .schedule = 1, .reinject = 1, + .fec = XQC_DEFAULT_SIZE_REQ, }; xqc_h3_request_set_priority(h3_request, &h3_prio); @@ -2472,7 +2525,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream xqc_http_header_t priority_hdr = { .name = {.iov_base = "priority", .iov_len = 8}, - .value = {.iov_base = g_priority, .iov_len = strlen(g_priority)}, + .value = {.iov_base = g_priority, .iov_len = 63}, .flags = 0, }; header[header_size] = priority_hdr; @@ -2870,25 +2923,6 @@ xqc_client_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ fin = 1; } - /* close initial path */ - if (g_test_case == 100 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - - /* close new path */ - if (g_test_case == 101 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 1); - mp_has_closed = 1; - } - - /* close all path */ - if (g_test_case == 102 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 1); - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - // mpshell: 批量测试,无需打印 // printf("xqc_h3_request_recv_body read:%zd, offset:%zu, fin:%d\n", read_sum, user_stream->recv_body_len, fin); } @@ -2905,13 +2939,15 @@ xqc_client_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ user_stream->recv_fin = 1; xqc_request_stats_t stats; stats = xqc_h3_request_get_stats(h3_request); - xqc_msec_t now_us = now(); - printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" + xqc_usec_t now_us = xqc_now(); + printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" Kbit/s \n" ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, - (stats.send_body_size + stats.recv_body_size)*1000/(now_us - user_stream->start_time), + (stats.send_body_size + stats.recv_body_size)*8000/(now_us - user_stream->start_time), stats.send_body_size, stats.recv_body_size); - printf("test_result_speed: %"PRIu64" K/s. request_cnt: %d.\n", (stats.send_body_size + stats.recv_body_size)*1000/(now_us - user_stream->start_time), g_req_cnt); + printf("test_result_speed: %"PRIu64" Kbit/s. request_cnt: %d.\n", (stats.send_body_size + stats.recv_body_size)*8000/(now_us - user_stream->start_time), g_req_cnt); + + printf("retx:%u, sent:%u, max_pto:%u\n", stats.retrans_cnt, stats.sent_pkt_cnt, stats.max_pto_backoff); printf("[rr_benchmark]|request_time:%"PRIu64"|" "request_size:%zu|response_size:%zu|\n", @@ -2959,6 +2995,8 @@ xqc_client_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) stats.mp_standby_path_send_weight, stats.mp_standby_path_recv_weight, stats.stream_info); + printf("retx:%u, sent:%u, max_pto:%u\n", stats.retrans_cnt, stats.sent_pkt_cnt, stats.max_pto_backoff); + if (g_echo_check) { int pass = 0; if (user_stream->recv_fin && user_stream->send_body_len == user_stream->recv_body_len @@ -2988,19 +3026,7 @@ xqc_client_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) free(user_stream); return 0; } - - /* close initial path */ - if (g_test_case == 105 && !mp_has_closed) { - xqc_conn_close_path(p_ctx->engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - - /* close new path */ - if (g_test_case == 106 && !mp_has_closed) { - xqc_conn_close_path(p_ctx->engine, &user_stream->user_conn->cid, 1); - mp_has_closed = 1; - } - + printf("***** xqc_client_request_send\n"); xqc_client_request_send(user_stream->h3_request, user_stream); xqc_engine_main_logic(p_ctx->engine); @@ -3090,21 +3116,14 @@ xqc_client_socket_read_handler(user_conn_t *user_conn, int fd) break; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); for (int i = 0; i < retval; i++) { recv_sum += msgs[i].msg_len; -#ifdef XQC_NO_PID_PACKET_PROCESS - ret = xqc_engine_packet_process(p_ctx->engine, iovecs[i].iov_base, msgs[i].msg_len, - user_conn->local_addr, user_conn->local_addrlen, - user_conn->peer_addr, user_conn->peer_addrlen, - (xqc_msec_t)recv_time, user_conn); -#else ret = xqc_engine_packet_process(p_ctx->engine, iovecs[i].iov_base, msgs[i].msg_len, user_conn->local_addr, user_conn->local_addrlen, user_conn->peer_addr, user_conn->peer_addrlen, - path_id, (xqc_msec_t)recv_time, user_conn); -#endif + (xqc_usec_t)recv_time, user_conn); if (ret != XQC_OK) { printf("xqc_server_read_handler: packet process err, ret: %d\n", ret); @@ -3125,12 +3144,12 @@ xqc_client_socket_read_handler(user_conn_t *user_conn, int fd) recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, user_conn->peer_addr, &user_conn->peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("recvfrom: recvmsg = %zd(%s)\n", recv_size, strerror(errno)); + printf("recvfrom: recvmsg = %zd(%s)\n", recv_size, strerror(get_sys_errno())); break; } @@ -3147,13 +3166,13 @@ xqc_client_socket_read_handler(user_conn_t *user_conn, int fd) socklen_t tmp = sizeof(struct sockaddr_in6); int ret = getsockname(user_conn->fd, (struct sockaddr *) user_conn->local_addr, &tmp); if (ret < 0) { - printf("getsockname error, errno: %d\n", errno); + printf("getsockname error, errno: %d\n", get_sys_errno()); break; } user_conn->local_addrlen = tmp; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); g_last_sock_op_time = recv_time; @@ -3192,17 +3211,11 @@ xqc_client_socket_read_handler(user_conn_t *user_conn, int fd) continue; } } -#ifdef XQC_NO_PID_PACKET_PROCESS - ret = xqc_engine_packet_process(p_ctx->engine, packet_buf, recv_size, - user_conn->local_addr, user_conn->local_addrlen, - user_conn->peer_addr, user_conn->peer_addrlen, - (xqc_msec_t)recv_time, user_conn); -#else + ret = xqc_engine_packet_process(p_ctx->engine, packet_buf, recv_size, user_conn->local_addr, user_conn->local_addrlen, user_conn->peer_addr, user_conn->peer_addrlen, - path_id, (xqc_msec_t)recv_time, user_conn); -#endif + (xqc_usec_t)recv_time, user_conn); if (ret != XQC_OK) { printf("xqc_client_read_handler: packet process err, ret: %d\n", ret); return; @@ -3216,10 +3229,10 @@ xqc_client_socket_read_handler(user_conn_t *user_conn, int fd) } while (recv_size > 0); - if ((now() - last_recv_ts) > 200000) { + if ((xqc_now() - last_recv_ts) > 200000) { // mpshell - // printf("recving rate: %.3lf Kbps\n", (rcv_sum - last_rcv_sum) * 8.0 * 1000 / (now() - last_recv_ts)); - last_recv_ts = now(); + // printf("recving rate: %.3lf Kbps\n", (rcv_sum - last_rcv_sum) * 8.0 * 1000 / (xqc_now() - last_recv_ts)); + last_recv_ts = xqc_now(); last_rcv_sum = rcv_sum; } @@ -3253,7 +3266,7 @@ static void xqc_client_engine_callback(int fd, short what, void *arg) { // mpshell: 批量测试,无需打印 - // printf("engine timer wakeup now:%"PRIu64"\n", now()); + // printf("engine timer wakeup now:%"PRIu64"\n", xqc_now()); client_ctx_t *ctx = (client_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); @@ -3264,7 +3277,7 @@ xqc_client_abs_timeout_callback(int fd, short what, void *arg) { user_conn_t *user_conn = (user_conn_t *) arg; int rc; - printf("[qperf]|ts:%"PRIu64"|test_end|\n", now()); + printf("[qperf]|ts:%"PRIu64"|test_end|\n", xqc_now()); printf("xqc_client_abs_timeout_callback | forced conn_close\n"); rc = xqc_conn_close(ctx.engine, &user_conn->cid); if (rc) { @@ -3353,7 +3366,7 @@ static void xqc_client_timeout_callback(int fd, short what, void *arg) { // mpshell - // printf("xqc_client_timeout_callback now %"PRIu64"\n", now()); + // printf("xqc_client_timeout_callback now %"PRIu64"\n", xqc_now()); user_conn_t *user_conn = (user_conn_t *) arg; int rc; static int restart_after_a_while = 1; @@ -3371,7 +3384,7 @@ xqc_client_timeout_callback(int fd, short what, void *arg) }*/ - if (now() - g_last_sock_op_time < (uint64_t)g_conn_timeout * 1000000) { + if (xqc_now() - g_last_sock_op_time < (uint64_t)g_conn_timeout * 1000000) { struct timeval tv; tv.tv_sec = g_conn_timeout; tv.tv_usec = 0; @@ -3466,10 +3479,11 @@ xqc_client_path_callback(int fd, short what, void *arg) static int base = 0; int path_index = rand() % 2; base++; - printf("***** remove a path. index: %d, path_id: %" PRIu64 ". now:%"PRIu64"\n", path_index, g_client_path[path_index].path_id, now()); + printf("***** remove a path. index: %d, path_id: %" PRIu64 ". now:%"PRIu64"\n", + path_index, g_client_path[path_index].path_id, xqc_now()); xqc_conn_close_path(ctx.engine, &user_conn->cid, g_client_path[path_index].path_id); xqc_engine_main_logic(ctx.engine); - // printf("***** finish call. now:%"PRIu64"\n", now()); + // printf("***** finish call. now:%"PRIu64"\n", xqc_now()); } } @@ -3495,7 +3509,7 @@ xqc_client_epoch_callback(int fd, short what, void *arg) g_req_cnt++; user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); user_stream->user_conn = user_conn; - user_stream->last_recv_log_time = now(); + user_stream->last_recv_log_time = xqc_now(); user_stream->recv_log_bytes = 0; if (user_conn->h3 == 0 || user_conn->h3 == 2) { user_stream->h3_request = xqc_h3_request_create(ctx.engine, &user_conn->cid, NULL, user_stream); @@ -3562,6 +3576,22 @@ xqc_client_epoch_callback(int fd, short what, void *arg) } } + /* close initial path */ + if (g_test_case == 100 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 0); + } + + /* close new path */ + if (g_test_case == 101 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 1); + } + + /* close all path */ + if (g_test_case == 102 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 1); + xqc_conn_close_path(ctx.engine, &user_conn->cid, 0); + } + if (g_cur_epoch < g_epoch) { struct timeval tv; tv.tv_sec = g_epoch_timeout / 1000000; @@ -3619,6 +3649,29 @@ xqc_client_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e } } +void +xqc_client_write_qlog(qlog_event_importance_t imp, const void *buf, size_t count, void *engine_user_data) +{ + unsigned char log_buf[XQC_MAX_LOG_LEN + 1]; + + client_ctx_t *ctx = (client_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + printf("xqc_client_write_qlog fd err\n"); + return; + } + + int log_len = snprintf(log_buf, XQC_MAX_LOG_LEN + 1, "%s\n", (char *)buf); + if (log_len < 0) { + printf("xqc_client_write_qlog err\n"); + return; + } + + int write_len = write(ctx->log_fd, log_buf, log_len); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", errno); + } +} + /** * key log functions @@ -3657,7 +3710,7 @@ xqc_keylog_cb(const xqc_cid_t *scid, const char *line, void *user_data) return; } - printf("scid:%s\n", xqc_scid_str(scid)); + printf("scid:%s\n", xqc_scid_str(ctx->engine, scid)); int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { @@ -3720,7 +3773,7 @@ xqc_client_ready_to_create_path(const xqc_cid_t *cid, } } - if (g_mp_backup_mode) { + if (g_mp_backup_mode || g_enable_fec) { ret = xqc_conn_mark_path_standby(ctx.engine, &(user_conn->cid), path_id); if (ret < 0) { printf("xqc_conn_mark_path_standby err = %d\n", ret); @@ -3736,6 +3789,47 @@ xqc_client_ready_to_create_path(const xqc_cid_t *cid, } } + + + +static void +xqc_client_create_req_callback(int fd, short what, void *arg) +{ + user_conn_t *user_conn = (user_conn_t *)arg; + if (user_conn->cur_stream_num < g_req_paral) { + int i = 0; + for (i = 0; i < g_req_per_time; i++) { + user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); + //user_stream_t * user_stream = client_create_user_stream(user_conn->ctx->engine, user_conn, &user_conn->cid); + if (user_stream == NULL) { + printf("error create user_stream\n"); + return; + } + + if (user_conn->h3 == 0 || user_conn->h3 == 2) { + user_stream->h3_request = xqc_h3_request_create(user_conn->ctx->engine, &user_conn->cid, NULL, user_stream); + if (user_stream->h3_request == NULL) { + printf("xqc_h3_request_create error\n"); + free(user_stream); + continue; + } + } + user_stream->user_conn = user_conn; + xqc_client_request_send(user_stream->h3_request, user_stream); + user_conn->cur_stream_num++; + if (user_conn->cur_stream_num >= g_req_paral) { + break; + } + } + } + if (user_conn->cur_stream_num < g_req_paral) { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + event_add(user_conn->ev_request, &tv); + } +} + static void xqc_client_concurrent_callback(int fd, short what, void *arg){ client_ctx_t *ctx = (client_ctx_t *)arg; struct timeval tv; @@ -3780,7 +3874,7 @@ static void xqc_client_concurrent_callback(int fd, short what, void *arg){ } }; - xqc_engine_register_alpn(ctx->engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + xqc_engine_register_alpn(ctx->engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); if (g_conn_count < g_max_conn_num) { @@ -3827,25 +3921,33 @@ static void xqc_client_concurrent_callback(int fd, short what, void *arg){ g_conn_count++; ctx->cur_conn_num++; memcpy(&user_conn->cid, cid, sizeof(*cid)); + - while (user_conn->cur_stream_num < g_req_paral) { + if (g_req_per_time) { + user_conn->ev_request = event_new(ctx->eb, -1, 0, xqc_client_create_req_callback, user_conn); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500000; + event_add(user_conn->ev_request, &tv); + + } else { + while (user_conn->cur_stream_num < g_req_paral) { - user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); - user_stream->user_conn = user_conn; - if (user_conn->h3 == 0 || user_conn->h3 == 2) { - user_stream->h3_request = xqc_h3_request_create(ctx->engine, cid, NULL, user_stream); - if (user_stream->h3_request == NULL) { - printf("xqc_h3_request_create error\n"); - continue; - } + user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); + user_stream->user_conn = user_conn; + if (user_conn->h3 == 0 || user_conn->h3 == 2) { + user_stream->h3_request = xqc_h3_request_create(ctx->engine, cid, NULL, user_stream); + if (user_stream->h3_request == NULL) { + printf("xqc_h3_request_create error\n"); + continue; + } - xqc_client_request_send(user_stream->h3_request, user_stream); + xqc_client_request_send(user_stream->h3_request, user_stream); - } - user_conn->cur_stream_num++; + } + user_conn->cur_stream_num++; + } } - - } return; } @@ -3870,7 +3972,7 @@ xqc_qch_ddos_cid_generate(const xqc_cid_t *ori_cid, uint8_t *cid_buf, size_t cid if (g_random_cid > XQC_CID_ARRAY_SIZE) { g_random_cid = XQC_CID_ARRAY_SIZE; } - int index = random()%g_random_cid; + int index = xqc_random()%g_random_cid; printf("%s\n", g_cid_array[index]); memcpy(cid_buf + cid_buf_index, g_cid_array[index], 3); cid_buf_index += 3; @@ -3878,6 +3980,26 @@ xqc_qch_ddos_cid_generate(const xqc_cid_t *ori_cid, uint8_t *cid_buf, size_t cid } } +xqc_int_t +xqc_client_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) +{ + switch (in) { + case XQC_REED_SOLOMON_CODE: + *out = XQC_REED_SOLOMON_CODE; + return XQC_OK; + case XQC_XOR_CODE: + *out = XQC_XOR_CODE; + return XQC_OK; + case XQC_PACKET_MASK_CODE: + *out = XQC_PACKET_MASK_CODE; + return XQC_OK; + default: + break; + } + + return -XQC_EFEC_SCHEME_ERROR; +} + client_ctx_t * client_create_ctx(xqc_engine_ssl_config_t *engine_ssl_config, xqc_transport_callbacks_t *tcbs, xqc_config_t *config) @@ -3893,6 +4015,7 @@ client_ctx_t * client_create_ctx(xqc_engine_ssl_config_t *engine_ssl_config, .log_callbacks = { .xqc_log_write_err = xqc_client_write_log, .xqc_log_write_stat = xqc_client_write_log, + .xqc_qlog_event_write = xqc_client_write_qlog, }, .keylog_cb = xqc_keylog_cb, .cid_generate_cb = xqc_qch_ddos_cid_generate, /* 设置cid 生产的回调函数 */ @@ -3941,7 +4064,7 @@ void usage(int argc, char *argv[]) { " -p Server port.\n" " -P Number of Parallel requests per single connection. Default 1.\n" " -n Total number of requests to send. Defaults 1.\n" -" -c Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+\n" +" -c Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ P:copa\n" " -C Pacing on.\n" " -t Connection timeout. Default 3 seconds.\n" " -T Transport protocol: 0 H3 (default), 1 Transport layer, 2 H3-ext.\n" @@ -3977,6 +4100,7 @@ void usage(int argc, char *argv[]) { " -A Multipath request accelerate on. default is 0(off).\n" " -y multipath backup path standby.\n" " -z periodically send request.\n" +" -S request per second.\n" , prog); } @@ -4017,6 +4141,13 @@ int main(int argc, char *argv[]) { int transport = 0; int use_1rtt = 0; uint64_t rate_limit = 0; + char conn_options[XQC_CO_STR_MAX_LEN] = {0}; + int g_close_red_redundancy = 0; + xqc_fec_schemes_e fec_encoder_scheme = 11; + xqc_fec_schemes_e fec_decoder_scheme = 11; + uint8_t c_qlog_disable = 0; + char c_qlog_importance = 'r'; + xqc_usec_t fec_timeout = 0; strcpy(g_log_path, "./clog"); @@ -4032,11 +4163,18 @@ int main(int argc, char *argv[]) { {"pmtud", required_argument, &long_opt_index, 5}, {"mp_ping", required_argument, &long_opt_index, 6}, {"rate_limit", required_argument, &long_opt_index, 7}, + {"conn_options", required_argument, &long_opt_index, 8}, + {"fec_encoder", required_argument, &long_opt_index, 9}, + {"fec_decoder", required_argument, &long_opt_index, 10}, + {"close_dg_red", required_argument, &long_opt_index, 11}, + {"qlog_disable", no_argument, &long_opt_index, 12}, + {"qlog_importance", required_argument, &long_opt_index, 13}, + {"fec_timeout", required_argument, &long_opt_index, 14}, {0, 0, 0, 0} }; int ch = 0; - while ((ch = getopt_long(argc, argv, "a:p:P:n:c:Ct:T:1s:w:r:l:Ed:u:H:h:Gx:6NMR:i:V:v:q:o:fe:F:D:b:B:J:Q:U:Ayz", long_opts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "a:p:P:n:c:Ct:T:1s:w:r:l:Ed:u:H:h:Gx:6NMR:i:V:v:q:o:fe:F:D:b:B:J:Q:U:AyzS:g", long_opts, NULL)) != -1) { switch (ch) { case 'U': printf("option send_datagram 0 (off), 1 (on), 2(on + batch): %s\n", optarg); @@ -4064,7 +4202,7 @@ int main(int argc, char *argv[]) { printf("option req_max :%s\n", optarg); g_req_max = atoi(optarg); break; - case 'c': /* Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ */ + case 'c': /* Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ P:copa */ c_cong_ctl = optarg[0]; if (strncmp("bbr2", optarg, 4) == 0) { c_cong_ctl = 'B'; @@ -4180,11 +4318,8 @@ int main(int argc, char *argv[]) { case 'v': /* Negotiate multipath version. 4: Multipath-04. 5: Multipath-05*/ printf("option multipath version: %s\n", optarg); - if (atoi(optarg) == 4) { - g_multipath_version = XQC_MULTIPATH_04; - - } else if (atoi(optarg) == 5) { - g_multipath_version = XQC_MULTIPATH_05; + if (atoi(optarg) == 10) { + g_multipath_version = XQC_MULTIPATH_10; } break; case 'R': @@ -4249,6 +4384,14 @@ int main(int argc, char *argv[]) { printf("option periodically send request :%s\n", "on"); g_periodically_request = 1; break; + case 'S': + printf("option stream per second:%s\n", optarg); + g_req_per_time = atoi(optarg); + break; + case 'g': + printf("option enable fec mode :on\n"); + g_enable_fec = 1; + break; /* long options */ case 0: @@ -4310,6 +4453,41 @@ int main(int argc, char *argv[]) { printf("option rate_limit: %"PRIu64" Bps\n", rate_limit); break; + case 8: + strncpy(conn_options, optarg, XQC_CO_STR_MAX_LEN); + printf("option conn_options: %s\n", conn_options); + break; + + case 9: + fec_encoder_scheme = atoi(optarg); + printf("option fec_encoder_scheme: %d\n", fec_encoder_scheme); + break; + + case 10: + fec_decoder_scheme = atoi(optarg); + printf("option fec_decoder_schemes: %d\n", fec_decoder_scheme); + break; + + case 11: + g_close_red_redundancy = atoi(optarg) ? 1 : 0; + printf("option close dgram redundancy: %d\n", g_close_red_redundancy); + break; + + case 12: + c_qlog_disable = 1; + printf("option disable qlog\n"); + break; + + case 13: + c_qlog_importance = optarg[0]; + printf("option qlog importance :%s\n", optarg); + break; + + case 14: + fec_timeout = atoi(optarg); + printf("option fec_timeout: %"PRId64"\n", fec_timeout); + break; + default: break; } @@ -4328,13 +4506,11 @@ int main(int argc, char *argv[]) { memset(g_header_value, 'v', sizeof(g_header_value)); memset(&ctx, 0, sizeof(ctx)); - if (g_test_case == 44) { - xqc_log_enable(XQC_FALSE); - } - xqc_client_open_keylog_file(&ctx); xqc_client_open_log_file(&ctx); + xqc_platform_init_env(); + xqc_engine_ssl_config_t engine_ssl_config; memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); /* client does not need to fill in private_key_file & cert_file */ @@ -4350,6 +4526,7 @@ int main(int argc, char *argv[]) { .log_callbacks = { .xqc_log_write_err = xqc_client_write_log, .xqc_log_write_stat = xqc_client_write_log, + .xqc_qlog_event_write = xqc_client_write_qlog, }, .keylog_cb = xqc_keylog_cb, }; @@ -4431,12 +4608,23 @@ int main(int argc, char *argv[]) { .keyupdate_pkt_threshold = 0, .max_datagram_frame_size = g_max_dgram_size, .enable_multipath = g_enable_multipath, + .enable_encode_fec = g_enable_fec, + .enable_decode_fec = g_enable_fec, .multipath_version = g_multipath_version, .marking_reinjection = 1, .mp_ping_on = g_mp_ping_on, .recv_rate_bytes_per_sec = rate_limit, + .close_dgram_redundancy = XQC_RED_NOT_USE }; + strncpy(conn_settings.conn_option_str, conn_options, XQC_CO_STR_MAX_LEN); + +#ifdef XQC_PROTECT_POOL_MEM + if (g_test_case == 600) { + conn_settings.protect_pool_mem = 1; + } +#endif + xqc_stream_settings_t stream_settings = { .recv_rate_bytes_per_sec = 0 }; if (g_test_case == 109) { @@ -4450,7 +4638,32 @@ int main(int argc, char *argv[]) { } if (g_pmtud_on) { - conn_settings.enable_pmtud = 1; + conn_settings.enable_pmtud = 3; + } + + if (g_test_case == 450) { + conn_settings.extended_ack_features = 2; + conn_settings.max_receive_timestamps_per_ack = 45; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 451) { + conn_settings.extended_ack_features = 0; + conn_settings.max_receive_timestamps_per_ack = 40; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 452) { + conn_settings.extended_ack_features = 2; + /* negotiation fail test, because max_receive_timestamps_per_ack > 63 */ + conn_settings.max_receive_timestamps_per_ack = 64; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 453) { + conn_settings.extended_ack_features = 2; + conn_settings.max_receive_timestamps_per_ack = 0; + conn_settings.receive_timestamps_exponent = 0; } conn_settings.pacing_on = pacing_on; @@ -4495,6 +4708,18 @@ int main(int argc, char *argv[]) { case 'd': config.cfg_log_level = XQC_LOG_DEBUG; break; default: config.cfg_log_level = XQC_LOG_DEBUG; } + + if (c_qlog_disable) { + config.cfg_log_event = 0; + } + switch(c_qlog_importance) { + case 's': config.cfg_qlog_importance = EVENT_IMPORTANCE_SELECTED; break; + case 'c': config.cfg_qlog_importance = EVENT_IMPORTANCE_CORE; break; + case 'b': config.cfg_qlog_importance = EVENT_IMPORTANCE_BASE; break; + case 'e': config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; break; + case 'r': config.cfg_qlog_importance = EVENT_IMPORTANCE_REMOVED; break; + default: config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; + } /* test different cid_len */ if (g_test_case == 13) { @@ -4506,7 +4731,7 @@ int main(int argc, char *argv[]) { conn_settings.proto_version = XQC_IDRAFT_VER_29; } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) if (g_test_case == 20) { /* test sendmmsg */ printf("test sendmmsg!\n"); tcbs.write_mmsg = xqc_client_write_mmsg; @@ -4536,8 +4761,10 @@ int main(int argc, char *argv[]) { if (g_test_case == 201) { conn_settings.max_pkt_out_size = 1216; } + if (g_test_qch_mode) { +#ifndef XQC_SYS_WINDOWS pid_t pid; int i; for (i = 1; i < g_process_num; i++) { @@ -4551,7 +4778,7 @@ int main(int argc, char *argv[]) { sleep(1); } } - +#endif client_ctx_t * ctx = NULL; ctx = client_create_ctx(&engine_ssl_config, &tcbs, &config); @@ -4569,6 +4796,11 @@ int main(int argc, char *argv[]) { ctx.ev_engine = event_new(eb, -1, 0, xqc_client_engine_callback, &ctx); + if (g_test_case == 44) { + // turn off the log switch + xqc_log_disable(XQC_TRUE); + } + ctx.engine = xqc_engine_create(XQC_ENGINE_CLIENT, &config, &engine_ssl_config, &callback, &tcbs, &ctx); if (ctx.engine == NULL) { @@ -4604,6 +4836,11 @@ int main(int argc, char *argv[]) { }, }; + if (g_test_case == 502) { + /* test h3 init settings callback */ + h3_cbs.h3c_cbs.h3_conn_init_settings = xqc_client_h3_conn_init_settings_notify; + } + /* init http3 context */ int ret = xqc_h3_ctx_init(ctx.engine, &h3_cbs); if (ret != XQC_OK) { @@ -4611,6 +4848,63 @@ int main(int argc, char *argv[]) { return ret; } + if (g_test_case == 18) { /* test h3 settings */ + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 512, + .qpack_enc_max_table_capacity = 4096, + .qpack_dec_max_table_capacity = 4096, + .qpack_blocked_streams = 32, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 32) { + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 10000000, + .qpack_enc_max_table_capacity = 4096, + .qpack_dec_max_table_capacity = 4096, + .qpack_blocked_streams = 32, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 19) { /* test header size constraints */ + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 100, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 152) { + conn_settings.proto_version = XQC_IDRAFT_VER_29; + g_test_case = 150; + } + + if (g_test_case == 153) { + conn_settings.proto_version = XQC_IDRAFT_VER_29; + g_test_case = 151; + } + + /* modify h3 default settings */ + if (g_test_case == 150) { + xqc_h3_engine_set_dec_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_enc_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + if (g_test_case == 151) { + xqc_h3_engine_set_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + /* register transport callbacks */ xqc_app_proto_callbacks_t ap_cbs = { .conn_cbs = { @@ -4633,9 +4927,9 @@ int main(int argc, char *argv[]) { } }; - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); /* test alpn negotiation failure */ - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT_TEST, 14, &ap_cbs); + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT_TEST, 14, &ap_cbs, NULL); user_conn_t *user_conn = xqc_client_user_conn_create(server_addr, server_port, transport); if (user_conn == NULL) { @@ -4691,16 +4985,52 @@ int main(int argc, char *argv[]) { conn_settings.datagram_redundant_probe = 30000; } + if (g_enable_fec) { + xqc_fec_params_t fec_params; + if (xqc_client_set_fec_scheme(fec_encoder_scheme, &fec_params.fec_encoder_schemes[0]) == XQC_OK) { + fec_params.fec_encoder_schemes_num = 1; + // limit repair number if fec scheme is xor + fec_params.fec_code_rate = 0.1; + fec_params.fec_max_symbol_num_per_block = 3; + fec_params.fec_mp_mode = XQC_FEC_MP_USE_STB; + conn_settings.fec_conn_queue_rpr_timeout = fec_timeout; + + } else { + conn_settings.enable_encode_fec = 0; + } + + if (xqc_client_set_fec_scheme(fec_decoder_scheme, &fec_params.fec_decoder_schemes[0]) == XQC_OK) { + fec_params.fec_decoder_schemes_num = 1; + + } else { + conn_settings.enable_decode_fec = 0; + } + + if (g_test_case == 80) { + fec_params.fec_code_rate = 1; + } + + conn_settings.fec_params = fec_params; + } + if (g_mp_backup_mode) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; } + if (g_close_red_redundancy) { + conn_settings.close_dgram_redundancy = XQC_RED_SET_CLOSE; + } + if (g_test_case == 501) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; conn_settings.mp_enable_reinjection = 0; conn_settings.standby_path_probe_timeout = 500; } + if (g_enable_fec) { + conn_settings.scheduler_callback = xqc_backup_fec_scheduler_cb; + } + unsigned char token[XQC_MAX_TOKEN_LEN]; int token_len = XQC_MAX_TOKEN_LEN; token_len = xqc_client_read_token(token, token_len); @@ -4806,7 +5136,7 @@ int main(int argc, char *argv[]) { g_req_cnt++; user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); user_stream->user_conn = user_conn; - user_stream->last_recv_log_time = now(); + user_stream->last_recv_log_time = xqc_now(); user_stream->recv_log_bytes = 0; user_stream->h3_request = xqc_h3_request_create(ctx.engine, cid, NULL, user_stream); if (user_stream->h3_request == NULL) { @@ -4824,7 +5154,7 @@ int main(int argc, char *argv[]) { g_bytestream_cnt++; user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); user_stream->user_conn = user_conn; - user_stream->last_recv_log_time = now(); + user_stream->last_recv_log_time = xqc_now(); user_stream->recv_log_bytes = 0; user_stream->h3_ext_bs = xqc_h3_ext_bytestream_create(ctx.engine, cid, user_stream); if (user_stream->h3_ext_bs == NULL) { @@ -4875,7 +5205,7 @@ int main(int argc, char *argv[]) { g_req_cnt++; user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); user_stream->user_conn = user_conn; - user_stream->last_recv_log_time = now(); + user_stream->last_recv_log_time = xqc_now(); user_stream->recv_log_bytes = 0; if (user_conn->h3 == 0 || user_conn->h3 == 2) { if (g_test_case == 11) { /* create stream fail */ @@ -4898,13 +5228,13 @@ int main(int argc, char *argv[]) { printf("xqc_stream_create error\n"); continue; } - printf("[qperf]|ts:%"PRIu64"|test_start|\n", now()); + printf("[qperf]|ts:%"PRIu64"|test_start|\n", xqc_now()); xqc_client_stream_send(user_stream->stream, user_stream); } } } - last_recv_ts = now(); + last_recv_ts = xqc_now(); } else { user_conn->dgram_blk->data = calloc(1, g_send_body_size); diff --git a/tests/test_server.c b/tests/test_server.c index faca4c431..3b2d135e2 100644 --- a/tests/test_server.c +++ b/tests/test_server.c @@ -7,18 +7,28 @@ #include #include #include -#include -#include -#include #include #include #include #include #include #include -#include +#include +#include #include +#include "platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#include +#else +#include "getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib, "Iphlpapi.lib") +#endif + #define XQC_FIRST_OCTET 1 int printf_null(const char *format, ...) @@ -41,6 +51,10 @@ printf_null(const char *format, ...) #define XQC_TEST_DGRAM_BATCH_SZ 32 +extern long xqc_random(void); +extern xqc_usec_t xqc_now(); + + typedef struct user_datagram_block_s { unsigned char *data; size_t data_len; @@ -136,11 +150,11 @@ int g_ipv6; int g_batch=0; int g_lb_cid_encryption_on = 0; int g_enable_multipath = 0; -// xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_05; int g_enable_reinjection = 0; int g_spec_local_addr = 0; int g_mpshell = 0; int g_endless_sending = 0; +int g_enable_fec = 0; double g_copa_ai = 1.0; double g_copa_delta = 0.05; int g_enable_h3_ext = 1; @@ -162,7 +176,6 @@ static uint64_t last_snd_ts; #define XQC_TEST_LONG_HEADER_LEN 32769 char test_long_value[XQC_TEST_LONG_HEADER_LEN] = {'\0'}; - /* CDF file format: N (N lines) @@ -226,23 +239,12 @@ get_val_from_cdf_by_p(double p) static int get_random_from_cdf() { - int r = 1 + (random() % 1000); + int r = 1 + (xqc_random() % 1000); double p = r * 1.0 / 1000; // 0.001 ~ 1 return get_val_from_cdf_by_p(p); } -static inline uint64_t -now() -{ - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; -} - - static void xqc_server_datagram_send(user_conn_t *user_conn) { @@ -532,11 +534,11 @@ xqc_server_h3_ext_datagram_read_callback(xqc_h3_conn_t *conn, const void *data, if (data_len >= 13) { dgram_type = *(uint8_t*)data; - dgram_id = *(uint32_t*)(data + 1); - timestamp = *(uint64_t*)(data + 5); + dgram_id = *(uint32_t*)((uint8_t *)data + 1); + timestamp = *(uint64_t*)((uint8_t *)data + 5); if (dgram_type == 0x32) { - printf("[h3-dgram-benchmark]|dgram_id:%u|time:%"PRIu64"|\n", dgram_id, now() - timestamp); + printf("[h3-dgram-benchmark]|dgram_id:%u|time:%"PRIu64"|\n", dgram_id, xqc_now() - timestamp); } } @@ -601,7 +603,7 @@ xqc_server_h3_ext_datagram_lost_callback(xqc_h3_conn_t *conn, uint64_t dgram_id, } void -xqc_server_set_event_timer(xqc_msec_t wake_after, void *user_data) +xqc_server_set_event_timer(xqc_usec_t wake_after, void *user_data) { xqc_server_ctx_t *ctx = (xqc_server_ctx_t *) user_data; @@ -717,8 +719,8 @@ xqc_server_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1004,8 +1006,8 @@ xqc_server_h3_conn_update_cid_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *re memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1366,7 +1368,8 @@ xqc_server_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ for (int i = 0; i < headers->count; i++) { printf("%s = %s\n", (char *)headers->headers[i].name.iov_base, (char *)headers->headers[i].value.iov_base); - if (memcmp((char *)headers->headers[i].name.iov_base, "priority", 8) == 0) { + if (headers->headers[i].name.iov_len == 8 + && memcmp((char *)headers->headers[i].name.iov_base, "priority", 8) == 0) { xqc_h3_priority_t h3_prio; xqc_int_t ret = xqc_parse_http_priority(&h3_prio, headers->headers[i].value.iov_base, @@ -1510,24 +1513,24 @@ xqc_server_write_socket(const unsigned char *buf, size_t size, } do { - errno = 0; + set_sys_errno(0); res = sendto(fd, send_buf, send_buf_size, 0, peer_addr, peer_addrlen); - //printf("xqc_server_send write %zd, %s\n", res, strerror(errno)); + // printf("xqc_server_send write %zd, %s\n", res, strerror(get_sys_errno())); if (res < 0) { - printf("xqc_server_write_socket err %zd %s\n", res, strerror(errno)); - if (errno == EAGAIN) { + printf("xqc_server_write_socket err %zd %s\n", res, strerror(get_sys_errno())); + if (get_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } else { snd_sum += res; } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (EINTR== get_sys_errno())); - if ((now() - last_snd_ts) > 200000) { + if ((xqc_now() - last_snd_ts) > 200000) { // mpshell - // printf("sending rate: %.3f Kbps\n", (snd_sum - last_snd_sum) * 8.0 * 1000 / (now() - last_snd_ts)); - last_snd_ts = now(); + // printf("sending rate: %.3f Kbps\n", (snd_sum - last_snd_sum) * 8.0 * 1000 / (xqc_now() - last_snd_ts)); + last_snd_ts = xqc_now(); last_snd_sum = snd_sum; } @@ -1628,20 +1631,13 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) break; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); for (int i = 0; i < retval; i++) { recv_sum += msgs[i].msg_len; -#ifdef XQC_NO_PID_PACKET_PROCESS if (xqc_engine_packet_process(ctx->engine, iovecs[i].iov_base, msgs[i].msg_len, (struct sockaddr *) (&ctx->local_addr), ctx->local_addrlen, (struct sockaddr *) (&pa[i]), peer_addrlen, - (xqc_msec_t)recv_time, NULL) != XQC_OK) -#else - if (xqc_engine_packet_process(ctx->engine, iovecs[i].iov_base, msgs[i].msg_len, - (struct sockaddr *) (&ctx->local_addr), ctx->local_addrlen, - (struct sockaddr *) (&pa[i]), peer_addrlen, - XQC_UNKNOWN_PATH_ID, (xqc_msec_t)recv_time, NULL) != XQC_OK) -#endif + (xqc_usec_t)recv_time, NULL) != XQC_OK) { printf("xqc_server_read_handler: packet process err\n"); return; @@ -1655,12 +1651,12 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) do { recv_size = recvfrom(ctx->fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *) &peer_addr, &peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(errno)); + printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); break; } @@ -1676,22 +1672,15 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) recv_sum += recv_size; - recv_time = now(); - //printf("xqc_server_read_handler recv_size=%zd, recv_time=%llu, now=%llu, recv_total=%d\n", recv_size, recv_time, now(), ++g_recv_total); + recv_time = xqc_now(); + //printf("xqc_server_read_handler recv_size=%zd, recv_time=%llu, now=%llu, recv_total=%d\n", recv_size, recv_time, xqc_now(), ++g_recv_total); /*printf("peer_ip: %s, peer_port: %d\n", inet_ntoa(ctx->peer_addr.sin_addr), ntohs(ctx->peer_addr.sin_port)); printf("local_ip: %s, local_port: %d\n", inet_ntoa(ctx->local_addr.sin_addr), ntohs(ctx->local_addr.sin_port));*/ -#ifdef XQC_NO_PID_PACKET_PROCESS ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, (struct sockaddr *) (&ctx->local_addr), ctx->local_addrlen, (struct sockaddr *) (&peer_addr), peer_addrlen, - (xqc_msec_t) recv_time, NULL); -#else - ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, - (struct sockaddr *) (&ctx->local_addr), ctx->local_addrlen, - (struct sockaddr *) (&peer_addr), peer_addrlen, - XQC_UNKNOWN_PATH_ID, (xqc_msec_t) recv_time, NULL); -#endif + (xqc_usec_t) recv_time, NULL); if (ret != XQC_OK) { printf("xqc_server_read_handler: packet process err: %d\n", ret); @@ -1737,6 +1726,8 @@ xqc_server_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t return -1; } + printf("-- server_accept user_conn: %p\n", user_conn); + memcpy(&user_conn->cid, cid, sizeof(*cid)); if (g_test_case == 11) { @@ -1747,7 +1738,7 @@ xqc_server_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t if (g_batch) { int ret = connect(ctx.fd, (struct sockaddr *)&user_conn->peer_addr, user_conn->peer_addrlen); if (ret != 0) { - printf("connect error, errno: %d\n", errno); + printf("connect error, errno: %d\n", get_sys_errno()); return ret; } } @@ -1755,6 +1746,17 @@ xqc_server_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t return 0; } +void +xqc_server_refuse(xqc_engine_t *engine, xqc_connection_t *conn, + const xqc_cid_t *cid, void *user_data) +{ + user_conn_t *user_conn = (user_conn_t *)user_data; + printf("-- server_refuse user_conn: %p\n", user_conn); + + free(user_conn); + user_conn = NULL; +} + static int xqc_server_create_socket(const char *addr, unsigned int port) { @@ -1767,29 +1769,35 @@ xqc_server_create_socket(const char *addr, unsigned int port) fd = socket(type, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_sys_errno()); return -1; } +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &optval) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { printf("set socket nonblock failed, errno: %d\n", errno); goto err; } +#endif optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_sys_errno()); goto err; } @@ -1813,7 +1821,7 @@ xqc_server_create_socket(const char *addr, unsigned int port) } if (bind(fd, saddr, ctx.local_addrlen) < 0) { - printf("bind socket failed, errno: %d\n", errno); + printf("bind socket failed, errno: %d\n", get_sys_errno()); goto err; } @@ -1828,9 +1836,8 @@ xqc_server_create_socket(const char *addr, unsigned int port) static void xqc_server_engine_callback(int fd, short what, void *arg) { - //DEBUG; // mpshell - // printf("timer wakeup now:%"PRIu64"\n", now()); + // printf("timer wakeup now:%"PRIu64"\n", xqc_now()); xqc_server_ctx_t *ctx = (xqc_server_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); @@ -1924,7 +1931,30 @@ xqc_server_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e int write_len = write(ctx->log_fd, log_buf, log_len); if (write_len < 0) { - printf("xqc_server_write_log write failed, errno: %d\n", errno); + printf("xqc_server_write_log write failed, errno: %d\n", get_sys_errno()); + } +} + +void +xqc_server_write_qlog(qlog_event_importance_t imp, const void *buf, size_t count, void *engine_user_data) +{ + unsigned char log_buf[XQC_MAX_LOG_LEN + 1]; + + xqc_server_ctx_t *ctx = (xqc_server_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + printf("xqc_server_write_qlog fd err\n"); + return; + } + + int log_len = snprintf(log_buf, XQC_MAX_LOG_LEN + 1, "%s\n", (char *)buf); + if (log_len < 0) { + printf("xqc_server_write_qlog err\n"); + return; + } + + int write_len = write(ctx->log_fd, log_buf, log_len); + if (write_len < 0) { + printf("xqc_server_write_log write failed, errno: %d\n", get_sys_errno()); } } @@ -1966,20 +1996,20 @@ xqc_keylog_cb(const xqc_cid_t *scid, const char *line, void *user_data) return; } - printf("scid:%s\n", xqc_scid_str(scid)); + printf("scid:%s\n", xqc_scid_str(ctx->engine, scid)); int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); return; } write_len = write(ctx->keylog_fd, "\n", 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_sys_errno()); } } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *user) @@ -1995,7 +2025,7 @@ ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, mmsg[i].msg_hdr.msg_iovlen = 1; } do { - errno = 0; + set_sys_errno(0); res = sendmmsg(fd, mmsg, vlen, 0); if (res < 0) { printf("sendmmsg err %zd %s\n", res, strerror(errno)); @@ -2092,6 +2122,8 @@ int main(int argc, char *argv[]) { char c_cong_ctl = 'b'; char c_log_level = 'd'; int c_cong_plus = 0; + uint8_t c_qlog_disable = 0; + char c_qlog_importance = 'r'; int pacing_on = 0; strncpy(g_log_path, "./slog", sizeof(g_log_path)); @@ -2105,11 +2137,13 @@ int main(int argc, char *argv[]) { {"copa_ai_unit", required_argument, &long_opt_index, 2}, {"dgram_qos", required_argument, &long_opt_index, 3}, {"pmtud", required_argument, &long_opt_index, 4}, + {"qlog_disable", no_argument, &long_opt_index, 5}, + {"qlog_importance", required_argument, &long_opt_index, 6}, {0, 0, 0, 0} }; int ch = 0; - while ((ch = getopt_long(argc, argv, "a:p:ec:Cs:w:r:l:u:x:6bS:MR:o:EK:mLQ:U:yH", long_opts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "a:p:efc:Cs:w:r:l:u:x:6bS:MR:o:EK:mLQ:U:yH", long_opts, NULL)) != -1) { switch (ch) { case 'H': printf("option disable h3_ext\n"); @@ -2137,6 +2171,10 @@ int main(int argc, char *argv[]) { printf("option echo :%s\n", "on"); g_echo = 1; break; + case 'f': + printf("option fec: on\n"); + g_enable_fec = 1; + break; case 'c': /* Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ */ c_cong_ctl = optarg[0]; if (strncmp("bbr2", optarg, 4) == 0) { @@ -2283,6 +2321,16 @@ int main(int argc, char *argv[]) { printf("option g_pmtud_on: %d\n", g_pmtud_on); break; + case 5: + c_qlog_disable = 1; + printf("option disable qlog\n"); + break; + + case 6: + c_qlog_importance = optarg[0]; + printf("option qlog importance :%s\n", optarg); + break; + default: break; } @@ -2304,6 +2352,8 @@ int main(int argc, char *argv[]) { xqc_server_open_keylog_file(&ctx); xqc_server_open_log_file(&ctx); + xqc_platform_init_env(); + xqc_engine_ssl_config_t engine_ssl_config; memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); engine_ssl_config.private_key_file = "./server.key"; @@ -2328,6 +2378,7 @@ int main(int argc, char *argv[]) { .log_callbacks = { .xqc_log_write_err = xqc_server_write_log, .xqc_log_write_stat = xqc_server_write_log, + .xqc_qlog_event_write = xqc_server_write_qlog, }, .keylog_cb = xqc_keylog_cb, @@ -2335,6 +2386,7 @@ int main(int argc, char *argv[]) { xqc_transport_callbacks_t tcbs = { .server_accept = xqc_server_accept, + .server_refuse = xqc_server_refuse, .write_socket = xqc_server_write_socket, .write_socket_ex = xqc_server_write_socket_ex, .conn_update_cid_notify = xqc_server_conn_update_cid_notify, @@ -2404,14 +2456,17 @@ int main(int argc, char *argv[]) { }, .enable_multipath = g_enable_multipath, // .multipath_version = g_multipath_version, + .enable_encode_fec = g_enable_fec, + .enable_decode_fec = g_enable_fec, .spurious_loss_detect_on = 0, .max_datagram_frame_size = g_max_dgram_size, // .datagram_force_retrans_on = 1, .marking_reinjection = 1, + .close_dgram_redundancy = XQC_RED_NOT_USE, }; if (g_pmtud_on) { - conn_settings.enable_pmtud = 1; + conn_settings.enable_pmtud = 3; } if (g_test_case == 6) { @@ -2442,6 +2497,27 @@ int main(int argc, char *argv[]) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; } + if (g_enable_fec) { + conn_settings.scheduler_callback = xqc_backup_fec_scheduler_cb; + } + + if (g_enable_fec) { + xqc_fec_params_t fec_params; + memset(&fec_params, 0, sizeof(xqc_fec_params_t)); + xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {XQC_XOR_CODE, XQC_REED_SOLOMON_CODE, XQC_PACKET_MASK_CODE}; + for (xqc_int_t i = 0; i < 3; i++) { + fec_params.fec_encoder_schemes[i] = fec_schemes[i]; + fec_params.fec_decoder_schemes[i] = fec_schemes[i]; + } + fec_params.fec_encoder_schemes_num = 3; + fec_params.fec_decoder_schemes_num = 3; + fec_params.fec_max_window_size = 8; + fec_params.fec_code_rate = 0.2; + fec_params.fec_max_symbol_num_per_block = 10; + fec_params.fec_mp_mode = XQC_FEC_MP_USE_STB; + conn_settings.fec_params = fec_params; + } + if (g_test_case == 12) { conn_settings.linger.linger_on = 1; } @@ -2472,7 +2548,30 @@ int main(int argc, char *argv[]) { conn_settings.datagram_redundant_probe = 30000; } - xqc_server_set_conn_settings(&conn_settings); + if (g_test_case == 450) { + conn_settings.extended_ack_features = 2; + conn_settings.max_receive_timestamps_per_ack = 45; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 451) { + conn_settings.extended_ack_features = 0; + conn_settings.max_receive_timestamps_per_ack = 40; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 452) { + conn_settings.extended_ack_features = 2; + /* negotiation fail test, because max_receive_timestamps_per_ack > 63 */ + conn_settings.max_receive_timestamps_per_ack = 64; + conn_settings.receive_timestamps_exponent = 0; + } + + if (g_test_case == 453) { + conn_settings.extended_ack_features = 2; + conn_settings.max_receive_timestamps_per_ack = 0; + conn_settings.receive_timestamps_exponent = 0; + } xqc_config_t config; if (xqc_engine_get_default_config(&config, XQC_ENGINE_SERVER) < 0) { @@ -2490,10 +2589,22 @@ int main(int argc, char *argv[]) { default: config.cfg_log_level = XQC_LOG_DEBUG; } + if (c_qlog_disable) { + config.cfg_log_event = 0; + } + switch(c_qlog_importance) { + case 's': config.cfg_qlog_importance = EVENT_IMPORTANCE_SELECTED; break; + case 'c': config.cfg_qlog_importance = EVENT_IMPORTANCE_CORE; break; + case 'b': config.cfg_qlog_importance = EVENT_IMPORTANCE_BASE; break; + case 'e': config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; break; + case 'r': config.cfg_qlog_importance = EVENT_IMPORTANCE_REMOVED; break; + default: config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; + } + eb = event_base_new(); ctx.ev_engine = event_new(eb, -1, 0, xqc_server_engine_callback, &ctx); -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) if (g_batch) { tcbs.write_mmsg = xqc_server_write_mmsg, tcbs.write_mmsg_ex = xqc_server_mp_write_mmsg; @@ -2524,6 +2635,8 @@ int main(int argc, char *argv[]) { return -1; } + xqc_server_set_conn_settings(ctx.engine, &conn_settings); + /* register http3 callbacks */ xqc_h3_callbacks_t h3_cbs = { .h3c_cbs = { @@ -2587,7 +2700,27 @@ int main(int argc, char *argv[]) { return ret; } - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + /* modify h3 default settings */ + if (g_test_case == 150 || g_test_case == 152) { + xqc_h3_engine_set_dec_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_enc_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + if (g_test_case == 151 || g_test_case == 153) { + xqc_h3_engine_set_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); if (g_test_case == 10) { xqc_h3_engine_set_max_field_section_size(ctx.engine, 10000000); diff --git a/tests/unittest/main.c b/tests/unittest/main.c index 56b337ab3..8c5b1404f 100644 --- a/tests/unittest/main.c +++ b/tests/unittest/main.c @@ -18,7 +18,6 @@ #include "xqc_cubic_test.h" #include "xqc_packet_test.h" #include "xqc_stream_frame_test.h" -#include "xqc_wakeup_pq_test.h" #include "xqc_process_frame_test.h" #include "xqc_tp_test.h" #include "xqc_tls_test.h" @@ -38,7 +37,10 @@ #include "xqc_retry_test.h" #include "xqc_datagram_test.h" #include "xqc_h3_ext_test.h" - +#include "xqc_galois_test.h" +#include "xqc_fec_scheme_test.h" +#include "xqc_fec_test.h" +#include "xqc_ack_with_timestamp_test.h" static int xqc_init_suite(void) { return 0; } static int xqc_clean_suite(void) { return 0; } @@ -71,9 +73,9 @@ main() || !CU_add_test(pSuite, "xqc_test_cubic", xqc_test_cubic) || !CU_add_test(pSuite, "xqc_test_short_header_parse_cid", xqc_test_short_header_packet_parse_cid) || !CU_add_test(pSuite, "xqc_test_long_header_parse_cid", xqc_test_long_header_packet_parse_cid) + || !CU_add_test(pSuite, "xqc_test_empty_pkt", xqc_test_empty_pkt) || !CU_add_test(pSuite, "xqc_test_engine_packet_process", xqc_test_engine_packet_process) || !CU_add_test(pSuite, "xqc_test_stream_frame", xqc_test_stream_frame) - || !CU_add_test(pSuite, "xqc_test_wakeup_pq", xqc_test_wakeup_pq) || !CU_add_test(pSuite, "xqc_test_process_frame", xqc_test_process_frame) || !CU_add_test(pSuite, "xqc_test_parse_padding_frame", xqc_test_parse_padding_frame) || !CU_add_test(pSuite, "xqc_test_large_ack_frame", xqc_test_large_ack_frame) @@ -98,6 +100,12 @@ main() || !CU_add_test(pSuite, "xqc_test_retry", xqc_test_retry) || !CU_add_test(pSuite, "xqc_test_receive_invalid_dgram", xqc_test_receive_invalid_dgram) || !CU_add_test(pSuite, "xqc_test_h3_ext_frame", xqc_test_h3_ext_frame) +#ifdef XQC_ENABLE_FEC + || !CU_add_test(pSuite, "xqc_test_galois_calculation", xqc_test_galois_calculation) + || !CU_add_test(pSuite, "xqc_test_fec_scheme", xqc_test_fec_scheme) + || !CU_add_test(pSuite, "xqc_test_fec", xqc_test_fec) +#endif + || !CU_add_test(pSuite, "xqc_test_ack_with_timestamp", xqc_test_ack_with_timestamp) /* ADD TESTS HERE */) { CU_cleanup_registry(); diff --git a/tests/unittest/xqc_ack_with_timestamp_test.c b/tests/unittest/xqc_ack_with_timestamp_test.c new file mode 100644 index 000000000..a0cd7c97c --- /dev/null +++ b/tests/unittest/xqc_ack_with_timestamp_test.c @@ -0,0 +1,213 @@ +#include +#include +#include "xqc_cid_test.h" +#include "xqc_common_test.h" +#include "src/common/xqc_malloc.h" +#include "src/transport/xqc_recv_timestamps_info.h" +#include "src/transport/xqc_packet_parser.h" +#include "src/transport/xqc_frame_parser.h" +#include "src/transport/xqc_multipath.h" +#include "src/transport/xqc_send_ctl.h" +#include "src/transport/xqc_conn.h" + +#define test_pkt_num 13 + +void +xqc_test_ack_with_timestamp_normal() +{ + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + xqc_connection_t *conn = test_engine_connect(); + xqc_path_ctx_t *path = xqc_calloc(1, sizeof(xqc_path_ctx_t)); + path->path_pn_ctl = xqc_calloc(1, sizeof(xqc_pn_ctl_t)); + // path->path_send_ctl->ctl_largest_recv_time[pns] + path->path_send_ctl = xqc_calloc(1, sizeof(xqc_send_ctl_t)); + path->path_send_ctl->ctl_largest_recv_time[XQC_PNS_APP_DATA] = 15000; + xqc_init_list_head(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA].list_head); + packet_out->po_used_size = 0; + xqc_recv_timestamps_info_t *recv_timestamp_info = xqc_recv_timestamps_info_create(); + xqc_packet_number_t pkt_num_test_list[test_pkt_num] = {1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}; + xqc_usec_t recv_time_test_list[test_pkt_num] = {1000, 3000, 4000, 5000, 6000, 7000, 9000, 10000, 11000, 12000, 13000, 14000, 15000}; + for (int i = 0; i < test_pkt_num; i++) { + xqc_recv_timestamps_info_add_pkt(recv_timestamp_info, pkt_num_test_list[i], recv_time_test_list[i]); + xqc_recv_record_add(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA], pkt_num_test_list[i]); + } + CU_ASSERT(conn != NULL); + conn->conn_settings.extended_ack_features = 2; + conn->conn_settings.max_receive_timestamps_per_ack = 30; + conn->conn_settings.receive_timestamps_exponent = 0; + + conn->remote_settings.extended_ack_features = 2; + conn->remote_settings.max_receive_timestamps_per_ack = 30; + conn->remote_settings.receive_timestamps_exponent = 0; + conn->local_settings.max_receive_timestamps_per_ack = 30; + conn->conn_create_time = 0; + + packet_out->po_largest_ack = 15; + conn->conn_create_time = 0; + + path->recv_ts_info = recv_timestamp_info; + conn->conn_initial_path = path; + + int ret = xqc_write_ack_ext_to_one_packet(conn, packet_out, XQC_PNS_APP_DATA, 1); + CU_ASSERT(ret == XQC_OK); + packet_out->po_used_size += ret; + + xqc_packet_in_t* packet_in = xqc_calloc(1, sizeof(xqc_packet_in_t)); + packet_in->buf = packet_out->po_buf; + packet_in->pos = packet_out->po_buf; + packet_in->last = packet_out->po_buf + packet_out->po_used_size; + xqc_ack_timestamp_info_t ack_timestamp; + ack_timestamp.report_num = 0; + xqc_ack_info_t ack_info; + ret = xqc_parse_ack_ext_frame(packet_in, conn, &ack_info, &ack_timestamp); + CU_ASSERT(ret == XQC_OK); + CU_ASSERT(ack_timestamp.report_num == test_pkt_num); + for (int i = 0; i < ack_timestamp.report_num; i++) { + // printf("pkt_num:%lu, recv_ts:%lu\n", ack_timestamp.pkt_nums[i], ack_timestamp.recv_ts[i]); + CU_ASSERT(ack_timestamp.recv_ts[i] == recv_time_test_list[test_pkt_num - 1 - i]/1000); + } + xqc_engine_destroy(conn->engine); + xqc_packet_out_destroy(packet_out); + xqc_recv_timestamps_info_destroy(recv_timestamp_info); + xqc_free(packet_in); + xqc_free(path->path_pn_ctl); + xqc_free(path->path_send_ctl); + xqc_free(path); +} + +void +xqc_test_ack_with_timestamp_no_buf_space() +{ + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + xqc_connection_t *conn = test_engine_connect(); + xqc_path_ctx_t *path = xqc_calloc(1, sizeof(xqc_path_ctx_t)); + path->path_pn_ctl = xqc_calloc(1, sizeof(xqc_pn_ctl_t)); + // path->path_send_ctl->ctl_largest_recv_time[pns] + path->path_send_ctl = xqc_calloc(1, sizeof(xqc_send_ctl_t)); + path->path_send_ctl->ctl_largest_recv_time[XQC_PNS_APP_DATA] = 15000; + xqc_init_list_head(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA].list_head); + packet_out->po_used_size = 0; + xqc_recv_timestamps_info_t *recv_timestamp_info = xqc_recv_timestamps_info_create(); + xqc_packet_number_t pkt_num_test_list[test_pkt_num] = {1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}; + xqc_usec_t recv_time_test_list[test_pkt_num] = {1000, 3000, 4000, 5000, 6000, 7000, 9000, 10000, 11000, 12000, 13000, 14000, 15000}; + for (int i = 0; i < test_pkt_num; i++) { + xqc_recv_timestamps_info_add_pkt(recv_timestamp_info, pkt_num_test_list[i], recv_time_test_list[i]); + xqc_recv_record_add(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA], pkt_num_test_list[i]); + } + CU_ASSERT(conn != NULL); + conn->conn_settings.extended_ack_features = 2; + conn->conn_settings.max_receive_timestamps_per_ack = 30; + conn->conn_settings.receive_timestamps_exponent = 0; + + conn->remote_settings.extended_ack_features = 2; + conn->remote_settings.max_receive_timestamps_per_ack = 30; + conn->remote_settings.receive_timestamps_exponent = 0; + conn->local_settings.max_receive_timestamps_per_ack = 30; + conn->conn_create_time = 0; + + packet_out->po_largest_ack = 15; + conn->conn_create_time = 0; + + path->recv_ts_info = recv_timestamp_info; + conn->conn_initial_path = path; + packet_out->po_used_size = 1400; + + ssize_t ret; + int has_gap; + xqc_packet_number_t largest_ack; + xqc_usec_t now = xqc_monotonic_timestamp(); + + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); + + ret = xqc_gen_ack_ext_frame(conn, packet_out, now, conn->local_settings.ack_delay_exponent, + &pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA], path->path_send_ctl->ctl_largest_recv_time[XQC_PNS_APP_DATA], + &has_gap, &largest_ack, path->recv_ts_info); + + CU_ASSERT(ret == -XQC_ENOBUF); + xqc_engine_destroy(conn->engine); + xqc_packet_out_destroy(packet_out); + xqc_recv_timestamps_info_destroy(recv_timestamp_info); + xqc_free(path->path_pn_ctl); + xqc_free(path->path_send_ctl); + xqc_free(path); +} + + +void +xqc_test_ack_with_timestamp_partial_writing() +{ + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + xqc_connection_t *conn = test_engine_connect(); + xqc_path_ctx_t *path = xqc_calloc(1, sizeof(xqc_path_ctx_t)); + path->path_pn_ctl = xqc_calloc(1, sizeof(xqc_pn_ctl_t)); + // path->path_send_ctl->ctl_largest_recv_time[pns] + path->path_send_ctl = xqc_calloc(1, sizeof(xqc_send_ctl_t)); + path->path_send_ctl->ctl_largest_recv_time[XQC_PNS_APP_DATA] = 15000; + xqc_init_list_head(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA].list_head); + packet_out->po_used_size = 0; + xqc_recv_timestamps_info_t *recv_timestamp_info = xqc_recv_timestamps_info_create(); + xqc_packet_number_t pkt_num_test_list[test_pkt_num] = {1, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}; + xqc_usec_t recv_time_test_list[test_pkt_num] = {1000, 3000, 4000, 5000, 6000, 7000, 9000, 10000, 11000, 12000, 13000, 14000, 15000}; + for (int i = 0; i < test_pkt_num; i++) { + xqc_recv_timestamps_info_add_pkt(recv_timestamp_info, pkt_num_test_list[i], recv_time_test_list[i]); + xqc_recv_record_add(&path->path_pn_ctl->ctl_recv_record[XQC_PNS_APP_DATA], pkt_num_test_list[i]); + } + CU_ASSERT(conn != NULL); + conn->conn_settings.extended_ack_features = 2; + conn->conn_settings.max_receive_timestamps_per_ack = 30; + conn->conn_settings.receive_timestamps_exponent = 0; + + conn->remote_settings.extended_ack_features = 2; + conn->remote_settings.max_receive_timestamps_per_ack = 30; + conn->remote_settings.receive_timestamps_exponent = 0; + conn->local_settings.max_receive_timestamps_per_ack = 30; + conn->conn_create_time = 0; + + packet_out->po_largest_ack = 15; + conn->conn_create_time = 0; + + path->recv_ts_info = recv_timestamp_info; + conn->conn_initial_path = path; + int used_size = 1398; + packet_out->po_used_size = used_size; + + int ret; + int has_gap; + xqc_packet_number_t largest_ack; + xqc_usec_t now = xqc_monotonic_timestamp(); + + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); + + ret = xqc_write_ack_ext_to_one_packet(conn, packet_out, XQC_PNS_APP_DATA, 1); + CU_ASSERT(ret == XQC_OK); + CU_ASSERT(recv_timestamp_info->nobuf_for_ts_in_last_ext_ack == 1); + packet_out->po_used_size += ret; + + xqc_packet_in_t* packet_in = xqc_calloc(1, sizeof(xqc_packet_in_t)); + packet_in->buf = packet_out->po_buf; + packet_in->pos = packet_out->po_buf + used_size; + packet_in->last = packet_out->po_buf + packet_out->po_used_size; + xqc_ack_timestamp_info_t ack_timestamp; + ack_timestamp.report_num = 0; + xqc_ack_info_t ack_info; + ret = xqc_parse_ack_ext_frame(packet_in, conn, &ack_info, &ack_timestamp); + CU_ASSERT(ack_info.n_ranges == 3); + CU_ASSERT(ret == XQC_OK); + CU_ASSERT(ack_timestamp.report_num == 0); + xqc_engine_destroy(conn->engine); + xqc_packet_out_destroy(packet_out); + xqc_recv_timestamps_info_destroy(recv_timestamp_info); + xqc_free(packet_in); + xqc_free(path->path_pn_ctl); + xqc_free(path->path_send_ctl); + xqc_free(path); +} + + +void +xqc_test_ack_with_timestamp() +{ + xqc_test_ack_with_timestamp_normal(); + xqc_test_ack_with_timestamp_no_buf_space(); + xqc_test_ack_with_timestamp_partial_writing(); +} \ No newline at end of file diff --git a/tests/unittest/xqc_ack_with_timestamp_test.h b/tests/unittest/xqc_ack_with_timestamp_test.h new file mode 100644 index 000000000..02a59ea96 --- /dev/null +++ b/tests/unittest/xqc_ack_with_timestamp_test.h @@ -0,0 +1,6 @@ +#ifndef XQC_ACK_WITH_TIMESTAMP_TEST_H +#define XQC_ACK_WITH_TIMESTAMP_TEST_H + +void xqc_test_ack_with_timestamp(); + +#endif \ No newline at end of file diff --git a/tests/unittest/xqc_cid_test.c b/tests/unittest/xqc_cid_test.c index 1d3587776..ab1f2dd3b 100644 --- a/tests/unittest/xqc_cid_test.c +++ b/tests/unittest/xqc_cid_test.c @@ -25,35 +25,31 @@ xqc_test_cid_basic() ret = xqc_generate_cid(conn->engine, NULL, &test_scid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &test_scid, XQC_CID_UNUSED, conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &test_scid, XQC_CID_UNUSED, conn->remote_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set.cid_set, &test_scid) != NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->scid_set.cid_set, 1), &test_scid) == XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set, &test_scid, 0) != NULL); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_delete_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_cid_set_delete_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set.cid_set, &test_scid) == NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->scid_set.cid_set, 1), &test_scid) != XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set, &test_scid, 0) == NULL); ret = xqc_generate_cid(conn->engine, NULL, &test_dcid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &test_dcid) != NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->dcid_set.cid_set, 1), &test_dcid) == XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set, &test_dcid, 0) != NULL); - ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &test_dcid); + ret = xqc_get_unused_cid(&conn->dcid_set, &test_dcid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_delete_cid(&conn->dcid_set.cid_set, &test_dcid); + ret = xqc_cid_set_delete_cid(&conn->dcid_set, &test_dcid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &test_dcid) == NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->dcid_set.cid_set, 1), &test_dcid) != XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set, &test_dcid, 0) == NULL); xqc_engine_destroy(conn->engine); } @@ -71,11 +67,11 @@ xqc_test_new_cid() /* New Conn ID */ ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(conn->scid_set.cid_set.unused_cnt == 1); + CU_ASSERT(xqc_cid_set_get_unused_cnt(&conn->scid_set, 0) == 1); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(conn->scid_set.cid_set.unused_cnt == 0); + CU_ASSERT(xqc_cid_set_get_unused_cnt(&conn->scid_set, 0) == 0); xqc_engine_destroy(conn->engine); } @@ -96,7 +92,7 @@ xqc_test_retire_cid() ret = xqc_generate_cid(conn->engine, NULL, &test_dcid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); ret = xqc_write_retire_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); @@ -116,7 +112,7 @@ xqc_test_recv_retire_cid() ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); xqc_cid_t ori_cid; @@ -135,7 +131,7 @@ xqc_test_recv_retire_cid() CU_ASSERT(packet_in.pi_frame_types == XQC_FRAME_BIT_RETIRE_CONNECTION_ID); /* ori_scid retired */ - xqc_cid_inner_t *ori_inner_cid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, &ori_cid); + xqc_cid_inner_t *ori_inner_cid = xqc_cid_in_cid_set(&conn->scid_set, &ori_cid, 0); CU_ASSERT(ori_inner_cid != NULL); CU_ASSERT(ori_inner_cid->state == XQC_CID_RETIRED); @@ -168,7 +164,7 @@ xqc_test_retire_cid_with_odcid_in_set() ret = xqc_generate_cid(conn->engine, NULL, &test_odcid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &test_odcid, XQC_CID_USED, conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &test_odcid, XQC_CID_USED, conn->remote_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); /* generate new cid with default cid_len:8 */ @@ -178,7 +174,7 @@ xqc_test_retire_cid_with_odcid_in_set() ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); /* retire user_scid */ diff --git a/tests/unittest/xqc_common_test.c b/tests/unittest/xqc_common_test.c index a96673c44..4cba6b555 100644 --- a/tests/unittest/xqc_common_test.c +++ b/tests/unittest/xqc_common_test.c @@ -269,7 +269,7 @@ test_create_engine() /* transport ALPN */ xqc_app_proto_callbacks_t transport_cbs = {{NULL}, {NULL}}; - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } @@ -313,7 +313,7 @@ test_create_engine_server() /* transport ALPN */ xqc_app_proto_callbacks_t transport_cbs = {{NULL}, {NULL}}; - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } diff --git a/tests/unittest/xqc_common_test.h b/tests/unittest/xqc_common_test.h index 395dc3f8c..967e8ae89 100644 --- a/tests/unittest/xqc_common_test.h +++ b/tests/unittest/xqc_common_test.h @@ -18,4 +18,6 @@ xqc_engine_t *test_create_engine(); xqc_engine_t *test_create_engine_server(); +extern const xqc_log_callbacks_t xqc_null_log_cb; + #endif diff --git a/tests/unittest/xqc_engine_test.c b/tests/unittest/xqc_engine_test.c index 003354d86..16286e3dc 100644 --- a/tests/unittest/xqc_engine_test.c +++ b/tests/unittest/xqc_engine_test.c @@ -45,19 +45,11 @@ xqc_test_engine_packet_process() xqc_msec_t recv_time = xqc_monotonic_timestamp(); -#ifdef XQC_NO_PID_PACKET_PROCESS xqc_int_t rc = xqc_engine_packet_process(engine, XQC_TEST_LONG_HEADER_PACKET_B, sizeof(XQC_TEST_LONG_HEADER_PACKET_B) - 1, (struct sockaddr *)(&local_addr), local_addrlen, (struct sockaddr *)(&peer_addr), peer_addrlen, - recv_time, NULL); -#else - xqc_int_t rc = xqc_engine_packet_process(engine, XQC_TEST_LONG_HEADER_PACKET_B, - sizeof(XQC_TEST_LONG_HEADER_PACKET_B) - 1, - (struct sockaddr *)(&local_addr), local_addrlen, - (struct sockaddr *)(&peer_addr), peer_addrlen, - XQC_UNKNOWN_PATH_ID, recv_time, NULL); -#endif + recv_time, NULL); //CU_ASSERT(rc == XQC_OK); /* get connection */ @@ -76,17 +68,10 @@ xqc_test_engine_packet_process() conn->conn_flag |= XQC_CONN_FLAG_HANDSHAKE_COMPLETED; recv_time = xqc_monotonic_timestamp(); -#ifdef XQC_NO_PID_PACKET_PROCESS rc = xqc_engine_packet_process(engine, XQC_TEST_SHORT_HEADER_PACKET_A, sizeof(XQC_TEST_SHORT_HEADER_PACKET_A) - 1, (struct sockaddr *)&local_addr, local_addrlen, (struct sockaddr *)&peer_addr, peer_addrlen, recv_time, NULL); -#else - rc = xqc_engine_packet_process(engine, XQC_TEST_SHORT_HEADER_PACKET_A, - sizeof(XQC_TEST_SHORT_HEADER_PACKET_A) - 1, - (struct sockaddr *)&local_addr, local_addrlen, - (struct sockaddr *)&peer_addr, peer_addrlen, XQC_UNKNOWN_PATH_ID, recv_time, NULL); -#endif //CU_ASSERT(rc == XQC_OK); xqc_engine_destroy(engine); diff --git a/tests/unittest/xqc_fec_scheme_test.c b/tests/unittest/xqc_fec_scheme_test.c new file mode 100644 index 000000000..472a0e2d0 --- /dev/null +++ b/tests/unittest/xqc_fec_scheme_test.c @@ -0,0 +1,376 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include + +#include "xqc_fec_scheme_test.h" +#include "src/transport/xqc_conn.h" +#include "src/transport/xqc_engine.h" +#include "src/transport/xqc_frame.h" +#include "src/transport/xqc_frame_parser.h" +#include "src/transport/xqc_packet_out.h" +#include "src/transport/xqc_packet_in.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/fec_schemes/xqc_xor.h" +#include "xqc_common_test.h" +#include "src/transport/fec_schemes/xqc_packet_mask.h" +#include "include/xquic/xqc_errno.h" + +char XQC_TEST_SID_FRAME[] = {0x80, 0x00, 0xfe, 0xc5, 0x00, 0x00, 0x00, 0x00}; +char XQC_TEST_RPR_FRAME[] = {0x80, 0x00, 0xfe, 0xc6, 0x00, 0x00, 0x00, 0x00}; +char XQC_TEST_STREAM[] = {0x7f, 0x6e, 0x5d, 0x4c, 0x3b}; +char XQC_TEST_REPAIR_KEY[] = {0x00}; + + +const xqc_cid_t * +test_cid_connect_fec(xqc_engine_t *engine) +{ + xqc_conn_settings_t conn_settings; + memset(&conn_settings, 0, sizeof(xqc_conn_settings_t)); + conn_settings.proto_version = XQC_VERSION_V1; + conn_settings.enable_encode_fec = 1; + conn_settings.enable_decode_fec = 1; + + xqc_conn_ssl_config_t conn_ssl_config; + memset(&conn_ssl_config, 0, sizeof(conn_ssl_config)); + const xqc_cid_t *cid = xqc_connect(engine, &conn_settings, NULL, 0, "", 0, &conn_ssl_config, + NULL, 0, "transport", NULL); + return cid; +} +static xqc_connection_t * +test_fec_connect(xqc_engine_t *engine) +{ + const xqc_cid_t *cid = test_cid_connect_fec(engine); + if (cid == NULL) { + return NULL; + } + return xqc_engine_conns_hash_find(engine, cid, 's'); +} + +xqc_connection_t * +test_engine_connect_fec() +{ + xqc_engine_t *engine = test_create_engine(); + if (engine == NULL) { + return NULL; + } + xqc_connection_t *conn = test_fec_connect(engine); + return conn; +} + +xqc_connection_t * +test_engine_connect_fec_server() +{ + xqc_engine_t *engine = test_create_engine_server(); + if (engine == NULL) { + return NULL; + } + xqc_connection_t *conn = test_fec_connect(engine); + return conn; +} + +void +xqc_test_fec_frame_err() +{ + xqc_connection_t *conn = test_engine_connect_fec(); + CU_ASSERT(conn != NULL); + xqc_packet_in_t packet_in; + packet_in.pos = XQC_TEST_SID_FRAME; + packet_in.last = packet_in.pos + sizeof(XQC_TEST_SID_FRAME); + int ret = xqc_process_frames(conn, &packet_in); + CU_ASSERT(ret == -XQC_EIGNORE_PKT); + + packet_in.pos = XQC_TEST_RPR_FRAME; + packet_in.last = packet_in.pos + sizeof(XQC_TEST_RPR_FRAME); + ret = xqc_process_frames(conn, &packet_in); + CU_ASSERT(ret == -XQC_EIGNORE_PKT); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_invalid_encoder_params() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + CU_ASSERT(conn != NULL); + + /** test invalid fec parameters */ + conn->conn_settings.fec_params.fec_encoder_scheme = XQC_XOR_CODE; + conn->conn_settings.fec_params.fec_max_symbol_num_per_block = 4; + conn->fec_ctl->fec_send_required_repair_num[0] = 2; + /** invalid repair numbers for XOR scheme */ + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, 5, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + /** invalid symbol size */ + conn->fec_ctl->fec_send_required_repair_num[0] = 1; + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, XQC_MAX_SYMBOL_SIZE + 1, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + /** test undefined fec encoder */ + conn->conn_settings.fec_callback.xqc_fec_encode = NULL; + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, 5, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + /** test null repair symbols buffer */ + conn->conn_settings.fec_callback = xqc_xor_code_cb; + conn->fec_ctl->fec_send_repair_symbols_buff[0][0].payload = NULL; + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, 5, 0); + CU_ASSERT(ret == -XQC_EMALLOC); + + /** test fec encoder processing error */ + + conn->conn_settings.fec_callback = xqc_packet_mask_code_cb; + conn->fec_ctl->fec_send_symbol_num[0] = 16; + conn->fec_ctl->fec_send_repair_symbols_buff[0][0].payload = xqc_malloc(5); + conn->fec_ctl->fec_send_repair_symbols_buff[0][0].payload_size = 5; + conn->fec_ctl->fec_send_repair_symbols_buff[0][0].is_valid = 1; + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, 5, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + xqc_free(conn->fec_ctl->fec_send_repair_symbols_buff[0][0].payload); + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[0][0], 0, NULL, + 5); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_invalid_decoder_params() +{ + xqc_int_t ret, symbol_size; + xqc_usec_t now; + xqc_list_head_t *symbol_list; + xqc_connection_t *conn = test_engine_connect_fec(); + xqc_fec_rpr_syb_t *rpr_symbol; + + CU_ASSERT(conn != NULL); + now = xqc_monotonic_timestamp();; + // when fec_recv_symbols_num is smaller than expected, should return error; + // conn->remote_settings.fec_max_symbols_num = 3; + // ret = xqc_fec_bc_decoder(conn, 0, 1); + // CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + // when fec_processed_blk_num overflow, it should process it properly; + conn->remote_settings.fec_max_symbols_num = 0; + conn->fec_ctl->fec_processed_blk_num = XQC_MAX_UINT32_VALUE; + ret = xqc_fec_bc_decoder(conn, 0, 0, now); + CU_ASSERT(ret == XQC_OK && conn->fec_ctl->fec_processed_blk_num == 0); + + + // when decoder function is NULL, should return error; + conn->conn_settings.fec_callback.xqc_fec_decode = NULL; + conn->remote_settings.fec_max_symbols_num = 3; + symbol_size = 5; + symbol_list = &conn->fec_ctl->fec_recv_src_syb_list; + // 给recv symbol list加入一些节点 + for (xqc_int_t i = 0; i < 2; i++) { + ret = xqc_insert_src_symbol_by_seq(conn, symbol_list, 0, i, &conn->fec_ctl->fec_src_syb_num, XQC_TEST_STREAM, symbol_size); + } + symbol_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 0, + .payload = XQC_TEST_STREAM, + .payload_size = symbol_size, + .repair_key = XQC_TEST_REPAIR_KEY, + .repair_key_size = 1 + }; + for (xqc_int_t i = 0; i < 1; i++) { + tmp_rpr_symbol.symbol_idx = i; + rpr_symbol = NULL; + xqc_insert_rpr_symbol_by_seq(conn, symbol_list, &tmp_rpr_symbol, &conn->fec_ctl->fec_rpr_syb_num, &rpr_symbol); + } + ret = xqc_fec_bc_decoder(conn, 0, 1, now); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + + // when recovered_failed_cnt overflow, it should process it properly; + conn->conn_settings.fec_callback.xqc_fec_decode = xqc_xor_decode; + conn->fec_ctl->fec_recover_failed_cnt = XQC_MAX_UINT32_VALUE; + ret = xqc_fec_bc_decoder(conn, 0, 0, now); + CU_ASSERT(ret == XQC_OK); + + xqc_engine_destroy(conn->engine); +} + + +void +xqc_test_init_repair_syb(xqc_fec_rpr_syb_t *symbol) +{ + symbol->block_id = 0; + symbol->symbol_idx = 0; + symbol->payload = NULL; + symbol->payload_size = 0; + symbol->repair_key = NULL; + symbol->recv_mask = NULL; + symbol->repair_key_size = 0; +} + +void +xqc_test_fec_decode() +{ + xqc_int_t ret, loss_cnt; + xqc_connection_t *conn = test_engine_connect_fec(); + char* test_buffer; + + /** test failed recover process */ + ret = xqc_process_recovered_packet(conn, XQC_TEST_STREAM, 5, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + + /** init repair symbol */ + xqc_fec_rpr_syb_t symbol; + xqc_test_init_repair_syb(&symbol); + + /** Following tests focus on fec_cc_decoder */ + /** test invalid repair symbol size */ + test_buffer = conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload; + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload = NULL; + ret = xqc_fec_cc_decoder(conn, &symbol, 0); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid fec_decode_one */ + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload = test_buffer; + symbol.payload = XQC_TEST_RPR_FRAME; + symbol.payload_size = 8; + conn->conn_settings.fec_callback.xqc_fec_decode_one = NULL; + ret = xqc_fec_cc_decoder(conn, &symbol, 0); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid fec_decode_one process */ + conn->conn_settings.fec_callback.xqc_fec_decode_one = xqc_packet_mask_decode_one; + ret = xqc_fec_cc_decoder(conn, &symbol, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + + /** Following tests focus on fec_bc_decoder */ + /** test invalid repair symbol size */ + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload = NULL; + loss_cnt = 1; + ret = xqc_fec_bc_decoder(conn, 0, loss_cnt, 0); + CU_ASSERT(ret == -XQC_EMALLOC); + + /** test invlid decode process */ + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload = test_buffer; + conn->conn_settings.fec_callback.xqc_fec_decode = xqc_xor_decode; + ret = xqc_fec_bc_decoder(conn, 0, loss_cnt, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_fec_xor_decode() +{ + size_t size; + xqc_int_t ret; + unsigned char *output[1], *pm; + xqc_connection_t *conn = test_engine_connect_fec(); + + output[0] = xqc_malloc(XQC_MAX_SYMBOL_SIZE); + size = 0; + + // empty list + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + // repair symbol size error + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 1, + .symbol_idx = 0, + .payload = XQC_TEST_STREAM, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1, + }; + xqc_init_list_head(&tmp_rpr_symbol.fec_list); + xqc_list_add(&tmp_rpr_symbol.fec_list, &conn->fec_ctl->fec_recv_rpr_syb_list); + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // rpr block idx err + tmp_rpr_symbol.payload_size = 5; + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src syb size err + xqc_fec_src_syb_t tmp_src_symbol = { + .block_id = 0, + .symbol_idx = 0, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1 + }; + tmp_rpr_symbol.block_id = 0; + xqc_init_list_head(&tmp_src_symbol.fec_list); + xqc_list_add(&tmp_src_symbol.fec_list, &conn->fec_ctl->fec_recv_src_syb_list); + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + xqc_list_del(&tmp_src_symbol.fec_list); + xqc_list_del(&tmp_rpr_symbol.fec_list); + xqc_free(output[0]); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_fec_pm_decode() +{ + xqc_int_t ret; + unsigned char *output, *pm; + xqc_connection_t *conn = test_engine_connect_fec(); + + output = xqc_calloc(1, XQC_MAX_SYMBOL_SIZE); + pm = xqc_calloc(1, XQC_MAX_RPR_KEY_SIZE); + *pm |= (1 << 7); + // output is NULL + ret = xqc_packet_mask_decode_one(conn, NULL, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + // no repair symbol + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + // repair symbol size error + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 0, + .symbol_idx = 0, + .payload = output, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1, + .recv_mask = pm + }; + xqc_init_list_head(&tmp_rpr_symbol.fec_list); + xqc_list_add(&tmp_rpr_symbol.fec_list, &conn->fec_ctl->fec_recv_rpr_syb_list); + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src symbol idx err + tmp_rpr_symbol.payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_fec_src_syb_t tmp_src_symbol = { + .block_id = 0, + .symbol_idx = 80, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1 + }; + xqc_init_list_head(&tmp_src_symbol.fec_list); + xqc_list_add(&tmp_src_symbol.fec_list, &conn->fec_ctl->fec_recv_src_syb_list); + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src symbol size err + tmp_src_symbol.symbol_idx = 0; + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + xqc_list_del(&tmp_src_symbol.fec_list); + xqc_list_del(&tmp_rpr_symbol.fec_list); + xqc_free(output); + xqc_free(pm); + xqc_engine_destroy(conn->engine); +} + +void xqc_test_fec_scheme() +{ + xqc_test_fec_frame_err(); + xqc_test_invalid_encoder_params(); + xqc_test_invalid_decoder_params(); + xqc_test_fec_decode(); + xqc_test_fec_xor_decode(); + xqc_test_fec_pm_decode(); +} diff --git a/tests/unittest/xqc_fec_scheme_test.h b/tests/unittest/xqc_fec_scheme_test.h new file mode 100644 index 000000000..62eceec7d --- /dev/null +++ b/tests/unittest/xqc_fec_scheme_test.h @@ -0,0 +1,20 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_FEC_SCHEME_TEST_H_INCLUDED_ +#define _XQC_FEC_SCHEME_TEST_H_INCLUDED_ +#include "src/common/xqc_queue.h" +#include "src/common/xqc_hash.h" +#include "xquic/xquic.h" +#include "src/common/xqc_log.h" +#include "src/transport/xqc_engine.h" + +void xqc_test_fec_scheme(); + +const xqc_cid_t *test_cid_connect_fec(xqc_engine_t *engine); +static xqc_connection_t *test_fec_connect(xqc_engine_t *engine); +xqc_connection_t *test_engine_connect_fec(); +xqc_connection_t *test_engine_connect_fec_server(); + +#endif diff --git a/tests/unittest/xqc_fec_test.c b/tests/unittest/xqc_fec_test.c new file mode 100644 index 000000000..eb8454145 --- /dev/null +++ b/tests/unittest/xqc_fec_test.c @@ -0,0 +1,233 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include +#include "xqc_fec_test.h" +#include "xqc_fec_scheme_test.h" +#include "include/xquic/xquic.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_conn.h" +#include "src/transport/xqc_packet_out.h" +#include "xqc_common_test.h" + +xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {0, XQC_XOR_CODE, XQC_REED_SOLOMON_CODE, XQC_PACKET_MASK_CODE}; + +void +xqc_test_fec_scheme_setter() +{ + xqc_int_t ret, encoder_scheme_len; + xqc_fec_schemes_e encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + + ret = xqc_set_fec_schemes(fec_schemes, 4, encoder_schemes, &encoder_scheme_len); + CU_ASSERT(ret == XQC_OK && encoder_scheme_len == 3); +} + +void +xqc_test_fec_negotiation() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + xqc_connection_t *conn_server = test_engine_connect_fec_server(); + xqc_transport_params_t params; + xqc_trans_settings_t *ls = &conn->local_settings; + + params.fec_version = XQC_ERR_FEC_VERSION; + ret = xqc_negotiate_fec_schemes(conn, params); + CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + + params.fec_version = XQC_FEC_02; + params.enable_encode_fec = 1; + params.enable_decode_fec = 1; + ls->enable_encode_fec = 1; + ls->enable_decode_fec = 1; + + params.fec_encoder_schemes_num = 2; + params.fec_decoder_schemes_num = 2; + ret = xqc_negotiate_fec_schemes(conn, params); + CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + + xqc_engine_destroy(conn->engine); + + params.fec_encoder_schemes[0] = 20; + params.fec_decoder_schemes[0] = 20; + params.fec_encoder_schemes_num = 1; + params.fec_decoder_schemes_num = 1; + + ls->fec_encoder_schemes[0] = 8; + ls->fec_decoder_schemes[0] = 8; + ls->fec_encoder_schemes_num = 1; + ls->fec_decoder_schemes_num = 1; + ret = xqc_negotiate_fec_schemes(conn_server, params); + CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + + xqc_engine_destroy(conn_server->engine); +} + + +void +xqc_test_write_repair_packet() +{ + uint8_t bm_mode; + xqc_int_t ret; + xqc_list_head_t *prev = NULL; + xqc_connection_t *conn = test_engine_connect_fec(); + + bm_mode = 0; + + ret = xqc_write_repair_packets(conn, 0, prev, 0, bm_mode); + CU_ASSERT(ret == XQC_OK); + + conn->conn_settings.fec_params.fec_max_symbol_num_per_block = 4; + conn->conn_settings.fec_params.fec_code_rate = 1; + conn->fec_ctl->fec_send_symbol_num[0] = 3; + ret = xqc_write_repair_packets(conn, 0, prev, 1, bm_mode); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + /** test repair packets number larger than maximun repair number */ + conn->fec_ctl->fec_send_required_repair_num[bm_mode] = XQC_REPAIR_LEN + 1; + ret = xqc_send_repair_packets(conn, XQC_PACKET_MASK_CODE, prev, bm_mode); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test repair packets number larger than source symbol number */ + conn->fec_ctl->fec_send_symbol_num[bm_mode] = 1; + conn->fec_ctl->fec_send_required_repair_num[bm_mode] = conn->fec_ctl->fec_send_symbol_num[bm_mode] + 1; + ret = xqc_send_repair_packets(conn, XQC_PACKET_MASK_CODE, prev, bm_mode); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid scheme */ + conn->fec_ctl->fec_send_symbol_num[bm_mode] = 4; + conn->fec_ctl->fec_send_required_repair_num[bm_mode] = 1; + ret = xqc_send_repair_packets(conn, 0, prev, bm_mode); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_gen_fec_frames() +{ + xqc_int_t ret, padding_len, limit; + xqc_connection_t *conn = test_engine_connect_fec(); + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + packet_out->po_used_size = 1000; + padding_len = 500; + limit = 1200; + ret = xqc_gen_padding_frame_with_len(conn, packet_out, padding_len, limit); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + // invalid po_used_size + packet_out->po_used_size = XQC_QUIC_MAX_MSS + 1; + ret = xqc_gen_sid_frame(conn, packet_out); + CU_ASSERT(ret == -XQC_EPARAM); + + // invalid fec_send_block_num + conn->fec_ctl->fec_send_block_num[0] = XQC_FEC_MAX_BLOCK_NUM + 1; + packet_out->po_reserved_size = 12; + packet_out->po_used_size = 0; + ret = xqc_gen_sid_frame(conn, packet_out); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + ret = xqc_gen_repair_frame(conn, NULL, 0, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + conn->conn_settings.fec_params.fec_ele_bit_size = 0; + ret = xqc_gen_repair_frame(conn, packet_out, 0, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + xqc_packet_out_destroy(packet_out); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_chk_fec_param() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + + /** test invalid repair numbers */ + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN + 1, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + /** test too low repair number */ + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, 0, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid src symbol number */ + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK + 1, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid symbol window */ + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN + 1, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + /** test invalid symbol size */ + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE + 1); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_encoder_chk_param() +{ + xqc_int_t ret, rpr_syb_num; + xqc_connection_t *conn = test_engine_connect_fec(); + + ret = xqc_fec_encoder_check_params(conn, 2, XQC_XOR_CODE, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EPARAM); + + ret = xqc_fec_encoder_check_params(conn, 1, XQC_XOR_CODE, XQC_MAX_SYMBOL_SIZE + 1); + CU_ASSERT(ret == -XQC_EPARAM); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_process_src_syb() +{ + uint8_t bm_mode; + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + + /** test invalid fec_params */ + bm_mode = 0; + packet_out->po_stream_fec_blk_mode = bm_mode; + conn->fec_ctl->fec_send_required_repair_num[bm_mode] = 0; + ret = xqc_process_fec_protected_packet(conn, packet_out); + CU_ASSERT(ret == -XQC_EPARAM); + + /** test invalid process of write sid frame */ + conn->fec_ctl->fec_send_block_mode_size[bm_mode] = 4; + conn->fec_ctl->fec_send_required_repair_num[bm_mode] = 1; + conn->conn_settings.fec_params.fec_max_window_size = XQC_SYMBOL_CACHE_LEN; + packet_out->po_used_size = 1100; + packet_out->po_payload = packet_out->po_buf + 16; + packet_out->po_flag |= XQC_POF_STREAM_NO_LEN; + ret = xqc_process_fec_protected_packet(conn, packet_out); + CU_ASSERT(ret == XQC_OK); + + /** */ + packet_out->po_flag &= ~XQC_POF_STREAM_NO_LEN; + conn->fec_ctl->fec_send_block_num[bm_mode] = XQC_FEC_MAX_BLOCK_NUM + 1; + packet_out->po_reserved_size = 12; + ret = xqc_process_fec_protected_packet(conn, packet_out); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + xqc_packet_out_destroy(packet_out); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_fec() +{ + xqc_test_fec_scheme_setter(); + xqc_test_fec_negotiation(); + xqc_test_write_repair_packet(); + xqc_test_gen_fec_frames(); + xqc_test_chk_fec_param(); + xqc_test_encoder_chk_param(); + xqc_test_process_src_syb(); +} \ No newline at end of file diff --git a/tests/unittest/xqc_fec_test.h b/tests/unittest/xqc_fec_test.h new file mode 100644 index 000000000..a47f97ed9 --- /dev/null +++ b/tests/unittest/xqc_fec_test.h @@ -0,0 +1,10 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_FEC_TEST_H_INCLUDED_ +#define _XQC_FEC_TEST_H_INCLUDED_ + +void xqc_test_fec(); + +#endif diff --git a/tests/unittest/xqc_galois_test.c b/tests/unittest/xqc_galois_test.c new file mode 100644 index 000000000..64c01f2df --- /dev/null +++ b/tests/unittest/xqc_galois_test.c @@ -0,0 +1,32 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include +#include +#include "src/transport/fec_schemes/xqc_galois_calculation.h" + + +void +xqc_test_galois_divide() +{ + xqc_int_t ret; + unsigned char res; + ret = xqc_galois_divide(0, 1, &res); + CU_ASSERT(res == 0 && ret == 0); + + ret = xqc_galois_divide(1, 0, &res); + CU_ASSERT(ret == -XQC_EPARAM); + + ret = xqc_galois_divide(5, 3, &res); + CU_ASSERT(ret == 0 && res == 3); + + ret = xqc_galois_divide(3, 5, &res); + CU_ASSERT(ret == 0 && res == 244); +} + +void +xqc_test_galois_calculation() +{ + xqc_test_galois_divide(); +} \ No newline at end of file diff --git a/tests/unittest/xqc_galois_test.h b/tests/unittest/xqc_galois_test.h new file mode 100644 index 000000000..d347f0f36 --- /dev/null +++ b/tests/unittest/xqc_galois_test.h @@ -0,0 +1,10 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef XQUIC_XQC_GALOIS_TEST_H +#define XQUIC_XQC_GALOIS_TEST_H + +void xqc_test_galois_calculation(); + +#endif //XQUIC_XQC_H3_EXT_TEST_H diff --git a/tests/unittest/xqc_h3_test.c b/tests/unittest/xqc_h3_test.c index 74f48f8ee..09c4f5304 100644 --- a/tests/unittest/xqc_h3_test.c +++ b/tests/unittest/xqc_h3_test.c @@ -430,6 +430,14 @@ xqc_test_stream() xqc_connection_t *conn = test_engine_connect(); CU_ASSERT(conn != NULL); + /* set alpn to H3 */ + if (conn->alpn) { + xqc_free(conn->alpn); + } + conn->alpn_len = strlen(XQC_ALPN_H3); + conn->alpn = xqc_calloc(1, conn->alpn_len + 1); + xqc_memcpy(conn->alpn, XQC_ALPN_H3, conn->alpn_len); + xqc_stream_t *stream = xqc_create_stream_with_conn(conn, XQC_UNDEFINE_STREAM_ID, XQC_CLI_UNI, NULL, NULL); CU_ASSERT(stream != NULL); @@ -448,4 +456,8 @@ xqc_test_stream() xqc_h3_stream_destroy(h3s); xqc_h3_conn_destroy(h3c); xqc_destroy_stream(stream); + + if (conn->alpn) { + xqc_free(conn->alpn); + } } diff --git a/tests/unittest/xqc_packet_test.c b/tests/unittest/xqc_packet_test.c index 4994beb4b..5d4cdb505 100644 --- a/tests/unittest/xqc_packet_test.c +++ b/tests/unittest/xqc_packet_test.c @@ -67,3 +67,213 @@ xqc_test_long_header_packet_parse_cid() } + + + +extern xqc_usec_t xqc_now(); + + + +typedef struct test_ctx { + xqc_engine_t *engine; + xqc_connection_t *c; + xqc_cid_t cid; + char buf[2048]; + size_t buf_len; +} test_ctx; + + +ssize_t +xqc_test_server_write(const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data) +{ + test_ctx *tctx = (test_ctx *)conn_user_data; + memcpy(tctx->buf, buf, size); + tctx->buf_len = size; + + return size; +} + +int +xqc_test_server_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, + void *user_data, void *conn_proto_data) +{ + test_ctx *tctx = (test_ctx *)user_data; + tctx->c = conn; + memcpy(&tctx->cid, cid, sizeof(xqc_cid_t)); + + xqc_conn_set_alp_user_data(conn, tctx); + + return 0; +} + +ssize_t +xqc_test_client_write(const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data) +{ + test_ctx *tctx = (test_ctx *)conn_user_data; + memcpy(tctx->buf, buf, size); + tctx->buf_len = size; + + return size; +} + +int +xqc_test_client_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, + void *user_data, void *conn_proto_data) +{ + test_ctx *tctx = (test_ctx *)user_data; + tctx->c = conn; + memcpy(&tctx->cid, cid, sizeof(xqc_cid_t)); + + xqc_conn_set_alp_user_data(conn, tctx); + + return 0; +} + +void +xqc_test_set_event_timer(xqc_msec_t wake_after, void *engine_user_data) +{ + return; +} + +xqc_engine_t * +test_create_engine_buf_server(test_ctx *tctx) +{ + xqc_engine_ssl_config_t engine_ssl_config; + engine_ssl_config.private_key_file = "./server.key"; + engine_ssl_config.cert_file = "./server.crt"; + engine_ssl_config.ciphers = XQC_TLS_CIPHERS; + engine_ssl_config.groups = XQC_TLS_GROUPS; + engine_ssl_config.session_ticket_key_len = 0; + engine_ssl_config.session_ticket_key_data = NULL; + + xqc_engine_callback_t callback = { + .set_event_timer = xqc_test_set_event_timer, + }; + + xqc_transport_callbacks_t tcbs = { + .write_socket = xqc_test_server_write, + }; + + xqc_app_proto_callbacks_t transport_cbs = { + .conn_cbs.conn_create_notify = xqc_test_server_conn_create_notify, + }; + + xqc_conn_settings_t conn_settings; + xqc_engine_t *engine = xqc_engine_create(XQC_ENGINE_SERVER, NULL, &engine_ssl_config, + &callback, &tcbs, tctx); + + /* transport ALPN */ + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); + + return engine; +} + + + +xqc_engine_t * +test_create_engine_buf_client(test_ctx *tctx) +{ + xqc_engine_ssl_config_t engine_ssl_config; + engine_ssl_config.private_key_file = "./server.key"; + engine_ssl_config.cert_file = "./server.crt"; + engine_ssl_config.ciphers = XQC_TLS_CIPHERS; + engine_ssl_config.groups = XQC_TLS_GROUPS; + engine_ssl_config.session_ticket_key_len = 0; + engine_ssl_config.session_ticket_key_data = NULL; + + xqc_engine_callback_t callback = { + .set_event_timer = xqc_test_set_event_timer, + }; + + xqc_transport_callbacks_t tcbs = { + .write_socket = xqc_test_client_write, + }; + + xqc_app_proto_callbacks_t transport_cbs = { + .conn_cbs.conn_create_notify = xqc_test_client_conn_create_notify, + }; + + xqc_conn_settings_t conn_settings; + xqc_engine_t *engine = xqc_engine_create(XQC_ENGINE_CLIENT, NULL, &engine_ssl_config, + &callback, &tcbs, tctx); + + /* transport ALPN */ + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); + + return engine; +} + + +void +xqc_test_empty_pkt() +{ + test_ctx svr_tctx = {0}; + test_ctx cli_tctx = {0}; + + svr_tctx.engine = test_create_engine_buf_server(&svr_tctx); + cli_tctx.engine = test_create_engine_buf_client(&cli_tctx); + + + xqc_conn_settings_t conn_settings; + memset(&conn_settings, 0, sizeof(xqc_conn_settings_t)); + conn_settings.proto_version = XQC_VERSION_V1; + xqc_conn_ssl_config_t conn_ssl_config; + memset(&conn_ssl_config, 0, sizeof(conn_ssl_config)); + + /* create client instance, will trigger create_notiry and write_socket */ + xqc_connect(cli_tctx.engine, &conn_settings, NULL, 0, "", 0, + &conn_ssl_config, NULL, 0, "transport", &cli_tctx); + + struct sockaddr_in6 peer_addr; + socklen_t peer_addrlen = sizeof(peer_addr); + + struct sockaddr_in6 local_addr; + socklen_t local_addrlen = sizeof(local_addr); + + /* server will process the initial packet and get the secret of initial pns */ + xqc_engine_packet_process(svr_tctx.engine, cli_tctx.buf, cli_tctx.buf_len, + (struct sockaddr *)&local_addr, local_addrlen, + (struct sockaddr *)&peer_addr, peer_addrlen, xqc_now(), &svr_tctx); + + + /* generate an Initial pkt with no payload */ + xqc_packet_out_t *po = xqc_packet_out_create(2048); + CU_ASSERT(po != NULL); + + memcpy(po->po_pkt.pkt_scid.cid_buf, cli_tctx.c->scid_set.user_scid.cid_buf, + cli_tctx.c->scid_set.user_scid.cid_len); + po->po_pkt.pkt_scid.cid_len = cli_tctx.c->scid_set.user_scid.cid_len; + + memcpy(po->po_pkt.pkt_dcid.cid_buf, cli_tctx.c->dcid_set.current_dcid.cid_buf, + cli_tctx.c->dcid_set.current_dcid.cid_len); + po->po_pkt.pkt_dcid.cid_len = cli_tctx.c->dcid_set.current_dcid.cid_len; + + ssize_t po_size = xqc_gen_long_packet_header( + po, po->po_pkt.pkt_dcid.cid_buf, po->po_pkt.pkt_dcid.cid_len, + po->po_pkt.pkt_scid.cid_buf, po->po_pkt.pkt_scid.cid_len, + NULL, 0, XQC_VERSION_V1, XQC_PKTNO_BITS); + CU_ASSERT(po_size > 0); + po->po_used_size += po_size; + + /* client encrypt the Initial pkt */ + xqc_int_t ret = xqc_packet_encrypt(cli_tctx.c, po); + CU_ASSERT(ret == XQC_OK); + + /* server decrypt the Initial pkt */ + ret = xqc_conn_process_packet(svr_tctx.c, cli_tctx.c->enc_pkt, + cli_tctx.c->enc_pkt_len, xqc_now()); + CU_ASSERT(svr_tctx.c->conn_err == TRA_PROTOCOL_VIOLATION); + + + xqc_packet_out_destroy(po); + xqc_conn_close(cli_tctx.engine, &cli_tctx.cid); + xqc_engine_destroy(cli_tctx.engine); + + xqc_conn_close(svr_tctx.engine, &svr_tctx.cid); + xqc_engine_destroy(svr_tctx.engine); +} + diff --git a/tests/unittest/xqc_packet_test.h b/tests/unittest/xqc_packet_test.h index e1f695b58..f68768ef5 100644 --- a/tests/unittest/xqc_packet_test.h +++ b/tests/unittest/xqc_packet_test.h @@ -7,5 +7,7 @@ void xqc_test_short_header_packet_parse_cid(); void xqc_test_long_header_packet_parse_cid(); +void xqc_test_empty_pkt(); + #endif diff --git a/tests/unittest/xqc_pq_test.c b/tests/unittest/xqc_pq_test.c index 52bc807c3..bb1247caf 100644 --- a/tests/unittest/xqc_pq_test.c +++ b/tests/unittest/xqc_pq_test.c @@ -11,14 +11,14 @@ xqc_test_pq() { xqc_pq_t pq; memset(&pq, 0, sizeof(pq)); - int i = xqc_pq_init(&pq, sizeof(xqc_pq_key_t), 4, xqc_default_allocator, xqc_pq_default_cmp); + int i = xqc_pq_init(&pq, sizeof(xqc_pq_key_t), 4, xqc_default_allocator, xqc_pq_default_cmp, NULL); CU_ASSERT(i == 0); - xqc_pq_push(&pq, 4); - xqc_pq_push(&pq, 5); - xqc_pq_push(&pq, 1); - xqc_pq_push(&pq, 3); - xqc_pq_push(&pq, 2); + xqc_pq_push(&pq, 4, NULL); + xqc_pq_push(&pq, 5, NULL); + xqc_pq_push(&pq, 1, NULL); + xqc_pq_push(&pq, 3, NULL); + xqc_pq_push(&pq, 2, NULL); xqc_pq_key_t key = (xqc_pq_key_t) -1; diff --git a/tests/unittest/xqc_qpack_test.c b/tests/unittest/xqc_qpack_test.c index d0588a6f2..9fa56f463 100644 --- a/tests/unittest/xqc_qpack_test.c +++ b/tests/unittest/xqc_qpack_test.c @@ -462,6 +462,7 @@ xqc_qpack_test_robust() xqc_http_header_t header_in[header_in_cnt]; for (size_t i = 0; i < header_in_cnt; i++) { xqc_http_header_t *hdr = header_in + i; + hdr->src_header = NULL; size_t nlen = (random() & 255) + 1; hdr->name.iov_base = calloc(1, nlen + 1); diff --git a/tests/unittest/xqc_tls_test.c b/tests/unittest/xqc_tls_test.c index e7bf9f8fe..304970e0a 100644 --- a/tests/unittest/xqc_tls_test.c +++ b/tests/unittest/xqc_tls_test.c @@ -13,191 +13,28 @@ #define XQC_TEST_SESSION_TICKET_KEY "\xa8\x6d\x19\x70\x06\x08\x9b\x2d" \ "\xa7\x17\x50\xf7\x97\x78\xf7\xe8\x3c\x5a\xc4\x9d\x61\x34\xe3\xa1\xfa" \ "\x62\x7b\x66\xf0\x2f\x5b\xdc\x63\x12\x8d\x10\x9a\x57\x5c\xdd\x1b\xc3" \ -"\x8f\x13\x93\x3c\x85\xe6\x0a" - -void -xqc_test_create_client_tls_ctx() -{ - xqc_engine_t *engine = test_create_engine(); - - xqc_engine_ssl_config_t engine_ssl_config; - memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); - - /* not set ciphers and groups */ - xqc_tls_ctx_t *ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx != NULL); - - SSL_CTX *ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); - CU_ASSERT(ssl_ctx != NULL); - - xqc_tls_type_t tls_type = xqc_tls_ctx_get_type(ctx); - CU_ASSERT(tls_type == XQC_TLS_TYPE_CLIENT); - - xqc_engine_ssl_config_t *cfg = NULL; - xqc_tls_ctx_get_cfg(ctx, &cfg); - CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); - CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); - - xqc_tls_ctx_destroy(ctx); - - /* set ciphers and groups */ - engine_ssl_config.ciphers = XQC_TLS_CIPHERS; - engine_ssl_config.groups = XQC_TLS_GROUPS; - - ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx != NULL); - - ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); - CU_ASSERT(ssl_ctx != NULL); - - tls_type = xqc_tls_ctx_get_type(ctx); - CU_ASSERT(tls_type == XQC_TLS_TYPE_CLIENT); - - cfg = NULL; - xqc_tls_ctx_get_cfg(ctx, &cfg); - CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); - CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); - - xqc_tls_ctx_destroy(ctx); - xqc_engine_destroy(engine); -} - -void -xqc_test_create_server_tls_ctx() -{ - xqc_engine_t *engine = test_create_engine_server(); - - xqc_engine_ssl_config_t engine_ssl_config; - memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); - - engine_ssl_config.ciphers = XQC_TLS_CIPHERS; - engine_ssl_config.groups = XQC_TLS_GROUPS; - - /* no private key file */ - xqc_tls_ctx_t *ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, - &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx == NULL); - - /* no cert file */ - engine_ssl_config.private_key_file = "./server.key"; - ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx == NULL); - - /* no session ticket key data */ - engine_ssl_config.cert_file = "./server.crt"; - engine_ssl_config.session_ticket_key_data = NULL; - engine_ssl_config.session_ticket_key_len = 0; - ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx != NULL); - - SSL_CTX *ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); - CU_ASSERT(ssl_ctx != NULL); - - xqc_tls_type_t tls_type = xqc_tls_ctx_get_type(ctx); - CU_ASSERT(tls_type == XQC_TLS_TYPE_SERVER); - - xqc_engine_ssl_config_t *cfg = NULL; - xqc_tls_ctx_get_cfg(ctx, &cfg); - CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); - CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); - CU_ASSERT(0 == strcmp(cfg->private_key_file, "./server.key")); - CU_ASSERT(0 == strcmp(cfg->cert_file, "./server.crt")); - - xqc_ssl_session_ticket_key_t *key = NULL; - xqc_tls_ctx_get_session_ticket_key(ctx, &key); - CU_ASSERT(key->size == 0); - - xqc_tls_ctx_destroy(ctx); - - /* init session ticket key error */ - engine_ssl_config.session_ticket_key_data = "test_stk"; - engine_ssl_config.session_ticket_key_len = 8; - - ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx == NULL); - - xqc_engine_destroy(engine); -} - -#define TEST_ALPN_1 "transport" -#define TEST_ALPN_2 "h3" - -void -xqc_test_tls_ctx_register_alpn() -{ - xqc_engine_t *engine = test_create_engine(); - xqc_engine_ssl_config_t engine_ssl_config; - memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); - xqc_tls_ctx_t *ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &xqc_conn_tls_cbs, engine->log); - CU_ASSERT(ctx != NULL); - - xqc_int_t ret; - uint8_t *alpn_list = NULL; - size_t alpn_list_len = 0; - - /* register alpn in tls context */ - ret = xqc_tls_ctx_register_alpn(ctx, TEST_ALPN_1, sizeof(TEST_ALPN_1) - 1); - CU_ASSERT(ret == XQC_OK); - - ret = xqc_tls_ctx_register_alpn(ctx, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); - CU_ASSERT(ret == XQC_OK); - - xqc_tls_ctx_get_alpn_list(ctx, &alpn_list, &alpn_list_len); - CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_1) + sizeof(TEST_ALPN_2)); - - /* unregister alpn in tls context */ - ret = xqc_tls_ctx_unregister_alpn(ctx, TEST_ALPN_1, sizeof(TEST_ALPN_1) - 1); - CU_ASSERT(ret == XQC_OK); - - xqc_tls_ctx_get_alpn_list(ctx, &alpn_list, &alpn_list_len); - CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_2)); - - ret = xqc_tls_ctx_unregister_alpn(ctx, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); - CU_ASSERT(ret == XQC_OK); - - xqc_tls_ctx_get_alpn_list(ctx, &alpn_list, &alpn_list_len); - CU_ASSERT(alpn_list_len == 0); - - xqc_tls_ctx_destroy(ctx); - xqc_engine_destroy(engine); -} - -void -xqc_test_tls_reset_initial() -{ - xqc_connection_t *conn = test_engine_connect(); - CU_ASSERT(conn != NULL); - - /* reset initial keys */ - xqc_int_t ret = xqc_tls_reset_initial(conn->tls, conn->version, &conn->original_dcid); - CU_ASSERT(ret == XQC_OK); - - ret = xqc_tls_is_key_ready(conn->tls, XQC_ENC_LEV_INIT, XQC_KEY_TYPE_RX_READ); - CU_ASSERT(ret == XQC_TRUE); - ret = xqc_tls_is_key_ready(conn->tls, XQC_ENC_LEV_INIT, XQC_KEY_TYPE_TX_WRITE); - CU_ASSERT(ret == XQC_TRUE); - - xqc_engine_destroy(conn->engine); -} +"\x8f\x13\x93\x3c\x85" typedef struct xqc_tls_test_buff_s { - xqc_list_head_t initial_crypto_data_list; - xqc_list_head_t hsk_crypto_data_list; - xqc_list_head_t application_crypto_data_list; - - xqc_bool_t handshake_completed; - - unsigned char *new_session_ticket; - size_t new_session_ticket_len; - - /* for test corner case: multiple crypto data */ - int crypto_data_cnt; - size_t crypto_data_total_len; - - uint64_t error_code; - + union { + struct { + xqc_list_head_t initial_crypto_data_list; + xqc_list_head_t hsk_crypto_data_list; + xqc_list_head_t application_crypto_data_list; + + xqc_bool_t handshake_completed; + + unsigned char *new_session_ticket; + size_t new_session_ticket_len; + + /* for test corner case: multiple crypto data */ + int crypto_data_cnt; + size_t crypto_data_total_len; + + uint64_t error_code; + }; + xqc_connection_t conn; + }; } xqc_tls_test_buff_t; static inline xqc_tls_test_buff_t* @@ -382,68 +219,244 @@ xqc_tls_callbacks_t tls_test_cbs = { .hsk_completed_cb = xqc_tt_handshake_completed_cb, }; -#define def_engine_ssl_config \ - xqc_engine_ssl_config_t engine_ssl_config; \ - engine_ssl_config.private_key_file = "./server.key"; \ - engine_ssl_config.cert_file = "./server.crt"; \ - engine_ssl_config.ciphers = XQC_TLS_CIPHERS; \ - engine_ssl_config.groups = XQC_TLS_GROUPS; \ - engine_ssl_config.session_ticket_key_len = 48; \ - engine_ssl_config.session_ticket_key_data = XQC_TEST_SESSION_TICKET_KEY; +#define def_engine_ssl_config_svr \ + xqc_engine_ssl_config_t engine_ssl_config_svr = {0}; \ + engine_ssl_config_svr.private_key_file = "./server.key"; \ + engine_ssl_config_svr.cert_file = "./server.crt"; \ + engine_ssl_config_svr.ciphers = XQC_TLS_CIPHERS; \ + engine_ssl_config_svr.groups = XQC_TLS_GROUPS; \ + engine_ssl_config_svr.session_ticket_key_len = 48; \ + engine_ssl_config_svr.session_ticket_key_data = XQC_TEST_SESSION_TICKET_KEY; + +#define def_engine_ssl_config_cli \ + xqc_engine_ssl_config_t engine_ssl_config_cli = {0}; \ + engine_ssl_config_cli.ciphers = XQC_TLS_CIPHERS; \ + engine_ssl_config_cli.groups = XQC_TLS_GROUPS; + +static xqc_log_t *test_log; +static xqc_tls_ctx_t *ctx_cli, *ctx_svr; void -xqc_test_tls_generic() +xqc_test_create_client_tls_ctx() +{ + xqc_engine_ssl_config_t engine_ssl_config; + memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); + + /* not set ciphers and groups */ + xqc_tls_ctx_t *ctx; + SSL_CTX *ssl_ctx; + xqc_tls_type_t tls_type; + xqc_engine_ssl_config_t *cfg = NULL; + + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, + &tls_test_cbs, test_log); + CU_ASSERT(ctx != NULL); + + ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); + CU_ASSERT(ssl_ctx != NULL); + + tls_type = xqc_tls_ctx_get_type(ctx); + CU_ASSERT(tls_type == XQC_TLS_TYPE_CLIENT); + + xqc_tls_ctx_get_cfg(ctx, &cfg); + CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); + CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); + + xqc_tls_ctx_destroy(ctx); + + /* set ciphers and groups */ + def_engine_ssl_config_cli; + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config_cli, &tls_test_cbs, test_log); + CU_ASSERT(ctx != NULL); + + ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); + CU_ASSERT(ssl_ctx != NULL); + + tls_type = xqc_tls_ctx_get_type(ctx); + CU_ASSERT(tls_type == XQC_TLS_TYPE_CLIENT); + + cfg = NULL; + xqc_tls_ctx_get_cfg(ctx, &cfg); + CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); + CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); + + ctx_cli = ctx; +} + +void +xqc_test_create_server_tls_ctx() +{ + xqc_engine_ssl_config_t engine_ssl_config; + memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); + + engine_ssl_config.ciphers = XQC_TLS_CIPHERS; + engine_ssl_config.groups = XQC_TLS_GROUPS; + /* no private key file */ + xqc_tls_ctx_t *ctx; + SSL_CTX *ssl_ctx; + xqc_tls_type_t tls_type; + xqc_engine_ssl_config_t *cfg = NULL; + xqc_ssl_session_ticket_key_t *key = NULL; + + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, + &tls_test_cbs, test_log); + CU_ASSERT(ctx == NULL); + + /* no cert file */ + engine_ssl_config.private_key_file = "./server.key"; + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &tls_test_cbs, test_log); + CU_ASSERT(ctx == NULL); + + /* no session ticket key data */ + engine_ssl_config.cert_file = "./server.crt"; + engine_ssl_config.session_ticket_key_data = NULL; + engine_ssl_config.session_ticket_key_len = 0; + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &tls_test_cbs, test_log); + CU_ASSERT(ctx != NULL); + + ssl_ctx = xqc_tls_ctx_get_ssl_ctx(ctx); + CU_ASSERT(ssl_ctx != NULL); + + tls_type = xqc_tls_ctx_get_type(ctx); + CU_ASSERT(tls_type == XQC_TLS_TYPE_SERVER); + + + xqc_tls_ctx_get_cfg(ctx, &cfg); + CU_ASSERT(0 == strcmp(cfg->ciphers, XQC_TLS_CIPHERS)); + CU_ASSERT(0 == strcmp(cfg->groups, XQC_TLS_GROUPS)); + CU_ASSERT(0 == strcmp(cfg->private_key_file, "./server.key")); + CU_ASSERT(0 == strcmp(cfg->cert_file, "./server.crt")); + + + xqc_tls_ctx_get_session_ticket_key(ctx, &key); + CU_ASSERT(key->size == 0); + + xqc_tls_ctx_destroy(ctx); + + /* init session ticket key error */ + engine_ssl_config.session_ticket_key_data = "test_stk"; + engine_ssl_config.session_ticket_key_len = 8; + + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, &tls_test_cbs, test_log); + CU_ASSERT(ctx == NULL); + + /* final one */ + def_engine_ssl_config_svr; + ctx = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config_svr, + &tls_test_cbs, test_log); + CU_ASSERT(ctx != NULL); + + ctx_svr = ctx; +} + +#define TEST_ALPN_1 "transport" +#define TEST_ALPN_2 "h3" + +void +xqc_test_tls_ctx_register_alpn() { - def_engine_ssl_config xqc_int_t ret; - int cnt; + uint8_t *alpn_list = NULL; + size_t alpn_list_len = 0; - uint8_t *data_buf = malloc(XQC_TEST_MAX_CRYPTO_DATA_BUF); - size_t data_len = 0; + /* register alpn in tls context */ + ret = xqc_tls_ctx_register_alpn(ctx_cli, TEST_ALPN_1, sizeof(TEST_ALPN_1) - 1); + CU_ASSERT(ret == XQC_OK); - /* 1-RTT */ + ret = xqc_tls_ctx_register_alpn(ctx_cli, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); + CU_ASSERT(ret == XQC_OK); - /* create server engine and tls_ctx */ - xqc_engine_t *engine_svr = test_create_engine_server(); - xqc_tls_ctx_t *ctx_svr = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, - &tls_test_cbs, engine_svr->log); - CU_ASSERT(ctx_svr != NULL); + xqc_tls_ctx_get_alpn_list(ctx_cli, &alpn_list, &alpn_list_len); + CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_1) + sizeof(TEST_ALPN_2)); - ret = xqc_tls_ctx_register_alpn(ctx_svr, "transport", 9); + /* unregister alpn in tls context */ + ret = xqc_tls_ctx_unregister_alpn(ctx_cli, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); CU_ASSERT(ret == XQC_OK); - /* create client engine and tls_ctx */ - xqc_engine_t *engine_cli = test_create_engine(); - xqc_tls_ctx_t *ctx_cli = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &tls_test_cbs, engine_cli->log); - CU_ASSERT(ctx_cli != NULL); + xqc_tls_ctx_get_alpn_list(ctx_cli, &alpn_list, &alpn_list_len); + CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_1)); - ret = xqc_tls_ctx_register_alpn(ctx_cli, "transport", 9); + /* register alpn in tls context */ + ret = xqc_tls_ctx_register_alpn(ctx_svr, TEST_ALPN_1, sizeof(TEST_ALPN_1) - 1); CU_ASSERT(ret == XQC_OK); + ret = xqc_tls_ctx_register_alpn(ctx_svr, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); + CU_ASSERT(ret == XQC_OK); + + xqc_tls_ctx_get_alpn_list(ctx_svr, &alpn_list, &alpn_list_len); + CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_1) + sizeof(TEST_ALPN_2)); + + /* unregister alpn in tls context */ + ret = xqc_tls_ctx_unregister_alpn(ctx_svr, TEST_ALPN_2, sizeof(TEST_ALPN_2) - 1); + CU_ASSERT(ret == XQC_OK); + + xqc_tls_ctx_get_alpn_list(ctx_svr, &alpn_list, &alpn_list_len); + CU_ASSERT(alpn_list_len == sizeof(TEST_ALPN_1)); +} + +void +xqc_test_tls_reset_initial() +{ /* get tls config */ - xqc_connection_t *test_conn = test_engine_connect(); xqc_tls_config_t tls_config = {0}; tls_config.session_ticket = NULL; tls_config.session_ticket_len = 0; tls_config.cert_verify_flag = 0; - tls_config.hostname = "127.0.0.1"; + tls_config.hostname = "test.xquic.com"; tls_config.alpn = "transport"; tls_config.no_crypto_flag = 0; + tls_config.trans_params = "10086"; + tls_config.trans_params_len = 5; + + /* create client tls */ + xqc_tls_test_buff_t *ttbuf_cli = xqc_create_tls_test_buffer(); + xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_cli); - /* encode local transport params */ - char tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; - tls_config.trans_params = tp_buf; - xqc_conn_encode_local_tp(test_conn, tls_config.trans_params, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tls_config.trans_params_len); + /* client start handshake, generate ClientHello */ + xqc_cid_t odcid = {1}; + + xqc_int_t ret = xqc_tls_init(tls_cli, XQC_VERSION_V1, &odcid); + CU_ASSERT(ret == XQC_OK); + + /* reset initial keys */ + ret = xqc_tls_reset_initial(tls_cli, XQC_VERSION_V1, &odcid); + CU_ASSERT(ret == XQC_OK); + + ret = xqc_tls_is_key_ready(tls_cli, XQC_ENC_LEV_INIT, XQC_KEY_TYPE_RX_READ); + CU_ASSERT(ret == XQC_TRUE); + ret = xqc_tls_is_key_ready(tls_cli, XQC_ENC_LEV_INIT, XQC_KEY_TYPE_TX_WRITE); + CU_ASSERT(ret == XQC_TRUE); + + xqc_destroy_tls_test_buffer(ttbuf_cli); + xqc_tls_destroy(tls_cli); +} + +void +xqc_test_tls_generic() +{ + xqc_int_t ret; + int cnt; + + uint8_t *data_buf = malloc(XQC_TEST_MAX_CRYPTO_DATA_BUF); + size_t data_len = 0; + + /* get tls config */ + xqc_tls_config_t tls_config = {0}; + tls_config.session_ticket = NULL; + tls_config.session_ticket_len = 0; + tls_config.cert_verify_flag = 0; + tls_config.hostname = "test.xquic.com"; + tls_config.alpn = "transport"; + tls_config.no_crypto_flag = 0; + tls_config.trans_params = "10086"; + tls_config.trans_params_len = 5; /* create client tls */ xqc_tls_test_buff_t *ttbuf_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_cli); + xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_cli); /* client start handshake, generate ClientHello */ - xqc_cid_t odcid; - xqc_generate_cid(engine_cli, NULL, &odcid, 0); + xqc_cid_t odcid = {1}; ret = xqc_tls_init(tls_cli, XQC_VERSION_V1, &odcid); CU_ASSERT(ret == XQC_OK); @@ -451,7 +464,7 @@ xqc_test_tls_generic() /* create server tls */ xqc_tls_test_buff_t *ttbuf_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_svr); + xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_svr); /* server handshake, process ClientHello, genrate ServerHello & Handshake data */ ret = xqc_tls_init(tls_svr, XQC_VERSION_V1, &odcid); @@ -492,15 +505,13 @@ xqc_test_tls_generic() CU_ASSERT(ttbuf_cli->new_session_ticket != NULL); CU_ASSERT(ttbuf_cli->new_session_ticket_len > 0); - /* 0-RTT */ - tls_config.session_ticket = ttbuf_cli->new_session_ticket; tls_config.session_ticket_len = ttbuf_cli->new_session_ticket_len; /* create client tls */ xqc_tls_test_buff_t *ttbuf_0rtt_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_0rtt_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_0rtt_cli); + xqc_tls_t *tls_0rtt_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_0rtt_cli); /* client start handshake, generate ClientHello */ ret = xqc_tls_init(tls_0rtt_cli, XQC_VERSION_V1, &odcid); @@ -509,7 +520,7 @@ xqc_test_tls_generic() /* create server tls */ xqc_tls_test_buff_t *ttbuf_0rtt_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_0rtt_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_0rtt_svr); + xqc_tls_t *tls_0rtt_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_0rtt_svr); /* server handshake, process ClientHello, genrate ServerHello & Handshake data */ ret = xqc_tls_init(tls_0rtt_svr, XQC_VERSION_V1, &odcid); @@ -542,8 +553,6 @@ xqc_test_tls_generic() CU_ASSERT(ret == XQC_OK); CU_ASSERT(ttbuf_0rtt_svr->handshake_completed == XQC_TRUE); - - xqc_destroy_tls_test_buffer(ttbuf_cli); xqc_destroy_tls_test_buffer(ttbuf_svr); xqc_destroy_tls_test_buffer(ttbuf_0rtt_cli); @@ -554,67 +563,35 @@ xqc_test_tls_generic() xqc_tls_destroy(tls_0rtt_cli); xqc_tls_destroy(tls_0rtt_svr); - xqc_tls_ctx_destroy(ctx_cli); - xqc_tls_ctx_destroy(ctx_svr); - - xqc_engine_destroy(engine_cli); - xqc_engine_destroy(engine_svr); - xqc_engine_destroy(test_conn->engine); - free(data_buf); } void xqc_test_tls_multiple_crypto_data() { - def_engine_ssl_config xqc_int_t ret; int cnt; uint8_t *data_buf = malloc(XQC_TEST_MAX_CRYPTO_DATA_BUF); size_t data_len = 0; - /* create server engine and tls_ctx */ - xqc_engine_t *engine_svr = test_create_engine_server(); - xqc_tls_ctx_t *ctx_svr = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, - &tls_test_cbs, engine_svr->log); - CU_ASSERT(ctx_svr != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_svr, "transport", 9); - CU_ASSERT(ret == XQC_OK); - - /* create client engine and tls_ctx */ - xqc_engine_t *engine_cli = test_create_engine(); - xqc_tls_ctx_t *ctx_cli = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &tls_test_cbs, engine_cli->log); - CU_ASSERT(ctx_cli != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_cli, "transport", 9); - CU_ASSERT(ret == XQC_OK); - /* get tls config */ - xqc_connection_t *test_conn = test_engine_connect(); xqc_tls_config_t tls_config = {0}; tls_config.session_ticket = NULL; tls_config.session_ticket_len = 0; tls_config.cert_verify_flag = 0; - tls_config.hostname = "127.0.0.1"; + tls_config.hostname = "test.xquic.com"; tls_config.alpn = "transport"; tls_config.no_crypto_flag = 0; - - /* encode local transport params */ - char tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; - tls_config.trans_params = tp_buf; - xqc_conn_encode_local_tp(test_conn, tls_config.trans_params, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tls_config.trans_params_len); + tls_config.trans_params = "test"; + tls_config.trans_params_len = 4; /* create client tls */ xqc_tls_test_buff_t *ttbuf_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_cli); + xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_cli); /* client start handshake, generate ClientHello */ - xqc_cid_t odcid; - xqc_generate_cid(engine_cli, NULL, &odcid, 0); + xqc_cid_t odcid = {1}; ret = xqc_tls_init(tls_cli, XQC_VERSION_V1, &odcid); CU_ASSERT(ret == XQC_OK); @@ -622,7 +599,7 @@ xqc_test_tls_multiple_crypto_data() /* create server tls */ xqc_tls_test_buff_t *ttbuf_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_svr); + xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_svr); /* server handshake, process ClientHello, genrate ServerHello & Handshake data */ ret = xqc_tls_init(tls_svr, XQC_VERSION_V1, &odcid); @@ -654,10 +631,6 @@ xqc_test_tls_multiple_crypto_data() xqc_destroy_tls_test_buffer(ttbuf_svr); xqc_tls_destroy(tls_cli); xqc_tls_destroy(tls_svr); - xqc_tls_ctx_destroy(ctx_cli); - xqc_tls_ctx_destroy(ctx_svr); - xqc_engine_destroy(engine_cli); - xqc_engine_destroy(engine_svr); free(data_buf); } @@ -665,56 +638,29 @@ xqc_test_tls_multiple_crypto_data() void xqc_test_tls_process_truncated_crypto_handshake() { - def_engine_ssl_config xqc_int_t ret; int cnt; uint8_t *data_buf = malloc(XQC_TEST_MAX_CRYPTO_DATA_BUF); size_t data_len = 0; - /* 1-RTT */ - - /* create server engine and tls_ctx */ - xqc_engine_t *engine_svr = test_create_engine_server(); - xqc_tls_ctx_t *ctx_svr = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, - &tls_test_cbs, engine_svr->log); - CU_ASSERT(ctx_svr != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_svr, "transport", 9); - CU_ASSERT(ret == XQC_OK); - - /* create client engine and tls_ctx */ - xqc_engine_t *engine_cli = test_create_engine(); - xqc_tls_ctx_t *ctx_cli = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &tls_test_cbs, engine_cli->log); - CU_ASSERT(ctx_cli != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_cli, "transport", 9); - CU_ASSERT(ret == XQC_OK); - /* get tls config */ - xqc_connection_t *test_conn = test_engine_connect(); xqc_tls_config_t tls_config = {0}; tls_config.session_ticket = NULL; tls_config.session_ticket_len = 0; tls_config.cert_verify_flag = 0; - tls_config.hostname = "127.0.0.1"; + tls_config.hostname = "test.xquic.com"; tls_config.alpn = "transport"; tls_config.no_crypto_flag = 0; - - /* encode local transport params */ - char tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; - tls_config.trans_params = tp_buf; - xqc_conn_encode_local_tp(test_conn, tls_config.trans_params, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tls_config.trans_params_len); + tls_config.trans_params = "test"; + tls_config.trans_params_len = 4; /* create client tls */ xqc_tls_test_buff_t *ttbuf_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_cli); + xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_cli); /* client start handshake, generate ClientHello */ - xqc_cid_t odcid; - xqc_generate_cid(engine_cli, NULL, &odcid, 0); + xqc_cid_t odcid = {1}; ret = xqc_tls_init(tls_cli, XQC_VERSION_V1, &odcid); CU_ASSERT(ret == XQC_OK); @@ -722,7 +668,7 @@ xqc_test_tls_process_truncated_crypto_handshake() /* create server tls */ xqc_tls_test_buff_t *ttbuf_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_svr); + xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_svr); /* server handshake */ ret = xqc_tls_init(tls_svr, XQC_VERSION_V1, &odcid); @@ -776,14 +722,13 @@ xqc_test_tls_process_truncated_crypto_handshake() CU_ASSERT(ttbuf_cli->new_session_ticket != NULL); CU_ASSERT(ttbuf_cli->new_session_ticket_len > 0); - /* 0-RTT and Resumption */ tls_config.session_ticket = ttbuf_cli->new_session_ticket; tls_config.session_ticket_len = ttbuf_cli->new_session_ticket_len; /* create client tls */ xqc_tls_test_buff_t *ttbuf_0rtt_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_0rtt_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_0rtt_cli); + xqc_tls_t *tls_0rtt_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_0rtt_cli); /* client start handshake, generate ClientHello */ ret = xqc_tls_init(tls_0rtt_cli, XQC_VERSION_V1, &odcid); @@ -792,7 +737,7 @@ xqc_test_tls_process_truncated_crypto_handshake() /* create server buffer */ xqc_tls_test_buff_t *ttbuf_0rtt_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_0rtt_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_0rtt_svr); + xqc_tls_t *tls_0rtt_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_0rtt_svr); /* create server tls */ ret = xqc_tls_init(tls_0rtt_svr, XQC_VERSION_V1, &odcid); @@ -820,7 +765,7 @@ xqc_test_tls_process_truncated_crypto_handshake() CU_ASSERT(data_len > 0); for (size_t i = 0; i < data_len; i++) { ret = xqc_tls_process_crypto_data(tls_0rtt_cli, XQC_ENC_LEV_HSK, data_buf + i, 1); - CU_ASSERT(ret == XQC_OK); + CU_ASSERT(ret == XQC_OK); } CU_ASSERT(ttbuf_0rtt_cli->handshake_completed == XQC_TRUE); CU_ASSERT(!xqc_list_empty(&ttbuf_0rtt_cli->hsk_crypto_data_list)); /* FIN */ @@ -834,22 +779,16 @@ xqc_test_tls_process_truncated_crypto_handshake() } CU_ASSERT(ttbuf_0rtt_svr->handshake_completed == XQC_TRUE); - xqc_destroy_tls_test_buffer(ttbuf_cli); xqc_destroy_tls_test_buffer(ttbuf_svr); - xqc_tls_destroy(tls_cli); - xqc_tls_destroy(tls_svr); - xqc_destroy_tls_test_buffer(ttbuf_0rtt_cli); xqc_destroy_tls_test_buffer(ttbuf_0rtt_svr); + + xqc_tls_destroy(tls_cli); + xqc_tls_destroy(tls_svr); xqc_tls_destroy(tls_0rtt_cli); xqc_tls_destroy(tls_0rtt_svr); - xqc_tls_ctx_destroy(ctx_cli); - xqc_tls_ctx_destroy(ctx_svr); - xqc_engine_destroy(engine_cli); - xqc_engine_destroy(engine_svr); - free(data_buf); } @@ -857,7 +796,6 @@ xqc_test_tls_process_truncated_crypto_handshake() void xqc_test_tls_failure() { - def_engine_ssl_config xqc_int_t ret; int cnt; @@ -865,48 +803,23 @@ xqc_test_tls_failure() size_t data_len = 0; /* 1-RTT */ - - /* create server engine and tls_ctx */ - xqc_engine_t *engine_svr = test_create_engine_server(); - xqc_tls_ctx_t *ctx_svr = xqc_tls_ctx_create(XQC_TLS_TYPE_SERVER, &engine_ssl_config, - &tls_test_cbs, engine_svr->log); - CU_ASSERT(ctx_svr != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_svr, "transport", 9); - CU_ASSERT(ret == XQC_OK); - - /* create client engine and tls_ctx */ - xqc_engine_t *engine_cli = test_create_engine(); - xqc_tls_ctx_t *ctx_cli = xqc_tls_ctx_create(XQC_TLS_TYPE_CLIENT, &engine_ssl_config, - &tls_test_cbs, engine_cli->log); - CU_ASSERT(ctx_cli != NULL); - - ret = xqc_tls_ctx_register_alpn(ctx_cli, "transport", 9); - CU_ASSERT(ret == XQC_OK); - /* get tls config */ - xqc_connection_t *test_conn = test_engine_connect(); xqc_tls_config_t tls_config = {0}; tls_config.session_ticket = NULL; tls_config.session_ticket_len = 0; tls_config.cert_verify_flag = 0; - tls_config.hostname = "127.0.0.1"; + tls_config.hostname = "test.xquic.com"; tls_config.alpn = "transport"; tls_config.no_crypto_flag = 0; - - /* encode local transport params */ - char tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; - tls_config.trans_params = tp_buf; - xqc_conn_encode_local_tp(test_conn, tls_config.trans_params, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tls_config.trans_params_len); + tls_config.trans_params = "test"; + tls_config.trans_params_len = 4; /* create client tls */ xqc_tls_test_buff_t *ttbuf_cli = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, engine_cli->log, ttbuf_cli); + xqc_tls_t *tls_cli = xqc_tls_create(ctx_cli, &tls_config, test_log, ttbuf_cli); /* client start handshake, generate ClientHello */ - xqc_cid_t odcid; - xqc_generate_cid(engine_cli, NULL, &odcid, 0); + xqc_cid_t odcid = {1}; ret = xqc_tls_init(tls_cli, XQC_VERSION_V1, &odcid); CU_ASSERT(ret == XQC_OK); @@ -914,7 +827,7 @@ xqc_test_tls_failure() /* create server tls */ xqc_tls_test_buff_t *ttbuf_svr = xqc_create_tls_test_buffer(); - xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, engine_svr->log, ttbuf_svr); + xqc_tls_t *tls_svr = xqc_tls_create(ctx_svr, &tls_config, test_log, ttbuf_svr); /* server handshake, process ClientHello, genrate ServerHello & Handshake data */ ret = xqc_tls_init(tls_svr, XQC_VERSION_V1, &odcid); @@ -959,26 +872,31 @@ xqc_test_tls_failure() xqc_tls_destroy(tls_cli); xqc_tls_destroy(tls_svr); + free(data_buf); +} + +void xqc_test_destroy_tls_ctx() +{ xqc_tls_ctx_destroy(ctx_cli); xqc_tls_ctx_destroy(ctx_svr); - xqc_engine_destroy(engine_cli); - xqc_engine_destroy(engine_svr); - - free(data_buf); } void xqc_test_tls() { + xqc_log_callbacks_t log_cb = xqc_null_log_cb; + test_log = xqc_log_init(0, 0, 0, 0, 0, NULL, &log_cb, NULL); + xqc_test_create_client_tls_ctx(); xqc_test_create_server_tls_ctx(); xqc_test_tls_ctx_register_alpn(); - xqc_test_tls_reset_initial(); - xqc_test_tls_generic(); - + xqc_test_tls_multiple_crypto_data(); + xqc_test_tls_generic(); xqc_test_tls_process_truncated_crypto_handshake(); - xqc_test_tls_failure(); + + xqc_test_destroy_tls_ctx(); + xqc_free(test_log); } \ No newline at end of file diff --git a/tests/unittest/xqc_wakeup_pq_test.c b/tests/unittest/xqc_wakeup_pq_test.c deleted file mode 100644 index e53548f8b..000000000 --- a/tests/unittest/xqc_wakeup_pq_test.c +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#include -#include "xqc_wakeup_pq_test.h" -#include "src/transport/xqc_wakeup_pq.h" - - -void -xqc_test_wakeup_pq() -{ - int ret; - xqc_wakeup_pq_t pq; - memset(&pq, 0, sizeof(pq)); - ret = xqc_wakeup_pq_init(&pq, 4, xqc_default_allocator, xqc_wakeup_pq_revert_cmp); - CU_ASSERT(ret == 0); - - xqc_wakeup_pq_elem_t *elem; - xqc_connection_t *conn = (xqc_connection_t *)malloc(5 * sizeof(xqc_connection_t)); - - elem = xqc_wakeup_pq_push(&pq, 3, &conn[0]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 1, &conn[1]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 4, &conn[2]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 2, &conn[3]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 5, &conn[4]); - CU_ASSERT(elem != NULL); - - - xqc_wakeup_pq_remove(&pq, &conn[0]); - - while (!xqc_wakeup_pq_empty(&pq)) { - elem = xqc_wakeup_pq_top(&pq); - //printf("key:%llu\n", elem->wakeup_time); - xqc_wakeup_pq_pop(&pq); - } - - free(conn); - - xqc_wakeup_pq_destroy(&pq); -} \ No newline at end of file diff --git a/tests/unittest/xqc_wakeup_pq_test.h b/tests/unittest/xqc_wakeup_pq_test.h deleted file mode 100644 index 28a3a227f..000000000 --- a/tests/unittest/xqc_wakeup_pq_test.h +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#ifndef _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ -#define _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ - -void xqc_test_wakeup_pq(); - -#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ diff --git a/xqc_build.sh b/xqc_build.sh index 6b1fcabc2..d085f592f 100755 --- a/xqc_build.sh +++ b/xqc_build.sh @@ -3,6 +3,8 @@ android_archs=(armeabi-v7a arm64-v8a) ios_archs=(armv7 arm64 x86_64) +hmos_archs=(arm64-v8a) +CMAKE_CMD="cmake" cur_dir=$(cd "$(dirname "$0")";pwd) cp -f $cur_dir/cmake/CMakeLists.txt $cur_dir/CMakeLists.txt @@ -14,24 +16,28 @@ artifact_dir=$3 # boringssl is used as default ssl_type="boringssl" ssl_path=$4 -ssl_lib_path="${ssl_path}/" -if [ -z "$ssl_path" ] || [ -z "$ssl_lib_path" ] ; then - echo "ssl environment not specified" +# if ssl_path is not defined, try to use the default path +if [ -z "$ssl_path" ] ; then + ssl_path="`pwd`/third_party/boringssl" + echo "use default ssl path: $ssl_path" +fi + +if [ ! -d "$ssl_path" ] ; then + echo "ssl environment not exists" exit 0 fi -create_dir_or_exit() { +create_dir_force() { if [ x"$2" == x ] ; then echo "$1 MUST NOT be empty" exit 1 fi if [ -d $2 ] ; then - echo "directory already exists" - else - mkdir $2 - echo "create $1 directory($2) suc" + rm -rf $2 fi + mkdir $2 + echo "create $1 directory($2) suc" } platform=$(echo $platform | tr A-Z a-z ) @@ -45,21 +51,26 @@ if [ x"$platform" == xios ] ; then archs=${ios_archs[@]} configures="-DSSL_TYPE=${ssl_type} -DSSL_PATH=${ssl_path} - -DSSL_LIB_PATH=${ssl_lib_path} + -DBORINGSSL_PREFIX=bs + -DBORINGSSL_PREFIX_SYMBOLS=$cur_dir/bssl_symbols.txt -DDEPLOYMENT_TARGET=10.0 -DCMAKE_BUILD_TYPE=Minsizerel -DXQC_ENABLE_TESTING=OFF -DXQC_BUILD_SAMPLE=OFF -DGCOV=OFF -DCMAKE_TOOLCHAIN_FILE=${IOS_CMAKE_TOOLCHAIN} - -DENABLE_BITCODE=0 - -DXQC_NO_SHARED=1 - -DXQC_COMPAT_GENERATE_SR_PKT=1 - -DXQC_ENABLE_RENO=0 - -DXQC_ENABLE_BBR2=0 - -DXQC_ENABLE_COPA=0 - -DXQC_ENABLE_UNLIMITED=0 - -DXQC_ENABLE_MP_INTEROP=0" + -DENABLE_BITCODE=OFF + -DXQC_NO_SHARED=ON + -DXQC_ENABLE_TH3=ON + -DXQC_COMPAT_GENERATE_SR_PKT=ON + -DXQC_ENABLE_RENO=OFF + -DXQC_ENABLE_BBR2=ON + -DXQC_ENABLE_COPA=OFF + -DXQC_ENABLE_UNLIMITED=OFF + -DXQC_ENABLE_MP_INTEROP=OFF + -DXQC_DISABLE_LOG=OFF + -DXQC_ONLY_ERROR_LOG=ON + -DXQC_COMPAT_GENERATE_SR_PKT=ON" elif [ x"$platform" == xandroid ] ; then if [ x"$ANDROID_NDK" == x ] ; then @@ -70,7 +81,6 @@ elif [ x"$platform" == xandroid ] ; then archs=${android_archs[@]} configures="-DSSL_TYPE=${ssl_type} -DSSL_PATH=${ssl_path} - -DSSL_LIB_PATH=${ssl_lib_path} -DCMAKE_BUILD_TYPE=Minsizerel -DXQC_ENABLE_TESTING=OFF -DXQC_BUILD_SAMPLE=OFF @@ -79,13 +89,45 @@ elif [ x"$platform" == xandroid ] ; then -DANDROID_STL=c++_shared -DANDROID_NATIVE_API_LEVEL=android-19 -DXQC_ENABLE_RENO=OFF - -DXQC_ENABLE_BBR2=OFF + -DXQC_ENABLE_BBR2=ON -DXQC_ENABLE_COPA=OFF -DXQC_ENABLE_UNLIMITED=OFF -DXQC_ENABLE_MP_INTEROP=OFF -DXQC_DISABLE_LOG=OFF -DXQC_ONLY_ERROR_LOG=ON + -DXQC_ENABLE_TH3=ON -DXQC_COMPAT_GENERATE_SR_PKT=ON" +elif [ x"$platform" == xharmony ] ; then + if [ x"$HMOS_CMAKE_TOOLCHAIN" == x ] ; then + echo "HMOS_CMAKE_TOOLCHAIN MUST be defined" + exit 0 + fi + echo "HMOS_CMAKE_TOOLCHAIN: ${HMOS_CMAKE_TOOLCHAIN}" + + if [ x"$HMOS_CMAKE_PATH" == x ] ; then + echo "HMOS_CMAKE_PATH MUST be defined" + exit 0 + fi + echo "HMOS_CMAKE_PATH: ${HMOS_CMAKE_PATH}" + CMAKE_CMD=${HMOS_CMAKE_PATH} + + archs=${hmos_archs[@]} + configures="-DSSL_TYPE=${ssl_type} + -DSSL_PATH=${ssl_path} + -DCMAKE_BUILD_TYPE=Release + -DXQC_ENABLE_TESTING=OFF + -DXQC_BUILD_SAMPLE=OFF + -DGCOV=OFF + -DCMAKE_TOOLCHAIN_FILE=${HMOS_CMAKE_TOOLCHAIN} + -DXQC_ENABLE_RENO=OFF + -DXQC_ENABLE_BBR2=ON + -DXQC_ENABLE_COPA=OFF + -DXQC_ENABLE_UNLIMITED=OFF + -DXQC_ENABLE_MP_INTEROP=OFF + -DXQC_DISABLE_LOG=OFF + -DXQC_ONLY_ERROR_LOG=ON + -DXQC_COMPAT_GENERATE_SR_PKT=ON + -DDISABLE_WARNINGS=ON" else echo "no support platform" exit 0 @@ -101,17 +143,19 @@ generate_plat_spec() { elif [ x"$1" == xi386 ] ; then plat_spec="$plat_spec -DPLATFORM=SIMULATOR" fi + elif [ x"$platform" == xharmony ] ; then + plat_spec="-DOHOS_ARCH=$1" else plat_spec="-DANDROID_ABI=$1" fi echo $plat_spec } -create_dir_or_exit build $build_dir +create_dir_force build $build_dir # to absoulute path build_dir=$cur_dir/$build_dir -create_dir_or_exit artifact $artifact_dir +create_dir_force artifact $artifact_dir artifact_dir=$cur_dir/$artifact_dir cd $build_dir @@ -127,7 +171,7 @@ do rm -rf third_party echo "compiling xquic on $i arch" - cmake $configures $(generate_plat_spec $i ) -DLIBRARY_OUTPUT_PATH=`pwd`/outputs/ .. + "${CMAKE_CMD}" $configures $(generate_plat_spec $i ) -DLIBRARY_OUTPUT_PATH=`pwd`/outputs/ .. make -j 4 if [ $? != 0 ] ; then exit 0 diff --git a/xqc_configure.h.in b/xqc_configure.h.in index 05d7691cf..b9b91c117 100644 --- a/xqc_configure.h.in +++ b/xqc_configure.h.in @@ -7,4 +7,10 @@ #cmakedefine XQC_ENABLE_COPA #cmakedefine XQC_ENABLE_UNLIMITED #cmakedefine XQC_ENABLE_MP_INTEROP -#cmakedefine XQC_NO_PID_PACKET_PROCESS \ No newline at end of file +#cmakedefine XQC_NO_PID_PACKET_PROCESS +#cmakedefine XQC_PROTECT_POOL_MEM +#cmakedefine XQC_COMPAT_DUPLICATE +#cmakedefine XQC_ENABLE_FEC +#cmakedefine XQC_ENABLE_XOR +#cmakedefine XQC_ENABLE_RSC +#cmakedefine XQC_ENABLE_PKM \ No newline at end of file