Skip to content

bugfix(network): Increase message buffer and max packet sizes to reduce connection issues#2277

Open
Mauller wants to merge 1 commit intoTheSuperHackers:mainfrom
Mauller:Mauller/tweak-network-packet-handling
Open

bugfix(network): Increase message buffer and max packet sizes to reduce connection issues#2277
Mauller wants to merge 1 commit intoTheSuperHackers:mainfrom
Mauller:Mauller/tweak-network-packet-handling

Conversation

@Mauller
Copy link

@Mauller Mauller commented Feb 8, 2026

Closes: #203

This PR increases the send and receive buffer sizes, this can help to alleviate network pressure that can lead to the DC menu appearing when the game is waiting for more network data or has to wait for a resend.

The PR also implements a non retail change to increase the amount of data stored per UDP packet.

The retail game was designed with Dialup limitations in mind, which tended to limit the MTU side to 576 bytes.
Internally they chose 512 bytes as their packet size limit and then incorrectly calculated a lower max UDP payload than necessary on top of this.

The fix allows the game to use 1100 Bytes as the UDP payload for the greatest compatibility between different types of network connections. This should take into account overhead of PPPOE, VPN's and IPV6 on supporting networks without causing fragmentation.

As 6 bytes is required for the current network packet header, game data packets can only be up to 1094 bytes in size.

At 1094 bytes per game packet we are now handling ~2.3x the amount of data per packet compared to retail, this should allow a reduction of network traffic by up to 2/3's depending on how game commands are being generated.

When testing this on GO with a full 8 player Mayhem game, we did not see a single DC screen popup.
All players were creating large armies and using QQA repeatedly to move them.

@Mauller Mauller self-assigned this Feb 8, 2026
@Mauller Mauller added Bug Something is not working right, typically is user facing Major Severity: Minor < Major < Critical < Blocker Network Anything related to network, servers Gen Relates to Generals ZH Relates to Zero Hour labels Feb 8, 2026
@greptile-apps
Copy link

greptile-apps bot commented Feb 8, 2026

Greptile Overview

Greptile Summary

This PR improves network stability by doubling the message buffer size from 128 to 256 messages and introducing larger UDP packet payloads (1100 bytes) for non-retail builds. The changes maintain backward compatibility through the RETAIL_COMPATIBLE_NETWORKING flag while allowing modernized network configurations to handle ~2.3x more data per packet.

Key changes:

  • Doubled MAX_MESSAGES from 128 to 256 to reduce buffer pressure during high-traffic scenarios
  • Increased non-retail MAX_PACKET_SIZE from 476 to 1094 bytes (1100 byte UDP payload - 6 byte header)
  • Introduced MAX_UDP_PAYLOAD_SIZE constant (1100 bytes) optimized for modern networks with PPPoE/VPN/IPv6 overhead
  • Refactored packet size constants with clearer naming (RETAIL_GAME_PACKET_SIZE, MAX_LANAPI_PACKET_SIZE)
  • Updated all references from deprecated MAX_MESSAGE_LEN macro to MAX_NETWORK_MESSAGE_LEN constant
  • Added extensive comments explaining the confusing payload/header sizing logic

The implementation correctly accounts for the 6-byte TransportMessageHeader (CRC + magic number) when calculating payload sizes, and testing showed elimination of disconnection screens in 8-player games with large armies.

Confidence Score: 4/5

  • This PR is safe to merge with minor concerns about memory footprint and comment clarity
  • The implementation is sound and well-tested, with proper backward compatibility through feature flags. The score is 4 rather than 5 due to: (1) the MAX_MESSAGES increase doubles buffer memory usage for all builds including retail-compatible ones, which wasn't mentioned in previous thread discussions, and (2) some comments contain author tags in prologues that were flagged in previous reviews. The core networking logic is correct and the 6-byte header calculation matches the struct definition.
  • Pay attention to NetworkDefs.h for the prologue author tag issue flagged in previous reviews

Important Files Changed

Filename Overview
Core/GameEngine/Include/Common/GameDefines.h Added RETAIL_COMPATIBLE_NETWORKING flag to control non-retail networking improvements
Core/GameEngine/Include/GameNetwork/NetworkDefs.h Increased MAX_MESSAGES from 128 to 256, introduced larger UDP payload sizes (1100 bytes) conditionally, and refactored constants with better naming
Core/GameEngine/Source/GameNetwork/Transport.cpp Updated send/receive operations to use MAX_NETWORK_MESSAGE_LEN and added clarifying comments about payload sizing logic

Flowchart

flowchart TD
    A[UDP Payload Size] -->|Retail| B[512 bytes total MTU]
    A -->|Non-Retail| C[1100 bytes UDP payload]
    
    B --> D[512 - 36 IP/UDP headers = 476 bytes]
    C --> E[1100 bytes max UDP payload]
    
    D --> F[MAX_PACKET_SIZE = 476<br/>RETAIL_GAME_PACKET_SIZE]
    E --> G[MAX_PACKET_SIZE = 1094<br/>1100 - 6 header bytes]
    
    F --> H[TransportMessageHeader: 6 bytes<br/>CRC + Magic]
    G --> H
    
    H --> I[Game Data Payload]
    
    I --> J[MAX_MESSAGES buffer<br/>128 → 256 doubled]
    
    J --> K{RETAIL_COMPATIBLE_NETWORKING?}
    K -->|Yes| L[Use 476 byte packets<br/>256 message buffers]
    K -->|No| M[Use 1094 byte packets<br/>256 message buffers<br/>~2.3x more data per packet]
Loading

Last reviewed commit: 671170a

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@Mauller Mauller force-pushed the Mauller/tweak-network-packet-handling branch from 188298b to 535b4db Compare February 8, 2026 17:10
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

static const Int MAX_MESSAGE_LEN = MAX_UDP_PAYLOAD;
#endif

static const Int MAX_MESSAGES = 256;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increases buffer footprint

Bumping MAX_MESSAGES from 128 to 256 doubles the size of Transport::m_inBuffer/m_outBuffer (and m_delayedInBuffer in debug) because these arrays are sized by MAX_MESSAGES (see Core/GameEngine/Include/GameNetwork/Transport.h:73-78). This is a behavioral change that can increase memory pressure (and potentially stack/heap usage depending on how Transport is instantiated) even when RETAIL_COMPATIBLE_NETWORKING is kept enabled; please confirm this is intended and safe for all builds, or gate it behind the same retail-compat switch.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Include/GameNetwork/NetworkDefs.h
Line: 71:71

Comment:
**Increases buffer footprint**

Bumping `MAX_MESSAGES` from 128 to 256 doubles the size of `Transport::m_inBuffer`/`m_outBuffer` (and `m_delayedInBuffer` in debug) because these arrays are sized by `MAX_MESSAGES` (see `Core/GameEngine/Include/GameNetwork/Transport.h:73-78`). This is a behavioral change that can increase memory pressure (and potentially stack/heap usage depending on how `Transport` is instantiated) even when `RETAIL_COMPATIBLE_NETWORKING` is kept enabled; please confirm this is intended and safe for all builds, or gate it behind the same retail-compat switch.


How can I resolve this? If you propose a fix, please make it concise.

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presentation can be polished more.

@Mauller Mauller force-pushed the Mauller/tweak-network-packet-handling branch from 535b4db to 66fef26 Compare February 10, 2026 06:57
@Mauller
Copy link
Author

Mauller commented Feb 10, 2026

Tweaked and addressed comments

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 10, 2026

Additional Comments (1)

Core/GameEngine/Source/GameNetwork/NetPacket.cpp
Incorrect memcpy length

NetPacket::NetPacket(TransportMessage *msg) copies MAX_PACKET_SIZE bytes (memcpy(m_packet, msg->data, MAX_PACKET_SIZE)) even though msg->length may be smaller. With this PR increasing MAX_PACKET_SIZE to 1200 in non-retail builds, this will read past the end of the received UDP payload for most packets and can cause out-of-bounds reads / crashes. This should copy msg->length (or m_packetLen) bytes instead of MAX_PACKET_SIZE.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/GameNetwork/NetPacket.cpp
Line: 960:964

Comment:
**Incorrect memcpy length**

`NetPacket::NetPacket(TransportMessage *msg)` copies `MAX_PACKET_SIZE` bytes (`memcpy(m_packet, msg->data, MAX_PACKET_SIZE)`) even though `msg->length` may be smaller. With this PR increasing `MAX_PACKET_SIZE` to 1200 in non-retail builds, this will read past the end of the received UDP payload for most packets and can cause out-of-bounds reads / crashes. This should copy `msg->length` (or `m_packetLen`) bytes instead of `MAX_PACKET_SIZE`.

How can I resolve this? If you propose a fix, please make it concise.

@Mauller Mauller force-pushed the Mauller/tweak-network-packet-handling branch from 66fef26 to 022692a Compare February 10, 2026 07:01
xezon
xezon previously approved these changes Feb 10, 2026
// TheSuperHackers @info As we are not detecting for network fragmentation and adjusting max payload, we set 1200 bytes UDP payload as a safe upper limit for various networks
// We chose 1200 bytes as when taking mobile networks into account, maximum transmission unit sizes can vary from 1340 - 1500 bytes
// and when the packet headers for PPPOE, IPV6 and virtual network encapsulation are considered, we need a lower safe UDP payload to prevent fragmentation.
static constexpr const Int MAX_UDP_PAYLOAD = 1200;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps add a SIZE into the name

static constexpr const Int MAX_UDP_PAYLOAD = 1200;
// UDP (8 bytes) + IP header (28 bytes) = 36 bytes total. We want a total packet size of 512, so 512 - 36 = 476
static const Int MAX_PACKET_SIZE = 476;
static constexpr const Int RESTRICTED_UDP_PAYLOAD = 476;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps use RETAIL instead of RESTRICTED

@xezon xezon added this to the Major bug fixes milestone Feb 10, 2026
static constexpr const Int MAX_PACKET_SIZE = RESTRICTED_UDP_PAYLOAD;
static constexpr const Int MAX_MESSAGE_LEN = 1024;
#else
static constexpr const Int MAX_PACKET_SIZE = MAX_UDP_PAYLOAD;
Copy link
Author

@Mauller Mauller Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After having another quick look, i actually need to tweak this.

MAX_MESSAGE_LEN is the maximum data that goes out on the wire in the end, MAX_PACKET_SIZE is the max size a game message packet can be, but it gets encapsulated into a NetworkMessage struct with a NetworkMessageHeader prepended to the data, which adds 6 bytes to the start of the data.

So the MAX_PACKET_SIZE actually needs to be MAX_MESSAGE_LEN - Sizeof(NetworkMessageHeader) to not cause bytes to be missed at the end of the data.

The networking code is a mess...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To save the confusion again i am going to look at renaming these to better suit their purpose.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tweaked the naming and added some extra comments to affected places, the issue here is the entire handling of network data. It really needs refactoring but theres no clean way to do that while properly maintaining the retail mishandling for now.

It's something i can come back to in the future with more network api tweaking.

@xezon xezon dismissed their stale review February 10, 2026 17:54

Dismissed because the Mauller wants to do another pass

@Mauller
Copy link
Author

Mauller commented Feb 13, 2026

After some talking with X64 i will need to adjust the packet size (data that goes onto the wire) down to 1100, the extra 100 bytes is to help with TURN relay headers and extra reliability layers That GO uses. this still gives 2.2-2.3x the packet size of retail.

This means that data on the wire, UDP payload, needs to be a max of 1100, but game messages can only be a max of 1094 due to the 6 bytes of game packet header that i overlooked originally.

We can always adjust these values in future when refactoring more of the networking.

@Mauller Mauller force-pushed the Mauller/tweak-network-packet-handling branch from 022692a to 265fab3 Compare February 13, 2026 14:32
@Mauller
Copy link
Author

Mauller commented Feb 13, 2026

Updated now with the tweaks

@xezon
Copy link

xezon commented Feb 13, 2026

In future, we can also introduce packet data compression to help reduce the traffic pressure.

@Mauller
Copy link
Author

Mauller commented Feb 13, 2026

In future, we can also introduce packet data compression to help reduce the traffic pressure.

Yes it would be worth investigating.

I want to overhaul the entire packet structure to get something more standardised between message types with a common header containing an enumeration for message type, then relevant payload data etc.

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Pull title says tweak but the comments have 2 bugfix. Should be bugfix in title?

if (m_outBuffer[i].length != 0)
{
int bytesSent = 0;
// TheSuperHackers @info The handling of data sizing of the payload within a UDP packet is confusing due to poor implementation
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe reword this without "poor implementation"

Twice

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tweaked the wording.

// TheSuperHackers @info This value is not the correct one that should be used here, it should have been max packet size
// The non retail max network message len takes the extra bytes of the network message header into account when handling UDP payload data
// In retail this only works since no data larger than the retail game packet size is put into a network message
UnsignedByte data[MAX_NETWORK_MESSAGE_LEN];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If MAX_PACKET_SIZE was never exceeded in practice, then why would it not be allowed to change this now?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just wanting to minimise changes that could cause issues, in theory it shouldn't be a problem to set it to max packet size of 476, but with how bad the rest of the netcode is i didn't want to accidentally overlook something.

@xezon xezon added Critical Severity: Minor < Major < Critical < Blocker and removed Major Severity: Minor < Major < Critical < Blocker labels Feb 13, 2026
@Mauller Mauller changed the title tweak(network): Increase message buffer and max packet sizes to reduce connection issues bugfix(network): Increase message buffer and max packet sizes to reduce connection issues Feb 14, 2026
@Mauller Mauller force-pushed the Mauller/tweak-network-packet-handling branch from 265fab3 to 671170a Compare February 14, 2026 15:50
@Mauller
Copy link
Author

Mauller commented Feb 14, 2026

The Pull title says tweak but the comments have 2 bugfix. Should be bugfix in title?

I changed it to say bugfix now, initially i was considering this a tweak but after more testing it does appear to be a considerable bugfix towards connection issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something is not working right, typically is user facing Critical Severity: Minor < Major < Critical < Blocker Gen Relates to Generals Network Anything related to network, servers ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Game can get stuck in Disconnect screen

2 participants