Files
VerseVDI-Data-Plane/gateway/apollo_native_test.go
T
sechmachine 55afea72a1
Verify Data Plane / gateway (push) Successful in 4m14s
fix(gateway): bound Apollo video ingress
2026-08-09 19:07:22 +07:00

1355 lines
52 KiB
Go

package gateway
import (
"bytes"
"context"
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/binary"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"runtime"
"strconv"
"strings"
"sync"
"testing"
"time"
protocol "git.sechmachine.io.vn/sechmachine/VerseVDI-Protocol/gen/go/protocol"
)
type nativeRoundTripFunc func(*http.Request) (*http.Response, error)
func (fn nativeRoundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) {
return fn(request)
}
func TestNativeApolloManagementUsesSessionScopedMTLS(t *testing.T) {
serverTLS, clientTLS := testTLS(t)
server := httptest.NewUnstartedServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
if request.URL.Path != "/serverinfo" || request.TLS == nil || len(request.TLS.PeerCertificates) != 1 {
http.Error(response, "mTLS required", http.StatusUnauthorized)
return
}
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid></root>"))
}))
server.TLS = serverTLS
server.StartTLS()
defer server.Close()
host, portText, err := net.SplitHostPort(server.Listener.Addr().String())
if err != nil {
t.Fatal(err)
}
port, err := strconv.ParseInt(portText, 10, 64)
if err != nil {
t.Fatal(err)
}
pinned := sha256.Sum256(serverTLS.Certificates[0].Certificate[0])
work := protocol.ProviderSessionWork{
Version: "1", SessionID: "session-1", GatewayID: "gateway-1", ReconnectSequence: 0,
ExpiresAt: "2099-01-01T00:00:00Z", ProviderProfile: ProviderProfileApollo,
ProviderIdentity: "apollo-server#sha256:" + hex.EncodeToString(pinned[:]), PolicyVersionID: "policy-1", ApplicationID: "1", ClientID: "paired-client",
StreamPolicy: protocol.ProviderStreamPolicy{ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 8000, AudioEnabled: true},
ManagementHost: host, ManagementPort: port, StreamHost: host, StreamPort: 47984,
ClientCertificatePem: certificatePEM(t, clientTLS.Certificates[0]),
ClientPrivateKeyPem: privateKeyPEM(t, clientTLS.Certificates[0]),
ServerCertificatePem: certificatePEM(t, tls.Certificate{Certificate: [][]byte{serverTLS.Certificates[0].Certificate[1]}}),
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}
data, err := NewNativeApolloBackend().Management(context.Background(), LaunchRequest{SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work})
if err != nil {
t.Fatalf("Management() error = %v", err)
}
if info, err := ParseManagementXML(data); err != nil || info.Identity.UniqueID != "apollo-server" {
t.Fatalf("ParseManagementXML() = %+v, %v", info, err)
}
}
func TestNativeApolloSetupRejectsUnsupportedStreamPolicyBeforeProviderReadiness(t *testing.T) {
work := protocol.ProviderSessionWork{
Version: "1", SessionID: "session-1", GatewayID: "gateway-1",
ExpiresAt: "2099-01-01T00:00:00Z", ProviderProfile: ProviderProfileApollo,
ProviderIdentity: "provider#sha256:00", PolicyVersionID: "policy-1",
ApplicationID: "1", ClientID: "client-1", ManagementHost: "127.0.0.1", ManagementPort: 1,
StreamHost: "127.0.0.1", StreamPort: 1, ClientCertificatePem: "invalid",
ClientPrivateKeyPem: "invalid", ServerCertificatePem: "invalid",
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}
for name, policy := range map[string]protocol.ProviderStreamPolicy{
"audio-disabled": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 8000, AudioEnabled: false},
"av1": {ResolutionWidth: 3840, ResolutionHeight: 2160, Fps: 60, Codec: "AV1", BitrateKbps: 50000, AudioEnabled: true},
"h264-resolution": {ResolutionWidth: 4097, ResolutionHeight: 2160, Fps: 60, Codec: "H264", BitrateKbps: 50000, AudioEnabled: true},
"hevc-resolution": {ResolutionWidth: 8193, ResolutionHeight: 4320, Fps: 60, Codec: "HEVC", BitrateKbps: 80000, AudioEnabled: true},
"fps": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 241, Codec: "H264", BitrateKbps: 8000, AudioEnabled: true},
"bitrate-cap": {ResolutionWidth: 1920, ResolutionHeight: 1080, Fps: 60, Codec: "H264", BitrateKbps: 125001, AudioEnabled: true},
} {
t.Run(name, func(t *testing.T) {
work.StreamPolicy = policy
_, err := NewNativeApolloBackend().Setup(context.Background(), LaunchRequest{
SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work,
}, nil)
if !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("Setup() error = %v, want ErrProviderMalformed before provider readiness", err)
}
})
}
}
func TestNativeApolloRejectsProviderCapabilityMismatchBeforeInventoryOrLaunch(t *testing.T) {
serverTLS, clientTLS := testTLS(t)
var paths []string
management := httptest.NewUnstartedServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
paths = append(paths, request.URL.Path)
switch request.URL.Path {
case "/serverinfo":
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>1</ServerCodecModeSupport><MaxLumaPixelsHEVC>0</MaxLumaPixelsHEVC></root>"))
case "/applist":
_, _ = response.Write([]byte("<root><App><ID>42</ID></App></root>"))
default:
http.Error(response, "unexpected provider request", http.StatusBadRequest)
}
}))
management.TLS = serverTLS
management.StartTLS()
defer management.Close()
host, portText, err := net.SplitHostPort(management.Listener.Addr().String())
if err != nil {
t.Fatal(err)
}
port, err := strconv.ParseInt(portText, 10, 64)
if err != nil {
t.Fatal(err)
}
pinned := sha256.Sum256(serverTLS.Certificates[0].Certificate[0])
work := protocol.ProviderSessionWork{
Version: "1", SessionID: "session-source-policy", GatewayID: "gateway-1",
ExpiresAt: "2099-01-01T00:00:00Z", ProviderProfile: ProviderProfileApollo,
ProviderIdentity: "apollo-server#sha256:" + hex.EncodeToString(pinned[:]), PolicyVersionID: "policy-1",
ApplicationID: "42", ClientID: "paired-client",
StreamPolicy: protocol.ProviderStreamPolicy{
ResolutionWidth: 2560, ResolutionHeight: 1440, Fps: 120,
Codec: "HEVC", BitrateKbps: 40000, AudioEnabled: true,
},
ManagementHost: host, ManagementPort: port, StreamHost: host, StreamPort: 47984,
ClientCertificatePem: certificatePEM(t, clientTLS.Certificates[0]),
ClientPrivateKeyPem: privateKeyPEM(t, clientTLS.Certificates[0]),
ServerCertificatePem: certificatePEM(t, tls.Certificate{Certificate: [][]byte{serverTLS.Certificates[0].Certificate[1]}}),
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
}
adapter := NewApolloAdapter(NewNativeApolloBackend(), ProviderIdentity{UniqueID: "apollo-server", Fingerprint: "sha256:" + hex.EncodeToString(pinned[:])})
if _, err := adapter.Start(context.Background(), LaunchRequest{
SessionID: work.SessionID, ProviderProfile: ProviderProfileApollo,
ProviderIdentity: work.ProviderIdentity, ProviderWork: work,
}); err == nil {
t.Fatal("Start() accepted a provider/source policy mismatch")
}
if got := strings.Join(paths, ","); got != "/serverinfo" {
t.Fatalf("provider requests before capability rejection = %s", got)
}
}
func TestApolloProviderCapabilityRejectsHEVCLumaDowngrade(t *testing.T) {
info := ManagementInfo{
ServerCodecModeSupport: 0x101, HasServerCodecModeSupport: true,
MaxLumaPixelsHEVC: 1920 * 1080, HasMaxLumaPixelsHEVC: true,
}
policy := protocol.ProviderStreamPolicy{
ResolutionWidth: 3840, ResolutionHeight: 2160, Fps: 60,
Codec: "HEVC", BitrateKbps: 80000, AudioEnabled: true,
}
if err := validateApolloProviderStreamPolicy(info, policy); !errors.Is(err, ErrProviderMalformed) {
t.Fatalf("provider HEVC luma downgrade error = %v", err)
}
}
func TestNativeApolloSetupRequiresModernEncryptedRTSPOrder(t *testing.T) {
serverTLS, clientTLS := testTLS(t)
streamListener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer streamListener.Close()
controlServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer controlServer.Close()
audioServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer audioServer.Close()
videoServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer videoServer.Close()
streamHost, streamPortText, err := net.SplitHostPort(streamListener.Addr().String())
if err != nil {
t.Fatal(err)
}
streamPort, err := strconv.ParseInt(streamPortText, 10, 64)
if err != nil {
t.Fatal(err)
}
type fixtureKeyMaterial struct {
key []byte
keyID uint32
}
keyReady := make(chan []byte, 1)
keyMaterialReady := make(chan fixtureKeyMaterial, 1)
clipboardWrites := make(chan string, 1)
cancelCalls := make(chan struct{}, 1)
streamDone := make(chan error, 1)
go func() {
key := <-keyReady
codec, codecErr := newEncryptedRTSPCodec(key)
if codecErr != nil {
streamDone <- codecErr
return
}
expectedMethods := []string{"OPTIONS", "DESCRIBE", "SETUP", "SETUP", "SETUP", "ANNOUNCE", "PLAY"}
expectedTargets := []string{"rtspenc://" + streamListener.Addr().String(), "rtspenc://" + streamListener.Addr().String(), "streamid=audio/0/0", "streamid=video/0/0", "streamid=control/13/0", "streamid=control/13/0", "/"}
describeBody := "a=x-ss-general.featureFlags:1\r\na=x-ss-general.encryptionSupported:7\r\na=x-ss-general.encryptionRequested:1\r\na=fmtp:97 surround-params=21101\r\n"
responses := []string{
"RTSP/1.0 200 OK\r\nCSeq: 1\r\n\r\n",
fmt.Sprintf("RTSP/1.0 200 OK\r\nCSeq: 2\r\nContent-Type: application/sdp\r\nContent-Length: %d\r\n\r\n%s", len(describeBody), describeBody),
fmt.Sprintf("RTSP/1.0 200 OK\r\nCSeq: 3\r\nSession: fixture-session;timeout=90\r\nTransport: unicast;server_port=%d\r\nX-SS-Ping-Payload: 0123456789abcdef\r\n\r\n", audioServer.LocalAddr().(*net.UDPAddr).Port),
fmt.Sprintf("RTSP/1.0 200 OK\r\nCSeq: 4\r\nSession: fixture-session\r\nTransport: unicast;server_port=%d\r\nX-SS-Ping-Payload: fedcba9876543210\r\n\r\n", videoServer.LocalAddr().(*net.UDPAddr).Port),
fmt.Sprintf("RTSP/1.0 200 OK\r\nCSeq: 5\r\nSession: fixture-session\r\nTransport: unicast;server_port=%d\r\nX-SS-Connect-Data: 305419896\r\n\r\n", controlServer.LocalAddr().(*net.UDPAddr).Port),
"RTSP/1.0 200 OK\r\nCSeq: 6\r\nSession: fixture-session\r\n\r\n",
"RTSP/1.0 200 OK\r\nCSeq: 7\r\nSession: fixture-session\r\n\r\n",
}
for index, method := range expectedMethods {
connection, acceptErr := streamListener.Accept()
if acceptErr != nil {
streamDone <- acceptErr
return
}
header := make([]byte, encryptedRTSPHeaderSize)
if _, readErr := io.ReadFull(connection, header); readErr != nil {
_ = connection.Close()
streamDone <- readErr
return
}
length := binary.BigEndian.Uint32(header[:4]) & 0x7fffffff
frame := make([]byte, encryptedRTSPHeaderSize+int(length))
copy(frame, header)
if _, readErr := io.ReadFull(connection, frame[encryptedRTSPHeaderSize:]); readErr != nil {
_ = connection.Close()
streamDone <- readErr
return
}
plaintext, decryptErr := codec.OpenClient(frame)
firstLine, _, _ := strings.Cut(string(plaintext), "\r\n")
if decryptErr != nil || firstLine != method+" "+expectedTargets[index]+" RTSP/1.0" || !strings.Contains(string(plaintext), "CSeq: "+strconv.Itoa(index+1)+"\r\n") {
_, _ = connection.Write(hostEncryptedRTSPFrame(t, key, uint32(index+1), []byte("RTSP/1.0 400 Bad Request\r\nCSeq: "+strconv.Itoa(index+1)+"\r\n\r\n")))
_ = connection.Close()
streamDone <- ErrProviderMalformed
return
}
if method == "ANNOUNCE" {
for _, required := range []string{
"a=x-nv-video[0].clientViewportWd:2560", "a=x-nv-video[0].clientViewportHt:1440", "a=x-nv-video[0].maxFPS:120",
"a=x-nv-video[0].packetSize:1024", "a=x-nv-clientSupportHevc:1", "a=x-nv-vqos[0].bitStreamFormat:1",
"a=x-nv-vqos[0].bw.maximumBitrateKbps:32000", "a=x-ml-video.configuredBitrateKbps:40000", "a=x-nv-audio.surround.numChannels:2",
"a=x-nv-general.useReliableUdp:13", "a=x-ss-general.encryptionEnabled:7",
} {
if !strings.Contains(string(plaintext), required+"\r\n") {
_ = connection.Close()
streamDone <- ErrProviderMalformed
return
}
}
}
_, writeErr := connection.Write(hostEncryptedRTSPFrame(t, key, uint32(index+1), []byte(responses[index])))
_ = connection.Close()
if writeErr != nil {
streamDone <- writeErr
return
}
}
streamDone <- nil
}()
management := httptest.NewUnstartedServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
if request.TLS == nil || len(request.TLS.PeerCertificates) != 1 {
http.Error(response, "mTLS required", http.StatusUnauthorized)
return
}
switch request.URL.Path {
case "/serverinfo":
_, _ = response.Write([]byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>257</ServerCodecModeSupport><MaxLumaPixelsHEVC>1869449984</MaxLumaPixelsHEVC></root>"))
case "/applist":
if request.URL.Query().Get("uniqueid") != "paired-client" {
http.Error(response, "wrong client", http.StatusBadRequest)
return
}
_, _ = response.Write([]byte("<root><App><ID>42</ID></App></root>"))
case "/launch":
query := request.URL.Query()
if query.Get("uniqueid") != "paired-client" || query.Get("appid") != "42" || query.Get("corever") != "1" || query.Get("localAudioPlayMode") != "0" {
http.Error(response, "wrong launch", http.StatusBadRequest)
return
}
key, decodeErr := hex.DecodeString(query.Get("rikey"))
if decodeErr != nil || len(key) != 16 || query.Get("rikeyid") == "" {
http.Error(response, "bad key", http.StatusBadRequest)
return
}
keyID, keyIDErr := strconv.ParseUint(query.Get("rikeyid"), 10, 32)
if keyIDErr != nil {
http.Error(response, "bad key id", http.StatusBadRequest)
return
}
keyReady <- key
keyMaterialReady <- fixtureKeyMaterial{key: append([]byte(nil), key...), keyID: uint32(keyID)}
_, _ = response.Write([]byte("<root status_code=\"200\"><sessionUrl0>rtspenc://" + streamListener.Addr().String() + "</sessionUrl0></root>"))
case "/resume":
_, _ = response.Write([]byte("<root status_code=\"200\"/>"))
case "/cancel":
if request.Method != http.MethodGet {
http.Error(response, "cancel must be GET", http.StatusMethodNotAllowed)
return
}
cancelCalls <- struct{}{}
_, _ = response.Write([]byte("<root status_code=\"200\"><cancel>1</cancel></root>"))
case "/actions/clipboard":
if request.URL.Query().Get("type") != "text" || (request.Method != http.MethodGet && request.Method != http.MethodPost) {
http.Error(response, "bad clipboard request", http.StatusBadRequest)
return
}
if request.Method == http.MethodPost {
body, readErr := io.ReadAll(request.Body)
if readErr != nil || string(body) != "client clipboard" {
http.Error(response, "bad clipboard body", http.StatusBadRequest)
return
}
clipboardWrites <- string(body)
return
}
_, _ = response.Write([]byte("fixture clipboard"))
default:
http.NotFound(response, request)
}
}))
management.TLS = serverTLS
management.StartTLS()
defer management.Close()
managementHost, managementPortText, err := net.SplitHostPort(management.Listener.Addr().String())
if err != nil {
t.Fatal(err)
}
managementPort, err := strconv.ParseInt(managementPortText, 10, 64)
if err != nil {
t.Fatal(err)
}
pinned := sha256.Sum256(serverTLS.Certificates[0].Certificate[0])
work := protocol.ProviderSessionWork{
Version: "1", SessionID: "session-1", GatewayID: "gateway-1", ReconnectSequence: 0,
ExpiresAt: "2099-01-01T00:00:00Z", ProviderProfile: ProviderProfileApollo,
ProviderIdentity: "apollo-server#sha256:" + hex.EncodeToString(pinned[:]), PolicyVersionID: "policy-1", ApplicationID: "42", ClientID: "paired-client",
StreamPolicy: protocol.ProviderStreamPolicy{ResolutionWidth: 2560, ResolutionHeight: 1440, Fps: 120, Codec: "HEVC", BitrateKbps: 40000, AudioEnabled: true},
ManagementHost: managementHost, ManagementPort: managementPort, StreamHost: streamHost, StreamPort: streamPort,
ClientCertificatePem: certificatePEM(t, clientTLS.Certificates[0]), ClientPrivateKeyPem: privateKeyPEM(t, clientTLS.Certificates[0]),
ServerCertificatePem: certificatePEM(t, tls.Certificate{Certificate: [][]byte{serverTLS.Certificates[0].Certificate[1]}}),
ClipboardPolicy: protocol.ClipboardPolicy{MaxTextBytes: 65536, MaxUpdatesPerMinute: 30},
ProviderApplicationTerminationAllowed: true,
}
backend := NewNativeApolloBackend()
response, err := backend.Setup(context.Background(), LaunchRequest{SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work}, []byte("<root><uniqueid>apollo-server</uniqueid><ServerCodecModeSupport>257</ServerCodecModeSupport><MaxLumaPixelsHEVC>1869449984</MaxLumaPixelsHEVC></root>"))
if err != nil {
t.Fatalf("Setup() error = %v", err)
}
if parsed, err := ParseRTSPResponse(response); err != nil || parsed.Session != "fixture-session" {
t.Fatalf("ParseRTSPResponse() = %+v, %v", parsed, err)
}
if err := <-streamDone; err != nil {
t.Fatalf("stream transaction error = %v", err)
}
material := <-keyMaterialReady
videoData, videoParity := sourceShapedEncryptedVideoFEC(t, material.key)
audioPackets := make([][]byte, 0, apolloAudioDataShards)
for index, payload := range [][]byte{{'A'}, {'B'}, {'C'}, {'D'}} {
audioPackets = append(audioPackets, sourceShapedEncryptedAudioPacket(t, material.key, material.keyID, uint16(index), payload))
}
mediaDone := make(chan error, 2)
serveMedia := func(server *net.UDPConn, ping string, packets [][]byte) {
buffer := make([]byte, apolloMediaMaximumPacket)
count, remote, readErr := server.ReadFromUDP(buffer)
if readErr != nil || count != 20 || string(buffer[:16]) != ping {
if readErr != nil {
mediaDone <- readErr
} else {
mediaDone <- ErrProviderMalformed
}
return
}
for _, packet := range packets {
if _, writeErr := server.WriteToUDP(packet, remote); writeErr != nil {
mediaDone <- writeErr
return
}
}
mediaDone <- nil
}
go serveMedia(audioServer, "0123456789abcdef", audioPackets)
go serveMedia(videoServer, "fedcba9876543210", [][]byte{videoData, videoParity})
type observedControl struct {
typeID uint16
reliable bool
}
controls := make(chan observedControl, 16)
controlRemote := make(chan *net.UDPAddr, 1)
controlDone := make(chan error, 1)
go func() {
buffer := make([]byte, apolloENetMaximumPacket)
count, remote, readErr := controlServer.ReadFromUDP(buffer)
if readErr != nil {
controlDone <- readErr
return
}
connect := buffer[:count]
if count != 52 || connect[4] != apolloENetConnect|apolloENetAcknowledged || connect[5] != 0xff || binary.BigEndian.Uint32(connect[20:24]) != apolloENetChannels || binary.BigEndian.Uint32(connect[48:52]) != 305419896 {
controlDone <- ErrProviderMalformed
return
}
verify := make([]byte, 48)
apolloENetHeader(verify, 0, 0, time.Now())
verify[4] = apolloENetVerifyConnect | apolloENetAcknowledged
verify[5] = 0xff
binary.BigEndian.PutUint16(verify[6:8], 1)
binary.BigEndian.PutUint16(verify[8:10], 7)
verify[10], verify[11] = 2, 3
binary.BigEndian.PutUint32(verify[12:16], 1400)
binary.BigEndian.PutUint32(verify[16:20], 32768)
binary.BigEndian.PutUint32(verify[20:24], apolloENetChannels)
binary.BigEndian.PutUint32(verify[44:48], binary.BigEndian.Uint32(connect[44:48]))
if _, writeErr := controlServer.WriteToUDP(verify, remote); writeErr != nil {
controlDone <- writeErr
return
}
controlRemote <- remote
for {
count, _, readErr = controlServer.ReadFromUDP(buffer)
if readErr != nil {
controlDone <- readErr
return
}
packet := buffer[:count]
if len(packet) < 8 {
controlDone <- ErrProviderMalformed
return
}
command, channel := packet[4]&apolloENetCommandMask, packet[5]
sequence := binary.BigEndian.Uint16(packet[6:8])
switch command {
case 1:
continue
case apolloENetSendReliable:
if len(packet) < 10 || int(binary.BigEndian.Uint16(packet[8:10])) != len(packet)-10 {
controlDone <- ErrProviderMalformed
return
}
typeID, _ := sourceOpenClientControl(t, material.key, packet[10:])
controls <- observedControl{typeID: typeID, reliable: true}
if _, writeErr := controlServer.WriteToUDP(sourceShapedENetAcknowledgePacket(7, 2, channel, sequence), remote); writeErr != nil {
controlDone <- writeErr
return
}
case apolloENetSendUnsequenced:
if len(packet) < 12 || int(binary.BigEndian.Uint16(packet[10:12])) != len(packet)-12 {
controlDone <- ErrProviderMalformed
return
}
typeID, _ := sourceOpenClientControl(t, material.key, packet[12:])
controls <- observedControl{typeID: typeID}
case apolloENetPing:
if _, writeErr := controlServer.WriteToUDP(sourceShapedENetAcknowledgePacket(7, 2, channel, sequence), remote); writeErr != nil {
controlDone <- writeErr
return
}
case apolloENetDisconnect:
_, writeErr := controlServer.WriteToUDP(sourceShapedENetAcknowledgePacket(7, 2, channel, sequence), remote)
controlDone <- writeErr
return
default:
controlDone <- ErrProviderMalformed
return
}
}
}()
request := LaunchRequest{SessionID: "session-1", ProviderProfile: ProviderProfileApollo, ProviderWork: work}
parsed, err := ParseRTSPResponse(response)
if err != nil {
t.Fatal(err)
}
session, err := backend.Open(context.Background(), request, parsed)
if err != nil {
t.Fatalf("Open() error = %v", err)
}
if err := session.Ready(context.Background()); err != nil {
t.Fatalf("Ready() error = %v", err)
}
if clipboard, clipboardErr := session.ReadClipboard(context.Background()); clipboardErr != nil || clipboard != "fixture clipboard" {
t.Fatalf("ReadClipboard() = %q, %v", clipboard, clipboardErr)
}
if err := session.WriteClipboard(context.Background(), "client clipboard"); err != nil {
t.Fatalf("WriteClipboard() error = %v", err)
}
select {
case <-clipboardWrites:
case <-time.After(time.Second):
t.Fatal("provider did not receive authenticated clipboard write")
}
awaitControl := func(want uint16, reliable bool) {
deadline := time.NewTimer(time.Second)
defer deadline.Stop()
for {
select {
case observed := <-controls:
if observed.typeID == want && observed.reliable == reliable {
return
}
case <-deadline.C:
t.Fatalf("provider did not receive control %#x", want)
}
}
}
awaitControl(apolloControlTypeIDR, true)
awaitControl(apolloControlTypeStart, true)
if err := session.Input(context.Background(), InputEvent{Device: "keyboard", Code: 7, Pressed: true}); err != nil {
t.Fatal(err)
}
awaitControl(apolloControlTypeInput, true)
if err := session.Feedback(context.Background(), Feedback{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}}); err != nil {
t.Fatal(err)
}
awaitControl(apolloControlTypeFEC, false)
select {
case media := <-session.Video():
payload := media.Payload
if len(payload) != 1001 || payload[0] != 'A' || payload[1000] != 'B' {
t.Fatalf("source-shaped video relay = %x", payload)
}
case <-time.After(time.Second):
t.Fatal("source-shaped video was not relayed")
}
select {
case media := <-session.Audio():
payload := media.Payload
if string(payload) != "A" {
t.Fatalf("source-shaped audio relay = %x", payload)
}
case <-time.After(time.Second):
t.Fatal("source-shaped audio was not relayed")
}
remote := <-controlRemote
hostTermination := sourceSealHostControl(t, material.key, 0, apolloControlTypeTerm, []byte{1, 2, 3, 4})
if _, err := controlServer.WriteToUDP(sourceShapedENetReliablePacketOn(7, 2, apolloChannelGeneric, 1, hostTermination), remote); err != nil {
t.Fatal(err)
}
select {
case event := <-session.Events():
if event.Kind != ProviderEventTerminated || string(event.Payload) != string([]byte{1, 2, 3, 4}) {
t.Fatalf("provider termination event = %#v", event)
}
case <-time.After(time.Second):
t.Fatal("encrypted host termination was not forwarded")
}
terminateCtx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := session.Terminate(terminateCtx); err != nil {
t.Fatalf("Terminate() error = %v", err)
}
select {
case <-cancelCalls:
case <-time.After(time.Second):
t.Fatal("authorized provider application cancellation was not sent")
}
if err := <-controlDone; err != nil {
t.Fatalf("control fake = %v", err)
}
for range 2 {
if err := <-mediaDone; err != nil {
t.Fatalf("media fake = %v", err)
}
}
}
func TestValidateApolloDescribeRejectsUnknownLines(t *testing.T) {
message := apolloRTSPMessage{
headers: map[string]string{"content-type": "application/sdp"},
body: []byte("a=x-ss-general.featureFlags:1\r\n" +
"a=x-ss-general.encryptionSupported:7\r\n" +
"a=x-ss-general.encryptionRequested:1\r\n" +
"a=fmtp:97 surround-params=21101\r\n" +
"unexpected-source-line\r\n"),
}
if err := validateApolloDescribe(message); err == nil {
t.Fatal("validateApolloDescribe() accepted an unknown source line")
}
}
func TestNativeApolloTerminateSkipsProviderCancelWithoutServerPolicy(t *testing.T) {
session := newNativeApolloSession("session-1")
close(session.readDone)
session.managementClient = &http.Client{Transport: nativeRoundTripFunc(func(request *http.Request) (*http.Response, error) {
t.Fatalf("unauthorized provider cancellation request: %s %s", request.Method, request.URL)
return nil, fmt.Errorf("unexpected provider cancellation")
})}
session.managementHost = "provider.invalid"
session.managementPort = 47984
if err := session.Terminate(context.Background()); err != nil {
t.Fatalf("Terminate() error = %v", err)
}
}
func TestNativeApolloTerminateRetainsCleanupPendingAfterFailure(t *testing.T) {
session := newNativeApolloSession("session-1")
failed, cancel := context.WithCancel(context.Background())
cancel()
if err := session.Terminate(failed); !errors.Is(err, context.Canceled) {
t.Fatalf("first Terminate() error = %v", err)
}
if state := session.State(); state.State != ProviderStateCleanup || !state.CleanupPending {
t.Fatalf("failed cleanup state = %#v", state)
}
if err := session.Terminate(context.Background()); !errors.Is(err, context.Canceled) {
t.Fatalf("second Terminate() error = %v", err)
}
if state := session.State(); state.State != ProviderStateCleanup || !state.CleanupPending {
t.Fatalf("repeated cleanup state = %#v", state)
}
}
func TestApolloReconnectUsesResumeWithFreshRIK(t *testing.T) {
work := protocol.ProviderSessionWork{ReconnectSequence: 1, ApplicationID: "42", ClientID: "paired-client"}
path, values := apolloSessionRequest(work, []byte("0123456789abcdef"), 0x01020304)
if path != "/resume" || values.Get("rikey") != "30313233343536373839616263646566" || values.Get("rikeyid") != "16909060" || values.Get("localAudioPlayMode") != "0" {
t.Fatalf("resume request = path %q values %#v", path, values)
}
if values.Get("appid") != "" || values.Get("uniqueid") != "" || values.Get("corever") != "" {
t.Fatalf("resume request leaked launch-only values %#v", values)
}
}
func TestNativeApolloSessionRelaysOnlyAuthenticatedEncodedUDPMedia(t *testing.T) {
key := []byte("0123456789abcdef")
audioServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer audioServer.Close()
videoServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer videoServer.Close()
audioClient, err := net.DialUDP("udp", nil, audioServer.LocalAddr().(*net.UDPAddr))
if err != nil {
t.Fatal(err)
}
videoClient, err := net.DialUDP("udp", nil, videoServer.LocalAddr().(*net.UDPAddr))
if err != nil {
t.Fatal(err)
}
session := newNativeApolloSession("session-media")
const keyID = 0x01020304
session.media, err = newApolloMediaCodec(key, keyID)
if err != nil {
t.Fatal(err)
}
session.audioConn, session.videoConn = audioClient, videoClient
go session.readUDPMedia()
videoPacket := sourceShapedEncryptedVideoPacket(t, key, []byte{0x01, 0x02, 0x03})
if _, err := videoServer.WriteToUDP(videoPacket, videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
wantAudio := [][]byte{{0xf8, 0x08}, {0xf8, 0x09}, {0xf8, 0x0a}, {0xf8, 0x0b}}
for index, payload := range wantAudio {
packet := sourceShapedEncryptedAudioPacket(t, key, keyID, uint16(8+index), payload)
if _, err := audioServer.WriteToUDP(packet, audioClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
select {
case media := <-session.Video():
payload := media.Payload
if string(payload) != string([]byte{0x01, 0x02, 0x03}) {
t.Fatalf("video relay = %x, want encoded payload", payload)
}
case <-time.After(time.Second):
t.Fatal("encrypted video was not relayed")
}
for _, want := range wantAudio {
select {
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("audio relay = %x, want %x", payload, want)
}
case <-time.After(time.Second):
t.Fatal("encrypted audio was not relayed")
}
}
dataPacket, parityPacket := sourceShapedEncryptedVideoFEC(t, key)
for _, packet := range [][]byte{dataPacket, parityPacket} {
if _, err := videoServer.WriteToUDP(packet, videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
select {
case media := <-session.Video():
payload := media.Payload
if len(payload) != 1001 || payload[0] != 'A' || payload[999] != 'A' || payload[1000] != 'B' {
t.Fatalf("FEC video relay = %x", payload)
}
case <-time.After(time.Second):
t.Fatal("encrypted FEC video was not recovered")
}
for _, packet := range sourceShapedEncryptedAudioFEC(t, key, keyID) {
if _, err := audioServer.WriteToUDP(packet, audioClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
for _, want := range [][]byte{{'A'}, {'B'}, {'C'}, {'D'}} {
select {
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("FEC audio relay = %x, want %x", payload, want)
}
case <-time.After(time.Second):
t.Fatal("encrypted FEC audio was not recovered")
}
}
for block := 0; block < apolloAudioMaximumBlocks+1; block++ {
sequence := uint16(100 + block*apolloAudioDataShards)
packet := sourceShapedEncryptedAudioPacketWithHeaders(t, key, keyID, sequence, uint32(sequence)*5, 1, []byte{byte(block)})
if _, err := audioServer.WriteToUDP(packet, audioClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
for index, want := range [][]byte{{0xa0}, {0xa1}, {0xa2}, {0xa3}} {
sequence := uint16(124 + index)
packet := sourceShapedEncryptedAudioPacketWithHeaders(t, key, keyID, sequence, uint32(sequence)*5, 1, want)
if _, err := audioServer.WriteToUDP(packet, audioClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
for _, want := range [][]byte{{0xa0}, {0xa1}, {0xa2}, {0xa3}} {
select {
case media := <-session.Audio():
payload := media.Payload
if string(payload) != string(want) {
t.Fatalf("post-loss audio relay = %x, want %x", payload, want)
}
case <-time.After(time.Second):
t.Fatal("sustained loss permanently stalled newer audio")
}
}
if drops := session.Telemetry().MediaDrops; drops < 2 {
t.Fatalf("stale FEC eviction drops = %d, want at least 2", drops)
}
beforeIngress := session.mediaIngress.Load()
beforeDrops := session.mediaDrops.Load()
if _, err := videoServer.WriteToUDP(make([]byte, apolloMediaMaximumPacket+2), videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
marker := []byte{0xde, 0xad, 0xbe, 0xef}
markerPayload := make([]byte, apolloVideoShardPayloadSize)
markerPayload[0], markerPayload[3] = 0x01, 0x01
binary.LittleEndian.PutUint16(markerPayload[4:6], uint16(8+len(marker)))
copy(markerPayload[8:], marker)
markerPacket := sourceEncryptVideoRaw(t, key, sourceShapedVideoRaw(44, 103, 103, 0x07, 1, 0, 0, markerPayload), "0123456789dV")
if _, err := videoServer.WriteToUDP(markerPacket, videoClient.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
select {
case media := <-session.Video():
if !bytes.Equal(media.Payload, marker) {
t.Fatalf("post-oversize marker relay = %x, want %x", media.Payload, marker)
}
case <-time.After(time.Second):
t.Fatal("post-oversize marker was not relayed")
}
if got := session.mediaIngress.Load() - beforeIngress; got != 1 {
t.Fatalf("post-oversize video ingress = %d, want 1 valid marker", got)
}
if got := session.mediaDrops.Load(); got != beforeDrops {
t.Fatalf("post-oversize video drops = %d, want unchanged %d", got, beforeDrops)
}
terminateCtx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := session.Terminate(terminateCtx); err != nil {
t.Fatalf("Terminate() error = %v", err)
}
}
func TestNativeApolloVideoIngressSaturationIsBoundedAndAccounted(t *testing.T) {
if nativeApolloVideoIngressSlots != 2048 || nativeApolloVideoReadBuffer != 2_195_456 {
t.Fatalf("video ingress bounds = %d slots/%d bytes, want 2048/2195456", nativeApolloVideoIngressSlots, nativeApolloVideoReadBuffer)
}
ingress := newNativeApolloVideoIngress()
if len(ingress.slots) != 2048 || len(ingress.free) != 2048 || cap(ingress.ready) != 2048 || len(ingress.slots[0].packet) != apolloMediaMaximumPacket+1 {
t.Fatalf("video ingress pool = slots:%d free:%d ready-cap:%d packet:%d",
len(ingress.slots), len(ingress.free), cap(ingress.ready), len(ingress.slots[0].packet))
}
key := []byte("0123456789abcdef")
session, audioServer, videoServer := newNativeApolloMediaTestSession(t, key)
defer audioServer.Close()
defer videoServer.Close()
blockCtx, cancelBlock := context.WithCancel(context.Background())
defer cancelBlock()
blocked := make(chan struct{})
release := make(chan struct{})
var releaseOnce sync.Once
releaseAEAD := func() { releaseOnce.Do(func() { close(release) }) }
defer releaseAEAD()
session.media.aead = &qualificationBlockingAEAD{
AEAD: session.media.aead, ctx: blockCtx, blocked: blocked, release: release,
}
go session.readUDPMedia()
packet := sourceShapedEncryptedVideoPacket(t, key, []byte{1})
if _, err := videoServer.WriteToUDP(packet, session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
select {
case <-blocked:
case <-time.After(time.Second):
t.Fatal("video processor did not block")
}
waitIngress := func(want uint64) {
t.Helper()
deadline := time.NewTimer(time.Second)
defer deadline.Stop()
for session.mediaIngress.Load() < want {
select {
case <-deadline.C:
t.Fatalf("video ingress = %d, want at least %d", session.mediaIngress.Load(), want)
default:
runtime.Gosched()
}
}
}
waitIngress(1)
const overflow = 33
sent := uint64(1)
for remaining := nativeApolloVideoIngressSlots - 1 + overflow; remaining > 0; {
batch := min(32, remaining)
for range batch {
if _, err := videoServer.WriteToUDP([]byte{1}, session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
}
sent += uint64(batch)
waitIngress(sent)
remaining -= batch
}
if got := session.mediaDrops.Load(); got != overflow {
t.Fatalf("saturated video ingress drops = %d, want %d", got, overflow)
}
session.quiesceMedia()
cancelBlock()
select {
case <-session.readDone:
case <-time.After(time.Second):
t.Fatal("video ingress workers did not stop")
}
}
func TestNativeApolloTerminateStopsActiveVideoDrainAndProcessor(t *testing.T) {
key := []byte("0123456789abcdef")
session, audioServer, videoServer := newNativeApolloMediaTestSession(t, key)
defer audioServer.Close()
defer videoServer.Close()
blockCtx, cancelBlock := context.WithCancel(context.Background())
t.Cleanup(cancelBlock)
blocked := make(chan struct{})
session.media.aead = &qualificationBlockingAEAD{
AEAD: session.media.aead, ctx: blockCtx, blocked: blocked, release: make(chan struct{}),
}
go session.readUDPMedia()
if _, err := videoServer.WriteToUDP(sourceShapedEncryptedVideoPacket(t, key, []byte{1}), session.videoConn.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatal(err)
}
select {
case <-blocked:
case <-time.After(time.Second):
t.Fatal("video processor did not block")
}
terminateCtx, cancelTerminate := context.WithTimeout(context.Background(), time.Second)
defer cancelTerminate()
terminated := make(chan error, 1)
go func() { terminated <- session.Terminate(terminateCtx) }()
cancelBlock()
if err := <-terminated; err != nil {
t.Fatalf("Terminate() error = %v", err)
}
select {
case <-session.readDone:
default:
t.Fatal("Terminate returned before video drain and processor stopped")
}
select {
case _, ok := <-session.Video():
if ok {
t.Fatal("video channel remained open after worker shutdown")
}
default:
t.Fatal("video channel was not closed after worker shutdown")
}
}
func newNativeApolloMediaTestSession(t *testing.T, key []byte) (*nativeApolloSession, *net.UDPConn, *net.UDPConn) {
t.Helper()
audioServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
videoServer, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
_ = audioServer.Close()
t.Fatal(err)
}
audioClient, err := net.DialUDP("udp", nil, audioServer.LocalAddr().(*net.UDPAddr))
if err != nil {
_ = audioServer.Close()
_ = videoServer.Close()
t.Fatal(err)
}
videoClient, err := net.DialUDP("udp", nil, videoServer.LocalAddr().(*net.UDPAddr))
if err != nil {
_ = audioClient.Close()
_ = audioServer.Close()
_ = videoServer.Close()
t.Fatal(err)
}
session := newNativeApolloSession("session-video-ingress")
session.media, err = newApolloMediaCodec(key, 1)
if err != nil {
_ = audioClient.Close()
_ = videoClient.Close()
_ = audioServer.Close()
_ = videoServer.Close()
t.Fatal(err)
}
session.audioConn, session.videoConn = audioClient, videoClient
t.Cleanup(func() {
_ = audioClient.Close()
_ = videoClient.Close()
})
return session, audioServer, videoServer
}
func TestNativeApolloTerminateReleasesPressedProviderInput(t *testing.T) {
server, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1")})
if err != nil {
t.Fatal(err)
}
defer server.Close()
client, err := net.DialUDP("udp", nil, server.LocalAddr().(*net.UDPAddr))
if err != nil {
t.Fatal(err)
}
peer, err := newApolloENetPeer(client, time.Now)
if err != nil {
t.Fatal(err)
}
peer.state, peer.peerID, peer.outboundSession = apolloENetConnected, 1, 1
codecKey := []byte("0123456789abcdef")
codec, err := newApolloControlCodec(codecKey)
if err != nil {
t.Fatal(err)
}
session := newNativeApolloSession("session-terminate")
session.enet, session.control = peer, codec
close(session.readDone)
packets := make(chan []byte, 3)
go func() {
defer close(packets)
buffer := make([]byte, apolloENetMaximumPacket)
for {
_ = server.SetReadDeadline(time.Now().Add(time.Second))
count, _, readErr := server.ReadFromUDP(buffer)
if readErr != nil {
return
}
packet := append([]byte(nil), buffer[:count]...)
packets <- packet
if len(packet) >= 5 && packet[4]&apolloENetCommandMask == apolloENetDisconnect {
peer.close(nil)
return
}
}
}()
if err := session.Input(context.Background(), InputEvent{Device: "keyboard", Code: 7, Pressed: true}); err != nil {
t.Fatal(err)
}
terminateCtx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := session.Terminate(terminateCtx); err != nil {
t.Fatalf("Terminate() error = %v", err)
}
var observed [][]byte
for packet := range packets {
observed = append(observed, packet)
}
if len(observed) != 3 {
t.Fatalf("provider packets = %d, want pressed input, release, disconnect", len(observed))
}
typeID, payload := sourceOpenClientControl(t, codecKey, observed[1][10:])
if typeID != apolloControlTypeInput || len(payload) < 8 || binary.LittleEndian.Uint32(payload[4:8]) != 4 {
t.Fatalf("release packet = type %#x payload %x", typeID, payload)
}
}
func TestNativeApolloSessionForwardsEncryptedHostFeedback(t *testing.T) {
key := []byte("0123456789abcdef")
codec, err := newApolloControlCodec(key)
if err != nil {
t.Fatal(err)
}
session := newNativeApolloSession("session-feedback")
session.control = codec
messages := []struct {
typeID uint16
payload []byte
want ProviderEvent
}{
{apolloControlTypeRumble, []byte{0, 0, 0, 0, 1, 0, 0x34, 0x12, 0x78, 0x56}, ProviderEvent{Kind: ProviderEventRumble, Payload: []byte{1, 0x12, 0x34, 0x56, 0x78}}},
{apolloControlTypeHDR, append([]byte{1}, make([]byte, 26)...), ProviderEvent{Kind: ProviderEventHDR, Payload: []byte{1}}},
{apolloControlTypeTerm, []byte{1, 2, 3, 4}, ProviderEvent{Kind: ProviderEventTerminated, Payload: []byte{1, 2, 3, 4}}},
}
for sequence, message := range messages {
session.handleApolloControlPayload(apolloChannelGeneric, true, sourceSealHostControl(t, key, uint32(sequence), message.typeID, message.payload))
select {
case event := <-session.Events():
if event.Kind != message.want.Kind || string(event.Payload) != string(message.want.Payload) {
t.Fatalf("provider event = %#v, want %#v", event, message.want)
}
case <-time.After(time.Second):
t.Fatalf("host event %#x was not forwarded", message.typeID)
}
}
}
func TestApolloTerminalEventSurvivesFullFeedbackQueue(t *testing.T) {
session := newNativeApolloSession("session-full-feedback")
key := []byte("0123456789abcdef")
codec, err := newApolloControlCodec(key)
if err != nil {
t.Fatal(err)
}
session.control = codec
for range cap(session.events) {
session.events <- ProviderEvent{Kind: ProviderEventRumble, Payload: []byte{1, 0, 0, 0, 0}}
}
session.handleApolloControlPayload(
apolloChannelGeneric,
true,
sourceSealHostControl(t, key, 0, apolloControlTypeTerm, []byte{1, 2, 3, 4}),
)
foundTerminal := false
for range cap(session.events) {
event := <-session.events
foundTerminal = foundTerminal || event.Kind == ProviderEventTerminated
}
if !foundTerminal {
t.Fatal("encrypted host termination was lost behind a full feedback queue")
}
}
func TestPushLatestDropsExactlyOneOldPayload(t *testing.T) {
queue := make(chan []byte, 1)
if dropped := pushLatest(queue, []byte("old")); dropped {
t.Fatal("first media payload dropped")
}
if dropped := pushLatest(queue, []byte("new")); !dropped {
t.Fatal("bounded media queue did not report a drop")
}
if got := string(<-queue); got != "new" {
t.Fatalf("bounded media queue payload = %q", got)
}
}
func TestNativeProviderVideoQueueBoundsRealFrames(t *testing.T) {
const maximumQueuedVideoBytes = 4 << 20
session := newNativeApolloSession("bounded-video")
frame := bytes.Repeat([]byte{0x65}, 768<<10)
for index := 0; index < 12; index++ {
if !session.enqueueMedia(session.video, append([]byte(nil), frame...), time.Now()) {
t.Fatalf("frame %d was not accepted", index)
}
}
var queuedBytes int
for {
select {
case media := <-session.Video():
queuedBytes += len(media.Payload)
default:
if queuedBytes > maximumQueuedVideoBytes {
t.Fatalf("video queue retained %d bytes, limit %d", queuedBytes, maximumQueuedVideoBytes)
}
if drops := session.Telemetry().MediaDrops; drops != 7 {
t.Fatalf("latest-frame replacements = %d, want 7", drops)
}
if maximum := session.mediaQueueMaximum.Load(); maximum > nativeApolloVideoQueuePackets {
t.Fatalf("maximum video queue entries = %d", maximum)
}
if maximum := session.mediaQueueMaximumBytes.Load(); maximum > maximumQueuedVideoBytes {
t.Fatalf("maximum video queue bytes = %d", maximum)
}
return
}
}
}
func TestNativeProviderVideoQueueExpiresResidence(t *testing.T) {
session := newNativeApolloSession("expiring-video")
if !session.enqueueMedia(session.video, []byte("stale-frame"), time.Now()) {
t.Fatal("video frame was not accepted")
}
time.Sleep(nativeApolloVideoQueueLatency + 25*time.Millisecond)
select {
case media := <-session.Video():
t.Fatalf("expired video remained queued: %#v", media)
default:
}
if drops := session.Telemetry().MediaDrops; drops != 1 {
t.Fatalf("expired video drops = %d, want 1", drops)
}
}
func sourceShapedEncryptedVideoPacket(t *testing.T, key, encoded []byte) []byte {
t.Helper()
payload := make([]byte, apolloVideoShardPayloadSize)
payload[0], payload[3] = 0x01, 0x01
binary.LittleEndian.PutUint16(payload[4:6], uint16(8+len(encoded)))
copy(payload[8:], encoded)
plaintext := sourceShapedVideoRaw(42, 7, 1, 0x07, 1, 0, 0, payload)
return sourceEncryptVideoRaw(t, key, plaintext, "0123456789aV")
}
func sourceShapedEncryptedVideoFEC(t *testing.T, key []byte) ([]byte, []byte) {
t.Helper()
firstPayload := make([]byte, apolloVideoShardPayloadSize)
firstPayload[0], firstPayload[3] = 0x01, 0x01
binary.LittleEndian.PutUint16(firstPayload[4:6], 1)
for index := 8; index < len(firstPayload); index++ {
firstPayload[index] = 'A'
}
secondPayload := make([]byte, apolloVideoShardPayloadSize)
secondPayload[0] = 'B'
first := sourceShapedVideoRaw(43, 100, 100, 0x05, 2, 50, 0, firstPayload)
second := sourceShapedVideoRaw(43, 101, 101, 0x03, 2, 50, 1, secondPayload)
parity := make([]byte, len(first))
for index := range parity {
parity[index] = first[index] ^ sourceGFMultiply(second[index], 142)
}
sourceConfigureVideoShard(first, 43, 100, 0, 2, 50, 0)
sourceConfigureVideoShard(second, 43, 101, 1, 2, 50, 1)
sourceConfigureVideoShard(parity, 43, 102, 2, 2, 50, 2)
return sourceEncryptVideoRaw(t, key, second, "0123456789bV"), sourceEncryptVideoRaw(t, key, parity, "0123456789cV")
}
func sourceShapedVideoRaw(frame uint32, sequence uint16, streamIndex uint32, flags byte, dataShards, percentage, shardIndex int, payload []byte) []byte {
raw := make([]byte, apolloVideoRawPacketSize)
binary.LittleEndian.PutUint32(raw[16:20], streamIndex<<8)
binary.LittleEndian.PutUint32(raw[20:24], frame)
raw[24], raw[26] = flags, 0x10
binary.LittleEndian.PutUint32(raw[28:32], uint32(shardIndex<<12|dataShards<<22|percentage<<4))
copy(raw[32:], payload)
sourceConfigureVideoShard(raw, frame, sequence, streamIndex, dataShards, percentage, shardIndex)
return raw
}
func sourceConfigureVideoShard(raw []byte, frame uint32, sequence uint16, streamIndex uint32, dataShards, percentage, shardIndex int) {
raw[0] = 0x90
binary.BigEndian.PutUint16(raw[2:4], sequence)
binary.BigEndian.PutUint32(raw[4:8], 99)
binary.LittleEndian.PutUint32(raw[20:24], frame)
raw[27] = 0
binary.LittleEndian.PutUint32(raw[28:32], uint32(shardIndex<<12|dataShards<<22|percentage<<4))
}
func sourceEncryptVideoRaw(t *testing.T, key, plaintext []byte, iv string) []byte {
t.Helper()
if len(plaintext) != apolloVideoRawPacketSize || len(iv) != 12 {
t.Fatal("invalid source video fixture")
}
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
aead, err := cipher.NewGCM(block)
if err != nil {
t.Fatal(err)
}
sealed := aead.Seal(nil, []byte(iv), plaintext, nil)
packet := make([]byte, 32+len(plaintext))
copy(packet[:12], iv)
binary.LittleEndian.PutUint32(packet[12:16], binary.LittleEndian.Uint32(plaintext[20:24]))
copy(packet[16:32], sealed[len(plaintext):])
copy(packet[32:], sealed[:len(plaintext)])
return packet
}
func sourceOpenClientControl(t *testing.T, key, packet []byte) (uint16, []byte) {
t.Helper()
if len(packet) < apolloControlHeaderSize+apolloControlTagSize+apolloControlInnerSize || binary.LittleEndian.Uint16(packet[:2]) != apolloControlOuterType || int(binary.LittleEndian.Uint16(packet[2:4])) != len(packet)-4 {
t.Fatalf("control packet = %x", packet)
}
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
aead, err := cipher.NewGCM(block)
if err != nil {
t.Fatal(err)
}
nonce := make([]byte, 12)
binary.LittleEndian.PutUint32(nonce, binary.LittleEndian.Uint32(packet[4:8]))
nonce[10], nonce[11] = 'C', 'C'
sealed := append([]byte(nil), packet[24:]...)
sealed = append(sealed, packet[8:24]...)
plaintext, err := aead.Open(nil, nonce, sealed, nil)
if err != nil || len(plaintext) < apolloControlInnerSize || int(binary.LittleEndian.Uint16(plaintext[2:4])) != len(plaintext)-apolloControlInnerSize {
t.Fatalf("control open = %x, %v", packet, err)
}
return binary.LittleEndian.Uint16(plaintext[:2]), append([]byte(nil), plaintext[4:]...)
}
func sourceSealHostControl(t *testing.T, key []byte, sequence uint32, typeID uint16, payload []byte) []byte {
t.Helper()
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
aead, err := cipher.NewGCM(block)
if err != nil {
t.Fatal(err)
}
inner := make([]byte, apolloControlInnerSize+len(payload))
binary.LittleEndian.PutUint16(inner[:2], typeID)
binary.LittleEndian.PutUint16(inner[2:4], uint16(len(payload)))
copy(inner[4:], payload)
nonce := make([]byte, 12)
binary.LittleEndian.PutUint32(nonce, sequence)
nonce[10], nonce[11] = 'H', 'C'
sealed := aead.Seal(nil, nonce, inner, nil)
packet := make([]byte, apolloControlHeaderSize+len(sealed))
binary.LittleEndian.PutUint16(packet[:2], apolloControlOuterType)
binary.LittleEndian.PutUint16(packet[2:4], uint16(4+len(sealed)))
binary.LittleEndian.PutUint32(packet[4:8], sequence)
copy(packet[8:24], sealed[len(inner):])
copy(packet[24:], sealed[:len(inner)])
return packet
}
func sourceGFMultiply(first, second byte) byte {
var product byte
for second != 0 {
if second&1 != 0 {
product ^= first
}
high := first & 0x80
first <<= 1
if high != 0 {
first ^= 0x1d
}
second >>= 1
}
return product
}
func sourceShapedEncryptedAudioPacket(t *testing.T, key []byte, keyID uint32, sequence uint16, encoded []byte) []byte {
return sourceShapedEncryptedAudioPacketWithHeaders(t, key, keyID, sequence, 99, 1, encoded)
}
func sourceShapedEncryptedAudioPacketWithHeaders(t *testing.T, key []byte, keyID uint32, sequence uint16, timestamp, ssrc uint32, encoded []byte) []byte {
t.Helper()
packet := make([]byte, 12)
packet[0], packet[1] = 0x80, 97
binary.BigEndian.PutUint16(packet[2:4], sequence)
binary.BigEndian.PutUint32(packet[4:8], timestamp)
binary.BigEndian.PutUint32(packet[8:12], ssrc)
padded := append([]byte(nil), encoded...)
padding := aes.BlockSize - len(padded)%aes.BlockSize
for range padding {
padded = append(padded, byte(padding))
}
iv := make([]byte, aes.BlockSize)
binary.BigEndian.PutUint32(iv, keyID+uint32(sequence))
block, err := aes.NewCipher(key)
if err != nil {
t.Fatal(err)
}
cipher.NewCBCEncrypter(block, iv).CryptBlocks(padded, padded)
return append(packet, padded...)
}
func sourceShapedEncryptedAudioFEC(t *testing.T, key []byte, keyID uint32) [][]byte {
t.Helper()
const base = uint16(12)
const timestamp = uint32(100)
data := make([][]byte, apolloAudioDataShards)
for index, payload := range [][]byte{{'A'}, {'B'}, {'C'}, {'D'}} {
data[index] = sourceShapedEncryptedAudioPacketWithHeaders(t, key, keyID, base+uint16(index), timestamp+uint32(index*5), 0, payload)
}
parity := make([]byte, len(data[0])-apolloRTPHeaderSize)
for index, coefficient := range sourceAudioFECRow() {
for offset, value := range data[index][apolloRTPHeaderSize:] {
parity[offset] ^= sourceGFMultiply(value, coefficient)
}
}
fec := make([]byte, apolloRTPHeaderSize+12+len(parity))
fec[0], fec[1] = 0x80, 127
binary.BigEndian.PutUint16(fec[2:4], base+apolloAudioDataShards)
fec[apolloRTPHeaderSize+1] = 97
binary.BigEndian.PutUint16(fec[apolloRTPHeaderSize+2:apolloRTPHeaderSize+4], base)
binary.BigEndian.PutUint32(fec[apolloRTPHeaderSize+4:apolloRTPHeaderSize+8], timestamp)
binary.BigEndian.PutUint32(fec[apolloRTPHeaderSize+8:apolloRTPHeaderSize+12], 0)
copy(fec[apolloRTPHeaderSize+12:], parity)
return [][]byte{data[1], data[2], data[3], fec}
}
func sourceAudioFECRow() []byte {
return []byte{0x77, 0x40, 0x38, 0x0e}
}
func certificatePEM(t *testing.T, certificate tls.Certificate) string {
t.Helper()
if len(certificate.Certificate) == 0 {
t.Fatal("expected certificate")
}
return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certificate.Certificate[0]}))
}
func privateKeyPEM(t *testing.T, certificate tls.Certificate) string {
t.Helper()
encoded, err := x509.MarshalPKCS8PrivateKey(certificate.PrivateKey)
if err != nil {
t.Fatal(err)
}
return string(pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encoded}))
}