Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,34 @@ add_library(moqx_core STATIC
src/stats/PicoQuicStatsCollector.cpp
src/stats/QuicStatsCollector.cpp
src/UpstreamProvider.cpp
src/tls/TlsCertLoader.cpp
src/tls/InsecureCertProvider.cpp
src/tls/FileCertLoader.cpp
src/tls/DirectoryCertLoader.cpp
src/tls/FizzContextFactory.cpp
src/tls/BuiltinTlsProviders.cpp
)

target_include_directories(moqx_core
PUBLIC
${PROJECT_SOURCE_DIR}/src
)

target_link_libraries(moqx_core PUBLIC
moxygen::moxygen_relay_moq_forwarder
moxygen::moxygen_relay_moq_cache
moxygen::moxygen_moq_relay_session
moxygen::moxygen_moq_server
moxygen::openmoq_pico_evb_server_transport
proxygen::proxygenhttpserver
# Workaround: wangle::wangle_acceptor_acceptor_core uses AsyncFdSocket from
# FizzAcceptorHandshakeHelper but omits this dep from its cmake config.
Folly::folly_io_async_fdsock_async_fd_socket
moxygen::moxygen_moqclient
target_link_libraries(moqx_core
PUBLIC
moxygen::moxygen_relay_moq_forwarder
moxygen::moxygen_relay_moq_cache
moxygen::moxygen_moq_relay_session
moxygen::moxygen_moq_server
moxygen::openmoq_pico_evb_server_transport
proxygen::proxygenhttpserver
# Workaround: wangle::wangle_acceptor_acceptor_core uses AsyncFdSocket from
# FizzAcceptorHandshakeHelper but omits this dep from its cmake config.
Folly::folly_io_async_fdsock_async_fd_socket
moxygen::moxygen_moqclient
PRIVATE
# builtin_tls_providers.cpp includes parsed_config.h (rfl types)
reflectcpp
)

target_compile_options(moqx_core PRIVATE -Wall -Wextra -Wpedantic)
Expand Down Expand Up @@ -133,6 +143,7 @@ add_library(moqx_config_loader STATIC
src/config/Loader.cpp
src/config/ConfigResolver.cpp
src/config/ConfigInit.cpp
src/tls/TlsProviderRegistry.cpp
)

target_include_directories(moqx_config_loader
Expand Down
12 changes: 9 additions & 3 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ listeners:
address: "::" # Bind address (default: "::" = all interfaces)
port: 9668 # Listen port (1-65535)
tls:
# cert_file: /path/to/cert.pem # Required when insecure: false
# key_file: /path/to/key.pem # Required when insecure: false
insecure: true # Skip TLS for local development
type: insecure # Skip TLS for local development
# --- OR single cert+key pair ---
# type: file
# cert_file: /path/to/cert.pem
# key_file: /path/to/key.pem
# --- OR directory with multiple certs (SNI selection) ---
# type: directory
# cert_dir: /etc/ssl/certs.d/ # contains <name>.crt + <name>.key pairs
# default_cert: example.com # optional: SNI identity for default fallback
endpoint: "/moq-relay" # WebTransport endpoint path
# moqt_versions: [14, 16] # MOQT draft versions (empty = all supported)
# quic: # Per-listener QUIC overrides (optional; inherits listener_defaults.quic)
Expand Down
35 changes: 13 additions & 22 deletions src/MoqxPicoRelayServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "MoqxPicoRelayServer.h"

#include "stats/PicoQuicStatsCollector.h"
#include "tls/TlsCertLoader.h"
#include <folly/io/async/EventBase.h>
#include <folly/logging/xlog.h>
#include <moxygen/MoQRelaySession.h>
Expand Down Expand Up @@ -35,31 +36,21 @@ moxygen::PicoTransportConfig picoTransportConfigFromQuicConfig(const config::Qui
}

std::string resolveCert(const config::ListenerConfig& cfg) {
return std::visit(
[](const auto& tls) -> std::string {
using T = std::decay_t<decltype(tls)>;
if constexpr (std::is_same_v<T, config::Insecure>) {
return "";
} else {
return tls.certFile;
}
},
cfg.tlsMode
);
auto result = cfg.tlsProvider->getCertPath();
if (result.hasError()) {
XLOG(FATAL) << "Unable to get certificate path for picoquic: " << result.error();
}

return result.value();
}

std::string resolveKey(const config::ListenerConfig& cfg) {
return std::visit(
[](const auto& tls) -> std::string {
using T = std::decay_t<decltype(tls)>;
if constexpr (std::is_same_v<T, config::Insecure>) {
return "";
} else {
return tls.keyFile;
}
},
cfg.tlsMode
);
auto result = cfg.tlsProvider->getKeyPath();
if (result.hasError()) {
XLOG(FATAL) << "Unable to get key path for picoquic: " << result.error();
}

return result.value();
}

} // namespace
Expand Down
36 changes: 2 additions & 34 deletions src/MoqxRelayServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,6 @@ namespace openmoq::moqx {

namespace {

std::vector<std::string> buildAlpns(const std::string& versions) {
std::vector<std::string> alpns = {"h3"};
auto moqt = getMoqtProtocols(versions, true);
alpns.insert(alpns.end(), moqt.begin(), moqt.end());
return alpns;
}

std::shared_ptr<const fizz::server::FizzServerContext>
buildFizzContext(const config::ListenerConfig& cfg) {
auto alpns = buildAlpns(cfg.moqtVersions);
return std::visit(
[&alpns](const auto& tls) -> std::shared_ptr<const fizz::server::FizzServerContext> {
using T = std::decay_t<decltype(tls)>;
if constexpr (std::is_same_v<T, config::Insecure>) {
return quic::samples::createFizzServerContextWithInsecureDefault(
alpns,
fizz::server::ClientAuthMode::None,
"",
""
);
} else {
return quic::samples::createFizzServerContext(
alpns,
fizz::server::ClientAuthMode::Optional,
tls.certFile,
tls.keyFile
);
}
},
cfg.tlsMode
);
}

quic::TransportSettings buildTransportSettings(const config::QuicConfig& quic) {
// Start with MoQServer's optimized defaults, then apply config overrides.
quic::TransportSettings ts;
Expand Down Expand Up @@ -91,10 +58,11 @@ quic::TransportSettings buildTransportSettings(const config::QuicConfig& quic) {
MoqxRelayServer::MoqxRelayServer(
const config::ListenerConfig& listenerCfg,
std::shared_ptr<MoqxRelayContext> context,
std::shared_ptr<const fizz::server::FizzServerContext> fizzContext,
std::shared_ptr<folly::IOThreadPoolExecutor> ioExecutor
)
: MoQServer(
buildFizzContext(listenerCfg),
std::move(fizzContext),
listenerCfg.endpoint,
buildTransportSettings(listenerCfg.quic)
),
Expand Down
1 change: 1 addition & 0 deletions src/MoqxRelayServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MoqxRelayServer : public moxygen::MoQServer {
MoqxRelayServer(
const config::ListenerConfig& listenerCfg,
std::shared_ptr<MoqxRelayContext> context,
std::shared_ptr<const fizz::server::FizzServerContext> fizzContext,
std::shared_ptr<folly::IOThreadPoolExecutor> ioExecutor
);

Expand Down
17 changes: 15 additions & 2 deletions src/MoqxServerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "MoqxRelayServer.h"
#include "config/Config.h"
#include "stats/StatsRegistry.h"
#include "tls/FizzContextFactory.h"
#include "tls/TlsCertLoader.h"
#include <folly/executors/IOThreadPoolExecutor.h>
#include <moxygen/MoQServerBase.h>
namespace openmoq::moqx {
Expand All @@ -34,8 +36,19 @@ inline std::shared_ptr<moxygen::MoQServerBase> makeRelayServer(
server->setStatsRegistry(std::move(statsRegistry));
return server;
}
auto server =
std::make_shared<MoqxRelayServer>(listenerCfg, std::move(context), std::move(ioExecutor));

auto alpns = openmoq::moqx::tls::buildAlpns(listenerCfg.moqtVersions);
auto fizzCtx = listenerCfg.tlsProvider->createContext(alpns);
if (fizzCtx.hasError()) {
XLOG(FATAL) << "Failed to create TLS context: " << fizzCtx.error();
}

auto server = std::make_shared<MoqxRelayServer>(
listenerCfg,
std::move(context),
std::move(fizzCtx).value(),
std::move(ioExecutor)
);
server->setStatsRegistry(std::move(statsRegistry));
return server;
}
Expand Down
10 changes: 5 additions & 5 deletions src/config/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include <folly/SocketAddress.h>
#include <folly/container/F14Map.h>

namespace openmoq::moqx::tls {
class TlsCertProvider;
} // namespace openmoq::moqx::tls

namespace openmoq::moqx::config {

struct TlsConfig {
Expand All @@ -25,10 +29,6 @@ struct TlsConfig {
std::vector<std::string> alpn; // must be empty for QUIC listener: ALPN derived from moqt_versions
};

struct Insecure {};

using TlsMode = std::variant<Insecure, TlsConfig>;

struct CacheConfig {
size_t maxCachedTracks; // 0 when cache disabled
size_t maxCachedGroupsPerTrack;
Expand Down Expand Up @@ -60,7 +60,7 @@ struct QuicConfig {
struct ListenerConfig {
std::string name;
folly::SocketAddress address;
TlsMode tlsMode;
std::shared_ptr<tls::TlsCertProvider> tlsProvider;
std::string endpoint;
std::string moqtVersions; // comma-separated string
QuicStack quicStack{QuicStack::Mvfst};
Expand Down
5 changes: 3 additions & 2 deletions src/config/ConfigInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ folly::Expected<ResolvedConfig, int> handleConfigSubcommand(
std::string_view subcommand,
std::string_view configPath,
bool strictConfig,
const char* programName
const char* programName,
const tls::TlsProviderRegistry& registry
) {
if (subcommand == kDumpConfigSchemaCommand) {
std::cout << generateSchema() << '\n';
Expand All @@ -46,7 +47,7 @@ folly::Expected<ResolvedConfig, int> handleConfigSubcommand(
return folly::makeUnexpected(1);
}

auto result = resolveConfig(parsed);
auto result = resolveConfig(parsed, registry);
if (result.hasError()) {
std::cerr << "Error: " << result.error() << std::endl;
return folly::makeUnexpected(1);
Expand Down
Loading
Loading