mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
Release 1.19.0
- [FEATURE, API Change] 0-RTT support. Add function to export 0-RTT information; it can be supplied to a subsequent connect() call. - [FEATURE] Add -0 flag to http_client to exercise 0-RTT support. - [BUGFIX] Resuscitate the Windows build. - [BUGFIX] Send HTTP settings (max header list size) if necessary. - [BUGFIX] Buffered packets can contain ACK frames. - [BUGFIX] Make packet writeable once all STREAM frames are elided. - [BUGFIX] Fix potential null dereference when realloc fails. - cmake: simplify build configuration.
This commit is contained in:
parent
03fb93526e
commit
8ca33e0e19
21 changed files with 631 additions and 381 deletions
12
CHANGELOG
12
CHANGELOG
|
@ -1,3 +1,15 @@
|
|||
2019-02-04
|
||||
- 1.19.0
|
||||
- [FEATURE, API Change] 0-RTT support. Add function to export 0-RTT
|
||||
information; it can be supplied to a subsequent connect() call.
|
||||
- [FEATURE] Add -0 flag to http_client to exercise 0-RTT support.
|
||||
- [BUGFIX] Resuscitate the Windows build.
|
||||
- [BUGFIX] Send HTTP settings (max header list size) if necessary.
|
||||
- [BUGFIX] Buffered packets can contain ACK frames.
|
||||
- [BUGFIX] Make packet writeable once all STREAM frames are elided.
|
||||
- [BUGFIX] Fix potential null dereference when realloc fails.
|
||||
- cmake: simplify build configuration.
|
||||
|
||||
2019-01-28
|
||||
- 1.18.0
|
||||
- [API Change] Can specify clock granularity in engine settings.
|
||||
|
|
|
@ -81,42 +81,74 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MY_CMAKE_FLAGS} $ENV{EXTRA_CFLAGS}")
|
|||
|
||||
MESSAGE(STATUS "Compiler flags: ${CMAKE_C_FLAGS}")
|
||||
|
||||
# This must be done before adding other include directories to take
|
||||
# precedence over header files from other SSL installs.
|
||||
FIND_PATH(BORINGSSL_INCLUDE_DIR NAMES openssl/ssl.h
|
||||
IF (NOT DEFINED BORINGSSL_INCLUDE AND DEFINED BORINGSSL_DIR)
|
||||
FIND_PATH(BORINGSSL_INCLUDE NAMES openssl/ssl.h
|
||||
PATHS ${BORINGSSL_DIR}/include
|
||||
NO_DEFAULT_PATH)
|
||||
IF (BORINGSSL_INCLUDE_DIR)
|
||||
MESSAGE(STATUS "BoringSSL include directory ${BORINGSSL_INCLUDE_DIR}")
|
||||
INCLUDE_DIRECTORIES(${BORINGSSL_INCLUDE_DIR})
|
||||
ENDIF()
|
||||
# This must be done before adding other include directories to take
|
||||
# precedence over header files from other SSL installs.
|
||||
|
||||
IF (BORINGSSL_INCLUDE)
|
||||
MESSAGE(STATUS "BoringSSL include directory ${BORINGSSL_INCLUDE}")
|
||||
INCLUDE_DIRECTORIES(${BORINGSSL_INCLUDE})
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "BoringSSL headers not found")
|
||||
ENDIF()
|
||||
|
||||
FOREACH(BORINGSSL_LIB ssl crypto decrepit)
|
||||
IF (NOT DEFINED BORINGSSL_LIB AND DEFINED BORINGSSL_DIR)
|
||||
FOREACH(LIB_NAME ssl crypto decrepit)
|
||||
IF (CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${BORINGSSL_LIB}
|
||||
NAMES ${BORINGSSL_LIB}
|
||||
PATHS ${BORINGSSL_DIR}/${BORINGSSL_LIB}
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
|
||||
NAMES ${LIB_NAME}
|
||||
PATHS ${BORINGSSL_DIR}/${LIB_NAME}
|
||||
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
|
||||
NO_DEFAULT_PATH)
|
||||
ELSE()
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${BORINGSSL_LIB}
|
||||
NAMES lib${BORINGSSL_LIB}.a
|
||||
PATHS ${BORINGSSL_DIR}/${BORINGSSL_LIB}
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
|
||||
NAMES lib${LIB_NAME}.a
|
||||
PATHS ${BORINGSSL_DIR}/${LIB_NAME}
|
||||
NO_DEFAULT_PATH)
|
||||
ENDIF()
|
||||
IF(BORINGSSL_LIB_${BORINGSSL_LIB})
|
||||
MESSAGE(STATUS "Found ${BORINGSSL_LIB} library: ${BORINGSSL_LIB_${BORINGSSL_LIB}}")
|
||||
IF(BORINGSSL_LIB_${LIB_NAME})
|
||||
MESSAGE(STATUS "Found ${LIB_NAME} library: ${BORINGSSL_LIB_${LIB_NAME}}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "${LIB_NAME} library not found")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
|
||||
ELSE()
|
||||
|
||||
|
||||
FOREACH(LIB_NAME ssl crypto decrepit)
|
||||
IF (CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
|
||||
NAMES ${LIB_NAME}
|
||||
PATHS ${BORINGSSL_LIB}
|
||||
PATH_SUFFIXES Debug Release MinSizeRel RelWithDebInfo
|
||||
NO_DEFAULT_PATH)
|
||||
ELSE()
|
||||
FIND_LIBRARY(BORINGSSL_LIB_${LIB_NAME}
|
||||
NAMES lib${LIB_NAME}.a
|
||||
PATHS ${BORINGSSL_LIB}
|
||||
NO_DEFAULT_PATH)
|
||||
ENDIF()
|
||||
IF(BORINGSSL_LIB_${LIB_NAME})
|
||||
MESSAGE(STATUS "Found ${BORINGSSL_LIB} library: ${BORINGSSL_LIB_${LIB_NAME}}")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "${BORINGSSL_LIB} library not found")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ENDFOREACH()
|
||||
#endif
|
||||
|
||||
ENDIF()
|
||||
|
||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
INCLUDE_DIRECTORIES(include src/lshpack)
|
||||
IF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
# Find libevent on FreeBSD:
|
||||
INCLUDE_DIRECTORIES( /usr/local/include )
|
||||
LINK_DIRECTORIES( /usr/local/lib )
|
||||
include_directories( /usr/local/include )
|
||||
link_directories( /usr/local/lib )
|
||||
ENDIF()
|
||||
|
||||
# Find zlib and libevent header files and library files
|
||||
|
@ -157,8 +189,8 @@ ELSE()
|
|||
MESSAGE(STATUS "libevent not found")
|
||||
ENDIF()
|
||||
|
||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories( include src/lshpack)
|
||||
|
||||
SET(LIBS lsquic ${EVENT_LIB} ${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${ZLIB_LIB} ${LIBS})
|
||||
|
||||
IF (NOT MSVC)
|
||||
add_executable(http_client
|
||||
|
@ -166,8 +198,7 @@ add_executable(http_client
|
|||
test/prog.c
|
||||
test/test_common.c
|
||||
)
|
||||
TARGET_LINK_LIBRARIES(http_client lsquic ${EVENT_LIB} pthread
|
||||
${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${LIBS} ${ZLIB_LIB} m)
|
||||
LIST(APPEND LIBS pthread m)
|
||||
|
||||
#MSVC
|
||||
ELSE()
|
||||
|
@ -178,19 +209,12 @@ add_executable(http_client
|
|||
wincompat/getopt.c
|
||||
wincompat/getopt1.c
|
||||
)
|
||||
|
||||
target_link_libraries(http_client
|
||||
lsquic
|
||||
${EVENT_LIB}
|
||||
${ZLIB_LIB}
|
||||
${BORINGSSL_LIB_ssl}
|
||||
${BORINGSSL_LIB_crypto}
|
||||
ws2_32
|
||||
${LIBS} )
|
||||
LIST(APPEND LIBS ws2_32)
|
||||
|
||||
ENDIF()
|
||||
|
||||
#target_link_libraries(http_client lsquic event pthread libssl.a libcrypto.a ${LIBS} z m)
|
||||
TARGET_LINK_LIBRARIES(http_client ${LIBS})
|
||||
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define LSQUIC_MAJOR_VERSION 1
|
||||
#define LSQUIC_MINOR_VERSION 18
|
||||
#define LSQUIC_MINOR_VERSION 19
|
||||
#define LSQUIC_PATCH_VERSION 0
|
||||
|
||||
/**
|
||||
|
@ -137,6 +137,22 @@ enum lsquic_version
|
|||
*/
|
||||
#define LSQUIC_FORCED_TCID0_VERSIONS (1 << LSQVER_044)
|
||||
|
||||
enum lsquic_hsk_status
|
||||
{
|
||||
/**
|
||||
* The handshake failed.
|
||||
*/
|
||||
LSQ_HSK_FAIL,
|
||||
/**
|
||||
* The handshake succeeded without 0-RTT.
|
||||
*/
|
||||
LSQ_HSK_OK,
|
||||
/**
|
||||
* The handshake succeeded with 0-RTT.
|
||||
*/
|
||||
LSQ_HSK_0RTT_OK,
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct lsquic_stream_if
|
||||
* @brief The definition of callback functions call by lsquic_stream to
|
||||
|
@ -178,7 +194,7 @@ struct lsquic_stream_if {
|
|||
*
|
||||
* This callback is optional.
|
||||
*/
|
||||
void (*on_hsk_done)(lsquic_conn_t *c, int ok);
|
||||
void (*on_hsk_done)(lsquic_conn_t *c, enum lsquic_hsk_status s);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -650,7 +666,8 @@ lsquic_conn_t *
|
|||
lsquic_engine_connect (lsquic_engine_t *, const struct sockaddr *local_sa,
|
||||
const struct sockaddr *peer_sa,
|
||||
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||
const char *hostname, unsigned short max_packet_size);
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
|
||||
/**
|
||||
* Pass incoming packet to the QUIC engine. This function can be called
|
||||
|
@ -835,6 +852,14 @@ int lsquic_stream_close(lsquic_stream_t *s);
|
|||
struct stack_st_X509 *
|
||||
lsquic_conn_get_server_cert_chain (lsquic_conn_t *);
|
||||
|
||||
/**
|
||||
* Get server config zero_rtt from the encryption session.
|
||||
* Returns the number of bytes written to the zero_rtt.
|
||||
*/
|
||||
ssize_t
|
||||
lsquic_conn_get_zero_rtt(const lsquic_conn_t *,
|
||||
unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
|
||||
/** Returns ID of the stream */
|
||||
uint32_t
|
||||
lsquic_stream_id (const lsquic_stream_t *s);
|
||||
|
|
|
@ -47,6 +47,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
struct client_hsk_ctx *const c_hsk = (struct client_hsk_ctx *) sh;
|
||||
ssize_t nread;
|
||||
int s;
|
||||
enum lsquic_hsk_status status;
|
||||
|
||||
if (!c_hsk->buf_in)
|
||||
{
|
||||
|
@ -95,7 +96,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
lsquic_mm_put_16k(c_hsk->mm, c_hsk->buf_in);
|
||||
c_hsk->buf_in = NULL;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
c_hsk->lconn->cn_if->ci_handshake_failed(c_hsk->lconn);
|
||||
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
|
||||
lsquic_conn_close(c_hsk->lconn);
|
||||
}
|
||||
break;
|
||||
|
@ -106,7 +107,9 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
if (c_hsk->lconn->cn_esf->esf_is_hsk_done(c_hsk->lconn->cn_enc_session))
|
||||
{
|
||||
LSQ_DEBUG("handshake is successful, inform connection");
|
||||
c_hsk->lconn->cn_if->ci_handshake_ok(c_hsk->lconn);
|
||||
status = (c_hsk->lconn->cn_esf->esf_did_zero_rtt_succeed(
|
||||
c_hsk->lconn->cn_enc_session)) ? LSQ_HSK_0RTT_OK : LSQ_HSK_OK;
|
||||
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, status);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -122,7 +125,7 @@ hsk_client_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *sh)
|
|||
LSQ_INFO("lsquic_enc_session_handle_chlo_reply returned an error");
|
||||
c_hsk->buf_in = NULL;
|
||||
lsquic_stream_wantread(stream, 0);
|
||||
c_hsk->lconn->cn_if->ci_handshake_failed(c_hsk->lconn);
|
||||
c_hsk->lconn->cn_if->ci_hsk_done(c_hsk->lconn, LSQ_HSK_FAIL);
|
||||
lsquic_conn_close(c_hsk->lconn);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -150,3 +150,16 @@ lsquic_conn_get_server_cert_chain (struct lsquic_conn *lconn)
|
|||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
lsquic_conn_get_zero_rtt(const lsquic_conn_t *lconn,
|
||||
unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
ssize_t ret = -1;
|
||||
if (lconn->cn_enc_session && (lconn->cn_flags & LSCONN_VER_SET))
|
||||
ret = lconn->cn_esf->esf_get_zero_rtt(lconn->cn_enc_session,
|
||||
lconn->cn_version,
|
||||
zero_rtt, zero_rtt_len);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -73,10 +73,7 @@ struct conn_iface
|
|||
(*ci_packet_not_sent) (struct lsquic_conn *, struct lsquic_packet_out *);
|
||||
|
||||
void
|
||||
(*ci_handshake_ok) (struct lsquic_conn *);
|
||||
|
||||
void
|
||||
(*ci_handshake_failed) (struct lsquic_conn *);
|
||||
(*ci_hsk_done) (struct lsquic_conn *, enum lsquic_hsk_status);
|
||||
|
||||
void
|
||||
(*ci_destroy) (struct lsquic_conn *);
|
||||
|
|
|
@ -453,7 +453,8 @@ maybe_grow_conn_heaps (struct lsquic_engine *engine)
|
|||
|
||||
static lsquic_conn_t *
|
||||
new_full_conn_client (lsquic_engine_t *engine, const char *hostname,
|
||||
unsigned short max_packet_size)
|
||||
unsigned short max_packet_size, const unsigned char *zero_rtt,
|
||||
size_t zero_rtt_len)
|
||||
{
|
||||
lsquic_conn_t *conn;
|
||||
unsigned flags;
|
||||
|
@ -461,7 +462,8 @@ new_full_conn_client (lsquic_engine_t *engine, const char *hostname,
|
|||
return NULL;
|
||||
flags = engine->flags & (ENG_SERVER|ENG_HTTP);
|
||||
conn = full_conn_client_new(&engine->pub, engine->stream_if,
|
||||
engine->stream_if_ctx, flags, hostname, max_packet_size);
|
||||
engine->stream_if_ctx, flags, hostname,
|
||||
max_packet_size, zero_rtt, zero_rtt_len);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
++engine->n_conns;
|
||||
|
@ -662,7 +664,8 @@ lsquic_conn_t *
|
|||
lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *local_sa,
|
||||
const struct sockaddr *peer_sa,
|
||||
void *peer_ctx, lsquic_conn_ctx_t *conn_ctx,
|
||||
const char *hostname, unsigned short max_packet_size)
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
lsquic_conn_t *conn;
|
||||
ENGINE_IN(engine);
|
||||
|
@ -693,7 +696,8 @@ lsquic_engine_connect (lsquic_engine_t *engine, const struct sockaddr *local_sa,
|
|||
}
|
||||
}
|
||||
|
||||
conn = new_full_conn_client(engine, hostname, max_packet_size);
|
||||
conn = new_full_conn_client(engine, hostname, max_packet_size,
|
||||
zero_rtt, zero_rtt_len);
|
||||
if (!conn)
|
||||
goto err;
|
||||
lsquic_conn_record_sockaddr(conn, local_sa, peer_sa);
|
||||
|
|
|
@ -418,14 +418,16 @@ check_headers_size (const struct lsquic_frame_writer *fw,
|
|||
headers_sz = calc_headers_size(headers);
|
||||
if (extra_headers)
|
||||
headers_sz += calc_headers_size(extra_headers);
|
||||
if (headers_sz > fw->fw_max_header_list_sz)
|
||||
|
||||
if (headers_sz <= fw->fw_max_header_list_sz)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
LSQ_INFO("Headers size %u is larger than max allowed (%u)",
|
||||
headers_sz, fw->fw_max_header_list_sz);
|
||||
errno = EMSGSIZE;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -435,7 +435,6 @@ send_smhl (const struct full_conn *conn)
|
|||
{
|
||||
uint32_t smhl;
|
||||
return conn->fc_conn.cn_enc_session
|
||||
&& (conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
&& 0 == conn->fc_conn.cn_esf->esf_get_peer_setting(
|
||||
conn->fc_conn.cn_enc_session, QTAG_SMHL, &smhl)
|
||||
&& 1 == smhl;
|
||||
|
@ -509,8 +508,6 @@ apply_peer_settings (struct full_conn *conn)
|
|||
LSQ_DEBUG("peer settings: CFCW: %u; SFCW: %u; MIDS: %u",
|
||||
cfcw, sfcw, mids);
|
||||
conn_on_peer_config(conn, cfcw, sfcw, mids);
|
||||
if (conn->fc_flags & FC_HTTP)
|
||||
maybe_send_settings(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -640,7 +637,8 @@ struct lsquic_conn *
|
|||
full_conn_client_new (struct lsquic_engine_public *enpub,
|
||||
const struct lsquic_stream_if *stream_if,
|
||||
void *stream_if_ctx, unsigned flags,
|
||||
const char *hostname, unsigned short max_packet_size)
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
struct full_conn *conn;
|
||||
enum lsquic_version version;
|
||||
|
@ -656,7 +654,8 @@ full_conn_client_new (struct lsquic_engine_public *enpub,
|
|||
return NULL;
|
||||
conn->fc_conn.cn_esf = esf;
|
||||
conn->fc_conn.cn_enc_session =
|
||||
conn->fc_conn.cn_esf->esf_create_client(hostname, cid, conn->fc_enpub);
|
||||
conn->fc_conn.cn_esf->esf_create_client(hostname, cid, conn->fc_enpub,
|
||||
zero_rtt, zero_rtt_len);
|
||||
if (!conn->fc_conn.cn_enc_session)
|
||||
{
|
||||
LSQ_WARN("could not create enc session: %s", strerror(errno));
|
||||
|
@ -2985,7 +2984,9 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
|
|||
}
|
||||
|
||||
lsquic_send_ctl_set_buffer_stream_packets(&conn->fc_send_ctl, 0);
|
||||
if (!(conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE))
|
||||
if (!(conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE) &&
|
||||
!conn->fc_conn.cn_esf->esf_is_zero_rtt_enabled(
|
||||
conn->fc_conn.cn_enc_session))
|
||||
{
|
||||
process_hsk_stream_write_events(conn);
|
||||
goto end_write;
|
||||
|
@ -3145,29 +3146,30 @@ full_conn_ci_packet_not_sent (lsquic_conn_t *lconn, lsquic_packet_out_t *packet_
|
|||
|
||||
|
||||
static void
|
||||
full_conn_ci_handshake_ok (lsquic_conn_t *lconn)
|
||||
full_conn_ci_hsk_done (lsquic_conn_t *lconn, enum lsquic_hsk_status status)
|
||||
{
|
||||
struct full_conn *conn = (struct full_conn *) lconn;
|
||||
LSQ_DEBUG("handshake reportedly done");
|
||||
lsquic_alarmset_unset(&conn->fc_alset, AL_HANDSHAKE);
|
||||
switch (status)
|
||||
{
|
||||
case LSQ_HSK_FAIL:
|
||||
conn->fc_flags |= FC_HSK_FAILED;
|
||||
break;
|
||||
case LSQ_HSK_OK:
|
||||
case LSQ_HSK_0RTT_OK:
|
||||
if (0 == apply_peer_settings(conn))
|
||||
{
|
||||
if (conn->fc_flags & FC_HTTP)
|
||||
maybe_send_settings(conn);
|
||||
lconn->cn_flags |= LSCONN_HANDSHAKE_DONE;
|
||||
}
|
||||
else
|
||||
conn->fc_flags |= FC_ERROR;
|
||||
break;
|
||||
}
|
||||
if (conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done)
|
||||
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done(lconn, 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
full_conn_ci_handshake_failed (lsquic_conn_t *lconn)
|
||||
{
|
||||
struct full_conn *conn = (struct full_conn *) lconn;
|
||||
LSQ_DEBUG("handshake failed");
|
||||
lsquic_alarmset_unset(&conn->fc_alset, AL_HANDSHAKE);
|
||||
conn->fc_flags |= FC_HSK_FAILED;
|
||||
if (conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done)
|
||||
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done(lconn, 0);
|
||||
conn->fc_stream_ifs[STREAM_IF_STD].stream_if->on_hsk_done(lconn,
|
||||
status);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3539,7 +3541,9 @@ full_conn_ci_is_tickable (lsquic_conn_t *lconn)
|
|||
return 1;
|
||||
if (!TAILQ_EMPTY(&conn->fc_pub.sending_streams))
|
||||
return 1;
|
||||
if (conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE)
|
||||
if ((conn->fc_conn.cn_flags & LSCONN_HANDSHAKE_DONE) ||
|
||||
conn->fc_conn.cn_esf->esf_is_zero_rtt_enabled(
|
||||
conn->fc_conn.cn_enc_session))
|
||||
{
|
||||
TAILQ_FOREACH(stream, &conn->fc_pub.write_streams,
|
||||
next_write_stream)
|
||||
|
@ -3617,8 +3621,7 @@ static const struct conn_iface full_conn_iface = {
|
|||
#if LSQUIC_CONN_STATS
|
||||
.ci_get_stats = full_conn_ci_get_stats,
|
||||
#endif
|
||||
.ci_handshake_failed = full_conn_ci_handshake_failed,
|
||||
.ci_handshake_ok = full_conn_ci_handshake_ok,
|
||||
.ci_hsk_done = full_conn_ci_hsk_done,
|
||||
.ci_is_tickable = full_conn_ci_is_tickable,
|
||||
.ci_next_packet_to_send = full_conn_ci_next_packet_to_send,
|
||||
.ci_next_tick_time = full_conn_ci_next_tick_time,
|
||||
|
|
|
@ -11,7 +11,8 @@ full_conn_client_new (struct lsquic_engine_public *,
|
|||
const struct lsquic_stream_if *,
|
||||
void *stream_if_ctx,
|
||||
unsigned flags /* Only FC_SERVER and FC_HTTP */,
|
||||
const char *hostname, unsigned short max_packet_size);
|
||||
const char *hostname, unsigned short max_packet_size,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len);
|
||||
|
||||
void
|
||||
full_conn_client_call_on_new (struct lsquic_conn *);
|
||||
|
|
|
@ -115,6 +115,9 @@ typedef struct hs_ctx_st
|
|||
struct lsquic_enc_session
|
||||
{
|
||||
enum handshake_state hsk_state;
|
||||
enum {
|
||||
ES_RECV_REJ = 1 << 2,
|
||||
} es_flags;
|
||||
|
||||
uint8_t have_key; /* 0, no 1, I, 2, D, 3, F */
|
||||
uint8_t peer_have_final_key;
|
||||
|
@ -138,6 +141,7 @@ struct lsquic_enc_session
|
|||
|
||||
hs_ctx_t hs_ctx;
|
||||
lsquic_session_cache_info_t *info;
|
||||
c_cert_item_t *cert_item;
|
||||
SSL_CTX * ssl_ctx;
|
||||
const struct lsquic_engine_public *enpub;
|
||||
struct lsquic_str * cert_ptr; /* pointer to the leaf cert of the server, not real copy */
|
||||
|
@ -152,29 +156,10 @@ struct lsquic_enc_session
|
|||
};
|
||||
|
||||
|
||||
/***
|
||||
* client side, it will store the domain/certs as cache cert
|
||||
*/
|
||||
static struct lsquic_hash *s_cached_client_certs;
|
||||
|
||||
/**
|
||||
* client side will save the session_info for next time 0rtt
|
||||
*/
|
||||
static struct lsquic_hash *s_cached_client_session_infos;
|
||||
|
||||
/* save to hash table */
|
||||
static lsquic_session_cache_info_t *retrieve_session_info_entry(const char *key);
|
||||
static void remove_expire_session_info_entry();
|
||||
static void remove_session_info_entry(struct lsquic_str *key);
|
||||
|
||||
static void free_info (lsquic_session_cache_info_t *);
|
||||
|
||||
|
||||
/* client */
|
||||
static cert_hash_item_t *make_cert_hash_item(struct lsquic_str *domain, struct lsquic_str **certs, int count);
|
||||
static int c_insert_certs(cert_hash_item_t *item);
|
||||
static void c_erase_certs(struct lsquic_hash_elem *el);
|
||||
static void c_free_cert_hash_item (cert_hash_item_t *item);
|
||||
static c_cert_item_t *make_c_cert_item(struct lsquic_str **certs, int count);
|
||||
static void free_c_cert_item(c_cert_item_t *item);
|
||||
|
||||
static int get_tag_val_u32 (unsigned char *v, int len, uint32_t *val);
|
||||
static int init_hs_hash_tables(int flags);
|
||||
|
@ -207,42 +192,9 @@ lsquic_handshake_init(int flags)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
cleanup_hs_hash_tables (void)
|
||||
{
|
||||
struct lsquic_hash_elem *el;
|
||||
|
||||
if (s_cached_client_session_infos)
|
||||
{
|
||||
for (el = lsquic_hash_first(s_cached_client_session_infos); el;
|
||||
el = lsquic_hash_next(s_cached_client_session_infos))
|
||||
{
|
||||
lsquic_session_cache_info_t *entry = lsquic_hashelem_getdata(el);
|
||||
free_info(entry);
|
||||
}
|
||||
lsquic_hash_destroy(s_cached_client_session_infos);
|
||||
s_cached_client_session_infos = NULL;
|
||||
}
|
||||
|
||||
if (s_cached_client_certs)
|
||||
{
|
||||
for (el = lsquic_hash_first(s_cached_client_certs); el;
|
||||
el = lsquic_hash_next(s_cached_client_certs))
|
||||
{
|
||||
cert_hash_item_t *item = lsquic_hashelem_getdata(el);
|
||||
c_free_cert_hash_item(item);
|
||||
}
|
||||
lsquic_hash_destroy(s_cached_client_certs);
|
||||
s_cached_client_certs = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lsquic_handshake_cleanup (void)
|
||||
{
|
||||
cleanup_hs_hash_tables();
|
||||
lsquic_crt_cleanup();
|
||||
}
|
||||
|
||||
|
@ -250,63 +202,26 @@ lsquic_handshake_cleanup (void)
|
|||
/* return -1 for fail, 0 OK*/
|
||||
static int init_hs_hash_tables(int flags)
|
||||
{
|
||||
if (flags & LSQUIC_GLOBAL_CLIENT)
|
||||
{
|
||||
s_cached_client_session_infos = lsquic_hash_create();
|
||||
if (!s_cached_client_session_infos)
|
||||
return -1;
|
||||
|
||||
s_cached_client_certs = lsquic_hash_create();
|
||||
if (!s_cached_client_certs)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* client */
|
||||
struct lsquic_hash_elem *
|
||||
c_get_certs_elem (const lsquic_str_t *domain)
|
||||
{
|
||||
if (!s_cached_client_certs)
|
||||
return NULL;
|
||||
|
||||
return lsquic_hash_find(s_cached_client_certs, lsquic_str_cstr(domain),
|
||||
lsquic_str_len(domain));
|
||||
}
|
||||
|
||||
|
||||
/* client */
|
||||
cert_hash_item_t *
|
||||
c_find_certs (const lsquic_str_t *domain)
|
||||
{
|
||||
struct lsquic_hash_elem *el = c_get_certs_elem(domain);
|
||||
|
||||
if (el == NULL)
|
||||
return NULL;
|
||||
|
||||
return lsquic_hashelem_getdata(el);
|
||||
}
|
||||
|
||||
|
||||
/* client */
|
||||
/* certs is an array of lsquic_str_t * */
|
||||
static cert_hash_item_t *
|
||||
make_cert_hash_item (lsquic_str_t *domain, lsquic_str_t **certs, int count)
|
||||
static c_cert_item_t *
|
||||
make_c_cert_item (lsquic_str_t **certs, int count)
|
||||
{
|
||||
int i;
|
||||
uint64_t hash;
|
||||
cert_hash_item_t *item = (cert_hash_item_t *)malloc(sizeof(cert_hash_item_t));
|
||||
c_cert_item_t *item = (c_cert_item_t *)malloc(sizeof(c_cert_item_t));
|
||||
item->crts = (lsquic_str_t *)malloc(count * sizeof(lsquic_str_t));
|
||||
item->domain = lsquic_str_new(NULL, 0);
|
||||
item->hashs = lsquic_str_new(NULL, 0);
|
||||
lsquic_str_copy(item->domain, domain);
|
||||
item->count = count;
|
||||
for(i=0; i<count; ++i)
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
lsquic_str_copy(&item->crts[i], certs[i]);
|
||||
hash = fnv1a_64((const uint8_t *)lsquic_str_cstr(certs[i]), lsquic_str_len(certs[i]));
|
||||
hash = fnv1a_64((const uint8_t *)lsquic_str_cstr(certs[i]),
|
||||
lsquic_str_len(certs[i]));
|
||||
lsquic_str_append(item->hashs, (char *)&hash, 8);
|
||||
}
|
||||
return item;
|
||||
|
@ -315,13 +230,12 @@ make_cert_hash_item (lsquic_str_t *domain, lsquic_str_t **certs, int count)
|
|||
|
||||
/* client */
|
||||
static void
|
||||
c_free_cert_hash_item (cert_hash_item_t *item)
|
||||
free_c_cert_item (c_cert_item_t *item)
|
||||
{
|
||||
int i;
|
||||
if (item)
|
||||
{
|
||||
lsquic_str_delete(item->hashs);
|
||||
lsquic_str_delete(item->domain);
|
||||
for(i=0; i<item->count; ++i)
|
||||
lsquic_str_d(&item->crts[i]);
|
||||
free(item->crts);
|
||||
|
@ -330,112 +244,134 @@ c_free_cert_hash_item (cert_hash_item_t *item)
|
|||
}
|
||||
|
||||
|
||||
/* client */
|
||||
static int
|
||||
c_insert_certs (cert_hash_item_t *item)
|
||||
enum rtt_deserialize_return_type
|
||||
{
|
||||
if (lsquic_hash_insert(s_cached_client_certs,
|
||||
lsquic_str_cstr(item->domain),
|
||||
lsquic_str_len(item->domain), item) == NULL)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
RTT_DESERIALIZE_OK = 0,
|
||||
RTT_DESERIALIZE_BAD_QUIC_VER = 1,
|
||||
RTT_DESERIALIZE_BAD_SERIAL_VER = 2,
|
||||
RTT_DESERIALIZE_BAD_CERT_SIZE = 3,
|
||||
};
|
||||
|
||||
#define RTT_SERIALIZER_VERSION (1 << 0)
|
||||
|
||||
/* client */
|
||||
static void
|
||||
c_erase_certs (struct lsquic_hash_elem *el)
|
||||
lsquic_enc_session_serialize_zero_rtt(struct lsquic_zero_rtt_storage *storage,
|
||||
enum lsquic_version version,
|
||||
const lsquic_session_cache_info_t *info,
|
||||
const c_cert_item_t *cert_item)
|
||||
{
|
||||
if (s_cached_client_certs && el)
|
||||
lsquic_hash_erase(s_cached_client_certs, el);
|
||||
}
|
||||
|
||||
|
||||
static int save_session_info_entry(lsquic_str_t *key, lsquic_session_cache_info_t *entry)
|
||||
{
|
||||
lsquic_str_setto(&entry->sni_key, lsquic_str_cstr(key), lsquic_str_len(key));
|
||||
if (lsquic_hash_insert(s_cached_client_session_infos,
|
||||
lsquic_str_cstr(&entry->sni_key),
|
||||
lsquic_str_len(&entry->sni_key), entry) == NULL)
|
||||
uint32_t i;
|
||||
uint8_t *next_cert;
|
||||
struct lsquic_cert_storage *cert_storage;
|
||||
/*
|
||||
* assign versions
|
||||
*/
|
||||
storage->quic_version_tag = lsquic_ver2tag(version);
|
||||
storage->serializer_version = RTT_SERIALIZER_VERSION;
|
||||
/*
|
||||
* server config
|
||||
*/
|
||||
storage->ver = info->ver;
|
||||
storage->aead = info->aead;
|
||||
storage->kexs = info->kexs;
|
||||
storage->pdmd = info->pdmd;
|
||||
storage->orbt = info->orbt;
|
||||
storage->expy = info->expy;
|
||||
storage->sstk_len = lsquic_str_len(&info->sstk);
|
||||
storage->scfg_len = lsquic_str_len(&info->scfg);
|
||||
storage->scfg_flag = info->scfg_flag;
|
||||
memcpy(storage->sstk, lsquic_str_buf(&info->sstk), storage->sstk_len);
|
||||
memcpy(storage->scfg, lsquic_str_buf(&info->scfg), storage->scfg_len);
|
||||
memcpy(storage->sscid, &info->sscid, SCID_LENGTH);
|
||||
memcpy(storage->spubs, &info->spubs, MAX_SPUBS_LENGTH);
|
||||
/*
|
||||
* certificate chain
|
||||
*/
|
||||
storage->cert_count = (uint32_t)cert_item->count;
|
||||
next_cert = (uint8_t *)&storage->cert_storage;
|
||||
for (i = 0; i < storage->cert_count; i++)
|
||||
{
|
||||
lsquic_str_d(&entry->sni_key);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* If entry updated and need to remove cached entry */
|
||||
static void
|
||||
remove_session_info_entry (lsquic_str_t *key)
|
||||
{
|
||||
lsquic_session_cache_info_t *entry;
|
||||
struct lsquic_hash_elem *el;
|
||||
el = lsquic_hash_find(s_cached_client_session_infos,
|
||||
lsquic_str_cstr(key), lsquic_str_len(key));
|
||||
if (el)
|
||||
{
|
||||
entry = lsquic_hashelem_getdata(el);
|
||||
lsquic_str_d(&entry->sni_key);
|
||||
lsquic_hash_erase(s_cached_client_session_infos, el);
|
||||
cert_storage = (struct lsquic_cert_storage *)next_cert;
|
||||
cert_storage->len = lsquic_str_len(&cert_item->crts[i]);
|
||||
memcpy(cert_storage->data, lsquic_str_buf(&cert_item->crts[i]),
|
||||
cert_storage->len);
|
||||
next_cert += sizeof(struct lsquic_cert_storage) + cert_storage->len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* client */
|
||||
static lsquic_session_cache_info_t *
|
||||
retrieve_session_info_entry (const char *key)
|
||||
#define CHECK_SPACE(need, start, end) \
|
||||
do { if ((intptr_t) (need) > ( (intptr_t) (end) - (intptr_t) (start))) \
|
||||
{ return RTT_DESERIALIZE_BAD_CERT_SIZE; } \
|
||||
} while (0) \
|
||||
|
||||
static enum rtt_deserialize_return_type
|
||||
lsquic_enc_session_deserialize_zero_rtt(
|
||||
const struct lsquic_zero_rtt_storage *storage,
|
||||
size_t storage_size,
|
||||
const struct lsquic_engine_settings *settings,
|
||||
lsquic_session_cache_info_t *info,
|
||||
c_cert_item_t *cert_item)
|
||||
{
|
||||
lsquic_session_cache_info_t *entry;
|
||||
struct lsquic_hash_elem *el;
|
||||
|
||||
if (!s_cached_client_session_infos)
|
||||
return NULL;
|
||||
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
el = lsquic_hash_find(s_cached_client_session_infos, key, strlen(key));
|
||||
if (el == NULL)
|
||||
return NULL;
|
||||
|
||||
entry = lsquic_hashelem_getdata(el);
|
||||
LSQ_DEBUG("[QUIC]retrieve_session_info_entry find cached session info %p.\n", entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
/* call it in timer() */
|
||||
#if __GNUC__
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static void
|
||||
remove_expire_session_info_entry (void)
|
||||
{
|
||||
time_t tm = time(NULL);
|
||||
struct lsquic_hash_elem *el;
|
||||
|
||||
for (el = lsquic_hash_first(s_cached_client_session_infos); el;
|
||||
el = lsquic_hash_next(s_cached_client_session_infos))
|
||||
uint32_t i, len;
|
||||
uint64_t hash;
|
||||
uint8_t *next_cert;
|
||||
struct lsquic_cert_storage *cert_storage;
|
||||
void *storage_end = (uint8_t *)storage + storage_size;
|
||||
/*
|
||||
* check versions
|
||||
*/
|
||||
if (lsquic_tag2ver(storage->quic_version_tag) & ~settings->es_versions)
|
||||
return RTT_DESERIALIZE_BAD_QUIC_VER;
|
||||
if (storage->serializer_version != RTT_SERIALIZER_VERSION)
|
||||
return RTT_DESERIALIZE_BAD_SERIAL_VER;
|
||||
/*
|
||||
* server config
|
||||
*/
|
||||
info->ver = storage->ver;
|
||||
info->aead = storage->aead;
|
||||
info->kexs = storage->kexs;
|
||||
info->pdmd = storage->pdmd;
|
||||
info->orbt = storage->orbt;
|
||||
info->expy = storage->expy;
|
||||
info->scfg_flag = storage->scfg_flag;
|
||||
lsquic_str_setto(&info->sstk, storage->sstk, storage->sstk_len);
|
||||
lsquic_str_setto(&info->scfg, storage->scfg, storage->scfg_len);
|
||||
memcpy(&info->sscid, storage->sscid, SCID_LENGTH);
|
||||
memcpy(&info->spubs, storage->spubs, MAX_SPUBS_LENGTH);
|
||||
/*
|
||||
* certificate chain
|
||||
*/
|
||||
cert_item->count = storage->cert_count;
|
||||
cert_item->crts = malloc(cert_item->count * sizeof(lsquic_str_t));
|
||||
cert_item->hashs = lsquic_str_new(NULL, 0);
|
||||
next_cert = (uint8_t *)storage->cert_storage;
|
||||
for (i = 0; i < storage->cert_count; i++)
|
||||
{
|
||||
lsquic_session_cache_info_t *entry = lsquic_hashelem_getdata(el);
|
||||
if ((uint64_t)tm > entry->expy)
|
||||
{
|
||||
free_info(entry);
|
||||
lsquic_hash_erase(s_cached_client_session_infos, el);
|
||||
}
|
||||
CHECK_SPACE(sizeof(struct lsquic_cert_storage), next_cert, storage_end);
|
||||
cert_storage = (struct lsquic_cert_storage *)next_cert;
|
||||
memcpy(&len, cert_storage, sizeof(len));
|
||||
CHECK_SPACE(len, cert_storage->data, storage_end);
|
||||
lsquic_str_prealloc(&cert_item->crts[i], len);
|
||||
lsquic_str_setlen(&cert_item->crts[i], len);
|
||||
memcpy(lsquic_str_buf(&cert_item->crts[i]), cert_storage->data, len);
|
||||
hash = fnv1a_64((const uint8_t *)cert_storage->data, len);
|
||||
lsquic_str_append(cert_item->hashs, (char *)&hash, 8);
|
||||
next_cert += sizeof(struct lsquic_cert_storage) + len;
|
||||
}
|
||||
return RTT_DESERIALIZE_OK;
|
||||
}
|
||||
|
||||
|
||||
static lsquic_enc_session_t *
|
||||
lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *enpub)
|
||||
const struct lsquic_engine_public *enpub,
|
||||
const unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
lsquic_session_cache_info_t *info;
|
||||
lsquic_enc_session_t *enc_session;
|
||||
c_cert_item_t *item;
|
||||
const struct lsquic_zero_rtt_storage *zero_rtt_storage;
|
||||
|
||||
if (!domain)
|
||||
{
|
||||
|
@ -447,19 +383,47 @@ lsquic_enc_session_create_client (const char *domain, lsquic_cid_t cid,
|
|||
if (!enc_session)
|
||||
return NULL;
|
||||
|
||||
info = retrieve_session_info_entry(domain);
|
||||
if (info)
|
||||
memcpy(enc_session->hs_ctx.pubs, info->spubs, 32);
|
||||
else
|
||||
{
|
||||
/* have to allocate every time */
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (!info)
|
||||
{
|
||||
free(enc_session);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (zero_rtt && zero_rtt_len > sizeof(struct lsquic_zero_rtt_storage))
|
||||
{
|
||||
item = calloc(1, sizeof(*item));
|
||||
if (!item)
|
||||
{
|
||||
free(enc_session);
|
||||
free(info);
|
||||
return NULL;
|
||||
}
|
||||
zero_rtt_storage = (const struct lsquic_zero_rtt_storage *)zero_rtt;
|
||||
switch (lsquic_enc_session_deserialize_zero_rtt(zero_rtt_storage,
|
||||
zero_rtt_len,
|
||||
&enpub->enp_settings,
|
||||
info, item))
|
||||
{
|
||||
case RTT_DESERIALIZE_BAD_QUIC_VER:
|
||||
LSQ_ERROR("provided zero_rtt has unsupported QUIC version");
|
||||
free(item);
|
||||
break;
|
||||
case RTT_DESERIALIZE_BAD_SERIAL_VER:
|
||||
LSQ_ERROR("provided zero_rtt has bad serializer version");
|
||||
free(item);
|
||||
break;
|
||||
case RTT_DESERIALIZE_BAD_CERT_SIZE:
|
||||
LSQ_ERROR("provided zero_rtt has bad cert size");
|
||||
free(item);
|
||||
break;
|
||||
case RTT_DESERIALIZE_OK:
|
||||
memcpy(enc_session->hs_ctx.pubs, info->spubs, 32);
|
||||
enc_session->cert_item = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
enc_session->enpub = enpub;
|
||||
enc_session->cid = cid;
|
||||
enc_session->info = info;
|
||||
|
@ -507,21 +471,23 @@ lsquic_enc_session_destroy (lsquic_enc_session_t *enc_session)
|
|||
EVP_AEAD_CTX_cleanup(enc_session->enc_ctx_f);
|
||||
free(enc_session->enc_ctx_f);
|
||||
}
|
||||
if (enc_session->info)
|
||||
{
|
||||
lsquic_str_d(&enc_session->info->sstk);
|
||||
lsquic_str_d(&enc_session->info->scfg);
|
||||
lsquic_str_d(&enc_session->info->sni_key);
|
||||
free(enc_session->info);
|
||||
}
|
||||
if (enc_session->cert_item)
|
||||
{
|
||||
free_c_cert_item(enc_session->cert_item);
|
||||
enc_session->cert_item = NULL;
|
||||
}
|
||||
free(enc_session);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_info (lsquic_session_cache_info_t *info)
|
||||
{
|
||||
lsquic_str_d(&info->sstk);
|
||||
lsquic_str_d(&info->scfg);
|
||||
lsquic_str_d(&info->sni_key);
|
||||
free(info);
|
||||
}
|
||||
|
||||
|
||||
static int get_hs_state(lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return enc_session->hsk_state;
|
||||
|
@ -663,8 +629,6 @@ static int parse_hs_data (lsquic_enc_session_t *enc_session, uint32_t tag,
|
|||
break;
|
||||
|
||||
case QTAG_STK:
|
||||
if (lsquic_str_len(&enc_session->info->sstk) > 0)
|
||||
remove_session_info_entry(&enc_session->info->sstk);
|
||||
lsquic_str_setto(&enc_session->info->sstk, val, len);
|
||||
ESHIST_APPEND(enc_session, ESHE_SET_STK);
|
||||
break;
|
||||
|
@ -952,8 +916,7 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
|||
const lsquic_str_t *const ccs = get_common_certs_hash();
|
||||
const struct lsquic_engine_settings *const settings =
|
||||
&enc_session->enpub->enp_settings;
|
||||
cert_hash_item_t *const cached_certs_item =
|
||||
c_find_certs(&enc_session->hs_ctx.sni);
|
||||
c_cert_item_t *const cert_item = enc_session->cert_item;
|
||||
unsigned char pub_key[32];
|
||||
size_t ua_len;
|
||||
uint32_t opts[1]; /* Only NSTP is supported for now */
|
||||
|
@ -1006,10 +969,10 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
|||
MSG_LEN_ADD(msg_len, lsquic_str_len(&enc_session->hs_ctx.sni));
|
||||
++n_tags; /* SNI */
|
||||
MSG_LEN_ADD(msg_len, lsquic_str_len(ccs)); ++n_tags; /* CCS */
|
||||
if (cached_certs_item)
|
||||
if (cert_item)
|
||||
{
|
||||
enc_session->cert_ptr = &cached_certs_item->crts[0];
|
||||
MSG_LEN_ADD(msg_len, lsquic_str_len(cached_certs_item->hashs));
|
||||
enc_session->cert_ptr = &cert_item->crts[0];
|
||||
MSG_LEN_ADD(msg_len, lsquic_str_len(cert_item->hashs));
|
||||
++n_tags; /* CCRT */
|
||||
MSG_LEN_ADD(msg_len, 8); ++n_tags; /* XLCT */
|
||||
}
|
||||
|
@ -1083,14 +1046,14 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
|
|||
MW_WRITE_UINT32(&mw, QTAG_MIDS, settings->es_max_streams_in);
|
||||
MW_WRITE_UINT32(&mw, QTAG_SCLS, settings->es_silent_close);
|
||||
MW_WRITE_UINT32(&mw, QTAG_KEXS, settings->es_kexs);
|
||||
if (cached_certs_item)
|
||||
MW_WRITE_BUFFER(&mw, QTAG_XLCT, lsquic_str_buf(cached_certs_item->hashs), 8);
|
||||
if (cert_item)
|
||||
MW_WRITE_BUFFER(&mw, QTAG_XLCT, lsquic_str_buf(cert_item->hashs), 8);
|
||||
/* CSCT is empty on purpose (retained from original code) */
|
||||
MW_WRITE_TABLE_ENTRY(&mw, QTAG_CSCT, 0);
|
||||
if (n_opts > 0)
|
||||
MW_WRITE_BUFFER(&mw, QTAG_COPT, opts, n_opts * sizeof(opts[0]));
|
||||
if (cached_certs_item)
|
||||
MW_WRITE_LS_STR(&mw, QTAG_CCRT, cached_certs_item->hashs);
|
||||
if (cert_item)
|
||||
MW_WRITE_LS_STR(&mw, QTAG_CCRT, cert_item->hashs);
|
||||
MW_WRITE_UINT32(&mw, QTAG_CFCW, settings->es_cfcw);
|
||||
MW_WRITE_UINT32(&mw, QTAG_SFCW, settings->es_sfcw);
|
||||
MW_END(&mw);
|
||||
|
@ -1337,16 +1300,16 @@ static int determine_keys(lsquic_enc_session_t *enc_session)
|
|||
|
||||
|
||||
/* 0 Match */
|
||||
static int cached_certs_match(cert_hash_item_t *cached_certs_item, lsquic_str_t **certs,
|
||||
int certs_count)
|
||||
static int cached_certs_match(c_cert_item_t *item,
|
||||
lsquic_str_t **certs, int count)
|
||||
{
|
||||
int i;
|
||||
if (!cached_certs_item || cached_certs_item->count != certs_count)
|
||||
if (!item || item->count != count)
|
||||
return -1;
|
||||
|
||||
for (i=0; i<certs_count; ++i)
|
||||
for (i=0; i<count; ++i)
|
||||
{
|
||||
if (lsquic_str_bcmp(certs[i], &cached_certs_item->crts[i]) != 0)
|
||||
if (lsquic_str_bcmp(certs[i], &item->crts[i]) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1383,12 +1346,7 @@ lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
|||
uint32_t head_tag;
|
||||
int ret;
|
||||
lsquic_session_cache_info_t *info = enc_session->info;
|
||||
hs_ctx_t * hs_ctx = &enc_session->hs_ctx;
|
||||
cert_hash_item_t *cached_certs_item = NULL;
|
||||
struct lsquic_hash_elem *el = c_get_certs_elem(&hs_ctx->sni);
|
||||
|
||||
if (el)
|
||||
cached_certs_item = lsquic_hashelem_getdata(el);
|
||||
c_cert_item_t *cert_item = enc_session->cert_item;
|
||||
|
||||
/* FIXME get the number first */
|
||||
lsquic_str_t **out_certs = NULL;
|
||||
|
@ -1407,7 +1365,10 @@ lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
|||
}
|
||||
|
||||
if (head_tag == QTAG_SREJ || head_tag == QTAG_REJ)
|
||||
{
|
||||
enc_session->hsk_state = HSK_CHLO_REJ;
|
||||
enc_session->es_flags |= ES_RECV_REJ;
|
||||
}
|
||||
else if(head_tag == QTAG_SHLO)
|
||||
{
|
||||
enc_session->hsk_state = HSK_COMPLETED;
|
||||
|
@ -1428,7 +1389,7 @@ lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
|||
out_certs_count = get_certs_count(&enc_session->hs_ctx.crt);
|
||||
if (out_certs_count > 0)
|
||||
{
|
||||
out_certs = (lsquic_str_t **)malloc(out_certs_count * sizeof(lsquic_str_t *));
|
||||
out_certs = malloc(out_certs_count * sizeof(lsquic_str_t *));
|
||||
if (!out_certs)
|
||||
{
|
||||
ret = -1;
|
||||
|
@ -1440,30 +1401,22 @@ lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
|||
|
||||
ret = handle_chlo_reply_verify_prof(enc_session, out_certs,
|
||||
&out_certs_count,
|
||||
(cached_certs_item ? cached_certs_item->crts : NULL),
|
||||
(cached_certs_item ? cached_certs_item->count : 0));
|
||||
(cert_item ? cert_item->crts : NULL),
|
||||
(cert_item ? cert_item->count : 0));
|
||||
if (ret == 0)
|
||||
{
|
||||
if (out_certs_count > 0)
|
||||
{
|
||||
if (cached_certs_item &&
|
||||
cached_certs_match(cached_certs_item, out_certs, out_certs_count) == 0)
|
||||
;
|
||||
else
|
||||
if (cached_certs_match(cert_item, out_certs,
|
||||
out_certs_count) != 0)
|
||||
{
|
||||
if (el)
|
||||
c_erase_certs(el);
|
||||
if (cached_certs_item)
|
||||
c_free_cert_hash_item(cached_certs_item);
|
||||
|
||||
cached_certs_item = make_cert_hash_item(&hs_ctx->sni,
|
||||
out_certs, out_certs_count);
|
||||
c_insert_certs(cached_certs_item);
|
||||
}
|
||||
enc_session->cert_ptr = &cached_certs_item->crts[0];
|
||||
cert_item = make_c_cert_item(out_certs,
|
||||
out_certs_count);
|
||||
enc_session->cert_item = cert_item;
|
||||
enc_session->cert_ptr = &cert_item->crts[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<out_certs_count; ++i)
|
||||
lsquic_str_delete(out_certs[i]);
|
||||
free(out_certs);
|
||||
|
@ -1476,8 +1429,6 @@ lsquic_enc_session_handle_chlo_reply (lsquic_enc_session_t *enc_session,
|
|||
|
||||
if (enc_session->hsk_state == HSK_COMPLETED)
|
||||
{
|
||||
if (!lsquic_str_buf(&info->sni_key))
|
||||
save_session_info_entry(&enc_session->hs_ctx.sni, info);
|
||||
ret = determine_keys(enc_session
|
||||
); /* FIXME: check ret */
|
||||
enc_session->have_key = 3;
|
||||
|
@ -1894,15 +1845,36 @@ lsquic_enc_session_verify_reset_token (lsquic_enc_session_t *enc_session,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
lsquic_enc_session_did_zero_rtt_succeed (const lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return !(enc_session->es_flags & ES_RECV_REJ);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lsquic_enc_session_is_zero_rtt_enabled (const lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return enc_session->info && enc_session->cert_item;
|
||||
}
|
||||
|
||||
|
||||
static c_cert_item_t *
|
||||
lsquic_enc_session_get_cert_item (const lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
return enc_session->cert_item;
|
||||
}
|
||||
|
||||
|
||||
static STACK_OF(X509) *
|
||||
lsquic_enc_session_get_server_cert_chain (lsquic_enc_session_t *enc_session)
|
||||
{
|
||||
const struct cert_hash_item_st *item;
|
||||
const struct c_cert_item_st *item;
|
||||
STACK_OF(X509) *chain;
|
||||
X509 *cert;
|
||||
int i;
|
||||
|
||||
item = c_find_certs(&enc_session->hs_ctx.sni);
|
||||
item = enc_session->cert_item;
|
||||
if (!item)
|
||||
{
|
||||
LSQ_WARN("could not find certificates for `%.*s'",
|
||||
|
@ -1929,6 +1901,37 @@ lsquic_enc_session_get_server_cert_chain (lsquic_enc_session_t *enc_session)
|
|||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
lsquic_enc_session_get_zero_rtt (lsquic_enc_session_t *enc_session,
|
||||
enum lsquic_version version,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
size_t sz = 0;
|
||||
if (!enc_session->info || !enc_session->cert_item)
|
||||
{
|
||||
LSQ_DEBUG("client asked for rtt_into but it is not available");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < enc_session->cert_item->count; ++i)
|
||||
{
|
||||
sz += sizeof(struct lsquic_cert_storage);
|
||||
sz += lsquic_str_len(&enc_session->cert_item->crts[i]);
|
||||
}
|
||||
sz += sizeof(struct lsquic_zero_rtt_storage);
|
||||
if (len < sz)
|
||||
{
|
||||
LSQ_DEBUG("client provided buf is too small %lu < %lu", len, sz);
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
lsquic_enc_session_serialize_zero_rtt((struct lsquic_zero_rtt_storage *)buf,
|
||||
version, enc_session->info,
|
||||
enc_session->cert_item);
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
const
|
||||
#endif
|
||||
|
@ -1951,7 +1954,11 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 =
|
|||
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
|
||||
.esf_mem_used = lsquic_enc_session_mem_used,
|
||||
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
|
||||
.esf_did_zero_rtt_succeed = lsquic_enc_session_did_zero_rtt_succeed,
|
||||
.esf_is_zero_rtt_enabled = lsquic_enc_session_is_zero_rtt_enabled,
|
||||
.esf_get_cert_item = lsquic_enc_session_get_cert_item,
|
||||
.esf_get_server_cert_chain = lsquic_enc_session_get_server_cert_chain,
|
||||
.esf_get_zero_rtt = lsquic_enc_session_get_zero_rtt,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ struct stack_st_X509;
|
|||
|
||||
typedef struct lsquic_enc_session lsquic_enc_session_t;
|
||||
|
||||
#define MAX_SCFG_LENGTH 512
|
||||
#define MAX_SPUBS_LENGTH 32
|
||||
#define STK_LENGTH 60
|
||||
#define SNO_LENGTH 56
|
||||
#define SCID_LENGTH 16
|
||||
|
@ -37,6 +39,14 @@ enum enc_level
|
|||
|
||||
extern const char *const lsquic_enclev2str[];
|
||||
|
||||
/* client */
|
||||
typedef struct c_cert_item_st
|
||||
{
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
int count;
|
||||
} c_cert_item_t;
|
||||
|
||||
/* client side need to store 0rtt info per STK */
|
||||
typedef struct lsquic_session_cache_info_st
|
||||
{
|
||||
|
@ -55,6 +65,33 @@ typedef struct lsquic_session_cache_info_st
|
|||
|
||||
} lsquic_session_cache_info_t;
|
||||
|
||||
struct lsquic_cert_storage
|
||||
{
|
||||
uint32_t len;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct lsquic_zero_rtt_storage
|
||||
{
|
||||
uint32_t quic_version_tag;
|
||||
uint32_t serializer_version;
|
||||
uint32_t ver;
|
||||
uint32_t aead;
|
||||
uint32_t kexs;
|
||||
uint32_t pdmd;
|
||||
uint64_t orbt;
|
||||
uint64_t expy;
|
||||
uint64_t sstk_len;
|
||||
uint64_t scfg_len;
|
||||
uint64_t scfg_flag;
|
||||
uint8_t sstk[STK_LENGTH];
|
||||
uint8_t scfg[MAX_SCFG_LENGTH];
|
||||
uint8_t sscid[SCID_LENGTH];
|
||||
uint8_t spubs[MAX_SPUBS_LENGTH];
|
||||
uint32_t cert_count;
|
||||
struct lsquic_cert_storage cert_storage[0];
|
||||
};
|
||||
|
||||
#ifndef LSQUIC_KEEP_ENC_SESS_HISTORY
|
||||
# ifndef NDEBUG
|
||||
# define LSQUIC_KEEP_ENC_SESS_HISTORY 1
|
||||
|
@ -120,7 +157,8 @@ struct enc_session_funcs
|
|||
/* Create client session */
|
||||
lsquic_enc_session_t *
|
||||
(*esf_create_client) (const char *domain, lsquic_cid_t cid,
|
||||
const struct lsquic_engine_public *);
|
||||
const struct lsquic_engine_public *,
|
||||
const unsigned char *, size_t);
|
||||
|
||||
/* Generate connection ID */
|
||||
lsquic_cid_t (*esf_generate_cid) (void);
|
||||
|
@ -141,8 +179,21 @@ struct enc_session_funcs
|
|||
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
|
||||
size_t);
|
||||
|
||||
int
|
||||
(*esf_did_zero_rtt_succeed) (const lsquic_enc_session_t *);
|
||||
|
||||
int
|
||||
(*esf_is_zero_rtt_enabled) (const lsquic_enc_session_t *);
|
||||
|
||||
c_cert_item_t *
|
||||
(*esf_get_cert_item) (const lsquic_enc_session_t *);
|
||||
|
||||
struct stack_st_X509 *
|
||||
(*esf_get_server_cert_chain) (lsquic_enc_session_t *);
|
||||
|
||||
ssize_t
|
||||
(*esf_get_zero_rtt) (lsquic_enc_session_t *, enum lsquic_version,
|
||||
void *, size_t);
|
||||
};
|
||||
|
||||
extern
|
||||
|
@ -154,14 +205,4 @@ struct enc_session_funcs lsquic_enc_session_gquic_1;
|
|||
#define select_esf_by_ver(ver) \
|
||||
(ver ? &lsquic_enc_session_gquic_1 : &lsquic_enc_session_gquic_1)
|
||||
|
||||
/* client side, certs and hashs
|
||||
*/
|
||||
typedef struct cert_hash_item_st
|
||||
{
|
||||
struct lsquic_str* domain; /*with port, such as "xyz.com:8088" as the key */
|
||||
struct lsquic_str* crts;
|
||||
struct lsquic_str* hashs;
|
||||
int count;
|
||||
} cert_hash_item_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -323,7 +323,10 @@ lsquic_packet_out_elide_reset_stream_frames (lsquic_packet_out_t *packet_out,
|
|||
|
||||
assert(n_stream_frames);
|
||||
if (n_elided == n_stream_frames)
|
||||
{
|
||||
packet_out->po_frame_types &= ~(1 << QUIC_FRAME_STREAM);
|
||||
packet_out->po_flags &= ~PO_STREAM_END;
|
||||
}
|
||||
|
||||
return adj;
|
||||
}
|
||||
|
|
|
@ -674,8 +674,6 @@ lsquic_send_ctl_got_ack (lsquic_send_ctl_t *ctl,
|
|||
const struct ack_info *acki,
|
||||
lsquic_time_t ack_recv_time)
|
||||
{
|
||||
struct lsquic_packets_tailq acked_acks =
|
||||
TAILQ_HEAD_INITIALIZER(acked_acks);
|
||||
const struct lsquic_packno_range *range =
|
||||
&acki->ranges[ acki->n_ranges - 1 ];
|
||||
lsquic_packet_out_t *packet_out, *next;
|
||||
|
@ -1401,7 +1399,8 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
|||
packet_out; packet_out = next)
|
||||
{
|
||||
next = TAILQ_NEXT(packet_out, po_next);
|
||||
assert(packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM));
|
||||
if (packet_out->po_frame_types & (1 << QUIC_FRAME_STREAM))
|
||||
{
|
||||
lsquic_packet_out_elide_reset_stream_frames(packet_out, stream_id);
|
||||
if (0 == packet_out->po_frame_types)
|
||||
{
|
||||
|
@ -1416,6 +1415,7 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1687,7 +1687,6 @@ send_ctl_get_buffered_packet (lsquic_send_ctl_t *ctl,
|
|||
if (packet_q->bpq_count >= send_ctl_max_bpq_count(ctl, packet_type))
|
||||
return NULL;
|
||||
|
||||
bits = lsquic_send_ctl_guess_packno_bits(ctl);
|
||||
if (packet_q->bpq_count == 0)
|
||||
{
|
||||
/* If ACK was written to the low-priority queue first, steal it */
|
||||
|
|
|
@ -109,7 +109,7 @@ find_and_set_lowest_priority (struct stream_prio_iter *iter)
|
|||
if (iter->spi_set[ set ])
|
||||
break;
|
||||
|
||||
if (set == 4)
|
||||
if (set >= 4)
|
||||
{
|
||||
//SPI_DEBUG("%s: cannot find any", __func__);
|
||||
return -1;
|
||||
|
|
|
@ -5860,7 +5860,7 @@ henc_huffman_enc (const unsigned char *src, const unsigned char *const src_end,
|
|||
bits_left -= cur_enc_code.bits;
|
||||
while (bits_left <= 32)
|
||||
{
|
||||
*p_dst++ = bits >> 32;
|
||||
*p_dst++ = (unsigned char) (bits >> 32);
|
||||
bits <<= 8;
|
||||
bits_left += 8;
|
||||
if (p_dst == dst_end)
|
||||
|
@ -5872,7 +5872,7 @@ henc_huffman_enc (const unsigned char *src, const unsigned char *const src_end,
|
|||
{
|
||||
assert(bits_left < 40 && bits_left > 0);
|
||||
bits |= ((uint64_t)1 << bits_left) - 1;
|
||||
*p_dst++ = bits >> 32;
|
||||
*p_dst++ = (unsigned char) (bits >> 32);
|
||||
}
|
||||
|
||||
return p_dst - dst;
|
||||
|
@ -5925,7 +5925,7 @@ lshpack_enc_enc_str (unsigned char *const dst, size_t dst_len,
|
|||
{
|
||||
if (str_len < 127)
|
||||
{
|
||||
*dst = str_len;
|
||||
*dst = (unsigned char) str_len;
|
||||
memcpy(dst + 1, str, str_len);
|
||||
return 1 + str_len;
|
||||
}
|
||||
|
|
|
@ -174,9 +174,16 @@ struct http_client_ctx {
|
|||
unsigned hcc_cc_reqs_per_conn;
|
||||
unsigned hcc_n_open_conns;
|
||||
|
||||
unsigned char *hcc_zero_rtt;
|
||||
size_t hcc_zero_rtt_len;
|
||||
size_t hcc_zero_rtt_max_len;
|
||||
FILE *hcc_zero_rtt_file;
|
||||
char *hcc_zero_rtt_file_name;
|
||||
|
||||
enum {
|
||||
HCC_SEEN_FIN = (1 << 1),
|
||||
HCC_ABORT_ON_INCOMPLETE = (1 << 2),
|
||||
HCC_RTT_INFO = (1 << 3),
|
||||
} hcc_flags;
|
||||
struct prog *prog;
|
||||
};
|
||||
|
@ -218,9 +225,18 @@ display_cert_chain (lsquic_conn_t *);
|
|||
static void
|
||||
create_connections (struct http_client_ctx *client_ctx)
|
||||
{
|
||||
unsigned char *zero_rtt = NULL;
|
||||
size_t zero_rtt_len = 0;
|
||||
if (client_ctx->hcc_flags & HCC_RTT_INFO)
|
||||
{
|
||||
zero_rtt = client_ctx->hcc_zero_rtt;
|
||||
zero_rtt_len = client_ctx->hcc_zero_rtt_len;
|
||||
LSQ_INFO("create connection zero_rtt %ld bytes", zero_rtt_len);
|
||||
}
|
||||
|
||||
while (client_ctx->hcc_n_open_conns < client_ctx->hcc_concurrency &&
|
||||
client_ctx->hcc_total_n_reqs > 0)
|
||||
if (0 != prog_connect(client_ctx->prog))
|
||||
if (0 != prog_connect(client_ctx->prog, zero_rtt, zero_rtt_len))
|
||||
{
|
||||
LSQ_ERROR("connection failed");
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -330,15 +346,74 @@ http_client_on_conn_closed (lsquic_conn_t *conn)
|
|||
|
||||
|
||||
static void
|
||||
http_client_on_hsk_done (lsquic_conn_t *conn, int ok)
|
||||
http_client_on_hsk_done (lsquic_conn_t *conn, enum lsquic_hsk_status status)
|
||||
{
|
||||
lsquic_conn_ctx_t *conn_h;
|
||||
LSQ_INFO("handshake %s", ok ? "completed successfully" : "failed");
|
||||
lsquic_conn_ctx_t *conn_ctx = lsquic_conn_get_ctx(conn);
|
||||
struct http_client_ctx *client_ctx = conn_ctx->client_ctx;
|
||||
ssize_t ret;
|
||||
if (status == LSQ_HSK_FAIL)
|
||||
LSQ_INFO("handshake failed");
|
||||
else
|
||||
LSQ_INFO("handshake success %s",
|
||||
status == LSQ_HSK_0RTT_OK ? "with 0-RTT" : "");
|
||||
if (!(client_ctx->hcc_flags & HCC_RTT_INFO) ||
|
||||
((client_ctx->hcc_flags & HCC_RTT_INFO) && status != LSQ_HSK_0RTT_OK))
|
||||
{
|
||||
ret = lsquic_conn_get_zero_rtt(conn, client_ctx->hcc_zero_rtt,
|
||||
client_ctx->hcc_zero_rtt_max_len);
|
||||
if (ret > 0)
|
||||
{
|
||||
client_ctx->hcc_zero_rtt_len = ret;
|
||||
LSQ_INFO("get zero_rtt %ld bytes", client_ctx->hcc_zero_rtt_len);
|
||||
client_ctx->hcc_flags |= HCC_RTT_INFO;
|
||||
/* clear file and prepare to write */
|
||||
if (client_ctx->hcc_zero_rtt_file)
|
||||
{
|
||||
client_ctx->hcc_zero_rtt_file = freopen(
|
||||
client_ctx->hcc_zero_rtt_file_name,
|
||||
"wb", client_ctx->hcc_zero_rtt_file);
|
||||
LSQ_DEBUG("reopen and clear zero_rtt file");
|
||||
}
|
||||
/* open file for the first time */
|
||||
if (client_ctx->hcc_zero_rtt_file_name &&
|
||||
!client_ctx->hcc_zero_rtt_file)
|
||||
{
|
||||
client_ctx->hcc_zero_rtt_file = fopen(
|
||||
client_ctx->hcc_zero_rtt_file_name, "wb+");
|
||||
if (client_ctx->hcc_zero_rtt_file)
|
||||
LSQ_DEBUG("opened zero_rtt file");
|
||||
else
|
||||
LSQ_DEBUG("zero_rtt file cannot be created");
|
||||
}
|
||||
/* write to file */
|
||||
if (client_ctx->hcc_zero_rtt_file)
|
||||
{
|
||||
size_t ret2 = fwrite(client_ctx->hcc_zero_rtt, 1,
|
||||
client_ctx->hcc_zero_rtt_len,
|
||||
client_ctx->hcc_zero_rtt_file);
|
||||
LSQ_DEBUG("wrote %ld bytes to zero_rtt file", ret2);
|
||||
if (ret2 == client_ctx->hcc_zero_rtt_len)
|
||||
{
|
||||
fclose(client_ctx->hcc_zero_rtt_file);
|
||||
client_ctx->hcc_zero_rtt_file = NULL;
|
||||
LSQ_DEBUG("close zero_rtt file");
|
||||
}
|
||||
else
|
||||
LSQ_ERROR("did not write full blob to zero_rtt file");
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
LSQ_INFO("zero_rtt not available");
|
||||
} else
|
||||
LSQ_INFO("get_zero_rtt failed %s", strerror(errno));
|
||||
}
|
||||
|
||||
if (ok && s_display_cert_chain)
|
||||
if ((status != LSQ_HSK_FAIL) && s_display_cert_chain)
|
||||
display_cert_chain(conn);
|
||||
|
||||
if (ok)
|
||||
if (status != LSQ_HSK_FAIL)
|
||||
{
|
||||
conn_h = lsquic_conn_get_ctx(conn);
|
||||
++s_stat_conns_ok;
|
||||
|
@ -703,6 +778,7 @@ usage (const char *prog)
|
|||
" -I Abort on incomplete reponse from server\n"
|
||||
" -4 Prefer IPv4 when resolving hostname\n"
|
||||
" -6 Prefer IPv6 when resolving hostname\n"
|
||||
" -0 FILE Provide RTT info file (reading or writing)\n"
|
||||
#ifndef WIN32
|
||||
" -C DIR Certificate store. If specified, server certificate will\n"
|
||||
" be verified.\n"
|
||||
|
@ -758,6 +834,7 @@ init_x509_cert_store (const char *path)
|
|||
X509 *cert;
|
||||
DIR *dir;
|
||||
char file_path[NAME_MAX];
|
||||
int ret;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir)
|
||||
|
@ -772,7 +849,18 @@ init_x509_cert_store (const char *path)
|
|||
{
|
||||
if (ends_in_pem(ent->d_name))
|
||||
{
|
||||
snprintf(file_path, sizeof(file_path), "%s/%s", path, ent->d_name);
|
||||
ret = snprintf(file_path, sizeof(file_path), "%s/%s",
|
||||
path, ent->d_name);
|
||||
if (ret < 0)
|
||||
{
|
||||
LSQ_WARN("file_path formatting error %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
else if ((unsigned)ret >= sizeof(file_path))
|
||||
{
|
||||
LSQ_WARN("file_path was truncated %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
cert = file2cert(file_path);
|
||||
if (cert)
|
||||
{
|
||||
|
@ -945,6 +1033,7 @@ main (int argc, char **argv)
|
|||
struct path_elem *pe;
|
||||
struct sport_head sports;
|
||||
struct prog prog;
|
||||
unsigned char zero_rtt[8192];
|
||||
|
||||
TAILQ_INIT(&sports);
|
||||
memset(&client_ctx, 0, sizeof(client_ctx));
|
||||
|
@ -955,6 +1044,9 @@ main (int argc, char **argv)
|
|||
client_ctx.hcc_cc_reqs_per_conn = 1;
|
||||
client_ctx.hcc_reqs_per_conn = 1;
|
||||
client_ctx.hcc_total_n_reqs = 1;
|
||||
client_ctx.hcc_zero_rtt = (unsigned char *)zero_rtt;
|
||||
client_ctx.hcc_zero_rtt_len = sizeof(zero_rtt);
|
||||
client_ctx.hcc_zero_rtt_max_len = sizeof(zero_rtt);
|
||||
client_ctx.prog = &prog;
|
||||
#ifdef WIN32
|
||||
WSADATA wsd;
|
||||
|
@ -963,7 +1055,7 @@ main (int argc, char **argv)
|
|||
|
||||
prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx);
|
||||
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46Br:R:IKu:EP:M:n:w:H:p:h"
|
||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46Br:R:IKu:EP:M:n:w:H:p:0:h"
|
||||
#ifndef WIN32
|
||||
"C:atT:"
|
||||
#endif
|
||||
|
@ -1061,6 +1153,14 @@ main (int argc, char **argv)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
client_ctx.hcc_zero_rtt_file_name = optarg;
|
||||
client_ctx.hcc_zero_rtt_file = fopen(optarg, "rb+");
|
||||
if (client_ctx.hcc_zero_rtt_file)
|
||||
LSQ_DEBUG("opened zero_rtt file");
|
||||
else
|
||||
LSQ_DEBUG("zero_rtt file is empty, opening later");
|
||||
break;
|
||||
default:
|
||||
if (0 != prog_set_opt(&prog, opt, optarg))
|
||||
exit(1);
|
||||
|
@ -1071,6 +1171,20 @@ main (int argc, char **argv)
|
|||
prog.prog_api.ea_stats_fh = stats_fh;
|
||||
#endif
|
||||
|
||||
if (client_ctx.hcc_zero_rtt_file)
|
||||
{
|
||||
size_t ret = fread(client_ctx.hcc_zero_rtt, 1,
|
||||
client_ctx.hcc_zero_rtt_max_len,
|
||||
client_ctx.hcc_zero_rtt_file);
|
||||
if (ret)
|
||||
{
|
||||
client_ctx.hcc_flags |= HCC_RTT_INFO;
|
||||
client_ctx.hcc_zero_rtt_len = ret;
|
||||
LSQ_DEBUG("read %ld bytes from zero_rtt file", ret);
|
||||
}
|
||||
else
|
||||
LSQ_DEBUG("zero_rtt file is empty");
|
||||
}
|
||||
if (TAILQ_EMPTY(&client_ctx.hcc_path_elems))
|
||||
{
|
||||
fprintf(stderr, "Specify at least one path using -p option\n");
|
||||
|
@ -1090,6 +1204,13 @@ main (int argc, char **argv)
|
|||
|
||||
s = prog_run(&prog);
|
||||
|
||||
if (client_ctx.hcc_zero_rtt_file)
|
||||
{
|
||||
fclose(client_ctx.hcc_zero_rtt_file);
|
||||
client_ctx.hcc_zero_rtt_file = NULL;
|
||||
LSQ_DEBUG("close zero_rtt file");
|
||||
}
|
||||
|
||||
if (stats_fh)
|
||||
{
|
||||
elapsed = (long double) (lsquic_time_now() - start_time) / 1000000;
|
||||
|
|
|
@ -253,7 +253,7 @@ prog_eb (struct prog *prog)
|
|||
|
||||
|
||||
int
|
||||
prog_connect (struct prog *prog)
|
||||
prog_connect (struct prog *prog, unsigned char *zero_rtt, size_t zero_rtt_len)
|
||||
{
|
||||
struct service_port *sport;
|
||||
|
||||
|
@ -262,7 +262,7 @@ prog_connect (struct prog *prog)
|
|||
(struct sockaddr *) &sport->sp_local_addr,
|
||||
(struct sockaddr *) &sport->sas, sport, NULL,
|
||||
prog->prog_hostname ? prog->prog_hostname : sport->host,
|
||||
prog->prog_max_packet_size))
|
||||
prog->prog_max_packet_size, zero_rtt, zero_rtt_len))
|
||||
return -1;
|
||||
|
||||
prog_process_conns(prog);
|
||||
|
|
|
@ -68,7 +68,7 @@ int
|
|||
prog_prep (struct prog *);
|
||||
|
||||
int
|
||||
prog_connect (struct prog *);
|
||||
prog_connect (struct prog *, unsigned char *, size_t);
|
||||
|
||||
void
|
||||
prog_print_common_options (const struct prog *, FILE *);
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
# Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE.
|
||||
|
||||
INCLUDE_DIRECTORIES(../../src/liblsquic)
|
||||
|
||||
ENABLE_TESTING()
|
||||
|
||||
SET(LIBS lsquic ${BORINGSSL_LIB_crypto} ${BORINGSSL_LIB_ssl} ${ZLIB_LIB})
|
||||
|
||||
IF (MSVC)
|
||||
LIST(APPEND LIBS ws2_32)
|
||||
SET(ADDL_SOURCES ../../wincompat/getopt.c ../../wincompat/getopt1.c)
|
||||
SET(LIB_FLAGS "-FORCE:MULTIPLE")
|
||||
ELSE()
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-value")
|
||||
LIST(APPEND LIBS m pthread)
|
||||
ENDIF()
|
||||
|
||||
SET(TESTS
|
||||
|
@ -72,6 +67,7 @@ IF (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|||
SET(TESTS ${TESTS} frame_rw)
|
||||
ENDIF()
|
||||
|
||||
|
||||
FOREACH(TEST_NAME ${TESTS})
|
||||
ADD_EXECUTABLE(test_${TEST_NAME} test_${TEST_NAME}.c ${ADDL_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(test_${TEST_NAME} ${LIBS} ${LIB_FLAGS})
|
||||
|
@ -87,3 +83,4 @@ ADD_TEST(stream_hash_A test_stream -A -h)
|
|||
|
||||
ADD_EXECUTABLE(graph_cubic graph_cubic.c ${ADDL_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(graph_cubic ${LIBS})
|
||||
|
||||
|
|
|
@ -460,7 +460,6 @@ test_priority (void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_errors (void)
|
||||
{
|
||||
|
@ -596,7 +595,6 @@ perl tools/hpack.pl :method GET :path /index.html :authority www.example.com :sc
|
|||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue