Segmented launcher protocol rework
The existing implementation of segmented protocol has some issues (see #4178) and was a little awkward for launchers to implement, so I thought it best to re-work it. This implementation is a lot simpler and less clever than the old one, but should probably work better in reality. It merely just generates a regular response like normal, and splits it up into multiple packets. As a result, the packets are not standalone: all the data must arrive to be useful. This wasn't supposed to be a problem in the design of the old one but it was in practice: it was still possible for a packet to exceed MTU (there was no way of handling if a packet was longer than sv_maxpacketsize
, so it still resulted in a massive packet), and some fields were dependant on prior fields, which made them unreadable if packets were missing or out of order.
This is also limited to the size of g_MasterServerBuffer
, but no server with massive launcher responses has yet to reach MAX_UDP_PACKET
, and if that becomes an issue then that buffer just can have its size increased or NETBUFFER_s
could gain automatic resizing somehow.
This is backwards-compatible with the old protocols. I sort of now question the usefulness of a separate LAUNCHER_SERVER_SEGMENTED_CHALLENGE
challenge, as the old LAUNCHER_SERVER_CHALLENGE
also allows specifying whether to get a segmented response and is backwards compatible while LAUNCHER_SERVER_SEGMENTED_CHALLENGE
is not.
Pseudo-code for handling this could be:
segmented_data = null
segs_read = 0
response = readLong()
if (response == SERVER_LAUNCHER_SEGMENTED_CHALLENGE) {
seg_num = readByte()
seg_count = readByte()
seg_offset = readShort()
seg_size = readShort()
data_size = readShort()
if (segmented_data == null)
segmented_data = malloc(data_size)
// 12 is the size of the header above, including challenge
memcpy(segmented_data + seg_offset, this_packet + 12, seg_size)
segs_read += 1
if (segs_read == seg_count) {
// read the accumulated data from segmented_data like a normal
// LAUNCHER_SERVER_CHALLENGE packet, just without the challenge
time = readLong()
version = readString()
flags = readLong()
}
}