diff --git a/CMakeLists.txt b/CMakeLists.txt index ff1c516a9..0f6671cab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,9 +17,40 @@ if(NOT SSL_TYPE) set(SSL_TYPE "babassl") endif() -# PATH of ssl -if(NOT SSL_PATH) - set(SSL_PATH "/usr/local/babassl") +if(${SSL_TYPE} MATCHES "babassl") + # PATH of ssl + if(NOT SSL_PATH) + set(SSL_PATH "/usr/local/babassl") + endif() + + # ssl lib denpendency + if(NOT SSL_LIB_PATH) + set(SSL_LIB_PATH + ${SSL_PATH}/lib/libssl.a + ${SSL_PATH}/lib/libcrypto.a + ) + endif() +elseif(${SSL_TYPE} MATCHES "boringssl") + # PATH of ssl + if(NOT SSL_PATH) + set(SSL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/third_party/boringssl) + endif() + + # ssl lib denpendency + if(NOT SSL_LIB_PATH) + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + add_definitions(-DNOCRYPT=1) + set(SSL_LIB_PATH + ${SSL_PATH}/build/ssl/${CMAKE_BUILD_TYPE}/ssl.lib + ${SSL_PATH}/build/crypto/${CMAKE_BUILD_TYPE}/crypto.lib + ) + else() + set(SSL_LIB_PATH + ${SSL_PATH}/build/ssl/libssl.a + ${SSL_PATH}/build/crypto/libcrypto.a + ) + endif() + endif() endif() # ssl include path @@ -29,13 +60,10 @@ if(NOT SSL_INC_PATH) ) endif() -# ssl lib denpendency -if(NOT SSL_LIB_PATH) - set(SSL_LIB_PATH - ${SSL_PATH}/lib/libssl.a - ${SSL_PATH}/lib/libcrypto.a - ) -endif() +MESSAGE("SSL_TYPE= ${SSL_TYPE}") +MESSAGE("SSL_PATH= ${SSL_PATH}") +MESSAGE("SSL_LIB_PATH= ${SSL_LIB_PATH}") +MESSAGE("SSL_INC_PATH= ${SSL_INC_PATH}") # print tls traffic secret in keylog if(XQC_PRINT_SECRET) @@ -65,8 +93,15 @@ endif() # C_FLAGS -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -std=gnu11 -Werror -Wall -Wno-unused -Wno-pointer-sign -Wno-format-security -DNDEBUG_PRINT -DNPRINT_MALLOC ") -set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Werror -Wall -Wno-unused -Wno-pointer-sign -Wno-format-security -DNDEBUG_PRINT -DNPRINT_MALLOC -DXQC_DEBUG ") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -std=gnu11 -Wall -DNDEBUG_PRINT -DNPRINT_MALLOC ") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Wall -DNDEBUG_PRINT -DNPRINT_MALLOC -DXQC_DEBUG ") + +if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-unused -Wno-pointer-sign -Wno-format-security ") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror -Wno-unused -Wno-pointer-sign -Wno-format-security ") +else() + add_definitions(-DXQC_SYS_WINDOWS=1) +endif() # additional C_FLAGS on mac if(PLATFORM STREQUAL "mac32") @@ -263,10 +298,9 @@ include_directories(${SSL_INC_PATH}) include_directories(${CMAKE_SOURCE_DIR}/) - ##### build unittest, test client/server, demo client/server ##### if (XQC_ENABLE_TESTING) - # CUnit + # CUnit TODO: fix test unit on windows find_package(CUnit 2.1) enable_testing() set(HAVE_CUNIT ${CUNIT_FOUND}) @@ -275,10 +309,24 @@ if (XQC_ENABLE_TESTING) endif() add_subdirectory(tests) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/test) + + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + # used wingetopt on windows + if(NOT GETOPT_INC_PATH) + set(GETOPT_INC_PATH + ${CMAKE_SOURCE_DIR}/third_party/wingetopt + ) + endif() + MESSAGE("GETOPT_INC_PATH= ${GETOPT_INC_PATH}") + + include_directories(${GETOPT_INC_PATH}/src) + set(GETOPT_SOURCES "${GETOPT_INC_PATH}/src/getopt.c") + endif() ### test client/server ### - add_executable(test_server tests/test_server.c) - add_executable(test_client tests/test_client.c) + add_executable(test_server tests/test_server.c ${GETOPT_SOURCES}) + add_executable(test_client tests/test_client.c ${GETOPT_SOURCES}) ### hq demo client/server ### set( @@ -300,10 +348,24 @@ if (XQC_ENABLE_TESTING) "demo/demo_server.c" ) - add_executable(demo_server ${DEMO_SERVER_SOURCES}) - add_executable(demo_client ${DEMO_CLIENT_SOURCES}) - - link_directories(/usr/local/lib) + add_executable(demo_server ${DEMO_SERVER_SOURCES} ${GETOPT_SOURCES}) + add_executable(demo_client ${DEMO_CLIENT_SOURCES} ${GETOPT_SOURCES}) + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + if (NOT EVENT_LIB_DIR) + message("YOU NEED SET -DEVENT_LIB_DIR=your_event_path, eg:-DEVENT_LIB_DIR=D:/project/vcpkg/packages/libevent_x64-windows-static") + endif() + + include_directories( ${EVENT_LIB_DIR}/include ) + link_directories( ${EVENT_LIB_DIR}/lib ) + + SET(EVENT_LIB_PATH + ${EVENT_LIB_DIR}/lib/event.lib + ${EVENT_LIB_DIR}/lib/event_core.lib + ${EVENT_LIB_DIR}/lib/event_extra.lib + ) + else() + link_directories( /usr/local/lib ) + endif() if(PLATFORM STREQUAL "mac32") target_link_libraries(test_server xquic -lm ${CMAKE_CURRENT_SOURCE_DIR}/../libevent32/lib/libevent.dylib) @@ -315,6 +377,11 @@ if (XQC_ENABLE_TESTING) target_link_libraries(test_client xquic -lm -L/usr/local/lib -levent) target_link_libraries(demo_server xquic -lm -L/usr/local/lib -levent) target_link_libraries(demo_client xquic -lm -L/usr/local/lib -levent) + elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") + target_link_libraries(test_server xquic ${EVENT_LIB_PATH} -lm) + target_link_libraries(test_client xquic ${EVENT_LIB_PATH} -lm) + target_link_libraries(demo_server xquic ${EVENT_LIB_PATH} -lm) + target_link_libraries(demo_client xquic ${EVENT_LIB_PATH} -lm) else() target_link_libraries(test_server xquic -levent -lm) target_link_libraries(test_client xquic -levent -lm) diff --git a/README.md b/README.md index 8e8dfff34..b19d256a4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ XQUIC Library released by Alibaba is … … **a client and server implementation of QUIC and HTTP/3 as specified by the IETF.** Currently supported QUIC versions are v1 and draft-29. -… **OS and platform agnostic.** It currently supports Android, iOS, Linux and macOS. Most of the code is used in our own products, and has been tested at scale on android, iOS apps, as well as servers. +… **OS and platform agnostic.** It currently supports Android, iOS, Linux, macOS and Windows. Most of the code is used in our own products, and has been tested at scale on android, iOS apps, as well as servers. … **still in active development.** [Interoperability](https://interop.seemann.io/) is regularly tested with other QUIC implementations. diff --git a/demo/common.h b/demo/common.h index 6ced07f35..f3c96793b 100644 --- a/demo/common.h +++ b/demo/common.h @@ -94,16 +94,4 @@ xqc_demo_read_file_data(char * data, size_t data_len, char *filename) return ret; } - -static inline uint64_t -xqc_demo_now() -{ - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; -} - - #endif diff --git a/demo/demo_client.c b/demo/demo_client.c index ab956df28..3c9559941 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -8,20 +8,30 @@ #include #include #include -#include + #include -#include -#include #include #include #include #include #include #include -#include #include +#include #include "common.h" #include "xqc_hq.h" +#include "../tests/platform.h" + +#ifdef XQC_SYS_WINDOWS +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#include +#else +#include +#include +#include +#endif #define XQC_PACKET_TMP_BUF_LEN 1600 @@ -396,7 +406,7 @@ void xqc_demo_cli_set_event_timer(xqc_usec_t wake_after, void *eng_user_data) { xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t *) eng_user_data; - //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_demo_now()); + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); struct timeval tv; tv.tv_sec = wake_after / 1000000; @@ -436,12 +446,12 @@ xqc_demo_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v //printf("%s", (char *)buf); int write_len = write(ctx->log_fd, buf, size); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->log_fd, line_break, 1); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_last_sys_errno()); } } @@ -479,12 +489,12 @@ xqc_demo_cli_keylog_cb(const char *line, void *engine_user_data) int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->keylog_fd, line_break, 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); } } @@ -535,7 +545,7 @@ xqc_demo_cli_save_token(const unsigned char *token, uint32_t token_len, void *co { xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t*)conn_user_data; - int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, S_IRWXU); + int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, 0666); if (fd < 0) { return; } @@ -569,23 +579,25 @@ xqc_demo_cli_write_socket(const unsigned char *buf, size_t size, const struct so xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *)conn_user_data; ssize_t res = 0; do { - errno = 0; + set_last_sys_errno(0); res = sendto(user_conn->fd, buf, size, 0, peer_addr, peer_addrlen); if (res < 0) { printf("xqc_demo_cli_write_socket err %zd %s, fd: %d, buf: %p, size: %zu, " - "server_addr: %s\n", res, strerror(errno), user_conn->fd, buf, size, - user_conn->ctx->args->net_cfg.server_addr); - if (errno == EAGAIN) { + "server_addr: %s\n", res, strerror(get_last_sys_errno()), user_conn->fd, + buf, size, user_conn->ctx->args->net_cfg.server_addr); + if (get_last_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } - user_conn->last_sock_op_time = xqc_demo_now(); - } while ((res < 0) && (errno == EINTR)); + user_conn->last_sock_op_time = xqc_now(); + + } while ((res < 0) && (get_last_sys_errno() == EINTR)); return res; } +#ifndef XQC_SYS_WINDOWS #if defined(XQC_SUPPORT_SENDMMSG) ssize_t xqc_demo_cli_write_mmsg(void *conn_user_data, struct iovec *msg_iov, unsigned int vlen, @@ -610,11 +622,12 @@ xqc_demo_cli_write_mmsg(void *conn_user_data, struct iovec *msg_iov, unsigned in res = XQC_SOCKET_EAGAIN; } } - } while ((res < 0) && (errno == EINTR)); + + } while ((res < 0) && (get_last_sys_errno() == EINTR)); return res; } #endif - +#endif void xqc_demo_cli_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, @@ -668,7 +681,7 @@ xqc_demo_cli_hq_req_send(xqc_hq_request_t *hqr, xqc_demo_cli_user_stream_t *user ssize_t ret = 0; if (user_stream->start_time == 0) { - user_stream->start_time = xqc_demo_now(); + user_stream->start_time = xqc_now(); } ret = xqc_hq_request_send_req(hqr, user_stream->send_buf); @@ -742,7 +755,7 @@ xqc_demo_cli_hq_req_read_notify(xqc_hq_request_t *hqr, void *req_user_data) if (fin) { user_stream->recv_fin = 1; - xqc_msec_t now_us = xqc_demo_now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" ">>>>>>>> user_stream[%p], req: %s, send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, @@ -787,7 +800,7 @@ xqc_demo_cli_h3_request_send(xqc_demo_cli_user_stream_t *user_stream) if (!user_stream->hdr_sent) { if (user_stream->start_time == 0) { - user_stream->start_time = xqc_demo_now(); + user_stream->start_time = xqc_now(); } ret = xqc_h3_request_send_headers(user_stream->h3_request, &user_stream->h3_hdrs, 1); @@ -880,7 +893,7 @@ xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_no user_stream->recv_fin = 1; xqc_request_stats_t stats; stats = xqc_h3_request_get_stats(h3_request); - xqc_msec_t now_us = xqc_demo_now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, @@ -946,7 +959,7 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn) do { recv_size = recvfrom(user_conn->fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *)&addr, &addr_len); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_last_sys_errno() == EAGAIN) { break; } @@ -958,11 +971,11 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn) xqc_int_t ret = getsockname(user_conn->fd, (struct sockaddr*)&user_conn->local_addr, &user_conn->local_addrlen); if (ret != 0) { - printf("getsockname error, errno: %d\n", errno); + printf("getsockname error, errno: %d\n", get_last_sys_errno()); } recv_sum += recv_size; - uint64_t recv_time = xqc_demo_now(); + uint64_t recv_time = xqc_now(); user_conn->last_sock_op_time = recv_time; if (xqc_engine_packet_process(user_conn->ctx->engine, packet_buf, recv_size, (struct sockaddr *)(&user_conn->local_addr), @@ -1002,7 +1015,7 @@ xqc_demo_cli_socket_event_callback(int fd, short what, void *arg) static void xqc_demo_cli_engine_callback(int fd, short what, void *arg) { - // printf("timer wakeup now:%"PRIu64"\n", xqc_demo_now()); + // printf("timer wakeup now:%"PRIu64"\n", xqc_now()); xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); } @@ -1013,7 +1026,7 @@ xqc_demo_cli_idle_callback(int fd, short what, void *arg) { int rc = 0; xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *) arg; - if (xqc_demo_now() - user_conn->last_sock_op_time < (uint64_t)user_conn->ctx->args->net_cfg.conn_timeout * 1000000) { + if (xqc_now() - user_conn->last_sock_op_time < (uint64_t)user_conn->ctx->args->net_cfg.conn_timeout * 1000000) { struct timeval tv; tv.tv_sec = user_conn->ctx->args->net_cfg.conn_timeout; tv.tv_usec = 0; @@ -1110,11 +1123,11 @@ xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, break; case CC_TYPE_CUBIC: - cong_ctrl = xqc_reno_cb; + cong_ctrl = xqc_cubic_cb; break; case CC_TYPE_RENO: - cong_ctrl = xqc_cubic_cb; + cong_ctrl = xqc_reno_cb; break; default: @@ -1252,7 +1265,6 @@ xqc_demo_cli_usage(int argc, char *argv[]) , prog); } - void xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args) { @@ -1867,30 +1879,35 @@ xqc_demo_cli_create_socket(xqc_demo_cli_user_conn_t *user_conn, xqc_demo_cli_net int size; int fd = 0; int ret; + int flags = 1; struct sockaddr *addr = (struct sockaddr*)&cfg->addr; fd = socket(addr->sa_family, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_last_sys_errno()); return -1; } - +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_last_sys_errno()); goto err; } - +#endif size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } - user_conn->last_sock_op_time = xqc_demo_now(); + user_conn->last_sock_op_time = xqc_now(); return fd; @@ -2121,6 +2138,9 @@ xqc_demo_cli_free_ctx(xqc_demo_cli_ctx_t *ctx) int main(int argc, char *argv[]) { + /* init env if necessary */ + xqc_platform_init_env(); + /* get input client args */ xqc_demo_cli_client_args_t *args = calloc(1, sizeof(xqc_demo_cli_client_args_t)); xqc_demo_cli_init_args(args); diff --git a/demo/demo_server.c b/demo/demo_server.c index 8325199b4..c34510862 100644 --- a/demo/demo_server.c +++ b/demo/demo_server.c @@ -7,21 +7,32 @@ #include #include #include -#include #include -#include #include #include #include #include #include #include +#include "../tests/platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#endif + #include "common.h" #include "xqc_hq.h" + #define XQC_PACKET_TMP_BUF_LEN 1500 #define MAX_BUF_SIZE (100*1024*1024) @@ -256,12 +267,12 @@ xqc_demo_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v int write_len = write(ctx->log_fd, buf, size); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->log_fd, line_break, 1); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_last_sys_errno()); } } @@ -302,12 +313,12 @@ xqc_demo_svr_keylog_cb(const char *line, void *eng_user_data) int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->keylog_fd, line_break, 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); } } @@ -912,15 +923,16 @@ xqc_demo_svr_write_socket(const unsigned char *buf, size_t size, const struct so int fd = svr_ctx.current_fd; do { - errno = 0; + set_last_sys_errno(0); res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); if (res < 0) { - printf("xqc_demo_svr_write_socket err %zd %s, fd: %d\n", res, strerror(errno), fd); - if (errno == EAGAIN) { + printf("xqc_demo_svr_write_socket err %zd %s, fd: %d\n", + res, strerror(get_last_sys_errno()), fd); + if (get_last_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (get_last_sys_errno() == EINTR)); return res; } @@ -947,17 +959,17 @@ xqc_demo_svr_socket_read_handler(xqc_demo_svr_ctx_t *ctx, int fd) do { recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *) &peer_addr, &peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_last_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(errno)); + printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_last_sys_errno())); break; } recv_sum += recv_size; - uint64_t recv_time = xqc_demo_now(); + uint64_t recv_time = xqc_now(); xqc_int_t ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, (struct sockaddr *)(&ctx->local_addr), ctx->local_addrlen, (struct sockaddr *)(&peer_addr), peer_addrlen, @@ -998,39 +1010,47 @@ xqc_demo_svr_init_socket(int family, uint16_t port, { int size; int opt_reuseaddr; + int flags = 1; int fd = socket(family, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_last_sys_errno()); return -1; } /* non-block */ +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_last_sys_errno()); goto err; } +#endif /* reuse port */ opt_reuseaddr = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt_reuseaddr, sizeof(opt_reuseaddr)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } /* send/recv buffer size */ size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } /* bind port */ if (bind(fd, local_addr, local_addrlen) < 0) { - printf("bind socket failed, family: %d, errno: %d, %s\n", family, errno, strerror(errno)); + printf("bind socket failed, family: %d, errno: %d, %s\n", family, + get_last_sys_errno(), strerror(get_last_sys_errno())); goto err; } @@ -1445,6 +1465,9 @@ xqc_demo_svr_free_ctx(xqc_demo_svr_ctx_t *ctx) int main(int argc, char *argv[]) { + /* init env if necessary */ + xqc_platform_init_env(); + /* get input server args */ xqc_demo_svr_args_t *args = calloc(1, sizeof(xqc_demo_svr_args_t)); xqc_demo_svr_init_args(args); diff --git a/docs/Platforms.md b/docs/Platforms.md index 3138804f0..25fb15ce1 100644 --- a/docs/Platforms.md +++ b/docs/Platforms.md @@ -47,3 +47,57 @@ mkdir build; cd build cmake -DPLATFORM=mac -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. make -j ``` + +## Windows Release (beta) +xquic possible dependencies for Windows: Perl, Go, BoringSSL, libevent, set after installation to set the corresponding program PATH to the $PATH environment variable + +* install GO: https://go.dev/dl/ +* install cmake:https://cmake.org/download/ +* install NASM :https://www.nasm.us/ (boringssl build need) +* install vcpkg:https://github.com/Microsoft/vcpkg + +```bash +VCPKG_DEFAULT_TRIPLET=x64-windows-static + +#install libevent +vcpkg install libevent:x64-windows-static +``` + +build XQUIC + +```bash +# step 1: get sourcecode +git clone git@github.com:alibaba/xquic.git +cd xquic +git submodule update --init --recursive + +# step 2:build boringssl +git clone git@github.com:google/boringssl.git ./third_party/boringssl +cd ./third_party/boringssl +mkdir build +cd build + +cmake -DCMAKE_GENERATOR_PLATFORM=x64 --config Debug -DBUILD_SHARED_LIBS=0 -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. + +# build ssl && crypto +MSBuild.exe ALL_BUILD.vcxproj + +cd ../../../ + +# step 3:build xquic +mkdir build +cd build +cmake -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + +MSBuild.exe xquic.vcxproj + +# build demo && test +git clone https://github.com/alex85k/wingetopt.git third_party/wingetopt +#eg: cmake -DEVENT_LIB_DIR=D:/project/vcpkg/packages/libevent_x64-windows-static .. +cmake -DXQC_ENABLE_TESTING=1 -DEVENT_LIB_DIR=your_event_path .. + +MSBuild.exe demo_client.vcxproj +MSBuild.exe demo_server.vcxproj +MSBuild.exe test_client.vcxproj +MSBuild.exe test_server.vcxproj +``` diff --git a/docs/docs-zh/FAQ-zh.md b/docs/docs-zh/FAQ-zh.md index 00ccf9a93..a01ca5e6b 100644 --- a/docs/docs-zh/FAQ-zh.md +++ b/docs/docs-zh/FAQ-zh.md @@ -21,7 +21,7 @@ > XQUIC 还支持什么平台?其他平台如何编译? -XQUIC 支持 Android、iOS、Linux 和 MacOS,编译方法参见 [Platforms](../Platforms.md)。 +XQUIC 支持 Android、iOS、Linux 和 MacOS,对Windows的支持处于beta阶段,编译方法参见 [Platforms](../Platforms.md)。 > 在各平台的编译产物大小 diff --git a/docs/docs-zh/README-zh.md b/docs/docs-zh/README-zh.md index 1c4170944..8e717f584 100644 --- a/docs/docs-zh/README-zh.md +++ b/docs/docs-zh/README-zh.md @@ -6,7 +6,7 @@ * **是一个遵循IETF标准的QUIC和HTTP/3的客户端和服务端实现。** 目前支持的QUIC版本是v1和draft-29。 -* **是跨平台的。** 目前支持Android、iOS、Linux和macOS。绝大部分代码被用于我们自己的产品,并已在安卓、iOS APP以及服务端上进行了大规模测试。 +* **是跨平台的。** 目前支持Android、iOS、Linux、macOS和Windows。绝大部分代码被用于我们自己的产品,并已在安卓、iOS APP以及服务端上进行了大规模测试。 * **目前仍在积极开发中。** 我们定期与其他QUIC实现进行[互通性测试](https://interop.seemann.io/)。 diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 235588df9..9e031b78a 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -8,14 +8,16 @@ /** * Public API for using libxquic */ -#ifdef WIN32 + +#include "xquic_typedef.h" + +#if defined(XQC_SYS_WINDOWS) && !defined(XQC_ON_MINGW) #include #include #else #include #include #endif -#include "xquic_typedef.h" #ifdef __cplusplus extern "C" { @@ -614,13 +616,13 @@ typedef struct xqc_congestion_control_callback_s { } xqc_cong_ctrl_callback_t; #ifndef XQC_DISABLE_RENO -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_reno_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_reno_cb; #endif #ifdef XQC_ENABLE_BBR2 -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_bbr2_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_bbr2_cb; #endif -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_bbr_cb; -XQC_EXPORT_PUBLIC_API extern const xqc_cong_ctrl_callback_t xqc_cubic_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_bbr_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_cong_ctrl_callback_t xqc_cubic_cb; /** @@ -1104,6 +1106,11 @@ unsigned char *xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid) XQC_EXPORT_PUBLIC_API uint8_t xqc_engine_config_get_cid_len(xqc_engine_t *engine); +XQC_EXPORT_PUBLIC_API +xqc_connection_t *xqc_engine_conns_hash_find(xqc_engine_t *engine, const xqc_cid_t *cid, char type); + +XQC_EXPORT_PUBLIC_API +xqc_usec_t xqc_now(); /** * User should call xqc_conn_continue_send when write event ready diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index 939acb635..009948e96 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -9,6 +9,48 @@ #include #include "xqc_errno.h" +#define XQC_EXTERN extern + +/* defined UNIX system default */ +#ifndef XQC_SYS_WINDOWS +# define XQC_SYS_UNIX +#endif + +#if defined(_WIN32) || defined(WIN32) || defined(XQC_SYS_WIN32) +# if !defined(XQC_SYS_WIN32) +# define XQC_SYS_WIN32 +# endif +#endif + +#if defined(_WIN64) || defined(WIN64) || defined(XQC_SYS_WIN64) +# if !defined(XQC_SYS_WIN64) +# define XQC_SYS_WIN64 +# endif +#endif + +#if defined(XQC_SYS_WIN32) || defined(XQC_SYS_WIN64) +#undef XQC_SYS_UNIX +#define XQC_SYS_WINDOWS +#endif + +#if defined(__MINGW64__) || defined(__MINGW32__) +# if !defined(XQC_ON_MINGW) +# define XQC_ON_MINGW +# endif +#endif + +#if defined(XQC_SYS_WINDOWS) && !defined(XQC_ON_MINGW) +# undef XQC_EXTERN +# define XQC_EXTERN + +#ifdef XQC_SYS_WIN64 + typedef __int64 ssize_t; +#elif defined(XQC_SYS_WIN32) + typedef __int32 ssize_t; +#endif +#endif + + /* TODO: there may be problems using -o2 under Android platform */ #if defined(__GNUC__) && !defined(ANDROID) # define XQC_UNLIKELY(cond) __builtin_expect(!!(cond), 0) @@ -100,13 +142,20 @@ typedef enum { #endif } xqc_bbr2_optimization_flag_t; -#ifdef WIN32 +#define XQC_EXPORT_PUBLIC_API __attribute__((visibility("default"))) + +#ifdef XQC_SYS_WINDOWS struct iovec { void *iov_base; /* [XSI] Base address of I/O memory region */ size_t iov_len; /* [XSI] Size of region iov_base points to */ }; + +#if !(defined __MINGW32__) && !(defined __MINGW64__) +#undef XQC_EXPORT_PUBLIC_API +#define XQC_EXPORT_PUBLIC_API _declspec(dllexport) +#endif + #endif -#define XQC_EXPORT_PUBLIC_API __attribute__((visibility("default"))) #endif /*_XQUIC_TYPEDEF_H_INCLUDED_*/ diff --git a/scripts/xquic.lds b/scripts/xquic.lds index 8d501f156..91d170246 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -65,6 +65,7 @@ XQUIC_VERS_1.0 { xqc_engine_unregister_alpn; xqc_conn_set_alp_user_data; xqc_h3_request_finish; + xqc_now; local: *; }; diff --git a/src/common/utils/vint/xqc_variable_len_int.h b/src/common/utils/vint/xqc_variable_len_int.h index 640b1f527..ef6d68170 100644 --- a/src/common/utils/vint/xqc_variable_len_int.h +++ b/src/common/utils/vint/xqc_variable_len_int.h @@ -7,7 +7,11 @@ #include #include "src/common/xqc_str.h" +#ifdef XQC_SYS_WINDOWS +#include +#else #include +#endif #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) #include @@ -19,7 +23,7 @@ #define bswap_16 OSSwapInt16 #define bswap_32 OSSwapInt32 #define bswap_64 OSSwapInt64 -#elif defined(WIN32) +#elif (defined XQC_SYS_WINDOWS) #include #define bswap_16 _byteswap_ushort #define bswap_32 _byteswap_ulong diff --git a/src/common/xqc_common.h b/src/common/xqc_common.h index d07c802f5..a4650d949 100644 --- a/src/common/xqc_common.h +++ b/src/common/xqc_common.h @@ -10,7 +10,6 @@ #include #include - #ifndef XQC_LITTLE_ENDIAN # define XQC_LITTLE_ENDIAN 1 #endif diff --git a/src/common/xqc_config.h b/src/common/xqc_config.h index 1dca67037..fd4757d19 100644 --- a/src/common/xqc_config.h +++ b/src/common/xqc_config.h @@ -5,13 +5,21 @@ #ifndef _XQC_H_CONFIG_INCLUDED_ #define _XQC_H_CONFIG_INCLUDED_ +#include + #define xqc_min(a, b) ((a) < (b) ? (a) : (b)) #define xqc_max(a, b) ((a) > (b) ? (a) : (b)) #define xqc_sub_abs(a, b) ((a) > (b) ? ((a) - (b)): ((b) - (a))) #define xqc_clamp(a, min, max) xqc_max(xqc_min(a, max), min) +#ifdef XQC_SYS_WINDOWS +static const unsigned char LF = '\n'; +static const unsigned char CR = '\r'; +#else #define LF (unsigned char) '\n' #define CR (unsigned char) '\r' +#endif + #define CRLF "\r\n" #define XQC_PTR_SIZE 8 diff --git a/src/common/xqc_id_hash.h b/src/common/xqc_id_hash.h index ade6a9052..2d7350a8f 100644 --- a/src/common/xqc_id_hash.h +++ b/src/common/xqc_id_hash.h @@ -35,12 +35,31 @@ typedef struct xqc_id_hash_table_s { static inline int xqc_pow2(unsigned int n) { - int clz , power = sizeof(n); - if (__builtin_popcount(n) <= 1) { + + int clz , power = sizeof(n), count1 = 0; + +#ifdef __GNUC__ + count1 = __builtin_popcount(n) ; +#else + while (n) { + count1 += n & 1; + n >>= 1; + } +#endif + + if (count1 <= 1) { return n ; } - clz = __builtin_clz(n); - power = (power << 3) - clz ; + +#if defined(XQC_SYS_WINDOWS) && defined(_MSC_VER) + /* __lzcnt available beginning VS2008 or up*/ + _BitScanReverse(&clz, n); +#else + clz = __builtin_clz(n); +#endif + + power = (power << 3) - clz ; + return pow(2 , power); } diff --git a/src/common/xqc_log.c b/src/common/xqc_log.c index 06c185bab..8b5aed702 100644 --- a/src/common/xqc_log.c +++ b/src/common/xqc_log.c @@ -226,7 +226,7 @@ xqc_log_time(char *buf, size_t buf_len) struct tm tm; -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS time_t t = tv.tv_sec; #ifdef _USE_32BIT_TIME_T _localtime32_s(&tm, &t); diff --git a/src/common/xqc_log.h b/src/common/xqc_log.h index dda0ba2cb..078489051 100644 --- a/src/common/xqc_log.h +++ b/src/common/xqc_log.h @@ -13,14 +13,18 @@ #include #include #include -#include #include +#include #include "src/common/xqc_config.h" #include "src/common/xqc_malloc.h" #include "src/common/xqc_str.h" #include "src/common/xqc_time.h" +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + /* max length for log buffer */ #define XQC_MAX_LOG_LEN 2048 diff --git a/src/common/xqc_priority_q.h b/src/common/xqc_priority_q.h index 098113062..ff2234740 100644 --- a/src/common/xqc_priority_q.h +++ b/src/common/xqc_priority_q.h @@ -97,7 +97,12 @@ xqc_pq_destroy(xqc_pq_t *pq) static inline void xqc_pq_element_swap(xqc_pq_t *pq, size_t i, size_t j) { +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) char buf[pq->element_size]; +#else + char *buf = (char *)_alloca(pq->element_size); +#endif + memcpy(buf, xqc_pq_element(pq, j), pq->element_size); memcpy(xqc_pq_element(pq, j), xqc_pq_element(pq, i), pq->element_size); memcpy(xqc_pq_element(pq, i), buf, pq->element_size); diff --git a/src/common/xqc_random.c b/src/common/xqc_random.c index 158d04c6f..cac37d639 100644 --- a/src/common/xqc_random.c +++ b/src/common/xqc_random.c @@ -5,14 +5,18 @@ #include #include #include -#include #include #include +#include #include "src/common/xqc_random.h" #include "src/common/xqc_str.h" #include "src/common/xqc_log.h" +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + #define XQC_RANDOM_BUFFER_SIZE 4096 xqc_random_generator_t * @@ -32,7 +36,7 @@ xqc_random_generator_create(xqc_log_t *log) rand_gen->rand_buf_size = XQC_RANDOM_BUFFER_SIZE; rand_gen->rand_fd = -1; rand_gen->log = log; -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS rand_gen->hProvider = 0; int res = CryptAcquireContextW(&rand_gen->hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT); assert(res); @@ -43,7 +47,7 @@ xqc_random_generator_create(xqc_log_t *log) void xqc_random_generator_destroy(xqc_random_generator_t *rand_gen) { -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS CryptReleaseContext(rand_gen->hProvider, 0); #endif xqc_free(rand_gen->rand_buf.data); @@ -53,7 +57,7 @@ xqc_random_generator_destroy(xqc_random_generator_t *rand_gen) xqc_int_t xqc_get_random(xqc_random_generator_t *rand_gen, u_char *buf, size_t need_len) { -#ifndef WIN32 +#ifndef XQC_SYS_WINDOWS size_t total_read = 0; ssize_t bytes_read = 0; diff --git a/src/common/xqc_random.h b/src/common/xqc_random.h index fa5a13e5c..8562f0e42 100644 --- a/src/common/xqc_random.h +++ b/src/common/xqc_random.h @@ -11,7 +11,7 @@ #include "src/common/xqc_str.h" #include "src/common/xqc_log.h" #include "src/common/xqc_common.h" -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS #include #endif @@ -24,8 +24,7 @@ typedef struct xqc_random_generator_s { xqc_str_t rand_buf; /* buffer for random bytes*/ xqc_log_t *log; - -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS HCRYPTPROV hProvider; #endif } xqc_random_generator_t; diff --git a/src/common/xqc_str.c b/src/common/xqc_str.c index d4b156a61..33ab9fda5 100644 --- a/src/common/xqc_str.c +++ b/src/common/xqc_str.c @@ -218,7 +218,7 @@ xqc_vsprintf(unsigned char *buf, unsigned char *last, const char *fmt, va_list a fmt++; continue; -#ifndef WIN32 +#ifndef XQC_SYS_WINDOWS case 'r': i64 = (int64_t) va_arg(args, rlim_t); sign = 1; diff --git a/src/common/xqc_str.h b/src/common/xqc_str.h index 9852c194c..655235c1b 100644 --- a/src/common/xqc_str.h +++ b/src/common/xqc_str.h @@ -9,15 +9,15 @@ #include #include #include -#ifndef WIN32 -#include -#endif #include #include +#include #include "src/common/xqc_config.h" -#include "include/xquic/xquic_typedef.h" +#ifndef XQC_SYS_WINDOWS +#include +#endif typedef struct xqc_str_s { size_t len; diff --git a/src/common/xqc_time.c b/src/common/xqc_time.c index dc2fb29a3..4036d918c 100644 --- a/src/common/xqc_time.c +++ b/src/common/xqc_time.c @@ -4,15 +4,15 @@ #include "xqc_time.h" -#ifdef WIN32 +#ifdef XQC_SYS_WINDOWS +#ifndef _GETTIMEOFDAY_DEFINED #define DELTA_EPOCH_IN_TICKS 116444736000000000ULL int -gettimeofday(struct timeval *tv, struct timezone *tz) +gettimeofday(struct timeval *tv, void *tzp) { FILETIME ft; uint64_t tmpres; - static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); @@ -25,20 +25,12 @@ gettimeofday(struct timeval *tv, struct timezone *tz) tv->tv_usec = tmpres % 1000000; } - if (NULL != tz) { - if (!tzflag) { - _tzset(); - tzflag++; - } - tz->tz_minuteswest = _timezone / 60; - tz->tz_dsttime = _daylight; - } - return 0; } #endif +#endif -static xqc_usec_t +xqc_usec_t xqc_now() { /* get microsecond unit time */ diff --git a/src/common/xqc_time.h b/src/common/xqc_time.h index 604e02752..dfbc756fa 100644 --- a/src/common/xqc_time.h +++ b/src/common/xqc_time.h @@ -5,18 +5,19 @@ #ifndef _XQC_TIME_H_INCLUDED_ #define _XQC_TIME_H_INCLUDED_ -#ifndef WIN32 -#include -#endif -#ifdef MINGW_HAS_SECURE_API -#include -#endif #include #include +#include -#ifdef WIN32 +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif + +#ifdef XQC_SYS_WINDOWS +#ifndef _GETTIMEOFDAY_DEFINED int gettimeofday(struct timeval *tv, struct timezone *tz); #endif +#endif /** diff --git a/src/congestion_control/xqc_bbr.c b/src/congestion_control/xqc_bbr.c index 12d3b81a3..f6269d0eb 100644 --- a/src/congestion_control/xqc_bbr.c +++ b/src/congestion_control/xqc_bbr.c @@ -2,9 +2,17 @@ * @copyright Copyright (c) 2022, Alibaba Group Holding Limited */ +#if (defined _WIN32) || (defined _WIN64) +#define _CRT_RAND_S +#endif + #include #include #include +#include +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) +#include +#endif #include "src/congestion_control/xqc_bbr.h" #include "src/congestion_control/xqc_sample.h" #include "src/common/xqc_time.h" @@ -80,6 +88,21 @@ static const float xqc_bbr_rtt_compensation_thresh = 1; static const float xqc_bbr_rtt_compensation_cwnd_factor = 1; #endif +long xqc_random(void) { + +#ifdef XQC_SYS_WINDOWS + unsigned int val; + if (rand_s(&val)) { + val = rand(); + } + return (long)val && 0xFFFFFFFF; +#else + return random(); +#endif + +} + + size_t xqc_bbr_size() { @@ -420,7 +443,7 @@ xqc_bbr_enter_probe_bw(xqc_bbr_t *bbr, xqc_sample_t *sampler) { bbr->mode = BBR_PROBE_BW; bbr->cwnd_gain = xqc_bbr_cwnd_gain; - bbr->cycle_idx = random() % (XQC_BBR_CYCLE_LENGTH - 1); + bbr->cycle_idx = xqc_random() % (XQC_BBR_CYCLE_LENGTH - 1); bbr->cycle_idx = bbr->cycle_idx == 0 ? bbr->cycle_idx : bbr->cycle_idx + 1; bbr->pacing_gain = xqc_bbr_get_pacing_gain(bbr, bbr->cycle_idx); bbr->cycle_start_stamp = sampler->now; @@ -555,7 +578,8 @@ xqc_bbr_update_min_rtt(xqc_bbr_t *bbr, xqc_sample_t *sampler) /* Ignore low rate samples during this mode. */ xqc_send_ctl_t *send_ctl = sampler->send_ctl; send_ctl->ctl_app_limited = (send_ctl->ctl_delivered - + send_ctl->ctl_bytes_in_flight)? : 1; + + send_ctl->ctl_bytes_in_flight)? (send_ctl->ctl_delivered + + send_ctl->ctl_bytes_in_flight) : 1; xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|BBR PROBE_RTT|inflight:%ud|done_stamp:%ui|done:%ud|" "round_start:%ud|", diff --git a/src/congestion_control/xqc_bbr2.c b/src/congestion_control/xqc_bbr2.c index 35afe7100..f58a28c45 100644 --- a/src/congestion_control/xqc_bbr2.c +++ b/src/congestion_control/xqc_bbr2.c @@ -101,6 +101,8 @@ static void xqc_bbr2_enter_probe_rtt(xqc_bbr2_t *bbr2); static void xqc_bbr2_save_cwnd(xqc_bbr2_t *bbr2); static bool xqc_bbr2_is_probing_bandwidth(xqc_bbr2_t *bbr2); +extern long xqc_random(void); + size_t xqc_bbr2_size() { @@ -871,19 +873,19 @@ xqc_bbr2_enter_drain(xqc_bbr2_t *bbr2) static void xqc_bbr2_pick_probe_wait(xqc_bbr2_t *bbr2) { - bbr2->rounds_since_probe = random() % xqc_bbr2_bw_probe_rand_rounds; + bbr2->rounds_since_probe = xqc_random() % xqc_bbr2_bw_probe_rand_rounds; #if XQC_BBR2_PLUS_ENABLED if (bbr2->fast_convergence_on) { - uint32_t rand_rtt_rounds = random() % + uint32_t rand_rtt_rounds = xqc_random() % xqc_bbr2_fast_convergence_probe_round_rand; rand_rtt_rounds += (1 + xqc_bbr2_fast_convergence_probe_round_base); } else { bbr2->probe_wait_us = xqc_bbr2_bw_probe_base_us + - (random() % xqc_bbr2_bw_probe_rand_us); + (xqc_random() % xqc_bbr2_bw_probe_rand_us); } #else bbr2->probe_wait_us = xqc_bbr2_bw_probe_base_us + - (random() % xqc_bbr2_bw_probe_rand_us); + (xqc_random() % xqc_bbr2_bw_probe_rand_us); #endif } @@ -991,7 +993,8 @@ xqc_bbr2_update_min_rtt(xqc_bbr2_t *bbr2, xqc_sample_t *sampler) /* Ignore low rate samples during this mode. */ xqc_send_ctl_t *send_ctl = sampler->send_ctl; send_ctl->ctl_app_limited = (send_ctl->ctl_delivered - + send_ctl->ctl_bytes_in_flight)? : 1; + + send_ctl->ctl_bytes_in_flight) + ? (send_ctl->ctl_delivered + send_ctl->ctl_bytes_in_flight) : 1; xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|BBR PROBE_RTT|inflight:%ud|done_stamp:%ui|done:%ud|" "round_start:%ud|", diff --git a/src/congestion_control/xqc_sample.c b/src/congestion_control/xqc_sample.c index f6da13c2f..0aa6cfb12 100644 --- a/src/congestion_control/xqc_sample.c +++ b/src/congestion_control/xqc_sample.c @@ -124,8 +124,8 @@ xqc_sample_check_app_limited(xqc_sample_t *sampler, xqc_send_ctl_t *send_ctl) && xqc_list_empty(&send_ctl->ctl_lost_packets) /* All lost packets have been retransmitted. */ && xqc_list_empty(&send_ctl->ctl_pto_probe_packets)) { - send_ctl->ctl_app_limited = (send_ctl->ctl_delivered + - send_ctl->ctl_bytes_in_flight) ?: 1; + send_ctl->ctl_app_limited = (send_ctl->ctl_delivered + send_ctl->ctl_bytes_in_flight) + ? (send_ctl->ctl_delivered + send_ctl->ctl_bytes_in_flight) : 1; if (send_ctl->ctl_app_limited > 0) { xqc_log_event(send_ctl->ctl_conn->log, REC_CONGESTION_STATE_UPDATED, "application_limit"); } diff --git a/src/http3/frame/xqc_h3_frame_defs.h b/src/http3/frame/xqc_h3_frame_defs.h index 10f2aa939..9ee9a9414 100644 --- a/src/http3/frame/xqc_h3_frame_defs.h +++ b/src/http3/frame/xqc_h3_frame_defs.h @@ -21,9 +21,11 @@ typedef enum xqc_h3_frm_type_s { typedef struct xqc_h3_frm_data_s { + char reserved; } xqc_h3_frame_data_t; typedef struct xqc_h3_frm_headers_s { + char reserved; } xqc_h3_frame_headers_t; typedef struct xqc_h3_frm_cancel_push_s { diff --git a/src/tls/babassl/xqc_aead_impl.h b/src/tls/babassl/xqc_aead_impl.h index 873a59680..540e50d65 100644 --- a/src/tls/babassl/xqc_aead_impl.h +++ b/src/tls/babassl/xqc_aead_impl.h @@ -25,46 +25,46 @@ #define XQC_AEAD_OVERHEAD_IMPL(obj, cln) (0) + (obj)->taglen /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_AEAD_INIT(obj, a, tgl) ({ \ +#define DO_NOT_CALL_XQC_AEAD_INIT(obj, a, tgl) do { \ obj->aead = a; \ obj->keylen = EVP_CIPHER_key_length(obj->aead); \ obj->noncelen = EVP_CIPHER_iv_length(obj->aead); \ obj->taglen = (tgl); \ obj->encrypt = xqc_ossl_aead_encrypt; \ obj->decrypt = xqc_ossl_aead_decrypt; \ -}) +} while(0) /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) ({ \ +#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) do { \ obj->cipher = c; \ obj->keylen = EVP_CIPHER_key_length(obj->cipher); \ obj->noncelen = EVP_CIPHER_iv_length(obj->cipher); \ obj->hp_mask = xqc_ossl_hp_mask; \ -}) +} while(0) /* aes gcm initialization */ -#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d, ...) ({ \ +#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aes_##d##_gcm(), EVP_GCM_TLS_TAG_LEN); \ -}) +} while(0) /* chacha20 initialization */ -#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, ...) ({ \ +#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_chacha20_poly1305(), EVP_CHACHAPOLY_TLS_TAG_LEN); \ -}) +} while(0) /* aes cipher initialization */ -#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d, ...) ({ \ +#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_aes_##d##_ctr()); \ -}) +} while(0) /* chacha20 cipher initialization */ -#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj, ...) ({ \ +#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_chacha20()); \ -}) +} while(0) xqc_int_t xqc_ossl_aead_encrypt(const xqc_pkt_protect_aead_t *pp_aead, diff --git a/src/tls/boringssl/xqc_aead_impl.h b/src/tls/boringssl/xqc_aead_impl.h index 251534b36..b477df1d3 100644 --- a/src/tls/boringssl/xqc_aead_impl.h +++ b/src/tls/boringssl/xqc_aead_impl.h @@ -25,48 +25,50 @@ #define XQC_AEAD_OVERHEAD_IMPL(obj,cln) (0) + (obj)->taglen /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_AEAD_INIT(obj,a) ({ \ +#define DO_NOT_CALL_XQC_AEAD_INIT(obj,a) do { \ obj->aead = a; \ obj->taglen = EVP_AEAD_max_tag_len(obj->aead); \ obj->keylen = EVP_AEAD_key_length(obj->aead); \ obj->noncelen = EVP_AEAD_nonce_length(obj->aead); \ obj->encrypt = xqc_bssl_aead_encrypt; \ obj->decrypt = xqc_bssl_aead_decrypt; \ - 0;}) + } while (0) + /* inner definition, MUST NOT be called directly */ -#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) ({ \ +#define DO_NOT_CALL_XQC_CIPHER_INIT(obj, c) do { \ obj->cipher = c; \ obj->keylen = EVP_CIPHER_key_length(obj->cipher); \ obj->noncelen = EVP_CIPHER_iv_length(obj->cipher); \ - 0;}) + } while (0) + /* aes gcm initialization */ -#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d, ...) ({ \ +#define XQC_AEAD_INIT_AES_GCM_IMPL(obj, d) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aead_aes_##d##_gcm()); \ - 0;}) + } while (0) /* chacha20 initialization */ -#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, ...) ({ \ +#define XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) do { \ xqc_pkt_protect_aead_t *___aead = (obj); \ DO_NOT_CALL_XQC_AEAD_INIT(___aead, EVP_aead_chacha20_poly1305()); \ - 0;}) + } while(0) /* aes cipher initialization */ -#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d, ...) ({ \ +#define XQC_CIPHER_INIT_AES_CTR_IMPL(obj, d) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ DO_NOT_CALL_XQC_CIPHER_INIT(___cipher, EVP_aes_##d##_ctr()); \ ___cipher->hp_mask = xqc_bssl_hp_mask; \ - 0;}) + } while(0) /* chacha20 follow openssl impl */ -#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj, ...) ({ \ +#define XQC_CIPHER_INIT_CHACHA20_IMPL(obj) do { \ xqc_hdr_protect_cipher_t *___cipher = (obj); \ ___cipher->keylen = 32; \ ___cipher->noncelen = 16; \ ___cipher->hp_mask = xqc_bssl_hp_mask_chacha20; \ - 0;}) + } while(0) /* extern */ diff --git a/src/tls/xqc_crypto.h b/src/tls/xqc_crypto.h index 38b456b36..6586659a1 100644 --- a/src/tls/xqc_crypto.h +++ b/src/tls/xqc_crypto.h @@ -27,16 +27,16 @@ typedef struct xqc_hdr_protect_cipher_s xqc_hdr_protect_cipher_t; /* aes_d_gcm d is the length of key */ -#define xqc_aead_init_aes_gcm(aead, d, ...) XQC_AEAD_INIT_AES_GCM_IMPL(aead, d, __VA_ARGS__) +#define xqc_aead_init_aes_gcm(aead, d) XQC_AEAD_INIT_AES_GCM_IMPL(aead, d) /* chacha20_poly1305 */ -#define xqc_aead_init_chacha20_poly1305(obj, ...) XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj, __VA_ARGS__) +#define xqc_aead_init_chacha20_poly1305(obj) XQC_AEAD_INIT_CHACHA20_POLY1305_IMPL(obj) /* aes_d_ctr */ -#define xqc_cipher_init_aes_ctr(cipher, d, ...) XQC_CIPHER_INIT_AES_CTR_IMPL(cipher, d, __VA_ARGS__) +#define xqc_cipher_init_aes_ctr(cipher, d) XQC_CIPHER_INIT_AES_CTR_IMPL(cipher, d) /* chacha20 */ -#define xqc_cipher_init_chacha20(cipher, ...) XQC_CIPHER_INIT_CHACHA20_IMPL(cipher, __VA_ARGS__) +#define xqc_cipher_init_chacha20(cipher) XQC_CIPHER_INIT_CHACHA20_IMPL(cipher) /* length of aead overhead */ #define xqc_aead_overhead(obj, cln) (XQC_AEAD_OVERHEAD_IMPL((obj), cln)) diff --git a/src/tls/xqc_tls.h b/src/tls/xqc_tls.h index e114a760f..afe09f716 100644 --- a/src/tls/xqc_tls.h +++ b/src/tls/xqc_tls.h @@ -6,10 +6,25 @@ #define XQC_TLS_H #include -#include "xqc_tls_defs.h" #include + +#include "src/tls/xqc_tls_defs.h" #include "src/transport/xqc_packet.h" +#ifdef XQC_SYS_WINDOWS +// wincrypt.h defines macros which conflict with OpenSSL's types. This header +// includes wincrypt and undefines the OpenSSL macros which conflict. +#define WIN32_LEAN_AND_MEAN +#include +#include +// Undefine the macros which conflict with OpenSSL and define replacements. +// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx +#undef PKCS7_SIGNER_INFO +#undef X509_CERT_PAIR +#undef X509_EXTENSIONS +#undef X509_NAME +#endif + /** * @brief init tls context. MUST be called before any creation of xqc_tls_t */ diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index b89f2e507..f9603d83e 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -1563,7 +1563,9 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) if (conn->conn_settings.linger.linger_on && !xqc_send_ctl_out_q_empty(ctl)) { conn->conn_flag |= XQC_CONN_FLAG_LINGER_CLOSING; xqc_send_ctl_timer_set(ctl, XQC_TIMER_LINGER_CLOSE, - xqc_monotonic_timestamp(), (conn->conn_settings.linger.linger_timeout ? : 3 * xqc_send_ctl_calc_pto(ctl))); + xqc_monotonic_timestamp(), (conn->conn_settings.linger.linger_timeout + ? conn->conn_settings.linger.linger_timeout + : 3 * xqc_send_ctl_calc_pto(ctl))); goto end; } diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index aed3cf75d..d9506ac9e 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -202,7 +202,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x01: ret = xqc_process_ping_frame(conn, packet_in); break; - case 0x02 ... 0x03: + case 0x02: + case 0x03: ret = xqc_process_ack_frame(conn, packet_in); break; case 0x04: @@ -217,7 +218,14 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x07: ret = xqc_process_new_token_frame(conn, packet_in); break; - case 0x08 ... 0x0f: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: ret = xqc_process_stream_frame(conn, packet_in); break; case 0x10: @@ -226,7 +234,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x11: ret = xqc_process_max_stream_data_frame(conn, packet_in); break; - case 0x12 ... 0x13: + case 0x12: + case 0x13: ret = xqc_process_max_streams_frame(conn, packet_in); break; case 0x14: @@ -235,7 +244,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x15: ret = xqc_process_stream_data_blocked_frame(conn, packet_in); break; - case 0x16 ... 0x17: + case 0x16: + case 0x17: ret = xqc_process_streams_blocked_frame(conn, packet_in); break; case 0x18: @@ -244,7 +254,8 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x19: ret = xqc_process_retire_conn_id_frame(conn, packet_in); break; - case 0x1c ... 0x1d: + case 0x1c: + case 0x1d: ret = xqc_process_conn_close_frame(conn, packet_in); break; case 0x1e: diff --git a/src/transport/xqc_packet_parser.c b/src/transport/xqc_packet_parser.c index 98937bfdb..2cd65ba33 100644 --- a/src/transport/xqc_packet_parser.c +++ b/src/transport/xqc_packet_parser.c @@ -3,6 +3,9 @@ */ #include +#ifdef XQC_SYS_WINDOWS +#include +#endif #include #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_cid.h" diff --git a/src/transport/xqc_send_ctl.c b/src/transport/xqc_send_ctl.c index 8c27795bc..9dcea31c2 100644 --- a/src/transport/xqc_send_ctl.c +++ b/src/transport/xqc_send_ctl.c @@ -1026,7 +1026,7 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *ctl, xqc_ack_info_t *const ack_info xqc_log(ctl->ctl_conn->log, XQC_LOG_DEBUG, "|conn:%p|pkt_num:%ui|origin_pktnum:%ui|size:%ud|pkt_type:%s|frame:%s|conn_state:%s|", ctl->ctl_conn, packet_out->po_pkt.pkt_num, - (xqc_packet_number_t)packet_out->po_origin ? packet_out->po_origin->po_pkt.pkt_num : 0, + (xqc_packet_number_t)(packet_out->po_origin ? packet_out->po_origin->po_pkt.pkt_num : 0), packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), xqc_frame_type_2_str(packet_out->po_frame_types), diff --git a/src/transport/xqc_wakeup_pq.h b/src/transport/xqc_wakeup_pq.h index 2e18bffc6..b0a58bc98 100644 --- a/src/transport/xqc_wakeup_pq.h +++ b/src/transport/xqc_wakeup_pq.h @@ -94,7 +94,13 @@ xqc_wakeup_pq_destroy(xqc_wakeup_pq_t *pq) static inline void xqc_wakeup_pq_element_swap(xqc_wakeup_pq_t *pq, size_t i, size_t j) { + +#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) char buf[pq->element_size]; +#else + char *buf = (char *)_alloca(pq->element_size); +#endif + xqc_wakeup_pq_elem_t* p; p = xqc_wakeup_pq_element(pq, i); p->conn->wakeup_pq_index = j; diff --git a/tests/platform.h b/tests/platform.h new file mode 100644 index 000000000..6130e35f7 --- /dev/null +++ b/tests/platform.h @@ -0,0 +1,62 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef PLATFORM_H +#define PLATFORM_H + +#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) +#define XQC_SYS_WINDOWS +#endif + +#ifdef XQC_SYS_WINDOWS +# define EAGAIN WSAEWOULDBLOCK +# define EINTR WSAEINTR +#endif + + +/** + * @brief get system last errno + * + * @return int + */ +int get_last_sys_errno() +{ + int err = 0; +#ifdef XQC_SYS_WINDOWS + err = WSAGetLastError(); +#else + err = errno; +#endif + return err; +} + +/** + * @brief init platform env if necessary + * + */ +void xqc_platform_init_env() +{ + int result = 0; + + #ifdef XQC_SYS_WINDOWS + // Initialize Winsock + WSADATA wsaData; + if ((result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { + printf("WSAStartup failed with error %d\n", result); + exit(1); + } +#endif + +} + +void set_last_sys_errno(int err) +{ +#ifdef XQC_SYS_WINDOWS + WSASetLastError(err); +#else + errno = err; +#endif +} + +#endif diff --git a/tests/test_client.c b/tests/test_client.c index 1a593f1ac..03c24e3de 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -6,8 +6,7 @@ #include #include #include -#include -#include + #include #include #include @@ -15,12 +14,24 @@ #include #include #include -#include -#include #include #include #include +#include "platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#include +#include +#else +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#include +#endif + int printf_null(const char *format, ...) { @@ -167,22 +178,25 @@ static uint64_t last_recv_ts = 0; static void xqc_client_socket_event_callback(int fd, short what, void *arg); static void xqc_client_timeout_callback(int fd, short what, void *arg); - -static inline uint64_t -now() +#ifdef XQC_SYS_WINDOWS +static void usleep(unsigned long usec) { - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; + HANDLE timer; + LARGE_INTEGER interval; + interval.QuadPart = -(10 * usec); + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &interval, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); } +#endif void xqc_client_set_event_timer(xqc_msec_t wake_after, void *user_data) { client_ctx_t *ctx = (client_ctx_t *) user_data; - //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, now()); + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); struct timeval tv; tv.tv_sec = wake_after / 1000000; @@ -235,15 +249,15 @@ xqc_client_save_token(const unsigned char *token, unsigned token_len, void *user if (g_test_case == 16) { /* test application delay */ usleep(300*1000); } - int fd = open("./xqc_token", O_TRUNC | O_CREAT | O_WRONLY, S_IRWXU); + int fd = open("./xqc_token", O_TRUNC | O_CREAT | O_WRONLY, 0666); if (fd < 0) { - printf("save token error %s\n", strerror(errno)); + printf("save token error %s\n", strerror(get_last_sys_errno())); return; } ssize_t n = write(fd, token, token_len); if (n < token_len) { - printf("save token error %s\n", strerror(errno)); + printf("save token error %s\n", strerror(get_last_sys_errno())); close(fd); return; } @@ -255,7 +269,7 @@ xqc_client_read_token(unsigned char *token, unsigned token_len) { int fd = open("./xqc_token", O_RDONLY); if (fd < 0) { - printf("read token error %s\n", strerror(errno)); + printf("read token error %s\n", strerror(get_last_sys_errno())); return -1; } @@ -339,16 +353,16 @@ xqc_client_write_socket(const unsigned char *buf, size_t size, } do { - errno = 0; + set_last_sys_errno(0); - g_last_sock_op_time = now(); + g_last_sock_op_time = xqc_now(); if (TEST_DROP) { return send_buf_size; } if (g_test_case == 5) { /* socket send fail */ g_test_case = -1; - errno = EAGAIN; + set_last_sys_errno(EAGAIN); return XQC_SOCKET_EAGAIN; } @@ -370,12 +384,12 @@ xqc_client_write_socket(const unsigned char *buf, size_t size, res = sendto(fd, send_buf, send_buf_size, 0, peer_addr, peer_addrlen); if (res < 0) { - printf("xqc_client_write_socket err %zd %s\n", res, strerror(errno)); - if (errno == EAGAIN) { + printf("xqc_client_write_socket err %zd %s\n", res, strerror(get_last_sys_errno())); + if (get_last_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (get_last_sys_errno() == EINTR)); return res; } @@ -388,7 +402,7 @@ xqc_client_send_stateless_reset(const unsigned char *buf, size_t size, } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_client_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *user) @@ -404,7 +418,7 @@ xqc_client_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, mmsg[i].msg_hdr.msg_iovlen = 1; } do { - errno = 0; + set_last_sys_errno(0); if (TEST_DROP) return vlen; if (g_test_case == 5) { /* socket send fail */ @@ -431,36 +445,43 @@ xqc_client_create_socket(int type, { int size; int fd = -1; + int flags; /* create fd & set socket option */ fd = socket(type, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_last_sys_errno()); return -1; } +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { - printf("set socket nonblock failed, errno: %d\n", errno); + printf("set socket nonblock failed, errno: %d\n", get_last_sys_errno()); goto err; } +#endif size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } - g_last_sock_op_time = now(); + g_last_sock_op_time = xqc_now(); /* connect to peer addr */ #if !defined(__APPLE__) if (connect(fd, (struct sockaddr *)saddr, saddr_len) < 0) { - printf("connect socket failed, errno: %d\n", errno); + printf("connect socket failed, errno: %d\n", get_last_sys_errno()); goto err; } #endif @@ -520,7 +541,7 @@ xqc_client_init_addr(user_conn_t *user_conn, } } - +#ifndef XQC_SYS_WINDOWS static int xqc_client_bind_to_interface(int fd, const char *interface_name) @@ -533,14 +554,14 @@ xqc_client_bind_to_interface(int fd, #if (XQC_TEST_MP) if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)) < 0) { - printf("bind to nic error: %d, try use sudo\n", errno); + printf("bind to nic error: %d, try use sudo\n", get_last_sys_errno()); return XQC_ERROR; } #endif return XQC_OK; } - +#endif static int xqc_client_create_path_socket(xqc_user_path_t *path, @@ -552,13 +573,14 @@ xqc_client_create_path_socket(xqc_user_path_t *path, printf("|xqc_client_create_path_socket error|"); return XQC_ERROR; } - +#ifndef XQC_SYS_WINDOWS if (path_interface != NULL && xqc_client_bind_to_interface(path->path_fd, path_interface) < 0) { printf("|xqc_client_bind_to_interface error|"); return XQC_ERROR; } +#endif return XQC_OK; } @@ -788,7 +810,7 @@ xqc_client_stream_send(xqc_stream_t *stream, void *user_data) user_stream_t *user_stream = (user_stream_t *) user_data; if (user_stream->start_time == 0) { - user_stream->start_time = now(); + user_stream->start_time = xqc_now(); } if (user_stream->send_body == NULL) { @@ -918,12 +940,12 @@ xqc_client_stream_read_notify(xqc_stream_t *stream, void *user_data) /* test first frame rendering time */ if (g_test_case == 14 && user_stream->first_frame_time == 0 && user_stream->recv_body_len >= 98*1024) { - user_stream->first_frame_time = now(); + user_stream->first_frame_time = xqc_now(); } /* test abnormal rate */ if (g_test_case == 14) { - xqc_msec_t tmp = now(); + xqc_msec_t tmp = xqc_now(); if (tmp - user_stream->last_read_time > 150*1000 && user_stream->last_read_time != 0 ) { user_stream->abnormal_count++; printf("\033[33m!!!!!!!!!!!!!!!!!!!!abnormal!!!!!!!!!!!!!!!!!!!!!!!!\033[0m\n"); @@ -933,7 +955,7 @@ xqc_client_stream_read_notify(xqc_stream_t *stream, void *user_data) if (fin) { user_stream->recv_fin = 1; - xqc_msec_t now_us = now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, @@ -1008,7 +1030,7 @@ int xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream) { if (user_stream->start_time == 0) { - user_stream->start_time = now(); + user_stream->start_time = xqc_now(); } ssize_t ret = 0; char content_len[10]; @@ -1451,7 +1473,7 @@ xqc_client_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ user_stream->recv_fin = 1; xqc_request_stats_t stats; stats = xqc_h3_request_get_stats(h3_request); - xqc_msec_t now_us = now(); + xqc_msec_t now_us = xqc_now(); printf("\033[33m>>>>>>>> request time cost:%"PRIu64" us, speed:%"PRIu64" K/s \n" ">>>>>>>> send_body_size:%zu, recv_body_size:%zu \033[0m\n", now_us - user_stream->start_time, @@ -1574,7 +1596,7 @@ xqc_client_socket_read_handler(user_conn_t *user_conn) break; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); for (int i = 0; i < retval; i++) { recv_sum += msgs[i].msg_len; @@ -1601,12 +1623,12 @@ xqc_client_socket_read_handler(user_conn_t *user_conn) recv_size = recvfrom(user_conn->fd, packet_buf, sizeof(packet_buf), 0, user_conn->peer_addr, &user_conn->peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_last_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("recvfrom: recvmsg = %zd(%s)\n", recv_size, strerror(errno)); + printf("recvfrom: recvmsg = %zd(%s)\n", recv_size, strerror(get_last_sys_errno())); break; } @@ -1623,13 +1645,13 @@ xqc_client_socket_read_handler(user_conn_t *user_conn) socklen_t tmp = sizeof(struct sockaddr_in6); int ret = getsockname(user_conn->fd, (struct sockaddr *) user_conn->local_addr, &tmp); if (ret < 0) { - printf("getsockname error, errno: %d\n", errno); + printf("getsockname error, errno: %d\n", get_last_sys_errno()); break; } user_conn->local_addrlen = tmp; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); g_last_sock_op_time = recv_time; @@ -1686,9 +1708,9 @@ xqc_client_socket_read_handler(user_conn_t *user_conn) } while (recv_size > 0); - if ((now() - last_recv_ts) > 200000) { - printf("recving rate: %.3lf Kbps\n", (rcv_sum - last_rcv_sum) * 8.0 * 1000 / (now() - last_recv_ts)); - last_recv_ts = now(); + if ((xqc_now() - last_recv_ts) > 200000) { + printf("recving rate: %.3lf Kbps\n", (rcv_sum - last_rcv_sum) * 8.0 * 1000 / (xqc_now() - last_recv_ts)); + last_recv_ts = xqc_now(); last_rcv_sum = rcv_sum; } @@ -1720,7 +1742,7 @@ xqc_client_socket_event_callback(int fd, short what, void *arg) static void xqc_client_engine_callback(int fd, short what, void *arg) { - printf("timer wakeup now:%"PRIu64"\n", now()); + printf("timer wakeup now:%"PRIu64"\n", xqc_now()); client_ctx_t *ctx = (client_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); @@ -1729,7 +1751,7 @@ xqc_client_engine_callback(int fd, short what, void *arg) static void xqc_client_timeout_callback(int fd, short what, void *arg) { - printf("xqc_client_timeout_callback now %"PRIu64"\n", now()); + printf("xqc_client_timeout_callback now %"PRIu64"\n", xqc_now()); user_conn_t *user_conn = (user_conn_t *) arg; int rc; static int restart_after_a_while = 1; @@ -1768,7 +1790,7 @@ xqc_client_timeout_callback(int fd, short what, void *arg) return; } - if (now() - g_last_sock_op_time < (uint64_t)g_conn_timeout * 1000000) { + if (xqc_now() - g_last_sock_op_time < (uint64_t)g_conn_timeout * 1000000) { struct timeval tv; tv.tv_sec = g_conn_timeout; tv.tv_usec = 0; @@ -1829,7 +1851,7 @@ xqc_client_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e int write_len = write(ctx->log_fd, log_buf, log_len); if (write_len < 0) { - printf("write log failed, errno: %d\n", errno); + printf("write log failed, errno: %d\n", get_last_sys_errno()); } } @@ -1873,13 +1895,13 @@ xqc_keylog_cb(const char *line, void *user_data) int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->keylog_fd, "\n", 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); } } @@ -2097,6 +2119,8 @@ int main(int argc, char *argv[]) { xqc_client_open_keylog_file(&ctx); xqc_client_open_log_file(&ctx); + xqc_platform_init_env(); + xqc_engine_ssl_config_t engine_ssl_config; memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); /* client does not need to fill in private_key_file & cert_file */ @@ -2188,7 +2212,7 @@ int main(int argc, char *argv[]) { conn_settings.proto_version = XQC_IDRAFT_VER_29; } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) if (g_test_case == 20) { /* test sendmmsg */ printf("test sendmmsg!\n"); tcbs.write_mmsg = xqc_client_write_mmsg; @@ -2353,7 +2377,7 @@ int main(int argc, char *argv[]) { } } - last_recv_ts = now(); + last_recv_ts = xqc_now(); event_base_dispatch(eb); event_free(user_conn->ev_socket); diff --git a/tests/test_server.c b/tests/test_server.c index 8b053311a..e03923848 100644 --- a/tests/test_server.c +++ b/tests/test_server.c @@ -7,15 +7,26 @@ #include #include #include -#include -#include -#include #include #include #include #include #include #include +#include +#include + +#include "platform.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#endif int printf_null(const char *format, ...) @@ -104,17 +115,6 @@ static uint64_t last_snd_ts; #define XQC_TEST_LONG_HEADER_LEN 32769 char test_long_value[XQC_TEST_LONG_HEADER_LEN] = {'\0'}; - -static inline uint64_t -now() -{ - /* get microsecond unit time */ - struct timeval tv; - gettimeofday(&tv, NULL); - uint64_t ul = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec; - return ul; -} - void xqc_server_set_event_timer(xqc_msec_t wake_after, void *user_data) { @@ -739,23 +739,23 @@ xqc_server_write_socket(const unsigned char *buf, size_t size, } do { - errno = 0; + set_last_sys_errno(0); res = sendto(fd, send_buf, send_buf_size, 0, peer_addr, peer_addrlen); - //printf("xqc_server_send write %zd, %s\n", res, strerror(errno)); + printf("xqc_server_send write %zd, %s\n", res, strerror(get_last_sys_errno())); if (res < 0) { - printf("xqc_server_write_socket err %zd %s\n", res, strerror(errno)); - if (errno == EAGAIN) { + printf("xqc_server_write_socket err %zd %s\n", res, strerror(get_last_sys_errno())); + if (get_last_sys_errno() == EAGAIN) { res = XQC_SOCKET_EAGAIN; } } else { snd_sum += res; } - } while ((res < 0) && (errno == EINTR)); + } while ((res < 0) && (EINTR== get_last_sys_errno())); - if ((now() - last_snd_ts) > 200000) { - printf("sending rate: %.3f Kbps\n", (snd_sum - last_snd_sum) * 8.0 * 1000 / (now() - last_snd_ts)); - last_snd_ts = now(); + if ((xqc_now() - last_snd_ts) > 200000) { + printf("sending rate: %.3f Kbps\n", (snd_sum - last_snd_sum) * 8.0 * 1000 / (xqc_now() - last_snd_ts)); + last_snd_ts = xqc_now(); last_snd_sum = snd_sum; } @@ -820,7 +820,7 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) break; } - uint64_t recv_time = now(); + uint64_t recv_time = xqc_now(); for (int i = 0; i < retval; i++) { recv_sum += msgs[i].msg_len; @@ -841,12 +841,12 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) do { recv_size = recvfrom(ctx->fd, packet_buf, sizeof(packet_buf), 0, (struct sockaddr *) &peer_addr, &peer_addrlen); - if (recv_size < 0 && errno == EAGAIN) { + if (recv_size < 0 && get_last_sys_errno() == EAGAIN) { break; } if (recv_size < 0) { - printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(errno)); + printf("!!!!!!!!!recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_last_sys_errno())); break; } @@ -862,7 +862,7 @@ xqc_server_socket_read_handler(xqc_server_ctx_t *ctx) recv_sum += recv_size; - recv_time = now(); + recv_time = xqc_now(); //printf("xqc_server_read_handler recv_size=%zd, recv_time=%llu, now=%llu, recv_total=%d\n", recv_size, recv_time, now(), ++g_recv_total); /*printf("peer_ip: %s, peer_port: %d\n", inet_ntoa(ctx->peer_addr.sin_addr), ntohs(ctx->peer_addr.sin_port)); printf("local_ip: %s, local_port: %d\n", inet_ntoa(ctx->local_addr.sin_addr), ntohs(ctx->local_addr.sin_port));*/ @@ -923,7 +923,7 @@ xqc_server_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t if (g_batch) { int ret = connect(ctx.fd, (struct sockaddr *)&user_conn->peer_addr, user_conn->peer_addrlen); if (ret != 0) { - printf("connect error, errno: %d\n", errno); + printf("connect error, errno: %d\n", get_last_sys_errno()); return ret; } } @@ -943,29 +943,35 @@ xqc_server_create_socket(const char *addr, unsigned int port) fd = socket(type, SOCK_DGRAM, 0); if (fd < 0) { - printf("create socket failed, errno: %d\n", errno); + printf("create socket failed, errno: %d\n", get_last_sys_errno()); return -1; } +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &optval) == SOCKET_ERROR) { + goto err; + } +#else if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { printf("set socket nonblock failed, errno: %d\n", errno); goto err; } +#endif optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } size = 1 * 1024 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { - printf("setsockopt failed, errno: %d\n", errno); + printf("setsockopt failed, errno: %d\n", get_last_sys_errno()); goto err; } @@ -985,7 +991,7 @@ xqc_server_create_socket(const char *addr, unsigned int port) } if (bind(fd, saddr, ctx.local_addrlen) < 0) { - printf("bind socket failed, errno: %d\n", errno); + printf("bind socket failed, errno: %d\n", get_last_sys_errno()); goto err; } @@ -1001,7 +1007,7 @@ static void xqc_server_engine_callback(int fd, short what, void *arg) { //DEBUG; - printf("timer wakeup now:%"PRIu64"\n", now()); + printf("timer wakeup now:%"PRIu64"\n", xqc_now()); xqc_server_ctx_t *ctx = (xqc_server_ctx_t *) arg; xqc_engine_main_logic(ctx->engine); @@ -1081,7 +1087,7 @@ xqc_server_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e int write_len = write(ctx->log_fd, log_buf, log_len); if (write_len < 0) { - printf("xqc_server_write_log write failed, errno: %d\n", errno); + printf("xqc_server_write_log write failed, errno: %d\n", get_last_sys_errno()); } } @@ -1125,17 +1131,17 @@ xqc_keylog_cb(const char *line, void *user_data) int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); return; } write_len = write(ctx->keylog_fd, "\n", 1); if (write_len < 0) { - printf("write keys failed, errno: %d\n", errno); + printf("write keys failed, errno: %d\n", get_last_sys_errno()); } } -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *user) @@ -1152,7 +1158,7 @@ ssize_t xqc_server_write_mmsg(const struct iovec *msg_iov, unsigned int vlen, mmsg[i].msg_hdr.msg_iovlen = 1; } do { - errno = 0; + set_last_sys_errno(0); res = sendmmsg(fd, mmsg, vlen, 0); if (res < 0) { printf("sendmmsg err %zd %s\n", res, strerror(errno)); @@ -1310,6 +1316,8 @@ int main(int argc, char *argv[]) { xqc_server_open_keylog_file(&ctx); xqc_server_open_log_file(&ctx); + xqc_platform_init_env(); + xqc_engine_ssl_config_t engine_ssl_config; memset(&engine_ssl_config, 0, sizeof(engine_ssl_config)); engine_ssl_config.private_key_file = "./server.key"; @@ -1413,7 +1421,7 @@ int main(int argc, char *argv[]) { eb = event_base_new(); ctx.ev_engine = event_new(eb, -1, 0, xqc_server_engine_callback, &ctx); -#if defined(XQC_SUPPORT_SENDMMSG) +#if defined(XQC_SUPPORT_SENDMMSG) && !defined(XQC_SYS_WINDOWS) if (g_batch) { tcbs.write_mmsg = xqc_server_write_mmsg, config.sendmmsg_on = 1;