merged to upstream

This commit is contained in:
Rahul Jadhav 2020-06-08 19:33:14 +08:00
commit 6b5bc6d41c
92 changed files with 2054 additions and 1112 deletions

View file

@ -1,3 +1,25 @@
2020-06-03
- 2.16.0
- [API] Use lsxpack_header v206.
- [FEATURE] Windows supported.
- [BUGFIX] Fix uninitialized variable use in client (regression in
2.15.0).
- Use ls-hpack 2.2.0.
- Use ls-qpack 2.2.0.
- Sample programs: fix the way maximum number of packets is
calculated.
- Remove some dead code.
2020-05-27
- 2.15.0
- [FEATURE] QUIC and HTTP/3 Internet Draft 28 support.
- [BUGFIX] Ignore Retry packets after other packets are decrypted
successfully.
- [BUGFIX] Transport parameter decoding: CID no longer has 4-byte
length minimum.
- http_client: fix and optimize lsxpack_header allocator.
- Drop support for Internet Draft 25.
2020-05-19 2020-05-19
- 2.14.8 - 2.14.8
- Support Android. - Support Android.

View file

@ -85,7 +85,22 @@ ENDIF()
#MSVC #MSVC
ELSE() ELSE()
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4100") # unreferenced formal parameter
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4115") # unnamed type definition in parentheses
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4116") # named type definition in parentheses
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4146") # unary minus operator applied to unsigned type, result still unsigned
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4132") # const initialization
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4200") # zero-sized array
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4204") # non-constant aggregate initializer
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4244") # integer conversion
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4245") # conversion from 'int' to 'unsigned int', signed/unsigned mismatch
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4267") # integer conversion
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4214") # nonstandard extension used: bit field types other than int SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4214") # nonstandard extension used: bit field types other than int
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4295") # array is too small to include a terminating null character
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4334") # result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4456") # hide previous local declaration
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4459") # hide global declaration
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} /wd4706") # assignment within conditional expression
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -W4 -WX -Zi -DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -I${CMAKE_CURRENT_SOURCE_DIR}/wincompat") SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -W4 -WX -Zi -DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -I${CMAKE_CURRENT_SOURCE_DIR}/wincompat")
IF(CMAKE_BUILD_TYPE STREQUAL "Debug") IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Od") SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Od")
@ -103,6 +118,11 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MY_CMAKE_FLAGS} $ENV{EXTRA_CFLAGS}")
MESSAGE(STATUS "Compiler flags: ${CMAKE_C_FLAGS}") MESSAGE(STATUS "Compiler flags: ${CMAKE_C_FLAGS}")
find_package(Perl)
IF(NOT PERL_FOUND)
MESSAGE(FATAL_ERROR "Perl not found -- need it to generate source code")
ENDIF()
IF (NOT DEFINED BORINGSSL_INCLUDE AND DEFINED BORINGSSL_DIR) IF (NOT DEFINED BORINGSSL_INCLUDE AND DEFINED BORINGSSL_DIR)
FIND_PATH(BORINGSSL_INCLUDE NAMES openssl/ssl.h FIND_PATH(BORINGSSL_INCLUDE NAMES openssl/ssl.h
PATHS ${BORINGSSL_DIR}/include PATHS ${BORINGSSL_DIR}/include
@ -124,7 +144,7 @@ IF (NOT DEFINED BORINGSSL_LIB AND DEFINED BORINGSSL_DIR)
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME} FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
NAMES ${LIB_NAME} NAMES ${LIB_NAME}
PATHS ${BORINGSSL_DIR}/${LIB_NAME} PATHS ${BORINGSSL_DIR}/${LIB_NAME}
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
NO_DEFAULT_PATH) NO_DEFAULT_PATH)
ELSE() ELSE()
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME} FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
@ -195,7 +215,7 @@ ELSE()
MESSAGE(STATUS "zlib not found") MESSAGE(STATUS "zlib not found")
ENDIF() ENDIF()
IF (LSQUIC_BIN) IF (LSQUIC_BIN OR LSQUIC_TESTS)
FIND_PATH(EVENT_INCLUDE_DIR NAMES event2/event.h) FIND_PATH(EVENT_INCLUDE_DIR NAMES event2/event.h)
IF (EVENT_INCLUDE_DIR) IF (EVENT_INCLUDE_DIR)
INCLUDE_DIRECTORIES(${EVENT_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${EVENT_INCLUDE_DIR})
@ -215,15 +235,38 @@ IF(EVENT_LIB)
ELSE() ELSE()
MESSAGE(STATUS "libevent not found") MESSAGE(STATUS "libevent not found")
ENDIF() ENDIF()
add_executable(http_server bin/http_server.c bin/prog.c bin/test_common.c bin/test_cert.c)
add_executable(md5_server bin/md5_server.c bin/prog.c bin/test_common.c bin/test_cert.c)
add_executable(md5_client bin/md5_client.c bin/prog.c bin/test_common.c bin/test_cert.c)
add_executable(echo_server bin/echo_server.c bin/prog.c bin/test_common.c bin/test_cert.c)
add_executable(echo_client bin/echo_client.c bin/prog.c bin/test_common.c bin/test_cert.c)
SET(LIBS lsquic ${EVENT_LIB} ${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${ZLIB_LIB} ${LIBS}) SET(LIBS lsquic ${EVENT_LIB} ${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${ZLIB_LIB} ${LIBS})
IF(MSVC)
FIND_LIBRARY(PCRE_LIB pcre)
IF(PCRE_LIB)
MESSAGE(STATUS "Found pcre: ${PCRE_LIB}")
LIST(APPEND LIBS ${PCRE_LIB})
ELSE()
MESSAGE(STATUS "pcre not found: http_server won't work")
ENDIF()
FIND_LIBRARY(PCREPOSIX_LIB pcreposix)
IF(PCREPOSIX_LIB)
MESSAGE(STATUS "Found pcreposix: ${PCREPOSIX_LIB}")
LIST(APPEND LIBS ${PCREPOSIX_LIB})
ELSE()
MESSAGE(STATUS "pcreposix not found: http_server won't work")
ENDIF()
LIST(APPEND LIBS ws2_32)
ENDIF()
ENDIF() # LSQUIC_BIN OR LSQUIC_TESTS
IF(LSQUIC_BIN)
IF(MSVC)
SET(GETOPT_C wincompat/getopt.c)
ENDIF()
add_executable(http_server bin/http_server.c bin/prog.c bin/test_common.c bin/test_cert.c ${GETOPT_C})
IF(NOT MSVC) # TODO: port MD5 server and client to Windows
add_executable(md5_server bin/md5_server.c bin/prog.c bin/test_common.c bin/test_cert.c ${GETOPT_C})
add_executable(md5_client bin/md5_client.c bin/prog.c bin/test_common.c bin/test_cert.c ${GETOPT_C})
ENDIF()
add_executable(echo_server bin/echo_server.c bin/prog.c bin/test_common.c bin/test_cert.c ${GETOPT_C})
add_executable(echo_client bin/echo_client.c bin/prog.c bin/test_common.c bin/test_cert.c ${GETOPT_C})
IF (NOT MSVC) IF (NOT MSVC)
@ -242,6 +285,7 @@ add_executable(http_client
bin/http_client.c bin/http_client.c
bin/prog.c bin/prog.c
bin/test_common.c bin/test_common.c
bin/test_cert.c
wincompat/getopt.c wincompat/getopt.c
wincompat/getopt1.c wincompat/getopt1.c
) )
@ -251,8 +295,10 @@ ENDIF()
TARGET_LINK_LIBRARIES(http_client ${LIBS}) TARGET_LINK_LIBRARIES(http_client ${LIBS})
TARGET_LINK_LIBRARIES(http_server ${LIBS}) TARGET_LINK_LIBRARIES(http_server ${LIBS})
IF(NOT MSVC)
TARGET_LINK_LIBRARIES(md5_server ${LIBS}) TARGET_LINK_LIBRARIES(md5_server ${LIBS})
TARGET_LINK_LIBRARIES(md5_client ${LIBS}) TARGET_LINK_LIBRARIES(md5_client ${LIBS})
ENDIF()
TARGET_LINK_LIBRARIES(echo_server ${LIBS}) TARGET_LINK_LIBRARIES(echo_server ${LIBS})
TARGET_LINK_LIBRARIES(echo_client ${LIBS}) TARGET_LINK_LIBRARIES(echo_client ${LIBS})

View file

@ -1,6 +1,6 @@
[![Build Status](https://travis-ci.org/litespeedtech/lsquic.svg?branch=master)](https://travis-ci.org/litespeedtech/lsquic) [![Build Status](https://travis-ci.org/litespeedtech/lsquic.svg?branch=master)](https://travis-ci.org/litespeedtech/lsquic)
[![Build Status](https://api.cirrus-ci.com/github/litespeedtech/lsquic.svg)](https://cirrus-ci.com/github/litespeedtech/lsquic) [![Build Status](https://api.cirrus-ci.com/github/litespeedtech/lsquic.svg)](https://cirrus-ci.com/github/litespeedtech/lsquic)
[![Build status](https://ci.appveyor.com/api/projects/status/kei9649t9leoqicr?svg=true)](https://ci.appveyor.com/project/litespeedtech/lsquic) [![Build status](https://ci.appveyor.com/api/projects/status/ij4n3vy343pkgm1j?svg=true)](https://ci.appveyor.com/project/litespeedtech/lsquic)
LiteSpeed QUIC (LSQUIC) Library README LiteSpeed QUIC (LSQUIC) Library README
============================================= =============================================
@ -15,7 +15,7 @@ and OpenLiteSpeed. We think it is free of major problems. Nevertheless, do
not hesitate to report bugs back to us. Even better, send us fixes and not hesitate to report bugs back to us. Even better, send us fixes and
improvements! improvements!
Currently supported QUIC versions are Q043, Q046, Q050, ID-25, and ID-27. Currently supported QUIC versions are Q043, Q046, Q050, ID-27, and ID-28.
Support for newer versions will be added soon after they are released. Support for newer versions will be added soon after they are released.
Documentation Documentation
@ -137,7 +137,7 @@ The library has been tested on the following platforms:
- x86_64 - x86_64
- Android - Android
- ARM - ARM
- Windows (this needs updating for the server part, now broken) - Windows
- x86_64 - x86_64
Have fun, Have fun,

63
appveyor.yml Normal file
View file

@ -0,0 +1,63 @@
version: 1.{branch}.{build}
image: Visual Studio 2017
cache: c:\tools\vcpkg\installed
init:
- cmd: ''
install:
- cmd: >-
vcpkg install zlib:x64-windows-static
vcpkg install libevent:x64-windows-static
vcpkg install pcre:x64-windows-static
vcpkg integrate install
build_script:
- cmd: >-
vcpkg list
git clone https://boringssl.googlesource.com/boringssl
cd boringssl
git checkout bfe527fa35735e8e045cbfb42b012e13ca68f9cf
cmake -DCMAKE_GENERATOR_PLATFORM=x64 --config Debug -DBUILD_SHARED_LIBS=OFF -DOPENSSL_NO_ASM=1 .
msbuild /m ALL_BUILD.vcxproj
cd ..
git submodule init
git submodule update
cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DBUILD_SHARED_LIBS=OFF -DVCPKG_TARGET_TRIPLET=x64-windows-static -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DBORINGSSL_DIR=%cd%\boringssl .
msbuild /m ALL_BUILD.vcxproj
test_script:
- cmd: msbuild /m RUN_TESTS.vcxproj

View file

@ -21,6 +21,16 @@ CHECK_SYMBOL_EXISTS(
INCLUDE(CheckIncludeFiles) INCLUDE(CheckIncludeFiles)
IF (MSVC AND PCRE_LIB)
FIND_PATH(EVENT_INCLUDE_DIR NAMES pcreposix.h)
IF (EVENT_INCLUDE_DIR)
MESSAGE(STATUS "found pcreposix.h")
SET(HAVE_REGEX 1)
ELSE()
MESSAGE(FATAL_ERROR "event2/event.h was not found")
ENDIF()
ELSE()
CHECK_INCLUDE_FILES(regex.h HAVE_REGEX) CHECK_INCLUDE_FILES(regex.h HAVE_REGEX)
ENDIF()
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/test_config.h) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/test_config.h)

View file

@ -9,11 +9,21 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef WIN32
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
#define Read read
#else
#include "vc_compat.h"
#include "getopt.h"
#include <io.h>
#define Read _read
#define STDIN_FILENO 0
#endif
#include <event2/event.h> #include <event2/event.h>
@ -69,12 +79,12 @@ struct lsquic_stream_ctx {
static void static void
read_stdin (int fd, short what, void *ctx) read_stdin (evutil_socket_t fd, short what, void *ctx)
{ {
ssize_t nr; ssize_t nr;
lsquic_stream_ctx_t *st_h = ctx; lsquic_stream_ctx_t *st_h = ctx;
nr = read(fd, st_h->buf + st_h->buf_off++, 1); nr = Read(fd, st_h->buf + st_h->buf_off++, 1);
LSQ_DEBUG("read %zd bytes from stdin", nr); LSQ_DEBUG("read %zd bytes from stdin", nr);
if (0 == nr) if (0 == nr)
{ {
@ -217,6 +227,7 @@ main (int argc, char **argv)
} }
} }
#ifndef WIN32
int flags = fcntl(STDIN_FILENO, F_GETFL); int flags = fcntl(STDIN_FILENO, F_GETFL);
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
if (0 != fcntl(STDIN_FILENO, F_SETFL, flags)) if (0 != fcntl(STDIN_FILENO, F_SETFL, flags))
@ -224,6 +235,12 @@ main (int argc, char **argv)
perror("fcntl"); perror("fcntl");
exit(1); exit(1);
} }
#else
{
u_long on = 1;
ioctlsocket(STDIN_FILENO, FIONBIO, &on);
}
#endif
if (0 != prog_prep(&prog)) if (0 != prog_prep(&prog))
{ {

View file

@ -4,14 +4,19 @@
*/ */
#include <assert.h> #include <assert.h>
#include <netinet/in.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <time.h> #include <time.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#include <netinet/in.h>
#else
#include "vc_compat.h"
#include "getopt.h"
#endif
#include "lsquic.h" #include "lsquic.h"
#include "test_common.h" #include "test_common.h"

View file

@ -220,6 +220,7 @@ struct lsquic_conn_ctx {
struct hset_elem struct hset_elem
{ {
STAILQ_ENTRY(hset_elem) next; STAILQ_ENTRY(hset_elem) next;
size_t nalloc;
struct lsxpack_header xhdr; struct lsxpack_header xhdr;
}; };
@ -530,18 +531,20 @@ static void
send_headers (lsquic_stream_ctx_t *st_h) send_headers (lsquic_stream_ctx_t *st_h)
{ {
const char *hostname = st_h->client_ctx->hostname; const char *hostname = st_h->client_ctx->hostname;
struct header_buf hbuf;
if (!hostname) if (!hostname)
hostname = st_h->client_ctx->prog->prog_hostname; hostname = st_h->client_ctx->prog->prog_hostname;
hbuf.off = 0;
struct lsxpack_header headers_arr[7]; struct lsxpack_header headers_arr[7];
#define V(v) (v), strlen(v) #define V(v) (v), strlen(v)
lsxpack_header_set_ptr(&headers_arr[0], V(":method"), V(st_h->client_ctx->method)); header_set_ptr(&headers_arr[0], &hbuf, V(":method"), V(st_h->client_ctx->method));
lsxpack_header_set_ptr(&headers_arr[1], V(":scheme"), V("https")); header_set_ptr(&headers_arr[1], &hbuf, V(":scheme"), V("https"));
lsxpack_header_set_ptr(&headers_arr[2], V(":path"), V(st_h->path)); header_set_ptr(&headers_arr[2], &hbuf, V(":path"), V(st_h->path));
lsxpack_header_set_ptr(&headers_arr[3], V(":authority"), V(hostname)); header_set_ptr(&headers_arr[3], &hbuf, V(":authority"), V(hostname));
lsxpack_header_set_ptr(&headers_arr[4], V("user-agent"), V(st_h->client_ctx->prog->prog_settings.es_ua)); header_set_ptr(&headers_arr[4], &hbuf, V("user-agent"), V(st_h->client_ctx->prog->prog_settings.es_ua));
/* The following headers only gets sent if there is request payload: */ /* The following headers only gets sent if there is request payload: */
lsxpack_header_set_ptr(&headers_arr[5], V("content-type"), V("application/octet-stream")); header_set_ptr(&headers_arr[5], &hbuf, V("content-type"), V("application/octet-stream"));
lsxpack_header_set_ptr(&headers_arr[6], V("content-length"), V( st_h->client_ctx->payload_size)); header_set_ptr(&headers_arr[6], &hbuf, V("content-length"), V( st_h->client_ctx->payload_size));
lsquic_http_headers_t headers = { lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]), .count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr, .headers = headers_arr,
@ -999,16 +1002,19 @@ hset_prepare_decode (void *hset_p, struct lsxpack_header *xhdr,
} }
STAILQ_INSERT_TAIL(hset, el, next); STAILQ_INSERT_TAIL(hset, el, next);
lsxpack_header_prepare_decode(&el->xhdr, buf, 0, req_space); lsxpack_header_prepare_decode(&el->xhdr, buf, 0, req_space);
el->nalloc = req_space;
} }
else else
{ {
el = (struct hset_elem *) ((char *) xhdr el = (struct hset_elem *) ((char *) xhdr
- offsetof(struct hset_elem, xhdr)); - offsetof(struct hset_elem, xhdr));
if (req_space <= xhdr->val_len) if (req_space <= el->nalloc)
{ {
LSQ_ERROR("requested space is smaller than already allocated"); LSQ_ERROR("requested space is smaller than already allocated");
return NULL; return NULL;
} }
if (req_space < el->nalloc * 2)
req_space = el->nalloc * 2;
buf = realloc(el->xhdr.buf, req_space); buf = realloc(el->xhdr.buf, req_space);
if (!buf) if (!buf)
{ {
@ -1017,6 +1023,7 @@ hset_prepare_decode (void *hset_p, struct lsxpack_header *xhdr,
} }
el->xhdr.buf = buf; el->xhdr.buf = buf;
el->xhdr.val_len = req_space; el->xhdr.val_len = req_space;
el->nalloc = req_space;
} }
return &el->xhdr; return &el->xhdr;
@ -1067,11 +1074,11 @@ hset_dump (const struct hset *hset, FILE *out)
const struct hset_elem *el; const struct hset_elem *el;
STAILQ_FOREACH(el, hset, next) STAILQ_FOREACH(el, hset, next)
if (el->xhdr.flags & (LSXPACK_HPACK_IDX|LSXPACK_QPACK_IDX)) if (el->xhdr.flags & (LSXPACK_HPACK_VAL_MATCHED|LSXPACK_QPACK_IDX))
fprintf(out, "%.*s (%s static table idx %u): %.*s\n", fprintf(out, "%.*s (%s static table idx %u): %.*s\n",
(int) el->xhdr.name_len, lsxpack_header_get_name(&el->xhdr), (int) el->xhdr.name_len, lsxpack_header_get_name(&el->xhdr),
el->xhdr.flags & LSXPACK_HPACK_IDX ? "hpack" : "qpack", el->xhdr.flags & LSXPACK_HPACK_VAL_MATCHED ? "hpack" : "qpack",
el->xhdr.flags & LSXPACK_HPACK_IDX ? el->xhdr.hpack_index el->xhdr.flags & LSXPACK_HPACK_VAL_MATCHED ? el->xhdr.hpack_index
: el->xhdr.qpack_index, : el->xhdr.qpack_index,
(int) el->xhdr.val_len, lsxpack_header_get_value(&el->xhdr)); (int) el->xhdr.val_len, lsxpack_header_get_value(&el->xhdr));
else else
@ -1152,7 +1159,6 @@ qif_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
struct lsxpack_header *header; struct lsxpack_header *header;
static int reqno; static int reqno;
size_t nalloc; size_t nalloc;
int i;
char *end, *tab, *line; char *end, *tab, *line;
char line_buf[0x1000]; char line_buf[0x1000];
@ -1210,20 +1216,11 @@ qif_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
exit(1); exit(1);
} }
header = &ctx->headers.headers[ctx->headers.count++]; header = &ctx->headers.headers[ctx->headers.count++];
lsxpack_header_set_ptr(header, (void *) ctx->qif_sz, tab - line, lsxpack_header_set_offset2(header, ctx->qif_str + ctx->qif_sz, 0,
(void *) (ctx->qif_sz + (tab - line + 1)), end - tab - 1); tab - line, tab - line + 1, end - tab - 1);
ctx->qif_sz += end + 1 - line; ctx->qif_sz += end + 1 - line;
} }
for (i = 0; i < ctx->headers.count; ++i)
{
ctx->headers.headers[i].buf = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].buf;
ctx->headers.headers[i].name_ptr = ctx->qif_str
+ (uintptr_t) ctx->headers.headers[i].name_ptr;
}
lsquic_stream_wantwrite(stream, 1); lsquic_stream_wantwrite(stream, 1);
if (!line) if (!line)
@ -1421,10 +1418,6 @@ main (int argc, char **argv)
client_ctx.hcc_reset_after_nbytes = 0; client_ctx.hcc_reset_after_nbytes = 0;
client_ctx.hcc_retire_cid_after_nbytes = 0; client_ctx.hcc_retire_cid_after_nbytes = 0;
client_ctx.prog = &prog; client_ctx.prog = &prog;
#ifdef WIN32
WSADATA wsd;
WSAStartup(MAKEWORD(2, 2), &wsd);
#endif
prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx); prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx);

View file

@ -10,15 +10,20 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include <regex.h>
#include <netinet/in.h>
#include <inttypes.h> #include <inttypes.h>
#ifndef WIN32
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#else
#include "vc_compat.h"
#include "getopt.h"
#endif
#include <event2/event.h> #include <event2/event.h>
#include <openssl/md5.h> #include <openssl/md5.h>
@ -29,12 +34,243 @@
#include "test_common.h" #include "test_common.h"
#include "prog.h" #include "prog.h"
#if HAVE_REGEX
#ifndef WIN32
#include <regex.h>
#else
#include <pcreposix.h>
#endif
#endif
#include "../src/liblsquic/lsquic_logger.h" #include "../src/liblsquic/lsquic_logger.h"
#include "../src/liblsquic/lsquic_int_types.h" #include "../src/liblsquic/lsquic_int_types.h"
#include "../src/liblsquic/lsquic_util.h" #include "../src/liblsquic/lsquic_util.h"
static const char on_being_idle[]; #if HAVE_REGEX
static const size_t IDLE_SIZE; static const char on_being_idle[] =
"ON BEING IDLE.\n"
"\n"
"Now, this is a subject on which I flatter myself I really am _au fait_.\n"
"The gentleman who, when I was young, bathed me at wisdom's font for nine\n"
"guineas a term--no extras--used to say he never knew a boy who could\n"
"do less work in more time; and I remember my poor grandmother once\n"
"incidentally observing, in the course of an instruction upon the use\n"
"of the Prayer-book, that it was highly improbable that I should ever do\n"
"much that I ought not to do, but that she felt convinced beyond a doubt\n"
"that I should leave undone pretty well everything that I ought to do.\n"
"\n"
"I am afraid I have somewhat belied half the dear old lady's prophecy.\n"
"Heaven help me! I have done a good many things that I ought not to have\n"
"done, in spite of my laziness. But I have fully confirmed the accuracy\n"
"of her judgment so far as neglecting much that I ought not to have\n"
"neglected is concerned. Idling always has been my strong point. I take\n"
"no credit to myself in the matter--it is a gift. Few possess it. There\n"
"are plenty of lazy people and plenty of slow-coaches, but a genuine\n"
"idler is a rarity. He is not a man who slouches about with his hands in\n"
"his pockets. On the contrary, his most startling characteristic is that\n"
"he is always intensely busy.\n"
"\n"
"It is impossible to enjoy idling thoroughly unless one has plenty of\n"
"work to do. There is no fun in doing nothing when you have nothing to\n"
"do. Wasting time is merely an occupation then, and a most exhausting\n"
"one. Idleness, like kisses, to be sweet must be stolen.\n"
"\n"
"Many years ago, when I was a young man, I was taken very ill--I never\n"
"could see myself that much was the matter with me, except that I had\n"
"a beastly cold. But I suppose it was something very serious, for the\n"
"doctor said that I ought to have come to him a month before, and that\n"
"if it (whatever it was) had gone on for another week he would not have\n"
"answered for the consequences. It is an extraordinary thing, but I\n"
"never knew a doctor called into any case yet but what it transpired\n"
"that another day's delay would have rendered cure hopeless. Our medical\n"
"guide, philosopher, and friend is like the hero in a melodrama--he\n"
"always comes upon the scene just, and only just, in the nick of time. It\n"
"is Providence, that is what it is.\n"
"\n"
"Well, as I was saying, I was very ill and was ordered to Buxton for a\n"
"month, with strict injunctions to do nothing whatever all the while\n"
"that I was there. \"Rest is what you require,\" said the doctor, \"perfect\n"
"rest.\"\n"
"\n"
"It seemed a delightful prospect. \"This man evidently understands my\n"
"complaint,\" said I, and I pictured to myself a glorious time--a four\n"
"weeks' _dolce far niente_ with a dash of illness in it. Not too much\n"
"illness, but just illness enough--just sufficient to give it the flavor\n"
"of suffering and make it poetical. I should get up late, sip chocolate,\n"
"and have my breakfast in slippers and a dressing-gown. I should lie out\n"
"in the garden in a hammock and read sentimental novels with a melancholy\n"
"ending, until the books should fall from my listless hand, and I should\n"
"recline there, dreamily gazing into the deep blue of the firmament,\n"
"watching the fleecy clouds floating like white-sailed ships across\n"
"its depths, and listening to the joyous song of the birds and the low\n"
"rustling of the trees. Or, on becoming too weak to go out of doors,\n"
"I should sit propped up with pillows at the open window of the\n"
"ground-floor front, and look wasted and interesting, so that all the\n"
"pretty girls would sigh as they passed by.\n"
"\n"
"And twice a day I should go down in a Bath chair to the Colonnade to\n"
"drink the waters. Oh, those waters! I knew nothing about them then,\n"
"and was rather taken with the idea. \"Drinking the waters\" sounded\n"
"fashionable and Queen Anne-fied, and I thought I should like them. But,\n"
"ugh! after the first three or four mornings! Sam Weller's description of\n"
"them as \"having a taste of warm flat-irons\" conveys only a faint idea of\n"
"their hideous nauseousness. If anything could make a sick man get well\n"
"quickly, it would be the knowledge that he must drink a glassful of them\n"
"every day until he was recovered. I drank them neat for six consecutive\n"
"days, and they nearly killed me; but after then I adopted the plan of\n"
"taking a stiff glass of brandy-and-water immediately on the top of them,\n"
"and found much relief thereby. I have been informed since, by various\n"
"eminent medical gentlemen, that the alcohol must have entirely\n"
"counteracted the effects of the chalybeate properties contained in the\n"
"water. I am glad I was lucky enough to hit upon the right thing.\n"
"\n"
"But \"drinking the waters\" was only a small portion of the torture I\n"
"experienced during that memorable month--a month which was, without\n"
"exception, the most miserable I have ever spent. During the best part of\n"
"it I religiously followed the doctor's mandate and did nothing whatever,\n"
"except moon about the house and garden and go out for two hours a day in\n"
"a Bath chair. That did break the monotony to a certain extent. There is\n"
"more excitement about Bath-chairing--especially if you are not used to\n"
"the exhilarating exercise--than might appear to the casual observer. A\n"
"sense of danger, such as a mere outsider might not understand, is ever\n"
"present to the mind of the occupant. He feels convinced every minute\n"
"that the whole concern is going over, a conviction which becomes\n"
"especially lively whenever a ditch or a stretch of newly macadamized\n"
"road comes in sight. Every vehicle that passes he expects is going to\n"
"run into him; and he never finds himself ascending or descending a\n"
"hill without immediately beginning to speculate upon his chances,\n"
"supposing--as seems extremely probable--that the weak-kneed controller\n"
"of his destiny should let go.\n"
"\n"
"But even this diversion failed to enliven after awhile, and the _ennui_\n"
"became perfectly unbearable. I felt my mind giving way under it. It is\n"
"not a strong mind, and I thought it would be unwise to tax it too far.\n"
"So somewhere about the twentieth morning I got up early, had a good\n"
"breakfast, and walked straight off to Hayfield, at the foot of the\n"
"Kinder Scout--a pleasant, busy little town, reached through a lovely\n"
"valley, and with two sweetly pretty women in it. At least they were\n"
"sweetly pretty then; one passed me on the bridge and, I think, smiled;\n"
"and the other was standing at an open door, making an unremunerative\n"
"investment of kisses upon a red-faced baby. But it is years ago, and I\n"
"dare say they have both grown stout and snappish since that time.\n"
"Coming back, I saw an old man breaking stones, and it roused such strong\n"
"longing in me to use my arms that I offered him a drink to let me take\n"
"his place. He was a kindly old man and he humored me. I went for those\n"
"stones with the accumulated energy of three weeks, and did more work in\n"
"half an hour than he had done all day. But it did not make him jealous.\n"
"\n"
"Having taken the plunge, I went further and further into dissipation,\n"
"going out for a long walk every morning and listening to the band in\n"
"the pavilion every evening. But the days still passed slowly\n"
"notwithstanding, and I was heartily glad when the last one came and I\n"
"was being whirled away from gouty, consumptive Buxton to London with its\n"
"stern work and life. I looked out of the carriage as we rushed through\n"
"Hendon in the evening. The lurid glare overhanging the mighty city\n"
"seemed to warm my heart, and when, later on, my cab rattled out of St.\n"
"Pancras' station, the old familiar roar that came swelling up around me\n"
"sounded the sweetest music I had heard for many a long day.\n"
"\n"
"I certainly did not enjoy that month's idling. I like idling when I\n"
"ought not to be idling; not when it is the only thing I have to do. That\n"
"is my pig-headed nature. The time when I like best to stand with my\n"
"back to the fire, calculating how much I owe, is when my desk is heaped\n"
"highest with letters that must be answered by the next post. When I like\n"
"to dawdle longest over my dinner is when I have a heavy evening's work\n"
"before me. And if, for some urgent reason, I ought to be up particularly\n"
"early in the morning, it is then, more than at any other time, that I\n"
"love to lie an extra half-hour in bed.\n"
"\n"
"Ah! how delicious it is to turn over and go to sleep again: \"just for\n"
"five minutes.\" Is there any human being, I wonder, besides the hero of\n"
"a Sunday-school \"tale for boys,\" who ever gets up willingly? There\n"
"are some men to whom getting up at the proper time is an utter\n"
"impossibility. If eight o'clock happens to be the time that they should\n"
"turn out, then they lie till half-past. If circumstances change and\n"
"half-past eight becomes early enough for them, then it is nine before\n"
"they can rise. They are like the statesman of whom it was said that he\n"
"was always punctually half an hour late. They try all manner of schemes.\n"
"They buy alarm-clocks (artful contrivances that go off at the wrong time\n"
"and alarm the wrong people). They tell Sarah Jane to knock at the door\n"
"and call them, and Sarah Jane does knock at the door and does call them,\n"
"and they grunt back \"awri\" and then go comfortably to sleep again. I\n"
"knew one man who would actually get out and have a cold bath; and even\n"
"that was of no use, for afterward he would jump into bed again to warm\n"
"himself.\n"
"\n"
"I think myself that I could keep out of bed all right if I once got\n"
"out. It is the wrenching away of the head from the pillow that I find so\n"
"hard, and no amount of over-night determination makes it easier. I say\n"
"to myself, after having wasted the whole evening, \"Well, I won't do\n"
"any more work to-night; I'll get up early to-morrow morning;\" and I am\n"
"thoroughly resolved to do so--then. In the morning, however, I feel less\n"
"enthusiastic about the idea, and reflect that it would have been much\n"
"better if I had stopped up last night. And then there is the trouble of\n"
"dressing, and the more one thinks about that the more one wants to put\n"
"it off.\n"
"\n"
"It is a strange thing this bed, this mimic grave, where we stretch our\n"
"tired limbs and sink away so quietly into the silence and rest. \"O bed,\n"
"O bed, delicious bed, that heaven on earth to the weary head,\" as sang\n"
"poor Hood, you are a kind old nurse to us fretful boys and girls. Clever\n"
"and foolish, naughty and good, you take us all in your motherly lap and\n"
"hush our wayward crying. The strong man full of care--the sick man\n"
"full of pain--the little maiden sobbing for her faithless lover--like\n"
"children we lay our aching heads on your white bosom, and you gently\n"
"soothe us off to by-by.\n"
"\n"
"Our trouble is sore indeed when you turn away and will not comfort us.\n"
"How long the dawn seems coming when we cannot sleep! Oh! those hideous\n"
"nights when we toss and turn in fever and pain, when we lie, like living\n"
"men among the dead, staring out into the dark hours that drift so slowly\n"
"between us and the light. And oh! those still more hideous nights when\n"
"we sit by another in pain, when the low fire startles us every now and\n"
"then with a falling cinder, and the tick of the clock seems a hammer\n"
"beating out the life that we are watching.\n"
"\n"
"But enough of beds and bedrooms. I have kept to them too long, even for\n"
"an idle fellow. Let us come out and have a smoke. That wastes time just\n"
"as well and does not look so bad. Tobacco has been a blessing to us\n"
"idlers. What the civil-service clerk before Sir Walter's time found\n"
"to occupy their minds with it is hard to imagine. I attribute the\n"
"quarrelsome nature of the Middle Ages young men entirely to the want of\n"
"the soothing weed. They had no work to do and could not smoke, and\n"
"the consequence was they were forever fighting and rowing. If, by any\n"
"extraordinary chance, there was no war going, then they got up a deadly\n"
"family feud with the next-door neighbor, and if, in spite of this, they\n"
"still had a few spare moments on their hands, they occupied them with\n"
"discussions as to whose sweetheart was the best looking, the arguments\n"
"employed on both sides being battle-axes, clubs, etc. Questions of taste\n"
"were soon decided in those days. When a twelfth-century youth fell in\n"
"love he did not take three paces backward, gaze into her eyes, and tell\n"
"her she was too beautiful to live. He said he would step outside and see\n"
"about it. And if, when he got out, he met a man and broke his head--the\n"
"other man's head, I mean--then that proved that his--the first\n"
"fellow's--girl was a pretty girl. But if the other fellow broke _his_\n"
"head--not his own, you know, but the other fellow's--the other fellow\n"
"to the second fellow, that is, because of course the other fellow would\n"
"only be the other fellow to him, not the first fellow who--well, if he\n"
"broke his head, then _his_ girl--not the other fellow's, but the fellow\n"
"who _was_ the--Look here, if A broke B's head, then A's girl was a\n"
"pretty girl; but if B broke A's head, then A's girl wasn't a pretty\n"
"girl, but B's girl was. That was their method of conducting art\n"
"criticism.\n"
"\n"
"Nowadays we light a pipe and let the girls fight it out among\n"
"themselves.\n"
"\n"
"They do it very well. They are getting to do all our work. They are\n"
"doctors, and barristers, and artists. They manage theaters, and promote\n"
"swindles, and edit newspapers. I am looking forward to the time when we\n"
"men shall have nothing to do but lie in bed till twelve, read two novels\n"
"a day, have nice little five-o'clock teas all to ourselves, and tax\n"
"our brains with nothing more trying than discussions upon the latest\n"
"patterns in trousers and arguments as to what Mr. Jones' coat was\n"
"made of and whether it fitted him. It is a glorious prospect--for idle\n"
"fellows.\n"
"\n\n\n"
;
static const size_t IDLE_SIZE = sizeof(on_being_idle) - 1;
#endif
/* This is the "LSWS" mode: first write is performed immediately, outside /* This is the "LSWS" mode: first write is performed immediately, outside
* of the on_write() callback. This makes it possible to play with buffered * of the on_write() callback. This makes it possible to play with buffered
@ -43,11 +279,13 @@ static const size_t IDLE_SIZE;
static int s_immediate_write; static int s_immediate_write;
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define V(v) (v), strlen(v)
struct lsquic_conn_ctx; struct lsquic_conn_ctx;
static void interop_server_hset_destroy (void *); static void interop_server_hset_destroy (void *);
struct server_ctx { struct server_ctx {
struct lsquic_conn_ctx *conn_h; struct lsquic_conn_ctx *conn_h;
lsquic_engine_t *engine; lsquic_engine_t *engine;
@ -278,12 +516,14 @@ static int
send_headers (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h) send_headers (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{ {
const char *content_type; const char *content_type;
struct header_buf hbuf;
content_type = select_content_type(st_h); content_type = select_content_type(st_h);
struct lsxpack_header headers_arr[2]; struct lsxpack_header headers_arr[2];
lsxpack_header_set_ptr(&headers_arr[0], ":status", 7, "200", 3); hbuf.off = 0;
lsxpack_header_set_ptr(&headers_arr[1], "content-type", 12, header_set_ptr(&headers_arr[0], &hbuf, ":status", 7, "200", 3);
header_set_ptr(&headers_arr[1], &hbuf, "content-type", 12,
content_type, strlen(content_type)); content_type, strlen(content_type));
lsquic_http_headers_t headers = { lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]), .count = sizeof(headers_arr) / sizeof(headers_arr[0]),
@ -301,7 +541,7 @@ send_headers (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
static void static void
resume_response (int fd, short what, void *arg) resume_response (evutil_socket_t fd, short what, void *arg)
{ {
struct lsquic_stream_ctx *const st_h = arg; struct lsquic_stream_ctx *const st_h = arg;
@ -551,6 +791,7 @@ push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
regex_t re; regex_t re;
regmatch_t matches[2]; regmatch_t matches[2];
struct hset_fm *hfm; struct hset_fm *hfm;
struct header_buf hbuf;
s = regcomp(&re, "\r\nHost: *([[:alnum:].][[:alnum:].]*)\r\n", s = regcomp(&re, "\r\nHost: *([[:alnum:].][[:alnum:].]*)\r\n",
REG_EXTENDED|REG_ICASE); REG_EXTENDED|REG_ICASE);
@ -577,16 +818,17 @@ push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
} }
#define V(v) (v), strlen(v) #define V(v) (v), strlen(v)
hbuf.off = 0;
struct lsxpack_header headers_arr[6]; struct lsxpack_header headers_arr[6];
lsxpack_header_set_ptr(&headers_arr[0], V(":method"), V("GET")); header_set_ptr(&headers_arr[0], &hbuf, V(":method"), V("GET"));
lsxpack_header_set_ptr(&headers_arr[1], V(":path"), header_set_ptr(&headers_arr[1], &hbuf, V(":path"),
V(st_h->server_ctx->push_path)); V(st_h->server_ctx->push_path));
lsxpack_header_set_ptr(&headers_arr[2], V(":authority"), header_set_ptr(&headers_arr[2], &hbuf, V(":authority"),
st_h->req_buf + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); st_h->req_buf + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
lsxpack_header_set_ptr(&headers_arr[3], V(":scheme"), V("https")); header_set_ptr(&headers_arr[3], &hbuf, V(":scheme"), V("https"));
lsxpack_header_set_ptr(&headers_arr[4], V("x-some-header"), header_set_ptr(&headers_arr[4], &hbuf, V("x-some-header"),
V("x-some-value")); V("x-some-value"));
lsxpack_header_set_ptr(&headers_arr[5], V("x-kenny-status"), header_set_ptr(&headers_arr[5], &hbuf, V("x-kenny-status"),
V("Oh my God! They killed Kenny!!! You bastards!")); V("Oh my God! They killed Kenny!!! You bastards!"));
lsquic_http_headers_t headers = { lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]), .count = sizeof(headers_arr) / sizeof(headers_arr[0]),
@ -605,7 +847,6 @@ push_promise (lsquic_stream_ctx_t *st_h, lsquic_stream_t *stream)
return 0; return 0;
} }
#endif
static void static void
@ -641,7 +882,6 @@ static void
http_server_on_read_regular (struct lsquic_stream *stream, http_server_on_read_regular (struct lsquic_stream *stream,
lsquic_stream_ctx_t *st_h) lsquic_stream_ctx_t *st_h)
{ {
#if HAVE_OPEN_MEMSTREAM
unsigned char buf[0x400]; unsigned char buf[0x400];
ssize_t nread; ssize_t nread;
int s; int s;
@ -674,20 +914,22 @@ http_server_on_read_regular (struct lsquic_stream *stream,
LSQ_ERROR("error reading: %s", strerror(errno)); LSQ_ERROR("error reading: %s", strerror(errno));
lsquic_stream_close(stream); lsquic_stream_close(stream);
} }
#else
LSQ_ERROR("%s: open_memstream not supported\n", __func__);
exit(1);
#endif
} }
#endif
static void static void
http_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h) http_server_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *st_h)
{ {
#if HAVE_OPEN_MEMSTREAM
if (lsquic_stream_is_pushed(stream)) if (lsquic_stream_is_pushed(stream))
http_server_on_read_pushed(stream, st_h); http_server_on_read_pushed(stream, st_h);
else else
http_server_on_read_regular(stream, st_h); http_server_on_read_regular(stream, st_h);
#else
LSQ_ERROR("%s: open_memstream not supported\n", __func__);
exit(1);
#endif
} }
@ -716,6 +958,7 @@ const struct lsquic_stream_if http_server_if = {
}; };
#if HAVE_REGEX
struct req_map struct req_map
{ {
enum method method; enum method method;
@ -848,12 +1091,12 @@ read_md5 (void *ctx, const unsigned char *buf, size_t sz, int fin)
static void static void
http_server_interop_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h) http_server_interop_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{ {
#define ERROR_RESP(code, args...) do { \ #define ERROR_RESP(code, ...) do { \
LSQ_WARN(args); \ LSQ_WARN(__VA_ARGS__); \
st_h->interop_handler = IOH_ERROR; \ st_h->interop_handler = IOH_ERROR; \
st_h->resp_status = #code; \ st_h->resp_status = #code; \
st_h->interop_u.err.resp.sz = snprintf(st_h->interop_u.err.buf, \ st_h->interop_u.err.resp.sz = snprintf(st_h->interop_u.err.buf, \
sizeof(st_h->interop_u.err.buf), args); \ sizeof(st_h->interop_u.err.buf), __VA_ARGS__); \
if (st_h->interop_u.err.resp.sz >= sizeof(st_h->interop_u.err.buf)) \ if (st_h->interop_u.err.resp.sz >= sizeof(st_h->interop_u.err.buf)) \
st_h->interop_u.err.resp.sz = sizeof(st_h->interop_u.err.buf) - 1; \ st_h->interop_u.err.resp.sz = sizeof(st_h->interop_u.err.buf) - 1; \
st_h->interop_u.err.resp.buf = st_h->interop_u.err.buf; \ st_h->interop_u.err.resp.buf = st_h->interop_u.err.buf; \
@ -1047,14 +1290,16 @@ send_headers2 (struct lsquic_stream *stream, struct lsquic_stream_ctx *st_h,
size_t content_len) size_t content_len)
{ {
char clbuf[0x20]; char clbuf[0x20];
struct header_buf hbuf;
snprintf(clbuf, sizeof(clbuf), "%zd", content_len); snprintf(clbuf, sizeof(clbuf), "%zd", content_len);
hbuf.off = 0;
struct lsxpack_header headers_arr[4]; struct lsxpack_header headers_arr[4];
lsxpack_header_set_ptr(&headers_arr[0], V(":status"), V(st_h->resp_status)); header_set_ptr(&headers_arr[0], &hbuf, V(":status"), V(st_h->resp_status));
lsxpack_header_set_ptr(&headers_arr[1], V("server"), V(LITESPEED_ID)); header_set_ptr(&headers_arr[1], &hbuf, V("server"), V(LITESPEED_ID));
lsxpack_header_set_ptr(&headers_arr[2], V("content-type"), V("text/html")); header_set_ptr(&headers_arr[2], &hbuf, V("content-type"), V("text/html"));
lsxpack_header_set_ptr(&headers_arr[3], V("content-length"), V(clbuf)); header_set_ptr(&headers_arr[3], &hbuf, V("content-length"), V(clbuf));
lsquic_http_headers_t headers = { lsquic_http_headers_t headers = {
.count = sizeof(headers_arr) / sizeof(headers_arr[0]), .count = sizeof(headers_arr) / sizeof(headers_arr[0]),
.headers = headers_arr, .headers = headers_arr,
@ -1070,7 +1315,7 @@ idle_read (void *lsqr_ctx, void *buf, size_t count)
{ {
struct gen_file_ctx *const gfc = lsqr_ctx; struct gen_file_ctx *const gfc = lsqr_ctx;
unsigned char *p = buf; unsigned char *p = buf;
unsigned char *const end = buf + count; unsigned char *const end = p + count;
size_t towrite; size_t towrite;
while (p < end && gfc->remain > 0) while (p < end && gfc->remain > 0)
@ -1133,6 +1378,7 @@ idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
struct lsquic_http_headers headers; struct lsquic_http_headers headers;
struct req *req; struct req *req;
ssize_t nw; ssize_t nw;
struct header_buf hbuf;
if (st_h->flags & SH_HEADERS_SENT) if (st_h->flags & SH_HEADERS_SENT)
{ {
@ -1158,10 +1404,11 @@ idle_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
{ {
STAILQ_REMOVE_HEAD(&gfc->push_paths, next); STAILQ_REMOVE_HEAD(&gfc->push_paths, next);
LSQ_DEBUG("pushing promise for %s", push_path->path); LSQ_DEBUG("pushing promise for %s", push_path->path);
lsxpack_header_set_ptr(&header_arr[0], V(":method"), V("GET")); hbuf.off = 0;
lsxpack_header_set_ptr(&header_arr[1], V(":path"), V(push_path->path)); header_set_ptr(&header_arr[0], &hbuf, V(":method"), V("GET"));
lsxpack_header_set_ptr(&header_arr[2], V(":authority"), V(st_h->req->authority_str)); header_set_ptr(&header_arr[1], &hbuf, V(":path"), V(push_path->path));
lsxpack_header_set_ptr(&header_arr[3], V(":scheme"), V("https")); header_set_ptr(&header_arr[2], &hbuf, V(":authority"), V(st_h->req->authority_str));
header_set_ptr(&header_arr[3], &hbuf, V(":scheme"), V("https"));
headers.headers = header_arr; headers.headers = header_arr;
headers.count = sizeof(header_arr) / sizeof(header_arr[0]); headers.count = sizeof(header_arr) / sizeof(header_arr[0]);
req = new_req(GET, push_path->path, st_h->req->authority_str); req = new_req(GET, push_path->path, st_h->req->authority_str);
@ -1243,6 +1490,7 @@ const struct lsquic_stream_if interop_http_server_if = {
.on_write = http_server_interop_on_write, .on_write = http_server_interop_on_write,
.on_close = http_server_on_close, .on_close = http_server_on_close,
}; };
#endif /* HAVE_REGEX */
static void static void
@ -1308,6 +1556,23 @@ interop_server_hset_prepare_decode (void *hset_p, struct lsxpack_header *xhdr,
} }
#ifdef WIN32
char *
strndup (const char *s, size_t n)
{
char *copy;
copy = malloc(n + 1);
if (!copy)
return NULL;
memcpy(copy, s, n);
copy[n] = '\0';
return copy;
}
#endif
static int static int
interop_server_hset_add_header (void *hset_p, struct lsxpack_header *xhdr) interop_server_hset_add_header (void *hset_p, struct lsxpack_header *xhdr)
{ {
@ -1403,6 +1668,11 @@ main (int argc, char **argv)
struct server_ctx server_ctx; struct server_ctx server_ctx;
struct prog prog; struct prog prog;
#if !(HAVE_OPEN_MEMSTREAM || HAVE_REGEX)
fprintf(stderr, "cannot run server without regex or open_memstream\n");
return 1;
#endif
memset(&server_ctx, 0, sizeof(server_ctx)); memset(&server_ctx, 0, sizeof(server_ctx));
TAILQ_INIT(&server_ctx.sports); TAILQ_INIT(&server_ctx.sports);
server_ctx.prog = &prog; server_ctx.prog = &prog;
@ -1425,11 +1695,13 @@ main (int argc, char **argv)
perror("stat"); perror("stat");
exit(2); exit(2);
} }
#ifndef WIN32
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode))
{ {
fprintf(stderr, "`%s' is not a directory\n", optarg); fprintf(stderr, "`%s' is not a directory\n", optarg);
exit(2); exit(2);
} }
#endif
server_ctx.document_root = optarg; server_ctx.document_root = optarg;
break; break;
case 'w': case 'w':
@ -1450,11 +1722,16 @@ main (int argc, char **argv)
if (!server_ctx.document_root) if (!server_ctx.document_root)
{ {
#if HAVE_REGEX
LSQ_NOTICE("Document root is not set: start in Interop Mode"); LSQ_NOTICE("Document root is not set: start in Interop Mode");
init_map_regexes(); init_map_regexes();
prog.prog_api.ea_stream_if = &interop_http_server_if; prog.prog_api.ea_stream_if = &interop_http_server_if;
prog.prog_api.ea_hsi_if = &header_bypass_api; prog.prog_api.ea_hsi_if = &header_bypass_api;
prog.prog_api.ea_hsi_ctx = NULL; prog.prog_api.ea_hsi_ctx = NULL;
#else
LSQ_ERROR("Document root is not set: use -r option");
exit(EXIT_FAILURE);
#endif
} }
if (0 != prog_prep(&prog)) if (0 != prog_prep(&prog))
@ -1468,233 +1745,10 @@ main (int argc, char **argv)
s = prog_run(&prog); s = prog_run(&prog);
prog_cleanup(&prog); prog_cleanup(&prog);
#if HAVE_REGEX
if (!server_ctx.document_root) if (!server_ctx.document_root)
free_map_regexes(); free_map_regexes();
#endif
exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE); exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
} }
static const char on_being_idle[] =
"ON BEING IDLE.\n"
"\n"
"Now, this is a subject on which I flatter myself I really am _au fait_.\n"
"The gentleman who, when I was young, bathed me at wisdom's font for nine\n"
"guineas a term--no extras--used to say he never knew a boy who could\n"
"do less work in more time; and I remember my poor grandmother once\n"
"incidentally observing, in the course of an instruction upon the use\n"
"of the Prayer-book, that it was highly improbable that I should ever do\n"
"much that I ought not to do, but that she felt convinced beyond a doubt\n"
"that I should leave undone pretty well everything that I ought to do.\n"
"\n"
"I am afraid I have somewhat belied half the dear old lady's prophecy.\n"
"Heaven help me! I have done a good many things that I ought not to have\n"
"done, in spite of my laziness. But I have fully confirmed the accuracy\n"
"of her judgment so far as neglecting much that I ought not to have\n"
"neglected is concerned. Idling always has been my strong point. I take\n"
"no credit to myself in the matter--it is a gift. Few possess it. There\n"
"are plenty of lazy people and plenty of slow-coaches, but a genuine\n"
"idler is a rarity. He is not a man who slouches about with his hands in\n"
"his pockets. On the contrary, his most startling characteristic is that\n"
"he is always intensely busy.\n"
"\n"
"It is impossible to enjoy idling thoroughly unless one has plenty of\n"
"work to do. There is no fun in doing nothing when you have nothing to\n"
"do. Wasting time is merely an occupation then, and a most exhausting\n"
"one. Idleness, like kisses, to be sweet must be stolen.\n"
"\n"
"Many years ago, when I was a young man, I was taken very ill--I never\n"
"could see myself that much was the matter with me, except that I had\n"
"a beastly cold. But I suppose it was something very serious, for the\n"
"doctor said that I ought to have come to him a month before, and that\n"
"if it (whatever it was) had gone on for another week he would not have\n"
"answered for the consequences. It is an extraordinary thing, but I\n"
"never knew a doctor called into any case yet but what it transpired\n"
"that another day's delay would have rendered cure hopeless. Our medical\n"
"guide, philosopher, and friend is like the hero in a melodrama--he\n"
"always comes upon the scene just, and only just, in the nick of time. It\n"
"is Providence, that is what it is.\n"
"\n"
"Well, as I was saying, I was very ill and was ordered to Buxton for a\n"
"month, with strict injunctions to do nothing whatever all the while\n"
"that I was there. \"Rest is what you require,\" said the doctor, \"perfect\n"
"rest.\"\n"
"\n"
"It seemed a delightful prospect. \"This man evidently understands my\n"
"complaint,\" said I, and I pictured to myself a glorious time--a four\n"
"weeks' _dolce far niente_ with a dash of illness in it. Not too much\n"
"illness, but just illness enough--just sufficient to give it the flavor\n"
"of suffering and make it poetical. I should get up late, sip chocolate,\n"
"and have my breakfast in slippers and a dressing-gown. I should lie out\n"
"in the garden in a hammock and read sentimental novels with a melancholy\n"
"ending, until the books should fall from my listless hand, and I should\n"
"recline there, dreamily gazing into the deep blue of the firmament,\n"
"watching the fleecy clouds floating like white-sailed ships across\n"
"its depths, and listening to the joyous song of the birds and the low\n"
"rustling of the trees. Or, on becoming too weak to go out of doors,\n"
"I should sit propped up with pillows at the open window of the\n"
"ground-floor front, and look wasted and interesting, so that all the\n"
"pretty girls would sigh as they passed by.\n"
"\n"
"And twice a day I should go down in a Bath chair to the Colonnade to\n"
"drink the waters. Oh, those waters! I knew nothing about them then,\n"
"and was rather taken with the idea. \"Drinking the waters\" sounded\n"
"fashionable and Queen Anne-fied, and I thought I should like them. But,\n"
"ugh! after the first three or four mornings! Sam Weller's description of\n"
"them as \"having a taste of warm flat-irons\" conveys only a faint idea of\n"
"their hideous nauseousness. If anything could make a sick man get well\n"
"quickly, it would be the knowledge that he must drink a glassful of them\n"
"every day until he was recovered. I drank them neat for six consecutive\n"
"days, and they nearly killed me; but after then I adopted the plan of\n"
"taking a stiff glass of brandy-and-water immediately on the top of them,\n"
"and found much relief thereby. I have been informed since, by various\n"
"eminent medical gentlemen, that the alcohol must have entirely\n"
"counteracted the effects of the chalybeate properties contained in the\n"
"water. I am glad I was lucky enough to hit upon the right thing.\n"
"\n"
"But \"drinking the waters\" was only a small portion of the torture I\n"
"experienced during that memorable month--a month which was, without\n"
"exception, the most miserable I have ever spent. During the best part of\n"
"it I religiously followed the doctor's mandate and did nothing whatever,\n"
"except moon about the house and garden and go out for two hours a day in\n"
"a Bath chair. That did break the monotony to a certain extent. There is\n"
"more excitement about Bath-chairing--especially if you are not used to\n"
"the exhilarating exercise--than might appear to the casual observer. A\n"
"sense of danger, such as a mere outsider might not understand, is ever\n"
"present to the mind of the occupant. He feels convinced every minute\n"
"that the whole concern is going over, a conviction which becomes\n"
"especially lively whenever a ditch or a stretch of newly macadamized\n"
"road comes in sight. Every vehicle that passes he expects is going to\n"
"run into him; and he never finds himself ascending or descending a\n"
"hill without immediately beginning to speculate upon his chances,\n"
"supposing--as seems extremely probable--that the weak-kneed controller\n"
"of his destiny should let go.\n"
"\n"
"But even this diversion failed to enliven after awhile, and the _ennui_\n"
"became perfectly unbearable. I felt my mind giving way under it. It is\n"
"not a strong mind, and I thought it would be unwise to tax it too far.\n"
"So somewhere about the twentieth morning I got up early, had a good\n"
"breakfast, and walked straight off to Hayfield, at the foot of the\n"
"Kinder Scout--a pleasant, busy little town, reached through a lovely\n"
"valley, and with two sweetly pretty women in it. At least they were\n"
"sweetly pretty then; one passed me on the bridge and, I think, smiled;\n"
"and the other was standing at an open door, making an unremunerative\n"
"investment of kisses upon a red-faced baby. But it is years ago, and I\n"
"dare say they have both grown stout and snappish since that time.\n"
"Coming back, I saw an old man breaking stones, and it roused such strong\n"
"longing in me to use my arms that I offered him a drink to let me take\n"
"his place. He was a kindly old man and he humored me. I went for those\n"
"stones with the accumulated energy of three weeks, and did more work in\n"
"half an hour than he had done all day. But it did not make him jealous.\n"
"\n"
"Having taken the plunge, I went further and further into dissipation,\n"
"going out for a long walk every morning and listening to the band in\n"
"the pavilion every evening. But the days still passed slowly\n"
"notwithstanding, and I was heartily glad when the last one came and I\n"
"was being whirled away from gouty, consumptive Buxton to London with its\n"
"stern work and life. I looked out of the carriage as we rushed through\n"
"Hendon in the evening. The lurid glare overhanging the mighty city\n"
"seemed to warm my heart, and when, later on, my cab rattled out of St.\n"
"Pancras' station, the old familiar roar that came swelling up around me\n"
"sounded the sweetest music I had heard for many a long day.\n"
"\n"
"I certainly did not enjoy that month's idling. I like idling when I\n"
"ought not to be idling; not when it is the only thing I have to do. That\n"
"is my pig-headed nature. The time when I like best to stand with my\n"
"back to the fire, calculating how much I owe, is when my desk is heaped\n"
"highest with letters that must be answered by the next post. When I like\n"
"to dawdle longest over my dinner is when I have a heavy evening's work\n"
"before me. And if, for some urgent reason, I ought to be up particularly\n"
"early in the morning, it is then, more than at any other time, that I\n"
"love to lie an extra half-hour in bed.\n"
"\n"
"Ah! how delicious it is to turn over and go to sleep again: \"just for\n"
"five minutes.\" Is there any human being, I wonder, besides the hero of\n"
"a Sunday-school \"tale for boys,\" who ever gets up willingly? There\n"
"are some men to whom getting up at the proper time is an utter\n"
"impossibility. If eight o'clock happens to be the time that they should\n"
"turn out, then they lie till half-past. If circumstances change and\n"
"half-past eight becomes early enough for them, then it is nine before\n"
"they can rise. They are like the statesman of whom it was said that he\n"
"was always punctually half an hour late. They try all manner of schemes.\n"
"They buy alarm-clocks (artful contrivances that go off at the wrong time\n"
"and alarm the wrong people). They tell Sarah Jane to knock at the door\n"
"and call them, and Sarah Jane does knock at the door and does call them,\n"
"and they grunt back \"awri\" and then go comfortably to sleep again. I\n"
"knew one man who would actually get out and have a cold bath; and even\n"
"that was of no use, for afterward he would jump into bed again to warm\n"
"himself.\n"
"\n"
"I think myself that I could keep out of bed all right if I once got\n"
"out. It is the wrenching away of the head from the pillow that I find so\n"
"hard, and no amount of over-night determination makes it easier. I say\n"
"to myself, after having wasted the whole evening, \"Well, I won't do\n"
"any more work to-night; I'll get up early to-morrow morning;\" and I am\n"
"thoroughly resolved to do so--then. In the morning, however, I feel less\n"
"enthusiastic about the idea, and reflect that it would have been much\n"
"better if I had stopped up last night. And then there is the trouble of\n"
"dressing, and the more one thinks about that the more one wants to put\n"
"it off.\n"
"\n"
"It is a strange thing this bed, this mimic grave, where we stretch our\n"
"tired limbs and sink away so quietly into the silence and rest. \"O bed,\n"
"O bed, delicious bed, that heaven on earth to the weary head,\" as sang\n"
"poor Hood, you are a kind old nurse to us fretful boys and girls. Clever\n"
"and foolish, naughty and good, you take us all in your motherly lap and\n"
"hush our wayward crying. The strong man full of care--the sick man\n"
"full of pain--the little maiden sobbing for her faithless lover--like\n"
"children we lay our aching heads on your white bosom, and you gently\n"
"soothe us off to by-by.\n"
"\n"
"Our trouble is sore indeed when you turn away and will not comfort us.\n"
"How long the dawn seems coming when we cannot sleep! Oh! those hideous\n"
"nights when we toss and turn in fever and pain, when we lie, like living\n"
"men among the dead, staring out into the dark hours that drift so slowly\n"
"between us and the light. And oh! those still more hideous nights when\n"
"we sit by another in pain, when the low fire startles us every now and\n"
"then with a falling cinder, and the tick of the clock seems a hammer\n"
"beating out the life that we are watching.\n"
"\n"
"But enough of beds and bedrooms. I have kept to them too long, even for\n"
"an idle fellow. Let us come out and have a smoke. That wastes time just\n"
"as well and does not look so bad. Tobacco has been a blessing to us\n"
"idlers. What the civil-service clerk before Sir Walter's time found\n"
"to occupy their minds with it is hard to imagine. I attribute the\n"
"quarrelsome nature of the Middle Ages young men entirely to the want of\n"
"the soothing weed. They had no work to do and could not smoke, and\n"
"the consequence was they were forever fighting and rowing. If, by any\n"
"extraordinary chance, there was no war going, then they got up a deadly\n"
"family feud with the next-door neighbor, and if, in spite of this, they\n"
"still had a few spare moments on their hands, they occupied them with\n"
"discussions as to whose sweetheart was the best looking, the arguments\n"
"employed on both sides being battle-axes, clubs, etc. Questions of taste\n"
"were soon decided in those days. When a twelfth-century youth fell in\n"
"love he did not take three paces backward, gaze into her eyes, and tell\n"
"her she was too beautiful to live. He said he would step outside and see\n"
"about it. And if, when he got out, he met a man and broke his head--the\n"
"other man's head, I mean--then that proved that his--the first\n"
"fellow's--girl was a pretty girl. But if the other fellow broke _his_\n"
"head--not his own, you know, but the other fellow's--the other fellow\n"
"to the second fellow, that is, because of course the other fellow would\n"
"only be the other fellow to him, not the first fellow who--well, if he\n"
"broke his head, then _his_ girl--not the other fellow's, but the fellow\n"
"who _was_ the--Look here, if A broke B's head, then A's girl was a\n"
"pretty girl; but if B broke A's head, then A's girl wasn't a pretty\n"
"girl, but B's girl was. That was their method of conducting art\n"
"criticism.\n"
"\n"
"Nowadays we light a pipe and let the girls fight it out among\n"
"themselves.\n"
"\n"
"They do it very well. They are getting to do all our work. They are\n"
"doctors, and barristers, and artists. They manage theaters, and promote\n"
"swindles, and edit newspapers. I am looking forward to the time when we\n"
"men shall have nothing to do but lie in bed till twelve, read two novels\n"
"a day, have nice little five-o'clock teas all to ourselves, and tax\n"
"our brains with nothing more trying than discussions upon the latest\n"
"patterns in trousers and arguments as to what Mr. Jones' coat was\n"
"made of and whether it fitted him. It is a glorious prospect--for idle\n"
"fellows.\n"
"\n\n\n"
;
static const size_t IDLE_SIZE = sizeof(on_being_idle) - 1;

View file

@ -10,11 +10,17 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#else
#include "vc_compat.h"
#include "getopt.h"
#endif
#include <event2/event.h> #include <event2/event.h>
#include <openssl/md5.h> #include <openssl/md5.h>

View file

@ -16,7 +16,8 @@
#ifndef WIN32 #ifndef WIN32
#include <unistd.h> #include <unistd.h>
#else #else
#include <getopt.h> #include "vc_compat.h"
#include "getopt.h"
#pragma warning(disable:4028) #pragma warning(disable:4028)
#endif// WIN32 #endif// WIN32
@ -47,11 +48,20 @@ static const struct lsquic_packout_mem_if pmi = {
}; };
void int
prog_init (struct prog *prog, unsigned flags, prog_init (struct prog *prog, unsigned flags,
struct sport_head *sports, struct sport_head *sports,
const struct lsquic_stream_if *stream_if, void *stream_if_ctx) const struct lsquic_stream_if *stream_if, void *stream_if_ctx)
{ {
#ifdef WIN32
WSADATA wsd;
int s = WSAStartup(MAKEWORD(2, 2), &wsd);
if (s != 0)
{
LSQ_ERROR("WSAStartup failed: %d", s);
return -1;
}
#endif
/* prog-specific initialization: */ /* prog-specific initialization: */
memset(prog, 0, sizeof(*prog)); memset(prog, 0, sizeof(*prog));
prog->prog_engine_flags = flags; prog->prog_engine_flags = flags;
@ -82,6 +92,7 @@ prog_init (struct prog *prog, unsigned flags,
LSQUIC_GLOBAL_CLIENT); LSQUIC_GLOBAL_CLIENT);
lsquic_log_to_fstream(stderr, LLTS_HHMMSSMS); lsquic_log_to_fstream(stderr, LLTS_HHMMSSMS);
lsquic_logger_lopt("=notice"); lsquic_logger_lopt("=notice");
return 0;
} }
@ -245,8 +256,10 @@ int supports_gso(void)
int int
prog_set_opt (struct prog *prog, int opt, const char *arg) prog_set_opt (struct prog *prog, int opt, const char *arg)
{ {
#ifndef WIN32
struct stat st; struct stat st;
int s; int s;
#endif
switch (opt) switch (opt)
{ {

View file

@ -55,7 +55,7 @@ struct prog
} prog_flags; } prog_flags;
}; };
void int
prog_init (struct prog *, unsigned lsquic_engine_flags, struct sport_head *, prog_init (struct prog *, unsigned lsquic_engine_flags, struct sport_head *,
const struct lsquic_stream_if *, void *stream_if_ctx); const struct lsquic_stream_if *, void *stream_if_ctx);

View file

@ -21,7 +21,7 @@ static int
select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen, select_alpn (SSL *ssl, const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg) const unsigned char *in, unsigned int inlen, void *arg)
{ {
const unsigned char alpn[] = "\x5h3-25\x5h3-27"; const unsigned char alpn[] = "\x5h3-27\x5h3-28";
int r; int r;
r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen, r = SSL_select_next_proto((unsigned char **) out, outlen, in, inlen,

View file

@ -31,8 +31,13 @@
#include <fcntl.h> #include <fcntl.h>
#include "test_config.h" #include "test_config.h"
#if HAVE_REGEX #if HAVE_REGEX
#ifndef WIN32
#include <regex.h> #include <regex.h>
#else
#include <pcreposix.h>
#endif
#endif #endif
#include <event2/event.h> #include <event2/event.h>
@ -40,6 +45,7 @@
#include "test_common.h" #include "test_common.h"
#include "lsquic.h" #include "lsquic.h"
#include "prog.h" #include "prog.h"
#include "lsxpack_header.h"
#include "../src/liblsquic/lsquic_logger.h" #include "../src/liblsquic/lsquic_logger.h"
@ -50,16 +56,6 @@
#define LSQUIC_USE_POOLS 1 #define LSQUIC_USE_POOLS 1
#endif #endif
#ifndef WIN32
# define SOCKET_TYPE int
# define CLOSE_SOCKET close
# define CHAR_CAST
#else
# define SOCKET_TYPE SOCKET
# define CLOSE_SOCKET closesocket
# define CHAR_CAST (char *)
#endif
#if __linux__ #if __linux__
# define NDROPPED_SZ CMSG_SPACE(sizeof(uint32_t)) /* SO_RXQ_OVFL */ # define NDROPPED_SZ CMSG_SPACE(sizeof(uint32_t)) /* SO_RXQ_OVFL */
#else #else
@ -178,9 +174,10 @@ allocate_packets_in (SOCKET_TYPE fd)
return NULL; return NULL;
} }
n_alloc = (unsigned) recvsz / MAX_PACKET_SZ * 2; n_alloc = (unsigned) recvsz / 1370;
LSQ_INFO("socket buffer size: %d bytes; max # packets is set to %u", LSQ_INFO("socket buffer size: %d bytes; max # packets is set to %u",
recvsz, n_alloc); recvsz, n_alloc);
recvsz += MAX_PACKET_SZ;
packs_in = malloc(sizeof(*packs_in)); packs_in = malloc(sizeof(*packs_in));
packs_in->data_sz = recvsz; packs_in->data_sz = recvsz;
@ -521,7 +518,9 @@ read_one_packet (struct read_iter *iter)
packs_in->vecs[iter->ri_idx].len = MAX_PACKET_SZ; packs_in->vecs[iter->ri_idx].len = MAX_PACKET_SZ;
#endif #endif
#ifndef WIN32
top: top:
#endif
ctl_buf = packs_in->ctlmsg_data + iter->ri_idx * CTL_SZ; ctl_buf = packs_in->ctlmsg_data + iter->ri_idx * CTL_SZ;
#ifndef WIN32 #ifndef WIN32
@ -800,7 +799,11 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
struct event_base *eb) struct event_base *eb)
{ {
const struct sockaddr *sa_local = (struct sockaddr *) &sport->sas; const struct sockaddr *sa_local = (struct sockaddr *) &sport->sas;
int sockfd, saved_errno, flags, s, on; int sockfd, saved_errno, s;
#ifndef WIN32
int flags;
#endif
SOCKOPT_VAL on;
socklen_t socklen; socklen_t socklen;
char addr_str[0x20]; char addr_str[0x20];
@ -817,6 +820,9 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
return -1; return -1;
} }
#if WIN32
getExtensionPtrs();
#endif
sockfd = socket(sa_local->sa_family, SOCK_DGRAM, 0); sockfd = socket(sa_local->sa_family, SOCK_DGRAM, 0);
if (-1 == sockfd) if (-1 == sockfd)
return -1; return -1;
@ -830,6 +836,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
} }
/* Make socket non-blocking */ /* Make socket non-blocking */
#ifndef WIN32
flags = fcntl(sockfd, F_GETFL); flags = fcntl(sockfd, F_GETFL);
if (-1 == flags) { if (-1 == flags) {
saved_errno = errno; saved_errno = errno;
@ -844,20 +851,33 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
errno = saved_errno; errno = saved_errno;
return -1; return -1;
} }
#else
{
u_long on = 1;
ioctlsocket(sockfd, FIONBIO, &on);
}
#endif
on = 1; on = 1;
if (AF_INET == sa_local->sa_family) if (AF_INET == sa_local->sa_family)
s = setsockopt(sockfd, IPPROTO_IP, s = setsockopt(sockfd, IPPROTO_IP,
#if __linux__ && defined(IP_RECVORIGDSTADDR) #if __linux__ && defined(IP_RECVORIGDSTADDR)
IP_RECVORIGDSTADDR, IP_RECVORIGDSTADDR,
#elif __linux__ || __APPLE__ #elif __linux__ || __APPLE__ || defined(WIN32)
IP_PKTINFO, IP_PKTINFO,
#else #else
IP_RECVDSTADDR, IP_RECVDSTADDR,
#endif #endif
&on, sizeof(on)); CHAR_CAST &on, sizeof(on));
else else
{
#ifndef WIN32
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
#else
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, CHAR_CAST &on, sizeof(on));
#endif
}
if (0 != s) if (0 != s)
{ {
saved_errno = errno; saved_errno = errno;
@ -866,12 +886,12 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
return -1; return -1;
} }
#if (__linux__ && !defined(IP_RECVORIGDSTADDR)) || __APPLE__ #if (__linux__ && !defined(IP_RECVORIGDSTADDR)) || __APPLE__ || defined(WIN32)
/* Need to set IP_PKTINFO for sending */ /* Need to set IP_PKTINFO for sending */
if (AF_INET == sa_local->sa_family) if (AF_INET == sa_local->sa_family)
{ {
on = 1; on = 1;
s = setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, CHAR_CAST &on, sizeof(on));
if (0 != s) if (0 != s)
{ {
saved_errno = errno; saved_errno = errno;
@ -933,7 +953,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
sizeof(on)); sizeof(on));
#else #else
on = 1; on = 1;
s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, CHAR_CAST &on, sizeof(on));
#endif #endif
if (0 != s) if (0 != s)
{ {
@ -949,9 +969,9 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
#if ECN_SUPPORTED #if ECN_SUPPORTED
on = 1; on = 1;
if (AF_INET == sa_local->sa_family) if (AF_INET == sa_local->sa_family)
s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, CHAR_CAST &on, sizeof(on));
else else
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, CHAR_CAST &on, sizeof(on));
if (0 != s) if (0 != s)
{ {
saved_errno = errno; saved_errno = errno;
@ -963,7 +983,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
if (sport->sp_flags & SPORT_SET_SNDBUF) if (sport->sp_flags & SPORT_SET_SNDBUF)
{ {
s = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sport->sp_sndbuf, s = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, CHAR_CAST &sport->sp_sndbuf,
sizeof(sport->sp_sndbuf)); sizeof(sport->sp_sndbuf));
if (0 != s) if (0 != s)
{ {
@ -976,7 +996,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
if (sport->sp_flags & SPORT_SET_RCVBUF) if (sport->sp_flags & SPORT_SET_RCVBUF)
{ {
s = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sport->sp_rcvbuf, s = setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, CHAR_CAST &sport->sp_rcvbuf,
sizeof(sport->sp_rcvbuf)); sizeof(sport->sp_rcvbuf));
if (0 != s) if (0 != s)
{ {
@ -1122,7 +1142,7 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
sizeof(on)); sizeof(on));
#elif WIN32 #elif WIN32
on = 1; on = 1;
s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAGMENT, (char*)&on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAGMENT, CHAR_CAST &on, sizeof(on));
#else #else
on = 1; on = 1;
s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &on, sizeof(on));
@ -1142,10 +1162,11 @@ sport_init_client (struct service_port *sport, struct lsquic_engine *engine,
{ {
int on = 1; int on = 1;
if (AF_INET == sa_local->sa_family) if (AF_INET == sa_local->sa_family)
s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, &on, sizeof(on)); s = setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS,
CHAR_CAST &on, sizeof(on));
else else
s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, s = setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVTCLASS,
sizeof(on)); CHAR_CAST &on, sizeof(on));
if (0 != s) if (0 != s)
{ {
saved_errno = errno; saved_errno = errno;
@ -1549,6 +1570,7 @@ send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count,
#else #else
DWORD bytes; DWORD bytes;
WSAMSG msg; WSAMSG msg;
WSABUF wsaBuf;
#endif #endif
union { union {
/* cmsg(3) recommends union for proper alignment */ /* cmsg(3) recommends union for proper alignment */
@ -1612,12 +1634,14 @@ send_packets_one_by_one (const struct lsquic_out_spec *specs, unsigned count,
msg.msg_iovlen = specs[n].iovlen; msg.msg_iovlen = specs[n].iovlen;
msg.msg_flags = 0; msg.msg_flags = 0;
#else #else
wsaBuf.buf = specs[n].iov->iov_base;
wsaBuf.len = specs[n].iov->iov_len;
msg.name = (void *) specs[n].dest_sa; msg.name = (void *) specs[n].dest_sa;
msg.namelen = (AF_INET == specs[n].dest_sa->sa_family ? msg.namelen = (AF_INET == specs[n].dest_sa->sa_family ?
sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6)), sizeof(struct sockaddr_in6));
msg.lpBuffers = specs[n].iov; msg.dwBufferCount = 1;
msg.dwBufferCount = specs[n].iovlen; msg.lpBuffers = &wsaBuf;
msg.dwFlags = 0; msg.dwFlags = 0;
#endif #endif
if ((sport->sp_flags & SPORT_SERVER) && specs[n].local_sa->sa_family) if ((sport->sp_flags & SPORT_SERVER) && specs[n].local_sa->sa_family)
@ -1882,13 +1906,13 @@ set_engine_option (struct lsquic_engine_settings *settings,
settings->es_versions = 0; settings->es_versions = 0;
} }
enum lsquic_version ver = lsquic_str2ver(val, strlen(val)); enum lsquic_version ver = lsquic_str2ver(val, strlen(val));
if (ver < N_LSQVER) if ((unsigned) ver < N_LSQVER)
{ {
settings->es_versions |= 1 << ver; settings->es_versions |= 1 << ver;
return 0; return 0;
} }
ver = lsquic_alpn2ver(val, strlen(val)); ver = lsquic_alpn2ver(val, strlen(val));
if (ver < N_LSQVER) if ((unsigned) ver < N_LSQVER)
{ {
settings->es_versions |= 1 << ver; settings->es_versions |= 1 << ver;
return 0; return 0;
@ -2049,11 +2073,6 @@ set_engine_option (struct lsquic_engine_settings *settings,
settings->es_qpack_dec_max_size = atoi(val); settings->es_qpack_dec_max_size = atoi(val);
return 0; return 0;
} }
if (0 == strncmp(name, "max_packet_size_rx", 18))
{
settings->es_max_packet_size_rx = atoi(val);
return 0;
}
break; break;
case 20: case 20:
if (0 == strncmp(name, "max_header_list_size", 20)) if (0 == strncmp(name, "max_header_list_size", 20))
@ -2079,6 +2098,13 @@ set_engine_option (struct lsquic_engine_settings *settings,
return 0; return 0;
} }
break; break;
case 23:
if (0 == strncmp(name, "max_udp_payload_size_rx", 18))
{
settings->es_max_udp_payload_size_rx = atoi(val);
return 0;
}
break;
case 24: case 24:
if (0 == strncmp(name, "init_max_stream_data_uni", 24)) if (0 == strncmp(name, "init_max_stream_data_uni", 24))
{ {
@ -2339,3 +2365,22 @@ sport_set_token (struct service_port *sport, const char *token_str)
sport->sp_token_sz = len / 2; sport->sp_token_sz = len / 2;
return 0; return 0;
} }
int
header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf,
const char *name, size_t name_len,
const char *val, size_t val_len)
{
if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf))
{
memcpy(header_buf->buf + header_buf->off, name, name_len);
memcpy(header_buf->buf + header_buf->off + name_len, val, val_len);
lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off,
0, name_len, name_len, val_len);
header_buf->off += name_len + val_len;
return 0;
}
else
return -1;
}

View file

@ -10,6 +10,11 @@
# include <net/if.h> /* For IFNAMSIZ */ # include <net/if.h> /* For IFNAMSIZ */
#endif #endif
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
struct lsquic_engine; struct lsquic_engine;
struct lsquic_engine_settings; struct lsquic_engine_settings;
struct lsquic_out_spec; struct lsquic_out_spec;
@ -19,6 +24,19 @@ struct packets_in;
struct lsquic_conn; struct lsquic_conn;
struct prog; struct prog;
struct reader_ctx; struct reader_ctx;
struct lsxpack_header;
#ifndef WIN32
# define SOCKOPT_VAL int
# define SOCKET_TYPE int
# define CLOSE_SOCKET close
# define CHAR_CAST
#else
# define SOCKOPT_VAL DWORD
# define SOCKET_TYPE SOCKET
# define CLOSE_SOCKET closesocket
# define CHAR_CAST (char *)
#endif
enum sport_flags enum sport_flags
{ {
@ -51,8 +69,8 @@ struct service_port {
struct sockaddr_storage sp_local_addr; struct sockaddr_storage sp_local_addr;
struct packets_in *packs_in; struct packets_in *packs_in;
enum sport_flags sp_flags; enum sport_flags sp_flags;
int sp_sndbuf; /* If SPORT_SET_SNDBUF is set */ SOCKOPT_VAL sp_sndbuf; /* If SPORT_SET_SNDBUF is set */
int sp_rcvbuf; /* If SPORT_SET_RCVBUF is set */ SOCKOPT_VAL sp_rcvbuf; /* If SPORT_SET_RCVBUF is set */
struct prog *sp_prog; struct prog *sp_prog;
unsigned char *sp_token_buf; unsigned char *sp_token_buf;
size_t sp_token_sz; size_t sp_token_sz;
@ -140,4 +158,15 @@ destroy_lsquic_reader_ctx (struct reader_ctx *ctx);
#endif #endif
#endif #endif
struct header_buf
{
unsigned off;
char buf[UINT16_MAX];
};
int
header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf,
const char *name, size_t name_len,
const char *val, size_t val_len);
#endif #endif

View file

@ -693,7 +693,7 @@ settings structure:
Default value is @ref LSQUIC_DF_TIMESTAMPS Default value is @ref LSQUIC_DF_TIMESTAMPS
.. member:: unsigned short es_max_packet_size_rx .. member:: unsigned short es_max_udp_payload_size_rx
Maximum packet size we are willing to receive. This is sent to Maximum packet size we are willing to receive. This is sent to
peer in transport parameters: the library does not enforce this peer in transport parameters: the library does not enforce this
@ -701,7 +701,7 @@ settings structure:
If set to zero, limit is not set. If set to zero, limit is not set.
Default value is :macro:`LSQUIC_DF_MAX_PACKET_SIZE_RX` Default value is :macro:`LSQUIC_DF_MAX_UDP_PAYLOAD_SIZE_RX`
To initialize the settings structure to library defaults, use the following To initialize the settings structure to library defaults, use the following
convenience function: convenience function:
@ -877,7 +877,7 @@ out of date. Please check your :file:`lsquic.h` for actual values.*
Delayed ACKs are off by default. Delayed ACKs are off by default.
.. macro:: LSQUIC_DF_MAX_PACKET_SIZE_RX .. macro:: LSQUIC_DF_MAX_UDP_PAYLOAD_SIZE_RX
By default, incoming packet size is not limited. By default, incoming packet size is not limited.
@ -1099,7 +1099,7 @@ callback.
In client mode, a new connection is created by In client mode, a new connection is created by
.. function:: lsquic_conn_t * lsquic_engine_connect (lsquic_engine_t *engine, enum lsquic_version version, const struct sockaddr *local_sa, const struct sockaddr *peer_sa, void *peer_ctx, lsquic_conn_ctx_t *conn_ctx, const char *sni, unsigned short max_packet_size, const unsigned char *zero_rtt, size_t zero_rtt_len, const unsigned char *token, size_t token_sz) .. function:: lsquic_conn_t * lsquic_engine_connect (lsquic_engine_t *engine, enum lsquic_version version, const struct sockaddr *local_sa, const struct sockaddr *peer_sa, void *peer_ctx, lsquic_conn_ctx_t *conn_ctx, const char *sni, unsigned short max_udp_payload_size, const unsigned char *zero_rtt, size_t zero_rtt_len, const unsigned char *token, size_t token_sz)
:param engine: Engine to use. :param engine: Engine to use.
@ -1132,7 +1132,7 @@ In client mode, a new connection is created by
The SNI is required for Google QUIC connections; it is optional for The SNI is required for Google QUIC connections; it is optional for
IETF QUIC and may be set to NULL. IETF QUIC and may be set to NULL.
:param max_packet_size: :param max_udp_payload_size:
Maximum packet size. If set to zero, it is inferred based on `peer_sa` Maximum packet size. If set to zero, it is inferred based on `peer_sa`
and `version`. and `version`.
@ -1168,11 +1168,7 @@ Closing Connections
Mark connection as going away: send GOAWAY frame and do not accept Mark connection as going away: send GOAWAY frame and do not accept
any more incoming streams, nor generate streams of our own. any more incoming streams, nor generate streams of our own.
In the server mode, of course, we can call this function just fine in both Only applicable to HTTP/3 and GQUIC connections. Otherwise a no-op.
Google and IETF QUIC.
In client mode, calling this function in for an IETF QUIC connection does
not do anything, as the client MUST NOT send GOAWAY frames.
.. function:: void lsquic_conn_close (lsquic_conn_t *conn) .. function:: void lsquic_conn_close (lsquic_conn_t *conn)
@ -1531,7 +1527,9 @@ fields yourself. In that case, the header set must be "read" from the stream vi
.. member:: enum lsquic_hsi_flag hsi_flags .. member:: enum lsquic_hsi_flag hsi_flags
These flags specify properties of decoded headers passed to These flags specify properties of decoded headers passed to
``hsi_process_header()``. ``hsi_process_header()``. This is only applicable to QPACK headers;
HPACK library header properties are based on compilation, not
run-time, options.
.. function:: void * lsquic_stream_get_hset (lsquic_stream_t *stream) .. function:: void * lsquic_stream_get_hset (lsquic_stream_t *stream)

View file

@ -24,9 +24,9 @@ copyright = u'2020, LiteSpeed Technologies'
author = u'LiteSpeed Technologies' author = u'LiteSpeed Technologies'
# The short X.Y version # The short X.Y version
version = u'2.14' version = u'2.16'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = u'2.14.8' release = u'2.16.0'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------

View file

@ -4,10 +4,8 @@ Getting Started
Supported Platforms Supported Platforms
------------------- -------------------
LSQUIC compiles and runs on Linux, FreeBSD, Mac OS, and Android. It has been LSQUIC compiles and runs on Linux, Windows, FreeBSD, Mac OS, and Android.
tested on i386, x86_64, and ARM (Raspberry Pi and Android). It has been tested on i386, x86_64, and ARM (Raspberry Pi and Android).
Windows support is on the TODO list.
Dependencies Dependencies
------------ ------------
@ -25,8 +23,8 @@ What's in the box
----------------- -----------------
- ``src/liblsquic`` -- the library - ``src/liblsquic`` -- the library
- ``test`` -- demo client and server programs - ``bin`` -- demo client and server programs
- ``test/unittests`` -- unit tests - ``tests`` -- unit tests
Building Building
-------- --------

View file

@ -16,7 +16,7 @@ Most of the code in this distribution has been used in our own products
-- `LiteSpeed Web Server`_, `LiteSpeed Web ADC`_, and OpenLiteSpeed_ -- -- `LiteSpeed Web Server`_, `LiteSpeed Web ADC`_, and OpenLiteSpeed_ --
since 2017. since 2017.
Currently supported QUIC versions are Q043, Q046, Q050, ID-25, and ID-27. Currently supported QUIC versions are Q043, Q046, Q050, ID-27, and ID-28.
Support for newer versions will be added soon after they are released. Support for newer versions will be added soon after they are released.
LSQUIC is licensed under the `MIT License`_; see LICENSE in the source LSQUIC is licensed under the `MIT License`_; see LICENSE in the source

View file

@ -24,8 +24,8 @@ extern "C" {
#endif #endif
#define LSQUIC_MAJOR_VERSION 2 #define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 14 #define LSQUIC_MINOR_VERSION 16
#define LSQUIC_PATCH_VERSION 8 #define LSQUIC_PATCH_VERSION 0
/** /**
* Engine flags: * Engine flags:
@ -76,16 +76,16 @@ enum lsquic_version
#define LSQUIC_EXPERIMENTAL_Q098 0 #define LSQUIC_EXPERIMENTAL_Q098 0
#endif #endif
/**
* IETF QUIC Draft-25
*/
LSQVER_ID25,
/** /**
* IETF QUIC Draft-27 * IETF QUIC Draft-27
*/ */
LSQVER_ID27, LSQVER_ID27,
/**
* IETF QUIC Draft-28
*/
LSQVER_ID28,
/** /**
* Special version to trigger version negotiation. * Special version to trigger version negotiation.
* [draft-ietf-quic-transport-11], Section 3. * [draft-ietf-quic-transport-11], Section 3.
@ -96,7 +96,7 @@ enum lsquic_version
}; };
/** /**
* We currently support versions 43, 46, 50, Draft-25, and Draft-27. * We currently support versions 43, 46, 50, Draft-27, and Draft-28.
* @see lsquic_version * @see lsquic_version
*/ */
#define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1) #define LSQUIC_SUPPORTED_VERSIONS ((1 << N_LSQVER) - 1)
@ -113,10 +113,10 @@ enum lsquic_version
#define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043) #define LSQUIC_GQUIC_HEADER_VERSIONS (1 << LSQVER_043)
#define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID25) | (1 << LSQVER_ID27) \ #define LSQUIC_IETF_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
| (1 << LSQVER_VERNEG)) | (1 << LSQVER_VERNEG))
#define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID25) | (1 << LSQVER_ID27) \ #define LSQUIC_IETF_DRAFT_VERSIONS ((1 << LSQVER_ID27) | (1 << LSQVER_ID28) \
| (1 << LSQVER_VERNEG)) | (1 << LSQVER_VERNEG))
enum lsquic_hsk_status enum lsquic_hsk_status
@ -341,7 +341,7 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
#define LSQUIC_DF_CC_ALGO 1 #define LSQUIC_DF_CC_ALGO 1
/** By default, incoming packet size is not limited. */ /** By default, incoming packet size is not limited. */
#define LSQUIC_DF_MAX_PACKET_SIZE_RX 0 #define LSQUIC_DF_MAX_UDP_PAYLOAD_SIZE_RX 0
struct lsquic_engine_settings { struct lsquic_engine_settings {
/** /**
@ -749,9 +749,9 @@ struct lsquic_engine_settings {
* *
* If set to zero, limit is not set. * If set to zero, limit is not set.
* *
* Default value is @ref LSQUIC_DF_MAX_PACKET_SIZE_RX * Default value is @ref LSQUIC_DF_MAX_UDP_PAYLOAD_SIZE_RX
*/ */
unsigned short es_max_packet_size_rx; unsigned short es_max_udp_payload_size_rx;
}; };
/* Initialize `settings' to default values */ /* Initialize `settings' to default values */
@ -943,7 +943,9 @@ struct lsquic_hset_if
void (*hsi_discard_header_set)(void *hdr_set); void (*hsi_discard_header_set)(void *hdr_set);
/** /**
* These flags specify properties of decoded headers passed to * These flags specify properties of decoded headers passed to
* hsi_process_header(). * hsi_process_header(). This is only applicable to QPACK headers;
* HPACK library header properties are based on compilation, not
* run-time, options.
*/ */
enum lsquic_hsi_flag hsi_flags; enum lsquic_hsi_flag hsi_flags;
}; };
@ -1078,7 +1080,7 @@ lsquic_engine_new (unsigned lsquic_engine_flags,
* To let the engine specify QUIC version, use N_LSQVER. If zero-rtt info * To let the engine specify QUIC version, use N_LSQVER. If zero-rtt info
* is supplied, version is picked from there instead. * is supplied, version is picked from there instead.
* *
* If `max_packet_size' is set to zero, it is inferred based on `peer_sa': * If `max_udp_payload_size' is set to zero, it is inferred based on `peer_sa':
* 1350 for IPv6 and 1370 for IPv4. * 1350 for IPv6 and 1370 for IPv4.
*/ */
lsquic_conn_t * lsquic_conn_t *
@ -1086,7 +1088,7 @@ lsquic_engine_connect (lsquic_engine_t *, enum lsquic_version,
const struct sockaddr *local_sa, const struct sockaddr *local_sa,
const struct sockaddr *peer_sa, const struct sockaddr *peer_sa,
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx, void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
const char *hostname, unsigned short max_packet_size, const char *hostname, unsigned short max_udp_payload_size,
const unsigned char *zero_rtt, size_t zero_rtt_len, const unsigned char *zero_rtt, size_t zero_rtt_len,
/** Resumption token: optional */ /** Resumption token: optional */
const unsigned char *token, size_t token_sz); const unsigned char *token, size_t token_sz);
@ -1174,12 +1176,7 @@ lsquic_conn_cancel_pending_streams (lsquic_conn_t *, unsigned n);
* Mark connection as going away: send GOAWAY frame and do not accept * Mark connection as going away: send GOAWAY frame and do not accept
* any more incoming streams, nor generate streams of our own. * any more incoming streams, nor generate streams of our own.
* *
* In the server mode, of course, we can call this function just fine in both * Only applicable to HTTP/3 and GQUIC connections. Otherwise a no-op.
* Google and IETF QUIC.
*
* In client mode, calling this function in for an IETF QUIC connection does
* not do anything, as the client MUST NOT send GOAWAY frames.
* See [draft-ietf-quic-http-17] Section 4.2.7.
*/ */
void void
lsquic_conn_going_away (lsquic_conn_t *); lsquic_conn_going_away (lsquic_conn_t *);

View file

@ -1,6 +1,6 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ /* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#ifndef LSXPACK_HEADER_H_v205 #ifndef LSXPACK_HEADER_H_v206
#define LSXPACK_HEADER_H_v205 #define LSXPACK_HEADER_H_v206
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -26,7 +26,7 @@ typedef uint32_t lsxpack_strlen_t;
enum lsxpack_flag enum lsxpack_flag
{ {
LSXPACK_HPACK_IDX = 1, LSXPACK_HPACK_VAL_MATCHED = 1,
LSXPACK_QPACK_IDX = 2, LSXPACK_QPACK_IDX = 2,
LSXPACK_APP_IDX = 4, LSXPACK_APP_IDX = 4,
LSXPACK_NAME_HASH = 8, LSXPACK_NAME_HASH = 8,
@ -47,7 +47,6 @@ enum lsxpack_flag
struct lsxpack_header struct lsxpack_header
{ {
char *buf; /* the buffer for headers */ char *buf; /* the buffer for headers */
const char *name_ptr; /* the name pointer can be optionally set for encoding */
uint32_t name_hash; /* hash value for name */ uint32_t name_hash; /* hash value for name */
uint32_t nameval_hash; /* hash value for name + value */ uint32_t nameval_hash; /* hash value for name + value */
lsxpack_strlen_t name_offset; /* the offset for name in the buffer */ lsxpack_strlen_t name_offset; /* the offset for name in the buffer */
@ -74,7 +73,6 @@ lsxpack_header_set_idx(lsxpack_header_t *hdr, int hpack_idx,
hdr->buf = (char *)val; hdr->buf = (char *)val;
hdr->hpack_index = hpack_idx; hdr->hpack_index = hpack_idx;
assert(hpack_idx != 0); assert(hpack_idx != 0);
hdr->flags = LSXPACK_HPACK_IDX;
assert(val_len <= LSXPACK_MAX_STRLEN); assert(val_len <= LSXPACK_MAX_STRLEN);
hdr->val_len = val_len; hdr->val_len = val_len;
} }
@ -94,21 +92,6 @@ lsxpack_header_set_qpack_idx(lsxpack_header_t *hdr, int qpack_idx,
} }
static inline void
lsxpack_header_set_ptr(lsxpack_header_t *hdr,
const char *name, size_t name_len,
const char *val, size_t val_len)
{
memset(hdr, 0, sizeof(*hdr));
hdr->buf = (char *)val;
assert(val_len <= LSXPACK_MAX_STRLEN);
hdr->val_len = val_len;
hdr->name_ptr = name;
assert(name_len <= LSXPACK_MAX_STRLEN);
hdr->name_len = name_len;
}
static inline void static inline void
lsxpack_header_set_offset(lsxpack_header_t *hdr, const char *buf, lsxpack_header_set_offset(lsxpack_header_t *hdr, const char *buf,
size_t name_offset, size_t name_len, size_t name_offset, size_t name_len,
@ -161,9 +144,7 @@ lsxpack_header_prepare_decode(lsxpack_header_t *hdr,
static inline const char * static inline const char *
lsxpack_header_get_name(const lsxpack_header_t *hdr) lsxpack_header_get_name(const lsxpack_header_t *hdr)
{ {
return hdr->name_ptr ? hdr->name_ptr return (hdr->name_len)? hdr->buf + hdr->name_offset : NULL;
: (hdr->name_len) ? hdr->buf + hdr->name_offset
: NULL;
} }
@ -179,10 +160,10 @@ static inline void
lsxpack_header_mark_val_changed(lsxpack_header_t *hdr) lsxpack_header_mark_val_changed(lsxpack_header_t *hdr)
{ {
hdr->flags = (enum lsxpack_flag)(hdr->flags & hdr->flags = (enum lsxpack_flag)(hdr->flags &
~(LSXPACK_VAL_MATCHED|LSXPACK_NAMEVAL_HASH)); ~(LSXPACK_HPACK_VAL_MATCHED|LSXPACK_VAL_MATCHED|LSXPACK_NAMEVAL_HASH));
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif //LSXPACK_HEADER_H_v205 #endif //LSXPACK_HEADER_H_v206

View file

@ -79,7 +79,9 @@ SET(lsquic_STAT_SRCS
lsquic_version.c lsquic_version.c
) )
IF(NOT MSVC)
set_source_files_properties(ls-qpack/lsqpack.c PROPERTIES COMPILE_FLAGS -Wno-uninitialized) set_source_files_properties(ls-qpack/lsqpack.c PROPERTIES COMPILE_FLAGS -Wno-uninitialized)
ENDIF()
include_directories(ls-qpack) include_directories(ls-qpack)
@ -95,8 +97,8 @@ ENDIF()
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/lsquic_versions_to_string.c OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/lsquic_versions_to_string.c
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen-verstrs.pl COMMAND ${PERL}
ARGS ${CMAKE_CURRENT_SOURCE_DIR}/../../include/lsquic.h ${CMAKE_CURRENT_SOURCE_DIR}/lsquic_versions_to_string.c ARGS ${CMAKE_CURRENT_SOURCE_DIR}/gen-verstrs.pl ${CMAKE_CURRENT_SOURCE_DIR}/../../include/lsquic.h ${CMAKE_CURRENT_SOURCE_DIR}/lsquic_versions_to_string.c
DEPENDS ./gen-verstrs.pl ${CMAKE_CURRENT_SOURCE_DIR}/../../include/lsquic.h DEPENDS ./gen-verstrs.pl ${CMAKE_CURRENT_SOURCE_DIR}/../../include/lsquic.h
) )
SET(lsquic_STAT_SRCS ${lsquic_STAT_SRCS} lsquic_versions_to_string.c) SET(lsquic_STAT_SRCS ${lsquic_STAT_SRCS} lsquic_versions_to_string.c)

@ -1 +1 @@
Subproject commit f41613843f6164bb83993e435e8a164c1bb157e2 Subproject commit a8ae6ef90197df0620ffd51891fb16016b1bb807

View file

@ -33,6 +33,8 @@ enum alarm_id {
AL_PATH_CHAL, AL_PATH_CHAL,
AL_PATH_CHAL_0 = AL_PATH_CHAL, AL_PATH_CHAL_0 = AL_PATH_CHAL,
AL_PATH_CHAL_1, AL_PATH_CHAL_1,
AL_PATH_CHAL_2,
AL_PATH_CHAL_3,
AL_SESS_TICKET, AL_SESS_TICKET,
AL_BLOCKED_KA, /* Blocked Keep-Alive */ AL_BLOCKED_KA, /* Blocked Keep-Alive */
MAX_LSQUIC_ALARMS MAX_LSQUIC_ALARMS
@ -51,6 +53,8 @@ enum alarm_id_bit {
ALBIT_CID_THROT = 1 << AL_CID_THROT, ALBIT_CID_THROT = 1 << AL_CID_THROT,
ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0, ALBIT_PATH_CHAL_0 = 1 << AL_PATH_CHAL_0,
ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1, ALBIT_PATH_CHAL_1 = 1 << AL_PATH_CHAL_1,
ALBIT_PATH_CHAL_2 = 1 << AL_PATH_CHAL_2,
ALBIT_PATH_CHAL_3 = 1 << AL_PATH_CHAL_3,
ALBIT_SESS_TICKET = 1 << AL_SESS_TICKET, ALBIT_SESS_TICKET = 1 << AL_SESS_TICKET,
ALBIT_BLOCKED_KA = 1 << AL_BLOCKED_KA, ALBIT_BLOCKED_KA = 1 << AL_BLOCKED_KA,
}; };

View file

@ -180,7 +180,7 @@ init_bbr (struct lsquic_bbr *bbr)
bbr->bbr_min_cwnd = kDefaultMinimumCongestionWindow; bbr->bbr_min_cwnd = kDefaultMinimumCongestionWindow;
bbr->bbr_high_gain = kDefaultHighGain; bbr->bbr_high_gain = kDefaultHighGain;
bbr->bbr_high_cwnd_gain = kDefaultHighGain; bbr->bbr_high_cwnd_gain = kDefaultHighGain;
bbr->bbr_drain_gain = 1.0 / kDefaultHighGain; bbr->bbr_drain_gain = 1.0f / kDefaultHighGain;
bbr->bbr_pacing_rate = BW_ZERO(); bbr->bbr_pacing_rate = BW_ZERO();
bbr->bbr_pacing_gain = 1.0; bbr->bbr_pacing_gain = 1.0;
bbr->bbr_cwnd_gain = 1.0; bbr->bbr_cwnd_gain = 1.0;
@ -298,7 +298,7 @@ is_pipe_sufficiently_full (struct lsquic_bbr *bbr, uint64_t bytes_in_flight)
else else
// If bytes_in_flight are above the target congestion window, it should // If bytes_in_flight are above the target congestion window, it should
// be possible to observe the same or more bandwidth if it's available. // be possible to observe the same or more bandwidth if it's available.
return bytes_in_flight >= get_target_cwnd(bbr, 1.1); return bytes_in_flight >= get_target_cwnd(bbr, 1.1f);
} }

View file

@ -79,11 +79,11 @@ bw_sampler_abort_conn (struct bw_sampler *sampler)
} }
#define BW_WARN_ONCE(msg...) do { \ #define BW_WARN_ONCE(...) do { \
if (!(sampler->bws_flags & BWS_WARNED)) \ if (!(sampler->bws_flags & BWS_WARNED)) \
{ \ { \
sampler->bws_flags |= BWS_WARNED; \ sampler->bws_flags |= BWS_WARNED; \
LSQ_WARN(msg); \ LSQ_WARN(__VA_ARGS__); \
} \ } \
} while (0) } while (0)

View file

@ -243,6 +243,10 @@ struct conn_iface
/* Optional method. Only used by the IETF client code. */ /* Optional method. Only used by the IETF client code. */
void void
(*ci_drop_crypto_streams) (struct lsquic_conn *); (*ci_drop_crypto_streams) (struct lsquic_conn *);
/* Optional method. Only used by IETF connections */
void
(*ci_count_garbage) (struct lsquic_conn *, size_t);
}; };
#define LSCONN_CCE_BITS 3 #define LSCONN_CCE_BITS 3

View file

@ -276,6 +276,9 @@ struct enc_session_funcs_iquic
(*esfi_reset_dcid) (enc_session_t *, const struct lsquic_cid *, (*esfi_reset_dcid) (enc_session_t *, const struct lsquic_cid *,
const struct lsquic_cid *); const struct lsquic_cid *);
void
(*esfi_set_iscid) (enc_session_t *, const struct lsquic_packet_in *);
int int
(*esfi_init_server) (enc_session_t *); (*esfi_init_server) (enc_session_t *);
@ -288,7 +291,8 @@ struct enc_session_funcs_iquic
const struct lsquic_cid *, const struct lsquic_cid *,
void *(crypto_streams)[4], void *(crypto_streams)[4],
const struct crypto_stream_if *, const struct crypto_stream_if *,
const struct lsquic_cid *odcid); const struct lsquic_cid *odcid,
const struct lsquic_cid *iscid );
void void
(*esfi_shake_stream)(enc_session_t *, struct lsquic_stream *, (*esfi_shake_stream)(enc_session_t *, struct lsquic_stream *,
@ -328,8 +332,8 @@ struct enc_session_funcs_gquic lsquic_enc_session_gquic_gquic_1;
extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1; extern const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1;
#define select_esf_common_by_ver(ver) ( \ #define select_esf_common_by_ver(ver) ( \
ver == LSQVER_ID25 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \ ver == LSQVER_ID27 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_ID28 ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \ ver == LSQVER_VERNEG ? &lsquic_enc_session_common_ietf_v1 : \
ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \ ver == LSQVER_050 ? &lsquic_enc_session_common_gquic_2 : \
&lsquic_enc_session_common_gquic_1 ) &lsquic_enc_session_common_gquic_1 )

View file

@ -71,9 +71,9 @@ static const struct alpn_map {
enum lsquic_version version; enum lsquic_version version;
const unsigned char *alpn; const unsigned char *alpn;
} s_h3_alpns[] = { } s_h3_alpns[] = {
{ LSQVER_ID25, (unsigned char *) "\x05h3-25", },
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", }, { LSQVER_ID27, (unsigned char *) "\x05h3-27", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-27", }, { LSQVER_ID28, (unsigned char *) "\x05h3-28", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-28", },
}; };
struct enc_sess_iquic; struct enc_sess_iquic;
@ -221,6 +221,8 @@ struct enc_sess_iquic
struct header_prot *esi_hsk_hps; struct header_prot *esi_hsk_hps;
lsquic_packno_t esi_max_packno[N_PNS]; lsquic_packno_t esi_max_packno[N_PNS];
lsquic_cid_t esi_odcid; lsquic_cid_t esi_odcid;
lsquic_cid_t esi_rscid; /* Retry SCID */
lsquic_cid_t esi_iscid; /* Initial SCID */
unsigned esi_key_phase; unsigned esi_key_phase;
enum { enum {
ESI_INITIALIZED = 1 << 0, ESI_INITIALIZED = 1 << 0,
@ -237,6 +239,9 @@ struct enc_sess_iquic
ESI_WANT_TICKET = 1 << 11, ESI_WANT_TICKET = 1 << 11,
ESI_RECV_QL_BITS = 1 << 12, ESI_RECV_QL_BITS = 1 << 12,
ESI_SEND_QL_BITS = 1 << 13, ESI_SEND_QL_BITS = 1 << 13,
ESI_RSCID = 1 << 14,
ESI_ISCID = 1 << 15,
ESI_RETRY = 1 << 16, /* Connection was retried */
} esi_flags; } esi_flags;
enum evp_aead_direction_t enum evp_aead_direction_t
esi_dir[2]; /* client, server */ esi_dir[2]; /* client, server */
@ -429,9 +434,15 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
const struct lsquic_engine_settings *const settings = const struct lsquic_engine_settings *const settings =
&enc_sess->esi_enpub->enp_settings; &enc_sess->esi_enpub->enp_settings;
struct transport_params params; struct transport_params params;
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
int len; int len;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
if (version > LSQVER_ID27)
{
params.tp_initial_source_cid = *CN_SCID(enc_sess->esi_conn);
params.tp_set |= 1 << TPI_INITIAL_SOURCE_CID;
}
if (enc_sess->esi_flags & ESI_SERVER) if (enc_sess->esi_flags & ESI_SERVER)
{ {
const struct lsquic_conn *const lconn = enc_sess->esi_conn; const struct lsquic_conn *const lconn = enc_sess->esi_conn;
@ -442,8 +453,8 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
if (enc_sess->esi_flags & ESI_ODCID) if (enc_sess->esi_flags & ESI_ODCID)
{ {
params.tp_original_cid = enc_sess->esi_odcid; params.tp_original_dest_cid = enc_sess->esi_odcid;
params.tp_set |= 1 << TPI_ORIGINAL_CONNECTION_ID; params.tp_set |= 1 << TPI_ORIGINAL_DEST_CID;
} }
#if LSQUIC_PREFERRED_ADDR #if LSQUIC_PREFERRED_ADDR
char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1]; char addr_buf[INET6_ADDRSTRLEN + 6 /* port */ + 1];
@ -544,10 +555,10 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
| (1 << TPI_MAX_ACK_DELAY) | (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT) | (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT)
; ;
if (settings->es_max_packet_size_rx) if (settings->es_max_udp_payload_size_rx)
{ {
params.tp_max_packet_size = settings->es_max_packet_size_rx; params.tp_max_udp_payload_size = settings->es_max_udp_payload_size_rx;
params.tp_set |= 1 << TPI_MAX_PACKET_SIZE; params.tp_set |= 1 << TPI_MAX_UDP_PAYLOAD_SIZE;
} }
if (!settings->es_allow_migration) if (!settings->es_allow_migration)
params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION; params.tp_set |= 1 << TPI_DISABLE_ACTIVE_MIGRATION;
@ -564,10 +575,15 @@ gen_trans_params (struct enc_sess_iquic *enc_sess, unsigned char *buf,
if (settings->es_timestamps) if (settings->es_timestamps)
params.tp_set |= 1 << TPI_TIMESTAMPS; params.tp_set |= 1 << TPI_TIMESTAMPS;
len = (enc_sess->esi_conn->cn_version == LSQVER_ID25 ? lsquic_tp_encode_id25 : len = (version == LSQVER_ID27 ? lsquic_tp_encode_27 : lsquic_tp_encode)(
lsquic_tp_encode)(&params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz); &params, enc_sess->esi_flags & ESI_SERVER, buf, bufsz);
if (len >= 0) if (len >= 0)
{
char str[MAX_TP_STR_SZ];
LSQ_DEBUG("generated transport parameters buffer of %d bytes", len); LSQ_DEBUG("generated transport parameters buffer of %d bytes", len);
LSQ_DEBUG("%s", ((version == LSQVER_ID27 ? lsquic_tp_to_str_27
: lsquic_tp_to_str)(&params, str, sizeof(str)), str));
}
else else
LSQ_WARN("cannot generate transport parameters: %d", errno); LSQ_WARN("cannot generate transport parameters: %d", errno);
return len; return len;
@ -726,6 +742,9 @@ iquic_esfi_create_client (const char *hostname,
enc_sess->esi_dir[0] = evp_aead_seal; enc_sess->esi_dir[0] = evp_aead_seal;
enc_sess->esi_dir[1] = evp_aead_open; enc_sess->esi_dir[1] = evp_aead_open;
enc_sess->esi_odcid = *dcid;
enc_sess->esi_flags |= ESI_ODCID;
LSQ_DEBUGC("created client, DCID: %"CID_FMT, CID_BITS(dcid)); LSQ_DEBUGC("created client, DCID: %"CID_FMT, CID_BITS(dcid));
{ {
const char *log; const char *log;
@ -793,7 +812,8 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
struct lsquic_conn *lconn, const lsquic_cid_t *first_dcid, struct lsquic_conn *lconn, const lsquic_cid_t *first_dcid,
void *(crypto_streams)[4], void *(crypto_streams)[4],
const struct crypto_stream_if *cryst_if, const struct crypto_stream_if *cryst_if,
const struct lsquic_cid *odcid) const struct lsquic_cid *odcid,
const struct lsquic_cid *iscid )
{ {
struct enc_sess_iquic *enc_sess; struct enc_sess_iquic *enc_sess;
@ -819,6 +839,8 @@ iquic_esfi_create_server (struct lsquic_engine_public *enpub,
enc_sess->esi_odcid = *odcid; enc_sess->esi_odcid = *odcid;
enc_sess->esi_flags |= ESI_ODCID; enc_sess->esi_flags |= ESI_ODCID;
} }
enc_sess->esi_iscid = *iscid;
enc_sess->esi_flags |= ESI_ISCID;
init_frals(enc_sess); init_frals(enc_sess);
@ -1470,6 +1492,7 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
const uint8_t *params_buf; const uint8_t *params_buf;
size_t bufsz; size_t bufsz;
char *params_str; char *params_str;
const enum lsquic_version version = enc_sess->esi_conn->cn_version;
SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, &params_buf, &bufsz); SSL_get_peer_quic_transport_params(enc_sess->esi_ssl, &params_buf, &bufsz);
if (!params_buf) if (!params_buf)
@ -1479,8 +1502,8 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
} }
LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz); LSQ_DEBUG("have peer transport parameters (%zu bytes)", bufsz);
if (0 > (enc_sess->esi_conn->cn_version == LSQVER_ID25 if (0 > (version == LSQVER_ID27 ? lsquic_tp_decode_27
? lsquic_tp_decode_id25 : lsquic_tp_decode)(params_buf, bufsz, : lsquic_tp_decode)(params_buf, bufsz,
!(enc_sess->esi_flags & ESI_SERVER), !(enc_sess->esi_flags & ESI_SERVER),
trans_params)) trans_params))
{ {
@ -1501,30 +1524,72 @@ get_peer_transport_params (struct enc_sess_iquic *enc_sess)
return -1; return -1;
} }
if ((enc_sess->esi_flags & (ESI_ODCID|ESI_SERVER)) == ESI_ODCID) const lsquic_cid_t *const cids[LAST_TPI + 1] = {
[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)] = enc_sess->esi_flags & ESI_ODCID ? &enc_sess->esi_odcid : NULL,
[TP_CID_IDX(TPI_RETRY_SOURCE_CID)] = enc_sess->esi_flags & ESI_RSCID ? &enc_sess->esi_rscid : NULL,
[TP_CID_IDX(TPI_INITIAL_SOURCE_CID)] = enc_sess->esi_flags & ESI_ISCID ? &enc_sess->esi_iscid : NULL,
};
unsigned must_have, must_not_have = 0;
if (version > LSQVER_ID27)
{ {
if (!(trans_params->tp_set & (1 << TPI_ORIGINAL_CONNECTION_ID))) must_have = 1 << TPI_INITIAL_SOURCE_CID;
if (enc_sess->esi_flags & ESI_SERVER)
must_not_have |= 1 << TPI_ORIGINAL_DEST_CID;
else
must_have |= 1 << TPI_ORIGINAL_DEST_CID;
if ((enc_sess->esi_flags & (ESI_RETRY|ESI_SERVER)) == ESI_RETRY)
must_have |= 1 << TPI_RETRY_SOURCE_CID;
else
must_not_have |= 1 << TPI_RETRY_SOURCE_CID;
}
else if ((enc_sess->esi_flags & (ESI_RETRY|ESI_SERVER)) == ESI_RETRY)
must_have = 1 << TPI_ORIGINAL_DEST_CID;
else
must_have = 0;
enum transport_param_id tpi;
for (tpi = FIRST_TP_CID; tpi <= LAST_TP_CID; ++tpi)
{
if (!(must_have & (1 << tpi)))
continue;
if (!(trans_params->tp_set & (1 << tpi)))
{ {
LSQ_DEBUG("server did not produce original DCID (ODCID)"); LSQ_DEBUG("server did not produce %s", lsquic_tpi2str[tpi]);
return -1; return -1;
} }
if (LSQUIC_CIDS_EQ(&enc_sess->esi_odcid, if (!cids[TP_CID_IDX(tpi)])
&trans_params->tp_original_cid)) {
LSQ_DEBUG("ODCID values match"); LSQ_WARN("do not have CID %s for checking",
lsquic_tpi2str[tpi]);
return -1;
}
if (LSQUIC_CIDS_EQ(cids[TP_CID_IDX(tpi)],
&trans_params->tp_cids[TP_CID_IDX(tpi)]))
LSQ_DEBUG("%s values match", lsquic_tpi2str[tpi]);
else else
{ {
if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG)) if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG))
{ {
char cidbuf[2][MAX_CID_LEN * 2 + 1]; char cidbuf[2][MAX_CID_LEN * 2 + 1];
lsquic_cid2str(&enc_sess->esi_odcid, cidbuf[0]); LSQ_DEBUG("server provided %s %"CID_FMT" that does not "
lsquic_cid2str(&trans_params->tp_original_cid, cidbuf[1]); "match ours %"CID_FMT, lsquic_tpi2str[tpi],
LSQ_DEBUG("server provided ODCID %s that does not match " CID_BITS_B(&trans_params->tp_cids[TP_CID_IDX(tpi)],
"our ODCID %s", cidbuf[1], cidbuf[0]); cidbuf[0]),
CID_BITS_B(cids[TP_CID_IDX(tpi)], cidbuf[1]));
} }
return -1; return -1;
} }
} }
for (tpi = FIRST_TP_CID; tpi <= LAST_TP_CID; ++tpi)
if (must_not_have & (1 << tpi) & trans_params->tp_set)
{
LSQ_DEBUG("server transport parameters unexpectedly contain %s",
lsquic_tpi2str[tpi]);
return -1;
}
if ((trans_params->tp_set & (1 << TPI_LOSS_BITS)) if ((trans_params->tp_set & (1 << TPI_LOSS_BITS))
&& enc_sess->esi_enpub->enp_settings.es_ql_bits) && enc_sess->esi_enpub->enp_settings.es_ql_bits)
{ {
@ -2239,6 +2304,21 @@ iquic_esf_zero_rtt_enabled (enc_session_t *enc_session_p)
} }
static void
iquic_esfi_set_iscid (enc_session_t *enc_session_p,
const struct lsquic_packet_in *packet_in)
{
struct enc_sess_iquic *const enc_sess = enc_session_p;
if (!(enc_sess->esi_flags & ESI_ISCID))
{
lsquic_scid_from_packet_in(packet_in, &enc_sess->esi_iscid);
enc_sess->esi_flags |= ESI_ISCID;
LSQ_DEBUGC("set ISCID to %"CID_FMT, CID_BITS(&enc_sess->esi_iscid));
}
}
static int static int
iquic_esfi_reset_dcid (enc_session_t *enc_session_p, iquic_esfi_reset_dcid (enc_session_t *enc_session_p,
const lsquic_cid_t *old_dcid, const lsquic_cid_t *new_dcid) const lsquic_cid_t *old_dcid, const lsquic_cid_t *new_dcid)
@ -2247,7 +2327,8 @@ iquic_esfi_reset_dcid (enc_session_t *enc_session_p,
struct crypto_ctx_pair *pair; struct crypto_ctx_pair *pair;
enc_sess->esi_odcid = *old_dcid; enc_sess->esi_odcid = *old_dcid;
enc_sess->esi_flags |= ESI_ODCID; enc_sess->esi_rscid = *new_dcid;
enc_sess->esi_flags |= ESI_ODCID|ESI_RSCID|ESI_RETRY;
/* Free previous handshake keys */ /* Free previous handshake keys */
assert(enc_sess->esi_hsk_pairs); assert(enc_sess->esi_hsk_pairs);
@ -2340,6 +2421,7 @@ const struct enc_session_funcs_iquic lsquic_enc_session_iquic_ietf_v1 =
= iquic_esfi_get_peer_transport_params, = iquic_esfi_get_peer_transport_params,
.esfi_reset_dcid = iquic_esfi_reset_dcid, .esfi_reset_dcid = iquic_esfi_reset_dcid,
.esfi_init_server = iquic_esfi_init_server, .esfi_init_server = iquic_esfi_init_server,
.esfi_set_iscid = iquic_esfi_set_iscid,
.esfi_set_streams = iquic_esfi_set_streams, .esfi_set_streams = iquic_esfi_set_streams,
.esfi_create_server = iquic_esfi_create_server, .esfi_create_server = iquic_esfi_create_server,
.esfi_shake_stream = iquic_esfi_shake_stream, .esfi_shake_stream = iquic_esfi_shake_stream,

View file

@ -25,6 +25,15 @@
#ifndef NDEBUG #ifndef NDEBUG
#include <sys/types.h> #include <sys/types.h>
#endif
#if defined(WIN32) || defined(NDEBUG)
#define CAN_LOSE_PACKETS 0
#else
#define CAN_LOSE_PACKETS 1
#endif
#if CAN_LOSE_PACKETS
#include <regex.h> /* For code that loses packets */ #include <regex.h> /* For code that loses packets */
#endif #endif
@ -208,7 +217,11 @@ struct lsquic_engine
= (1 << 9), /* Connections are hashed by address */ = (1 << 9), /* Connections are hashed by address */
#ifndef NDEBUG #ifndef NDEBUG
ENG_COALESCE = (1 << 24), /* Packet coalescing is enabled */ ENG_COALESCE = (1 << 24), /* Packet coalescing is enabled */
#endif
#if CAN_LOSE_PACKETS
ENG_LOSE_PACKETS= (1 << 25), /* Lose *some* outgoing packets */ ENG_LOSE_PACKETS= (1 << 25), /* Lose *some* outgoing packets */
#endif
#ifndef NDEBUG
ENG_DTOR = (1 << 26), /* Engine destructor */ ENG_DTOR = (1 << 26), /* Engine destructor */
#endif #endif
} flags; } flags;
@ -223,13 +236,14 @@ struct lsquic_engine
struct min_heap conns_out; struct min_heap conns_out;
struct eng_hist history; struct eng_hist history;
unsigned batch_size; unsigned batch_size;
struct lsquic_conn *curr_conn;
struct pr_queue *pr_queue; struct pr_queue *pr_queue;
struct attq *attq; struct attq *attq;
/* Track time last time a packet was sent to give new connections /* Track time last time a packet was sent to give new connections
* priority lower than that of existing connections. * priority lower than that of existing connections.
*/ */
lsquic_time_t last_sent; lsquic_time_t last_sent;
#ifndef NDEBUG #if CAN_LOSE_PACKETS
regex_t lose_packets_re; regex_t lose_packets_re;
const char *lose_packets_str; const char *lose_packets_str;
#endif #endif
@ -638,6 +652,7 @@ lsquic_engine_new (unsigned flags,
{ {
const char *env; const char *env;
env = getenv("LSQUIC_LOSE_PACKETS_RE"); env = getenv("LSQUIC_LOSE_PACKETS_RE");
#if CAN_LOSE_PACKETS
if (env) if (env)
{ {
if (0 != regcomp(&engine->lose_packets_re, env, if (0 != regcomp(&engine->lose_packets_re, env,
@ -651,6 +666,7 @@ lsquic_engine_new (unsigned flags,
LSQ_WARN("will lose packets that match the following regex: %s", LSQ_WARN("will lose packets that match the following regex: %s",
env); env);
} }
#endif
env = getenv("LSQUIC_COALESCE"); env = getenv("LSQUIC_COALESCE");
if (env) if (env)
{ {
@ -1320,8 +1336,12 @@ process_packet_in (lsquic_engine_t *engine, lsquic_packet_in_t *packet_in,
} }
if (engine->flags & ENG_SERVER) if (engine->flags & ENG_SERVER)
{
conn = find_or_create_conn(engine, packet_in, ppstate, sa_local, conn = find_or_create_conn(engine, packet_in, ppstate, sa_local,
sa_peer, peer_ctx, packet_in_size); sa_peer, peer_ctx, packet_in_size);
if (!engine->curr_conn)
engine->curr_conn = conn;
}
else else
conn = find_conn(engine, packet_in, ppstate, sa_local); conn = find_conn(engine, packet_in, ppstate, sa_local);
@ -1434,7 +1454,7 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
lsquic_stock_shared_hash_destroy(engine->pub.enp_shi_ctx); lsquic_stock_shared_hash_destroy(engine->pub.enp_shi_ctx);
lsquic_mm_cleanup(&engine->pub.enp_mm); lsquic_mm_cleanup(&engine->pub.enp_mm);
free(engine->conns_tickable.mh_elems); free(engine->conns_tickable.mh_elems);
#ifndef NDEBUG #if CAN_LOSE_PACKETS
if (engine->flags & ENG_LOSE_PACKETS) if (engine->flags & ENG_LOSE_PACKETS)
regfree(&engine->lose_packets_re); regfree(&engine->lose_packets_re);
#endif #endif
@ -2032,7 +2052,7 @@ coi_reheap (struct conns_out_iter *iter, lsquic_engine_t *engine)
} }
#ifndef NDEBUG #if CAN_LOSE_PACKETS
static void static void
lose_matching_packets (const lsquic_engine_t *engine, struct out_batch *batch, lose_matching_packets (const lsquic_engine_t *engine, struct out_batch *batch,
unsigned n) unsigned n)
@ -2131,7 +2151,7 @@ send_batch (lsquic_engine_t *engine, const struct send_batch_ctx *sb_ctx,
CONST_BATCH struct out_batch *const batch = sb_ctx->batch; CONST_BATCH struct out_batch *const batch = sb_ctx->batch;
struct lsquic_packet_out *CONST_BATCH *packet_out, *CONST_BATCH *end; struct lsquic_packet_out *CONST_BATCH *packet_out, *CONST_BATCH *end;
#ifndef NDEBUG #if CAN_LOSE_PACKETS
if (engine->flags & ENG_LOSE_PACKETS) if (engine->flags & ENG_LOSE_PACKETS)
lose_matching_packets(engine, batch, n_to_send); lose_matching_packets(engine, batch, n_to_send);
#endif #endif
@ -2641,6 +2661,20 @@ process_connections (lsquic_engine_t *engine, conn_iter_f next_conn,
} }
static void
maybe_count_garbage (struct lsquic_engine *engine, size_t garbage_sz)
{
/* This is not very pretty (action at a distance via engine->curr_conn),
* but it's the cheapest I can come up with to handle the "count garbage
* toward amplification limit" requirement in
* [draft-ietf-quic-transport-28] Section 8.1.
*/
if (engine->curr_conn && engine->curr_conn->cn_if->ci_count_garbage)
engine->curr_conn->cn_if->ci_count_garbage(engine->curr_conn,
garbage_sz);
}
/* Return 0 if packet is being processed by a real connection, 1 if the /* Return 0 if packet is being processed by a real connection, 1 if the
* packet was processed, but not by a connection, and -1 on error. * packet was processed, but not by a connection, and -1 on error.
*/ */
@ -2680,20 +2714,25 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
parse_packet_in_begin = lsquic_Q050_parse_packet_in_begin; parse_packet_in_begin = lsquic_Q050_parse_packet_in_begin;
else else
{ {
assert(conn->cn_version == LSQVER_046
#if LSQUIC_USE_Q098 #if LSQUIC_USE_Q098
|| conn->cn_version == LSQVER_098 assert(conn->cn_version == LSQVER_046 || conn->cn_version == LSQVER_098);
#else
assert(conn->cn_version == LSQVER_046);
#endif #endif
);
parse_packet_in_begin = lsquic_Q046_parse_packet_in_begin; parse_packet_in_begin = lsquic_Q046_parse_packet_in_begin;
} }
} }
else else
parse_packet_in_begin = lsquic_parse_packet_in_begin; parse_packet_in_begin = lsquic_parse_packet_in_begin;
engine->curr_conn = NULL;
n_zeroes = 0; n_zeroes = 0;
is_ietf = 0; is_ietf = 0;
#ifdef _MSC_VER
s = 0;
cid.len = 0;
cid.idbuf[0] = 0;
#endif
do do
{ {
packet_in = lsquic_mm_get_packet_in(&engine->pub.enp_mm); packet_in = lsquic_mm_get_packet_in(&engine->pub.enp_mm);
@ -2709,6 +2748,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
engine->pub.enp_settings.es_scid_len, &ppstate)) engine->pub.enp_settings.es_scid_len, &ppstate))
{ {
LSQ_DEBUG("Cannot parse incoming packet's header"); LSQ_DEBUG("Cannot parse incoming packet's header");
maybe_count_garbage(engine, packet_end - packet_in_data);
lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in); lsquic_mm_put_packet_in(&engine->pub.enp_mm, packet_in);
s = 1; s = 1;
break; break;
@ -2724,6 +2764,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine,
&& LSQUIC_CIDS_EQ(&packet_in->pi_dcid, &cid))) && LSQUIC_CIDS_EQ(&packet_in->pi_dcid, &cid)))
{ {
packet_in_data += packet_in->pi_data_sz; packet_in_data += packet_in->pi_data_sz;
maybe_count_garbage(engine, packet_in->pi_data_sz);
continue; continue;
} }
} }

View file

@ -528,15 +528,10 @@ lsquic_frame_writer_write_promise (struct lsquic_frame_writer *fw,
free(buf); free(buf);
if (0 == s) EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id,
{ htonl(promised_stream_id), headers);
EV_LOG_GENERATED_HTTP_PUSH_PROMISE(LSQUIC_LOG_CONN_ID, stream_id, hfc_terminate_frame(&hfc, HFHF_END_HEADERS);
htonl(promised_stream_id), headers); return lsquic_frame_writer_flush(fw);
hfc_terminate_frame(&hfc, HFHF_END_HEADERS);
return lsquic_frame_writer_flush(fw);
}
else
return -1;
} }

View file

@ -144,7 +144,7 @@ enum more_flags
}; };
#define N_PATHS 2 #define N_PATHS 4
enum send enum send
{ {
@ -154,9 +154,13 @@ enum send
SEND_PATH_CHAL, SEND_PATH_CHAL,
SEND_PATH_CHAL_PATH_0 = SEND_PATH_CHAL + 0, SEND_PATH_CHAL_PATH_0 = SEND_PATH_CHAL + 0,
SEND_PATH_CHAL_PATH_1 = SEND_PATH_CHAL + 1, SEND_PATH_CHAL_PATH_1 = SEND_PATH_CHAL + 1,
SEND_PATH_CHAL_PATH_2 = SEND_PATH_CHAL + 2,
SEND_PATH_CHAL_PATH_3 = SEND_PATH_CHAL + 3,
SEND_PATH_RESP, SEND_PATH_RESP,
SEND_PATH_RESP_PATH_0 = SEND_PATH_RESP + 0, SEND_PATH_RESP_PATH_0 = SEND_PATH_RESP + 0,
SEND_PATH_RESP_PATH_1 = SEND_PATH_RESP + 1, SEND_PATH_RESP_PATH_1 = SEND_PATH_RESP + 1,
SEND_PATH_RESP_PATH_2 = SEND_PATH_RESP + 2,
SEND_PATH_RESP_PATH_3 = SEND_PATH_RESP + 3,
SEND_MAX_DATA, SEND_MAX_DATA,
SEND_PING, SEND_PING,
SEND_NEW_CID, SEND_NEW_CID,
@ -181,9 +185,13 @@ enum send_flags
SF_SEND_PATH_CHAL = 1 << SEND_PATH_CHAL, SF_SEND_PATH_CHAL = 1 << SEND_PATH_CHAL,
SF_SEND_PATH_CHAL_PATH_0 = 1 << SEND_PATH_CHAL_PATH_0, SF_SEND_PATH_CHAL_PATH_0 = 1 << SEND_PATH_CHAL_PATH_0,
SF_SEND_PATH_CHAL_PATH_1 = 1 << SEND_PATH_CHAL_PATH_1, SF_SEND_PATH_CHAL_PATH_1 = 1 << SEND_PATH_CHAL_PATH_1,
SF_SEND_PATH_CHAL_PATH_2 = 1 << SEND_PATH_CHAL_PATH_2,
SF_SEND_PATH_CHAL_PATH_3 = 1 << SEND_PATH_CHAL_PATH_3,
SF_SEND_PATH_RESP = 1 << SEND_PATH_RESP, SF_SEND_PATH_RESP = 1 << SEND_PATH_RESP,
SF_SEND_PATH_RESP_PATH_0 = 1 << SEND_PATH_RESP_PATH_0, SF_SEND_PATH_RESP_PATH_0 = 1 << SEND_PATH_RESP_PATH_0,
SF_SEND_PATH_RESP_PATH_1 = 1 << SEND_PATH_RESP_PATH_1, SF_SEND_PATH_RESP_PATH_1 = 1 << SEND_PATH_RESP_PATH_1,
SF_SEND_PATH_RESP_PATH_2 = 1 << SEND_PATH_RESP_PATH_2,
SF_SEND_PATH_RESP_PATH_3 = 1 << SEND_PATH_RESP_PATH_3,
SF_SEND_NEW_CID = 1 << SEND_NEW_CID, SF_SEND_NEW_CID = 1 << SEND_NEW_CID,
SF_SEND_RETIRE_CID = 1 << SEND_RETIRE_CID, SF_SEND_RETIRE_CID = 1 << SEND_RETIRE_CID,
SF_SEND_CONN_CLOSE = 1 << SEND_CONN_CLOSE, SF_SEND_CONN_CLOSE = 1 << SEND_CONN_CLOSE,
@ -464,6 +472,10 @@ ietf_full_conn_ci_get_log_cid (const struct lsquic_conn *);
static void static void
ietf_full_conn_ci_destroy (struct lsquic_conn *); ietf_full_conn_ci_destroy (struct lsquic_conn *);
static int
insert_new_dcid (struct ietf_full_conn *, uint64_t seqno,
const lsquic_cid_t *, const unsigned char *token, int update_cur_dcid);
static unsigned static unsigned
highest_bit_set (unsigned sz) highest_bit_set (unsigned sz)
{ {
@ -652,11 +664,11 @@ migra_begin (struct ietf_full_conn *conn, struct conn_path *copath,
copath->cop_path.np_pack_size = IQUIC_MAX_IPv6_PACKET_SZ; copath->cop_path.np_pack_size = IQUIC_MAX_IPv6_PACKET_SZ;
else else
copath->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ; copath->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
if ((params->tp_set & (1 << TPI_MAX_PACKET_SIZE)) if ((params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE] && params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< copath->cop_path.np_pack_size) < copath->cop_path.np_pack_size)
copath->cop_path.np_pack_size copath->cop_path.np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE]; = params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
memcpy(&copath->cop_path.np_local_addr, NP_LOCAL_SA(CUR_NPATH(conn)), memcpy(&copath->cop_path.np_local_addr, NP_LOCAL_SA(CUR_NPATH(conn)),
sizeof(copath->cop_path.np_local_addr)); sizeof(copath->cop_path.np_local_addr));
memcpy(&copath->cop_path.np_peer_addr, dest_sa, memcpy(&copath->cop_path.np_peer_addr, dest_sa,
@ -1113,6 +1125,8 @@ ietf_full_conn_init (struct ietf_full_conn *conn,
conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO; conn->ifc_max_ack_packno[PNS_APP] = IQUIC_INVALID_PACKNO;
conn->ifc_paths[0].cop_path.np_path_id = 0; conn->ifc_paths[0].cop_path.np_path_id = 0;
conn->ifc_paths[1].cop_path.np_path_id = 1; conn->ifc_paths[1].cop_path.np_path_id = 1;
conn->ifc_paths[2].cop_path.np_path_id = 2;
conn->ifc_paths[3].cop_path.np_path_id = 3;
#define valid_stream_id(v) ((v) <= VINT_MAX_VALUE) #define valid_stream_id(v) ((v) <= VINT_MAX_VALUE)
conn->ifc_max_req_id = VINT_MAX_VALUE + 1; conn->ifc_max_req_id = VINT_MAX_VALUE + 1;
conn->ifc_ping_unretx_thresh = 20; conn->ifc_ping_unretx_thresh = 20;
@ -2740,7 +2754,7 @@ ietf_full_conn_ci_going_away (struct lsquic_conn *lconn)
{ {
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn; struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
if ((conn->ifc_flags & (IFC_SERVER|IFC_HTTP)) == (IFC_SERVER|IFC_HTTP)) if (conn->ifc_flags & IFC_HTTP)
{ {
if (!(conn->ifc_flags & (IFC_CLOSING|IFC_GOING_AWAY))) if (!(conn->ifc_flags & (IFC_CLOSING|IFC_GOING_AWAY)))
{ {
@ -2760,7 +2774,7 @@ ietf_full_conn_ci_going_away (struct lsquic_conn *lconn)
} }
} }
else else
LSQ_NOTICE("going away has no effect in IETF QUIC"); LSQ_NOTICE("going away has no effect in non-HTTP mode");
} }
@ -2834,8 +2848,8 @@ retire_cid_from_tp (struct ietf_full_conn *conn,
} }
static int static enum { BM_MIGRATING, BM_NOT_MIGRATING, BM_ERROR, }
begin_migra_or_retire_cid (struct ietf_full_conn *conn, try_to_begin_migration (struct ietf_full_conn *conn,
const struct transport_params *params) const struct transport_params *params)
{ {
struct conn_path *copath; struct conn_path *copath;
@ -2853,8 +2867,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
LSQ_DEBUG("TP disables migration: retire PreferredAddress CID"); LSQ_DEBUG("TP disables migration: retire PreferredAddress CID");
else else
LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID"); LSQ_DEBUG("Migration not allowed: retire PreferredAddress CID");
retire_cid_from_tp(conn, params); return BM_NOT_MIGRATING;
return 0;
} }
is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn)); is_ipv6 = NP_IS_IPv6(CUR_NPATH(conn));
@ -2867,8 +2880,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
*/ */
LSQ_DEBUG("Cannot migrate from IPv%u to IPv%u", is_ipv6 ? 6 : 4, LSQ_DEBUG("Cannot migrate from IPv%u to IPv%u", is_ipv6 ? 6 : 4,
is_ipv6 ? 4 : 6); is_ipv6 ? 4 : 6);
retire_cid_from_tp(conn, params); return BM_NOT_MIGRATING;
return 0;
} }
if (0 == params->tp_preferred_address.cid.len) if (0 == params->tp_preferred_address.cid.len)
@ -2877,15 +2889,14 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
* DCID becomes available. * DCID becomes available.
*/ */
LSQ_DEBUG("Cannot migrate using zero-length DCID"); LSQ_DEBUG("Cannot migrate using zero-length DCID");
retire_cid_from_tp(conn, params); return BM_NOT_MIGRATING;
return 0;
} }
dce = get_new_dce(conn); dce = get_new_dce(conn);
if (!dce) if (!dce)
{ {
ABORT_WARN("cannot allocate DCE"); ABORT_WARN("cannot allocate DCE");
return -1; return BM_ERROR;
} }
memset(dce, 0, sizeof(*dce)); memset(dce, 0, sizeof(*dce));
@ -2902,7 +2913,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
{ {
lsquic_malo_put(dce); lsquic_malo_put(dce);
ABORT_WARN("cannot insert DCE"); ABORT_WARN("cannot insert DCE");
return -1; return BM_ERROR;
} }
} }
@ -2925,7 +2936,7 @@ begin_migra_or_retire_cid (struct ietf_full_conn *conn,
assert(!(conn->ifc_used_paths & (1 << (copath - conn->ifc_paths)))); assert(!(conn->ifc_used_paths & (1 << (copath - conn->ifc_paths))));
migra_begin(conn, copath, dce, (struct sockaddr *) &sockaddr, params); migra_begin(conn, copath, dce, (struct sockaddr *) &sockaddr, params);
return 0; return BM_MIGRATING;
} }
@ -2938,10 +2949,33 @@ maybe_start_migration (struct ietf_full_conn *conn)
params = lconn->cn_esf.i->esfi_get_peer_transport_params( params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session); lconn->cn_enc_session);
if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS)) if (params->tp_set & (1 << TPI_PREFERRED_ADDRESS))
{ switch (try_to_begin_migration(conn, params))
if (0 != begin_migra_or_retire_cid(conn, params)) {
case BM_MIGRATING:
break;
case BM_NOT_MIGRATING:
if (lconn->cn_version == LSQVER_ID27)
retire_cid_from_tp(conn, params);
else
{
/*
* [draft-ietf-quic-transport-28] Section 5.1.1:
" Connection IDs that are issued and not
" retired are considered active; any active connection ID is valid for
" use with the current connection at any time, in any packet type.
" This includes the connection ID issued by the server via the
" preferred_address transport parameter.
*/
LSQ_DEBUG("not migrating: save DCID from transport params");
(void) insert_new_dcid(conn, 1,
&params->tp_preferred_address.cid,
params->tp_preferred_address.srst, 0);
}
break;
case BM_ERROR:
ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration"); ABORT_QUIETLY(0, TEC_INTERNAL_ERROR, "error initiating migration");
} break;
}
} }
@ -2955,7 +2989,7 @@ handshake_ok (struct lsquic_conn *lconn)
const struct transport_params *params; const struct transport_params *params;
enum stream_id_type sit; enum stream_id_type sit;
uint64_t limit; uint64_t limit;
char buf[0x200]; char buf[MAX_TP_STR_SZ];
fiu_return_on("full_conn_ietf/handshake_ok", -1); fiu_return_on("full_conn_ietf/handshake_ok", -1);
@ -2973,7 +3007,8 @@ handshake_ok (struct lsquic_conn *lconn)
} }
LSQ_DEBUG("peer transport parameters: %s", LSQ_DEBUG("peer transport parameters: %s",
(lsquic_tp_to_str(params, buf, sizeof(buf)), buf)); ((lconn->cn_version == LSQVER_ID27 ? lsquic_tp_to_str_27
: lsquic_tp_to_str)(params, buf, sizeof(buf)), buf));
if ((params->tp_set & (1 << TPI_LOSS_BITS)) if ((params->tp_set & (1 << TPI_LOSS_BITS))
&& conn->ifc_settings->es_ql_bits == 2) && conn->ifc_settings->es_ql_bits == 2)
@ -3088,12 +3123,12 @@ handshake_ok (struct lsquic_conn *lconn)
conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000; conn->ifc_max_peer_ack_usec = params->tp_max_ack_delay * 1000;
if ((params->tp_set & (1 << TPI_MAX_PACKET_SIZE)) if ((params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE] && params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< CUR_NPATH(conn)->np_pack_size) < CUR_NPATH(conn)->np_pack_size)
{ {
CUR_NPATH(conn)->np_pack_size CUR_NPATH(conn)->np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE]; = params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
LSQ_DEBUG("decrease packet size to %hu bytes", LSQ_DEBUG("decrease packet size to %hu bytes",
CUR_NPATH(conn)->np_pack_size); CUR_NPATH(conn)->np_pack_size);
} }
@ -3937,6 +3972,20 @@ generate_path_chal_1 (struct ietf_full_conn *conn, lsquic_time_t now)
} }
static void
generate_path_chal_2 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_chal_frame(conn, now, 2);
}
static void
generate_path_chal_3 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_chal_frame(conn, now, 3);
}
static void static void
generate_path_resp_frame (struct ietf_full_conn *conn, lsquic_time_t now, generate_path_resp_frame (struct ietf_full_conn *conn, lsquic_time_t now,
unsigned path_id) unsigned path_id)
@ -3986,6 +4035,20 @@ generate_path_resp_1 (struct ietf_full_conn *conn, lsquic_time_t now)
} }
static void
generate_path_resp_2 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_resp_frame(conn, now, 2);
}
static void
generate_path_resp_3 (struct ietf_full_conn *conn, lsquic_time_t now)
{
generate_path_resp_frame(conn, now, 3);
}
static struct lsquic_packet_out * static struct lsquic_packet_out *
ietf_full_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size) ietf_full_conn_ci_next_packet_to_send (struct lsquic_conn *lconn, size_t size)
{ {
@ -5140,17 +5203,91 @@ retire_dcids_prior_to (struct ietf_full_conn *conn, unsigned retire_prior_to)
} }
static int
insert_new_dcid (struct ietf_full_conn *conn, uint64_t seqno,
const lsquic_cid_t *cid, const unsigned char *token, int update_cur_dcid)
{
struct dcid_elem **dce, **el;
char tokstr[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
dce = NULL;
for (el = conn->ifc_dces; el < conn->ifc_dces + sizeof(conn->ifc_dces)
/ sizeof(conn->ifc_dces[0]); ++el)
if (*el)
{
if ((*el)->de_seqno == seqno)
{
if (!LSQUIC_CIDS_EQ(&(*el)->de_cid, cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: already have CID seqno %"PRIu64
" but with a different CID", seqno);
return -1;
}
else
{
LSQ_DEBUG("Ignore duplicate CID seqno %"PRIu64, seqno);
return 0;
}
}
else if (LSQUIC_CIDS_EQ(&(*el)->de_cid, cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received the same CID with sequence "
"numbers %u and %"PRIu64, (*el)->de_seqno, seqno);
return -1;
}
else if (((*el)->de_flags & DE_SRST)
&& 0 == memcmp((*el)->de_srst, token,
IQUIC_SRESET_TOKEN_SZ))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received second instance of reset "
"token %s in seqno %"PRIu64", same as in seqno %u",
(lsquic_hexstr(token, IQUIC_SRESET_TOKEN_SZ, tokstr,
sizeof(tokstr)), tokstr),
seqno, (*el)->de_seqno);
return -1;
}
}
else if (!dce)
dce = el;
if (!dce)
{
ABORT_QUIETLY(0, TEC_CONNECTION_ID_LIMIT_ERROR,
"NEW_CONNECTION_ID: received connection ID that is going over the "
"limit of %u CIDs", MAX_IETF_CONN_DCIDS);
return -1;
}
*dce = lsquic_malo_get(conn->ifc_pub.mm->malo.dcid_elem);
if (*dce)
{
memset(*dce, 0, sizeof(**dce));
(*dce)->de_seqno = seqno;
(*dce)->de_cid = *cid;
memcpy((*dce)->de_srst, token, sizeof((*dce)->de_srst));
(*dce)->de_flags |= DE_SRST;
if (update_cur_dcid)
*CUR_DCID(conn) = *cid;
}
else
LSQ_WARN("cannot allocate dce to insert DCID seqno %"PRIu64, seqno);
return 0;
}
static unsigned static unsigned
process_new_connection_id_frame (struct ietf_full_conn *conn, process_new_connection_id_frame (struct ietf_full_conn *conn,
struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len) struct lsquic_packet_in *packet_in, const unsigned char *p, size_t len)
{ {
struct dcid_elem **dce, **el;
const unsigned char *token; const unsigned char *token;
const char *action_str; const char *action_str;
lsquic_cid_t cid; lsquic_cid_t cid;
uint64_t seqno, retire_prior_to; uint64_t seqno, retire_prior_to;
int parsed_len, update_cur_dcid; int parsed_len, update_cur_dcid;
char tokstr[IQUIC_SRESET_TOKEN_SZ * 2 + 1];
parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_conn_id(p, len, parsed_len = conn->ifc_conn.cn_pf->pf_parse_new_conn_id(p, len,
&seqno, &retire_prior_to, &cid, &token); &seqno, &retire_prior_to, &cid, &token);
@ -5194,71 +5331,9 @@ process_new_connection_id_frame (struct ietf_full_conn *conn,
else else
update_cur_dcid = 0; update_cur_dcid = 0;
dce = NULL; if (0 != insert_new_dcid(conn, seqno, &cid, token, update_cur_dcid))
for (el = conn->ifc_dces; el < conn->ifc_dces + sizeof(conn->ifc_dces)
/ sizeof(conn->ifc_dces[0]); ++el)
if (*el)
{
if ((*el)->de_seqno == seqno)
{
if (!LSQUIC_CIDS_EQ(&(*el)->de_cid, &cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: already have CID seqno %"PRIu64
" but with a different CID", seqno);
return 0;
}
else
{
LSQ_DEBUG("Ignore duplicate CID seqno %"PRIu64, seqno);
return parsed_len;
}
}
else if (LSQUIC_CIDS_EQ(&(*el)->de_cid, &cid))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received the same CID with sequence "
"numbers %u and %"PRIu64, (*el)->de_seqno, seqno);
return 0;
}
else if (((*el)->de_flags & DE_SRST)
&& 0 == memcmp((*el)->de_srst, token,
IQUIC_SRESET_TOKEN_SZ))
{
ABORT_QUIETLY(0, TEC_PROTOCOL_VIOLATION,
"NEW_CONNECTION_ID: received second instance of reset "
"token %s in seqno %"PRIu64", same as in seqno %u",
(lsquic_hexstr(token, IQUIC_SRESET_TOKEN_SZ, tokstr,
sizeof(tokstr)), tokstr),
seqno, (*el)->de_seqno);
return 0;
}
}
else if (!dce)
dce = el;
if (!dce)
{
ABORT_QUIETLY(0, TEC_CONNECTION_ID_LIMIT_ERROR,
"NEW_CONNECTION_ID: received connection ID that is going over the "
"limit of %u CIDs", MAX_IETF_CONN_DCIDS);
return 0; return 0;
} action_str = "Saved";
*dce = lsquic_malo_get(conn->ifc_pub.mm->malo.dcid_elem);
if (*dce)
{
memset(*dce, 0, sizeof(**dce));
(*dce)->de_seqno = seqno;
(*dce)->de_cid = cid;
memcpy((*dce)->de_srst, token, sizeof((*dce)->de_srst));
(*dce)->de_flags |= DE_SRST;
action_str = "Saved";
if (update_cur_dcid)
*CUR_DCID(conn) = cid;
}
else
action_str = "Ignored (alloc failure)";
end: end:
LSQ_DEBUGC("Got new connection ID from peer: seq=%"PRIu64"; " LSQ_DEBUGC("Got new connection ID from peer: seq=%"PRIu64"; "
@ -5642,7 +5717,8 @@ process_packet_frame (struct ietf_full_conn *conn,
enc_level = lsquic_packet_in_enc_level(packet_in); enc_level = lsquic_packet_in_enc_level(packet_in);
type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p, len); type = conn->ifc_conn.cn_pf->pf_parse_frame_type(p, len);
if (lsquic_legal_frames_by_level[enc_level] & (1 << type)) if (lsquic_legal_frames_by_level[conn->ifc_conn.cn_version][enc_level]
& (1 << type))
{ {
LSQ_DEBUG("about to process %s frame", frame_type_2_str[type]); LSQ_DEBUG("about to process %s frame", frame_type_2_str[type]);
packet_in->pi_frame_types |= 1 << type; packet_in->pi_frame_types |= 1 << type;
@ -5724,11 +5800,11 @@ init_new_path (struct ietf_full_conn *conn, struct conn_path *path,
path->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ; path->cop_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
params = lconn->cn_esf.i->esfi_get_peer_transport_params( params = lconn->cn_esf.i->esfi_get_peer_transport_params(
lconn->cn_enc_session); lconn->cn_enc_session);
if (params && (params->tp_set & (1 << TPI_MAX_PACKET_SIZE)) if (params && (params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
&& params->tp_numerics[TPI_MAX_PACKET_SIZE] && params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< path->cop_path.np_pack_size) < path->cop_path.np_pack_size)
path->cop_path.np_pack_size path->cop_path.np_pack_size
= params->tp_numerics[TPI_MAX_PACKET_SIZE]; = params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
LSQ_DEBUG("initialized path %u", (unsigned) (path - conn->ifc_paths)); LSQ_DEBUG("initialized path %u", (unsigned) (path - conn->ifc_paths));
@ -6158,6 +6234,9 @@ process_regular_packet (struct ietf_full_conn *conn,
return process_retry_packet(conn, packet_in); return process_retry_packet(conn, packet_in);
pns = lsquic_hety2pns[ packet_in->pi_header_type ]; pns = lsquic_hety2pns[ packet_in->pi_header_type ];
if (pns == PNS_INIT)
conn->ifc_conn.cn_esf.i->esfi_set_iscid(conn->ifc_conn.cn_enc_session,
packet_in);
if ((pns == PNS_INIT && (conn->ifc_flags & IFC_IGNORE_INIT)) if ((pns == PNS_INIT && (conn->ifc_flags & IFC_IGNORE_INIT))
|| (pns == PNS_HSK && (conn->ifc_flags & IFC_IGNORE_HSK))) || (pns == PNS_HSK && (conn->ifc_flags & IFC_IGNORE_HSK)))
{ {
@ -6241,6 +6320,10 @@ process_regular_packet (struct ietf_full_conn *conn,
"decrypter reports protocol violation"); "decrypter reports protocol violation");
return -1; return -1;
case DECPI_OK: case DECPI_OK:
/* Receiving any other type of packet precludes subsequent retries.
* We only set it if decryption is successful.
*/
conn->ifc_flags |= IFC_RETRIED;
break; break;
} }
} }
@ -6344,13 +6427,6 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn,
if (lsquic_packet_in_is_verneg(packet_in)) if (lsquic_packet_in_is_verneg(packet_in))
{ {
if (!verneg_ok(conn))
{
ABORT_ERROR("version negotiation not permitted in this version "
"of QUIC");
return -1;
}
LSQ_DEBUG("Processing version-negotiation packet"); LSQ_DEBUG("Processing version-negotiation packet");
if (conn->ifc_u.cli.ifcli_ver_neg.vn_state != VN_START) if (conn->ifc_u.cli.ifcli_ver_neg.vn_state != VN_START)
@ -6383,10 +6459,26 @@ process_incoming_packet_verneg (struct ietf_full_conn *conn,
} }
} }
/* [draft-ietf-quic-transport-28] Section 6.2:
" A client MUST discard a Version Negotiation packet that lists the
" QUIC version selected by the client.
*/
if (versions & (1 << conn->ifc_u.cli.ifcli_ver_neg.vn_ver)) if (versions & (1 << conn->ifc_u.cli.ifcli_ver_neg.vn_ver))
{ {
ABORT_ERROR("server replied with version we support: %s", LSQ_DEBUG("server replied with version we sent, %s, ignore",
lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]); lsquic_ver2str[conn->ifc_u.cli.ifcli_ver_neg.vn_ver]);
return 0;
}
/* [draft-ietf-quic-transport-28] Section 6.2:
" A client that supports only this version of QUIC MUST abandon the
" current connection attempt if it receives a Version Negotiation
" packet [...]
*/
if (!verneg_ok(conn))
{
ABORT_ERROR("version negotiation not permitted in this version "
"of QUIC");
return -1; return -1;
} }
@ -6530,8 +6622,12 @@ static void (*const send_funcs[N_SEND])(
[SEND_STOP_SENDING] = generate_stop_sending_frames, [SEND_STOP_SENDING] = generate_stop_sending_frames,
[SEND_PATH_CHAL_PATH_0] = generate_path_chal_0, [SEND_PATH_CHAL_PATH_0] = generate_path_chal_0,
[SEND_PATH_CHAL_PATH_1] = generate_path_chal_1, [SEND_PATH_CHAL_PATH_1] = generate_path_chal_1,
[SEND_PATH_CHAL_PATH_2] = generate_path_chal_2,
[SEND_PATH_CHAL_PATH_3] = generate_path_chal_3,
[SEND_PATH_RESP_PATH_0] = generate_path_resp_0, [SEND_PATH_RESP_PATH_0] = generate_path_resp_0,
[SEND_PATH_RESP_PATH_1] = generate_path_resp_1, [SEND_PATH_RESP_PATH_1] = generate_path_resp_1,
[SEND_PATH_RESP_PATH_2] = generate_path_resp_2,
[SEND_PATH_RESP_PATH_3] = generate_path_resp_3,
[SEND_PING] = generate_ping_frame, [SEND_PING] = generate_ping_frame,
[SEND_HANDSHAKE_DONE] = generate_handshake_done_frame, [SEND_HANDSHAKE_DONE] = generate_handshake_done_frame,
[SEND_ACK_FREQUENCY] = generate_ack_frequency_frame, [SEND_ACK_FREQUENCY] = generate_ack_frequency_frame,
@ -6543,7 +6639,9 @@ static void (*const send_funcs[N_SEND])(
|SF_SEND_STREAMS_BLOCKED_UNI|SF_SEND_STREAMS_BLOCKED_BIDI\ |SF_SEND_STREAMS_BLOCKED_UNI|SF_SEND_STREAMS_BLOCKED_BIDI\
|SF_SEND_MAX_STREAMS_UNI|SF_SEND_MAX_STREAMS_BIDI\ |SF_SEND_MAX_STREAMS_UNI|SF_SEND_MAX_STREAMS_BIDI\
|SF_SEND_PATH_CHAL_PATH_0|SF_SEND_PATH_CHAL_PATH_1\ |SF_SEND_PATH_CHAL_PATH_0|SF_SEND_PATH_CHAL_PATH_1\
|SF_SEND_PATH_CHAL_PATH_2|SF_SEND_PATH_CHAL_PATH_3\
|SF_SEND_PATH_RESP_PATH_0|SF_SEND_PATH_RESP_PATH_1\ |SF_SEND_PATH_RESP_PATH_0|SF_SEND_PATH_RESP_PATH_1\
|SF_SEND_PATH_RESP_PATH_2|SF_SEND_PATH_RESP_PATH_3\
|SF_SEND_PING|SF_SEND_HANDSHAKE_DONE\ |SF_SEND_PING|SF_SEND_HANDSHAKE_DONE\
|SF_SEND_ACK_FREQUENCY\ |SF_SEND_ACK_FREQUENCY\
|SF_SEND_STOP_SENDING) |SF_SEND_STOP_SENDING)
@ -7119,6 +7217,17 @@ ietf_full_conn_ci_drop_crypto_streams (struct lsquic_conn *lconn)
} }
void
ietf_full_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
{
struct ietf_full_conn *conn = (struct ietf_full_conn *) lconn;
conn->ifc_pub.bytes_in = garbage_sz;
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
conn->ifc_pub.bytes_in);
}
#define IETF_FULL_CONN_FUNCS \ #define IETF_FULL_CONN_FUNCS \
.ci_abort = ietf_full_conn_ci_abort, \ .ci_abort = ietf_full_conn_ci_abort, \
.ci_abort_error = ietf_full_conn_ci_abort_error, \ .ci_abort_error = ietf_full_conn_ci_abort_error, \
@ -7127,6 +7236,7 @@ ietf_full_conn_ci_drop_crypto_streams (struct lsquic_conn *lconn)
.ci_cancel_pending_streams = ietf_full_conn_ci_cancel_pending_streams, \ .ci_cancel_pending_streams = ietf_full_conn_ci_cancel_pending_streams, \
.ci_client_call_on_new = ietf_full_conn_ci_client_call_on_new, \ .ci_client_call_on_new = ietf_full_conn_ci_client_call_on_new, \
.ci_close = ietf_full_conn_ci_close, \ .ci_close = ietf_full_conn_ci_close, \
.ci_count_garbage = ietf_full_conn_ci_count_garbage, \
.ci_destroy = ietf_full_conn_ci_destroy, \ .ci_destroy = ietf_full_conn_ci_destroy, \
.ci_drain_time = ietf_full_conn_ci_drain_time, \ .ci_drain_time = ietf_full_conn_ci_drain_time, \
.ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams, \ .ci_drop_crypto_streams = ietf_full_conn_ci_drop_crypto_streams, \
@ -7630,4 +7740,4 @@ static const struct lsquic_stream_if unicla_if =
static const struct lsquic_stream_if *unicla_if_ptr = &unicla_if; static const struct lsquic_stream_if *unicla_if_ptr = &unicla_if;
typedef char dcid_elem_fits_in_128_bytes[(sizeof(struct dcid_elem) <= 128) - 1]; typedef char dcid_elem_fits_in_128_bytes[sizeof(struct dcid_elem) <= 128 ? 1 : - 1];

View file

@ -1,9 +1,6 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ /* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#define _GNU_SOURCE /* for memmem */ #define _GNU_SOURCE /* for memmem */
#include <netinet/in.h>
#include <netdb.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -11,6 +8,8 @@
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif

View file

@ -126,12 +126,12 @@ lsquic_hcso_write_settings (struct hcso_writer *writer,
unsigned bits; unsigned bits;
int was_empty; int was_empty;
#ifdef NDEBUG #ifdef NDEBUG
const unsigned frame_size_len = 1; # define frame_size_len 1
#else #else
/* Need to use two bytes for frame length, as randomization may require /* Need to use two bytes for frame length, as randomization may require
* more than 63 bytes. * more than 63 bytes.
*/ */
const unsigned frame_size_len = 2; # define frame_size_len 2
#endif #endif
unsigned char buf[1 /* Frame type */ + /* Frame size */ frame_size_len unsigned char buf[1 /* Frame type */ + /* Frame size */ frame_size_len
/* There are maximum three settings that need to be written out and /* There are maximum three settings that need to be written out and

View file

@ -81,17 +81,8 @@ static lsquic_stream_ctx_t *
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream) headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
{ {
struct headers_stream *hs = stream_if_ctx; struct headers_stream *hs = stream_if_ctx;
enum lshpack_dec_flags flags;
flags = 0; lshpack_dec_init(&hs->hs_hdec);
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X)
flags |= LSHPACK_DEC_HTTP1X;
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME)
flags |= LSHPACK_DEC_HASH_NAME;
if (hs->hs_enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL)
flags |= LSHPACK_DEC_HASH_NAMEVAL;
lshpack_dec_init(&hs->hs_hdec, flags);
if (0 != lshpack_enc_init(&hs->hs_henc)) if (0 != lshpack_enc_init(&hs->hs_henc))
{ {
LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno)); LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));

View file

@ -17,7 +17,12 @@ lsquic_qhkdf_expand (const EVP_MD *md, const unsigned char *secret,
#ifndef NDEBUG #ifndef NDEBUG
int s; int s;
#endif #endif
const size_t len = 2 + 1 + 6 + label_len + 1;
#ifndef WIN32
unsigned char info[ 2 + 1 + 6 + label_len + 1]; unsigned char info[ 2 + 1 + 6 + label_len + 1];
#else
unsigned char info[ 2 + 1 + 6 + UINT8_MAX + 1];
#endif
info[0] = out_len >> 8; info[0] = out_len >> 8;
info[1] = out_len; info[1] = out_len;
@ -35,6 +40,6 @@ lsquic_qhkdf_expand (const EVP_MD *md, const unsigned char *secret,
#else #else
(void) (void)
#endif #endif
HKDF_expand(out, out_len, md, secret, secret_len, info, sizeof(info)); HKDF_expand(out, out_len, md, secret, secret_len, info, len);
assert(s); assert(s);
} }

View file

@ -527,17 +527,13 @@ h1h_prepare_decode (void *hset, struct lsxpack_header *xhdr, size_t req_space)
if (0 == hwc->hwc_header_buf_nalloc if (0 == hwc->hwc_header_buf_nalloc
|| req_space > hwc->hwc_header_buf_nalloc) || req_space > hwc->hwc_header_buf_nalloc)
{ {
if (req_space < 0x100) buf = malloc(req_space);
nalloc = 0x100;
else
nalloc = req_space;
buf = malloc(nalloc);
if (!buf) if (!buf)
{ {
LSQ_DEBUG("cannot allocate %zd bytes", nalloc); LSQ_DEBUG("cannot allocate %zd bytes", req_space);
return NULL; return NULL;
} }
hwc->hwc_header_buf_nalloc = nalloc; hwc->hwc_header_buf_nalloc = req_space;
} }
else else
buf = hwc->hwc_xhdr.buf; buf = hwc->hwc_xhdr.buf;

View file

@ -4,7 +4,7 @@
/* Things specific to the IETF version of QUIC that do not fit anywhere else */ /* Things specific to the IETF version of QUIC that do not fit anywhere else */
/* [draft-ietf-quic-transport-25] Section 22.4 */ /* [draft-ietf-quic-transport-28] Section 20 */
enum trans_error_code enum trans_error_code
{ {
TEC_NO_ERROR = 0x0, TEC_NO_ERROR = 0x0,
@ -19,6 +19,7 @@ enum trans_error_code
TEC_CONNECTION_ID_LIMIT_ERROR = 0x9, TEC_CONNECTION_ID_LIMIT_ERROR = 0x9,
TEC_PROTOCOL_VIOLATION = 0xA, TEC_PROTOCOL_VIOLATION = 0xA,
TEC_INVALID_TOKEN = 0xB, TEC_INVALID_TOKEN = 0xB,
TEC_APPLICATION_ERROR = 0xC,
TEC_CRYPTO_BUFFER_EXCEEDED = 0xD, TEC_CRYPTO_BUFFER_EXCEEDED = 0xD,
}; };

View file

@ -248,8 +248,10 @@ lsquic_logger_lopt (const char *optarg);
#define CID_FMT ".*s" #define CID_FMT ".*s"
#define CID_BITS(cid) 2 * (int) (cid)->len, \ #define CID_BITS_B(cid, b) 2 * (int) (cid)->len, \
(lsquic_cid2str(cid, cidbuf_), cidbuf_) (lsquic_cid2str(cid, b), b)
#define CID_BITS(cid) CID_BITS_B(cid, cidbuf_)
void void
lsquic_cid2str (const struct lsquic_cid *, char *out); lsquic_cid2str (const struct lsquic_cid *, char *out);

View file

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <time.h>
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
@ -95,7 +96,7 @@ process_deferred_packets (struct mini_conn *mc);
/* If this is not true, highest_bit_set() may be broken */ /* If this is not true, highest_bit_set() may be broken */
typedef char packno_set_is_unsigned_long[ typedef char packno_set_is_unsigned_long[
(sizeof(unsigned long long) == sizeof(mconn_packno_set_t)) - 1]; sizeof(unsigned long long) == sizeof(mconn_packno_set_t) ? 1 : -1 ];
static unsigned static unsigned
highest_bit_set (unsigned long long sz) highest_bit_set (unsigned long long sz)
@ -2030,7 +2031,10 @@ mini_conn_ci_destroy (struct lsquic_conn *lconn)
(int) (sizeof(mc->mc_hist_buf) - hist_idx), (int) (sizeof(mc->mc_hist_buf) - hist_idx),
mc->mc_hist_buf + hist_idx, (int) hist_idx, mc->mc_hist_buf); mc->mc_hist_buf + hist_idx, (int) hist_idx, mc->mc_hist_buf);
#else #else
LSQ_LOG(log_level, "destroyed. Diagnostics: conn flags: 0x%X, " if (LSQ_LOG_ENABLED(log_level))
lsquic_logger_log2(log_level, LSQUIC_LOGGER_MODULE,
LSQUIC_LOG_CONN_ID,
"destroyed. Diagnostics: conn flags: 0x%X, "
"mc flags: 0x%X, " "mc flags: 0x%X, "
#if LSQUIC_RECORD_INORD_HIST #if LSQUIC_RECORD_INORD_HIST
"incoming-history (trunc: %d) %s, " "incoming-history (trunc: %d) %s, "
@ -2235,8 +2239,8 @@ static const struct conn_iface mini_conn_iface_standard_Q050 = {
typedef char largest_recv_holds_at_least_16_seconds[ typedef char largest_recv_holds_at_least_16_seconds[
((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) / 1000000 ((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) / 1000000
>= 16) - 1]; >= 16) ? 1 : -1];
typedef char max_lifespan_smaller_than_largest_recv[ typedef char max_lifespan_smaller_than_largest_recv[
((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) > ((1 << (sizeof(((struct mini_conn *) 0)->mc_largest_recv) * 8)) >
MAX_MINI_CONN_LIFESPAN_IN_USEC) - 1]; MAX_MINI_CONN_LIFESPAN_IN_USEC) ? 1 : -1];

View file

@ -188,12 +188,12 @@ imico_maybe_process_params (struct ietf_mini_conn *conn)
{ {
conn->imc_flags |= IMC_HAVE_TP; conn->imc_flags |= IMC_HAVE_TP;
conn->imc_ack_exp = params->tp_ack_delay_exponent; conn->imc_ack_exp = params->tp_ack_delay_exponent;
if (params->tp_set & (1 << TPI_MAX_PACKET_SIZE)) if (params->tp_set & (1 << TPI_MAX_UDP_PAYLOAD_SIZE))
{ {
if (params->tp_numerics[TPI_MAX_PACKET_SIZE] if (params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
< conn->imc_path.np_pack_size) < conn->imc_path.np_pack_size)
conn->imc_path.np_pack_size = conn->imc_path.np_pack_size =
params->tp_numerics[TPI_MAX_PACKET_SIZE]; params->tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE];
} }
LSQ_DEBUG("read transport params, packet size is set to %hu bytes", LSQ_DEBUG("read transport params, packet size is set to %hu bytes",
conn->imc_path.np_pack_size); conn->imc_path.np_pack_size);
@ -493,6 +493,7 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
conn->imc_conn.cn_cur_cce_idx = 1; conn->imc_conn.cn_cur_cce_idx = 1;
conn->imc_conn.cn_flags = LSCONN_MINI|LSCONN_IETF|LSCONN_SERVER; conn->imc_conn.cn_flags = LSCONN_MINI|LSCONN_IETF|LSCONN_SERVER;
conn->imc_conn.cn_version = version;
for (i = 0; i < N_ENC_LEVS; ++i) for (i = 0; i < N_ENC_LEVS; ++i)
{ {
@ -503,7 +504,7 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
esfi = select_esf_iquic_by_ver(version); esfi = select_esf_iquic_by_ver(version);
enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn, enc_sess = esfi->esfi_create_server(enpub, &conn->imc_conn,
&packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if, &packet_in->pi_dcid, conn->imc_stream_ps, &crypto_stream_if,
odcid); &conn->imc_cces[0].cce_cid, &conn->imc_path.np_dcid);
if (!enc_sess) if (!enc_sess)
{ {
lsquic_malo_put(conn); lsquic_malo_put(conn);
@ -518,7 +519,6 @@ lsquic_mini_conn_ietf_new (struct lsquic_engine_public *enpub,
if (getenv("LSQUIC_CN_PACK_SIZE")) if (getenv("LSQUIC_CN_PACK_SIZE"))
conn->imc_path.np_pack_size = atoi(getenv("LSQUIC_CN_PACK_SIZE")); conn->imc_path.np_pack_size = atoi(getenv("LSQUIC_CN_PACK_SIZE"));
#endif #endif
conn->imc_conn.cn_version = version;
conn->imc_conn.cn_pf = select_pf_by_ver(version); conn->imc_conn.cn_pf = select_pf_by_ver(version);
conn->imc_conn.cn_esf.i = esfi; conn->imc_conn.cn_esf.i = esfi;
conn->imc_conn.cn_enc_session = enc_sess; conn->imc_conn.cn_enc_session = enc_sess;
@ -1099,7 +1099,8 @@ imico_process_packet_frame (struct ietf_mini_conn *conn,
enc_level = lsquic_packet_in_enc_level(packet_in); enc_level = lsquic_packet_in_enc_level(packet_in);
type = conn->imc_conn.cn_pf->pf_parse_frame_type(p, len); type = conn->imc_conn.cn_pf->pf_parse_frame_type(p, len);
if (lsquic_legal_frames_by_level[enc_level] & (1 << type)) if (lsquic_legal_frames_by_level[conn->imc_conn.cn_version][enc_level]
& (1 << type))
{ {
packet_in->pi_frame_types |= 1 << type; packet_in->pi_frame_types |= 1 << type;
return imico_process_frames[type](conn, packet_in, p, len); return imico_process_frames[type](conn, packet_in, p, len);
@ -1193,6 +1194,17 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
enum dec_packin dec_packin; enum dec_packin dec_packin;
enum packnum_space pns; enum packnum_space pns;
/* Update "bytes in" count as early as possible. From
* [draft-ietf-quic-transport-28] Section 8.1:
" For the purposes of
" avoiding amplification prior to address validation, servers MUST
" count all of the payload bytes received in datagrams that are
" uniquely attributed to a single connection. This includes datagrams
" that contain packets that are successfully processed and datagrams
" that contain packets that are all discarded.
*/
conn->imc_bytes_in += packet_in->pi_data_sz;
if (conn->imc_flags & IMC_ERROR) if (conn->imc_flags & IMC_ERROR)
{ {
LSQ_DEBUG("ignore incoming packet: connection is in error state"); LSQ_DEBUG("ignore incoming packet: connection is in error state");
@ -1216,7 +1228,6 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn,
} }
EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in); EV_LOG_PACKET_IN(LSQUIC_LOG_CONN_ID, packet_in);
conn->imc_bytes_in += packet_in->pi_data_sz + IQUIC_TAG_LEN;
if (pns == PNS_APP) if (pns == PNS_APP)
{ {
@ -1580,7 +1591,7 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
else if (conn->imc_flags & IMC_BAD_TRANS_PARAMS) else if (conn->imc_flags & IMC_BAD_TRANS_PARAMS)
{ {
is_app = 0; is_app = 0;
error_code = TEC_NO_ERROR; error_code = TEC_PROTOCOL_VIOLATION;
reason = "bad transport parameters"; reason = "bad transport parameters";
rlen = 24; rlen = 24;
} }
@ -1607,7 +1618,7 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
} }
/* [draft-ietf-quic-transport-23] Section 12.2: /* [draft-ietf-quic-transport-28] Section 10.3.1:
* *
" A client will always know whether the server has Handshake keys (see " A client will always know whether the server has Handshake keys (see
" Section 17.2.2.1), but it is possible that a server does not know " Section 17.2.2.1), but it is possible that a server does not know
@ -1615,7 +1626,25 @@ imico_generate_conn_close (struct ietf_mini_conn *conn)
" server SHOULD send a CONNECTION_CLOSE frame in both Handshake and " server SHOULD send a CONNECTION_CLOSE frame in both Handshake and
" Initial packets to ensure that at least one of them is processable by " Initial packets to ensure that at least one of them is processable by
" the client. " the client.
--- 8< ---
" Sending a CONNECTION_CLOSE of type 0x1d in an Initial or Handshake
" packet could expose application state or be used to alter application
" state. A CONNECTION_CLOSE of type 0x1d MUST be replaced by a
" CONNECTION_CLOSE of type 0x1c when sending the frame in Initial or
" Handshake packets. Otherwise, information about the application
" state might be revealed. Endpoints MUST clear the value of the
" Reason Phrase field and SHOULD use the APPLICATION_ERROR code when
" converting to a CONNECTION_CLOSE of type 0x1c.
*/ */
LSQ_DEBUG("sending CONNECTION_CLOSE, is_app: %d, error code: %u, "
"reason: %.*s", is_app, error_code, rlen, reason);
if (is_app && conn->imc_conn.cn_version > LSQVER_ID27)
{
LSQ_DEBUG("convert to 0x1C, replace code and reason");
is_app = 0;
error_code = TEC_APPLICATION_ERROR;
rlen = 0;
}
pns = (conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3; pns = (conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3;
switch ((!!(conn->imc_flags & IMC_HSK_PACKET_SENT) << 1) switch ((!!(conn->imc_flags & IMC_HSK_PACKET_SENT) << 1)
@ -1844,9 +1873,21 @@ ietf_mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
} }
void
ietf_mini_conn_ci_count_garbage (struct lsquic_conn *lconn, size_t garbage_sz)
{
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
conn->imc_bytes_in += garbage_sz;
LSQ_DEBUG("count %zd bytes of garbage, new value: %u bytes", garbage_sz,
conn->imc_bytes_in);
}
static const struct conn_iface mini_conn_ietf_iface = { static const struct conn_iface mini_conn_ietf_iface = {
.ci_abort_error = ietf_mini_conn_ci_abort_error, .ci_abort_error = ietf_mini_conn_ci_abort_error,
.ci_client_call_on_new = ietf_mini_conn_ci_client_call_on_new, .ci_client_call_on_new = ietf_mini_conn_ci_client_call_on_new,
.ci_count_garbage = ietf_mini_conn_ci_count_garbage,
.ci_destroy = ietf_mini_conn_ci_destroy, .ci_destroy = ietf_mini_conn_ci_destroy,
.ci_get_engine = ietf_mini_conn_ci_get_engine, .ci_get_engine = ietf_mini_conn_ci_get_engine,
.ci_get_log_cid = ietf_mini_conn_ci_get_log_cid, .ci_get_log_cid = ietf_mini_conn_ci_get_log_cid,

View file

@ -238,6 +238,6 @@ extern const char *const lsquic_pns2str[];
ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \ ALL_IQUIC_FRAMES & ~(QUIC_FTBIT_PADDING|QUIC_FTBIT_PATH_RESPONSE \
|QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP)) |QUIC_FTBIT_PATH_CHALLENGE|QUIC_FTBIT_ACK|QUIC_FTBIT_TIMESTAMP))
extern const enum quic_ft_bit lsquic_legal_frames_by_level[]; extern const enum quic_ft_bit lsquic_legal_frames_by_level[][4];
#endif #endif

View file

@ -217,9 +217,38 @@ lsquic_cid_from_packet (const unsigned char *buf, size_t bufsz,
} }
/* See [draft-ietf-quic-transport-25], Section 12.4 (Table 3) */ /* See [draft-ietf-quic-transport-28], Section 12.4 (Table 3) */
const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] = const enum quic_ft_bit lsquic_legal_frames_by_level[N_LSQVER][N_ENC_LEVS] =
{ {
[LSQVER_ID28] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_RETIRE_CONNECTION_ID,
[ENC_LEV_INIT] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK| QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_FORW] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE
| QUIC_FTBIT_STREAM | QUIC_FTBIT_RST_STREAM
| QUIC_FTBIT_BLOCKED
| QUIC_FTBIT_MAX_DATA | QUIC_FTBIT_MAX_STREAM_DATA
| QUIC_FTBIT_MAX_STREAMS | QUIC_FTBIT_STREAM_BLOCKED
| QUIC_FTBIT_STREAMS_BLOCKED
| QUIC_FTBIT_NEW_CONNECTION_ID | QUIC_FTBIT_STOP_SENDING
| QUIC_FTBIT_PATH_CHALLENGE | QUIC_FTBIT_PATH_RESPONSE
| QUIC_FTBIT_HANDSHAKE_DONE | QUIC_FTBIT_ACK_FREQUENCY
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
| QUIC_FTBIT_TIMESTAMP
,
},
[LSQVER_ID27] = {
[ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING [ENC_LEV_CLEAR] = QUIC_FTBIT_CRYPTO | QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
| QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE, | QUIC_FTBIT_ACK | QUIC_FTBIT_CONNECTION_CLOSE,
[ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING [ENC_LEV_EARLY] = QUIC_FTBIT_PADDING | QUIC_FTBIT_PING
@ -246,4 +275,5 @@ const enum quic_ft_bit lsquic_legal_frames_by_level[N_ENC_LEVS] =
| QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN | QUIC_FTBIT_RETIRE_CONNECTION_ID | QUIC_FTBIT_NEW_TOKEN
| QUIC_FTBIT_TIMESTAMP | QUIC_FTBIT_TIMESTAMP
, ,
},
}; };

View file

@ -6,6 +6,10 @@
#ifndef LSQUIC_PARSE_COMMON_H #ifndef LSQUIC_PARSE_COMMON_H
#define LSQUIC_PARSE_COMMON_H 1 #define LSQUIC_PARSE_COMMON_H 1
#ifdef WIN32
#include "vc_compat.h"
#endif
struct lsquic_packet_in; struct lsquic_packet_in;
struct packin_parse_state; struct packin_parse_state;

View file

@ -160,7 +160,7 @@ static const unsigned char simple_prst_payload[] = {
typedef char correct_simple_prst_size[(GQUIC_RESET_SZ == typedef char correct_simple_prst_size[(GQUIC_RESET_SZ ==
1 + GQUIC_CID_LEN + sizeof(simple_prst_payload)) - 1]; 1 + GQUIC_CID_LEN + sizeof(simple_prst_payload)) ? 1 : -1 ];
ssize_t ssize_t

View file

@ -353,6 +353,10 @@ ietf_v1_gen_stream_frame (unsigned char *buf, size_t buf_len,
unsigned slen, olen, dlen; unsigned slen, olen, dlen;
unsigned char *p = buf + 1; unsigned char *p = buf + 1;
#if _MSC_VER
obits = 0, dbits = 0;
#endif
assert(!!fin ^ !!size); assert(!!fin ^ !!size);
/* We do not check that stream_id, offset, and size are smaller /* We do not check that stream_id, offset, and size are smaller

View file

@ -6,11 +6,14 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <netinet/in.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif
#include <openssl/aead.h> #include <openssl/aead.h>
#include <openssl/rand.h> #include <openssl/rand.h>
@ -355,7 +358,7 @@ lsquic_prq_new_req (struct pr_queue *prq, enum packet_req_type type,
version = lsquic_tag2ver(ver_tag); version = lsquic_tag2ver(ver_tag);
} }
else /* Got to set it to something sensible... */ else /* Got to set it to something sensible... */
version = LSQVER_ID25; version = LSQVER_ID27;
lsquic_scid_from_packet_in(packet_in, &scid); lsquic_scid_from_packet_in(packet_in, &scid);
return lsquic_prq_new_req_ext(prq, type, flags, version, return lsquic_prq_new_req_ext(prq, type, flags, version,

View file

@ -10,6 +10,10 @@
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#ifdef WIN32
#include <malloc.h>
#endif
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_types.h" #include "lsquic_types.h"
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
@ -333,13 +337,22 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
enum lsqpack_enc_status st; enum lsqpack_enc_status st;
int i, s, write_to_stream; int i, s, write_to_stream;
enum lsqpack_enc_flags enc_flags; enum lsqpack_enc_flags enc_flags;
enum qwh_status retval;
#ifndef WIN32
unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ]; unsigned char enc_buf[ qeh->qeh_encoder.qpe_cur_max_capacity * 2 ];
#else
unsigned char *enc_buf;
enc_buf = _malloca(qeh->qeh_encoder.qpe_cur_max_capacity * 2);
if (!enc_buf)
return QWH_ERR;
#endif
s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0); s = lsqpack_enc_start_header(&qeh->qeh_encoder, stream_id, 0);
if (s != 0) if (s != 0)
{ {
LSQ_WARN("cannot start header"); LSQ_WARN("cannot start header");
return QWH_ERR; retval = QWH_ERR;
goto end;
} }
LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id); LSQ_DEBUG("begin encoding headers for stream %"PRIu64, stream_id);
@ -384,7 +397,8 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
{ {
LSQ_INFO("could not write to encoder stream: %s", LSQ_INFO("could not write to encoder stream: %s",
strerror(errno)); strerror(errno));
return QWH_ERR; retval = QWH_ERR;
goto end;
} }
write_to_stream = 0; write_to_stream = 0;
enc_p = enc_buf + (size_t) nw; enc_p = enc_buf + (size_t) nw;
@ -395,18 +409,22 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
if (0 != lsquic_frab_list_write(&qeh->qeh_fral, enc_p, enc_sz)) if (0 != lsquic_frab_list_write(&qeh->qeh_fral, enc_p, enc_sz))
{ {
LSQ_INFO("could not write to frab list"); LSQ_INFO("could not write to frab list");
return QWH_ERR; retval = QWH_ERR;
goto end;
} }
} }
break; break;
case LQES_NOBUF_HEAD: case LQES_NOBUF_HEAD:
return QWH_ENOBUF; retval = QWH_ENOBUF;
goto end;
default: default:
assert(0); assert(0);
return QWH_ERR; retval = QWH_ERR;
goto end;
case LQES_NOBUF_ENC: case LQES_NOBUF_ENC:
LSQ_DEBUG("not enough room to write encoder stream data"); LSQ_DEBUG("not enough room to write encoder stream data");
return QWH_ERR; retval = QWH_ERR;
goto end;
} }
} }
@ -415,7 +433,8 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
if (nw <= 0) if (nw <= 0)
{ {
LSQ_WARN("could not end header: %zd", nw); LSQ_WARN("could not end header: %zd", nw);
return QWH_ERR; retval = QWH_ERR;
goto end;
} }
if ((size_t) nw < *prefix_sz) if ((size_t) nw < *prefix_sz)
@ -429,7 +448,8 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
LSQ_DEBUG("all %zd bytes of encoder stream written out; header block " LSQ_DEBUG("all %zd bytes of encoder stream written out; header block "
"is %zd bytes; estimated compression ratio %.3f", total_enc_sz, "is %zd bytes; estimated compression ratio %.3f", total_enc_sz,
*headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder)); *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
return QWH_FULL; retval = QWH_FULL;
goto end;
} }
else else
{ {
@ -439,8 +459,15 @@ qeh_write_headers (struct qpack_enc_hdl *qeh, lsquic_stream_id_t stream_id,
"buffered; header block is %zd bytes; estimated compression ratio " "buffered; header block is %zd bytes; estimated compression ratio "
"%.3f", total_enc_sz, lsquic_frab_list_size(&qeh->qeh_fral), "%.3f", total_enc_sz, lsquic_frab_list_size(&qeh->qeh_fral),
*headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder)); *headers_sz, lsqpack_enc_ratio(&qeh->qeh_encoder));
return QWH_PARTIAL; retval = QWH_PARTIAL;
goto end;
} }
end:
#ifdef WIN32
_freea(enc_buf);
#endif
return retval;
} }

View file

@ -1542,6 +1542,9 @@ lsquic_send_ctl_do_sanity_check (const struct lsquic_send_ctl *ctl)
unsigned count, bytes; unsigned count, bytes;
enum packnum_space pns; enum packnum_space pns;
#if _MSC_VER
prev_packno = 0;
#endif
count = 0, bytes = 0; count = 0, bytes = 0;
for (pns = PNS_INIT; pns <= PNS_APP; ++pns) for (pns = PNS_INIT; pns <= PNS_APP; ++pns)
{ {

View file

@ -12,10 +12,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/socket.h>
#include <netdb.h>
#include <time.h> #include <time.h>
#ifndef WIN32
#include <netdb.h>
#include <sys/socket.h>
#endif
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
#include "lsquic.h" #include "lsquic.h"

View file

@ -205,4 +205,4 @@ const struct lsquic_shared_hash_if stock_shi =
/* Need this to save one malloc using malo: */ /* Need this to save one malloc using malo: */
typedef char hash_not_larger_than_hash_elem [ typedef char hash_not_larger_than_hash_elem [
(sizeof(struct stock_shared_hash) <= sizeof(struct hash_elem)) - 1]; (sizeof(struct stock_shared_hash) <= sizeof(struct hash_elem)) ? 1 : -1];

View file

@ -26,6 +26,10 @@
#include <sys/queue.h> #include <sys/queue.h>
#include <stddef.h> #include <stddef.h>
#ifdef WIN32
#include <malloc.h>
#endif
#include "fiu-local.h" #include "fiu-local.h"
#include "lsquic.h" #include "lsquic.h"
@ -3173,6 +3177,10 @@ update_buffered_hq_frames (struct lsquic_stream *stream, size_t len,
uint64_t cur_off, end; uint64_t cur_off, end;
size_t frame_sz; size_t frame_sz;
unsigned extendable; unsigned extendable;
#if _MSC_VER
end = 0;
extendable = 0;
#endif
cur_off = stream->sm_payload + stream->sm_n_buffered; cur_off = stream->sm_payload + stream->sm_n_buffered;
STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next) STAILQ_FOREACH(shf, &stream->sm_hq_frames, shf_next)
@ -3437,7 +3445,15 @@ send_headers_ietf (struct lsquic_stream *stream,
ssize_t nw; ssize_t nw;
unsigned char *header_block; unsigned char *header_block;
enum lsqpack_enc_header_flags hflags; enum lsqpack_enc_header_flags hflags;
unsigned char buf[max_push_size + max_prefix_size + MAX_HEADERS_SIZE]; int rv;
const size_t buf_sz = max_push_size + max_prefix_size + MAX_HEADERS_SIZE;
#ifndef WIN32
unsigned char buf[buf_sz];
#else
unsigned char *buf = _malloca(buf_sz);
if (!buf)
return -1;
#endif
stream->stream_flags &= ~STREAM_PUSHING; stream->stream_flags &= ~STREAM_PUSHING;
stream->stream_flags |= STREAM_NOPUSH; stream->stream_flags |= STREAM_NOPUSH;
@ -3446,7 +3462,7 @@ send_headers_ietf (struct lsquic_stream *stream,
* back to a larger buffer if that fails. * back to a larger buffer if that fails.
*/ */
prefix_sz = max_prefix_size; prefix_sz = max_prefix_size;
headers_sz = sizeof(buf) - max_prefix_size - max_push_size; headers_sz = buf_sz - max_prefix_size - max_push_size;
qwh = lsquic_qeh_write_headers(stream->conn_pub->u.ietf.qeh, stream->id, 0, qwh = lsquic_qeh_write_headers(stream->conn_pub->u.ietf.qeh, stream->id, 0,
headers, buf + max_push_size + max_prefix_size, &prefix_sz, headers, buf + max_push_size + max_prefix_size, &prefix_sz,
&headers_sz, &stream->sm_hb_compl, &hflags); &headers_sz, &stream->sm_hb_compl, &hflags);
@ -3457,7 +3473,7 @@ send_headers_ietf (struct lsquic_stream *stream,
LSQ_INFO("not enough room for header block"); LSQ_INFO("not enough room for header block");
else else
LSQ_WARN("internal error encoding and sending HTTP headers"); LSQ_WARN("internal error encoding and sending HTTP headers");
return -1; goto err;
} }
if (hflags & LSQECH_REF_NEW_ENTRIES) if (hflags & LSQECH_REF_NEW_ENTRIES)
@ -3471,7 +3487,7 @@ send_headers_ietf (struct lsquic_stream *stream,
if (!stream_activate_hq_frame(stream, if (!stream_activate_hq_frame(stream,
stream->sm_payload + stream->sm_n_buffered, HQFT_PUSH_PREAMBLE, stream->sm_payload + stream->sm_n_buffered, HQFT_PUSH_PREAMBLE,
SHF_FIXED_SIZE|SHF_PHANTOM, push_sz)) SHF_FIXED_SIZE|SHF_PHANTOM, push_sz))
return -1; goto err;
buf[max_push_size + max_prefix_size - prefix_sz - push_sz] = HQUST_PUSH; buf[max_push_size + max_prefix_size - prefix_sz - push_sz] = HQUST_PUSH;
vint_write(buf + max_push_size + max_prefix_size - prefix_sz vint_write(buf + max_push_size + max_prefix_size - prefix_sz
- push_sz + 1,stream->sm_promise->pp_id, bits, 1 << bits); - push_sz + 1,stream->sm_promise->pp_id, bits, 1 << bits);
@ -3485,7 +3501,7 @@ send_headers_ietf (struct lsquic_stream *stream,
if (!stream_activate_hq_frame(stream, if (!stream_activate_hq_frame(stream,
stream->sm_payload + stream->sm_n_buffered + push_sz, stream->sm_payload + stream->sm_n_buffered + push_sz,
HQFT_HEADERS, SHF_FIXED_SIZE, hblock_sz - push_sz)) HQFT_HEADERS, SHF_FIXED_SIZE, hblock_sz - push_sz))
return -1; goto err;
if (qwh == QWH_FULL) if (qwh == QWH_FULL)
{ {
@ -3496,14 +3512,14 @@ send_headers_ietf (struct lsquic_stream *stream,
if (nw < 0) if (nw < 0)
{ {
LSQ_WARN("cannot write to stream: %s", strerror(errno)); LSQ_WARN("cannot write to stream: %s", strerror(errno));
return -1; goto err;
} }
if ((size_t) nw == hblock_sz) if ((size_t) nw == hblock_sz)
{ {
stream->stream_flags |= STREAM_HEADERS_SENT; stream->stream_flags |= STREAM_HEADERS_SENT;
stream_hblock_sent(stream); stream_hblock_sent(stream);
LSQ_DEBUG("wrote all %zu bytes of header block", hblock_sz); LSQ_DEBUG("wrote all %zu bytes of header block", hblock_sz);
return 0; goto end;
} }
LSQ_DEBUG("wrote only %zd bytes of header block, stash", nw); LSQ_DEBUG("wrote only %zd bytes of header block, stash", nw);
} }
@ -3528,14 +3544,25 @@ send_headers_ietf (struct lsquic_stream *stream,
{ {
LSQ_WARN("cannot allocate %zd bytes to stash %s header block", LSQ_WARN("cannot allocate %zd bytes to stash %s header block",
hblock_sz - (size_t) nw, qwh == QWH_FULL ? "full" : "partial"); hblock_sz - (size_t) nw, qwh == QWH_FULL ? "full" : "partial");
return -1; goto err;
} }
memcpy(stream->sm_header_block, header_block + (size_t) nw, memcpy(stream->sm_header_block, header_block + (size_t) nw,
hblock_sz - (size_t) nw); hblock_sz - (size_t) nw);
stream->sm_hblock_sz = hblock_sz - (size_t) nw; stream->sm_hblock_sz = hblock_sz - (size_t) nw;
stream->sm_hblock_off = 0; stream->sm_hblock_off = 0;
LSQ_DEBUG("stashed %u bytes of header block", stream->sm_hblock_sz); LSQ_DEBUG("stashed %u bytes of header block", stream->sm_hblock_sz);
return 0;
end:
rv = 0;
clean:
#ifdef WIN32
_freea(buf);
#endif
return rv;
err:
rv = -1;
goto clean;
} }
@ -4560,7 +4587,7 @@ pp_reader_read (void *lsqr_ctx, void *buf, size_t count)
{ {
struct push_promise *const promise = lsqr_ctx; struct push_promise *const promise = lsqr_ctx;
unsigned char *dst = buf; unsigned char *dst = buf;
unsigned char *const end = buf + count; unsigned char *const end = dst + count;
size_t len; size_t len;
while (dst < end) while (dst < end)

View file

@ -1,13 +1,16 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ /* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h> #include <assert.h>
#include <netinet/in.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/socket.h>
#include <time.h> #include <time.h>
#ifndef WIN32
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <openssl/aead.h> #include <openssl/aead.h>
#include <openssl/hkdf.h> #include <openssl/hkdf.h>
#include <openssl/rand.h> #include <openssl/rand.h>
@ -31,7 +34,7 @@
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
#define TOKGEN_VERSION 1 #define TOKGEN_VERSION 2
#define CRYPTER_KEY_SIZE 16 #define CRYPTER_KEY_SIZE 16
#define SRST_MAX_PRK_SIZE EVP_MAX_MD_SIZE #define SRST_MAX_PRK_SIZE EVP_MAX_MD_SIZE
@ -65,6 +68,8 @@ struct crypter
}; };
struct token_generator struct token_generator
{ {
/* We encrypt different token types using different keys. */ /* We encrypt different token types using different keys. */

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ enum transport_param_id
* Numeric transport parameters that have default values: * Numeric transport parameters that have default values:
*/ */
TPI_MAX_IDLE_TIMEOUT, TPI_MAX_IDLE_TIMEOUT,
TPI_MAX_PACKET_SIZE, TPI_MAX_UDP_PAYLOAD_SIZE,
TPI_INIT_MAX_DATA, TPI_INIT_MAX_DATA,
TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL, TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE, TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
@ -45,7 +45,12 @@ enum transport_param_id
* Custom handlers: * Custom handlers:
*/ */
TPI_PREFERRED_ADDRESS, TPI_PREFERRED_ADDRESS,
TPI_ORIGINAL_CONNECTION_ID, /* CIDs must be in a contiguous range for tp_cids array to work */
#define FIRST_TP_CID TPI_ORIGINAL_DEST_CID
TPI_ORIGINAL_DEST_CID,
TPI_INITIAL_SOURCE_CID,
#define LAST_TP_CID TPI_RETRY_SOURCE_CID
TPI_RETRY_SOURCE_CID,
#if LSQUIC_TEST_QUANTUM_READINESS #if LSQUIC_TEST_QUANTUM_READINESS
/* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */ /* https://github.com/quicwg/base-drafts/wiki/Quantum-Readiness-test */
#define QUANTUM_READY_SZ 1200 #define QUANTUM_READY_SZ 1200
@ -54,6 +59,8 @@ enum transport_param_id
TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN TPI_STATELESS_RESET_TOKEN, LAST_TPI = TPI_STATELESS_RESET_TOKEN
}; };
#define TP_CID_IDX(tpi_) ((tpi_) - FIRST_TP_CID)
struct transport_params struct transport_params
{ {
@ -72,7 +79,7 @@ struct transport_params
#define tp_max_idle_timeout tp_numerics[TPI_MAX_IDLE_TIMEOUT] #define tp_max_idle_timeout tp_numerics[TPI_MAX_IDLE_TIMEOUT]
#define tp_init_max_streams_bidi tp_numerics[TPI_INIT_MAX_STREAMS_BIDI] #define tp_init_max_streams_bidi tp_numerics[TPI_INIT_MAX_STREAMS_BIDI]
#define tp_init_max_streams_uni tp_numerics[TPI_INIT_MAX_STREAMS_UNI] #define tp_init_max_streams_uni tp_numerics[TPI_INIT_MAX_STREAMS_UNI]
#define tp_max_packet_size tp_numerics[TPI_MAX_PACKET_SIZE] #define tp_max_udp_payload_size tp_numerics[TPI_MAX_UDP_PAYLOAD_SIZE]
#define tp_ack_delay_exponent tp_numerics[TPI_ACK_DELAY_EXPONENT] #define tp_ack_delay_exponent tp_numerics[TPI_ACK_DELAY_EXPONENT]
#define tp_max_ack_delay tp_numerics[TPI_MAX_ACK_DELAY] #define tp_max_ack_delay tp_numerics[TPI_MAX_ACK_DELAY]
#define tp_active_connection_id_limit tp_numerics[TPI_ACTIVE_CONNECTION_ID_LIMIT] #define tp_active_connection_id_limit tp_numerics[TPI_ACTIVE_CONNECTION_ID_LIMIT]
@ -87,10 +94,20 @@ struct transport_params
lsquic_cid_t cid; lsquic_cid_t cid;
uint8_t srst[IQUIC_SRESET_TOKEN_SZ]; uint8_t srst[IQUIC_SRESET_TOKEN_SZ];
} tp_preferred_address; } tp_preferred_address;
lsquic_cid_t tp_original_cid; lsquic_cid_t tp_cids[3];
#define tp_original_dest_cid tp_cids[TP_CID_IDX(TPI_ORIGINAL_DEST_CID)]
#define tp_initial_source_cid tp_cids[TP_CID_IDX(TPI_INITIAL_SOURCE_CID)]
#define tp_retry_source_cid tp_cids[TP_CID_IDX(TPI_RETRY_SOURCE_CID)]
}; };
#define TP_DEF_MAX_PACKET_SIZE 65527 #define MAX_TP_STR_SZ ((LAST_TPI + 1) * \
(34 /* longest entry in tt2str */ + 2 /* semicolon */ + 2 /* colon */) \
+ INET_ADDRSTRLEN + INET6_ADDRSTRLEN + 5 /* Port */ * 2 \
+ MAX_CID_LEN * 2 * 4 /* there are four CIDs */ \
+ 11 * (MAX_NUMERIC_TPI + 1) \
+ IQUIC_SRESET_TOKEN_SZ * 2 * 2 /* there are two reset tokens */)
#define TP_DEF_MAX_UDP_PAYLOAD_SIZE 65527
#define TP_DEF_ACK_DELAY_EXP 3 #define TP_DEF_ACK_DELAY_EXP 3
#define TP_DEF_INIT_MAX_STREAMS_UNI 0 #define TP_DEF_INIT_MAX_STREAMS_UNI 0
#define TP_DEF_INIT_MAX_STREAMS_BIDI 0 #define TP_DEF_INIT_MAX_STREAMS_BIDI 0
@ -111,7 +128,7 @@ struct transport_params
.tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \ .tp_active_connection_id_limit = TP_DEF_ACTIVE_CONNECTION_ID_LIMIT, \
.tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \ .tp_max_idle_timeout = TP_DEF_MAX_IDLE_TIMEOUT, \
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \ .tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, \
.tp_max_packet_size = TP_DEF_MAX_PACKET_SIZE, \ .tp_max_udp_payload_size = TP_DEF_MAX_UDP_PAYLOAD_SIZE, \
.tp_ack_delay_exponent = TP_DEF_ACK_DELAY_EXP, \ .tp_ack_delay_exponent = TP_DEF_ACK_DELAY_EXP, \
.tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \ .tp_init_max_streams_bidi = TP_DEF_INIT_MAX_STREAMS_BIDI, \
.tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \ .tp_init_max_streams_uni = TP_DEF_INIT_MAX_STREAMS_UNI, \
@ -124,10 +141,10 @@ struct transport_params
int int
lsquic_tp_encode (const struct transport_params *, int is_server, lsquic_tp_encode (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz); unsigned char *const buf, size_t bufsz);
int int
lsquic_tp_decode (const unsigned char *buf, size_t bufsz, lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
/* This argument specifies whose transport parameters we are parsing. If /* This argument specifies whose transport parameters we are parsing. If
* true, we are parsing parameters sent by the server; if false, we are * true, we are parsing parameters sent by the server; if false, we are
* parsing parameteres sent by the client. * parsing parameteres sent by the client.
@ -135,21 +152,27 @@ lsquic_tp_decode (const unsigned char *buf, size_t bufsz,
int is_server, int is_server,
struct transport_params *); struct transport_params *);
int
lsquic_tp_encode_id25 (const struct transport_params *, int is_server,
unsigned char *buf, size_t bufsz);
int
lsquic_tp_decode_id25 (const unsigned char *buf, size_t bufsz,
int is_server, struct transport_params *);
void void
lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz); lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz);
int
lsquic_tp_encode_27 (const struct transport_params *, int is_server,
unsigned char *const buf, size_t bufsz);
int
lsquic_tp_decode_27 (const unsigned char *const buf, size_t bufsz,
int is_server,
struct transport_params *);
void
lsquic_tp_to_str_27 (const struct transport_params *params, char *buf, size_t sz);
int int
lsquic_tp_has_pref_ipv4 (const struct transport_params *); lsquic_tp_has_pref_ipv4 (const struct transport_params *);
int int
lsquic_tp_has_pref_ipv6 (const struct transport_params *); lsquic_tp_has_pref_ipv6 (const struct transport_params *);
extern const char * const lsquic_tpi2str[LAST_TPI + 1];
#endif #endif

View file

@ -9,14 +9,15 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#ifndef WIN32 #ifndef WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <unistd.h> #include <unistd.h>
#else #else
#include <vc_compat.h> #include <vc_compat.h>
#include <ws2tcpip.h>
#endif #endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__) #if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
#include <mach/mach_time.h> #include <mach/mach_time.h>

View file

@ -5,6 +5,10 @@
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
#include "lsquic_version.h" #include "lsquic_version.h"
#if _MSC_VER
#include "vc_compat.h"
#endif
static const unsigned char version_tags[N_LSQVER][4] = static const unsigned char version_tags[N_LSQVER][4] =
{ {
@ -14,8 +18,8 @@ static const unsigned char version_tags[N_LSQVER][4] =
#if LSQUIC_USE_Q098 #if LSQUIC_USE_Q098
[LSQVER_098] = { 'Q', '0', '9', '8', }, [LSQVER_098] = { 'Q', '0', '9', '8', },
#endif #endif
[LSQVER_ID25] = { 0xFF, 0, 0, 25, },
[LSQVER_ID27] = { 0xFF, 0, 0, 27, }, [LSQVER_ID27] = { 0xFF, 0, 0, 27, },
[LSQVER_ID28] = { 0xFF, 0, 0, 28, },
[LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, }, [LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
}; };
@ -52,8 +56,8 @@ const char *const lsquic_ver2str[N_LSQVER] = {
#if LSQUIC_USE_Q098 #if LSQUIC_USE_Q098
[LSQVER_098] = "Q098", [LSQVER_098] = "Q098",
#endif #endif
[LSQVER_ID25] = "FF000019",
[LSQVER_ID27] = "FF00001B", [LSQVER_ID27] = "FF00001B",
[LSQVER_ID28] = "FF00001C",
[LSQVER_VERNEG] = "FAFAFAFA", [LSQVER_VERNEG] = "FAFAFAFA",
}; };

@ -1 +1 @@
Subproject commit 8d4b795ff661e73e10b7d46ce06cba3b88499769 Subproject commit b577d56964e443972adb38ec56706181846cc47f

View file

@ -45,7 +45,6 @@ SET(TESTS
frame_writer frame_writer
goaway_gquic_be goaway_gquic_be
h3_framing h3_framing
hcsi_reader
hkdf hkdf
lsquic_hash lsquic_hash
packet_out packet_out
@ -82,6 +81,8 @@ ENDIF()
IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") IF (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
# No regexes on Windows # No regexes on Windows
SET(TESTS ${TESTS} ack_merge) SET(TESTS ${TESTS} ack_merge)
# No open_memstream() on Windows
SET(TESTS ${TESTS} hcsi_reader)
ENDIF() ENDIF()
@ -98,21 +99,27 @@ ADD_TEST(stream_hash test_stream -h)
ADD_TEST(stream_A test_stream -A) ADD_TEST(stream_A test_stream -A)
ADD_TEST(stream_hash_A test_stream -A -h) ADD_TEST(stream_hash_A test_stream -A -h)
IF(NOT MSVC)
ADD_EXECUTABLE(graph_cubic graph_cubic.c ${ADDL_SOURCES}) ADD_EXECUTABLE(graph_cubic graph_cubic.c ${ADDL_SOURCES})
TARGET_LINK_LIBRARIES(graph_cubic ${LIBS}) TARGET_LINK_LIBRARIES(graph_cubic ${LIBS})
ADD_EXECUTABLE(mini_parse mini_parse.c ${ADDL_SOURCES}) ADD_EXECUTABLE(mini_parse mini_parse.c ${ADDL_SOURCES})
TARGET_LINK_LIBRARIES(mini_parse ${LIBS}) TARGET_LINK_LIBRARIES(mini_parse ${LIBS})
ENDIF()
ADD_EXECUTABLE(test_min_heap test_min_heap.c ../src/liblsquic/lsquic_min_heap.c) ADD_EXECUTABLE(test_min_heap test_min_heap.c ../src/liblsquic/lsquic_min_heap.c)
ADD_TEST(min_heap test_min_heap) ADD_TEST(min_heap test_min_heap)
ADD_EXECUTABLE(test_malo_pooled test_malo.c ../src/liblsquic/lsquic_malo.c) SET(MALO_SRC test_malo.c ../src/liblsquic/lsquic_malo.c)
IF(MSVC)
LIST(APPEND MALO_SRC ../wincompat/getopt.c)
ENDIF()
ADD_EXECUTABLE(test_malo_pooled ${MALO_SRC})
SET_TARGET_PROPERTIES(test_malo_pooled SET_TARGET_PROPERTIES(test_malo_pooled
PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSQUIC_USE_POOLS=1") PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSQUIC_USE_POOLS=1")
ADD_TEST(malo_pooled test_malo_pooled) ADD_TEST(malo_pooled test_malo_pooled)
ADD_EXECUTABLE(test_malo_nopool test_malo.c ../src/liblsquic/lsquic_malo.c) ADD_EXECUTABLE(test_malo_nopool ${MALO_SRC})
SET_TARGET_PROPERTIES(test_malo_nopool SET_TARGET_PROPERTIES(test_malo_nopool
PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSQUIC_USE_POOLS=0") PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -DLSQUIC_USE_POOLS=0")
ADD_TEST(malo_nopool test_malo_nopool) ADD_TEST(malo_nopool test_malo_nopool)

View file

@ -10,12 +10,16 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef WIN32
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#else
#include "getopt.h"
#endif
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_types.h" #include "lsquic_types.h"

View file

@ -179,7 +179,7 @@ run_test (const struct test *test)
size_t sz; size_t sz;
unsigned char buf[0x1000]; unsigned char buf[0x1000];
pf = select_pf_by_ver(LSQVER_ID25); pf = select_pf_by_ver(LSQVER_ID27);
if (!test->skip_gen) if (!test->skip_gen)
{ {
rechist.acki = &test->acki; rechist.acki = &test->acki;

View file

@ -9,6 +9,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef WIN32
#include "vc_compat.h"
#endif
#include "lsquic_types.h" #include "lsquic_types.h"
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
#include "lsquic_rechist.h" #include "lsquic_rechist.h"

View file

@ -5,6 +5,8 @@
#include <string.h> #include <string.h>
#ifndef WIN32 #ifndef WIN32
#include <sys/time.h> #include <sys/time.h>
#else
#include "vc_compat.h"
#endif #endif
#include "lsquic_types.h" #include "lsquic_types.h"

View file

@ -5,6 +5,8 @@
#include <string.h> #include <string.h>
#ifndef WIN32 #ifndef WIN32
#include <sys/time.h> #include <sys/time.h>
#else
#include "vc_compat.h"
#endif #endif
#include "lsquic_types.h" #include "lsquic_types.h"
@ -17,7 +19,7 @@
static struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0); static struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_ID25); static const struct parse_funcs *const pf = select_pf_by_ver(LSQVER_ID27);
static void static void

View file

@ -105,7 +105,8 @@ main (void)
unsigned const count = popcount(i); unsigned const count = popcount(i);
unsigned const min_n = i % count; unsigned const min_n = i % count;
unsigned const min_t = t++; unsigned const min_t = t++;
unsigned j, n, ids[2]; unsigned j, n;
enum alarm_id ids[2];
for (j = 0, n = 0; j < MAX_LSQUIC_ALARMS; ++j) for (j = 0, n = 0; j < MAX_LSQUIC_ALARMS; ++j)
{ {
if ((1u << j) & i) if ((1u << j) & i)

View file

@ -115,6 +115,9 @@ test_attq_ordering (enum sort_action sa)
} }
} }
#ifdef _MSC_VER
prev = 0;
#endif
for (i = 0; i < sizeof(curiosity); ++i) for (i = 0; i < sizeof(curiosity); ++i)
{ {
next_attq = lsquic_attq_next(q); next_attq = lsquic_attq_next(q);

View file

@ -33,7 +33,7 @@ struct test {
static const struct test tests[] = { static const struct test tests[] = {
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.offset = 0, .offset = 0,
.data_sz = 10, .data_sz = 10,
.data = "0123456789", .data = "0123456789",
@ -49,7 +49,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.offset = 500, .offset = 500,
.data_sz = 10, .data_sz = 10,
.data = "0123456789", .data = "0123456789",

View file

@ -38,7 +38,7 @@ test_post_quiescence_explosion (void)
struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 8); struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 8);
struct lsquic_conn_public conn_pub = { .lconn = &lconn, }; struct lsquic_conn_public conn_pub = { .lconn = &lconn, };
int i; int i;
struct lsquic_packet_out packet_out = {}; struct lsquic_packet_out packet_out; memset(&packet_out, 0, sizeof(packet_out));
cci->cci_init(&cubic, &conn_pub, 0); cci->cci_init(&cubic, &conn_pub, 0);
cubic.cu_ssthresh = cubic.cu_cwnd = 32 * 1370; cubic.cu_ssthresh = cubic.cu_cwnd = 32 * 1370;
@ -72,7 +72,7 @@ test_post_quiescence_explosion2 (void)
struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 8); struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 8);
struct lsquic_conn_public conn_pub = { .lconn = &lconn, }; struct lsquic_conn_public conn_pub = { .lconn = &lconn, };
int i; int i;
struct lsquic_packet_out packet_out = {}; struct lsquic_packet_out packet_out; memset(&packet_out, 0, sizeof(packet_out));
cci->cci_init(&cubic, &conn_pub, 0); cci->cci_init(&cubic, &conn_pub, 0);
cubic.cu_ssthresh = cubic.cu_cwnd = 32 * 1370; cubic.cu_ssthresh = cubic.cu_cwnd = 32 * 1370;

View file

@ -442,6 +442,8 @@ run_ekt_test (const struct export_key_test *test)
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
if (i && !(test->ekt_ikm_sz == 32 && test->ekt_client_key_sz == 16 && test->ekt_server_key_sz == 16))
continue;
s = lsquic_export_key_material(test->ekt_ikm, (uint32_t)test->ekt_ikm_sz, s = lsquic_export_key_material(test->ekt_ikm, (uint32_t)test->ekt_ikm_sz,
test->ekt_salt, (int)test->ekt_salt_sz, test->ekt_salt, (int)test->ekt_salt_sz,
test->ekt_context, (uint32_t)test->ekt_context_sz, test->ekt_context, (uint32_t)test->ekt_context_sz,

View file

@ -94,7 +94,7 @@ stream_write (struct lsquic_stream *stream, struct lsquic_reader *reader)
} }
#define XHDR(name_, value_) .buf = value_, .name_ptr = name_, .val_len = sizeof(value_) - 1, .name_len = sizeof(name_) - 1 #define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1,
static void static void

View file

@ -1136,7 +1136,7 @@ test_one_frt (const struct frame_reader_test *frt)
top: top:
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
lshpack_dec_init(&hdec, LSHPACK_DEC_HTTP1X); lshpack_dec_init(&hdec);
memset(&input, 0, sizeof(input)); memset(&input, 0, sizeof(input));
memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz); memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz);
input.in_sz = frt->frt_bufsz; input.in_sz = frt->frt_bufsz;

View file

@ -225,7 +225,7 @@ test_rw (unsigned max_frame_sz)
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lshpack_dec_init(&hdec, LSHPACK_DEC_HTTP1X); lshpack_dec_init(&hdec);
stream = stream_new(); stream = stream_new();
stream->sm_max_sz = 1; stream->sm_max_sz = 1;
@ -340,7 +340,7 @@ main (int argc, char **argv)
} }
#define XHDR(name_, value_) .buf = value_, .name_ptr = name_, .val_len = sizeof(value_) - 1, .name_len = sizeof(name_) - 1 #define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1,
/* This list is hardcoded to make the test deterministic */ /* This list is hardcoded to make the test deterministic */
static struct lsxpack_header header_arr[N_HEADERS] = static struct lsxpack_header header_arr[N_HEADERS] =

View file

@ -63,7 +63,7 @@ output_write (struct lsquic_stream *stream, struct lsquic_reader *reader)
#define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, } #define IOV(v) { .iov_base = (v), .iov_len = sizeof(v) - 1, }
#define XHDR(name_, value_) .buf = value_, .name_ptr = name_, .val_len = sizeof(value_) - 1, .name_len = sizeof(name_) - 1 #define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1,
static void static void
@ -162,6 +162,31 @@ test_one_header (void)
lsquic_mm_cleanup(&mm); lsquic_mm_cleanup(&mm);
} }
struct header_buf
{
unsigned off;
char buf[UINT16_MAX];
};
int
header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf,
const char *name, size_t name_len,
const char *val, size_t val_len)
{
if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf))
{
memcpy(header_buf->buf + header_buf->off, name, name_len);
memcpy(header_buf->buf + header_buf->off + name_len, val, val_len);
lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off,
0, name_len, name_len, val_len);
header_buf->off += name_len + val_len;
return 0;
}
else
return -1;
}
static void static void
test_oversize_header (void) test_oversize_header (void)
@ -172,6 +197,7 @@ test_oversize_header (void)
struct lsquic_mm mm; struct lsquic_mm mm;
const size_t big_len = LSXPACK_MAX_STRLEN - 20; const size_t big_len = LSXPACK_MAX_STRLEN - 20;
char *value; char *value;
struct header_buf hbuf;
lshpack_enc_init(&henc); lshpack_enc_init(&henc);
lsquic_mm_init(&mm); lsquic_mm_init(&mm);
@ -190,8 +216,9 @@ test_oversize_header (void)
{ {
{ XHDR(":status", "302") }, { XHDR(":status", "302") },
}; };
lsxpack_header_set_ptr(&header_arr[1], "some-header", 10, value, big_len); hbuf.off = 0;
lsxpack_header_set_ptr(&header_arr[2], "another-header", 10, value, big_len); header_set_ptr(&header_arr[1], &hbuf, "some-header", 10, value, big_len);
header_set_ptr(&header_arr[2], &hbuf, "another-header", 10, value, big_len);
struct lsquic_http_headers headers = { struct lsquic_http_headers headers = {
.count = sizeof(header_arr) / sizeof(header_arr[0]), .count = sizeof(header_arr) / sizeof(header_arr[0]),

View file

@ -59,7 +59,7 @@
#include "lsquic_hq.h" #include "lsquic_hq.h"
#include "lsquic_data_in_if.h" #include "lsquic_data_in_if.h"
static const struct parse_funcs *g_pf = select_pf_by_ver(LSQVER_ID25); static const struct parse_funcs *g_pf = select_pf_by_ver(LSQVER_ID27);
struct test_ctl_settings struct test_ctl_settings
{ {
@ -302,7 +302,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
memset(tobjs, 0, sizeof(*tobjs)); memset(tobjs, 0, sizeof(*tobjs));
LSCONN_INITIALIZE(&tobjs->lconn); LSCONN_INITIALIZE(&tobjs->lconn);
tobjs->lconn.cn_pf = g_pf; tobjs->lconn.cn_pf = g_pf;
tobjs->lconn.cn_version = LSQVER_ID25; tobjs->lconn.cn_version = LSQVER_ID27;
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1; tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
network_path.np_pack_size = packet_sz; network_path.np_pack_size = packet_sz;
tobjs->lconn.cn_if = &our_conn_if; tobjs->lconn.cn_if = &our_conn_if;
@ -493,6 +493,8 @@ static const struct lsquic_stream_if packetization_inside_many_stream_if = {
}; };
#define XHDR(name_, value_) .buf = name_ value_, .name_offset = 0, .name_len = sizeof(name_) - 1, .val_offset = sizeof(name_) - 1, .val_len = sizeof(value_) - 1,
static void static void
test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize, test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize,
int flush_after_each_write, size_t conn_limit, int flush_after_each_write, size_t conn_limit,
@ -509,8 +511,7 @@ test_hq_framing (int sched_immed, int dispatch_once, unsigned wsize,
* data-framing writer. This is simply so that we don't have to * data-framing writer. This is simply so that we don't have to
* expose more stream things only for testing. * expose more stream things only for testing.
*/ */
struct lsxpack_header header; struct lsxpack_header header = { XHDR(":method", "GET") };
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, }; struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz); buf_in = malloc(buf_in_sz);
@ -739,8 +740,7 @@ test_frame_header_split (unsigned n_packets, unsigned extra_sz,
const unsigned wsize = 70; const unsigned wsize = 70;
const size_t buf_in_sz = wsize, buf_out_sz = 0x500000; const size_t buf_in_sz = wsize, buf_out_sz = 0x500000;
struct lsxpack_header header; struct lsxpack_header header = { XHDR(":method", "GET") };
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, }; struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz); buf_in = malloc(buf_in_sz);
@ -855,8 +855,7 @@ test_zero_size_frame (void)
const unsigned wsize = 7000; const unsigned wsize = 7000;
const size_t buf_in_sz = wsize, buf_out_sz = 0x500000; const size_t buf_in_sz = wsize, buf_out_sz = 0x500000;
struct lsxpack_header header; struct lsxpack_header header = { XHDR(":method", "GET") };
lsxpack_header_set_ptr(&header, ":method", 7, "GET", 3);
struct lsquic_http_headers headers = { 1, &header, }; struct lsquic_http_headers headers = { 1, &header, };
buf_in = malloc(buf_in_sz); buf_in = malloc(buf_in_sz);

View file

@ -35,7 +35,7 @@ main (int argc, char **argv)
else else
nelems = 1000000; nelems = 1000000;
widgets = malloc(sizeof(widgets[0]) * nelems); widgets = calloc(nelems, sizeof(widgets[0]));
for (n = 0; n < nelems; ++n) for (n = 0; n < nelems; ++n)
{ {

View file

@ -6,7 +6,7 @@
#ifndef WIN32 #ifndef WIN32
#include <unistd.h> #include <unistd.h>
#else #else
#include <getopt.h> #include "getopt.h"
#endif #endif
#include "lsquic_malo.h" #include "lsquic_malo.h"

View file

@ -46,6 +46,9 @@ test_min_heap (void)
for (i = 0; i < MAX_ELEMS; ++i) for (i = 0; i < MAX_ELEMS; ++i)
lsquic_mh_insert(&heap, (void *) i, i); lsquic_mh_insert(&heap, (void *) i, i);
verify_min_heap(&heap); verify_min_heap(&heap);
#ifdef _MSC_VER
prev_val = 0;
#endif
for (i = 0; i < MAX_ELEMS; ++i) for (i = 0; i < MAX_ELEMS; ++i)
{ {
p = lsquic_mh_pop(&heap); p = lsquic_mh_pop(&heap);

View file

@ -2,7 +2,11 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#else
#include "getopt.h"
#endif
#include <openssl/rand.h> #include <openssl/rand.h>

View file

@ -38,7 +38,7 @@ main (void)
.sin_port = htons(443), .sin_port = htons(443),
.sin_addr = peer_addr, .sin_addr = peer_addr,
}; };
lsquic_cid_t cid = {}; lsquic_cid_t cid; memset(&cid, 0, sizeof(cid));
lsquic_qlog_create_connection(&cid, (const struct sockaddr *)&local, lsquic_qlog_create_connection(&cid, (const struct sockaddr *)&local,
(const struct sockaddr *)&peer); (const struct sockaddr *)&peer);

View file

@ -5,6 +5,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef WIN32
#include "vc_compat.h"
#endif
#include "lsquic_types.h" #include "lsquic_types.h"
#include "lsquic_int_types.h" #include "lsquic_int_types.h"
#include "lsquic_rechist.h" #include "lsquic_rechist.h"

View file

@ -161,8 +161,8 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
int s; int s;
memset(tobjs, 0, sizeof(*tobjs)); memset(tobjs, 0, sizeof(*tobjs));
LSCONN_INITIALIZE(&tobjs->lconn); LSCONN_INITIALIZE(&tobjs->lconn);
tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_ID25); tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_ID27);
tobjs->lconn.cn_version = LSQVER_ID25; tobjs->lconn.cn_version = LSQVER_ID27;
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1; tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
network_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ; network_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
tobjs->lconn.cn_if = &our_conn_if; tobjs->lconn.cn_if = &our_conn_if;

View file

@ -3,7 +3,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#else
#include "vc_compat.h"
#include <winbase.h>
#endif
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_stock_shi.h" #include "lsquic_stock_shi.h"
@ -85,7 +90,11 @@ test_shi (const struct order *order)
assert(0 == s); assert(0 == s);
} }
#ifndef WIN32
sleep(2); /* Let the thing expire */ sleep(2); /* Let the thing expire */
#else
Sleep(2000); /* Let the thing expire */
#endif
for (i = 0; i < N_PAIRS; ++i) for (i = 0; i < N_PAIRS; ++i)
{ {

View file

@ -325,7 +325,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
LSCONN_INITIALIZE(&tobjs->lconn); LSCONN_INITIALIZE(&tobjs->lconn);
tobjs->lconn.cn_pf = pf ? pf : g_pf; tobjs->lconn.cn_pf = pf ? pf : g_pf;
tobjs->lconn.cn_version = tobjs->lconn.cn_pf == &lsquic_parse_funcs_ietf_v1 ? tobjs->lconn.cn_version = tobjs->lconn.cn_pf == &lsquic_parse_funcs_ietf_v1 ?
LSQVER_ID25 : LSQVER_043; LSQVER_ID27 : LSQVER_043;
tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_gquic_1; tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_gquic_1;
network_path.np_pack_size = 1370; network_path.np_pack_size = 1370;
tobjs->lconn.cn_if = &our_conn_if; tobjs->lconn.cn_if = &our_conn_if;
@ -2243,7 +2243,7 @@ test_changing_pack_size (void)
enum lsquic_version versions_to_test[3] = enum lsquic_version versions_to_test[3] =
{ {
LSQVER_046, LSQVER_046,
LSQVER_ID25, LSQVER_ID27,
}; };
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
@ -3173,7 +3173,7 @@ main (int argc, char **argv)
/* Redo some tests using crypto streams and frames */ /* Redo some tests using crypto streams and frames */
g_use_crypto_ctor = 1; g_use_crypto_ctor = 1;
g_pf = select_pf_by_ver(LSQVER_ID25); g_pf = select_pf_by_ver(LSQVER_ID27);
main_test_packetization(); main_test_packetization();
return 0; return 0;

View file

@ -279,7 +279,7 @@ static const struct test tests[] = {
*/ */
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 0, 1, }, .fin = { 0, 1, },
.offset = 0x0807060504030201UL, .offset = 0x0807060504030201UL,
.stream_id = 0x210, .stream_id = 0x210,
@ -299,7 +299,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 0, 0, }, .fin = { 0, 0, },
.offset = 0, .offset = 0,
.stream_id = 0x210, .stream_id = 0x210,
@ -318,7 +318,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 0, 0, }, .fin = { 0, 0, },
.offset = 0, .offset = 0,
.stream_id = 0x21, .stream_id = 0x21,
@ -336,7 +336,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 0, 0, }, .fin = { 0, 0, },
.offset = 0x0807060504030201UL, .offset = 0x0807060504030201UL,
.stream_id = 0x210, .stream_id = 0x210,
@ -356,7 +356,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 1, 0, }, .fin = { 1, 0, },
.offset = 0x0807060504030201UL, .offset = 0x0807060504030201UL,
.stream_id = 0x210, .stream_id = 0x210,
@ -374,7 +374,7 @@ static const struct test tests[] = {
}, },
{ .lineno = __LINE__, { .lineno = __LINE__,
.pf = select_pf_by_ver(LSQVER_ID25), .pf = select_pf_by_ver(LSQVER_ID27),
.fin = { 1, 0, }, .fin = { 1, 0, },
.offset = 0x0807060504030201UL, .offset = 0x0807060504030201UL,
.stream_id = 0x210, .stream_id = 0x210,

View file

@ -243,7 +243,7 @@ static const struct test tests[] = {
{ "Balls to the wall: every possible bit is set", { "Balls to the wall: every possible bit is set",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 1<<0, { 0x10 | 1<<2 | 1<<1 | 1<<0,
0x41, 0x23, /* Stream ID */ 0x41, 0x23, /* Stream ID */
@ -262,7 +262,7 @@ static const struct test tests[] = {
{ "Balls to the wall #2: every possible bit is set except FIN", { "Balls to the wall #2: every possible bit is set except FIN",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 0<<0, { 0x10 | 1<<2 | 1<<1 | 0<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -281,7 +281,7 @@ static const struct test tests[] = {
{ "Data length is zero", { "Data length is zero",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 0<<1 | 0<<0, { 0x10 | 1<<2 | 0<<1 | 0<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -299,7 +299,7 @@ static const struct test tests[] = {
{ "Sanity check: what happens when data length is zero #1", { "Sanity check: what happens when data length is zero #1",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 0<<0, { 0x10 | 1<<2 | 1<<1 | 0<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -318,7 +318,7 @@ static const struct test tests[] = {
{ "Sanity check: what happens when data length is zero #2", { "Sanity check: what happens when data length is zero #2",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 0<<0, { 0x10 | 1<<2 | 1<<1 | 0<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -337,7 +337,7 @@ static const struct test tests[] = {
{ "Sanity check: what happens when data length is zero #3", { "Sanity check: what happens when data length is zero #3",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 0<<2 | 1<<1 | 0<<0, { 0x10 | 0<<2 | 1<<1 | 0<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -355,7 +355,7 @@ static const struct test tests[] = {
{ "Sanity check: what happens when data length is zero #3", { "Sanity check: what happens when data length is zero #3",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 1<<0, { 0x10 | 1<<2 | 1<<1 | 1<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -374,7 +374,7 @@ static const struct test tests[] = {
{ "Check data bounds #1", { "Check data bounds #1",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 1<<0, { 0x10 | 1<<2 | 1<<1 | 1<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */
@ -393,7 +393,7 @@ static const struct test tests[] = {
{ "Check data bounds #2", { "Check data bounds #2",
__LINE__, __LINE__,
select_pf_by_ver(LSQVER_ID25), select_pf_by_ver(LSQVER_ID27),
/* TYPE OFF DLEN FIN */ /* TYPE OFF DLEN FIN */
{ 0x10 | 1<<2 | 1<<1 | 1<<0, { 0x10 | 1<<2 | 1<<1 | 1<<0,
0x81, 0x23, 0x00, 0xE4, /* Stream ID */ 0x81, 0x23, 0x00, 0xE4, /* Stream ID */

View file

@ -10,7 +10,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef WIN32
#include <unistd.h> #include <unistd.h>
#else
#include "getopt.h"
#endif
#include "lsquic.h" #include "lsquic.h"
#include "lsquic_types.h" #include "lsquic_types.h"
@ -58,18 +62,20 @@ static const struct trapa_test tests[] =
| (1 << TPI_INIT_MAX_DATA) | (1 << TPI_INIT_MAX_DATA)
| (1 << TPI_MAX_IDLE_TIMEOUT) | (1 << TPI_MAX_IDLE_TIMEOUT)
| (1 << TPI_MAX_ACK_DELAY) | (1 << TPI_MAX_ACK_DELAY)
| (1 << TPI_MAX_PACKET_SIZE) | (1 << TPI_MAX_UDP_PAYLOAD_SIZE)
| (1 << TPI_ACK_DELAY_EXPONENT) | (1 << TPI_ACK_DELAY_EXPONENT)
| (1 << TPI_INITIAL_SOURCE_CID)
| (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT), | (1 << TPI_ACTIVE_CONNECTION_ID_LIMIT),
.tp_init_max_stream_data_bidi_local = 0x12348877, .tp_init_max_stream_data_bidi_local = 0x12348877,
.tp_init_max_data = 0xAABB, .tp_init_max_data = 0xAABB,
.tp_max_packet_size = 1213, .tp_max_udp_payload_size = 1213,
.tp_max_idle_timeout = 10 * 1000, .tp_max_idle_timeout = 10 * 1000,
.tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY, .tp_max_ack_delay = TP_DEF_MAX_ACK_DELAY,
.tp_active_connection_id_limit = 7, .tp_active_connection_id_limit = 7,
.tp_initial_source_cid = { .len = 8, .u_cid.id = 0x0807060504030201ull, },
}, },
.is_server = 0, .is_server = 0,
.enc_len = 26, .enc_len = 36,
.encoded = .encoded =
/* Idle timeout */ "\x01\x02\x67\x10" /* Idle timeout */ "\x01\x02\x67\x10"
/* Packet size */ "\x03\x02\x44\xBD" /* Packet size */ "\x03\x02\x44\xBD"
@ -77,6 +83,7 @@ static const struct trapa_test tests[] =
/* Bidi local */ "\x05\x04\x92\x34\x88\x77" /* Bidi local */ "\x05\x04\x92\x34\x88\x77"
/* Ack delay exp */ "\x0A\x01\x00" /* Ack delay exp */ "\x0A\x01\x00"
/* Active CID limit */ "\x0E\x01\x07" /* Active CID limit */ "\x0E\x01\x07"
/* Initial SCID */ "\x0F\x08\x01\x02\x03\x04\x05\x06\x07\x08"
/* Trailer to make the end easily visible in gdb: */ /* Trailer to make the end easily visible in gdb: */
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
}, },
@ -104,7 +111,7 @@ static const struct trapa_test tests[] =
TP_DEFAULT_VALUES, TP_DEFAULT_VALUES,
.tp_init_max_data = 0x123456, .tp_init_max_data = 0x123456,
.tp_init_max_stream_data_bidi_local = 0xABCDEF88, .tp_init_max_stream_data_bidi_local = 0xABCDEF88,
.tp_max_packet_size = 0x555, .tp_max_udp_payload_size = 0x555,
}, },
.is_server = 1, .is_server = 1,
.addl_set = 1 << TPI_DISABLE_ACTIVE_MIGRATION, .addl_set = 1 << TPI_DISABLE_ACTIVE_MIGRATION,
@ -125,7 +132,7 @@ static const struct trapa_test tests[] =
.params = { .params = {
TP_DEFAULT_VALUES, TP_DEFAULT_VALUES,
.tp_max_ack_delay = 25, .tp_max_ack_delay = 25,
.tp_max_packet_size = 0x555, .tp_max_udp_payload_size = 0x555,
.tp_preferred_address = { .tp_preferred_address = {
.ipv4_addr = "\x01\x02\x03\x04", .ipv4_addr = "\x01\x02\x03\x04",
.ipv4_port = 0x1234, .ipv4_port = 0x1234,
@ -172,8 +179,8 @@ params_are_equal (const struct transport_params *a,
&& a->tp_preferred_address.ipv4_port == b->tp_preferred_address.ipv4_port && a->tp_preferred_address.ipv4_port == b->tp_preferred_address.ipv4_port
&& a->tp_preferred_address.ipv6_port == b->tp_preferred_address.ipv6_port && a->tp_preferred_address.ipv6_port == b->tp_preferred_address.ipv6_port
&& a->tp_preferred_address.cid.len == b->tp_preferred_address.cid.len && a->tp_preferred_address.cid.len == b->tp_preferred_address.cid.len
&& MCMP(tp_original_cid.idbuf) && MCMP(tp_original_dest_cid.idbuf)
&& a->tp_original_cid.len == b->tp_original_cid.len && a->tp_original_dest_cid.len == b->tp_original_dest_cid.len
; ;
#undef MCMP #undef MCMP
} }

View file

@ -1,3 +1,4 @@
# Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE.
- only debug and release are expected in the Cmakelists.txt. If you need a different config, please follow the model in that file to add it. - only debug and release are expected in the Cmakelists.txt. If you need a different config, please follow the model in that file to add it.
- vcpkg does not have boringssl, so you'll have to build it yourself. Follow the instructions at the boringssl repository. - vcpkg does not have boringssl, so you'll have to build it yourself. Follow the instructions at the boringssl repository.

View file

@ -1,3 +1,4 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
/* Getopt for GNU. /* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu

View file

@ -1,3 +1,4 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
/* Declarations for getopt. /* Declarations for getopt.
Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.

View file

@ -1,3 +1,4 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
/* getopt_long and getopt_long_only entry points for GNU getopt. /* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
Free Software Foundation, Inc. Free Software Foundation, Inc.

View file

@ -1,3 +1,4 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
/*- /*-
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
* *

View file

@ -1,3 +1,4 @@
/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */
#pragma once #pragma once
#include <Windows.h> #include <Windows.h>
#include <winsock2.h> #include <winsock2.h>
@ -7,7 +8,9 @@ struct iovec {
size_t iov_len; /* Number of bytes to transfer */ size_t iov_len; /* Number of bytes to transfer */
}; };
#define strcasecmp(a,b) _strcmpi(a,b) #define strcasecmp(a,b) _strcmpi(a,b)
#define strncasecmp _strnicmp
#define strdup _strdup #define strdup _strdup
#define PATH_MAX MAX_PATH
#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) #define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno)