diff options
-rw-r--r-- | src/net_client.c | 7 | ||||
-rw-r--r-- | src/net_common.c | 195 | ||||
-rw-r--r-- | src/net_common.h | 14 | ||||
-rw-r--r-- | src/net_defs.h | 10 | ||||
-rw-r--r-- | src/net_server.c | 7 |
5 files changed, 217 insertions, 16 deletions
diff --git a/src/net_client.c b/src/net_client.c index eae95cc9..6ff437cb 100644 --- a/src/net_client.c +++ b/src/net_client.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_client.c 278 2006-01-09 02:03:39Z fraggle $ +// $Id: net_client.c 279 2006-01-10 19:59:26Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,9 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.16 2006/01/10 19:59:25 fraggle +// Reliable packet transport mechanism +// // Revision 1.15 2006/01/09 02:03:39 fraggle // Send clients their player number, and indicate on the waiting screen // which client we are. @@ -219,7 +222,7 @@ static void NET_CL_ParsePacket(net_packet_t *packet) return; } - if (NET_Conn_Packet(&client_connection, packet, packet_type)) + if (NET_Conn_Packet(&client_connection, packet, &packet_type)) { // Packet eaten by the common connection code } diff --git a/src/net_common.c b/src/net_common.c index a89b1bba..92c050e1 100644 --- a/src/net_common.c +++ b/src/net_common.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_common.c 268 2006-01-08 04:52:26Z fraggle $ +// $Id: net_common.c 279 2006-01-10 19:59:26Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,9 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.4 2006/01/10 19:59:26 fraggle +// Reliable packet transport mechanism +// // Revision 1.3 2006/01/08 04:52:26 fraggle // Allow the server to reject clients // @@ -36,6 +39,8 @@ // Common code shared between the client and server // +#include <stdlib.h> + #include "doomdef.h" #include "i_system.h" @@ -51,24 +56,40 @@ #define KEEPALIVE_PERIOD 1 -// Initialise as a client connection +// reliable packet that is guaranteed to reach its destination -void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr) +struct net_reliable_packet_s +{ + net_packet_t *packet; + int last_send_time; + int seq; + net_reliable_packet_t *next; +}; + +static void NET_Conn_Init(net_connection_t *conn, net_addr_t *addr) { - conn->state = NET_CONN_STATE_CONNECTING; conn->last_send_time = -1; conn->num_retries = 0; conn->addr = addr; + conn->reliable_packets = NULL; + conn->reliable_send_seq = 0; + conn->reliable_recv_seq = 0; +} + +// Initialise as a client connection + +void NET_Conn_InitClient(net_connection_t *conn, net_addr_t *addr) +{ + NET_Conn_Init(conn, addr); + conn->state = NET_CONN_STATE_CONNECTING; } // Initialise as a server connection void NET_Conn_InitServer(net_connection_t *conn, net_addr_t *addr) { + NET_Conn_Init(conn, addr); conn->state = NET_CONN_STATE_WAITING_ACK; - conn->last_send_time = -1; - conn->num_retries = 0; - conn->addr = addr; } // Send a packet to a connection @@ -158,16 +179,117 @@ static void NET_Conn_ParseReject(net_connection_t *conn, net_packet_t *packet) } } +static void NET_Conn_ParseReliableACK(net_connection_t *conn, net_packet_t *packet) +{ + unsigned int seq; + + if (!NET_ReadInt8(packet, &seq)) + { + return; + } + + if (conn->reliable_packets == NULL) + { + return; + } + + // Is this an acknowledgement for the first packet in the list? + + if (seq == ((conn->reliable_packets->seq + 1) & 0xff)) + { + net_reliable_packet_t *rp; + + // Discard it, then. + // Unlink from the list. + + rp = conn->reliable_packets; + conn->reliable_packets = rp->next; + + NET_FreePacket(rp->packet); + free(rp); + } +} + +// Process the header of a reliable packet +// +// Returns true if the packet should be discarded (incorrect sequence) + +static boolean NET_Conn_ReliablePacket(net_connection_t *conn, + net_packet_t *packet) +{ + unsigned int seq; + net_packet_t *reply; + boolean result; + + // Read the sequence number + + if (!NET_ReadInt8(packet, &seq)) + { + return true; + } + + if (seq != (conn->reliable_recv_seq & 0xff)) + { + // This is not the next expected packet in the sequence! + // + // Discard the packet. If we were smart, we would use a proper + // sliding window protocol to do this, but I'm lazy. + + result = true; + } + else + { + // Now we can receive the next packet in the sequence. + + conn->reliable_recv_seq = (conn->reliable_recv_seq + 1) & 0xff; + + result = false; + } + + // Send an acknowledgement + + // Note: this is braindead. It would be much more sensible to + // include this in the next packet, rather than the overhead of + // sending a complete packet just for one byte of information. + + reply = NET_NewPacket(10); + + NET_WriteInt16(reply, NET_PACKET_TYPE_RELIABLE_ACK); + NET_WriteInt8(reply, conn->reliable_recv_seq & 0xff); + + NET_Conn_SendPacket(conn, reply); + + NET_FreePacket(reply); + + return result; +} + // Process a packet received by the server // // Returns true if eaten by common code boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, - int packet_type) + unsigned int *packet_type) { conn->keepalive_recv_time = I_GetTimeMS(); + + // Is this a reliable packet? + + if (*packet_type & NET_RELIABLE_PACKET) + { + if (NET_Conn_ReliablePacket(conn, packet)) + { + // Invalid packet: eat it. + + return true; + } + + // Remove the reliable bit + + *packet_type &= ~NET_RELIABLE_PACKET; + } - switch (packet_type) + switch (*packet_type) { case NET_PACKET_TYPE_ACK: NET_Conn_ParseACK(conn, packet); @@ -184,6 +306,9 @@ boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, case NET_PACKET_TYPE_REJECTED: NET_Conn_ParseReject(conn, packet); break; + case NET_PACKET_TYPE_RELIABLE_ACK: + NET_Conn_ParseReliableACK(conn, packet); + break; default: // Not a common packet @@ -236,6 +361,21 @@ void NET_Conn_Run(net_connection_t *conn) NET_Conn_SendPacket(conn, packet); NET_FreePacket(packet); } + + // Check the reliable packet list. Has the first packet in the + // list timed out? + // + // NB. This is braindead, we have a fixed time of one second. + + if (conn->reliable_packets != NULL + && (conn->reliable_packets->last_send_time < 0 + || nowtime - conn->reliable_packets->last_send_time > 1000)) + { + // Packet timed out, time to resend + + NET_Conn_SendPacket(conn, conn->reliable_packets->packet); + conn->reliable_packets->last_send_time = nowtime; + } } else if (conn->state == NET_CONN_STATE_WAITING_ACK) { @@ -310,5 +450,42 @@ void NET_Conn_Run(net_connection_t *conn) } } +net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type) +{ + net_packet_t *packet; + net_reliable_packet_t *rp; + net_reliable_packet_t **listend; + + // Generate a packet with the right header + + packet = NET_NewPacket(100); + NET_WriteInt16(packet, packet_type | NET_RELIABLE_PACKET); + + // write the low byte of the send sequence number + + NET_WriteInt8(packet, conn->reliable_send_seq & 0xff); + + // Add to the list of reliable packets + + rp = malloc(sizeof(net_reliable_packet_t)); + rp->packet = packet; + rp->next = NULL; + rp->seq = conn->reliable_send_seq; + rp->last_send_time = -1; + + for (listend = &conn->reliable_packets; + *listend != NULL; + listend = &((*listend)->next)); + + *listend = rp; + + // Count along the sequence + + conn->reliable_send_seq = (conn->reliable_send_seq + 1) & 0xff; + + // Finished + + return packet; +} diff --git a/src/net_common.h b/src/net_common.h index 530a0e0d..4f5605dc 100644 --- a/src/net_common.h +++ b/src/net_common.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_common.h 264 2006-01-08 02:53:05Z fraggle $ +// $Id: net_common.h 279 2006-01-10 19:59:26Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,9 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.3 2006/01/10 19:59:26 fraggle +// Reliable packet transport mechanism +// // Revision 1.2 2006/01/08 02:53:05 fraggle // Send keepalives if the connection is not doing anything else. // Send all packets using a new NET_Conn_SendPacket to support this. @@ -37,6 +40,7 @@ #define NET_COMMON_H #include "net_defs.h" +#include "net_packet.h" typedef enum { @@ -74,6 +78,8 @@ typedef enum #define MAX_RETRIES 5 +typedef struct net_reliable_packet_s net_reliable_packet_t; + typedef struct { net_connstate_t state; @@ -82,6 +88,9 @@ typedef struct int num_retries; int keepalive_send_time; int keepalive_recv_time; + net_reliable_packet_t *reliable_packets; + int reliable_send_seq; + int reliable_recv_seq; } net_connection_t; @@ -89,9 +98,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); boolean NET_Conn_Packet(net_connection_t *conn, net_packet_t *packet, - int packet_type); + unsigned int *packet_type); void NET_Conn_Disconnect(net_connection_t *conn); void NET_Conn_Run(net_connection_t *conn); +net_packet_t *NET_Conn_NewReliable(net_connection_t *conn, int packet_type); #endif /* #ifndef NET_COMMON_H */ diff --git a/src/net_defs.h b/src/net_defs.h index ccaa3a08..6a8e20cb 100644 --- a/src/net_defs.h +++ b/src/net_defs.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_defs.h 268 2006-01-08 04:52:26Z fraggle $ +// $Id: net_defs.h 279 2006-01-10 19:59:26Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,9 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.7 2006/01/10 19:59:26 fraggle +// Reliable packet transport mechanism +// // Revision 1.6 2006/01/08 04:52:26 fraggle // Allow the server to reject clients // @@ -112,6 +115,10 @@ struct _net_addr_s #define NET_MAGIC_NUMBER 3436803284U +// header field value indicating that the packet is a reliable packet + +#define NET_RELIABLE_PACKET (1 << 15) + // packet types typedef enum @@ -125,6 +132,7 @@ typedef enum NET_PACKET_TYPE_GAMEDATA, NET_PACKET_TYPE_DISCONNECT, NET_PACKET_TYPE_DISCONNECT_ACK, + NET_PACKET_TYPE_RELIABLE_ACK, } net_packet_type_t; typedef struct diff --git a/src/net_server.c b/src/net_server.c index 4ed2e2b3..0fb058a0 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_server.c 278 2006-01-09 02:03:39Z fraggle $ +// $Id: net_server.c 279 2006-01-10 19:59:26Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,9 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.19 2006/01/10 19:59:26 fraggle +// Reliable packet transport mechanism +// // Revision 1.18 2006/01/09 02:03:39 fraggle // Send clients their player number, and indicate on the waiting screen // which client we are. @@ -408,7 +411,7 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) { // Must come from a valid client; ignore otherwise } - else if (NET_Conn_Packet(&client->connection, packet, packet_type)) + else if (NET_Conn_Packet(&client->connection, packet, &packet_type)) { // Packet was eaten by the common connection code } |