mirror of
				https://gitea.invidious.io/iv-org/litespeed-quic.git
				synced 2024-08-15 00:53:43 +00:00 
			
		
		
		
	compiles in debug/release. tests pass (in debug config at least)
This commit is contained in:
		
							parent
							
								
									0e7c6aad9e
								
							
						
					
					
						commit
						461e84d874
					
				
					 97 changed files with 4282 additions and 875 deletions
				
			
		| 
						 | 
				
			
			@ -4,6 +4,7 @@ cmake_minimum_required(VERSION 2.8)
 | 
			
		|||
 | 
			
		||||
project(lsquic)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
# We prefer clang
 | 
			
		||||
IF(NOT ("${CMAKE_C_COMPILER}" MATCHES "ccc-analyzer" OR
 | 
			
		||||
        "${CMAKE_C_COMPILER}" MATCHES "gcc"          OR
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,8 @@ IF(NOT ("${CMAKE_C_COMPILER}" MATCHES "ccc-analyzer" OR
 | 
			
		|||
    ENDIF()
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
# By default, we compile in development mode.  To compile production code,
 | 
			
		||||
# pass -DDEVEL_MODE=0 to cmake (before that, `make clean' and remove any
 | 
			
		||||
# cmake cache files).
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +28,8 @@ ENDIF()
 | 
			
		|||
 | 
			
		||||
MESSAGE(STATUS "DEVEL_MODE: ${DEVEL_MODE}")
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
 | 
			
		||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Wall -Wextra -Wno-unused-parameter")
 | 
			
		||||
SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -fno-omit-frame-pointer")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +63,36 @@ ELSE()
 | 
			
		|||
    MESSAGE(STATUS "AddressSanitizer is OFF")
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
#MSVC
 | 
			
		||||
ELSE()
 | 
			
		||||
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(DEVEL_MODE EQUAL 1)
 | 
			
		||||
    SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -Od ")
 | 
			
		||||
    #SET (MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DFIU_ENABLE=1")
 | 
			
		||||
    #SET (FIULIB "fiu")
 | 
			
		||||
ELSE()
 | 
			
		||||
    SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -OX")
 | 
			
		||||
    SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DNDEBUG")
 | 
			
		||||
    # Comment out the following line to compile out debug messages:
 | 
			
		||||
    #SET(MY_CMAKE_FLAGS "${MY_CMAKE_FLAGS} -DLSQUIC_LOWEST_LOG_LEVEL=LSQ_LOG_INFO")
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
SET (BORINGSSL_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/../boringssl/include)
 | 
			
		||||
SET (VCPKG_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/installed/x64-windows-static/include )
 | 
			
		||||
 | 
			
		||||
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
 | 
			
		||||
SET (BORINGSSL_LIB ${CMAKE_CURRENT_SOURCE_DIR}/../boringssl/build/ssl ${CMAKE_CURRENT_SOURCE_DIR}/../boringssl/build/x64/debug)
 | 
			
		||||
SET (VCPKG_LIB ${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/installed/x64-windows-static/lib)
 | 
			
		||||
SET (ZLIB_NAME "zlibd")
 | 
			
		||||
ELSE()
 | 
			
		||||
SET (BORINGSSL_LIB ${CMAKE_CURRENT_SOURCE_DIR}/../boringssl/build/ssl ${CMAKE_CURRENT_SOURCE_DIR}/../boringssl/build/x64)
 | 
			
		||||
SET (VCPKG_LIB ${CMAKE_CURRENT_SOURCE_DIR}/../vcpkg/installed/x64-windows-static/debug/lib)
 | 
			
		||||
SET (ZLIB_NAME zlibd)
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ENDIF() #MSVC
 | 
			
		||||
 | 
			
		||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  ${MY_CMAKE_FLAGS} $ENV{EXTRA_CFLAGS}")
 | 
			
		||||
 | 
			
		||||
MESSAGE(STATUS "Compiler flags: ${CMAKE_C_FLAGS}")
 | 
			
		||||
| 
						 | 
				
			
			@ -69,8 +104,9 @@ IF(NOT DEFINED BORINGSSL_LIB)
 | 
			
		|||
    SET(BORINGSSL_LIB /usr/local/lib)
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
include_directories( ${BORINGSSL_INCLUDE} )
 | 
			
		||||
link_directories( ${BORINGSSL_LIB} )
 | 
			
		||||
 | 
			
		||||
include_directories(${BORINGSSL_INCLUDE} ${VCPKG_INCLUDE} )
 | 
			
		||||
link_directories( ${BORINGSSL_LIB} ${VCPKG_LIB} )
 | 
			
		||||
 | 
			
		||||
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
 | 
			
		||||
include_directories( include )
 | 
			
		||||
| 
						 | 
				
			
			@ -81,13 +117,27 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
 | 
			
		|||
    link_directories( /usr/local/lib )
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(http_client
 | 
			
		||||
    test/http_client.c
 | 
			
		||||
    test/prog.c
 | 
			
		||||
    test/test_common.c
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(http_client lsquic event pthread libssl.a libcrypto.a ${FIULIB} z m)
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(http_client
 | 
			
		||||
    test/http_client.c
 | 
			
		||||
    test/prog.c
 | 
			
		||||
    wincompat/test_common_win.c
 | 
			
		||||
    wincompat/getopt.c
 | 
			
		||||
    wincompat/getopt1.c
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(http_client lsquic event ssl crypto ${FIULIB} ${ZLIB_NAME} ws2_32)
 | 
			
		||||
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_subdirectory(src)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,9 +10,13 @@
 | 
			
		|||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <lsquic_types.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct iovec;
 | 
			
		||||
struct sockaddr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,9 @@
 | 
			
		|||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include "lsquic_buf.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,8 +7,12 @@
 | 
			
		|||
#define LSQUIC_CONN_H
 | 
			
		||||
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <ws2ipdef.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct lsquic_conn;
 | 
			
		||||
struct lsquic_enc_session;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,11 @@
 | 
			
		|||
#include <zlib.h>
 | 
			
		||||
 | 
			
		||||
#include <openssl/ssl.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#else
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_crypto.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -440,7 +445,7 @@ int decompress_certs(const unsigned char *in, const unsigned char *in_end,
 | 
			
		|||
{
 | 
			
		||||
    int ret;
 | 
			
		||||
    size_t i;
 | 
			
		||||
    uint8_t* uncompressed_data, *uncompressed_data_buf;
 | 
			
		||||
    uint8_t* uncompressed_data = NULL, *uncompressed_data_buf = NULL;
 | 
			
		||||
    lsquic_str_t *dict;
 | 
			
		||||
    uint32_t uncompressed_size;
 | 
			
		||||
    size_t count = *out_certs_count;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,9 @@
 | 
			
		|||
#include <openssl/hmac.h>
 | 
			
		||||
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_crypto.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +214,7 @@ uint128 fnv1a_128(const uint8_t * data, int len)
 | 
			
		|||
 | 
			
		||||
void fnv1a_128_s(const uint8_t * data, int len, uint8_t  *md)
 | 
			
		||||
{
 | 
			
		||||
    return fnv1a_128_2_s(data, len, NULL, 0, md);
 | 
			
		||||
    fnv1a_128_2_s(data, len, NULL, 0, md);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -281,6 +284,7 @@ void lshkdf_extract(const unsigned char *ikm, int ikm_len, const unsigned char *
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SHA256LEN   32
 | 
			
		||||
int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_len,
 | 
			
		||||
                uint16_t c_key_len, uint8_t *c_key,
 | 
			
		||||
                uint16_t s_key_len, uint8_t *s_key,
 | 
			
		||||
| 
						 | 
				
			
			@ -288,7 +292,6 @@ int lshkdf_expand(const unsigned char *prk, const unsigned char *info, int info_
 | 
			
		|||
                uint16_t s_key_iv_len, uint8_t *s_key_iv,
 | 
			
		||||
                uint16_t sub_key_len, uint8_t *sub_key)
 | 
			
		||||
{
 | 
			
		||||
    const int SHA256LEN = 32;
 | 
			
		||||
    int L = c_key_len + s_key_len + c_key_iv_len + s_key_iv_len + sub_key_len;
 | 
			
		||||
    int N = (L + SHA256LEN - 1) / SHA256LEN;
 | 
			
		||||
    unsigned char *p_org;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,9 @@
 | 
			
		|||
#include <stddef.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -133,10 +136,10 @@ lsquic_cubic_was_quiet (struct lsquic_cubic *cubic, lsquic_time_t now)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
 | 
			
		||||
lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now_time,
 | 
			
		||||
                  lsquic_time_t rtt, int app_limited, unsigned n_bytes)
 | 
			
		||||
{
 | 
			
		||||
    LSQ_DEBUG("%s(cubic, %"PRIu64", %"PRIu64", %d, %u)", __func__, now, rtt,
 | 
			
		||||
    LSQ_DEBUG("%s(cubic, %"PRIu64", %"PRIu64", %d, %u)", __func__, now_time, rtt,
 | 
			
		||||
                                                        app_limited, n_bytes);
 | 
			
		||||
    if (0 == cubic->cu_min_delay || rtt < cubic->cu_min_delay)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +154,7 @@ lsquic_cubic_ack (struct lsquic_cubic *cubic, lsquic_time_t now,
 | 
			
		|||
    }
 | 
			
		||||
    else if (!app_limited)
 | 
			
		||||
    {
 | 
			
		||||
        cubic_update(cubic, now, n_bytes);
 | 
			
		||||
        cubic_update(cubic, now_time, n_bytes);
 | 
			
		||||
        LSQ_DEBUG("ACK: cwnd: %lu", cubic->cu_cwnd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,24 +9,17 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_data_in_if.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct data_in_iface di_if_error;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct data_in error_data_in = {
 | 
			
		||||
    .di_if    = &di_if_error,
 | 
			
		||||
    .di_flags = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_error_new (struct lsquic_conn_public *conn_pub)
 | 
			
		||||
{
 | 
			
		||||
    return (struct data_in *) &error_data_in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -87,3 +80,12 @@ static const struct data_in_iface di_if_error = {
 | 
			
		|||
    .di_mem_used     = error_di_mem_used,
 | 
			
		||||
    .di_switch_impl  = error_di_switch_impl,
 | 
			
		||||
};
 | 
			
		||||
static const struct data_in error_data_in = {
 | 
			
		||||
    .di_if    = &di_if_error,
 | 
			
		||||
    .di_flags = 0,
 | 
			
		||||
};
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_error_new (struct lsquic_conn_public *conn_pub)
 | 
			
		||||
{
 | 
			
		||||
    return (struct data_in *) &error_data_in;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,15 +53,14 @@ struct data_block
 | 
			
		|||
    unsigned char           db_data[DB_DATA_SIZE];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef char db_set_covers_all_db_data[(N_DB_SETS * 64 >= DB_DATA_SIZE) - 1];
 | 
			
		||||
typedef char db_set_no_waste[(N_DB_SETS * 64 - 64 <= DB_DATA_SIZE) - 1];
 | 
			
		||||
typedef char db_block_is_4K[(sizeof(struct data_block) == 0x1000) - 1];
 | 
			
		||||
typedef char db_set_covers_all_db_data[(N_DB_SETS * 64 >= DB_DATA_SIZE) ?1: - 1];
 | 
			
		||||
typedef char db_set_no_waste[(N_DB_SETS * 64 - 64 <= DB_DATA_SIZE)?1: - 1];
 | 
			
		||||
typedef char db_block_is_4K[(sizeof(struct data_block) == 0x1000) ?1:- 1];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TAILQ_HEAD(dblock_head, data_block);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct data_in_iface di_if_hash;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct hash_data_in
 | 
			
		||||
| 
						 | 
				
			
			@ -109,43 +108,6 @@ my_log2 /* silly name to suppress compiler warning */ (unsigned sz)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_hash_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id,
 | 
			
		||||
                  uint64_t byteage)
 | 
			
		||||
{
 | 
			
		||||
    struct hash_data_in *hdi;
 | 
			
		||||
    unsigned n;
 | 
			
		||||
 | 
			
		||||
    hdi = malloc(sizeof(*hdi));
 | 
			
		||||
    if (!hdi)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    hdi->hdi_data_in.di_if    = &di_if_hash;
 | 
			
		||||
    hdi->hdi_data_in.di_flags = 0;
 | 
			
		||||
    hdi->hdi_conn_pub         = conn_pub;
 | 
			
		||||
    hdi->hdi_stream_id        = stream_id;
 | 
			
		||||
    hdi->hdi_fin_off          = 0;
 | 
			
		||||
    hdi->hdi_flags            = 0;
 | 
			
		||||
    hdi->hdi_last_block       = NULL;
 | 
			
		||||
    if (byteage >= DB_DATA_SIZE /* __builtin_clz is undefined if
 | 
			
		||||
                                   argument is 0 */)
 | 
			
		||||
        hdi->hdi_nbits        = my_log2(byteage / DB_DATA_SIZE) + 2;
 | 
			
		||||
    else
 | 
			
		||||
        hdi->hdi_nbits        = 3;
 | 
			
		||||
    hdi->hdi_count            = 0;
 | 
			
		||||
    hdi->hdi_buckets          = malloc(sizeof(hdi->hdi_buckets[0]) *
 | 
			
		||||
                                                    N_BUCKETS(hdi->hdi_nbits));
 | 
			
		||||
    if (!hdi->hdi_buckets)
 | 
			
		||||
    {
 | 
			
		||||
        free(hdi);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (n = 0; n < N_BUCKETS(hdi->hdi_nbits); ++n)
 | 
			
		||||
        TAILQ_INIT(&hdi->hdi_buckets[n]);
 | 
			
		||||
 | 
			
		||||
    return &hdi->hdi_data_in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -637,3 +599,40 @@ static const struct data_in_iface di_if_hash = {
 | 
			
		|||
    .di_mem_used     = hash_di_mem_used,
 | 
			
		||||
    .di_switch_impl  = hash_di_switch_impl,
 | 
			
		||||
};
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_hash_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id,
 | 
			
		||||
                  uint64_t byteage)
 | 
			
		||||
{
 | 
			
		||||
    struct hash_data_in *hdi;
 | 
			
		||||
    unsigned n;
 | 
			
		||||
 | 
			
		||||
    hdi = malloc(sizeof(*hdi));
 | 
			
		||||
    if (!hdi)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    hdi->hdi_data_in.di_if    = &di_if_hash;
 | 
			
		||||
    hdi->hdi_data_in.di_flags = 0;
 | 
			
		||||
    hdi->hdi_conn_pub         = conn_pub;
 | 
			
		||||
    hdi->hdi_stream_id        = stream_id;
 | 
			
		||||
    hdi->hdi_fin_off          = 0;
 | 
			
		||||
    hdi->hdi_flags            = 0;
 | 
			
		||||
    hdi->hdi_last_block       = NULL;
 | 
			
		||||
    if (byteage >= DB_DATA_SIZE /* __builtin_clz is undefined if
 | 
			
		||||
                                   argument is 0 */)
 | 
			
		||||
        hdi->hdi_nbits        = my_log2(byteage / DB_DATA_SIZE) + 2;
 | 
			
		||||
    else
 | 
			
		||||
        hdi->hdi_nbits        = 3;
 | 
			
		||||
    hdi->hdi_count            = 0;
 | 
			
		||||
    hdi->hdi_buckets          = malloc(sizeof(hdi->hdi_buckets[0]) *
 | 
			
		||||
                                                    N_BUCKETS(hdi->hdi_nbits));
 | 
			
		||||
    if (!hdi->hdi_buckets)
 | 
			
		||||
    {
 | 
			
		||||
        free(hdi);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (n = 0; n < N_BUCKETS(hdi->hdi_nbits); ++n)
 | 
			
		||||
        TAILQ_INIT(&hdi->hdi_buckets[n]);
 | 
			
		||||
 | 
			
		||||
    return &hdi->hdi_data_in;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,30 +116,8 @@ struct nocopy_data_in
 | 
			
		|||
    ((unsigned char *) (data_frame) - offsetof(struct stream_frame, data_frame))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct data_in_iface di_if_nocopy;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_nocopy_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id)
 | 
			
		||||
{
 | 
			
		||||
    struct nocopy_data_in *ncdi;
 | 
			
		||||
 | 
			
		||||
    ncdi = malloc(sizeof(*ncdi));
 | 
			
		||||
    if (!ncdi)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    TAILQ_INIT(&ncdi->ncdi_frames_in);
 | 
			
		||||
    ncdi->ncdi_data_in.di_if    = &di_if_nocopy;
 | 
			
		||||
    ncdi->ncdi_data_in.di_flags = 0;
 | 
			
		||||
    ncdi->ncdi_conn_pub         = conn_pub;
 | 
			
		||||
    ncdi->ncdi_stream_id        = stream_id;
 | 
			
		||||
    ncdi->ncdi_byteage          = 0;
 | 
			
		||||
    ncdi->ncdi_n_frames         = 0;
 | 
			
		||||
    ncdi->ncdi_n_holes          = 0;
 | 
			
		||||
    ncdi->ncdi_cons_far         = 0;
 | 
			
		||||
    return &ncdi->ncdi_data_in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
nocopy_di_destroy (struct data_in *data_in)
 | 
			
		||||
| 
						 | 
				
			
			@ -444,3 +422,24 @@ static const struct data_in_iface di_if_nocopy = {
 | 
			
		|||
    .di_mem_used     = nocopy_di_mem_used,
 | 
			
		||||
    .di_switch_impl  = nocopy_di_switch_impl,
 | 
			
		||||
};
 | 
			
		||||
struct data_in *
 | 
			
		||||
data_in_nocopy_new (struct lsquic_conn_public *conn_pub, uint32_t stream_id)
 | 
			
		||||
{
 | 
			
		||||
    struct nocopy_data_in *ncdi;
 | 
			
		||||
 | 
			
		||||
    ncdi = malloc(sizeof(*ncdi));
 | 
			
		||||
    if (!ncdi)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    TAILQ_INIT(&ncdi->ncdi_frames_in);
 | 
			
		||||
    ncdi->ncdi_data_in.di_if    = &di_if_nocopy;
 | 
			
		||||
    ncdi->ncdi_data_in.di_flags = 0;
 | 
			
		||||
    ncdi->ncdi_conn_pub         = conn_pub;
 | 
			
		||||
    ncdi->ncdi_stream_id        = stream_id;
 | 
			
		||||
    ncdi->ncdi_byteage          = 0;
 | 
			
		||||
    ncdi->ncdi_n_frames         = 0;
 | 
			
		||||
    ncdi->ncdi_n_holes          = 0;
 | 
			
		||||
    ncdi->ncdi_cons_far         = 0;
 | 
			
		||||
    return &ncdi->ncdi_data_in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,9 @@
 | 
			
		|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#define localtime_r(a,b) localtime_s(b,a)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_eng_hist.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,14 +11,16 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,9 +166,11 @@ struct lsquic_engine
 | 
			
		|||
    union {
 | 
			
		||||
        struct {
 | 
			
		||||
            /* This iterator does not have any state: it uses `conns_in' */
 | 
			
		||||
            int ignore;
 | 
			
		||||
        }           conn_in;
 | 
			
		||||
        struct {
 | 
			
		||||
            /* This iterator does not have any state: it uses `conns_pend_rw' */
 | 
			
		||||
            int ignore;
 | 
			
		||||
        }           rw_pend;
 | 
			
		||||
        struct {
 | 
			
		||||
            /* Iterator state to process connections in Advisory Tick Time
 | 
			
		||||
| 
						 | 
				
			
			@ -176,6 +180,7 @@ struct lsquic_engine
 | 
			
		|||
        }           attq;
 | 
			
		||||
        struct {
 | 
			
		||||
            /* Iterator state to process all connections */
 | 
			
		||||
            int ignore;
 | 
			
		||||
        }           all;
 | 
			
		||||
        struct {
 | 
			
		||||
            lsquic_conn_t  *conn;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,14 @@
 | 
			
		|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +30,7 @@
 | 
			
		|||
/* Messages that do not include connection ID go above this point */
 | 
			
		||||
 | 
			
		||||
#define LSQUIC_LOG_CONN_ID cid
 | 
			
		||||
#define LCID(a...) LSQ_LOG2(LSQ_LOG_DEBUG, a)   /* LCID: log with CID */
 | 
			
		||||
#define LCID(...) LSQ_LOG2(LSQ_LOG_DEBUG, __VA_ARGS__)   /* LCID: log with CID */
 | 
			
		||||
 | 
			
		||||
/* Messages that are to include connection ID go below this point */
 | 
			
		||||
/*  ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||  */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,171 +19,171 @@ struct uncompressed_headers;
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
/* Log a generic event not tied to any particular connection */
 | 
			
		||||
#define EV_LOG_GENERIC_EVENT(args...) do {                                  \
 | 
			
		||||
#define EV_LOG_GENERIC_EVENT(...) do {                                  \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_logger_log1(LSQ_LOG_DEBUG, LSQLM_EVENT, args);               \
 | 
			
		||||
        lsquic_logger_log1(LSQ_LOG_DEBUG, LSQLM_EVENT, __VA_ARGS__);               \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/* Log a generic event associated with connection `cid' */
 | 
			
		||||
#define EV_LOG_CONN_EVENT(cid, args...) do {                                \
 | 
			
		||||
#define EV_LOG_CONN_EVENT(cid, ...) do {                                \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_logger_log2(LSQ_LOG_DEBUG, LSQLM_EVENT, cid, args);          \
 | 
			
		||||
        lsquic_logger_log2(LSQ_LOG_DEBUG, LSQLM_EVENT, cid, __VA_ARGS__);          \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_packet_in (lsquic_cid_t, const struct lsquic_packet_in *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PACKET_IN(args...) do {                                      \
 | 
			
		||||
#define EV_LOG_PACKET_IN(...) do {                                      \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_packet_in(args);                                      \
 | 
			
		||||
        lsquic_ev_log_packet_in(__VA_ARGS__);                                      \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_ack_frame_in (lsquic_cid_t, const struct ack_info *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_ACK_FRAME_IN(args...) do {                                   \
 | 
			
		||||
#define EV_LOG_ACK_FRAME_IN(...) do {                                   \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_ack_frame_in(args);                                   \
 | 
			
		||||
        lsquic_ev_log_ack_frame_in(__VA_ARGS__);                                   \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_stream_frame_in (lsquic_cid_t, const struct stream_frame *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_STREAM_FRAME_IN(args...) do {                                \
 | 
			
		||||
#define EV_LOG_STREAM_FRAME_IN(...) do {                                \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_stream_frame_in(args);                                \
 | 
			
		||||
        lsquic_ev_log_stream_frame_in(__VA_ARGS__);                                \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_window_update_frame_in (lsquic_cid_t, uint32_t stream_id,
 | 
			
		||||
                                                            uint64_t offset);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_WINDOW_UPDATE_FRAME_IN(args...) do {                         \
 | 
			
		||||
#define EV_LOG_WINDOW_UPDATE_FRAME_IN(...) do {                         \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_window_update_frame_in(args);                         \
 | 
			
		||||
        lsquic_ev_log_window_update_frame_in(__VA_ARGS__);                         \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_blocked_frame_in (lsquic_cid_t, uint32_t stream_id);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_BLOCKED_FRAME_IN(args...) do {                               \
 | 
			
		||||
#define EV_LOG_BLOCKED_FRAME_IN(...) do {                               \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_blocked_frame_in(args);                               \
 | 
			
		||||
        lsquic_ev_log_blocked_frame_in(__VA_ARGS__);                               \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_stop_waiting_frame_in (lsquic_cid_t, lsquic_packno_t);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_STOP_WAITING_FRAME_IN(args...) do {                          \
 | 
			
		||||
#define EV_LOG_STOP_WAITING_FRAME_IN(...) do {                          \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_stop_waiting_frame_in(args);                          \
 | 
			
		||||
        lsquic_ev_log_stop_waiting_frame_in(__VA_ARGS__);                          \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_connection_close_frame_in (lsquic_cid_t, uint32_t error_code,
 | 
			
		||||
                                        int reason_len, const char *reason);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_CONNECTION_CLOSE_FRAME_IN(args...) do {                      \
 | 
			
		||||
#define EV_LOG_CONNECTION_CLOSE_FRAME_IN(...) do {                      \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_connection_close_frame_in(args);                      \
 | 
			
		||||
        lsquic_ev_log_connection_close_frame_in(__VA_ARGS__);                      \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_goaway_frame_in (lsquic_cid_t, uint32_t error_code,
 | 
			
		||||
                uint32_t stream_id, int reason_len, const char *reason);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GOAWAY_FRAME_IN(args...) do {                                \
 | 
			
		||||
#define EV_LOG_GOAWAY_FRAME_IN(...) do {                                \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_goaway_frame_in(args);                                \
 | 
			
		||||
        lsquic_ev_log_goaway_frame_in(__VA_ARGS__);                                \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_rst_stream_frame_in (lsquic_cid_t, uint32_t stream_id,
 | 
			
		||||
                                        uint64_t offset, uint32_t error_code);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_RST_STREAM_FRAME_IN(args...) do {                            \
 | 
			
		||||
#define EV_LOG_RST_STREAM_FRAME_IN(...) do {                            \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_rst_stream_frame_in(args);                            \
 | 
			
		||||
        lsquic_ev_log_rst_stream_frame_in(__VA_ARGS__);                            \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_padding_frame_in (lsquic_cid_t, size_t len);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PADDING_FRAME_IN(args...) do {                               \
 | 
			
		||||
#define EV_LOG_PADDING_FRAME_IN(...) do {                               \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_padding_frame_in(args);                               \
 | 
			
		||||
        lsquic_ev_log_padding_frame_in(__VA_ARGS__);                               \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_ping_frame_in (lsquic_cid_t);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PING_FRAME_IN(args...) do {                                  \
 | 
			
		||||
#define EV_LOG_PING_FRAME_IN(...) do {                                  \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_ping_frame_in(args);                                  \
 | 
			
		||||
        lsquic_ev_log_ping_frame_in(__VA_ARGS__);                                  \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_packet_created (lsquic_cid_t, const struct lsquic_packet_out *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PACKET_CREATED(args...) do {                                 \
 | 
			
		||||
#define EV_LOG_PACKET_CREATED(...) do {                                 \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_packet_created(args);                                 \
 | 
			
		||||
        lsquic_ev_log_packet_created(__VA_ARGS__);                                 \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_packet_sent (lsquic_cid_t, const struct lsquic_packet_out *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PACKET_SENT(args...) do {                                    \
 | 
			
		||||
#define EV_LOG_PACKET_SENT(...) do {                                    \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_packet_sent(args);                                    \
 | 
			
		||||
        lsquic_ev_log_packet_sent(__VA_ARGS__);                                    \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_packet_not_sent (lsquic_cid_t, const struct lsquic_packet_out *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_PACKET_NOT_SENT(args...) do {                                \
 | 
			
		||||
#define EV_LOG_PACKET_NOT_SENT(...) do {                                \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_packet_not_sent(args);                                \
 | 
			
		||||
        lsquic_ev_log_packet_not_sent(__VA_ARGS__);                                \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_http_headers_in (lsquic_cid_t, int is_server,
 | 
			
		||||
                                        const struct uncompressed_headers *);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_HTTP_HEADERS_IN(args...) do {                                \
 | 
			
		||||
#define EV_LOG_HTTP_HEADERS_IN(...) do {                                \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_http_headers_in(args);                                \
 | 
			
		||||
        lsquic_ev_log_http_headers_in(__VA_ARGS__);                                \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_action_stream_frame (lsquic_cid_t, const struct parse_funcs *pf,
 | 
			
		||||
                       const unsigned char *, size_t len, const char *action);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GENERATED_STREAM_FRAME(args...) do {                         \
 | 
			
		||||
#define EV_LOG_GENERATED_STREAM_FRAME(...) do {                         \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_action_stream_frame(args, "generated");               \
 | 
			
		||||
        lsquic_ev_log_action_stream_frame(__VA_ARGS__, "generated");               \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_UPDATED_STREAM_FRAME(args...) do {                           \
 | 
			
		||||
#define EV_LOG_UPDATED_STREAM_FRAME(...) do {                           \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_action_stream_frame(args, "updated");                 \
 | 
			
		||||
        lsquic_ev_log_action_stream_frame(__VA_ARGS__, "updated");                 \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_generated_ack_frame (lsquic_cid_t, const struct parse_funcs *,
 | 
			
		||||
                                            const unsigned char *, size_t len);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GENERATED_ACK_FRAME(args...) do {                            \
 | 
			
		||||
#define EV_LOG_GENERATED_ACK_FRAME(...) do {                            \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_generated_ack_frame(args);                            \
 | 
			
		||||
        lsquic_ev_log_generated_ack_frame(__VA_ARGS__);                            \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_ev_log_generated_stop_waiting_frame (lsquic_cid_t, lsquic_packno_t);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GENERATED_STOP_WAITING_FRAME(args...) do {                   \
 | 
			
		||||
#define EV_LOG_GENERATED_STOP_WAITING_FRAME(...) do {                   \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_generated_stop_waiting_frame(args);                   \
 | 
			
		||||
        lsquic_ev_log_generated_stop_waiting_frame(__VA_ARGS__);                   \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -192,9 +192,9 @@ lsquic_ev_log_generated_http_headers (lsquic_cid_t, uint32_t stream_id,
 | 
			
		|||
                            const struct lsquic_http_headers *);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GENERATED_HTTP_HEADERS(args...) do {                         \
 | 
			
		||||
#define EV_LOG_GENERATED_HTTP_HEADERS(...) do {                         \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_generated_http_headers(args);                         \
 | 
			
		||||
        lsquic_ev_log_generated_http_headers(__VA_ARGS__);                         \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -203,9 +203,9 @@ lsquic_ev_log_generated_http_push_promise (lsquic_cid_t, uint32_t stream_id,
 | 
			
		|||
                            const struct lsquic_http_headers *headers,
 | 
			
		||||
                            const struct lsquic_http_headers *extra_headers);
 | 
			
		||||
 | 
			
		||||
#define EV_LOG_GENERATED_HTTP_PUSH_PROMISE(args...) do {                    \
 | 
			
		||||
#define EV_LOG_GENERATED_HTTP_PUSH_PROMISE(...) do {                    \
 | 
			
		||||
    if (LSQ_LOG_ENABLED_EXT(LSQ_LOG_DEBUG, LSQLM_EVENT))                    \
 | 
			
		||||
        lsquic_ev_log_generated_http_push_promise(args);                    \
 | 
			
		||||
        lsquic_ev_log_generated_http_push_promise(__VA_ARGS__);                    \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
 * lsquic_frame_reader.c -- Read HTTP frames from stream
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -698,11 +700,12 @@ code_str_to_reason (const char *code_str, int code_len)
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    long code;
 | 
			
		||||
    char code_buf[ code_len + 1 ];
 | 
			
		||||
    char * code_buf = malloc(code_len + 1 );
 | 
			
		||||
 | 
			
		||||
    strncpy(code_buf, code_str, code_len);
 | 
			
		||||
    code_buf[code_len] = '\0';
 | 
			
		||||
    code = strtol(code_buf, NULL, 10) - 100;
 | 
			
		||||
    free(code_buf);
 | 
			
		||||
    if (code > 0 && code < (long) (sizeof(http_reason_phrases) /
 | 
			
		||||
                                        sizeof(http_reason_phrases[0])))
 | 
			
		||||
        return http_reason_phrases[code];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,9 @@
 | 
			
		|||
 * the whole frame.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +56,7 @@ struct frame_buf
 | 
			
		|||
/* Make sure that frab_buf is at least five bytes long, otherwise a frame
 | 
			
		||||
 * won't fit into two adjacent frabs.
 | 
			
		||||
 */
 | 
			
		||||
typedef char three_byte_frab_buf[(sizeof(((struct frame_buf *)0)->frab_buf) >= 5) - 1];
 | 
			
		||||
typedef char three_byte_frab_buf[(sizeof(((struct frame_buf *)0)->frab_buf) >= 5) ?1 : - 1];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TAILQ_HEAD(frame_buf_head, frame_buf);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,15 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -208,22 +210,22 @@ struct full_conn
 | 
			
		|||
 | 
			
		||||
#define MAX_ERRMSG 256
 | 
			
		||||
 | 
			
		||||
#define SET_ERRMSG(conn, errmsg...) do {                                    \
 | 
			
		||||
#define SET_ERRMSG(conn, ...) do {                                    \
 | 
			
		||||
    if (!(conn)->fc_errmsg)                                                 \
 | 
			
		||||
        (conn)->fc_errmsg = malloc(MAX_ERRMSG);                             \
 | 
			
		||||
    if ((conn)->fc_errmsg)                                                  \
 | 
			
		||||
        snprintf((conn)->fc_errmsg, MAX_ERRMSG, errmsg);                    \
 | 
			
		||||
        snprintf((conn)->fc_errmsg, MAX_ERRMSG, __VA_ARGS__);                    \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define ABORT_WITH_FLAG(conn, flag, errmsg...) do {                         \
 | 
			
		||||
    SET_ERRMSG(conn, errmsg);                                               \
 | 
			
		||||
#define ABORT_WITH_FLAG(conn, flag, ...) do {                         \
 | 
			
		||||
    SET_ERRMSG(conn, __VA_ARGS__);                                               \
 | 
			
		||||
    (conn)->fc_flags |= flag;                                               \
 | 
			
		||||
    LSQ_ERROR("Abort connection: " errmsg);                                  \
 | 
			
		||||
    LSQ_ERROR("Abort connection: " __VA_ARGS__);                                  \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define ABORT_ERROR(errmsg...) ABORT_WITH_FLAG(conn, FC_ERROR, errmsg)
 | 
			
		||||
#define ABORT_ERROR(...) ABORT_WITH_FLAG(conn, FC_ERROR, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#define ABORT_TIMEOUT(errmsg...) ABORT_WITH_FLAG(conn, FC_TIMED_OUT, errmsg)
 | 
			
		||||
#define ABORT_TIMEOUT(...) ABORT_WITH_FLAG(conn, FC_TIMED_OUT, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
idle_alarm_expired (void *ctx, lsquic_time_t expiry, lsquic_time_t now);
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +251,6 @@ write_is_possible (struct full_conn *);
 | 
			
		|||
static int
 | 
			
		||||
dispatch_stream_read_events (struct full_conn *, struct lsquic_stream *);
 | 
			
		||||
 | 
			
		||||
static const struct headers_stream_callbacks headers_callbacks;
 | 
			
		||||
 | 
			
		||||
#if KEEP_CLOSED_STREAM_HISTORY
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -512,174 +513,9 @@ apply_peer_settings (struct full_conn *conn)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const struct conn_iface full_conn_iface;
 | 
			
		||||
 | 
			
		||||
static struct full_conn *
 | 
			
		||||
new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
 | 
			
		||||
                 const struct lsquic_stream_if *stream_if,
 | 
			
		||||
                 void *stream_if_ctx, unsigned flags,
 | 
			
		||||
                 unsigned short max_packet_size)
 | 
			
		||||
{
 | 
			
		||||
    struct full_conn *conn;
 | 
			
		||||
    lsquic_stream_t *headers_stream;
 | 
			
		||||
    int saved_errno;
 | 
			
		||||
 | 
			
		||||
    assert(0 == (flags & ~(FC_SERVER|FC_HTTP)));
 | 
			
		||||
 | 
			
		||||
    conn = calloc(1, sizeof(*conn));
 | 
			
		||||
    if (!conn)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    headers_stream = NULL;
 | 
			
		||||
    conn->fc_conn.cn_cid = cid;
 | 
			
		||||
    conn->fc_conn.cn_pack_size = max_packet_size;
 | 
			
		||||
    conn->fc_flags = flags;
 | 
			
		||||
    conn->fc_enpub = enpub;
 | 
			
		||||
    conn->fc_pub.enpub = enpub;
 | 
			
		||||
    conn->fc_pub.mm = &enpub->enp_mm;
 | 
			
		||||
    conn->fc_pub.lconn = &conn->fc_conn;
 | 
			
		||||
    conn->fc_pub.send_ctl = &conn->fc_send_ctl;
 | 
			
		||||
    conn->fc_pub.packet_out_malo =
 | 
			
		||||
                        lsquic_malo_create(sizeof(struct lsquic_packet_out));
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_STD].stream_if     = stream_if;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_STD].stream_if_ctx = stream_if_ctx;
 | 
			
		||||
    conn->fc_settings = &enpub->enp_settings;
 | 
			
		||||
    /* Calculate maximum number of incoming streams using the same mechanism
 | 
			
		||||
     * and parameters as found in Chrome:
 | 
			
		||||
     */
 | 
			
		||||
    conn->fc_cfg.max_streams_in =
 | 
			
		||||
        (unsigned) ((float) enpub->enp_settings.es_max_streams_in * 1.1f);
 | 
			
		||||
    if (conn->fc_cfg.max_streams_in <
 | 
			
		||||
                                enpub->enp_settings.es_max_streams_in + 10)
 | 
			
		||||
        conn->fc_cfg.max_streams_in =
 | 
			
		||||
                                enpub->enp_settings.es_max_streams_in + 10;
 | 
			
		||||
    /* `max_streams_out' gets reset when handshake is complete and we
 | 
			
		||||
     * learn of peer settings.  100 seems like a sane default value
 | 
			
		||||
     * because it is what other implementations use.  In server mode,
 | 
			
		||||
     * we do not open any streams until the handshake is complete; in
 | 
			
		||||
     * client mode, we are limited to 98 outgoing requests alongside
 | 
			
		||||
     * handshake and headers streams.
 | 
			
		||||
     */
 | 
			
		||||
    conn->fc_cfg.max_streams_out = 100;
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.sending_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.read_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.write_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.service_streams);
 | 
			
		||||
    STAILQ_INIT(&conn->fc_stream_ids_to_reset);
 | 
			
		||||
    lsquic_conn_cap_init(&conn->fc_pub.conn_cap, LSQUIC_MIN_FCW);
 | 
			
		||||
    lsquic_alarmset_init(&conn->fc_alset, cid);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_IDLE, idle_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_ACK, ack_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_PING, ping_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_HANDSHAKE, handshake_alarm_expired, conn);
 | 
			
		||||
    lsquic_set32_init(&conn->fc_closed_stream_ids[0]);
 | 
			
		||||
    lsquic_set32_init(&conn->fc_closed_stream_ids[1]);
 | 
			
		||||
    lsquic_cfcw_init(&conn->fc_pub.cfcw, &conn->fc_pub, conn->fc_settings->es_cfcw);
 | 
			
		||||
    lsquic_send_ctl_init(&conn->fc_send_ctl, &conn->fc_alset, conn->fc_enpub,
 | 
			
		||||
                 &conn->fc_ver_neg, &conn->fc_pub, conn->fc_conn.cn_pack_size);
 | 
			
		||||
 | 
			
		||||
    conn->fc_pub.all_streams = lsquic_hash_create();
 | 
			
		||||
    if (!conn->fc_pub.all_streams)
 | 
			
		||||
        goto cleanup_on_error;
 | 
			
		||||
    lsquic_rechist_init(&conn->fc_rechist, cid);
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        conn->fc_pub.hs = lsquic_headers_stream_new(
 | 
			
		||||
            !!(conn->fc_flags & FC_SERVER), conn->fc_pub.mm, conn->fc_settings,
 | 
			
		||||
                                                     &headers_callbacks, conn);
 | 
			
		||||
        if (!conn->fc_pub.hs)
 | 
			
		||||
            goto cleanup_on_error;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if     = lsquic_headers_stream_if;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if_ctx = conn->fc_pub.hs;
 | 
			
		||||
        headers_stream = new_stream(conn, LSQUIC_STREAM_HEADERS,
 | 
			
		||||
                                    SCF_CALL_ON_NEW);
 | 
			
		||||
        if (!headers_stream)
 | 
			
		||||
            goto cleanup_on_error;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if     = stream_if;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if_ctx = stream_if_ctx;
 | 
			
		||||
    }
 | 
			
		||||
    if (conn->fc_settings->es_support_push)
 | 
			
		||||
        conn->fc_flags |= FC_SUPPORT_PUSH;
 | 
			
		||||
    conn->fc_conn.cn_if = &full_conn_iface;
 | 
			
		||||
    return conn;
 | 
			
		||||
 | 
			
		||||
  cleanup_on_error:
 | 
			
		||||
    saved_errno = errno;
 | 
			
		||||
 | 
			
		||||
    if (conn->fc_pub.all_streams)
 | 
			
		||||
        lsquic_hash_destroy(conn->fc_pub.all_streams);
 | 
			
		||||
    lsquic_rechist_cleanup(&conn->fc_rechist);
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        if (conn->fc_pub.hs)
 | 
			
		||||
            lsquic_headers_stream_destroy(conn->fc_pub.hs);
 | 
			
		||||
        if (headers_stream)
 | 
			
		||||
            lsquic_stream_destroy(headers_stream);
 | 
			
		||||
    }
 | 
			
		||||
    memset(conn, 0, sizeof(*conn));
 | 
			
		||||
    free(conn);
 | 
			
		||||
 | 
			
		||||
    errno = saved_errno;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    struct full_conn *conn;
 | 
			
		||||
    enum lsquic_version version;
 | 
			
		||||
    lsquic_cid_t cid;
 | 
			
		||||
    const struct enc_session_funcs *esf;
 | 
			
		||||
 | 
			
		||||
    version = highest_bit_set(enpub->enp_settings.es_versions);
 | 
			
		||||
    esf = select_esf_by_ver(version);
 | 
			
		||||
    cid = esf->esf_generate_cid();
 | 
			
		||||
    conn = new_conn_common(cid, enpub, stream_if, stream_if_ctx, flags,
 | 
			
		||||
                                                            max_packet_size);
 | 
			
		||||
    if (!conn)
 | 
			
		||||
        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);
 | 
			
		||||
    if (!conn->fc_conn.cn_enc_session)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create enc session: %s", strerror(errno));
 | 
			
		||||
        conn->fc_conn.cn_if->ci_destroy(&conn->fc_conn);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
        conn->fc_last_stream_id = LSQUIC_STREAM_HEADERS;   /* Client goes 5, 7, 9.... */
 | 
			
		||||
    else
 | 
			
		||||
        conn->fc_last_stream_id = LSQUIC_STREAM_HANDSHAKE;
 | 
			
		||||
    conn->fc_hsk_ctx.client.lconn   = &conn->fc_conn;
 | 
			
		||||
    conn->fc_hsk_ctx.client.mm      = &enpub->enp_mm;
 | 
			
		||||
    conn->fc_hsk_ctx.client.ver_neg = &conn->fc_ver_neg;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_HSK]
 | 
			
		||||
                .stream_if     = &lsquic_client_hsk_stream_if;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
 | 
			
		||||
    init_ver_neg(conn, conn->fc_settings->es_versions);
 | 
			
		||||
    conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
 | 
			
		||||
    if (conn->fc_settings->es_handshake_to)
 | 
			
		||||
        lsquic_alarmset_set(&conn->fc_alset, AL_HANDSHAKE,
 | 
			
		||||
                    lsquic_time_now() + conn->fc_settings->es_handshake_to);
 | 
			
		||||
    if (!new_stream(conn, LSQUIC_STREAM_HANDSHAKE, SCF_CALL_ON_NEW))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create handshake stream: %s", strerror(errno));
 | 
			
		||||
        conn->fc_conn.cn_if->ci_destroy(&conn->fc_conn);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    conn->fc_flags |= FC_CREATED_OK;
 | 
			
		||||
    LSQ_INFO("Created new client connection");
 | 
			
		||||
    EV_LOG_CONN_EVENT(cid, "created full connection");
 | 
			
		||||
    return &conn->fc_conn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			@ -982,7 +818,7 @@ lsquic_conn_get_engine (lsquic_conn_t *lconn)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static unsigned
 | 
			
		||||
static ssize_t
 | 
			
		||||
count_zero_bytes (const unsigned char *p, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    const unsigned char *const end = p + len;
 | 
			
		||||
| 
						 | 
				
			
			@ -997,11 +833,11 @@ process_padding_frame (struct full_conn *conn, lsquic_packet_in_t *packet_in,
 | 
			
		|||
                       const unsigned char *p, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    if (conn->fc_conn.cn_version >= LSQVER_038)
 | 
			
		||||
        return count_zero_bytes(p, len);
 | 
			
		||||
        return (unsigned)count_zero_bytes(p, len);
 | 
			
		||||
    if (lsquic_is_zero(p, len))
 | 
			
		||||
    {
 | 
			
		||||
        EV_LOG_PADDING_FRAME_IN(LSQUIC_LOG_CONN_ID, len);
 | 
			
		||||
        return len;
 | 
			
		||||
        return (unsigned )len;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -3154,3 +2990,167 @@ static const struct conn_iface full_conn_iface = {
 | 
			
		|||
    .ci_tick                 =  full_conn_ci_tick,
 | 
			
		||||
    .ci_user_wants_read      =  full_conn_ci_user_wants_read,
 | 
			
		||||
};
 | 
			
		||||
static struct full_conn *
 | 
			
		||||
new_conn_common (lsquic_cid_t cid, struct lsquic_engine_public *enpub,
 | 
			
		||||
                 const struct lsquic_stream_if *stream_if,
 | 
			
		||||
                 void *stream_if_ctx, unsigned flags,
 | 
			
		||||
                 unsigned short max_packet_size)
 | 
			
		||||
{
 | 
			
		||||
    struct full_conn *conn;
 | 
			
		||||
    lsquic_stream_t *headers_stream;
 | 
			
		||||
    int saved_errno;
 | 
			
		||||
 | 
			
		||||
    assert(0 == (flags & ~(FC_SERVER|FC_HTTP)));
 | 
			
		||||
 | 
			
		||||
    conn = calloc(1, sizeof(*conn));
 | 
			
		||||
    if (!conn)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    headers_stream = NULL;
 | 
			
		||||
    conn->fc_conn.cn_cid = cid;
 | 
			
		||||
    conn->fc_conn.cn_pack_size = max_packet_size;
 | 
			
		||||
    conn->fc_flags = flags;
 | 
			
		||||
    conn->fc_enpub = enpub;
 | 
			
		||||
    conn->fc_pub.enpub = enpub;
 | 
			
		||||
    conn->fc_pub.mm = &enpub->enp_mm;
 | 
			
		||||
    conn->fc_pub.lconn = &conn->fc_conn;
 | 
			
		||||
    conn->fc_pub.send_ctl = &conn->fc_send_ctl;
 | 
			
		||||
    conn->fc_pub.packet_out_malo =
 | 
			
		||||
                        lsquic_malo_create(sizeof(struct lsquic_packet_out));
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_STD].stream_if     = stream_if;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_STD].stream_if_ctx = stream_if_ctx;
 | 
			
		||||
    conn->fc_settings = &enpub->enp_settings;
 | 
			
		||||
    /* Calculate maximum number of incoming streams using the same mechanism
 | 
			
		||||
     * and parameters as found in Chrome:
 | 
			
		||||
     */
 | 
			
		||||
    conn->fc_cfg.max_streams_in =
 | 
			
		||||
        (unsigned) ((float) enpub->enp_settings.es_max_streams_in * 1.1f);
 | 
			
		||||
    if (conn->fc_cfg.max_streams_in <
 | 
			
		||||
                                enpub->enp_settings.es_max_streams_in + 10)
 | 
			
		||||
        conn->fc_cfg.max_streams_in =
 | 
			
		||||
                                enpub->enp_settings.es_max_streams_in + 10;
 | 
			
		||||
    /* `max_streams_out' gets reset when handshake is complete and we
 | 
			
		||||
     * learn of peer settings.  100 seems like a sane default value
 | 
			
		||||
     * because it is what other implementations use.  In server mode,
 | 
			
		||||
     * we do not open any streams until the handshake is complete; in
 | 
			
		||||
     * client mode, we are limited to 98 outgoing requests alongside
 | 
			
		||||
     * handshake and headers streams.
 | 
			
		||||
     */
 | 
			
		||||
    conn->fc_cfg.max_streams_out = 100;
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.sending_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.read_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.write_streams);
 | 
			
		||||
    TAILQ_INIT(&conn->fc_pub.service_streams);
 | 
			
		||||
    STAILQ_INIT(&conn->fc_stream_ids_to_reset);
 | 
			
		||||
    lsquic_conn_cap_init(&conn->fc_pub.conn_cap, LSQUIC_MIN_FCW);
 | 
			
		||||
    lsquic_alarmset_init(&conn->fc_alset, cid);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_IDLE, idle_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_ACK, ack_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_PING, ping_alarm_expired, conn);
 | 
			
		||||
    lsquic_alarmset_init_alarm(&conn->fc_alset, AL_HANDSHAKE, handshake_alarm_expired, conn);
 | 
			
		||||
    lsquic_set32_init(&conn->fc_closed_stream_ids[0]);
 | 
			
		||||
    lsquic_set32_init(&conn->fc_closed_stream_ids[1]);
 | 
			
		||||
    lsquic_cfcw_init(&conn->fc_pub.cfcw, &conn->fc_pub, conn->fc_settings->es_cfcw);
 | 
			
		||||
    lsquic_send_ctl_init(&conn->fc_send_ctl, &conn->fc_alset, conn->fc_enpub,
 | 
			
		||||
                 &conn->fc_ver_neg, &conn->fc_pub, conn->fc_conn.cn_pack_size);
 | 
			
		||||
 | 
			
		||||
    conn->fc_pub.all_streams = lsquic_hash_create();
 | 
			
		||||
    if (!conn->fc_pub.all_streams)
 | 
			
		||||
        goto cleanup_on_error;
 | 
			
		||||
    lsquic_rechist_init(&conn->fc_rechist, cid);
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        conn->fc_pub.hs = lsquic_headers_stream_new(
 | 
			
		||||
            !!(conn->fc_flags & FC_SERVER), conn->fc_pub.mm, conn->fc_settings,
 | 
			
		||||
                                                     &headers_callbacks, conn);
 | 
			
		||||
        if (!conn->fc_pub.hs)
 | 
			
		||||
            goto cleanup_on_error;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if     = lsquic_headers_stream_if;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if_ctx = conn->fc_pub.hs;
 | 
			
		||||
        headers_stream = new_stream(conn, LSQUIC_STREAM_HEADERS,
 | 
			
		||||
                                    SCF_CALL_ON_NEW);
 | 
			
		||||
        if (!headers_stream)
 | 
			
		||||
            goto cleanup_on_error;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if     = stream_if;
 | 
			
		||||
        conn->fc_stream_ifs[STREAM_IF_HDR].stream_if_ctx = stream_if_ctx;
 | 
			
		||||
    }
 | 
			
		||||
    if (conn->fc_settings->es_support_push)
 | 
			
		||||
        conn->fc_flags |= FC_SUPPORT_PUSH;
 | 
			
		||||
    conn->fc_conn.cn_if = &full_conn_iface;
 | 
			
		||||
    return conn;
 | 
			
		||||
 | 
			
		||||
  cleanup_on_error:
 | 
			
		||||
    saved_errno = errno;
 | 
			
		||||
 | 
			
		||||
    if (conn->fc_pub.all_streams)
 | 
			
		||||
        lsquic_hash_destroy(conn->fc_pub.all_streams);
 | 
			
		||||
    lsquic_rechist_cleanup(&conn->fc_rechist);
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
    {
 | 
			
		||||
        if (conn->fc_pub.hs)
 | 
			
		||||
            lsquic_headers_stream_destroy(conn->fc_pub.hs);
 | 
			
		||||
        if (headers_stream)
 | 
			
		||||
            lsquic_stream_destroy(headers_stream);
 | 
			
		||||
    }
 | 
			
		||||
    memset(conn, 0, sizeof(*conn));
 | 
			
		||||
    free(conn);
 | 
			
		||||
 | 
			
		||||
    errno = saved_errno;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
    struct full_conn *conn;
 | 
			
		||||
    enum lsquic_version version;
 | 
			
		||||
    lsquic_cid_t cid;
 | 
			
		||||
    const struct enc_session_funcs *esf;
 | 
			
		||||
 | 
			
		||||
    version = highest_bit_set(enpub->enp_settings.es_versions);
 | 
			
		||||
    esf = select_esf_by_ver(version);
 | 
			
		||||
    cid = esf->esf_generate_cid();
 | 
			
		||||
    conn = new_conn_common(cid, enpub, stream_if, stream_if_ctx, flags,
 | 
			
		||||
                                                            max_packet_size);
 | 
			
		||||
    if (!conn)
 | 
			
		||||
        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);
 | 
			
		||||
    if (!conn->fc_conn.cn_enc_session)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create enc session: %s", strerror(errno));
 | 
			
		||||
        conn->fc_conn.cn_if->ci_destroy(&conn->fc_conn);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conn->fc_flags & FC_HTTP)
 | 
			
		||||
        conn->fc_last_stream_id = LSQUIC_STREAM_HEADERS;   /* Client goes 5, 7, 9.... */
 | 
			
		||||
    else
 | 
			
		||||
        conn->fc_last_stream_id = LSQUIC_STREAM_HANDSHAKE;
 | 
			
		||||
    conn->fc_hsk_ctx.client.lconn   = &conn->fc_conn;
 | 
			
		||||
    conn->fc_hsk_ctx.client.mm      = &enpub->enp_mm;
 | 
			
		||||
    conn->fc_hsk_ctx.client.ver_neg = &conn->fc_ver_neg;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_HSK]
 | 
			
		||||
                .stream_if     = &lsquic_client_hsk_stream_if;
 | 
			
		||||
    conn->fc_stream_ifs[STREAM_IF_HSK].stream_if_ctx = &conn->fc_hsk_ctx.client;
 | 
			
		||||
    init_ver_neg(conn, conn->fc_settings->es_versions);
 | 
			
		||||
    conn->fc_conn.cn_pf = select_pf_by_ver(conn->fc_ver_neg.vn_ver);
 | 
			
		||||
    if (conn->fc_settings->es_handshake_to)
 | 
			
		||||
        lsquic_alarmset_set(&conn->fc_alset, AL_HANDSHAKE,
 | 
			
		||||
                    lsquic_time_now() + conn->fc_settings->es_handshake_to);
 | 
			
		||||
    if (!new_stream(conn, LSQUIC_STREAM_HANDSHAKE, SCF_CALL_ON_NEW))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create handshake stream: %s", strerror(errno));
 | 
			
		||||
        conn->fc_conn.cn_if->ci_destroy(&conn->fc_conn);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    conn->fc_flags |= FC_CREATED_OK;
 | 
			
		||||
    LSQ_INFO("Created new client connection");
 | 
			
		||||
    EV_LOG_CONN_EVENT(cid, "created full connection");
 | 
			
		||||
    return &conn->fc_conn;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@
 | 
			
		|||
#include <time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <openssl/ssl.h>
 | 
			
		||||
#include <openssl/crypto.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -933,7 +935,7 @@ lsquic_enc_session_gen_chlo (lsquic_enc_session_t *enc_session,
 | 
			
		|||
    unsigned char pub_key[32];
 | 
			
		||||
    size_t ua_len;
 | 
			
		||||
    uint32_t opts[1];  /* Only NSTP is supported for now */
 | 
			
		||||
    unsigned n_opts, msg_len, n_tags, pad_size;
 | 
			
		||||
    unsigned n_opts, msg_len, n_tags, pad_size = 0;
 | 
			
		||||
    struct message_writer mw;
 | 
			
		||||
 | 
			
		||||
    /* Before we do anything else, sanity check: */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_malo.h"
 | 
			
		||||
#include "lsquic_hash.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_frame_common.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +29,6 @@
 | 
			
		|||
#define LSQUIC_LOG_CONN_ID lsquic_conn_id(lsquic_stream_conn(hs->hs_stream))
 | 
			
		||||
#include "lsquic_logger.h"
 | 
			
		||||
 | 
			
		||||
static const struct frame_reader_callbacks frame_callbacks;
 | 
			
		||||
 | 
			
		||||
struct headers_stream
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ struct headers_stream
 | 
			
		|||
            HS_HENC_INITED  = (1 << 1),
 | 
			
		||||
    }                                   hs_flags;
 | 
			
		||||
};
 | 
			
		||||
static lsquic_stream_ctx_t * headers_on_new_stream(void *stream_if_ctx, lsquic_stream_t *stream);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
| 
						 | 
				
			
			@ -70,42 +71,6 @@ lsquic_headers_stream_send_settings (struct headers_stream *hs,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static lsquic_stream_ctx_t *
 | 
			
		||||
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
 | 
			
		||||
{
 | 
			
		||||
    struct headers_stream *hs = stream_if_ctx;
 | 
			
		||||
    lsquic_hdec_init(&hs->hs_hdec);
 | 
			
		||||
    if (0 != lsquic_henc_init(&hs->hs_henc))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    hs->hs_flags |= HS_HENC_INITED;
 | 
			
		||||
    hs->hs_stream = stream;
 | 
			
		||||
    LSQ_DEBUG("stream created");
 | 
			
		||||
    hs->hs_fr = lsquic_frame_reader_new((hs->hs_flags & HS_IS_SERVER) ? FRF_SERVER : 0,
 | 
			
		||||
                                MAX_HEADERS_SIZE, hs->hs_mm,
 | 
			
		||||
                                stream, lsquic_stream_read, &hs->hs_hdec,
 | 
			
		||||
                                &frame_callbacks, hs);
 | 
			
		||||
    if (!hs->hs_fr)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create frame reader: %s", strerror(errno));
 | 
			
		||||
        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    hs->hs_fw = lsquic_frame_writer_new(hs->hs_mm, stream, 0, &hs->hs_henc,
 | 
			
		||||
                                lsquic_stream_write,
 | 
			
		||||
                                (hs->hs_flags & HS_IS_SERVER));
 | 
			
		||||
    if (!hs->hs_fw)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create frame writer: %s", strerror(errno));
 | 
			
		||||
        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    lsquic_stream_wantread(stream, 1);
 | 
			
		||||
    return (lsquic_stream_ctx_t *) hs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
headers_on_read (lsquic_stream_t *stream, struct lsquic_stream_ctx *ctx)
 | 
			
		||||
| 
						 | 
				
			
			@ -414,3 +379,39 @@ static const struct frame_reader_callbacks frame_callbacks = {
 | 
			
		|||
    .frc_on_settings     = headers_on_settings,
 | 
			
		||||
    .frc_on_priority     = headers_on_priority,
 | 
			
		||||
};
 | 
			
		||||
static lsquic_stream_ctx_t *
 | 
			
		||||
headers_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
 | 
			
		||||
{
 | 
			
		||||
    struct headers_stream *hs = stream_if_ctx;
 | 
			
		||||
    lsquic_hdec_init(&hs->hs_hdec);
 | 
			
		||||
    if (0 != lsquic_henc_init(&hs->hs_henc))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not initialize HPACK encoder: %s", strerror(errno));
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    hs->hs_flags |= HS_HENC_INITED;
 | 
			
		||||
    hs->hs_stream = stream;
 | 
			
		||||
    LSQ_DEBUG("stream created");
 | 
			
		||||
    hs->hs_fr = lsquic_frame_reader_new((hs->hs_flags & HS_IS_SERVER) ? FRF_SERVER : 0,
 | 
			
		||||
                                MAX_HEADERS_SIZE, hs->hs_mm,
 | 
			
		||||
                                stream, lsquic_stream_read, &hs->hs_hdec,
 | 
			
		||||
                                &frame_callbacks, hs);
 | 
			
		||||
    if (!hs->hs_fr)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create frame reader: %s", strerror(errno));
 | 
			
		||||
        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    hs->hs_fw = lsquic_frame_writer_new(hs->hs_mm, stream, 0, &hs->hs_henc,
 | 
			
		||||
                                lsquic_stream_write,
 | 
			
		||||
                                (hs->hs_flags & HS_IS_SERVER));
 | 
			
		||||
    if (!hs->hs_fw)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_WARN("could not create frame writer: %s", strerror(errno));
 | 
			
		||||
        hs->hs_callbacks->hsc_on_conn_error(hs->hs_cb_ctx);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    lsquic_stream_wantread(stream, 1);
 | 
			
		||||
    return (lsquic_stream_ctx_t *) hs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,9 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_arr.h"
 | 
			
		||||
#include "lsquic_hpack_common.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_hpack_common.h"
 | 
			
		||||
#include "lsquic_hpack_enc.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#define LSQUIC_LOGGER_MODULE LSQLM_LOGGER /* Quis custodiet ipsos custodes? */
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +124,7 @@ lsquic_printf (const char *fmt, ...)
 | 
			
		|||
static void
 | 
			
		||||
print_timestamp (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    struct tm tm;
 | 
			
		||||
    struct timeval tv;
 | 
			
		||||
    gettimeofday(&tv, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +146,27 @@ print_timestamp (void)
 | 
			
		|||
    else if (g_llts == LLTS_CHROMELIKE)
 | 
			
		||||
        lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.tm_mon + 1,
 | 
			
		||||
            tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
 | 
			
		||||
#else
 | 
			
		||||
    SYSTEMTIME tm = { 0 };
 | 
			
		||||
    GetSystemTime(&tm);
 | 
			
		||||
    if (g_llts == LLTS_YYYYMMDD_HHMMSSUS)
 | 
			
		||||
        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%06d ",
 | 
			
		||||
            tm.wYear + 1900, tm.wMonth + 1, tm.wDay,
 | 
			
		||||
            tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds*1000 );
 | 
			
		||||
    else if (g_llts == LLTS_YYYYMMDD_HHMMSSMS)
 | 
			
		||||
        lsquic_printf("%04d-%02d-%02d %02d:%02d:%02d.%03d ",
 | 
			
		||||
            tm.wYear + 1900, tm.wMonth + 1, tm.wDay,
 | 
			
		||||
            tm.wHour, tm.wMinute, tm.wSecond, tm.wMilliseconds*1000 );
 | 
			
		||||
    else if (g_llts == LLTS_HHMMSSMS)
 | 
			
		||||
        lsquic_printf("%02d:%02d:%02d.%03d ", tm.wHour, tm.wMinute,
 | 
			
		||||
                                    tm.wSecond, tm.wMilliseconds );
 | 
			
		||||
    else if (g_llts == LLTS_HHMMSSUS)
 | 
			
		||||
        lsquic_printf("%02d:%02d:%02d.%03d ", tm.wHour, tm.wMinute,
 | 
			
		||||
                                    tm.wSecond, tm.wMilliseconds*1000 );
 | 
			
		||||
    else if (g_llts == LLTS_CHROMELIKE)
 | 
			
		||||
        lsquic_printf("%02d%02d/%02d%02d%02d.%06d ", tm.wMonth + 1,
 | 
			
		||||
            tm.wDay,tm.wHour, tm.wMinute, tm.wSecond, (int) tm.wMilliseconds*1000);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,9 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "fiu-local.h"
 | 
			
		||||
#include "lsquic_malo.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +78,7 @@ struct malo_page {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
typedef char malo_header_fits_in_one_slot
 | 
			
		||||
    [0 - (sizeof(struct malo_page) > (1 << MALO_MAX_NBITS))];
 | 
			
		||||
    [(sizeof(struct malo_page) > (1 << MALO_MAX_NBITS)) ? -1 : 1];
 | 
			
		||||
 | 
			
		||||
struct malo {
 | 
			
		||||
    struct malo_page        page_header;
 | 
			
		||||
| 
						 | 
				
			
			@ -187,10 +190,18 @@ lsquic_malo_destroy (struct malo *malo)
 | 
			
		|||
    while (page != &malo->page_header)
 | 
			
		||||
    {
 | 
			
		||||
        next = SLIST_NEXT(page, next_page);
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
        free(page);
 | 
			
		||||
#else
 | 
			
		||||
        _aligned_free(page);
 | 
			
		||||
#endif
 | 
			
		||||
        page = next;
 | 
			
		||||
    }
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    free(page);
 | 
			
		||||
#else
 | 
			
		||||
        _aligned_free(page);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,9 @@
 | 
			
		|||
#include <stdlib.h>     /* getenv */
 | 
			
		||||
#endif
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,40 +10,6 @@
 | 
			
		|||
#include "lsquic_packet_common.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
 | 
			
		||||
    [QUIC_FRAME_INVALID]           =  "QUIC_FRAME_INVALID",
 | 
			
		||||
    [QUIC_FRAME_STREAM]            =  "QUIC_FRAME_STREAM",
 | 
			
		||||
    [QUIC_FRAME_ACK]               =  "QUIC_FRAME_ACK",
 | 
			
		||||
    [QUIC_FRAME_PADDING]           =  "QUIC_FRAME_PADDING",
 | 
			
		||||
    [QUIC_FRAME_RST_STREAM]        =  "QUIC_FRAME_RST_STREAM",
 | 
			
		||||
    [QUIC_FRAME_CONNECTION_CLOSE]  =  "QUIC_FRAME_CONNECTION_CLOSE",
 | 
			
		||||
    [QUIC_FRAME_GOAWAY]            =  "QUIC_FRAME_GOAWAY",
 | 
			
		||||
    [QUIC_FRAME_WINDOW_UPDATE]     =  "QUIC_FRAME_WINDOW_UPDATE",
 | 
			
		||||
    [QUIC_FRAME_BLOCKED]           =  "QUIC_FRAME_BLOCKED",
 | 
			
		||||
    [QUIC_FRAME_STOP_WAITING]      =  "QUIC_FRAME_STOP_WAITING",
 | 
			
		||||
    [QUIC_FRAME_PING]              =  "QUIC_FRAME_PING",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SLEN(x) (sizeof(#x) - sizeof("QUIC_FRAME_"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const size_t lsquic_frame_types_str_sz =
 | 
			
		||||
    /* We don't need to include INVALID frame in this list because it is
 | 
			
		||||
     * never a part of any frame list bitmask (e.g. po_frame_types).
 | 
			
		||||
     */
 | 
			
		||||
    SLEN(QUIC_FRAME_STREAM)           + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_ACK)              + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_PADDING)          + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_RST_STREAM)       + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_CONNECTION_CLOSE) + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_GOAWAY)           + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_WINDOW_UPDATE)    + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_BLOCKED)          + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_STOP_WAITING)     + 1 +
 | 
			
		||||
    SLEN(QUIC_FRAME_PING)             + 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
lsquic_frame_types_to_str (char *buf, size_t bufsz,
 | 
			
		||||
                                           enum quic_ft_bit frame_types)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,40 @@ enum quic_ft_bit {
 | 
			
		|||
    QUIC_FTBIT_PING             = 1 << QUIC_FRAME_PING,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const size_t lsquic_frame_types_str_sz;
 | 
			
		||||
static const char * const frame_type_2_str[N_QUIC_FRAMES] = {
 | 
			
		||||
    [QUIC_FRAME_INVALID]           =  "QUIC_FRAME_INVALID",
 | 
			
		||||
    [QUIC_FRAME_STREAM]            =  "QUIC_FRAME_STREAM",
 | 
			
		||||
    [QUIC_FRAME_ACK]               =  "QUIC_FRAME_ACK",
 | 
			
		||||
    [QUIC_FRAME_PADDING]           =  "QUIC_FRAME_PADDING",
 | 
			
		||||
    [QUIC_FRAME_RST_STREAM]        =  "QUIC_FRAME_RST_STREAM",
 | 
			
		||||
    [QUIC_FRAME_CONNECTION_CLOSE]  =  "QUIC_FRAME_CONNECTION_CLOSE",
 | 
			
		||||
    [QUIC_FRAME_GOAWAY]            =  "QUIC_FRAME_GOAWAY",
 | 
			
		||||
    [QUIC_FRAME_WINDOW_UPDATE]     =  "QUIC_FRAME_WINDOW_UPDATE",
 | 
			
		||||
    [QUIC_FRAME_BLOCKED]           =  "QUIC_FRAME_BLOCKED",
 | 
			
		||||
    [QUIC_FRAME_STOP_WAITING]      =  "QUIC_FRAME_STOP_WAITING",
 | 
			
		||||
    [QUIC_FRAME_PING]              =  "QUIC_FRAME_PING",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SLEN(x) (sizeof(#x) - sizeof("QUIC_FRAME_"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* We don't need to include INVALID frame in this list because it is
 | 
			
		||||
     * never a part of any frame list bitmask (e.g. po_frame_types).
 | 
			
		||||
     */
 | 
			
		||||
#define lsquic_frame_types_str_sz  \
 | 
			
		||||
    SLEN(QUIC_FRAME_STREAM)           + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_ACK)              + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_PADDING)          + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_RST_STREAM)       + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_CONNECTION_CLOSE) + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_GOAWAY)           + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_WINDOW_UPDATE)    + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_BLOCKED)          + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_STOP_WAITING)     + 1 + \
 | 
			
		||||
    SLEN(QUIC_FRAME_PING)             + 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,10 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,6 @@
 | 
			
		|||
#ifndef LSQUIC_PACKET_IN_H
 | 
			
		||||
#define LSQUIC_PACKET_IN_H 1
 | 
			
		||||
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
struct lsquic_packet_in;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
#include "lsquic_ev_log.h"
 | 
			
		||||
 | 
			
		||||
typedef char _stream_rec_arr_is_at_most_64bytes[
 | 
			
		||||
                                (sizeof(struct stream_rec_arr) <= 64) - 1];
 | 
			
		||||
                                (sizeof(struct stream_rec_arr) <= 64)? 1: - 1];
 | 
			
		||||
 | 
			
		||||
static struct stream_rec *
 | 
			
		||||
srec_one_posi_first (struct packet_out_srec_iter *posi,
 | 
			
		||||
| 
						 | 
				
			
			@ -615,7 +615,7 @@ lsquic_packet_out_split_in_two (struct lsquic_mm *mm,
 | 
			
		|||
    struct stream_rec **new_srecs, **srecs = local_arr;
 | 
			
		||||
    struct stream_rec *srec;
 | 
			
		||||
    unsigned n_srecs_alloced = sizeof(local_arr) / sizeof(local_arr[0]);
 | 
			
		||||
    unsigned n_srecs, max_idx, n, nbytes;
 | 
			
		||||
    unsigned n_srecs, max_idx = 0, n, nbytes;
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    unsigned short frame_sum = 0;
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,11 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -464,11 +468,13 @@ gquic_ietf_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
 | 
			
		|||
    p += largest_acked_len;
 | 
			
		||||
 | 
			
		||||
    CHECKOUT(2);
 | 
			
		||||
    lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
    gquic_be_write_float_time16(diff, p);
 | 
			
		||||
    LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
                                                            *(uint16_t*)p);
 | 
			
		||||
    p += 2;
 | 
			
		||||
    {
 | 
			
		||||
        lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
        gquic_be_write_float_time16(diff, p);
 | 
			
		||||
        LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
            *(uint16_t*)p);
 | 
			
		||||
        p += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *has_missing = n_ranges > 1;
 | 
			
		||||
    if (n_ranges > 1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,11 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -880,11 +884,13 @@ gquic_be_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
 | 
			
		|||
    p += largest_acked_len;
 | 
			
		||||
 | 
			
		||||
    CHECKOUT(2);
 | 
			
		||||
    lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
    gquic_be_write_float_time16(diff, p);
 | 
			
		||||
    LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
                                                            *(uint16_t*)p);
 | 
			
		||||
    p += 2;
 | 
			
		||||
    {
 | 
			
		||||
        lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
        gquic_be_write_float_time16(diff, p);
 | 
			
		||||
        LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
            *(uint16_t*)p);
 | 
			
		||||
        p += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (n_ranges > 1)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,10 @@
 | 
			
		|||
#define bswap_16 OSSwapInt16
 | 
			
		||||
#define bswap_32 OSSwapInt32
 | 
			
		||||
#define bswap_64 OSSwapInt64
 | 
			
		||||
#elif defined(WIN32)
 | 
			
		||||
#define bswap_16 _byteswap_ushort
 | 
			
		||||
#define bswap_32 _byteswap_ulong
 | 
			
		||||
#define bswap_64 _byteswap_uint64
 | 
			
		||||
#else
 | 
			
		||||
#include <byteswap.h>
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,12 @@
 | 
			
		|||
#include <inttypes.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_packet_common.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,11 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -766,11 +770,13 @@ gquic_le_gen_ack_frame (unsigned char *outbuf, size_t outbuf_sz,
 | 
			
		|||
    p += largest_acked_len;
 | 
			
		||||
 | 
			
		||||
    CHECKOUT(2);
 | 
			
		||||
    lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
    gquic_le_write_float_time16(diff, p);
 | 
			
		||||
    LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
                                                            *(uint16_t*)p);
 | 
			
		||||
    p += 2;
 | 
			
		||||
    {
 | 
			
		||||
        lsquic_time_t diff = now - rechist_largest_recv(rechist);
 | 
			
		||||
        gquic_le_write_float_time16(diff, p);
 | 
			
		||||
        LSQ_DEBUG("%s: diff: %"PRIu64"; encoded: 0x%04X", __func__, diff,
 | 
			
		||||
            *(uint16_t*)p);
 | 
			
		||||
        p += 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (n_ranges > 1)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <inttypes.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@
 | 
			
		|||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_rtt.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -299,7 +299,7 @@ static void
 | 
			
		|||
set_retx_alarm (lsquic_send_ctl_t *ctl)
 | 
			
		||||
{
 | 
			
		||||
    enum retx_mode rm;
 | 
			
		||||
    lsquic_time_t delay, now;
 | 
			
		||||
    lsquic_time_t delay = 0, now;
 | 
			
		||||
 | 
			
		||||
    assert(!TAILQ_EMPTY(&ctl->sc_unacked_packets));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -879,8 +879,10 @@ lsquic_send_ctl_pacer_blocked (struct lsquic_send_ctl *ctl)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
#if __GNUC__
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
int
 | 
			
		||||
lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -912,7 +914,7 @@ static void
 | 
			
		|||
send_ctl_expire (lsquic_send_ctl_t *ctl, enum expire_filter filter)
 | 
			
		||||
{
 | 
			
		||||
    lsquic_packet_out_t *packet_out, *next;
 | 
			
		||||
    int n_resubmitted;
 | 
			
		||||
    int n_resubmitted =0;
 | 
			
		||||
    static const char *const filter_type2str[] = {
 | 
			
		||||
        [EXFI_ALL] = "all",
 | 
			
		||||
        [EXFI_HSK] = "handshake",
 | 
			
		||||
| 
						 | 
				
			
			@ -1282,7 +1284,7 @@ lsquic_send_ctl_set_tcid0 (lsquic_send_ctl_t *ctl, int tcid0)
 | 
			
		|||
void
 | 
			
		||||
lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
 | 
			
		||||
{
 | 
			
		||||
    struct lsquic_packet_out *packet_out, *next;
 | 
			
		||||
    struct lsquic_packet_out *packet_out = NULL, *next = NULL;
 | 
			
		||||
    unsigned n, adj;
 | 
			
		||||
 | 
			
		||||
    for (packet_out = TAILQ_FIRST(&ctl->sc_scheduled_packets); packet_out;
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,8 +1339,10 @@ lsquic_send_ctl_elide_stream_frames (lsquic_send_ctl_t *ctl, uint32_t stream_id)
 | 
			
		|||
 * packets.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
#if  __GNUC__
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
int
 | 
			
		||||
lsquic_send_ctl_have_delayed_packets (const lsquic_send_ctl_t *ctl)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,9 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +24,7 @@
 | 
			
		|||
#define LSQUIC_LOG_CONN_ID iter->spi_cid
 | 
			
		||||
#include "lsquic_logger.h"
 | 
			
		||||
 | 
			
		||||
#define SPI_DEBUG(fmt, a...) LSQ_DEBUG("%s: " fmt, iter->spi_name, a)
 | 
			
		||||
#define SPI_DEBUG(fmt, ...) LSQ_DEBUG("%s: " fmt, iter->spi_name, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#define NEXT_STREAM(stream, off) \
 | 
			
		||||
    (* (struct lsquic_stream **) ((unsigned char *) (stream) + (off)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1702,7 +1702,7 @@ lsquic_stream_write (lsquic_stream_t *stream, const void *buf, size_t len)
 | 
			
		|||
 | 
			
		||||
struct inner_reader_iovec {
 | 
			
		||||
    const struct iovec       *iov;
 | 
			
		||||
    const struct iovec *const end;
 | 
			
		||||
    const struct iovec *end;
 | 
			
		||||
    unsigned                  cur_iovec_off;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,9 +7,13 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !(defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0) && defined(__APPLE__)
 | 
			
		||||
#include <mach/mach_time.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +26,9 @@
 | 
			
		|||
#if defined(__APPLE__)
 | 
			
		||||
static mach_timebase_info_data_t timebase;
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(WIN32)
 | 
			
		||||
static LARGE_INTEGER perf_frequency;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
lsquic_init_timers (void)
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +36,9 @@ lsquic_init_timers (void)
 | 
			
		|||
#if defined(__APPLE__)
 | 
			
		||||
    mach_timebase_info(&timebase);
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(WIN32)
 | 
			
		||||
    QueryPerformanceFrequency(&perf_frequency);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +55,14 @@ lsquic_time_now (void)
 | 
			
		|||
    t /= timebase.denom;
 | 
			
		||||
    t /= 1000;
 | 
			
		||||
    return t;
 | 
			
		||||
#elif defined(WIN32)
 | 
			
		||||
    LARGE_INTEGER counter;
 | 
			
		||||
    lsquic_time_t t;
 | 
			
		||||
    QueryPerformanceCounter(&counter);
 | 
			
		||||
    t = counter.QuadPart;
 | 
			
		||||
    t *= 1000000;
 | 
			
		||||
    t /= perf_frequency.QuadPart;
 | 
			
		||||
    return t;
 | 
			
		||||
#else
 | 
			
		||||
#   warn Monotonically increasing clock is not available on this platform
 | 
			
		||||
    struct timeval tv;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +114,7 @@ char *get_bin_str(const void *s, size_t len, size_t max_display_len)
 | 
			
		|||
 | 
			
		||||
    pOutput = &str[0] + sprintf(str, "(%zd/%zd)=0x", len, lenOrg);
 | 
			
		||||
 | 
			
		||||
    for(p = s, pEnd = s + len; p < pEnd; ++p)
 | 
			
		||||
    for(p = s, pEnd = (unsigned char*)s + len; p < pEnd; ++p)
 | 
			
		||||
    {
 | 
			
		||||
        sprintf(pOutput, "%02X", *p);
 | 
			
		||||
        pOutput += 2;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,16 +3,29 @@
 | 
			
		|||
 * http_client.c -- A simple HTTP/QUIC client
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#include <WinSock2.h>
 | 
			
		||||
#include <io.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#define STDOUT_FILENO 1
 | 
			
		||||
#define random rand
 | 
			
		||||
#pragma warning(disable:4996) //POSIX name deprecated
 | 
			
		||||
#endif
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,362 +46,365 @@ static int promise_fd = -1;
 | 
			
		|||
struct lsquic_conn_ctx;
 | 
			
		||||
 | 
			
		||||
struct path_elem {
 | 
			
		||||
    TAILQ_ENTRY(path_elem)      next_pe;
 | 
			
		||||
    const char                 *path;
 | 
			
		||||
	TAILQ_ENTRY(path_elem)      next_pe;
 | 
			
		||||
	const char                 *path;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct http_client_ctx {
 | 
			
		||||
    TAILQ_HEAD(, lsquic_conn_ctx)
 | 
			
		||||
                                 conn_ctxs;
 | 
			
		||||
    struct service_port         *sport;
 | 
			
		||||
    const char                  *hostname;
 | 
			
		||||
    const char                  *method;
 | 
			
		||||
    const char                  *payload;
 | 
			
		||||
    char                         payload_size[20];
 | 
			
		||||
	TAILQ_HEAD(, lsquic_conn_ctx)
 | 
			
		||||
								 conn_ctxs;
 | 
			
		||||
	struct service_port         *sport;
 | 
			
		||||
	const char                  *hostname;
 | 
			
		||||
	const char                  *method;
 | 
			
		||||
	const char                  *payload;
 | 
			
		||||
	char                         payload_size[20];
 | 
			
		||||
 | 
			
		||||
    /* hcc_path_elems holds a list of paths which are to be requested from
 | 
			
		||||
     * the server.  Each new request gets the next path from the list (the
 | 
			
		||||
     * iterator is stored in hcc_cur_pe); when the end is reached, the
 | 
			
		||||
     * iterator wraps around.
 | 
			
		||||
     */
 | 
			
		||||
    TAILQ_HEAD(, path_elem)      hcc_path_elems;
 | 
			
		||||
    struct path_elem            *hcc_cur_pe;
 | 
			
		||||
	/* hcc_path_elems holds a list of paths which are to be requested from
 | 
			
		||||
	 * the server.  Each new request gets the next path from the list (the
 | 
			
		||||
	 * iterator is stored in hcc_cur_pe); when the end is reached, the
 | 
			
		||||
	 * iterator wraps around.
 | 
			
		||||
	 */
 | 
			
		||||
	TAILQ_HEAD(, path_elem)      hcc_path_elems;
 | 
			
		||||
	struct path_elem            *hcc_cur_pe;
 | 
			
		||||
 | 
			
		||||
    unsigned                     hcc_total_n_reqs;
 | 
			
		||||
    unsigned                     hcc_reqs_per_conn;
 | 
			
		||||
    unsigned                     hcc_concurrency;
 | 
			
		||||
    unsigned                     hcc_n_open_conns;
 | 
			
		||||
	unsigned                     hcc_total_n_reqs;
 | 
			
		||||
	unsigned                     hcc_reqs_per_conn;
 | 
			
		||||
	unsigned                     hcc_concurrency;
 | 
			
		||||
	unsigned                     hcc_n_open_conns;
 | 
			
		||||
 | 
			
		||||
    enum {
 | 
			
		||||
        HCC_DISCARD_RESPONSE    = (1 << 0),
 | 
			
		||||
        HCC_SEEN_FIN            = (1 << 1),
 | 
			
		||||
        HCC_ABORT_ON_INCOMPLETE = (1 << 2),
 | 
			
		||||
    }                            hcc_flags;
 | 
			
		||||
    struct prog                 *prog;
 | 
			
		||||
	enum {
 | 
			
		||||
		HCC_DISCARD_RESPONSE    = (1 << 0),
 | 
			
		||||
		HCC_SEEN_FIN            = (1 << 1),
 | 
			
		||||
		HCC_ABORT_ON_INCOMPLETE = (1 << 2),
 | 
			
		||||
	}                            hcc_flags;
 | 
			
		||||
	struct prog                 *prog;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lsquic_conn_ctx {
 | 
			
		||||
    TAILQ_ENTRY(lsquic_conn_ctx) next_ch;
 | 
			
		||||
    lsquic_conn_t       *conn;
 | 
			
		||||
    struct http_client_ctx   *client_ctx;
 | 
			
		||||
    unsigned             ch_n_reqs;    /* This number gets decremented as streams are closed and
 | 
			
		||||
                                        * incremented as push promises are accepted.
 | 
			
		||||
                                        */
 | 
			
		||||
	TAILQ_ENTRY(lsquic_conn_ctx) next_ch;
 | 
			
		||||
	lsquic_conn_t       *conn;
 | 
			
		||||
	struct http_client_ctx   *client_ctx;
 | 
			
		||||
	unsigned             ch_n_reqs;    /* This number gets decremented as streams are closed and
 | 
			
		||||
										* incremented as push promises are accepted.
 | 
			
		||||
										*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
create_connections (struct http_client_ctx *client_ctx)
 | 
			
		||||
{
 | 
			
		||||
    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))
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_ERROR("connection failed");
 | 
			
		||||
            exit(EXIT_FAILURE);
 | 
			
		||||
        }
 | 
			
		||||
	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))
 | 
			
		||||
		{
 | 
			
		||||
			LSQ_ERROR("connection failed");
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static lsquic_conn_ctx_t *
 | 
			
		||||
http_client_on_new_conn (void *stream_if_ctx, lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    struct http_client_ctx *client_ctx = stream_if_ctx;
 | 
			
		||||
    lsquic_conn_ctx_t *conn_h = calloc(1, sizeof(*conn_h));
 | 
			
		||||
    conn_h->conn = conn;
 | 
			
		||||
    conn_h->client_ctx = client_ctx;
 | 
			
		||||
    conn_h->ch_n_reqs = client_ctx->hcc_total_n_reqs <
 | 
			
		||||
                                            client_ctx->hcc_reqs_per_conn ?
 | 
			
		||||
        client_ctx->hcc_total_n_reqs : client_ctx->hcc_reqs_per_conn;
 | 
			
		||||
    client_ctx->hcc_total_n_reqs -= conn_h->ch_n_reqs;
 | 
			
		||||
    TAILQ_INSERT_TAIL(&client_ctx->conn_ctxs, conn_h, next_ch);
 | 
			
		||||
    ++conn_h->client_ctx->hcc_n_open_conns;
 | 
			
		||||
    lsquic_conn_make_stream(conn);
 | 
			
		||||
    return conn_h;
 | 
			
		||||
	struct http_client_ctx *client_ctx = stream_if_ctx;
 | 
			
		||||
	lsquic_conn_ctx_t *conn_h = calloc(1, sizeof(*conn_h));
 | 
			
		||||
	conn_h->conn = conn;
 | 
			
		||||
	conn_h->client_ctx = client_ctx;
 | 
			
		||||
	conn_h->ch_n_reqs = client_ctx->hcc_total_n_reqs <
 | 
			
		||||
											client_ctx->hcc_reqs_per_conn ?
 | 
			
		||||
		client_ctx->hcc_total_n_reqs : client_ctx->hcc_reqs_per_conn;
 | 
			
		||||
	client_ctx->hcc_total_n_reqs -= conn_h->ch_n_reqs;
 | 
			
		||||
	TAILQ_INSERT_TAIL(&client_ctx->conn_ctxs, conn_h, next_ch);
 | 
			
		||||
	++conn_h->client_ctx->hcc_n_open_conns;
 | 
			
		||||
	lsquic_conn_make_stream(conn);
 | 
			
		||||
	return conn_h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
http_client_on_conn_closed (lsquic_conn_t *conn)
 | 
			
		||||
{
 | 
			
		||||
    lsquic_conn_ctx_t *conn_h = lsquic_conn_get_ctx(conn);
 | 
			
		||||
    enum LSQUIC_CONN_STATUS status;
 | 
			
		||||
    char errmsg[80];
 | 
			
		||||
	lsquic_conn_ctx_t *conn_h = lsquic_conn_get_ctx(conn);
 | 
			
		||||
	enum LSQUIC_CONN_STATUS status;
 | 
			
		||||
	char errmsg[80];
 | 
			
		||||
 | 
			
		||||
    status = lsquic_conn_status(conn, errmsg, sizeof(errmsg));
 | 
			
		||||
    LSQ_INFO("Connection closed.  Status: %d.  Message: %s", status,
 | 
			
		||||
        errmsg[0] ? errmsg : "<not set>");
 | 
			
		||||
	status = lsquic_conn_status(conn, errmsg, sizeof(errmsg));
 | 
			
		||||
	LSQ_INFO("Connection closed.  Status: %d.  Message: %s", status,
 | 
			
		||||
		errmsg[0] ? errmsg : "<not set>");
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    if (conn_h->client_ctx->hcc_flags & HCC_ABORT_ON_INCOMPLETE)
 | 
			
		||||
        assert(conn_h->client_ctx->hcc_flags & HCC_SEEN_FIN);
 | 
			
		||||
	if (conn_h->client_ctx->hcc_flags & HCC_ABORT_ON_INCOMPLETE)
 | 
			
		||||
		assert(conn_h->client_ctx->hcc_flags & HCC_SEEN_FIN);
 | 
			
		||||
#endif
 | 
			
		||||
    TAILQ_REMOVE(&conn_h->client_ctx->conn_ctxs, conn_h, next_ch);
 | 
			
		||||
    --conn_h->client_ctx->hcc_n_open_conns;
 | 
			
		||||
    create_connections(conn_h->client_ctx);
 | 
			
		||||
    if (0 == conn_h->client_ctx->hcc_n_open_conns)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("All connections are closed: stop engine");
 | 
			
		||||
        prog_stop(conn_h->client_ctx->prog);
 | 
			
		||||
    }
 | 
			
		||||
    free(conn_h);
 | 
			
		||||
	TAILQ_REMOVE(&conn_h->client_ctx->conn_ctxs, conn_h, next_ch);
 | 
			
		||||
	--conn_h->client_ctx->hcc_n_open_conns;
 | 
			
		||||
	create_connections(conn_h->client_ctx);
 | 
			
		||||
	if (0 == conn_h->client_ctx->hcc_n_open_conns)
 | 
			
		||||
	{
 | 
			
		||||
		LSQ_INFO("All connections are closed: stop engine");
 | 
			
		||||
		prog_stop(conn_h->client_ctx->prog);
 | 
			
		||||
	}
 | 
			
		||||
	free(conn_h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct lsquic_stream_ctx {
 | 
			
		||||
    lsquic_stream_t     *stream;
 | 
			
		||||
    struct http_client_ctx   *client_ctx;
 | 
			
		||||
    const char          *path;
 | 
			
		||||
    enum {
 | 
			
		||||
        HEADERS_SENT    = (1 << 0),
 | 
			
		||||
    }                    sh_flags;
 | 
			
		||||
    unsigned             count;
 | 
			
		||||
    struct lsquic_reader reader;
 | 
			
		||||
	lsquic_stream_t     *stream;
 | 
			
		||||
	struct http_client_ctx   *client_ctx;
 | 
			
		||||
	const char          *path;
 | 
			
		||||
	enum {
 | 
			
		||||
		HEADERS_SENT    = (1 << 0),
 | 
			
		||||
	}                    sh_flags;
 | 
			
		||||
	unsigned             count;
 | 
			
		||||
	struct lsquic_reader reader;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static lsquic_stream_ctx_t *
 | 
			
		||||
http_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
 | 
			
		||||
{
 | 
			
		||||
    const int pushed = lsquic_stream_is_pushed(stream);
 | 
			
		||||
	const int pushed = lsquic_stream_is_pushed(stream);
 | 
			
		||||
 | 
			
		||||
    if (pushed)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("not accepting server push");
 | 
			
		||||
        lsquic_stream_refuse_push(stream);
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
	if (pushed)
 | 
			
		||||
	{
 | 
			
		||||
		LSQ_INFO("not accepting server push");
 | 
			
		||||
		lsquic_stream_refuse_push(stream);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    lsquic_stream_ctx_t *st_h = calloc(1, sizeof(*st_h));
 | 
			
		||||
    st_h->stream = stream;
 | 
			
		||||
    st_h->client_ctx = stream_if_ctx;
 | 
			
		||||
    if (st_h->client_ctx->hcc_cur_pe)
 | 
			
		||||
    {
 | 
			
		||||
        st_h->client_ctx->hcc_cur_pe = TAILQ_NEXT(
 | 
			
		||||
                                        st_h->client_ctx->hcc_cur_pe, next_pe);
 | 
			
		||||
        if (!st_h->client_ctx->hcc_cur_pe)  /* Wrap around */
 | 
			
		||||
            st_h->client_ctx->hcc_cur_pe =
 | 
			
		||||
                                TAILQ_FIRST(&st_h->client_ctx->hcc_path_elems);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        st_h->client_ctx->hcc_cur_pe = TAILQ_FIRST(
 | 
			
		||||
                                            &st_h->client_ctx->hcc_path_elems);
 | 
			
		||||
    st_h->path = st_h->client_ctx->hcc_cur_pe->path;
 | 
			
		||||
    if (st_h->client_ctx->payload)
 | 
			
		||||
    {
 | 
			
		||||
        st_h->reader.lsqr_read = test_reader_read;
 | 
			
		||||
        st_h->reader.lsqr_size = test_reader_size;
 | 
			
		||||
        st_h->reader.lsqr_ctx = create_lsquic_reader_ctx(st_h->client_ctx->payload);
 | 
			
		||||
        if (!st_h->reader.lsqr_ctx)
 | 
			
		||||
            exit(1);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        st_h->reader.lsqr_ctx = NULL;
 | 
			
		||||
    LSQ_INFO("created new stream, path: %s", st_h->path);
 | 
			
		||||
    lsquic_stream_wantwrite(stream, 1);
 | 
			
		||||
	lsquic_stream_ctx_t *st_h = calloc(1, sizeof(*st_h));
 | 
			
		||||
	st_h->stream = stream;
 | 
			
		||||
	st_h->client_ctx = stream_if_ctx;
 | 
			
		||||
	if (st_h->client_ctx->hcc_cur_pe)
 | 
			
		||||
	{
 | 
			
		||||
		st_h->client_ctx->hcc_cur_pe = TAILQ_NEXT(
 | 
			
		||||
										st_h->client_ctx->hcc_cur_pe, next_pe);
 | 
			
		||||
		if (!st_h->client_ctx->hcc_cur_pe)  /* Wrap around */
 | 
			
		||||
			st_h->client_ctx->hcc_cur_pe =
 | 
			
		||||
								TAILQ_FIRST(&st_h->client_ctx->hcc_path_elems);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		st_h->client_ctx->hcc_cur_pe = TAILQ_FIRST(
 | 
			
		||||
											&st_h->client_ctx->hcc_path_elems);
 | 
			
		||||
	st_h->path = st_h->client_ctx->hcc_cur_pe->path;
 | 
			
		||||
	if (st_h->client_ctx->payload)
 | 
			
		||||
	{
 | 
			
		||||
		st_h->reader.lsqr_read = test_reader_read;
 | 
			
		||||
		st_h->reader.lsqr_size = test_reader_size;
 | 
			
		||||
		st_h->reader.lsqr_ctx = create_lsquic_reader_ctx(st_h->client_ctx->payload);
 | 
			
		||||
		if (!st_h->reader.lsqr_ctx)
 | 
			
		||||
			exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		st_h->reader.lsqr_ctx = NULL;
 | 
			
		||||
	LSQ_INFO("created new stream, path: %s", st_h->path);
 | 
			
		||||
	lsquic_stream_wantwrite(stream, 1);
 | 
			
		||||
 | 
			
		||||
    return st_h;
 | 
			
		||||
	return st_h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
send_headers (lsquic_stream_ctx_t *st_h)
 | 
			
		||||
{
 | 
			
		||||
    lsquic_http_header_t headers_arr[] = {
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = ":method",       .iov_len = 7, },
 | 
			
		||||
            .value = { .iov_base = (void *) st_h->client_ctx->method,
 | 
			
		||||
                       .iov_len = strlen(st_h->client_ctx->method), },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = ":scheme",       .iov_len = 7, },
 | 
			
		||||
            .value = { .iov_base = "HTTP",          .iov_len = 4, }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = ":path",         .iov_len = 5, },
 | 
			
		||||
            .value = { .iov_base = (void *) st_h->path,
 | 
			
		||||
                       .iov_len = strlen(st_h->path), },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { ":authority",     10, },
 | 
			
		||||
            .value = { .iov_base = (void *) st_h->client_ctx->hostname,
 | 
			
		||||
                       .iov_len = strlen(st_h->client_ctx->hostname), },
 | 
			
		||||
        },
 | 
			
		||||
        /*
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { "host",      4 },
 | 
			
		||||
            .value = { .iov_base = (void *) st_h->client_ctx->hostname,
 | 
			
		||||
                       .iov_len = strlen(st_h->client_ctx->hostname), },
 | 
			
		||||
        },
 | 
			
		||||
        */
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = "user-agent",    .iov_len = 10, },
 | 
			
		||||
            .value = { .iov_base = (char *) st_h->client_ctx->prog->prog_settings.es_ua,
 | 
			
		||||
                       .iov_len  = strlen(st_h->client_ctx->prog->prog_settings.es_ua), },
 | 
			
		||||
        },
 | 
			
		||||
        /* The following headers only gets sent if there is request payload: */
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = "content-type", .iov_len = 12, },
 | 
			
		||||
            .value = { .iov_base = "application/octet-stream", .iov_len = 24, },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name  = { .iov_base = "content-length", .iov_len = 14, },
 | 
			
		||||
            .value = { .iov_base = (void *) st_h->client_ctx->payload_size,
 | 
			
		||||
                       .iov_len = strlen(st_h->client_ctx->payload_size), },
 | 
			
		||||
        },
 | 
			
		||||
    };
 | 
			
		||||
    lsquic_http_headers_t headers = {
 | 
			
		||||
        .count = sizeof(headers_arr) / sizeof(headers_arr[0]),
 | 
			
		||||
        .headers = headers_arr,
 | 
			
		||||
    };
 | 
			
		||||
    if (!st_h->client_ctx->payload)
 | 
			
		||||
        headers.count -= 2;
 | 
			
		||||
    if (0 != lsquic_stream_send_headers(st_h->stream, &headers,
 | 
			
		||||
                                    st_h->client_ctx->payload == NULL))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("cannot send headers: %s", strerror(errno));
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
	lsquic_http_header_t headers_arr[] = {
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = ":method",       .iov_len = 7, },
 | 
			
		||||
			.value = { .iov_base = (void *) st_h->client_ctx->method,
 | 
			
		||||
					   .iov_len = strlen(st_h->client_ctx->method), },
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = ":scheme",       .iov_len = 7, },
 | 
			
		||||
			.value = { .iov_base = "HTTP",          .iov_len = 4, }
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = ":path",         .iov_len = 5, },
 | 
			
		||||
			.value = { .iov_base = (void *) st_h->path,
 | 
			
		||||
					   .iov_len = strlen(st_h->path), },
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { ":authority",     10, },
 | 
			
		||||
			.value = { .iov_base = (void *) st_h->client_ctx->hostname,
 | 
			
		||||
					   .iov_len = strlen(st_h->client_ctx->hostname), },
 | 
			
		||||
		},
 | 
			
		||||
		/*
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { "host",      4 },
 | 
			
		||||
			.value = { .iov_base = (void *) st_h->client_ctx->hostname,
 | 
			
		||||
					   .iov_len = strlen(st_h->client_ctx->hostname), },
 | 
			
		||||
		},
 | 
			
		||||
		*/
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = "user-agent",    .iov_len = 10, },
 | 
			
		||||
			.value = { .iov_base = (char *) st_h->client_ctx->prog->prog_settings.es_ua,
 | 
			
		||||
					   .iov_len  = strlen(st_h->client_ctx->prog->prog_settings.es_ua), },
 | 
			
		||||
		},
 | 
			
		||||
		/* The following headers only gets sent if there is request payload: */
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = "content-type", .iov_len = 12, },
 | 
			
		||||
			.value = { .iov_base = "application/octet-stream", .iov_len = 24, },
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			.name  = { .iov_base = "content-length", .iov_len = 14, },
 | 
			
		||||
			.value = { .iov_base = (void *) st_h->client_ctx->payload_size,
 | 
			
		||||
					   .iov_len = strlen(st_h->client_ctx->payload_size), },
 | 
			
		||||
		},
 | 
			
		||||
	};
 | 
			
		||||
	lsquic_http_headers_t headers = {
 | 
			
		||||
		.count = sizeof(headers_arr) / sizeof(headers_arr[0]),
 | 
			
		||||
		.headers = headers_arr,
 | 
			
		||||
	};
 | 
			
		||||
	if (!st_h->client_ctx->payload)
 | 
			
		||||
		headers.count -= 2;
 | 
			
		||||
	if (0 != lsquic_stream_send_headers(st_h->stream, &headers,
 | 
			
		||||
									st_h->client_ctx->payload == NULL))
 | 
			
		||||
	{
 | 
			
		||||
		LSQ_ERROR("cannot send headers: %s", strerror(errno));
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		||||
{
 | 
			
		||||
    ssize_t nw;
 | 
			
		||||
	ssize_t nw;
 | 
			
		||||
 | 
			
		||||
    if (st_h->sh_flags & HEADERS_SENT)
 | 
			
		||||
    {
 | 
			
		||||
        if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
 | 
			
		||||
        {
 | 
			
		||||
            nw = lsquic_stream_writef(stream, &st_h->reader);
 | 
			
		||||
            if (nw < 0)
 | 
			
		||||
            {
 | 
			
		||||
                LSQ_ERROR("write error: %s", strerror(errno));
 | 
			
		||||
                exit(1);
 | 
			
		||||
            }
 | 
			
		||||
            if (test_reader_size(st_h->reader.lsqr_ctx) > 0)
 | 
			
		||||
            {
 | 
			
		||||
                lsquic_stream_wantwrite(stream, 1);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                lsquic_stream_shutdown(stream, 1);
 | 
			
		||||
                lsquic_stream_wantread(stream, 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            lsquic_stream_shutdown(stream, 1);
 | 
			
		||||
            lsquic_stream_wantread(stream, 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        st_h->sh_flags |= HEADERS_SENT;
 | 
			
		||||
        send_headers(st_h);
 | 
			
		||||
    }
 | 
			
		||||
	if (st_h->sh_flags & HEADERS_SENT)
 | 
			
		||||
	{
 | 
			
		||||
		if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
 | 
			
		||||
		{
 | 
			
		||||
			nw = lsquic_stream_writef(stream, &st_h->reader);
 | 
			
		||||
			if (nw < 0)
 | 
			
		||||
			{
 | 
			
		||||
				LSQ_ERROR("write error: %s", strerror(errno));
 | 
			
		||||
				exit(1);
 | 
			
		||||
			}
 | 
			
		||||
			if (test_reader_size(st_h->reader.lsqr_ctx) > 0)
 | 
			
		||||
			{
 | 
			
		||||
				lsquic_stream_wantwrite(stream, 1);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				lsquic_stream_shutdown(stream, 1);
 | 
			
		||||
				lsquic_stream_wantread(stream, 1);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			lsquic_stream_shutdown(stream, 1);
 | 
			
		||||
			lsquic_stream_wantread(stream, 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		st_h->sh_flags |= HEADERS_SENT;
 | 
			
		||||
		send_headers(st_h);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		||||
{
 | 
			
		||||
    struct http_client_ctx *const client_ctx = st_h->client_ctx;
 | 
			
		||||
    ssize_t nread;
 | 
			
		||||
    unsigned old_prio, new_prio;
 | 
			
		||||
    unsigned char buf[0x200];
 | 
			
		||||
    unsigned nreads = 0;
 | 
			
		||||
 | 
			
		||||
    do
 | 
			
		||||
    {
 | 
			
		||||
        nread = lsquic_stream_read(stream, buf, sizeof(buf));
 | 
			
		||||
        if (nread > 0)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(client_ctx->hcc_flags & HCC_DISCARD_RESPONSE))
 | 
			
		||||
                write(STDOUT_FILENO, buf, nread);
 | 
			
		||||
            if (randomly_reprioritize_streams && (st_h->count++ & 0x3F) == 0)
 | 
			
		||||
            {
 | 
			
		||||
                old_prio = lsquic_stream_priority(stream);
 | 
			
		||||
                new_prio = random() & 0xFF;
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
                const int s =
 | 
			
		||||
	struct http_client_ctx *const client_ctx = st_h->client_ctx;
 | 
			
		||||
	ssize_t nread;
 | 
			
		||||
	unsigned old_prio, new_prio;
 | 
			
		||||
	unsigned char buf[0x200];
 | 
			
		||||
	unsigned nreads = 0;
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	srand(GetTickCount());
 | 
			
		||||
#endif
 | 
			
		||||
                lsquic_stream_set_priority(stream, new_prio);
 | 
			
		||||
                assert(s == 0);
 | 
			
		||||
                LSQ_NOTICE("changed stream %u priority from %u to %u",
 | 
			
		||||
                                lsquic_stream_id(stream), old_prio, new_prio);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (0 == nread)
 | 
			
		||||
        {
 | 
			
		||||
            client_ctx->hcc_flags |= HCC_SEEN_FIN;
 | 
			
		||||
            lsquic_stream_shutdown(stream, 0);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        else if (client_ctx->prog->prog_settings.es_rw_once && EWOULDBLOCK == errno)
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_NOTICE("emptied the buffer in 'once' mode");
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            LSQ_ERROR("could not read: %s", strerror(errno));
 | 
			
		||||
            exit(2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while (client_ctx->prog->prog_settings.es_rw_once
 | 
			
		||||
            && nreads++ < 3 /* Emulate just a few reads */);
 | 
			
		||||
 | 
			
		||||
	do
 | 
			
		||||
	{
 | 
			
		||||
		nread = lsquic_stream_read(stream, buf, sizeof(buf));
 | 
			
		||||
		if (nread > 0)
 | 
			
		||||
		{
 | 
			
		||||
			if (!(client_ctx->hcc_flags & HCC_DISCARD_RESPONSE))
 | 
			
		||||
				write(STDOUT_FILENO, buf, nread);
 | 
			
		||||
			if (randomly_reprioritize_streams && (st_h->count++ & 0x3F) == 0)
 | 
			
		||||
			{
 | 
			
		||||
				old_prio = lsquic_stream_priority(stream);
 | 
			
		||||
				new_prio = random() & 0xFF;
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
				const int s =
 | 
			
		||||
#endif
 | 
			
		||||
				lsquic_stream_set_priority(stream, new_prio);
 | 
			
		||||
				assert(s == 0);
 | 
			
		||||
				LSQ_NOTICE("changed stream %u priority from %u to %u",
 | 
			
		||||
								lsquic_stream_id(stream), old_prio, new_prio);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (0 == nread)
 | 
			
		||||
		{
 | 
			
		||||
			client_ctx->hcc_flags |= HCC_SEEN_FIN;
 | 
			
		||||
			lsquic_stream_shutdown(stream, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		else if (client_ctx->prog->prog_settings.es_rw_once && EWOULDBLOCK == errno)
 | 
			
		||||
		{
 | 
			
		||||
			LSQ_NOTICE("emptied the buffer in 'once' mode");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			LSQ_ERROR("could not read: %s", strerror(errno));
 | 
			
		||||
			exit(2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	while (client_ctx->prog->prog_settings.es_rw_once
 | 
			
		||||
			&& nreads++ < 3 /* Emulate just a few reads */);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
http_client_on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
 | 
			
		||||
{
 | 
			
		||||
    const int pushed = lsquic_stream_is_pushed(stream);
 | 
			
		||||
    if (pushed)
 | 
			
		||||
    {
 | 
			
		||||
        assert(NULL == st_h);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
	const int pushed = lsquic_stream_is_pushed(stream);
 | 
			
		||||
	if (pushed)
 | 
			
		||||
	{
 | 
			
		||||
		assert(NULL == st_h);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    LSQ_INFO("%s called", __func__);
 | 
			
		||||
    lsquic_conn_t *conn = lsquic_stream_conn(stream);
 | 
			
		||||
    lsquic_conn_ctx_t *conn_h;
 | 
			
		||||
    TAILQ_FOREACH(conn_h, &st_h->client_ctx->conn_ctxs, next_ch)
 | 
			
		||||
        if (conn_h->conn == conn)
 | 
			
		||||
            break;
 | 
			
		||||
    assert(conn_h);
 | 
			
		||||
    --conn_h->ch_n_reqs;
 | 
			
		||||
    if (0 == conn_h->ch_n_reqs)
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_INFO("all requests completed, closing connection");
 | 
			
		||||
        lsquic_conn_close(conn_h->conn);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        lsquic_conn_make_stream(conn);
 | 
			
		||||
    if (st_h->reader.lsqr_ctx)
 | 
			
		||||
        destroy_lsquic_reader_ctx(st_h->reader.lsqr_ctx);
 | 
			
		||||
    free(st_h);
 | 
			
		||||
	LSQ_INFO("%s called", __func__);
 | 
			
		||||
	lsquic_conn_t *conn = lsquic_stream_conn(stream);
 | 
			
		||||
	lsquic_conn_ctx_t *conn_h;
 | 
			
		||||
	TAILQ_FOREACH(conn_h, &st_h->client_ctx->conn_ctxs, next_ch)
 | 
			
		||||
		if (conn_h->conn == conn)
 | 
			
		||||
			break;
 | 
			
		||||
	assert(conn_h);
 | 
			
		||||
	--conn_h->ch_n_reqs;
 | 
			
		||||
	if (0 == conn_h->ch_n_reqs)
 | 
			
		||||
	{
 | 
			
		||||
		LSQ_INFO("all requests completed, closing connection");
 | 
			
		||||
		lsquic_conn_close(conn_h->conn);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		lsquic_conn_make_stream(conn);
 | 
			
		||||
	if (st_h->reader.lsqr_ctx)
 | 
			
		||||
		destroy_lsquic_reader_ctx(st_h->reader.lsqr_ctx);
 | 
			
		||||
	free(st_h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const struct lsquic_stream_if http_client_if = {
 | 
			
		||||
    .on_new_conn            = http_client_on_new_conn,
 | 
			
		||||
    .on_conn_closed         = http_client_on_conn_closed,
 | 
			
		||||
    .on_new_stream          = http_client_on_new_stream,
 | 
			
		||||
    .on_read                = http_client_on_read,
 | 
			
		||||
    .on_write               = http_client_on_write,
 | 
			
		||||
    .on_close               = http_client_on_close,
 | 
			
		||||
	.on_new_conn            = http_client_on_new_conn,
 | 
			
		||||
	.on_conn_closed         = http_client_on_conn_closed,
 | 
			
		||||
	.on_new_stream          = http_client_on_new_stream,
 | 
			
		||||
	.on_read                = http_client_on_read,
 | 
			
		||||
	.on_write               = http_client_on_write,
 | 
			
		||||
	.on_close               = http_client_on_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
usage (const char *prog)
 | 
			
		||||
{
 | 
			
		||||
    const char *const slash = strrchr(prog, '/');
 | 
			
		||||
    if (slash)
 | 
			
		||||
        prog = slash + 1;
 | 
			
		||||
    printf(
 | 
			
		||||
	const char *const slash = strrchr(prog, '/');
 | 
			
		||||
	if (slash)
 | 
			
		||||
		prog = slash + 1;
 | 
			
		||||
	printf(
 | 
			
		||||
"Usage: %s [opts]\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Options:\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -404,117 +420,121 @@ usage (const char *prog)
 | 
			
		|||
"                 content-length\n"
 | 
			
		||||
"   -K          Discard server response\n"
 | 
			
		||||
"   -I          Abort on incomplete reponse from server\n"
 | 
			
		||||
            , prog);
 | 
			
		||||
			, prog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    int opt, s;
 | 
			
		||||
    struct http_client_ctx client_ctx;
 | 
			
		||||
    struct stat st;
 | 
			
		||||
    struct path_elem *pe;
 | 
			
		||||
    struct sport_head sports;
 | 
			
		||||
    struct prog prog;
 | 
			
		||||
	int opt, s;
 | 
			
		||||
	struct http_client_ctx client_ctx;
 | 
			
		||||
	struct stat st;
 | 
			
		||||
	struct path_elem *pe;
 | 
			
		||||
	struct sport_head sports;
 | 
			
		||||
	struct prog prog;
 | 
			
		||||
 | 
			
		||||
    TAILQ_INIT(&sports);
 | 
			
		||||
    memset(&client_ctx, 0, sizeof(client_ctx));
 | 
			
		||||
    client_ctx.hcc_concurrency = 1;
 | 
			
		||||
    TAILQ_INIT(&client_ctx.hcc_path_elems);
 | 
			
		||||
    TAILQ_INIT(&client_ctx.conn_ctxs);
 | 
			
		||||
    client_ctx.hostname = "localhost";
 | 
			
		||||
    client_ctx.method = "GET";
 | 
			
		||||
    client_ctx.hcc_concurrency = 1;
 | 
			
		||||
    client_ctx.hcc_reqs_per_conn = 1;
 | 
			
		||||
    client_ctx.hcc_total_n_reqs = 1;
 | 
			
		||||
    client_ctx.prog = &prog;
 | 
			
		||||
	TAILQ_INIT(&sports);
 | 
			
		||||
	memset(&client_ctx, 0, sizeof(client_ctx));
 | 
			
		||||
	client_ctx.hcc_concurrency = 1;
 | 
			
		||||
	TAILQ_INIT(&client_ctx.hcc_path_elems);
 | 
			
		||||
	TAILQ_INIT(&client_ctx.conn_ctxs);
 | 
			
		||||
	client_ctx.hostname = "localhost";
 | 
			
		||||
	client_ctx.method = "GET";
 | 
			
		||||
	client_ctx.hcc_concurrency = 1;
 | 
			
		||||
	client_ctx.hcc_reqs_per_conn = 1;
 | 
			
		||||
	client_ctx.hcc_total_n_reqs = 1;
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
    while (-1 != (opt = getopt(argc, argv, PROG_OPTS "r:R:Ku:EP:M:n:H:p:h")))
 | 
			
		||||
    {
 | 
			
		||||
        switch (opt) {
 | 
			
		||||
        case 'I':
 | 
			
		||||
            client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE;
 | 
			
		||||
            break;
 | 
			
		||||
        case 'K':
 | 
			
		||||
            client_ctx.hcc_flags |= HCC_DISCARD_RESPONSE;
 | 
			
		||||
            break;
 | 
			
		||||
        case 'u':   /* Accept p<U>sh promise */
 | 
			
		||||
            promise_fd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644);
 | 
			
		||||
            if (promise_fd < 0)
 | 
			
		||||
            {
 | 
			
		||||
                perror("open");
 | 
			
		||||
                exit(1);
 | 
			
		||||
            }
 | 
			
		||||
            prog.prog_settings.es_support_push = 1;     /* Pokes into prog */
 | 
			
		||||
            break;
 | 
			
		||||
        case 'E':   /* E: randomly reprioritize str<E>ams.  Now, that's
 | 
			
		||||
                     * pretty random. :)
 | 
			
		||||
                     */
 | 
			
		||||
            randomly_reprioritize_streams = 1;
 | 
			
		||||
            break;
 | 
			
		||||
        case 'n':
 | 
			
		||||
            client_ctx.hcc_concurrency = atoi(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'P':
 | 
			
		||||
            client_ctx.payload = optarg;
 | 
			
		||||
            if (0 != stat(optarg, &st))
 | 
			
		||||
            {
 | 
			
		||||
                perror("stat");
 | 
			
		||||
                exit(2);
 | 
			
		||||
            }
 | 
			
		||||
            sprintf(client_ctx.payload_size, "%jd", (intmax_t) st.st_size);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'M':
 | 
			
		||||
            client_ctx.method = optarg;
 | 
			
		||||
            break;
 | 
			
		||||
        case 'r':
 | 
			
		||||
            client_ctx.hcc_total_n_reqs = atoi(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'R':
 | 
			
		||||
            client_ctx.hcc_reqs_per_conn = atoi(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'H':
 | 
			
		||||
            client_ctx.hostname = optarg;
 | 
			
		||||
            prog.prog_hostname = optarg;            /* Pokes into prog */
 | 
			
		||||
            break;
 | 
			
		||||
        case 'p':
 | 
			
		||||
            pe = calloc(1, sizeof(*pe));
 | 
			
		||||
            pe->path = optarg;
 | 
			
		||||
            TAILQ_INSERT_TAIL(&client_ctx.hcc_path_elems, pe, next_pe);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'h':
 | 
			
		||||
            usage(argv[0]);
 | 
			
		||||
            prog_print_common_options(&prog, stdout);
 | 
			
		||||
            exit(0);
 | 
			
		||||
        default:
 | 
			
		||||
            if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
                exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	while (-1 != (opt = getopt(argc, argv, PROG_OPTS "r:R:Ku:EP:M:n:H:p:h")))
 | 
			
		||||
	{
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		case 'I':
 | 
			
		||||
			client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'K':
 | 
			
		||||
			client_ctx.hcc_flags |= HCC_DISCARD_RESPONSE;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'u':   /* Accept p<U>sh promise */
 | 
			
		||||
			promise_fd = open(optarg, O_WRONLY|O_CREAT|O_TRUNC, 0644);
 | 
			
		||||
			if (promise_fd < 0)
 | 
			
		||||
			{
 | 
			
		||||
				perror("open");
 | 
			
		||||
				exit(1);
 | 
			
		||||
			}
 | 
			
		||||
			prog.prog_settings.es_support_push = 1;     /* Pokes into prog */
 | 
			
		||||
			break;
 | 
			
		||||
		case 'E':   /* E: randomly reprioritize str<E>ams.  Now, that's
 | 
			
		||||
					 * pretty random. :)
 | 
			
		||||
					 */
 | 
			
		||||
			randomly_reprioritize_streams = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'n':
 | 
			
		||||
			client_ctx.hcc_concurrency = atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'P':
 | 
			
		||||
			client_ctx.payload = optarg;
 | 
			
		||||
			if (0 != stat(optarg, &st))
 | 
			
		||||
			{
 | 
			
		||||
				perror("stat");
 | 
			
		||||
				exit(2);
 | 
			
		||||
			}
 | 
			
		||||
			sprintf(client_ctx.payload_size, "%jd", (intmax_t) st.st_size);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'M':
 | 
			
		||||
			client_ctx.method = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'r':
 | 
			
		||||
			client_ctx.hcc_total_n_reqs = atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'R':
 | 
			
		||||
			client_ctx.hcc_reqs_per_conn = atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'H':
 | 
			
		||||
			client_ctx.hostname = optarg;
 | 
			
		||||
			prog.prog_hostname = optarg;            /* Pokes into prog */
 | 
			
		||||
			break;
 | 
			
		||||
		case 'p':
 | 
			
		||||
			pe = calloc(1, sizeof(*pe));
 | 
			
		||||
			pe->path = optarg;
 | 
			
		||||
			TAILQ_INSERT_TAIL(&client_ctx.hcc_path_elems, pe, next_pe);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'h':
 | 
			
		||||
			usage(argv[0]);
 | 
			
		||||
			prog_print_common_options(&prog, stdout);
 | 
			
		||||
			exit(0);
 | 
			
		||||
		default:
 | 
			
		||||
			if (0 != prog_set_opt(&prog, opt, optarg))
 | 
			
		||||
				exit(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if (TAILQ_EMPTY(&client_ctx.hcc_path_elems))
 | 
			
		||||
    {
 | 
			
		||||
        fprintf(stderr, "Specify at least one path using -p option\n");
 | 
			
		||||
        exit(1);
 | 
			
		||||
    }
 | 
			
		||||
	if (TAILQ_EMPTY(&client_ctx.hcc_path_elems))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Specify at least one path using -p option\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if (0 != prog_prep(&prog))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("could not prep");
 | 
			
		||||
        exit(EXIT_FAILURE);
 | 
			
		||||
    }
 | 
			
		||||
	if (0 != prog_prep(&prog))
 | 
			
		||||
	{
 | 
			
		||||
		LSQ_ERROR("could not prep");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    create_connections(&client_ctx);
 | 
			
		||||
	create_connections(&client_ctx);
 | 
			
		||||
 | 
			
		||||
    LSQ_DEBUG("entering event loop");
 | 
			
		||||
	LSQ_DEBUG("entering event loop");
 | 
			
		||||
 | 
			
		||||
    s = prog_run(&prog);
 | 
			
		||||
    prog_cleanup(&prog);
 | 
			
		||||
    if (promise_fd >= 0)
 | 
			
		||||
        (void) close(promise_fd);
 | 
			
		||||
	s = prog_run(&prog);
 | 
			
		||||
	prog_cleanup(&prog);
 | 
			
		||||
	if (promise_fd >= 0)
 | 
			
		||||
		(void) close(promise_fd);
 | 
			
		||||
 | 
			
		||||
    exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
 | 
			
		||||
	exit(0 == s ? EXIT_SUCCESS : EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,19 @@
 | 
			
		|||
/* Copyright (c) 2017 LiteSpeed Technologies Inc.  See LICENSE. */
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#pragma warning(disable:4028)
 | 
			
		||||
#endif// WIN32
 | 
			
		||||
 | 
			
		||||
#include <event2/event.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -349,9 +356,11 @@ prog_run (struct prog *prog)
 | 
			
		|||
    prog->prog_timer = event_new(prog->prog_eb, -1, EV_PERSIST,
 | 
			
		||||
                                        prog_timer_handler, prog);
 | 
			
		||||
    event_add(prog->prog_timer, &timeout);
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    prog->prog_usr1 = evsignal_new(prog->prog_eb, SIGUSR1,
 | 
			
		||||
                                                    prog_usr1_handler, prog);
 | 
			
		||||
    evsignal_add(prog->prog_usr1, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    event_base_loop(prog->prog_eb, 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,13 +8,21 @@
 | 
			
		|||
#if defined(__APPLE__)
 | 
			
		||||
#   define __APPLE_USE_RFC_3542 1
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#include <WinSock2.h>
 | 
			
		||||
#include<io.h>
 | 
			
		||||
#pragma warning(disable:4996)//posix name deprecated
 | 
			
		||||
#define close closesocket
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include <event2/event.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +83,7 @@ allocate_packets_in (int fd)
 | 
			
		|||
    int recvsz;
 | 
			
		||||
 | 
			
		||||
    opt_len = sizeof(recvsz);
 | 
			
		||||
    if (0 != getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, &opt_len))
 | 
			
		||||
    if (0 != getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&recvsz, &opt_len))
 | 
			
		||||
    {
 | 
			
		||||
        LSQ_ERROR("getsockopt failed: %s", strerror(errno));
 | 
			
		||||
        return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -415,6 +423,7 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /* Make socket non-blocking */
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    flags = fcntl(sockfd, F_GETFL);
 | 
			
		||||
    if (-1 == flags) {
 | 
			
		||||
        saved_errno = errno;
 | 
			
		||||
| 
						 | 
				
			
			@ -429,6 +438,12 @@ sport_init_server (struct service_port *sport, struct lsquic_engine *engine,
 | 
			
		|||
        errno = saved_errno;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    {
 | 
			
		||||
        on = 1;
 | 
			
		||||
        ioctlsocket(sockfd, FIONBIO, &on);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    on = 1;
 | 
			
		||||
    if (AF_INET == sa_local->sa_family)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,11 @@ enum sport_flags
 | 
			
		|||
 | 
			
		||||
struct service_port {
 | 
			
		||||
    TAILQ_ENTRY(service_port)  next_sport;
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    int                        fd;
 | 
			
		||||
#else
 | 
			
		||||
    SOCKET                        fd;
 | 
			
		||||
#endif
 | 
			
		||||
#if __linux__
 | 
			
		||||
    uint32_t                   n_dropped;
 | 
			
		||||
    int                        drop_init;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,237 +3,278 @@ include_directories( BEFORE ../../ssl/include )
 | 
			
		|||
include_directories( ../../include )
 | 
			
		||||
include_directories( ../../src/liblsquic )
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-value")
 | 
			
		||||
set(MIN_LIBS_LIST "m ${FIULIB}")
 | 
			
		||||
set(LIBS_LIST "pthread libssl.a libcrypto.a z ${MIN_LIBS_LIST}")
 | 
			
		||||
ELSE()
 | 
			
		||||
set(MIN_LIBS_LIST ${FIULIB} ws2_32)
 | 
			
		||||
set(LIBS_LIST ssl crypto ${ZLIB_NAME} ${MIN_LIBS_LIST})
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
enable_testing()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_rechist test_rechist.c)
 | 
			
		||||
target_link_libraries(test_rechist lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_rechist lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(rechist test_rechist)
 | 
			
		||||
 | 
			
		||||
add_executable(test_senhist test_senhist.c)
 | 
			
		||||
target_link_libraries(test_senhist lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_senhist lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(senhist test_senhist)
 | 
			
		||||
 | 
			
		||||
add_executable(test_rtt test_rtt.c)
 | 
			
		||||
target_link_libraries(test_rtt lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_rtt lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(rtt test_rtt)
 | 
			
		||||
 | 
			
		||||
add_executable(test_set test_set.c)
 | 
			
		||||
target_link_libraries(test_set lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_set lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(set test_set)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_engine_ctor test_engine_ctor.c)
 | 
			
		||||
target_link_libraries(test_engine_ctor lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_engine_ctor lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(engine_ctor test_engine_ctor)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_stream test_stream.c)
 | 
			
		||||
target_link_libraries(test_stream lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_stream lsquic ${LIBS_LIST})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_stream test_stream.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
target_link_libraries(test_stream lsquic ${LIBS_LIST} -FORCE:multiple)
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
add_test(stream test_stream)
 | 
			
		||||
add_test(stream_hash test_stream -h)
 | 
			
		||||
add_test(stream_A test_stream -A)
 | 
			
		||||
add_test(stream_hash_A test_stream -A -h)
 | 
			
		||||
 | 
			
		||||
add_executable(test_spi test_spi.c)
 | 
			
		||||
target_link_libraries(test_spi lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_spi lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(spi test_spi)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_malo test_malo.c)
 | 
			
		||||
target_link_libraries(test_malo lsquic m ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_malo test_malo.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
target_link_libraries(test_malo lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(malo test_malo)
 | 
			
		||||
 | 
			
		||||
add_executable(test_conn_hash test_conn_hash.c)
 | 
			
		||||
target_link_libraries(test_conn_hash lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_conn_hash lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(conn_hash test_conn_hash)
 | 
			
		||||
 | 
			
		||||
add_executable(test_lsquic_hash test_lsquic_hash.c)
 | 
			
		||||
target_link_libraries(test_lsquic_hash lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_lsquic_hash lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(lsquic_hash test_lsquic_hash)
 | 
			
		||||
 | 
			
		||||
add_executable(test_blocked_gquic_le test_blocked_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_blocked_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_blocked_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(blocked_gquic_le test_blocked_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_blocked_gquic_be test_blocked_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_blocked_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_blocked_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(blocked_gquic_be test_blocked_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_rst_stream_gquic_le test_rst_stream_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_rst_stream_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_rst_stream_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(rst_stream_gquic_le test_rst_stream_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_rst_stream_gquic_be test_rst_stream_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_rst_stream_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_rst_stream_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(rst_stream_gquic_be test_rst_stream_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_rst_stream_ietf test_rst_stream_ietf.c)
 | 
			
		||||
target_link_libraries(test_rst_stream_ietf lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_rst_stream_ietf lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(rst_stream_ietf test_rst_stream_ietf)
 | 
			
		||||
 | 
			
		||||
add_executable(test_conn_close_gquic_le test_conn_close_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_conn_close_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_conn_close_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(conn_close_gquic_le test_conn_close_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_conn_close_gquic_be test_conn_close_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_conn_close_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_conn_close_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(conn_close_gquic_be test_conn_close_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_goaway_gquic_le test_goaway_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_goaway_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_goaway_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(goaway_gquic_le test_goaway_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_goaway_gquic_be test_goaway_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_goaway_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_goaway_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(goaway_gquic_be test_goaway_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_wuf_gquic_le test_wuf_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_wuf_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_wuf_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(wuf_gquic_le test_wuf_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_wuf_gquic_be test_wuf_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_wuf_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_wuf_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(wuf_gquic_be test_wuf_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackparse_gquic_le test_ackparse_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackparse_gquic_le test_ackparse_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackparse_gquic_be test_ackparse_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackparse_gquic_be test_ackparse_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackparse_gquic_ietf test_ackparse_gquic_ietf.c)
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_ietf lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackparse_gquic_ietf lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackparse_gquic_ietf test_ackparse_gquic_ietf)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackgen_gquic_le test_ackgen_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackgen_gquic_le test_ackgen_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackgen_gquic_be test_ackgen_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackgen_gquic_be test_ackgen_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ackgen_gquic_ietf test_ackgen_gquic_ietf.c)
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_ietf lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ackgen_gquic_ietf lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ackgen_gquic_ietf test_ackgen_gquic_ietf)
 | 
			
		||||
 | 
			
		||||
add_executable(test_sfcw test_sfcw.c)
 | 
			
		||||
target_link_libraries(test_sfcw lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_sfcw lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(sfcw test_sfcw)
 | 
			
		||||
 | 
			
		||||
add_executable(test_alarmset test_alarmset.c)
 | 
			
		||||
target_link_libraries(test_alarmset lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_alarmset lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(alarmset test_alarmset)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(graph_cubic graph_cubic.c)
 | 
			
		||||
target_link_libraries(graph_cubic lsquic m ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(graph_cubic graph_cubic.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
target_link_libraries(graph_cubic lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_streamparse test_streamparse.c)
 | 
			
		||||
target_link_libraries(test_streamparse lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_streamparse lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(streamparse test_streamparse)
 | 
			
		||||
 | 
			
		||||
add_executable(test_packet_out test_packet_out.c)
 | 
			
		||||
target_link_libraries(test_packet_out lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_packet_out lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(packet_out test_packet_out)
 | 
			
		||||
 | 
			
		||||
add_executable(test_reg_pkt_headergen test_reg_pkt_headergen.c)
 | 
			
		||||
target_link_libraries(test_reg_pkt_headergen lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_reg_pkt_headergen lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(reg_pkt_headergen test_reg_pkt_headergen)
 | 
			
		||||
 | 
			
		||||
add_executable(test_ver_nego test_ver_nego.c)
 | 
			
		||||
target_link_libraries(test_ver_nego lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_ver_nego lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(ver_nego test_ver_nego)
 | 
			
		||||
 | 
			
		||||
add_executable(test_packno_len test_packno_len.c)
 | 
			
		||||
target_link_libraries(test_packno_len lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_packno_len lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(packno_len test_packno_len)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_streamgen test_streamgen.c)
 | 
			
		||||
target_link_libraries(test_streamgen lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_streamgen lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(streamgen test_streamgen)
 | 
			
		||||
 | 
			
		||||
add_executable(test_some_packets test_some_packets.c)
 | 
			
		||||
target_link_libraries(test_some_packets lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_some_packets lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(some_packets test_some_packets)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_elision test_elision.c)
 | 
			
		||||
target_link_libraries(test_elision lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
target_link_libraries(test_elision lsquic ${LIBS_LIST})
 | 
			
		||||
ELSE()
 | 
			
		||||
target_link_libraries(test_elision lsquic ${LIBS_LIST} -FORCE:multiple)
 | 
			
		||||
ENDIF()
 | 
			
		||||
add_test(elision test_elision)
 | 
			
		||||
 | 
			
		||||
add_executable(test_stop_waiting_gquic_le test_stop_waiting_gquic_le.c)
 | 
			
		||||
target_link_libraries(test_stop_waiting_gquic_le lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_stop_waiting_gquic_le lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(stop_waiting_gquic_le test_stop_waiting_gquic_le)
 | 
			
		||||
 | 
			
		||||
add_executable(test_stop_waiting_gquic_be test_stop_waiting_gquic_be.c)
 | 
			
		||||
target_link_libraries(test_stop_waiting_gquic_be lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_stop_waiting_gquic_be lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(stop_waiting_gquic_be test_stop_waiting_gquic_be)
 | 
			
		||||
 | 
			
		||||
add_executable(test_parse_packet_in test_parse_packet_in.c)
 | 
			
		||||
target_link_libraries(test_parse_packet_in lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_parse_packet_in lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(parse_packet_in test_parse_packet_in)
 | 
			
		||||
 | 
			
		||||
add_executable(test_quic_le_floats test_quic_le_floats.c)
 | 
			
		||||
target_link_libraries(test_quic_le_floats lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_quic_le_floats lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(quic_le_floats test_quic_le_floats)
 | 
			
		||||
 | 
			
		||||
add_executable(test_quic_be_floats test_quic_be_floats.c)
 | 
			
		||||
target_link_libraries(test_quic_be_floats lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_quic_be_floats lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(quic_be_floats test_quic_be_floats)
 | 
			
		||||
 | 
			
		||||
add_executable(test_export_key test_export_key.c)
 | 
			
		||||
target_link_libraries(test_export_key lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_export_key lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(export_key test_export_key)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_frame_reader test_frame_reader.c)
 | 
			
		||||
target_link_libraries(test_frame_reader lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_frame_reader test_frame_reader.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
target_link_libraries(test_frame_reader lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(frame_reader test_frame_reader)
 | 
			
		||||
 | 
			
		||||
add_executable(test_frame_writer test_frame_writer.c)
 | 
			
		||||
target_link_libraries(test_frame_writer lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_frame_writer lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(frame_writer test_frame_writer)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_frame_chop test_frame_chop.c)
 | 
			
		||||
target_link_libraries(test_frame_chop lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_frame_chop test_frame_chop.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
target_link_libraries(test_frame_chop lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(frame_chop test_frame_chop)
 | 
			
		||||
 | 
			
		||||
IF (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 | 
			
		||||
IF (NOT ( (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") OR  (CMAKE_C_COMPILER MATCHES "MSVC")) )
 | 
			
		||||
    add_executable(test_frame_rw test_frame_rw.c)
 | 
			
		||||
    target_link_libraries(test_frame_rw lsquic pthread libssl.a libcrypto.a z m ${FIULIB})
 | 
			
		||||
    target_link_libraries(test_frame_rw lsquic ${LIBS_LIST})
 | 
			
		||||
    add_test(frame_rw test_frame_rw)
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
add_executable(test_hpack test_hpack.c)
 | 
			
		||||
target_link_libraries(test_hpack lsquic m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_hpack lsquic ${MIN_LIBS_LIST})
 | 
			
		||||
add_test(hpack test_hpack)
 | 
			
		||||
 | 
			
		||||
add_executable(test_hkdf test_hkdf.c)
 | 
			
		||||
target_link_libraries(test_hkdf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_hkdf lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(hkdf test_hkdf)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
add_executable(test_attq test_attq.c)
 | 
			
		||||
target_link_libraries(test_attq lsquic pthread libssl.a libcrypto.a m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_attq lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(attq test_attq)
 | 
			
		||||
 | 
			
		||||
add_executable(test_arr test_arr.c)
 | 
			
		||||
target_link_libraries(test_arr lsquic pthread libssl.a libcrypto.a m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_arr lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(arr test_arr)
 | 
			
		||||
 | 
			
		||||
add_executable(test_buf test_buf.c)
 | 
			
		||||
target_link_libraries(test_buf lsquic pthread libssl.a libcrypto.a m ${FIULIB})
 | 
			
		||||
target_link_libraries(test_buf lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(buf test_buf)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_cubic test_cubic.c)
 | 
			
		||||
target_link_libraries(test_cubic lsquic pthread libssl.a libcrypto.a m ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_cubic test_cubic.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
target_link_libraries(test_cubic lsquic ${LIBS_LIST})
 | 
			
		||||
add_test(cubic test_cubic)
 | 
			
		||||
 | 
			
		||||
IF (NOT (CMAKE_C_COMPILER MATCHES "MSVC"))
 | 
			
		||||
add_executable(test_dec test_dec.c)
 | 
			
		||||
target_link_libraries(test_dec libssl.a libcrypto.a z m pthread ${FIULIB})
 | 
			
		||||
ELSE()
 | 
			
		||||
add_executable(test_dec test_dec.c ../../wincompat/getopt.c ../../wincompat/getopt1.c)
 | 
			
		||||
ENDIF()
 | 
			
		||||
 | 
			
		||||
target_link_libraries(test_dec ${LIBS_LIST})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,9 +7,13 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <termios.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +64,9 @@ main (int argc, char **argv)
 | 
			
		|||
    struct rec *recs = NULL;
 | 
			
		||||
    unsigned max_cwnd, width;
 | 
			
		||||
    char *line;
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    struct winsize winsize;
 | 
			
		||||
#endif
 | 
			
		||||
    enum cubic_flags flags;
 | 
			
		||||
 | 
			
		||||
    lsquic_cubic_init(&cubic, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +122,7 @@ main (int argc, char **argv)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
    if (isatty(STDIN_FILENO))
 | 
			
		||||
    {
 | 
			
		||||
        if (0 == ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize))
 | 
			
		||||
| 
						 | 
				
			
			@ -127,6 +134,7 @@ main (int argc, char **argv)
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
#endif
 | 
			
		||||
        width = 80;
 | 
			
		||||
 | 
			
		||||
    width -= 5 /* cwnd */ + 1 /* space */ + 1 /* event type */ + 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,9 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <vc_compat.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_buf.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,11 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,11 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else 
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <openssl/aead.h>
 | 
			
		||||
#include <openssl/rand.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,6 @@ lsquic_stream_acked (lsquic_stream_t *stream)
 | 
			
		|||
static void
 | 
			
		||||
elide_single_stream_frame (void)
 | 
			
		||||
{
 | 
			
		||||
    struct packet_out_srec_iter posi;
 | 
			
		||||
    struct lsquic_engine_public enpub;
 | 
			
		||||
    lsquic_stream_t streams[1];
 | 
			
		||||
    lsquic_packet_out_t *packet_out;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,10 @@
 | 
			
		|||
 | 
			
		||||
#include "lsquic_crypto.h"
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#pragma warning(disable:4295 4245) //4295: array is too small to include a terminating null character, 4245:initializing': conversion from 'int' to 'unsigned char', signed/unsigned mismatch
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct export_key_test
 | 
			
		||||
{
 | 
			
		||||
    /* Line number for easy verification: */
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +67,7 @@ static const struct export_key_test tests[] = {
 | 
			
		|||
    {
 | 
			
		||||
        .ekt_lineno         = __LINE__,
 | 
			
		||||
        .ekt_ikm            = "secret",
 | 
			
		||||
		.ekt_ikm_sz         = 6,
 | 
			
		||||
        .ekt_ikm_sz         = 6,
 | 
			
		||||
        BUF_PAIR(salt,
 | 
			
		||||
            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 | 
			
		||||
            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 | 
			
		||||
| 
						 | 
				
			
			@ -436,13 +440,13 @@ run_ekt_test (const struct export_key_test *test)
 | 
			
		|||
    assert(test->ekt_server_iv_sz < sizeof(server_iv));
 | 
			
		||||
    assert(test->ekt_client_iv_sz < sizeof(client_iv));
 | 
			
		||||
 | 
			
		||||
    s = export_key_material(test->ekt_ikm,              test->ekt_ikm_sz,
 | 
			
		||||
                            test->ekt_salt,             test->ekt_salt_sz,
 | 
			
		||||
                            test->ekt_context,          test->ekt_context_sz,
 | 
			
		||||
                            test->ekt_client_key_sz,    client_key,
 | 
			
		||||
                            test->ekt_server_key_sz,    server_key,
 | 
			
		||||
                            test->ekt_client_iv_sz,     client_iv,
 | 
			
		||||
                            test->ekt_server_iv_sz,     server_iv,
 | 
			
		||||
    s = export_key_material(test->ekt_ikm,              (uint16_t)test->ekt_ikm_sz,
 | 
			
		||||
                            test->ekt_salt,             (uint16_t)test->ekt_salt_sz,
 | 
			
		||||
                            test->ekt_context,          (uint16_t)test->ekt_context_sz,
 | 
			
		||||
                            (uint16_t)test->ekt_client_key_sz,    client_key,
 | 
			
		||||
                            (uint16_t)test->ekt_server_key_sz,    server_key,
 | 
			
		||||
                            (uint16_t)test->ekt_client_iv_sz,     client_iv,
 | 
			
		||||
                            (uint16_t)test->ekt_server_iv_sz,     server_iv,
 | 
			
		||||
                            sub_key);
 | 
			
		||||
 | 
			
		||||
    assert(0 == s);     /* This function always returns zero */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,11 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,11 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ void test_HKDF()
 | 
			
		|||
{
 | 
			
		||||
    unsigned char prk[32];
 | 
			
		||||
    unsigned char okm[100];
 | 
			
		||||
    int L;
 | 
			
		||||
    uint16_t L;
 | 
			
		||||
    /*test case 1 */
 | 
			
		||||
    lshkdf_extract((const unsigned char *) "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
 | 
			
		||||
                 22,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -185,24 +185,28 @@ void displayHeader(unsigned char *buf, int len)
 | 
			
		|||
static void
 | 
			
		||||
printTable (struct lsquic_henc *enc)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    struct enc_dyn_table_entry entry;
 | 
			
		||||
    lsquic_henc_iter_reset(enc);
 | 
			
		||||
    printf("Dynamic Table : \n");
 | 
			
		||||
    while (0 == lsquic_henc_iter_next(enc, &entry))
 | 
			
		||||
        printf("[%d] `%.*s' = `%.*s'\n",
 | 
			
		||||
            entry.entry_id, entry.name_len, entry.name, entry.value_len, entry.value);
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void testNameValue(const char *name, const char *val, int result,
 | 
			
		||||
        int val_match_result)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    int val_match;
 | 
			
		||||
    int index = lsquic_henc_get_stx_tab_id((char *)name, (uint16_t)strlen(name) ,
 | 
			
		||||
            (char *)val, (uint16_t)strlen(val), &val_match);
 | 
			
		||||
    printf("name: %s, val: %s, index = %d match = %d\n", name, val, index,
 | 
			
		||||
            val_match);
 | 
			
		||||
    assert(index == result && val_match == val_match_result);
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -655,6 +659,7 @@ test_hpack_encode_and_decode (void)
 | 
			
		|||
static void
 | 
			
		||||
test_hpack_self_enc_dec_test_firefox_error (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    unsigned char respBuf[8192] = {0};
 | 
			
		||||
    unsigned char *respBufEnd;
 | 
			
		||||
    // Hpack hpack;
 | 
			
		||||
| 
						 | 
				
			
			@ -732,6 +737,7 @@ test_hpack_self_enc_dec_test_firefox_error (void)
 | 
			
		|||
    assert(memcmp(respBuf, buf, 90) == 0);
 | 
			
		||||
    lsquic_henc_cleanup(&henc);
 | 
			
		||||
    lsquic_hdec_cleanup(&hdec);
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -985,6 +991,7 @@ test_henc_long_uncompressable (void)
 | 
			
		|||
static void
 | 
			
		||||
test_static_table_search_exhaustive (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    int i;
 | 
			
		||||
    int count = sizeof(g_HpackStaticTableTset) / sizeof(hpack_hdr_tbl_t);
 | 
			
		||||
    assert(count == 61);
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,12 +1053,14 @@ test_static_table_search_exhaustive (void)
 | 
			
		|||
    assert(val_matched == 0);
 | 
			
		||||
 | 
			
		||||
    printf("%s Done.\n", __func__);
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_integer_decoding (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    static const struct integer_decoding_test
 | 
			
		||||
    {
 | 
			
		||||
        int             idt_lineno;
 | 
			
		||||
| 
						 | 
				
			
			@ -1129,12 +1138,14 @@ test_integer_decoding (void)
 | 
			
		|||
        if (0 == s)
 | 
			
		||||
            assert(value == test->idt_value);
 | 
			
		||||
    }
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_huffman_encoding_corner_cases (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    int s;
 | 
			
		||||
    unsigned char buf[0x10];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1162,6 +1173,7 @@ test_huffman_encoding_corner_cases (void)
 | 
			
		|||
    s = lsquic_henc_enc_str(buf, 1, (unsigned char *) "a", 1000);
 | 
			
		||||
    assert(-1 == s);
 | 
			
		||||
    assert(0 == buf[1]);
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_hash.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,11 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_malo.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,9 @@
 | 
			
		|||
#include <sys/queue.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
 | 
			
		||||
#include <openssl/md5.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +255,7 @@ test_restore (enum lsquic_packno_bits bits)
 | 
			
		|||
    unsigned len, n;
 | 
			
		||||
    enum { OP_PLUS, OP_MINUS, N_OPS } op;
 | 
			
		||||
    uint64_t epoch, epoch_delta;
 | 
			
		||||
    lsquic_packno_t orig_packno, cur_packno, restored_packno;
 | 
			
		||||
    lsquic_packno_t orig_packno= 0, cur_packno, restored_packno;
 | 
			
		||||
 | 
			
		||||
    len = packno_bits2len(bits);
 | 
			
		||||
    epoch_delta = 1ULL << (len << 3);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,14 +3,15 @@
 | 
			
		|||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_mm.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_packet_common.h"
 | 
			
		||||
#include "lsquic_packet_in.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
#include "lsquic_mm.h"
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_packet_in.h"
 | 
			
		||||
#include "lsquic_engine_public.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +88,7 @@ static const struct float_test to_float_tests[] = {
 | 
			
		|||
static void
 | 
			
		||||
run_to_float_tests (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    const struct float_test *test;
 | 
			
		||||
    const struct float_test *const test_end =
 | 
			
		||||
        &to_float_tests[ sizeof(to_float_tests) / sizeof(to_float_tests[0]) ];
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +99,7 @@ run_to_float_tests (void)
 | 
			
		|||
        assert(("Convertion to QUIC float format is successful",
 | 
			
		||||
                                0 == memcmp(out, test->float_time, 2)));
 | 
			
		||||
    }
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +151,7 @@ static const struct float_test from_float_tests[] = {
 | 
			
		|||
static void
 | 
			
		||||
run_from_float_tests (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    const struct float_test *test;
 | 
			
		||||
    const struct float_test *const test_end =
 | 
			
		||||
        &from_float_tests[ sizeof(from_float_tests) / sizeof(from_float_tests[0]) ];
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +161,7 @@ run_from_float_tests (void)
 | 
			
		|||
        assert(("Convertion to QUIC float format is successful",
 | 
			
		||||
                                                result == test->long_time));
 | 
			
		||||
    }
 | 
			
		||||
#endif // NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +88,7 @@ static const struct float_test to_float_tests[] = {
 | 
			
		|||
static void
 | 
			
		||||
run_to_float_tests (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    const struct float_test *test;
 | 
			
		||||
    const struct float_test *const test_end =
 | 
			
		||||
        &to_float_tests[ sizeof(to_float_tests) / sizeof(to_float_tests[0]) ];
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +99,7 @@ run_to_float_tests (void)
 | 
			
		|||
        assert(("Convertion to QUIC float format is successful",
 | 
			
		||||
                                0 == memcmp(out, test->float_time, 2)));
 | 
			
		||||
    }
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +151,7 @@ static const struct float_test from_float_tests[] = {
 | 
			
		|||
static void
 | 
			
		||||
run_from_float_tests (void)
 | 
			
		||||
{
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    const struct float_test *test;
 | 
			
		||||
    const struct float_test *const test_end =
 | 
			
		||||
        &from_float_tests[ sizeof(from_float_tests) / sizeof(from_float_tests[0]) ];
 | 
			
		||||
| 
						 | 
				
			
			@ -156,6 +161,7 @@ run_from_float_tests (void)
 | 
			
		|||
        assert(("Convertion to QUIC float format is successful",
 | 
			
		||||
                                                result == test->long_time));
 | 
			
		||||
    }
 | 
			
		||||
#endif //NDEBUG
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic_int_types.h"
 | 
			
		||||
#include "lsquic_rtt.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,11 @@
 | 
			
		|||
#include <sys/types.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +187,7 @@ read_from_scheduled_packets (lsquic_send_ctl_t *send_ctl, uint32_t stream_id,
 | 
			
		|||
    unsigned char *const begin, size_t bufsz, uint64_t first_offset, int *p_fin,
 | 
			
		||||
    int fullcheck)
 | 
			
		||||
{
 | 
			
		||||
    const struct parse_funcs *const pf = send_ctl->sc_conn_pub->lconn->cn_pf;
 | 
			
		||||
    const struct parse_funcs *const pf_local = send_ctl->sc_conn_pub->lconn->cn_pf;
 | 
			
		||||
    unsigned char *p = begin;
 | 
			
		||||
    unsigned char *const end = p + bufsz;
 | 
			
		||||
    const struct stream_rec *srec;
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +220,7 @@ read_from_scheduled_packets (lsquic_send_ctl_t *send_ctl, uint32_t stream_id,
 | 
			
		|||
                                            srec->sr_stream->id == stream_id)
 | 
			
		||||
            {
 | 
			
		||||
                assert(!fin);
 | 
			
		||||
                len = pf->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
 | 
			
		||||
                len = pf_local->pf_parse_stream_frame(packet_out->po_data + srec->sr_off,
 | 
			
		||||
                    packet_out->po_data_sz - srec->sr_off, &frame);
 | 
			
		||||
                assert(len > 0);
 | 
			
		||||
                assert(frame.stream_id == srec->sr_stream->id);
 | 
			
		||||
| 
						 | 
				
			
			@ -1421,8 +1425,8 @@ test_writing_to_stream_schedule_stream_packets_immediately (void)
 | 
			
		|||
    n_closed = 0;
 | 
			
		||||
    stream = new_stream(&tobjs, 123);
 | 
			
		||||
    assert(("Stream initialized", stream));
 | 
			
		||||
    const struct test_ctx *const test_ctx = tobjs.stream_if_ctx;
 | 
			
		||||
    assert(("on_new_stream called correctly", stream == test_ctx->stream));
 | 
			
		||||
    const struct test_ctx *const test_ctx_local  = tobjs.stream_if_ctx;
 | 
			
		||||
    assert(("on_new_stream called correctly", stream == test_ctx_local->stream));
 | 
			
		||||
    assert(LSQUIC_STREAM_DEFAULT_PRIO == lsquic_stream_priority(stream));
 | 
			
		||||
 | 
			
		||||
    assert(lconn == lsquic_stream_conn(stream));
 | 
			
		||||
| 
						 | 
				
			
			@ -1489,8 +1493,8 @@ test_writing_to_stream_outside_callback (void)
 | 
			
		|||
    n_closed = 0;
 | 
			
		||||
    stream = new_stream(&tobjs, 123);
 | 
			
		||||
    assert(("Stream initialized", stream));
 | 
			
		||||
    const struct test_ctx *const test_ctx = tobjs.stream_if_ctx;
 | 
			
		||||
    assert(("on_new_stream called correctly", stream == test_ctx->stream));
 | 
			
		||||
    const struct test_ctx *const test_ctx_local = tobjs.stream_if_ctx;
 | 
			
		||||
    assert(("on_new_stream called correctly", stream == test_ctx_local->stream));
 | 
			
		||||
    assert(LSQUIC_STREAM_DEFAULT_PRIO == lsquic_stream_priority(stream));
 | 
			
		||||
 | 
			
		||||
    assert(lconn == lsquic_stream_conn(stream));
 | 
			
		||||
| 
						 | 
				
			
			@ -2357,7 +2361,7 @@ static void
 | 
			
		|||
init_buf (void *buf, size_t sz)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *p = buf;
 | 
			
		||||
    unsigned char *const end = buf + sz;
 | 
			
		||||
    unsigned char *const end = (unsigned char*)buf + sz;
 | 
			
		||||
    size_t n;
 | 
			
		||||
 | 
			
		||||
    while (p < end)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,14 +4,16 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
#include "lsquic_sfcw.h"
 | 
			
		||||
#include "lsquic_stream.h"
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
 | 
			
		||||
struct test {
 | 
			
		||||
    int             lineno;
 | 
			
		||||
| 
						 | 
				
			
			@ -747,18 +749,18 @@ static struct test_ctx {
 | 
			
		|||
static int
 | 
			
		||||
stream_tosend_fin (void *stream)
 | 
			
		||||
{
 | 
			
		||||
    struct test_ctx *test_ctx = stream;
 | 
			
		||||
    return test_ctx->test->fin[ test_ctx->next_fin++ ];
 | 
			
		||||
    struct test_ctx *test_ctx2 = stream;
 | 
			
		||||
    return test_ctx2->test->fin[ test_ctx2->next_fin++ ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static size_t
 | 
			
		||||
stream_tosend_read (void *stream, void *buf, size_t len, int *reached_fin)
 | 
			
		||||
{
 | 
			
		||||
    struct test_ctx *test_ctx = stream;
 | 
			
		||||
    if (test_ctx->test->data_sz < len)
 | 
			
		||||
        len = test_ctx->test->data_sz;
 | 
			
		||||
    memcpy(buf, test_ctx->test->data, len);
 | 
			
		||||
    struct test_ctx *test_ctx2 = stream;
 | 
			
		||||
    if (test_ctx2->test->data_sz < len)
 | 
			
		||||
        len = test_ctx2->test->data_sz;
 | 
			
		||||
    memcpy(buf, test_ctx2->test->data, len);
 | 
			
		||||
    *reached_fin = stream_tosend_fin(stream);
 | 
			
		||||
    return len;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -767,8 +769,8 @@ stream_tosend_read (void *stream, void *buf, size_t len, int *reached_fin)
 | 
			
		|||
static size_t
 | 
			
		||||
stream_tosend_size (void *stream)
 | 
			
		||||
{
 | 
			
		||||
    struct test_ctx *test_ctx = stream;
 | 
			
		||||
    return test_ctx->test->data_sz;
 | 
			
		||||
    struct test_ctx *test_ctx2 = stream;
 | 
			
		||||
    return test_ctx2->test->data_sz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,14 +3,17 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
#include "lsquic_alarmset.h"
 | 
			
		||||
#include "lsquic_parse.h"
 | 
			
		||||
#include "lsquic_packet_common.h"
 | 
			
		||||
#include "lsquic_packet_in.h"
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
 | 
			
		||||
struct test {
 | 
			
		||||
    const char     *name;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,9 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/queue.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,9 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lsquic.h"
 | 
			
		||||
#include "lsquic_types.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								wincompat/README.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								wincompat/README.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
- vcpkg does not have boringssl, so you'll have to build it yourself. Follow the instructions at the boringssl repository.
 | 
			
		||||
  With the caveat that you should do it from a VC command prompt for the correct architecture and make sure to set all 
 | 
			
		||||
  the paths for perl,ninja,etc. correctly. Also watch out for C runtime library mismatches. The easiest fix for me was to
 | 
			
		||||
  change the flags in the CMake cache file.
 | 
			
		||||
 | 
			
		||||
- zlib and libevent do exist in vcpkg. 
 | 
			
		||||
 | 
			
		||||
- getopt files are really old and could probably use updating.
 | 
			
		||||
							
								
								
									
										758
									
								
								wincompat/getopt.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										758
									
								
								wincompat/getopt.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,758 @@
 | 
			
		|||
/* Getopt for GNU.
 | 
			
		||||
   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
 | 
			
		||||
   before changing it!
 | 
			
		||||
 | 
			
		||||
   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
 | 
			
		||||
    Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
   under the terms of the GNU General Public License as published by the
 | 
			
		||||
   Free Software Foundation; either version 2, or (at your option) any
 | 
			
		||||
   later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, write to the Free Software
 | 
			
		||||
   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 | 
			
		||||
 
 | 
			
		||||
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
 | 
			
		||||
   Ditto for AIX 3.2 and <stdlib.h>.  */
 | 
			
		||||
#ifndef _NO_PROTO
 | 
			
		||||
#define _NO_PROTO
 | 
			
		||||
#endif
 | 
			
		||||
#pragma warning(disable:4131)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#if defined (emacs) || defined (CONFIG_BROKETS)
 | 
			
		||||
/* We use <config.h> instead of "config.h" so that a compilation
 | 
			
		||||
   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
 | 
			
		||||
   (which it would do because it found this file in $srcdir).  */
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#else
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __STDC__
 | 
			
		||||
/* This is a separate conditional since some stdc systems
 | 
			
		||||
   reject `defined (const)'.  */
 | 
			
		||||
#ifndef const
 | 
			
		||||
#define const
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
/* Comment out all this code if we are using the GNU C Library, and are not
 | 
			
		||||
   actually compiling the library itself.  This code is part of the GNU C
 | 
			
		||||
   Library, but also included in many other GNU distributions.  Compiling
 | 
			
		||||
   and linking in this code is a waste when using the GNU C library
 | 
			
		||||
   (especially if it is a shared library).  Rather than having every GNU
 | 
			
		||||
   program understand `configure --with-gnu-libc' and omit the object files,
 | 
			
		||||
   it is simpler to just do this in the source for each such file.  */
 | 
			
		||||
 | 
			
		||||
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* This needs to come after some library #include
 | 
			
		||||
   to get __GNU_LIBRARY__ defined.  */
 | 
			
		||||
#ifdef	__GNU_LIBRARY__
 | 
			
		||||
/* Don't include stdlib.h for non-GNU C libraries because some of them
 | 
			
		||||
   contain conflicting prototypes for getopt.  */
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#endif	/* GNU C library.  */
 | 
			
		||||
 | 
			
		||||
/* This version of `getopt' appears to the caller like standard Unix `getopt'
 | 
			
		||||
   but it behaves differently for the user, since it allows the user
 | 
			
		||||
   to intersperse the options with the other arguments.
 | 
			
		||||
 | 
			
		||||
   As `getopt' works, it permutes the elements of ARGV so that,
 | 
			
		||||
   when it is done, all the options precede everything else.  Thus
 | 
			
		||||
   all application programs are extended to handle flexible argument order.
 | 
			
		||||
 | 
			
		||||
   Setting the environment variable POSIXLY_CORRECT disables permutation.
 | 
			
		||||
   Then the behavior is completely standard.
 | 
			
		||||
 | 
			
		||||
   GNU application programs can use a third alternative mode in which
 | 
			
		||||
   they can distinguish the relative order of options and other arguments.  */
 | 
			
		||||
 | 
			
		||||
#include "getopt.h"
 | 
			
		||||
 | 
			
		||||
/* For communication from `getopt' to the caller.
 | 
			
		||||
   When `getopt' finds an option that takes an argument,
 | 
			
		||||
   the argument value is returned here.
 | 
			
		||||
   Also, when `ordering' is RETURN_IN_ORDER,
 | 
			
		||||
   each non-option ARGV-element is returned here.  */
 | 
			
		||||
 | 
			
		||||
char *optarg = NULL;
 | 
			
		||||
 | 
			
		||||
/* Index in ARGV of the next element to be scanned.
 | 
			
		||||
   This is used for communication to and from the caller
 | 
			
		||||
   and for communication between successive calls to `getopt'.
 | 
			
		||||
 | 
			
		||||
   On entry to `getopt', zero means this is the first call; initialize.
 | 
			
		||||
 | 
			
		||||
   When `getopt' returns EOF, this is the index of the first of the
 | 
			
		||||
   non-option elements that the caller should itself scan.
 | 
			
		||||
 | 
			
		||||
   Otherwise, `optind' communicates from one call to the next
 | 
			
		||||
   how much of ARGV has been scanned so far.  */
 | 
			
		||||
 | 
			
		||||
/* XXX 1003.2 says this must be 1 before any call.  */
 | 
			
		||||
int optind = 0;
 | 
			
		||||
 | 
			
		||||
/* The next char to be scanned in the option-element
 | 
			
		||||
   in which the last option character we returned was found.
 | 
			
		||||
   This allows us to pick up the scan where we left off.
 | 
			
		||||
 | 
			
		||||
   If this is zero, or a null string, it means resume the scan
 | 
			
		||||
   by advancing to the next ARGV-element.  */
 | 
			
		||||
 | 
			
		||||
static char *nextchar;
 | 
			
		||||
 | 
			
		||||
/* Callers store zero here to inhibit the error message
 | 
			
		||||
   for unrecognized options.  */
 | 
			
		||||
 | 
			
		||||
int opterr = 1;
 | 
			
		||||
 | 
			
		||||
/* Set to an option character which was unrecognized.
 | 
			
		||||
   This must be initialized on some systems to avoid linking in the
 | 
			
		||||
   system's own getopt implementation.  */
 | 
			
		||||
 | 
			
		||||
int optopt = '?';
 | 
			
		||||
 | 
			
		||||
/* Describe how to deal with options that follow non-option ARGV-elements.
 | 
			
		||||
 | 
			
		||||
   If the caller did not specify anything,
 | 
			
		||||
   the default is REQUIRE_ORDER if the environment variable
 | 
			
		||||
   POSIXLY_CORRECT is defined, PERMUTE otherwise.
 | 
			
		||||
 | 
			
		||||
   REQUIRE_ORDER means don't recognize them as options;
 | 
			
		||||
   stop option processing when the first non-option is seen.
 | 
			
		||||
   This is what Unix does.
 | 
			
		||||
   This mode of operation is selected by either setting the environment
 | 
			
		||||
   variable POSIXLY_CORRECT, or using `+' as the first character
 | 
			
		||||
   of the list of option characters.
 | 
			
		||||
 | 
			
		||||
   PERMUTE is the default.  We permute the contents of ARGV as we scan,
 | 
			
		||||
   so that eventually all the non-options are at the end.  This allows options
 | 
			
		||||
   to be given in any order, even with programs that were not written to
 | 
			
		||||
   expect this.
 | 
			
		||||
 | 
			
		||||
   RETURN_IN_ORDER is an option available to programs that were written
 | 
			
		||||
   to expect options and other ARGV-elements in any order and that care about
 | 
			
		||||
   the ordering of the two.  We describe each non-option ARGV-element
 | 
			
		||||
   as if it were the argument of an option with character code 1.
 | 
			
		||||
   Using `-' as the first character of the list of option characters
 | 
			
		||||
   selects this mode of operation.
 | 
			
		||||
 | 
			
		||||
   The special argument `--' forces an end of option-scanning regardless
 | 
			
		||||
   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
 | 
			
		||||
   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
 | 
			
		||||
 | 
			
		||||
static enum
 | 
			
		||||
{
 | 
			
		||||
  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
 | 
			
		||||
} ordering;
 | 
			
		||||
 | 
			
		||||
/* Value of POSIXLY_CORRECT environment variable.  */
 | 
			
		||||
static char *posixly_correct;
 | 
			
		||||
 
 | 
			
		||||
#ifdef	__GNU_LIBRARY__
 | 
			
		||||
/* We want to avoid inclusion of string.h with non-GNU libraries
 | 
			
		||||
   because there are many ways it can cause trouble.
 | 
			
		||||
   On some systems, it contains special magic macros that don't work
 | 
			
		||||
   in GCC.  */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#define	my_index	strchr
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
/* Avoid depending on library functions or files
 | 
			
		||||
   whose names are inconsistent.  */
 | 
			
		||||
 | 
			
		||||
char *getenv ();
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
my_index (str, chr)
 | 
			
		||||
     const char *str;
 | 
			
		||||
     int chr;
 | 
			
		||||
{
 | 
			
		||||
  while (*str)
 | 
			
		||||
    {
 | 
			
		||||
      if (*str == chr)
 | 
			
		||||
    return (char *) str;
 | 
			
		||||
      str++;
 | 
			
		||||
    }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* If using GCC, we can safely declare strlen this way.
 | 
			
		||||
   If not using GCC, it is ok not to declare it.  */
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
 | 
			
		||||
   That was relevant to code that was here before.  */
 | 
			
		||||
#ifndef __STDC__
 | 
			
		||||
/* gcc with -traditional declares the built-in strlen to return int,
 | 
			
		||||
   and has done so at least since version 2.4.5. -- rms.  */
 | 
			
		||||
extern int strlen (const char *);
 | 
			
		||||
#endif /* not __STDC__ */
 | 
			
		||||
#endif /* __GNUC__ */
 | 
			
		||||
 | 
			
		||||
#endif /* not __GNU_LIBRARY__ */
 | 
			
		||||
 
 | 
			
		||||
/* Handle permutation of arguments.  */
 | 
			
		||||
 | 
			
		||||
/* Describe the part of ARGV that contains non-options that have
 | 
			
		||||
   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
 | 
			
		||||
   `last_nonopt' is the index after the last of them.  */
 | 
			
		||||
 | 
			
		||||
static int first_nonopt;
 | 
			
		||||
static int last_nonopt;
 | 
			
		||||
 | 
			
		||||
/* Exchange two adjacent subsequences of ARGV.
 | 
			
		||||
   One subsequence is elements [first_nonopt,last_nonopt)
 | 
			
		||||
   which contains all the non-options that have been skipped so far.
 | 
			
		||||
   The other is elements [last_nonopt,optind), which contains all
 | 
			
		||||
   the options processed since those non-options were skipped.
 | 
			
		||||
 | 
			
		||||
   `first_nonopt' and `last_nonopt' are relocated so that they describe
 | 
			
		||||
   the new indices of the non-options in ARGV after they are moved.  */
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
exchange (argv)
 | 
			
		||||
     char **argv;
 | 
			
		||||
{
 | 
			
		||||
  int bottom = first_nonopt;
 | 
			
		||||
  int middle = last_nonopt;
 | 
			
		||||
  int top = optind;
 | 
			
		||||
  char *tem;
 | 
			
		||||
 | 
			
		||||
  /* Exchange the shorter segment with the far end of the longer segment.
 | 
			
		||||
     That puts the shorter segment into the right place.
 | 
			
		||||
     It leaves the longer segment in the right place overall,
 | 
			
		||||
     but it consists of two parts that need to be swapped next.  */
 | 
			
		||||
 | 
			
		||||
  while (top > middle && middle > bottom)
 | 
			
		||||
    {
 | 
			
		||||
      if (top - middle > middle - bottom)
 | 
			
		||||
    {
 | 
			
		||||
      /* Bottom segment is the short one.  */
 | 
			
		||||
      int len = middle - bottom;
 | 
			
		||||
      register int i;
 | 
			
		||||
 | 
			
		||||
      /* Swap it with the top part of the top segment.  */
 | 
			
		||||
      for (i = 0; i < len; i++)
 | 
			
		||||
        {
 | 
			
		||||
          tem = argv[bottom + i];
 | 
			
		||||
          argv[bottom + i] = argv[top - (middle - bottom) + i];
 | 
			
		||||
          argv[top - (middle - bottom) + i] = tem;
 | 
			
		||||
        }
 | 
			
		||||
      /* Exclude the moved bottom segment from further swapping.  */
 | 
			
		||||
      top -= len;
 | 
			
		||||
    }
 | 
			
		||||
      else
 | 
			
		||||
    {
 | 
			
		||||
      /* Top segment is the short one.  */
 | 
			
		||||
      int len = top - middle;
 | 
			
		||||
      register int i;
 | 
			
		||||
 | 
			
		||||
      /* Swap it with the bottom part of the bottom segment.  */
 | 
			
		||||
      for (i = 0; i < len; i++)
 | 
			
		||||
        {
 | 
			
		||||
          tem = argv[bottom + i];
 | 
			
		||||
          argv[bottom + i] = argv[middle + i];
 | 
			
		||||
          argv[middle + i] = tem;
 | 
			
		||||
        }
 | 
			
		||||
      /* Exclude the moved top segment from further swapping.  */
 | 
			
		||||
      bottom += len;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Update records for the slots the non-options now occupy.  */
 | 
			
		||||
 | 
			
		||||
  first_nonopt += (optind - last_nonopt);
 | 
			
		||||
  last_nonopt = optind;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize the internal data when the first call is made.  */
 | 
			
		||||
 | 
			
		||||
static const char *
 | 
			
		||||
_getopt_initialize (optstring)
 | 
			
		||||
     const char *optstring;
 | 
			
		||||
{
 | 
			
		||||
  /* Start processing options with ARGV-element 1 (since ARGV-element 0
 | 
			
		||||
     is the program name); the sequence of previously skipped
 | 
			
		||||
     non-option ARGV-elements is empty.  */
 | 
			
		||||
 | 
			
		||||
  first_nonopt = last_nonopt = optind = 1;
 | 
			
		||||
 | 
			
		||||
  nextchar = NULL;
 | 
			
		||||
 | 
			
		||||
  posixly_correct = getenv ("POSIXLY_CORRECT");
 | 
			
		||||
 | 
			
		||||
  /* Determine how to handle the ordering of options and nonoptions.  */
 | 
			
		||||
 | 
			
		||||
  if (optstring[0] == '-')
 | 
			
		||||
    {
 | 
			
		||||
      ordering = RETURN_IN_ORDER;
 | 
			
		||||
      ++optstring;
 | 
			
		||||
    }
 | 
			
		||||
  else if (optstring[0] == '+')
 | 
			
		||||
    {
 | 
			
		||||
      ordering = REQUIRE_ORDER;
 | 
			
		||||
      ++optstring;
 | 
			
		||||
    }
 | 
			
		||||
  else if (posixly_correct != NULL)
 | 
			
		||||
    ordering = REQUIRE_ORDER;
 | 
			
		||||
  else
 | 
			
		||||
    ordering = PERMUTE;
 | 
			
		||||
 | 
			
		||||
  return optstring;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
 | 
			
		||||
   given in OPTSTRING.
 | 
			
		||||
 | 
			
		||||
   If an element of ARGV starts with '-', and is not exactly "-" or "--",
 | 
			
		||||
   then it is an option element.  The characters of this element
 | 
			
		||||
   (aside from the initial '-') are option characters.  If `getopt'
 | 
			
		||||
   is called repeatedly, it returns successively each of the option characters
 | 
			
		||||
   from each of the option elements.
 | 
			
		||||
 | 
			
		||||
   If `getopt' finds another option character, it returns that character,
 | 
			
		||||
   updating `optind' and `nextchar' so that the next call to `getopt' can
 | 
			
		||||
   resume the scan with the following option character or ARGV-element.
 | 
			
		||||
 | 
			
		||||
   If there are no more option characters, `getopt' returns `EOF'.
 | 
			
		||||
   Then `optind' is the index in ARGV of the first ARGV-element
 | 
			
		||||
   that is not an option.  (The ARGV-elements have been permuted
 | 
			
		||||
   so that those that are not options now come last.)
 | 
			
		||||
 | 
			
		||||
   OPTSTRING is a string containing the legitimate option characters.
 | 
			
		||||
   If an option character is seen that is not listed in OPTSTRING,
 | 
			
		||||
   return '?' after printing an error message.  If you set `opterr' to
 | 
			
		||||
   zero, the error message is suppressed but we still return '?'.
 | 
			
		||||
 | 
			
		||||
   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
 | 
			
		||||
   so the following text in the same ARGV-element, or the text of the following
 | 
			
		||||
   ARGV-element, is returned in `optarg'.  Two colons mean an option that
 | 
			
		||||
   wants an optional arg; if there is text in the current ARGV-element,
 | 
			
		||||
   it is returned in `optarg', otherwise `optarg' is set to zero.
 | 
			
		||||
 | 
			
		||||
   If OPTSTRING starts with `-' or `+', it requests different methods of
 | 
			
		||||
   handling the non-option ARGV-elements.
 | 
			
		||||
   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
 | 
			
		||||
 | 
			
		||||
   Long-named options begin with `--' instead of `-'.
 | 
			
		||||
   Their names may be abbreviated as long as the abbreviation is unique
 | 
			
		||||
   or is an exact match for some defined option.  If they have an
 | 
			
		||||
   argument, it follows the option name in the same ARGV-element, separated
 | 
			
		||||
   from the option name by a `=', or else the in next ARGV-element.
 | 
			
		||||
   When `getopt' finds a long-named option, it returns 0 if that option's
 | 
			
		||||
   `flag' field is nonzero, the value of the option's `val' field
 | 
			
		||||
   if the `flag' field is zero.
 | 
			
		||||
 | 
			
		||||
   The elements of ARGV aren't really const, because we permute them.
 | 
			
		||||
   But we pretend they're const in the prototype to be compatible
 | 
			
		||||
   with other systems.
 | 
			
		||||
 | 
			
		||||
   LONGOPTS is a vector of `struct option' terminated by an
 | 
			
		||||
   element containing a name which is zero.
 | 
			
		||||
 | 
			
		||||
   LONGIND returns the index in LONGOPT of the long-named option found.
 | 
			
		||||
   It is only valid when a long-named option has been found by the most
 | 
			
		||||
   recent call.
 | 
			
		||||
 | 
			
		||||
   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
 | 
			
		||||
   long-named options.  */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char *const *argv;
 | 
			
		||||
     const char *optstring;
 | 
			
		||||
     const struct option *longopts;
 | 
			
		||||
     int *longind;
 | 
			
		||||
     int long_only;
 | 
			
		||||
{
 | 
			
		||||
  optarg = NULL;
 | 
			
		||||
 | 
			
		||||
  if (optind == 0)
 | 
			
		||||
    optstring = _getopt_initialize (optstring);
 | 
			
		||||
 | 
			
		||||
  if (nextchar == NULL || *nextchar == '\0')
 | 
			
		||||
    {
 | 
			
		||||
      /* Advance to the next ARGV-element.  */
 | 
			
		||||
 | 
			
		||||
      if (ordering == PERMUTE)
 | 
			
		||||
    {
 | 
			
		||||
      /* If we have just processed some options following some non-options,
 | 
			
		||||
         exchange them so that the options come first.  */
 | 
			
		||||
 | 
			
		||||
      if (first_nonopt != last_nonopt && last_nonopt != optind)
 | 
			
		||||
        exchange ((char **) argv);
 | 
			
		||||
      else if (last_nonopt != optind)
 | 
			
		||||
        first_nonopt = optind;
 | 
			
		||||
 | 
			
		||||
      /* Skip any additional non-options
 | 
			
		||||
         and extend the range of non-options previously skipped.  */
 | 
			
		||||
 | 
			
		||||
      while (optind < argc
 | 
			
		||||
         && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
 | 
			
		||||
        optind++;
 | 
			
		||||
      last_nonopt = optind;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      /* The special ARGV-element `--' means premature end of options.
 | 
			
		||||
     Skip it like a null option,
 | 
			
		||||
     then exchange with previous non-options as if it were an option,
 | 
			
		||||
     then skip everything else like a non-option.  */
 | 
			
		||||
 | 
			
		||||
      if (optind != argc && !strcmp (argv[optind], "--"))
 | 
			
		||||
    {
 | 
			
		||||
      optind++;
 | 
			
		||||
 | 
			
		||||
      if (first_nonopt != last_nonopt && last_nonopt != optind)
 | 
			
		||||
        exchange ((char **) argv);
 | 
			
		||||
      else if (first_nonopt == last_nonopt)
 | 
			
		||||
        first_nonopt = optind;
 | 
			
		||||
      last_nonopt = argc;
 | 
			
		||||
 | 
			
		||||
      optind = argc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      /* If we have done all the ARGV-elements, stop the scan
 | 
			
		||||
     and back over any non-options that we skipped and permuted.  */
 | 
			
		||||
 | 
			
		||||
      if (optind == argc)
 | 
			
		||||
    {
 | 
			
		||||
      /* Set the next-arg-index to point at the non-options
 | 
			
		||||
         that we previously skipped, so the caller will digest them.  */
 | 
			
		||||
      if (first_nonopt != last_nonopt)
 | 
			
		||||
        optind = first_nonopt;
 | 
			
		||||
      return EOF;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      /* If we have come to a non-option and did not permute it,
 | 
			
		||||
     either stop the scan or describe it to the caller and pass it by.  */
 | 
			
		||||
 | 
			
		||||
      if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
 | 
			
		||||
    {
 | 
			
		||||
      if (ordering == REQUIRE_ORDER)
 | 
			
		||||
        return EOF;
 | 
			
		||||
      optarg = argv[optind++];
 | 
			
		||||
      return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      /* We have found another option-ARGV-element.
 | 
			
		||||
     Skip the initial punctuation.  */
 | 
			
		||||
 | 
			
		||||
      nextchar = (argv[optind] + 1
 | 
			
		||||
          + (longopts != NULL && argv[optind][1] == '-'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Decode the current option-ARGV-element.  */
 | 
			
		||||
 | 
			
		||||
  /* Check whether the ARGV-element is a long option.
 | 
			
		||||
 | 
			
		||||
     If long_only and the ARGV-element has the form "-f", where f is
 | 
			
		||||
     a valid short option, don't consider it an abbreviated form of
 | 
			
		||||
     a long option that starts with f.  Otherwise there would be no
 | 
			
		||||
     way to give the -f short option.
 | 
			
		||||
 | 
			
		||||
     On the other hand, if there's a long option "fubar" and
 | 
			
		||||
     the ARGV-element is "-fu", do consider that an abbreviation of
 | 
			
		||||
     the long option, just like "--fu", and not "-f" with arg "u".
 | 
			
		||||
 | 
			
		||||
     This distinction seems to be the most useful approach.  */
 | 
			
		||||
 | 
			
		||||
  if (longopts != NULL
 | 
			
		||||
      && (argv[optind][1] == '-'
 | 
			
		||||
      || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
 | 
			
		||||
    {
 | 
			
		||||
      char *nameend;
 | 
			
		||||
      const struct option *p;
 | 
			
		||||
      const struct option *pfound = NULL;
 | 
			
		||||
      int exact = 0;
 | 
			
		||||
      int ambig = 0;
 | 
			
		||||
      int indfound = 0;
 | 
			
		||||
      int option_index;
 | 
			
		||||
 | 
			
		||||
      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
 | 
			
		||||
    /* Do nothing.  */ ;
 | 
			
		||||
 | 
			
		||||
      /* Test all long options for either exact match
 | 
			
		||||
     or abbreviated matches.  */
 | 
			
		||||
      for (p = longopts, option_index = 0; p->name; p++, option_index++)
 | 
			
		||||
    if (!strncmp (p->name, nextchar, nameend - nextchar))
 | 
			
		||||
      {
 | 
			
		||||
        if (nameend - nextchar == (int) strlen (p->name))
 | 
			
		||||
          {
 | 
			
		||||
        /* Exact match found.  */
 | 
			
		||||
        pfound = p;
 | 
			
		||||
        indfound = option_index;
 | 
			
		||||
        exact = 1;
 | 
			
		||||
        break;
 | 
			
		||||
          }
 | 
			
		||||
        else if (pfound == NULL)
 | 
			
		||||
          {
 | 
			
		||||
        /* First nonexact match found.  */
 | 
			
		||||
        pfound = p;
 | 
			
		||||
        indfound = option_index;
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          /* Second or later nonexact match found.  */
 | 
			
		||||
          ambig = 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (ambig && !exact)
 | 
			
		||||
    {
 | 
			
		||||
      if (opterr)
 | 
			
		||||
        fprintf (stderr, "%s: option `%s' is ambiguous\n",
 | 
			
		||||
             argv[0], argv[optind]);
 | 
			
		||||
      nextchar += strlen (nextchar);
 | 
			
		||||
      optind++;
 | 
			
		||||
      return '?';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      if (pfound != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      option_index = indfound;
 | 
			
		||||
      optind++;
 | 
			
		||||
      if (*nameend)
 | 
			
		||||
        {
 | 
			
		||||
          /* Don't test has_arg with >, because some C compilers don't
 | 
			
		||||
         allow it to be used on enums.  */
 | 
			
		||||
          if (pfound->has_arg)
 | 
			
		||||
        optarg = nameend + 1;
 | 
			
		||||
          else
 | 
			
		||||
        {
 | 
			
		||||
          if (opterr)
 | 
			
		||||
            {
 | 
			
		||||
              if (argv[optind - 1][1] == '-')
 | 
			
		||||
            /* --option */
 | 
			
		||||
            fprintf (stderr,
 | 
			
		||||
                 "%s: option `--%s' doesn't allow an argument\n",
 | 
			
		||||
                 argv[0], pfound->name);
 | 
			
		||||
              else
 | 
			
		||||
            /* +option or -option */
 | 
			
		||||
            fprintf (stderr,
 | 
			
		||||
                 "%s: option `%c%s' doesn't allow an argument\n",
 | 
			
		||||
                 argv[0], argv[optind - 1][0], pfound->name);
 | 
			
		||||
            }
 | 
			
		||||
          nextchar += strlen (nextchar);
 | 
			
		||||
          return '?';
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
      else if (pfound->has_arg == 1)
 | 
			
		||||
        {
 | 
			
		||||
          if (optind < argc)
 | 
			
		||||
        optarg = argv[optind++];
 | 
			
		||||
          else
 | 
			
		||||
        {
 | 
			
		||||
          if (opterr)
 | 
			
		||||
            fprintf (stderr, "%s: option `%s' requires an argument\n",
 | 
			
		||||
                 argv[0], argv[optind - 1]);
 | 
			
		||||
          nextchar += strlen (nextchar);
 | 
			
		||||
          return optstring[0] == ':' ? ':' : '?';
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
      nextchar += strlen (nextchar);
 | 
			
		||||
      if (longind != NULL)
 | 
			
		||||
        *longind = option_index;
 | 
			
		||||
      if (pfound->flag)
 | 
			
		||||
        {
 | 
			
		||||
          *(pfound->flag) = pfound->val;
 | 
			
		||||
          return 0;
 | 
			
		||||
        }
 | 
			
		||||
      return pfound->val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      /* Can't find it as a long option.  If this is not getopt_long_only,
 | 
			
		||||
     or the option starts with '--' or is not a valid short
 | 
			
		||||
     option, then it's an error.
 | 
			
		||||
     Otherwise interpret it as a short option.  */
 | 
			
		||||
      if (!long_only || argv[optind][1] == '-'
 | 
			
		||||
      || my_index (optstring, *nextchar) == NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if (opterr)
 | 
			
		||||
        {
 | 
			
		||||
          if (argv[optind][1] == '-')
 | 
			
		||||
        /* --option */
 | 
			
		||||
        fprintf (stderr, "%s: unrecognized option `--%s'\n",
 | 
			
		||||
             argv[0], nextchar);
 | 
			
		||||
          else
 | 
			
		||||
        /* +option or -option */
 | 
			
		||||
        fprintf (stderr, "%s: unrecognized option `%c%s'\n",
 | 
			
		||||
             argv[0], argv[optind][0], nextchar);
 | 
			
		||||
        }
 | 
			
		||||
      nextchar = (char *) "";
 | 
			
		||||
      optind++;
 | 
			
		||||
      return '?';
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /* Look at and handle the next short option-character.  */
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    char c = *nextchar++;
 | 
			
		||||
    char *temp = my_index (optstring, c);
 | 
			
		||||
 | 
			
		||||
    /* Increment `optind' when we start to process its last character.  */
 | 
			
		||||
    if (*nextchar == '\0')
 | 
			
		||||
      ++optind;
 | 
			
		||||
 | 
			
		||||
    if (temp == NULL || c == ':')
 | 
			
		||||
      {
 | 
			
		||||
    if (opterr)
 | 
			
		||||
      {
 | 
			
		||||
        if (posixly_correct)
 | 
			
		||||
          /* 1003.2 specifies the format of this message.  */
 | 
			
		||||
          fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
 | 
			
		||||
        else
 | 
			
		||||
          fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
 | 
			
		||||
      }
 | 
			
		||||
    optopt = c;
 | 
			
		||||
    return '?';
 | 
			
		||||
      }
 | 
			
		||||
    if (temp[1] == ':')
 | 
			
		||||
      {
 | 
			
		||||
    if (temp[2] == ':')
 | 
			
		||||
      {
 | 
			
		||||
        /* This is an option that accepts an argument optionally.  */
 | 
			
		||||
        if (*nextchar != '\0')
 | 
			
		||||
          {
 | 
			
		||||
        optarg = nextchar;
 | 
			
		||||
        optind++;
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          optarg = NULL;
 | 
			
		||||
        nextchar = NULL;
 | 
			
		||||
      }
 | 
			
		||||
    else
 | 
			
		||||
      {
 | 
			
		||||
        /* This is an option that requires an argument.  */
 | 
			
		||||
        if (*nextchar != '\0')
 | 
			
		||||
          {
 | 
			
		||||
        optarg = nextchar;
 | 
			
		||||
        /* If we end this ARGV-element by taking the rest as an arg,
 | 
			
		||||
           we must advance to the next element now.  */
 | 
			
		||||
        optind++;
 | 
			
		||||
          }
 | 
			
		||||
        else if (optind == argc)
 | 
			
		||||
          {
 | 
			
		||||
        if (opterr)
 | 
			
		||||
          {
 | 
			
		||||
            /* 1003.2 specifies the format of this message.  */
 | 
			
		||||
            fprintf (stderr, "%s: option requires an argument -- %c\n",
 | 
			
		||||
                 argv[0], c);
 | 
			
		||||
          }
 | 
			
		||||
        optopt = c;
 | 
			
		||||
        if (optstring[0] == ':')
 | 
			
		||||
          c = ':';
 | 
			
		||||
        else
 | 
			
		||||
          c = '?';
 | 
			
		||||
          }
 | 
			
		||||
        else
 | 
			
		||||
          /* We already incremented `optind' once;
 | 
			
		||||
         increment it again when taking next ARGV-elt as argument.  */
 | 
			
		||||
          optarg = argv[optind++];
 | 
			
		||||
        nextchar = NULL;
 | 
			
		||||
      }
 | 
			
		||||
      }
 | 
			
		||||
    return c;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
getopt (argc, argv, optstring)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char *const *argv;
 | 
			
		||||
     const char *optstring;
 | 
			
		||||
{
 | 
			
		||||
  return _getopt_internal (argc, argv, optstring,
 | 
			
		||||
               (const struct option *) 0,
 | 
			
		||||
               (int *) 0,
 | 
			
		||||
               0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif	/* _LIBC or not __GNU_LIBRARY__.  */
 | 
			
		||||
 
 | 
			
		||||
#ifdef TEST
 | 
			
		||||
 | 
			
		||||
/* Compile with -DTEST to make an executable for use in testing
 | 
			
		||||
   the above definition of `getopt'.  */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (argc, argv)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char **argv;
 | 
			
		||||
{
 | 
			
		||||
  int c;
 | 
			
		||||
  int digit_optind = 0;
 | 
			
		||||
 | 
			
		||||
  while (1)
 | 
			
		||||
    {
 | 
			
		||||
      int this_option_optind = optind ? optind : 1;
 | 
			
		||||
 | 
			
		||||
      c = getopt (argc, argv, "abc:d:0123456789");
 | 
			
		||||
      if (c == EOF)
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
      switch (c)
 | 
			
		||||
    {
 | 
			
		||||
    case '0':
 | 
			
		||||
    case '1':
 | 
			
		||||
    case '2':
 | 
			
		||||
    case '3':
 | 
			
		||||
    case '4':
 | 
			
		||||
    case '5':
 | 
			
		||||
    case '6':
 | 
			
		||||
    case '7':
 | 
			
		||||
    case '8':
 | 
			
		||||
    case '9':
 | 
			
		||||
      if (digit_optind != 0 && digit_optind != this_option_optind)
 | 
			
		||||
        printf ("digits occur in two different argv-elements.\n");
 | 
			
		||||
      digit_optind = this_option_optind;
 | 
			
		||||
      printf ("option %c\n", c);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 'a':
 | 
			
		||||
      printf ("option a\n");
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 'b':
 | 
			
		||||
      printf ("option b\n");
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 'c':
 | 
			
		||||
      printf ("option c with value `%s'\n", optarg);
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case '?':
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
      printf ("?? getopt returned character code 0%o ??\n", c);
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (optind < argc)
 | 
			
		||||
    {
 | 
			
		||||
      printf ("non-option ARGV-elements: ");
 | 
			
		||||
      while (optind < argc)
 | 
			
		||||
    printf ("%s ", argv[optind++]);
 | 
			
		||||
      printf ("\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  exit (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* TEST */
 | 
			
		||||
							
								
								
									
										131
									
								
								wincompat/getopt.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								wincompat/getopt.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,131 @@
 | 
			
		|||
/* Declarations for getopt.
 | 
			
		||||
   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
   under the terms of the GNU General Public License as published by the
 | 
			
		||||
   Free Software Foundation; either version 2, or (at your option) any
 | 
			
		||||
   later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, write to the Free Software
 | 
			
		||||
   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 | 
			
		||||
 | 
			
		||||
/* $CVSid: @(#)getopt.h 1.7 94/09/21 $ */
 | 
			
		||||
 | 
			
		||||
#ifndef _GETOPT_H
 | 
			
		||||
#define _GETOPT_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef	__cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* For communication from `getopt' to the caller.
 | 
			
		||||
   When `getopt' finds an option that takes an argument,
 | 
			
		||||
   the argument value is returned here.
 | 
			
		||||
   Also, when `ordering' is RETURN_IN_ORDER,
 | 
			
		||||
   each non-option ARGV-element is returned here.  */
 | 
			
		||||
 | 
			
		||||
extern char *optarg;
 | 
			
		||||
 | 
			
		||||
/* Index in ARGV of the next element to be scanned.
 | 
			
		||||
   This is used for communication to and from the caller
 | 
			
		||||
   and for communication between successive calls to `getopt'.
 | 
			
		||||
 | 
			
		||||
   On entry to `getopt', zero means this is the first call; initialize.
 | 
			
		||||
 | 
			
		||||
   When `getopt' returns EOF, this is the index of the first of the
 | 
			
		||||
   non-option elements that the caller should itself scan.
 | 
			
		||||
 | 
			
		||||
   Otherwise, `optind' communicates from one call to the next
 | 
			
		||||
   how much of ARGV has been scanned so far.  */
 | 
			
		||||
 | 
			
		||||
extern int optind;
 | 
			
		||||
 | 
			
		||||
/* Callers store zero here to inhibit the error message `getopt' prints
 | 
			
		||||
   for unrecognized options.  */
 | 
			
		||||
 | 
			
		||||
extern int opterr;
 | 
			
		||||
 | 
			
		||||
/* Set to an option character which was unrecognized.  */
 | 
			
		||||
 | 
			
		||||
extern int optopt;
 | 
			
		||||
 | 
			
		||||
/* Describe the long-named options requested by the application.
 | 
			
		||||
   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
 | 
			
		||||
   of `struct option' terminated by an element containing a name which is
 | 
			
		||||
   zero.
 | 
			
		||||
 | 
			
		||||
   The field `has_arg' is:
 | 
			
		||||
   no_argument		(or 0) if the option does not take an argument,
 | 
			
		||||
   required_argument	(or 1) if the option requires an argument,
 | 
			
		||||
   optional_argument 	(or 2) if the option takes an optional argument.
 | 
			
		||||
 | 
			
		||||
   If the field `flag' is not NULL, it points to a variable that is set
 | 
			
		||||
   to the value given in the field `val' when the option is found, but
 | 
			
		||||
   left unchanged if the option is not found.
 | 
			
		||||
 | 
			
		||||
   To have a long-named option do something other than set an `int' to
 | 
			
		||||
   a compiled-in constant, such as set a value from `optarg', set the
 | 
			
		||||
   option's `flag' field to zero and its `val' field to a nonzero
 | 
			
		||||
   value (the equivalent single-letter option character, if there is
 | 
			
		||||
   one).  For long options that have a zero `flag' field, `getopt'
 | 
			
		||||
   returns the contents of the `val' field.  */
 | 
			
		||||
 | 
			
		||||
struct option
 | 
			
		||||
{
 | 
			
		||||
#if	__STDC__
 | 
			
		||||
  const char *name;
 | 
			
		||||
#else
 | 
			
		||||
  char *name;
 | 
			
		||||
#endif
 | 
			
		||||
  /* has_arg can't be an enum because some compilers complain about
 | 
			
		||||
     type mismatches in all the code that assumes it is an int.  */
 | 
			
		||||
  int has_arg;
 | 
			
		||||
  int *flag;
 | 
			
		||||
  int val;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Names for the values of the `has_arg' field of `struct option'.  */
 | 
			
		||||
 | 
			
		||||
#define	no_argument		0
 | 
			
		||||
#define required_argument	1
 | 
			
		||||
#define optional_argument	2
 | 
			
		||||
 | 
			
		||||
#if __STDC__
 | 
			
		||||
#if defined(__GNU_LIBRARY__)
 | 
			
		||||
/* Many other libraries have conflicting prototypes for getopt, with
 | 
			
		||||
   differences in the consts, in stdlib.h.  To avoid compilation
 | 
			
		||||
   errors, only prototype getopt for the GNU C library.  */
 | 
			
		||||
extern int getopt (int argc, char *const *argv, const char *shortopts);
 | 
			
		||||
#else /* not __GNU_LIBRARY__ */
 | 
			
		||||
extern int getopt ();
 | 
			
		||||
#endif /* not __GNU_LIBRARY__ */
 | 
			
		||||
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
 | 
			
		||||
		        const struct option *longopts, int *longind);
 | 
			
		||||
extern int getopt_long_only (int argc, char *const *argv,
 | 
			
		||||
			     const char *shortopts,
 | 
			
		||||
		             const struct option *longopts, int *longind);
 | 
			
		||||
 | 
			
		||||
/* Internal only.  Users should not call this directly.  */
 | 
			
		||||
extern int _getopt_internal (int argc, char *const *argv,
 | 
			
		||||
			     const char *shortopts,
 | 
			
		||||
		             const struct option *longopts, int *longind,
 | 
			
		||||
			     int long_only);
 | 
			
		||||
#else /* not __STDC__ */
 | 
			
		||||
extern int getopt ();
 | 
			
		||||
extern int getopt_long ();
 | 
			
		||||
extern int getopt_long_only ();
 | 
			
		||||
 | 
			
		||||
extern int _getopt_internal ();
 | 
			
		||||
#endif /* not __STDC__ */
 | 
			
		||||
 | 
			
		||||
#ifdef	__cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _GETOPT_H */
 | 
			
		||||
							
								
								
									
										188
									
								
								wincompat/getopt1.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								wincompat/getopt1.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,188 @@
 | 
			
		|||
/* getopt_long and getopt_long_only entry points for GNU getopt.
 | 
			
		||||
   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
 | 
			
		||||
	Free Software Foundation, Inc.
 | 
			
		||||
 | 
			
		||||
   This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
   under the terms of the GNU General Public License as published by the
 | 
			
		||||
   Free Software Foundation; either version 2, or (at your option) any
 | 
			
		||||
   later version.
 | 
			
		||||
 | 
			
		||||
   This program is distributed in the hope that it will be useful,
 | 
			
		||||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
   GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
   You should have received a copy of the GNU General Public License
 | 
			
		||||
   along with this program; if not, write to the Free Software
 | 
			
		||||
   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#if defined (emacs) || defined (CONFIG_BROKETS)
 | 
			
		||||
/* We use <config.h> instead of "config.h" so that a compilation
 | 
			
		||||
   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
 | 
			
		||||
   (which it would do because it found this file in $srcdir).  */
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#else
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma warning(disable:4131)
 | 
			
		||||
#include "getopt.h"
 | 
			
		||||
 | 
			
		||||
#ifndef __STDC__
 | 
			
		||||
/* This is a separate conditional since some stdc systems
 | 
			
		||||
   reject `defined (const)'.  */
 | 
			
		||||
#ifndef const
 | 
			
		||||
#define const
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
/* Comment out all this code if we are using the GNU C Library, and are not
 | 
			
		||||
   actually compiling the library itself.  This code is part of the GNU C
 | 
			
		||||
   Library, but also included in many other GNU distributions.  Compiling
 | 
			
		||||
   and linking in this code is a waste when using the GNU C library
 | 
			
		||||
   (especially if it is a shared library).  Rather than having every GNU
 | 
			
		||||
   program understand `configure --with-gnu-libc' and omit the object files,
 | 
			
		||||
   it is simpler to just do this in the source for each such file.  */
 | 
			
		||||
 | 
			
		||||
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* This needs to come after some library #include
 | 
			
		||||
   to get __GNU_LIBRARY__ defined.  */
 | 
			
		||||
#ifdef __GNU_LIBRARY__
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#else
 | 
			
		||||
char *getenv ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef	NULL
 | 
			
		||||
#define NULL 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
getopt_long (argc, argv, options, long_options, opt_index)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char *const *argv;
 | 
			
		||||
     const char *options;
 | 
			
		||||
     const struct option *long_options;
 | 
			
		||||
     int *opt_index;
 | 
			
		||||
{
 | 
			
		||||
  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
 | 
			
		||||
   If an option that starts with '-' (not '--') doesn't match a long option,
 | 
			
		||||
   but does match a short option, it is parsed as a short option
 | 
			
		||||
   instead.  */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
getopt_long_only (argc, argv, options, long_options, opt_index)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char *const *argv;
 | 
			
		||||
     const char *options;
 | 
			
		||||
     const struct option *long_options;
 | 
			
		||||
     int *opt_index;
 | 
			
		||||
{
 | 
			
		||||
  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif	/* _LIBC or not __GNU_LIBRARY__.  */
 | 
			
		||||
 | 
			
		||||
#ifdef TEST
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (argc, argv)
 | 
			
		||||
     int argc;
 | 
			
		||||
     char **argv;
 | 
			
		||||
{
 | 
			
		||||
  int c;
 | 
			
		||||
  int digit_optind = 0;
 | 
			
		||||
 | 
			
		||||
  while (1)
 | 
			
		||||
    {
 | 
			
		||||
      int this_option_optind = optind ? optind : 1;
 | 
			
		||||
      int option_index = 0;
 | 
			
		||||
      static struct option long_options[] =
 | 
			
		||||
      {
 | 
			
		||||
	{"add", 1, 0, 0},
 | 
			
		||||
	{"append", 0, 0, 0},
 | 
			
		||||
	{"delete", 1, 0, 0},
 | 
			
		||||
	{"verbose", 0, 0, 0},
 | 
			
		||||
	{"create", 0, 0, 0},
 | 
			
		||||
	{"file", 1, 0, 0},
 | 
			
		||||
	{0, 0, 0, 0}
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      c = getopt_long (argc, argv, "abc:d:0123456789",
 | 
			
		||||
		       long_options, &option_index);
 | 
			
		||||
      if (c == EOF)
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      switch (c)
 | 
			
		||||
	{
 | 
			
		||||
	case 0:
 | 
			
		||||
	  printf ("option %s", long_options[option_index].name);
 | 
			
		||||
	  if (optarg)
 | 
			
		||||
	    printf (" with arg %s", optarg);
 | 
			
		||||
	  printf ("\n");
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case '0':
 | 
			
		||||
	case '1':
 | 
			
		||||
	case '2':
 | 
			
		||||
	case '3':
 | 
			
		||||
	case '4':
 | 
			
		||||
	case '5':
 | 
			
		||||
	case '6':
 | 
			
		||||
	case '7':
 | 
			
		||||
	case '8':
 | 
			
		||||
	case '9':
 | 
			
		||||
	  if (digit_optind != 0 && digit_optind != this_option_optind)
 | 
			
		||||
	    printf ("digits occur in two different argv-elements.\n");
 | 
			
		||||
	  digit_optind = this_option_optind;
 | 
			
		||||
	  printf ("option %c\n", c);
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case 'a':
 | 
			
		||||
	  printf ("option a\n");
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case 'b':
 | 
			
		||||
	  printf ("option b\n");
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case 'c':
 | 
			
		||||
	  printf ("option c with value `%s'\n", optarg);
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case 'd':
 | 
			
		||||
	  printf ("option d with value `%s'\n", optarg);
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	case '?':
 | 
			
		||||
	  break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
	  printf ("?? getopt returned character code 0%o ??\n", c);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (optind < argc)
 | 
			
		||||
    {
 | 
			
		||||
      printf ("non-option ARGV-elements: ");
 | 
			
		||||
      while (optind < argc)
 | 
			
		||||
	printf ("%s ", argv[optind++]);
 | 
			
		||||
      printf ("\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  exit (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* TEST */
 | 
			
		||||
							
								
								
									
										859
									
								
								wincompat/sys/queue.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										859
									
								
								wincompat/sys/queue.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,859 @@
 | 
			
		|||
/*-
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 1991, 1993
 | 
			
		||||
 *	The Regents of the University of California.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. Neither the name of the University nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 *	@(#)queue.h	8.5 (Berkeley) 8/20/94
 | 
			
		||||
 * $FreeBSD$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _SYS_QUEUE_H_
 | 
			
		||||
#define	_SYS_QUEUE_H_
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file defines four types of data structures: singly-linked lists,
 | 
			
		||||
 * singly-linked tail queues, lists and tail queues.
 | 
			
		||||
 *
 | 
			
		||||
 * A singly-linked list is headed by a single forward pointer. The elements
 | 
			
		||||
 * are singly linked for minimum space and pointer manipulation overhead at
 | 
			
		||||
 * the expense of O(n) removal for arbitrary elements. New elements can be
 | 
			
		||||
 * added to the list after an existing element or at the head of the list.
 | 
			
		||||
 * Elements being removed from the head of the list should use the explicit
 | 
			
		||||
 * macro for this purpose for optimum efficiency. A singly-linked list may
 | 
			
		||||
 * only be traversed in the forward direction.  Singly-linked lists are ideal
 | 
			
		||||
 * for applications with large datasets and few or no removals or for
 | 
			
		||||
 * implementing a LIFO queue.
 | 
			
		||||
 *
 | 
			
		||||
 * A singly-linked tail queue is headed by a pair of pointers, one to the
 | 
			
		||||
 * head of the list and the other to the tail of the list. The elements are
 | 
			
		||||
 * singly linked for minimum space and pointer manipulation overhead at the
 | 
			
		||||
 * expense of O(n) removal for arbitrary elements. New elements can be added
 | 
			
		||||
 * to the list after an existing element, at the head of the list, or at the
 | 
			
		||||
 * end of the list. Elements being removed from the head of the tail queue
 | 
			
		||||
 * should use the explicit macro for this purpose for optimum efficiency.
 | 
			
		||||
 * A singly-linked tail queue may only be traversed in the forward direction.
 | 
			
		||||
 * Singly-linked tail queues are ideal for applications with large datasets
 | 
			
		||||
 * and few or no removals or for implementing a FIFO queue.
 | 
			
		||||
 *
 | 
			
		||||
 * A list is headed by a single forward pointer (or an array of forward
 | 
			
		||||
 * pointers for a hash table header). The elements are doubly linked
 | 
			
		||||
 * so that an arbitrary element can be removed without a need to
 | 
			
		||||
 * traverse the list. New elements can be added to the list before
 | 
			
		||||
 * or after an existing element or at the head of the list. A list
 | 
			
		||||
 * may be traversed in either direction.
 | 
			
		||||
 *
 | 
			
		||||
 * A tail queue is headed by a pair of pointers, one to the head of the
 | 
			
		||||
 * list and the other to the tail of the list. The elements are doubly
 | 
			
		||||
 * linked so that an arbitrary element can be removed without a need to
 | 
			
		||||
 * traverse the list. New elements can be added to the list before or
 | 
			
		||||
 * after an existing element, at the head of the list, or at the end of
 | 
			
		||||
 * the list. A tail queue may be traversed in either direction.
 | 
			
		||||
 *
 | 
			
		||||
 * For details on the use of these macros, see the queue(3) manual page.
 | 
			
		||||
 *
 | 
			
		||||
 * Below is a summary of implemented functions where:
 | 
			
		||||
 *  +  means the macro is available
 | 
			
		||||
 *  -  means the macro is not available
 | 
			
		||||
 *  s  means the macro is available but is slow (runs in O(n) time)
 | 
			
		||||
 *
 | 
			
		||||
 *				SLIST	LIST	STAILQ	TAILQ
 | 
			
		||||
 * _HEAD			+	+	+	+
 | 
			
		||||
 * _CLASS_HEAD			+	+	+	+
 | 
			
		||||
 * _HEAD_INITIALIZER		+	+	+	+
 | 
			
		||||
 * _ENTRY			+	+	+	+
 | 
			
		||||
 * _CLASS_ENTRY			+	+	+	+
 | 
			
		||||
 * _INIT			+	+	+	+
 | 
			
		||||
 * _EMPTY			+	+	+	+
 | 
			
		||||
 * _FIRST			+	+	+	+
 | 
			
		||||
 * _NEXT			+	+	+	+
 | 
			
		||||
 * _PREV			-	+	-	+
 | 
			
		||||
 * _LAST			-	-	+	+
 | 
			
		||||
 * _FOREACH			+	+	+	+
 | 
			
		||||
 * _FOREACH_FROM		+	+	+	+
 | 
			
		||||
 * _FOREACH_SAFE		+	+	+	+
 | 
			
		||||
 * _FOREACH_FROM_SAFE		+	+	+	+
 | 
			
		||||
 * _FOREACH_REVERSE		-	-	-	+
 | 
			
		||||
 * _FOREACH_REVERSE_FROM	-	-	-	+
 | 
			
		||||
 * _FOREACH_REVERSE_SAFE	-	-	-	+
 | 
			
		||||
 * _FOREACH_REVERSE_FROM_SAFE	-	-	-	+
 | 
			
		||||
 * _INSERT_HEAD			+	+	+	+
 | 
			
		||||
 * _INSERT_BEFORE		-	+	-	+
 | 
			
		||||
 * _INSERT_AFTER		+	+	+	+
 | 
			
		||||
 * _INSERT_TAIL			-	-	+	+
 | 
			
		||||
 * _CONCAT			s	s	+	+
 | 
			
		||||
 * _REMOVE_AFTER		+	-	+	-
 | 
			
		||||
 * _REMOVE_HEAD			+	-	+	-
 | 
			
		||||
 * _REMOVE			s	+	s	+
 | 
			
		||||
 * _SWAP			+	+	+	+
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#ifdef QUEUE_MACRO_DEBUG
 | 
			
		||||
#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
 | 
			
		||||
#define	QUEUE_MACRO_DEBUG_TRACE
 | 
			
		||||
#define	QUEUE_MACRO_DEBUG_TRASH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef QUEUE_MACRO_DEBUG_TRACE
 | 
			
		||||
/* Store the last 2 places the queue element or head was altered */
 | 
			
		||||
struct qm_trace {
 | 
			
		||||
	unsigned long	 lastline;
 | 
			
		||||
	unsigned long	 prevline;
 | 
			
		||||
	const char	*lastfile;
 | 
			
		||||
	const char	*prevfile;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define	TRACEBUF	struct qm_trace trace;
 | 
			
		||||
#define	TRACEBUF_INITIALIZER	{ __LINE__, 0, __FILE__, NULL } ,
 | 
			
		||||
 | 
			
		||||
#define	QMD_TRACE_HEAD(head) do {					\
 | 
			
		||||
	(head)->trace.prevline = (head)->trace.lastline;		\
 | 
			
		||||
	(head)->trace.prevfile = (head)->trace.lastfile;		\
 | 
			
		||||
	(head)->trace.lastline = __LINE__;				\
 | 
			
		||||
	(head)->trace.lastfile = __FILE__;				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	QMD_TRACE_ELEM(elem) do {					\
 | 
			
		||||
	(elem)->trace.prevline = (elem)->trace.lastline;		\
 | 
			
		||||
	(elem)->trace.prevfile = (elem)->trace.lastfile;		\
 | 
			
		||||
	(elem)->trace.lastline = __LINE__;				\
 | 
			
		||||
	(elem)->trace.lastfile = __FILE__;				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#else	/* !QUEUE_MACRO_DEBUG_TRACE */
 | 
			
		||||
#define	QMD_TRACE_ELEM(elem)
 | 
			
		||||
#define	QMD_TRACE_HEAD(head)
 | 
			
		||||
#define	TRACEBUF
 | 
			
		||||
#define	TRACEBUF_INITIALIZER
 | 
			
		||||
#endif	/* QUEUE_MACRO_DEBUG_TRACE */
 | 
			
		||||
 | 
			
		||||
#ifdef QUEUE_MACRO_DEBUG_TRASH
 | 
			
		||||
#define	TRASHIT(x)		do {(x) = (void *)-1;} while (0)
 | 
			
		||||
#define	QMD_IS_TRASHED(x)	((x) == (void *)(intptr_t)-1)
 | 
			
		||||
#else	/* !QUEUE_MACRO_DEBUG_TRASH */
 | 
			
		||||
#define	TRASHIT(x)
 | 
			
		||||
#define	QMD_IS_TRASHED(x)	0
 | 
			
		||||
#endif	/* QUEUE_MACRO_DEBUG_TRASH */
 | 
			
		||||
 | 
			
		||||
#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH)
 | 
			
		||||
#define	QMD_SAVELINK(name, link)	void **name = (void *)&(link)
 | 
			
		||||
#else	/* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */
 | 
			
		||||
#define	QMD_SAVELINK(name, link)
 | 
			
		||||
#endif	/* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
/*
 | 
			
		||||
 * In C++ there can be structure lists and class lists:
 | 
			
		||||
 */
 | 
			
		||||
#define	QUEUE_TYPEOF(type) type
 | 
			
		||||
#else
 | 
			
		||||
#define	QUEUE_TYPEOF(type) struct type
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Singly-linked List declarations.
 | 
			
		||||
 */
 | 
			
		||||
#define	SLIST_HEAD(name, type)						\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	struct type *slh_first;	/* first element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	SLIST_CLASS_HEAD(name, type)					\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	class type *slh_first;	/* first element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	SLIST_HEAD_INITIALIZER(head)					\
 | 
			
		||||
	{ NULL }
 | 
			
		||||
 | 
			
		||||
#define	SLIST_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	struct type *sle_next;	/* next element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	SLIST_CLASS_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	class type *sle_next;		/* next element */		\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Singly-linked List functions.
 | 
			
		||||
 */
 | 
			
		||||
#if (defined(_KERNEL) && defined(INVARIANTS))
 | 
			
		||||
#define	QMD_SLIST_CHECK_PREVPTR(prevp, elm) do {			\
 | 
			
		||||
	if (*(prevp) != (elm))						\
 | 
			
		||||
		panic("Bad prevptr *(%p) == %p != %p",			\
 | 
			
		||||
		    (prevp), *(prevp), (elm));				\
 | 
			
		||||
} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define	QMD_SLIST_CHECK_PREVPTR(prevp, elm)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SLIST_CONCAT(head1, head2, type, field) do {			\
 | 
			
		||||
	QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1);		\
 | 
			
		||||
	if (curelm == NULL) {						\
 | 
			
		||||
		if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL)	\
 | 
			
		||||
			SLIST_INIT(head2);				\
 | 
			
		||||
	} else if (SLIST_FIRST(head2) != NULL) {			\
 | 
			
		||||
		while (SLIST_NEXT(curelm, field) != NULL)		\
 | 
			
		||||
			curelm = SLIST_NEXT(curelm, field);		\
 | 
			
		||||
		SLIST_NEXT(curelm, field) = SLIST_FIRST(head2);		\
 | 
			
		||||
		SLIST_INIT(head2);					\
 | 
			
		||||
	}								\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FIRST(head)	((head)->slh_first)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FOREACH(var, head, field)					\
 | 
			
		||||
	for ((var) = SLIST_FIRST((head));				\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = SLIST_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FOREACH_FROM(var, head, field)				\
 | 
			
		||||
	for ((var) = ((var) ? (var) : SLIST_FIRST((head)));		\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = SLIST_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = SLIST_FIRST((head));				\
 | 
			
		||||
	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FOREACH_FROM_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = ((var) ? (var) : SLIST_FIRST((head)));		\
 | 
			
		||||
	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
 | 
			
		||||
	for ((varp) = &SLIST_FIRST((head));				\
 | 
			
		||||
	    ((var) = *(varp)) != NULL;					\
 | 
			
		||||
	    (varp) = &SLIST_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	SLIST_INIT(head) do {						\
 | 
			
		||||
	SLIST_FIRST((head)) = NULL;					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
 | 
			
		||||
	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
 | 
			
		||||
	SLIST_NEXT((slistelm), field) = (elm);				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
 | 
			
		||||
	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
 | 
			
		||||
	SLIST_FIRST((head)) = (elm);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_REMOVE(head, elm, type, field) do {			\
 | 
			
		||||
	QMD_SAVELINK(oldnext, (elm)->field.sle_next);			\
 | 
			
		||||
	if (SLIST_FIRST((head)) == (elm)) {				\
 | 
			
		||||
		SLIST_REMOVE_HEAD((head), field);			\
 | 
			
		||||
	}								\
 | 
			
		||||
	else {								\
 | 
			
		||||
		QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head);		\
 | 
			
		||||
		while (SLIST_NEXT(curelm, field) != (elm))		\
 | 
			
		||||
			curelm = SLIST_NEXT(curelm, field);		\
 | 
			
		||||
		SLIST_REMOVE_AFTER(curelm, field);			\
 | 
			
		||||
	}								\
 | 
			
		||||
	TRASHIT(*oldnext);						\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define SLIST_REMOVE_AFTER(elm, field) do {				\
 | 
			
		||||
	SLIST_NEXT(elm, field) =					\
 | 
			
		||||
	    SLIST_NEXT(SLIST_NEXT(elm, field), field);			\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_REMOVE_HEAD(head, field) do {				\
 | 
			
		||||
	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	SLIST_REMOVE_PREVPTR(prevp, elm, field) do {			\
 | 
			
		||||
	QMD_SLIST_CHECK_PREVPTR(prevp, elm);				\
 | 
			
		||||
	*(prevp) = SLIST_NEXT(elm, field);				\
 | 
			
		||||
	TRASHIT((elm)->field.sle_next);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define SLIST_SWAP(head1, head2, type) do {				\
 | 
			
		||||
	QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1);		\
 | 
			
		||||
	SLIST_FIRST(head1) = SLIST_FIRST(head2);			\
 | 
			
		||||
	SLIST_FIRST(head2) = swap_first;				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Singly-linked Tail queue declarations.
 | 
			
		||||
 */
 | 
			
		||||
#define	STAILQ_HEAD(name, type)						\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	struct type *stqh_first;/* first element */			\
 | 
			
		||||
	struct type **stqh_last;/* addr of last next element */		\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_CLASS_HEAD(name, type)					\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	class type *stqh_first;	/* first element */			\
 | 
			
		||||
	class type **stqh_last;	/* addr of last next element */		\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_HEAD_INITIALIZER(head)					\
 | 
			
		||||
	{ NULL, &(head).stqh_first }
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	struct type *stqe_next;	/* next element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_CLASS_ENTRY(type)					\
 | 
			
		||||
struct {								\
 | 
			
		||||
	class type *stqe_next;	/* next element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Singly-linked Tail queue functions.
 | 
			
		||||
 */
 | 
			
		||||
#define	STAILQ_CONCAT(head1, head2) do {				\
 | 
			
		||||
	if (!STAILQ_EMPTY((head2))) {					\
 | 
			
		||||
		*(head1)->stqh_last = (head2)->stqh_first;		\
 | 
			
		||||
		(head1)->stqh_last = (head2)->stqh_last;		\
 | 
			
		||||
		STAILQ_INIT((head2));					\
 | 
			
		||||
	}								\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_FIRST(head)	((head)->stqh_first)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_FOREACH(var, head, field)				\
 | 
			
		||||
	for((var) = STAILQ_FIRST((head));				\
 | 
			
		||||
	   (var);							\
 | 
			
		||||
	   (var) = STAILQ_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_FOREACH_FROM(var, head, field)				\
 | 
			
		||||
	for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));		\
 | 
			
		||||
	   (var);							\
 | 
			
		||||
	   (var) = STAILQ_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = STAILQ_FIRST((head));				\
 | 
			
		||||
	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)		\
 | 
			
		||||
	for ((var) = ((var) ? (var) : STAILQ_FIRST((head)));		\
 | 
			
		||||
	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_INIT(head) do {						\
 | 
			
		||||
	STAILQ_FIRST((head)) = NULL;					\
 | 
			
		||||
	(head)->stqh_last = &STAILQ_FIRST((head));			\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
 | 
			
		||||
	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
 | 
			
		||||
		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
 | 
			
		||||
	STAILQ_NEXT((tqelm), field) = (elm);				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
 | 
			
		||||
	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
 | 
			
		||||
		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
 | 
			
		||||
	STAILQ_FIRST((head)) = (elm);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
 | 
			
		||||
	STAILQ_NEXT((elm), field) = NULL;				\
 | 
			
		||||
	*(head)->stqh_last = (elm);					\
 | 
			
		||||
	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_LAST(head, type, field)				\
 | 
			
		||||
	(STAILQ_EMPTY((head)) ? NULL :				\
 | 
			
		||||
	    __containerof((head)->stqh_last,			\
 | 
			
		||||
	    QUEUE_TYPEOF(type), field.stqe_next))
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_REMOVE(head, elm, type, field) do {			\
 | 
			
		||||
	QMD_SAVELINK(oldnext, (elm)->field.stqe_next);			\
 | 
			
		||||
	if (STAILQ_FIRST((head)) == (elm)) {				\
 | 
			
		||||
		STAILQ_REMOVE_HEAD((head), field);			\
 | 
			
		||||
	}								\
 | 
			
		||||
	else {								\
 | 
			
		||||
		QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head);	\
 | 
			
		||||
		while (STAILQ_NEXT(curelm, field) != (elm))		\
 | 
			
		||||
			curelm = STAILQ_NEXT(curelm, field);		\
 | 
			
		||||
		STAILQ_REMOVE_AFTER(head, curelm, field);		\
 | 
			
		||||
	}								\
 | 
			
		||||
	TRASHIT(*oldnext);						\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
 | 
			
		||||
	if ((STAILQ_NEXT(elm, field) =					\
 | 
			
		||||
	     STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
 | 
			
		||||
		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	STAILQ_REMOVE_HEAD(head, field) do {				\
 | 
			
		||||
	if ((STAILQ_FIRST((head)) =					\
 | 
			
		||||
	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
 | 
			
		||||
		(head)->stqh_last = &STAILQ_FIRST((head));		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define STAILQ_SWAP(head1, head2, type) do {				\
 | 
			
		||||
	QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1);		\
 | 
			
		||||
	QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last;		\
 | 
			
		||||
	STAILQ_FIRST(head1) = STAILQ_FIRST(head2);			\
 | 
			
		||||
	(head1)->stqh_last = (head2)->stqh_last;			\
 | 
			
		||||
	STAILQ_FIRST(head2) = swap_first;				\
 | 
			
		||||
	(head2)->stqh_last = swap_last;					\
 | 
			
		||||
	if (STAILQ_EMPTY(head1))					\
 | 
			
		||||
		(head1)->stqh_last = &STAILQ_FIRST(head1);		\
 | 
			
		||||
	if (STAILQ_EMPTY(head2))					\
 | 
			
		||||
		(head2)->stqh_last = &STAILQ_FIRST(head2);		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List declarations.
 | 
			
		||||
 */
 | 
			
		||||
#define	LIST_HEAD(name, type)						\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	struct type *lh_first;	/* first element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	LIST_CLASS_HEAD(name, type)					\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	class type *lh_first;	/* first element */			\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	LIST_HEAD_INITIALIZER(head)					\
 | 
			
		||||
	{ NULL }
 | 
			
		||||
 | 
			
		||||
#define	LIST_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	struct type *le_next;	/* next element */			\
 | 
			
		||||
	struct type **le_prev;	/* address of previous next element */	\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	LIST_CLASS_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	class type *le_next;	/* next element */			\
 | 
			
		||||
	class type **le_prev;	/* address of previous next element */	\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List functions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if (defined(_KERNEL) && defined(INVARIANTS))
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * If the list is non-empty, validates that the first element of the list
 | 
			
		||||
 * points back at 'head.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_LIST_CHECK_HEAD(head, field) do {				\
 | 
			
		||||
	if (LIST_FIRST((head)) != NULL &&				\
 | 
			
		||||
	    LIST_FIRST((head))->field.le_prev !=			\
 | 
			
		||||
	     &LIST_FIRST((head)))					\
 | 
			
		||||
		panic("Bad list head %p first->prev != head", (head));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * If an element follows 'elm' in the list, validates that the next element
 | 
			
		||||
 * points back at 'elm.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_LIST_CHECK_NEXT(elm, field) do {				\
 | 
			
		||||
	if (LIST_NEXT((elm), field) != NULL &&				\
 | 
			
		||||
	    LIST_NEXT((elm), field)->field.le_prev !=			\
 | 
			
		||||
	     &((elm)->field.le_next))					\
 | 
			
		||||
	     	panic("Bad link elm %p next->prev != elm", (elm));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * Validates that the previous element (or head of the list) points to 'elm.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_LIST_CHECK_PREV(elm, field) do {				\
 | 
			
		||||
	if (*(elm)->field.le_prev != (elm))				\
 | 
			
		||||
		panic("Bad link elm %p prev->next != elm", (elm));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define	QMD_LIST_CHECK_HEAD(head, field)
 | 
			
		||||
#define	QMD_LIST_CHECK_NEXT(elm, field)
 | 
			
		||||
#define	QMD_LIST_CHECK_PREV(elm, field)
 | 
			
		||||
#endif /* (_KERNEL && INVARIANTS) */
 | 
			
		||||
 | 
			
		||||
#define LIST_CONCAT(head1, head2, type, field) do {			      \
 | 
			
		||||
	QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1);			      \
 | 
			
		||||
	if (curelm == NULL) {						      \
 | 
			
		||||
		if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) {	      \
 | 
			
		||||
			LIST_FIRST(head2)->field.le_prev =		      \
 | 
			
		||||
			    &LIST_FIRST((head1));			      \
 | 
			
		||||
			LIST_INIT(head2);				      \
 | 
			
		||||
		}							      \
 | 
			
		||||
	} else if (LIST_FIRST(head2) != NULL) {				      \
 | 
			
		||||
		while (LIST_NEXT(curelm, field) != NULL)		      \
 | 
			
		||||
			curelm = LIST_NEXT(curelm, field);		      \
 | 
			
		||||
		LIST_NEXT(curelm, field) = LIST_FIRST(head2);		      \
 | 
			
		||||
		LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
 | 
			
		||||
		LIST_INIT(head2);					      \
 | 
			
		||||
	}								      \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
 | 
			
		||||
 | 
			
		||||
#define	LIST_FIRST(head)	((head)->lh_first)
 | 
			
		||||
 | 
			
		||||
#define	LIST_FOREACH(var, head, field)					\
 | 
			
		||||
	for ((var) = LIST_FIRST((head));				\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = LIST_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	LIST_FOREACH_FROM(var, head, field)				\
 | 
			
		||||
	for ((var) = ((var) ? (var) : LIST_FIRST((head)));		\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = LIST_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = LIST_FIRST((head));				\
 | 
			
		||||
	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	LIST_FOREACH_FROM_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = ((var) ? (var) : LIST_FIRST((head)));		\
 | 
			
		||||
	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	LIST_INIT(head) do {						\
 | 
			
		||||
	LIST_FIRST((head)) = NULL;					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
 | 
			
		||||
	QMD_LIST_CHECK_NEXT(listelm, field);				\
 | 
			
		||||
	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
 | 
			
		||||
		LIST_NEXT((listelm), field)->field.le_prev =		\
 | 
			
		||||
		    &LIST_NEXT((elm), field);				\
 | 
			
		||||
	LIST_NEXT((listelm), field) = (elm);				\
 | 
			
		||||
	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
 | 
			
		||||
	QMD_LIST_CHECK_PREV(listelm, field);				\
 | 
			
		||||
	(elm)->field.le_prev = (listelm)->field.le_prev;		\
 | 
			
		||||
	LIST_NEXT((elm), field) = (listelm);				\
 | 
			
		||||
	*(listelm)->field.le_prev = (elm);				\
 | 
			
		||||
	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	LIST_INSERT_HEAD(head, elm, field) do {				\
 | 
			
		||||
	QMD_LIST_CHECK_HEAD((head), field);				\
 | 
			
		||||
	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
 | 
			
		||||
		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
 | 
			
		||||
	LIST_FIRST((head)) = (elm);					\
 | 
			
		||||
	(elm)->field.le_prev = &LIST_FIRST((head));			\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
 | 
			
		||||
 | 
			
		||||
#define	LIST_PREV(elm, head, type, field)			\
 | 
			
		||||
	((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL :	\
 | 
			
		||||
	    __containerof((elm)->field.le_prev,			\
 | 
			
		||||
	    QUEUE_TYPEOF(type), field.le_next))
 | 
			
		||||
 | 
			
		||||
#define	LIST_REMOVE(elm, field) do {					\
 | 
			
		||||
	QMD_SAVELINK(oldnext, (elm)->field.le_next);			\
 | 
			
		||||
	QMD_SAVELINK(oldprev, (elm)->field.le_prev);			\
 | 
			
		||||
	QMD_LIST_CHECK_NEXT(elm, field);				\
 | 
			
		||||
	QMD_LIST_CHECK_PREV(elm, field);				\
 | 
			
		||||
	if (LIST_NEXT((elm), field) != NULL)				\
 | 
			
		||||
		LIST_NEXT((elm), field)->field.le_prev = 		\
 | 
			
		||||
		    (elm)->field.le_prev;				\
 | 
			
		||||
	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
 | 
			
		||||
	TRASHIT(*oldnext);						\
 | 
			
		||||
	TRASHIT(*oldprev);						\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define LIST_SWAP(head1, head2, type, field) do {			\
 | 
			
		||||
	QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1);		\
 | 
			
		||||
	LIST_FIRST((head1)) = LIST_FIRST((head2));			\
 | 
			
		||||
	LIST_FIRST((head2)) = swap_tmp;					\
 | 
			
		||||
	if ((swap_tmp = LIST_FIRST((head1))) != NULL)			\
 | 
			
		||||
		swap_tmp->field.le_prev = &LIST_FIRST((head1));		\
 | 
			
		||||
	if ((swap_tmp = LIST_FIRST((head2))) != NULL)			\
 | 
			
		||||
		swap_tmp->field.le_prev = &LIST_FIRST((head2));		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Tail queue declarations.
 | 
			
		||||
 */
 | 
			
		||||
#define	TAILQ_HEAD(name, type)						\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	struct type *tqh_first;	/* first element */			\
 | 
			
		||||
	struct type **tqh_last;	/* addr of last next element */		\
 | 
			
		||||
	TRACEBUF							\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_CLASS_HEAD(name, type)					\
 | 
			
		||||
struct name {								\
 | 
			
		||||
	class type *tqh_first;	/* first element */			\
 | 
			
		||||
	class type **tqh_last;	/* addr of last next element */		\
 | 
			
		||||
	TRACEBUF							\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_HEAD_INITIALIZER(head)					\
 | 
			
		||||
	{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	struct type *tqe_next;	/* next element */			\
 | 
			
		||||
	struct type **tqe_prev;	/* address of previous next element */	\
 | 
			
		||||
	TRACEBUF							\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_CLASS_ENTRY(type)						\
 | 
			
		||||
struct {								\
 | 
			
		||||
	class type *tqe_next;	/* next element */			\
 | 
			
		||||
	class type **tqe_prev;	/* address of previous next element */	\
 | 
			
		||||
	TRACEBUF							\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Tail queue functions.
 | 
			
		||||
 */
 | 
			
		||||
#if (defined(_KERNEL) && defined(INVARIANTS))
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * If the tailq is non-empty, validates that the first element of the tailq
 | 
			
		||||
 * points back at 'head.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_TAILQ_CHECK_HEAD(head, field) do {				\
 | 
			
		||||
	if (!TAILQ_EMPTY(head) &&					\
 | 
			
		||||
	    TAILQ_FIRST((head))->field.tqe_prev !=			\
 | 
			
		||||
	     &TAILQ_FIRST((head)))					\
 | 
			
		||||
		panic("Bad tailq head %p first->prev != head", (head));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * Validates that the tail of the tailq is a pointer to pointer to NULL.
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_TAILQ_CHECK_TAIL(head, field) do {				\
 | 
			
		||||
	if (*(head)->tqh_last != NULL)					\
 | 
			
		||||
	    	panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); 	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * If an element follows 'elm' in the tailq, validates that the next element
 | 
			
		||||
 * points back at 'elm.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_TAILQ_CHECK_NEXT(elm, field) do {				\
 | 
			
		||||
	if (TAILQ_NEXT((elm), field) != NULL &&				\
 | 
			
		||||
	    TAILQ_NEXT((elm), field)->field.tqe_prev !=			\
 | 
			
		||||
	     &((elm)->field.tqe_next))					\
 | 
			
		||||
		panic("Bad link elm %p next->prev != elm", (elm));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME)
 | 
			
		||||
 *
 | 
			
		||||
 * Validates that the previous element (or head of the tailq) points to 'elm.'
 | 
			
		||||
 */
 | 
			
		||||
#define	QMD_TAILQ_CHECK_PREV(elm, field) do {				\
 | 
			
		||||
	if (*(elm)->field.tqe_prev != (elm))				\
 | 
			
		||||
		panic("Bad link elm %p prev->next != elm", (elm));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define	QMD_TAILQ_CHECK_HEAD(head, field)
 | 
			
		||||
#define	QMD_TAILQ_CHECK_TAIL(head, headname)
 | 
			
		||||
#define	QMD_TAILQ_CHECK_NEXT(elm, field)
 | 
			
		||||
#define	QMD_TAILQ_CHECK_PREV(elm, field)
 | 
			
		||||
#endif /* (_KERNEL && INVARIANTS) */
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_CONCAT(head1, head2, field) do {				\
 | 
			
		||||
	if (!TAILQ_EMPTY(head2)) {					\
 | 
			
		||||
		*(head1)->tqh_last = (head2)->tqh_first;		\
 | 
			
		||||
		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
 | 
			
		||||
		(head1)->tqh_last = (head2)->tqh_last;			\
 | 
			
		||||
		TAILQ_INIT((head2));					\
 | 
			
		||||
		QMD_TRACE_HEAD(head1);					\
 | 
			
		||||
		QMD_TRACE_HEAD(head2);					\
 | 
			
		||||
	}								\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FIRST(head)	((head)->tqh_first)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH(var, head, field)					\
 | 
			
		||||
	for ((var) = TAILQ_FIRST((head));				\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = TAILQ_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_FROM(var, head, field)				\
 | 
			
		||||
	for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));		\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = TAILQ_NEXT((var), field))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = TAILQ_FIRST((head));				\
 | 
			
		||||
	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar)			\
 | 
			
		||||
	for ((var) = ((var) ? (var) : TAILQ_FIRST((head)));		\
 | 
			
		||||
	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
 | 
			
		||||
	for ((var) = TAILQ_LAST((head), headname);			\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = TAILQ_PREV((var), headname, field))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field)		\
 | 
			
		||||
	for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));	\
 | 
			
		||||
	    (var);							\
 | 
			
		||||
	    (var) = TAILQ_PREV((var), headname, field))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
 | 
			
		||||
	for ((var) = TAILQ_LAST((head), headname);			\
 | 
			
		||||
	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
 | 
			
		||||
	for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname));	\
 | 
			
		||||
	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
 | 
			
		||||
	    (var) = (tvar))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_INIT(head) do {						\
 | 
			
		||||
	TAILQ_FIRST((head)) = NULL;					\
 | 
			
		||||
	(head)->tqh_last = &TAILQ_FIRST((head));			\
 | 
			
		||||
	QMD_TRACE_HEAD(head);						\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
 | 
			
		||||
	QMD_TAILQ_CHECK_NEXT(listelm, field);				\
 | 
			
		||||
	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
 | 
			
		||||
		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
 | 
			
		||||
		    &TAILQ_NEXT((elm), field);				\
 | 
			
		||||
	else {								\
 | 
			
		||||
		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
 | 
			
		||||
		QMD_TRACE_HEAD(head);					\
 | 
			
		||||
	}								\
 | 
			
		||||
	TAILQ_NEXT((listelm), field) = (elm);				\
 | 
			
		||||
	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
 | 
			
		||||
	QMD_TRACE_ELEM(&(elm)->field);					\
 | 
			
		||||
	QMD_TRACE_ELEM(&(listelm)->field);				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
 | 
			
		||||
	QMD_TAILQ_CHECK_PREV(listelm, field);				\
 | 
			
		||||
	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
 | 
			
		||||
	TAILQ_NEXT((elm), field) = (listelm);				\
 | 
			
		||||
	*(listelm)->field.tqe_prev = (elm);				\
 | 
			
		||||
	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
 | 
			
		||||
	QMD_TRACE_ELEM(&(elm)->field);					\
 | 
			
		||||
	QMD_TRACE_ELEM(&(listelm)->field);				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
 | 
			
		||||
	QMD_TAILQ_CHECK_HEAD(head, field);				\
 | 
			
		||||
	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
 | 
			
		||||
		TAILQ_FIRST((head))->field.tqe_prev =			\
 | 
			
		||||
		    &TAILQ_NEXT((elm), field);				\
 | 
			
		||||
	else								\
 | 
			
		||||
		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
 | 
			
		||||
	TAILQ_FIRST((head)) = (elm);					\
 | 
			
		||||
	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
 | 
			
		||||
	QMD_TRACE_HEAD(head);						\
 | 
			
		||||
	QMD_TRACE_ELEM(&(elm)->field);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
 | 
			
		||||
	QMD_TAILQ_CHECK_TAIL(head, field);				\
 | 
			
		||||
	TAILQ_NEXT((elm), field) = NULL;				\
 | 
			
		||||
	(elm)->field.tqe_prev = (head)->tqh_last;			\
 | 
			
		||||
	*(head)->tqh_last = (elm);					\
 | 
			
		||||
	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
 | 
			
		||||
	QMD_TRACE_HEAD(head);						\
 | 
			
		||||
	QMD_TRACE_ELEM(&(elm)->field);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_LAST(head, headname)					\
 | 
			
		||||
	(*(((struct headname *)((head)->tqh_last))->tqh_last))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_PREV(elm, headname, field)				\
 | 
			
		||||
	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
 | 
			
		||||
 | 
			
		||||
#define	TAILQ_REMOVE(head, elm, field) do {				\
 | 
			
		||||
	QMD_SAVELINK(oldnext, (elm)->field.tqe_next);			\
 | 
			
		||||
	QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);			\
 | 
			
		||||
	QMD_TAILQ_CHECK_NEXT(elm, field);				\
 | 
			
		||||
	QMD_TAILQ_CHECK_PREV(elm, field);				\
 | 
			
		||||
	if ((TAILQ_NEXT((elm), field)) != NULL)				\
 | 
			
		||||
		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
 | 
			
		||||
		    (elm)->field.tqe_prev;				\
 | 
			
		||||
	else {								\
 | 
			
		||||
		(head)->tqh_last = (elm)->field.tqe_prev;		\
 | 
			
		||||
		QMD_TRACE_HEAD(head);					\
 | 
			
		||||
	}								\
 | 
			
		||||
	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
 | 
			
		||||
	TRASHIT(*oldnext);						\
 | 
			
		||||
	TRASHIT(*oldprev);						\
 | 
			
		||||
	QMD_TRACE_ELEM(&(elm)->field);					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define TAILQ_SWAP(head1, head2, type, field) do {			\
 | 
			
		||||
	QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first;		\
 | 
			
		||||
	QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last;		\
 | 
			
		||||
	(head1)->tqh_first = (head2)->tqh_first;			\
 | 
			
		||||
	(head1)->tqh_last = (head2)->tqh_last;				\
 | 
			
		||||
	(head2)->tqh_first = swap_first;				\
 | 
			
		||||
	(head2)->tqh_last = swap_last;					\
 | 
			
		||||
	if ((swap_first = (head1)->tqh_first) != NULL)			\
 | 
			
		||||
		swap_first->field.tqe_prev = &(head1)->tqh_first;	\
 | 
			
		||||
	else								\
 | 
			
		||||
		(head1)->tqh_last = &(head1)->tqh_first;		\
 | 
			
		||||
	if ((swap_first = (head2)->tqh_first) != NULL)			\
 | 
			
		||||
		swap_first->field.tqe_prev = &(head2)->tqh_first;	\
 | 
			
		||||
	else								\
 | 
			
		||||
		(head2)->tqh_last = &(head2)->tqh_first;		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#endif /* !_SYS_QUEUE_H_ */
 | 
			
		||||
							
								
								
									
										1019
									
								
								wincompat/test_common_win.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1019
									
								
								wincompat/test_common_win.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										34
									
								
								wincompat/vc_compat.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								wincompat/vc_compat.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
typedef SSIZE_T ssize_t;
 | 
			
		||||
struct iovec {
 | 
			
		||||
  void  *iov_base;    /* Starting address */
 | 
			
		||||
  size_t iov_len;     /* Number of bytes to transfer */
 | 
			
		||||
};
 | 
			
		||||
#define strcasecmp(a,b) _strcmpi(a,b)
 | 
			
		||||
#define strdup _strdup
 | 
			
		||||
 | 
			
		||||
#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno)
 | 
			
		||||
 | 
			
		||||
#pragma warning(disable: 4018 4100 4127 4189 4200 4204 4214 4152 4221 4244 4245 4267 4334 4702 4706 4804 ) 
 | 
			
		||||
                                    /*
 | 
			
		||||
                                    4018:signed/unsigned mismatch
 | 
			
		||||
                                    4100:unreferenced formal parameter,
 | 
			
		||||
                                    4127: conditional expression is constant
 | 
			
		||||
									4152: nonstandard extension, function/data pointer conversion in expression
 | 
			
		||||
									4189:local variable is initialized but not referenced
 | 
			
		||||
                                    4200:zero-sized-array in struct, 
 | 
			
		||||
                                    4204: nonstandard extension used: non-constant aggregate initializer,
 | 
			
		||||
                                    4214: nonstandard extension used: bit field types other than int
 | 
			
		||||
                                    4221: nonstandard extension used:xx cannot be initialized using address of automatic variable y,
 | 
			
		||||
                                    4244: '+=': conversion from 'int' to 'unsigned short', possible loss of data
 | 
			
		||||
                                    4245:'=': conversion from 'int' to 'unsigned int', signed/unsigned mismatch
 | 
			
		||||
                                    4267 function': conversion from 'size_t' to 'int', possible loss of data
 | 
			
		||||
                                    4334: '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
 | 
			
		||||
                                    4702: unreachable code
 | 
			
		||||
                                    4706: assignment within conditional expression,
 | 
			
		||||
                                    4804: '-': unsafe use of type 'bool' in operation
 | 
			
		||||
                                    */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue