diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 213f5dde..dca967ab 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -674,7 +674,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) static void resynch_read_player(resynch_pak *rsp) { INT32 i = rsp->playernum, j; - mobj_t *savedmo = players[i].mo; + //mobj_t *savedmo = players[i].mo; // Do not send anything visual related. // Only send data that we need to know for physics. @@ -767,11 +767,17 @@ static void resynch_read_player(resynch_pak *rsp) return; //...but keep old mo even if it is corrupt or null! - players[i].mo = savedmo; + //players[i].mo = savedmo; //Transfer important mo information if they have a valid mo. if (!rsp->hasmo) + { + // Get rid of their object if they aren't supposed to have one.....?? + if (players[i].mo) + P_RemoveMobj(players[i].mo); + return; + } //server thinks player has a body. //Give them a new body that can be then manipulated by the server's info. @@ -1024,6 +1030,7 @@ static void SV_SendResynch(INT32 node) return; } + resynch_inprogress[node] = false; // Let's see if there's REALLY anyone left to sync..... netbuffer->packettype = PT_RESYNCHING; for (i = 0, j = 0; i < MAXPLAYERS; ++i) { @@ -1031,10 +1038,24 @@ static void SV_SendResynch(INT32 node) if (!(resynch_status[node] & 1< TICRATE) + { + CONS_Alert(CONS_ERROR, "Node %d (%s) somehow had a stupidly-long resync delay?! (%d tics to resync player %d)\n", + node, player_names[nodetoplayer[node]], resynch_sent[node][i], i + ); + resynch_sent[node][i] = TICRATE; + } + continue; } @@ -1048,6 +1069,15 @@ static void SV_SendResynch(INT32 node) break; } + if (!resynch_inprogress[node]) + { + CONS_Alert(CONS_ERROR, "Node %d (%s) somehow had resync status for nonexistent players?! (%08x)\n", + node, player_names[nodetoplayer[node]], resynch_status[node] = 0x00 + ); + resynch_status[node] = 0x00; + resynch_inprogress[node] = true; // So they get the PT_RESYNCHEND... + } + if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250) { XBOXSTATIC UINT8 buf[2]; @@ -2301,6 +2331,8 @@ static void CL_ConnectToServer(boolean viams) if (gamestate == GS_VOTING) Y_EndVote(); + resynch_local_inprogress = false; // Just in case this was never cleared... + DEBFILE(va("waiting %d nodes\n", doomcom->numnodes)); G_SetGamestate(GS_WAITINGPLAYERS); wipegamestate = GS_WAITINGPLAYERS; @@ -3397,6 +3429,7 @@ void D_QuitNetGame(void) HSendPacket(servernode, true, 0, 0); } + resynch_local_inprogress = false; // No more resyncing! D_CloseConnection(); ClearAdminPlayers(); @@ -3985,7 +4018,7 @@ static void HandlePacketFromAwayNode(SINT8 node) cl_challengenum = netbuffer->u.joinchallenge.challengenum; memcpy(cl_challengequestion, netbuffer->u.joinchallenge.question, 16); - Net_CloseConnection(node|FORCECLOSE); // Don't need to stay connected while challenging + Net_CloseConnection(node); // Don't need to stay connected while challenging cl_mode = CL_CHALLENGE; diff --git a/src/d_net.c b/src/d_net.c index 94b11d51..f8995b05 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -339,6 +339,7 @@ static boolean Processackpak(void) { UINT8 ack = netbuffer->ack; getackpacket++; + if (cmpack(ack, node->firstacktosend) <= 0) { DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack)); @@ -361,6 +362,7 @@ static boolean Processackpak(void) // Is a good packet so increment the acknowledge number, // Then search for a "hole" in the queue UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1); + if (!nextfirstack) nextfirstack = 1; @@ -1070,6 +1072,10 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen netbuffer->checksum = NetbufferChecksum(); sendbytes += packetheaderlength + doomcom->datalength; // For stat + // Joinpasswords close nodes, this may try to send to a waiting-to-close node, so cancel closing? + if (netbuffer->packettype == PT_CLIENTJOIN) + nodes[node].flags &= ~NF_CLOSE; + #ifdef PACKETDROP // Simulate internet :) //if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f))) @@ -1106,7 +1112,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen // boolean HGetPacket(void) { - //boolean nodejustjoined; + boolean nodejustjoined; // Get a packet from self if (rebound_tail != rebound_head) @@ -1133,11 +1139,54 @@ boolean HGetPacket(void) while(true) { - //nodejustjoined = I_NetGet(); - I_NetGet(); + nodejustjoined = I_NetGet(); + //I_NetGet(); if (doomcom->remotenode == -1) // No packet received - return false; + { + if (nodejustjoined) // _This_ means we did receive a packet, but either from a node we couldn't allocate or a gone player ackreting... + continue; + else + return false; + } + + if (nodejustjoined) + { + // If a new node sends an unexpected packet, just ignore it + if (server + && !(netbuffer->packettype == PT_ASKINFO + || netbuffer->packettype == PT_SERVERINFO + || netbuffer->packettype == PT_PLAYERINFO + || netbuffer->packettype == PT_REQUESTFILE + || netbuffer->packettype == PT_ASKINFOVIAMS + || netbuffer->packettype == PT_CLIENTJOIN)) + { + DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype])); + CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]); + Net_CloseConnection(doomcom->remotenode | FORCECLOSE); + continue; + } + + // UGLY PROBABLY-BAD HACK: If we get PT_CLIENTJOIN, assume this is an in-order packet? + if (netbuffer->packettype == PT_CLIENTJOIN) + nodes[doomcom->remotenode].firstacktosend = (UINT8)((netbuffer->ack-1+MAXACKTOSEND) % MAXACKTOSEND); + + if (netbuffer->ack > 1 && !(server && netbuffer->packettype == PT_CLIENTJOIN)) + { + DEBFILE("New node sent a packet with an out-of-sequence ack. Ghost connection? Ignoring...\n"); + CONS_Alert(CONS_NOTICE, "New node sent a packet with an out-of-sequence ack. Ghost connection? Ignoring...\n"); + Net_CloseConnection(doomcom->remotenode | FORCECLOSE); + continue; + } + + // Reinitialize vars for the new node just in case there's anything left over from other players..... + InitNode(&nodes[doomcom->remotenode]); + SV_AbortSendFiles(doomcom->remotenode); + } + + // Joinpasswords close nodes, this may receive from a waiting-to-close node, so cancel closing? + if (netbuffer->packettype == PT_CLIENTJOIN) + nodes[doomcom->remotenode].flags &= ~NF_CLOSE; getbytes += packetheaderlength + doomcom->datalength; // For stat @@ -1152,8 +1201,8 @@ boolean HGetPacket(void) if (netbuffer->checksum != NetbufferChecksum()) { DEBFILE("Bad packet checksum\n"); - //Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode); - Net_CloseConnection(doomcom->remotenode); + Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode); + //Net_CloseConnection(doomcom->remotenode); continue; } @@ -1162,21 +1211,6 @@ boolean HGetPacket(void) DebugPrintpacket("GET"); #endif - /*// If a new node sends an unexpected packet, just ignore it - if (nodejustjoined && server - && !(netbuffer->packettype == PT_ASKINFO - || netbuffer->packettype == PT_SERVERINFO - || netbuffer->packettype == PT_PLAYERINFO - || netbuffer->packettype == PT_REQUESTFILE - || netbuffer->packettype == PT_ASKINFOVIAMS - || netbuffer->packettype == PT_CLIENTJOIN)) - { - DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype])); - //CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]); - Net_CloseConnection(doomcom->remotenode | FORCECLOSE); - continue; - }*/ - // Proceed the ack and ackreturn field if (!Processackpak()) continue; // discarded (duplicated) diff --git a/src/i_tcp.c b/src/i_tcp.c index f58aa22b..7de94573 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -508,6 +508,8 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) return false; } +static void SOCK_FreeNodenum(INT32 numnode); + // This is a hack. For some reason, nodes aren't being freed properly. // This goes through and cleans up what nodes were supposed to be freed. /** \warning This function causes the file downloading to stop if someone joins. @@ -524,7 +526,7 @@ static void cleanupnodes(void) // Why can't I start at zero? for (j = 1; j < MAXNETNODES; j++) if (!(nodeingame[j] || SV_SendingFile(j))) - nodeconnected[j] = false; + SOCK_FreeNodenum(j); // At least free this PROPERLY } static SINT8 getfreenode(void) @@ -624,6 +626,13 @@ static boolean SOCK_Get(void) } // not found + if (netbuffer->packettype == PT_NOTHING) + { + DEBFILE(va("Ackret received from disconnected address:%s, ignoring...\n", SOCK_AddrToStr(&fromaddress))); + doomcom->remotenode = -1; // no packet + return true; + } + // find a free slot j = getfreenode(); if (j > 0) @@ -650,7 +659,11 @@ static boolean SOCK_Get(void) return true; } else + { DEBFILE("New node detected: No more free slots\n"); + doomcom->remotenode = -1; // no packet + return true; + } } }