cmake_minimum_required(VERSION 3.20)
project(packeteer CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Debug)
endif()

add_compile_options(-Wall -Wextra)

find_package(Threads REQUIRED)

include(FetchContent)
FetchContent_Declare(
  ftxui
  GIT_REPOSITORY https://github.com/ArthurSonzogni/FTXUI.git
  GIT_TAG v7.0.3
  GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(ftxui)

add_executable(packeteer src/main.cpp)
target_include_directories(packeteer PRIVATE include)
target_link_libraries(packeteer PRIVATE
  pcap
  Threads::Threads
  ftxui::component
  ftxui::dom
  ftxui::screen
)

# Standalone AF_PACKET/mmap ring buffer demo (see the file's own header
# comment for why this is separate from CaptureSession). AF_PACKET is a
# Linux-specific socket family, unlike the portable libpcap path the
# rest of this project uses - only built on Linux.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
  add_executable(packeteer_afpacket_demo src/afpacket_capture.cpp)
  target_include_directories(packeteer_afpacket_demo PRIVATE include)
  target_link_libraries(packeteer_afpacket_demo PRIVATE pcap)
endif()

# GUI (secondary to the TUI - see PLAN.md Decisions). Dear ImGui +
# SDL3, same FetchContent approach as FTXUI/doctest: no dependency on
# a system package, so it builds the same way on every platform this
# project targets. SDL3 over SDL2 because sdl2-compat (an SDL3-backed
# shim) is what's actually packaged in this ecosystem now - SDL3 is
# the live line. SDL_Renderer (not raw OpenGL3) avoids needing a
# separate GL function loader as another dependency.
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
set(SDL_STATIC ON CACHE BOOL "" FORCE)
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
  sdl3
  GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
  GIT_TAG release-3.4.14
  GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(sdl3)

FetchContent_Declare(
  imgui
  GIT_REPOSITORY https://github.com/ocornut/imgui.git
  GIT_TAG v1.92.9b
  GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(imgui)

add_library(imgui STATIC
  ${imgui_SOURCE_DIR}/imgui.cpp
  ${imgui_SOURCE_DIR}/imgui_draw.cpp
  ${imgui_SOURCE_DIR}/imgui_tables.cpp
  ${imgui_SOURCE_DIR}/imgui_widgets.cpp
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp
)
target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR} ${imgui_SOURCE_DIR}/backends)
target_link_libraries(imgui PUBLIC SDL3::SDL3)

add_executable(packeteer_gui src/gui_main.cpp)
target_include_directories(packeteer_gui PRIVATE include)
target_link_libraries(packeteer_gui PRIVATE pcap Threads::Threads imgui SDL3::SDL3)

enable_testing()

FetchContent_Declare(
  doctest
  GIT_REPOSITORY https://github.com/doctest/doctest.git
  GIT_TAG v2.5.3
  GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(doctest)

add_executable(packeteer_tests
  tests/main.cpp
  tests/test_byteio.cpp
  tests/test_net.cpp
  tests/test_ipv6.cpp
  tests/test_dns.cpp
  tests/test_mdns.cpp
  tests/test_ssh.cpp
  tests/test_http.cpp
  tests/test_tls.cpp
  tests/test_pcapng.cpp
  tests/test_capture_queue.cpp
  tests/test_filter.cpp
  tests/test_summarize.cpp
  tests/test_capture_session.cpp
  tests/test_search.cpp
  tests/test_privileges.cpp
  tests/test_icmp.cpp
  tests/test_checksum.cpp
  tests/test_tcp_reassembly.cpp
)
target_include_directories(packeteer_tests PRIVATE include)
target_link_libraries(packeteer_tests PRIVATE doctest::doctest Threads::Threads pcap)

add_test(NAME packeteer_tests COMMAND packeteer_tests)

# libFuzzer harnesses for the hand-rolled decoders - the actual point
# of this project (byte layout/alignment/UB) makes these the highest-
# value tests in the repo, not an afterthought. Opt-in and clang-only
# (libFuzzer is a clang/compiler-rt feature) so a normal `cmake --build`
# with the default compiler is unaffected.
option(PACKETEER_ENABLE_FUZZING "Build libFuzzer harnesses (requires clang)" OFF)
if(PACKETEER_ENABLE_FUZZING)
  if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    message(FATAL_ERROR "PACKETEER_ENABLE_FUZZING requires clang (libFuzzer); "
                         "reconfigure with -DCMAKE_CXX_COMPILER=clang++")
  endif()

  function(add_packeteer_fuzz_target name)
    add_executable(${name} fuzz/${name}.cpp)
    target_include_directories(${name} PRIVATE include)
    target_link_libraries(${name} PRIVATE pcap)
    target_compile_options(${name} PRIVATE -fsanitize=fuzzer,address,undefined -g -O1)
    target_link_options(${name} PRIVATE -fsanitize=fuzzer,address,undefined)
  endfunction()

  add_packeteer_fuzz_target(fuzz_ethernet)
  add_packeteer_fuzz_target(fuzz_ipv4)
  add_packeteer_fuzz_target(fuzz_ipv6)
  add_packeteer_fuzz_target(fuzz_tcp)
  add_packeteer_fuzz_target(fuzz_udp)
  add_packeteer_fuzz_target(fuzz_dns)
  add_packeteer_fuzz_target(fuzz_http)
  add_packeteer_fuzz_target(fuzz_tls)
  add_packeteer_fuzz_target(fuzz_pcapng_reader)
  add_packeteer_fuzz_target(fuzz_summarize)
  add_packeteer_fuzz_target(fuzz_checksum)
  add_packeteer_fuzz_target(fuzz_tcp_reassembly)
endif()
