I'm looking to understand how file transfers working in VNC/TightVNC/RFB.
In https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#serverinit I see there is mention of certain client messages that look relevant if using the Tight Security Type, e.g.
132 "TGHT" "FTC_UPRQ" File Upload Request
133 "TGHT" "FTC_UPDT" File Upload Data
But I don't see detail on how these messages are used in the protocol
At https://www.tightvnc.com/ there is lots of information on usage, but so far not found anything about the protocol itself.
How do the file transfers work? As in, what are the low-level details of the messages sent in both directions to initiate and complete an upload from the client to the server?
(Ultimately I am looking to implement this, say in NoVNC, but I'm quite a few steps away from any coding at this point)
This a very partial answer from looking at the code of
I think that an upload from the client is initiated by the client:
client -> server, 1 byte = 132: messages type of a file upload request
client -> server, 1 byte: compression level, where 0 is not compressed, and I don't think libvnc supports anything other than 0(?)
client -> server, 2 bytes big endian integer: the length of the file name
client -> server, 4 bytes big endian: the "position" - not sure what this is, but I suspect libvnc either ignores it, or there is a bug in libvnc where on little endian systems (e.g. intel) this might break in some situations if this isn't zero since there seems to be some code that assumes it's 2 bytes https://github.com/LibVNC/libvncserver/blob/5deb43e2837e05e5e24bd2bfb458ae6ba930bdaa/libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c#L401.
When uploading, TightVNC's "legacy" code also seems to set this as zero https://github.com/TurboVNC/tightvnc/blob/a235bae328c12fd1c3aed6f3f034a37a6ffbbd22/vnc_winsrc/vncviewer/FileTransfer.cpp#L552
client -> server, "length of the file name" bytes: the file name itself
I'm not sure how the server responds to say "yes, that's fine". See below for how the server can say "that's not fine" and abort
And then I think that uploads are done in max 64k chunks (num of bytes are limited to 16 bits). So each chunk is:
client -> server, 1 byte = 133: message type of file upload data request
client -> server, 1 byte: compression level, where 0 is not compressed, and I don't think libvnc supports anything other than 0(?)
client -> server, 2 bytes big endian: the uncompressed(?) size of the upload data
client -> server, 2 bytes big endian: the compressed size of the upload data. I think for libvnc since compression isn't supported, this has to equal the uncompressed size
client -> server, "compressed size" bytes: the data of the current chunk the file itself
not sure how the server acknowledges that this is all fine
Then once all the data has been uploaded, there is a final empty chunk followed by the modification/access time of the file:
client -> server, 1 byte = 133: message type of file upload data request
client -> server, 1 byte: compression level, where 0 is not compressed, and I don't think libvnc supports anything other than 0(?)
client -> server, 2 bytes = 0: the uncompressed(?) size of the upload data
client -> server, 2 bytes = 0: the compressed size of the upload data
client -> server, 4 bytes: the modification and access time of the file. libvnc sets both to be the same, and interestingly there doesn't seem to be a conversion from the endianness of the messages to the endianness of the system.
and as per the other parts of upload, not sure how the server acknowledges that this has been successful
If the client wants to cancel the upload:
client -> server, 1 byte = 135: message type of file upload failed
client -> server, 1 byte: unused(?)
client -> server, 1 byte: length of reason
client -> server, "length of reason" bytes: human readable reason of why the upload was cancelled
If the server wants to fail the upload:
server -> client, 1 byte = 132: message type of file upload cancel
server -> client, 1 byte: unused(?)
server -> client, 1 byte: length of reason
server -> client, "length of reason" bytes: human readable reason of why the upload failed
It does seem odd that there doesn't seem a way for the server to acknowledge any sort of success, so the client can't really give the user a "yes, it's worked!" sign. At least, not one with high confidence that everything has indeed worked.
It also does look like at most 1 upload at a time is possible: there is no ID or anything like that to distinguish multiple files being uploaded at the same time. Although given this would all be over the same TCP connection (typically) there would probably not be any speed benefit of this.