feat(gateway): repair native Apollo provider path

This commit is contained in:
sechmachine
2026-07-29 17:24:34 +07:00
parent 67eeb9e898
commit 236c7c2973
23 changed files with 5088 additions and 345 deletions
+89 -44
View File
@@ -55,24 +55,49 @@ func FuzzDecodeFrame(f *testing.F) {
})
}
func FuzzDecodeControlPacket(f *testing.F) {
seed, _ := EncodeControlPacket(ControlPacket{Kind: 1, Sequence: 2, Payload: []byte("fixture")})
f.Add(seed)
f.Add([]byte("APC1"))
f.Fuzz(func(t *testing.T, data []byte) {
_, _ = DecodeControlPacket(data)
})
}
func FuzzDecodeInputEvent(f *testing.F) {
seed, _ := EncodeInputEvent(InputEvent{Sequence: 1, Device: "keyboard", Code: 7, Pressed: true})
f.Add(seed)
f.Add([]byte("INP1"))
f.Add([]byte("VGI1"))
f.Fuzz(func(t *testing.T, data []byte) {
_, _ = DecodeInputEvent(data)
})
}
func TestInputEventUsesFixedProtocolVGI1Vector(t *testing.T) {
encoded, err := EncodeInputEvent(InputEvent{Sequence: 7, Device: "keyboard", Code: 30, Pressed: true, Payload: []byte{2}})
if err != nil {
t.Fatal(err)
}
const expected = "5647493101040102001e"
if hex.EncodeToString(encoded) != expected {
t.Fatalf("EncodeInputEvent() = %x, want %s", encoded, expected)
}
decoded, err := DecodeInputEvent(encoded)
if err != nil || decoded.Sequence != 0 || decoded.Device != "keyboard" || decoded.Code != 30 || !decoded.Pressed || string(decoded.Payload) != string([]byte{2}) {
t.Fatalf("DecodeInputEvent() = %#v, %v", decoded, err)
}
}
func TestClientFeedbackUsesFixedProtocolVGFVector(t *testing.T) {
feedback := Feedback{Sequence: 9, Kind: FeedbackFEC, Payload: []byte{0, 0, 0, 42, 0, 5, 0, 3, 0, 2, 0, 10, 0, 2, 0, 8, 0, 2, 20, 0, 1}}
encoded, err := EncodeClientFeedback(feedback)
if err != nil {
t.Fatal(err)
}
const expected = "56474631000200150000002a000500030002000a000200080002140001"
if hex.EncodeToString(encoded) != expected {
t.Fatalf("EncodeClientFeedback() = %x, want %s", encoded, expected)
}
decoded, err := DecodeClientFeedback(encoded)
if err != nil || decoded.Kind != FeedbackFEC || string(decoded.Payload) != string(feedback.Payload) {
t.Fatalf("DecodeClientFeedback() = %#v, %v", decoded, err)
}
if _, err := DecodeClientFeedback([]byte{'F', 'B', 'R', 'K', 0}); !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("legacy feedback accepted: %v", err)
}
}
func TestCapabilityIntersectionAndBoundedQueue(t *testing.T) {
capabilities := DefaultCapabilities()
if _, err := IntersectCapabilities(capabilities, capabilities); err != nil {
@@ -199,39 +224,6 @@ func TestProviderTimeoutAndBoundedInput(t *testing.T) {
if _, err := EncodeInputEvent(InputEvent{Device: strings.Repeat("d", 65)}); !errors.Is(err, ErrInputMalformed) {
t.Fatalf("oversized input accepted: %v", err)
}
if _, err := DecodeControlPacket([]byte("APC1")); !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("truncated control accepted: %v", err)
}
}
func TestNativeApolloEncodedRelay(t *testing.T) {
provider, peer := net.Pipe()
session := newNativeApolloSession(provider, "session-native")
go session.readMedia()
go func() {
_, _ = peer.Write([]byte{'$', 0, 0, 3, 1, 2, 3})
_, _ = peer.Write([]byte{'$', 1, 0, 2, 4, 5})
}()
select {
case payload := <-session.Video():
if string(payload) != string([]byte{1, 2, 3}) {
t.Fatalf("video payload changed: %x", payload)
}
case <-time.After(time.Second):
t.Fatal("video payload not relayed")
}
select {
case payload := <-session.Audio():
if string(payload) != string([]byte{4, 5}) {
t.Fatalf("audio payload changed: %x", payload)
}
case <-time.After(time.Second):
t.Fatal("audio payload not relayed")
}
terminateCtx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)
defer cancel()
_ = session.Terminate(terminateCtx)
_ = peer.Close()
}
func TestAdmissionQUICMTLSRelayAndCleanup(t *testing.T) {
@@ -240,7 +232,7 @@ func TestAdmissionQUICMTLSRelayAndCleanup(t *testing.T) {
authority := protocol.SessionAuthority{Version: "1", SessionID: "session-1", GatewayID: "gateway-1", Audience: "versevdi-gateway", ReconnectSequence: 0, ExpiresAt: time.Now().Add(5 * time.Second).UTC().Format(time.RFC3339Nano), Capabilities: DefaultCapabilities(), ProviderProfile: ProviderProfileApollo, ProviderIdentity: fake.config.Identity.Key()}
admission := &oneTimeAdmission{authority: authority, released: make(chan struct{})}
reporter := &recordingProviderStateReporter{}
server, err := NewServer(ServerConfig{ListenAddress: "127.0.0.1:0", TLSConfig: serverTLS, GatewayID: "gateway-1", Capabilities: DefaultCapabilities(), ProviderCapabilities: DefaultCapabilities(), Admission: admission, ProviderStateReporter: reporter, Provider: fake})
server, err := NewServer(ServerConfig{ListenAddress: "127.0.0.1:0", TLSConfig: serverTLS, GatewayID: "gateway-1", Capabilities: DefaultCapabilities(), ProviderCapabilities: DefaultCapabilities(), Admission: admission, ProviderStateReporter: reporter, ClipboardAuditReporter: reporter, Provider: fake})
if err != nil {
t.Fatal(err)
}
@@ -263,6 +255,44 @@ func TestAdmissionQUICMTLSRelayAndCleanup(t *testing.T) {
t.Fatalf("unexpected media channel %d", frame.Channel)
}
}
metrics := server.Metrics()
if metrics.AdmittedSessions != 1 || metrics.MediaPackets < 2 || metrics.MediaBytes == 0 || metrics.ProcessingSamples < 2 || metrics.ProviderState != 2 {
t.Fatalf("observed egress telemetry = %#v", metrics)
}
fakeSession, ok := fake.LastSession().(*fakeSession)
if !ok {
t.Fatal("fake provider session type")
}
fakeSession.mu.Lock()
fakeSession.clipboard = "host clipboard"
fakeSession.mu.Unlock()
fakeSession.EmitEvent(ProviderEvent{Kind: ProviderEventRumble, Payload: []byte{1, 0x12, 0x34, 0x56, 0x78}})
clipboardCtx, clipboardCancel := context.WithTimeout(context.Background(), 2*time.Second)
deliveredClipboard, clipboardErr := client.ReceiveClipboard(clipboardCtx)
clipboardCancel()
if clipboardErr != nil || deliveredClipboard.Direction != "provider_to_client" || deliveredClipboard.Text != "host clipboard" || deliveredClipboard.Encoding != "utf-8" {
t.Fatalf("provider clipboard = %#v, %v", deliveredClipboard, clipboardErr)
}
if audits := reporter.Audits(); len(audits) == 0 || audits[0].Direction != "provider_to_client" || audits[0].Outcome != "forwarded" || audits[0].Reason != "forwarded" || audits[0].TextBytes != int64(len("host clipboard")) {
t.Fatalf("clipboard audits = %#v", audits)
}
eventCtx, eventCancel := context.WithTimeout(context.Background(), time.Second)
event, eventErr := client.ReceiveProviderEvent(eventCtx)
eventCancel()
if eventErr != nil || event.Kind != ProviderEventRumble || string(event.Payload) != string([]byte{1, 0x12, 0x34, 0x56, 0x78}) {
t.Fatalf("provider event = %#v, %v", event, eventErr)
}
if err := client.SendClipboard(protocol.GatewayClipboardText{Direction: "client_to_provider", Text: "clipboard", Encoding: "utf-8", LoopToken: "abcdefghijklmnop"}); err != nil {
t.Fatal(err)
}
select {
case value := <-fakeSession.clipboardWrites:
if value != "clipboard" {
t.Fatalf("provider clipboard = %q", value)
}
case <-time.After(time.Second):
t.Fatal("gateway did not forward clipboard")
}
if err := client.SendInput(InputEvent{Sequence: 1, Device: "keyboard", Code: 7, Pressed: true}); err != nil {
t.Fatal(err)
}
@@ -331,6 +361,7 @@ type oneTimeAdmission struct {
type recordingProviderStateReporter struct {
mu sync.Mutex
states []protocol.ProviderState
audits []protocol.GatewayClipboardAudit
}
func (r *recordingProviderStateReporter) ReportProviderState(_ context.Context, state protocol.ProviderState) error {
@@ -346,6 +377,19 @@ func (r *recordingProviderStateReporter) States() []protocol.ProviderState {
return append([]protocol.ProviderState(nil), r.states...)
}
func (r *recordingProviderStateReporter) ReportClipboardAudit(_ context.Context, audit protocol.GatewayClipboardAudit) error {
r.mu.Lock()
defer r.mu.Unlock()
r.audits = append(r.audits, audit)
return nil
}
func (r *recordingProviderStateReporter) Audits() []protocol.GatewayClipboardAudit {
r.mu.Lock()
defer r.mu.Unlock()
return append([]protocol.GatewayClipboardAudit(nil), r.audits...)
}
func (a *oneTimeAdmission) Admit(context.Context, protocol.TunnelAdmissionRequest) (protocol.SessionAuthority, error) {
if !a.used.CompareAndSwap(false, true) {
return protocol.SessionAuthority{}, ErrAdmissionRejected
@@ -364,6 +408,7 @@ func (a *oneTimeAdmission) ProviderWork(_ context.Context, authority protocol.Se
PolicyVersionID: "policy-1", ApplicationID: "1", ClientID: "paired-client", ManagementHost: "apollo.test", ManagementPort: 47990,
StreamHost: "apollo.test", StreamPort: 47984, ClientCertificatePem: "certificate",
ClientPrivateKeyPem: "private-key", ServerCertificatePem: "server-certificate",
ClipboardPolicy: protocol.ClipboardPolicy{ClientToProviderEnabled: true, ProviderToClientEnabled: true, MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}, nil
}