ref: 78206090ebc2a2cbe150e440f6831cae810aa48b
parent: f1f8ecdeeadab2242c80cfa442c44c9d18a6fd6e
parent: 2855c1081facf4812cc74a48c880bc8832b0ede1
author: Simon Howard <[email protected]>
date: Sat Sep 30 22:19:15 EDT 2017
Merge pull request #943 from fragglet/sdl2-branch Introduce a network protocol versioning scheme. This will allow backwards-compatible protocol changes in future, and also allow forks to remain compatible with Chocolate Doom.
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -426,6 +426,41 @@
NET_CL_SendTics(starttic, endtic);
}
+// Parse a SYN packet received back from the server indicating a successful
+// connection attempt.
+static void NET_CL_ParseSYN(net_packet_t *packet)
+{
+ net_protocol_t protocol;
+ char *server_version;
+
+ server_version = NET_ReadSafeString(packet);
+ if (server_version == NULL)
+ {
+ return;
+ }
+
+ protocol = NET_ReadProtocol(packet);
+ if (protocol == NET_PROTOCOL_UNKNOWN)
+ {
+ return;
+ }
+
+ // We are now successfully connected.
+ client_connection.state = NET_CONN_STATE_CONNECTED;
+ client_connection.protocol = protocol;
+
+ // Even though we have negotiated a compatible protocol, the game may still
+ // desync. Chocolate Doom's philosophy makes this unlikely, but if we're
+ // playing with a forked version, or even against a different version that
+ // fixes a compatibility issue, we may still have problems.
+ if (strcmp(server_version, PACKAGE_STRING) != 0)
+ {
+ fprintf(stderr, "NET_CL_ParseSYN: This is '%s', but the server is "
+ "'%s'. It is possible that this mismatch may cause the game "
+ "to desync.\n", PACKAGE_STRING, server_version);
+ }
+}
+
// data received while we are waiting for the game to start
static void NET_CL_ParseWaitingData(net_packet_t *packet)
@@ -795,7 +830,7 @@
{
char *msg;
- msg = NET_ReadString(packet);
+ msg = NET_ReadSafeString(packet);
if (msg == NULL)
{
@@ -802,9 +837,7 @@
return;
}
- printf("Message from server: ");
-
- NET_SafePuts(msg);
+ printf("Message from server:\n%s\n", msg);
}
// parse a received packet
@@ -826,6 +859,10 @@
{
switch (packet_type)
{
+ case NET_PACKET_TYPE_SYN:
+ NET_CL_ParseSYN(packet);
+ break;
+
case NET_PACKET_TYPE_WAITING_DATA:
NET_CL_ParseWaitingData(packet);
break;
@@ -921,6 +958,7 @@
NET_WriteInt16(packet, NET_PACKET_TYPE_SYN);
NET_WriteInt32(packet, NET_MAGIC_NUMBER);
NET_WriteString(packet, PACKAGE_STRING);
+ NET_WriteProtocolList(packet);
NET_WriteConnectData(packet, data);
NET_WriteString(packet, net_player_name);
NET_Conn_SendPacket(&client_connection, packet);
@@ -927,8 +965,7 @@
NET_FreePacket(packet);
}
-// connect to a server
-
+// Connect to a server
boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data)
{
int start_time;
@@ -959,7 +996,7 @@
// Initialize connection
- NET_Conn_InitClient(&client_connection, addr);
+ NET_Conn_InitClient(&client_connection, addr, NET_PROTOCOL_UNKNOWN);
// try to connect
--- a/src/net_common.c
+++ b/src/net_common.c
@@ -19,6 +19,7 @@
#include "doomtype.h"
#include "d_mode.h"
+#include "i_system.h"
#include "i_timer.h"
#include "net_common.h"
@@ -34,9 +35,19 @@
#define KEEPALIVE_PERIOD 1
+// String names for the enum values in net_protocol_t, which are what is
+// sent over the wire. Every enum value must have an entry in this list.
+static struct
+{
+ net_protocol_t protocol;
+ const char *name;
+} protocol_names[] = {
+ {NET_PROTOCOL_CHOCOLATE_DOOM_0, "CHOCOLATE_DOOM_0"},
+};
+
// reliable packet that is guaranteed to reach its destination
-struct net_reliable_packet_s
+struct net_reliable_packet_s
{
net_packet_t *packet;
int last_send_time;
@@ -44,11 +55,13 @@
net_reliable_packet_t *next;
};
-static void NET_Conn_Init(net_connection_t *conn, net_addr_t *addr)
+static void NET_Conn_Init(net_connection_t *conn, net_addr_t *addr,
+ net_protocol_t protocol)
{
conn->last_send_time = -1;
conn->num_retries = 0;
conn->addr = addr;
+ conn->protocol = protocol;
conn->reliable_packets = NULL;
conn->reliable_send_seq = 0;
conn->reliable_recv_seq = 0;
@@ -56,18 +69,20 @@
// Initialize as a client connection
-void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr)
+void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr,
+ net_protocol_t protocol)
{
- NET_Conn_Init(conn, addr);
+ NET_Conn_Init(conn, addr, protocol);
conn->state = NET_CONN_STATE_CONNECTING;
}
// Initialize as a server connection
-void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr)
+void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr,
+ net_protocol_t protocol)
{
- NET_Conn_Init(conn, addr);
- conn->state = NET_CONN_STATE_WAITING_ACK;
+ NET_Conn_Init(conn, addr, protocol);
+ conn->state = NET_CONN_STATE_CONNECTED;
}
// Send a packet to a connection
@@ -80,38 +95,6 @@
NET_SendPacket(conn->addr, packet);
}
-// parse an ACK packet from a client
-
-static void NET_Conn_ParseACK(net_connection_t *conn, net_packet_t *packet)
-{
- net_packet_t *reply;
-
- if (conn->state == NET_CONN_STATE_CONNECTING)
- {
- // We are a client
-
- // received a response from the server to our SYN
-
- conn->state = NET_CONN_STATE_CONNECTED;
-
- // We must send an ACK reply to the server's ACK
-
- reply = NET_NewPacket(10);
- NET_WriteInt16(reply, NET_PACKET_TYPE_ACK);
- NET_Conn_SendPacket(conn, reply);
- NET_FreePacket(reply);
- }
-
- if (conn->state == NET_CONN_STATE_WAITING_ACK)
- {
- // We are a server
-
- // Client is connected
-
- conn->state = NET_CONN_STATE_CONNECTED;
- }
-}
-
static void NET_Conn_ParseDisconnect(net_connection_t *conn, net_packet_t *packet)
{
net_packet_t *reply;
@@ -151,7 +134,7 @@
{
char *msg;
- msg = NET_ReadString(packet);
+ msg = NET_ReadSafeString(packet);
if (msg == NULL)
{
@@ -165,8 +148,7 @@
conn->state = NET_CONN_STATE_DISCONNECTED;
conn->disconnect_reason = NET_DISCONNECT_REMOTE;
- printf("Rejected by server: ");
- NET_SafePuts(msg);
+ printf("Rejected by server: %s\n", msg);
}
}
@@ -282,9 +264,6 @@
switch (*packet_type)
{
- case NET_PACKET_TYPE_ACK:
- NET_Conn_ParseACK(conn, packet);
- break;
case NET_PACKET_TYPE_DISCONNECT:
NET_Conn_ParseDisconnect(conn, packet);
break;
@@ -370,35 +349,6 @@
conn->reliable_packets->last_send_time = nowtime;
}
}
- else if (conn->state == NET_CONN_STATE_WAITING_ACK)
- {
- if (conn->last_send_time < 0
- || nowtime - conn->last_send_time > 1000)
- {
- // it has been a second since the last ACK was sent, and
- // still no reply.
-
- if (conn->num_retries < MAX_RETRIES)
- {
- // send another ACK
-
- packet = NET_NewPacket(10);
- NET_WriteInt16(packet, NET_PACKET_TYPE_ACK);
- NET_Conn_SendPacket(conn, packet);
- NET_FreePacket(packet);
- conn->last_send_time = nowtime;
-
- ++conn->num_retries;
- }
- else
- {
- // no more retries allowed.
-
- conn->state = NET_CONN_STATE_DISCONNECTED;
- conn->disconnect_reason = NET_DISCONNECT_TIMEOUT;
- }
- }
- }
else if (conn->state == NET_CONN_STATE_DISCONNECTING)
{
// Waiting for a reply to our DISCONNECT request.
@@ -530,5 +480,108 @@
return false;
return true;
+}
+
+static net_protocol_t ParseProtocolName(const char *name)
+{
+ int i;
+
+ for (i = 0; i < arrlen(protocol_names); ++i)
+ {
+ if (!strcmp(protocol_names[i].name, name))
+ {
+ return protocol_names[i].protocol;
+ }
+ }
+
+ return NET_PROTOCOL_UNKNOWN;
+}
+
+// NET_ReadProtocol reads a single string-format protocol name from the given
+// packet, returning NET_PROTOCOL_UNKNOWN if the string describes an unknown
+// protocol.
+net_protocol_t NET_ReadProtocol(net_packet_t *packet)
+{
+ const char *name;
+
+ name = NET_ReadString(packet);
+ if (name == NULL)
+ {
+ return NET_PROTOCOL_UNKNOWN;
+ }
+
+ return ParseProtocolName(name);
+}
+
+// NET_WriteProtocol writes a single string-format protocol name to a packet.
+void NET_WriteProtocol(net_packet_t *packet, net_protocol_t protocol)
+{
+ int i;
+
+ for (i = 0; i < arrlen(protocol_names); ++i)
+ {
+ if (protocol_names[i].protocol == protocol)
+ {
+ NET_WriteString(packet, protocol_names[i].name);
+ return;
+ }
+ }
+
+ // If you add an entry to the net_protocol_t enum, a corresponding entry
+ // must be added to the protocol_names list.
+ I_Error("NET_WriteProtocol: protocol %d missing from protocol_names "
+ "list; please add it.", protocol);
+}
+
+// NET_ReadProtocolList reads a list of string-format protocol names from
+// the given packet, returning a single protocol number. The protocol that is
+// returned is the last protocol in the list that is a supported protocol. If
+// no recognized protocols are read, NET_PROTOCOL_UNKNOWN is returned.
+net_protocol_t NET_ReadProtocolList(net_packet_t *packet)
+{
+ net_protocol_t result;
+ unsigned int num_protocols;
+ int i;
+
+ if (!NET_ReadInt8(packet, &num_protocols))
+ {
+ return NET_PROTOCOL_UNKNOWN;
+ }
+
+ result = NET_PROTOCOL_UNKNOWN;
+
+ for (i = 0; i < num_protocols; ++i)
+ {
+ net_protocol_t p;
+ const char *name;
+
+ name = NET_ReadString(packet);
+ if (name == NULL)
+ {
+ return NET_PROTOCOL_UNKNOWN;
+ }
+
+ p = ParseProtocolName(name);
+ if (p != NET_PROTOCOL_UNKNOWN)
+ {
+ result = p;
+ }
+ }
+
+ return result;
+}
+
+// NET_WriteProtocolList writes a list of string-format protocol names into
+// the given packet, all the supported protocols in the net_protocol_t enum.
+void NET_WriteProtocolList(net_packet_t *packet)
+{
+ int i;
+
+ NET_WriteInt8(packet, NET_NUM_PROTOCOLS);
+
+ for (i = 0; i < NET_NUM_PROTOCOLS; ++i)
+ {
+ NET_WriteProtocol(packet, i);
+ }
}
--- a/src/net_common.h
+++ b/src/net_common.h
@@ -21,28 +21,18 @@
#include "net_defs.h"
#include "net_packet.h"
-typedef enum
+typedef enum
{
- // sending syn packets, waiting for an ACK reply
- // (client side)
-
+ // Client has sent a SYN, is waiting for a SYN in response.
NET_CONN_STATE_CONNECTING,
- // received a syn, sent an ack, waiting for an ack reply
- // (server side)
-
- NET_CONN_STATE_WAITING_ACK,
-
- // successfully connected
-
+ // Successfully connected.
NET_CONN_STATE_CONNECTED,
- // sent a DISCONNECT packet, waiting for a DISCONNECT_ACK reply
-
+ // Sent a DISCONNECT packet, waiting for a DISCONNECT_ACK reply
NET_CONN_STATE_DISCONNECTING,
- // client successfully disconnected
-
+ // Client successfully disconnected
NET_CONN_STATE_DISCONNECTED,
// We are disconnected, but in a sleep state, waiting for several
@@ -50,7 +40,6 @@
// to arrive, and we need to send another one. We keep this as
// a valid connection for a few seconds until we are sure that
// the other end has successfully disconnected as well.
-
NET_CONN_STATE_DISCONNECTED_SLEEP,
} net_connstate_t;
@@ -82,6 +71,7 @@
net_connstate_t state;
net_disconnect_reason_t disconnect_reason;
net_addr_t *addr;
+ net_protocol_t protocol;
int last_send_time;
int num_retries;
int keepalive_send_time;
@@ -93,8 +83,10 @@
void NET_Conn_SendPacket(net_connection_t *conn, net_packet_t *packet);
-void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr);
-void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr);
+void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr,
+ net_protocol_t protocol);
+void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr,
+ net_protocol_t protocol);
boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet,
unsigned int *packet_type);
void NET_Conn_Disconnect(net_connection_t *conn);
@@ -101,10 +93,15 @@
void NET_Conn_Run(net_connection_t *conn);
net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type);
-// Other miscellaneous common functions
+// Protocol list exchange.
+net_protocol_t NET_ReadProtocol(net_packet_t *packet);
+void NET_WriteProtocol(net_packet_t *packet, net_protocol_t protocol);
+net_protocol_t NET_ReadProtocolList(net_packet_t *packet);
+void NET_WriteProtocolList(net_packet_t *packet);
+// Other miscellaneous common functions
unsigned int NET_ExpandTicNum(unsigned int relative, unsigned int b);
-boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
+boolean NET_ValidGameSettings(GameMode_t mode, GameMission_t mission,
net_gamesettings_t *settings);
#endif /* #ifndef NET_COMMON_H */
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -98,20 +98,43 @@
void *handle;
};
-// magic number sent when connecting to check this is a valid client
+// Magic number sent when connecting to check this is a valid client
+#define NET_MAGIC_NUMBER 1454104972U
-#define NET_MAGIC_NUMBER 3436803284U
+// Old magic number used by Chocolate Doom versions before v3.0:
+#define NET_OLD_MAGIC_NUMBER 3436803284U
// header field value indicating that the packet is a reliable packet
#define NET_RELIABLE_PACKET (1 << 15)
+// Supported protocols. If you're developing a fork of Chocolate
+// Doom, you can add your own entry to this list while maintaining
+// compatibility with Chocolate Doom servers. Higher-numbered enum values
+// will be preferred when negotiating a protocol for the client and server
+// to use, so the order matters.
+// NOTE: The values in this enum do not have any special value outside of
+// the program they're compiled in. What matters is the string representation.
+typedef enum
+{
+ // Protocol introduced with Chocolate Doom v3.0. Each compatibility-
+ // breaking change to the network protocol will produce a new protocol
+ // number in this enum.
+ NET_PROTOCOL_CHOCOLATE_DOOM_0,
+
+ // Add your own protocol here; be sure to add a name for it to the list
+ // in net_common.c too.
+
+ NET_NUM_PROTOCOLS,
+ NET_PROTOCOL_UNKNOWN,
+} net_protocol_t;
+
// packet types
typedef enum
{
NET_PACKET_TYPE_SYN,
- NET_PACKET_TYPE_ACK,
+ NET_PACKET_TYPE_ACK, // deprecated
NET_PACKET_TYPE_REJECTED,
NET_PACKET_TYPE_KEEPALIVE,
NET_PACKET_TYPE_WAITING_DATA,
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -15,6 +15,7 @@
// Network packet manipulation (net_packet_t)
//
+#include <ctype.h>
#include <string.h>
#include "m_misc.h"
#include "net_packet.h"
@@ -202,6 +203,37 @@
return start;
}
+// Read a string from the packet, but (potentially) modify it to strip
+// out any unprintable characters which could be malicious control codes.
+// Note that this may modify the original packet contents.
+char *NET_ReadSafeString(net_packet_t *packet)
+{
+ char *r, *w, *result;
+
+ result = NET_ReadString(packet);
+ if (result == NULL)
+ {
+ return NULL;
+ }
+
+ // w is always <= r, so we never produce a longer string than the original.
+ w = result;
+ for (r = result; *r != '\0'; ++r)
+ {
+ // TODO: This is a very naive way of producing a safe string; only
+ // ASCII characters are allowed. Probably this should really support
+ // UTF-8 characters as well.
+ if (isprint(*r) || *r == '\n')
+ {
+ *w = *r;
+ ++w;
+ }
+ }
+ *w = '\0';
+
+ return result;
+}
+
// Dynamically increases the size of a packet
static void NET_IncreasePacket(net_packet_t *packet)
@@ -270,7 +302,7 @@
packet->len += 4;
}
-void NET_WriteString(net_packet_t *packet, char *string)
+void NET_WriteString(net_packet_t *packet, const char *string)
{
byte *p;
size_t string_size;
--- a/src/net_packet.h
+++ b/src/net_packet.h
@@ -33,12 +33,13 @@
boolean NET_ReadSInt32(net_packet_t *packet, signed int *data);
char *NET_ReadString(net_packet_t *packet);
+char *NET_ReadSafeString(net_packet_t *packet);
void NET_WriteInt8(net_packet_t *packet, unsigned int i);
void NET_WriteInt16(net_packet_t *packet, unsigned int i);
void NET_WriteInt32(net_packet_t *packet, unsigned int i);
-void NET_WriteString(net_packet_t *packet, char *string);
+void NET_WriteString(net_packet_t *packet, const char *string);
#endif /* #ifndef NET_PACKET_H */
--- a/src/net_query.c
+++ b/src/net_query.c
@@ -738,7 +738,7 @@
printf("(game running) ");
}
- NET_SafePuts(data->description);
+ printf("%s\n", data->description);
}
void NET_LANQuery(void)
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -213,7 +213,7 @@
va_start(args, s);
M_vsnprintf(buf, sizeof(buf), s, args);
va_end(args);
-
+
for (i=0; i<MAXNETNODES; ++i)
{
if (ClientConnected(&clients[i]))
@@ -222,7 +222,7 @@
}
}
- NET_SafePuts(buf);
+ printf("%s\n", buf);
}
@@ -555,16 +555,14 @@
NET_FreePacket(packet);
}
-static void NET_SV_InitNewClient(net_client_t *client,
- net_addr_t *addr,
- char *player_name)
+static void NET_SV_InitNewClient(net_client_t *client, net_addr_t *addr,
+ net_protocol_t protocol)
{
client->active = true;
client->connect_time = I_GetTimeMS();
- NET_Conn_InitServer(&client->connection, addr);
+ NET_Conn_InitServer(&client->connection, addr, protocol);
client->addr = addr;
client->last_send_time = -1;
- client->name = M_StringDuplicate(player_name);
// init the ticcmd send queue
@@ -580,99 +578,121 @@
// parse a SYN from a client(initiating a connection)
-static void NET_SV_ParseSYN(net_packet_t *packet,
- net_client_t *client,
+static void NET_SV_ParseSYN(net_packet_t *packet, net_client_t *client,
net_addr_t *addr)
{
unsigned int magic;
net_connect_data_t data;
+ net_packet_t *reply;
+ net_protocol_t protocol;
char *player_name;
char *client_version;
+ int num_players;
int i;
- // read the magic number
-
+ // Read the magic number and check it is the expected one.
if (!NET_ReadInt32(packet, &magic))
{
return;
}
- if (magic != NET_MAGIC_NUMBER)
+ switch (magic)
{
- // invalid magic number
+ case NET_MAGIC_NUMBER:
+ break;
- return;
+ case NET_OLD_MAGIC_NUMBER:
+ NET_SV_SendReject(addr,
+ "You are using an old client version that is not supported by "
+ "this server. This server is running " PACKAGE_STRING ".");
+ return;
+
+ default:
+ return;
}
- // Check the client version is the same as the server
-
+ // Read the client version string. We actually now only use this when
+ // sending a reject message, as we only reject if we can't negotiate a
+ // common protocol (below).
client_version = NET_ReadString(packet);
-
if (client_version == NULL)
{
return;
}
- if (strcmp(client_version, PACKAGE_STRING) != 0)
+ // Read the client's list of accepted protocols. Net play between forks
+ // of Chocolate Doom is accepted provided that they can negotiate a
+ // common accepted protocol.
+ protocol = NET_ReadProtocolList(packet);
+ if (protocol == NET_PROTOCOL_UNKNOWN)
{
- //!
- // @category net
- //
- // When running a netgame server, ignore version mismatches between
- // the server and the client. Using this option may cause game
- // desyncs to occur, or differences in protocol may mean the netgame
- // will simply not function at all.
- //
+ char reject_msg[256];
- if (M_CheckParm("-ignoreversion") == 0)
- {
- NET_SV_SendReject(addr,
- "Different " PACKAGE_NAME " versions cannot play a net game!\n"
- "Version mismatch: server version is: " PACKAGE_STRING);
- return;
- }
+ M_snprintf(reject_msg, sizeof(reject_msg),
+ "Version mismatch: server version is: " PACKAGE_STRING "; "
+ "client is: %s. No common compatible protocol could be "
+ "negotiated.", client_version);
+ NET_SV_SendReject(addr, reject_msg);
+ return;
}
- // read the game mode and mission
-
- if (!NET_ReadConnectData(packet, &data))
+ // Read connect data, and check that the game mode/mission are valid
+ // and the max_players value is in a sensible range.
+ if (!NET_ReadConnectData(packet, &data)
+ || !D_ValidGameMode(data.gamemission, data.gamemode)
+ || data.max_players > NET_MAXPLAYERS)
{
return;
}
- if (!D_ValidGameMode(data.gamemission, data.gamemode))
+ // Read the player's name
+ player_name = NET_ReadString(packet);
+ if (player_name == NULL)
{
return;
}
- // Check max_players value. This must be in a sensible range.
+ // At this point we have received a valid SYN.
- if (data.max_players > NET_MAXPLAYERS)
+ // Not accepting new connections?
+ if (server_state != SERVER_WAITING_LAUNCH)
{
+ NET_SV_SendReject(addr,
+ "Server is not currently accepting connections");
return;
}
- // read the player's name
+ // Before accepting a new client, check that there is a slot free.
+ NET_SV_AssignPlayers();
+ num_players = NET_SV_NumPlayers();
- player_name = NET_ReadString(packet);
-
- if (player_name == NULL)
+ if ((!data.drone && num_players >= NET_SV_MaxPlayers())
+ || NET_SV_NumClients() >= MAXNETNODES)
{
+ NET_SV_SendReject(addr, "Server is full!");
return;
}
- // received a valid SYN
+ // TODO: Add server option to allow rejecting clients which set
+ // lowres_turn. This is potentially desirable as the presence of such
+ // clients affects turning resolution.
- // not accepting new connections?
+ // Adopt the game mode and mission of the first connecting client:
+ if (num_players == 0 && !data.drone)
+ {
+ sv_gamemode = data.gamemode;
+ sv_gamemission = data.gamemission;
+ }
- if (server_state != SERVER_WAITING_LAUNCH)
+ // Check the connecting client is playing the same game as all
+ // the other clients
+ if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission)
{
- NET_SV_SendReject(addr, "Server is not currently accepting connections");
+ NET_SV_SendReject(addr, "You are playing the wrong game!");
return;
}
- // allocate a client slot if there isn't one already
-
+ // Allocate a client slot if there isn't one already
if (client == NULL)
{
// find a slot, or return if none found
@@ -702,67 +722,30 @@
}
}
- // New client?
-
- if (!client->active)
+ // Client already connected?
+ if (client->active)
{
- int num_players;
+ return;
+ }
- // Before accepting a new client, check that there is a slot
- // free
+ // Activate, initialize connection
+ NET_SV_InitNewClient(client, addr, protocol);
- NET_SV_AssignPlayers();
- num_players = NET_SV_NumPlayers();
+ // Save the SHA1 checksums and other details.
+ memcpy(client->wad_sha1sum, data.wad_sha1sum, sizeof(sha1_digest_t));
+ memcpy(client->deh_sha1sum, data.deh_sha1sum, sizeof(sha1_digest_t));
+ client->is_freedoom = data.is_freedoom;
+ client->max_players = data.max_players;
+ client->name = M_StringDuplicate(player_name);
+ client->recording_lowres = data.lowres_turn;
+ client->drone = data.drone;
+ client->player_class = data.player_class;
- if ((!data.drone && num_players >= NET_SV_MaxPlayers())
- || NET_SV_NumClients() >= MAXNETNODES)
- {
- NET_SV_SendReject(addr, "Server is full!");
- return;
- }
-
- // TODO: Add server option to allow rejecting clients which
- // set lowres_turn. This is potentially desirable as the
- // presence of such clients affects turning resolution.
-
- // Adopt the game mode and mission of the first connecting client
-
- if (num_players == 0 && !data.drone)
- {
- sv_gamemode = data.gamemode;
- sv_gamemission = data.gamemission;
- }
-
- // Save the SHA1 checksums
-
- memcpy(client->wad_sha1sum, data.wad_sha1sum, sizeof(sha1_digest_t));
- memcpy(client->deh_sha1sum, data.deh_sha1sum, sizeof(sha1_digest_t));
- client->is_freedoom = data.is_freedoom;
- client->max_players = data.max_players;
-
- // Check the connecting client is playing the same game as all
- // the other clients
-
- if (data.gamemode != sv_gamemode || data.gamemission != sv_gamemission)
- {
- NET_SV_SendReject(addr, "You are playing the wrong game!");
- return;
- }
-
- // Activate, initialize connection
-
- NET_SV_InitNewClient(client, addr, player_name);
-
- client->recording_lowres = data.lowres_turn;
- client->drone = data.drone;
- client->player_class = data.player_class;
- }
-
- if (client->connection.state == NET_CONN_STATE_WAITING_ACK)
- {
- // force an acknowledgement
- client->connection.last_send_time = -1;
- }
+ // Send a reply back to the client, indicating a successful connection
+ // and specifying the protocol that will be used for communications.
+ reply = NET_Conn_NewReliable(&client->connection, NET_PACKET_TYPE_SYN);
+ NET_WriteString(reply, PACKAGE_STRING);
+ NET_WriteProtocol(reply, protocol);
}
// Parse a launch packet. This is sent by the key player when the "start"
--- a/src/net_structrw.c
+++ b/src/net_structrw.c
@@ -17,7 +17,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include "doomtype.h"
#include "m_misc.h"
@@ -122,7 +121,7 @@
{
boolean result;
- query->version = NET_ReadString(packet);
+ query->version = NET_ReadSafeString(packet);
result = query->version != NULL
&& NET_ReadInt8(packet, (unsigned int *) &query->server_state)
@@ -133,7 +132,7 @@
if (result)
{
- query->description = NET_ReadString(packet);
+ query->description = NET_ReadSafeString(packet);
return query->description != NULL;
}
@@ -551,22 +550,3 @@
NET_WriteBlob(packet, seed, sizeof(prng_seed_t));
}
-// "Safe" version of puts, for displaying messages received from the
-// network.
-
-void NET_SafePuts(char *s)
-{
- char *p;
-
- // Do not do a straight "puts" of the string, as this could be
- // dangerous (sending control codes to terminals can do all
- // kinds of things)
-
- for (p=s; *p; ++p)
- {
- if (isprint(*p) || *p == '\n')
- putchar(*p);
- }
-
- putchar('\n');
-}
--- a/src/net_structrw.h
+++ b/src/net_structrw.h
@@ -43,8 +43,6 @@
void NET_WriteWaitData(net_packet_t *packet, net_waitdata_t *data);
boolean NET_ReadWaitData(net_packet_t *packet, net_waitdata_t *data);
-void NET_SafePuts(char *msg);
-
boolean NET_ReadPRNGSeed(net_packet_t *packet, prng_seed_t seed);
void NET_WritePRNGSeed(net_packet_t *packet, prng_seed_t seed);