Skip to content

Remote Desktop Stacks ru

Se.Cherkasov edited this page Aug 23, 2026 · 1 revision

Стеки удалённых рабочих столов

English · Русский

Оба протокола реализованы в этом репозитории. Внешние процессы не вызываются, сторонние клиенты не встраиваются.

Что видит UI

interface RemoteDesktopSession {
    val framebuffer: RemoteFramebuffer          // пиксели
    val updates: Flow<RemoteDesktopUpdate>      // холодный поток на одного сборщика; сбор запускает сессию
    val title: String
    val capabilities: RemoteDesktopCapabilities // какие необязательные возможности есть у протокола
    val diagnostics: RemoteDesktopDiagnostics
    suspend fun sendPointer(x: Int, y: Int, buttonMask: Int)
    suspend fun sendKey(event: RemoteKeyEvent, down: Boolean)
    suspend fun sendClipboardText(text: String)
    …
}

VNC и RDP различаются почти во всех деталях протокола и ни в чём из того, что нужно экрану, поэтому их словарь — keysym'ы, скан-коды, кодировки — заканчивается на адаптерах (VncRemoteDesktop, RdpRemoteDesktop). Маска указателя следует соглашению RFB как более выразительному; RDP, который шлёт переходы, выводит их из разницы с предыдущим вызовом.

RemoteFramebuffer — общий ARGB-буфер (resize / blit / fill / copyRect).

RDP

flowchart TD
  TCP[TCP + TLS<br/>RdpTcpTransport] --> X[Запрос соединения X.224]
  X --> NLA[CredSSP / NTLM<br/>nla: TsRequest, Ntlm*, Der]
  NLA --> MCS[MCS + GCC<br/>Mcs, McsConnect, Gcc, Per, Ber]
  MCS --> LIC[Лицензирование<br/>LicenseExchange + RdpLicenseCrypto]
  LIC --> CAP[Обмен возможностями → font map<br/>RdpConnectionSequence]
  CAP --> LIVE{живая сессия}
  LIVE --> FP[Fast-path обновления<br/>FastPath, SurfaceCommands, PointerUpdate]
  LIVE --> DYC[Динамические каналы · MS-RDPEDYC<br/>DynamicChannelHandler]
  DYC --> EGFX[egfx: GraphicsChannel, GraphicsSurface]
  DYC --> CLIP[ClipboardChannel]
  DYC --> DISP[DisplayControlChannel]
  DYC --> AUD[AudioChannel]
Loading
Слой Файлы
Байтовый ввод-вывод с проверкой границ RdpIo (RdpReader, RdpWriter, RdpSource, RdpSink); некорректный ввод → RdpProtocolException
Последовательность подключения RdpConnect (RdpConnectionSequence, RdpSessionState) — чистый протокол над внедрённым source/sink, поэтому вся последовательность прогоняется тестом
Точка входа и живая сессия RdpTransport (RdpTransport, RdpSession, RdpUpdate)
Растровые кодеки NsCodec, PlanarCodec, InterleavedRle, rfx/ (RemoteFX: DWT, RLGR, цвет)
Кодеки графического конвейера egfx/: Progressive, ProgressiveDwt, ClearCodec, Zgfx, AvcCodec, AvcStream, Avc444Planes, H264Color
Платформенная криптография nla/NtlmCrypto, LicenseCrypto / RdpLicenseCrypto — внедряются, чтобы протокол оставался платформенно-независимым
Доверие сертификату RdpCertificate / RdpCertificateVerifier (TOFU по отпечатку), RdpVerifyingTrustManager, FileRdpCertificateStore
Прочее в сессии RdpDisplayScale, RdpImageQuality, RdpClientSettings, RdpFile/RdpFileImport, ServerRedirection (маршрутизация фермы)

H.264 внедряется как egfx/H264Decoder: H264DecoderFactory + YuvFrame. Платформа отвечает только за декодер — формат на проводе и сборка 4:4:4 принадлежат AvcCodec — а available решает, объявляется ли AVC вообще. Десктоп ищет ffmpeg в PATH (process/resolveExecutableOnPath, FfmpegH264, Y4mFrameReader), Android использует MediaCodecH264.

Перенаправление звука идёт через общий контракт audio/RemoteAudio (AudioOutputs, RemoteAudioPlayerFactory, RemoteAudioFormat) и audio/PcmPlayer: платформенный sink отвечает за устройство, но никогда — за момент его открытия.

VNC

Слой Файлы
Точка входа, сессия, аутентификация VncTransport (VncTransport, VncSession, VncUpdate, VncAuth)
Провод VncIo, RfbCodec, RfbEncodings, RfbStreaming, PixelFormat
Адаптер к общему контракту VncRemoteDesktop
Внедряемые платформенные кодеки VncCodecPorts: InflaterFactory (zlib), VncImageDecoder (JPEG), VncChallengeResponder (DES-челлендж, которого требует VNC-Auth)
Транспорт VncTcpTransport (jvmShared)

VNC-Auth использует DES, потому что так написано в RFC 6143; это ограничение протокола, а не выбор, и соответствующие оповещения сканера закрыты как won't fix именно поэтому.

Общие правила

  • Типы протоколов не протекают в UI — граница проходит по общему контракту в graphics/.
  • Любое чтение PDU идёт через ридер с проверкой границ; некорректный ввод даёт типизированное исключение протокола, а не выход за пределы массива.
  • Текст, выбранный сервером (превью буфера, имена рабочих столов), недоверенный и рисуется через ui/design/UntrustedText.
  • Возможности платформы внедряются, а не определяются внутри кода протокола.

Clone this wiki locally