summaryrefslogtreecommitdiff
path: root/src/net_server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_server.c')
-rw-r--r--src/net_server.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/net_server.c b/src/net_server.c
new file mode 100644
index 00000000..db44d533
--- /dev/null
+++ b/src/net_server.c
@@ -0,0 +1,286 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// $Id: net_server.c 232 2005-12-29 17:48:25Z fraggle $
+//
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// $Log$
+// Revision 1.1 2005/12/29 17:48:25 fraggle
+// Add initial client/server connect code. Reorganise sources list in
+// Makefile.am.
+//
+//
+// Network server code
+//
+
+#include "doomdef.h"
+#include "doomstat.h"
+#include "i_system.h"
+#include "net_defs.h"
+#include "net_io.h"
+#include "net_loop.h"
+#include "net_packet.h"
+#include "net_server.h"
+
+typedef enum
+{
+ // received a syn, sent an ack, waiting for an ack reply
+
+ CLIENT_STATE_WAITING_ACK,
+
+ // waiting for a game to start
+
+ CLIENT_STATE_WAITING_START,
+
+ // in game
+
+ CLIENT_STATE_IN_GAME,
+
+} net_clientstate_t;
+
+#define MAX_RETRIES 5
+
+typedef struct
+{
+ boolean active;
+ net_clientstate_t state;
+ net_addr_t *addr;
+ int last_send_time;
+ int num_retries;
+} net_client_t;
+
+static boolean server_initialised = false;
+static net_client_t clients[MAXNETNODES];
+static net_context_t *server_context;
+
+// parse a SYN from a client(initiating a connection)
+
+static void NET_ServerParseSYN(net_packet_t *packet,
+ net_client_t *client,
+ net_addr_t *addr)
+{
+ unsigned int magic;
+ int i;
+
+ // read the magic number
+
+ if (!NET_ReadInt16(packet, &magic))
+ {
+ return;
+ }
+
+ if (magic != NET_MAGIC_NUMBER)
+ {
+ // invalid magic number
+
+ return;
+ }
+
+ // received a valid SYN
+
+ // allocate a client slot if there isn't one already
+
+ if (client == NULL)
+ {
+ // find a slot, or return if none found
+
+ for (i=0; i<MAXNETNODES; ++i)
+ {
+ if (!clients[i].active)
+ {
+ clients[i].active = true;
+ clients[i].addr = addr;
+ clients[i].state = CLIENT_STATE_WAITING_ACK;
+ clients[i].num_retries = 0;
+ client = &clients[i];
+ break;
+ }
+ }
+
+ if (client == NULL)
+ {
+ return;
+ }
+ }
+
+ if (client->state == CLIENT_STATE_WAITING_ACK)
+ {
+ // force an acknowledgement
+
+ client->last_send_time = -1;
+ }
+}
+
+// parse an ACK packet from a client
+
+static void NET_ServerParseACK(net_packet_t *packet, net_client_t *client)
+{
+ if (client == NULL)
+ {
+ return;
+ }
+
+ if (client->state == CLIENT_STATE_WAITING_ACK)
+ {
+ // now waiting for the game to start
+
+ client->state = CLIENT_STATE_WAITING_START;
+ }
+}
+
+// Process a packet received by the server
+
+static void NET_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
+
+ client = NULL;
+
+ for (i=0; i<MAXNETNODES; ++i)
+ {
+ if (clients[i].active && client[i].addr == addr)
+ {
+ // found the client
+
+ client = &clients[i];
+ break;
+ }
+ }
+
+ if (!NET_ReadInt16(packet, &packet_type))
+ {
+ // no packet type
+
+ return;
+ }
+
+ switch (packet_type)
+ {
+ case NET_PACKET_TYPE_SYN:
+ NET_ServerParseSYN(packet, client, addr);
+ break;
+ case NET_PACKET_TYPE_ACK:
+ NET_ServerParseACK(packet, client);
+ break;
+ case NET_PACKET_TYPE_GAMESTART:
+ break;
+ case NET_PACKET_TYPE_GAMEDATA:
+ break;
+ default:
+ // unknown packet type
+
+ break;
+ }
+}
+
+// Perform any needed action on a client
+
+void NET_ServerRunClient(net_client_t *client)
+{
+ net_packet_t *packet;
+
+ if (client->state == CLIENT_STATE_WAITING_ACK)
+ {
+ if (client->last_send_time < 0
+ || I_GetTime() - client->last_send_time > 35)
+ {
+ // it has been a second since the last ACK was sent, and
+ // still no reply.
+
+ if (client->num_retries < MAX_RETRIES)
+ {
+ // send another ACK
+
+ packet = NET_NewPacket(10);
+ NET_WriteInt16(packet, NET_PACKET_TYPE_ACK);
+ NET_SendPacket(client->addr, packet);
+ NET_FreePacket(packet);
+ client->last_send_time = I_GetTime();
+
+ ++client->num_retries;
+ }
+ else
+ {
+ // no more retries allowed.
+
+ NET_FreeAddress(client->addr);
+
+ client->active = false;
+ }
+ }
+ }
+}
+
+// Initialise server and wait for connections
+
+void NET_ServerInit(void)
+{
+ int i;
+
+ // initialise send/receive context, with loopback send/recv
+
+ server_context = NET_NewContext();
+ NET_AddModule(server_context, &net_loop_server_module);
+ net_loop_server_module.InitServer();
+
+ // no clients yet
+
+ for (i=0; i<MAXNETNODES; ++i)
+ {
+ clients[i].active = false;
+ }
+
+ server_initialised = true;
+}
+
+// Run server code to check for new packets/send packets as the server
+// requires
+
+void NET_ServerRun(void)
+{
+ net_addr_t *addr;
+ net_packet_t *packet;
+ int i;
+
+ if (!server_initialised)
+ {
+ return;
+ }
+
+ while (NET_RecvPacket(server_context, &addr, &packet))
+ {
+ NET_ServerPacket(packet, addr);
+ }
+
+ // "Run" any clients that may have things to do, independent of responses
+ // to received packets
+
+ for (i=0; i<MAXNETNODES; ++i)
+ {
+ if (clients[i].active)
+ {
+ NET_ServerRunClient(&clients[i]);
+ }
+ }
+}
+