1
0
Fork 0
forked from fte/fteqw

Add support for Q2E's lan networking layer (the annoying lobby bit).

This is separate from protocol 2023 stuff.
This commit is contained in:
Shpoike 2023-08-19 03:14:09 +01:00
parent 3357338ab7
commit 969134d9fd
8 changed files with 1145 additions and 158 deletions

View file

@ -310,6 +310,7 @@ static struct
CIM_DEFAULT, //sends both a qw getchallenge and nq connect (also with postfixed getchallenge so modified servers can force getchallenge) CIM_DEFAULT, //sends both a qw getchallenge and nq connect (also with postfixed getchallenge so modified servers can force getchallenge)
CIM_NQONLY, //disables getchallenge (so fte servers treat us as an nq client). should not be used for dpp7 servers. CIM_NQONLY, //disables getchallenge (so fte servers treat us as an nq client). should not be used for dpp7 servers.
CIM_QEONLY, //forces dtls and uses a different nq netchan version CIM_QEONLY, //forces dtls and uses a different nq netchan version
CIM_Q2EONLY, //forces dtls and uses a different nq netchan version
} mode; } mode;
enum coninfospec_e enum coninfospec_e
{ {
@ -825,6 +826,12 @@ char *CL_TryingToConnect(void)
if (!connectinfo.trying) if (!connectinfo.trying)
return NULL; return NULL;
if (connectinfo.numadr >= 1 && connectinfo.adr[0].prot == NP_KEXLAN)
{
char status[1024];
if (NET_GetConnectionCertificate(cls.sockets, &connectinfo.adr[0], QCERT_LOBBYSTATUS, status, sizeof(status))>0)
return va("%s\n%s", cls.servername, status);
}
return cls.servername; return cls.servername;
} }
@ -870,6 +877,15 @@ static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
} }
#endif #endif
if (connectinfo.mode == CIM_Q2EONLY)
{
for (i = 0; i < ctx->found; i++)
{ //if we've already established a dtls connection, stick with it
if (ctx->adr[i].prot == NP_DGRAM)
ctx->adr[i].prot = NP_KEXLAN;
}
}
connectinfo.numadr = ctx->found; connectinfo.numadr = ctx->found;
connectinfo.nextadr = 0; connectinfo.nextadr = 0;
connectinfo.resolving = false; connectinfo.resolving = false;
@ -889,7 +905,7 @@ static void CL_ResolveServer(void *vctx, void *data, size_t a, size_t b)
COM_AddWork(WG_MAIN, CL_ResolvedServer, ctx, data, a, b); COM_AddWork(WG_MAIN, CL_ResolvedServer, ctx, data, a, b);
} }
static qboolean CL_IsPendingServerAddress(netadr_t *adr) qboolean CL_IsPendingServerAddress(netadr_t *adr)
{ {
size_t i; size_t i;
for (i = 0; i < connectinfo.numadr; i++) for (i = 0; i < connectinfo.numadr; i++)
@ -1313,7 +1329,9 @@ void CL_CheckForResend (void)
if (to->prot == NP_DGRAM) if (to->prot == NP_DGRAM)
connectinfo.nextadr++; //cycle hosts with each ping (if we got multiple). connectinfo.nextadr++; //cycle hosts with each ping (if we got multiple).
if (connectinfo.mode==CIM_QEONLY || connectinfo.mode==CIM_NQONLY) if (connectinfo.mode==CIM_Q2EONLY)
contype |= 1; //don't ever try nq packets here.
else if (connectinfo.mode==CIM_QEONLY || connectinfo.mode==CIM_NQONLY)
contype |= 2; contype |= 2;
else else
{ {
@ -1321,7 +1339,16 @@ void CL_CheckForResend (void)
#ifdef VM_UI #ifdef VM_UI
if (!(q3&&q3->ui.IsRunning())) //don't try to connect to nq servers when running a q3ui. I was getting annoying error messages from q3 servers due to this. if (!(q3&&q3->ui.IsRunning())) //don't try to connect to nq servers when running a q3ui. I was getting annoying error messages from q3 servers due to this.
#endif #endif
contype |= 2; /*try nq connections periodically (or if its the default nq port)*/ {
COM_Parse(com_protocolname.string);
if (!strcmp(com_token, "Quake2"))
{
if (connectinfo.nextadr>3) //don't create an extra channel until we know our preferred one has failed.
contype |= 4; /*q2e's kex lan layer*/
}
else
contype |= 2; /*try nq connections periodically (or if its the default nq port)*/
}
} }
/*DP, QW, Q2, Q3*/ /*DP, QW, Q2, Q3*/
@ -1401,6 +1428,15 @@ void CL_CheckForResend (void)
} }
} }
#endif #endif
#ifdef Q2CLIENT
if ((contype & 4) && !connectinfo.clogged)
{
#define KEXLAN_SHAMELESSSELFPROMOMAGIC "\x08""CRANTIME" //hey, if you can't shove your own nick in your network protocols then you're doing it wrong.
#define KEXLAN_SUBPROTOCOL "\x08""Quake II" //this should be cvar-ised at some point, if its to ever be useful for anything but q2.
static char pkt[] = "\x01\x60\x80"KEXLAN_SHAMELESSSELFPROMOMAGIC KEXLAN_SUBPROTOCOL"\x01";
NET_SendPacket (cls.sockets, strlen(pkt), pkt, to);
}
#endif
connectinfo.tries++; connectinfo.tries++;
@ -1429,30 +1465,25 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
if (schemeend) if (schemeend)
{ {
//"qw:tcp://host/observe"
const char *schemestart = strchr(host, ':'); const char *schemestart = strchr(host, ':');
int schemelen; const struct urischeme_s *scheme;
//if its one of our explicit protocols then use the url as-is
const char *netschemes[] = {"udp", "udp4", "udp6", "ipx", "tcp", "tcp4", "tcp6", /*ipx*/"spx", "ws", "wss", "tls", "dtls", "ice", "rtc", "ices", "rtcs", "irc", "udg", "unix"};
int i;
size_t slen;
if (!schemestart || schemestart==schemeend) if (!schemestart || schemestart==schemeend)
schemestart = host; schemestart = host;
else else
schemestart++; schemestart++;
schemelen = schemeend-schemestart;
Q_strncpyz (cls.servername, "", sizeof(cls.servername)); //the scheme is either a network scheme in which case we use it directly, or a game-specific scheme.
for (i = 0; i < countof(netschemes); i++) scheme = NET_IsURIScheme(schemestart);
if (scheme->prot == NP_INVALID)
scheme = NULL; //qw:// or q3:// something that's just noise here.
if (scheme->flags&URISCHEME_NEEDSRESOURCE)
{ {
slen = strlen(netschemes[i]); Q_strncpyz (cls.servername, schemestart, sizeof(cls.servername)); //oh. will probably be okay then
if (schemelen == slen && !strncmp(schemestart, netschemes[i], slen)) arglist = NULL;
{
Q_strncpyz (cls.servername, host, sizeof(cls.servername)); //oh. will probably be okay then
break;
}
} }
if (!*cls.servername) else
{ //not some '/foo' name, not rtc:// either... { //not some '/foo' name, not rtc:// either...
char *sl = strchr(schemeend+3, '/'); char *sl = strchr(schemeend+3, '/');
if (sl) if (sl)
@ -1479,7 +1510,11 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
memmove(sl, sl+1, strlen(sl+1)+1); memmove(sl, sl+1, strlen(sl+1)+1);
} }
} }
Q_strncpyz (cls.servername, schemeend+3, sizeof(cls.servername)); //probably some game-specific mess that we don't know if (scheme) //preserve the scheme, the netchan cares.
Q_strncpyz (cls.servername, schemestart, sizeof(cls.servername)); //probably some game-specific mess that we don't know
else
Q_strncpyz (cls.servername, schemeend+3, sizeof(cls.servername)); //probably some game-specific mess that we don't know
arglist = strchr(cls.servername, '?');
} }
} }
else else
@ -1491,10 +1526,9 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
Q_strncpyz (cls.servername, host, sizeof(cls.servername)); Q_strncpyz (cls.servername, host, sizeof(cls.servername));
else else
Q_snprintfz(cls.servername, sizeof(cls.servername), "%s@%s", host, cl_proxyaddr.string); Q_snprintfz(cls.servername, sizeof(cls.servername), "%s@%s", host, cl_proxyaddr.string);
arglist = strchr(cls.servername, '?');
} }
arglist = strchr(cls.servername, '?');
if (!port) if (!port)
port = cl_defaultport.value; port = cl_defaultport.value;
@ -1748,6 +1782,7 @@ void CLNQ_Connect_f (void)
{ {
char *server; char *server;
enum coninfomode_e mode; enum coninfomode_e mode;
int port = 26000;
if (Cmd_Argc() != 2) if (Cmd_Argc() != 2)
{ {
@ -1765,7 +1800,26 @@ void CLNQ_Connect_f (void)
CL_Disconnect_f (); CL_Disconnect_f ();
CL_BeginServerConnect(server, 26000, true, mode, CIS_DEFAULT/*doesn't really do spec/join stuff, but if the server asks for our info later...*/); CL_BeginServerConnect(server, port, true, mode, CIS_DEFAULT/*doesn't really do spec/join stuff, but if the server asks for our info later...*/);
}
#endif
#ifdef Q2CLIENT
void CLQ2E_Connect_f (void)
{
char *server;
if (Cmd_Argc() != 2)
{
Con_TPrintf ("usage: connect <server>\n");
return;
}
server = Cmd_Argv (1);
server = strcpy(alloca(strlen(server)+1), server);
CL_Disconnect_f ();
CL_BeginServerConnect(server, PORT_Q2EXSERVER/*q2e servers ignore their own port cvar, so don't use the standard q2 port number here*/, true, CIM_Q2EONLY, CIS_DEFAULT);
} }
#endif #endif
@ -3564,6 +3618,7 @@ void CL_Reconnect_f (void)
static void CL_ConnectionlessPacket_Connection(char *tokens) static void CL_ConnectionlessPacket_Connection(char *tokens)
{ {
int qportsize = -1;
if (net_from.type == NA_INVALID) if (net_from.type == NA_INVALID)
return; //I've found a qizmo demo that contains one of these. its best left ignored. return; //I've found a qizmo demo that contains one of these. its best left ignored.
@ -3601,8 +3656,10 @@ static void CL_ConnectionlessPacket_Connection(char *tokens)
} }
#if defined(Q2CLIENT) #if defined(Q2CLIENT)
if (tokens) if (tokens && cls.protocol == CP_QUAKE2)
{ {
if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
qportsize = 1;
tokens = COM_Parse(tokens); //skip the client_connect bit tokens = COM_Parse(tokens); //skip the client_connect bit
while((tokens = COM_Parse(tokens))) while((tokens = COM_Parse(tokens)))
{ {
@ -3615,16 +3672,9 @@ static void CL_ConnectionlessPacket_Connection(char *tokens)
} }
} }
else if (!strncmp(com_token, "nc=", 3)) else if (!strncmp(com_token, "nc=", 3))
{ qportsize = atoi(com_token+3)?1:2;
int type = (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)?1:0;
if (atoi(com_token+3) != type)
{
CL_ConnectAbort("server's netchan type differs from expected.");
return;
}
}
else if (!strncmp(com_token, "map=", 4)) else if (!strncmp(com_token, "map=", 4))
; SCR_ImageName(com_token+4);
else if (!strncmp(com_token, "dlserver=", 9)) else if (!strncmp(com_token, "dlserver=", 9))
Q_strncpyz(cls.downloadurl, com_token+9, sizeof(cls.downloadurl)); Q_strncpyz(cls.downloadurl, com_token+9, sizeof(cls.downloadurl));
else else
@ -3642,12 +3692,9 @@ static void CL_ConnectionlessPacket_Connection(char *tokens)
cls.ezprotocolextensions1 = connectinfo.ext.ez1; cls.ezprotocolextensions1 = connectinfo.ext.ez1;
cls.challenge = connectinfo.challenge; cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport); Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
if (cls.protocol == CP_QUAKE2) cls.protocol_q2 = (cls.protocol == CP_QUAKE2)?connectinfo.subprotocol:0;
{ if (qportsize>=0)
cls.protocol_q2 = connectinfo.subprotocol; cls.netchan.qportsize = qportsize;
if (cls.protocol_q2 == PROTOCOL_VERSION_R1Q2 || cls.protocol_q2 == PROTOCOL_VERSION_Q2PRO)
cls.netchan.qportsize = 1;
}
cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false; cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false;
cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE); cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE);
if (connectinfo.ext.mtu >= 64) if (connectinfo.ext.mtu >= 64)
@ -5685,6 +5732,9 @@ void CL_Init (void)
#ifdef NQPROT #ifdef NQPROT
Cmd_AddCommandD ("connectnq", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also disables QW/Q2/Q3/DP handshakes preventing them from being favoured, so should only be used when you actually want NQ protocols specifically."); Cmd_AddCommandD ("connectnq", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also disables QW/Q2/Q3/DP handshakes preventing them from being favoured, so should only be used when you actually want NQ protocols specifically.");
Cmd_AddCommandD ("connectqe", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also forces the use of DTLS and QE-specific handshakes. You will also need to ensure the dtls_psk_* cvars are set properly or the server will refuse the connection."); Cmd_AddCommandD ("connectqe", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also forces the use of DTLS and QE-specific handshakes. You will also need to ensure the dtls_psk_* cvars are set properly or the server will refuse the connection.");
#endif
#ifdef Q2CLIENT
Cmd_AddCommandD ("connectq2e", CLQ2E_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_Q2ESERVER)".");
#endif #endif
Cmd_AddCommand ("reconnect", CL_Reconnect_f); Cmd_AddCommand ("reconnect", CL_Reconnect_f);
Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server."); Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server.");

View file

@ -1671,6 +1671,8 @@ int CLNQ_GetMessage (void);
#endif #endif
void CL_BeginServerReconnect(void); void CL_BeginServerReconnect(void);
qboolean CL_IsPendingServerAddress(netadr_t *adr);
void CL_Transfer(netadr_t *adr);
void SV_User_f (void); //called by client version of the function void SV_User_f (void); //called by client version of the function
void SV_Serverinfo_f (void); void SV_Serverinfo_f (void);

View file

@ -3871,6 +3871,11 @@ void CL_Say (qboolean team, char *extra)
strlcat (sendtext, va("\x7f!%c", 'A'+pv->playernum), sizeof(sendtext)); strlcat (sendtext, va("\x7f!%c", 'A'+pv->playernum), sizeof(sendtext));
} }
#ifdef Q2CLIENT
if (cls.netchan.remote_address.prot == NP_KEXLAN && NET_GetConnectionCertificate(cls.sockets, &cls.netchan.remote_address, QCERT_LOBBYSENDCHAT, sendtext, strlen(sendtext))>0)
return;
#endif
#ifdef Q3CLIENT #ifdef Q3CLIENT
if (cls.protocol == CP_QUAKE3) if (cls.protocol == CP_QUAKE3)
q3->cl.SendClientCommand("%s %s%s", team ? "say_team" : "say", extra?extra:"", sendtext); q3->cl.SendClientCommand("%s %s%s", team ? "say_team" : "say", extra?extra:"", sendtext);

View file

@ -397,7 +397,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef USE_EGL #undef USE_EGL
#endif #endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) #if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS)
#define HAVE_SSL #define HAVE_SSL
#endif #endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS) #if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS)

View file

@ -54,6 +54,9 @@ typedef enum {
typedef enum { typedef enum {
NP_DGRAM, NP_DGRAM,
NP_DTLS, //connected via ICE/WebRTC NP_DTLS, //connected via ICE/WebRTC
NP_KEXLAN, //layered over some silly lobby mess
#define NP_ISLAYERED(np) (np>=NP_DTLS && np<=NP_KEXLAN)
NP_STREAM, NP_STREAM,
NP_TLS, NP_TLS,
NP_WS, NP_WS,
@ -166,6 +169,18 @@ enum addressscope_e
}; };
enum addressscope_e NET_ClassifyAddress(netadr_t *adr, const char **outdesc); enum addressscope_e NET_ClassifyAddress(netadr_t *adr, const char **outdesc);
struct urischeme_s
{
const char *name;
netproto_t prot; //NP_INVALID means its a game-specific one that should really be handled elsewhere but is silently ignored by the netcode.
netadrtype_t family; //usually NA_INVALID, unless ipv4/ipv6-specific
enum
{
URISCHEME_NEEDSRESOURCE = (1<<0), //forwards it on to the server
} flags;
};
const struct urischeme_s *NET_IsURIScheme(const char *possible);
qboolean NET_AddrIsReliable(netadr_t *adr); //hints that the protocol is reliable. if so, we don't need to wait for acks qboolean NET_AddrIsReliable(netadr_t *adr); //hints that the protocol is reliable. if so, we don't need to wait for acks
qboolean NET_IsEncrypted(netadr_t *adr); qboolean NET_IsEncrypted(netadr_t *adr);
qboolean NET_CompareAdr (netadr_t *a, netadr_t *b); qboolean NET_CompareAdr (netadr_t *a, netadr_t *b);
@ -198,6 +213,9 @@ enum certprops_e
QCERT_PEERCERTIFICATE, //should be the primary cert, ignoring chain. no fixed maximum size required, mostly 2k but probably best to allow at leasy 5k.. or 8k. QCERT_PEERCERTIFICATE, //should be the primary cert, ignoring chain. no fixed maximum size required, mostly 2k but probably best to allow at leasy 5k.. or 8k.
QCERT_LOCALCERTIFICATE, //the cert we're using/advertising. may have no context. to tell people what fp to expect. QCERT_LOCALCERTIFICATE, //the cert we're using/advertising. may have no context. to tell people what fp to expect.
QCERT_LOBBYSTATUS, //for special-case lobby wrappers.
QCERT_LOBBYSENDCHAT, //to send chat via the stupid lobby instead of the game itself.
}; };
int NET_GetConnectionCertificate(struct ftenet_connections_s *col, netadr_t *a, enum certprops_e prop, char *out, size_t outsize); int NET_GetConnectionCertificate(struct ftenet_connections_s *col, netadr_t *a, enum certprops_e prop, char *out, size_t outsize);

View file

@ -387,7 +387,10 @@ void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport)
chan->qport = qport; chan->qport = qport;
chan->qportsize = 2; if (adr->prot == NP_KEXLAN)
chan->qportsize = 0;
else
chan->qportsize = 2;
} }
@ -790,6 +793,28 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
send_reliable = true; send_reliable = true;
} }
if (send_reliable && chan->remote_address.prot == NP_KEXLAN)
#ifndef SERVERONLY
if (!cls.demoplayback)
#endif
{
if (chan->reliable_length)
{
send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
send.cursize = 0;
MSG_WriteLong (&send, 1u<<31);
MSG_WriteLong (&send, 1u<<31);
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
if (NETERR_SENT == NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address))
chan->reliable_length = 0; //the lower layer will handle any retransmission for us.
}
send_reliable = 0;
chan->incoming_reliable_sequence = 0;
}
// write the packet header // write the packet header
send.data = send_buf; send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER; send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER;
@ -950,6 +975,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (e == NETERR_SENT) if (e == NETERR_SENT)
{ {
if (send_reliable && NET_AddrIsReliable(&chan->remote_address))
chan->reliable_length = 0; //we know the peer will receive it. don't worry about waiting for their acks.
chan->bytesout += send.cursize; chan->bytesout += send.cursize;
Netchan_Block(chan, send.cursize, rate); Netchan_Block(chan, send.cursize, rate);
} }
@ -1025,7 +1053,7 @@ qboolean Netchan_Process (netchan_t *chan)
// skip over the qport if we are a server (its handled elsewhere) // skip over the qport if we are a server (its handled elsewhere)
#ifndef CLIENTONLY #ifndef CLIENTONLY
if (chan->sock == NS_SERVER) if (chan->sock == NS_SERVER)
MSG_ReadShort (); MSG_ReadSkip (chan->qportsize);
#endif #endif
if (chan->pext_fragmentation) if (chan->pext_fragmentation)
@ -1083,7 +1111,8 @@ qboolean Netchan_Process (netchan_t *chan)
// //
// discard stale or duplicated packets // discard stale or duplicated packets
// //
if (sequence <= (unsigned)chan->incoming_sequence) if (sequence <= (unsigned)chan->incoming_sequence &&
!(reliable_message && chan->remote_address.prot == NP_KEXLAN)) //*sigh* reliables don't work properly here.
{ {
if (showdrop.value) if (showdrop.value)
Con_TPrintf ("%s:Out of order packet %i at %i\n" Con_TPrintf ("%s:Out of order packet %i at %i\n"
@ -1180,11 +1209,16 @@ qboolean Netchan_Process (netchan_t *chan)
// //
// if this message contains a reliable message, bump incoming_reliable_sequence // if this message contains a reliable message, bump incoming_reliable_sequence
// //
chan->incoming_sequence = sequence; if (reliable_message && chan->remote_address.prot == NP_KEXLAN) //*sigh* reliables don't work properly here.
chan->incoming_acknowledged = sequence_ack; ; //don't corrupt sequences/acks/etc.
chan->incoming_reliable_acknowledged = reliable_ack; else
if (reliable_message) {
chan->incoming_reliable_sequence ^= 1; chan->incoming_sequence = sequence;
chan->incoming_acknowledged = sequence_ack;
chan->incoming_reliable_acknowledged = reliable_ack;
if (reliable_message)
chan->incoming_reliable_sequence ^= 1;
}
// //
// the message can now be read from the current message pointer // the message can now be read from the current message pointer

File diff suppressed because it is too large Load diff

View file

@ -1943,7 +1943,7 @@ qboolean SV_ChallengePasses(int challenge)
//this means that DP clients tend to connect as generic NQ clients. //this means that DP clients tend to connect as generic NQ clients.
//and because DP _REQUIRES_ sv_bigcoords, they tend to end up being given fitz/rmq protocols //and because DP _REQUIRES_ sv_bigcoords, they tend to end up being given fitz/rmq protocols
//thus we don't respond to the connect if sv_listen_dp is 1, and we had a recent getchallenge request. recent is 2 secs. //thus we don't respond to the connect if sv_listen_dp is 1, and we had a recent getchallenge request. recent is 2 secs.
static qboolean SV_ChallengeRecent(void) qboolean SV_ChallengeRecent(void)
{ {
int curtime = realtime; //yeah, evil. sue me. consitent with challenges. int curtime = realtime; //yeah, evil. sue me. consitent with challenges.
int i; int i;
@ -3264,13 +3264,13 @@ void SV_DoDirectConnect(svconnectinfo_t *fte_restrict info)
else //measure this guy in minuites. else //measure this guy in minuites.
s = va(langtext("Welcome back %s. You have previously spent %i mins connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/60)); s = va(langtext("Welcome back %s. You have previously spent %i mins connected\n", newcl->language), newcl->name, (int)(rs.timeonserver/60));
SV_OutOfBandPrintf (info->protocol == SCP_QUAKE2, &info->adr, s); SV_OutOfBandPrintf (ISQ2CLIENT(info), &info->adr, s);
} }
else if (!preserveparms) else if (!preserveparms)
{ {
SV_GetNewSpawnParms(newcl); SV_GetNewSpawnParms(newcl);
SV_OutOfBandTPrintf (info->protocol == SCP_QUAKE2, &info->adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver); SV_OutOfBandTPrintf (ISQ2CLIENT(info), &info->adr, newcl->language, "Welcome %s. Your time on this server is being logged and ranked\n", newcl->name, (int)rs.timeonserver);
} }
//else loaded players already have their initial parms set //else loaded players already have their initial parms set
} }
@ -3570,7 +3570,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
}*/ }*/
version = atoi(Cmd_Argv(1)); version = atoi(Cmd_Argv(1));
if (version >= 31 && version <= 34) if (version >= PROTOCOL_VERSION_Q2_MIN && version <= PROTOCOL_VERSION_Q2)
info.protocol = SCP_QUAKE2; info.protocol = SCP_QUAKE2;
#ifdef NQPROT #ifdef NQPROT
else if (version == NQ_NETCHAN_VERSION) else if (version == NQ_NETCHAN_VERSION)
@ -3650,11 +3650,13 @@ void SVC_DirectConnect(int expectedreliablesequence)
} }
} }
// see if the challenge is valid.
if (net_from.type == NA_LOOPBACK) //normal rules don't apply if (net_from.type == NA_LOOPBACK) //normal rules don't apply
; ;
else if (net_from.prot != NP_DGRAM)
; //challenge checks are irrelevant when we've alread passed a challenge in a lower network layer.
else else
{ {
// see if the challenge is valid
if (!SV_ChallengePasses(info.challenge)) if (!SV_ChallengePasses(info.challenge))
{ {
if (sv_listen_dp.ival && !info.challenge && info.protocol == SCP_QUAKEWORLD) if (sv_listen_dp.ival && !info.challenge && info.protocol == SCP_QUAKEWORLD)
@ -4940,8 +4942,16 @@ void SV_ReadPacket(void)
continue; continue;
#endif #endif
if (cl->netchan.qport != qport) if (cl->netchan.qportsize == 0)
continue; { //no qports... use the actual port.
if (cl->netchan.remote_address.port != net_from.port)
continue;
}
else
{
if (cl->netchan.qport != qport)
continue;
}
if (cl->netchan.remote_address.port != net_from.port) if (cl->netchan.remote_address.port != net_from.port)
{ {
Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n"); Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n");
@ -4994,7 +5004,7 @@ dominping:
cl->send_message = true; // reply at end of frame cl->send_message = true; // reply at end of frame
#ifdef Q2SERVER #ifdef Q2SERVER
if (cl->protocol == SCP_QUAKE2) if (ISQ2CLIENT(cl))
SVQ2_ExecuteClientMessage(cl); SVQ2_ExecuteClientMessage(cl);
else else
#endif #endif
@ -5107,7 +5117,7 @@ qboolean SV_ReadPackets (float *delay)
cl->send_message = true; // reply at end of frame cl->send_message = true; // reply at end of frame
#ifdef Q2SERVER #ifdef Q2SERVER
if (cl->protocol == SCP_QUAKE2) if (ISQ2CLIENT(cl))
SVQ2_ExecuteClientMessage(cl); SVQ2_ExecuteClientMessage(cl);
else else
#endif #endif