#include <gtest/gtest.h>

#include "tuple.h"
#include "packet_private.h"
#include "packet_parser.h"
#include "session_private.h"
#include "session_manager.h"

struct session_manager_options opts = {
    // max session number
    .max_tcp_session_num = 256,
    .max_udp_session_num = 256,

    // session overload
    .tcp_overload_evict_old_sess = 1, // 1: evict old session, 0: bypass new session
    .udp_overload_evict_old_sess = 1, // 1: evict old session, 0: bypass new session

    // tcp timeout
    .tcp_init_timeout = 1,
    .tcp_handshake_timeout = 2,
    .tcp_data_timeout = 3,
    .tcp_half_closed_timeout = 4,
    .tcp_time_wait_timeout = 5,
    .tcp_discard_timeout = 6,
    .tcp_unverified_rst_timeout = 7,

    // udp timeout
    .udp_data_timeout = 8,
    .udp_discard_timeout = 0,

    // duplicate packet filter
    .duplicated_packet_filter_enable = 1,
    .duplicated_packet_filter_capacity = 1000,
    .duplicated_packet_filter_timeout = 10,
    .duplicated_packet_filter_error_rate = 0.0001,

    // evicted session filter
    .evicted_session_filter_enable = 1,
    .evicted_session_filter_capacity = 1000,
    .evicted_session_filter_timeout = 10,
    .evicted_session_filter_error_rate = 0.0001,

    // TCP Reassembly
    .tcp_reassembly_enable = 1,
    .tcp_reassembly_max_timeout = 60000,
    .tcp_reassembly_max_segments = 16,
};

static uint64_t session_id_generator(uint64_t now_ms __attribute__((unused)))
{
    static uint64_t count = 0;
    return (++count);
}

/******************************************************************************
 * case: TCP init -> opening (by TCP Fast Open)
 ******************************************************************************/

/*
 * Frame 1: 280 bytes on wire (2240 bits), 280 bytes captured (2240 bits)
 * Ethernet II, Src: HuaweiTechno_72:e3:9c (c8:b6:d3:72:e3:9c), Dst: HuaweiTechno_38:45:cb (28:b4:48:38:45:cb)
 *     Destination: HuaweiTechno_38:45:cb (28:b4:48:38:45:cb)
 *         Address: HuaweiTechno_38:45:cb (28:b4:48:38:45:cb)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Source: HuaweiTechno_72:e3:9c (c8:b6:d3:72:e3:9c)
 *         Address: HuaweiTechno_72:e3:9c (c8:b6:d3:72:e3:9c)
 *         .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
 *         .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
 *     Type: MPLS label switched packet (0x8847)
 * MultiProtocol Label Switching Header, Label: 0 (IPv4 Explicit-Null), Exp: 0, S: 0, TTL: 254
 *     0000 0000 0000 0000 0000 .... .... .... = MPLS Label: IPv4 Explicit-Null (0)
 *     .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
 *     .... .... .... .... .... ...0 .... .... = MPLS Bottom Of Label Stack: 0
 *     .... .... .... .... .... .... 1111 1110 = MPLS TTL: 254
 * MultiProtocol Label Switching Header, Label: 2 (IPv6 Explicit-Null), Exp: 0, S: 1, TTL: 255
 *     0000 0000 0000 0000 0010 .... .... .... = MPLS Label: IPv6 Explicit-Null (2)
 *     .... .... .... .... .... 000. .... .... = MPLS Experimental Bits: 0
 *     .... .... .... .... .... ...1 .... .... = MPLS Bottom Of Label Stack: 1
 *     .... .... .... .... .... .... 1111 1111 = MPLS TTL: 255
 * Internet Protocol Version 6, Src: 2400:ac40:620:a4d8:484f:d2b0:d539:bd4c, Dst: 2001:4860:4860::8844
 *     0110 .... = Version: 6
 *     .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
 *         .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
 *         .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
 *     .... 0111 1110 0101 0101 1110 = Flow Label: 0x7e55e
 *     Payload Length: 218
 *     Next Header: TCP (6)
 *     Hop Limit: 61
 *     Source Address: 2400:ac40:620:a4d8:484f:d2b0:d539:bd4c
 *     Destination Address: 2001:4860:4860::8844
 * Transmission Control Protocol, Src Port: 51682, Dst Port: 853, Seq: 568467008, Len: 166
 *     Source Port: 51682
 *     Destination Port: 853
 *     [Stream index: 0]
 *     [Conversation completeness: Incomplete, DATA (15)]
 *         ..0. .... = RST: Absent
 *         ...0 .... = FIN: Absent
 *         .... 1... = Data: Present
 *         .... .1.. = ACK: Present
 *         .... ..1. = SYN-ACK: Present
 *         .... ...1 = SYN: Present
 *         [Completeness Flags: ··DASS]
 *     [TCP Segment Len: 166]
 *     Sequence Number: 568467008
 *     [Next Sequence Number: 568467175]
 *     Acknowledgment Number: 0
 *     Acknowledgment number (raw): 0
 *     1101 .... = Header Length: 52 bytes (13)
 *     Flags: 0x002 (SYN)
 *         000. .... .... = Reserved: Not set
 *         ...0 .... .... = Accurate ECN: Not set
 *         .... 0... .... = Congestion Window Reduced: Not set
 *         .... .0.. .... = ECN-Echo: Not set
 *         .... ..0. .... = Urgent: Not set
 *         .... ...0 .... = Acknowledgment: Not set
 *         .... .... 0... = Push: Not set
 *         .... .... .0.. = Reset: Not set
 *         .... .... ..1. = Syn: Set
 *             [Expert Info (Chat/Sequence): Connection establish request (SYN): server port 853]
 *                 [Connection establish request (SYN): server port 853]
 *                 [Severity level: Chat]
 *                 [Group: Sequence]
 *         .... .... ...0 = Fin: Not set
 *         [TCP Flags: ··········S·]
 *     Window: 65535
 *     [Calculated window size: 65535]
 *     Checksum: 0x53f0 [correct]
 *         [Calculated Checksum: 0x53f0]
 *     [Checksum Status: Good]
 *     Urgent Pointer: 0
 *     Options: (32 bytes), Maximum segment size, SACK permitted, Timestamps, No-Operation (NOP), Window scale, TCP Fast Open, No-Operation (NOP), No-Operation (NOP)
 *         TCP Option - Maximum segment size: 1400 bytes
 *             Kind: Maximum Segment Size (2)
 *             Length: 4
 *             MSS Value: 1400
 *         TCP Option - SACK permitted
 *             Kind: SACK Permitted (4)
 *             Length: 2
 *         TCP Option - Timestamps: TSval 16364661, TSecr 0
 *             Kind: Time Stamp Option (8)
 *             Length: 10
 *             Timestamp value: 16364661
 *             Timestamp echo reply: 0
 *         TCP Option - No-Operation (NOP)
 *             Kind: No-Operation (1)
 *         TCP Option - Window scale: 8 (multiply by 256)
 *             Kind: Window Scale (3)
 *             Length: 3
 *             Shift count: 8
 *             [Multiplier: 256]
 *         TCP Option - TCP Fast Open
 *             Kind: TCP Fast Open Cookie (34)
 *             Length: 10
 *             Fast Open Cookie: e32ac2dbde890634
 *                 [Expert Info (Note/Sequence): TCP SYN with TFO Cookie]
 *                     [TCP SYN with TFO Cookie]
 *                     [Severity level: Note]
 *                     [Group: Sequence]
 *         TCP Option - No-Operation (NOP)
 *             Kind: No-Operation (1)
 *         TCP Option - No-Operation (NOP)
 *             Kind: No-Operation (1)
 *     [Timestamps]
 *         [Time since first frame in this TCP stream: 0.000000000 seconds]
 *         [Time since previous frame in this TCP stream: 0.000000000 seconds]
 *     [SEQ/ACK analysis]
 *         [iRTT: 0.040396000 seconds]
 *         [Bytes in flight: 166]
 *         [Bytes sent since last PSH flag: 166]
 *     TCP payload (166 bytes)
 * Transport Layer Security
 *     TLSv1.2 Record Layer: Handshake Protocol: Client Hello
 *         Content Type: Handshake (22)
 *         Version: TLS 1.0 (0x0301)
 *         Length: 161
 *         Handshake Protocol: Client Hello
 *             Handshake Type: Client Hello (1)
 *             Length: 157
 *             Version: TLS 1.2 (0x0303)
 *             Random: 587de49beac1db68e5b853c303c181eaa64c2ac984f5ff6e7ca05f8978cc72b4
 *                 GMT Unix Time: Jan 17, 2017 17:32:11.000000000 CST
 *                 Random Bytes: eac1db68e5b853c303c181eaa64c2ac984f5ff6e7ca05f8978cc72b4
 *             Session ID Length: 0
 *             Cipher Suites Length: 42
 *             Cipher Suites (21 suites)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
 *                 Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
 *                 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
 *                 Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
 *                 Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
 *                 Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
 *                 Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
 *                 Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
 *                 Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
 *                 Cipher Suite: TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a)
 *             Compression Methods Length: 1
 *             Compression Methods (1 method)
 *                 Compression Method: null (0)
 *             Extensions Length: 74
 *             Extension: renegotiation_info (len=1)
 *                 Type: renegotiation_info (65281)
 *                 Length: 1
 *                 Renegotiation Info extension
 *                     Renegotiation info extension length: 0
 *             Extension: server_name (len=15) name=dns.google
 *                 Type: server_name (0)
 *                 Length: 15
 *                 Server Name Indication extension
 *                     Server Name list length: 13
 *                     Server Name Type: host_name (0)
 *                     Server Name length: 10
 *                     Server Name: dns.google
 *             Extension: extended_master_secret (len=0)
 *                 Type: extended_master_secret (23)
 *                 Length: 0
 *             Extension: session_ticket (len=0)
 *                 Type: session_ticket (35)
 *                 Length: 0
 *                 Session Ticket: <MISSING>
 *             Extension: signature_algorithms (len=20)
 *                 Type: signature_algorithms (13)
 *                 Length: 20
 *                 Signature Hash Algorithms Length: 18
 *                 Signature Hash Algorithms (9 algorithms)
 *                     Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
 *                         Signature Hash Algorithm Hash: SHA256 (4)
 *                         Signature Hash Algorithm Signature: ECDSA (3)
 *                     Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
 *                         Signature Hash Algorithm Hash: Unknown (8)
 *                         Signature Hash Algorithm Signature: SM2 (4)
 *                     Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
 *                         Signature Hash Algorithm Hash: SHA256 (4)
 *                         Signature Hash Algorithm Signature: RSA (1)
 *                     Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
 *                         Signature Hash Algorithm Hash: SHA384 (5)
 *                         Signature Hash Algorithm Signature: ECDSA (3)
 *                     Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
 *                         Signature Hash Algorithm Hash: Unknown (8)
 *                         Signature Hash Algorithm Signature: Unknown (5)
 *                     Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
 *                         Signature Hash Algorithm Hash: SHA384 (5)
 *                         Signature Hash Algorithm Signature: RSA (1)
 *                     Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
 *                         Signature Hash Algorithm Hash: Unknown (8)
 *                         Signature Hash Algorithm Signature: Unknown (6)
 *                     Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
 *                         Signature Hash Algorithm Hash: SHA512 (6)
 *                         Signature Hash Algorithm Signature: RSA (1)
 *                     Signature Algorithm: rsa_pkcs1_sha1 (0x0201)
 *                         Signature Hash Algorithm Hash: SHA1 (2)
 *                         Signature Hash Algorithm Signature: RSA (1)
 *             Extension: ec_point_formats (len=2)
 *                 Type: ec_point_formats (11)
 *                 Length: 2
 *                 EC point formats Length: 1
 *                 Elliptic curves point formats (1)
 *                     EC point format: uncompressed (0)
 *             Extension: supported_groups (len=8)
 *                 Type: supported_groups (10)
 *                 Length: 8
 *                 Supported Groups List Length: 6
 *                 Supported Groups (3 groups)
 *                     Supported Group: x25519 (0x001d)
 *                     Supported Group: secp256r1 (0x0017)
 *                     Supported Group: secp384r1 (0x0018)
 *             [JA4: t12d210700_893976a58eef_0f3b2bcde21d]
 *             [JA4_r: t12d210700_000a,002f,0035,003c,003d,009c,009d,c009,c00a,c013,c014,c023,c024,c027,c028,c02b,c02c,c02f,c030,cca8,cca9_000a,000b,000d,0017,0023,ff01_0403,0804,0401,0503,0805,0501,0806,0601,0201]
 *             [JA3 Fullstring: 771,49195-49199-49196-49200-52393-52392-49161-49187-49171-49191-49162-49188-49172-49192-156-157-47-60-53-61-10,65281-0-23-35-13-11-10,29-23-24,0]
 *             [JA3: c20814b8dc467558acf2a4cd0551cf45]
 */

unsigned char tcp_fast_open_pkt[] = {
    0x28, 0xb4, 0x48, 0x38, 0x45, 0xcb, 0xc8, 0xb6, 0xd3, 0x72, 0xe3, 0x9c, 0x88, 0x47, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x21, 0xff, 0x60, 0x07, 0xe5, 0x5e,
    0x00, 0xda, 0x06, 0x3d, 0x24, 0x00, 0xac, 0x40, 0x06, 0x20, 0xa4, 0xd8, 0x48, 0x4f, 0xd2, 0xb0, 0xd5, 0x39, 0xbd, 0x4c, 0x20, 0x01, 0x48, 0x60, 0x48, 0x60,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x44, 0xc9, 0xe2, 0x03, 0x55, 0x21, 0xe2, 0x1e, 0x40, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x02, 0xff, 0xff,
    0x53, 0xf0, 0x00, 0x00, 0x02, 0x04, 0x05, 0x78, 0x04, 0x02, 0x08, 0x0a, 0x00, 0xf9, 0xb4, 0x75, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x08, 0x22, 0x0a,
    0xe3, 0x2a, 0xc2, 0xdb, 0xde, 0x89, 0x06, 0x34, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, 0xa1, 0x01, 0x00, 0x00, 0x9d, 0x03, 0x03, 0x58, 0x7d, 0xe4, 0x9b, 0xea,
    0xc1, 0xdb, 0x68, 0xe5, 0xb8, 0x53, 0xc3, 0x03, 0xc1, 0x81, 0xea, 0xa6, 0x4c, 0x2a, 0xc9, 0x84, 0xf5, 0xff, 0x6e, 0x7c, 0xa0, 0x5f, 0x89, 0x78, 0xcc, 0x72,
    0xb4, 0x00, 0x00, 0x2a, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a,
    0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x4a, 0xff, 0x01,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0x00, 0x0a, 0x64, 0x6e, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x00, 0x17, 0x00, 0x00,
    0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01,
    0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18};

unsigned char tcp_fast_open_payload[] = {
    0x16, 0x03, 0x01, 0x00, 0xa1, 0x01, 0x00, 0x00, 0x9d, 0x03, 0x03, 0x58, 0x7d, 0xe4, 0x9b, 0xea, 0xc1, 0xdb, 0x68, 0xe5, 0xb8, 0x53, 0xc3, 0x03, 0xc1, 0x81,
    0xea, 0xa6, 0x4c, 0x2a, 0xc9, 0x84, 0xf5, 0xff, 0x6e, 0x7c, 0xa0, 0x5f, 0x89, 0x78, 0xcc, 0x72, 0xb4, 0x00, 0x00, 0x2a, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c,
    0xc0, 0x30, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x09, 0xc0, 0x23, 0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x24, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x9c, 0x00, 0x9d,
    0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x4a, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0d, 0x00,
    0x00, 0x0a, 0x64, 0x6e, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12,
    0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a,
    0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18};

#if 1
TEST(CASE, TCP_FAST_OPEN)
{
    char buffer[1024] = {0};
    struct packet pkt;
    struct session *sess = NULL;
    struct session_manager *mgr = NULL;
    struct session_manager_stat *stat = NULL;

    mgr = session_manager_new(&opts, 1);
    EXPECT_TRUE(mgr != NULL);
    session_manager_set_session_id_generator(mgr, session_id_generator);

    // C2S SYN Packet
    printf("\n=> Packet Parse: TCP C2S fast open packet\n");
    memset(&pkt, 0, sizeof(pkt));
    packet_parse(&pkt, (const char *)tcp_fast_open_pkt, sizeof(tcp_fast_open_pkt));
    printf("<= Packet Parse: done\n\n");

    // lookup session
    EXPECT_TRUE(session_manager_lookup_session_by_packet(mgr, &pkt) == NULL);
    // new session
    sess = session_manager_new_session(mgr, &pkt, 1);
    EXPECT_TRUE(sess);

    EXPECT_TRUE(session_get_id(sess) != 0);
    tuple6_to_str(session_get_tuple6(sess), buffer, sizeof(buffer));
    EXPECT_STREQ(buffer, "2400:ac40:620:a4d8:484f:d2b0:d539:bd4c:51682-2001:4860:4860::8844:853-6-0");
    EXPECT_TRUE(session_get_current_state(sess) == SESSION_STATE_OPENING);
    EXPECT_TRUE(session_get_type(sess) == SESSION_TYPE_TCP);
    EXPECT_TRUE(session_has_duplicate_traffic(sess) == 0);
    EXPECT_TRUE(session_get_closing_reason(sess) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_RAW_BYTES_RECEIVED) == 280);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_RAW_BYTES_RECEIVED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_RAW_PACKETS_RECEIVED) == 1);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_RAW_PACKETS_RECEIVED) == 0);
    EXPECT_TRUE(session_get_timestamp(sess, SESSION_TIMESTAMP_START));
    EXPECT_TRUE(session_get_timestamp(sess, SESSION_TIMESTAMP_LAST));
    EXPECT_TRUE(session_get0_current_packet(sess) == &pkt);
    EXPECT_TRUE(session_get_current_flow_direction(sess) == FLOW_DIRECTION_C2S);
    EXPECT_TRUE(session_get_first_packet(sess, FLOW_DIRECTION_C2S) != NULL);
    EXPECT_TRUE(session_get_first_packet(sess, FLOW_DIRECTION_S2C) == NULL);

    // TCP Segment
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_RECEIVED) == 1);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_RECEIVED) == 166);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_EXPIRED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_EXPIRED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_RETRANSMIT) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_RETRANSMIT) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_OVERLAP) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_OVERLAP) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_NOSPACE) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_NOSPACE) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_INORDER) == 1);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_INORDER) == 166);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_REORDERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_REORDERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_BUFFERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_BUFFERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_SEGMENTS_RELEASED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_C2S, STAT_TCP_PAYLOADS_RELEASED) == 0);

    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_RECEIVED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_RECEIVED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_EXPIRED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_EXPIRED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_RETRANSMIT) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_RETRANSMIT) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_OVERLAP) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_OVERLAP) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_NOSPACE) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_NOSPACE) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_INORDER) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_INORDER) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_REORDERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_REORDERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_BUFFERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_BUFFERED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_SEGMENTS_RELEASED) == 0);
    EXPECT_TRUE(session_get_stat(sess, FLOW_DIRECTION_S2C, STAT_TCP_PAYLOADS_RELEASED) == 0);

    session_print(sess);

    struct tcp_segment *seg = session_get_tcp_segment(sess);
    EXPECT_TRUE(seg);
    EXPECT_TRUE(seg->len == sizeof(tcp_fast_open_payload));
    EXPECT_TRUE(memcmp(seg->data, tcp_fast_open_payload, seg->len) == 0);
    session_free_tcp_segment(sess, seg);

    // check stat
    stat = session_manager_stat(mgr);
    EXPECT_TRUE(stat);
    EXPECT_TRUE(stat->tcp_sess_used == 1);
    EXPECT_TRUE(stat->tcp_sess_opening == 1);
    EXPECT_TRUE(stat->tcp_sess_active == 0);
    EXPECT_TRUE(stat->tcp_sess_closing == 0);

    // expire session
    EXPECT_TRUE(session_manager_get_expired_session(mgr, 1 + opts.tcp_init_timeout) == NULL);           // opening -> closing
    sess = session_manager_get_expired_session(mgr, 1 + opts.tcp_init_timeout + opts.tcp_data_timeout); // closing -> closed
    EXPECT_TRUE(sess);
    EXPECT_TRUE(session_get_current_state(sess) == SESSION_STATE_CLOSED);
    EXPECT_TRUE(session_get_closing_reason(sess) == CLOSING_BY_TIMEOUT);
    session_print(sess);
    // free session
    session_manager_free_session(mgr, sess);

    // check stat
    stat = session_manager_stat(mgr);
    EXPECT_TRUE(stat);
    EXPECT_TRUE(stat->tcp_sess_used == 0);
    EXPECT_TRUE(stat->tcp_sess_opening == 0);
    EXPECT_TRUE(stat->tcp_sess_active == 0);
    EXPECT_TRUE(stat->tcp_sess_closing == 0);

    session_manager_free(mgr);
}
#endif

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}