Skip to content

Commit

Permalink
netplay: Enable TCP_NODELAY for game sockets
Browse files Browse the repository at this point in the history
Among other reasons, we already use an internal buffer
  • Loading branch information
past-due committed May 10, 2024
1 parent 717e5bd commit 2451786
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 0 deletions.
23 changes: 23 additions & 0 deletions lib/netplay/netplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ char masterserver_name[255] = {'\0'};
static unsigned int masterserver_port = 0, gameserver_port = 0;
static bool bJoinPrefTryIPv6First = true;
static bool bDefaultHostFreeChatEnabled = true;
static bool bEnableTCPNoDelay = true;

// This is for command line argument override
// Disables port saving and reading from/to config
Expand Down Expand Up @@ -3993,6 +3994,12 @@ static void NETallowJoining()
tmp_connectState[i].ip = rIP;
tmp_connectState[i].connectTime = std::chrono::steady_clock::now();
tmp_connectState[i].connectState = TmpSocketInfo::TmpConnectState::PendingInitialConnect;

if (bEnableTCPNoDelay)
{
// Enable TCP_NODELAY
socketSetTCPNoDelay(*tmp_socket[i], true);
}
}

if (checkSockets(*tmp_socket_set, NET_READ_TIMEOUT) > 0)
Expand Down Expand Up @@ -4921,6 +4928,12 @@ bool NETjoinGame(const char *host, uint32_t port, const char *playername, const
// `client_transient_socket` is used to talk to host machine
SocketSet_AddSocket(*client_socket_set, client_transient_socket);

if (bEnableTCPNoDelay)
{
// Enable TCP_NODELAY
socketSetTCPNoDelay(*client_transient_socket, true);
}

// Send NETCODE_VERSION_MAJOR and NETCODE_VERSION_MINOR
p_buffer = buffer;
auto pushu32 = [&](uint32_t value) {
Expand Down Expand Up @@ -5170,6 +5183,16 @@ bool NETgetDefaultMPHostFreeChatPreference()
return bDefaultHostFreeChatEnabled;
}

void NETsetEnableTCPNoDelay(bool enabled)
{
bEnableTCPNoDelay = enabled;
}

bool NETgetEnableTCPNoDelay()
{
return bEnableTCPNoDelay;
}

void NETsetPlayerConnectionStatus(CONNECTION_STATUS status, unsigned player)
{
unsigned n;
Expand Down
2 changes: 2 additions & 0 deletions lib/netplay/netplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ void NETsetJoinPreferenceIPv6(bool bTryIPv6First);
bool NETgetJoinPreferenceIPv6();
void NETsetDefaultMPHostFreeChatPreference(bool enabled);
bool NETgetDefaultMPHostFreeChatPreference();
void NETsetEnableTCPNoDelay(bool enabled);
bool NETgetEnableTCPNoDelay();

void NETsetGamePassword(const char *password);
void NETBroadcastPlayerInfo(uint32_t index);
Expand Down
19 changes: 19 additions & 0 deletions lib/netplay/netsocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@
#pragma clang diagnostic ignored "-Wshorten-64-to-32" // FIXME!!
#endif

#if defined(WZ_OS_UNIX)
# include <netinet/tcp.h> // For TCP_NODELAY
#elif defined(WZ_OS_WIN)
// Already included Winsock2.h which defines TCP_NODELAY
#endif

enum
{
SOCK_CONNECTION,
Expand Down Expand Up @@ -795,6 +801,19 @@ void socketBeginCompression(Socket& sock)
wzMutexUnlock(socketThreadMutex);
}

bool socketSetTCPNoDelay(Socket& sock, bool nodelay)
{
#if defined(TCP_NODELAY)
int value = (nodelay) ? 1 : 0;
int result = setsockopt(sock.fd[SOCK_CONNECTION], IPPROTO_TCP, TCP_NODELAY, (char *) &value, sizeof(int));
debug(LOG_INFO, "Setting TCP_NODELAY on socket: %s", (result != SOCKET_ERROR) ? "success" : "failure");
return result != SOCKET_ERROR;
#else
debug(LOG_INFO, "Unable to set TCP_NODELAY on socket - unsupported");
return false;
#endif
}

Socket::~Socket()
{
if (isCompressed)
Expand Down
2 changes: 2 additions & 0 deletions lib/netplay/netsocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ ssize_t readAll(Socket& sock, void *buf, size_t size, unsigned timeout);///< Rea
WZ_DECL_NONNULL(2)
ssize_t writeAll(Socket& sock, const void *buf, size_t size, size_t *rawByteCount = nullptr); ///< Nonblocking write of size bytes to the Socket. All bytes will be written asynchronously, by a separate thread. Raw count of bytes (after compression) returned in rawByteCount, which will often be 0 until the socket is flushed.

bool socketSetTCPNoDelay(Socket& sock, bool nodelay); ///< nodelay = true disables the Nagle algorithm for TCP socket

// Sockets, compressed.
void socketBeginCompression(Socket& sock); ///< Makes future data sent compressed, and future data received expected to be compressed.
bool socketReadDisconnected(const Socket& sock); ///< If readNoInt returned 0, returns true if this is the result of a disconnect, or false if the input compressed data just hasn't produced any output bytes.
Expand Down
3 changes: 3 additions & 0 deletions src/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ bool loadConfig()
}
NETsetJoinPreferenceIPv6(iniGetBool("prefer_ipv6", true).value());
NETsetDefaultMPHostFreeChatPreference(iniGetBool("hostingChatDefault", NETgetDefaultMPHostFreeChatPreference()).value());
NETsetEnableTCPNoDelay(iniGetBool("tcp_nodelay", NETgetEnableTCPNoDelay()).value());
setPublicIPv4LookupService(iniGetString("publicIPv4LookupService_Url", WZ_DEFAULT_PUBLIC_IPv4_LOOKUP_SERVICE_URL).value(), iniGetString("publicIPv4LookupService_JSONKey", WZ_DEFAULT_PUBLIC_IPv4_LOOKUP_SERVICE_JSONKEY).value());
setPublicIPv6LookupService(iniGetString("publicIPv6LookupService_Url", WZ_DEFAULT_PUBLIC_IPv6_LOOKUP_SERVICE_URL).value(), iniGetString("publicIPv6LookupService_JSONKey", WZ_DEFAULT_PUBLIC_IPv6_LOOKUP_SERVICE_JSONKEY).value());
war_SetFMVmode((FMV_MODE)iniGetInteger("FMVmode", war_GetFMVmode()).value());
Expand Down Expand Up @@ -722,6 +723,8 @@ bool saveConfig()
}
iniSetBool("prefer_ipv6", NETgetJoinPreferenceIPv6());
iniSetInteger("hostingChatDefault", (NETgetDefaultMPHostFreeChatPreference()) ? 1 : 0);
iniSetInteger("tcp_nodelay", (NETgetEnableTCPNoDelay()) ? 1 : 0);

iniSetString("publicIPv4LookupService_Url", getPublicIPv4LookupServiceUrl());
iniSetString("publicIPv4LookupService_JSONKey", getPublicIPv4LookupServiceJSONKey());
iniSetString("publicIPv6LookupService_Url", getPublicIPv6LookupServiceUrl());
Expand Down

0 comments on commit 2451786

Please sign in to comment.