Networking fixes

This commit is contained in:
OM 2023-05-28 21:36:09 +02:00
parent 3dc4418a93
commit 92a5883243
9 changed files with 246 additions and 90 deletions

View file

@ -1826,7 +1826,16 @@ wombat: sending conect here: an example connect string from MOHAA looks like thi
port = Cvar_VariableValue ("net_qport");
Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
Info_SetValueForKey( info, "protocol", va("%i", PROTOCOL_VERSION ) );
#ifdef LEGACY_PROTOCOL
if(com_legacyprotocol->integer == com_protocol->integer)
clc.compat = qtrue;
if(clc.compat)
Info_SetValueForKey(info, "protocol", va("%i", com_legacyprotocol->integer));
else
#endif
Info_SetValueForKey(info, "protocol", va("%i", com_protocol->integer));
Info_SetValueForKey( info, "qport", va("%i", port ) );
Info_SetValueForKey(info, "challenge", va("%i", clc.challenge));
Info_SetValueForKey(info, "version", TARGET_GAME_VERSION);
@ -2124,7 +2133,15 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
NET_AdrToString( clc.serverAddress ) );
return;
}
Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) );
#ifdef LEGACY_PROTOCOL
Netchan_Setup(NS_CLIENT, &clc.netchan, from, Cvar_VariableValue("net_qport"),
clc.challenge, clc.compat);
#else
Netchan_Setup(NS_CLIENT, &clc.netchan, from, Cvar_VariableValue("net_qport"),
clc.challenge, qfalse);
#endif
clc.state = CA_CONNECTED;
clc.lastPacketSentTime = -9999; // send first packet immediately
return;

View file

@ -240,6 +240,10 @@ typedef struct {
int timeDemoMaxDuration; // maximum frame duration
unsigned char timeDemoDurations[ MAX_TIMEDEMO_DURATIONS ]; // log of frame durations
#ifdef LEGACY_PROTOCOL
qboolean compat;
#endif
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;

View file

@ -1455,6 +1455,17 @@ void Com_Init( char *commandLine ) {
s = va( "%s %s %s", PRODUCT_VERSION_FULL, PLATFORM_STRING, PRODUCT_DATE );
com_version = Cvar_Get( "version", s, CVAR_ROM | CVAR_SERVERINFO );
com_shortversion = Cvar_Get( "shortversion", TARGET_GAME_VERSION, CVAR_ROM );
com_gamename = Cvar_Get("com_gamename", TARGET_GAME_NAME, CVAR_SERVERINFO | CVAR_INIT);
com_protocol = Cvar_Get("com_protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_INIT);
#ifdef LEGACY_PROTOCOL
com_legacyprotocol = Cvar_Get("com_legacyprotocol", va("%i", PROTOCOL_LEGACY_VERSION), CVAR_INIT);
// Keep for compatibility with old mods / mods that haven't updated yet.
if(com_legacyprotocol->integer > 0)
Cvar_Get("protocol", com_legacyprotocol->string, CVAR_ROM);
else
#endif
Cvar_Get("protocol", com_protocol->string, CVAR_ROM);
Sys_Init();
Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random

View file

@ -83,7 +83,8 @@ Netchan_Setup
called to open a channel to a remote system
==============
*/
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int challenge, qboolean compat)
{
Com_Memset (chan, 0, sizeof(*chan));
chan->sock = sock;
@ -91,6 +92,11 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
chan->qport = qport;
chan->incomingSequence = 0;
chan->outgoingSequence = 1;
chan->challenge = challenge;
#ifdef LEGACY_PROTOCOL
chan->compat = compat;
#endif
}
// TTimo: unused, commenting out to make gcc happy

View file

@ -48,6 +48,8 @@ extern "C" {
#define PRODUCT_DATE __DATE__
#define BASEGAME "main"
// We're always legacy
#define LEGACY_PROTOCOL
//
// The target type specifies which content pack the engine targets.

View file

@ -288,10 +288,14 @@ typedef struct {
int challenge;
int lastSentTime;
int lastSentSize;
#ifdef LEGACY_PROTOCOL
qboolean compat;
#endif
} netchan_t;
void Netchan_Init( int qport );
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );
void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, int challenge, qboolean compat);
void Netchan_Transmit( netchan_t *chan, size_t length, const byte *data );
void Netchan_TransmitNextFragment( netchan_t *chan );
@ -307,7 +311,8 @@ PROTOCOL
==============================================================
*/
#define PROTOCOL_VERSION TARGET_GAME_PROTOCOL
#define PROTOCOL_VERSION TARGET_GAME_PROTOCOL
#define PROTOCOL_LEGACY_VERSION PROTOCOL_VERSION
// su44: MoHAA v 1.00 uses protocol version 6
// maintain a list of compatible protocols for demo playing

View file

@ -119,6 +119,9 @@ typedef enum {
typedef struct netchan_buffer_s {
msg_t msg;
byte msgBuffer[MAX_MSGLEN];
#ifdef LEGACY_PROTOCOL
char clientCommandString[MAX_STRING_CHARS]; // valid command string for SV_Netchan_Encode
#endif
struct netchan_buffer_s *next;
} netchan_buffer_t;
@ -187,7 +190,11 @@ typedef struct client_s {
qboolean locprint;
int XOffset;
int YOffset;
char centerprint[ 256 ];
char centerprint[256];
#ifdef LEGACY_PROTOCOL
qboolean compat;
#endif
} client_t;
//=============================================================================
@ -542,6 +549,7 @@ void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, con
void SV_Netchan_Transmit( client_t *client, msg_t *msg);
int SV_Netchan_TransmitNextFragment( client_t *client );
qboolean SV_Netchan_Process( client_t *client, msg_t *msg );
void SV_Netchan_FreeQueue(client_t *client);
//
// sv_gamespy.c

View file

@ -237,16 +237,28 @@ void SV_DirectConnect( netadr_t from ) {
const char *denied;
int count;
char *ip;
#ifdef LEGACY_PROTOCOL
qboolean compat = qfalse;
#endif
Com_DPrintf( "SVC_DirectConnect ()\n" );
Q_strncpyz( userinfo, Cmd_Argv( 1 ), sizeof( userinfo ) );
version = atoi( Info_ValueForKey( userinfo, "protocol" ) );
if ( version != PROTOCOL_VERSION ) {
NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION );
Com_DPrintf (" rejected connect from version %i\n", version);
return;
#ifdef LEGACY_PROTOCOL
if(version > 0 && com_legacyprotocol->integer == version)
compat = qtrue;
else
#endif
{
if(version != com_protocol->integer)
{
NET_OutOfBandPrint(NS_SERVER, from, "print\nServer uses protocol version %i "
"(yours is %i).\n", com_protocol->integer, version);
Com_DPrintf(" rejected connect from version %i\n", version);
return;
}
}
challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) );
@ -416,7 +428,12 @@ gotnewcl:
newcl->challenge = challenge;
// save the address
Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport);
#ifdef LEGACY_PROTOCOL
newcl->compat = compat;
Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge, compat);
#else
Netchan_Setup(NS_SERVER, &newcl->netchan, from, qport, challenge, qfalse);
#endif
// init the netchan queue
newcl->netchan_end_queue = &newcl->netchan_start_queue;
@ -468,6 +485,31 @@ gotnewcl:
}
}
/*
=====================
SV_FreeClient
Destructor for data allocated in a client structure
=====================
*/
void SV_FreeClient(client_t* client)
{
#ifdef USE_VOIP
int index;
for (index = client->queuedVoipIndex; index < client->queuedVoipPackets; index++)
{
index %= ARRAY_LEN(client->voipPacket);
Z_Free(client->voipPacket[index]);
}
client->queuedVoipPackets = 0;
#endif
SV_Netchan_FreeQueue(client);
SV_CloseDownload(client);
}
/*
=====================
@ -496,10 +538,10 @@ void SV_DropClient( client_t *drop, const char *reason ) {
break;
}
}
}
}
// Kill any download
SV_CloseDownload( drop );
// Free all allocated data on the client structure
SV_FreeClient(drop);
// tell everyone why they got dropped
SV_SendServerCommand( NULL, "print \"%s %s\n\"", drop->name, reason );

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h"
#include "server.h"
#ifdef LEGACY_PROTOCOL
/*
==============
SV_Netchan_Encode
@ -33,30 +34,32 @@ SV_Netchan_Encode
==============
*/
static void SV_Netchan_Encode( client_t *client, msg_t *msg ) {
long reliableAcknowledge, i, index;
static void SV_Netchan_Encode(client_t *client, msg_t *msg, const char *clientCommandString)
{
long i, index;
byte key, *string;
int srdc, sbit, soob;
int srdc, sbit;
qboolean soob;
if ( msg->cursize < SV_ENCODE_START ) {
return;
}
srdc = msg->readcount;
sbit = msg->bit;
soob = msg->oob;
msg->bit = 0;
msg->readcount = 0;
msg->oob = 0;
reliableAcknowledge = MSG_ReadLong(msg);
srdc = msg->readcount;
sbit = msg->bit;
soob = msg->oob;
msg->oob = soob;
msg->bit = sbit;
msg->readcount = srdc;
string = (byte *)client->lastClientCommandString;
msg->bit = 0;
msg->readcount = 0;
msg->oob = qfalse;
/* reliableAcknowledge = */ MSG_ReadLong(msg);
msg->oob = soob;
msg->bit = sbit;
msg->readcount = srdc;
string = (byte *) clientCommandString;
index = 0;
// xor the client challenge with the netchan sequence number
key = client->challenge ^ client->netchan.outgoingSequence;
@ -89,23 +92,24 @@ SV_Netchan_Decode
*/
static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
int serverId, messageAcknowledge, reliableAcknowledge;
int i, index, srdc, sbit, soob;
int i, index, srdc, sbit;
qboolean soob;
byte key, *string;
srdc = msg->readcount;
sbit = msg->bit;
soob = msg->oob;
msg->oob = 0;
serverId = MSG_ReadLong(msg);
srdc = msg->readcount;
sbit = msg->bit;
soob = msg->oob;
msg->oob = qfalse;
serverId = MSG_ReadLong(msg);
messageAcknowledge = MSG_ReadLong(msg);
reliableAcknowledge = MSG_ReadLong(msg);
msg->oob = soob;
msg->bit = sbit;
msg->readcount = srdc;
msg->oob = soob;
msg->bit = sbit;
msg->readcount = srdc;
string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
index = 0;
//
@ -125,45 +129,84 @@ static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
*(msg->data + i) = *(msg->data + i) ^ key;
}
}
#endif
/*
=================
SV_Netchan_FreeQueue
=================
*/
void SV_Netchan_FreeQueue(client_t *client)
{
netchan_buffer_t *netbuf, *next;
for(netbuf = client->netchan_start_queue; netbuf; netbuf = next)
{
next = netbuf->next;
Z_Free(netbuf);
}
client->netchan_start_queue = NULL;
client->netchan_end_queue = &client->netchan_start_queue;
}
/*
=================
SV_Netchan_TransmitNextInQueue
=================
*/
void SV_Netchan_TransmitNextInQueue(client_t *client)
{
netchan_buffer_t *netbuf;
Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
netbuf = client->netchan_start_queue;
#ifdef LEGACY_PROTOCOL
if(client->compat)
SV_Netchan_Encode(client, &netbuf->msg, netbuf->clientCommandString);
#endif
Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
// pop from queue
client->netchan_start_queue = netbuf->next;
if(!client->netchan_start_queue)
{
Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
client->netchan_end_queue = &client->netchan_start_queue;
}
else
Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
Z_Free(netbuf);
}
/*
=================
SV_Netchan_TransmitNextFragment
Transmit the next fragment and the next queued packet
Return number of ms until next message can be sent based on throughput given by client rate,
-1 if no packet was sent.
=================
*/
int SV_Netchan_TransmitNextFragment( client_t *client ) {
Netchan_TransmitNextFragment( &client->netchan );
if (!client->netchan.unsentFragments)
{
// make sure the netchan queue has been properly initialized (you never know)
if (!client->netchan_end_queue) {
Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
}
// the last fragment was transmitted, check wether we have queued messages
if (client->netchan_start_queue) {
netchan_buffer_t* netbuf;
Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
netbuf = client->netchan_start_queue;
SV_Netchan_Encode(client, &netbuf->msg);
Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
// pop from queue
client->netchan_start_queue = netbuf->next;
if (!client->netchan_start_queue) {
Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
client->netchan_end_queue = &client->netchan_start_queue;
}
else
Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
Z_Free(netbuf);
return SV_RateMsec(client);
}
}
else
{
return SV_RateMsec(client);
}
return -1;
int SV_Netchan_TransmitNextFragment(client_t *client)
{
if(client->netchan.unsentFragments)
{
Netchan_TransmitNextFragment(&client->netchan);
return SV_RateMsec(client);
}
else if(client->netchan_start_queue)
{
SV_Netchan_TransmitNextInQueue(client);
return SV_RateMsec(client);
}
return -1;
}
@ -178,22 +221,35 @@ then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg) { //int length, const byte *data ) {
void SV_Netchan_Transmit( client_t *client, msg_t *msg)
{
MSG_WriteByte( msg, svc_EOF );
if (client->netchan.unsentFragments) {
if(client->netchan.unsentFragments || client->netchan_start_queue)
{
netchan_buffer_t *netbuf;
Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n");
netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t));
netbuf = (netchan_buffer_t *) Z_Malloc(sizeof(netchan_buffer_t));
// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg);
#ifdef LEGACY_PROTOCOL
if(client->compat)
{
Q_strncpyz(netbuf->clientCommandString, client->lastClientCommandString,
sizeof(netbuf->clientCommandString));
}
#endif
netbuf->next = NULL;
// insert it in the queue, the message will be encoded and sent later
*client->netchan_end_queue = netbuf;
client->netchan_end_queue = &(*client->netchan_end_queue)->next;
// emit the next fragment of the current message for now
Netchan_TransmitNextFragment(&client->netchan);
} else {
SV_Netchan_Encode( client, msg );
}
else
{
#ifdef LEGACY_PROTOCOL
if(client->compat)
SV_Netchan_Encode(client, msg, client->lastClientCommandString);
#endif
Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
}
}
@ -203,12 +259,17 @@ void SV_Netchan_Transmit( client_t *client, msg_t *msg) { //int length, const by
Netchan_SV_Process
=================
*/
qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
int ret;
ret = Netchan_Process( &client->netchan, msg );
if (!ret)
return qfalse;
SV_Netchan_Decode( client, msg );
return qtrue;
qboolean SV_Netchan_Process(client_t* client, msg_t* msg) {
int ret;
ret = Netchan_Process(&client->netchan, msg);
if (!ret)
return qfalse;
#ifdef LEGACY_PROTOCOL
if (client->compat)
SV_Netchan_Decode(client, msg);
#endif
return qtrue;
}