Maelstrom: Differentiate between timeout and sync corruption cases in the network sync code.

https://github.com/libsdl-org/Maelstrom/commit/655883923d2e30b55bbb82d4b6776af51cf015a8

From 655883923d2e30b55bbb82d4b6776af51cf015a8 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 20 Nov 2011 14:03:40 -0500
Subject: [PATCH] Differentiate between timeout and sync corruption cases in
 the network sync code.

---
 game/game.cpp    | 26 ++++++++++++++++++++++----
 game/netplay.cpp | 39 +++++++++++++++++++++------------------
 game/netplay.h   | 14 +++++++++++++-
 3 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/game/game.cpp b/game/game.cpp
index ea09726c..c7a04770 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -236,6 +236,7 @@ void
 GamePanelDelegate::OnTick()
 {
 	int i, j;
+	SYNC_RESULT syncResult;
 
 	if (!gGameOn) {
 		// This generally shouldn't happen, but could if there were
@@ -251,14 +252,31 @@ GamePanelDelegate::OnTick()
 		gGameOn = 0;
 		return;
 	}
-	int syncResult = SyncNetwork();
+
+	syncResult = SyncNetwork();
+
+	// Update state and see if the local player aborted
 	if ( !UpdateGameState() ) {
 		gGameOn = 0;
 		return;
 	}
-	if (syncResult < 0) {
-		// We didn't get a full frame yet, don't process it
-		return;
+	switch (syncResult) {
+		case SYNC_TIMEOUT:
+			// The other players might be minimized or doing
+			// the bonus screen and may not be able to respond.
+			return;
+		case SYNC_CORRUPT:
+			// Uh oh...
+			error("Network sync error, game aborted!\r\n");
+			gGameOn = 0;
+			return;
+		case SYNC_NETERROR:
+			// Uh oh...
+			error("Network socket error, game aborted!\r\n");
+			gGameOn = 0;
+			return;
+		case SYNC_COMPLETE:
+			break;
 	}
 	gReplay.HandleRecording();
 
diff --git a/game/netplay.cpp b/game/netplay.cpp
index 5592a833..c4eeaf25 100644
--- a/game/netplay.cpp
+++ b/game/netplay.cpp
@@ -199,7 +199,7 @@ static bool ProcessSync(int index, DynamicPacket &packet)
 	return true;
 }
 
-static int AwaitSync()
+static SYNC_RESULT AwaitSync()
 {
 	int i;
 	int timeout;
@@ -209,7 +209,7 @@ static int AwaitSync()
 	for (i = 0; i < MAX_NODES; ++i) {
 		if (CachedPacket[i].len > 0 && WaitingAcks[i]) {
 			if (!ProcessSync(i, CachedPacket[i])) {
-				return -1;
+				return SYNC_CORRUPT;
 			}
 			WaitingAcks[i] = 0;
 		}
@@ -229,7 +229,7 @@ static int AwaitSync()
 		int ready = SDLNet_CheckSockets(SocketSet, 100);
 		if (ready < 0) {
 			error("Network error: SDLNet_CheckSockets()\r\n");
-			return(-1);
+			return SYNC_NETERROR;
 		}
 		if (ready == 0) {
 #if DEBUG_NETWORK >= 1
@@ -245,7 +245,7 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
 			/* Don't wait forever */
 			++timeout;
 			if ( timeout == (PING_TIMEOUT/100) ) {
-				return(-1);
+				return SYNC_TIMEOUT;
 			}
 		}
 		if ( ready <= 0 ) {
@@ -256,7 +256,7 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
 		Packet.Reset();
 		if ( SDLNet_UDP_Recv(gNetFD, &Packet) <= 0 ) {
 			error("Network error: SDLNet_UDP_Recv()\r\n");
-			return(-1);
+			return SYNC_NETERROR;
 		}
 
 		/* We have a packet! */
@@ -322,7 +322,7 @@ error("Ignoring duplicate packet for frame %lu from player %d\r\n", frame, index
 
 			/* Do a consistency check!! */
 			if (!ProcessSync(index, Packet)) {
-				return -1;
+				return SYNC_CORRUPT;
 			}
 			WaitingAcks[index] = 0;
 		} else if (frame == (NextFrame-1)) {
@@ -352,16 +352,15 @@ error("Received packet for really old frame! (%lu, current = %lu)\r\n",
 							frame, NextFrame);
 #endif
 	}
-	return 0;
+	return SYNC_COMPLETE;
 }
 
-static int AdvanceFrame()
+static void AdvanceFrame()
 {
 	CurrOut = !CurrOut;
 	QueuedInput.Reset();
 	++NextFrame;
 	AdvancedFrame = true;
-	return 0;
 }
 
 /* This function is called every frame, and is used to flush the network
@@ -373,16 +372,18 @@ static int AdvanceFrame()
           otherwise we lose consistency.
 */
 	
-int SyncNetwork(void)
+SYNC_RESULT SyncNetwork(void)
 {
+	SYNC_RESULT result = SYNC_COMPLETE;
 	int i;
 
 	if (!AdvancedFrame) {
 		// We still have some nodes we're waiting on...
-		if (AwaitSync() < 0) {
-			return -1;
+		result = AwaitSync();
+		if (result == SYNC_COMPLETE) {
+			AdvanceFrame();
 		}
-		return AdvanceFrame();
+		return result;
 	}
 
 	FrameInput.Reset();
@@ -410,13 +411,15 @@ int SyncNetwork(void)
 		CurrPacket.Write(QueuedInput);
 
 		// Wait for sync packets from them
-		if (AwaitSync() < 0) {
-			AdvancedFrame = false;
-			return -1;
-		}
+		result = AwaitSync();
 	}
 
-	return AdvanceFrame();
+	if (result == SYNC_COMPLETE) {
+		AdvanceFrame();
+	} else {
+		AdvancedFrame = false;
+	}
+	return result;
 }
 
 /* This function retrieves the input for the frame */
diff --git a/game/netplay.h b/game/netplay.h
index 0754bfd9..75c088c8 100644
--- a/game/netplay.h
+++ b/game/netplay.h
@@ -20,17 +20,29 @@
     slouken@libsdl.org
 */
 
+#ifndef _netplay_h
+#define _netplay_h
+
 #include "SDL_net.h"
 
+enum SYNC_RESULT {
+	SYNC_COMPLETE,
+	SYNC_TIMEOUT,
+	SYNC_CORRUPT,
+	SYNC_NETERROR,
+};
+
 /* Functions in netplay.cpp */
 extern int   InitNetData(bool hosting);
 extern void  HaltNetData(void);
 extern int   CheckPlayers(void);
 extern void  QueueInput(Uint8 value);
-extern int   SyncNetwork(void);
+extern SYNC_RESULT SyncNetwork(void);
 extern int   GetSyncBuf(Uint8 **bufptr);
 extern int   Send_NewGame();
 
 /* Variables from netplay.cpp */
 extern UDPsocket gNetFD;
 extern Uint32 NextFrame;	// Exposed for debugging purposes
+
+#endif // _netplay_h