shithub: choc

Download patch

ref: 93ac1b74ab0f082a3ee8f1efc0ccd7f47bac3802
parent: 34c3dd253fa3d56b16c11a5263ffb3378529fc33
author: Simon Howard <fraggle@gmail.com>
date: Sun Jan 1 18:54:31 EST 2006

Client disconnect code

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 238

--- a/src/d_net.c
+++ b/src/d_net.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: d_net.c 237 2006-01-01 23:53:15Z fraggle $
+// $Id: d_net.c 238 2006-01-01 23:54:31Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -22,6 +22,9 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.11  2006/01/01 23:54:31  fraggle
+// Client disconnect code
+//
 // Revision 1.10  2006/01/01 23:53:15  fraggle
 // Remove GS_WAITINGSTART gamestate.  This will be independent of the main
 // loop to avoid interfering with the main game code too much.
@@ -67,7 +70,7 @@
 //-----------------------------------------------------------------------------
 
 
-static const char rcsid[] = "$Id: d_net.c 237 2006-01-01 23:53:15Z fraggle $";
+static const char rcsid[] = "$Id: d_net.c 238 2006-01-01 23:54:31Z fraggle $";
 
 
 #include "m_menu.h"
@@ -683,6 +686,8 @@
 	
     if (debugfile)
 	fclose (debugfile);
+
+    NET_ClientDisconnect();
 
     if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
 	return;
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.c 235 2005-12-30 18:58:22Z fraggle $
+// $Id: net_client.c 238 2006-01-01 23:54:31Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,9 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.4  2006/01/01 23:54:31  fraggle
+// Client disconnect code
+//
 // Revision 1.3  2005/12/30 18:58:22  fraggle
 // Fix client code to correctly send reply to server on connection.
 // Add "waiting screen" while waiting for the game to start.
@@ -60,6 +63,14 @@
     // in game
 
     CLIENT_STATE_IN_GAME,
+
+    // in disconnect state: sent DISCONNECT, waiting for DISCONNECT_ACK reply
+    
+    CLIENT_STATE_DISCONNECTING,
+
+    // successfully disconnected
+
+    CLIENT_STATE_DISCONNECTED,
 } net_clientstate_t;
 
 static boolean client_initialised = false;
@@ -109,6 +120,42 @@
     }
 }
 
+// parse a DISCONNECT packet
+
+static void ClientParseDisconnect(net_packet_t *packet)
+{
+    net_packet_t *reply;
+
+    // construct a DISCONNECT_ACK reply packet
+
+    reply = NET_NewPacket(10);
+    NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK);
+
+    // send the reply several times, in case of packet loss
+
+    NET_SendPacket(server_addr, reply);
+    NET_SendPacket(server_addr, reply);
+    NET_SendPacket(server_addr, reply);
+
+    client_state = CLIENT_STATE_DISCONNECTED;
+
+    I_Error("Disconnected from server.\n");
+}
+
+// parse a DISCONNECT_ACK packet
+
+static void ClientParseDisconnectACK(net_packet_t *packet)
+{
+    if (client_state == CLIENT_STATE_DISCONNECTING)
+    {
+        // successfully disconnected from the server.
+
+        client_state = CLIENT_STATE_DISCONNECTED;
+
+        // now what?
+    }
+}
+
 // parse a received packet
 
 static void ClientParsePacket(net_packet_t *packet)
@@ -139,6 +186,15 @@
 
         case NET_PACKET_TYPE_GAMEDATA:
             break;
+
+        case NET_PACKET_TYPE_DISCONNECT:
+            ClientParseDisconnect(packet);
+            break;
+
+        case NET_PACKET_TYPE_DISCONNECT_ACK:
+            ClientParseDisconnectACK(packet);
+            break;
+
         default:
             break;
     }
@@ -176,6 +232,35 @@
     }
 }
 
+// Called when we are in the "disconnecting" state, disconnecting from
+// the server.
+
+static void ClientDisconnecting(void)
+{
+    net_packet_t *packet;
+
+    // send a DISCONNECT packet every second
+
+    if (last_send_time < 0 || I_GetTimeMS() - last_send_time > 1000)
+    {
+        // construct packet
+
+        packet = NET_NewPacket(10);
+
+        // packet type
+     
+        NET_WriteInt16(packet, NET_PACKET_TYPE_DISCONNECT);
+
+        // send to the server
+
+        NET_SendPacket(server_addr, packet);
+
+        NET_FreePacket(packet);
+
+        last_send_time = I_GetTimeMS();
+    }
+}
+
 // "Run" the client code: check for new packets, send packets as
 // needed
 
@@ -208,9 +293,10 @@
         case CLIENT_STATE_CONNECTING:
             ClientConnecting();
             break;
-        case CLIENT_STATE_WAITING_START:
+        case CLIENT_STATE_DISCONNECTING:
+            ClientDisconnecting();
             break;
-        case CLIENT_STATE_IN_GAME:
+        default:
             break;
     }
 }
@@ -263,6 +349,10 @@
         // connect
 
         NET_ServerRun();
+
+        // Don't hog the CPU
+
+        I_Sleep(10);
     }
 
     if (client_state != CLIENT_STATE_CONNECTING)
@@ -279,4 +369,51 @@
     }
 }
 
+// disconnect from the server
+
+void NET_ClientDisconnect(void)
+{
+    int start_time;
+
+    if (!client_initialised)
+    {
+        return;
+    }
+    
+    // set the client into the DISCONNECTING state
+
+    if (client_state != CLIENT_STATE_DISCONNECTED)
+    {
+        client_state = CLIENT_STATE_DISCONNECTING;
+        last_send_time = -1;
+    }
+
+    start_time = I_GetTimeMS();
+
+    while (client_state != CLIENT_STATE_DISCONNECTED)
+    {
+        if (I_GetTimeMS() - start_time > 5000)
+        {
+            // time out after 5 seconds
+            
+            client_state = CLIENT_STATE_DISCONNECTED;
+
+            fprintf(stderr, "NET_ClientDisconnect: Timeout while disconnecting from server\n");
+            break;
+        }
+
+        NET_ClientRun();
+        NET_ServerRun();
+
+        I_Sleep(10);
+    }
+
+    // Finished sending disconnect packets, etc.
+
+    // Shut down network module, etc.  To do.
+
+    NET_FreeAddress(server_addr);
+
+    client_initialised = false;
+}
 
--- a/src/net_client.h
+++ b/src/net_client.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.h 235 2005-12-30 18:58:22Z fraggle $
+// $Id: net_client.h 238 2006-01-01 23:54:31Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,9 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.4  2006/01/01 23:54:31  fraggle
+// Client disconnect code
+//
 // Revision 1.3  2005/12/30 18:58:22  fraggle
 // Fix client code to correctly send reply to server on connection.
 // Add "waiting screen" while waiting for the game to start.
@@ -43,6 +46,7 @@
 #include "net_defs.h"
 
 boolean NET_ClientConnect(net_addr_t *addr);
+void NET_ClientDisconnect(void);
 void NET_ClientRun(void);
 
 #endif /* #ifndef NET_CLIENT_H */
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_defs.h 235 2005-12-30 18:58:22Z fraggle $
+// $Id: net_defs.h 238 2006-01-01 23:54:31Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,9 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.4  2006/01/01 23:54:31  fraggle
+// Client disconnect code
+//
 // Revision 1.3  2005/12/30 18:58:22  fraggle
 // Fix client code to correctly send reply to server on connection.
 // Add "waiting screen" while waiting for the game to start.
@@ -111,6 +114,8 @@
     NET_PACKET_TYPE_WAITING_DATA,
     NET_PACKET_TYPE_GAMESTART,
     NET_PACKET_TYPE_GAMEDATA,
+    NET_PACKET_TYPE_DISCONNECT,
+    NET_PACKET_TYPE_DISCONNECT_ACK,
 } net_packet_type_t;
 
 typedef struct 
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_server.c 235 2005-12-30 18:58:22Z fraggle $
+// $Id: net_server.c 238 2006-01-01 23:54:31Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -21,6 +21,9 @@
 // 02111-1307, USA.
 //
 // $Log$
+// Revision 1.4  2006/01/01 23:54:31  fraggle
+// Client disconnect code
+//
 // Revision 1.3  2005/12/30 18:58:22  fraggle
 // Fix client code to correctly send reply to server on connection.
 // Add "waiting screen" while waiting for the game to start.
@@ -60,6 +63,13 @@
 
     CLIENT_STATE_IN_GAME,
 
+    // sent a DISCONNECT packet, waiting for a DISCONNECT_ACK reply
+
+    CLIENT_STATE_DISCONNECTING,
+
+    // client successfully disconnected
+
+    CLIENT_STATE_DISCONNECTED,
 } net_clientstate_t;
 
 #define MAX_RETRIES 5
@@ -77,6 +87,17 @@
 static net_client_t clients[MAXNETNODES];
 static net_context_t *server_context;
 
+static boolean ClientConnected(net_client_t *client)
+{
+    // Check that the client is properly connected: ie. not in the 
+    // process of connecting or disconnecting
+
+    return clients->active
+        && clients->state != CLIENT_STATE_DISCONNECTING
+        && clients->state != CLIENT_STATE_DISCONNECTED
+        && clients->state != CLIENT_STATE_WAITING_ACK;
+}
+
 // returns the number of clients connected
 
 static int ServerNumClients(void)
@@ -88,7 +109,7 @@
 
     for (i=0; i<MAXNETNODES; ++i)
     {
-        if (clients[i].active)
+        if (ClientConnected(&clients[i]))
         {
             ++count;
         }
@@ -107,7 +128,7 @@
 
     for (i=0; i<MAXNETNODES; ++i)
     {
-        if (clients[i].active)
+        if (ClientConnected(&clients[i]))
         {
             return &clients[i];
         }
@@ -116,6 +137,25 @@
     return NULL;
 }
 
+// Given an address, find the corresponding client
+
+static net_client_t *ServerFindClient(net_addr_t *addr)
+{
+    int i;
+
+    for (i=0; i<MAXNETNODES; ++i) 
+    {
+        if (clients[i].active && clients[i].addr == addr)
+        {
+            // found the client
+
+            return &clients[i];
+        }
+    }
+
+    return NULL;
+}
+
 // parse a SYN from a client(initiating a connection)
 
 static void ServerParseSYN(net_packet_t *packet, 
@@ -195,6 +235,39 @@
     }
 }
 
+static void ServerParseDisconnect(net_packet_t *packet, net_client_t *client)
+{
+    net_packet_t *reply;
+
+    // sanity check
+
+    if (client == NULL)
+    {
+        return;
+    }
+
+    // This client wants to disconnect from the server.
+    // Send a DISCONNECT_ACK reply.
+    
+    reply = NET_NewPacket(10);
+    NET_WriteInt16(reply, NET_PACKET_TYPE_DISCONNECT_ACK);
+    NET_SendPacket(client->addr, reply);
+    NET_FreePacket(reply);
+
+    client->last_send_time = I_GetTimeMS();
+    
+    // Do not set to inactive immediately.  Instead, set to the 
+    // DISCONNECTED state.  This is in case our acknowledgement is
+    // not received and another must be sent.
+    //
+    // After a few seconds, the client will get properly removed
+    // and cleaned up from the clients list.
+
+    client->state = CLIENT_STATE_DISCONNECTED;
+
+    printf("client %i disconnected\n", client-clients);
+}
+
 // Process a packet received by the server
 
 static void ServerPacket(net_packet_t *packet, net_addr_t *addr)
@@ -201,23 +274,13 @@
 {
     net_client_t *client;
     unsigned int packet_type;
-    int i;
 
-    // find which client this packet came from
+    // Find which client this packet came from
 
-    client = NULL;
+    client = ServerFindClient(addr);
 
-    for (i=0; i<MAXNETNODES; ++i) 
-    {
-        if (clients[i].active && clients[i].addr == addr)
-        {
-            // found the client
+    // Read the packet type
 
-            client = &clients[i];
-            break;
-        }
-    }
-
     if (!NET_ReadInt16(packet, &packet_type))
     {
         // no packet type
@@ -237,11 +300,22 @@
             break;
         case NET_PACKET_TYPE_GAMEDATA:
             break;
+        case NET_PACKET_TYPE_DISCONNECT:
+            ServerParseDisconnect(packet, client);
+            break;
         default:
             // unknown packet type
 
             break;
     }
+
+    // If this address is not in the list of clients, be sure to
+    // free it back.
+
+    if (ServerFindClient(addr) == NULL)
+    {
+        NET_FreeAddress(addr);
+    }
 }
 
 
@@ -302,9 +376,8 @@
             {
                 // no more retries allowed.
 
-                NET_FreeAddress(client->addr);
-
                 client->active = false;
+                NET_FreeAddress(client->addr);
             }
         }
     }
@@ -313,10 +386,27 @@
 
     if (client->state == CLIENT_STATE_WAITING_START)
     {
+        // Send information once every second
+
         if (client->last_send_time < 0 
          || I_GetTimeMS() - client->last_send_time > 1000)
         {
             ServerSendWaitingData(client);
+        }
+    }
+
+    // Client has disconnected.  
+    //
+    // See ServerParseDisconnect() above.
+
+    if (client->state == CLIENT_STATE_DISCONNECTED)
+    {
+        // Remove from the list after five seconds
+
+        if (I_GetTimeMS() - client->last_send_time > 5000)
+        {
+            client->active = false;
+            NET_FreeAddress(client->addr);
         }
     }
 }