2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
net_main.c
|
|
|
|
|
|
|
|
@description@
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-05-09 05:41:34 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-31 05:19:03 +00:00
|
|
|
#include "QF/cbuf.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/cmd.h"
|
2001-05-31 03:41:35 +00:00
|
|
|
#include "QF/cvar.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/msg.h"
|
|
|
|
#include "QF/qargs.h"
|
2002-08-27 07:16:28 +00:00
|
|
|
#include "QF/quakeio.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/sizebuf.h"
|
|
|
|
#include "QF/sys.h"
|
2002-07-31 05:19:03 +00:00
|
|
|
|
2003-02-11 22:48:57 +00:00
|
|
|
#include "netmain.h"
|
2001-05-30 04:34:06 +00:00
|
|
|
#include "net_vcr.h"
|
2003-02-11 22:48:57 +00:00
|
|
|
|
|
|
|
#include "../nq/include/server.h"
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2022-04-06 10:32:55 +00:00
|
|
|
int net_is_dedicated = 0;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
qsocket_t *net_activeSockets = NULL;
|
|
|
|
qsocket_t *net_freeSockets = NULL;
|
|
|
|
int net_numsockets = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
bool tcpipAvailable = false;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int net_hostport;
|
|
|
|
int DEFAULTnet_hostport = 26000;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
char my_tcpip_address[NET_NAMELEN];
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
static bool listening = false;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
bool slistInProgress = false;
|
|
|
|
bool slistSilent = false;
|
|
|
|
bool slistLocal = true;
|
2001-02-26 06:48:02 +00:00
|
|
|
static double slistStartTime;
|
|
|
|
static int slistLastShown;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void Slist_Send (void *);
|
|
|
|
static void Slist_Poll (void *);
|
2001-02-26 06:48:02 +00:00
|
|
|
PollProcedure slistSendProcedure = { NULL, 0.0, Slist_Send };
|
|
|
|
PollProcedure slistPollProcedure = { NULL, 0.0, Slist_Poll };
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
|
2001-02-23 23:16:13 +00:00
|
|
|
static sizebuf_t _net_message_message;
|
2004-01-20 06:11:00 +00:00
|
|
|
static qmsg_t _net_message = { 0, 0, &_net_message_message };
|
|
|
|
qmsg_t *net_message = &_net_message;
|
2022-01-16 13:15:18 +00:00
|
|
|
unsigned net_activeconnections = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int messagesSent = 0;
|
|
|
|
int messagesReceived = 0;
|
|
|
|
int unreliableMessagesSent = 0;
|
|
|
|
int unreliableMessagesReceived = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
float net_messagetimeout;
|
|
|
|
static cvar_t net_messagetimeout_cvar = {
|
|
|
|
.name = "net_messagetimeout",
|
|
|
|
.description =
|
|
|
|
"None",
|
|
|
|
.default_value = "300",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &net_messagetimeout },
|
|
|
|
};
|
|
|
|
char *hostname;
|
|
|
|
static cvar_t hostname_cvar = {
|
|
|
|
.name = "hostname",
|
|
|
|
.description =
|
|
|
|
"None",
|
|
|
|
.default_value = "UNNAMED",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = 0, .value = &hostname },
|
|
|
|
};
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-08-27 07:16:28 +00:00
|
|
|
QFile *vcrFile;
|
2023-06-13 09:06:11 +00:00
|
|
|
bool recording = false;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// these two macros are to make the code more readable
|
|
|
|
#define sfunc net_drivers[sock->driver]
|
|
|
|
#define dfunc net_drivers[net_driverlevel]
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int net_driverlevel;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
double net_time;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2021-04-04 09:38:14 +00:00
|
|
|
static int hostCacheCount = 0;
|
|
|
|
static hostcache_t hostcache[HOSTCACHESIZE];
|
|
|
|
|
2022-04-06 10:32:55 +00:00
|
|
|
static cbuf_t *net_cbuf;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
double
|
|
|
|
SetNetTime (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
net_time = Sys_DoubleTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
return net_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-26 05:15:41 +00:00
|
|
|
qsocket_t *
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_NewQSocket (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
qsocket_t *sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (net_freeSockets == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (net_activeconnections >= svs.maxclients)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// get one from free list
|
|
|
|
sock = net_freeSockets;
|
|
|
|
net_freeSockets = sock->next;
|
|
|
|
|
|
|
|
// add it to active list
|
|
|
|
sock->next = net_activeSockets;
|
|
|
|
net_activeSockets = sock;
|
|
|
|
|
|
|
|
sock->disconnected = false;
|
|
|
|
sock->connecttime = net_time;
|
2001-02-26 06:48:02 +00:00
|
|
|
strcpy (sock->address, "UNSET ADDRESS");
|
2001-02-19 21:15:25 +00:00
|
|
|
sock->driver = net_driverlevel;
|
|
|
|
sock->socket = 0;
|
|
|
|
sock->driverdata = NULL;
|
|
|
|
sock->canSend = true;
|
|
|
|
sock->sendNext = false;
|
|
|
|
sock->lastMessageTime = net_time;
|
|
|
|
sock->ackSequence = 0;
|
|
|
|
sock->sendSequence = 0;
|
|
|
|
sock->unreliableSendSequence = 0;
|
|
|
|
sock->sendMessageLength = 0;
|
|
|
|
sock->receiveSequence = 0;
|
|
|
|
sock->unreliableReceiveSequence = 0;
|
|
|
|
sock->receiveMessageLength = 0;
|
|
|
|
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_FreeQSocket (qsocket_t *sock)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
qsocket_t *s;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// remove it from active list
|
|
|
|
if (sock == net_activeSockets)
|
|
|
|
net_activeSockets = net_activeSockets->next;
|
2001-02-26 06:48:02 +00:00
|
|
|
else {
|
2001-02-19 21:15:25 +00:00
|
|
|
for (s = net_activeSockets; s; s = s->next)
|
2001-02-26 06:48:02 +00:00
|
|
|
if (s->next == sock) {
|
2001-02-19 21:15:25 +00:00
|
|
|
s->next = sock->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!s)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("NET_FreeQSocket: not active");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add it to free list
|
|
|
|
sock->next = net_freeSockets;
|
|
|
|
net_freeSockets = sock;
|
|
|
|
sock->disconnected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
NET_Listen_f (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
if (Cmd_Argc () != 2) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
listening = atoi (Cmd_Argv (1)) ? true : false;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
|
|
continue;
|
|
|
|
dfunc.Listen (listening);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
MaxPlayers_f (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2022-01-16 13:15:18 +00:00
|
|
|
unsigned n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (Cmd_Argc () != 2) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (sv.active) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf
|
2001-02-26 06:48:02 +00:00
|
|
|
("maxplayers can not be changed while a server is running.\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
n = atoi (Cmd_Argv (1));
|
2001-02-19 21:15:25 +00:00
|
|
|
if (n < 1)
|
|
|
|
n = 1;
|
2001-02-26 06:48:02 +00:00
|
|
|
if (n > svs.maxclientslimit) {
|
2001-02-19 21:15:25 +00:00
|
|
|
n = svs.maxclientslimit;
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("\"maxplayers\" set to \"%u\"\n", n);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((n == 1) && listening)
|
2022-04-06 10:32:55 +00:00
|
|
|
Cbuf_AddText (net_cbuf, "listen 0\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if ((n > 1) && (!listening))
|
2022-04-06 10:32:55 +00:00
|
|
|
Cbuf_AddText (net_cbuf, "listen 1\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
svs.maxclients = n;
|
|
|
|
if (n == 1)
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Set ("deathmatch", "0");
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Set ("deathmatch", "1");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
NET_Port_f (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (Cmd_Argc () != 2) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("\"port\" is \"%u\"\n", net_hostport);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
n = atoi (Cmd_Argv (1));
|
|
|
|
if (n < 1 || n > 65534) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("Bad value, must be between 1 and 65534\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFAULTnet_hostport = n;
|
|
|
|
net_hostport = n;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (listening) {
|
2001-02-19 21:15:25 +00:00
|
|
|
// force a change to the new port
|
2022-04-06 10:32:55 +00:00
|
|
|
Cbuf_AddText (net_cbuf, "listen 0\n");
|
|
|
|
Cbuf_AddText (net_cbuf, "listen 1\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
PrintSlistHeader (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("Server Map Users\n");
|
|
|
|
Sys_Printf ("--------------- --------------- -----\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
slistLastShown = 0;
|
|
|
|
}
|
|
|
|
|
2021-04-04 09:38:14 +00:00
|
|
|
void
|
|
|
|
NET_AddCachedHost (const char *name, const char *map, const char *cname,
|
|
|
|
int users, int maxusers, int driver, int ldriver,
|
|
|
|
const netadr_t *addr)
|
|
|
|
{
|
|
|
|
if (hostCacheCount == HOSTCACHESIZE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < hostCacheCount; i++) {
|
|
|
|
// addr will be 0 for loopback, and there can be only one loopback
|
|
|
|
// server.
|
|
|
|
if (!addr || !memcmp (addr, &hostcache[i].addr, sizeof (netadr_t))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const int namesize = sizeof (hostcache[0].name) - 1;
|
|
|
|
const int mapsize = sizeof (hostcache[0].map) - 1;
|
|
|
|
const int cnamesize = sizeof (hostcache[0].cname) - 1;
|
|
|
|
|
|
|
|
hostcache_t *host = &hostcache[hostCacheCount++];
|
|
|
|
strncpy (host->name, name, namesize);
|
|
|
|
strncpy (host->map, map, mapsize);
|
|
|
|
strncpy (host->cname, cname, cnamesize);
|
|
|
|
host->name[namesize] = 0;
|
|
|
|
host->map[mapsize] = 0;
|
|
|
|
host->cname[cnamesize] = 0;
|
|
|
|
|
|
|
|
host->users = users;
|
|
|
|
host->maxusers = maxusers;
|
|
|
|
host->driver = driver;
|
|
|
|
host->ldriver = ldriver;
|
|
|
|
if (addr) {
|
|
|
|
host->addr = *addr;
|
|
|
|
} else {
|
|
|
|
memset (&host->addr, 0, sizeof (host->addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for and resolve name conflicts
|
|
|
|
for (int i = 0; i < hostCacheCount - 1; i++) {
|
|
|
|
if (strcasecmp (host->name, hostcache[i].name) == 0) {
|
|
|
|
int len = strlen (host->name);
|
|
|
|
if (len < namesize && host->name[len - 1] > '8') {
|
|
|
|
host->name[len] = '0';
|
|
|
|
host->name[len + 1] = 0;
|
|
|
|
} else {
|
|
|
|
host->name[len - 1]++;
|
|
|
|
}
|
|
|
|
i = -1; // restart loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
PrintSlist (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
for (n = slistLastShown; n < hostCacheCount; n++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (hostcache[n].maxusers)
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name,
|
2001-02-26 06:48:02 +00:00
|
|
|
hostcache[n].map, hostcache[n].users,
|
|
|
|
hostcache[n].maxusers);
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("%-15.15s %-15.15s\n", hostcache[n].name,
|
2001-02-26 06:48:02 +00:00
|
|
|
hostcache[n].map);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
slistLastShown = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
|
|
|
PrintSlistTrailer (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
if (hostCacheCount)
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("== end list ==\n\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("No Quake servers found.\n\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-26 05:15:41 +00:00
|
|
|
static void
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_Slist_f (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
if (slistInProgress)
|
|
|
|
return;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (!slistSilent) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("Looking for Quake servers...\n");
|
2001-02-26 06:48:02 +00:00
|
|
|
PrintSlistHeader ();
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
slistInProgress = true;
|
2001-02-26 06:48:02 +00:00
|
|
|
slistStartTime = Sys_DoubleTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SchedulePollProcedure (&slistSendProcedure, 0.0);
|
|
|
|
SchedulePollProcedure (&slistPollProcedure, 0.1);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
hostCacheCount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
2003-01-06 18:28:13 +00:00
|
|
|
Slist_Send (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!slistLocal && net_driverlevel == 0)
|
|
|
|
continue;
|
|
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
|
|
continue;
|
|
|
|
dfunc.SearchForHosts (true);
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if ((Sys_DoubleTime () - slistStartTime) < 0.5)
|
|
|
|
SchedulePollProcedure (&slistSendProcedure, 0.75);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static void
|
2003-01-06 18:28:13 +00:00
|
|
|
Slist_Poll (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!slistLocal && net_driverlevel == 0)
|
|
|
|
continue;
|
|
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
|
|
continue;
|
|
|
|
dfunc.SearchForHosts (false);
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (!slistSilent)
|
|
|
|
PrintSlist ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if ((Sys_DoubleTime () - slistStartTime) < 1.5) {
|
|
|
|
SchedulePollProcedure (&slistPollProcedure, 0.1);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (!slistSilent)
|
|
|
|
PrintSlistTrailer ();
|
2001-02-19 21:15:25 +00:00
|
|
|
slistInProgress = false;
|
|
|
|
slistSilent = false;
|
|
|
|
slistLocal = true;
|
|
|
|
}
|
|
|
|
|
2011-07-26 05:15:41 +00:00
|
|
|
qsocket_t *
|
2001-07-15 07:04:17 +00:00
|
|
|
NET_Connect (const char *host)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
qsocket_t *ret;
|
|
|
|
int n;
|
|
|
|
int numdrivers = net_numdrivers;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host && *host == 0)
|
|
|
|
host = NULL;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (host) {
|
|
|
|
if (strcasecmp (host, "local") == 0) {
|
2001-02-19 21:15:25 +00:00
|
|
|
numdrivers = 1;
|
|
|
|
goto JustDoIt;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (hostCacheCount) {
|
2001-02-19 21:15:25 +00:00
|
|
|
for (n = 0; n < hostCacheCount; n++)
|
2001-02-26 06:48:02 +00:00
|
|
|
if (strcasecmp (host, hostcache[n].name) == 0) {
|
2001-02-19 21:15:25 +00:00
|
|
|
host = hostcache[n].cname;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (n < hostCacheCount)
|
|
|
|
goto JustDoIt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
slistSilent = host ? true : false;
|
|
|
|
NET_Slist_f ();
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
while (slistInProgress)
|
|
|
|
NET_Poll ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (host == NULL) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (hostCacheCount != 1)
|
|
|
|
return NULL;
|
|
|
|
host = hostcache[0].cname;
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hostCacheCount)
|
|
|
|
for (n = 0; n < hostCacheCount; n++)
|
2001-02-26 06:48:02 +00:00
|
|
|
if (strcasecmp (host, hostcache[n].name) == 0) {
|
2001-02-19 21:15:25 +00:00
|
|
|
host = hostcache[n].cname;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
JustDoIt:
|
|
|
|
for (net_driverlevel = 0; net_driverlevel < numdrivers; net_driverlevel++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
|
|
continue;
|
|
|
|
ret = dfunc.Connect (host);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (host) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("\n");
|
2001-02-26 06:48:02 +00:00
|
|
|
PrintSlistHeader ();
|
|
|
|
PrintSlist ();
|
|
|
|
PrintSlistTrailer ();
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
struct {
|
|
|
|
double time;
|
|
|
|
int op;
|
2007-04-06 01:09:58 +00:00
|
|
|
intptr_t session;
|
2001-02-19 21:15:25 +00:00
|
|
|
} vcrConnect;
|
|
|
|
|
2011-07-26 05:15:41 +00:00
|
|
|
qsocket_t *
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_CheckNewConnections (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
qsocket_t *ret;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (net_drivers[net_driverlevel].initialized == false)
|
|
|
|
continue;
|
|
|
|
if (net_driverlevel && listening == false)
|
|
|
|
continue;
|
|
|
|
ret = dfunc.CheckNewConnections ();
|
2001-02-26 06:48:02 +00:00
|
|
|
if (ret) {
|
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrConnect.time = host_time;
|
|
|
|
vcrConnect.op = VCR_OP_CONNECT;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrConnect.session = (intptr_t) ret;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrConnect, sizeof (vcrConnect));
|
|
|
|
Qwrite (vcrFile, ret->address, NET_NAMELEN);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrConnect.time = host_time;
|
|
|
|
vcrConnect.op = VCR_OP_CONNECT;
|
|
|
|
vcrConnect.session = 0;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrConnect, sizeof (vcrConnect));
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_Close (qsocket_t *sock)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
if (!sock)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sock->disconnected)
|
|
|
|
return;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// call the driver_Close function
|
|
|
|
sfunc.Close (sock);
|
|
|
|
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "closing socket\n");
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_FreeQSocket (sock);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
struct {
|
|
|
|
double time;
|
|
|
|
int op;
|
2007-04-06 01:09:58 +00:00
|
|
|
intptr_t session;
|
2001-02-26 06:48:02 +00:00
|
|
|
int ret;
|
|
|
|
int len;
|
2001-02-19 21:15:25 +00:00
|
|
|
} vcrGetMessage;
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_GetMessage (qsocket_t *sock)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int ret;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!sock)
|
|
|
|
return -1;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (sock->disconnected) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("NET_GetMessage: disconnected socket\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
ret = sfunc.QGetMessage (sock);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// see if this connection has timed out
|
2001-02-26 06:48:02 +00:00
|
|
|
if (ret == 0 && sock->driver) {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (net_time - sock->lastMessageTime > net_messagetimeout) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "socket timed out\n");
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_Close (sock);
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (ret > 0) {
|
|
|
|
if (sock->driver) {
|
2001-02-19 21:15:25 +00:00
|
|
|
sock->lastMessageTime = net_time;
|
|
|
|
if (ret == 1)
|
|
|
|
messagesReceived++;
|
|
|
|
else if (ret == 2)
|
|
|
|
unreliableMessagesReceived++;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrGetMessage.time = host_time;
|
|
|
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrGetMessage.session = (intptr_t) sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrGetMessage.ret = ret;
|
2001-02-23 23:16:13 +00:00
|
|
|
vcrGetMessage.len = _net_message_message.cursize;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrGetMessage, 24);
|
|
|
|
Qwrite (vcrFile, _net_message_message.data,
|
2001-02-26 06:48:02 +00:00
|
|
|
_net_message_message.cursize);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
} else {
|
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrGetMessage.time = host_time;
|
|
|
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrGetMessage.session = (intptr_t) sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrGetMessage.ret = ret;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrGetMessage, 20);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
struct {
|
|
|
|
double time;
|
|
|
|
int op;
|
2007-04-06 01:09:58 +00:00
|
|
|
intptr_t session;
|
2001-02-26 06:48:02 +00:00
|
|
|
int r;
|
2001-02-19 21:15:25 +00:00
|
|
|
} vcrSendMessage;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int r;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!sock)
|
|
|
|
return -1;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (sock->disconnected) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("NET_SendMessage: disconnected socket\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
|
|
|
r = sfunc.QSendMessage (sock, data);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (r == 1 && sock->driver)
|
|
|
|
messagesSent++;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.time = host_time;
|
|
|
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrSendMessage.session = (intptr_t) sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.r = r;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrSendMessage, 20);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int r;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!sock)
|
|
|
|
return -1;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (sock->disconnected) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("NET_SendMessage: disconnected socket\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
|
|
|
r = sfunc.SendUnreliableMessage (sock, data);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (r == 1 && sock->driver)
|
|
|
|
unreliableMessagesSent++;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.time = host_time;
|
|
|
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrSendMessage.session = (intptr_t) sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.r = r;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrSendMessage, 20);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-06-13 09:06:11 +00:00
|
|
|
bool
|
2011-07-26 05:15:41 +00:00
|
|
|
NET_CanSendMessage (qsocket_t *sock)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int r;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!sock)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (sock->disconnected)
|
|
|
|
return false;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
|
|
|
|
|
|
|
r = sfunc.CanSendMessage (sock);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (recording) {
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.time = host_time;
|
|
|
|
vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
|
2007-04-06 01:09:58 +00:00
|
|
|
vcrSendMessage.session = (intptr_t) sock;
|
2001-02-19 21:15:25 +00:00
|
|
|
vcrSendMessage.r = r;
|
2001-03-30 23:24:57 +00:00
|
|
|
Qwrite (vcrFile, &vcrSendMessage, 20);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2010-11-21 05:27:43 +00:00
|
|
|
NET_SendToAll (sizebuf_t *data, double blocktime)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
double start;
|
2022-01-16 13:15:18 +00:00
|
|
|
unsigned i;
|
2001-02-26 06:48:02 +00:00
|
|
|
int count = 0;
|
2023-06-13 09:06:11 +00:00
|
|
|
bool state1[MAX_SCOREBOARD]; /* can we send */
|
|
|
|
bool state2[MAX_SCOREBOARD]; /* did we send */
|
2001-02-26 06:48:02 +00:00
|
|
|
|
|
|
|
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
|
|
|
i++, host_client++) {
|
2010-11-21 05:27:43 +00:00
|
|
|
if (host_client->netconnection && host_client->active) {
|
2001-02-26 06:48:02 +00:00
|
|
|
if (host_client->netconnection->driver == 0) {
|
|
|
|
NET_SendMessage (host_client->netconnection, data);
|
2001-02-19 21:15:25 +00:00
|
|
|
state1[i] = true;
|
|
|
|
state2[i] = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
state1[i] = false;
|
|
|
|
state2[i] = false;
|
2001-02-26 06:48:02 +00:00
|
|
|
} else {
|
2001-02-19 21:15:25 +00:00
|
|
|
state1[i] = true;
|
|
|
|
state2[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
start = Sys_DoubleTime ();
|
|
|
|
while (count) {
|
2001-02-19 21:15:25 +00:00
|
|
|
count = 0;
|
2001-02-26 06:48:02 +00:00
|
|
|
for (i = 0, host_client = svs.clients; i < svs.maxclients;
|
|
|
|
i++, host_client++) {
|
|
|
|
if (!state1[i]) {
|
|
|
|
if (NET_CanSendMessage (host_client->netconnection)) {
|
2001-02-19 21:15:25 +00:00
|
|
|
state1[i] = true;
|
2001-02-26 06:48:02 +00:00
|
|
|
NET_SendMessage (host_client->netconnection, data);
|
|
|
|
} else {
|
2001-02-19 21:15:25 +00:00
|
|
|
NET_GetMessage (host_client->netconnection);
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (!state2[i]) {
|
|
|
|
if (NET_CanSendMessage (host_client->netconnection)) {
|
2001-02-19 21:15:25 +00:00
|
|
|
state2[i] = true;
|
2001-02-26 06:48:02 +00:00
|
|
|
} else {
|
2001-02-19 21:15:25 +00:00
|
|
|
NET_GetMessage (host_client->netconnection);
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
if ((Sys_DoubleTime () - start) > blocktime)
|
2001-02-19 21:15:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
2019-07-12 14:15:26 +00:00
|
|
|
static void
|
2020-06-25 05:03:52 +00:00
|
|
|
NET_shutdown (void *data)
|
2019-07-12 14:15:26 +00:00
|
|
|
{
|
|
|
|
qsocket_t *sock;
|
|
|
|
|
|
|
|
SetNetTime ();
|
|
|
|
|
|
|
|
for (sock = net_activeSockets; sock; sock = sock->next)
|
|
|
|
NET_Close (sock);
|
|
|
|
|
|
|
|
//
|
|
|
|
// shutdown the drivers
|
|
|
|
//
|
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
|
|
|
if (net_drivers[net_driverlevel].initialized == true) {
|
|
|
|
net_drivers[net_driverlevel].Shutdown ();
|
|
|
|
net_drivers[net_driverlevel].initialized = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vcrFile) {
|
|
|
|
Sys_Printf ("Closing vcrfile.\n");
|
|
|
|
Qclose (vcrFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
2022-04-06 10:32:55 +00:00
|
|
|
NET_Init (cbuf_t *cbuf)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int i;
|
|
|
|
int controlSocket;
|
|
|
|
qsocket_t *s;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2022-04-06 10:32:55 +00:00
|
|
|
net_cbuf = cbuf;
|
|
|
|
|
2020-06-25 05:03:52 +00:00
|
|
|
Sys_RegisterShutdown (NET_shutdown, 0);
|
2019-07-12 14:15:26 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (COM_CheckParm ("-playback")) {
|
2001-02-19 21:15:25 +00:00
|
|
|
net_numdrivers = 1;
|
|
|
|
net_drivers[0].Init = VCR_Init;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (COM_CheckParm ("-record"))
|
2001-02-19 21:15:25 +00:00
|
|
|
recording = true;
|
|
|
|
|
|
|
|
i = COM_CheckParm ("-port");
|
|
|
|
if (!i)
|
|
|
|
i = COM_CheckParm ("-udpport");
|
|
|
|
if (!i)
|
|
|
|
i = COM_CheckParm ("-ipxport");
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (i) {
|
|
|
|
if (i < com_argc - 1)
|
|
|
|
DEFAULTnet_hostport = atoi (com_argv[i + 1]);
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
|
|
|
Sys_Error ("NET_Init: you must specify a number after -port");
|
|
|
|
}
|
|
|
|
net_hostport = DEFAULTnet_hostport;
|
|
|
|
|
2022-04-06 10:32:55 +00:00
|
|
|
if (COM_CheckParm ("-listen") || net_is_dedicated)
|
2001-02-19 21:15:25 +00:00
|
|
|
listening = true;
|
|
|
|
net_numsockets = svs.maxclientslimit;
|
2022-04-06 10:32:55 +00:00
|
|
|
if (!net_is_dedicated)
|
2001-02-19 21:15:25 +00:00
|
|
|
net_numsockets++;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
for (i = 0; i < net_numsockets; i++) {
|
2021-07-28 06:01:45 +00:00
|
|
|
s = (qsocket_t *) Hunk_AllocName (0, sizeof (qsocket_t), "qsocket");
|
2001-02-19 21:15:25 +00:00
|
|
|
s->next = net_freeSockets;
|
|
|
|
net_freeSockets = s;
|
|
|
|
s->disconnected = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// allocate space for network message buffer
|
2001-02-23 23:16:13 +00:00
|
|
|
SZ_Alloc (&_net_message_message, NET_MAXMESSAGE);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Register (&net_messagetimeout_cvar, 0, 0);
|
|
|
|
Cvar_Register (&hostname_cvar, 0, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-21 19:35:06 +00:00
|
|
|
Cmd_AddCommand ("slist", NET_Slist_f, "No Description");
|
|
|
|
Cmd_AddCommand ("listen", NET_Listen_f, "No Description");
|
|
|
|
Cmd_AddCommand ("maxplayers", MaxPlayers_f, "No Description");
|
|
|
|
Cmd_AddCommand ("port", NET_Port_f, "No Description");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// initialize all the drivers
|
2001-02-26 06:48:02 +00:00
|
|
|
for (net_driverlevel = 0; net_driverlevel < net_numdrivers;
|
|
|
|
net_driverlevel++) {
|
|
|
|
controlSocket = net_drivers[net_driverlevel].Init ();
|
2001-02-19 21:15:25 +00:00
|
|
|
if (controlSocket == -1)
|
|
|
|
continue;
|
|
|
|
net_drivers[net_driverlevel].initialized = true;
|
|
|
|
net_drivers[net_driverlevel].controlSock = controlSocket;
|
|
|
|
if (listening)
|
|
|
|
net_drivers[net_driverlevel].Listen (true);
|
2001-02-26 06:48:02 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (*my_tcpip_address)
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "TCP/IP address %s\n", my_tcpip_address);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PollProcedure *pollProcedureList = NULL;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
|
|
|
NET_Poll (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
PollProcedure *pp;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
SetNetTime ();
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
for (pp = pollProcedureList; pp; pp = pp->next) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (pp->nextTime > net_time)
|
|
|
|
break;
|
|
|
|
pollProcedureList = pp->next;
|
2001-02-26 06:48:02 +00:00
|
|
|
pp->procedure (pp->arg);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
2011-07-26 05:15:41 +00:00
|
|
|
SchedulePollProcedure (PollProcedure *proc, double timeOffset)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
PollProcedure *pp, *prev;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
proc->nextTime = Sys_DoubleTime () + timeOffset;
|
|
|
|
for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (pp->nextTime >= proc->nextTime)
|
|
|
|
break;
|
|
|
|
prev = pp;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (prev == NULL) {
|
2001-02-19 21:15:25 +00:00
|
|
|
proc->next = pollProcedureList;
|
|
|
|
pollProcedureList = proc;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
proc->next = pp;
|
|
|
|
prev->next = proc;
|
|
|
|
}
|