Replace Probe with Agent across node runtime, Fleet contracts, backend state, API and storage. Report incoming sessions and outgoing link health through each Agent uplink, and retain directed link controls and retry. Update protocol fixtures and end-to-end coverage for the unified model; accept requested cancellation during the Fleet timeout test cleanup.
163 lines
6.0 KiB
C#
163 lines
6.0 KiB
C#
namespace MoShiro.Protocol;
|
||
|
||
/// <summary>
|
||
/// Kind 目录。新增一种采集方法 = 在这里加一个静态字段并放进 <see cref="All"/>;
|
||
/// 参数一律用 <see cref="P"/> 声明默认值和上下限。
|
||
/// </summary>
|
||
public static class Kinds
|
||
{
|
||
private static readonly string[] s_directions = ["fwd", "rev", "bidir"];
|
||
|
||
private static readonly StreamSpec s_echoMsg = new(
|
||
"msg",
|
||
[
|
||
Col.Seq("seq"), Col.U16("size"),
|
||
Col.TsDialer("t1"), Col.TsListener("t2", nullable: true), Col.TsListener("t3", nullable: true), Col.TsDialer("t4", nullable: true),
|
||
],
|
||
Side.Dialer,
|
||
"seq");
|
||
|
||
private static readonly StreamSpec s_tcpInfo = new(
|
||
"tcp_info",
|
||
[
|
||
Col.TsLocal("ts"), Col.U8("side"), Col.U32("srtt_us"), Col.U32("rttvar_us"), Col.U32("cwnd"),
|
||
Col.U32("retrans_total"), Col.U32("segs_out"), Col.U64("bytes_acked"),
|
||
new ColumnSpec("conn", ColumnType.U64, ColumnEnc.Plain, true),
|
||
],
|
||
Union: true);
|
||
|
||
public static readonly KindSpec UdpEcho = new(
|
||
"udp_echo",
|
||
"QUIC Datagram echo",
|
||
"Fixed-rate QUIC Datagram echo with four timestamps per packet.",
|
||
Scope.Line,
|
||
new BlockSet("quic_datagram", "fixed", "fixed", "echo", []),
|
||
[
|
||
P.Int("rate_hz", 10, 1, 200, "Hz"),
|
||
P.Int("size", 64, 44, 1400, "B"),
|
||
P.Int("port", 7443, 1, 65535),
|
||
],
|
||
[s_echoMsg],
|
||
p => Bandwidth.UdpEcho(p.GetInt("rate_hz"), p.GetInt("size")));
|
||
|
||
public static readonly KindSpec UdpTrain = new(
|
||
"udp_train",
|
||
"QUIC Datagram train",
|
||
"Fixed-rate or laddered one-way QUIC Datagram stream (Agent to 拨号方) for loss and delay variation under load.",
|
||
Scope.Line,
|
||
new BlockSet("quic_datagram", "ladder", "fixed", "sink", []),
|
||
[
|
||
P.Number("mbps", 10, 0.1, 1000, "Mbit/s"),
|
||
P.Int("size", 1250, 200, 1400, "B"),
|
||
P.Int("duration_s", 10, 1, 120, "s"),
|
||
P.Enum("direction", "rev", s_directions),
|
||
P.Int("port", 7443, 1, 65535),
|
||
],
|
||
[
|
||
new StreamSpec("pkt", [Col.Seq("seq"), Col.U16("size"), Col.TsListener("t_send"), Col.TsDialer("t_recv", nullable: true)], Side.Listener, "seq"),
|
||
new StreamSpec("step", [Col.U16("index"), Col.U32("mbps"), Col.TsDialer("start_ts"), Col.TsDialer("end_ts")]),
|
||
],
|
||
p => (long)(p.GetNumber("mbps") * 1_000_000));
|
||
|
||
public static readonly KindSpec TcpEcho = new(
|
||
"tcp_echo",
|
||
"TCP echo",
|
||
"Small TCP messages echoed with four timestamps, plus periodic kernel tcp_info samples.",
|
||
Scope.Line,
|
||
new BlockSet("tcp", "fixed", "uniform", "echo", ["tcp_info"]),
|
||
[
|
||
P.Int("rate_hz", 20, 1, 200, "Hz"),
|
||
P.Int("min", 32, 16, 1400, "B"),
|
||
P.Int("max", 64, 16, 1400, "B"),
|
||
P.Int("tcp_info_ms", 100, 10, 1000, "ms"),
|
||
P.Int("port", 7444, 1, 65535),
|
||
P.Bool("tls", false),
|
||
],
|
||
[s_echoMsg, s_tcpInfo],
|
||
p => Bandwidth.TcpEcho(p.GetInt("rate_hz"), p.GetInt("max")));
|
||
|
||
public static readonly KindSpec TcpBulk = new(
|
||
"tcp_bulk",
|
||
"TCP bulk",
|
||
"Bulk TCP transfer on several streams with periodic byte counters and tcp_info.",
|
||
Scope.Line,
|
||
new BlockSet("tcp", "fixed", "fixed", "source", ["tcp_info"]),
|
||
[
|
||
P.Int("streams", 4, 1, 16),
|
||
P.Int("duration_s", 4, 1, 120, "s"),
|
||
P.Enum("direction", "rev", s_directions),
|
||
P.Int("sample_ms", 100, 20, 1000, "ms"),
|
||
P.Int("port", 7444, 1, 65535),
|
||
P.Bool("tls", true),
|
||
],
|
||
[
|
||
new StreamSpec("bytes", [Col.TsDialer("ts"), Col.U8("conn"), Col.U64("bytes")]),
|
||
s_tcpInfo,
|
||
],
|
||
_ => 0);
|
||
|
||
public static readonly KindSpec Connect = new(
|
||
"connect",
|
||
"Connect",
|
||
"Repeated TCP and TLS connection establishment with per-phase timings and outcome.",
|
||
Scope.Line | Scope.Target,
|
||
new BlockSet("tcp", "fixed", "fixed", "connect", []),
|
||
[
|
||
P.Int("per_minute", 6, 1, 60),
|
||
P.Bool("tls", true),
|
||
P.Int("timeout_ms", 5000, 500, 30000, "ms"),
|
||
P.Int("port", 7444, 1, 65535),
|
||
],
|
||
[
|
||
new StreamSpec(
|
||
"conn",
|
||
[Col.Seq("attempt"), Col.TsDialer("ts"), Col.U32("tcp_us", nullable: true), Col.U32("tls_us", nullable: true), Col.U8("outcome")]),
|
||
],
|
||
p => p.GetInt("per_minute") * 4000 / 60);
|
||
|
||
public static readonly KindSpec Hold = new(
|
||
"hold",
|
||
"Hold",
|
||
"A long-lived TLS connection with periodic heartbeats; records resets and lifetime.",
|
||
Scope.Line,
|
||
new BlockSet("tls", "fixed", "fixed", "hold", []),
|
||
[
|
||
P.Int("heartbeat_s", 30, 5, 300, "s"),
|
||
P.Int("port", 7444, 1, 65535),
|
||
],
|
||
[
|
||
new StreamSpec("hold", [Col.TsDialer("ts"), Col.U8("event"), Col.U32("lifetime_ms")]),
|
||
],
|
||
p => 2000 / Math.Max(1, p.GetInt("heartbeat_s")) * 8);
|
||
|
||
public static readonly KindSpec IcmpEcho = new(
|
||
"icmp_echo",
|
||
"ICMP echo",
|
||
"拨号方 or Agent side ICMP echo to a target address.",
|
||
Scope.Target,
|
||
new BlockSet("icmp", "fixed", "fixed", "echo", []),
|
||
[
|
||
P.Int("rate_hz", 1, 1, 20, "Hz"),
|
||
P.Int("size", 64, 44, 1400, "B"),
|
||
],
|
||
[
|
||
new StreamSpec("msg", [Col.Seq("seq"), Col.U16("size"), Col.TsLocal("t1"), new ColumnSpec("t4", ColumnType.I64, ColumnEnc.Delta, true, ColumnRole.TsLocal)]),
|
||
],
|
||
p => Bandwidth.UdpEcho(p.GetInt("rate_hz"), p.GetInt("size")));
|
||
|
||
public static readonly IReadOnlyList<KindSpec> All = [UdpEcho, UdpTrain, TcpEcho, TcpBulk, Connect, Hold, IcmpEcho];
|
||
|
||
public static KindSpec? Find(string id)
|
||
{
|
||
foreach (KindSpec kind in All)
|
||
{
|
||
if (kind.Id == id)
|
||
{
|
||
return kind;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|