From 66c39f2dc90a7df7124e8847bb58c5acc77175c1 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 17 Jun 2022 17:17:57 +0300 Subject: [PATCH 1/6] Clean up netchan code. Stop subclassing netchan_t struct. Use simpler types. --- inc/common/net/chan.h | 58 ++--- src/common/net/chan.c | 486 +++++++++++++++++------------------------- 2 files changed, 219 insertions(+), 325 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 1b5e717c3..30ef5b926 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -59,6 +59,24 @@ typedef struct netchan_s { int incoming_acknowledged; int outgoing_sequence; + bool incoming_reliable_acknowledged; // single bit + bool incoming_reliable_sequence; // single bit, maintained local + bool reliable_sequence; // single bit + int last_reliable_sequence; // sequence number of last send + int fragment_sequence; + + byte *message_buf; // leave space for header + + // message is copied to this buffer when it is first transfered + byte *reliable_buf; // unacked reliable message + + sizebuf_t fragment_in; + byte *fragment_in_buf; + + sizebuf_t fragment_out; + byte *fragment_out_buf; + + // common methods size_t (*Transmit)(struct netchan_s *, size_t, const void *, int); size_t (*TransmitNextFragment)(struct netchan_s *); bool (*Process)(struct netchan_s *); @@ -79,44 +97,4 @@ void Netchan_Close(netchan_t *netchan); #define OOB_PRINT(sock, addr, data) \ NET_SendPacket(sock, CONST_STR_LEN("\xff\xff\xff\xff" data), addr) -//============================================================================ - -typedef struct netchan_old_s { - netchan_t pub; - -// sequencing variables - int incoming_reliable_acknowledged; // single bit - int incoming_reliable_sequence; // single bit, maintained local - int reliable_sequence; // single bit - int last_reliable_sequence; // sequence number of last send - - byte *message_buf; // leave space for header - -// message is copied to this buffer when it is first transfered - byte *reliable_buf; // unacked reliable message -} netchan_old_t; - -typedef struct netchan_new_s { - netchan_t pub; - -// sequencing variables - int incoming_reliable_acknowledged; // single bit - int incoming_reliable_sequence; // single bit, maintained local - int reliable_sequence; // single bit - int last_reliable_sequence; // sequence number of last send - int fragment_sequence; - -// reliable staging and holding areas - byte message_buf[MAX_MSGLEN]; // leave space for header - -// message is copied to this buffer when it is first transfered - byte reliable_buf[MAX_MSGLEN]; // unacked reliable message - - sizebuf_t fragment_in; - byte fragment_in_buf[MAX_MSGLEN]; - - sizebuf_t fragment_out; - byte fragment_out_buf[MAX_MSGLEN]; -} netchan_new_t; - #endif // NET_CHAN_H diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 6d38fb933..b28934daf 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -95,8 +95,6 @@ static cvar_t *showdrop; #define SHOWDROP(...) #endif -#define SOCK_TAG(sock) ((sock) == NS_SERVER ? TAG_SERVER : TAG_GENERAL) - cvar_t *net_qport; cvar_t *net_maxmsglen; cvar_t *net_chantype; @@ -139,30 +137,26 @@ Netchan_OutOfBand Sends a text message in an out-of-band datagram ================ */ -void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, - const char *format, ...) +void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *format, ...) { va_list argptr; - struct { - uint32_t header; - char data[MAX_PACKETLEN_DEFAULT - 4]; - } packet; + char data[MAX_PACKETLEN_DEFAULT]; size_t len; // write the packet header - packet.header = 0xffffffff; + memset(data, 0xff, 4); va_start(argptr, format); - len = Q_vsnprintf(packet.data, sizeof(packet.data), format, argptr); + len = Q_vsnprintf(data + 4, sizeof(data) - 4, format, argptr); va_end(argptr); - if (len >= sizeof(packet.data)) { + if (len >= sizeof(data) - 4) { Com_WPrintf("%s: overflow\n", __func__); return; } // send the datagram - NET_SendPacket(sock, &packet, len + 4, address); + NET_SendPacket(sock, data, len + 4, address); } // ============================================================================ @@ -183,46 +177,45 @@ transmition / retransmition of the reliable messages. A 0 length will still generate a packet and deal with the reliable messages. ================ */ -static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets) +static size_t NetchanOld_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { - netchan_old_t *chan = (netchan_old_t *)netchan; sizebuf_t send; byte send_buf[MAX_PACKETLEN]; bool send_reliable; - uint32_t w1, w2; - int i; + int i, w1, w2; // check for message overflow - if (netchan->message.overflowed) { - netchan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", - NET_AdrToString(&netchan->remote_address)); + if (chan->message.overflowed) { + chan->fatal_error = true; + Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); return 0; } send_reliable = false; // if the remote side dropped the last reliable message, resend it - if (netchan->incoming_acknowledged > chan->last_reliable_sequence && + if (chan->incoming_acknowledged > chan->last_reliable_sequence && chan->incoming_reliable_acknowledged != chan->reliable_sequence) { send_reliable = true; } // if the reliable transmit buffer is empty, copy the current message out - if (!netchan->reliable_length && netchan->message.cursize) { + if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, - netchan->message.cursize); - netchan->reliable_length = netchan->message.cursize; - netchan->message.cursize = 0; + memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + chan->reliable_length = chan->message.cursize; + chan->message.cursize = 0; chan->reliable_sequence ^= 1; } // write the packet header - w1 = (netchan->outgoing_sequence & 0x7FFFFFFF) | - ((unsigned)send_reliable << 31); - w2 = (netchan->incoming_sequence & 0x7FFFFFFF) | - ((unsigned)chan->incoming_reliable_sequence << 31); + w1 = chan->outgoing_sequence & 0x7FFFFFFF; + if (send_reliable) + w1 |= 0x80000000; + + w2 = chan->incoming_sequence & 0x7FFFFFFF; + if (chan->incoming_reliable_sequence) + w2 |= 0x80000000; SZ_TagInit(&send, send_buf, sizeof(send_buf), "nc_send_old"); @@ -231,32 +224,31 @@ static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void #if USE_CLIENT // send the qport if we are a client - if (netchan->sock == NS_CLIENT) { - if (netchan->protocol < PROTOCOL_VERSION_R1Q2) { - SZ_WriteShort(&send, netchan->qport); - } else if (netchan->qport) { - SZ_WriteByte(&send, netchan->qport); + if (chan->sock == NS_CLIENT) { + if (chan->protocol < PROTOCOL_VERSION_R1Q2) { + SZ_WriteShort(&send, chan->qport); + } else if (chan->qport) { + SZ_WriteByte(&send, chan->qport); } } #endif // copy the reliable message to the packet first if (send_reliable) { - SZ_Write(&send, chan->reliable_buf, netchan->reliable_length); - chan->last_reliable_sequence = netchan->outgoing_sequence; + SZ_Write(&send, chan->reliable_buf, chan->reliable_length); + chan->last_reliable_sequence = chan->outgoing_sequence; } // add the unreliable part if space is available if (send.maxsize - send.cursize >= length) SZ_Write(&send, data, length); else - Com_WPrintf("%s: dumped unreliable\n", - NET_AdrToString(&netchan->remote_address)); + Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", send.cursize, - netchan->outgoing_sequence, - netchan->incoming_sequence, + chan->outgoing_sequence, + chan->incoming_sequence, chan->incoming_reliable_sequence); if (send_reliable) { SHOWPACKET(" reliable=%i", chan->reliable_sequence); @@ -265,13 +257,12 @@ static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void // send the datagram for (i = 0; i < numpackets; i++) { - NET_SendPacket(netchan->sock, send.data, send.cursize, - &netchan->remote_address); + NET_SendPacket(chan->sock, send.data, send.cursize, &chan->remote_address); } - netchan->outgoing_sequence++; - netchan->reliable_ack_pending = false; - netchan->last_sent = com_localTime; + chan->outgoing_sequence++; + chan->reliable_ack_pending = false; + chan->last_sent = com_localTime; return send.cursize * numpackets; } @@ -284,11 +275,10 @@ called when the current net_message is from remote_address modifies net_message so that it points to the packet payload ================= */ -static bool NetchanOld_Process(netchan_t *netchan) +static bool NetchanOld_Process(netchan_t *chan) { - netchan_old_t *chan = (netchan_old_t *)netchan; - uint32_t sequence, sequence_ack; - uint32_t reliable_ack, reliable_message; + int sequence, sequence_ack; + bool reliable_ack, reliable_message; // get sequence numbers MSG_BeginReading(); @@ -296,19 +286,16 @@ static bool NetchanOld_Process(netchan_t *netchan) sequence_ack = MSG_ReadLong(); // read the qport if we are a server -#if USE_CLIENT - if (netchan->sock == NS_SERVER) -#endif - { - if (netchan->protocol < PROTOCOL_VERSION_R1Q2) { + if (chan->sock == NS_SERVER) { + if (chan->protocol < PROTOCOL_VERSION_R1Q2) { MSG_ReadShort(); - } else if (netchan->qport) { + } else if (chan->qport) { MSG_ReadByte(); } } - reliable_message = sequence >> 31; - reliable_ack = sequence_ack >> 31; + reliable_message = sequence & 0x80000000; + reliable_ack = sequence_ack & 0x80000000; sequence &= 0x7FFFFFFF; sequence_ack &= 0x7FFFFFFF; @@ -326,21 +313,21 @@ static bool NetchanOld_Process(netchan_t *netchan) // // discard stale or duplicated packets // - if (sequence <= netchan->incoming_sequence) { + if (sequence <= chan->incoming_sequence) { SHOWDROP("%s: out of order packet %i at %i\n", - NET_AdrToString(&netchan->remote_address), - sequence, netchan->incoming_sequence); + NET_AdrToString(&chan->remote_address), + sequence, chan->incoming_sequence); return false; } // // dropped packets don't keep the message from being used // - netchan->dropped = sequence - (netchan->incoming_sequence + 1); - if (netchan->dropped > 0) { + chan->dropped = sequence - (chan->incoming_sequence + 1); + if (chan->dropped > 0) { SHOWDROP("%s: dropped %i packets at %i\n", - NET_AdrToString(&netchan->remote_address), - netchan->dropped, sequence); + NET_AdrToString(&chan->remote_address), + chan->dropped, sequence); } // @@ -349,25 +336,25 @@ static bool NetchanOld_Process(netchan_t *netchan) // chan->incoming_reliable_acknowledged = reliable_ack; if (reliable_ack == chan->reliable_sequence) - netchan->reliable_length = 0; // it has been received + chan->reliable_length = 0; // it has been received // // if this message contains a reliable message, bump incoming_reliable_sequence // - netchan->incoming_sequence = sequence; - netchan->incoming_acknowledged = sequence_ack; + chan->incoming_sequence = sequence; + chan->incoming_acknowledged = sequence_ack; if (reliable_message) { - netchan->reliable_ack_pending = true; + chan->reliable_ack_pending = true; chan->incoming_reliable_sequence ^= 1; } // // the message can now be read from the current message pointer // - netchan->last_received = com_localTime; + chan->last_received = com_localTime; - netchan->total_dropped += netchan->dropped; - netchan->total_received += netchan->dropped + 1; + chan->total_dropped += chan->dropped; + chan->total_received += chan->dropped + 1; return true; } @@ -377,79 +364,38 @@ static bool NetchanOld_Process(netchan_t *netchan) NetchanOld_ShouldUpdate ================ */ -static bool NetchanOld_ShouldUpdate(netchan_t *netchan) +static bool NetchanOld_ShouldUpdate(netchan_t *chan) { - if (netchan->message.cursize || netchan->reliable_ack_pending || - com_localTime - netchan->last_sent > 1000) { - return true; - } - - return false; -} - -/* -============== -NetchanOld_Setup - -called to open a channel to a remote system -============== -*/ -static netchan_t *NetchanOld_Setup(netsrc_t sock, const netadr_t *adr, - int qport, size_t maxpacketlen) -{ - netchan_old_t *chan; - netchan_t *netchan; - - chan = Z_TagMallocz(sizeof(*chan), SOCK_TAG(sock)); - netchan = (netchan_t *)chan; - netchan->sock = sock; - netchan->remote_address = *adr; - netchan->qport = qport; - netchan->maxpacketlen = maxpacketlen; - netchan->last_received = com_localTime; - netchan->last_sent = com_localTime; - netchan->incoming_sequence = 0; - netchan->outgoing_sequence = 1; - - netchan->Process = NetchanOld_Process; - netchan->Transmit = NetchanOld_Transmit; - netchan->TransmitNextFragment = NetchanOld_TransmitNextFragment; - netchan->ShouldUpdate = NetchanOld_ShouldUpdate; - - chan->message_buf = Z_TagMalloc(maxpacketlen, SOCK_TAG(sock)); - SZ_Init(&netchan->message, chan->message_buf, maxpacketlen); - - chan->reliable_buf = Z_TagMalloc(maxpacketlen, SOCK_TAG(sock)); - - return netchan; + return chan->message.cursize + || chan->reliable_ack_pending + || com_localTime - chan->last_sent > 1000; } // ============================================================================ - /* =============== NetchanNew_TransmitNextFragment ================ */ -static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan) +static size_t NetchanNew_TransmitNextFragment(netchan_t *chan) { - netchan_new_t *chan = (netchan_new_t *)netchan; sizebuf_t send; byte send_buf[MAX_PACKETLEN]; - bool send_reliable; - uint32_t w1, w2; - uint16_t offset; + bool send_reliable, more_fragments; + int w1, w2, offset; size_t fragment_length; - bool more_fragments; - send_reliable = netchan->reliable_length; + send_reliable = chan->reliable_length; // write the packet header - w1 = (netchan->outgoing_sequence & 0x3FFFFFFF) | (1 << 30) | - ((unsigned)send_reliable << 31); - w2 = (netchan->incoming_sequence & 0x3FFFFFFF) | (0 << 30) | - ((unsigned)chan->incoming_reliable_sequence << 31); + w1 = (chan->outgoing_sequence & 0x3FFFFFFF) | (1 << 30); + if (send_reliable) + w1 |= 0x80000000; + + w2 = chan->incoming_sequence & 0x3FFFFFFF; + if (chan->incoming_reliable_sequence) + w2 |= 0x80000000; SZ_TagInit(&send, send_buf, sizeof(send_buf), "nc_send_frg"); @@ -458,36 +404,35 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan) #if USE_CLIENT // send the qport if we are a client - if (netchan->sock == NS_CLIENT && netchan->qport) { - SZ_WriteByte(&send, netchan->qport); + if (chan->sock == NS_CLIENT && chan->qport) { + SZ_WriteByte(&send, chan->qport); } #endif fragment_length = chan->fragment_out.cursize - chan->fragment_out.readcount; - if (fragment_length > netchan->maxpacketlen) { - fragment_length = netchan->maxpacketlen; + if (fragment_length > chan->maxpacketlen) { + fragment_length = chan->maxpacketlen; } more_fragments = true; - if (chan->fragment_out.readcount + fragment_length == - chan->fragment_out.cursize) { + if (chan->fragment_out.readcount + fragment_length == chan->fragment_out.cursize) { more_fragments = false; } // write fragment offset - offset = (chan->fragment_out.readcount & 0x7FFF) | - (more_fragments << 15); + offset = chan->fragment_out.readcount & 0x7FFF; + if (more_fragments) + offset |= 0x8000; SZ_WriteShort(&send, offset); // write fragment contents - SZ_Write(&send, chan->fragment_out.data + chan->fragment_out.readcount, - fragment_length); + SZ_Write(&send, chan->fragment_out.data + chan->fragment_out.readcount, fragment_length); SHOWPACKET("send %4zu : s=%d ack=%d rack=%d " "fragment_offset=%zu more_fragments=%d", send.cursize, - netchan->outgoing_sequence, - netchan->incoming_sequence, + chan->outgoing_sequence, + chan->incoming_sequence, chan->incoming_reliable_sequence, chan->fragment_out.readcount, more_fragments); @@ -497,18 +442,17 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan) SHOWPACKET("\n"); chan->fragment_out.readcount += fragment_length; - netchan->fragment_pending = more_fragments; + chan->fragment_pending = more_fragments; // if the message has been sent completely, clear the fragment buffer - if (!netchan->fragment_pending) { - netchan->outgoing_sequence++; - netchan->last_sent = com_localTime; + if (!chan->fragment_pending) { + chan->outgoing_sequence++; + chan->last_sent = com_localTime; SZ_Clear(&chan->fragment_out); } // send the datagram - NET_SendPacket(netchan->sock, send.data, send.cursize, - &netchan->remote_address); + NET_SendPacket(chan->sock, send.data, send.cursize, &chan->remote_address); return send.cursize; } @@ -518,65 +462,63 @@ static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan) NetchanNew_Transmit ================ */ -static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets) +static size_t NetchanNew_Transmit(netchan_t *chan, size_t length, const void *data, int numpackets) { - netchan_new_t *chan = (netchan_new_t *)netchan; sizebuf_t send; byte send_buf[MAX_PACKETLEN]; bool send_reliable; - uint32_t w1, w2; - int i; + int i, w1, w2; // check for message overflow - if (netchan->message.overflowed) { - netchan->fatal_error = true; - Com_WPrintf("%s: outgoing message overflow\n", - NET_AdrToString(&netchan->remote_address)); + if (chan->message.overflowed) { + chan->fatal_error = true; + Com_WPrintf("%s: outgoing message overflow\n", NET_AdrToString(&chan->remote_address)); return 0; } - if (netchan->fragment_pending) { - return NetchanNew_TransmitNextFragment(netchan); + if (chan->fragment_pending) { + return NetchanNew_TransmitNextFragment(chan); } send_reliable = false; // if the remote side dropped the last reliable message, resend it - if (netchan->incoming_acknowledged > chan->last_reliable_sequence && + if (chan->incoming_acknowledged > chan->last_reliable_sequence && chan->incoming_reliable_acknowledged != chan->reliable_sequence) { send_reliable = true; } // if the reliable transmit buffer is empty, copy the current message out - if (!netchan->reliable_length && netchan->message.cursize) { + if (!chan->reliable_length && chan->message.cursize) { send_reliable = true; - memcpy(chan->reliable_buf, chan->message_buf, - netchan->message.cursize); - netchan->reliable_length = netchan->message.cursize; - netchan->message.cursize = 0; + memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + chan->reliable_length = chan->message.cursize; + chan->message.cursize = 0; chan->reliable_sequence ^= 1; } - if (length > netchan->maxpacketlen || (send_reliable && - (netchan->reliable_length + length > netchan->maxpacketlen))) { + if (length > chan->maxpacketlen || (send_reliable && + (chan->reliable_length + length > chan->maxpacketlen))) { if (send_reliable) { - chan->last_reliable_sequence = netchan->outgoing_sequence; - SZ_Write(&chan->fragment_out, chan->reliable_buf, - netchan->reliable_length); + chan->last_reliable_sequence = chan->outgoing_sequence; + SZ_Write(&chan->fragment_out, chan->reliable_buf, chan->reliable_length); } // add the unreliable part if space is available if (chan->fragment_out.maxsize - chan->fragment_out.cursize >= length) SZ_Write(&chan->fragment_out, data, length); else - Com_WPrintf("%s: dumped unreliable\n", - NET_AdrToString(&netchan->remote_address)); - return NetchanNew_TransmitNextFragment(netchan); + Com_WPrintf("%s: dumped unreliable\n", NET_AdrToString(&chan->remote_address)); + return NetchanNew_TransmitNextFragment(chan); } // write the packet header - w1 = (netchan->outgoing_sequence & 0x3FFFFFFF) | ((unsigned)send_reliable << 31); - w2 = (netchan->incoming_sequence & 0x3FFFFFFF) | - ((unsigned)chan->incoming_reliable_sequence << 31); + w1 = chan->outgoing_sequence & 0x3FFFFFFF; + if (send_reliable) + w1 |= 0x80000000; + + w2 = chan->incoming_sequence & 0x3FFFFFFF; + if (chan->incoming_reliable_sequence) + w2 |= 0x80000000; SZ_TagInit(&send, send_buf, sizeof(send_buf), "nc_send_new"); @@ -585,15 +527,15 @@ static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void #if USE_CLIENT // send the qport if we are a client - if (netchan->sock == NS_CLIENT && netchan->qport) { - SZ_WriteByte(&send, netchan->qport); + if (chan->sock == NS_CLIENT && chan->qport) { + SZ_WriteByte(&send, chan->qport); } #endif // copy the reliable message to the packet first if (send_reliable) { - chan->last_reliable_sequence = netchan->outgoing_sequence; - SZ_Write(&send, chan->reliable_buf, netchan->reliable_length); + chan->last_reliable_sequence = chan->outgoing_sequence; + SZ_Write(&send, chan->reliable_buf, chan->reliable_length); } // add the unreliable part @@ -601,8 +543,8 @@ static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void SHOWPACKET("send %4zu : s=%d ack=%d rack=%d", send.cursize, - netchan->outgoing_sequence, - netchan->incoming_sequence, + chan->outgoing_sequence, + chan->incoming_sequence, chan->incoming_reliable_sequence); if (send_reliable) { SHOWPACKET(" reliable=%d", chan->reliable_sequence); @@ -611,13 +553,12 @@ static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void // send the datagram for (i = 0; i < numpackets; i++) { - NET_SendPacket(netchan->sock, send.data, send.cursize, - &netchan->remote_address); + NET_SendPacket(chan->sock, send.data, send.cursize, &chan->remote_address); } - netchan->outgoing_sequence++; - netchan->reliable_ack_pending = false; - netchan->last_sent = com_localTime; + chan->outgoing_sequence++; + chan->reliable_ack_pending = false; + chan->last_sent = com_localTime; return send.cursize * numpackets; } @@ -627,12 +568,10 @@ static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void NetchanNew_Process ================= */ -static bool NetchanNew_Process(netchan_t *netchan) +static bool NetchanNew_Process(netchan_t *chan) { - netchan_new_t *chan = (netchan_new_t *)netchan; - uint32_t sequence, sequence_ack, reliable_ack; - bool reliable_message, fragmented_message, more_fragments; - uint16_t fragment_offset; + int sequence, sequence_ack, fragment_offset; + bool reliable_message, reliable_ack, fragmented_message, more_fragments; size_t length; // get sequence numbers @@ -641,16 +580,13 @@ static bool NetchanNew_Process(netchan_t *netchan) sequence_ack = MSG_ReadLong(); // read the qport if we are a server -#if USE_CLIENT - if (netchan->sock == NS_SERVER) -#endif - if (netchan->qport) { - MSG_ReadByte(); - } + if (chan->sock == NS_SERVER && chan->qport) { + MSG_ReadByte(); + } - reliable_message = sequence >> 31; - reliable_ack = sequence_ack >> 31; - fragmented_message = (sequence >> 30) & 1; + reliable_message = sequence & 0x80000000; + reliable_ack = sequence_ack & 0x80000000; + fragmented_message = sequence & 0x40000000; sequence &= 0x3FFFFFFF; sequence_ack &= 0x3FFFFFFF; @@ -659,7 +595,7 @@ static bool NetchanNew_Process(netchan_t *netchan) more_fragments = false; if (fragmented_message) { fragment_offset = MSG_ReadWord(); - more_fragments = fragment_offset >> 15; + more_fragments = fragment_offset & 0x8000; fragment_offset &= 0x7FFF; } @@ -677,21 +613,21 @@ static bool NetchanNew_Process(netchan_t *netchan) // // discard stale or duplicated packets // - if (sequence <= netchan->incoming_sequence) { + if (sequence <= chan->incoming_sequence) { SHOWDROP("%s: out of order packet %i at %i\n", - NET_AdrToString(&netchan->remote_address), - sequence, netchan->incoming_sequence); + NET_AdrToString(&chan->remote_address), + sequence, chan->incoming_sequence); return false; } // // dropped packets don't keep the message from being used // - netchan->dropped = sequence - (netchan->incoming_sequence + 1); - if (netchan->dropped > 0) { + chan->dropped = sequence - (chan->incoming_sequence + 1); + if (chan->dropped > 0) { SHOWDROP("%s: dropped %i packets at %i\n", - NET_AdrToString(&netchan->remote_address), - netchan->dropped, sequence); + NET_AdrToString(&chan->remote_address), + chan->dropped, sequence); } // @@ -700,10 +636,9 @@ static bool NetchanNew_Process(netchan_t *netchan) // chan->incoming_reliable_acknowledged = reliable_ack; if (reliable_ack == chan->reliable_sequence) { - netchan->reliable_length = 0; // it has been received + chan->reliable_length = 0; // it has been received } - // // parse fragment header, if any // @@ -716,54 +651,52 @@ static bool NetchanNew_Process(netchan_t *netchan) if (fragment_offset < chan->fragment_in.cursize) { SHOWDROP("%s: out of order fragment at %i\n", - NET_AdrToString(&netchan->remote_address), sequence); + NET_AdrToString(&chan->remote_address), sequence); return false; } if (fragment_offset > chan->fragment_in.cursize) { SHOWDROP("%s: dropped fragment(s) at %i\n", - NET_AdrToString(&netchan->remote_address), sequence); + NET_AdrToString(&chan->remote_address), sequence); return false; } length = msg_read.cursize - msg_read.readcount; if (chan->fragment_in.cursize + length > chan->fragment_in.maxsize) { SHOWDROP("%s: oversize fragment at %i\n", - NET_AdrToString(&netchan->remote_address), sequence); + NET_AdrToString(&chan->remote_address), sequence); return false; } - SZ_Write(&chan->fragment_in, msg_read.data + - msg_read.readcount, length); + SZ_Write(&chan->fragment_in, msg_read.data + msg_read.readcount, length); if (more_fragments) { return false; } // message has been sucessfully assembled SZ_Clear(&msg_read); - SZ_Write(&msg_read, chan->fragment_in.data, - chan->fragment_in.cursize); + SZ_Write(&msg_read, chan->fragment_in.data, chan->fragment_in.cursize); SZ_Clear(&chan->fragment_in); } - netchan->incoming_sequence = sequence; - netchan->incoming_acknowledged = sequence_ack; + chan->incoming_sequence = sequence; + chan->incoming_acknowledged = sequence_ack; // // if this message contains a reliable message, bump incoming_reliable_sequence // if (reliable_message) { - netchan->reliable_ack_pending = true; + chan->reliable_ack_pending = true; chan->incoming_reliable_sequence ^= 1; } // // the message can now be read from the current message pointer // - netchan->last_received = com_localTime; + chan->last_received = com_localTime; - netchan->total_dropped += netchan->dropped; - netchan->total_received += netchan->dropped + 1; + chan->total_dropped += chan->dropped; + chan->total_received += chan->dropped + 1; return true; } @@ -773,55 +706,12 @@ static bool NetchanNew_Process(netchan_t *netchan) NetchanNew_ShouldUpdate ============== */ -static bool NetchanNew_ShouldUpdate(netchan_t *netchan) +static bool NetchanNew_ShouldUpdate(netchan_t *chan) { - netchan_new_t *chan = (netchan_new_t *)netchan; - - if (netchan->message.cursize || - netchan->reliable_ack_pending || - chan->fragment_out.cursize || - com_localTime - netchan->last_sent > 1000) { - return true; - } - - return false; -} - -/* -============== -NetchanNew_Setup -============== -*/ -static netchan_t *NetchanNew_Setup(netsrc_t sock, const netadr_t *adr, - int qport, size_t maxpacketlen) -{ - netchan_new_t *chan; - netchan_t *netchan; - - chan = Z_TagMallocz(sizeof(*chan), SOCK_TAG(sock)); - netchan = (netchan_t *)chan; - netchan->sock = sock; - netchan->remote_address = *adr; - netchan->qport = qport; - netchan->maxpacketlen = maxpacketlen; - netchan->last_received = com_localTime; - netchan->last_sent = com_localTime; - netchan->incoming_sequence = 0; - netchan->outgoing_sequence = 1; - - netchan->Process = NetchanNew_Process; - netchan->Transmit = NetchanNew_Transmit; - netchan->TransmitNextFragment = NetchanNew_TransmitNextFragment; - netchan->ShouldUpdate = NetchanNew_ShouldUpdate; - - SZ_Init(&netchan->message, chan->message_buf, - sizeof(chan->message_buf)); - SZ_TagInit(&chan->fragment_in, chan->fragment_in_buf, - sizeof(chan->fragment_in_buf), "nc_frg_in"); - SZ_TagInit(&chan->fragment_out, chan->fragment_out_buf, - sizeof(chan->fragment_out_buf), "nc_frg_out"); - - return netchan; + return chan->message.cursize + || chan->reliable_ack_pending + || chan->fragment_out.cursize + || com_localTime - chan->last_sent > 1000; } /* @@ -832,26 +722,57 @@ Netchan_Setup netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) { - netchan_t *netchan; + int tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; + netchan_t *chan; clamp(maxpacketlen, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE); + chan = Z_TagMallocz(sizeof(*chan), tag); + chan->type = type; + chan->protocol = protocol; + chan->sock = sock; + chan->remote_address = *adr; + chan->qport = qport; + chan->maxpacketlen = maxpacketlen; + chan->last_received = com_localTime; + chan->last_sent = com_localTime; + chan->incoming_sequence = 0; + chan->outgoing_sequence = 1; + switch (type) { case NETCHAN_OLD: - netchan = NetchanOld_Setup(sock, adr, qport, maxpacketlen); + chan->Process = NetchanOld_Process; + chan->Transmit = NetchanOld_Transmit; + chan->TransmitNextFragment = NetchanOld_TransmitNextFragment; + chan->ShouldUpdate = NetchanOld_ShouldUpdate; + + chan->message_buf = Z_TagMalloc(maxpacketlen * 2, tag); + chan->reliable_buf = chan->message_buf + maxpacketlen; + + SZ_Init(&chan->message, chan->message_buf, maxpacketlen); break; + case NETCHAN_NEW: - netchan = NetchanNew_Setup(sock, adr, qport, maxpacketlen); + chan->Process = NetchanNew_Process; + chan->Transmit = NetchanNew_Transmit; + chan->TransmitNextFragment = NetchanNew_TransmitNextFragment; + chan->ShouldUpdate = NetchanNew_ShouldUpdate; + + chan->message_buf = Z_TagMalloc(MAX_MSGLEN * 4, tag); + chan->reliable_buf = chan->message_buf + MAX_MSGLEN; + chan->fragment_in_buf = chan->message_buf + MAX_MSGLEN * 2; + chan->fragment_out_buf = chan->message_buf + MAX_MSGLEN * 3; + + SZ_Init(&chan->message, chan->message_buf, MAX_MSGLEN); + SZ_TagInit(&chan->fragment_in, chan->fragment_in_buf, MAX_MSGLEN, "nc_frg_in"); + SZ_TagInit(&chan->fragment_out, chan->fragment_out_buf, MAX_MSGLEN, "nc_frg_out"); break; + default: Q_assert(!"bad type"); - netchan = NULL; } - netchan->protocol = protocol; - netchan->type = type; - - return netchan; + return chan; } @@ -860,14 +781,9 @@ netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, Netchan_Close ============== */ -void Netchan_Close(netchan_t *netchan) +void Netchan_Close(netchan_t *chan) { - if (netchan->type == NETCHAN_OLD) { - netchan_old_t *chan = (netchan_old_t *)netchan; - - Z_Free(chan->message_buf); - Z_Free(chan->reliable_buf); - } - Z_Free(netchan); + Z_Free(chan->message_buf); + Z_Free(chan); } From a9208e8e36878a1b35f581dd1a9e67b9afbbb6e9 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 21 Dec 2022 20:32:33 +0300 Subject: [PATCH 2/6] Allow Netchan_Close() with NULL argument. --- src/common/net/chan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/net/chan.c b/src/common/net/chan.c index b28934daf..ff665803e 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -783,7 +783,9 @@ Netchan_Close */ void Netchan_Close(netchan_t *chan) { - Z_Free(chan->message_buf); - Z_Free(chan); + if (chan) { + Z_Free(chan->message_buf); + Z_Free(chan); + } } From b1c90358b29eb5c7604e5d7e78a6342dc738c39e Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Wed, 21 Dec 2022 20:32:56 +0300 Subject: [PATCH 3/6] Fix variable type. --- src/common/net/chan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/net/chan.c b/src/common/net/chan.c index ff665803e..341cde8fb 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -722,7 +722,7 @@ Netchan_Setup netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) { - int tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; + memtag_t tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; netchan_t *chan; clamp(maxpacketlen, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE); From e234eba1639e106bbfe4068404337431b3d602b6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 22 Dec 2022 16:40:08 +0300 Subject: [PATCH 4/6] Stop allocating netchan_t on heap. It used to be subclassed, but not anymore. Just store it in parent struct. --- inc/common/net/chan.h | 4 +- src/client/client.h | 2 +- src/client/entities.c | 5 +- src/client/input.c | 41 +++++++------- src/client/main.c | 122 +++++++++++++++++----------------------- src/client/parse.c | 16 ++---- src/client/predict.c | 6 +- src/client/screen.c | 6 +- src/client/view.c | 7 +-- src/common/net/chan.c | 20 +++---- src/server/ac.c | 10 ++-- src/server/commands.c | 13 ++--- src/server/main.c | 37 ++++++------ src/server/mvd.c | 4 +- src/server/mvd/client.c | 2 +- src/server/mvd/game.c | 4 +- src/server/send.c | 60 ++++++++++---------- src/server/server.h | 6 +- src/server/user.c | 18 +++--- 19 files changed, 170 insertions(+), 213 deletions(-) diff --git a/inc/common/net/chan.h b/inc/common/net/chan.h index 30ef5b926..d7a5cc746 100644 --- a/inc/common/net/chan.h +++ b/inc/common/net/chan.h @@ -90,8 +90,8 @@ extern cvar_t *net_chantype; void Netchan_Init(void); void Netchan_OutOfBand(netsrc_t sock, const netadr_t *adr, const char *format, ...) q_printf(3, 4); -netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, - const netadr_t *adr, int qport, size_t maxpacketlen, int protocol); +void Netchan_Setup(netchan_t *netchan, netsrc_t sock, netchan_type_t type, + const netadr_t *adr, int qport, size_t maxpacketlen, int protocol); void Netchan_Close(netchan_t *netchan); #define OOB_PRINT(sock, addr, data) \ diff --git a/src/client/client.h b/src/client/client.h index 877406a29..23992406d 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -419,7 +419,7 @@ typedef struct client_static_s { int quakePort; // a 16 bit value that allows quake servers // to work around address translating routers - netchan_t *netchan; + netchan_t netchan; int serverProtocol; // in case we are doing some kind of version hack int protocolVersion; // minor version diff --git a/src/client/entities.c b/src/client/entities.c index c653b2e19..2273766f6 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -250,10 +250,7 @@ static void set_active_state(void) #endif cl.frameflags = 0; - - if (cls.netchan) { - cl.initialSeq = cls.netchan->outgoing_sequence; - } + cl.initialSeq = cls.netchan.outgoing_sequence; if (cls.demo.playback) { // init some demo things diff --git a/src/client/input.c b/src/client/input.c index 69c39810d..b5ab948be 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -375,7 +375,7 @@ static void IN_AttackDown(void) { KeyDown(&in_attack); - if (cl_instantpacket->integer && cls.state == ca_active && cls.netchan) { + if (cl_instantpacket->integer && cls.state == ca_active && !cls.demo.playback) { cl.sendPacketNow = true; } } @@ -389,7 +389,7 @@ static void IN_UseDown(void) { KeyDown(&in_use); - if (cl_instantpacket->integer && cls.state == ca_active && cls.netchan) { + if (cl_instantpacket->integer && cls.state == ca_active && !cls.demo.playback) { cl.sendPacketNow = true; } } @@ -842,7 +842,7 @@ static inline bool ready_to_send(void) if (cl.sendPacketNow) { return true; } - if (cls.netchan->message.cursize || cls.netchan->reliable_ack_pending) { + if (cls.netchan.message.cursize || cls.netchan.reliable_ack_pending) { return true; } if (!cl_maxpackets->integer) { @@ -889,7 +889,7 @@ static void CL_SendDefaultCmd(void) client_history_t *history; // archive this packet - history = &cl.history[cls.netchan->outgoing_sequence & CMD_MASK]; + history = &cl.history[cls.netchan.outgoing_sequence & CMD_MASK]; history->cmdNumber = cl.cmdNumber; history->sent = cls.realtime; // for ping calculation history->rcvd = 0; @@ -898,7 +898,7 @@ static void CL_SendDefaultCmd(void) // see if we are ready to send this packet if (!ready_to_send_hacked()) { - cls.netchan->outgoing_sequence++; // just drop the packet + cls.netchan.outgoing_sequence++; // just drop the packet return; } @@ -942,9 +942,9 @@ static void CL_SendDefaultCmd(void) if (cls.serverProtocol <= PROTOCOL_VERSION_DEFAULT) { // calculate a checksum over the move commands msg_write.data[checksumIndex] = COM_BlockSequenceCRCByte( - msg_write.data + checksumIndex + 1, - msg_write.cursize - checksumIndex - 1, - cls.netchan->outgoing_sequence); + msg_write.data + checksumIndex + 1, + msg_write.cursize - checksumIndex - 1, + cls.netchan.outgoing_sequence); } P_FRAMES++; @@ -952,7 +952,7 @@ static void CL_SendDefaultCmd(void) // // deliver the message // - cursize = cls.netchan->Transmit(cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer) { Com_Printf("%zu ", cursize); @@ -983,7 +983,7 @@ static void CL_SendBatchedCmd(void) } // archive this packet - seq = cls.netchan->outgoing_sequence; + seq = cls.netchan.outgoing_sequence; history = &cl.history[seq & CMD_MASK]; history->cmdNumber = cl.cmdNumber; history->sent = cls.realtime; // for ping calculation @@ -1052,7 +1052,7 @@ static void CL_SendBatchedCmd(void) // // deliver the message // - cursize = cls.netchan->Transmit(cls.netchan, msg_write.cursize, msg_write.data, 1); + cursize = cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 1); #if USE_DEBUG if (cl_showpackets->integer == 1) { Com_Printf("%zu(%i) ", cursize, totalCmds); @@ -1072,7 +1072,7 @@ static void CL_SendKeepAlive(void) size_t cursize q_unused; // archive this packet - history = &cl.history[cls.netchan->outgoing_sequence & CMD_MASK]; + history = &cl.history[cls.netchan.outgoing_sequence & CMD_MASK]; history->cmdNumber = cl.cmdNumber; history->sent = cls.realtime; // for ping calculation history->rcvd = 0; @@ -1081,7 +1081,7 @@ static void CL_SendKeepAlive(void) cl.lastTransmitCmdNumber = cl.cmdNumber; cl.lastTransmitCmdNumberReal = cl.cmdNumber; - cursize = cls.netchan->Transmit(cls.netchan, 0, "", 1); + cursize = cls.netchan.Transmit(&cls.netchan, 0, "", 1); #if USE_DEBUG if (cl_showpackets->integer) { Com_Printf("%zu ", cursize); @@ -1100,7 +1100,7 @@ static void CL_SendUserinfo(void) Com_DDPrintf("%s: %u: full update\n", __func__, com_framenum); MSG_WriteByte(clc_userinfo); MSG_WriteData(userinfo, len + 1); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } else if (cls.serverProtocol == PROTOCOL_VERSION_Q2PRO) { Com_DDPrintf("%s: %u: %d updates\n", __func__, com_framenum, cls.userinfo_modified); @@ -1115,7 +1115,7 @@ static void CL_SendUserinfo(void) MSG_WriteString(NULL); } } - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } else { Com_WPrintf("%s: update count is %d, should never happen.\n", __func__, cls.userinfo_modified); @@ -1129,8 +1129,8 @@ static void CL_SendReliable(void) cls.userinfo_modified = 0; } - if (cls.netchan->message.overflowed) { - SZ_Clear(&cls.netchan->message); + if (cls.netchan.message.overflowed) { + SZ_Clear(&cls.netchan.message); Com_Error(ERR_DROP, "Reliable message overflowed"); } } @@ -1141,9 +1141,8 @@ void CL_SendCmd(void) return; // not talking to a server } - // generate usercmds while playing a demo, - // but do not send them - if (!cls.netchan) { + // generate usercmds while playing a demo, but do not send them + if (cls.demo.playback) { return; } @@ -1152,7 +1151,7 @@ void CL_SendCmd(void) CL_SendReliable(); // just keepalive or update reliable - if (cls.netchan->ShouldUpdate(cls.netchan)) { + if (cls.netchan.ShouldUpdate(&cls.netchan)) { CL_SendKeepAlive(); } diff --git a/src/client/main.c b/src/client/main.c index 8f5b57c52..897240306 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -188,10 +188,7 @@ static void CL_UpdateGunSetting(void) { int nogun; - if (!cls.netchan) { - return; - } - if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) { + if (cls.netchan.protocol < PROTOCOL_VERSION_R1Q2) { return; } @@ -204,68 +201,56 @@ static void CL_UpdateGunSetting(void) MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_NOGUN); MSG_WriteShort(nogun); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } static void CL_UpdateGibSetting(void) { - if (!cls.netchan) { - return; - } - if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) { + if (cls.netchan.protocol != PROTOCOL_VERSION_Q2PRO) { return; } MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_NOGIBS); MSG_WriteShort(!cl_gibs->integer); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } static void CL_UpdateFootstepsSetting(void) { - if (!cls.netchan) { - return; - } - if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) { + if (cls.netchan.protocol != PROTOCOL_VERSION_Q2PRO) { return; } MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_NOFOOTSTEPS); MSG_WriteShort(!cl_footsteps->integer); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } static void CL_UpdatePredictSetting(void) { - if (!cls.netchan) { - return; - } - if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) { + if (cls.netchan.protocol != PROTOCOL_VERSION_Q2PRO) { return; } MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_NOPREDICT); MSG_WriteShort(!cl_predict->integer); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } #if USE_FPS static void CL_UpdateRateSetting(void) { - if (!cls.netchan) { - return; - } - if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) { + if (cls.netchan.protocol != PROTOCOL_VERSION_Q2PRO) { return; } MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_FPS); MSG_WriteShort(cl_updaterate->integer); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } #endif @@ -273,10 +258,7 @@ void CL_UpdateRecordingSetting(void) { int rec; - if (!cls.netchan) { - return; - } - if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) { + if (cls.netchan.protocol < PROTOCOL_VERSION_R1Q2) { return; } @@ -295,7 +277,7 @@ void CL_UpdateRecordingSetting(void) MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_RECORDING); MSG_WriteShort(rec); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } /* @@ -305,7 +287,7 @@ CL_ClientCommand */ void CL_ClientCommand(const char *string) { - if (!cls.netchan) { + if (!cls.netchan.protocol) { return; } @@ -313,7 +295,7 @@ void CL_ClientCommand(const char *string) MSG_WriteByte(clc_stringcmd); MSG_WriteString(string); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } /* @@ -674,7 +656,8 @@ static void CL_Rcon_f(void) return; } - if (!cls.netchan) { + address = cls.netchan.remote_address; + if (!address.type) { if (!rcon_address->string[0]) { Com_Printf("You must either be connected, " "or set the 'rcon_address' cvar " @@ -685,8 +668,6 @@ static void CL_Rcon_f(void) Com_Printf("Bad address: %s\n", rcon_address->string); return; } - } else { - address = cls.netchan->remote_address; } CL_SendRcon(&address, rcon_password->string, COM_StripQuotes(Cmd_RawArgs())); @@ -764,17 +745,16 @@ void CL_Disconnect(error_type_t type) cls.errorReceived = false; #endif - if (cls.netchan) { + if (cls.netchan.protocol) { // send a disconnect message to the server MSG_WriteByte(clc_stringcmd); MSG_WriteData("disconnect", 11); - cls.netchan->Transmit(cls.netchan, msg_write.cursize, msg_write.data, 3); + cls.netchan.Transmit(&cls.netchan, msg_write.cursize, msg_write.data, 3); SZ_Clear(&msg_write); - Netchan_Close(cls.netchan); - cls.netchan = NULL; + Netchan_Close(&cls.netchan); } // stop playback and/or recording @@ -833,11 +813,11 @@ static void CL_ServerStatus_f(void) neterr_t ret; if (Cmd_Argc() < 2) { - if (!cls.netchan) { + adr = cls.netchan.remote_address; + if (!adr.type) { Com_Printf("Usage: %s [address]\n", Cmd_Argv(0)); return; } - adr = cls.netchan->remote_address; } else { s = Cmd_Argv(1); if (!NET_StringToAdr(s, &adr, PORT_SERVER)) { @@ -1401,18 +1381,15 @@ static void CL_ConnectionlessPacket(void) Com_Printf("Connected to %s (protocol %d).\n", NET_AdrToString(&cls.serverAddress), cls.serverProtocol); - if (cls.netchan) { - // this may happen after svc_reconnect - Netchan_Close(cls.netchan); - } - cls.netchan = Netchan_Setup(NS_CLIENT, type, &cls.serverAddress, - cls.quakePort, 1024, cls.serverProtocol); + Netchan_Close(&cls.netchan); + Netchan_Setup(&cls.netchan, NS_CLIENT, type, &cls.serverAddress, + cls.quakePort, 1024, cls.serverProtocol); #if USE_AC_CLIENT if (anticheat) { MSG_WriteByte(clc_nop); - MSG_FlushTo(&cls.netchan->message); - cls.netchan->Transmit(cls.netchan, 0, "", 3); + MSG_FlushTo(&cls.netchan.message); + cls.netchan.Transmit(&cls.netchan, 0, "", 3); S_StopAllSounds(); cls.connect_count = -1; Com_Printf("Loading anticheat, this may take a few moments...\n"); @@ -1492,7 +1469,7 @@ static void CL_PacketEvent(void) return; } - if (!cls.netchan) { + if (cls.demo.playback) { return; // dump it if not connected } @@ -1504,13 +1481,13 @@ static void CL_PacketEvent(void) // // packet from server // - if (!NET_IsEqualAdr(&net_from, &cls.netchan->remote_address)) { + if (!NET_IsEqualAdr(&net_from, &cls.netchan.remote_address)) { Com_DPrintf("%s: sequenced packet without connection\n", NET_AdrToString(&net_from)); return; } - if (!cls.netchan->Process(cls.netchan)) + if (!cls.netchan.Process(&cls.netchan)) return; // wasn't accepted for some reason #if USE_ICMP @@ -1519,6 +1496,8 @@ static void CL_PacketEvent(void) CL_ParseServerMessage(); + SCR_LagSample(); + // if recording demo, write the message out if (cls.demo.recording && !cls.demo.paused && CL_FRAMESYNC) { CL_WriteDemoMessage(&cls.demo.buffer); @@ -1526,11 +1505,6 @@ static void CL_PacketEvent(void) // if running GTV server, transmit to client CL_GTV_Transmit(); - - if (!cls.netchan) - return; // might have disconnected - - SCR_LagSample(); } #if USE_ICMP @@ -1544,13 +1518,13 @@ void CL_ErrorEvent(netadr_t *from) if (cls.state < ca_connected) { return; } - if (!cls.netchan) { + if (cls.demo.playback) { return; // dump it if not connected } - if (!NET_IsEqualBaseAdr(from, &cls.netchan->remote_address)) { + if (!NET_IsEqualBaseAdr(from, &cls.netchan.remote_address)) { return; } - if (from->port && from->port != cls.netchan->remote_address.port) { + if (from->port && from->port != cls.netchan.remote_address.port) { return; } @@ -1591,7 +1565,11 @@ void CL_UpdateUserinfo(cvar_t *var, from_t from) CL_FixUpGender(); } - if (!cls.netchan) { + if (cls.state < ca_connected) { + return; + } + + if (cls.demo.playback) { return; } @@ -2220,9 +2198,9 @@ static size_t CL_Ping_m(char *buffer, size_t size) static size_t CL_Lag_m(char *buffer, size_t size) { - return Q_scnprintf(buffer, size, "%.2f%%", cls.netchan ? - ((float)cls.netchan->total_dropped / - cls.netchan->total_received) * 100.0f : 0); + return Q_scnprintf(buffer, size, "%.2f%%", + ((float)cls.netchan.total_dropped / + cls.netchan.total_received) * 100.0f); } static size_t CL_Health_m(char *buffer, size_t size) @@ -2954,8 +2932,8 @@ static void CL_MeasureStats(void) } // measure average ping - if (cls.netchan) { - int ack = cls.netchan->incoming_acknowledged; + if (cls.netchan.protocol) { + int ack = cls.netchan.incoming_acknowledged; int ping = 0; int j, k = 0; @@ -3002,17 +2980,20 @@ static void CL_CheckForReply(void) static void CL_CheckTimeout(void) { - if (NET_IsLocalAddress(&cls.netchan->remote_address)) { + if (!cls.netchan.protocol) { + return; + } + if (NET_IsLocalAddress(&cls.netchan.remote_address)) { return; } #if USE_ICMP - if (cls.errorReceived && com_localTime - cls.netchan->last_received > 5000) { + if (cls.errorReceived && com_localTime - cls.netchan.last_received > 5000) { Com_Error(ERR_DISCONNECT, "Server connection was reset."); } #endif - if (cl_timeout->integer && com_localTime - cls.netchan->last_received > cl_timeout->integer) { + if (cl_timeout->integer && com_localTime - cls.netchan.last_received > cl_timeout->integer) { // timeoutcount saves debugger if (++cl.timeoutcount > 5) { Com_Error(ERR_DISCONNECT, "Server connection timed out."); @@ -3295,8 +3276,7 @@ unsigned CL_Frame(unsigned msec) } // check connection timeout - if (cls.netchan) - CL_CheckTimeout(); + CL_CheckTimeout(); C_FRAMES++; diff --git a/src/client/parse.c b/src/client/parse.c index c50b9f365..7d2680b3e 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -241,7 +241,7 @@ static void CL_ParseFrame(int extrabits) frame.number = currentframe; frame.delta = deltaframe; - if (cls.netchan && cls.netchan->dropped) { + if (cls.netchan.dropped) { cl.frameflags |= FF_SERVERDROP; } @@ -362,11 +362,8 @@ static void CL_ParseFrame(int extrabits) #if USE_DEBUG if (cl_shownet->integer > 2) { - int rtt = 0; - if (cls.netchan) { - int seq = cls.netchan->incoming_acknowledged & CMD_MASK; - rtt = cls.realtime - cl.history[seq].sent; - } + int seq = cls.netchan.incoming_acknowledged & CMD_MASK; + int rtt = cls.demo.playback ? 0 : cls.realtime - cl.history[seq].sent; Com_LPrintf(PRINT_DEVELOPER, "%3zu:frame:%d delta:%d rtt:%d\n", msg_read.readcount - 1, frame.number, frame.delta, rtt); } @@ -865,12 +862,9 @@ static void CL_ParseReconnect(void) Com_Printf("Server disconnected, reconnecting\n"); - // free netchan now to prevent `disconnect' + // close netchan now to prevent `disconnect' // message from being sent to server - if (cls.netchan) { - Netchan_Close(cls.netchan); - cls.netchan = NULL; - } + Netchan_Close(&cls.netchan); CL_Disconnect(ERR_RECONNECT); diff --git a/src/client/predict.c b/src/client/predict.c index dbf77cdfa..03e65633e 100644 --- a/src/client/predict.c +++ b/src/client/predict.c @@ -30,7 +30,7 @@ void CL_CheckPredictionError(void) unsigned cmd; int len; - if (!cls.netchan) { + if (cls.demo.playback) { return; } @@ -43,7 +43,7 @@ void CL_CheckPredictionError(void) return; // calculate the last usercmd_t we sent that the server has processed - frame = cls.netchan->incoming_acknowledged & CMD_MASK; + frame = cls.netchan.incoming_acknowledged & CMD_MASK; cmd = cl.history[frame].cmdNumber; // compare what the server returned with what we had predicted it to be @@ -195,7 +195,7 @@ void CL_PredictMovement(void) return; } - ack = cl.history[cls.netchan->incoming_acknowledged & CMD_MASK].cmdNumber; + ack = cl.history[cls.netchan.incoming_acknowledged & CMD_MASK].cmdNumber; current = cl.cmdNumber; // if we are too far out of date, just freeze diff --git a/src/client/screen.c b/src/client/screen.c index ebf8f3723..891f1472a 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -432,7 +432,7 @@ void SCR_LagClear(void) void SCR_LagSample(void) { - int i = cls.netchan->incoming_acknowledged & CMD_MASK; + int i = cls.netchan.incoming_acknowledged & CMD_MASK; client_history_t *h = &cl.history[i]; unsigned ping; @@ -442,7 +442,7 @@ void SCR_LagSample(void) } ping = h->rcvd - h->sent; - for (i = 0; i < cls.netchan->dropped; i++) { + for (i = 0; i < cls.netchan.dropped; i++) { lag.samples[lag.head % LAG_WIDTH] = ping | LAG_CRIT_BIT; lag.head++; } @@ -510,7 +510,7 @@ static void SCR_DrawNet(void) } // draw phone jack - if (cls.netchan && cls.netchan->outgoing_sequence - cls.netchan->incoming_acknowledged >= CMD_BACKUP) { + if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged >= CMD_BACKUP) { if ((cls.realtime >> 8) & 3) { R_DrawStretchPic(x, y, LAG_WIDTH, LAG_HEIGHT, scr.net_pic); } diff --git a/src/client/view.c b/src/client/view.c index 19533cfae..932add55c 100644 --- a/src/client/view.c +++ b/src/client/view.c @@ -384,17 +384,14 @@ static void V_TestLights(void) void CL_UpdateBlendSetting(void) { - if (cls.state < ca_connected) { - return; - } - if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) { + if (cls.netchan.protocol < PROTOCOL_VERSION_R1Q2) { return; } MSG_WriteByte(clc_setting); MSG_WriteShort(CLS_NOBLEND); MSG_WriteShort(!cl_add_blend->integer); - MSG_FlushTo(&cls.netchan->message); + MSG_FlushTo(&cls.netchan.message); } //============================================================================ diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 341cde8fb..fe7dd2e42 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -719,15 +719,17 @@ static bool NetchanNew_ShouldUpdate(netchan_t *chan) Netchan_Setup ============== */ -netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, - const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) +void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, + const netadr_t *adr, int qport, size_t maxpacketlen, int protocol) { memtag_t tag = sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL; - netchan_t *chan; + + Q_assert(chan); + Q_assert(!chan->message_buf); + Q_assert(adr); clamp(maxpacketlen, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE); - chan = Z_TagMallocz(sizeof(*chan), tag); chan->type = type; chan->protocol = protocol; chan->sock = sock; @@ -771,9 +773,6 @@ netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type, default: Q_assert(!"bad type"); } - - return chan; - } /* @@ -783,9 +782,8 @@ Netchan_Close */ void Netchan_Close(netchan_t *chan) { - if (chan) { - Z_Free(chan->message_buf); - Z_Free(chan); - } + Q_assert(chan); + Z_Free(chan->message_buf); + memset(chan, 0, sizeof(*chan)); } diff --git a/src/server/ac.c b/src/server/ac.c index 3f10f66f7..ca5968e6e 100644 --- a/src/server/ac.c +++ b/src/server/ac.c @@ -681,7 +681,7 @@ static void AC_ParseViolation(void) cl->name, showreason); Com_Printf("ANTICHEAT VIOLATION: %s[%s] was kicked: %s\n", - cl->name, NET_AdrToString(&cl->netchan->remote_address), reason); + cl->name, NET_AdrToString(&cl->netchan.remote_address), reason); if (clientreason[0]) SV_ClientPrintf(cl, PRINT_HIGH, "%s\n", clientreason); @@ -698,7 +698,7 @@ static void AC_ParseViolation(void) Com_Printf("ANTICHEAT DISCONNECT: %s[%s] disconnected from " "anticheat server\n", cl->name, - NET_AdrToString(&cl->netchan->remote_address)); + NET_AdrToString(&cl->netchan.remote_address)); if (ac_client_disconnect_action->integer == 1) { AC_Announce(cl, "%s lost connection to anticheat server.\n", cl->name); @@ -781,7 +781,7 @@ static void AC_ParseFileViolation(void) } Com_Printf("ANTICHEAT FILE VIOLATION: %s[%s] has a modified %s [%s]\n", - cl->name, NET_AdrToString(&cl->netchan->remote_address), path, hash); + cl->name, NET_AdrToString(&cl->netchan.remote_address), path, hash); switch (action) { case 0: AC_Announce(cl, "%s was kicked for modified %s\n", cl->name, path); @@ -1048,7 +1048,7 @@ bool AC_ClientBegin(client_t *cl) // AFTER QUERY, anticheat is REQUIRED Com_Printf("ANTICHEAT: Rejected connecting client %s[%s], " "no anticheat response.\n", cl->name, - NET_AdrToString(&cl->netchan->remote_address)); + NET_AdrToString(&cl->netchan.remote_address)); SV_ClientPrintf(cl, PRINT_HIGH, "%s\n", ac_message->string); SV_DropClient(cl, NULL); return false; @@ -1062,7 +1062,7 @@ bool AC_ClientBegin(client_t *cl) // anticheat is REQUIRED, error action is DENY Com_Printf("ANTICHEAT: Rejected connecting client %s[%s], " "no connection to anticheat server.\n", cl->name, - NET_AdrToString(&cl->netchan->remote_address)); + NET_AdrToString(&cl->netchan.remote_address)); SV_ClientPrintf(cl, PRINT_HIGH, "This server is unable to take new connections right now. " "Please try again later.\n"); diff --git a/src/server/commands.c b/src/server/commands.c index 9addb3a2b..f330da6ec 100644 --- a/src/server/commands.c +++ b/src/server/commands.c @@ -479,7 +479,7 @@ static void SV_Kick_f(void) // optionally ban their IP address if (!strcmp(Cmd_Argv(0), "kickban")) { - netadr_t *addr = &sv_client->netchan->remote_address; + netadr_t *addr = &sv_client->netchan.remote_address; if (addr->type == NA_IP || addr->type == NA_IP6) { addrmatch_t *match = Z_Malloc(sizeof(*match)); match->addr = *addr; @@ -532,8 +532,7 @@ static void dump_clients(void) Com_Printf("%-15.15s ", client->name); Com_Printf("%7u ", svs.realtime - client->lastmessage); - Com_Printf("%-21s ", NET_AdrToString( - &client->netchan->remote_address)); + Com_Printf("%-21s ", NET_AdrToString(&client->netchan.remote_address)); Com_Printf("%5i ", client->rate); Com_Printf("%2i ", client->protocol); Com_Printf("%3i ", client->moves_per_sec); @@ -633,9 +632,9 @@ static void dump_protocols(void) FOR_EACH_CLIENT(cl) { Com_Printf("%3i %-15.15s %5d %5d %6zu %s %s\n", cl->number, cl->name, cl->protocol, cl->version, - cl->netchan->maxpacketlen, + cl->netchan.maxpacketlen, cl->has_zlib ? "yes" : "no ", - cl->netchan->type ? "new" : "old"); + cl->netchan.type ? "new" : "old"); } } @@ -773,9 +772,9 @@ void SV_PrintMiscInfo(void) sv_client->version_string ? sv_client->version_string : "-"); Com_Printf("protocol (maj/min) %d/%d\n", sv_client->protocol, sv_client->version); - Com_Printf("maxmsglen %zu\n", sv_client->netchan->maxpacketlen); + Com_Printf("maxmsglen %zu\n", sv_client->netchan.maxpacketlen); Com_Printf("zlib support %s\n", sv_client->has_zlib ? "yes" : "no"); - Com_Printf("netchan type %s\n", sv_client->netchan->type ? "new" : "old"); + Com_Printf("netchan type %s\n", sv_client->netchan.type ? "new" : "old"); Com_Printf("ping %d\n", sv_client->ping); Com_Printf("movement fps %d\n", sv_client->moves_per_sec); #if USE_FPS diff --git a/src/server/main.c b/src/server/main.c index 88a9eb0e0..10a4a9271 100644 --- a/src/server/main.c +++ b/src/server/main.c @@ -122,10 +122,7 @@ void SV_RemoveClient(client_t *client) SV_ShutdownClientSend(client); } - if (client->netchan) { - Netchan_Close(client->netchan); - client->netchan = NULL; - } + Netchan_Close(&client->netchan); // unlink them from active client list, but don't clear the list entry // itself to make code that traverses client list in a loop happy! @@ -200,9 +197,9 @@ static void print_drop_reason(client_t *client, const char *reason, clstate_t ol client->name, prefix, reason); // print to server console - if (COM_DEDICATED && client->netchan) + if (COM_DEDICATED) Com_Printf("%s[%s]%s%s\n", client->name, - NET_AdrToString(&client->netchan->remote_address), + NET_AdrToString(&client->netchan.remote_address), prefix, reason); } @@ -709,7 +706,7 @@ static bool permit_connection(conn_params_t *p) if (sv_iplimit->integer > 0) { count = 0; FOR_EACH_CLIENT(cl) { - netadr_t *adr = &cl->netchan->remote_address; + netadr_t *adr = &cl->netchan.remote_address; if (net_from.type != adr->type) continue; @@ -940,7 +937,7 @@ static client_t *find_client_slot(conn_params_t *params) // if there is already a slot for this ip, reuse it FOR_EACH_CLIENT(cl) { - if (NET_IsEqualAdr(&net_from, &cl->netchan->remote_address)) { + if (NET_IsEqualAdr(&net_from, &cl->netchan.remote_address)) { if (cl->state == cs_zombie) { strcpy(params->reconnect_var, cl->reconnect_var); strcpy(params->reconnect_val, cl->reconnect_val); @@ -1144,10 +1141,8 @@ static void SVC_DirectConnect(void) } // setup netchan - newcl->netchan = Netchan_Setup(NS_SERVER, params.nctype, - &net_from, params.qport, - params.maxlength, - params.protocol); + Netchan_Setup(&newcl->netchan, NS_SERVER, params.nctype, &net_from, + params.qport, params.maxlength, params.protocol); newcl->numpackets = 1; // parse some info from the info strings @@ -1478,7 +1473,7 @@ static void SV_GiveMsec(void) if (sv_timescale_warn->value > 1.0f && cl->timescale > sv_timescale_warn->value) { Com_Printf("%s[%s]: detected time skew: %.3f\n", cl->name, - NET_AdrToString(&cl->netchan->remote_address), cl->timescale); + NET_AdrToString(&cl->netchan.remote_address), cl->timescale); } if (sv_timescale_kick->value > 1.0f && cl->timescale > sv_timescale_kick->value) { @@ -1512,7 +1507,7 @@ static void SV_PacketEvent(void) // check for packets from connected clients FOR_EACH_CLIENT(client) { - netchan = client->netchan; + netchan = &client->netchan; if (!NET_IsEqualBaseAdr(&net_from, &netchan->remote_address)) { continue; } @@ -1566,7 +1561,7 @@ static void SV_PacketEvent(void) // Total 64 bytes of headers is assumed. static void update_client_mtu(client_t *client, int ee_info) { - netchan_t *netchan = client->netchan; + netchan_t *netchan = &client->netchan; size_t newpacketlen; // sanity check discovered MTU @@ -1613,7 +1608,7 @@ void SV_ErrorEvent(netadr_t *from, int ee_errno, int ee_info) if (client->state == cs_zombie) { continue; // already a zombie } - netchan = client->netchan; + netchan = &client->netchan; if (!NET_IsEqualBaseAdr(from, &netchan->remote_address)) { continue; } @@ -1652,7 +1647,7 @@ static void SV_CheckTimeouts(void) FOR_EACH_CLIENT(client) { // never timeout local clients - if (NET_IsLocalAddress(&client->netchan->remote_address)) { + if (NET_IsLocalAddress(&client->netchan.remote_address)) { continue; } // NOTE: delta calculated this way is not sensitive to overflow @@ -2009,7 +2004,7 @@ void SV_UserinfoChanged(client_t *cl) if (cl->name[0] && strcmp(cl->name, name)) { if (COM_DEDICATED) { Com_Printf("%s[%s] changed name to %s\n", cl->name, - NET_AdrToString(&cl->netchan->remote_address), name); + NET_AdrToString(&cl->netchan.remote_address), name); } #if USE_MVD_CLIENT if (sv.state == ss_broadcast) { @@ -2034,13 +2029,13 @@ void SV_UserinfoChanged(client_t *cl) } // never drop over the loopback - if (NET_IsLocalAddress(&cl->netchan->remote_address)) { + if (NET_IsLocalAddress(&cl->netchan.remote_address)) { cl->rate = 0; } // don't drop over LAN connections if (sv_lan_force_rate->integer && - NET_IsLanAddress(&cl->netchan->remote_address)) { + NET_IsLanAddress(&cl->netchan.remote_address)) { cl->rate = 0; } @@ -2314,7 +2309,7 @@ static void SV_FinalMessage(const char *message, error_type_t type) if (client->state == cs_zombie) { continue; } - netchan = client->netchan; + netchan = &client->netchan; while (netchan->fragment_pending) { netchan->TransmitNextFragment(netchan); } diff --git a/src/server/mvd.c b/src/server/mvd.c index 794f5fc12..eab3adabe 100644 --- a/src/server/mvd.c +++ b/src/server/mvd.c @@ -374,8 +374,7 @@ static int dummy_create(void) newcl->state = cs_connected; newcl->AddMessage = dummy_add_message; newcl->edict = EDICT_NUM(number + 1); - newcl->netchan = SV_Mallocz(sizeof(netchan_t)); - newcl->netchan->remote_address.type = NA_LOOPBACK; + newcl->netchan.remote_address.type = NA_LOOPBACK; List_Init(&newcl->entry); @@ -402,7 +401,6 @@ static int dummy_create(void) s = "Connection refused"; } Com_EPrintf("Dummy MVD client rejected by game: %s\n", s); - Z_Free(newcl->netchan); mvd.dummy = NULL; return -1; } diff --git a/src/server/mvd/client.c b/src/server/mvd/client.c index 76105b09d..768ef89ea 100644 --- a/src/server/mvd/client.c +++ b/src/server/mvd/client.c @@ -217,7 +217,7 @@ static mvd_t *find_local_channel(void) FOR_EACH_MVD(mvd) { FOR_EACH_MVDCL(client, mvd) { - if (NET_IsLocalAddress(&client->cl->netchan->remote_address)) { + if (NET_IsLocalAddress(&client->cl->netchan.remote_address)) { return mvd; } } diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c index 72ebdb458..32a3dd46d 100644 --- a/src/server/mvd/game.c +++ b/src/server/mvd/game.c @@ -847,7 +847,7 @@ static void MVD_Admin_f(mvd_client_t *client) return; } - if (!NET_IsLocalAddress(&client->cl->netchan->remote_address)) { + if (!NET_IsLocalAddress(&client->cl->netchan.remote_address)) { if (Cmd_Argc() < 2) { SV_ClientPrintf(client->cl, PRINT_HIGH, "Usage: %s \n", Cmd_Argv(0)); return; @@ -1855,7 +1855,7 @@ static void MVD_GameClientBegin(edict_t *ent) client->notified = false; // skip notifications for local clients - if (NET_IsLocalAddress(&client->cl->netchan->remote_address)) + if (NET_IsLocalAddress(&client->cl->netchan.remote_address)) client->notified = true; // skip notifications for Waiting Room channel diff --git a/src/server/send.c b/src/server/send.c index 4860d263e..65bb9bdda 100644 --- a/src/server/send.c +++ b/src/server/send.c @@ -323,10 +323,10 @@ void SV_Multicast(const vec3_t origin, multicast_t to) #if USE_ZLIB static size_t max_compressed_len(client_t *client) { - if (client->netchan->type == NETCHAN_NEW) + if (client->netchan.type == NETCHAN_NEW) return MAX_MSGLEN - ZPACKET_HEADER; - return client->netchan->maxpacketlen - ZPACKET_HEADER; + return client->netchan.maxpacketlen - ZPACKET_HEADER; } static bool can_compress_message(client_t *client) @@ -343,7 +343,7 @@ static bool can_compress_message(client_t *client) } // compress only sufficiently large layouts - if (msg_write.cursize < client->netchan->maxpacketlen / 2) + if (msg_write.cursize < client->netchan.maxpacketlen / 2) return false; return true; @@ -615,7 +615,7 @@ FRAME UPDATES - OLD NETCHAN static void add_message_old(client_t *client, byte *data, size_t len, bool reliable) { - if (len > client->netchan->maxpacketlen) { + if (len > client->netchan.maxpacketlen) { if (reliable) { SV_DropClient(client, "oversize reliable message"); } else { @@ -633,7 +633,7 @@ static void write_reliables_old(client_t *client, size_t maxsize) message_packet_t *msg, *next; int count; - if (client->netchan->reliable_length) { + if (client->netchan.reliable_length) { SV_DPrintf(1, "%s to %s: unacked\n", __func__, client->name); return; // there is still outgoing reliable message pending } @@ -642,7 +642,7 @@ static void write_reliables_old(client_t *client, size_t maxsize) count = 0; FOR_EACH_MSG_SAFE(&client->msg_reliable_list) { // stop if this msg doesn't fit (reliables must be delivered in order) - if (client->netchan->message.cursize + msg->cursize > maxsize) { + if (client->netchan.message.cursize + msg->cursize > maxsize) { if (!count) { // this should never happen Com_WPrintf("%s to %s: overflow on the first message\n", @@ -654,7 +654,7 @@ static void write_reliables_old(client_t *client, size_t maxsize) SV_DPrintf(1, "%s to %s: writing msg %d: %d bytes\n", __func__, client->name, count, msg->cursize); - SZ_Write(&client->netchan->message, msg->data, msg->cursize); + SZ_Write(&client->netchan.message, msg->data, msg->cursize); free_msg_packet(client, msg); count++; } @@ -723,10 +723,10 @@ static void write_datagram_old(client_t *client) size_t maxsize, cursize; // determine how much space is left for unreliable data - maxsize = client->netchan->maxpacketlen; - if (client->netchan->reliable_length) { + maxsize = client->netchan.maxpacketlen; + if (client->netchan.reliable_length) { // there is still unacked reliable message pending - maxsize -= client->netchan->reliable_length; + maxsize -= client->netchan.reliable_length; } else { // find at least one reliable message to send // and make sure to reserve space for it @@ -757,13 +757,13 @@ static void write_datagram_old(client_t *client) } // write at least one reliable message - write_reliables_old(client, client->netchan->maxpacketlen - msg_write.cursize); + write_reliables_old(client, client->netchan.maxpacketlen - msg_write.cursize); // send the datagram - cursize = client->netchan->Transmit(client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = client->netchan.Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -785,7 +785,7 @@ static void add_message_new(client_t *client, byte *data, { if (reliable) { // don't packetize, netchan level will do fragmentation as needed - SZ_Write(&client->netchan->message, data, len); + SZ_Write(&client->netchan.message, data, len); } else { // still have to packetize, relative sounds need special processing add_msg_packet(client, data, len, false); @@ -830,10 +830,10 @@ static void write_datagram_new(client_t *client) #endif // send the datagram - cursize = client->netchan->Transmit(client->netchan, - msg_write.cursize, - msg_write.data, - client->numpackets); + cursize = client->netchan.Transmit(&client->netchan, + msg_write.cursize, + msg_write.data, + client->numpackets); // record the size for rate estimation SV_CalcSendTime(client, cursize); @@ -904,8 +904,8 @@ void SV_SendClientMessages(void) // if the reliable message overflowed, // drop the client (should never happen) - if (client->netchan->message.overflowed) { - SZ_Clear(&client->netchan->message); + if (client->netchan.message.overflowed) { + SZ_Clear(&client->netchan.message); SV_DropClient(client, "reliable message overflowed"); goto finish; } @@ -915,9 +915,9 @@ void SV_SendClientMessages(void) goto advance; // don't write any frame data until all fragments are sent - if (client->netchan->fragment_pending) { + if (client->netchan.fragment_pending) { client->frameflags |= FF_SUPPRESSED; - cursize = client->netchan->TransmitNextFragment(client->netchan); + cursize = client->netchan.TransmitNextFragment(&client->netchan); SV_CalcSendTime(client, cursize); goto advance; } @@ -938,7 +938,7 @@ void SV_SendClientMessages(void) static void write_pending_download(client_t *client) { - sizebuf_t *buf = &client->netchan->message; + sizebuf_t *buf = &client->netchan.message; int chunk; if (!client->download) @@ -947,14 +947,14 @@ static void write_pending_download(client_t *client) if (!client->downloadpending) return; - if (client->netchan->reliable_length) + if (client->netchan.reliable_length) return; - if (buf->cursize >= client->netchan->maxpacketlen - 4) + if (buf->cursize >= client->netchan.maxpacketlen - 4) return; chunk = min(client->downloadsize - client->downloadcount, - client->netchan->maxpacketlen - buf->cursize - 4); + client->netchan.maxpacketlen - buf->cursize - 4); client->downloadpending = false; client->downloadcount += chunk; @@ -995,7 +995,7 @@ void SV_SendAsyncPackets(void) continue; } - netchan = client->netchan; + netchan = &client->netchan; // make sure all fragments are transmitted first if (netchan->fragment_pending) { @@ -1049,7 +1049,7 @@ void SV_InitClientSend(client_t *newcl) } // setup protocol - if (newcl->netchan->type == NETCHAN_NEW) { + if (newcl->netchan.type == NETCHAN_NEW) { newcl->AddMessage = add_message_new; newcl->WriteDatagram = write_datagram_new; } else { diff --git a/src/server/server.h b/src/server/server.h index 1553c0de2..df7616b89 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -249,8 +249,8 @@ typedef struct { #define PL_S2C(cl) (cl->frames_sent ? \ (1.0f - (float)cl->frames_acked / cl->frames_sent) * 100.0f : 0.0f) -#define PL_C2S(cl) (cl->netchan->total_received ? \ - ((float)cl->netchan->total_dropped / cl->netchan->total_received) * 100.0f : 0.0f) +#define PL_C2S(cl) (cl->netchan.total_received ? \ + ((float)cl->netchan.total_dropped / cl->netchan.total_received) * 100.0f : 0.0f) #define AVG_PING(cl) (cl->avg_ping_count ? \ cl->avg_ping_time / cl->avg_ping_count : cl->ping) @@ -371,7 +371,7 @@ typedef struct client_s { void (*WriteDatagram)(struct client_s *); // netchan - netchan_t *netchan; + netchan_t netchan; int numpackets; // for that nasty packetdup hack // misc diff --git a/src/server/user.c b/src/server/user.c index 04ed8861d..367225150 100644 --- a/src/server/user.c +++ b/src/server/user.c @@ -97,7 +97,7 @@ static bool need_flush_msg(size_t size) if (sv_client->has_zlib) size = ZPACKET_HEADER + deflateBound(&svs.z, size); #endif - return size > sv_client->netchan->maxpacketlen; + return size > sv_client->netchan.maxpacketlen; } static void write_configstrings(void) @@ -292,7 +292,7 @@ void SV_New_f(void) // stuff some junk, drop them and expect them to be back soon if (sv_force_reconnect->string[0] && !sv_client->reconnect_var[0] && - !NET_IsLocalAddress(&sv_client->netchan->remote_address)) { + !NET_IsLocalAddress(&sv_client->netchan.remote_address)) { stuff_junk(); SV_DropClient(sv_client, NULL); return; @@ -377,7 +377,7 @@ void SV_New_f(void) return; // send gamestate - if (sv_client->netchan->type == NETCHAN_NEW) { + if (sv_client->netchan.type == NETCHAN_NEW) { write_gamestate(); } else { write_configstrings(); @@ -810,7 +810,7 @@ static bool handle_cvar_ban(const cvarban_t *ban, const char *v) if (ban->action == FA_LOG || ban->action == FA_KICK) Com_Printf("%s[%s]: matched cvarban: \"%s\" is \"%s\"\n", sv_client->name, - NET_AdrToString(&sv_client->netchan->remote_address), ban->var, v); + NET_AdrToString(&sv_client->netchan.remote_address), ban->var, v); if (ban->action == FA_LOG) return false; @@ -847,7 +847,7 @@ static void SV_CvarResult_f(void) v = Cmd_RawArgsFrom(2); if (COM_DEDICATED) { Com_Printf("%s[%s]: %s\n", sv_client->name, - NET_AdrToString(&sv_client->netchan->remote_address), v); + NET_AdrToString(&sv_client->netchan.remote_address), v); } sv_client->version_string = SV_CopyString(v); } @@ -862,7 +862,7 @@ static void SV_CvarResult_f(void) } else if (!strcmp(c, "console")) { if (sv_client->console_queries > 0) { Com_Printf("%s[%s]: \"%s\" is \"%s\"\n", sv_client->name, - NET_AdrToString(&sv_client->netchan->remote_address), + NET_AdrToString(&sv_client->netchan.remote_address), Cmd_Argv(2), Cmd_RawArgsFrom(3)); sv_client->console_queries--; } @@ -927,7 +927,7 @@ static void handle_filtercmd(filtercmd_t *filter) if (filter->action == FA_LOG || filter->action == FA_KICK) Com_Printf("%s[%s]: issued banned command: %s\n", sv_client->name, - NET_AdrToString(&sv_client->netchan->remote_address), filter->string); + NET_AdrToString(&sv_client->netchan.remote_address), filter->string); if (filter->action == FA_LOG) return; @@ -1110,7 +1110,7 @@ static void SV_OldClientExecuteMove(void) SV_SetLastFrame(lastframe); - net_drop = sv_client->netchan->dropped; + net_drop = sv_client->netchan.dropped; if (net_drop > 2) { sv_client->frameflags |= FF_CLIENTPRED; } @@ -1207,7 +1207,7 @@ static void SV_NewClientExecuteMove(int c) return; // should never happen } - net_drop = sv_client->netchan->dropped; + net_drop = sv_client->netchan.dropped; if (net_drop > numDups) { sv_client->frameflags |= FF_CLIENTPRED; } From 3799367a99126f9d89fb71626c1b1ef17b213297 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 22 Dec 2022 17:35:44 +0300 Subject: [PATCH 5/6] Check for overread in netchan process function. Otherwise it is possible for fragment length to underflow and cause a fatal error. --- src/common/net/chan.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/common/net/chan.c b/src/common/net/chan.c index fe7dd2e42..8eead710f 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -294,6 +294,12 @@ static bool NetchanOld_Process(netchan_t *chan) } } + if (msg_read.readcount > msg_read.cursize) { + SHOWDROP("%s: message too short\n", + NET_AdrToString(&chan->remote_address)); + return false; + } + reliable_message = sequence & 0x80000000; reliable_ack = sequence_ack & 0x80000000; @@ -599,6 +605,12 @@ static bool NetchanNew_Process(netchan_t *chan) fragment_offset &= 0x7FFF; } + if (msg_read.readcount > msg_read.cursize) { + SHOWDROP("%s: message too short\n", + NET_AdrToString(&chan->remote_address)); + return false; + } + SHOWPACKET("recv %4zu : s=%d ack=%d rack=%d", msg_read.cursize, sequence, sequence_ack, reliable_ack); if (fragmented_message) { @@ -662,7 +674,7 @@ static bool NetchanNew_Process(netchan_t *chan) } length = msg_read.cursize - msg_read.readcount; - if (chan->fragment_in.cursize + length > chan->fragment_in.maxsize) { + if (length > chan->fragment_in.maxsize - chan->fragment_in.cursize) { SHOWDROP("%s: oversize fragment at %i\n", NET_AdrToString(&chan->remote_address), sequence); return false; @@ -674,7 +686,7 @@ static bool NetchanNew_Process(netchan_t *chan) } // message has been sucessfully assembled - SZ_Clear(&msg_read); + SZ_Init(&msg_read, msg_read_buffer, sizeof(msg_read_buffer)); SZ_Write(&msg_read, chan->fragment_in.data, chan->fragment_in.cursize); SZ_Clear(&chan->fragment_in); } From 816be148c67537f4669924f5cf925f89d0f9dcf6 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Fri, 4 Aug 2023 19:31:57 +0300 Subject: [PATCH 6/6] Assert maxpacketlen is valid in Netchan_Setup(). --- src/common/net/chan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/net/chan.c b/src/common/net/chan.c index 8eead710f..387f88bb7 100644 --- a/src/common/net/chan.c +++ b/src/common/net/chan.c @@ -739,8 +739,8 @@ void Netchan_Setup(netchan_t *chan, netsrc_t sock, netchan_type_t type, Q_assert(chan); Q_assert(!chan->message_buf); Q_assert(adr); - - clamp(maxpacketlen, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE); + Q_assert(maxpacketlen >= MIN_PACKETLEN); + Q_assert(maxpacketlen <= MAX_PACKETLEN_WRITABLE); chan->type = type; chan->protocol = protocol;