xdeskv1.0.0
ReferenceRéférence

ProtocolProtocole

The wire format between a client and the host: the port, the JSON control messages, the binary frames, the encrypted UDP video, byte by byte.Le format réseau entre un client et l'hôte : le port, les messages de contrôle JSON, les trames binaires, la vidéo UDP chiffrée, octet par octet.

Read from include/xdesk/net/Protocol.hpp, Datagram.hpp and the writers of the encoder. Protocol version 1 (XDESK_PROTOCOL_VERSION, bumped on every incompatible change).

Lu depuis include/xdesk/net/Protocol.hpp, Datagram.hpp et les écritures de l'encodeur. Version du protocole 1 (XDESK_PROTOCOL_VERSION, augmentée à chaque changement incompatible).

1. FramingTrames

One TLS 1.3 port (47800 by default) serves HTTPS (/, /api/info, /app/xdesk.apk, /app/version) and the websocket /ws (RFC 6455); the extra video sockets of the web viewers open /lane.

  • a text frame is one JSON object {"t": "<type>", ...} (control), 64 KiB at most;
  • a binary frame is [u8 type][payload], every integer big endian, 32 MiB at most (a full 4K frame);
  • the LAN discovery is a UDP broadcast on port 47801.

Un seul port TLS 1.3 (47800 par défaut) sert le HTTPS (/, /api/info, /app/xdesk.apk, /app/version) et la websocket /ws (RFC 6455) ; les sockets vidéo supplémentaires des viewers web ouvrent /lane.

  • une trame texte est un objet JSON {"t": "<type>", ...} (contrôle), 64 Kio au plus ;
  • une trame binaire est [u8 type][payload], tous les entiers en big endian, 32 Mio au plus (une image 4K complète) ;
  • la découverte sur le LAN est un broadcast UDP sur le port 47801.

2. HandshakeHandshake

  1. client → host
    TLS 1.3, group X25519MLKEM768 first (native clients: post-quantum groups only), certificate checked against the pinned fingerprint.
  2. client → host
    hello: v kind name os device nonce udp.
  3. host → client
    challenge: host version nonce salt kdf known.
  4. client → host
    auth: method = code (web) or proof (native, HMAC(Argon2id(code, salt), transcript)), device, remember.
  5. host → client
    pending while the person at the PC decides (unknown device), then welcome (session perms screen capture device proof) or denied (reason).
  1. client → hôte
    TLS 1.3, groupe X25519MLKEM768 en premier (clients natifs : groupes post-quantiques seulement), certificat vérifié avec l'empreinte épinglée.
  2. client → hôte
    hello : v kind name os device nonce udp.
  3. hôte → client
    challenge : host version nonce salt kdf known.
  4. client → hôte
    auth : method = code (web) ou proof (natif, HMAC(Argon2id(code, sel), transcript)), device, remember.
  5. hôte → client
    pending pendant que la personne devant le PC décide (appareil inconnu), puis welcome (session perms screen capture device proof) ou denied (reason).

3. JSON messagesMessages JSON

tdirectionfields
helloC → Sv kind name os device nonce udp (udp: the Android app has its own UDP socket)
challengeS → Chost version nonce salt kdf known
authC → Smethod = code (web) or proof, device, remember
pending / welcome / deniedS → Csession perms screen capture device proof / reason
ping / pong↔ts
welcome.udp / udp_offS → C / C → Sport connection down up (keys of the UDP video) / the viewer could not reach it
welcome.lanes / lanesS → Ctoken max (token of the extra sockets) / n sockets to keep for the video
laneC → S (first message of /lane)session token index
quality / mode / refreshC → Squality scale fps / view or control
term_open / term_resize / term_close / term_exit↔id cols rows code
perms / screen / info / bye / clipS → C (clip ↔)perms, w h, text, reason, clipboard text
focus_requestC → Scontrol paused by the host panel: given back after 1 min unless refused
inputS → Cstate (loading, ready, paused, none), error, wait, asked
tsenschamps
helloC → Sv kind name os device nonce udp (udp : l'appli Android a sa propre socket UDP)
challengeS → Chost version nonce salt kdf known
authC → Smethod = code (web) ou proof, device, remember
pending / welcome / deniedS → Csession perms screen capture device proof / reason
ping / pong↔ts
welcome.udp / udp_offS → C / C → Sport connection down up (clés de la vidéo UDP) / le viewer n'a pas pu l'atteindre
welcome.lanes / lanesS → Ctoken max (jeton des sockets supplémentaires) / n sockets à garder pour la vidéo
laneC → S (premier message de /lane)session token index
quality / mode / refreshC → Squality scale fps / view ou control
term_open / term_resize / term_close / term_exit↔id cols rows code
perms / screen / info / bye / clipS → C (clip ↔)perms, w h, text, reason, texte du presse-papiers
focus_requestC → Scontrôle mis en pause par le panneau de l'hôte : rendu après 1 min sauf refus
inputS → Cstate (loading, ready, paused, none), error, wait, asked

4. Binary messagesMessages binaires

Frame 0x10
fieldtypesizedescription
typeu810x10
idu324frame id
widthu162screen width
heightu162screen height
countu162number of tiles
tilestilevarcount tiles, see below

Sent when the window of the session is open; acked by a FrameAck on arrival. The first frame holds every tile, the next ones only the changed tiles.

FrameAck 0x11
fieldtypesizedescription
typeu810x11
idu324frame id

The acks size the frames in flight and measure the ping and the bandwidth.

Cursor 0x12
fieldtypesizedescription
typeu810x12
xi162
yi162
visibleu810 / 1

The remote cursor, drawn by the viewer.

Video 0x13
fieldtypesizedescription
typeu810x13
idu324frame id
widthu162rounded up to even
heightu162rounded up to even
flagsu811 = key frame
datah264varannex B access unit of the whole frame

Only to the clients listing h264 in enc, while their frames keep their order; acked like a frame.

MouseMove 0x20
fieldtypesizedescription
typeu810x20
xu162absolute
yu162absolute

Pixels of the host screen; dropped without the control right.

MouseButton 0x21
fieldtypesizedescription
typeu810x21
buttonu81see the codes
downu811 pressed, 0 released
MouseWheel 0x22
fieldtypesizedescription
typeu810x22
dxi1621/120 of a notch
dyi1621/120 of a notch
Key 0x23
fieldtypesizedescription
typeu810x23
downu811 pressed, 0 released
lengthu81length of code
codeasciivarKeyboardEvent.code: KeyA, ShiftLeft...

Physical key codes: the layout of the host applies.

Text 0x24
fieldtypesizedescription
typeu810x24
textutf8varthe rest of the message

A soft keyboard sends only what changed in its input (Backspace keys + the new letters).

TermData 0x31
fieldtypesizedescription
typeu810x31
idu81terminal id
databytesvarraw bytes

C → S: the input of terminal id; S → C: its output.

Frame 0x10
champtypetailledescription
typeu810x10
idu324id de l'image
widthu162largeur de l'écran
heightu162hauteur de l'écran
countu162nombre de tuiles
tilestilevarcount tuiles, voir plus bas

Envoyée quand la fenêtre de la session est ouverte ; acquittée par un FrameAck à l'arrivée. La première image contient toutes les tuiles, les suivantes seulement les tuiles changées.

FrameAck 0x11
champtypetailledescription
typeu810x11
idu324id de l'image

Les acquittements dimensionnent les images en vol et mesurent le ping et le débit.

Cursor 0x12
champtypetailledescription
typeu810x12
xi162
yi162
visibleu810 / 1

Le curseur distant, dessiné par le viewer.

Video 0x13
champtypetailledescription
typeu810x13
idu324id de l'image
widthu162arrondie au pair supérieur
heightu162arrondie au pair supérieur
flagsu811 = image clé
datah264varaccess unit annex B de toute l'image

Seulement aux clients annonçant h264 dans enc, tant que leurs images gardent leur ordre ; acquittée comme une image.

MouseMove 0x20
champtypetailledescription
typeu810x20
xu162absolue
yu162absolue

Pixels de l'écran de l'hôte ; ignoré sans le droit de contrôle.

MouseButton 0x21
champtypetailledescription
typeu810x21
buttonu81voir les codes
downu811 appuyé, 0 relâché
MouseWheel 0x22
champtypetailledescription
typeu810x22
dxi1621/120 de cran
dyi1621/120 de cran
Key 0x23
champtypetailledescription
typeu810x23
downu811 appuyé, 0 relâché
lengthu81longueur de code
codeasciivarKeyboardEvent.code : KeyA, ShiftLeft...

Codes physiques de touches : la disposition de l'hôte s'applique.

Text 0x24
champtypetailledescription
typeu810x24
textutf8varle reste du message

Un clavier virtuel n'envoie que ce qui a changé dans son champ (touches Backspace + les nouvelles lettres).

TermData 0x31
champtypetailledescription
typeu810x31
idu81id du terminal
databytesvaroctets bruts

C → S : l'entrée du terminal id ; S → C : sa sortie.

5. Tiles of a FrameTuiles d'une Frame

Each tile of a Frame starts with u16 x, u16 y, u16 w, u16 h, u8 enc, then:

encnamepayload
1Jpegu32 length, JPEG data
2Solidu8 r, u8 g, u8 b: the whole tile of one color
3Paletteu8 n (1-64), n × (u8 r, g, b), u32 length, zlib stream of w × h u8 indices (lossless; clients listing palette)
4Copyu16 sx, u16 sy: the w × h rectangle at (sx, sy) of the frame as it was before this message (scroll; clients listing copy)

Chaque tuile d'une Frame commence par u16 x, u16 y, u16 w, u16 h, u8 enc, puis :

encnompayload
1Jpegu32 longueur, données JPEG
2Solidu8 r, u8 g, u8 b : toute la tuile d'une seule couleur
3Paletteu8 n (1-64), n × (u8 r, g, b), u32 longueur, flux zlib de w × h index u8 (sans perte ; clients annonçant palette)
4Copyu16 sx, u16 sy : le rectangle w × h en (sx, sy) de l'image telle qu'elle était avant ce message (défilement ; clients annonçant copy)

6. Encrypted UDP videoVidéo UDP chiffrée

Native viewers and the Android app, on the port of the server. A datagram is a 13-byte header in clear but authenticated, the AES-256-GCM payload and its 16-byte tag. Two random 256-bit keys per session (one per direction) come in the welcome.udp inside TLS; nonce = direction + sequence (never reused); a window of 2048 sequences drops replays; the host only answers an address that sent an authentic datagram.

fieldtypesizedescription
typeu811 Hello ... 7 Pong
connectionu324connection id of the session
sequenceu648per direction, authenticated
payloadAES-256-GCMvarthe fields below
tagbytes16GCM tag
typenamedirectionpayload
1HelloV → Hempty: the viewer proves the keys from its address
2HelloAckH → Vempty
3DataH → Vu32 frame, u16 index (data pieces first, then one parity per group of 8), u16 data count, u32 frame size, bytes (1150 per piece)
4AckV → Hu32 frame (complete)
5NackV → Hu32 frame, u16 n, n × u16 missing indexes
6PingV → Hu64 ms (keeps the NAT open)
7PongH → Vu64 ms (the same)

Back to the websocket when UDP is blocked (2.5 s of unanswered hellos) or silent (4 s); a frame given up after 3 s asks a complete one.

Viewers natifs et appli Android, sur le port du serveur. Un datagramme est un en-tête de 13 octets en clair mais authentifié, le payload AES-256-GCM et son tag de 16 octets. Deux clés aléatoires de 256 bits par session (une par sens) arrivent dans le welcome.udp à l'intérieur de TLS ; nonce = sens + séquence (jamais réutilisé) ; une fenêtre de 2048 séquences écarte les rejeux ; l'hôte ne répond qu'à une adresse qui a envoyé un datagramme authentique.

champtypetailledescription
typeu811 Hello ... 7 Pong
connectionu324id de connexion de la session
sequenceu648par sens, authentifiée
payloadAES-256-GCMvarles champs ci-dessous
tagoctets16tag GCM
typenomsenspayload
1HelloV → Hvide : le viewer prouve les clés depuis son adresse
2HelloAckH → Vvide
3DataH → Vu32 image, u16 index (morceaux de données d'abord, puis une parité par groupe de 8), u16 nombre de données, u32 taille de l'image, octets (1150 par morceau)
4AckV → Hu32 image (complète)
5NackV → Hu32 image, u16 n, n × u16 index manquants
6PingV → Hu64 ms (garde le NAT ouvert)
7PongH → Vu64 ms (le même)

Retour sur la websocket quand l'UDP est bloqué (2,5 s de hellos sans réponse) ou muet (4 s) ; une image abandonnée après 3 s demande une image complète.

7. CodesCodes

Mouse buttons: 0 left, 1 middle, 2 right, 3 back, 4 forward. Client kinds: 0 gui, 1 tty, 2 web, 3 apk (an unknown kind is treated as web, the most restricted).

Boutons de souris : 0 gauche, 1 milieu, 2 droit, 3 précédent, 4 suivant. Types de client : 0 gui, 1 tty, 2 web, 3 apk (un type inconnu est traité comme web, le plus restreint).