From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Sat, 21 Feb 2004 11:58:08 +0000 (+0000)
Subject: rate limited networking ("rate" command in client console, limited by sv_maxrate... 
X-Git-Tag: xonotic-v0.1.0preview~6079
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=8ee2396ccf926ee8221f533dd930e016d41c0755;p=xonotic%2Fdarkplaces.git

rate limited networking ("rate" command in client console, limited by sv_maxrate cvar on server), also cleaned up some of the MAX_DATAGRAM and similar defines (now only uses NET_MAXMESSAGE)


git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3916 d7cf8633-e32d-0410-b094-e92efae38249
---

diff --git a/cl_demo.c b/cl_demo.c
index 546ce450..78f14fe2 100644
--- a/cl_demo.c
+++ b/cl_demo.c
@@ -168,6 +168,8 @@ void CL_ReadDemoMessage(void)
 		// get the next message
 		FS_Read(cls.demofile, &net_message.cursize, 4);
 		net_message.cursize = LittleLong(net_message.cursize);
+		if (net_message.cursize > net_message.maxsize)
+			Host_Error("Demo message (%i) > net_message.maxsize (%i)", net_message.cursize, net_message.maxsize);
 		VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
 		for (i = 0;i < 3;i++)
 		{
@@ -175,8 +177,6 @@ void CL_ReadDemoMessage(void)
 			cl.mviewangles[0][i] = LittleFloat(f);
 		}
 
-		if (net_message.cursize > NET_MAXMESSAGE)
-			Host_Error("Demo message > NET_MAXMESSAGE");
 		if (FS_Read(cls.demofile, net_message.data, net_message.cursize) == (size_t)net_message.cursize)
 		{
 			MSG_BeginReading();
diff --git a/cl_parse.c b/cl_parse.c
index 43cb2c28..0a1d5ede 100644
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -290,6 +290,9 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
 			MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
 		}
 
+		MSG_WriteByte (&cls.message, clc_stringcmd);
+		MSG_WriteString (&cls.message, va("rate %i\n", cl_rate.integer));
+
 		MSG_WriteByte (&cls.message, clc_stringcmd);
 		MSG_WriteString (&cls.message, "spawn");
 		break;
diff --git a/client.h b/client.h
index 692b0e50..d7b281b0 100644
--- a/client.h
+++ b/client.h
@@ -454,6 +454,7 @@ extern mempool_t *cl_scores_mempool;
 //
 extern cvar_t cl_name;
 extern cvar_t cl_color;
+extern cvar_t cl_rate;
 extern cvar_t cl_pmodel;
 
 extern cvar_t cl_upspeed;
diff --git a/host_cmd.c b/host_cmd.c
index 668d30bc..3e74ef72 100644
--- a/host_cmd.c
+++ b/host_cmd.c
@@ -930,6 +930,37 @@ void Host_Color_f(void)
 	}
 }
 
+cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000"};
+cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
+void Host_Rate_f(void)
+{
+	int rate, maxrate;
+
+	if (Cmd_Argc() != 2)
+	{
+		Con_Printf ("\"rate\" is \"%i\"\n", cl_rate.integer);
+		Con_Printf ("rate <500-25000>\n");
+		return;
+	}
+
+	rate = atoi(Cmd_Argv(1));
+
+	if (cmd_source == src_command)
+	{
+		Cvar_SetValue ("_cl_rate", bound(NET_MINRATE, rate, NET_MAXRATE));
+		if (cls.state == ca_connected)
+			Cmd_ForwardToServer ();
+		return;
+	}
+
+	maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
+	if (sv_maxrate.integer != maxrate)
+		Cvar_SetValueQuick(&sv_maxrate, maxrate);
+
+	if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
+		host_client->netconnection->rate = bound(NET_MINRATE, rate, maxrate);
+}
+
 /*
 ==================
 Host_Kill_f
@@ -1730,6 +1761,9 @@ void Host_InitCommands (void)
 	Cmd_AddCommand ("name", Host_Name_f);
 	Cvar_RegisterVariable (&cl_color);
 	Cmd_AddCommand ("color", Host_Color_f);
+	Cvar_RegisterVariable (&cl_rate);
+	Cmd_AddCommand ("rate", Host_Rate_f);
+	Cvar_RegisterVariable (&sv_maxrate);
 	if (gamemode == GAME_NEHAHRA)
 	{
 		Cvar_RegisterVariable (&cl_pmodel);
diff --git a/netconn.c b/netconn.c
index c573bd64..a9c1963d 100755
--- a/netconn.c
+++ b/netconn.c
@@ -78,8 +78,8 @@ int serverreplycount = 0;
 int hostCacheCount = 0;
 hostcache_t hostcache[HOSTCACHESIZE];
 
-static qbyte sendbuffer[NET_MAXMESSAGE];
-static qbyte readbuffer[NET_MAXMESSAGE];
+static qbyte sendbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
+static qbyte readbuffer[NET_HEADERSIZE+NET_MAXMESSAGE];
 
 int cl_numsockets;
 lhnetsocket_t *cl_sockets[16];
@@ -163,8 +163,8 @@ int NetConn_SendReliableMessage(netconn_t *conn, sizebuf_t *data)
 	if (data->cursize == 0)
 		Sys_Error("Datagram_SendMessage: zero length message\n");
 
-	if (data->cursize > NET_MAXMESSAGE)
-		Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize);
+	if (data->cursize > (int)sizeof(conn->sendMessage))
+		Sys_Error("Datagram_SendMessage: message too big (%u > %u)\n", data->cursize, sizeof(conn->sendMessage));
 
 	if (conn->canSend == false)
 		Sys_Error("SendMessage: called with canSend == false\n");
@@ -189,7 +189,7 @@ int NetConn_SendReliableMessage(netconn_t *conn, sizebuf_t *data)
 	header = (void *)sendbuffer;
 	header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
 	header[1] = BigLong(conn->sendSequence);
-	memcpy(sendbuffer + 8, conn->sendMessage, dataLen);
+	memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
 
 	conn->sendSequence++;
 	conn->canSend = false;
@@ -228,7 +228,7 @@ static void NetConn_SendMessageNext(netconn_t *conn)
 		header = (void *)sendbuffer;
 		header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
 		header[1] = BigLong(conn->sendSequence);
-		memcpy(sendbuffer + 8, conn->sendMessage, dataLen);
+		memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
 
 		conn->sendSequence++;
 		conn->sendNext = false;
@@ -266,7 +266,7 @@ static void NetConn_ReSendMessage(netconn_t *conn)
 		header = (void *)sendbuffer;
 		header[0] = BigLong(packetLen | (NETFLAG_DATA | eom));
 		header[1] = BigLong(conn->sendSequence - 1);
-		memcpy(sendbuffer + 8, conn->sendMessage, dataLen);
+		memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen);
 
 		conn->sendNext = false;
 
@@ -288,20 +288,20 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data)
 	int packetLen;
 	int *header;
 
-#ifdef DEBUG
+	packetLen = NET_HEADERSIZE + data->cursize;
+
+//#ifdef DEBUG
 	if (data->cursize == 0)
 		Sys_Error("Datagram_SendUnreliableMessage: zero length message\n");
 
-	if (data->cursize > MAX_DATAGRAM)
+	if (packetLen > (int)sizeof(sendbuffer))
 		Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize);
-#endif
-
-	packetLen = NET_HEADERSIZE + data->cursize;
+//#endif
 
 	header = (void *)sendbuffer;
 	header[0] = BigLong(packetLen | NETFLAG_UNRELIABLE);
 	header[1] = BigLong(conn->unreliableSendSequence);
-	memcpy(sendbuffer + 8, data->data, data->cursize);
+	memcpy(sendbuffer + NET_HEADERSIZE, data->data, data->cursize);
 
 	conn->unreliableSendSequence++;
 
@@ -431,6 +431,11 @@ netconn_t *NetConn_Open(lhnetsocket_t *mysocket, lhnetaddress_t *peeraddress)
 	conn = Mem_Alloc(netconn_mempool, sizeof(*conn));
 	conn->mysocket = mysocket;
 	conn->peeraddress = *peeraddress;
+	// updated by receiving "rate" command from client
+	conn->rate = NET_MINRATE;
+	// no limits for local player
+	if (LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP)
+		conn->rate = 1000000000;
 	conn->canSend = true;
 	conn->connecttime = realtime;
 	conn->lastMessageTime = realtime;
diff --git a/netconn.h b/netconn.h
index cc991276..a2ab98f0 100755
--- a/netconn.h
+++ b/netconn.h
@@ -24,11 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "lhnet.h"
 
-#define NET_NAMELEN			128
-
-#define NET_MAXMESSAGE		65536
 #define NET_HEADERSIZE		(2 * sizeof(unsigned int))
-#define NET_DATAGRAMSIZE	(MAX_DATAGRAM + NET_HEADERSIZE)
 
 // NetHeader flags
 #define NETFLAG_LENGTH_MASK	0x0000ffff
@@ -120,6 +116,9 @@ typedef struct netconn_s
 
 	lhnetsocket_t *mysocket;
 	lhnetaddress_t peeraddress;
+	
+	// requested rate in bytes per second
+	int rate;
 
 	// this is mostly identical to qsocket_t from quake
 
@@ -143,7 +142,7 @@ typedef struct netconn_s
 	int receiveMessageLength;
 	qbyte receiveMessage[NET_MAXMESSAGE];
 
-	char address[NET_NAMELEN];
+	char address[128];
 } netconn_t;
 
 extern netconn_t *netconn_list;
diff --git a/quakedef.h b/quakedef.h
index 14b431e7..107a9917 100644
--- a/quakedef.h
+++ b/quakedef.h
@@ -46,9 +46,9 @@ extern char *buildstring;
 #define	ON_EPSILON		0.1			// point on plane side epsilon
 
 #define MAX_PACKETFRAGMENT 1024		// max length of packet fragment
-// LordHavoc: this was 1024, now 65536
-#define	MAX_DATAGRAM	65536		// max length of unreliable
-#define	MAX_NETRELIABLE	65536		// max length of reliable message (fragments into unreliable packets)
+#define NET_MAXMESSAGE	65536
+#define NET_MINRATE		500 // limits "rate" and "sv_maxrate" cvars
+#define NET_MAXRATE		25000 // limits "rate" and "sv_maxrate" cvars
 
 //
 // per-level limits
diff --git a/server.h b/server.h
index de23230a..90c42bbc 100644
--- a/server.h
+++ b/server.h
@@ -84,15 +84,15 @@ typedef struct
 	server_state_t state;
 
 	sizebuf_t datagram;
-	qbyte datagram_buf[MAX_DATAGRAM];
+	qbyte datagram_buf[NET_MAXMESSAGE];
 
 	// copied to all clients at end of frame
 	sizebuf_t reliable_datagram;
-	qbyte reliable_datagram_buf[MAX_DATAGRAM];
+	qbyte reliable_datagram_buf[NET_MAXMESSAGE];
 
 	sizebuf_t signon;
-	// LordHavoc: increased signon message buffer from 8192 to 32768
-	qbyte signon_buf[32768];
+	// LordHavoc: increased signon message buffer from 8192
+	qbyte signon_buf[NET_MAXMESSAGE];
 } server_t;
 
 
@@ -127,7 +127,7 @@ typedef struct client_s
 
 	// can be added to at any time, copied and clear once per frame
 	sizebuf_t message;
-	qbyte msgbuf[MAX_DATAGRAM];
+	qbyte msgbuf[NET_MAXMESSAGE];
 	// EDICT_NUM(clientnum+1)
 	edict_t *edict;
 
diff --git a/sv_main.c b/sv_main.c
index 9893dc36..d695f3bf 100644
--- a/sv_main.c
+++ b/sv_main.c
@@ -1001,10 +1001,15 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
 	vec3_t testorigin;
 	entity_state_t *s;
 	entity_database4_t *d;
-	int maxbytes, n, startnumber;
+	int n, startnumber;
 	entity_state_t *e, inactiveentitystate;
 	sizebuf_t buf;
 	qbyte data[128];
+
+	// if there isn't enough space to accomplish anything, skip it
+	if (msg->cursize + 24 > msg->maxsize)
+		return;
+
 	// prepare the buffer
 	memset(&buf, 0, sizeof(buf));
 	buf.data = data;
@@ -1056,10 +1061,6 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
 	for (i = 0;i < numsendentities;i++)
 		SV_MarkWriteEntityStateToClient(sendentities + i);
 
-	// calculate maximum bytes to allow in this packet
-	// deduct 4 to account for the end data
-	maxbytes = min(msg->maxsize, MAX_PACKETFRAGMENT) - 4;
-
 	d->currentcommit->numentities = 0;
 	d->currentcommit->framenum = ++client->entityframenumber;
 	MSG_WriteByte(msg, svc_entities);
@@ -1117,7 +1118,7 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
 			}
 		}
 		// if the commit is full, we're done this frame
-		if (msg->cursize + buf.cursize > maxbytes)
+		if (msg->cursize + buf.cursize > msg->maxsize - 4)
 		{
 			// next frame we will continue where we left off
 			break;
@@ -1341,13 +1342,13 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
 SV_SendClientDatagram
 =======================
 */
-static qbyte sv_sendclientdatagram_buf[MAX_DATAGRAM]; // FIXME?
+static qbyte sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
 qboolean SV_SendClientDatagram (client_t *client)
 {
 	sizebuf_t	msg;
 
 	msg.data = sv_sendclientdatagram_buf;
-	msg.maxsize = sizeof(sv_sendclientdatagram_buf);
+	msg.maxsize = (int)bound(50.0, client->netconnection->rate * host_realframetime, (double)sizeof(sv_sendclientdatagram_buf));
 	msg.cursize = 0;
 
 	MSG_WriteByte (&msg, svc_time);
@@ -1359,7 +1360,8 @@ qboolean SV_SendClientDatagram (client_t *client)
 	SV_WriteEntitiesToClient (client, client->edict, &msg);
 
 	// copy the server datagram if there is space
-	if (msg.cursize + sv.datagram.cursize < msg.maxsize)
+	// FIXME: put in delayed queue of effects to send
+	if (msg.cursize + sv.datagram.cursize <= msg.maxsize)
 		SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
 
 // send the datagram