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);
}
}
}