Skip to content
Open
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
63 changes: 60 additions & 3 deletions moxygen/MoQServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,63 @@
#include <proxygen/lib/http/webtransport/QuicWebTransport.h>
#include <proxygen/lib/http/webtransport/QuicWtSession.h>
#include <moxygen/events/MoQFollyExecutorImpl.h>
#include <quic/api/QuicTransportBaseLite.h>

#include <utility>

using namespace quic::samples;
using namespace proxygen;

namespace {

// Wraps HQServerTransportFactory to attach a QLogger to every new transport
// via a subclass-supplied makeQLogger() hook. This covers both paths:
// - WebTransport (H3): HQServerTransportFactory::make() is called by mvfst
// for every incoming QUIC connection, regardless of ALPN.
// - Direct QUIC ALPN (moqt-*): same make() call, before the ALPN handler
// fires and hands the socket to createMoQQuicSession().
// Using FileQLogger(streaming=true) each logger writes via its own
// folly::AsyncFileWriter background thread — no separate executor needed.
class MoQQLogFactory : public quic::QuicServerTransportFactory {
public:
MoQQLogFactory(
std::unique_ptr<HQServerTransportFactory> inner,
std::function<std::shared_ptr<quic::QLogger>(quic::VantagePoint)>
makeQLoggerFn)
: inner_(std::move(inner)),
makeQLoggerFn_(std::move(makeQLoggerFn)) {}

quic::QuicServerTransport::Ptr make(
folly::EventBase* evb,
std::unique_ptr<quic::FollyAsyncUDPSocketAlias> socket,
const folly::SocketAddress& addr,
quic::QuicVersion quicVersion,
std::shared_ptr<const fizz::server::FizzServerContext>
ctx) noexcept override {
auto transport =
inner_->make(evb, std::move(socket), addr, quicVersion, std::move(ctx));
if (transport && makeQLoggerFn_) {
if (auto logger = makeQLoggerFn_(quic::VantagePoint::Server)) {
auto* base =
dynamic_cast<quic::QuicTransportBaseLite*>(transport.get());
if (base) {
base->setQLogger(std::move(logger));
}
}
}
return transport;
}

HQServerTransportFactory* inner() const noexcept { return inner_.get(); }

private:
std::unique_ptr<HQServerTransportFactory> inner_;
std::function<std::shared_ptr<quic::QLogger>(quic::VantagePoint)>
makeQLoggerFn_;
};

} // namespace

namespace moxygen {

MoQServer::MoQServer(
Expand Down Expand Up @@ -91,8 +142,14 @@ MoQServer::MoQServer(
}
}

factory_ = std::make_unique<HQServerTransportFactory>(
// Build the factory chain: inner handles H3/ALPN dispatch; outer attaches a
// QLogger (from makeQLogger()) to every transport before any session starts.
auto inner = std::make_unique<HQServerTransportFactory>(
params_, [this](HTTPMessage*) { return new Handler(*this); }, nullptr);
innerFactory_ = inner.get();
factory_ = std::make_unique<MoQQLogFactory>(
std::move(inner),
[this](quic::VantagePoint vp) { return makeQLogger(vp); });

// Register ALPN handlers for direct QUIC MoQT connections
XLOG(DBG1) << "MoQServer: Registering ALPN handlers: "
Expand All @@ -104,7 +161,7 @@ MoQServer::MoQServer(
}

void MoQServer::registerAlpnHandler(const std::vector<std::string>& alpns) {
if (!factory_) {
if (!innerFactory_) {
XLOG(INFO) << "Cannot register ALPN handler: factory not initialized";
return;
}
Expand All @@ -114,7 +171,7 @@ void MoQServer::registerAlpnHandler(const std::vector<std::string>& alpns) {
return;
}

factory_->addAlpnHandler(
innerFactory_->addAlpnHandler(
alpns,
[this](
std::shared_ptr<quic::QuicSocket> quicSocket,
Expand Down
16 changes: 15 additions & 1 deletion moxygen/MoQServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <proxygen/httpserver/samples/hq/HQServer.h>
#include <moxygen/MoQServerBase.h>
#include <quic/logging/QLogger.h>

#include <folly/init/Init.h>
#include <folly/io/async/EventBaseLocal.h>
Expand Down Expand Up @@ -107,6 +108,16 @@ class MoQServer : public MoQServerBase {
// Register ALPN handlers for direct QUIC connections (internal use)
void registerAlpnHandler(const std::vector<std::string>& alpns);

// Hook called once per new QUIC connection (both WebTransport/H3 and direct
// QUIC ALPN paths). Override to return a FileQLogger or similar for this
// connection; return nullptr to skip qlog. Default returns nullptr.
// FileQLogger(streaming=true) is recommended: it uses its own
// folly::AsyncFileWriter background thread — no executor needed.
virtual std::shared_ptr<quic::QLogger> makeQLogger(
quic::VantagePoint /*vantagePoint*/) {
return nullptr;
}

private:
void createMoQQuicSession(std::shared_ptr<quic::QuicSocket> quicSocket);

Expand Down Expand Up @@ -178,7 +189,10 @@ class MoQServer : public MoQServerBase {
quic::samples::HQServerParams params_;
std::shared_ptr<const fizz::server::FizzServerContext> fizzContext_;
std::vector<std::string> wtMoqtProtocols_;
std::unique_ptr<quic::samples::HQServerTransportFactory> factory_;
// inner_ is owned by factory_ (MoQQLogFactory); kept as a raw ptr for
// addAlpnHandler() access in registerAlpnHandler().
quic::samples::HQServerTransportFactory* innerFactory_{nullptr};
std::unique_ptr<quic::QuicServerTransportFactory> factory_;
std::unique_ptr<quic::samples::HQServer> hqServer_;
folly::EventBaseLocal<std::shared_ptr<MoQExecutor>> executorLocal_;
std::function<bool()> useQuicWtSession_;
Expand Down