cmake_minimum_required(VERSION 3.24)
project(net C CXX)


set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)

set(VPN_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(THIRD_PARTY_DIR ${VPN_LIB_DIR}/third-party)
set(NET_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)

set(SOURCE_FILES
        ${NET_SOURCE_DIR}/tcp_socket.cpp
        ${NET_SOURCE_DIR}/udp_socket.cpp
        ${NET_SOURCE_DIR}/tls.cpp
        ${NET_SOURCE_DIR}/http_header.cpp
        ${NET_SOURCE_DIR}/http_session.cpp
        ${NET_SOURCE_DIR}/http_stream.cpp
        ${NET_SOURCE_DIR}/http1.cpp
        ${NET_SOURCE_DIR}/http2.cpp
        ${NET_SOURCE_DIR}/utils.cpp
        ${NET_SOURCE_DIR}/socks5_listener.cpp
        ${NET_SOURCE_DIR}/dns_manager.cpp
        ${NET_SOURCE_DIR}/socket_manager.cpp
        ${NET_SOURCE_DIR}/network_manager.cpp
        ${NET_SOURCE_DIR}/ping.cpp
        ${NET_SOURCE_DIR}/locations_pinger.cpp
        ${NET_SOURCE_DIR}/locations_pinger_runner.cpp
        ${NET_SOURCE_DIR}/dns_utils.cpp
        ${NET_SOURCE_DIR}/quic_utils.cpp
        ${NET_SOURCE_DIR}/os_tunnel.cpp
        ${NET_SOURCE_DIR}/tls13_utils.cpp
        ${NET_SOURCE_DIR}/quic_connector.cpp
    )

if(APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL iOS)
    list(APPEND SOURCE_FILES ${NET_SOURCE_DIR}/os_tunnel_mac.cpp)
    list(APPEND SOURCE_FILES ${NET_SOURCE_DIR}/mac_dns_settings_manager.mm)
elseif(WIN32)
    list(APPEND SOURCE_FILES ${NET_SOURCE_DIR}/os_tunnel_win.cpp)
    list(APPEND SOURCE_FILES ${NET_SOURCE_DIR}/wincrypt_helper.cpp)
elseif(CMAKE_SYSTEM_NAME STREQUAL Linux)
    list(APPEND SOURCE_FILES ${NET_SOURCE_DIR}/os_tunnel_linux.cpp)
endif()

add_library(vpnlibs_net STATIC EXCLUDE_FROM_ALL ${SOURCE_FILES})
set_target_properties(vpnlibs_net PROPERTIES POSITION_INDEPENDENT_CODE ON)
if (NOT MSVC)
    if(APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL iOS)
        target_compile_options(vpnlibs_net PRIVATE -fobjc-arc)
        target_link_libraries(vpnlibs_net "-framework Foundation" "-framework SystemConfiguration")
    endif()
else()
    target_include_directories(vpnlibs_net PRIVATE ${THIRD_PARTY_DIR}/wintun/include)
endif()
target_include_directories(vpnlibs_net PUBLIC include)

find_package(ZLIB REQUIRED)
find_package(brotli REQUIRED)
find_package(http_parser REQUIRED)
find_package(ldns REQUIRED)
find_package(nghttp2 REQUIRED)
find_package(klib REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(libevent REQUIRED)
find_package(magic_enum REQUIRED)
find_package(ngtcp2 REQUIRED)
if (NOT DISABLE_HTTP3)
    find_package(quiche REQUIRED)
endif()

if(NOT TARGET vpnlibs_common)
    add_subdirectory(${VPN_LIB_DIR}/common ${CMAKE_BINARY_DIR}/common)
endif(NOT TARGET vpnlibs_common)

target_link_libraries(vpnlibs_net vpnlibs_common)
target_link_libraries(vpnlibs_net ZLIB::ZLIB brotli::brotli http_parser::http_parser)
target_link_libraries(vpnlibs_net ldns::ldns nghttp2::nghttp2 klib::klib openssl::openssl)
target_link_libraries(vpnlibs_net libevent::libevent magic_enum::magic_enum ngtcp2::ngtcp2)
if (WIN32)
    target_link_libraries(vpnlibs_net Fwpuclnt) # WFP firewall
    target_link_libraries(vpnlibs_net wsock32 ws2_32 ntdll iphlpapi)
else()
    if (NOT ANDROID)
        target_link_libraries(vpnlibs_net resolv)
    endif()
    if (APPLE)
        target_link_libraries(vpnlibs_net "-framework CoreFoundation" "-framework Security")
    endif ()
endif()
if (NOT DISABLE_HTTP3)
    target_link_libraries(vpnlibs_net quiche::quiche)
    if (WIN32)
        target_link_libraries(vpnlibs_net BCrypt) # Quiche requirement
    endif()
else()
    target_compile_definitions(vpnlibs_net PRIVATE DISABLE_HTTP3)
endif()

enable_testing()

find_package(nlohmann_json REQUIRED)
include(${VPN_LIB_DIR}/cmake/add_unit_test.cmake)
include(${VPN_LIB_DIR}/cmake/add_live_test.cmake)
link_libraries(vpnlibs_net nlohmann_json::nlohmann_json)
set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
set(TEST_EXTRA_INCLUDES ${NET_SOURCE_DIR})

add_library(ja4 STATIC EXCLUDE_FROM_ALL test/ja4.cpp)
target_include_directories(ja4 PUBLIC test)

find_package(fmt REQUIRED)
target_link_libraries(ja4 openssl::openssl fmt::fmt)

link_libraries(ja4)

add_unit_test(test_http_headers "${TEST_DIR}" "" FALSE FALSE)
add_unit_test(test_tls_parse "${TEST_DIR}" "" FALSE FALSE)
add_unit_test(test_ping_offline "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_live_test(test_ping "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_quic_parse "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_locations_pinger_offline "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_locations_pinger_runner_offline "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_live_test(test_locations_pinger "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_live_test(test_locations_pinger_runner "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_dns_utils "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_tls_serialize "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
add_unit_test(test_net_utils "${TEST_DIR}" "${TEST_EXTRA_INCLUDES}" TRUE TRUE)
