]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
implemented shownetgraph
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 16 Apr 2007 13:08:38 +0000 (13:08 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 16 Apr 2007 13:08:38 +0000 (13:08 +0000)
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
cl_main.c
cl_parse.c
cl_screen.c
host.c
host_cmd.c
netconn.c
netconn.h
sv_main.c

index a1a7aad12a5ad0c665592544ac7a14be7a063ae3..c84b3c649c52e781d1f6b879f17398dbc68aa25e 100644 (file)
@@ -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)
        {
index a95388a340f8bd8b15c780299bbf02c62638d999..5ecb37e003b5f4bf2e41f8ddb711bc5167da82ba 100644 (file)
--- 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;
        }
index c234fb740b4b4ef85e12c1df22a2a4055ac2a63e..779650bd4558e6e46628b4b9c39e56b79d31abe2 100644 (file)
@@ -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);
        }
 }
 
index 8483e1966e8dbe452d5b2d72cbbe098b55d7037d..869b893f033501c99a5ec95f6d4f173b1d3d2242 100644 (file)
@@ -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 b81f181c5f818272a56879bc1d3670a2d4a9a357..6d1788a9d9d56ad82ff6df6be16df5282dcc8194 100644 (file)
--- 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);
index bac0d1424776a3556a672d62739b1eb3cb7ce006..2ea15b8155c6bc6e08a9002592b60d0c2d174f2a 100644 (file)
@@ -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)
index c0c4c1e8db1f63e613e47e967c29deeef072f54f..833c50a5fb418ec556375f242e4b229fb0194820 100755 (executable)
--- 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);
        }
 }
 
index 9b54313d94599d13bf4eb1a35d71dbcba7edf94a..603d987b7395263a059dd57f00e6e37d4d3a90d9 100755 (executable)
--- 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);
index ebd85b80918cdfcb0fe1ecc86a097a0d29e18b32..2fdbee46d2b25a4d545784d7ba42f7e4c0003d01 100644 (file)
--- 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);
 }
 
 /*