#include "quakedef.h"
#include "net_dgrm.h"
+#include "net_master.h"
cvar_t cl_port = {CVAR_SAVE, "cl_port", "0"};
{
char addrStr [32];
char maskStr [32];
- void (*print) (char *fmt, ...);
+ void (*print) (const char *fmt, ...);
if (cmd_source == src_command)
{
break;
case 2:
- if (Q_strcasecmp(Cmd_Argv(1), "off") == 0)
+ if (strcasecmp(Cmd_Argv(1), "off") == 0)
banAddr = 0x00000000;
else
banAddr = inet_addr(Cmd_Argv(1));
if (length == 0)
break;
- if (length == -1)
+ if ((int)length == -1)
{
Con_Printf("Read error\n");
return -1;
if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0)
{
-#ifdef DEBUG
Con_DPrintf("Forged packet received\n");
Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr));
Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
-#endif
continue;
}
else
{
for (s = net_activeSockets; s; s = s->next)
- if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0)
+ if (strcasecmp(Cmd_Argv(1), s->address) == 0)
break;
if (s == NULL)
return;
while (1)
{
len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);
- if (len < sizeof(int))
+ if (len < (int)sizeof(int))
break;
net_message.cursize = len;
MSG_ReadLong();
if (control == -1)
break;
- if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
+ if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
break;
if ((control & NETFLAG_LENGTH_MASK) != len)
break;
static void Test_f (void)
{
- char *host;
- int n;
- int max = MAX_SCOREBOARD;
+ const char *host;
+ int n, max = MAX_SCOREBOARD;
struct qsockaddr sendaddr;
if (testInProgress)
if (host && hostCacheCount)
{
for (n = 0; n < hostCacheCount; n++)
- if (Q_strcasecmp (host, hostcache[n].name) == 0)
+ if (strcasecmp (host, hostcache[n].name) == 0)
{
if (hostcache[n].driver != myDriverLevel)
continue;
name[0] = 0;
len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);
- if (len < sizeof(int))
+ if (len < (int)sizeof(int))
goto Reschedule;
net_message.cursize = len;
MSG_ReadLong();
if (control == -1)
goto Error;
- if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
+ if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
goto Error;
if ((control & NETFLAG_LENGTH_MASK) != len)
goto Error;
static void Test2_f (void)
{
- char *host;
- int n;
+ const char *host;
+ int n;
struct qsockaddr sendaddr;
if (test2InProgress)
if (host && hostCacheCount)
{
for (n = 0; n < hostCacheCount; n++)
- if (Q_strcasecmp (host, hostcache[n].name) == 0)
+ if (strcasecmp (host, hostcache[n].name) == 0)
{
if (hostcache[n].driver != myDriverLevel)
continue;
SZ_Clear(&net_message);
len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);
- if (len < sizeof(int))
+ if (len < (int)sizeof(int))
return NULL;
net_message.cursize = len;
MSG_BeginReading ();
control = BigLong(*((int *)net_message.data));
MSG_ReadLong();
- if (control == -1)
+
+ // Messages starting by 0xFFFFFFFF are master server messages
+ if ((unsigned int)control == 0xFFFFFFFF)
+ {
+ int responsesize = Master_HandleMessage();
+ if (responsesize > 0)
+ {
+ dfunc.Write(acceptsock, net_message.data, responsesize, &clientaddr);
+ SZ_Clear(&net_message);
+ }
return NULL;
- if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
+ }
+ if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
return NULL;
if ((control & NETFLAG_LENGTH_MASK) != len)
return NULL;
if (strcmp(MSG_ReadString(), "QUAKE") != 0)
return NULL;
+ Con_DPrintf("Datagram_CheckNewConnections: received CCREQ_SERVERINFO, replying.\n");
+
SZ_Clear(&net_message);
// save space for the header, filled in later
MSG_WriteLong(&net_message, 0);
MSG_WriteByte(&net_message, playerNumber);
MSG_WriteString(&net_message, client->name);
MSG_WriteLong(&net_message, client->colors);
- MSG_WriteLong(&net_message, (int)client->edict->v.frags);
+ MSG_WriteLong(&net_message, (int)client->edict->v->frags);
MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
MSG_WriteString(&net_message, client->netconnection->address);
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
// find the search start location
prevCvarName = MSG_ReadString();
- if (*prevCvarName)
- {
- var = Cvar_FindVar (prevCvarName);
- if (!var)
- return NULL;
- var = var->next;
- }
- else
- var = cvar_vars;
-
- // search for the next server cvar
- while (var)
- {
- if (var->flags & CVAR_NOTIFY)
- break;
- var = var->next;
- }
+ var = Cvar_FindVarAfter(prevCvarName, CVAR_NOTIFY);
// send the response
ret = dfunc.AddrCompare(&clientaddr, &s->addr);
if (ret >= 0)
{
- // is this a duplicate connection reqeust?
+ // is this a duplicate connection request?
if (ret == 0 && net_time - s->connecttime < 2.0)
{
// yes, so send a duplicate reply
dfunc.GetSocketAddr(s->socket, &newaddr);
MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+ // LordHavoc: send from s->socket instead of acceptsock, this
+ // way routers usually identify the connection correctly
+ // (thanks to faded for provoking me to recite a lengthy
+ // explanation of NAT nightmares, and realize this easy
+ // workaround for quake)
+ dfunc.Write (s->socket, net_message.data, net_message.cursize, &clientaddr);
+ // LordHavoc: also send from acceptsock, for good measure
dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
SZ_Clear(&net_message);
return NULL;
dfunc.GetSocketAddr(newsock, &newaddr);
MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
+ // LordHavoc: send from sock->socket instead of acceptsock, this way routers
+ // usually identify the connection correctly (thanks to faded for provoking
+ // me to recite a lengthy explanation of NAT nightmares, and realize this
+ // easy workaround for quake)
+ dfunc.Write (sock->socket, net_message.data, net_message.cursize, &clientaddr);
+ // LordHavoc: also send from acceptsock, for good measure
dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);
SZ_Clear(&net_message);
}
+static qboolean Datagram_HandleServerInfo (struct qsockaddr *readaddr)
+{
+ //struct qsockaddr myaddr;
+ int control;
+ int c, n, i;
+
+ if (net_message.cursize < (int)sizeof(int))
+ return false;
+
+ // don't answer our own query
+ //dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
+ //if (dfunc.AddrCompare(readaddr, &myaddr) >= 0)
+ // return false;
+
+ // is the cache full?
+ if (hostCacheCount == HOSTCACHESIZE)
+ return false;
+
+ MSG_BeginReading ();
+ control = BigLong(*((int *)net_message.data));
+ MSG_ReadLong();
+ if (control == -1)
+ return false;
+ if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
+ return false;
+ if ((control & NETFLAG_LENGTH_MASK) != net_message.cursize)
+ return false;
+
+ c = MSG_ReadByte();
+ if (c != CCREP_SERVER_INFO)
+ return false;
+
+ dfunc.GetAddrFromName(MSG_ReadString(), readaddr);
+ // search the cache for this server
+ for (n = 0; n < hostCacheCount; n++)
+ if (dfunc.AddrCompare(readaddr, &hostcache[n].addr) == 0)
+ break;
+
+ // is it already there?
+ if (n < hostCacheCount)
+ return false;;
+
+ // add it
+ hostCacheCount++;
+ strcpy(hostcache[n].name, MSG_ReadString());
+ strcpy(hostcache[n].map, MSG_ReadString());
+ hostcache[n].users = MSG_ReadByte();
+ hostcache[n].maxusers = MSG_ReadByte();
+ c = MSG_ReadByte();
+ if (c != NET_PROTOCOL_VERSION)
+ {
+ strcpy(hostcache[n].cname, hostcache[n].name);
+ hostcache[n].cname[14] = 0;
+ strcpy(hostcache[n].name, "*");
+ strcat(hostcache[n].name, hostcache[n].cname);
+ }
+ memcpy(&hostcache[n].addr, readaddr, sizeof(struct qsockaddr));
+ hostcache[n].driver = net_driverlevel;
+ hostcache[n].ldriver = net_landriverlevel;
+ strcpy(hostcache[n].cname, dfunc.AddrToString(readaddr));
+
+ // check for a name conflict
+ for (i = 0; i < hostCacheCount; i++)
+ {
+ if (i == n)
+ continue;
+ if (strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
+ {
+ i = strlen(hostcache[n].name);
+ if (i < 15 && hostcache[n].name[i-1] > '8')
+ {
+ hostcache[n].name[i] = '0';
+ hostcache[n].name[i+1] = 0;
+ }
+ else
+ hostcache[n].name[i-1]++;
+ i = -1;
+ }
+ }
+
+ return true;
+}
+
+
static void _Datagram_SearchForHosts (qboolean xmit)
{
int ret;
- int n;
- int i;
struct qsockaddr readaddr;
- struct qsockaddr myaddr;
- int control;
- int c;
- dfunc.GetSocketAddr (dfunc.controlSock, &myaddr);
if (xmit)
{
SZ_Clear(&net_message);
while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
{
- if (ret < sizeof(int))
- continue;
net_message.cursize = ret;
+ Datagram_HandleServerInfo (&readaddr);
+ }
+}
- // don't answer our own query
- if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)
- continue;
-
- // is the cache full?
+void Datagram_SearchForHosts (qboolean xmit)
+{
+ for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+ {
if (hostCacheCount == HOSTCACHESIZE)
- continue;
-
- MSG_BeginReading ();
- control = BigLong(*((int *)net_message.data));
- MSG_ReadLong();
- if (control == -1)
- continue;
- if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
- continue;
- if ((control & NETFLAG_LENGTH_MASK) != ret)
- continue;
-
- c = MSG_ReadByte();
- if (c != CCREP_SERVER_INFO)
- continue;
+ break;
+ if (net_landrivers[net_landriverlevel].initialized)
+ _Datagram_SearchForHosts (xmit);
+ }
+}
- dfunc.GetAddrFromName(MSG_ReadString(), &readaddr);
- // search the cache for this server
- for (n = 0; n < hostCacheCount; n++)
- if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)
- break;
- // is it already there?
- if (n < hostCacheCount)
- continue;
+static qboolean _Datagram_SearchForInetHosts (const char *master)
+{
+ qboolean result = false;
+ struct qsockaddr masteraddr;
+ struct qsockaddr readaddr;
+ int ret;
- // add it
- hostCacheCount++;
- strcpy(hostcache[n].name, MSG_ReadString());
- strcpy(hostcache[n].map, MSG_ReadString());
- hostcache[n].users = MSG_ReadByte();
- hostcache[n].maxusers = MSG_ReadByte();
- c = MSG_ReadByte();
- if (c != NET_PROTOCOL_VERSION)
+ if (master)
+ {
+ if (dfunc.GetAddrFromName(master, &masteraddr) != -1)
{
- strcpy(hostcache[n].cname, hostcache[n].name);
- hostcache[n].cname[14] = 0;
- strcpy(hostcache[n].name, "*");
- strcat(hostcache[n].name, hostcache[n].cname);
+ int portnum = 0;
+ const char* port = strrchr (master, ':');
+ if (port)
+ portnum = atoi (port + 1);
+ if (!portnum)
+ portnum = MASTER_PORT;
+ Con_DPrintf("Datagram_SearchForInetHosts: sending %d byte message to master %s port %i\n", net_message.cursize, master, portnum);
+ dfunc.SetSocketPort (&masteraddr, portnum);
+ dfunc.Write (dfunc.controlSock, net_message.data, net_message.cursize, &masteraddr);
}
- memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));
- hostcache[n].driver = net_driverlevel;
- hostcache[n].ldriver = net_landriverlevel;
- strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));
+ }
- // check for a name conflict
- for (i = 0; i < hostCacheCount; i++)
- {
- if (i == n)
- continue;
- if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0)
- {
- i = strlen(hostcache[n].name);
- if (i < 15 && hostcache[n].name[i-1] > '8')
- {
- hostcache[n].name[i] = '0';
- hostcache[n].name[i+1] = 0;
- }
- else
- hostcache[n].name[i-1]++;
- i = -1;
- }
- }
+ while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)
+ {
+ net_message.cursize = ret;
+ Con_DPrintf("Datagram_SearchForInetHosts: Read received %d byte message\n", net_message.cursize);
+ if (Datagram_HandleServerInfo (&readaddr))
+ result = true;
+ else
+ Master_ParseServerList (&dfunc);
}
+
+ return result;
}
-void Datagram_SearchForHosts (qboolean xmit)
+
+qboolean Datagram_SearchForInetHosts (const char *master)
{
+ qboolean result = false;
for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
{
if (hostCacheCount == HOSTCACHESIZE)
break;
if (net_landrivers[net_landriverlevel].initialized)
- _Datagram_SearchForHosts (xmit);
+ if (_Datagram_SearchForInetHosts (master))
+ result = true;
}
+
+ return result;
}
-static qsocket_t *_Datagram_Connect (char *host)
+static qsocket_t *_Datagram_Connect (const char *host)
{
struct qsockaddr sendaddr;
struct qsockaddr readaddr;
+ struct qsockaddr testaddr;
qsocket_t *sock;
int newsock;
int ret;
if (ret > 0)
{
// is it from the right place?
- if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)
+ // we don't care if the port matches (this adds support for
+ // the NAT fix in the server inspired by faded)
+ memcpy(&testaddr, &sendaddr, sizeof(struct qsockaddr));
+ dfunc.SetSocketPort (&testaddr, dfunc.GetSocketPort(&readaddr));
+ if (sfunc.AddrCompare(&readaddr, &testaddr) != 0)
{
- Con_DPrintf("wrong reply address\n");
- Con_DPrintf("Expected: %s\n", StrAddr (&sendaddr));
- Con_DPrintf("Received: %s\n", StrAddr (&readaddr));
+ Con_Printf("wrong reply address\n");
+ Con_Printf("Expected: %s\n", StrAddr (&sendaddr));
+ Con_Printf("Received: %s\n", StrAddr (&readaddr));
+ CL_UpdateScreen ();
CL_UpdateScreen ();
ret = 0;
continue;
}
- if (ret < sizeof(int))
+ if (ret < (int)sizeof(int))
{
ret = 0;
continue;
ret = 0;
continue;
}
- if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL)
+ if ((control & (~NETFLAG_LENGTH_MASK)) != (int)NETFLAG_CTL)
{
ret = 0;
continue;
return NULL;
}
-qsocket_t *Datagram_Connect (char *host)
+qsocket_t *Datagram_Connect (const char *host)
{
qsocket_t *ret = NULL;
return ret;
}
+static void _Datagram_Heartbeat (const char *master)
+{
+ struct qsockaddr masteraddr;
+ int portnum;
+ const char* port;
+
+ if (dfunc.GetAddrFromName(master, &masteraddr) == -1)
+ return;
+
+ portnum = 0;
+ port = strrchr (master, ':');
+ if (port)
+ portnum = atoi (port + 1);
+ if (!portnum)
+ portnum = MASTER_PORT;
+ dfunc.SetSocketPort (&masteraddr, portnum);
+
+ // FIXME: this is the only use of UDP_Send in the entire engine, add a dfunc.acceptSock to get rid of this function!
+ dfunc.Send (net_message.data, net_message.cursize, &masteraddr);
+}
+
+void Datagram_Heartbeat (const char *master)
+{
+ for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)
+ if (net_landrivers[net_landriverlevel].initialized)
+ _Datagram_Heartbeat (master);
+}