From 9cce5b7eefa8ec89bda698afc50759914f6347ea Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 16 Apr 2007 13:08:38 +0000 Subject: [PATCH] implemented shownetgraph major overhaul of rate limiting code implemented packet-frequency rate limiting (like qw/q2/q3) as a fallback when packet size limiting fails (such as packet sizes below 100 bytes causing all sorts of issues, so now the minimum bound on maxsize is 100, and another good example is reliable messages exceeding the rate limit) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7108 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_input.c | 16 +++++++--- cl_main.c | 6 ++-- cl_parse.c | 2 +- cl_screen.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ host.c | 6 ++-- host_cmd.c | 6 ++-- netconn.c | 91 +++++++++++++++++++++++++++++++++++++++++++---------- netconn.h | 27 +++++++++++----- sv_main.c | 45 +++++++++++++++++--------- 9 files changed, 230 insertions(+), 52 deletions(-) diff --git a/cl_input.c b/cl_input.c index a1a7aad1..c84b3c64 100644 --- a/cl_input.c +++ b/cl_input.c @@ -1314,12 +1314,18 @@ void CL_SendMove(void) return; cl.cmd.time = cl.mtime[0]; } + // don't let it fall behind if CL_SendMove hasn't been called recently // (such is the case when framerate is too low for instance) lastsendtime = bound(realtime, lastsendtime + packettime, realtime + packettime); // set the flag indicating that we sent a packet recently cl.movement_needupdate = false; + // don't send a new input packet if the connection is still saturated from + // the last one (or chat messages, etc) + // note: this behavior comes from QW + if (!NetConn_CanSend(cls.netcon)) + return; buf.maxsize = sizeof(data); buf.cursize = 0; @@ -1432,8 +1438,10 @@ void CL_SendMove(void) checksumindex = buf.cursize; MSG_WriteByte(&buf, 0); // packet loss percentage - for (j = 0, packetloss = 0;j < 100;j++) - packetloss += cls.netcon->packetlost[j]; + for (j = 0, packetloss = 0;j < NETGRAPH_PACKETS;j++) + if (cls.netcon->incoming_unreliablesize[i] == NETGRAPH_LOSTPACKET) + packetloss++; + packetloss = packetloss * 100 / NETGRAPH_PACKETS; MSG_WriteByte(&buf, packetloss); // write most recent 3 moves QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, &cl.movecmd[2]); @@ -1564,7 +1572,7 @@ void CL_SendMove(void) { if (cl.latestframenums[i] > 0) { - if (developer_networkentities.integer >= 1) + if (developer_networkentities.integer >= 10) Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]); MSG_WriteByte(&buf, clc_ackframe); MSG_WriteLong(&buf, cl.latestframenums[i]); @@ -1589,7 +1597,7 @@ void CL_SendMove(void) } // send the reliable message (forwarded commands) if there is one - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, max(20*(buf.cursize+40), cl_rate.integer)); if (cls.netcon->message.overflowed) { diff --git a/cl_main.c b/cl_main.c index a95388a3..5ecb37e0 100644 --- a/cl_main.c +++ b/cl_main.c @@ -338,9 +338,9 @@ void CL_Disconnect(void) Con_DPrint("Sending clc_disconnect\n"); MSG_WriteByte(&buf, clc_disconnect); } - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol); - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol); - NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000); + NetConn_SendUnreliableMessage(cls.netcon, &buf, cls.protocol, 10000); NetConn_Close(cls.netcon); cls.netcon = NULL; } diff --git a/cl_parse.c b/cl_parse.c index c234fb74..779650bd 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -309,7 +309,7 @@ void CL_KeepaliveMessage (qboolean readmessages) msg.data = buf; msg.maxsize = sizeof(buf); MSG_WriteChar(&msg, clc_nop); - NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol); + NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000); } } diff --git a/cl_screen.c b/cl_screen.c index 8483e196..869b893f 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -46,6 +46,7 @@ cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20", "fov of zoom window"}; cvar_t scr_stipple = {0, "scr_stipple", "0", "interlacing-like stippling of the display"}; cvar_t scr_refresh = {0, "scr_refresh", "1", "allows you to completely shut off rendering for benchmarking purposes"}; +cvar_t shownetgraph = {CVAR_SAVE, "shownetgraph", "0", "shows a graph of packet sizes and other information"}; int jpeg_supported = false; @@ -184,6 +185,86 @@ void SCR_CheckDrawCenterString (void) SCR_DrawCenterString (); } +void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int barwidth, int barheight, int bardivide, const char *label, float textsize, int packetcounter, int numparameters, const int **parameters, const float parametercolors[][4]) +{ + int j, k, x, y, index, offset, height; + // dim background + DrawQ_Pic (graphx, graphy, NULL, barwidth * NETGRAPH_PACKETS, barheight + textsize, 0, 0, 0, 0.5, 0); + // draw a label + DrawQ_String (graphx, graphy + barheight, label, 0, textsize, textsize, 1, 1, 1, 1, 0); + // draw the bar graph itself + for (j = 0;j < NETGRAPH_PACKETS;j++) + { + x = graphx + j * barwidth; + y = graphy + barheight; + index = (packetcounter + j) % NETGRAPH_PACKETS; + if (parameters[0][index] == NETGRAPH_LOSTPACKET) + DrawQ_Pic(x, y - barheight, NULL, barwidth, barheight, 1, 0, 0, 1, 0); + else if (parameters[0][index] == NETGRAPH_CHOKEDPACKET) + DrawQ_Pic(x, y - min(2, barheight), NULL, barwidth, min(2, barheight), 1, 1, 0, 1, 0); + else + { + offset = 0; + for (k = 0;k < numparameters;k++) + { + height = (parameters[k][index] + bardivide - 1) / bardivide; + height = min(height, barheight - offset); + offset += height; + if (height) + DrawQ_Pic(x, y - offset, NULL, barwidth, height, parametercolors[k][0], parametercolors[k][1], parametercolors[k][2], parametercolors[k][3], 0); + } + } + } +} + +const float netgraphcolors[3][4] = +{ + {1 , 0.5, 0 , 1}, + {1 , 1 , 1 , 1}, + {0 , 1 , 0 , 1}, +}; + +void SCR_DrawNetGraph_DrawConnection (netconn_t *conn, int graphx, int graphy, int barwidth, int barheight, int bardivide, const char *labelincoming, int separator, const char *labeloutgoing, float textsize) +{ + int numparameters; + const int *parameters[3]; + numparameters = 3; + parameters[0] = conn->incoming_unreliablesize; + parameters[1] = conn->incoming_reliablesize; + parameters[2] = conn->incoming_acksize; + SCR_DrawNetGraph_DrawGraph(graphx, graphy, barwidth, barheight, bardivide, labelincoming, textsize, conn->incoming_packetcounter, numparameters, parameters, netgraphcolors); + parameters[0] = conn->outgoing_unreliablesize; + parameters[1] = conn->outgoing_reliablesize; + parameters[2] = conn->outgoing_acksize; + SCR_DrawNetGraph_DrawGraph(graphx + barwidth * NETGRAPH_PACKETS + separator, graphy, barwidth, barheight, bardivide, labeloutgoing, textsize, conn->outgoing_packetcounter, numparameters, parameters, netgraphcolors); +} + +/* +============== +SCR_DrawNetGraph +============== +*/ +void SCR_DrawNetGraph (void) +{ + int separator, barwidth, barheight, bardivide, netgraph_x, netgraph_y, textsize; + + if (cls.state != ca_connected) + return; + if (!cls.netcon) + return; + if (!shownetgraph.integer) + return; + + separator = 4; + textsize = 8; + barwidth = 1; + barheight = 50; + bardivide = 20; + netgraph_x = 0; + netgraph_y = vid_conheight.integer - 48 - barheight - textsize; + SCR_DrawNetGraph_DrawConnection(cls.netcon, netgraph_x, netgraph_y, barwidth, barheight, bardivide, "incoming", separator, "outgoing", textsize); +} + /* ============== SCR_DrawTurtle @@ -639,6 +720,7 @@ void CL_Screen_Init(void) Cvar_RegisterVariable(&scr_zoomwindow_fov); Cvar_RegisterVariable(&scr_stipple); Cvar_RegisterVariable(&scr_refresh); + Cvar_RegisterVariable(&shownetgraph); Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)"); Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)"); @@ -1591,6 +1673,7 @@ void SCR_DrawScreen (void) SHOWLMP_drawall(); SCR_CheckDrawCenterString(); } + SCR_DrawNetGraph (); MR_Draw(); CL_DrawVideo(); R_Shadow_EditLights_DrawSelectedLightProperties(); diff --git a/host.c b/host.c index b81f181c..6d1788a9 100644 --- a/host.c +++ b/host.c @@ -435,9 +435,9 @@ void SV_DropClient(qboolean crash) buf.data = bufdata; buf.maxsize = sizeof(bufdata); MSG_WriteByte(&buf, svc_disconnect); - NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol); - NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol); - NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000); } // break the net connection NetConn_Close(host_client->netconnection); diff --git a/host_cmd.c b/host_cmd.c index bac0d142..2ea15b81 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -2324,8 +2324,10 @@ void Host_Pings_f (void) { packetloss = 0; if (svs.clients[i].netconnection) - for (j = 0;j < 100;j++) - packetloss += svs.clients[i].netconnection->packetlost[j]; + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET) + packetloss++; + packetloss = packetloss * 100 / NETGRAPH_PACKETS; ping = (int)floor(svs.clients[i].ping*1000+0.5); ping = bound(0, ping, 9999); if (sv.protocol == PROTOCOL_QUAKEWORLD) diff --git a/netconn.c b/netconn.c index c0c4c1e8..833c50a5 100755 --- a/netconn.c +++ b/netconn.c @@ -472,8 +472,31 @@ int NetConn_WriteString(lhnetsocket_t *mysocket, const char *string, const lhnet return NetConn_Write(mysocket, string, (int)strlen(string), peeraddress); } -int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol) +qboolean NetConn_CanSend(netconn_t *conn) { + conn->outgoing_packetcounter = (conn->outgoing_packetcounter + 1) % NETGRAPH_PACKETS; + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] = NETGRAPH_NOPACKET; + conn->outgoing_reliablesize[conn->outgoing_packetcounter] = NETGRAPH_NOPACKET; + conn->outgoing_acksize[conn->outgoing_packetcounter] = NETGRAPH_NOPACKET; + if (realtime > conn->cleartime) + return true; + else + { + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] = NETGRAPH_CHOKEDPACKET; + return false; + } +} + +int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate) +{ + int totallen = 0; + + // if this packet was supposedly choked, but we find ourselves sending one + // anyway, make sure the size counting starts at zero + // (this mostly happens on level changes and disconnects and such) + if (conn->outgoing_unreliablesize[conn->outgoing_packetcounter] == NETGRAPH_CHOKEDPACKET) + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] = NETGRAPH_NOPACKET; + if (protocol == PROTOCOL_QUAKEWORLD) { int packetLen; @@ -514,16 +537,22 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers Con_Printf ("NetConn_SendUnreliableMessage: reliable message too big %u\n", data->cursize); return -1; } + + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] += packetLen; + // add the reliable message if there is one if (sendreliable) { + conn->outgoing_reliablesize[conn->outgoing_packetcounter] += conn->sendMessageLength; memcpy(sendbuffer + packetLen, conn->sendMessage, conn->sendMessageLength); packetLen += conn->sendMessageLength; conn->qw.last_reliable_sequence = conn->qw.outgoing_sequence; } + // add the unreliable message if possible if (packetLen + data->cursize <= 1400) { + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] += data->cursize; memcpy(sendbuffer + packetLen, data->data, data->cursize); packetLen += data->cursize; } @@ -533,10 +562,7 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers packetsSent++; unreliableMessagesSent++; - // delay later packets to obey rate limit - conn->qw.cleartime = max(conn->qw.cleartime, realtime) + packetLen * conn->qw.rate; - - return 0; + totallen += packetLen + 18; } else { @@ -566,11 +592,15 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers header[1] = BigLong(conn->nq.sendSequence - 1); memcpy(sendbuffer + NET_HEADERSIZE, conn->sendMessage, dataLen); + conn->outgoing_reliablesize[conn->outgoing_packetcounter] += packetLen; + if (NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress) == (int)packetLen) { conn->lastSendTime = realtime; packetsReSent++; } + + totallen += packetLen + 18; } // if we have a new reliable message to send, do so @@ -613,15 +643,19 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers conn->nq.sendSequence++; + conn->outgoing_reliablesize[conn->outgoing_packetcounter] += packetLen; + NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress); conn->lastSendTime = realtime; packetsSent++; reliableMessagesSent++; + + totallen += packetLen + 18; } // if we have an unreliable message to send, do so - if (data->cursize) + //if (data->cursize) { packetLen = NET_HEADERSIZE + data->cursize; @@ -638,13 +672,26 @@ int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolvers conn->nq.unreliableSendSequence++; + conn->outgoing_unreliablesize[conn->outgoing_packetcounter] += packetLen; + NetConn_Write(conn->mysocket, (void *)&sendbuffer, packetLen, &conn->peeraddress); packetsSent++; unreliableMessagesSent++; + + if (data->cursize) + totallen += packetLen + 18; } - return 0; } + + // delay later packets to obey rate limit + if (conn->cleartime < realtime - 0.1) + conn->cleartime = realtime - 0.1; + conn->cleartime = conn->cleartime + (double)totallen / (double)rate; + if (conn->cleartime < realtime) + conn->cleartime = realtime; + + return 0; } void NetConn_CloseClientPorts(void) @@ -850,6 +897,7 @@ void NetConn_UpdateSockets(void) static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int length, protocolversion_t protocol, double newtimeout) { + int originallength = length; if (length < 8) return 0; @@ -895,12 +943,16 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len //Con_DPrintf("Dropped %u datagram(s)\n", count); while (count--) { - conn->packetlost[conn->packetlostcounter] = true; - conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_unreliablesize[conn->incoming_packetcounter] = NETGRAPH_LOSTPACKET; + conn->incoming_reliablesize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; + conn->incoming_acksize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; } } - conn->packetlost[conn->packetlostcounter] = false; - conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_unreliablesize[conn->incoming_packetcounter] = originallength; + conn->incoming_reliablesize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; + conn->incoming_acksize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; if (reliable_ack == conn->qw.reliable_sequence) { // received, now we will be able to send another reliable message @@ -950,12 +1002,16 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len //Con_DPrintf("Dropped %u datagram(s)\n", count); while (count--) { - conn->packetlost[conn->packetlostcounter] = true; - conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_unreliablesize[conn->incoming_packetcounter] = NETGRAPH_LOSTPACKET; + conn->incoming_reliablesize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; + conn->incoming_acksize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; } } - conn->packetlost[conn->packetlostcounter] = false; - conn->packetlostcounter = (conn->packetlostcounter + 1) % 100; + conn->incoming_packetcounter = (conn->incoming_packetcounter + 1) % NETGRAPH_PACKETS; + conn->incoming_unreliablesize[conn->incoming_packetcounter] = originallength; + conn->incoming_reliablesize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; + conn->incoming_acksize[conn->incoming_packetcounter] = NETGRAPH_NOPACKET; conn->nq.unreliableReceiveSequence = sequence + 1; conn->lastMessageTime = realtime; conn->timeout = realtime + newtimeout; @@ -974,6 +1030,7 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len } else if (flags & NETFLAG_ACK) { + conn->incoming_acksize[conn->incoming_packetcounter] += originallength; if (sequence == (conn->nq.sendSequence - 1)) { if (sequence == conn->nq.ackSequence) @@ -1032,6 +1089,8 @@ static int NetConn_ReceivedMessage(netconn_t *conn, unsigned char *data, int len else if (flags & NETFLAG_DATA) { unsigned int temppacket[2]; + conn->incoming_reliablesize[conn->incoming_packetcounter] += originallength; + conn->outgoing_acksize[conn->outgoing_packetcounter] += 8; temppacket[0] = BigLong(8 | NETFLAG_ACK); temppacket[1] = BigLong(sequence); NetConn_Write(conn->mysocket, (unsigned char *)temppacket, 8, &conn->peeraddress); @@ -1105,7 +1164,7 @@ void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_t *peer msg.data = buf; msg.maxsize = sizeof(buf); MSG_WriteChar(&msg, clc_nop); - NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol); + NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000); } } diff --git a/netconn.h b/netconn.h index 9b54313d..603d987b 100755 --- a/netconn.h +++ b/netconn.h @@ -169,10 +169,6 @@ typedef struct netconn_s int qport; - // bandwidth estimator - double cleartime; // if realtime > nc->cleartime, free to go - double rate; // seconds / byte - // sequencing variables int incoming_sequence; int incoming_acknowledged; @@ -186,9 +182,23 @@ typedef struct netconn_s } qw; - // this tracks which of the last 100 received packet sequence numbers were lost - int packetlostcounter; - unsigned char packetlost[100]; + // bandwidth estimator + double cleartime; // if realtime > nc->cleartime, free to go + + // this tracks packet loss and packet sizes on the most recent packets + // used by shownetgraph feature +#define NETGRAPH_PACKETS 100 +#define NETGRAPH_NOPACKET 0 +#define NETGRAPH_LOSTPACKET -1 +#define NETGRAPH_CHOKEDPACKET -2 + int incoming_packetcounter; + int incoming_reliablesize[NETGRAPH_PACKETS]; + int incoming_unreliablesize[NETGRAPH_PACKETS]; + int incoming_acksize[NETGRAPH_PACKETS]; + int outgoing_packetcounter; + int outgoing_reliablesize[NETGRAPH_PACKETS]; + int outgoing_unreliablesize[NETGRAPH_PACKETS]; + int outgoing_acksize[NETGRAPH_PACKETS]; char address[128]; } netconn_t; @@ -331,7 +341,8 @@ extern cvar_t sv_netport; extern cvar_t net_address; //extern cvar_t net_netaddress_ipv6; -int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol); +qboolean NetConn_CanSend(netconn_t *conn); +int NetConn_SendUnreliableMessage(netconn_t *conn, sizebuf_t *data, protocolversion_t protocol, int rate); void NetConn_CloseClientPorts(void); void NetConn_OpenClientPorts(void); void NetConn_CloseServerPorts(void); diff --git a/sv_main.c b/sv_main.c index ebd85b80..2fdbee46 100644 --- a/sv_main.c +++ b/sv_main.c @@ -1357,36 +1357,42 @@ SV_SendClientDatagram static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME? void SV_SendClientDatagram (client_t *client) { - int rate, maxrate, maxsize, maxsize2, downloadsize; + int clientrate, maxrate, maxsize, maxsize2, downloadsize; sizebuf_t msg; int stats[MAX_CL_STATS]; + // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates + maxrate = max(NET_MINRATE, sv_maxrate.integer); + if (sv_maxrate.integer != maxrate) + Cvar_SetValueQuick(&sv_maxrate, maxrate); + // clientrate determines the 'cleartime' of a packet + // (how long to wait before sending another, based on this packet's size) + clientrate = bound(NET_MINRATE, client->rate, maxrate); + if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer) { - // for good singleplayer, send huge packets + // for good singleplayer, send huge packets and never limit frequency + clientrate = 1000000000; maxsize = sizeof(sv_sendclientdatagram_buf); maxsize2 = sizeof(sv_sendclientdatagram_buf); } else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4) { - // no rate limiting support on older protocols because dp protocols - // 1-4 kick the client off if they overflow, and quake protocol shows - // less than the full entity set if rate limited + // no packet size limit support on older protocols because DP1-4 kick + // the client off if they overflow, and quake protocol shows less than + // the full entity set if rate limited maxsize = 1400; maxsize2 = 1400; } else { - // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates - maxrate = max(NET_MINRATE, sv_maxrate.integer); - if (sv_maxrate.integer != maxrate) - Cvar_SetValueQuick(&sv_maxrate, maxrate); - + // DP5 and later protocols support packet size limiting which is a + // better method than limiting packet frequency as QW does + // // this rate limiting does not understand sys_ticrate 0 // (but no one should be running that on a server!) - rate = bound(NET_MINRATE, client->rate, maxrate); - rate = (int)(rate * sys_ticrate.value); - maxsize = bound(50, rate, 1400); + maxsize = (int)(clientrate * sys_ticrate.value); + maxsize = bound(100, maxsize, 1400); maxsize2 = 1400; } @@ -1399,7 +1405,16 @@ void SV_SendClientDatagram (client_t *client) msg.maxsize = maxsize; msg.cursize = 0; - if (host_client->spawned) + // obey rate limit by limiting packet frequency if the packet size + // limiting fails + // (usually this is caused by reliable messages) + if (!NetConn_CanSend(client->netconnection)) + { + // send the datagram + NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate); + return; + } + else if (host_client->spawned) { MSG_WriteByte (&msg, svc_time); MSG_WriteFloat (&msg, sv.time); @@ -1457,7 +1472,7 @@ void SV_SendClientDatagram (client_t *client) } // send the datagram - NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol); + NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate); } /* -- 2.39.2