Restore choke lines into the netgraph, and support discontinuities so it doesn't look so weird. Also tweak realip warnings. Don't honour dupes if it would exceed rate limits (new data is better than dupe data), which can also double-up as a CBR type thing to try to reserve the bandwidth (avoiding packetloss bursts at the worst times).

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5525 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-08-24 16:09:08 +00:00
parent 2377c3fa54
commit 9202c3f015
5 changed files with 124 additions and 45 deletions

View file

@ -2686,25 +2686,31 @@ void CL_Packet_f (void)
} }
if (Cmd_FromGamecode()) //some mvd servers stuffcmd a packet command which lets them know which ip the client is from. if (Cmd_FromGamecode()) //some mvdsv servers stuffcmd a packet command which lets them know which ip the client is from.
{ //unfortunatly, 50% of servers are badly configured. { //unfortunatly, 50% of servers are badly configured resulting in them poking local services that THEY MUST NOT HAVE ACCESS TO.
char *addrdesc;
char *realdesc;
if (cls.demoplayback) if (cls.demoplayback)
{ {
Con_DPrintf ("Not sending realip packet from demo\n"); Con_DPrintf ("Not sending realip packet from demo\n");
return; return;
} }
if (adr.type == NA_IP) if (!NET_CompareAdr(&adr, &cls.netchan.remote_address))
if ((adr.address.ip[0] == 127 && adr.address.ip[1] == 0 && adr.address.ip[2] == 0 && adr.address.ip[3] == 1) || {
(adr.address.ip[0] == 0 && adr.address.ip[1] == 0 && adr.address.ip[2] == 0 && adr.address.ip[3] == 0)) if (NET_ClassifyAddress(&adr, &addrdesc) < ASCOPE_LAN)
{ {
adr.address.ip[0] = cls.netchan.remote_address.address.ip[0]; if (NET_ClassifyAddress(&cls.netchan.remote_address, &realdesc) < ASCOPE_LAN)
adr.address.ip[1] = cls.netchan.remote_address.address.ip[1]; { //this isn't necessarily buggy... but its still a potential exploit so we need to block it regardless.
adr.address.ip[2] = cls.netchan.remote_address.address.ip[2]; Con_Printf (CON_WARNING "Ignoring buggy %s realip request for %s server.\n", addrdesc, realdesc);
adr.address.ip[3] = cls.netchan.remote_address.address.ip[3]; }
adr.port = cls.netchan.remote_address.port; else
Con_Printf (CON_WARNING "Server is broken. Trying to send to server instead.\n"); {
adr = cls.netchan.remote_address;
Con_Printf (CON_WARNING "Ignoring buggy %s realip request, sending to %s server instead.\n", addrdesc, realdesc);
}
} }
}
cls.realserverip = adr; cls.realserverip = adr;
Con_DPrintf ("Sending realip packet\n"); Con_DPrintf ("Sending realip packet\n");

View file

@ -387,6 +387,16 @@ qboolean Netchan_CanPacket (netchan_t *chan, int rate)
return false; return false;
} }
int Netchan_CanBytes (netchan_t *chan, int rate)
{
const double slop = 0.25;
if (chan->remote_address.type == NA_LOOPBACK)
return 0x7fffffff; //don't ever drop packets due to possible routing problems when there is no routing.
if (!rate)
return 0x7fffffff;
return ((realtime+slop)-chan->cleartime)*rate;
}
void Netchan_Block (netchan_t *chan, int bytes, int rate) void Netchan_Block (netchan_t *chan, int bytes, int rate)
{ {
if (rate) if (rate)
@ -583,6 +593,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
int i; int i;
neterr_t e; neterr_t e;
int dupes = chan->dupe;
int availbytes = Netchan_CanBytes(chan, rate);
#ifdef NQPROT #ifdef NQPROT
if (chan->isnqprotocol) if (chan->isnqprotocol)
{ {
@ -789,10 +802,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
#endif #endif
{ {
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/ int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
dupes = min(chan->dupe, availbytes / send.cursize);
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7)) if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7))
{ //vanilla sends { //vanilla sends
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++) for (i = -1; i < dupes && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address); e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * i; send.cursize += send.cursize * i;
@ -809,6 +823,8 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
{ //fte's fragmentaton protocol { //fte's fragmentaton protocol
int offset = 0, no; int offset = 0, no;
qboolean more; qboolean more;
int outbytes = 0;
int fragbytes;
/*FIXME: splurge over a number of frames, if we have an outgoing reliable*/ /*FIXME: splurge over a number of frames, if we have an outgoing reliable*/
@ -842,9 +858,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (e == NETERR_SENT) if (e == NETERR_SENT)
{ {
for (i = -1; i < chan->dupe && e == NETERR_SENT; i++) for (i = -1; i < dupes && e == NETERR_SENT; i++)
{ {
e = NET_SendPacket (chan->sock, (no - offset) + hsz, send.data + offset, &chan->remote_address); fragbytes = (no - offset) + hsz;
e = NET_SendPacket (chan->sock, fragbytes, send.data + offset, &chan->remote_address);
outbytes += fragbytes;
if (e == NETERR_MTU && !offset && chan->mtu > 560) if (e == NETERR_MTU && !offset && chan->mtu > 560)
{ {
chan->mtu -= 16; chan->mtu -= 16;
@ -857,6 +875,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
} }
offset = no; offset = no;
} while(more); } while(more);
send.cursize = outbytes;
} }
} }
@ -939,8 +958,8 @@ qboolean Netchan_Process (netchan_t *chan)
reliable_message = sequence >> 31; reliable_message = sequence >> 31;
reliable_ack = sequence_ack >> 31; reliable_ack = sequence_ack >> 31;
sequence &= ~(1<<31); sequence &= ~(1u<<31);
sequence_ack &= ~(1<<31); sequence_ack &= ~(1u<<31);
if (showpackets.value) if (showpackets.value)
Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n" Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n"

View file

@ -159,7 +159,7 @@ static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue)
} }
} }
} }
cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections)."); cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: clientside choice.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections).");
#endif #endif
#ifdef HAVE_CLIENT #ifdef HAVE_CLIENT
@ -372,6 +372,8 @@ qboolean NET_CompareAdr (netadr_t *a, netadr_t *b)
if (a->type != b->type) if (a->type != b->type)
{ {
int i; int i;
if (a->port != b->port)
return false;
if (a->type == NA_IP && b->type == NA_IPV6) if (a->type == NA_IP && b->type == NA_IPV6)
{ {
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
@ -7193,6 +7195,28 @@ int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_gener
return found; return found;
} }
static enum addressscope_e NET_ClassifyAddressipv4(int ip, char **outdesc)
{
int scope = ASCOPE_NET;
char *desc = NULL;
if ((ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16
scope = ASCOPE_LINK, desc = "link-local";
else if ((ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8
scope = ASCOPE_LAN, desc = "private";
else if ((ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8
scope = ASCOPE_HOST, desc = "localhost";
else if ((ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12
scope = ASCOPE_LAN, desc = "private";
else if ((ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16
scope = ASCOPE_LAN, desc = "private";
else if ((ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10
scope = ASCOPE_LAN, desc = "CGNAT";
else if (ip == BigLong(0x00000000)) //0.0.0.0/32
scope = ASCOPE_LAN, desc = "any";
*outdesc = desc;
return scope;
}
enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc) enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc)
{ {
int scope = ASCOPE_NET; int scope = ASCOPE_NET;
@ -7217,24 +7241,15 @@ enum addressscope_e NET_ClassifyAddress(netadr_t *adr, char **outdesc)
scope = ASCOPE_HOST, desc = "localhost"; scope = ASCOPE_HOST, desc = "localhost";
else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) //:: else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0) //::
scope = ASCOPE_NET, desc = "any"; scope = ASCOPE_NET, desc = "any";
else if (memcmp(adr->address.ip6, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12) == 0) //::ffff:x.y.z.w
{
scope = NET_ClassifyAddressipv4(*(int*)(adr->address.ip6+12), &desc);
if (!desc)
desc = "vp-mapped";
}
} }
else if (adr->type == NA_IP) else if (adr->type == NA_IP)
{ scope = NET_ClassifyAddressipv4(*(int*)adr->address.ip, &desc);
if ((*(int*)adr->address.ip&BigLong(0xffff0000)) == BigLong(0xA9FE0000)) //169.254.x.x/16
scope = ASCOPE_LINK, desc = "link-local";
else if ((*(int*)adr->address.ip&BigLong(0xff000000)) == BigLong(0x0a000000)) //10.x.x.x/8
scope = ASCOPE_LAN, desc = "private";
else if ((*(int*)adr->address.ip&BigLong(0xff000000)) == BigLong(0x7f000000)) //127.x.x.x/8
scope = ASCOPE_HOST, desc = "localhost";
else if ((*(int*)adr->address.ip&BigLong(0xfff00000)) == BigLong(0xac100000)) //172.16.x.x/12
scope = ASCOPE_LAN, desc = "private";
else if ((*(int*)adr->address.ip&BigLong(0xffff0000)) == BigLong(0xc0a80000)) //192.168.x.x/16
scope = ASCOPE_LAN, desc = "private";
else if ((*(int*)adr->address.ip&BigLong(0xffc00000)) == BigLong(0x64400000)) //100.64.x.x/10
scope = ASCOPE_LAN, desc = "CGNAT";
else if (*(int*)adr->address.ip == BigLong(0x00000000)) //0.0.0.0/32
scope = ASCOPE_LAN, desc = "any";
}
if (outdesc) if (outdesc)
*outdesc = desc; *outdesc = desc;
return scope; return scope;

View file

@ -91,6 +91,7 @@ void R_NetGraph (void)
int a, x, i; int a, x, i;
float y; float y;
float pi, po, bi, bo; float pi, po, bi, bo;
int errorbar;
vec2_t p[4]; vec2_t p[4];
vec2_t tc[4]; vec2_t tc[4];
@ -120,10 +121,10 @@ void R_NetGraph (void)
for (a=0 ; a<NET_TIMINGS ; a++) for (a=0 ; a<NET_TIMINGS ; a++)
{ {
i = (cl.movesequence-a) & NET_TIMINGSMASK; i = (cl.movesequence-a) & NET_TIMINGSMASK;
if (packet_latency[i] != 10000) // if (packet_latency[i] != 10000)
last = packet_latency[i]; last = packet_latency[i];
else if (last >= 0) // else if (last >= 0)
last = -last; // last = -last;
R_LineGraph (NET_TIMINGS-1-a, last); R_LineGraph (NET_TIMINGS-1-a, last);
} }
} }
@ -188,6 +189,7 @@ void R_NetGraph (void)
Vector2Set(p[3], 0,0); Vector2Set(p[3], 0,0);
Vector4Set(rgba[2], 0,0,0,0); Vector4Set(rgba[2], 0,0,0,0);
Vector4Set(rgba[3], 0,0,0,0); Vector4Set(rgba[3], 0,0,0,0);
errorbar = 1; //first is discontinuous
for (a=0 ; a<NET_TIMINGS ; a++) for (a=0 ; a<NET_TIMINGS ; a++)
{ {
Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]); Vector2Copy(p[3], p[0]); Vector4Copy(rgba[3], rgba[0]);
@ -196,13 +198,22 @@ void R_NetGraph (void)
Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT); Vector2Set(p[2+0], x+a, y+(1-ngraph[a].height)*NET_GRAPHHEIGHT);
Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT); Vector2Set(p[2+1], x+a, y+NET_GRAPHHEIGHT);
Vector2Set(tc[2+0], x/(float)NET_TIMINGS, (1-ngraph[a].height)); Vector2Set(tc[2+0], a/(float)NET_TIMINGS, (1-ngraph[a].height));
Vector2Set(tc[2+1], x/(float)NET_TIMINGS, 1); Vector2Set(tc[2+1], a/(float)NET_TIMINGS, 1);
Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0); Vector4Set(rgba[2+0], ((ngraph[a].col>>0)&0xff)/255.0, ((ngraph[a].col>>8)&0xff)/255.0, ((ngraph[a].col>>16)&0xff)/255.0, ((ngraph[a].col>>24)&0xff)/255.0);
Vector4Copy(rgba[2+0], rgba[2+1]); Vector4Copy(rgba[2+0], rgba[2+1]);
if (a) if (ngraph[a].height==1)
R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill); errorbar = 2; //this one and the following should be discontiguous
if (errorbar --> 0)
{ //if this is a full-height bar, break the smooth curve and just make it discontinuous
p[0][1] = p[3][1];
p[1][1] = p[2][1];
Vector4Copy(rgba[3], rgba[0]);
Vector4Copy(rgba[2], rgba[1]);
}
R2D_Image2dQuad((const vec2_t*)p, (const vec2_t*)tc, (const vec4_t*)rgba, shader_draw_fill);
} }
#endif #endif
} }

View file

@ -279,6 +279,30 @@ static qboolean JSON_Equals(json_t *t, const char *child, const char *expected)
return false; return false;
} }
#include <inttypes.h> #include <inttypes.h>
static quintptr_t JSON_GetUInteger(json_t *t, const char *child, unsigned int fallback)
{
if (child)
t = JSON_FindChild(t, child);
if (t)
{ //copy it to another buffer. can probably skip that tbh.
char tmp[MAX_QPATH];
char *trail;
size_t l = t->bodyend-t->bodystart;
quintptr_t r;
if (l > MAX_QPATH-1)
l = MAX_QPATH-1;
memcpy(tmp, t->bodystart, l);
tmp[l] = 0;
if (!strcmp(tmp, "false")) //special cases, for booleans
return 0u;
if (!strcmp(tmp, "true")) //special cases, for booleans
return 1u;
r = (quintptr_t)strtoull(tmp, &trail, 0);
if (!*trail)
return r;
}
return fallback;
}
static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback) static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
{ {
if (child) if (child)
@ -286,7 +310,9 @@ static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
if (t) if (t)
{ //copy it to another buffer. can probably skip that tbh. { //copy it to another buffer. can probably skip that tbh.
char tmp[MAX_QPATH]; char tmp[MAX_QPATH];
char *trail;
size_t l = t->bodyend-t->bodystart; size_t l = t->bodyend-t->bodystart;
qintptr_t r;
if (l > MAX_QPATH-1) if (l > MAX_QPATH-1)
l = MAX_QPATH-1; l = MAX_QPATH-1;
memcpy(tmp, t->bodystart, l); memcpy(tmp, t->bodystart, l);
@ -295,7 +321,9 @@ static qintptr_t JSON_GetInteger(json_t *t, const char *child, int fallback)
return 0; return 0;
if (!strcmp(tmp, "true")) //special cases, for booleans if (!strcmp(tmp, "true")) //special cases, for booleans
return 1; return 1;
return (qintptr_t)strtoll(tmp, NULL, 0); r = (qintptr_t)strtoll(tmp, &trail, 0);
if (!*trail)
return r;
} }
return fallback; return fallback;
} }
@ -588,7 +616,7 @@ static struct gltf_buffer *GLTF_GetBufferData(gltf_t *gltf, int bufferidx)
{ {
json_t *b = JSON_FindIndexedChild(gltf->r, "buffers", bufferidx); json_t *b = JSON_FindIndexedChild(gltf->r, "buffers", bufferidx);
json_t *uri = JSON_FindChild(b, "uri"); json_t *uri = JSON_FindChild(b, "uri");
size_t length = JSON_GetInteger(b, "byteLength", 0); size_t length = JSON_GetUInteger(b, "byteLength", 0);
struct gltf_buffer *out; struct gltf_buffer *out;
// JSON_WarnIfChild(b, "name"); // JSON_WarnIfChild(b, "name");
@ -649,9 +677,9 @@ static qboolean GLTF_GetBufferViewData(gltf_t *gltf, int bufferview, struct gltf
buf = GLTF_GetBufferData(gltf, JSON_GetInteger(bv, "buffer", 0)); buf = GLTF_GetBufferData(gltf, JSON_GetInteger(bv, "buffer", 0));
if (!buf) if (!buf)
return false; return false;
offset = JSON_GetInteger(bv, "byteOffset", 0); offset = JSON_GetUInteger(bv, "byteOffset", 0);
view->data = (char*)buf->data + offset; view->data = (char*)buf->data + offset;
view->length = JSON_GetInteger(bv, "byteLength", 0); //required view->length = JSON_GetUInteger(bv, "byteLength", 0); //required
view->bytestride = JSON_GetInteger(bv, "byteStride", 0); view->bytestride = JSON_GetInteger(bv, "byteStride", 0);
if (offset + view->length > buf->length) if (offset + view->length > buf->length)
return false; return false;
@ -691,7 +719,7 @@ static qboolean GLTF_GetAccessor(gltf_t *gltf, int accessorid, struct gltf_acces
if (!GLTF_GetBufferViewData(gltf, JSON_GetInteger(a, "bufferView", 0), &bv)) if (!GLTF_GetBufferViewData(gltf, JSON_GetInteger(a, "bufferView", 0), &bv))
return false; return false;
offset = JSON_GetInteger(a, "byteOffset", 0); offset = JSON_GetUInteger(a, "byteOffset", 0);
if (offset > bv.length) if (offset > bv.length)
return false; return false;
out->length = bv.length - offset; out->length = bv.length - offset;