From 8ee2396ccf926ee8221f533dd930e016d41c0755 Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 21 Feb 2004 11:58:08 +0000 Subject: [PATCH] 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 --- cl_demo.c | 4 ++-- cl_parse.c | 3 +++ client.h | 1 + host_cmd.c | 34 ++++++++++++++++++++++++++++++++++ netconn.c | 31 ++++++++++++++++++------------- netconn.h | 9 ++++----- quakedef.h | 6 +++--- server.h | 10 +++++----- sv_main.c | 20 +++++++++++--------- 9 files changed, 81 insertions(+), 37 deletions(-) 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 -- 2.39.2