Client disconnect code

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 238
This commit is contained in:
Simon Howard 2006-01-01 23:54:31 +00:00
parent 34c3dd253f
commit 93ac1b74ab
5 changed files with 266 additions and 25 deletions

View file

@ -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"
@ -684,6 +687,8 @@ void D_QuitNetGame (void)
if (debugfile)
fclose (debugfile);
NET_ClientDisconnect();
if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
return;

View file

@ -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 @@ typedef enum
// 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 @@ static void ClientParseACK(net_packet_t *packet)
}
}
// 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 @@ static void ClientParsePacket(net_packet_t *packet)
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 @@ static void ClientConnecting(void)
}
}
// 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 @@ void NET_ClientRun(void)
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 @@ boolean NET_ClientConnect(net_addr_t *addr)
// connect
NET_ServerRun();
// Don't hog the CPU
I_Sleep(10);
}
if (client_state != CLIENT_STATE_CONNECTING)
@ -279,4 +369,51 @@ boolean NET_ClientConnect(net_addr_t *addr)
}
}
// 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;
}

View file

@ -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 */

View file

@ -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 @@ typedef enum
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

View file

@ -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 @@ typedef enum
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 boolean server_initialised = false;
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 @@ static int ServerNumClients(void)
for (i=0; i<MAXNETNODES; ++i)
{
if (clients[i].active)
if (ClientConnected(&clients[i]))
{
++count;
}
@ -107,7 +128,7 @@ static net_client_t *ServerController(void)
for (i=0; i<MAXNETNODES; ++i)
{
if (clients[i].active)
if (ClientConnected(&clients[i]))
{
return &clients[i];
}
@ -116,6 +137,25 @@ static net_client_t *ServerController(void)
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,28 +235,51 @@ static void ServerParseACK(net_packet_t *packet, net_client_t *client)
}
}
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)
{
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
client = &clients[i];
break;
}
}
// Read the packet type
if (!NET_ReadInt16(packet, &packet_type))
{
@ -237,11 +300,22 @@ static void ServerPacket(net_packet_t *packet, net_addr_t *addr)
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 @@ static void ServerRunClient(net_client_t *client)
{
// no more retries allowed.
NET_FreeAddress(client->addr);
client->active = false;
NET_FreeAddress(client->addr);
}
}
}
@ -313,12 +386,29 @@ static void ServerRunClient(net_client_t *client)
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);
}
}
}
// Initialise server and wait for connections