feat(quic): replace probe UDP data plane with QUIC datagrams

This commit is contained in:
justme committed 2026-10-10 02:59:56 +08:00
1 parent 4609048865
commit b964dc2bbc
53 files changed
+2413 -411

No files matched your search

+16 -15
View File
@@ -33,7 +33,7 @@ public sealed class AgentApp : IDisposable
private readonly Outbox _outbox = new(64 << 20);
private readonly RestartUpdater? _update;
private readonly BackendUplink _uplink;
private readonly UdpMux _udp;
private readonly QuicDatagramTransport _datagrams;
private readonly TcpAcceptor _tcp;
private readonly PeerListener _peers;
private readonly PeerHub _hub;
@@ -62,7 +62,7 @@ public sealed class AgentApp : IDisposable
_ipv6Supported = bind.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6;
_admission = new AgentAdmission(_streams);
_udp = new UdpMux(_sessions, _admission, _clock, _counters.Data, log, bind, config.Listen.UdpPorts);
_datagrams = new QuicDatagramTransport(_sessions, _admission, _clock, _counters.Data, log, bind, config.Listen.EffectiveQuicPorts, identity.Certificate);
// 预握手敲门:控制端口和数据端口共用一个关卡(限速和去重一起算);名册就是期望状态里的 peers
_trust = TrustAnchor.Load(config.Fleet.IdentityDir, log);
_knock = new KnockGate(identity.PeerIdentity, RosterKeys, time);
@@ -74,7 +74,7 @@ public sealed class AgentApp : IDisposable
Clock = _clock,
Log = log,
Session = () => null, // 每个 Probe 会话各用自己绑定的环境(BlockEnv.WithSession)
Udp = _udp,
Datagrams = _datagrams,
TcpListen = _tcp,
Admission = _admission,
Counters = _counters.Data,
@@ -83,14 +83,14 @@ public sealed class AgentApp : IDisposable
};
var chunks = new ChunkAssembler(_streams, _clock, _counters, _outbox, identity.NodeId, time, log);
var targets = new TargetRunners(chunks, identity.NodeId, _clock, time, log);
_tasks = new TaskManager(CreateGuard, _streams, env, targets, () => _udp.BoundPorts, () => _tcp.BoundPorts, _trust);
_tasks = new TaskManager(CreateGuard, _streams, env, targets, () => _datagrams.BoundPorts, () => _tcp.BoundPorts, _trust);
_hub = new PeerHub(_sessions, _clock, chunks, _tasks, _uplink, time, log);
_tests = new TestRunner(_tasks, _sessions, _streams, env, _uplink, config.Limits.MaxConcurrentTests, transport => transport == "udp" ? _udp.BoundPorts : _tcp.BoundPorts, time, log);
_tests = new TestRunner(_tasks, _sessions, _streams, env, _uplink, config.Limits.MaxConcurrentTests, transport => transport == "quic_datagram" ? _datagrams.BoundPorts : _tcp.BoundPorts, time, log);
_tasks.OnLineTasksChanged = (probe, set) => _ = _hub.PushToAsync(probe, set).AsTask();
_tasks.OnPeersChanged = _hub.CloseNotIn;
_hub.OnProbeLost = probe => _tests.ProbeLost(probe);
_admission.OnEndpointChanged = probe => _ = _uplink.EmitEventAsync(AgentEventKinds.EndpointChanged, probe.UdpEndpoint?.ToString()).AsTask();
_admission.OnEndpointChanged = probe => _ = _uplink.EmitEventAsync(AgentEventKinds.EndpointChanged, probe.DatagramRemoteEndPoint?.ToString()).AsTask();
_peers = new PeerListener(
new PeerListenerOptions
@@ -113,13 +113,13 @@ public sealed class AgentApp : IDisposable
public void Dispose()
{
_udp.Dispose();
_datagrams.Dispose();
_ownedRestart?.Dispose();
}
internal StreamRegistry Streams => _streams;
public IReadOnlyList<int> UdpPorts => _udp.BoundPorts;
public IReadOnlyList<int> QuicPorts => _datagrams.BoundPorts;
public IReadOnlyList<int> TcpPorts => _tcp.BoundPorts;
@@ -146,23 +146,23 @@ public sealed class AgentApp : IDisposable
_log.Info("moshiro agent starting", MoShiro.Protocol.BuildInfo.Fields);
using CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(ct);
// 数据面和控制端口先开始监听,再连接 Backend:hello 里上报的是实际端口
_udp.Bind();
_datagrams.Bind();
_tcp.Bind();
Task udp = _udp.RunAsync(linked.Token);
Task quic = _datagrams.RunAsync(linked.Token);
Task tcp = _tcp.RunAsync(linked.Token);
Task peers = _peers.RunAsync(linked.Token);
await Task.WhenAny(_peers.Started.Task, peers);
if (peers.IsFaulted)
{
await linked.CancelAsync();
await Task.WhenAll(udp, tcp, peers); // 抛出监听失败的原因(端口被占用等)
await Task.WhenAll(quic, tcp, peers); // 抛出监听失败的原因(端口被占用等)
}
_ready.TrySetResult();
_log.Info("agent listening", ("control", ControlPort), ("udp", string.Join(',', UdpPorts)), ("tcp", string.Join(',', TcpPorts)));
_log.Info("agent listening", ("control", ControlPort), ("quic", string.Join(',', QuicPorts)), ("tcp", string.Join(',', TcpPorts)));
try
{
await Task.WhenAll(udp, tcp, peers, _link.RunAsync(linked.Token), ReportHostAsync(linked.Token));
await Task.WhenAll(quic, tcp, peers, _link.RunAsync(linked.Token), ReportHostAsync(linked.Token));
}
finally
{
@@ -203,7 +203,7 @@ public sealed class AgentApp : IDisposable
MaxTotalPps = _config.Limits.MaxTotalPps,
AllowedTargetCidrs = _config.Limits.AllowedTargetCidrs,
MaxConcurrentTests = _config.Limits.MaxConcurrentTests,
AllowedUdpPorts = _udp.BoundPorts,
AllowedQuicPorts = _datagrams.BoundPorts,
AllowedTcpPorts = _tcp.BoundPorts,
},
BlockCatalog.AgentKinds);
@@ -310,7 +310,8 @@ public sealed class AgentApp : IDisposable
Platform = MoShiro.Measurement.PlatformDetector.Detect(),
TlsPublicKey = Convert.ToBase64String(_identity.Certificate.PublicKey.ExportSubjectPublicKeyInfo()),
ProbeTcpPort = ControlPort,
ProbeUdpPorts = [.. UdpPorts],
ProbeQuicPorts = [.. QuicPorts],
LegacyProbeUdpPorts = [.. QuicPorts],
LocalLimits = new LocalLimits
{
MaxTotalMbps = _config.Limits.MaxTotalMbps,