diff --git a/.gitmodules b/.gitmodules
index 9a0f58b4..8e28db52 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -19,3 +19,6 @@
[submodule "repos/LGProtocol"]
path = repos/LGProtocol
url = https://github.com/gnif/LGProtocol.git
+[submodule "repos/MsQuic"]
+ path = repos/MsQuic
+ url = https://github.com/microsoft/msquic.git
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index c3e684a4..d781454f 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -115,6 +115,17 @@ option(ENABLE_SPICE "Build with SPICE transport support"
${LG_CLIENT_PLATFORM_LINUX})
add_feature_info(ENABLE_SPICE ENABLE_SPICE "SPICE transport support.")
+option(ENABLE_NETWORK "Build with network transport support" OFF)
+add_feature_info(ENABLE_NETWORK ENABLE_NETWORK "QUIC network transport.")
+if(ENABLE_NETWORK AND NOT ENABLE_EGL)
+ message(FATAL_ERROR "ENABLE_NETWORK requires ENABLE_EGL")
+endif()
+
+if(ENABLE_NETWORK AND LG_CLIENT_PLATFORM_WINDOWS)
+ include(MsQuic)
+ lg_add_static_msquic()
+endif()
+
cmake_dependent_option(
ENABLE_USB_AUDIO
"Build with USB audio support"
diff --git a/cmake/CheckSubmodule.cmake b/cmake/CheckSubmodule.cmake
index 7a741848..e0567477 100644
--- a/cmake/CheckSubmodule.cmake
+++ b/cmake/CheckSubmodule.cmake
@@ -3,6 +3,8 @@ if (EXISTS "${PROJECT_TOP}/.git" AND (
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimplot/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/LGMP/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/LGProtocol/.git") OR
+ (NOT EXISTS "${PROJECT_TOP}/repos/MsQuic/.git") OR
+ (NOT EXISTS "${PROJECT_TOP}/repos/MsQuic/submodules/xdp-for-windows/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/PureSpice/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimgui/imgui/.git") OR
(NOT EXISTS "${PROJECT_TOP}/repos/gui/cimplot/implot/.git") OR
diff --git a/cmake/MsQuic.Static.targets b/cmake/MsQuic.Static.targets
new file mode 100644
index 00000000..df0f778f
--- /dev/null
+++ b/cmake/MsQuic.Static.targets
@@ -0,0 +1,44 @@
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\repos\MsQuic'))
+ $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)\$(IntDir)MsQuic'))
+ Win32
+ x64
+ $(LGMsQuicBuildDir)bin\$(LGBaseConfiguration)\msquic.lib
+
+
+
+ $(LGMsQuicSourceDir)src\inc;%(AdditionalIncludeDirectories)
+ QUIC_BUILD_STATIC;%(PreprocessorDefinitions)
+
+
+ $(LGMsQuicLibrary);ws2_32.lib;schannel.lib;secur32.lib;OneCore.lib;wbemuuid.lib;winmm.lib;ntdll.lib;bcrypt.lib;ncrypt.lib;crypt32.lib;iphlpapi.lib;advapi32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cmake/MsQuic.cmake b/cmake/MsQuic.cmake
new file mode 100644
index 00000000..2fa9fc45
--- /dev/null
+++ b/cmake/MsQuic.cmake
@@ -0,0 +1,164 @@
+include(ExternalProject)
+
+function(lg_add_static_msquic)
+ if(TARGET msquic::msquic)
+ return()
+ endif()
+
+ if(NOT WIN32)
+ message(FATAL_ERROR
+ "The in-tree static MsQuic target is only available on Windows")
+ endif()
+
+ if(CMAKE_VERSION VERSION_LESS 3.20)
+ message(FATAL_ERROR
+ "The in-tree static MsQuic target requires CMake 3.20 or newer")
+ endif()
+
+ set(LG_MSQUIC_SOURCE_DIR "${PROJECT_TOP}/repos/MsQuic")
+ set(LG_MSQUIC_BINARY_DIR "${CMAKE_BINARY_DIR}/MsQuic")
+ set(LG_MSQUIC_SYSTEM_LIBRARIES
+ ws2_32
+ schannel
+ secur32
+ onecore
+ wbemuuid
+ winmm
+ ntdll
+ bcrypt
+ ncrypt
+ crypt32
+ iphlpapi
+ advapi32
+ )
+ set(LG_MSQUIC_CMAKE_ARGS
+ "-DQUIC_BUILD_SHARED=OFF"
+ "-DQUIC_BUILD_TOOLS=OFF"
+ "-DQUIC_BUILD_TEST=OFF"
+ "-DQUIC_BUILD_PERF=OFF"
+ "-DQUIC_TLS_LIB=schannel"
+ "-DQUIC_ENABLE_LOGGING=OFF"
+ "-DQUIC_STATIC_LINK_CRT=OFF"
+ "-DQUIC_STATIC_LINK_PARTIAL_CRT=OFF"
+ "-DQUIC_SOURCE_LINK=OFF"
+ "-DQUIC_PDBALTPATH=OFF"
+ "-DQUIC_EMBED_GIT_HASH=OFF"
+ )
+
+ if(NOT EXISTS "${LG_MSQUIC_SOURCE_DIR}/CMakeLists.txt")
+ message(FATAL_ERROR
+ "The MsQuic submodule is not initialized; run "
+ "git submodule update --init --recursive")
+ endif()
+
+ if(MSVC)
+ set(LG_MSQUIC_DEBUG_LIBRARY
+ "${LG_MSQUIC_BINARY_DIR}/bin/Debug/msquic.lib")
+ set(LG_MSQUIC_BUILD_CONFIG "$")
+ set(LG_MSQUIC_BUILD_COMMAND
+ "${CMAKE_COMMAND}" --build
+ --config ${LG_MSQUIC_BUILD_CONFIG}
+ --target msquic_lib
+ --parallel
+ )
+ elseif(MINGW)
+ if(NOT MINGW64_TRIPLE)
+ set(MINGW64_TRIPLE x86_64-w64-mingw32)
+ endif()
+
+ if(CMAKE_FIND_ROOT_PATH)
+ list(GET CMAKE_FIND_ROOT_PATH 0 LG_MSQUIC_MINGW_ROOT)
+ else()
+ set(LG_MSQUIC_MINGW_ROOT "/usr/${MINGW64_TRIPLE}")
+ endif()
+
+ set(LG_MSQUIC_DEBUG_LIBRARY
+ "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib")
+ find_program(LG_MSQUIC_CLANG_CL clang-cl REQUIRED)
+ find_program(LG_MSQUIC_LLVM_LIB llvm-lib REQUIRED)
+ find_program(LG_MSQUIC_MINGW_GCC
+ NAMES "${MINGW64_TRIPLE}-gcc" x86_64-w64-mingw32-gcc
+ REQUIRED)
+ find_program(LG_MSQUIC_WINDRES
+ NAMES "${MINGW64_TRIPLE}-windres" x86_64-w64-mingw32-windres
+ REQUIRED)
+
+ # MsQuic's Windows sources use the CL command-line ABI and its monolithic
+ # archive rule uses lib.exe syntax. Compile those sources with clang-cl,
+ # while targeting the same MinGW-w64 ABI and import libraries as the
+ # surrounding client build.
+ set(LG_MSQUIC_IMPORT_DIR "${LG_MSQUIC_BINARY_DIR}/mingw-imports")
+ file(MAKE_DIRECTORY "${LG_MSQUIC_IMPORT_DIR}")
+
+ foreach(LG_MSQUIC_SYSTEM_LIBRARY
+ onecore
+ secur32
+ wbemuuid
+ winmm)
+ string(TOUPPER "${LG_MSQUIC_SYSTEM_LIBRARY}"
+ LG_MSQUIC_SYSTEM_LIBRARY_UPPER)
+ find_library(LG_MSQUIC_${LG_MSQUIC_SYSTEM_LIBRARY_UPPER}_LIBRARY
+ NAMES "${LG_MSQUIC_SYSTEM_LIBRARY}"
+ PATHS "${LG_MSQUIC_MINGW_ROOT}/lib"
+ NO_DEFAULT_PATH
+ REQUIRED)
+ configure_file(
+ "${LG_MSQUIC_${LG_MSQUIC_SYSTEM_LIBRARY_UPPER}_LIBRARY}"
+ "${LG_MSQUIC_IMPORT_DIR}/${LG_MSQUIC_SYSTEM_LIBRARY}.lib"
+ COPYONLY)
+ endforeach()
+
+ list(APPEND LG_MSQUIC_CMAKE_ARGS
+ "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
+ "-DCMAKE_TOOLCHAIN_FILE=${PROJECT_TOP}/cmake/toolchains/msquic-clangcl-mingw64.cmake"
+ "-DMSQUIC_MINGW_TRIPLE=${MINGW64_TRIPLE}"
+ "-DMSQUIC_MINGW_ROOT=${LG_MSQUIC_MINGW_ROOT}"
+ "-DMSQUIC_CLANG_CL=${LG_MSQUIC_CLANG_CL}"
+ "-DMSQUIC_LLVM_LIB=${LG_MSQUIC_LLVM_LIB}"
+ "-DMSQUIC_MINGW_GCC=${LG_MSQUIC_MINGW_GCC}"
+ "-DMSQUIC_WINDRES=${LG_MSQUIC_WINDRES}"
+ "-DHAS_SPECTRE=OFF"
+ "-DHAS_GUARDCF=OFF"
+ )
+ set(LG_MSQUIC_BUILD_COMMAND
+ "${CMAKE_COMMAND}" -E env "LIB=${LG_MSQUIC_IMPORT_DIR}"
+ "${CMAKE_COMMAND}" --build
+ --target msquic_lib
+ --parallel
+ )
+ else()
+ message(FATAL_ERROR
+ "Static MsQuic on Windows requires MSVC or the MinGW-w64 "
+ "clang-cl cross-build toolchain")
+ endif()
+
+ ExternalProject_Add(lg_msquic_build
+ SOURCE_DIR "${LG_MSQUIC_SOURCE_DIR}"
+ BINARY_DIR "${LG_MSQUIC_BINARY_DIR}"
+ DOWNLOAD_COMMAND ""
+ UPDATE_COMMAND ""
+ INSTALL_COMMAND ""
+ CMAKE_ARGS ${LG_MSQUIC_CMAKE_ARGS}
+ BUILD_COMMAND ${LG_MSQUIC_BUILD_COMMAND}
+ BUILD_BYPRODUCTS
+ "${LG_MSQUIC_BINARY_DIR}/bin/Debug/msquic.lib"
+ "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib"
+ )
+
+ add_library(lg_msquic STATIC IMPORTED GLOBAL)
+ set_target_properties(lg_msquic PROPERTIES
+ IMPORTED_CONFIGURATIONS "Debug;Release;RelWithDebInfo;MinSizeRel"
+ IMPORTED_LOCATION_DEBUG "${LG_MSQUIC_DEBUG_LIBRARY}"
+ IMPORTED_LOCATION_RELEASE
+ "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib"
+ IMPORTED_LOCATION_RELWITHDEBINFO
+ "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib"
+ IMPORTED_LOCATION_MINSIZEREL
+ "${LG_MSQUIC_BINARY_DIR}/bin/Release/msquic.lib"
+ INTERFACE_COMPILE_DEFINITIONS QUIC_BUILD_STATIC
+ INTERFACE_INCLUDE_DIRECTORIES "${LG_MSQUIC_SOURCE_DIR}/src/inc"
+ INTERFACE_LINK_LIBRARIES "${LG_MSQUIC_SYSTEM_LIBRARIES}"
+ )
+ add_dependencies(lg_msquic lg_msquic_build)
+ add_library(msquic::msquic ALIAS lg_msquic)
+endfunction()
diff --git a/cmake/toolchains/msquic-clangcl-mingw64.cmake b/cmake/toolchains/msquic-clangcl-mingw64.cmake
new file mode 100644
index 00000000..864469f5
--- /dev/null
+++ b/cmake/toolchains/msquic-clangcl-mingw64.cmake
@@ -0,0 +1,138 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR AMD64)
+
+set(MSQUIC_MINGW_TRIPLE x86_64-w64-mingw32 CACHE STRING
+ "MinGW-w64 target triple")
+set(MSQUIC_MINGW_ROOT "/usr/${MSQUIC_MINGW_TRIPLE}" CACHE PATH
+ "MinGW-w64 target root")
+set(MSQUIC_CLANG_CL clang-cl CACHE FILEPATH
+ "clang-cl used to build the static MsQuic archive")
+set(MSQUIC_LLVM_LIB llvm-lib CACHE FILEPATH
+ "llvm-lib used to create the static MsQuic archive")
+set(MSQUIC_WINDRES "${MSQUIC_MINGW_TRIPLE}-windres" CACHE FILEPATH
+ "MinGW-w64 resource compiler")
+set(MSQUIC_MINGW_GCC "${MSQUIC_MINGW_TRIPLE}-gcc" CACHE FILEPATH
+ "MinGW-w64 compiler used to locate compatibility headers")
+
+if(NOT MSQUIC_CLANG_RESOURCE_DIR)
+ execute_process(
+ COMMAND "${MSQUIC_CLANG_CL}" /clang:-print-resource-dir
+ RESULT_VARIABLE MSQUIC_CLANG_RESOURCE_RESULT
+ OUTPUT_VARIABLE MSQUIC_CLANG_RESOURCE_ROOT
+ ERROR_VARIABLE MSQUIC_CLANG_RESOURCE_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT MSQUIC_CLANG_RESOURCE_RESULT EQUAL 0)
+ message(FATAL_ERROR
+ "Unable to locate the clang resource headers: "
+ "${MSQUIC_CLANG_RESOURCE_ERROR}")
+ endif()
+
+ set(MSQUIC_CLANG_RESOURCE_DIR
+ "${MSQUIC_CLANG_RESOURCE_ROOT}/include" CACHE PATH
+ "clang resource headers used by the MsQuic cross-build")
+endif()
+
+if(NOT MSQUIC_MINGW_GCC_INCLUDE)
+ execute_process(
+ COMMAND "${MSQUIC_MINGW_GCC}" -print-file-name=include
+ RESULT_VARIABLE MSQUIC_MINGW_GCC_INCLUDE_RESULT
+ OUTPUT_VARIABLE MSQUIC_MINGW_GCC_INCLUDE
+ ERROR_VARIABLE MSQUIC_MINGW_GCC_INCLUDE_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT MSQUIC_MINGW_GCC_INCLUDE_RESULT EQUAL 0)
+ message(FATAL_ERROR
+ "Unable to locate the MinGW-w64 compiler headers: "
+ "${MSQUIC_MINGW_GCC_INCLUDE_ERROR}")
+ endif()
+
+ set(MSQUIC_MINGW_GCC_INCLUDE "${MSQUIC_MINGW_GCC_INCLUDE}" CACHE PATH
+ "MinGW-w64 compiler headers used by the MsQuic cross-build")
+endif()
+
+if(NOT MSQUIC_MINGW_GCC_INCLUDE_FIXED)
+ execute_process(
+ COMMAND "${MSQUIC_MINGW_GCC}" -print-file-name=include-fixed
+ RESULT_VARIABLE MSQUIC_MINGW_GCC_FIXED_RESULT
+ OUTPUT_VARIABLE MSQUIC_MINGW_GCC_INCLUDE_FIXED
+ ERROR_VARIABLE MSQUIC_MINGW_GCC_FIXED_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT MSQUIC_MINGW_GCC_FIXED_RESULT EQUAL 0)
+ message(FATAL_ERROR
+ "Unable to locate the fixed MinGW-w64 compiler headers: "
+ "${MSQUIC_MINGW_GCC_FIXED_ERROR}")
+ endif()
+
+ set(MSQUIC_MINGW_GCC_INCLUDE_FIXED
+ "${MSQUIC_MINGW_GCC_INCLUDE_FIXED}" CACHE PATH
+ "Fixed MinGW-w64 compiler headers used by the MsQuic cross-build")
+endif()
+
+foreach(MSQUIC_REQUIRED_INCLUDE
+ "${MSQUIC_MINGW_ROOT}/include"
+ "${MSQUIC_CLANG_RESOURCE_DIR}"
+ "${MSQUIC_MINGW_GCC_INCLUDE}")
+ if(NOT IS_DIRECTORY "${MSQUIC_REQUIRED_INCLUDE}")
+ message(FATAL_ERROR
+ "Required MsQuic cross-build headers are missing: "
+ "${MSQUIC_REQUIRED_INCLUDE}")
+ endif()
+endforeach()
+
+set(CMAKE_C_COMPILER "${MSQUIC_CLANG_CL}")
+set(CMAKE_CXX_COMPILER "${MSQUIC_CLANG_CL}")
+set(CMAKE_C_COMPILER_TARGET "${MSQUIC_MINGW_TRIPLE}")
+set(CMAKE_CXX_COMPILER_TARGET "${MSQUIC_MINGW_TRIPLE}")
+set(CMAKE_AR "${MSQUIC_LLVM_LIB}")
+set(CMAKE_RC_COMPILER "${MSQUIC_WINDRES}")
+
+set(MSQUIC_COMPAT_HEADER
+ "${CMAKE_CURRENT_LIST_DIR}/msquic-mingw-compat.h")
+set(MSQUIC_CLANG_CL_OPTIONS
+ "/clang:-nostdinc"
+ "/clang:-isystem"
+ "/clang:${MSQUIC_MINGW_ROOT}/include"
+ "/clang:-isystem"
+ "/clang:${MSQUIC_CLANG_RESOURCE_DIR}"
+ "/clang:-isystem"
+ "/clang:${MSQUIC_MINGW_GCC_INCLUDE}")
+
+if(IS_DIRECTORY "${MSQUIC_MINGW_GCC_INCLUDE_FIXED}")
+ list(APPEND MSQUIC_CLANG_CL_OPTIONS
+ "/clang:-isystem"
+ "/clang:${MSQUIC_MINGW_GCC_INCLUDE_FIXED}")
+endif()
+
+list(APPEND MSQUIC_CLANG_CL_OPTIONS
+ "/clang:-fms-extensions"
+ "/clang:-Wno-unknown-pragmas"
+ "/clang:-Wno-microsoft-anon-tag"
+ "/clang:-Wno-missing-field-initializers"
+ "/clang:-Wno-sign-compare"
+ "/clang:-Wno-int-conversion"
+ "/clang:-Wno-unused-function"
+ "/clang:-Wno-incompatible-pointer-types"
+ "/FI${MSQUIC_COMPAT_HEADER}")
+list(JOIN MSQUIC_CLANG_CL_OPTIONS " " MSQUIC_CLANG_CL_FLAGS)
+
+set(CMAKE_C_FLAGS "${MSQUIC_CLANG_CL_FLAGS}" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS "${MSQUIC_CLANG_CL_FLAGS}" CACHE STRING "" FORCE)
+set(CMAKE_C_FLAGS_DEBUG "/clang:-O0 /Zi" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS_DEBUG "/clang:-O0 /Zi" CACHE STRING "" FORCE)
+set(CMAKE_C_FLAGS_RELEASE "/clang:-O3 /DNDEBUG" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS_RELEASE "/clang:-O3 /DNDEBUG" CACHE STRING "" FORCE)
+set(CMAKE_C_FLAGS_RELWITHDEBINFO
+ "/clang:-O2 /Zi /DNDEBUG" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ "/clang:-O2 /Zi /DNDEBUG" CACHE STRING "" FORCE)
+set(CMAKE_C_FLAGS_MINSIZEREL "/clang:-Os /DNDEBUG" CACHE STRING "" FORCE)
+set(CMAKE_CXX_FLAGS_MINSIZEREL
+ "/clang:-Os /DNDEBUG" CACHE STRING "" FORCE)
+
+set(CMAKE_USER_MAKE_RULES_OVERRIDE
+ "${CMAKE_CURRENT_LIST_DIR}/msquic-clangcl-rules.cmake")
+
+set(CMAKE_FIND_ROOT_PATH "${MSQUIC_MINGW_ROOT}")
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/cmake/toolchains/msquic-clangcl-rules.cmake b/cmake/toolchains/msquic-clangcl-rules.cmake
new file mode 100644
index 00000000..cedfd17e
--- /dev/null
+++ b/cmake/toolchains/msquic-clangcl-rules.cmake
@@ -0,0 +1,21 @@
+set(CMAKE_DEPFILE_FLAGS_C
+ "-clang:-MD -clang:-MT -clang:-MF")
+set(CMAKE_DEPFILE_FLAGS_CXX
+ "-clang:-MD -clang:-MT -clang:-MF")
+
+set(CMAKE_C_COMPILE_OBJECT
+ " /Fo