1
0
Fork 0
forked from fte/fteqw

Try to fix up some ICE quirks.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6302 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2022-08-07 23:49:33 +00:00
parent cbb18429f1
commit a0f2ffda90
15 changed files with 227 additions and 141 deletions

View file

@ -1348,7 +1348,7 @@ void CL_CheckForResend (void)
if (contype & 1) if (contype & 1)
{ {
char tmp[256]; char tmp[256];
MSG_WriteString(&sb, va("%c%c%c%cgetchallenge %i %s\n", 255, 255, 255, 255, connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false))); MSG_WriteString(&sb, va("getchallenge %i %s\n", connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false)));
} }
} }
@ -3600,7 +3600,7 @@ void CL_ConnectionlessPacket (void)
} }
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (candtls && net_from.prot == NP_DGRAM && (connectinfo.dtlsupgrade || candtls > 1)) if (candtls && net_from.prot == NP_DGRAM && (connectinfo.dtlsupgrade || candtls > 1) && !NET_IsEncrypted(&net_from))
{ {
//c2s getchallenge //c2s getchallenge
//s2c c%u\0DTLS=$candtls //s2c c%u\0DTLS=$candtls

View file

@ -2254,14 +2254,18 @@ void Master_CheckPollSockets(void)
continue; continue;
} }
#endif #endif
//#ifdef Q3CLIENT //q3/dpm server responses
if (!strcmp(s, "statusResponse")) if (!strcmp(s, "statusResponse"))
{ { //originally q3, but oh well.
CL_ReadServerInfo(MSG_ReadString(), MP_QUAKE3, false); CL_ReadServerInfo(MSG_ReadString(), MP_DPMASTER, false);
continue; continue;
} }
//#endif if (!strcmp(s, "infoResponse")) //parse a bit more...
{ //originally q3, but oh well.
CL_ReadServerInfo(MSG_ReadString(), MP_DPMASTER, false);
continue;
}
//q3/dpm master responses
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more... if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more...
{ {
@ -2282,11 +2286,6 @@ void Master_CheckPollSockets(void)
CL_MasterListParse(NA_IP, SS_GETINFO, true); CL_MasterListParse(NA_IP, SS_GETINFO, true);
continue; continue;
} }
if (!strcmp(s, "infoResponse")) //parse a bit more...
{
CL_ReadServerInfo(MSG_ReadString(), MP_DPMASTER, false);
continue;
}
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (!strncmp(s, "qw_slist6\\", 10)) //parse a bit more... if (!strncmp(s, "qw_slist6\\", 10)) //parse a bit more...
@ -3294,7 +3293,7 @@ static int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolea
info->special |= SS_QUAKE2; info->special |= SS_QUAKE2;
#endif #endif
#ifdef Q3CLIENT #ifdef Q3CLIENT
else if (prototype == MP_QUAKE3) else if (prototype == MP_QUAKE3 || prototype == MP_DPMASTER/*if no protocol, assume q3 behaviours*/)
info->special |= SS_QUAKE3; info->special |= SS_QUAKE3;
#endif #endif
#ifdef NQPROT #ifdef NQPROT

View file

@ -1038,8 +1038,8 @@ void QCBUILTIN PF_cl_clipboard_set(pubprogfuncs_t *prinst, struct globalvars_s *
void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_cl_localsound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
const char * s = PR_GetStringOfs(prinst, OFS_PARM0); const char * s = PR_GetStringOfs(prinst, OFS_PARM0);
float chan = (prinst->callargc>=1)?G_FLOAT(OFS_PARM1):0; float chan = (prinst->callargc>1)?G_FLOAT(OFS_PARM1):0;
float vol = (prinst->callargc>=2)?G_FLOAT(OFS_PARM2):1; float vol = (prinst->callargc>2)?G_FLOAT(OFS_PARM2):1;
S_LocalSound2(s, chan, vol); S_LocalSound2(s, chan, vol);
} }

View file

@ -5170,7 +5170,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
} }
if (!strcmp(gamename, "quake")) if (!strcmp(gamename, "quake") || !strcmp(gamename, "afterquake") || !strcmp(gamename, "netquake") || !strcmp(gamename, "spasm") || !strcmp(gamename, "fitz") || !strcmp(gamename, "tenebrae"))
{ {
char *prefix[] = char *prefix[] =
{ {
@ -5383,9 +5383,14 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
char *s; char *s;
if (!*gamename) if (!*gamename)
gamename = "quake"; //just a paranoia fallback, shouldn't be needed. gamename = "quake"; //just a paranoia fallback, shouldn't be needed.
if (!strcmp(gamename, "quake")) if (!strcmp(gamename, "quake_rerel"))
if (Sys_SteamHasFile(basepath, basepathlen, "Quake/rerelease", "id1/pak0.pak"))
return true;
if (!strcmp(gamename, "quake") || !strcmp(gamename, "afterquake") || !strcmp(gamename, "netquake") || !strcmp(gamename, "spasm") || !strcmp(gamename, "fitz") || !strcmp(gamename, "tenebrae"))
{ {
if (Sys_SteamHasFile(basepath, basepathlen, "quake", "id1/pak0.pak")) if (Sys_SteamHasFile(basepath, basepathlen, "Quake", "id1/PAK0.PAK")) //dos legacies need to die.
return true;
if (Sys_SteamHasFile(basepath, basepathlen, "Quake", "id1/pak0.pak")) //people may have tried to sanitise it already.
return true; return true;
if (stat("/usr/share/quake/", &sb) == 0) if (stat("/usr/share/quake/", &sb) == 0)

View file

@ -103,6 +103,8 @@ this allows the connection to pick a new route if some router dies (like a relay
FIXME: the client currently disconnects from the broker. the server tracks players via ip rather than ICE. FIXME: the client currently disconnects from the broker. the server tracks players via ip rather than ICE.
tcp rtp framing should generally be done with a 16-bit network-endian length prefix followed by the data. tcp rtp framing should generally be done with a 16-bit network-endian length prefix followed by the data.
NOTE: we do NOT distinguish between media-level and session-level attributes, as such we can only handle ONE media stream per session. we also don't support rtcp.
*/ */
struct icecandidate_s struct icecandidate_s
@ -162,7 +164,8 @@ struct icestate_s
} server[8]; } server[8];
unsigned int servers; unsigned int servers;
unsigned int timeout; //time when we consider the connection dead qboolean brokerless; //we lost connection to our broker... clean up on failure status.
unsigned int icetimeout; //time when we consider the connection dead
unsigned int keepalive; //sent periodically... unsigned int keepalive; //sent periodically...
unsigned int retries; //bumped after each round of connectivity checks. affects future intervals. unsigned int retries; //bumped after each round of connectivity checks. affects future intervals.
enum iceproto_e proto; enum iceproto_e proto;
@ -189,7 +192,7 @@ struct icestate_s
unsigned int tielow; unsigned int tielow;
int foundation; int foundation;
qboolean blockcandidates; //don't send candidates yet. qboolean blockcandidates; //don't send candidates yet. FIXME: replace with gathering.
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
void *dtlsstate; void *dtlsstate;
struct sctp_s *sctp; //ffs! extra processing needed. struct sctp_s *sctp; //ffs! extra processing needed.
@ -253,6 +256,7 @@ typedef struct sctp_s
unsigned short qstreamid; //in network endian. unsigned short qstreamid; //in network endian.
} sctp_t; } sctp_t;
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
extern cvar_t net_enable_dtls;
static neterr_t SCTP_Transmit(sctp_t *sctp, struct icestate_s *peer, const void *data, size_t length); static neterr_t SCTP_Transmit(sctp_t *sctp, struct icestate_s *peer, const void *data, size_t length);
#endif #endif
static neterr_t ICE_Transmit(void *cbctx, const qbyte *data, size_t datasize); static neterr_t ICE_Transmit(void *cbctx, const qbyte *data, size_t datasize);
@ -536,17 +540,14 @@ static neterr_t TURN_Encapsulate(struct icestate_s *ice, netadr_t *to, const qby
struct iceserver_s *srv; struct iceserver_s *srv;
if (to->type == NA_INVALID) if (to->type == NA_INVALID)
return NETERR_NOROUTE; return NETERR_NOROUTE;
if (network >= MAX_CONNECTIONS) if (to->connum && network >= MAX_CONNECTIONS)
{ //fancy turn-related gubbins { //fancy turn-related gubbins
network -= MAX_CONNECTIONS; network -= MAX_CONNECTIONS;
if (network >= countof(ice->server)) if (network >= countof(ice->server))
{ //really high, its from the raw socket, unstunned. { //really high, its from the raw socket, unstunned.
network -= countof(ice->server); network -= countof(ice->server);
if (network >= countof(ice->server)) if (network >= countof(ice->server))
{
Con_Printf("TURN_Encapsulate: %i\n", to->connum);
return NETERR_NOROUTE; return NETERR_NOROUTE;
}
srv = &ice->server[network]; srv = &ice->server[network];
if (!srv->con || net_ice_relayonly.ival) if (!srv->con || net_ice_relayonly.ival)
@ -990,7 +991,7 @@ static qboolean ICE_SendSpam(struct icestate_s *con)
} }
extern ftenet_generic_connection_t *FTENET_Datagram_EstablishConnection(ftenet_connections_t *col, const char *address, netadr_t adr); extern ftenet_generic_connection_t *FTENET_Datagram_EstablishConnection(ftenet_connections_t *col, const char *address, netadr_t adr);
#ifdef TCPCONNECT #ifdef HAVE_TCP
struct turntcp_connection_s struct turntcp_connection_s
{ //this sends packets only to the relay, and accepts them only from there too. all packets must be stun packets (for byte-count framing) { //this sends packets only to the relay, and accepts them only from there too. all packets must be stun packets (for byte-count framing)
ftenet_generic_connection_t pub; ftenet_generic_connection_t pub;
@ -1178,7 +1179,13 @@ static void ICE_ToStunServer(struct icestate_s *con, struct iceserver_s *srv)
if (srv->addr.type == NA_INVALID) if (srv->addr.type == NA_INVALID)
return; //nope... return; //nope...
if (srv->addr.prot != NP_DGRAM) if (srv->addr.prot != NP_DGRAM)
{
#ifdef HAVE_TCP
srv->con = TURN_TCP_EstablishConnection(collection, srv->realm, srv->addr); srv->con = TURN_TCP_EstablishConnection(collection, srv->realm, srv->addr);
#else
srv->con = NULL;
#endif
}
else else
{ {
netadr_t localadr; netadr_t localadr;
@ -2096,7 +2103,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
Con_Printf("ICE_Set invalid state %s\n", value); Con_Printf("ICE_Set invalid state %s\n", value);
con->state = ICE_INACTIVE; con->state = ICE_INACTIVE;
} }
con->timeout = Sys_Milliseconds() + 30; con->icetimeout = Sys_Milliseconds() + 30*1000;
con->retries = 0; con->retries = 0;
@ -2117,15 +2124,14 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
{ {
if (!con->dtlsstate && con->dtlsfuncs) if (!con->dtlsstate && con->dtlsfuncs)
{ {
extern cvar_t net_enable_dtls;
if (con->cred.peer.hash) if (con->cred.peer.hash)
con->dtlsstate = con->dtlsfuncs->CreateContext(&con->cred, con, ICE_Transmit, con->dtlspassive); con->dtlsstate = con->dtlsfuncs->CreateContext(&con->cred, con, ICE_Transmit, con->dtlspassive);
else if (net_enable_dtls.ival) else if (net_enable_dtls.ival >= 3)
{ //peer doesn't seem to support dtls. { //peer doesn't seem to support dtls.
con->state = ICE_FAILED; con->state = ICE_FAILED;
Con_Printf(CON_WARNING"WARNING: peer does not support dtls. Set net_enable_dtls to 0 to make optional.\n"); Con_Printf(CON_WARNING"WARNING: peer does not support dtls. Set net_enable_dtls to 0 to make optional.\n");
} }
else if (con->state == ICE_CONNECTING) else if (con->state == ICE_CONNECTING && net_enable_dtls.ival>=2)
Con_Printf(CON_WARNING"WARNING: peer does not support dtls.\n"); Con_Printf(CON_WARNING"WARNING: peer does not support dtls.\n");
} }
if (!con->sctp && (!con->sctpoptional || !con->peersctpoptional) && con->mysctpport && con->peersctpport) if (!con->sctp && (!con->sctpoptional || !con->peersctpoptional) && con->mysctpport && con->peersctpport)
@ -2408,6 +2414,9 @@ static qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *va
case ICE_FAILED: case ICE_FAILED:
Q_strncpyz(value, STRINGIFY(ICE_FAILED), valuelen); Q_strncpyz(value, STRINGIFY(ICE_FAILED), valuelen);
break; break;
case ICE_GATHERING:
Q_strncpyz(value, STRINGIFY(ICE_GATHERING), valuelen);
break;
case ICE_CONNECTING: case ICE_CONNECTING:
Q_strncpyz(value, STRINGIFY(ICE_CONNECTING), valuelen); Q_strncpyz(value, STRINGIFY(ICE_CONNECTING), valuelen);
break; break;
@ -2512,6 +2521,13 @@ static qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *va
if (con->proto == ICEP_QWSERVER || con->proto == ICEP_QWCLIENT) if (con->proto == ICEP_QWSERVER || con->proto == ICEP_QWCLIENT)
{ {
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (net_enable_dtls.ival >= 3)
{ //this is a preliminary check to avoid wasting time
if (!con->cred.local.certsize)
return false; //fail if we cannot do dtls when its required.
if (!strcmp(prop, "sdpanswer") || !con->cred.peer.hash)
return false; //don't answer if they failed to provide a cert
}
if (con->cred.local.certsize) if (con->cred.local.certsize)
{ {
qbyte fingerprint[DIGEST_MAXSIZE]; qbyte fingerprint[DIGEST_MAXSIZE];
@ -2607,12 +2623,17 @@ static void ICE_PrintSummary(struct icestate_s *con, qboolean islisten)
{ {
case ICE_INACTIVE: Con_Printf(S_COLOR_RED "inactive"); break; case ICE_INACTIVE: Con_Printf(S_COLOR_RED "inactive"); break;
case ICE_FAILED: Con_Printf(S_COLOR_RED "failed"); break; case ICE_FAILED: Con_Printf(S_COLOR_RED "failed"); break;
case ICE_GATHERING: Con_Printf(S_COLOR_YELLOW "gathering"); break;
case ICE_CONNECTING: Con_Printf(S_COLOR_YELLOW "connecting"); break; case ICE_CONNECTING: Con_Printf(S_COLOR_YELLOW "connecting"); break;
case ICE_CONNECTED: Con_Printf(S_COLOR_GRAY"%s via %s", NET_AdrToString(msg,sizeof(msg), &con->chosenpeer), ICE_NetworkToName(con, con->chosenpeer.connum)); break; case ICE_CONNECTED: Con_Printf(S_COLOR_GRAY"%s via %s", NET_AdrToString(msg,sizeof(msg), &con->chosenpeer), ICE_NetworkToName(con, con->chosenpeer.connum)); break;
} }
#ifdef HAVE_DTLS
if (con->dtlsstate) if (con->dtlsstate)
Con_Printf(S_COLOR_GREEN " (encrypted)"); Con_Printf(S_COLOR_GREEN " (encrypted%s)", con->sctp?", sctp":"");
else if (con->sctp)
Con_Printf(S_COLOR_RED " (plain-text, sctp)"); //weeeeeeird and pointless...
else else
#endif
Con_Printf(S_COLOR_RED " (plain-text)"); Con_Printf(S_COLOR_RED " (plain-text)");
Con_Printf("\n"); Con_Printf("\n");
} }
@ -2622,6 +2643,14 @@ static void ICE_Debug(struct icestate_s *con)
char buf[65536]; char buf[65536];
ICE_Get(con, "state", buf, sizeof(buf)); ICE_Get(con, "state", buf, sizeof(buf));
Con_Printf("ICE [%s] (%s):\n", con->friendlyname, buf); Con_Printf("ICE [%s] (%s):\n", con->friendlyname, buf);
if (con->brokerless)
Con_Printf(" timeout: %g\n", (int)(con->icetimeout-Sys_Milliseconds())/1000.0);
else
{
unsigned int idle = (Sys_Milliseconds()+30*1000 - con->icetimeout);
if (idle > 500)
Con_Printf(" idle: %g\n", idle/1000.0);
}
if (net_ice_debug.ival >= 2) if (net_ice_debug.ival >= 2)
{ //rather uninteresting really... { //rather uninteresting really...
if (con->initiator) if (con->initiator)
@ -2880,7 +2909,7 @@ static void ICE_Destroy(struct icestate_s *con)
//send pings to establish/keep the connection alive //send pings to establish/keep the connection alive
void ICE_Tick(void) void ICE_Tick(void)
{ {
struct icestate_s *con; struct icestate_s **link, *con;
unsigned int curtime; unsigned int curtime;
if (!icelist) if (!icelist)
@ -2889,8 +2918,20 @@ void ICE_Tick(void)
MDNS_SendQueries(); MDNS_SendQueries();
for (con = icelist; con; con = con->next) for (link = &icelist; (con=*link);)
{ {
if (con->brokerless)
{
if (con->state <= ICE_GATHERING)
{
*link = con->next;
ICE_Destroy(con);
continue;
}
else if ((signed int)(curtime-con->icetimeout) > 0)
ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); //with no broker context, if we're not trying to send anything then kill the link.
}
switch(con->mode) switch(con->mode)
{ {
case ICEM_RAW: case ICEM_RAW:
@ -3008,9 +3049,11 @@ void ICE_Tick(void)
} }
break; break;
} }
link = &con->next;
} }
} }
static void QDECL ICE_Close(struct icestate_s *con) static void QDECL ICE_Close(struct icestate_s *con, qboolean force)
{ {
struct icestate_s **link; struct icestate_s **link;
@ -3018,8 +3061,13 @@ static void QDECL ICE_Close(struct icestate_s *con)
{ {
if (con == *link) if (con == *link)
{ {
*link = con->next; if (!force)
ICE_Destroy(con); con->brokerless = true;
else
{
*link = con->next;
ICE_Destroy(con);
}
return; return;
} }
else else
@ -3938,7 +3986,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
{ {
char str[256]; char str[256];
if (net_ice_debug.ival >= 1) if (net_ice_debug.ival >= 1)
Con_Printf(S_COLOR_GRAY"[%s]: We can reach %s (%s)\n", con->friendlyname, NET_AdrToString(str, sizeof(str), &net_from), ICE_GetCandidateType(&rc->info)); Con_Printf(S_COLOR_GRAY"[%s]: We can reach %s (%s) via %s\n", con->friendlyname, NET_AdrToString(str, sizeof(str), &net_from), ICE_GetCandidateType(&rc->info), ICE_NetworkToName(con, net_from.connum));
} }
rc->reachable |= 1u<<(net_from.connum-1); rc->reachable |= 1u<<(net_from.connum-1);
rc->reached = Sys_Milliseconds(); rc->reached = Sys_Milliseconds();
@ -4698,8 +4746,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
{ {
// if (rc->reachable) // if (rc->reachable)
{ //found it. fix up its source address to our ICE connection (so we don't have path-switching issues) and keep chugging along. { //found it. fix up its source address to our ICE connection (so we don't have path-switching issues) and keep chugging along.
con->icetimeout = Sys_Milliseconds() + 1000*30; //not dead yet...
con->timeout = Sys_Milliseconds() + 32; //not dead yet...
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (con->dtlsstate) if (con->dtlsstate)
@ -4711,7 +4758,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
case NETERR_NOROUTE: case NETERR_NOROUTE:
return false; //not a dtls packet at all. don't de-ICE it when we're meant to be using ICE. return false; //not a dtls packet at all. don't de-ICE it when we're meant to be using ICE.
case NETERR_DISCONNECTED: //dtls failure. ICE failed. case NETERR_DISCONNECTED: //dtls failure. ICE failed.
iceapi.ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); iceapi.Set(con, "state", STRINGIFY(ICE_FAILED));
return true; return true;
default: //some kind of failure decoding the dtls packet. drop it. default: //some kind of failure decoding the dtls packet. drop it.
return true; return true;
@ -4722,6 +4769,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (con->sctp) if (con->sctp)
SCTP_Decode(con->sctp, con, col); SCTP_Decode(con->sctp, con, col);
else
#endif #endif
if (net_message.cursize) if (net_message.cursize)
col->ReadGamePacket(); col->ReadGamePacket();
@ -4769,6 +4817,12 @@ neterr_t ICE_SendPacket(size_t length, const void *data, netadr_t *to)
{ {
if (NET_CompareAdr(to, &con->qadr)) if (NET_CompareAdr(to, &con->qadr))
{ {
con->icetimeout = Sys_Milliseconds()+30*1000; //keep it alive a little longer.
if (con->state == ICE_CONNECTING)
return NETERR_CLOGGED;
else if (con->state != ICE_CONNECTED)
return NETERR_DISCONNECTED;
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (con->sctp) if (con->sctp)
return SCTP_Transmit(con->sctp, con, data, length); return SCTP_Transmit(con->sctp, con, data, length);
@ -4777,8 +4831,6 @@ neterr_t ICE_SendPacket(size_t length, const void *data, netadr_t *to)
#endif #endif
if (con->chosenpeer.type != NA_INVALID) if (con->chosenpeer.type != NA_INVALID)
return ICE_Transmit(con, data, length); return ICE_Transmit(con, data, length);
if (con->state < ICE_CONNECTING)
return NETERR_DISCONNECTED;
return NETERR_CLOGGED; //still pending return NETERR_CLOGGED; //still pending
} }
} }
@ -4835,10 +4887,10 @@ static void FTENET_ICE_Close(ftenet_generic_connection_t *gcon)
for (cl = 0; cl < b->numclients; cl++) for (cl = 0; cl < b->numclients; cl++)
if (b->clients[cl].ice) if (b->clients[cl].ice)
iceapi.ICE_Close(b->clients[cl].ice); iceapi.Close(b->clients[cl].ice, true);
Z_Free(b->clients); Z_Free(b->clients);
if (b->ice) if (b->ice)
iceapi.ICE_Close(b->ice); iceapi.Close(b->ice, true);
Z_Free(b); Z_Free(b);
} }
@ -4940,9 +4992,11 @@ static void FTENET_ICE_SendOffer(ftenet_ice_connection_t *b, int cl, struct ices
{ {
char buf[8192]; char buf[8192];
//okay, now send the sdp to our peer. //okay, now send the sdp to our peer.
if (iceapi.ICE_Get(ice, type, buf, sizeof(buf))) if (iceapi.Get(ice, type, buf, sizeof(buf)))
{ {
char json[8192+256]; char json[8192+256];
if (ice->state == ICE_GATHERING)
ice->state = ICE_CONNECTING;
if (ice->mode == ICEM_WEBRTC) if (ice->mode == ICEM_WEBRTC)
{ {
Q_strncpyz(json, va("{\"type\":\"%s\",\"sdp\":\"", type+3), sizeof(json)); Q_strncpyz(json, va("{\"type\":\"%s\",\"sdp\":\"", type+3), sizeof(json));
@ -4962,24 +5016,24 @@ static void FTENET_ICE_Establish(ftenet_ice_connection_t *b, int cl, struct ices
qboolean usewebrtc; qboolean usewebrtc;
char *s; char *s;
if (*ret) if (*ret)
iceapi.ICE_Close(*ret); iceapi.Close(*ret, false);
#ifndef HAVE_DTLS #ifndef HAVE_DTLS
usewebrtc = false; usewebrtc = false;
#else #else
if (!*net_ice_usewebrtc.string) if (!*net_ice_usewebrtc.string && net_enable_dtls.ival)
usewebrtc = true; //let the peer decide. this means we use dtls, but not sctp. usewebrtc = true; //let the peer decide. this means we can use dtls, but not sctp.
else else
usewebrtc = net_ice_usewebrtc.ival; usewebrtc = net_ice_usewebrtc.ival;
#endif #endif
ice = *ret = iceapi.ICE_Create(b, NULL, b->generic.islisten?NULL:va("/%s", b->gamename), usewebrtc?ICEM_WEBRTC:ICEM_ICE, b->generic.islisten?ICEP_QWSERVER:ICEP_QWCLIENT, !b->generic.islisten); ice = *ret = iceapi.Create(b, NULL, b->generic.islisten?NULL:va("/%s", b->gamename), usewebrtc?ICEM_WEBRTC:ICEM_ICE, b->generic.islisten?ICEP_QWSERVER:ICEP_QWCLIENT, !b->generic.islisten);
if (!*ret) if (!*ret)
return; //some kind of error?!? return; //some kind of error?!?
iceapi.ICE_Set(ice, "server", va("stun:%s:%i", b->brokername, BigShort(b->brokeradr.port))); iceapi.Set(ice, "server", va("stun:%s:%i", b->brokername, BigShort(b->brokeradr.port)));
s = net_ice_servers.string; s = net_ice_servers.string;
while((s=COM_Parse(s))) while((s=COM_Parse(s)))
iceapi.ICE_Set(ice, "server", com_token); iceapi.Set(ice, "server", com_token);
if (!b->generic.islisten) if (!b->generic.islisten)
FTENET_ICE_SendOffer(b, cl, ice, "sdpoffer"); FTENET_ICE_SendOffer(b, cl, ice, "sdpoffer");
@ -4989,7 +5043,7 @@ static void FTENET_ICE_Refresh(ftenet_ice_connection_t *b, int cl, struct icesta
char buf[8192]; char buf[8192];
if (ice->blockcandidates) if (ice->blockcandidates)
return; //don't send candidates before the offers... return; //don't send candidates before the offers...
while (ice && iceapi.ICE_GetLCandidateSDP(ice, buf, sizeof(buf))) while (ice && iceapi.GetLCandidateSDP(ice, buf, sizeof(buf)))
{ {
char json[8192+256]; char json[8192+256];
if (ice->mode == ICEM_WEBRTC) if (ice->mode == ICEM_WEBRTC)
@ -5058,11 +5112,11 @@ handleerror:
for (cl = 0; cl < b->numclients; cl++) for (cl = 0; cl < b->numclients; cl++)
{ {
if (b->clients[cl].ice) if (b->clients[cl].ice)
iceapi.ICE_Close(b->clients[cl].ice); iceapi.Close(b->clients[cl].ice, false);
b->clients[cl].ice = NULL; b->clients[cl].ice = NULL;
} }
if (b->ice) if (b->ice)
iceapi.ICE_Close(b->ice); iceapi.Close(b->ice, false);
b->ice = NULL; b->ice = NULL;
if (b->error != 1 || !b->generic.islisten) if (b->error != 1 || !b->generic.islisten)
return false; //permanant error... return false; //permanant error...
@ -5163,7 +5217,7 @@ handleerror:
switch(cmd) switch(cmd)
{ {
case ICEMSG_PEERDROP: //connection closing... case ICEMSG_PEERLOST: //the broker lost its connection to our peer...
if (cl == -1) if (cl == -1)
{ {
b->error = true; b->error = true;
@ -5172,7 +5226,7 @@ handleerror:
else if (cl >= 0 && cl < b->numclients) else if (cl >= 0 && cl < b->numclients)
{ {
if (b->clients[cl].ice) if (b->clients[cl].ice)
iceapi.ICE_Close(b->clients[cl].ice); iceapi.Close(b->clients[cl].ice, false);
b->clients[cl].ice = NULL; b->clients[cl].ice = NULL;
// Con_Printf("Broker closing connection: %s\n", data); // Con_Printf("Broker closing connection: %s\n", data);
} }
@ -5223,8 +5277,8 @@ handleerror:
{ {
if (cl >= 0 && cl < b->numclients && b->clients[cl].ice) if (cl >= 0 && cl < b->numclients && b->clients[cl].ice)
{ {
iceapi.ICE_Set(b->clients[cl].ice, "sdpoffer", data); iceapi.Set(b->clients[cl].ice, "sdpoffer", data);
iceapi.ICE_Set(b->clients[cl].ice, "state", STRINGIFY(ICE_CONNECTING)); iceapi.Set(b->clients[cl].ice, "state", STRINGIFY(ICE_CONNECTING));
FTENET_ICE_SendOffer(b, cl, b->clients[cl].ice, "sdpanswer"); FTENET_ICE_SendOffer(b, cl, b->clients[cl].ice, "sdpanswer");
} }
@ -5233,8 +5287,8 @@ handleerror:
{ {
if (b->ice) if (b->ice)
{ {
iceapi.ICE_Set(b->ice, "sdpanswer", data); iceapi.Set(b->ice, "sdpanswer", data);
iceapi.ICE_Set(b->ice, "state", STRINGIFY(ICE_CONNECTING)); iceapi.Set(b->ice, "state", STRINGIFY(ICE_CONNECTING));
} }
} }
break; break;
@ -5251,12 +5305,12 @@ handleerror:
if (b->generic.islisten) if (b->generic.islisten)
{ {
if (cl >= 0 && cl < b->numclients && b->clients[cl].ice) if (cl >= 0 && cl < b->numclients && b->clients[cl].ice)
iceapi.ICE_Set(b->clients[cl].ice, "sdp", data); iceapi.Set(b->clients[cl].ice, "sdp", data);
} }
else else
{ {
if (b->ice) if (b->ice)
iceapi.ICE_Set(b->ice, "sdp", data); iceapi.Set(b->ice, "sdp", data);
} }
break; break;
} }

View file

@ -635,7 +635,10 @@ static int QDECL SSL_Read(struct vfsfile_s *f, void *buffer, int bytestoread)
return 0; //caller is expected to try again later, no real need to loop here, just in case it repeats (eg E_AGAIN) return 0; //caller is expected to try again later, no real need to loop here, just in case it repeats (eg E_AGAIN)
else else
{ {
Con_Printf("GNUTLS Read Warning %i (bufsize %i)\n", read, bytestoread); if (read == GNUTLS_E_PULL_ERROR)
Con_Printf("GNUTLS_E_PULL_ERROR (%s)\n", file->certname);
else
Con_Printf("GNUTLS Read Warning %i (bufsize %i)\n", read, bytestoread);
return -1; return -1;
} }
} }
@ -752,6 +755,7 @@ static ssize_t DTLS_Push(gnutls_transport_ptr_t p, const void *data, size_t size
switch(ne) switch(ne)
{ {
case NETERR_CLOGGED: case NETERR_CLOGGED:
case NETERR_NOROUTE:
qgnutls_transport_set_errno(file->session, EAGAIN); qgnutls_transport_set_errno(file->session, EAGAIN);
return -1; return -1;
case NETERR_MTU: case NETERR_MTU:

View file

@ -3151,6 +3151,8 @@ qboolean NET_DTLS_CheckInbound(ftenet_connections_t *col)
netadr_t *from = &net_from; netadr_t *from = &net_from;
if (from->prot != NP_DGRAM || !net_enable_dtls.ival || !col->dtlsfuncs) if (from->prot != NP_DGRAM || !net_enable_dtls.ival || !col->dtlsfuncs)
return false; return false;
if (!net_message.cursize || !(20 <= net_message.data[0] && net_message.data[0] <= 63))
return false; //lead byte must be between 20 and 63 to be valid dtls.
for (peer = col->dtls; peer; peer = peer->next) for (peer = col->dtls; peer; peer = peer->next)
{ {
if (NET_CompareAdr(&peer->addr, from)) if (NET_CompareAdr(&peer->addr, from))
@ -5385,7 +5387,7 @@ static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_s
if (o->clienttype == TCPC_WEBRTC_HOST && !strcmp(o->webrtc.resource, st->webrtc.resource)) if (o->clienttype == TCPC_WEBRTC_HOST && !strcmp(o->webrtc.resource, st->webrtc.resource))
{ {
qbyte msg[3]; qbyte msg[3];
msg[0] = ICEMSG_PEERDROP; msg[0] = ICEMSG_PEERLOST;
msg[1] = (st->webrtc.clientnum>>0)&0xff; msg[1] = (st->webrtc.clientnum>>0)&0xff;
msg[2] = (st->webrtc.clientnum>>8)&0xff; msg[2] = (st->webrtc.clientnum>>8)&0xff;
@ -5402,7 +5404,7 @@ static qboolean FTENET_TCP_KillStream(ftenet_tcp_connection_t *con, ftenet_tcp_s
if (o->clienttype == TCPC_WEBRTC_CLIENT && !strcmp(o->webrtc.resource, st->webrtc.resource)) if (o->clienttype == TCPC_WEBRTC_CLIENT && !strcmp(o->webrtc.resource, st->webrtc.resource))
{ {
qbyte msg[3]; qbyte msg[3];
msg[0] = ICEMSG_PEERDROP; msg[0] = ICEMSG_PEERLOST;
msg[1] = (st->webrtc.clientnum>>0)&0xff; msg[1] = (st->webrtc.clientnum>>0)&0xff;
msg[2] = (st->webrtc.clientnum>>8)&0xff; msg[2] = (st->webrtc.clientnum>>8)&0xff;
@ -7356,11 +7358,11 @@ static qboolean FTENET_WebRTC_GetPacket(ftenet_generic_connection_t *gcon)
switch(cmd) switch(cmd)
{ {
case ICEMSG_PEERDROP: //connection closing... case ICEMSG_PEERLOST: //connection closing...
if (cl == -1) if (cl == -1)
{ {
wsc->failed = true; wsc->failed = true;
Con_Printf("Broker closing connection: %s\n", MSG_ReadString()); // Con_Printf("Broker closing connection: %s\n", MSG_ReadString());
} }
else if (cl >= 0 && cl < wsc->numclients) else if (cl >= 0 && cl < wsc->numclients)
{ {
@ -7368,7 +7370,7 @@ static qboolean FTENET_WebRTC_GetPacket(ftenet_generic_connection_t *gcon)
if (wsc->clients[cl].datasock != INVALID_SOCKET) if (wsc->clients[cl].datasock != INVALID_SOCKET)
emscriptenfte_ws_close(wsc->clients[cl].datasock); emscriptenfte_ws_close(wsc->clients[cl].datasock);
wsc->clients[cl].datasock = INVALID_SOCKET; wsc->clients[cl].datasock = INVALID_SOCKET;
Con_Printf("Broker closing connection: %s\n", MSG_ReadString()); // Con_Printf("Broker closing connection: %s\n", MSG_ReadString());
} }
break; break;
case ICEMSG_GREETING: //reports the trailing url we're 'listening' on. anyone else using that url will connect to us. case ICEMSG_GREETING: //reports the trailing url we're 'listening' on. anyone else using that url will connect to us.

View file

@ -274,6 +274,7 @@ enum icestate_e
{ {
ICE_INACTIVE, //idle. ICE_INACTIVE, //idle.
ICE_FAILED, ICE_FAILED,
ICE_GATHERING,
ICE_CONNECTING, //exchanging pings. ICE_CONNECTING, //exchanging pings.
ICE_CONNECTED //media is flowing, supposedly. sending keepalives. ICE_CONNECTED //media is flowing, supposedly. sending keepalives.
}; };
@ -281,15 +282,15 @@ struct icestate_s;
#define ICE_API_CURRENT "Internet Connectivity Establishment 0.0" #define ICE_API_CURRENT "Internet Connectivity Establishment 0.0"
typedef struct typedef struct
{ {
struct icestate_s *(QDECL *ICE_Create)(void *module, const char *conname, const char *peername, enum icemode_e mode, enum iceproto_e proto, qboolean initiator); //doesn't start pinging anything. struct icestate_s *(QDECL *Create)(void *module, const char *conname, const char *peername, enum icemode_e mode, enum iceproto_e proto, qboolean initiator); //doesn't start pinging anything.
qboolean (QDECL *ICE_Set)(struct icestate_s *con, const char *prop, const char *value); qboolean (QDECL *Set)(struct icestate_s *con, const char *prop, const char *value);
qboolean (QDECL *ICE_Get)(struct icestate_s *con, const char *prop, char *value, size_t valuesize); qboolean (QDECL *Get)(struct icestate_s *con, const char *prop, char *value, size_t valuesize);
struct icecandinfo_s *(QDECL *ICE_GetLCandidateInfo)(struct icestate_s *con); //retrieves candidates that need reporting to the peer. struct icecandinfo_s *(QDECL *GetLCandidateInfo)(struct icestate_s *con); //retrieves candidates that need reporting to the peer.
void (QDECL *ICE_AddRCandidateInfo)(struct icestate_s *con, struct icecandinfo_s *cand); //stuff that came from the peer. void (QDECL *AddRCandidateInfo)(struct icestate_s *con, struct icecandinfo_s *cand); //stuff that came from the peer.
void (QDECL *ICE_Close)(struct icestate_s *con); //bye then. void (QDECL *Close)(struct icestate_s *con, qboolean force); //bye then.
void (QDECL *ICE_CloseModule)(void *module); //closes all unclosed connections, with warning. void (QDECL *CloseModule)(void *module); //closes all unclosed connections, with warning.
// struct icestate_s *(QDECL *ICE_Find)(void *module, const char *conname); // struct icestate_s *(QDECL *Find)(void *module, const char *conname);
qboolean (QDECL *ICE_GetLCandidateSDP)(struct icestate_s *con, char *out, size_t valuesize); //retrieves candidates that need reporting to the peer. qboolean (QDECL *GetLCandidateSDP)(struct icestate_s *con, char *out, size_t valuesize); //retrieves candidates that need reporting to the peer.
} icefuncs_t; } icefuncs_t;
extern icefuncs_t iceapi; extern icefuncs_t iceapi;
#endif #endif
@ -439,7 +440,7 @@ void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrn
ftenet_generic_connection_t *FTENET_ICE_EstablishConnection(ftenet_connections_t *col, const char *address, netadr_t adr); ftenet_generic_connection_t *FTENET_ICE_EstablishConnection(ftenet_connections_t *col, const char *address, netadr_t adr);
enum icemsgtype_s enum icemsgtype_s
{ //shared by rtcpeers+broker { //shared by rtcpeers+broker
ICEMSG_PEERDROP=0, //other side dropped connection ICEMSG_PEERLOST=0, //other side dropped connection
ICEMSG_GREETING=1, //master telling us our unique game name ICEMSG_GREETING=1, //master telling us our unique game name
ICEMSG_NEWPEER=2, //relay established, send an offer now. ICEMSG_NEWPEER=2, //relay established, send an offer now.
ICEMSG_OFFER=3, //peer's initial details ICEMSG_OFFER=3, //peer's initial details

View file

@ -1564,10 +1564,10 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
break; break;
} }
//MORE HUGE HACKS! WHEN WILL THEY CEASE! //MORE HUGE HACKS! WHEN WILL THEY CEASE!
// clamp lighting so it doesn't overbright as much // clamp lighting so it doesn't overbright as much
// ZOID: never allow players to go totally black // ZOID: never allow players to go totally black
if (e->playerindex >= 0) if (e->playerindex >= 0 && !(e->flags & (RF_WEAPONMODEL|RF_WEAPONMODELNOBOB|RF_DEPTHHACK)))
{ {
float fb = r_fullbrightSkins.value; float fb = r_fullbrightSkins.value;
if (fb > cls.allow_fbskins) if (fb > cls.allow_fbskins)

View file

@ -10845,6 +10845,12 @@ static void QCBUILTIN PF_CheckPlayerEXFlags_qex(pubprogfuncs_t *prinst, struct g
G_FLOAT(OFS_RETURN) = flags; G_FLOAT(OFS_RETURN) = flags;
} }
static void QCBUILTIN PF_walkpathtogoal_qex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ //this builtin is supposed to provide more advanced routing.
//the possible return values include an 'inprogress' which is kinda vague and implies persistent state.
//we can get away with returning false as a failure here, equivelent to if the map has no waypoints defined. the gamecode is expected to then fall back on the really lame movetogoal builtin.
G_FLOAT(OFS_RETURN) = false;
}
static void QCBUILTIN PF_centerprint_qex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_centerprint_qex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ //TODO: send the strings to the client for localisation+reordering { //TODO: send the strings to the client for localisation+reordering
const char *arg[8]; const char *arg[8];
@ -11208,7 +11214,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"ex_bot_movetopoint",PF_Fixme, 0, 0, 0,0, D("float(entity bot, vector point)", "Behaviour is undocumented.")}, {"ex_bot_movetopoint",PF_Fixme, 0, 0, 0,0, D("float(entity bot, vector point)", "Behaviour is undocumented.")},
{"ex_bot_followentity",PF_Fixme, 0, 0, 0,0, D("float(entity bot, entity goal)", "Behaviour is undocumented.")}, {"ex_bot_followentity",PF_Fixme, 0, 0, 0,0, D("float(entity bot, entity goal)", "Behaviour is undocumented.")},
{"ex_CheckPlayerEXFlags",PF_CheckPlayerEXFlags_qex,0,0, 0,0, D("float(entity playerEnt)", "Behaviour is undocumented.")}, {"ex_CheckPlayerEXFlags",PF_CheckPlayerEXFlags_qex,0,0, 0,0, D("float(entity playerEnt)", "Behaviour is undocumented.")},
{"ex_walkpathtogoal",PF_Fixme, 0, 0, 0,0, D("float(float movedist, vector goal)", "Behaviour is undocumented.")}, {"ex_walkpathtogoal",PF_walkpathtogoal_qex,0, 0, 0,0, D("float(float movedist, vector goal)", "Behaviour is undocumented.")},
//End QuakeEx, for now. :( //End QuakeEx, for now. :(
// Tomaz - QuakeC String Manipulation Begin // Tomaz - QuakeC String Manipulation Begin

View file

@ -2211,8 +2211,8 @@ static void SV_Status_f (void)
Con_Printf(" Qizmo"); Con_Printf(" Qizmo");
if (net_enable_qtv.ival) if (net_enable_qtv.ival)
Con_Printf(" QTV"); Con_Printf(" QTV");
#endif
Con_Printf("\n"); Con_Printf("\n");
#endif
break; break;
} }
#ifdef SUBSERVERS #ifdef SUBSERVERS
@ -2354,7 +2354,7 @@ static void SV_Status_f (void)
columns |= 1<<5; columns |= 1<<5;
if (cl->protocol != SCP_BAD && (cl->protocol >= SCP_NETQUAKE || cl->spectator || (cl->protocol == SCP_QUAKEWORLD && !(cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)))) if (cl->protocol != SCP_BAD && (cl->protocol >= SCP_NETQUAKE || cl->spectator || (cl->protocol == SCP_QUAKEWORLD && !(cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))))
columns |= 1<<9; columns |= 1<<9;
if (cl->netchan.remote_address.type == NA_IPV6||cl->reversedns) if ((cl->netchan.remote_address.type == NA_IPV6 && memcmp(cl->netchan.remote_address.address.ip6, "\0\0\0\0""\0\0\0\0""\0\0\xff\xff", 12))||cl->reversedns)
columns |= (1<<10); columns |= (1<<10);
} }
if (columns&(1<<10)) //if address2, remove the limited length addresses. if (columns&(1<<10)) //if address2, remove the limited length addresses.

View file

@ -3517,7 +3517,7 @@ void SVC_DirectConnect(int expectedreliablesequence)
} }
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (net_enable_dtls.ival > 2 && (net_from.prot == NP_DGRAM || net_from.prot == NP_STREAM || net_from.prot == NP_WS) && net_from.type != NA_LOOPBACK) if (net_enable_dtls.ival > 2 && (net_from.prot == NP_DGRAM || net_from.prot == NP_STREAM || net_from.prot == NP_WS) && net_from.type != NA_LOOPBACK && !NET_IsEncrypted(&net_from))
{ {
SV_RejectMessage (info.protocol, "This server requires the use of DTLS/TLS/WSS.\n"); SV_RejectMessage (info.protocol, "This server requires the use of DTLS/TLS/WSS.\n");
return; return;
@ -4432,7 +4432,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, "Incorrect game\n"); MSG_WriteString(&sb, "Incorrect game\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our game. return true; //not our game.
} }
if (protver != NQ_NETCHAN_VERSION && protver != NQ_NETCHAN_VERSION_QEX) if (protver != NQ_NETCHAN_VERSION && protver != NQ_NETCHAN_VERSION_QEX)
{ {
@ -4442,7 +4442,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, "Incorrect version\n"); MSG_WriteString(&sb, "Incorrect version\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return true; //not our version...
} }
banreason = SV_BannedReason (&net_from); banreason = SV_BannedReason (&net_from);
@ -4454,7 +4454,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, *banreason?va("You are banned: %s\n", banreason):"You are banned\n"); MSG_WriteString(&sb, *banreason?va("You are banned: %s\n", banreason):"You are banned\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return true; //not our version...
} }
//proquake's extensions //proquake's extensions
@ -4462,6 +4462,8 @@ qboolean SVNQ_ConnectionlessPacket(void)
modver = MSG_ReadByte(); modver = MSG_ReadByte();
flags = MSG_ReadByte(); flags = MSG_ReadByte();
passwd = MSG_ReadLong(); passwd = MSG_ReadLong();
if (msg_badread)
passwd = 0;
if (SV_ChallengeRecent()) if (SV_ChallengeRecent())
return true; return true;
@ -4482,10 +4484,21 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, "NQ clients are not supported with hexen2 gamecode\n"); MSG_WriteString(&sb, "NQ clients are not supported with hexen2 gamecode\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return true; //not our version...
} }
if (sv_listen_nq.ival == 2 && net_from.prot == NP_DGRAM) if (NET_WasSpecialPacket(svs.sockets))
return true;
if (sv_listen_nq.ival == 2 && net_from.prot == NP_DGRAM && net_from.type != NA_ICE)
{ {
if (password.string[0] &&
stricmp(password.string, "none") &&
strcmp(password.string, va("%i", passwd)) )
{ //make sure we don't get crippled because of being unable to specify the actual password with proquake's stuff.
Con_TPrintf ("%s:password failed (nq)\n", NET_AdrToString (buffer2, sizeof(buffer2), &net_from));
SV_RejectMessage (SCP_NETQUAKE, "server requires a password\n\n");
return true;
}
SZ_Clear(&sb); SZ_Clear(&sb);
MSG_WriteLong(&sb, 0); MSG_WriteLong(&sb, 0);
MSG_WriteByte(&sb, CCREP_ACCEPT); MSG_WriteByte(&sb, CCREP_ACCEPT);
@ -4714,6 +4727,8 @@ void SV_ReadPacket(void)
return; return;
} }
if (NET_WasSpecialPacket(svs.sockets)) //fixes up IP->ICE addresses (so we don't break when routes change).
return;
SV_ConnectionlessPacket(); SV_ConnectionlessPacket();
return; return;
} }

View file

@ -1312,37 +1312,37 @@ static struct ircice_s *IRC_ICE_Create(ircclient_t *irc, const char *sender, enu
return NULL; return NULL;
if (!creator && type == ICEP_QWSERVER) if (!creator && type == ICEP_QWSERVER)
ice = piceapi->ICE_Create(NULL, NULL, sender, ICEM_ICE, ICEP_QWCLIENT, creator); ice = piceapi->Create(NULL, NULL, sender, ICEM_ICE, ICEP_QWCLIENT, creator);
else if (!creator && type == ICEP_QWCLIENT) else if (!creator && type == ICEP_QWCLIENT)
ice = piceapi->ICE_Create(NULL, NULL, sender, ICEM_ICE, ICEP_QWSERVER, creator); ice = piceapi->Create(NULL, NULL, sender, ICEM_ICE, ICEP_QWSERVER, creator);
else else
ice = piceapi->ICE_Create(NULL, NULL, sender, ICEM_ICE, type, creator); ice = piceapi->Create(NULL, NULL, sender, ICEM_ICE, type, creator);
if (!ice) if (!ice)
return NULL; return NULL;
piceapi->ICE_Set(ice, "controller", creator?"1":"0"); piceapi->Set(ice, "controller", creator?"1":"0");
if (creator && type == ICEP_VOICE) if (creator && type == ICEP_VOICE)
{ {
//note: the engine will ignore codecs it does not support. //note: the engine will ignore codecs it does not support.
piceapi->ICE_Set(ice, "codec96", "opus@48000"); piceapi->Set(ice, "codec96", "opus@48000");
piceapi->ICE_Set(ice, "codec97", "speex@16000"); //wide piceapi->Set(ice, "codec97", "speex@16000"); //wide
piceapi->ICE_Set(ice, "codec98", "speex@8000"); //narrow piceapi->Set(ice, "codec98", "speex@8000"); //narrow
piceapi->ICE_Set(ice, "codec99", "speex@32000"); //ultrawide piceapi->Set(ice, "codec99", "speex@32000"); //ultrawide
piceapi->ICE_Set(ice, "codec8", "pcma@8000"); piceapi->Set(ice, "codec8", "pcma@8000");
piceapi->ICE_Set(ice, "codec0", "pcmu@8000"); piceapi->Set(ice, "codec0", "pcmu@8000");
} }
//query dns to see if there's a stunserver hosted by the same domain //query dns to see if there's a stunserver hosted by the same domain
//nslookup -querytype=SRV _stun._udp.example.com //nslookup -querytype=SRV _stun._udp.example.com
// Q_snprintf(stunhost, sizeof(stunhost), "_stun._udp.%s", ice->server); // Q_snprintf(stunhost, sizeof(stunhost), "_stun._udp.%s", ice->server);
// if (NET_DNSLookup_SRV(stunhost, stunhost, sizeof(stunhost))) // if (NET_DNSLookup_SRV(stunhost, stunhost, sizeof(stunhost)))
// piceapi->ICE_Set(ice, "stunip", stunhost); // piceapi->Set(ice, "stunip", stunhost);
// else // else
{ {
//irc services tend to not provide any stun info, so steal someone's... hopefully they won't mind too much. :( //irc services tend to not provide any stun info, so steal someone's... hopefully they won't mind too much. :(
piceapi->ICE_Set(ice, "stunport", "19302"); piceapi->Set(ice, "stunport", "19302");
piceapi->ICE_Set(ice, "stunip", "stun.l.google.com"); piceapi->Set(ice, "stunip", "stun.l.google.com");
} }
ircice = malloc(sizeof(*ircice)); ircice = malloc(sizeof(*ircice));
@ -1395,8 +1395,8 @@ static void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatety
char ufrag[256]; char ufrag[256];
char pwd[256]; char pwd[256];
piceapi->ICE_Get(ice->ice, "lufrag", ufrag, sizeof(ufrag)); piceapi->Get(ice->ice, "lufrag", ufrag, sizeof(ufrag));
piceapi->ICE_Get(ice->ice, "lpwd", pwd, sizeof(pwd)); piceapi->Get(ice->ice, "lpwd", pwd, sizeof(pwd));
Q_snprintf(message, sizeof(message), " ufrag/%s pwd/%s", ufrag, pwd); Q_snprintf(message, sizeof(message), " ufrag/%s pwd/%s", ufrag, pwd);
} }
@ -1410,7 +1410,7 @@ static void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatety
char codecname[64]; char codecname[64];
char argn[64]; char argn[64];
Q_snprintf(argn, sizeof(argn), "codec%i", i); Q_snprintf(argn, sizeof(argn), "codec%i", i);
if (!piceapi->ICE_Get(ice->ice, argn, codecname, sizeof(codecname))) if (!piceapi->Get(ice->ice, argn, codecname, sizeof(codecname)))
continue; continue;
if (!strcmp(codecname, "speex@8000")) //speex narrowband if (!strcmp(codecname, "speex@8000")) //speex narrowband
@ -1448,7 +1448,7 @@ static void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatety
*/ */
if (updatetype != '+' && updatetype != '-') if (updatetype != '+' && updatetype != '-')
{ {
while ((c = piceapi->ICE_GetLCandidateInfo(ice->ice))) while ((c = piceapi->GetLCandidateInfo(ice->ice)))
{ {
char type[] = "hspr"; char type[] = "hspr";
char cand[256]; char cand[256];
@ -1503,7 +1503,7 @@ static void IRC_ICE_ParseCandidate(struct icestate_s *ice, char *cand)
Q_strlcpy(info.candidateid, cand+1, sizeof(info.candidateid)); Q_strlcpy(info.candidateid, cand+1, sizeof(info.candidateid));
Q_strlcpy(info.addr, addr, sizeof(info.candidateid)); Q_strlcpy(info.addr, addr, sizeof(info.candidateid));
piceapi->ICE_AddRCandidateInfo(ice, &info); piceapi->AddRCandidateInfo(ice, &info);
} }
static void IRC_ICE_ParseCodec(struct icestate_s *ice, char *codec) static void IRC_ICE_ParseCodec(struct icestate_s *ice, char *codec)
@ -1518,7 +1518,7 @@ static void IRC_ICE_ParseCodec(struct icestate_s *ice, char *codec)
Q_strlcat(name, va("@%u", rate), sizeof(name)); Q_strlcat(name, va("@%u", rate), sizeof(name));
piceapi->ICE_Set(ice, va("codec%i", num), name); piceapi->Set(ice, va("codec%i", num), name);
} }
static void IRC_ICE_Parse(ircclient_t *irc, const char *sender, char *message) static void IRC_ICE_Parse(ircclient_t *irc, const char *sender, char *message)
@ -1559,16 +1559,16 @@ static void IRC_ICE_Parse(ircclient_t *irc, const char *sender, char *message)
else if (!strncmp(token, "codec/", 6)) else if (!strncmp(token, "codec/", 6))
IRC_ICE_ParseCodec(ice->ice, token); IRC_ICE_ParseCodec(ice->ice, token);
else if (!strncmp(token, "ufrag/", 6)) else if (!strncmp(token, "ufrag/", 6))
piceapi->ICE_Set(ice->ice, "rufrag", token+6); piceapi->Set(ice->ice, "rufrag", token+6);
else if (!strncmp(token, "pwd/", 4)) else if (!strncmp(token, "pwd/", 4))
piceapi->ICE_Set(ice->ice, "rpwd", token+4); piceapi->Set(ice->ice, "rpwd", token+4);
else if (*token) else if (*token)
IRC_Printf(irc, sender, "unknown ice token %s\n", token); IRC_Printf(irc, sender, "unknown ice token %s\n", token);
} }
if ((icetype == '=' || icetype == '*') && !ice->accepted && ice->allowed) if ((icetype == '=' || icetype == '*') && !ice->accepted && ice->allowed)
{ {
piceapi->ICE_Set(ice->ice, "state", STRINGIFY(ICE_CONNECTING)); piceapi->Set(ice->ice, "state", STRINGIFY(ICE_CONNECTING));
ice->accepted = true; ice->accepted = true;
} }
@ -1642,7 +1642,7 @@ static void IRC_ICE_Frame(ircclient_t *irc)
if (!ice->accepted || !ice->allowed) if (!ice->accepted || !ice->allowed)
continue; continue;
//ice needs some maintainence. if things change then we need to be prepared to send updated candidate info //ice needs some maintainence. if things change then we need to be prepared to send updated candidate info
piceapi->ICE_Get(ice->ice, "newlc", bah, sizeof(bah)); piceapi->Get(ice->ice, "newlc", bah, sizeof(bah));
if (atoi(bah)) if (atoi(bah))
{ {
IRC_Printf(irc, ice->peer, "Sending updated peer info\n"); IRC_Printf(irc, ice->peer, "Sending updated peer info\n");
@ -1687,7 +1687,7 @@ static void IRC_ICE_Authorise(ircclient_t *irc, const char *with, enum iceproto_
IRC_ICE_Update(irc, ice, '-'); IRC_ICE_Update(irc, ice, '-');
*link = ice->next; *link = ice->next;
if (ice->ice) if (ice->ice)
piceapi->ICE_Close(ice->ice); piceapi->Close(ice->ice, true);
IRC_Free(ice); IRC_Free(ice);
IRC_Printf(irc, announce, "Connection terminated\n"); IRC_Printf(irc, announce, "Connection terminated\n");

View file

@ -22,24 +22,24 @@ static struct c2c_s *JCL_JingleAddContentToSession(jclient_t *jcl, struct c2c_s
} }
if (piceapi) if (piceapi)
ice = piceapi->ICE_Create(NULL, sid, with, method, mediatype, creator); ice = piceapi->Create(NULL, sid, with, method, mediatype, creator);
if (ice) if (ice)
{ {
piceapi->ICE_Get(ice, "sid", generatedname, sizeof(generatedname)); piceapi->Get(ice, "sid", generatedname, sizeof(generatedname));
sid = generatedname; sid = generatedname;
//the controlling role MUST be assumed by the initiator and the controlled role MUST be assumed by the responder //the controlling role MUST be assumed by the initiator and the controlled role MUST be assumed by the responder
piceapi->ICE_Set(ice, "controller", creator?"1":"0"); piceapi->Set(ice, "controller", creator?"1":"0");
if (creator && mediatype == ICEP_VOICE) if (creator && mediatype == ICEP_VOICE)
{ {
//note: the engine will ignore codecs it does not support. //note: the engine will ignore codecs it does not support.
piceapi->ICE_Set(ice, "codec96", "opus@48000"); piceapi->Set(ice, "codec96", "opus@48000");
piceapi->ICE_Set(ice, "codec97", "speex@16000"); //wide piceapi->Set(ice, "codec97", "speex@16000"); //wide
piceapi->ICE_Set(ice, "codec98", "speex@8000"); //narrow piceapi->Set(ice, "codec98", "speex@8000"); //narrow
piceapi->ICE_Set(ice, "codec99", "speex@32000"); //ultrawide piceapi->Set(ice, "codec99", "speex@32000"); //ultrawide
piceapi->ICE_Set(ice, "codec0", "pcmu@8000"); piceapi->Set(ice, "codec0", "pcmu@8000");
piceapi->ICE_Set(ice, "codec8", "pcma@8000"); piceapi->Set(ice, "codec8", "pcma@8000");
} }
} }
else else
@ -73,7 +73,7 @@ static struct c2c_s *JCL_JingleAddContentToSession(jclient_t *jcl, struct c2c_s
//google doesn't provide a stun srv entry //google doesn't provide a stun srv entry
//facebook doesn't provide a stun srv entry //facebook doesn't provide a stun srv entry
if (!Q_snprintfz(stunhost, sizeof(stunhost), "_stun._udp.%s", jcl->domain) && NET_DNSLookup_SRV(stunhost, stunhost, sizeof(stunhost))) if (!Q_snprintfz(stunhost, sizeof(stunhost), "_stun._udp.%s", jcl->domain) && NET_DNSLookup_SRV(stunhost, stunhost, sizeof(stunhost)))
piceapi->ICE_Set(ice, "stunip", stunhost); piceapi->Set(ice, "stunip", stunhost);
else else
{ {
//there is no real way to query stun servers from the xmpp server. //there is no real way to query stun servers from the xmpp server.
@ -83,8 +83,8 @@ static struct c2c_s *JCL_JingleAddContentToSession(jclient_t *jcl, struct c2c_s
//so we're basically screwed if we want to work with the googletalk xmpp service long term. //so we're basically screwed if we want to work with the googletalk xmpp service long term.
//more methods are best, I suppose, but I'm lazy. //more methods are best, I suppose, but I'm lazy.
//yes, hardcoding means that other services might 'borrow' googles' stun servers. //yes, hardcoding means that other services might 'borrow' googles' stun servers.
piceapi->ICE_Set(ice, "stunport", "19302"); piceapi->Set(ice, "stunport", "19302");
piceapi->ICE_Set(ice, "stunip", "stun.l.google.com"); piceapi->Set(ice, "stunip", "stun.l.google.com");
} }
return c2c; return c2c;
} }
@ -101,7 +101,7 @@ static qboolean JCL_JingleAcceptAck(jclient_t *jcl, xmltree_t *tree, struct iq_s
for (i = 0; i < c2c->contents; i++) for (i = 0; i < c2c->contents; i++)
{ {
if (c2c->content[i].ice) if (c2c->content[i].ice)
piceapi->ICE_Set(c2c->content[i].ice, "state", STRINGIFY(ICE_CONNECTING)); piceapi->Set(c2c->content[i].ice, "state", STRINGIFY(ICE_CONNECTING));
} }
} }
} }
@ -120,7 +120,7 @@ static void JCL_PopulateAudioDescription(xmltree_t *description, struct icestate
char codecname[64]; char codecname[64];
char argn[64]; char argn[64];
Q_snprintf(argn, sizeof(argn), "codec%i", i); Q_snprintf(argn, sizeof(argn), "codec%i", i);
if (piceapi->ICE_Get(ice, argn, codecname, sizeof(codecname))) if (piceapi->Get(ice, argn, codecname, sizeof(codecname)))
{ {
if (!strcasecmp(codecname, "speex@8000") || !strcasecmp(codecname, "speex@16000") || !strcasecmp(codecname, "speex@32000")) if (!strcasecmp(codecname, "speex@8000") || !strcasecmp(codecname, "speex@16000") || !strcasecmp(codecname, "speex@32000"))
{ //speex narrowband { //speex narrowband
@ -373,7 +373,7 @@ static qboolean JCL_JingleSend(jclient_t *jcl, struct c2c_s *c2c, char *action)
for (c = 0; c < c2c->contents; c++) for (c = 0; c < c2c->contents; c++)
{ {
if (c2c->content[c].ice) if (c2c->content[c].ice)
piceapi->ICE_Close(c2c->content[c].ice); piceapi->Close(c2c->content[c].ice, true);
c2c->content[c].ice = NULL; c2c->content[c].ice = NULL;
} }
@ -406,7 +406,7 @@ static qboolean JCL_JingleSend(jclient_t *jcl, struct c2c_s *c2c, char *action)
xmltree_t *candidate; xmltree_t *candidate;
struct icecandinfo_s *b = NULL; struct icecandinfo_s *b = NULL;
struct icecandinfo_s *c; struct icecandinfo_s *c;
while ((c = piceapi->ICE_GetLCandidateInfo(ice))) while ((c = piceapi->GetLCandidateInfo(ice)))
{ {
if (!b || b->priority < c->priority) if (!b || b->priority < c->priority)
b = c; b = c;
@ -426,13 +426,13 @@ static qboolean JCL_JingleSend(jclient_t *jcl, struct c2c_s *c2c, char *action)
{ {
char val[64]; char val[64];
transport = XML_CreateNode(content, "transport", "urn:xmpp:jingle:transports:ice-udp:1", ""); transport = XML_CreateNode(content, "transport", "urn:xmpp:jingle:transports:ice-udp:1", "");
piceapi->ICE_Get(ice, "lufrag", val, sizeof(val)); piceapi->Get(ice, "lufrag", val, sizeof(val));
XML_AddParameter(transport, "ufrag", val); XML_AddParameter(transport, "ufrag", val);
piceapi->ICE_Get(ice, "lpwd", val, sizeof(val)); piceapi->Get(ice, "lpwd", val, sizeof(val));
XML_AddParameter(transport, "pwd", val); XML_AddParameter(transport, "pwd", val);
{ {
struct icecandinfo_s *c; struct icecandinfo_s *c;
while ((c = piceapi->ICE_GetLCandidateInfo(ice))) while ((c = piceapi->GetLCandidateInfo(ice)))
{ {
char *ctypename[]={"host", "srflx", "prflx", "relay"}; char *ctypename[]={"host", "srflx", "prflx", "relay"};
xmltree_t *candidate = XML_CreateNode(transport, "candidate", "", ""); xmltree_t *candidate = XML_CreateNode(transport, "candidate", "", "");
@ -509,7 +509,7 @@ void JCL_JingleTimeouts(jclient_t *jcl, qboolean killall)
if (c2c->content[c].method == ICEM_ICE) if (c2c->content[c].method == ICEM_ICE)
{ {
char bah[2]; char bah[2];
piceapi->ICE_Get(c2c->content[c].ice, "newlc", bah, sizeof(bah)); piceapi->Get(c2c->content[c].ice, "newlc", bah, sizeof(bah));
if (atoi(bah)) if (atoi(bah))
{ {
Con_DPrintf("Sending updated local addresses\n"); Con_DPrintf("Sending updated local addresses\n");
@ -659,8 +659,8 @@ static void JCL_JingleParsePeerPorts(jclient_t *jcl, struct c2c_s *c2c, xmltree_
if (!intransport) if (!intransport)
continue; //err, I guess it wasn't a transport update then (or related). continue; //err, I guess it wasn't a transport update then (or related).
piceapi->ICE_Set(ice, "rufrag", XML_GetParameter(intransport, "ufrag", "")); piceapi->Set(ice, "rufrag", XML_GetParameter(intransport, "ufrag", ""));
piceapi->ICE_Set(ice, "rpwd", XML_GetParameter(intransport, "pwd", "")); piceapi->Set(ice, "rpwd", XML_GetParameter(intransport, "pwd", ""));
for (i = 0; (incandidate = XML_ChildOfTree(intransport, "candidate", i)); i++) for (i = 0; (incandidate = XML_ChildOfTree(intransport, "candidate", i)); i++)
{ {
@ -689,7 +689,7 @@ static void JCL_JingleParsePeerPorts(jclient_t *jcl, struct c2c_s *c2c, xmltree_
rem.transport = 0; rem.transport = 0;
else else
rem.transport = 0; rem.transport = 0;
piceapi->ICE_AddRCandidateInfo(ice, &rem); piceapi->AddRCandidateInfo(ice, &rem);
} }
} }
} }
@ -946,12 +946,12 @@ static struct c2c_s *JCL_JingleHandleInitiate(jclient_t *jcl, xmltree_t *inj, co
{ {
Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id));
Q_snprintf(val, sizeof(val), "%s@%i", name, atoi(clock)); Q_snprintf(val, sizeof(val), "%s@%i", name, atoi(clock));
okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, val); okay |= piceapi->Set(c2c->content[c].ice, parm, val);
} }
else if (!strcasecmp(name, "opus")) else if (!strcasecmp(name, "opus"))
{ {
Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id));
okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, "opus@48000"); okay |= piceapi->Set(c2c->content[c].ice, parm, "opus@48000");
} }
} }
} }
@ -966,7 +966,7 @@ static struct c2c_s *JCL_JingleHandleInitiate(jclient_t *jcl, xmltree_t *inj, co
XMPP_ConversationPrintf(b->accountdomain, b->name, false, "%s does not support any compatible codecs, and is unable to call you.\n", convolink); XMPP_ConversationPrintf(b->accountdomain, b->name, false, "%s does not support any compatible codecs, and is unable to call you.\n", convolink);
if (c2c->content[c].ice) if (c2c->content[c].ice)
piceapi->ICE_Close(c2c->content[c].ice); piceapi->Close(c2c->content[c].ice, true);
c2c->content[c].ice = NULL; c2c->content[c].ice = NULL;
c2c->contents--; c2c->contents--;
} }
@ -1022,7 +1022,7 @@ static qboolean JCL_JingleHandleSessionTerminate(jclient_t *jcl, xmltree_t *tree
for (c = 0; c < c2c->contents; c++) for (c = 0; c < c2c->contents; c++)
if (c2c->content[c].ice) if (c2c->content[c].ice)
piceapi->ICE_Close(c2c->content[c].ice); piceapi->Close(c2c->content[c].ice, true);
free(c2c); free(c2c);
return true; return true;
} }
@ -1066,7 +1066,7 @@ static qboolean JCL_JingleHandleSessionAccept(jclient_t *jcl, xmltree_t *tree, c
//if we didn't error out, the ICE stuff is meant to start sending handshakes/media as soon as the connection is accepted //if we didn't error out, the ICE stuff is meant to start sending handshakes/media as soon as the connection is accepted
for (c = 0; c < c2c->contents; c++) for (c = 0; c < c2c->contents; c++)
if (c2c->content[c].ice) if (c2c->content[c].ice)
piceapi->ICE_Set(c2c->content[c].ice, "state", STRINGIFY(ICE_CONNECTING)); piceapi->Set(c2c->content[c].ice, "state", STRINGIFY(ICE_CONNECTING));
} }
return true; return true;
} }

View file

@ -930,7 +930,7 @@ static neterr_t OSSL_Transmit(void *ctx, const qbyte *data, size_t datasize)
} }
} }
if (BIO_should_retry(o->bio)) if (BIO_should_retry(o->bio))
return 0; return NETERR_CLOGGED;
return NETERR_DISCONNECTED; //eof or something return NETERR_DISCONNECTED; //eof or something
} }
return NETERR_SENT; return NETERR_SENT;