diff --git a/CMakeLists.txt b/CMakeLists.txt index 70d61d13..d3e5e629 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,7 @@ endif() if(XQC_ENABLE_TESTING) add_subdirectory(tests) add_subdirectory(demo) + add_subdirectory(mini) endif(XQC_ENABLE_TESTING) diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index b72b3aea..a9b84d3b 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -5,16 +5,22 @@ set( "xqc_hq_conn.c" "xqc_hq_request.c" ) +set( + TEST_PLATFORM_SOURCES + "../tests/platform.c" +) set( DEMO_CLIENT_SOURCES ${HQ_SOURCES} + ${TEST_PLATFORM_SOURCES} "demo_client.c" ) set( DEMO_SERVER_SOURCES ${HQ_SOURCES} + ${TEST_PLATFORM_SOURCES} "demo_server.c" ) diff --git a/demo/demo_client.c b/demo/demo_client.c index 11992da1..cf408ac4 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -892,7 +892,7 @@ xqc_demo_cli_conn_create_path(const xqc_cid_t *cid, void *conn_user_data) printf("set No.%d path (id = %"PRIu64") to STANDBY state\n", 1, path_id); xqc_conn_mark_path_standby(ctx->engine, &(user_conn->cid), path_id); } - + } } @@ -2225,7 +2225,7 @@ xqc_demo_cli_send_h3_req(xqc_demo_cli_user_conn_t *user_conn, if (req_create_cnt == user_conn->ctx->args->req_cfg.throttled_req) { settings.recv_rate_bytes_per_sec = user_conn->ctx->args->quic_cfg.recv_rate; } - + if (req_create_cnt != 0 && user_conn->ctx->args->req_cfg.throttled_req != 0 && (req_create_cnt % user_conn->ctx->args->req_cfg.throttled_req) == 0) diff --git a/include/xquic/xqc_errno.h b/include/xquic/xqc_errno.h index b8cd7ad6..894f1c9d 100644 --- a/include/xquic/xqc_errno.h +++ b/include/xquic/xqc_errno.h @@ -5,8 +5,8 @@ #ifndef _XQC_ERRNO_H_INCLUDED_ #define _XQC_ERRNO_H_INCLUDED_ -/* - * QUIC Transport Protocol error codes +/** + * @brief QUIC Transport Protocol error codes */ typedef enum { TRA_NO_ERROR = 0x0, @@ -23,14 +23,14 @@ typedef enum { TRA_INVALID_TOKEN = 0xB, TRA_APPLICATION_ERROR = 0xC, TRA_CRYPTO_BUFFER_EXCEEDED = 0xD, - TRA_0RTT_TRANS_PARAMS_ERROR = 0xE, /* MUST delete the current saved 0RTT transport parameters */ - TRA_HS_CERTIFICATE_VERIFY_FAIL = 0x1FE, /* for handshake certificate verify error */ - TRA_CRYPTO_ERROR = 0x1FF, /* 0x1XX */ + TRA_0RTT_TRANS_PARAMS_ERROR = 0xE, /**< MUST delete the current saved 0RTT transport parameters */ + TRA_HS_CERTIFICATE_VERIFY_FAIL = 0x1FE, /**< for handshake certificate verify error */ + TRA_CRYPTO_ERROR = 0x1FF, /**< 0x1XX */ } xqc_trans_err_code_t; -/* - * Multipath error codes +/** + * @brief Multipath error codes */ typedef enum { TRA_MP_PROTOCOL_VIOLATION = 0x1001d76d3ded42f3 @@ -39,8 +39,8 @@ typedef enum { #define TRA_CRYPTO_ERROR_BASE 0x100 -/* - * QUIC Http/3 Protocol error codes +/** + * @brief QUIC Http/3 Protocol error codes */ typedef enum { H3_NO_ERROR = 0x100, @@ -61,8 +61,8 @@ typedef enum { H3_VERSION_FALLBACK = 0x110, } xqc_h3_err_code_t; -/* - * QUIC QPACK protocol error codes +/** + * @brief QPACK protocol error codes */ typedef enum { QPACK_DECOMPRESSION_FAILED = 0x200, @@ -75,74 +75,76 @@ typedef enum { #define XQC_ERROR -1 -/* xquic transport internal error codes: 6xx */ +/** + * @brief xquic transport internal error codes: 6xx + */ typedef enum { - XQC_ENOBUF = 600, /* not enough buf space */ - XQC_EVINTREAD = 601, /* parse frame error */ - XQC_ENULLPTR = 602, /* empty pointer, usually a malloc failure */ - XQC_EMALLOC = 603, /* malloc failure */ - XQC_EILLPKT = 604, /* illegal packet, don't close connection, just drop it */ - XQC_ELEVEL = 605, /* incorrect encryption level */ - XQC_ECREATE_CONN = 606, /* fail to create a connection */ - XQC_CLOSING = 607, /* connection is closing, operation denied */ - XQC_ECONN_NFOUND = 608, /* fail to find the corresponding connection */ - XQC_ESYS = 609, /* system error, usually a public library interface failure */ - XQC_EAGAIN = 610, /* write blocking, similar to EAGAIN */ - XQC_EPARAM = 611, /* wrong parameters */ - XQC_ESTATE = 612, /* abnormal connection status */ - XQC_ELIMIT = 613, /* exceed cache limit */ - XQC_EPROTO = 614, /* violation of protocol */ - XQC_ESOCKET = 615, /* socket interface error */ - XQC_EFATAL = 616, /* fatal error, engine will immediately destroy the connection */ - XQC_ESTREAM_ST = 617, /* abnormal flow status */ - XQC_ESEND_RETRY = 618, /* send retry failure */ - XQC_ECONN_BLOCKED = 619, /* connection-level flow control */ - XQC_ESTREAM_BLOCKED = 620, /* stream-level flow control */ - XQC_EENCRYPT = 621, /* encryption error */ - XQC_EDECRYPT = 622, /* decryption error */ - XQC_ESTREAM_NFOUND = 623, /* fail to find the corresponding stream */ - XQC_EWRITE_PKT = 624, /* fail to create a package or write a package header */ - XQC_ECREATE_STREAM = 625, /* fail to create stream */ - XQC_ESTREAM_RESET = 626, /* stream has been reset */ - XQC_EDUP_FRAME = 627, /* duplicate frames */ - XQC_EFINAL_SIZE = 628, /* STREAM frame final size error */ - XQC_EVERSION = 629, /* this version is not supported and requires negotiation */ - XQC_EWAITING = 630, /* need to wait */ - XQC_EIGNORE_PKT = 631, /* ignore unknown packet/frame, don't close connection */ - XQC_EGENERATE_CID = 632, /* connection ID generation error */ - XQC_EANTI_AMPLIFICATION_LIMIT = 633, /* server reached the anti-amplification limit */ - XQC_ECONN_NO_AVAIL_CID = 634, /* no available connection ID */ - XQC_ECONN_CID_NOT_FOUND = 635, /* can't find cid in connection */ - XQC_EILLEGAL_FRAME = 636, /* illegal stream & frame, close connection */ - XQC_ECID_STATE = 637, /* abnormal connection ID status */ - XQC_EACTIVE_CID_LIMIT = 638, /* active cid exceed active_connection_id_limit */ - XQC_EALPN_NOT_SUPPORTED = 639, /* alpn is not supported by server */ - XQC_EALPN_NOT_REGISTERED = 640, /* alpn is not registered */ - XQC_ESTATELESS_RESET = 641, /* connection is reset by peer */ - XQC_EPACKET_FILETER_CALLBACK = 642, /* error with packet filter callback function */ - - XQC_EMP_NOT_SUPPORT_MP = 650, /* Multipath - don't support multipath */ - XQC_EMP_NO_AVAIL_PATH_ID = 651, /* Multipath - no available path id */ - XQC_EMP_CREATE_PATH = 652, /* Multipath - create path error */ - XQC_EMP_PATH_NOT_FOUND = 653, /* Multipath - can't find path in paths_list */ - XQC_EMP_PATH_STATE_ERROR = 654, /* Multipath - abnormal path status */ - XQC_EMP_SCHEDULE_PATH = 655, /* Multipath - fail to schedule path for sending */ - XQC_EMP_NO_ACTIVE_PATH = 656, /* Multipath - no another active path */ - XQC_EMP_INVALID_MP_VERTION = 657, /* Multipath - the multipath version value is invalid */ - XQC_EMP_NO_AVAILABLE_CID_FOR_PATH = 658, /* Multipath - there's no available unused cid for this path */ - - XQC_EFEC_NOT_SUPPORT_FEC = 660, /* FEC - fec not supported */ - XQC_EFEC_SCHEME_ERROR = 661, /* FEC - no available scheme */ - XQC_EFEC_SYMBOL_ERROR = 662, /* FEC - symbol value error */ - XQC_EFEC_TOLERABLE_ERROR = 663, /* FEC - tolerable error */ + XQC_ENOBUF = 600, /**< not enough buf space */ + XQC_EVINTREAD = 601, /**< parse frame error */ + XQC_ENULLPTR = 602, /**< empty pointer, usually a malloc failure */ + XQC_EMALLOC = 603, /**< malloc failure */ + XQC_EILLPKT = 604, /**< illegal packet, don't close connection, just drop it */ + XQC_ELEVEL = 605, /**< incorrect encryption level */ + XQC_ECREATE_CONN = 606, /**< fail to create a connection */ + XQC_CLOSING = 607, /**< connection is closing, operation denied */ + XQC_ECONN_NFOUND = 608, /**< fail to find the corresponding connection */ + XQC_ESYS = 609, /**< system error, usually a public library interface failure */ + XQC_EAGAIN = 610, /**< write blocking, similar to EAGAIN */ + XQC_EPARAM = 611, /**< wrong parameters */ + XQC_ESTATE = 612, /**< abnormal connection status */ + XQC_ELIMIT = 613, /**< exceed cache limit */ + XQC_EPROTO = 614, /**< violation of protocol */ + XQC_ESOCKET = 615, /**< socket interface error */ + XQC_EFATAL = 616, /**< fatal error, engine will immediately destroy the connection */ + XQC_ESTREAM_ST = 617, /**< abnormal flow status */ + XQC_ESEND_RETRY = 618, /**< send retry failure */ + XQC_ECONN_BLOCKED = 619, /**< connection-level flow control */ + XQC_ESTREAM_BLOCKED = 620, /**< stream-level flow control */ + XQC_EENCRYPT = 621, /**< encryption error */ + XQC_EDECRYPT = 622, /**< decryption error */ + XQC_ESTREAM_NFOUND = 623, /**< fail to find the corresponding stream */ + XQC_EWRITE_PKT = 624, /**< fail to create a package or write a package header */ + XQC_ECREATE_STREAM = 625, /**< fail to create stream */ + XQC_ESTREAM_RESET = 626, /**< stream has been reset */ + XQC_EDUP_FRAME = 627, /**< duplicate frames */ + XQC_EFINAL_SIZE = 628, /**< STREAM frame final size error */ + XQC_EVERSION = 629, /**< this version is not supported and requires negotiation */ + XQC_EWAITING = 630, /**< need to wait */ + XQC_EIGNORE_PKT = 631, /**< ignore unknown packet/frame, don't close connection */ + XQC_EGENERATE_CID = 632, /**< connection ID generation error */ + XQC_EANTI_AMPLIFICATION_LIMIT = 633, /**< server reached the anti-amplification limit */ + XQC_ECONN_NO_AVAIL_CID = 634, /**< no available connection ID */ + XQC_ECONN_CID_NOT_FOUND = 635, /**< can't find cid in connection */ + XQC_EILLEGAL_FRAME = 636, /**< illegal stream & frame, close connection */ + XQC_ECID_STATE = 637, /**< abnormal connection ID status */ + XQC_EACTIVE_CID_LIMIT = 638, /**< active cid exceed active_connection_id_limit */ + XQC_EALPN_NOT_SUPPORTED = 639, /**< alpn is not supported by server */ + XQC_EALPN_NOT_REGISTERED = 640, /**< alpn is not registered */ + XQC_ESTATELESS_RESET = 641, /**< connection is reset by peer */ + XQC_EPACKET_FILETER_CALLBACK = 642, /**< error with packet filter callback function */ + + XQC_EMP_NOT_SUPPORT_MP = 650, /**< Multipath - don't support multipath */ + XQC_EMP_NO_AVAIL_PATH_ID = 651, /**< Multipath - no available path id */ + XQC_EMP_CREATE_PATH = 652, /**< Multipath - create path error */ + XQC_EMP_PATH_NOT_FOUND = 653, /**< Multipath - can't find path in paths_list */ + XQC_EMP_PATH_STATE_ERROR = 654, /**< Multipath - abnormal path status */ + XQC_EMP_SCHEDULE_PATH = 655, /**< Multipath - fail to schedule path for sending */ + XQC_EMP_NO_ACTIVE_PATH = 656, /**< Multipath - no another active path */ + XQC_EMP_INVALID_MP_VERTION = 657, /**< Multipath - the multipath version value is invalid */ + XQC_EMP_NO_AVAILABLE_CID_FOR_PATH = 658, /**< Multipath - there's no available unused cid for this path */ + + XQC_EFEC_NOT_SUPPORT_FEC = 660, /**< FEC - fec not supported */ + XQC_EFEC_SCHEME_ERROR = 661, /**< FEC - no available scheme */ + XQC_EFEC_SYMBOL_ERROR = 662, /**< FEC - symbol value error */ + XQC_EFEC_TOLERABLE_ERROR = 663, /**< FEC - tolerable error */ - XQC_EENCRYPT_LB_CID = 670, /* load balance connection ID encryption error */ - XQC_EENCRYPT_AES_128_ECB = 671, /* aes_128_ecb algorithm error */ + XQC_EENCRYPT_LB_CID = 670, /**< load balance connection ID encryption error */ + XQC_EENCRYPT_AES_128_ECB = 671, /**< aes_128_ecb algorithm error */ - XQC_EDGRAM_NOT_SUPPORTED = 680, /* Datagram - not supported */ - XQC_EDGRAM_TOO_LARGE = 681, /* Datagram - payload size too large */ + XQC_EDGRAM_NOT_SUPPORTED = 680, /**< Datagram - not supported */ + XQC_EDGRAM_TOO_LARGE = 681, /**< Datagram - payload size too large */ - XQC_EPMTUD_PROBING_SIZE = 682, /* PMTUD - probing size error */ + XQC_EPMTUD_PROBING_SIZE = 682, /**< PMTUD - probing size error */ XQC_E_MAX, } xqc_transport_error_t; @@ -151,7 +153,9 @@ typedef enum { static const int TRANS_ERR_CNT = XQC_E_MAX - TRANS_ERR_START; -/* xquic TLS internal error codes: 7xx */ +/** + * @brief xquic TLS internal error codes: 7xx + */ typedef enum { XQC_TLS_INVALID_ARGUMENT = 700, XQC_TLS_UNKNOWN_PKT_TYPE = 701, @@ -207,42 +211,43 @@ typedef enum { static const int TLS_ERR_CNT = XQC_TLS_ERR_MAX - TLS_ERR_START; -/* xquic HTTP3/QPACK application error codes: 8xx */ +/** + * @brief xquic HTTP3/QPACK application error codes: 8xx + */ typedef enum { - /* HTTP/3 error codes */ - XQC_H3_EMALLOC = 800, /* malloc failure */ - XQC_H3_ECREATE_STREAM = 801, /* fail to create a stream */ - XQC_H3_ECREATE_REQUEST = 802, /* fail to create a request */ - XQC_H3_EGOAWAY_RECVD = 803, /* GOAWAY received, operation denied */ - XQC_H3_ECREATE_CONN = 804, /* fail to create a connection */ - XQC_H3_EQPACK_ENCODE = 805, /* QPACK - encode error */ - XQC_H3_EQPACK_DECODE = 806, /* QPACK - decode error */ - XQC_H3_EPRI_TREE = 807, /* priority tree error */ - XQC_H3_EPROC_CONTROL = 808, /* fail to process control stream */ - XQC_H3_EPROC_REQUEST = 809, /* fail to process request stream */ - XQC_H3_EPROC_PUSH = 810, /* fail to process push stream */ - XQC_H3_EPARAM = 811, /* wrong parameters */ - XQC_H3_BUFFER_EXCEED = 812, /* http send buffer exceeds the maximum */ - XQC_H3_DECODE_ERROR = 813, /* decode error */ - XQC_H3_INVALID_STREAM = 814, /* invalid stream, such as multiple control streams, etc. */ - XQC_H3_CLOSE_CRITICAL_STREAM = 815, /* illegal closure of control stream and qpack encoder/decoder stream */ - XQC_H3_STATE_ERROR = 816, /* http3 decoding status error */ - XQC_H3_CONTROL_ERROR = 817, /* control stream error, such as setting not send first or send twice */ - XQC_H3_CONTROL_DECODE_ERROR = 818, /* control stream decode error, such as encountering an unrecognized frame type */ - XQC_H3_CONTROL_DECODE_INVALID = 819, /* control stream decode invalid, eg. illegal remaining length */ - XQC_H3_PRIORITY_ERROR = 820, /* priority error */ - XQC_H3_INVALID_FRAME_TYPE = 821, /* invalid frame type */ - XQC_H3_UNSUPPORT_FRAME_TYPE = 822, /* unsupported frame type */ - XQC_H3_INVALID_HEADER = 823, /* invalid header field, such as the length exceeds the limit, etc. */ - XQC_H3_SETTING_ERROR = 824, /* SETTING error */ - XQC_H3_BLOCKED_STREAM_EXCEED = 825, /* blocked_stream exceed limit */ - XQC_H3_STREAM_RECV_ERROR = 826, /* call xqc_stream_recv error */ - XQC_H3_INVALID_PRIORITY = 827, /* invalid http priority params or values */ - XQC_H3_INVALID_BIDI_STREAM_TYPE = 828, /* invalid bidi stream type */ - XQC_H3_ECREATE_BYTESTREAM = 829, /* fail to create a bytestream */ - XQC_H3_EPROC_BYTESTREAM = 830, /* fail to process bytestream */ - XQC_H3_BYTESTREAM_FIN_SENT = 831, /* try to send data on a bytestream that already sent FIN */ - XQC_H3_BYTESTREAM_MSG_BUF_EXIST = 832, /* try to create a msg buf while it already exists */ + XQC_H3_EMALLOC = 800, /**< malloc failure */ + XQC_H3_ECREATE_STREAM = 801, /**< fail to create a stream */ + XQC_H3_ECREATE_REQUEST = 802, /**< fail to create a request */ + XQC_H3_EGOAWAY_RECVD = 803, /**< GOAWAY received, operation denied */ + XQC_H3_ECREATE_CONN = 804, /**< fail to create a connection */ + XQC_H3_EQPACK_ENCODE = 805, /**< QPACK - encode error */ + XQC_H3_EQPACK_DECODE = 806, /**< QPACK - decode error */ + XQC_H3_EPRI_TREE = 807, /**< priority tree error */ + XQC_H3_EPROC_CONTROL = 808, /**< fail to process control stream */ + XQC_H3_EPROC_REQUEST = 809, /**< fail to process request stream */ + XQC_H3_EPROC_PUSH = 810, /**< fail to process push stream */ + XQC_H3_EPARAM = 811, /**< wrong parameters */ + XQC_H3_BUFFER_EXCEED = 812, /**< http send buffer exceeds the maximum */ + XQC_H3_DECODE_ERROR = 813, /**< decode error */ + XQC_H3_INVALID_STREAM = 814, /**< invalid stream, such as multiple control streams, etc. */ + XQC_H3_CLOSE_CRITICAL_STREAM = 815, /**< illegal closure of control stream and qpack encoder/decoder stream */ + XQC_H3_STATE_ERROR = 816, /**< http3 decoding status error */ + XQC_H3_CONTROL_ERROR = 817, /**< control stream error, such as setting not send first or send twice */ + XQC_H3_CONTROL_DECODE_ERROR = 818, /**< control stream decode error, such as encountering an unrecognized frame type */ + XQC_H3_CONTROL_DECODE_INVALID = 819, /**< control stream decode invalid, eg. illegal remaining length */ + XQC_H3_PRIORITY_ERROR = 820, /**< priority error */ + XQC_H3_INVALID_FRAME_TYPE = 821, /**< invalid frame type */ + XQC_H3_UNSUPPORT_FRAME_TYPE = 822, /**< unsupported frame type */ + XQC_H3_INVALID_HEADER = 823, /**< invalid header field, such as the length exceeds the limit, etc. */ + XQC_H3_SETTING_ERROR = 824, /**< SETTING error */ + XQC_H3_BLOCKED_STREAM_EXCEED = 825, /**< blocked_stream exceed limit */ + XQC_H3_STREAM_RECV_ERROR = 826, /**< call xqc_stream_recv error */ + XQC_H3_INVALID_PRIORITY = 827, /**< invalid http priority params or values */ + XQC_H3_INVALID_BIDI_STREAM_TYPE = 828, /**< invalid bidi stream type */ + XQC_H3_ECREATE_BYTESTREAM = 829, /**< fail to create a bytestream */ + XQC_H3_EPROC_BYTESTREAM = 830, /**< fail to process bytestream */ + XQC_H3_BYTESTREAM_FIN_SENT = 831, /**< try to send data on a bytestream that already sent FIN */ + XQC_H3_BYTESTREAM_MSG_BUF_EXIST = 832, /**< try to create a msg buf while it already exists */ XQC_H3_ERR_MAX, } xqc_h3_error_t; @@ -250,25 +255,26 @@ typedef enum { #define H3_ERR_START 800 static const int H3_ERR_CNT = XQC_H3_ERR_MAX - H3_ERR_START; - +/** + * @brief xquic QPACK application error codes: 9xx + */ typedef enum { - /* QPACK error codes */ - XQC_QPACK_DECODER_VARINT_ERROR = 900, /* qpack decode variable-length integer error */ - XQC_QPACK_ENCODER_ERROR = 901, /* qpack encode error */ - XQC_QPACK_DECODER_ERROR = 902, /* qpack decode error */ - XQC_QPACK_DYNAMIC_TABLE_ERROR = 903, /* qpack dynamic table error */ - XQC_QPACK_STATIC_TABLE_ERROR = 904, /* qpack static table error */ - XQC_QPACK_SET_DTABLE_CAP_ERROR = 905, /* set dynamic table capacity error */ - XQC_QPACK_SEND_ERROR = 906, /* send data error or control message error */ - XQC_QPACK_SAVE_HEADERS_ERROR = 907, /* failed to save name-value to header structure */ - XQC_QPACK_UNKNOWN_INSTRUCTION = 908, /* unknown encoder/decoder instruction */ - XQC_QPACK_INSTRUCTION_ERROR = 909, /* error instruction */ - XQC_QPACK_DYNAMIC_TABLE_REFERRED = 910, /* dynamic table entry is still referred */ - XQC_QPACK_DYNAMIC_TABLE_VOID_ENTRY = 911, /* entry inexists in dynamic table */ - XQC_QPACK_STATE_ERROR = 912, /* state is error */ - XQC_QPACK_DYNAMIC_TABLE_NOT_ENOUGH = 913, /* dynamic table not enough */ - XQC_QPACK_HUFFMAN_DEC_ERROR = 914, /* huffman decode error */ - XQC_QPACK_HUFFMAN_DEC_STATE_ERROR = 915, /* huffman decode state error */ + XQC_QPACK_DECODER_VARINT_ERROR = 900, /**< qpack decode variable-length integer error */ + XQC_QPACK_ENCODER_ERROR = 901, /**< qpack encode error */ + XQC_QPACK_DECODER_ERROR = 902, /**< qpack decode error */ + XQC_QPACK_DYNAMIC_TABLE_ERROR = 903, /**< qpack dynamic table error */ + XQC_QPACK_STATIC_TABLE_ERROR = 904, /**< qpack static table error */ + XQC_QPACK_SET_DTABLE_CAP_ERROR = 905, /**< set dynamic table capacity error */ + XQC_QPACK_SEND_ERROR = 906, /**< send data error or control message error */ + XQC_QPACK_SAVE_HEADERS_ERROR = 907, /**< failed to save name-value to header structure */ + XQC_QPACK_UNKNOWN_INSTRUCTION = 908, /**< unknown encoder/decoder instruction */ + XQC_QPACK_INSTRUCTION_ERROR = 909, /**< error instruction */ + XQC_QPACK_DYNAMIC_TABLE_REFERRED = 910, /**< dynamic table entry is still referred */ + XQC_QPACK_DYNAMIC_TABLE_VOID_ENTRY = 911, /**< entry inexists in dynamic table */ + XQC_QPACK_STATE_ERROR = 912, /**< state is error */ + XQC_QPACK_DYNAMIC_TABLE_NOT_ENOUGH = 913, /**< dynamic table not enough */ + XQC_QPACK_HUFFMAN_DEC_ERROR = 914, /**< huffman decode error */ + XQC_QPACK_HUFFMAN_DEC_STATE_ERROR = 915, /**< huffman decode state error */ XQC_QPACK_ERR_MAX, } xqc_qpack_error_t; diff --git a/include/xquic/xqc_http3.h b/include/xquic/xqc_http3.h index 9f42073c..64c24fe8 100644 --- a/include/xquic/xqc_http3.h +++ b/include/xquic/xqc_http3.h @@ -17,20 +17,22 @@ extern "C" { * @brief read flag of xqc_h3_request_read_notify_pt */ typedef enum { - /* nothing readable */ + /** nothing readable */ XQC_REQ_NOTIFY_READ_NULL = 0, - /* read header section flag, this will be set when the first HEADERS is processed */ + /** read header section flag, this will be set when the first HEADERS is processed */ XQC_REQ_NOTIFY_READ_HEADER = 1 << 0, - /* read body flag, this will be set when a DATA frame is processed */ + /** read body flag, this will be set when a DATA frame is processed */ XQC_REQ_NOTIFY_READ_BODY = 1 << 1, - /* read trailer section flag, this will be set when trailer HEADERS frame is processed */ + /** read trailer section flag, this will be set when trailer HEADERS frame is processed */ XQC_REQ_NOTIFY_READ_TRAILER = 1 << 2, - /* read empty fin flag, notify callback will be triggered when a single fin frame is received - while HEADERS and DATA were notified. This flag will NEVER be set with other flags */ + /** + * read empty fin flag, notify callback will be triggered when a single fin frame is received + while HEADERS and DATA were notified. This flag will NEVER be set with other flags + */ XQC_REQ_NOTIFY_READ_EMPTY_FIN = 1 << 3, } xqc_request_notify_flag_t; @@ -88,28 +90,28 @@ typedef enum xqc_http3_nv_flag_s { typedef struct xqc_http_header_s { - /* name of http header */ + /** name of http header */ struct iovec name; - /* value of http header */ + /** value of http header */ struct iovec value; - /* flags of xqc_http3_nv_flag_t with OR operator */ + /** flags of xqc_http3_nv_flag_t with OR operator */ uint8_t flags; } xqc_http_header_t; typedef struct xqc_http_headers_s { - /* array of http headers */ + /** array of http headers */ xqc_http_header_t *headers; - /* count of headers */ + /** count of headers */ size_t count; - /* capacity of headers */ + /** capacity of headers */ size_t capacity; - /* total byte count of headers */ + /** total byte count of headers */ size_t total_len; } xqc_http_headers_t; @@ -122,19 +124,32 @@ typedef struct xqc_http_headers_s { typedef struct xqc_request_stats_s { size_t send_body_size; size_t recv_body_size; - size_t send_header_size; /* plaintext header size */ - size_t recv_header_size; /* plaintext header size */ - size_t send_hdr_compressed; /* compressed header size */ - size_t recv_hdr_compressed; /* compressed header size */ - int stream_err; /* QUIC layer error code, 0 for no error */ - xqc_usec_t blocked_time; /* time of h3 stream being blocked */ - xqc_usec_t unblocked_time; /* time of h3 stream being unblocked */ - xqc_usec_t stream_fin_time; /* time of receiving transport fin */ - xqc_usec_t h3r_begin_time; /* time of creating request */ - xqc_usec_t h3r_end_time; /* time of request fin */ - xqc_usec_t h3r_header_begin_time; /* time of receiving HEADERS frame */ - xqc_usec_t h3r_header_end_time; /* time of finishing processing HEADERS frame */ - xqc_usec_t h3r_body_begin_time; /* time of receiving DATA frame */ + /** plaintext header size */ + size_t send_header_size; + /** plaintext header size */ + size_t recv_header_size; + /** compressed header size */ + size_t send_hdr_compressed; + /** compressed header size */ + size_t recv_hdr_compressed; + /** QUIC layer error code, 0 for no error */ + int stream_err; + /** time of h3 stream being blocked */ + xqc_usec_t blocked_time; + /** time of h3 stream being unblocked */ + xqc_usec_t unblocked_time; + /** time of receiving transport fin */ + xqc_usec_t stream_fin_time; + /** time of creating request */ + xqc_usec_t h3r_begin_time; + /** time of request fin */ + xqc_usec_t h3r_end_time; + /** time of receiving HEADERS frame */ + xqc_usec_t h3r_header_begin_time; + /** time of finishing processing HEADERS frame */ + xqc_usec_t h3r_header_end_time; + /** time of receiving DATA frame */ + xqc_usec_t h3r_body_begin_time; xqc_usec_t h3r_header_send_time; xqc_usec_t h3r_body_send_time; xqc_usec_t stream_fin_send_time; @@ -171,7 +186,7 @@ typedef struct xqc_request_stats_s { /** * @brief how long the request was blocked by congestion control (ms) */ - xqc_msec_t cwnd_blocked_ms; + xqc_msec_t cwnd_blocked_ms; /** * @brief the number of packet has been retransmitted */ @@ -209,25 +224,27 @@ typedef struct xqc_h3_ext_bytestream_stats_s { xqc_usec_t first_byte_rcvd_time; } xqc_h3_ext_bytestream_stats_t; -/* connection settings for http3 */ +/** + * @brief connection settings for http3 + */ typedef struct xqc_h3_conn_settings_s { - /* MAX_FIELD_SECTION_SIZE of http3 */ + /** MAX_FIELD_SECTION_SIZE of http3 */ uint64_t max_field_section_size; - /* MAX_PUSH_STREAMS */ + /** MAX_PUSH_STREAMS */ uint64_t max_pushes; - /* ENC_MAX_DYNAMIC_TABLE_CAPACITY */ + /** ENC_MAX_DYNAMIC_TABLE_CAPACITY */ uint64_t qpack_enc_max_table_capacity; - /* DEC_MAX_DYNAMIC_TABLE_CAPACITY */ + /** DEC_MAX_DYNAMIC_TABLE_CAPACITY */ uint64_t qpack_dec_max_table_capacity; - /* MAX_BLOCKED_STREAMS */ + /** MAX_BLOCKED_STREAMS */ uint64_t qpack_blocked_streams; #ifdef XQC_COMPAT_DUPLICATE - /* compat with the original qpack encoder's duplicate strategy */ + /** compat with the original qpack encoder's duplicate strategy */ xqc_bool_t qpack_compat_duplicate; #endif @@ -316,16 +333,16 @@ typedef void (*xqc_h3_ext_datagram_mss_updated_notify_pt)(xqc_h3_conn_t *conn, typedef struct xqc_h3_ext_dgram_callbacks_s { - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_read_notify_pt dgram_read_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_write_notify_pt dgram_write_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_acked_notify_pt dgram_acked_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_datagram_lost_notify_pt dgram_lost_notify; xqc_h3_ext_datagram_mss_updated_notify_pt dgram_mss_updated_notify; @@ -335,16 +352,16 @@ typedef struct xqc_h3_ext_dgram_callbacks_s { * @brief http3 connection callbacks for application layer */ typedef struct xqc_h3_conn_callbacks_s { - /* http3 connection creation callback, REQUIRED for server, OPTIONAL for client */ + /** http3 connection creation callback, REQUIRED for server, OPTIONAL for client */ xqc_h3_conn_notify_pt h3_conn_create_notify; - /* http3 connection close callback */ + /** http3 connection close callback */ xqc_h3_conn_notify_pt h3_conn_close_notify; - /* handshake finished callback. which will be triggered when HANDSHAKE_DONE is received */ + /** handshake finished callback. which will be triggered when HANDSHAKE_DONE is received */ xqc_h3_handshake_finished_pt h3_conn_handshake_finished; - /* ping callback. which will be triggered when ping is acked */ + /** ping callback. which will be triggered when ping is acked */ xqc_h3_conn_ping_ack_notify_pt h3_conn_ping_acked; /* optional */ } xqc_h3_conn_callbacks_t; @@ -354,36 +371,36 @@ typedef struct xqc_h3_conn_callbacks_s { * @brief http3 request callbacks for application layer */ typedef struct xqc_h3_request_callbacks_s { - /* request creation notify. it will be triggered after a request was created, and is required + /** request creation notify. it will be triggered after a request was created, and is required for server, optional for client */ xqc_h3_request_notify_pt h3_request_create_notify; - /* request close notify. which will be triggered after a request was closed */ + /** request close notify. which will be triggered after a request was closed */ xqc_h3_request_notify_pt h3_request_close_notify; - /* request read notify callback. which will be triggered after received http headers or body */ + /** request read notify callback. which will be triggered after received http headers or body */ xqc_h3_request_read_notify_pt h3_request_read_notify; - /* request write notify callback. when triggered, users can continue to send headers or body */ + /** request write notify callback. when triggered, users can continue to send headers or body */ xqc_h3_request_notify_pt h3_request_write_notify; - /* request closing notify callback, will be triggered when request is closing */ + /** request closing notify callback, will be triggered when request is closing */ xqc_h3_request_closing_notify_pt h3_request_closing_notify; } xqc_h3_request_callbacks_t; typedef struct xqc_h3_ext_bytestream_callbacks_s { - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_bytestream_notify_pt bs_create_notify; - /* the return value is ignored by XQUIC stack */ + /** the return value is ignored by XQUIC stack */ xqc_h3_ext_bytestream_notify_pt bs_close_notify; - /* negative return values will cause the connection to be closed */ + /** negative return values will cause the connection to be closed */ xqc_h3_ext_bytestream_read_notify_pt bs_read_notify; - /* negative return values will cause the connection to be closed */ + /** negative return values will cause the connection to be closed */ xqc_h3_ext_bytestream_notify_pt bs_write_notify; } xqc_h3_ext_bytestream_callbacks_t; @@ -391,16 +408,16 @@ typedef struct xqc_h3_ext_bytestream_callbacks_s { typedef struct xqc_h3_callbacks_s { - /* http3 connection callbacks */ + /** http3 connection callbacks */ xqc_h3_conn_callbacks_t h3c_cbs; - /* http3 request callbacks */ + /** http3 request callbacks */ xqc_h3_request_callbacks_t h3r_cbs; - /* datagram callbacks */ + /** datagram callbacks */ xqc_h3_ext_dgram_callbacks_t h3_ext_dgram_cbs; - /* bytestream callbacks */ + /** bytestream callbacks */ xqc_h3_ext_bytestream_callbacks_t h3_ext_bs_cbs; } xqc_h3_callbacks_t; @@ -496,7 +513,7 @@ void xqc_h3_engine_set_local_settings(xqc_engine_t *engine, * @brief create and http3 connection * * @param engine return from xqc_engine_create - * @param conn_settings connection settings + * @param conn_settings Include all the connection settings, which should be customized according to the actual needs, and will be defaultly set to internal_default_conn_settings if not specified. * @param token token receive from server, xqc_save_token_pt callback * @param token_len length of token * @param server_host server domain diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 0c5ea0f4..392caf49 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -28,8 +28,8 @@ extern "C" { * @brief engine type definition */ typedef enum { - XQC_ENGINE_SERVER, - XQC_ENGINE_CLIENT + XQC_ENGINE_SERVER = 0, + XQC_ENGINE_CLIENT = 1 } xqc_engine_type_t; @@ -37,19 +37,20 @@ typedef enum { * @brief supported versions for IETF drafts */ typedef enum xqc_proto_version_s { - /* placeholder */ - XQC_IDRAFT_INIT_VER, + /** placeholder */ + XQC_IDRAFT_INIT_VER = 0, - /* former version of QUIC RFC 9000 */ - XQC_VERSION_V1, + /** former version of QUIC RFC 9000 */ + XQC_VERSION_V1 = 1, - /* IETF Draft-29 */ - XQC_IDRAFT_VER_29, + /** IETF Draft-29 */ + XQC_IDRAFT_VER_29 = 2, - /* Special version for version negotiation. */ - XQC_IDRAFT_VER_NEGOTIATION, + /** Special version for version negotiation. */ + XQC_IDRAFT_VER_NEGOTIATION = 3, - XQC_VERSION_MAX + /** max value of proto value. */ + XQC_VERSION_MAX = 4 } xqc_proto_version_t; #define XQC_SUPPORT_VERSION_MAX 64 @@ -197,9 +198,10 @@ typedef ssize_t (*xqc_stateless_reset_pt)(const unsigned char *buf, size_t size, void *user_data); /** - * @brief connection closing notify callback function. will be triggered when a - * connection is not available and will not send/receive data any more. this - * callback is helpful to avoid attempts to send data on a closing connection. + * @brief connection closing notify callback function. + * + * This function will be triggered when a connection is not available and will not send/receive data any more. this + * callback is helpful to avoid attempts to send data on a closing connection. \n * NOTICE: this callback function will be triggered at the beginning of * connection close, while the conn_close_notify will be triggered at the end of * connection close. @@ -430,8 +432,8 @@ typedef void (*xqc_path_removed_notify_pt)(const xqc_cid_t *scid, uint64_t path_ void *conn_user_data); typedef enum { - XQC_PATH_DEGRADE, - XQC_PATH_RECOVERY, + XQC_PATH_DEGRADE = 0, + XQC_PATH_RECOVERY = 1, } xqc_path_status_change_type_t; @@ -523,6 +525,7 @@ typedef void (*xqc_datagram_write_notify_pt)(xqc_connection_t *conn, /** * @brief the callback API to notify application that a datagram is declared lost. + * * However, the datagram could also be acknowledged later, as the underlying * loss detection is not fully accurate. Applications should handle this type of * spurious loss. The return value indicates how this lost datagram is @@ -542,7 +545,7 @@ typedef xqc_int_t (*xqc_datagram_lost_notify_pt)(xqc_connection_t *conn, /** * @brief the callback API to notify application that a datagram is acked. Note, - * for every unique dgram_id, this callback will be only called once. + * for every unique dgram_id, this callback will be only called once. * * @param conn the connection handle * @param user_data the dgram_data set by xqc_datagram_set_user_data @@ -554,8 +557,8 @@ typedef void (*xqc_datagram_acked_notify_pt)(xqc_connection_t *conn, /** * @brief the callback to notify application the MSS of QUIC datagrams. Note, - * the MSS of QUIC datagrams will never shrink. If the MSS is zero, it - * means this connection does not support sending QUIC datagrams. + * the MSS of QUIC datagrams will never shrink. If the MSS is zero, it + * means this connection does not support sending QUIC datagrams. * * @param conn the connection handle * @param user_data the dgram_data set by xqc_datagram_set_user_data @@ -566,8 +569,9 @@ typedef void (*xqc_datagram_mss_updated_notify_pt)(xqc_connection_t *conn, /** - * @brief callback functions which are more related to attributes of QUIC [Transport] but not ALPN. - * In another word, these callback functions are events of QUIC Transport layer, and need to + * @brief tranport callback functions are more related to attributes of QUIC [Transport] but not ALPN. + * + * These callback functions are events of QUIC Transport layer, and need to * interact with application-layer, which have less thing to do with ALPN layer. * * These callback functions shall directly call back to application layer, with user_data from @@ -585,17 +589,17 @@ typedef void (*xqc_datagram_mss_updated_notify_pt)(xqc_connection_t *conn, * 3. Callbacks between Transport and Application Protocol: * QUIC events that might be more essential to Application-Layer-Protocols, especially stream data * - * +------------------------------------------------------------------------------+ - * | Application | - * | +-- Application Protocol defined callbacks --+ - * | | Application Protocol | - * +-------- transport callbacks ----+--------- app protocol callbacks -----------+ - * | Transport | - * +------------------------------------------------------------------------------+ */ +// * +------------------------------------------------------------------------------+ +// * | Application | +// * | +-- Application Protocol defined callbacks --+ +// * | | Application Protocol | +// * +-------- transport callbacks ----+--------- app protocol callbacks -----------+ +// * | Transport | +// * +------------------------------------------------------------------------------+ typedef struct xqc_transport_callbacks_s { /** - * accept new connection callback. REQUIRED only for server + * accept new connection callback. REQUIRED only for server \n * NOTICE: this is the headmost callback trigger by xquic, the user_data of server_accept is * what was passed into xqc_engine_packet_process */ @@ -606,7 +610,7 @@ typedef struct xqc_transport_callbacks_s { */ xqc_server_refuse_pt server_refuse; - /* stateless reset callback */ + /** stateless reset callback */ xqc_stateless_reset_pt stateless_reset; /** @@ -728,10 +732,12 @@ typedef struct xqc_conn_callbacks_s { } xqc_conn_callbacks_t; -/* QUIC layer stream callback functions */ +/** + * @brief QUIC layer stream callback functions + */ typedef struct xqc_stream_callbacks_s { /** - * stream read callback function. REQUIRED for both client and server + * @brief stream read callback function. REQUIRED for both client and server * * this will be triggered when QUIC stream data is ready for read. application layer could read * data when xqc_stream_recv interface. @@ -739,7 +745,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_read_notify; /** - * stream write callback function. REQUIRED for both client and server + * @brief stream write callback function. REQUIRED for both client and server * * when sending data with xqc_stream_send, xquic might be blocked or send part of the data. if * this callback function is triggered, applications can continue to send the rest data. @@ -747,7 +753,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_write_notify; /** - * stream create callback function. REQUIRED for server, OPTIONAL for client. + * @brief stream create callback function. REQUIRED for server, OPTIONAL for client. * * this will be triggered when QUIC stream is created. applications can create its own stream * context in this callback function. @@ -755,7 +761,7 @@ typedef struct xqc_stream_callbacks_s { xqc_stream_notify_pt stream_create_notify; /** - * stream close callback function. REQUIRED for both server and client. + * @brief stream close callback function. REQUIRED for both server and client. * * this will be triggered when QUIC stream is finally closed. xquic will close stream after * sending or receiving RESET_STREAM frame after 3 times of PTO, or when connection is closed. @@ -772,10 +778,12 @@ typedef struct xqc_stream_callbacks_s { } xqc_stream_callbacks_t; -/* QUIC layer datagram callback functions */ +/** + * @brief QUIC layer datagram callback functions + */ typedef struct xqc_datagram_callbacks_s { /** - * datagram read callback function. REQUIRED for both client and server if they want to use datagram + * @brief datagram read callback function. REQUIRED for both client and server if they want to use datagram * * this will be triggered when a QUIC datagram is received. application layer could read * data from the arguments of this callback. @@ -783,7 +791,7 @@ typedef struct xqc_datagram_callbacks_s { xqc_datagram_read_notify_pt datagram_read_notify; /** - * datagram write callback function. REQUIRED for both client and server if they want to use datagram + * @brief datagram write callback function. REQUIRED for both client and server if they want to use datagram * * when sending data with xqc_datagram_send or xqc_datagram_send_multiple, xquic might be blocked or send part of the data. if * this callback function is triggered, applications can continue to send the rest data. @@ -791,14 +799,14 @@ typedef struct xqc_datagram_callbacks_s { xqc_datagram_write_notify_pt datagram_write_notify; /** - * datagram acked callback function. OPTIONAL for server and client. + * @brief datagram acked callback function. OPTIONAL for server and client. * * this will be triggered when a QUIC packet containing a DATAGRAM frame is acked. */ xqc_datagram_acked_notify_pt datagram_acked_notify; /** - * datagram lost callback function. OPTIONAL for server and client. + * @brief datagram lost callback function. OPTIONAL for server and client. * * this will be triggered when a QUIC packet containing a DATAGRAM frame is lost. */ @@ -815,13 +823,19 @@ typedef struct xqc_datagram_callbacks_s { */ typedef struct xqc_app_proto_callbacks_s { - /* QUIC connection callback functions for Application-Layer-Protocol */ + /** + * @brief QUIC connection callback functions for Application-Layer-Protocol + */ xqc_conn_callbacks_t conn_cbs; - /* QUIC stream callback functions */ + /** + * @brief QUIC stream callback functions + */ xqc_stream_callbacks_t stream_cbs; - /* QUIC datagram callback functions */ + /** + * @brief QUIC datagram callback functions + */ xqc_datagram_callbacks_t dgram_cbs; } xqc_app_proto_callbacks_t; @@ -836,6 +850,9 @@ typedef enum { XQC_DATA_QOS_PROBING = 7, } xqc_data_qos_level_t; +/** + * @brief congestion control algorithm parameters + */ typedef struct xqc_cc_params_s { uint32_t customize_on; uint32_t init_cwnd; @@ -845,17 +862,20 @@ typedef struct xqc_cc_params_s { uint8_t bbr_enable_lt_bw; uint8_t bbr_ignore_app_limit; uint32_t cc_optimization_flags; - /* 0 < delta <= delta_max, default 0.05, ->0 = more throughput-oriented */ + /** 0 < delta <= delta_max, default 0.05, ->0 = more throughput-oriented */ double copa_delta_base; - /* 0 < delta_max <= 1.0, default 0.5 */ + /** 0 < delta_max <= 1.0, default 0.5 */ double copa_delta_max; - /* + /** * 1.0 <= delta_ai_unit, default 1.0, greater values mean more aggressive * when Copa competes with loss-based CCAs. */ double copa_delta_ai_unit; } xqc_cc_params_t; +/** + * @brief multipath scheduler algorithm parameters + */ typedef struct xqc_scheduler_params_u { uint64_t rtt_us_thr_high; uint64_t rtt_us_thr_low; @@ -865,6 +885,9 @@ typedef struct xqc_scheduler_params_u { uint32_t pto_cnt_thr; } xqc_scheduler_params_t; +/** + * @brief FEC schemes type enum + */ typedef enum { XQC_REED_SOLOMON_CODE = 8, XQC_XOR_CODE = 11, @@ -872,65 +895,81 @@ typedef enum { } xqc_fec_schemes_e; typedef enum { - XQC_FEC_MP_DEFAULT, - XQC_FEC_MP_USE_STB, + XQC_FEC_MP_DEFAULT = 0, + XQC_FEC_MP_USE_STB = 1, } xqc_fec_mp_mode_e; +/** + * @brief FEC parameters on connection settings + */ typedef struct xqc_fec_params_s { - float fec_code_rate; /* code rate represents the source symbol percents in total symbols */ - xqc_int_t fec_ele_bit_size; /* element bit size of current fec finite filed */ - uint64_t fec_protected_frames; /* frame type that should be protected by fec */ - uint64_t fec_max_window_size; /* maximum number of block that current host can store */ - uint64_t fec_max_symbol_num_per_block; /* (B) maximum symbol number of each block */ + /** code rate represents the source symbol percents in total symbols */ + float fec_code_rate; + /** element bit size of current fec finite filed */ + xqc_int_t fec_ele_bit_size; + /** frame type that should be protected by fec */ + uint64_t fec_protected_frames; + /** maximum number of block that current host can store */ + uint64_t fec_max_window_size; + /** fec specific mp mode */ xqc_fec_mp_mode_e fec_mp_mode; - + /** (B) maximum symbol number of each block */ + uint64_t fec_max_symbol_num_per_block; + xqc_int_t fec_encoder_schemes_num; xqc_int_t fec_decoder_schemes_num; - xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; /* fec schemes supported by current host as encoder */ - xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; /* fec schemes supported by current host as decoder */ - - xqc_fec_schemes_e fec_encoder_scheme; /* final fec scheme as encoder after negotiation */ - xqc_fec_schemes_e fec_decoder_scheme; /* final fec scheme as decoder after negotiation */ + /** fec schemes supported by current host as encoder */ + xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + /** fec schemes supported by current host as decoder */ + xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + + /** final fec scheme as encoder after negotiation */ + xqc_fec_schemes_e fec_encoder_scheme; + /** final fec scheme as decoder after negotiation */ + xqc_fec_schemes_e fec_decoder_scheme; } xqc_fec_params_t; +/** + * @brief congestion control callbacks + */ typedef struct xqc_congestion_control_callback_s { - /* Callback on initialization, for memory allocation */ + /** Callback on initialization, for memory allocation */ size_t (*xqc_cong_ctl_size)(void); - /* Callback on connection initialization, support for passing in congestion algorithm parameters */ + /** Callback on connection initialization, support for passing in congestion algorithm parameters */ void (*xqc_cong_ctl_init)(void *cong_ctl, xqc_send_ctl_t *ctl_ctx, xqc_cc_params_t cc_params); - /* Callback when packet loss is detected, reduce congestion window according to algorithm */ + /** Callback when packet loss is detected, reduce congestion window according to algorithm */ void (*xqc_cong_ctl_on_lost)(void *cong_ctl, xqc_usec_t lost_sent_time); - /* Callback when packet acked, increase congestion window according to algorithm */ + /** Callback when packet acked, increase congestion window according to algorithm */ void (*xqc_cong_ctl_on_ack)(void *cong_ctl, xqc_packet_out_t *po, xqc_usec_t now); - /* Callback when sending a packet, to determine if the packet can be sent */ + /** Callback when sending a packet, to determine if the packet can be sent */ uint64_t (*xqc_cong_ctl_get_cwnd)(void *cong_ctl); - /* Callback when all packets are detected as lost within 1-RTT, reset the congestion window */ + /** Callback when all packets are detected as lost within 1-RTT, reset the congestion window */ void (*xqc_cong_ctl_reset_cwnd)(void *cong_ctl); - /* If the connection is in slow start state */ + /** If the connection is in slow start state */ int (*xqc_cong_ctl_in_slow_start)(void *cong_ctl); - /* If the connection is in recovery state. */ + /** If the connection is in recovery state. */ int (*xqc_cong_ctl_in_recovery)(void *cong_ctl); - /* This function is used by BBR and Cubic*/ + /** This function is used by BBR and Cubic*/ void (*xqc_cong_ctl_restart_from_idle)(void *cong_ctl, uint64_t arg); - /* For BBR */ + /** For BBR */ void (*xqc_cong_ctl_on_ack_multiple_pkts)(void *cong_ctl, xqc_sample_t *sampler); - /* initialize bbr */ + /** initialize bbr */ void (*xqc_cong_ctl_init_bbr)(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params); - /* get pacing rate */ + /** get pacing rate */ uint32_t (*xqc_cong_ctl_get_pacing_rate)(void *cong_ctl); - /* get estimation of bandwidth */ + /** get estimation of bandwidth */ uint32_t (*xqc_cong_ctl_get_bandwidth_estimate)(void *cong_ctl); xqc_bbr_info_interface_t *xqc_cong_ctl_info_cb; @@ -960,6 +999,9 @@ typedef enum xqc_scheduler_conn_event_e { XQC_SCHED_EVENT_CONN_ROUND_FIN = 1, } xqc_scheduler_conn_event_t; +/** + * @brief multipath scheduler callbacks + */ typedef struct xqc_scheduler_callback_s { size_t (*xqc_scheduler_size)(void); @@ -1029,43 +1071,43 @@ XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_packet_mask_code_ * QUIC config parameters */ typedef struct xqc_config_s { - /* log level */ + /** log level */ xqc_log_level_t cfg_log_level; - /* enable log based on event or not, non-zero for enable, 0 for not */ + /** enable log based on event or not, non-zero for enable, 0 for not */ xqc_flag_t cfg_log_event; - /* qlog evnet importance */ + /** qlog evnet importance */ qlog_event_importance_t cfg_qlog_importance; - /* print timestamp in log or not, non-zero for print, 0 for not */ + /** print timestamp in log or not, non-zero for print, 0 for not */ xqc_flag_t cfg_log_timestamp; - /* print level name in log or not, non-zero for print, 0 for not */ + /** print level name in log or not, non-zero for print, 0 for not */ xqc_flag_t cfg_log_level_name; - /* connection memory pool size, which will be used for congestion control */ + /** connection memory pool size, which will be used for congestion control */ size_t conn_pool_size; - /* bucket size of stream hash table in xqc_connection_t */ + /** bucket size of stream hash table in xqc_connection_t */ size_t streams_hash_bucket_size; - /* bucket size of connection hash table in engine */ + /** bucket size of connection hash table in engine */ size_t conns_hash_bucket_size; - /* capacity of connection priority queue in engine */ + /** capacity of connection priority queue in engine */ size_t conns_active_pq_capacity; - /* capacity of wakeup connection priority queue in engine */ + /** capacity of wakeup connection priority queue in engine */ size_t conns_wakeup_pq_capacity; - /* supported quic version list, actually draft-29 and quic-v1 is supported */ + /** supported quic version list, actually draft-29 and quic-v1 is supported */ uint32_t support_version_list[XQC_SUPPORT_VERSION_MAX]; - /* supported quic version count */ + /** supported quic version count */ uint32_t support_version_count; - /* default connection id length */ + /** default connection id length */ uint8_t cid_len; /** @@ -1077,7 +1119,7 @@ typedef struct xqc_config_s { */ uint8_t cid_negotiate; - /* used to generate stateless reset token */ + /** used to generate stateless reset token */ char reset_token_key[XQC_RESET_TOKEN_MAX_KEY_LEN]; size_t reset_token_keylen; @@ -1109,43 +1151,49 @@ typedef struct xqc_config_s { * @brief engine callback functions. */ typedef struct xqc_engine_callback_s { - /* timer callback for event loop */ + /** timer callback for event loop */ xqc_set_event_timer_pt set_event_timer; - /* write log file callback, REQUIRED */ + /** write log file callback, REQUIRED */ xqc_log_callbacks_t log_callbacks; - /* custom cid generator, OPTIONAL for server */ + /** custom cid generator, OPTIONAL for server */ xqc_cid_generate_pt cid_generate_cb; - /* tls secret callback, OPTIONAL */ + /** tls secret callback, OPTIONAL */ xqc_eng_keylog_pt keylog_cb; - /* get realtime timestamp callback function. if not set, xquic will get timestamp with inner + /** get realtime timestamp callback function. if not set, xquic will get timestamp with inner function xqc_now, which relies on gettimeofday */ xqc_timestamp_pt realtime_ts; - /* get monotonic increasing timestamp callback function. if not set, xquic will get timestamp + /** get monotonic increasing timestamp callback function. if not set, xquic will get timestamp with inner function xqc_now, which relies on gettimeofday */ xqc_timestamp_pt monotonic_ts; } xqc_engine_callback_t; - +/** + * @brief engine's ssl config + */ typedef struct xqc_engine_ssl_config_s { - char *private_key_file; /* For server */ - char *cert_file; /* For server */ + /** private key filefor server */ + char *private_key_file; + /** certificate file for server */ + char *cert_file; char *ciphers; char *groups; - uint32_t session_timeout; /* Session lifetime in second */ - char *session_ticket_key_data; /* For server */ - size_t session_ticket_key_len; /* For server */ + /** session lifetime in second */ + uint32_t session_timeout; + /** session ticket key for server */ + char *session_ticket_key_data; + /** session ticket key length for server */ + size_t session_ticket_key_len; } xqc_engine_ssl_config_t; - typedef enum { XQC_TLS_CERT_FLAG_NEED_VERIFY = 1 << 0, XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED = 1 << 1, @@ -1190,8 +1238,10 @@ typedef struct xqc_conn_ssl_config_s { } xqc_conn_ssl_config_t; typedef struct xqc_linger_s { - uint32_t linger_on; /* close connection after all data sent and acked, default: 0 */ - xqc_usec_t linger_timeout; /* 3*PTO if linger_timeout is 0 */ + /** close connection after all data sent and acked, default: 0 */ + uint32_t linger_on; + /** 3*PTO if linger_timeout is 0 */ + xqc_usec_t linger_timeout; } xqc_linger_t; typedef enum { @@ -1204,37 +1254,50 @@ typedef enum { XQC_FEC_02 = 0x02, } xqc_fec_version_t; + +/** + * @brief structures of connection settings + */ typedef struct xqc_conn_settings_s { - int pacing_on; /* default: 0 */ - int ping_on; /* client sends PING to keepalive, default:0 */ - xqc_cong_ctrl_callback_t cong_ctrl_callback; /* default: xqc_cubic_cb */ + /** default: 0 */ + int pacing_on; + /** client sends PING to keepalive, default:0 */ + int ping_on; + /** default: xqc_cubic_cb */ + xqc_cong_ctrl_callback_t cong_ctrl_callback; xqc_cc_params_t cc_params; - uint32_t so_sndbuf; /* socket option SO_SNDBUF, 0 for unlimited */ - uint64_t sndq_packets_used_max; /* - * default: XQC_SNDQ_PACKETS_USED_MAX. - * It should be set to buffer 2xBDP packets at least for performance consideration. - * The default value is 16000 pkts. - */ + /** socket option SO_SNDBUF, 0 for unlimited */ + uint32_t so_sndbuf; + /** + * default: XQC_SNDQ_PACKETS_USED_MAX. + * It should be set to buffer 2xBDP packets at least for performance consideration. + * The default value is 16000 pkts. + */ + uint64_t sndq_packets_used_max; xqc_linger_t linger; - xqc_proto_version_t proto_version; /* QUIC protocol version */ - xqc_msec_t init_idle_time_out; /* initial idle timeout interval, effective before handshake completion */ - xqc_msec_t idle_time_out; /* idle timeout interval, effective after handshake completion */ + /** QUIC protocol version */ + xqc_proto_version_t proto_version; + /** initial idle timeout interval, effective before handshake completion */ + xqc_msec_t init_idle_time_out; + /** idle timeout interval, effective after handshake completion */ + xqc_msec_t idle_time_out; int32_t spurious_loss_detect_on; - uint32_t anti_amplification_limit; /* limit of anti-amplification, default 3 */ - uint64_t keyupdate_pkt_threshold; /* packet limit of a single 1-rtt key, 0 for unlimited */ + /** limit of anti-amplification, default 5 */ + uint32_t anti_amplification_limit; + /** packet limit of a single 1-rtt key, 0 for unlimited */ + uint64_t keyupdate_pkt_threshold; size_t max_pkt_out_size; size_t probing_pkt_out_size; - /* - * datgram option - * 0: no support for datagram mode (default) - * >0: the max size of datagrams that the local end is willing to receive - * 65535: the local end is willing to receive a datagram with any length as - * long as it fits in a QUIC packet - */ + /** + * datgram option + * 0: no support for datagram mode (default) + * >0: the max size of datagrams that the local end is willing to receive + * 65535: the local end is willing to receive a datagram with any length as long as it fits in a QUIC packet + */ uint16_t max_datagram_frame_size; - /* + /** * multipath option: * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#section-3 * 0: don't support multipath @@ -1245,7 +1308,7 @@ typedef struct xqc_conn_settings_s { uint64_t init_max_path_id; uint64_t least_available_cid_count; - /* + /** * reinjection option: * 0: default, no reinjection * bit0 = 1: @@ -1256,7 +1319,7 @@ typedef struct xqc_conn_settings_s { * reinject unacked packets after sending packets. */ int mp_enable_reinjection; - /* + /** * deadline = max(low_bound, min(hard_deadline, srtt * srtt_factor)) * default values: * low_bound = 0 @@ -1267,7 +1330,7 @@ typedef struct xqc_conn_settings_s { uint64_t reinj_hard_deadline; uint64_t reinj_deadline_lower_bound; - /* + /** * By default, XQUIC returns ACK_MPs on the path where the data * is received unless the path is not avaliable anymore. * @@ -1276,46 +1339,46 @@ typedef struct xqc_conn_settings_s { */ uint8_t mp_ack_on_any_path; - /* + /** * When sending a ping packet for connection keep-alive, we replicate the * the packet on all acitve paths to keep all paths alive (disable:0, enable:1). * The default value is 0. */ uint8_t mp_ping_on; - /* scheduler callback, default: xqc_minrtt_scheduler_cb */ + /** scheduler callback, default: xqc_minrtt_scheduler_cb */ xqc_scheduler_callback_t scheduler_callback; xqc_scheduler_params_t scheduler_params; - /* reinj_ctl callback, default: xqc_default_reinj_ctl_cb */ + /** reinj_ctl callback, default: xqc_default_reinj_ctl_cb */ xqc_reinj_ctl_callback_t reinj_ctl_callback; - /* ms */ + /** ms */ xqc_msec_t standby_path_probe_timeout; - /* params for performance tuning */ - /* max ack delay: ms */ + /** params for performance tuning */ + /** max ack delay: ms */ uint32_t max_ack_delay; - /* generate an ACK if received ack-eliciting pkts >= ack_frequency */ + /** generate an ACK if received ack-eliciting pkts >= ack_frequency */ uint32_t ack_frequency; uint8_t adaptive_ack_frequency; uint64_t loss_detection_pkt_thresh; double pto_backoff_factor; - /* datagram redundancy: 0 disable, 1 enable, 2 only enable multipath redundancy */ + /** datagram redundancy: 0 disable, 1 enable, 2 only enable multipath redundancy */ uint8_t datagram_redundancy; uint8_t datagram_force_retrans_on; uint64_t datagram_redundant_probe; - /* enable PMTUD */ + /** enable PMTUD */ uint8_t enable_pmtud; - /* probing interval (us), default: 500000 */ + /** probing interval (us), default: 500000 */ uint64_t pmtud_probing_interval; - /* enable marking reinjected packets with reserved bits */ + /** enable marking reinjected packets with reserved bits */ uint8_t marking_reinjection; - /* + /** * The limitation on conn recv rate (only applied to stream data) in bytes per second. * NOTE: the minimal rate limitation is (63000/RTT) Bps. For instance, if RTT is 60ms, * the minimal valid rate limitation is about 1MBps. Any recv_rate_bytes_per_sec less @@ -1324,17 +1387,17 @@ typedef struct xqc_conn_settings_s { */ uint64_t recv_rate_bytes_per_sec; - /* + /** * The switch to enable stream-level recv rate throttling. Default: off (0) */ uint8_t enable_stream_rate_limit; - /* + /** * initial recv window. Default: 0 (use the internal default value) */ uint32_t init_recv_window; - /* + /** * initial flow control value */ xqc_bool_t is_interop_mode; @@ -1356,7 +1419,7 @@ typedef struct xqc_conn_settings_s { */ xqc_usec_t initial_pto_duration; - /* + /** * fec option: * 0: don't support fec * 1: supports fec @@ -1384,9 +1447,12 @@ typedef struct xqc_conn_settings_s { typedef enum { - XQC_0RTT_NONE, /* without 0-RTT */ - XQC_0RTT_ACCEPT, /* 0-RTT was accepted */ - XQC_0RTT_REJECT, /* 0-RTT was rejected */ + /** without 0-RTT */ + XQC_0RTT_NONE = 0, + /** 0-RTT was accepted */ + XQC_0RTT_ACCEPT = 1, + /** 0-RTT was rejected */ + XQC_0RTT_REJECT = 2, } xqc_0rtt_flag_t; @@ -1411,16 +1477,22 @@ typedef struct xqc_path_metrics_s { uint8_t path_app_status; } xqc_path_metrics_t; - +/** + * @brief connection stats + */ typedef struct xqc_conn_stats_s { uint32_t send_count; uint32_t lost_count; uint32_t tlp_count; uint32_t spurious_loss_count; - uint32_t lost_dgram_count; /* how many datagram frames (pkts) are lost */ - xqc_usec_t srtt; /* smoothed SRTT at present: initial value = 250000 */ - xqc_usec_t min_rtt; /* minimum RTT until now: initial value = 0xFFFFFFFF */ - uint64_t inflight_bytes; /* initial value = 0 */ + /** how many datagram frames (pkts) are lost */ + uint32_t lost_dgram_count; + /** smoothed SRTT at present: initial value = 250000 */ + xqc_usec_t srtt; + /** minimum RTT until now: initial value = 0xFFFFFFFF */ + xqc_usec_t min_rtt; + /** initial value = 0 */ + uint64_t inflight_bytes; xqc_0rtt_flag_t early_data_flag; uint32_t recv_count; int spurious_loss_detect_on; @@ -1454,15 +1526,18 @@ typedef struct xqc_conn_stats_s { uint32_t send_fec_cnt; uint8_t enable_fec; - /* only accounts for stream and datagram packets */ + /** only accounts for stream and datagram packets */ uint64_t total_app_bytes; uint64_t standby_path_app_bytes; } xqc_conn_stats_t; typedef struct xqc_conn_qos_stats_s { - xqc_usec_t srtt; /* smoothed SRTT at present: initial value = 250000 */ - xqc_usec_t min_rtt; /* minimum RTT until now: initial value = 0xFFFFFFFF */ - uint64_t inflight_bytes; /* initial value = 0 */ + /** smoothed SRTT at present: initial value = 250000 */ + xqc_usec_t srtt; + /** minimum RTT until now: initial value = 0xFFFFFFFF */ + xqc_usec_t min_rtt; + /** initial value = 0 */ + uint64_t inflight_bytes; } xqc_conn_qos_stats_t; /************************************************************* @@ -1489,7 +1564,7 @@ xqc_engine_t *xqc_engine_create(xqc_engine_type_t engine_type, /** - * @brief destroy engine. this is called after all connections are destroyed + * @brief destroy engine. this is called after all connections are destroyed \n * NOTICE: MUST NOT be called in any xquic callback functions, for this function will destroy engine * immediately, result in segmentation fault. */ @@ -1650,11 +1725,11 @@ xqc_connection_t *xqc_engine_get_conn_by_scid(xqc_engine_t *engine, * @param token token receive from server, xqc_save_token_pt callback * @param token_len * @param server_host server domain - * @param no_crypto_flag 1: without encryption on 0-RTT and 1-RTT packets. this flag will add - * no_crypto transport parameter when initiating a connection, which is not an official parameter + * @param no_crypto_flag 1: stop encrypt 0-RTT and 1-RTT packets. \n + * This flag will add no_crypto transport parameter when initiating a connection, which is not an official parameter * and might be modified or removed * @param conn_ssl_config For handshake - * @param user_data For connection + * @param user_data application data, for connection usage * @param peer_addr address of peer * @param peer_addrlen length of peer_addr * @param alpn Application-Layer-Protocol, MUST NOT be NULL @@ -1750,7 +1825,7 @@ XQC_EXPORT_PUBLIC_API xqc_bool_t xqc_conn_is_ready_to_send_early_data(xqc_connection_t *conn); /** - * @brief set the packet filter callback function, and replace write_socket. + * @brief set the packet filter callback function, and replace write_socket. \n * NOTICE: this function is not conflict with send_mmsg. */ XQC_EXPORT_PUBLIC_API @@ -1794,7 +1869,7 @@ void xqc_conn_set_public_remote_trans_settings(xqc_connection_t *conn, /** - * Create new stream in quic connection. + * @brief Create new stream in quic connection. * @param user_data user_data for this stream */ XQC_EXPORT_PUBLIC_API @@ -1864,12 +1939,12 @@ ssize_t xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t s /** * @brief the API to get the max length of the data that can be sent - * via a single call of xqc_datagram_send; NOTE, if the DCID length could - * be changed during the lifetime of the connection, applications is - * suggested to call xqc_datagram_get_mss every time before - * send datagram data or when getting -XQC_EDGRAM_TOO_LARGE error - * from sending datagram data. In MPQUIC cases, the DCID of all paths - * MUST be the same. Otherwise, there might be unexpected errors. + * via a single call of xqc_datagram_send; + * + * NOTE: if the DCID length could be changed during the lifetime of the connection, applications is + * suggested to call xqc_datagram_get_mss every time before send datagram data or when + * getting -XQC_EDGRAM_TOO_LARGE error from sending datagram data. In MPQUIC cases, + * the DCID of all paths MUST be the same. Otherwise, there might be unexpected errors. * * @param conn the connection handle * @return 0 = the peer does not support datagram, >0 = the max length diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index 31388025..0d998fe7 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -111,41 +111,46 @@ typedef uint8_t xqc_bool_t; #define XQC_TRUE 1 #define XQC_FALSE 0 -/* restrictions of cid length */ +/** restrictions of cid length */ #define XQC_MAX_CID_LEN 20 #define XQC_MIN_CID_LEN 4 -/* restrictions of key length in lb cid encryption */ +/** restrictions of key length in lb cid encryption */ #define XQC_LB_CID_KEY_LEN 16 -/* length of stateless reset token */ +/** length of stateless reset token */ #define XQC_STATELESS_RESET_TOKENLEN 16 +/** + * @brief cid structure for xquic connection identification + */ typedef struct xqc_cid_s { uint8_t cid_len; uint8_t cid_buf[XQC_MAX_CID_LEN]; uint64_t cid_seq_num; uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; - uint64_t path_id; /* preallocate for multi-path */ + uint64_t path_id; /**< preallocate for multi-path */ } xqc_cid_t; typedef enum xqc_log_level_s { - XQC_LOG_REPORT, - XQC_LOG_FATAL, - XQC_LOG_ERROR, - XQC_LOG_WARN, - XQC_LOG_STATS, - XQC_LOG_INFO, - XQC_LOG_DEBUG, + XQC_LOG_REPORT = 0, + XQC_LOG_FATAL = 1, + XQC_LOG_ERROR = 2, + XQC_LOG_WARN = 3, + XQC_LOG_STATS = 4, + XQC_LOG_INFO = 5, + XQC_LOG_DEBUG = 6, } xqc_log_level_t; -/* qlog Importance level definition */ +/** + * @brief qlog Importance level definition + */ typedef enum qlog_event_importance_s { - EVENT_IMPORTANCE_SELECTED, /* qlog will be emitted selectly */ - EVENT_IMPORTANCE_CORE, - EVENT_IMPORTANCE_BASE, - EVENT_IMPORTANCE_EXTRA, - EVENT_IMPORTANCE_REMOVED, /* Currently, some events have been removed in the latest qlog draft. But old qvis need them! */ + EVENT_IMPORTANCE_SELECTED = 0, /**< qlog will be emitted selectly */ + EVENT_IMPORTANCE_CORE = 1, + EVENT_IMPORTANCE_BASE = 2, + EVENT_IMPORTANCE_EXTRA = 3, + EVENT_IMPORTANCE_REMOVED = 4, /**< Currently, some events have been removed in the latest qlog draft. But old qvis need them! */ } qlog_event_importance_t; #define XQC_BBR_RTTVAR_COMPENSATION_ENABLED 0 @@ -183,22 +188,22 @@ struct iovec { typedef enum { - XQC_CONN_TYPE_CLIENT, - XQC_CONN_TYPE_SERVER, + XQC_CONN_TYPE_CLIENT = 0, + XQC_CONN_TYPE_SERVER = 1, } xqc_conn_type_t; typedef enum { - XQC_STREAM_BIDI, - XQC_STREAM_UNI + XQC_STREAM_BIDI = 0, + XQC_STREAM_UNI = 1 } xqc_stream_direction_t; typedef enum { - XQC_DEFAULT_SIZE_REQ, - XQC_SLIM_SIZE_REQ, - XQC_NORMAL_SIZE_REQ, - XQC_MIDDLE_SIZE_REQ, - XQC_LARGE_SIZE_REQ + XQC_DEFAULT_SIZE_REQ = 0, + XQC_SLIM_SIZE_REQ = 1, + XQC_NORMAL_SIZE_REQ = 2, + XQC_MIDDLE_SIZE_REQ = 3, + XQC_LARGE_SIZE_REQ = 4 } xqc_stream_size_type_t; #define XQC_DEFAULT_HTTP_PRIORITY_URGENCY 3 @@ -224,8 +229,8 @@ typedef struct xqc_http_priority_s { #define XQC_UNKNOWN_PATH_ID ((uint64_t)-1) typedef enum xqc_conn_settings_type_e { - XQC_CONN_SETTINGS_DEFAULT, - XQC_CONN_SETTINGS_LOW_DELAY, + XQC_CONN_SETTINGS_DEFAULT = 0, + XQC_CONN_SETTINGS_LOW_DELAY = 1, } xqc_conn_settings_type_t; typedef struct xqc_conn_public_local_trans_settings_s { @@ -301,7 +306,7 @@ typedef enum xqc_conn_option_e { /* application layer path status */ typedef enum { /* max */ - XQC_APP_PATH_STATUS_NONE, + XQC_APP_PATH_STATUS_NONE = 0, /* suggest that no traffic should be sent on that path if another path is available */ XQC_APP_PATH_STATUS_STANDBY = 1, /* allow the peer to use its own logic to split traffic among available paths */ diff --git a/mini/CMakeLists.txt b/mini/CMakeLists.txt new file mode 100644 index 00000000..5d6490f5 --- /dev/null +++ b/mini/CMakeLists.txt @@ -0,0 +1,57 @@ +### hq mini client/server ### +set( + HQ_SOURCES + "../demo/xqc_hq_ctx.c" + "../demo/xqc_hq_conn.c" + "../demo/xqc_hq_request.c" +) + +set( + TEST_PLATFORM_SOURCES + "../tests/platform.c" +) + +set( + MINI_CLIENT_SOURCES + ${HQ_SOURCES} + ${TEST_PLATFORM_SOURCES} + "common.c" + "mini_client.c" + "mini_client_cb.c" +) + +set( + MINI_SERVER_SOURCES + ${HQ_SOURCES} + ${TEST_PLATFORM_SOURCES} + "common.c" + "mini_server.c" + "mini_server_cb.c" +) + + +if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(MINI_SERVER_SOURCES + ${MINI_SERVER_SOURCES} + ${GETOPT_SOURCES} + ) + + set(MINI_CLIENT_SOURCES + ${MINI_CLIENT_SOURCES} + ${GETOPT_SOURCES} + ) +endif() + +include_directories( + "${CMAKE_SOURCE_DIR}/" + "${CMAKE_SOURCE_DIR}/include" + ${CMAKE_SOURCE_DIR} + ${CUNIT_INCLUDE_DIRS} + ${LIBEVENT_INCLUDE_DIR} +) + +add_executable(mini_server ${MINI_SERVER_SOURCES}) +add_executable(mini_client ${MINI_CLIENT_SOURCES}) + +target_link_libraries(mini_server ${APP_DEPEND_LIBS}) +target_link_libraries(mini_client ${APP_DEPEND_LIBS}) diff --git a/mini/common.c b/mini/common.c new file mode 100644 index 00000000..91dcc3bd --- /dev/null +++ b/mini/common.c @@ -0,0 +1,39 @@ +#include "common.h" + +char method_s[][16] = { + {"GET"}, + {"POST"} +}; +int +xqc_mini_read_file_data(char * data, size_t data_len, char *filename) +{ + int ret = 0; + size_t total_len, read_len; + FILE *fp = fopen(filename, "rb"); + if (fp == NULL) { + ret = -1; + goto end; + } + + fseek(fp, 0 , SEEK_END); + total_len = ftell(fp); + fseek(fp, 0, SEEK_SET); + if (total_len > data_len) { + ret = -1; + goto end; + } + + read_len = fread(data, 1, total_len, fp); + if (read_len != total_len) { + ret = -1; + goto end; + } + + ret = read_len; + +end: + if (fp) { + fclose(fp); + } + return ret; +} diff --git a/mini/common.h b/mini/common.h new file mode 100644 index 00000000..ce13c89a --- /dev/null +++ b/mini/common.h @@ -0,0 +1,71 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + + +#include +#include +#include + +/* definition for connection */ +#define DEFAULT_SERVER_ADDR "127.0.0.1" +#define DEFAULT_SERVER_PORT 8443 + +#define CIPHER_SUIT_LEN 256 +#define TLS_GROUPS_LEN 64 + +#define PATH_LEN 1024 +#define RESOURCE_LEN 1024 +#define AUTHORITY_LEN 128 +#define URL_LEN 1024 + +/* the congestion control types */ +typedef enum cc_type_s { + CC_TYPE_BBR, + CC_TYPE_CUBIC, + CC_TYPE_RENO, + CC_TYPE_COPA +} CC_TYPE; + + + +/* request method */ +typedef enum request_method_e { + REQUEST_METHOD_GET, + REQUEST_METHOD_POST, +} REQUEST_METHOD; + +extern char method_s[][16]; + + +static size_t READ_FILE_BUF_LEN = 2 *1024 * 1024; + +#define DEBUG ; +// #define DEBUG printf("%s:%d (%s)\n",__FILE__, __LINE__ ,__FUNCTION__); + + +#define RSP_HDR_BUF_LEN 32 +typedef enum h3_hdr_type { + /* rsp */ + H3_HDR_STATUS, + H3_HDR_CONTENT_TYPE, + H3_HDR_CONTENT_LENGTH, + H3_HDR_METHOD, + H3_HDR_SCHEME, + H3_HDR_HOST, + H3_HDR_PATH, + + H3_HDR_CNT +} H3_HDR_TYPE; + + +extern long xqc_random(void); +extern xqc_usec_t xqc_now(); + + +int xqc_mini_read_file_data(char * data, size_t data_len, char *filename); + +#endif diff --git a/mini/mini_client.c b/mini/mini_client.c new file mode 100644 index 00000000..4e1d716e --- /dev/null +++ b/mini/mini_client.c @@ -0,0 +1,745 @@ +#include "mini_client.h" + +#include + +void +xqc_mini_cli_init_engine_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_cli_args_t *args) +{ + ssl_cfg->ciphers = args->quic_cfg.ciphers; + ssl_cfg->groups = args->quic_cfg.groups; +} + + +void +xqc_mini_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, xqc_mini_cli_args_t *args) +{ + static xqc_engine_callback_t callback = { + .set_event_timer = xqc_mini_cli_set_event_timer, + .log_callbacks = { + .xqc_log_write_err = xqc_mini_cli_write_log_file, + .xqc_log_write_stat = xqc_mini_cli_write_log_file, + .xqc_qlog_event_write = xqc_mini_cli_write_qlog_file + }, + .keylog_cb = xqc_mini_cli_keylog_cb, + }; + + static xqc_transport_callbacks_t transport_cbs = { + .write_socket = xqc_mini_cli_write_socket, + .write_socket_ex = xqc_mini_cli_write_socket_ex, + .save_token = xqc_mini_cli_save_token, + .save_session_cb = xqc_mini_cli_save_session_cb, + .save_tp_cb = xqc_mini_cli_save_tp_cb, + }; + + *cb = callback; + *tcb = transport_cbs; +} + +int +xqc_mini_cli_init_xquic_engine(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + int ret; + xqc_config_t egn_cfg; + xqc_engine_callback_t callback; + xqc_engine_ssl_config_t ssl_cfg = {0}; + xqc_transport_callbacks_t transport_cbs; + + /* get default parameters of xquic engine */ + ret = xqc_engine_get_default_config(&egn_cfg, XQC_ENGINE_CLIENT); + if (ret < 0) { + return XQC_ERROR; + } + + /* init ssl config */ + xqc_mini_cli_init_engine_ssl_config(&ssl_cfg, args); + + /* init engine & transport callbacks */ + xqc_mini_cli_init_callback(&callback, &transport_cbs, args); + + /* create client engine */ + ctx->engine = xqc_engine_create(XQC_ENGINE_CLIENT, &egn_cfg, &ssl_cfg, + &callback, &transport_cbs, ctx); + if (ctx->engine == NULL) { + printf("[error] xqc_engine_create error\n"); + return XQC_ERROR; + } + + ctx->ev_engine = event_new(ctx->eb, -1, 0, xqc_mini_cli_engine_cb, ctx); + return XQC_OK; +} + +void +xqc_mini_cli_convert_text_to_sockaddr(int type, + const char *addr_text, unsigned int port, + struct sockaddr **saddr, socklen_t *saddr_len) +{ + *saddr = calloc(1, sizeof(struct sockaddr_in)); + struct sockaddr_in *addr_v4 = (struct sockaddr_in *)(*saddr); + inet_pton(type, addr_text, &(addr_v4->sin_addr.s_addr)); + addr_v4->sin_family = type; + addr_v4->sin_port = htons(port); + *saddr_len = sizeof(struct sockaddr_in); +} + +void +xqc_mini_cli_init_args(xqc_mini_cli_args_t *args) +{ + /* init network args */ + args->net_cfg.conn_timeout = 9; + + /** + * init quic config + * it's recommended to replace the constant value with option arguments according to actual needs + */ + strncpy(args->quic_cfg.ciphers, XQC_TLS_CIPHERS, CIPHER_SUIT_LEN - 1); + strncpy(args->quic_cfg.groups, XQC_TLS_GROUPS, TLS_GROUPS_LEN - 1); + args->quic_cfg.multipath = 0; + + + /* init environmen args */ + // args->env_cfg.log_level = XQC_LOG_DEBUG; + strncpy(args->env_cfg.log_path, LOG_PATH, sizeof(args->env_cfg.log_path)); + strncpy(args->env_cfg.out_file_dir, OUT_DIR, sizeof(args->env_cfg.out_file_dir)); + strncpy(args->env_cfg.key_out_path, KEY_PATH, sizeof(args->env_cfg.key_out_path)); + + /* init request args */ + args->req_cfg.method = REQUEST_METHOD_GET; // GET + strncpy(args->req_cfg.scheme, "https", sizeof(args->req_cfg.scheme)); + strncpy(args->req_cfg.url, "/", sizeof(args->req_cfg.url)); + strncpy(args->req_cfg.host, DEFAULT_HOST, sizeof(args->req_cfg.host)); +} + +int +xqc_mini_cli_init_ctx(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + memset(ctx, 0, sizeof(xqc_mini_cli_ctx_t)); + + /* init event base */ + struct event_base *eb = event_base_new(); + ctx->eb = eb; + + ctx->args = args; + + /* init log writer fd */ + ctx->log_fd = xqc_mini_cli_open_log_file(ctx); + if (ctx->log_fd < 0) { + printf("[error] open log file failed\n"); + return XQC_ERROR; + } + /* init keylog writer fd */ + ctx->keylog_fd = xqc_mini_cli_open_keylog_file(ctx); + if (ctx->keylog_fd < 0) { + printf("[error] open keylog file failed\n"); + return XQC_ERROR; + } + + return 0; +} + + +int +xqc_mini_cli_init_env(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args) +{ + int ret = XQC_OK; + + /* init client args */ + xqc_mini_cli_init_args(args); + + /* init client ctx */ + ret = xqc_mini_cli_init_ctx(ctx, args); + + return ret; +} + +xqc_scheduler_callback_t +xqc_mini_cli_get_sched_cb(xqc_mini_cli_args_t *args) +{ + xqc_scheduler_callback_t sched = xqc_minrtt_scheduler_cb; + if (strncmp(args->quic_cfg.mp_sched, "minrtt", strlen("minrtt")) == 0) { + sched = xqc_minrtt_scheduler_cb; + + } if (strncmp(args->quic_cfg.mp_sched, "backup", strlen("backup")) == 0) { + sched = xqc_backup_scheduler_cb; + } + return sched; +} + +xqc_cong_ctrl_callback_t +xqc_mini_cli_get_cc_cb(xqc_mini_cli_args_t *args) +{ + xqc_cong_ctrl_callback_t ccc = xqc_bbr_cb; + switch (args->quic_cfg.cc) { + case CC_TYPE_BBR: + ccc = xqc_bbr_cb; + break; + case CC_TYPE_CUBIC: + ccc = xqc_cubic_cb; + break; + default: + break; + } + return ccc; +} + +void +xqc_mini_cli_init_conn_settings(xqc_conn_settings_t *settings, xqc_mini_cli_args_t *args) +{ + /* parse congestion control callback */ + xqc_cong_ctrl_callback_t ccc = xqc_mini_cli_get_cc_cb(args); + /* parse mp scheduler callback */ + xqc_scheduler_callback_t sched = xqc_mini_cli_get_sched_cb(args); + + /* init connection settings */ + memset(settings, 0, sizeof(xqc_conn_settings_t)); + settings->cong_ctrl_callback = ccc; + settings->cc_params.customize_on = 1; + settings->cc_params.init_cwnd = 96; + settings->so_sndbuf = 1024*1024; + settings->proto_version = XQC_VERSION_V1; + settings->spurious_loss_detect_on = 1; + settings->scheduler_callback = sched; + settings->reinj_ctl_callback = xqc_deadline_reinj_ctl_cb; + settings->adaptive_ack_frequency = 1; +} + +int +xqc_mini_cli_init_alpn_ctx(xqc_mini_cli_ctx_t *ctx) +{ + int ret = XQC_OK; + + /* init http3 callbacks */ + xqc_h3_callbacks_t h3_cbs = { + .h3c_cbs = { + .h3_conn_create_notify = xqc_mini_cli_h3_conn_create_notify, + .h3_conn_close_notify = xqc_mini_cli_h3_conn_close_notify, + .h3_conn_handshake_finished = xqc_mini_cli_h3_conn_handshake_finished, + }, + .h3r_cbs = { + .h3_request_create_notify = xqc_mini_cli_h3_request_create_notify, + .h3_request_close_notify = xqc_mini_cli_h3_request_close_notify, + .h3_request_read_notify = xqc_mini_cli_h3_request_read_notify, + .h3_request_write_notify = xqc_mini_cli_h3_request_write_notify, + } + }; + + /* init http3 context */ + ret = xqc_h3_ctx_init(ctx->engine, &h3_cbs); + if (ret != XQC_OK) { + printf("init h3 context error, ret: %d\n", ret); + return ret; + } + + return ret; +} + +int +xqc_mini_cli_init_engine_ctx(xqc_mini_cli_ctx_t *ctx) +{ + int ret; + + /* init alpn ctx */ + ret = xqc_mini_cli_init_alpn_ctx(ctx); + + return ret; +} + +void +xqc_mini_cli_free_ctx(xqc_mini_cli_ctx_t *ctx) +{ + xqc_mini_cli_close_keylog_file(ctx); + xqc_mini_cli_close_log_file(ctx); + + if (ctx->args) { + free(ctx->args); + ctx->args = NULL; + } +} + +void +xqc_mini_cli_init_0rtt(xqc_mini_cli_args_t *args) +{ + /* read session ticket */ + int ret = xqc_mini_read_file_data(args->quic_cfg.session_ticket, + SESSION_TICKET_BUF_MAX_SIZE, SESSION_TICKET_FILE); + args->quic_cfg.session_ticket_len = ret > 0 ? ret : 0; + + /* read transport params */ + ret = xqc_mini_read_file_data(args->quic_cfg.transport_parameter, + TRANSPORT_PARAMS_MAX_SIZE, TRANSPORT_PARAMS_FILE); + args->quic_cfg.transport_parameter_len = ret > 0 ? ret : 0; + + /* read token */ + ret = xqc_mini_cli_read_token( + args->quic_cfg.token, TOKEN_MAX_SIZE); + args->quic_cfg.token_len = ret > 0 ? ret : 0; +} + +void +xqc_mini_cli_init_conn_ssl_config(xqc_conn_ssl_config_t *conn_ssl_config, xqc_mini_cli_args_t *args) +{ + /* set session ticket and transport parameter args */ + if (args->quic_cfg.session_ticket_len < 0 || args->quic_cfg.transport_parameter_len < 0) { + conn_ssl_config->session_ticket_data = NULL; + conn_ssl_config->transport_parameter_data = NULL; + + } else { + conn_ssl_config->session_ticket_data = args->quic_cfg.session_ticket; + conn_ssl_config->session_ticket_len = args->quic_cfg.session_ticket_len; + conn_ssl_config->transport_parameter_data = args->quic_cfg.transport_parameter; + conn_ssl_config->transport_parameter_data_len = args->quic_cfg.transport_parameter_len; + } +} + +int +xqc_mini_cli_format_h3_req(xqc_http_header_t *headers, xqc_mini_cli_req_config_t* req_cfg) +{ + /* response header buf list */ + xqc_http_header_t req_hdr[] = { + { + .name = {.iov_base = ":method", .iov_len = 7}, + .value = {.iov_base = method_s[req_cfg->method], .iov_len = strlen(method_s[req_cfg->method])}, + .flags = 0, + }, + { + .name = {.iov_base = ":scheme", .iov_len = 7}, + .value = {.iov_base = req_cfg->scheme, .iov_len = strlen(req_cfg->scheme)}, + .flags = 0, + }, + { + .name = {.iov_base = "host", .iov_len = 4}, + .value = {.iov_base = req_cfg->host, .iov_len = strlen(req_cfg->host)}, + .flags = 0, + }, + { + .name = {.iov_base = ":path", .iov_len = 5}, + .value = {.iov_base = req_cfg->url, .iov_len = strlen(req_cfg->path)}, + .flags = 0, + }, + { + .name = {.iov_base = "content-type", .iov_len = 12}, + .value = {.iov_base = "text/plain", .iov_len = 10}, + .flags = 0, + }, + { + .name = {.iov_base = "content-length", .iov_len = 14}, + .value = {.iov_base = 0, .iov_len = 0}, + .flags = 0, + }, + }; + + size_t req_sz = sizeof(req_hdr) / sizeof(req_hdr[0]); + if (req_sz > H3_HDR_CNT) { + printf("[error] header length is too large, request_size: %zd\n", req_sz); + return XQC_ERROR; + } + + for (size_t i = 0; i < req_sz; i++) { + headers[i] = req_hdr[i]; + } + return req_sz; +} + +int +xqc_mini_cli_request_send(xqc_h3_request_t *h3_request, xqc_mini_cli_user_stream_t *user_stream) +{ + int ret, fin; + /* send packet header/body */ + xqc_http_header_t header[H3_HDR_CNT]; + xqc_mini_cli_req_config_t* req_cfg; + + req_cfg = &user_stream->user_conn->ctx->args->req_cfg; + + fin = 1; + ret = xqc_mini_cli_format_h3_req(header, req_cfg); + if (ret > 0) { + user_stream->h3_hdrs.headers = header; + user_stream->h3_hdrs.count = ret; + + if (user_stream->start_time == 0) { + user_stream->start_time = xqc_now(); + } + /* send header */ + ret = xqc_h3_request_send_headers(user_stream->h3_request, &user_stream->h3_hdrs, fin); + if (ret < 0) { + printf("[error] xqc_mini_cli_h3_request_send error %d\n", ret); + } else { + printf("[stats] xqc_mini_cli_h3_request_send success \n"); + user_stream->hdr_sent = 1; + } + } + + if (req_cfg->method == REQUEST_METHOD_GET) { + return XQC_OK; + } + + return XQC_OK; +} + +int +xqc_mini_cli_send_h3_req(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_user_stream_t *user_stream) +{ + user_stream->user_conn = user_conn; + + xqc_stream_settings_t settings = { .recv_rate_bytes_per_sec = 0 }; + user_stream->h3_request = xqc_h3_request_create(user_conn->ctx->engine, &user_conn->cid, + &settings, user_stream); + if (user_stream->h3_request == NULL) { + printf("[error] xqc_h3_request_create error\n"); + return XQC_ERROR; + } + + xqc_mini_cli_request_send(user_stream->h3_request, user_stream); + + /* generate engine main log to send packets */ + xqc_engine_main_logic(user_conn->ctx->engine); + return XQC_OK; +} + + +int +xqc_mini_cli_init_socket(xqc_mini_cli_user_conn_t *user_conn) +{ + int fd, size; + xqc_mini_cli_ctx_t *ctx = user_conn->ctx; + xqc_mini_cli_net_config_t* cfg = &ctx->args->net_cfg; + struct sockaddr *addr = user_conn->local_addr; + + fd = socket(addr->sa_family, SOCK_DGRAM, 0); + if (fd < 0) { + printf("[error] create socket failed, errno: %d\n", get_sys_errno()); + return XQC_ERROR; + } + +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + printf("[error] set socket nonblock failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + size = 1 * 1024 * 1024; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { + printf("[error] setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { + printf("[error] setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + +#if !defined(__APPLE__) + int val = IP_PMTUDISC_DO; + setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); +#endif + +#if !defined(__APPLE__) + if (connect(fd, (struct sockaddr *)user_conn->peer_addr, user_conn->peer_addrlen) < 0) { + printf("[error] connect socket failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + ctx->args->net_cfg.last_socket_time = xqc_now(); + printf("[stats] init socket succesfully \n"); + + user_conn->fd = fd; + + return XQC_OK; +err: + close(fd); + return XQC_ERROR; +} + +void +xqc_mini_cli_socket_write_handler(xqc_mini_cli_user_conn_t *user_conn, int fd) +{ + DEBUG + printf("[stats] socket write handler\n"); +} + +void +xqc_mini_cli_socket_read_handler(xqc_mini_cli_user_conn_t *user_conn, int fd) +{ + DEBUG + ssize_t recv_size, recv_sum; + uint64_t recv_time; + xqc_int_t ret; + unsigned char packet_buf[XQC_PACKET_BUF_LEN]; + xqc_mini_cli_ctx_t *ctx; + + recv_size = recv_sum = 0; + ctx = user_conn->ctx; + + do { + /* recv quic packet from server */ + recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, + user_conn->peer_addr, &user_conn->peer_addrlen); + if (recv_size < 0 && get_sys_errno() == EAGAIN) { + break; + } + + if (recv_size < 0) { + printf("recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); + break; + } + + if (user_conn->get_local_addr == 0) { + user_conn->get_local_addr = 1; + user_conn->local_addrlen = sizeof(struct sockaddr_in6); + ret = getsockname(user_conn->fd, (struct sockaddr*)user_conn->local_addr, + &user_conn->local_addrlen); + if (ret != 0) { + printf("getsockname error, errno: %d\n", get_sys_errno()); + user_conn->local_addrlen = 0; + break; + } + } + + recv_sum += recv_size; + recv_time = xqc_now(); + ctx->args->net_cfg.last_socket_time = recv_time; + + /* process quic packet with xquic engine */ + ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, + user_conn->local_addr, user_conn->local_addrlen, + user_conn->peer_addr, user_conn->peer_addrlen, + (xqc_usec_t)recv_time, user_conn); + if (ret != XQC_OK) { + printf("[error] client_read_handler: packet process err, ret: %d\n", ret); + return; + } + } while (recv_size > 0); + +finish_recv: + // printf("[stats] xqc_mini_cli_socket_read_handler, recv size:%zu\n", recv_sum); + xqc_engine_finish_recv(ctx->engine); +} + +static void +xqc_mini_cli_socket_event_callback(int fd, short what, void *arg) +{ + //DEBUG; + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)arg; + + if (what & EV_WRITE) { + xqc_mini_cli_socket_write_handler(user_conn, fd); + + } else if (what & EV_READ) { + xqc_mini_cli_socket_read_handler(user_conn, fd); + + } else { + printf("event callback: fd=%d, what=%d\n", fd, what); + exit(1); + } +} +int +xqc_mini_cli_init_xquic_connection(xqc_mini_cli_user_conn_t *user_conn) +{ + xqc_conn_ssl_config_t conn_ssl_config = {0}; + xqc_conn_settings_t conn_settings = {0}; + xqc_mini_cli_ctx_t *ctx; + xqc_mini_cli_args_t *args; + + ctx = user_conn->ctx; + args = ctx->args; + + /* load 0-rtt args */ + xqc_mini_cli_init_0rtt(ctx->args); + + /* init connection settings */ + xqc_mini_cli_init_conn_settings(&conn_settings, ctx->args); + + /* init connection ssl config */ + xqc_mini_cli_init_conn_ssl_config(&conn_ssl_config, ctx->args); + + /* build connection */ + const xqc_cid_t *cid = xqc_h3_connect(ctx->engine, &conn_settings, args->quic_cfg.token, + args->quic_cfg.token_len, args->req_cfg.host, args->quic_cfg.no_encryption, &conn_ssl_config, + user_conn->peer_addr, user_conn->peer_addrlen, user_conn); + if (cid == NULL) { + return XQC_ERROR; + } + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); + printf("[stats] init xquic connection success \n"); + + return XQC_OK; +} +void +xqc_mini_cli_on_socket_created(xqc_mini_cli_user_conn_t *user_conn) +{ + xqc_mini_cli_ctx_t *ctx; + + ctx = user_conn->ctx; + + /* init callback function for READ/PERSIST EVENT */ + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_cli_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); +} +int +xqc_mini_cli_main_process(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_ctx_t *ctx) +{ + int ret; + xqc_mini_cli_args_t *args; + + user_conn->ctx = ctx; + args = ctx->args; + + ret = xqc_mini_cli_init_xquic_connection(user_conn); + if (ret < 0) { + printf("[error] mini socket init xquic connection failed\n"); + return XQC_ERROR; + } + + xqc_mini_cli_user_stream_t *user_stream = calloc(1, sizeof(xqc_mini_cli_user_stream_t)); + ret = xqc_mini_cli_send_h3_req(user_conn, user_stream); + if (ret < 0) { + return XQC_ERROR; + } + + return XQC_OK; +} + +void +xqc_mini_cli_init_local_addr(struct sockaddr *local_addr) +{ + char s_port[16] = "8443"; + struct addrinfo hints = {0}; + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + /* resolve server's ip from hostname */ + struct addrinfo *result = NULL; + int rv = getaddrinfo(DEFAULT_IP, s_port, &hints, &result); + if (rv != 0) { + printf("get addr info from hostname: %s\n", gai_strerror(rv)); + } + memcpy(local_addr, result->ai_addr, result->ai_addrlen); +} + +xqc_mini_cli_user_conn_t * +xqc_mini_cli_user_conn_create(xqc_mini_cli_ctx_t *ctx) +{ + int ret; + xqc_mini_cli_user_conn_t *user_conn = calloc(1, sizeof(xqc_mini_cli_user_conn_t)); + + user_conn->ctx = ctx; + + /* set connection timeout */ + struct timeval tv; + tv.tv_sec = ctx->args->net_cfg.conn_timeout; + tv.tv_usec = 0; + user_conn->ev_timeout = event_new(ctx->eb, -1, 0, xqc_mini_cli_timeout_callback, user_conn); + event_add(user_conn->ev_timeout, &tv); + + user_conn->local_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); + xqc_mini_cli_init_local_addr(user_conn->local_addr); + user_conn->local_addrlen = sizeof(struct sockaddr_in); + + xqc_mini_cli_convert_text_to_sockaddr(AF_INET, DEFAULT_IP, DEFAULT_PORT, + &(user_conn->peer_addr), &(user_conn->peer_addrlen)); + + /* init socket fd */ + ret = xqc_mini_cli_init_socket(user_conn); + if (ret < 0) { + printf("[error] mini socket init socket failed\n"); + return NULL; + } + + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_cli_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); + + return user_conn; +} + +void +xqc_mini_cli_free_user_conn(xqc_mini_cli_user_conn_t *user_conn) +{ + free(user_conn->peer_addr); + free(user_conn->local_addr); + free(user_conn); +} + +void +xqc_mini_cli_on_connection_finish(xqc_mini_cli_user_conn_t *user_conn) +{ + if (user_conn->ev_timeout) { + event_del(user_conn->ev_timeout); + user_conn->ev_timeout = NULL; + } + + if (user_conn->ev_socket) { + event_del(user_conn->ev_socket); + user_conn->ev_timeout = NULL; + } + + close(user_conn->fd); +} + +int main(int argc, char *argv[]) +{ + int ret; + xqc_mini_cli_ctx_t cli_ctx = {0}, *ctx = &cli_ctx; + xqc_mini_cli_args_t *args = NULL; + xqc_mini_cli_user_conn_t *user_conn = NULL; + + args = calloc(1, sizeof(xqc_mini_cli_args_t)); + if (args == NULL) { + printf("[error] calloc args failed\n"); + goto exit; + } + + /* init env (for windows) */ + xqc_platform_init_env(); + + /* init client environment (ctx & args) */ + ret = xqc_mini_cli_init_env(ctx, args); + if (ret < 0) { + goto exit; + } + + /* init client engine */ + ret = xqc_mini_cli_init_xquic_engine(ctx, args); + if (ret < 0) { + printf("[error] init xquic engine failed\n"); + goto exit; + } + + /* init engine ctx */ + ret = xqc_mini_cli_init_engine_ctx(ctx); + if (ret < 0) { + printf("[error] init engine ctx failed\n"); + goto exit; + } + + user_conn = xqc_mini_cli_user_conn_create(ctx); + if (user_conn == NULL) { + printf("[error] init user_conn failed.\n"); + goto exit; + } + + /* cli main process: build connection, process request, etc. */ + xqc_mini_cli_main_process(user_conn, ctx); + + /* start event loop */ + event_base_dispatch(ctx->eb); + +exit: + xqc_engine_destroy(ctx->engine); + xqc_mini_cli_on_connection_finish(user_conn); + xqc_mini_cli_free_ctx(ctx); + xqc_mini_cli_free_user_conn(user_conn); + + return 0; +} \ No newline at end of file diff --git a/mini/mini_client.h b/mini/mini_client.h new file mode 100644 index 00000000..e33654bd --- /dev/null +++ b/mini/mini_client.h @@ -0,0 +1,261 @@ +#ifndef XQC_MINI_CLIENT_H +#define XQC_MINI_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef XQC_SYS_WINDOWS +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#include "../tests/getopt.h" +#else +#include +#include +#include +#include +#include +#endif + + +#include "../tests/platform.h" +#include "common.h" +#include "mini_client_cb.h" + + +#define DEFAULT_IP "127.0.0.1" +#define DEFAULT_PORT 8443 +#define DEFAULT_HOST "test.xquic.com" + +#define SESSION_TICKET_BUF_MAX_SIZE 8192 +#define TRANSPORT_PARAMS_MAX_SIZE 8192 +#define TOKEN_MAX_SIZE 8192 +#define MAX_PATH_CNT 2 +#define XQC_PACKET_BUF_LEN 1500 + +#define SESSION_TICKET_FILE "session_ticket" +#define TRANSPORT_PARAMS_FILE "transport_params" +#define TOKEN_FILE "token" + +#define LOG_PATH "clog.log" +#define KEY_PATH "ckeys.log" +#define OUT_DIR "." + +/** + * net config definition + * net config is those arguments about socket information + * all configuration on net should be put under this section + */ + +typedef struct xqc_mini_cli_net_config_s { + int conn_timeout; + xqc_usec_t last_socket_time; + + // /* server addr info */ + // struct sockaddr *addr; + // socklen_t addr_len; + // char server_addr[64]; + // short server_port; +} xqc_mini_cli_net_config_t; + +/** + * quic config definition + * quic config is those arguments required by quic features, including connection settings, ssl configs, etc. + * all configuration on quic should be put under this section + */ + +typedef struct xqc_mini_cli_quic_config_s { + /* cipher config */ + char ciphers[CIPHER_SUIT_LEN]; + char groups[TLS_GROUPS_LEN]; + + /* connection ssl config */ + char session_ticket[SESSION_TICKET_BUF_MAX_SIZE]; + int session_ticket_len; + char transport_parameter[TRANSPORT_PARAMS_MAX_SIZE]; + int transport_parameter_len; + + char token[TOKEN_MAX_SIZE]; + int token_len; + + int no_encryption; + + /* multipath */ + int multipath; // mp option, 0: disable, 1: enable + char mp_sched[32]; // mp scheduler, minrtt/backup + + /* congestion control */ + CC_TYPE cc; // cc algrithm, bbr/cubic +} xqc_mini_cli_quic_config_t; + +/** + * the environment config definition + * environment config is those arguments about IO inputs and outputs + * all configuration on environment should be put under this section + */ + +typedef struct xqc_mini_cli_env_config_s { + /* log config */ + char log_path[PATH_LEN]; + + /* tls certificates */ + char private_key_file[PATH_LEN]; + char cert_file[PATH_LEN]; + + /* key export */ + char key_out_path[PATH_LEN]; + + /* output file */ + char out_file_dir[PATH_LEN]; +} xqc_mini_cli_env_config_t; + + +/** + * the request config definition + * request config is those arguments about request information + * all configuration on request should be put under this section + */ +typedef struct xqc_mini_cli_req_config_s { + char path[RESOURCE_LEN]; /* request path */ + char scheme[8]; /* request scheme, http/https */ + REQUEST_METHOD method; + char host[256]; /* request host */ + // char auth[AUTHORITY_LEN]; + char url[URL_LEN]; /* original url */ +} xqc_mini_cli_req_config_t; + + +typedef struct xqc_mini_cli_args_s { + /* network args */ + xqc_mini_cli_net_config_t net_cfg; + + /* xquic args */ + xqc_mini_cli_quic_config_t quic_cfg; + + /* environment args */ + xqc_mini_cli_env_config_t env_cfg; + + /* request args */ + xqc_mini_cli_req_config_t req_cfg; +} xqc_mini_cli_args_t; + + +typedef struct xqc_mini_cli_ctx_s { + struct event_base *eb; + + xqc_mini_cli_args_t *args; // server arguments for current context + + xqc_engine_t *engine; // xquic engine for current context + struct event *ev_engine; + + int log_fd; + int keylog_fd; +} xqc_mini_cli_ctx_t; + + +typedef struct xqc_mini_cli_user_conn_s { + xqc_cid_t cid; + xqc_h3_conn_t *h3_conn; + + xqc_mini_cli_ctx_t *ctx; + + /* ipv4 server */ + int fd; + int get_local_addr; + struct sockaddr *local_addr; + socklen_t local_addrlen; + struct sockaddr *peer_addr; + socklen_t peer_addrlen; + + struct event *ev_socket; + struct event *ev_timeout; + +} xqc_mini_cli_user_conn_t; + +typedef struct xqc_mini_cli_user_stream_s { + xqc_mini_cli_user_conn_t *user_conn; + + /* save file */ + // char file_name[RESOURCE_LEN]; + // FILE *recv_body_fp; + + /* stat for IO */ + size_t send_body_len; + size_t recv_body_len; + int recv_fin; + xqc_msec_t start_time; + + + /* h3 request content */ + xqc_h3_request_t *h3_request; + + xqc_http_headers_t h3_hdrs; + uint8_t hdr_sent; + + char *send_body_buff; + int send_body_size; + size_t send_offset; + +} xqc_mini_cli_user_stream_t; + + + +void xqc_mini_cli_init_engine_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_cli_args_t *args); + +void xqc_mini_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_xquic_engine(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +void xqc_mini_cli_convert_text_to_sockaddr(int type, + const char *addr_text, unsigned int port, + struct sockaddr **saddr, socklen_t *saddr_len); + +void xqc_mini_cli_init_args(xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_ctx(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_env(xqc_mini_cli_ctx_t *ctx, xqc_mini_cli_args_t *args); + +xqc_scheduler_callback_t xqc_mini_cli_get_sched_cb(xqc_mini_cli_args_t *args); +xqc_cong_ctrl_callback_t xqc_mini_cli_get_cc_cb(xqc_mini_cli_args_t *args); +void xqc_mini_cli_init_conn_settings(xqc_conn_settings_t *settings, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_init_alpn_ctx(xqc_mini_cli_ctx_t *ctx); +int xqc_mini_cli_init_engine_ctx(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_free_ctx(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_init_0rtt(xqc_mini_cli_args_t *args); + +void xqc_mini_cli_init_conn_ssl_config(xqc_conn_ssl_config_t *conn_ssl_config, xqc_mini_cli_args_t *args); + +int xqc_mini_cli_format_h3_req(xqc_http_header_t *headers, xqc_mini_cli_req_config_t* req_cfg); + +int xqc_mini_cli_request_send(xqc_h3_request_t *h3_request, xqc_mini_cli_user_stream_t *user_stream); + +int xqc_mini_cli_send_h3_req(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_user_stream_t *user_stream); + +int xqc_mini_cli_init_socket(xqc_mini_cli_user_conn_t *user_conn); + +void xqc_mini_cli_socket_write_handler(xqc_mini_cli_user_conn_t *user_conn, int fd); + +void xqc_mini_cli_socket_read_handler(xqc_mini_cli_user_conn_t *user_conn, int fd); + +static void xqc_mini_cli_socket_event_callback(int fd, short what, void *arg); +int xqc_mini_cli_init_xquic_connection(xqc_mini_cli_user_conn_t *user_conn); + +int xqc_mini_cli_main_process(xqc_mini_cli_user_conn_t *user_conn, xqc_mini_cli_ctx_t *ctx); +xqc_mini_cli_user_conn_t *xqc_mini_cli_user_conn_create(xqc_mini_cli_ctx_t *ctx); + +void xqc_mini_cli_free_user_conn(xqc_mini_cli_user_conn_t *user_conn); +void xqc_mini_cli_on_connection_finish(xqc_mini_cli_user_conn_t *user_conn); +#endif \ No newline at end of file diff --git a/mini/mini_client_cb.c b/mini/mini_client_cb.c new file mode 100644 index 00000000..045d3edc --- /dev/null +++ b/mini/mini_client_cb.c @@ -0,0 +1,405 @@ +/** + * @file mini_server_cb.c contains callbacks definitions for mini_server, including: + * 1. engine callbacks + * 2. hq callbacks + * 3. h3 callbacks + */ +#include "mini_client_cb.h" +/** + * @brief engine callbacks to trigger engine main logic + */ +const char *line_break = "\n"; +void +xqc_mini_cli_engine_cb(int fd, short what, void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t *) arg; + + xqc_engine_main_logic(ctx->engine); +} + +int +xqc_mini_cli_open_log_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + return open(ctx->args->env_cfg.log_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_cli_close_log_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + if (ctx->log_fd > 0) { + close(ctx->log_fd); + ctx->log_fd = 0; + } +} + +void +xqc_mini_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + //printf("%s", (char *)buf); + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + } +} + + +int +xqc_mini_cli_open_keylog_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + return open(ctx->args->env_cfg.key_out_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_cli_close_keylog_file(void *arg) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)arg; + if (ctx->keylog_fd > 0) { + close(ctx->keylog_fd); + ctx->keylog_fd = 0; + } +} + +void +xqc_mini_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} + + +void +xqc_mini_cli_keylog_cb(const xqc_cid_t *scid, const char *line, void *engine_user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t*)engine_user_data; + + if (ctx->keylog_fd <= 0) { + printf("write keys error!\n"); + return; + } + + int write_len = write(ctx->keylog_fd, line, strlen(line)); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->keylog_fd, line_break, 1); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + } +} +int +xqc_mini_cli_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + + user_conn->h3_conn = conn; + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); + + return XQC_OK; +} + +int +xqc_mini_cli_h3_conn_close_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + + event_base_loopbreak(user_conn->ctx->eb); + printf("[stats] xqc_mini_cli_h3_conn_close_notify success \n"); + return XQC_OK; +} + +void +xqc_mini_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) +{ + return; +} +int +xqc_mini_cli_h3_request_create_notify(xqc_h3_request_t *h3_request, void *h3s_user_data) +{ + return 0; +} + +int +xqc_mini_cli_h3_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) +{ + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)user_data; + xqc_mini_cli_user_conn_t *user_conn = user_stream->user_conn; + xqc_mini_cli_ctx_t *conn_ctx = user_conn->ctx; + xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); + + xqc_h3_conn_close(conn_ctx->engine, &user_conn->cid); + free(user_stream); + + printf("[stats] xqc_mini_cli_h3_request_close_notify success, cwnd_blocked:%"PRIu64"\n", stats.cwnd_blocked_ms); + return 0; +} +int +xqc_mini_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, + xqc_request_notify_flag_t flag, void *h3s_user_data) +{ + char recv_buff[XQC_MAX_BUFF_SIZE] = {0}; + size_t recv_buff_size; + ssize_t read, read_sum; + unsigned char fin = 0; + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)h3s_user_data; + xqc_mini_cli_user_conn_t *user_conn = user_stream->user_conn; + + if (flag & XQC_REQ_NOTIFY_READ_HEADER) { + xqc_http_headers_t *headers; + headers = xqc_h3_request_recv_headers(h3_request, &fin); + if (headers == NULL) { + printf("[error] xqc_h3_request_recv_headers error\n"); + return XQC_ERROR; + } + + for (int i = 0; i < headers->count; i++) { + printf("[receive report] %s = %s\n", (char *)headers->headers[i].name.iov_base, + (char *)headers->headers[i].value.iov_base); + } + + if (fin) { + /* only header in request */ + user_stream->recv_fin = 1; + printf("[stats] h3 request read header finish \n"); + return XQC_OK; + } + } + + /* continue to recv body */ + if (!(flag & XQC_REQ_NOTIFY_READ_BODY)) { + return XQC_OK; + } + + recv_buff_size = XQC_MAX_BUFF_SIZE; + read = read_sum = 0; + + do { + read = xqc_h3_request_recv_body(h3_request, recv_buff, recv_buff_size, &fin); + if (read == -XQC_EAGAIN) { + break; + + } else if (read < 0) { + printf("xqc_h3_request_recv_body error %zd\n", read); + return XQC_OK; + } + + read_sum += read; + user_stream->recv_body_len += read; + } while (read > 0 && !fin); + + printf("[report] xqc_h3_request_recv_body size %zd, fin:%d\n", read, fin); + + if (fin) { + printf("[stats] read h3 request finish. \n"); + } + + return XQC_OK; +} + +int +xqc_mini_cli_h3_request_write_notify(xqc_h3_request_t *h3_request, void *h3s_user_data) +{ + int ret = 0; + xqc_mini_cli_user_stream_t *user_stream = (xqc_mini_cli_user_stream_t *)h3s_user_data; + + ret = xqc_mini_cli_request_send(h3_request, user_stream); + + printf("[stats] finish h3 request write notify!:%"PRIu64"\n", xqc_h3_stream_id(h3_request)); + + return ret; +} + +void +xqc_mini_cli_set_event_timer(xqc_usec_t wake_after, void *user_data) +{ + xqc_mini_cli_ctx_t *ctx = (xqc_mini_cli_ctx_t *) user_data; + //printf("xqc_engine_wakeup_after %llu us, now %llu\n", wake_after, xqc_now()); + + struct timeval tv; + tv.tv_sec = wake_after / 1000000; + tv.tv_usec = wake_after % 1000000; + event_add(ctx->ev_engine, &tv); +} + +ssize_t +xqc_mini_cli_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data) +{ + return xqc_mini_cli_write_socket_ex(0, buf, size, peer_addr, peer_addrlen, conn_user_data); +} + +ssize_t +xqc_mini_cli_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *conn_user_data) +{ + int fd; + ssize_t res; + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)conn_user_data; + + fd = user_conn->fd; + res = 0; + + do { + set_sys_errno(0); + res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); + if (res < 0) { + printf("xqc_mini_cli_write_socket err %zd %s, fd: %d, buf: %p, size: %zu, " + "server_addr: %s\n", res, strerror(get_sys_errno()), fd, buf, size, + user_conn->peer_addr->sa_data); + if (get_sys_errno() == EAGAIN) { + res = XQC_SOCKET_EAGAIN; + } + } + } while ((res < 0) && (get_sys_errno() == EINTR)); + + // printf("[report] xqc_mini_cli_write_socket_ex success size=%lu\n", size); + + return res; +} + +int +xqc_mini_cli_read_token(unsigned char *token, unsigned token_len) +{ + int fd = open(TOKEN_FILE, O_RDONLY); + if (fd < 0) { + return -1; + } + + ssize_t n = read(fd, token, token_len); + close(fd); + return n; +} + +void +xqc_mini_cli_save_token(const unsigned char *token, unsigned token_len, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start xqc_mini_cli_save_token, use client ip as the key.\n"); + + int fd = open(TOKEN_FILE, O_TRUNC | O_CREAT | O_WRONLY, 0666); + if (fd < 0) { + printf("save token error %s\n", strerror(get_sys_errno())); + return; + } + + ssize_t n = write(fd, token, token_len); + if (n < token_len) { + printf("save token error %s\n", strerror(get_sys_errno())); + close(fd); + return; + } + close(fd); +} + +void +xqc_mini_cli_save_session_cb(const char * data, size_t data_len, void *user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start save_session_cb. \n"); + + FILE * fp = fopen(SESSION_TICKET_FILE, "wb"); + if (fp < 0) { + printf("save session error %s\n", strerror(get_sys_errno())); + return; + } + + int write_size = fwrite(data, 1, data_len, fp); + if (data_len != write_size) { + printf("save _session_cb error\n"); + fclose(fp); + return; + } + fclose(fp); + return; +} + + +void +xqc_mini_cli_save_tp_cb(const char * data, size_t data_len, void * user_data) +{ + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *)user_data; + printf("[stats] start save_tp_cb\n"); + + FILE * fp = fopen(TRANSPORT_PARAMS_FILE, "wb"); + if (fp < 0) { + printf("save transport callback error %s\n", strerror(get_sys_errno())); + return; + } + + int write_size = fwrite(data, 1, data_len, fp); + if (data_len != write_size) { + printf("save _tp_cb error\n"); + fclose(fp); + return; + } + + fclose(fp); + return; +} + + +void +xqc_mini_cli_timeout_callback(int fd, short what, void *arg) +{ + int conn_timeout, last_socket_time, ret; + xqc_usec_t socket_idle_time; + struct timeval tv; + xqc_mini_cli_ctx_t *ctx; + xqc_mini_cli_user_conn_t *user_conn; + + user_conn = (xqc_mini_cli_user_conn_t *)arg; + ctx = user_conn->ctx; + conn_timeout = ctx->args->net_cfg.conn_timeout; + last_socket_time = ctx->args->net_cfg.last_socket_time; + socket_idle_time = xqc_now() - last_socket_time; + + if (socket_idle_time < conn_timeout * 1000000) { + tv.tv_sec = conn_timeout; + tv.tv_usec = 0; + event_add(user_conn->ev_timeout, &tv); + return; + } + +conn_close: + printf("[stats] client process timeout, connection closing... \n"); + ret = xqc_h3_conn_close(ctx->engine, &user_conn->cid); + if (ret) { + printf("[error] xqc_conn_close error:%d\n", ret); + return; + } +} + +int +xqc_mini_cli_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data, void *conn_proto_data) +{ + DEBUG; + + xqc_mini_cli_user_conn_t *user_conn = (xqc_mini_cli_user_conn_t *) user_data; + xqc_conn_set_alp_user_data(conn, user_conn); + + printf("[stats] xqc_conn_is_ready_to_send_early_data:%d\n", xqc_conn_is_ready_to_send_early_data(conn)); + return XQC_OK; +} \ No newline at end of file diff --git a/mini/mini_client_cb.h b/mini/mini_client_cb.h new file mode 100644 index 00000000..730d9515 --- /dev/null +++ b/mini/mini_client_cb.h @@ -0,0 +1,65 @@ +#ifndef XQC_MINI_CLIENT_CB_H +#define XQC_MINI_CLIENT_CB_H +#include +#include +#include "mini_client.h" + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include "../tests/getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#endif + +#define XQC_MAX_BUFF_SIZE 4096 + +void xqc_mini_cli_engine_cb(int fd, short what, void *arg); + +int xqc_mini_cli_open_log_file(void *arg); +void xqc_mini_cli_close_log_file(void *arg); +void xqc_mini_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); + +int xqc_mini_cli_open_keylog_file(void *arg); +void xqc_mini_cli_close_keylog_file(void *arg); + +void xqc_mini_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data); + +void xqc_mini_cli_keylog_cb(const xqc_cid_t *scid, const char *line, void *engine_user_data); + +int xqc_mini_cli_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data); +int xqc_mini_cli_h3_conn_close_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void *user_data); +void xqc_mini_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data); + +int xqc_mini_cli_h3_request_create_notify(xqc_h3_request_t *h3_request, void *h3s_user_data); +void xqc_mini_cli_h3_request_closing_notify(xqc_h3_request_t *h3_request, + xqc_int_t err, void *h3s_user_data); +int xqc_mini_cli_h3_request_close_notify(xqc_h3_request_t *h3_request, void *user_data); +int xqc_mini_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, + xqc_request_notify_flag_t flag, void *h3s_user_data); +int xqc_mini_cli_h3_request_write_notify(xqc_h3_request_t *h3_request, void *h3s_user_data); + +void xqc_mini_cli_set_event_timer(xqc_usec_t wake_after, void *user_data); + +ssize_t xqc_mini_cli_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *conn_user_data); + +ssize_t xqc_mini_cli_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr, socklen_t peer_addrlen, void *conn_user_data); + +int xqc_mini_cli_read_token(unsigned char *token, unsigned token_len); + +void xqc_mini_cli_save_token(const unsigned char *token, unsigned token_len, void *user_data); + +void xqc_mini_cli_save_session_cb(const char * data, size_t data_len, void *user_data); + +void xqc_mini_cli_save_tp_cb(const char * data, size_t data_len, void * user_data); + +void xqc_mini_cli_timeout_callback(int fd, short what, void *arg); + +int xqc_mini_cli_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data, void *conn_proto_data); + +#endif \ No newline at end of file diff --git a/mini/mini_server.c b/mini/mini_server.c new file mode 100644 index 00000000..8efa4f75 --- /dev/null +++ b/mini/mini_server.c @@ -0,0 +1,544 @@ +#include "mini_server.h" + +void +xqc_mini_svr_init_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_svr_args_t *args) +{ + ssl_cfg->private_key_file = args->env_cfg.private_key_file; + ssl_cfg->cert_file = args->env_cfg.cert_file; + ssl_cfg->ciphers = args->quic_cfg.ciphers; + ssl_cfg->groups = args->quic_cfg.groups; + + /* for server, load session ticket key if there exists */ + if (args->quic_cfg.session_ticket_key_len <= 0) { + ssl_cfg->session_ticket_key_data = NULL; + ssl_cfg->session_ticket_key_len = 0; + + } else { + ssl_cfg->session_ticket_key_data = args->quic_cfg.session_ticket_key_data; + ssl_cfg->session_ticket_key_len = args->quic_cfg.session_ticket_key_len; + } +} + +void +xqc_mini_svr_init_args(xqc_mini_svr_args_t *args) +{ + int ret; + char *p = NULL; + + /* init network args */ + strncpy(args->net_cfg.ip, DEFAULT_IP, sizeof(args->net_cfg.ip) - 1); + args->net_cfg.port = DEFAULT_PORT; + + /** + * init quic config + * it's recommended to replace the constant value with option arguments according to actual needs + */ + p = args->quic_cfg.session_ticket_key_data; + ret = xqc_mini_read_file_data(p, + SESSION_TICKET_KEY_BUF_LEN, SESSION_TICKET_KEY_FILE); + args->quic_cfg.session_ticket_key_len = ret > 0 ? ret : 0; + args->quic_cfg.cc = CC_TYPE_BBR; + args->quic_cfg.multipath = 1; + strncpy(args->quic_cfg.mp_sched, "minrtt", 32); + strncpy(args->quic_cfg.ciphers, XQC_TLS_CIPHERS, CIPHER_SUIT_LEN - 1); + strncpy(args->quic_cfg.groups, XQC_TLS_GROUPS, TLS_GROUPS_LEN - 1); + + /* init env config */ + strncpy(args->env_cfg.log_path, LOG_PATH, TLS_GROUPS_LEN - 1); + strncpy(args->env_cfg.key_out_path, KEY_PATH, PATH_LEN - 1); + strncpy(args->env_cfg.private_key_file, PRIV_KEY_PATH, PATH_LEN - 1); + strncpy(args->env_cfg.cert_file, CERT_PEM_PATH, PATH_LEN - 1); +} + +int +xqc_mini_svr_init_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + memset(ctx, 0, sizeof(xqc_mini_svr_ctx_t)); + + /* init event base */ + struct event_base *eb = event_base_new(); + ctx->eb = eb; + + ctx->args = args; + /* init log writer fd */ + ctx->log_fd = xqc_mini_svr_open_log_file(ctx); + if (ctx->log_fd < 0) { + printf("[error] open log file failed\n"); + return XQC_ERROR; + } + /* init keylog writer fd */ + ctx->keylog_fd = xqc_mini_svr_open_keylog_file(ctx); + if (ctx->keylog_fd < 0) { + printf("[error] open keylog file failed\n"); + return XQC_ERROR; + } + return XQC_OK; +} + +/** + * @brief init engine & transport callbacks + */ +void +xqc_mini_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, + xqc_mini_svr_args_t *args) +{ + static xqc_engine_callback_t callback = { + .set_event_timer = xqc_mini_svr_set_event_timer, + .log_callbacks = { + .xqc_log_write_err = xqc_mini_svr_write_log_file, + .xqc_log_write_stat = xqc_mini_svr_write_log_file, + .xqc_qlog_event_write = xqc_mini_svr_write_qlog_file + }, + .keylog_cb = xqc_mini_svr_keylog_cb, + }; + + static xqc_transport_callbacks_t transport_cbs = { + .server_accept = xqc_mini_svr_accept, + .write_socket = xqc_mini_svr_write_socket, + .write_socket_ex = xqc_mini_svr_write_socket_ex, + .conn_update_cid_notify = xqc_mini_svr_conn_update_cid_notify, + }; + + *cb = callback; + *tcb = transport_cbs; +} + +/** + * @brief init xquic server engine + */ +int +xqc_mini_svr_init_xquic_engine(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret; + xqc_config_t egn_cfg; + xqc_engine_callback_t callback; + xqc_engine_ssl_config_t ssl_cfg = {0}; + xqc_transport_callbacks_t transport_cbs; + + /* get default parameters of xquic engine */ + ret = xqc_engine_get_default_config(&egn_cfg, XQC_ENGINE_SERVER); + if (ret < 0) { + return XQC_ERROR; + } + + /* init ssl config */ + xqc_mini_svr_init_ssl_config(&ssl_cfg, args); + + /* init engine & transport callbacks */ + xqc_mini_svr_init_callback(&callback, &transport_cbs, args); + + /* create server engine */ + ctx->engine = xqc_engine_create(XQC_ENGINE_SERVER, &egn_cfg, &ssl_cfg, + &callback, &transport_cbs, ctx); + if (ctx->engine == NULL) { + printf("[error] xqc_engine_create error\n"); + return XQC_ERROR; + } + + ctx->ev_engine = event_new(ctx->eb, -1, 0, xqc_mini_svr_engine_cb, ctx); + + return XQC_OK; +} + +int +xqc_mini_svr_init_env(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret = XQC_OK; + + /* init server args */ + xqc_mini_svr_init_args(args); + + /* init server ctx */ + ret = xqc_mini_svr_init_ctx(ctx, args); + + return ret; +} + +xqc_cong_ctrl_callback_t +xqc_mini_svr_get_cc_cb(xqc_mini_svr_args_t *args) +{ + xqc_cong_ctrl_callback_t ccc = xqc_bbr_cb; + switch (args->quic_cfg.cc) { + case CC_TYPE_BBR: + ccc = xqc_bbr_cb; + break; + case CC_TYPE_CUBIC: + ccc = xqc_cubic_cb; + break; + default: + break; + } + return ccc; +} + +xqc_scheduler_callback_t +xqc_mini_svr_get_sched_cb(xqc_mini_svr_args_t *args) +{ + xqc_scheduler_callback_t sched = xqc_minrtt_scheduler_cb; + if (strncmp(args->quic_cfg.mp_sched, "minrtt", strlen("minrtt")) == 0) { + sched = xqc_minrtt_scheduler_cb; + + } if (strncmp(args->quic_cfg.mp_sched, "backup", strlen("backup")) == 0) { + sched = xqc_backup_scheduler_cb; + } + return sched; +} + +void +xqc_mini_svr_init_conn_settings(xqc_engine_t *engine, xqc_mini_svr_args_t *args) +{ + /* parse congestion control callback */ + xqc_cong_ctrl_callback_t ccc = xqc_mini_svr_get_cc_cb(args); + /* parse mp scheduler callback */ + xqc_scheduler_callback_t sched = xqc_mini_svr_get_sched_cb(args); + + /* init connection settings */ + xqc_conn_settings_t conn_settings = { + .cong_ctrl_callback = ccc, + .cc_params = { + .customize_on = 1, + .init_cwnd = 32, + .bbr_enable_lt_bw = 1, + }, + .spurious_loss_detect_on = 1, + .init_idle_time_out = 60000, + .enable_multipath = args->quic_cfg.multipath, + .scheduler_callback = sched, + .standby_path_probe_timeout = 1000, + .adaptive_ack_frequency = 1, + .anti_amplification_limit = 4, + }; + + /* set customized connection settings to engine ctx */ + xqc_server_set_conn_settings(engine, &conn_settings); +} + +/* create socket and bind port */ +static int +xqc_mini_svr_init_socket(int family, uint16_t port, + struct sockaddr *local_addr, socklen_t local_addrlen) +{ + int size; + int opt_reuseaddr; + int flags = 1; + int fd = socket(family, SOCK_DGRAM, 0); + if (fd < 0) { + printf("create socket failed, errno: %d\n", get_sys_errno()); + return XQC_ERROR; + } + + /* non-block */ +#ifdef XQC_SYS_WINDOWS + if (ioctlsocket(fd, FIONBIO, &flags) == SOCKET_ERROR) { + goto err; + } +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { + printf("set socket nonblock failed, errno: %d\n", get_sys_errno()); + goto err; + } +#endif + + /* reuse port */ + opt_reuseaddr = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt_reuseaddr, sizeof(opt_reuseaddr)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + /* send/recv buffer size */ + size = 1 * 1024 * 1024; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0) { + printf("setsockopt failed, errno: %d\n", get_sys_errno()); + goto err; + } + + /* bind port */ + if (bind(fd, local_addr, local_addrlen) < 0) { + printf("bind socket failed, family: %d, errno: %d, %s\n", family, + get_sys_errno(), strerror(get_sys_errno())); + goto err; + } + + return fd; + +err: + close(fd); + return -1; +} + +static int +xqc_mini_svr_create_socket(xqc_mini_svr_user_conn_t *user_conn, xqc_mini_svr_net_config_t* cfg) +{ + /* ipv4 socket */ + user_conn->local_addr->sin_family = AF_INET; + user_conn->local_addr->sin_port = htons(cfg->port); + user_conn->local_addr->sin_addr.s_addr = htonl(INADDR_ANY); + user_conn->local_addrlen = sizeof(struct sockaddr_in); + user_conn->fd = xqc_mini_svr_init_socket(AF_INET, cfg->port, (struct sockaddr*)user_conn->local_addr, + user_conn->local_addrlen); + printf("[stats] create ipv4 socket fd: %d success, bind socket to ip: %s, port: %d\n", user_conn->fd, cfg->ip, cfg->port); + + if (!user_conn->fd) { + return -1; + } + + return 0; +} + +int +xqc_mini_svr_init_alpn_ctx(xqc_engine_t *engine) +{ + int ret = 0; + + /* init http3 callbacks */ + xqc_h3_callbacks_t h3_cbs = { + .h3c_cbs = { + .h3_conn_create_notify = xqc_mini_svr_h3_conn_create_notify, + .h3_conn_close_notify = xqc_mini_svr_h3_conn_close_notify, + .h3_conn_handshake_finished = xqc_mini_svr_h3_conn_handshake_finished, + }, + .h3r_cbs = { + .h3_request_create_notify = xqc_mini_svr_h3_request_create_notify, + .h3_request_close_notify = xqc_mini_svr_h3_request_close_notify, + .h3_request_read_notify = xqc_mini_svr_h3_request_read_notify, + .h3_request_write_notify = xqc_mini_svr_h3_request_write_notify, + } + }; + + /* init http3 context */ + ret = xqc_h3_ctx_init(engine, &h3_cbs); + if (ret != XQC_OK) { + printf("init h3 context error, ret: %d\n", ret); + return ret; + } + + return ret; +} + +int +xqc_mini_svr_init_engine_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args) +{ + int ret; + + /* init connection settings */ + xqc_mini_svr_init_conn_settings(ctx->engine, args); + + /* init alpn ctx */ + ret = xqc_mini_svr_init_alpn_ctx(ctx->engine); + + return ret; +} + +void +xqc_mini_svr_socket_write_handler(xqc_mini_svr_user_conn_t *user_conn, int fd) +{ + DEBUG + printf("[stats] socket write handler\n"); +} + +void +xqc_mini_svr_socket_read_handler(xqc_mini_svr_user_conn_t *user_conn, int fd) +{ + DEBUG; + ssize_t recv_size, recv_sum; + struct sockaddr_in peer_addr = {0}; + socklen_t peer_addrlen = sizeof(peer_addr); + uint64_t recv_time; + xqc_int_t ret; + unsigned char packet_buf[XQC_PACKET_BUF_LEN] = {0}; + xqc_mini_svr_ctx_t *ctx; + + ctx = user_conn->ctx; + ctx->current_fd = fd; + recv_size = recv_sum = 0; + + do { + /* recv quic packet from client */ + recv_size = recvfrom(fd, packet_buf, sizeof(packet_buf), 0, + (struct sockaddr *) &peer_addr, &peer_addrlen); + if (recv_size < 0 && get_sys_errno() == EAGAIN) { + break; + } + memcpy(user_conn->peer_addr, &peer_addr, peer_addrlen); + user_conn->peer_addrlen = peer_addrlen; + + if (recv_size < 0) { + printf("recvfrom: recvmsg = %zd err=%s\n", recv_size, strerror(get_sys_errno())); + break; + } + + user_conn->local_addrlen = sizeof(struct sockaddr_in6); + ret = getsockname(user_conn->fd, (struct sockaddr *)user_conn->local_addr, + &user_conn->local_addrlen); + if (ret != 0) { + printf("[error] getsockname error, errno: %d\n", get_sys_errno()); + } + // printf("[stats] get sock name %d\n", user_conn->local_addr->sin_family); + + recv_sum += recv_size; + recv_time = xqc_now(); + /* process quic packet with xquic engine */ + ret = xqc_engine_packet_process(ctx->engine, packet_buf, recv_size, + (struct sockaddr *)(user_conn->local_addr), user_conn->local_addrlen, + (struct sockaddr *)(user_conn->peer_addr), user_conn->peer_addrlen, + (xqc_usec_t)recv_time, user_conn); + if (ret != XQC_OK) { + printf("[error] server_read_handler: packet process err, ret: %d\n", ret); + return; + } + } while (recv_size > 0); + +finish_recv: + // printf("[stats] xqc_mini_svr_socket_read_handler, recv size:%zu\n", recv_sum); + xqc_engine_finish_recv(ctx->engine); +} + +static void +xqc_mini_svr_socket_event_callback(int fd, short what, void *arg) +{ + //DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)arg; + if (what & EV_WRITE) { + xqc_mini_svr_socket_write_handler(user_conn, fd); + + } else if (what & EV_READ) { + xqc_mini_svr_socket_read_handler(user_conn, fd); + + } else { + printf("event callback: fd=%d, what=%d\n", fd, what); + exit(1); + } +} + +void +xqc_mini_svr_free_ctx(xqc_mini_svr_ctx_t *ctx) +{ + xqc_mini_svr_close_keylog_file(ctx); + xqc_mini_svr_close_log_file(ctx); + + if (ctx->args) { + free(ctx->args); + ctx->args = NULL; + } + +} + +void +xqc_mini_svr_free_user_conn(xqc_mini_svr_user_conn_t *user_conn) +{ + if (user_conn->local_addr) { + free(user_conn->local_addr); + user_conn->local_addr = NULL; + } + if (user_conn->peer_addr) { + free(user_conn->peer_addr); + user_conn->peer_addr = NULL; + } + if (user_conn) { + free(user_conn); + user_conn = NULL; + } +} + +xqc_mini_svr_user_conn_t * +xqc_mini_svr_create_user_conn(xqc_mini_svr_ctx_t *ctx) +{ + int ret; + xqc_mini_svr_user_conn_t *user_conn = calloc(1, sizeof(xqc_mini_svr_user_conn_t)); + + user_conn->ctx = ctx; + + user_conn->local_addr = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in)); + user_conn->peer_addr = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in)); + + /* init server socket and save to ctx->fd */ + ret = xqc_mini_svr_create_socket(user_conn, &ctx->args->net_cfg); + if (ret < 0) { + printf("[error] xqc_create_socket error\n"); + goto error; + } + + /* bind socket event callback to fd event */ + user_conn->ev_socket = event_new(ctx->eb, user_conn->fd, EV_READ | EV_PERSIST, + xqc_mini_svr_socket_event_callback, user_conn); + event_add(user_conn->ev_socket, NULL); + + return user_conn; +error: + xqc_mini_svr_free_user_conn(user_conn); + return NULL; +} + +void +xqc_mini_cli_on_connection_finish(xqc_mini_svr_user_conn_t *user_conn) +{ + if (user_conn->ev_timeout) { + event_del(user_conn->ev_timeout); + user_conn->ev_timeout = NULL; + } + + if (user_conn->ev_socket) { + event_del(user_conn->ev_socket); + user_conn->ev_timeout = NULL; + } +} + +int +main(int argc, char *argv[]) +{ + int ret; + xqc_mini_svr_ctx_t svr_ctx = {0}, *ctx = &svr_ctx; + xqc_mini_svr_args_t *args = NULL; + xqc_mini_svr_user_conn_t *user_conn = NULL; + + args = calloc(1, sizeof(xqc_mini_svr_args_t)); + if (args == NULL) { + printf("[error] calloc args failed\n"); + goto exit; + } + + /* init env (for windows) */ + xqc_platform_init_env(); + + /* init server environment */ + ret = xqc_mini_svr_init_env(ctx, args); + if (ret < 0) { + printf("[error] init server environment failed\n"); + goto exit; + } + + /* create & init engine to ctx->engine */ + ret = xqc_mini_svr_init_xquic_engine(ctx, args); + if (ret < 0) { + printf("[error] init xquic engine failed\n"); + goto exit; + } + + /* init engine ctx */ + ret = xqc_mini_svr_init_engine_ctx(ctx, args); + if (ret < 0) { + printf("[error] init engine ctx failed\n"); + goto exit; + } + + /* initiate user_conn */ + user_conn = xqc_mini_svr_create_user_conn(ctx); + + /* start event loop */ + event_base_dispatch(ctx->eb); + +exit: + xqc_engine_destroy(ctx->engine); + xqc_mini_svr_free_ctx(ctx); + if (user_conn) { + xqc_mini_svr_free_user_conn(user_conn); + } + + return 0; +} \ No newline at end of file diff --git a/mini/mini_server.h b/mini/mini_server.h new file mode 100644 index 00000000..b7e2a390 --- /dev/null +++ b/mini/mini_server.h @@ -0,0 +1,160 @@ +#ifndef XQC_MINI_SERVER_H +#define XQC_MINI_SERVER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "../demo/xqc_hq.h" +#include "../tests/platform.h" +#include "mini_server_cb.h" + +#define DEFAULT_IP "127.0.0.1" +#define DEFAULT_PORT 8443 +#define XQC_PACKET_BUF_LEN 1500 + +/** + * net config definition + * net config is those arguments about socket information + * all configuration on net should be put under this section + */ +typedef struct xqc_mini_svr_net_config_s +{ + /* server addr info */ + char ip[64]; + short port; + + /* idle persist timeout */ + int conn_timeout; +} xqc_mini_svr_net_config_t; + +/** + * quic config definition + * quic config is those arguments required by quic features, including connection settings, ssl configs, etc. + * all configuration on quic should be put under this section + */ +#define SESSION_TICKET_KEY_FILE "session_ticket.key" +#define SESSION_TICKET_KEY_BUF_LEN 2048 + +typedef struct xqc_mini_svr_quic_config_s +{ + /* cipher config */ + char ciphers[CIPHER_SUIT_LEN]; + char groups[TLS_GROUPS_LEN]; + + /* multipath */ + int multipath; // mp option, 0: disable, 1: enable + char mp_sched[32]; // mp scheduler, minrtt/backup + + /* congestion control */ + CC_TYPE cc; // cc algrithm, bbr/cubic + + + /* server should load session ticket key to enable 0-RTT */ + char session_ticket_key_data[SESSION_TICKET_KEY_BUF_LEN]; + size_t session_ticket_key_len; + +} xqc_mini_svr_quic_config_t; + +/** + * the environment config definition + * environment config is those arguments about IO inputs and outputs + * all configuration on environment should be put under this section + */ + +#define LOG_PATH "slog.log" +#define KEY_PATH "skeys.log" +#define SOURCE_DIR "." +#define PRIV_KEY_PATH "server.key" +#define CERT_PEM_PATH "server.crt" + +typedef struct xqc_mini_svr_env_config_s { + /* log config */ + char log_path[PATH_LEN]; + + /* tls certificates */ + char private_key_file[PATH_LEN]; + char cert_file[PATH_LEN]; + + /* key export */ + char key_out_path[PATH_LEN]; + +} xqc_mini_svr_env_config_t; + +typedef struct xqc_mini_svr_args_s { + /* network args */ + xqc_mini_svr_net_config_t net_cfg; + + /* xquic args */ + xqc_mini_svr_quic_config_t quic_cfg; + + /* environment args */ + xqc_mini_svr_env_config_t env_cfg; + +} xqc_mini_svr_args_t; + +typedef struct xqc_mini_svr_ctx_s { + struct event_base *eb; + + /* used to remember fd type to send stateless reset */ + int current_fd; + + xqc_engine_t *engine; // xquic engine for current context + struct event *ev_engine; + + xqc_mini_svr_args_t *args; // server arguments for current context + + int log_fd; + int keylog_fd; +} xqc_mini_svr_ctx_t; + + +typedef struct xqc_mini_svr_user_conn_s { + struct event *ev_timeout; + xqc_cid_t cid; + xqc_mini_svr_ctx_t *ctx; + + /* ipv4 server */ + int fd; + struct sockaddr_in *local_addr; + socklen_t local_addrlen; + struct event *ev_socket; + struct sockaddr_in *peer_addr; + socklen_t peer_addrlen; + +} xqc_mini_svr_user_conn_t; + + +void xqc_mini_svr_init_ssl_config(xqc_engine_ssl_config_t *ssl_cfg, xqc_mini_svr_args_t *args); + +void xqc_mini_svr_init_args(xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); +/** + * @brief init engine & transport callbacks + */ +void xqc_mini_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t *tcb, + xqc_mini_svr_args_t *args); +/** + * @brief init xquic server engine + */ +int xqc_mini_svr_init_xquic_engine(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_env(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +int xqc_mini_svr_init_engine_ctx(xqc_mini_svr_ctx_t *ctx, xqc_mini_svr_args_t *args); + +void xqc_mini_svr_init_conn_settings(xqc_engine_t *engine, xqc_mini_svr_args_t *args); + +static int xqc_mini_svr_init_socket(int family, uint16_t port, struct sockaddr *local_addr, + socklen_t local_addrlen); + +static void xqc_mini_svr_socket_event_callback(int fd, short what, void *arg); +#endif \ No newline at end of file diff --git a/mini/mini_server_cb.c b/mini/mini_server_cb.c new file mode 100644 index 00000000..178fa4de --- /dev/null +++ b/mini/mini_server_cb.c @@ -0,0 +1,350 @@ +/** + * @file mini_server_cb.c contains callbacks definitions for mini_server, including: + * 1. engine callbacks + * 2. hq callbacks + * 3. h3 callbacks + */ + +#include "mini_server_cb.h" +/* engine callbacks */ + + +const char *line_break = "\n"; + +/** + * @brief engine callbacks to trigger engine main logic + */ +void +xqc_mini_svr_engine_cb(int fd, short what, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t *) arg; + + xqc_engine_main_logic(ctx->engine); +} + +/** + * @brief callbacks to set timer of engine callbacks + */ +void +xqc_mini_svr_set_event_timer(xqc_msec_t wake_after, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t *)arg; + + struct timeval tv; + tv.tv_sec = wake_after / 1000000; + tv.tv_usec = wake_after % 1000000; + event_add(ctx->ev_engine, &tv); +} + +int +xqc_mini_svr_open_log_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + return open(ctx->args->env_cfg.log_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} +void +xqc_mini_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write log failed, errno: %d\n", get_sys_errno()); + } +} + + +void +xqc_mini_svr_close_log_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd > 0) { + close(ctx->log_fd); + ctx->log_fd = 0; + } +} + +void +xqc_mini_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} + +int +xqc_mini_svr_open_keylog_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + return open(ctx->args->env_cfg.key_out_path, (O_WRONLY | O_APPEND | O_CREAT), 0644); +} + +void +xqc_mini_svr_keylog_cb(const xqc_cid_t *scid, const char *line, void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->keylog_fd <= 0) { + printf("write keys error!\n"); + return; + } + + int write_len = write(ctx->keylog_fd, line, strlen(line)); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->keylog_fd, line_break, 1); + if (write_len < 0) { + printf("write keys failed, errno: %d\n", get_sys_errno()); + } +} + +void +xqc_mini_svr_close_keylog_file(void *arg) +{ + xqc_mini_svr_ctx_t *ctx = (xqc_mini_svr_ctx_t*)arg; + if (ctx->keylog_fd > 0) { + close(ctx->keylog_fd); + ctx->keylog_fd = 0; + } +} +int +xqc_mini_svr_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t *cid, + void *arg) +{ + DEBUG; + + return 0; +} + + +ssize_t +xqc_mini_svr_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *arg) +{ + ssize_t res = XQC_OK; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)arg; + int fd = user_conn->ctx->current_fd; + + do { + set_sys_errno(0); + res = sendto(fd, buf, size, 0, peer_addr, peer_addrlen); + if (res < 0) { + printf("[error] xqc_mini_svr_write_socket err %zd %s, fd: %d\n", + res, strerror(get_sys_errno()), fd); + if (get_sys_errno() == EAGAIN) { + res = XQC_SOCKET_EAGAIN; + } + } + } while ((res < 0) && (get_sys_errno() == EINTR)); + + // printf("[report] xqc_mini_svr_write_socket success size=%lu\n", size); + return res; +} + +ssize_t +xqc_mini_svr_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr,socklen_t peer_addrlen, void *conn_user_data) +{ + return xqc_mini_svr_write_socket(buf, size, peer_addr, peer_addrlen, conn_user_data); +} + +void +xqc_mini_svr_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, + const xqc_cid_t *new_cid, void *user_data) +{ + DEBUG; + // xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)user_data; + // memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); +} + +/* h3 callbacks */ +int +xqc_mini_svr_h3_conn_create_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)conn_user_data; + xqc_h3_conn_set_user_data(h3_conn, user_conn); + xqc_h3_conn_get_peer_addr(h3_conn, (struct sockaddr *)user_conn->peer_addr, + sizeof(struct sockaddr_in), &user_conn->peer_addrlen); + memcpy(&user_conn->cid, cid, sizeof(*cid)); + + printf("[stats] xqc_mini_svr_h3_conn_create_notify \n"); + return 0; +} + + +int +xqc_mini_svr_h3_conn_close_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t*)conn_user_data; + + printf("[stats] xqc_mini_svr_h3_conn_close_notify success \n"); + return 0; +} + + +void +xqc_mini_svr_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *conn_user_data) +{ + DEBUG; + xqc_mini_svr_user_conn_t *user_conn = (xqc_mini_svr_user_conn_t *)conn_user_data; + xqc_conn_stats_t stats = xqc_conn_get_stats(user_conn->ctx->engine, &user_conn->cid); +} + + +int +xqc_mini_svr_h3_request_create_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_mini_svr_user_stream_t *user_stream = calloc(1, sizeof(*user_stream)); + user_stream->h3_request = h3_request; + + xqc_h3_request_set_user_data(h3_request, user_stream); + user_stream->recv_buf = calloc(1, REQ_BUF_SIZE); + + printf("[stats] xqc_mini_svr_h3_request_create_notify success \n"); + return 0; +} + +int +xqc_mini_svr_h3_request_close_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_request_stats_t stats = xqc_h3_request_get_stats(h3_request); + printf("[stats] xqc_mini_svr_h3_request_close_notify success, cwnd_blocked:%"PRIu64"\n", stats.cwnd_blocked_ms); + + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t*)strm_user_data; + free(user_stream); + + return 0; +} +int +xqc_mini_cli_handle_h3_request(xqc_mini_svr_user_stream_t *user_stream) +{ + DEBUG; + ssize_t ret = 0; + + /* response header buf list */ + xqc_http_header_t rsp_hdr[] = { + { + .name = {.iov_base = "content-type", .iov_len = 12}, + .value = {.iov_base = "text/plain", .iov_len = 10}, + .flags = 0, + } + }; + /* response header */ + xqc_http_headers_t rsp_hdrs; + rsp_hdrs.headers = rsp_hdr; + rsp_hdrs.count = sizeof(rsp_hdr) / sizeof(rsp_hdr[0]); + + if (user_stream->header_sent == 0) { + ret = xqc_h3_request_send_headers(user_stream->h3_request, &rsp_hdrs, 0); + if (ret < 0) { + printf("[error] xqc_h3_request_send_headers error %zd\n", ret); + return ret; + } else { + printf("[stats] xqc_h3_request_send_headers success \n"); + user_stream->header_sent = 1; + } + } + + ret = xqc_mini_svr_send_body(user_stream); + return ret; +} + +int +xqc_mini_svr_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_flag_t flag, + void *strm_user_data) +{ + DEBUG; + int ret; + char recv_buff[4096] = {0}; + ssize_t recv_buff_size, read, read_sum; + unsigned char fin = 0; + xqc_http_headers_t *headers = NULL; + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t *)strm_user_data; + + read = read_sum = 0; + recv_buff_size = 4096; + + /* recv headers */ + if (flag & XQC_REQ_NOTIFY_READ_HEADER) { + headers = xqc_h3_request_recv_headers(h3_request, &fin); + if (headers == NULL) { + printf("[error] xqc_h3_request_recv_headers error\n"); + return XQC_ERROR; + } + + /* TODO: if recv headers once for all? */ + user_stream->header_recvd = 1; + + } else if (flag & XQC_REQ_NOTIFY_READ_BODY) { /* recv body */ + do { + read = xqc_h3_request_recv_body(h3_request, recv_buff, recv_buff_size, &fin); + if (read == -XQC_EAGAIN) { + break; + + } else if (read < 0) { + printf("[error] xqc_h3_request_recv_body error %zd\n", read); + return XQC_OK; + } + + read_sum += read; + user_stream->recv_body_len += read; + } while (read > 0 && !fin); + } + if (fin) { + printf("[stats] read h3 request finish. \n"); + xqc_mini_cli_handle_h3_request(user_stream); + } + return 0; +} + +int +xqc_mini_svr_send_body(xqc_mini_svr_user_stream_t *user_stream) +{ + int fin = 1, send_buf_size, ret; + char send_buf[REQ_BUF_SIZE]; + + send_buf_size = REQ_BUF_SIZE; + memset(send_buf, 'D', send_buf_size); + + ret = xqc_h3_request_send_body(user_stream->h3_request, send_buf, send_buf_size, fin); + + printf("[reports] xqc_mini_svr_send_body success, size:%d \n", ret); + return ret; +} + +int +xqc_mini_svr_h3_request_write_notify(xqc_h3_request_t *h3_request, void *strm_user_data) +{ + DEBUG; + xqc_mini_svr_user_stream_t *user_stream = (xqc_mini_svr_user_stream_t *)strm_user_data; + int ret = xqc_mini_svr_send_body(user_stream); + + printf("[stats] write h3 request notify finish \n"); + return ret; +} diff --git a/mini/mini_server_cb.h b/mini/mini_server_cb.h new file mode 100644 index 00000000..26260309 --- /dev/null +++ b/mini/mini_server_cb.h @@ -0,0 +1,85 @@ +#ifndef XQC_MINI_SERVER_CB_H +#define XQC_MINI_SERVER_CB_H + +#include +#include + +#ifndef XQC_SYS_WINDOWS +#include +#include +#else +#include "../tests/getopt.h" +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"event.lib") +#pragma comment(lib, "Iphlpapi.lib") +#pragma comment(lib, "Bcrypt.lib") +#endif + +#include "mini_server.h" +#include + +#define REQ_BUF_SIZE 2048 + +typedef struct xqc_mini_svr_user_stream_s { + xqc_h3_request_t *h3_request; + + // uint64_t send_offset; + int header_sent; + int header_recvd; + size_t send_body_len; + size_t recv_body_len; + char *recv_buf; +} xqc_mini_svr_user_stream_t; + + +/* engine callbacks */ +void xqc_mini_svr_engine_cb(int fd, short what, void *arg); + +void xqc_mini_svr_set_event_timer(xqc_msec_t wake_after, void *arg); + +int xqc_mini_svr_open_log_file(void *arg); + +void xqc_mini_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, void *arg); + +void xqc_mini_svr_close_log_file(void *arg); + +void xqc_mini_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *arg); + +int xqc_mini_svr_open_keylog_file(void *arg); + +void xqc_mini_svr_keylog_cb(const xqc_cid_t *scid, const char *line, void *arg); + +void xqc_mini_svr_close_keylog_file(void *arg); + +int xqc_mini_svr_accept(xqc_engine_t *engine, xqc_connection_t *conn, const xqc_cid_t *cid, + void *eng_user_data); + +ssize_t xqc_mini_svr_write_socket(const unsigned char *buf, size_t size, const struct sockaddr *peer_addr, + socklen_t peer_addrlen, void *arg); + +ssize_t xqc_mini_svr_write_socket_ex(uint64_t path_id, const unsigned char *buf, size_t size, + const struct sockaddr *peer_addr,socklen_t peer_addrlen, void *arg); + +void xqc_mini_svr_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retire_cid, + const xqc_cid_t *new_cid, void *user_data); + +/* h3 callbacks */ +int xqc_mini_svr_h3_conn_create_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data); + +int xqc_mini_svr_h3_conn_close_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *cid, + void *conn_user_data); + +void xqc_mini_svr_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *conn_user_data); + +int xqc_mini_svr_h3_request_create_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_h3_request_close_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_flag_t flag, + void *strm_user_data); + +int xqc_mini_svr_h3_request_write_notify(xqc_h3_request_t *h3_request, void *strm_user_data); + +int xqc_mini_svr_send_body(xqc_mini_svr_user_stream_t *user_stream); +#endif \ No newline at end of file diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index 412cc5a4..73a8bef4 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -73,70 +73,70 @@ extern const xqc_tls_callbacks_t xqc_conn_tls_cbs; typedef enum { /* server */ XQC_CONN_STATE_SERVER_INIT = 0, - XQC_CONN_STATE_SERVER_INITIAL_RECVD, - XQC_CONN_STATE_SERVER_INITIAL_SENT, - XQC_CONN_STATE_SERVER_HANDSHAKE_SENT, - XQC_CONN_STATE_SERVER_HANDSHAKE_RECVD, + XQC_CONN_STATE_SERVER_INITIAL_RECVD = 1, + XQC_CONN_STATE_SERVER_INITIAL_SENT = 2, + XQC_CONN_STATE_SERVER_HANDSHAKE_SENT = 3, + XQC_CONN_STATE_SERVER_HANDSHAKE_RECVD = 4, /* client */ XQC_CONN_STATE_CLIENT_INIT = 5, - XQC_CONN_STATE_CLIENT_INITIAL_SENT, - XQC_CONN_STATE_CLIENT_INITIAL_RECVD, - XQC_CONN_STATE_CLIENT_HANDSHAKE_RECVD, - XQC_CONN_STATE_CLIENT_HANDSHAKE_SENT, + XQC_CONN_STATE_CLIENT_INITIAL_SENT = 6, + XQC_CONN_STATE_CLIENT_INITIAL_RECVD = 7, + XQC_CONN_STATE_CLIENT_HANDSHAKE_RECVD = 8, + XQC_CONN_STATE_CLIENT_HANDSHAKE_SENT = 9, /* client & server */ XQC_CONN_STATE_ESTABED = 10, - XQC_CONN_STATE_CLOSING, - XQC_CONN_STATE_DRAINING, - XQC_CONN_STATE_CLOSED, - XQC_CONN_STATE_N, + XQC_CONN_STATE_CLOSING = 11, + XQC_CONN_STATE_DRAINING = 12, + XQC_CONN_STATE_CLOSED = 13, + XQC_CONN_STATE_N = 14, } xqc_conn_state_t; #define XQC_CONN_IMMEDIATE_CLOSE_FLAGS (XQC_CONN_FLAG_ERROR) /* !!WARNING: to add flag, please update conn_flag_2_str */ typedef enum { - XQC_CONN_FLAG_WAIT_WAKEUP_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT, - XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT, - XQC_CONN_FLAG_TICKING_SHIFT, - XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT, - XQC_CONN_FLAG_TIME_OUT_SHIFT, - XQC_CONN_FLAG_ERROR_SHIFT, - XQC_CONN_FLAG_DATA_BLOCKED_SHIFT, - XQC_CONN_FLAG_DCID_OK_SHIFT, - XQC_CONN_FLAG_TOKEN_OK_SHIFT, - XQC_CONN_FLAG_HAS_0RTT_SHIFT, - XQC_CONN_FLAG_0RTT_OK_SHIFT, - XQC_CONN_FLAG_0RTT_REJ_SHIFT, - XQC_CONN_FLAG_UPPER_CONN_EXIST_SHIFT, - XQC_CONN_FLAG_INIT_RECVD_SHIFT, - XQC_CONN_FLAG_NEED_RUN_SHIFT, - XQC_CONN_FLAG_PING_SHIFT, - XQC_CONN_FLAG_HSK_ACKED_SHIFT, - XQC_CONN_FLAG_RESERVE_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_DONE_RECVD_SHIFT, - XQC_CONN_FLAG_UPDATE_NEW_TOKEN_SHIFT, - XQC_CONN_FLAG_VERSION_NEGOTIATION_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT, - XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT, - XQC_CONN_FLAG_LINGER_CLOSING_SHIFT, - XQC_CONN_FLAG_RETRY_RECVD_SHIFT, - XQC_CONN_FLAG_TLS_CH_SHIFT, - XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT, - XQC_CONN_FLAG_RECV_NEW_PATH_SHIFT, - XQC_CONN_FLAG_VALIDATE_REBINDING_SHIFT, - XQC_CONN_FLAG_CONN_CLOSING_NOTIFY_SHIFT, - XQC_CONN_FLAG_CONN_CLOSING_NOTIFIED_SHIFT, - XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT_SHIFT, - XQC_CONN_FLAG_LOCAL_TP_UPDATED_SHIFT, - XQC_CONN_FLAG_PMTUD_PROBING_SHIFT, - XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT, - XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT, - XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT, - XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, - XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT, - XQC_CONN_FLAG_SHIFT_NUM, + XQC_CONN_FLAG_WAIT_WAKEUP_SHIFT = 0, + XQC_CONN_FLAG_HANDSHAKE_COMPLETED_SHIFT = 1, + XQC_CONN_FLAG_CAN_SEND_1RTT_SHIFT = 2, + XQC_CONN_FLAG_TICKING_SHIFT = 3, + XQC_CONN_FLAG_ACK_HAS_GAP_SHIFT = 4, + XQC_CONN_FLAG_TIME_OUT_SHIFT = 5, + XQC_CONN_FLAG_ERROR_SHIFT = 6, + XQC_CONN_FLAG_DATA_BLOCKED_SHIFT = 7, + XQC_CONN_FLAG_DCID_OK_SHIFT = 8, + XQC_CONN_FLAG_TOKEN_OK_SHIFT = 9, + XQC_CONN_FLAG_HAS_0RTT_SHIFT = 10, + XQC_CONN_FLAG_0RTT_OK_SHIFT = 11, + XQC_CONN_FLAG_0RTT_REJ_SHIFT = 12, + XQC_CONN_FLAG_UPPER_CONN_EXIST_SHIFT = 13, + XQC_CONN_FLAG_INIT_RECVD_SHIFT = 14, + XQC_CONN_FLAG_NEED_RUN_SHIFT = 15, + XQC_CONN_FLAG_PING_SHIFT = 16, + XQC_CONN_FLAG_HSK_ACKED_SHIFT = 17, + XQC_CONN_FLAG_RESERVE_SHIFT = 18, + XQC_CONN_FLAG_HANDSHAKE_DONE_RECVD_SHIFT = 19, + XQC_CONN_FLAG_UPDATE_NEW_TOKEN_SHIFT = 20, + XQC_CONN_FLAG_VERSION_NEGOTIATION_SHIFT = 21, + XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT = 22, + XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT = 23, + XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT = 24, + XQC_CONN_FLAG_LINGER_CLOSING_SHIFT = 25, + XQC_CONN_FLAG_RETRY_RECVD_SHIFT = 26, + XQC_CONN_FLAG_TLS_CH_SHIFT = 27, + XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT = 28, + XQC_CONN_FLAG_RECV_NEW_PATH_SHIFT = 29, + XQC_CONN_FLAG_VALIDATE_REBINDING_SHIFT = 30, + XQC_CONN_FLAG_CONN_CLOSING_NOTIFY_SHIFT = 31, + XQC_CONN_FLAG_CONN_CLOSING_NOTIFIED_SHIFT = 32, + XQC_CONN_FLAG_DGRAM_WAIT_FOR_1RTT_SHIFT = 33, + XQC_CONN_FLAG_LOCAL_TP_UPDATED_SHIFT = 34, + XQC_CONN_FLAG_PMTUD_PROBING_SHIFT = 35, + XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT = 36, + XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT = 37, + XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT = 38, + XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT = 39, + XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT = 40, + XQC_CONN_FLAG_SHIFT_NUM = 41, } xqc_conn_flag_shift_t; typedef enum { diff --git a/src/transport/xqc_stream.h b/src/transport/xqc_stream.h index 6692d819..ea8b1357 100644 --- a/src/transport/xqc_stream.h +++ b/src/transport/xqc_stream.h @@ -41,21 +41,21 @@ typedef enum { } xqc_stream_flag_t; typedef enum { - XQC_SEND_STREAM_ST_READY, - XQC_SEND_STREAM_ST_SEND, - XQC_SEND_STREAM_ST_DATA_SENT, - XQC_SEND_STREAM_ST_DATA_RECVD, - XQC_SEND_STREAM_ST_RESET_SENT, - XQC_SEND_STREAM_ST_RESET_RECVD, + XQC_SEND_STREAM_ST_READY = 0, + XQC_SEND_STREAM_ST_SEND = 1, + XQC_SEND_STREAM_ST_DATA_SENT = 2, + XQC_SEND_STREAM_ST_DATA_RECVD = 3, + XQC_SEND_STREAM_ST_RESET_SENT = 4, + XQC_SEND_STREAM_ST_RESET_RECVD = 5, } xqc_send_stream_state_t; typedef enum { - XQC_RECV_STREAM_ST_RECV, - XQC_RECV_STREAM_ST_SIZE_KNOWN, - XQC_RECV_STREAM_ST_DATA_RECVD, - XQC_RECV_STREAM_ST_DATA_READ, - XQC_RECV_STREAM_ST_RESET_RECVD, - XQC_RECV_STREAM_ST_RESET_READ, + XQC_RECV_STREAM_ST_RECV = 0, + XQC_RECV_STREAM_ST_SIZE_KNOWN = 1, + XQC_RECV_STREAM_ST_DATA_RECVD = 2, + XQC_RECV_STREAM_ST_DATA_READ = 3, + XQC_RECV_STREAM_ST_RESET_RECVD = 4, + XQC_RECV_STREAM_ST_RESET_READ = 5, } xqc_recv_stream_state_t; typedef struct { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bcd2b0e2..de82f8a8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,12 +21,18 @@ include_directories( ${LIBEVENT_INCLUDE_DIR} ) +set(TEST_PLATFORM_SOURCES + platform.c +) + set(TEST_SERVER_SOURCES test_server.c + ${TEST_PLATFORM_SOURCES} ) set(TEST_CLIENT_SOURCES test_client.c + ${TEST_PLATFORM_SOURCES} ) if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") diff --git a/tests/platform.c b/tests/platform.c new file mode 100644 index 00000000..d7e75001 --- /dev/null +++ b/tests/platform.c @@ -0,0 +1,49 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include "platform.h" + +/** + * @brief get system last errno + * + * @return int + */ +int get_sys_errno() +{ + int err = 0; +#ifdef XQC_SYS_WINDOWS + err = WSAGetLastError(); +#else + err = errno; +#endif + return err; +} + +void set_sys_errno(int err) +{ +#ifdef XQC_SYS_WINDOWS + WSASetLastError(err); +#else + errno = err; +#endif +} + +/** + * @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 + +} diff --git a/tests/platform.h b/tests/platform.h index d3435932..534c38bb 100644 --- a/tests/platform.h +++ b/tests/platform.h @@ -5,6 +5,8 @@ #ifndef PLATFORM_H #define PLATFORM_H +#include + #if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) #define XQC_SYS_WINDOWS #endif @@ -20,42 +22,13 @@ * * @return int */ -static inline int get_sys_errno() -{ - int err = 0; -#ifdef XQC_SYS_WINDOWS - err = WSAGetLastError(); -#else - err = errno; -#endif - return err; -} +int get_sys_errno(); -static inline void set_sys_errno(int err) -{ -#ifdef XQC_SYS_WINDOWS - WSASetLastError(err); -#else - errno = err; -#endif -} +void set_sys_errno(int err); /** * @brief init platform env if necessary * */ -static inline void xqc_platform_init_env() -{ - int result = 0; - - #ifdef XQC_SYS_WINDOWS - // Initialize Winsock - WSADATA wsaData; - if ((result = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { - printf("WSAStartup failed with error %d\n", result); - exit(1); - } -#endif - -} +void xqc_platform_init_env(); #endif