Many small adjustments to networking code

In an attempt to track down an issue that causes packet flooding and
hanging, I've looked at every step of the networking process and tried
to clean up anything strange I saw.
This commit is contained in:
MysterD 2021-06-20 04:36:33 -07:00
parent ac85a7e4a7
commit 99308a3145
15 changed files with 71 additions and 40 deletions

View file

@ -16,11 +16,9 @@ Global
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x64.ActiveCfg = Debug|x64 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x64.ActiveCfg = Debug|x64
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x64.Build.0 = Debug|x64 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x64.Build.0 = Debug|x64
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x86.ActiveCfg = Debug|Win32 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x86.ActiveCfg = Debug|Win32
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Debug|x86.Build.0 = Debug|Win32
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x64.ActiveCfg = Release|x64 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x64.ActiveCfg = Release|x64
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x64.Build.0 = Release|x64 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x64.Build.0 = Release|x64
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x86.ActiveCfg = Release|Win32 {8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x86.ActiveCfg = Release|Win32
{8ADFCAB9-E7D6-4588-86B5-A128DA4F811D}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -72,6 +72,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<IncludePath>../;../include/;../src/;$(IncludePath)</IncludePath> <IncludePath>../;../include/;../src/;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)\..\build\us_pc\</OutDir>
<TargetName>sm64.us.f3dex2e</TargetName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>

View file

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerAttach>true</LocalDebuggerAttach>
</PropertyGroup>
</Project> </Project>

View file

@ -29,7 +29,6 @@ bool gNetworkAreaLoaded = false;
bool gNetworkAreaSyncing = true; bool gNetworkAreaSyncing = true;
u32 gNetworkAreaTimer = 0; u32 gNetworkAreaTimer = 0;
clock_t gLastNetworkSend = 0;
struct StringLinkedList gRegisteredMods = { 0 }; struct StringLinkedList gRegisteredMods = { 0 };
struct ServerSettings gServerSettings = { struct ServerSettings gServerSettings = {
@ -114,8 +113,12 @@ void network_send_to(u8 localIndex, struct Packet* p) {
if (gNetworkType == NT_NONE) { LOG_ERROR("network type error none!"); return; } if (gNetworkType == NT_NONE) { LOG_ERROR("network type error none!"); return; }
if (p->error) { LOG_ERROR("packet error!"); return; } if (p->error) { LOG_ERROR("packet error!"); return; }
if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; }
if (p->buffer[0] != PACKET_JOIN_REQUEST && p->buffer[0] != PACKET_KICK && p->buffer[0] != PACKET_ACK && gNetworkPlayerLocal != NULL && gNetworkPlayerServer->localIndex != gNetworkPlayerLocal->localIndex) { if (localIndex == 0) {
assert(localIndex != gNetworkPlayerLocal->localIndex); if (p->buffer[0] != PACKET_JOIN_REQUEST && p->buffer[0] != PACKET_KICK && p->buffer[0] != PACKET_ACK) {
LOG_ERROR("\n####################\nsending to myself, packetType: %d\n####################\n", p->packetType);
assert(false);
return;
}
} }
if (gNetworkType == NT_SERVER) { if (gNetworkType == NT_SERVER) {
@ -143,7 +146,7 @@ void network_send_to(u8 localIndex, struct Packet* p) {
network_remember_reliable(p); network_remember_reliable(p);
// set ordered data (MUST BE IMMEDITAELY BEFORE HASING+SENDING) // set ordered data (MUST BE IMMEDITAELY BEFORE HASING+SENDING)
if (p->orderedGroupId != 0) { if (p->orderedGroupId != 0 && !p->sent) {
packet_set_ordered_data(p); packet_set_ordered_data(p);
} }
@ -156,12 +159,14 @@ void network_send_to(u8 localIndex, struct Packet* p) {
localIndex = gNetworkPlayerServer->localIndex; localIndex = gNetworkPlayerServer->localIndex;
} }
assert(p->dataLength < PACKET_LENGTH);
// send // send
int rc = gNetworkSystem->send(localIndex, p->buffer, p->cursor + sizeof(u32)); int rc = gNetworkSystem->send(localIndex, p->buffer, p->cursor + sizeof(u32));
if (rc == SOCKET_ERROR) { LOG_ERROR("send error %d", rc); return; } if (rc == SOCKET_ERROR) { LOG_ERROR("send error %d", rc); return; }
p->sent = true; p->sent = true;
gLastNetworkSend = clock(); gNetworkPlayers[localIndex].lastSent = clock();
} }
void network_send(struct Packet* p) { void network_send(struct Packet* p) {
@ -174,7 +179,6 @@ void network_send(struct Packet* p) {
int i = gNetworkPlayerServer->localIndex; int i = gNetworkPlayerServer->localIndex;
p->localIndex = i; p->localIndex = i;
network_send_to(i, p); network_send_to(i, p);
gLastNetworkSend = clock();
return; return;
} }
} }
@ -194,7 +198,6 @@ void network_send(struct Packet* p) {
p->localIndex = i; p->localIndex = i;
network_send_to(i, p); network_send_to(i, p);
} }
gLastNetworkSend = clock();
} }
void network_receive(u8 localIndex, u8* data, u16 dataLength) { void network_receive(u8 localIndex, u8* data, u16 dataLength) {

View file

@ -86,7 +86,6 @@ extern bool gNetworkAreaSyncing;
extern u32 gNetworkAreaTimer; extern u32 gNetworkAreaTimer;
extern struct SyncObject gSyncObjects[]; extern struct SyncObject gSyncObjects[];
extern struct ServerSettings gServerSettings; extern struct ServerSettings gServerSettings;
extern clock_t gLastNetworkSend;
extern struct StringLinkedList gRegisteredMods; extern struct StringLinkedList gRegisteredMods;
// network.c // network.c

View file

@ -80,19 +80,21 @@ struct NetworkPlayer* get_network_player_smallest_global(void) {
} }
void network_player_update(void) { void network_player_update(void) {
float elapsed = (clock() - gLastNetworkSend) / (float)CLOCKS_PER_SEC;
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
network_send_keep_alive();
}
#ifndef DEVELOPMENT //#ifndef DEVELOPMENT
if (gNetworkType == NT_SERVER) { if (gNetworkType == NT_SERVER) {
for (int i = 1; i < MAX_PLAYERS; i++) { for (int i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i]; struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; } if (!np->connected) { continue; }
float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC; float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC;
if (elapsed > NETWORK_PLAYER_TIMEOUT) { if (elapsed > NETWORK_PLAYER_TIMEOUT) {
LOG_INFO("dropping player %d", i);
network_player_disconnected(i); network_player_disconnected(i);
continue;
}
elapsed = (clock() - np->lastSent) / (float)CLOCKS_PER_SEC;
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
network_send_keep_alive(np->localIndex);
} }
} }
} else if (gNetworkType == NT_CLIENT) { } else if (gNetworkType == NT_CLIENT) {
@ -100,15 +102,23 @@ void network_player_update(void) {
struct NetworkPlayer* np = gNetworkPlayerServer; struct NetworkPlayer* np = gNetworkPlayerServer;
if (!np->connected) { return; } if (!np->connected) { return; }
float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC; float elapsed = (clock() - np->lastReceived) / (float)CLOCKS_PER_SEC;
if (elapsed <= NETWORK_PLAYER_TIMEOUT * 1.5f) { if (elapsed <= NETWORK_PLAYER_TIMEOUT * 1.5f) {
connectionAlive = true; connectionAlive = true;
return; return;
} }
if (!connectionAlive) { if (!connectionAlive) {
LOG_INFO("dropping due to no server connectivity");
network_shutdown(); network_shutdown();
} }
elapsed = (clock() - np->lastSent) / (float)CLOCKS_PER_SEC;
if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) {
network_send_keep_alive(np->localIndex);
}
} }
#endif //#endif
} }
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) { u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
@ -149,6 +159,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
if (np->globalIndex != globalIndex) { continue; } if (np->globalIndex != globalIndex) { continue; }
np->localIndex = i; np->localIndex = i;
np->lastReceived = clock(); np->lastReceived = clock();
np->lastSent = clock();
if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); } if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); }
LOG_ERROR("player connected, reusing local %d, global %d, duplicate event?", i, globalIndex); LOG_ERROR("player connected, reusing local %d, global %d, duplicate event?", i, globalIndex);
return i; return i;
@ -174,6 +185,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->globalIndex = (gNetworkType == NT_SERVER) ? i : globalIndex; np->globalIndex = (gNetworkType == NT_SERVER) ? i : globalIndex;
np->type = type; np->type = type;
np->lastReceived = clock(); np->lastReceived = clock();
np->lastSent = clock();
if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); } if (gNetworkType == NT_SERVER || type == NPT_SERVER) { gNetworkSystem->save_id(i, 0); }
for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; } for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
if (type == NPT_SERVER) { gNetworkPlayerServer = np; } if (type == NPT_SERVER) { gNetworkPlayerServer = np; }

View file

@ -23,6 +23,7 @@ struct NetworkPlayer {
u8 localIndex; u8 localIndex;
u8 globalIndex; u8 globalIndex;
clock_t lastReceived; clock_t lastReceived;
clock_t lastSent;
u16 currLevelAreaSeqId; u16 currLevelAreaSeqId;
s16 currCourseNum; s16 currCourseNum;
s16 currActNum; s16 currActNum;

View file

@ -177,7 +177,7 @@ void network_send_kick(enum KickReasonType kickReason);
void network_receive_kick(struct Packet* p); void network_receive_kick(struct Packet* p);
// packet_keep_alive.c // packet_keep_alive.c
void network_send_keep_alive(void); void network_send_keep_alive(u8 localIndex);
void network_receive_keep_alive(struct Packet* p); void network_receive_keep_alive(struct Packet* p);
// packet_leaving.c // packet_leaving.c

View file

@ -38,12 +38,6 @@ void network_receive_join_request(struct Packet* p) {
void network_send_join(struct Packet* joinRequestPacket) { void network_send_join(struct Packet* joinRequestPacket) {
assert(gNetworkType == NT_SERVER); assert(gNetworkType == NT_SERVER);
fs_file_t* fp = fs_open(SAVE_FILENAME);
if (fp != NULL) {
fs_read(fp, eeprom, 512);
fs_close(fp);
}
// do connection event // do connection event
joinRequestPacket->localIndex = network_player_connected(NPT_CLIENT, joinRequestPacket->localIndex); joinRequestPacket->localIndex = network_player_connected(NPT_CLIENT, joinRequestPacket->localIndex);
if (joinRequestPacket->localIndex == UNKNOWN_LOCAL_INDEX) { if (joinRequestPacket->localIndex == UNKNOWN_LOCAL_INDEX) {
@ -51,6 +45,12 @@ void network_send_join(struct Packet* joinRequestPacket) {
return; return;
} }
fs_file_t* fp = fs_open(SAVE_FILENAME);
if (fp != NULL) {
fs_read(fp, eeprom, 512);
fs_close(fp);
}
char version[MAX_VERSION_LENGTH] = { 0 }; char version[MAX_VERSION_LENGTH] = { 0 };
snprintf(version, MAX_VERSION_LENGTH, "%s", get_version()); snprintf(version, MAX_VERSION_LENGTH, "%s", get_version());
LOG_INFO("sending version: %s", version); LOG_INFO("sending version: %s", version);

View file

@ -2,15 +2,10 @@
#include "../network.h" #include "../network.h"
#include "pc/debuglog.h" #include "pc/debuglog.h"
void network_send_keep_alive(void) { void network_send_keep_alive(u8 localIndex) {
struct Packet p; struct Packet p;
packet_init(&p, PACKET_KEEP_ALIVE, false, false); packet_init(&p, PACKET_KEEP_ALIVE, false, false);
if (gNetworkType == NT_SERVER) { network_send_to(localIndex, &p);
network_send(&p);
} else {
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
gLastNetworkSend = clock();
LOG_INFO("sending keep alive"); LOG_INFO("sending keep alive");
} }

View file

@ -126,7 +126,7 @@ void network_send_level_respawn_info(struct Object* o, u8 respawnInfoBits) {
// send the packet // send the packet
if (gNetworkType == NT_SERVER) { if (gNetworkType == NT_SERVER) {
// broadcast // broadcast
for (int i = 0; i < MAX_PLAYERS; i++) { for (int i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i]; struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; } if (!np->connected) { continue; }
if (!np->currLevelSyncValid) { continue; } if (!np->currLevelSyncValid) { continue; }
@ -174,7 +174,7 @@ void network_receive_level_respawn_info(struct Packet* p) {
} }
// broadcast this change to the other players in that level // broadcast this change to the other players in that level
for (int i = 0; i < MAX_PLAYERS; i++) { for (int i = 1; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i]; struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; } if (!np->connected) { continue; }
if (!np->currLevelSyncValid) { continue; } if (!np->currLevelSyncValid) { continue; }

View file

@ -14,6 +14,7 @@ static u8 sCurrentOrderedSeqId = 0;
void packet_init(struct Packet* packet, enum PacketType packetType, bool reliable, bool levelAreaMustMatch) { void packet_init(struct Packet* packet, enum PacketType packetType, bool reliable, bool levelAreaMustMatch) {
memset(packet->buffer, 0, PACKET_LENGTH); memset(packet->buffer, 0, PACKET_LENGTH);
packet->packetType = packetType;
packet->cursor = 0; packet->cursor = 0;
packet->dataLength = 0; packet->dataLength = 0;
packet->error = false; packet->error = false;
@ -69,6 +70,7 @@ void packet_init(struct Packet* packet, enum PacketType packetType, bool reliabl
void packet_duplicate(struct Packet* srcPacket, struct Packet* dstPacket) { void packet_duplicate(struct Packet* srcPacket, struct Packet* dstPacket) {
memset(dstPacket->buffer, 0, PACKET_LENGTH); memset(dstPacket->buffer, 0, PACKET_LENGTH);
dstPacket->packetType = srcPacket->packetType;
dstPacket->cursor = 0; dstPacket->cursor = 0;
dstPacket->dataLength = 0; dstPacket->dataLength = 0;
dstPacket->error = srcPacket->error; dstPacket->error = srcPacket->error;
@ -90,6 +92,8 @@ void packet_duplicate(struct Packet* srcPacket, struct Packet* dstPacket) {
dstPacket->seqId = sNextSeqNum; dstPacket->seqId = sNextSeqNum;
sNextSeqNum++; sNextSeqNum++;
if (sNextSeqNum == 0) { sNextSeqNum++; } if (sNextSeqNum == 0) { sNextSeqNum++; }
} else {
dstPacket->seqId = 0;
} }
memcpy(&dstPacket->buffer[1], &dstPacket->seqId, 2); memcpy(&dstPacket->buffer[1], &dstPacket->seqId, 2);

View file

@ -101,8 +101,13 @@ void network_update_reliable(void) {
float elapsed = (clock() - node->lastSend) / CLOCKS_PER_SEC; float elapsed = (clock() - node->lastSend) / CLOCKS_PER_SEC;
float maxElapsed = (node->sendAttempts * node->sendAttempts * RELIABLE_RESEND_RATE) / ((float)MAX_RESEND_ATTEMPTS); float maxElapsed = (node->sendAttempts * node->sendAttempts * RELIABLE_RESEND_RATE) / ((float)MAX_RESEND_ATTEMPTS);
if (elapsed > maxElapsed) { if (elapsed > maxElapsed) {
if (node->p.packetType == PACKET_JOIN_REQUEST && gNetworkPlayerServer != NULL) {
node->p.localIndex = gNetworkPlayerServer->localIndex;
}
// resend // resend
node->p.sent = true;
network_send_to(node->p.localIndex, &node->p); network_send_to(node->p.localIndex, &node->p);
node->lastSend = clock(); node->lastSend = clock();
node->sendAttempts++; node->sendAttempts++;
if (node->sendAttempts >= MAX_RESEND_ATTEMPTS) { if (node->sendAttempts >= MAX_RESEND_ATTEMPTS) {

View file

@ -24,10 +24,12 @@ static int socket_bind(SOCKET socket, unsigned int port) {
static int socket_send(SOCKET socket, struct sockaddr_in* addr, u8* buffer, u16 bufferLength) { static int socket_send(SOCKET socket, struct sockaddr_in* addr, u8* buffer, u16 bufferLength) {
int addrSize = sizeof(struct sockaddr_in); int addrSize = sizeof(struct sockaddr_in);
int rc = sendto(socket, (char*)buffer, bufferLength, 0, (struct sockaddr*)addr, addrSize); int rc = sendto(socket, (char*)buffer, bufferLength, 0, (struct sockaddr*)addr, addrSize);
if (rc == SOCKET_ERROR) { if (rc != SOCKET_ERROR) { return NO_ERROR; }
LOG_ERROR("sendto failed with error: %d", SOCKET_LAST_ERROR);
}
int error = SOCKET_LAST_ERROR;
if (error == SOCKET_EWOULDBLOCK) { return NO_ERROR; }
LOG_ERROR("sendto failed with error: %d", error);
return rc; return rc;
} }
@ -49,7 +51,7 @@ static int socket_receive(SOCKET socket, struct sockaddr_in* rxAddr, u8* buffer,
if (error != SOCKET_EWOULDBLOCK && error != SOCKET_ECONNRESET) { if (error != SOCKET_EWOULDBLOCK && error != SOCKET_ECONNRESET) {
LOG_ERROR("recvfrom failed with error %d", SOCKET_LAST_ERROR); LOG_ERROR("recvfrom failed with error %d", SOCKET_LAST_ERROR);
} }
return rc; return SOCKET_ERROR;
} }
*receiveLength = rc; *receiveLength = rc;
@ -118,10 +120,11 @@ static void ns_socket_update(void) {
if (gNetworkType == NT_NONE) { return; } if (gNetworkType == NT_NONE) { return; }
do { do {
// receive packet // receive packet
u8 data[PACKET_LENGTH]; u8 data[PACKET_LENGTH + 1];
u16 dataLength = 0; u16 dataLength = 0;
u8 localIndex = UNKNOWN_LOCAL_INDEX; u8 localIndex = UNKNOWN_LOCAL_INDEX;
int rc = socket_receive(curSocket, &addr[0], data, PACKET_LENGTH, &dataLength, &localIndex); int rc = socket_receive(curSocket, &addr[0], data, PACKET_LENGTH + 1, &dataLength, &localIndex);
assert(dataLength < PACKET_LENGTH);
if (rc != NO_ERROR) { break; } if (rc != NO_ERROR) { break; }
network_receive(localIndex, data, dataLength); network_receive(localIndex, data, dataLength);
} while (true); } while (true);
@ -132,7 +135,11 @@ static int ns_socket_send(u8 localIndex, u8* data, u16 dataLength) {
if (gNetworkType == NT_SERVER && gNetworkPlayers[localIndex].type != NPT_CLIENT) { return SOCKET_ERROR; } if (gNetworkType == NT_SERVER && gNetworkPlayers[localIndex].type != NPT_CLIENT) { return SOCKET_ERROR; }
if (gNetworkType == NT_CLIENT && gNetworkPlayers[localIndex].type != NPT_SERVER) { return SOCKET_ERROR; } if (gNetworkType == NT_CLIENT && gNetworkPlayers[localIndex].type != NPT_SERVER) { return SOCKET_ERROR; }
} }
return socket_send(curSocket, &addr[localIndex], data, dataLength); int rc = socket_send(curSocket, &addr[localIndex], data, dataLength);
if (rc) {
LOG_ERROR(" localIndex: %d, packetType: %d, dataLength: %d", localIndex, data[0], dataLength);
}
return rc;
} }
static void ns_socket_shutdown(void) { static void ns_socket_shutdown(void) {

View file

@ -311,7 +311,9 @@ void main_func(void) {
#ifdef DISCORDRPC #ifdef DISCORDRPC
discord_update_rich_presence(); discord_update_rich_presence();
#endif #endif
#ifdef DEBUG
fflush(stdout); fflush(stdout);
#endif
} }
#endif #endif
} }