mirror of
https://github.com/nzp-team/glquake.git
synced 2024-11-27 14:22:12 +00:00
998 lines
19 KiB
C
998 lines
19 KiB
C
|
/*
|
||
|
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 the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
*/
|
||
|
// net_main.c
|
||
|
|
||
|
#include "quakedef.h"
|
||
|
#include "net_vcr.h"
|
||
|
|
||
|
qsocket_t *net_activeSockets = NULL;
|
||
|
qsocket_t *net_freeSockets = NULL;
|
||
|
int net_numsockets = 0;
|
||
|
|
||
|
qboolean serialAvailable = false;
|
||
|
qboolean ipxAvailable = false;
|
||
|
qboolean tcpipAvailable = false;
|
||
|
|
||
|
int net_hostport;
|
||
|
int DEFAULTnet_hostport = 26000;
|
||
|
|
||
|
char my_ipx_address[NET_NAMELEN];
|
||
|
char my_tcpip_address[NET_NAMELEN];
|
||
|
|
||
|
void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
|
||
|
void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
|
||
|
void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
|
||
|
void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
|
||
|
|
||
|
static qboolean listening = false;
|
||
|
|
||
|
qboolean slistInProgress = false;
|
||
|
qboolean slistSilent = false;
|
||
|
qboolean slistLocal = true;
|
||
|
static double slistStartTime;
|
||
|
static int slistLastShown;
|
||
|
|
||
|
static void Slist_Send(void);
|
||
|
static void Slist_Poll(void);
|
||
|
PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
|
||
|
PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
|
||
|
|
||
|
|
||
|
sizebuf_t net_message;
|
||
|
int net_activeconnections = 0;
|
||
|
|
||
|
int messagesSent = 0;
|
||
|
int messagesReceived = 0;
|
||
|
int unreliableMessagesSent = 0;
|
||
|
int unreliableMessagesReceived = 0;
|
||
|
|
||
|
cvar_t net_messagetimeout = {"net_messagetimeout","300"};
|
||
|
cvar_t hostname = {"hostname", "UNNAMED"};
|
||
|
|
||
|
qboolean configRestored = false;
|
||
|
cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
|
||
|
cvar_t config_com_irq = {"_config_com_irq", "4", true};
|
||
|
cvar_t config_com_baud = {"_config_com_baud", "57600", true};
|
||
|
cvar_t config_com_modem = {"_config_com_modem", "1", true};
|
||
|
cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
|
||
|
cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
|
||
|
cvar_t config_modem_init = {"_config_modem_init", "", true};
|
||
|
cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
|
||
|
|
||
|
#ifdef IDGODS
|
||
|
cvar_t idgods = {"idgods", "0"};
|
||
|
#endif
|
||
|
|
||
|
int vcrFile = -1;
|
||
|
qboolean recording = false;
|
||
|
|
||
|
// these two macros are to make the code more readable
|
||
|
#define sfunc net_drivers[sock->driver]
|
||
|
#define dfunc net_drivers[net_driverlevel]
|
||
|
|
||
|
int net_driverlevel;
|
||
|
|
||
|
|
||
|
double net_time;
|
||
|
|
||
|
double SetNetTime(void)
|
||
|
{
|
||
|
net_time = Sys_FloatTime();
|
||
|
return net_time;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
NET_NewQSocket
|
||
|
|
||
|
Called by drivers when a new communications endpoint is required
|
||
|
The sequence and buffer fields will be filled in properly
|
||
|
===================
|
||
|
*/
|
||
|
qsocket_t *NET_NewQSocket (void)
|
||
|
{
|
||
|
qsocket_t *sock;
|
||
|
|
||
|
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;
|
||
|
Q_strcpy (sock->address,"UNSET ADDRESS");
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
void NET_FreeQSocket(qsocket_t *sock)
|
||
|
{
|
||
|
qsocket_t *s;
|
||
|
|
||
|
// remove it from active list
|
||
|
if (sock == net_activeSockets)
|
||
|
net_activeSockets = net_activeSockets->next;
|
||
|
else
|
||
|
{
|
||
|
for (s = net_activeSockets; s; s = s->next)
|
||
|
if (s->next == sock)
|
||
|
{
|
||
|
s->next = sock->next;
|
||
|
break;
|
||
|
}
|
||
|
if (!s)
|
||
|
Sys_Error ("NET_FreeQSocket: not active\n");
|
||
|
}
|
||
|
|
||
|
// add it to free list
|
||
|
sock->next = net_freeSockets;
|
||
|
net_freeSockets = sock;
|
||
|
sock->disconnected = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void NET_Listen_f (void)
|
||
|
{
|
||
|
if (Cmd_Argc () != 2)
|
||
|
{
|
||
|
Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
listening = Q_atoi(Cmd_Argv(1)) ? true : false;
|
||
|
|
||
|
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
|
||
|
{
|
||
|
if (net_drivers[net_driverlevel].initialized == false)
|
||
|
continue;
|
||
|
dfunc.Listen (listening);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void MaxPlayers_f (void)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
if (Cmd_Argc () != 2)
|
||
|
{
|
||
|
Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (sv.active)
|
||
|
{
|
||
|
Con_Printf ("maxplayers can not be changed while a server is running.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
n = Q_atoi(Cmd_Argv(1));
|
||
|
if (n < 1)
|
||
|
n = 1;
|
||
|
if (n > svs.maxclientslimit)
|
||
|
{
|
||
|
n = svs.maxclientslimit;
|
||
|
Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
|
||
|
}
|
||
|
|
||
|
if ((n == 1) && listening)
|
||
|
Cbuf_AddText ("listen 0\n");
|
||
|
|
||
|
if ((n > 1) && (!listening))
|
||
|
Cbuf_AddText ("listen 1\n");
|
||
|
|
||
|
svs.maxclients = n;
|
||
|
if (n == 1)
|
||
|
Cvar_Set ("deathmatch", "0");
|
||
|
else
|
||
|
Cvar_Set ("deathmatch", "1");
|
||
|
}
|
||
|
|
||
|
|
||
|
static void NET_Port_f (void)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
if (Cmd_Argc () != 2)
|
||
|
{
|
||
|
Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
n = Q_atoi(Cmd_Argv(1));
|
||
|
if (n < 1 || n > 65534)
|
||
|
{
|
||
|
Con_Printf ("Bad value, must be between 1 and 65534\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DEFAULTnet_hostport = n;
|
||
|
net_hostport = n;
|
||
|
|
||
|
if (listening)
|
||
|
{
|
||
|
// force a change to the new port
|
||
|
Cbuf_AddText ("listen 0\n");
|
||
|
Cbuf_AddText ("listen 1\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void PrintSlistHeader(void)
|
||
|
{
|
||
|
Con_Printf("Server Map Users\n");
|
||
|
Con_Printf("--------------- --------------- -----\n");
|
||
|
slistLastShown = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void PrintSlist(void)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
for (n = slistLastShown; n < hostCacheCount; n++)
|
||
|
{
|
||
|
if (hostcache[n].maxusers)
|
||
|
Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
|
||
|
else
|
||
|
Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
|
||
|
}
|
||
|
slistLastShown = n;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void PrintSlistTrailer(void)
|
||
|
{
|
||
|
if (hostCacheCount)
|
||
|
Con_Printf("== end list ==\n\n");
|
||
|
else
|
||
|
Con_Printf("No Quake servers found.\n\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
void NET_Slist_f (void)
|
||
|
{
|
||
|
if (slistInProgress)
|
||
|
return;
|
||
|
|
||
|
if (! slistSilent)
|
||
|
{
|
||
|
Con_Printf("Looking for Quake servers...\n");
|
||
|
PrintSlistHeader();
|
||
|
}
|
||
|
|
||
|
slistInProgress = true;
|
||
|
slistStartTime = Sys_FloatTime();
|
||
|
|
||
|
SchedulePollProcedure(&slistSendProcedure, 0.0);
|
||
|
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||
|
|
||
|
hostCacheCount = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void Slist_Send(void)
|
||
|
{
|
||
|
for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
||
|
{
|
||
|
if (!slistLocal && net_driverlevel == 0)
|
||
|
continue;
|
||
|
if (net_drivers[net_driverlevel].initialized == false)
|
||
|
continue;
|
||
|
dfunc.SearchForHosts (true);
|
||
|
}
|
||
|
|
||
|
if ((Sys_FloatTime() - slistStartTime) < 0.5)
|
||
|
SchedulePollProcedure(&slistSendProcedure, 0.75);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void Slist_Poll(void)
|
||
|
{
|
||
|
for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
|
||
|
{
|
||
|
if (!slistLocal && net_driverlevel == 0)
|
||
|
continue;
|
||
|
if (net_drivers[net_driverlevel].initialized == false)
|
||
|
continue;
|
||
|
dfunc.SearchForHosts (false);
|
||
|
}
|
||
|
|
||
|
if (! slistSilent)
|
||
|
PrintSlist();
|
||
|
|
||
|
if ((Sys_FloatTime() - slistStartTime) < 1.5)
|
||
|
{
|
||
|
SchedulePollProcedure(&slistPollProcedure, 0.1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (! slistSilent)
|
||
|
PrintSlistTrailer();
|
||
|
slistInProgress = false;
|
||
|
slistSilent = false;
|
||
|
slistLocal = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
NET_Connect
|
||
|
===================
|
||
|
*/
|
||
|
|
||
|
int hostCacheCount = 0;
|
||
|
hostcache_t hostcache[HOSTCACHESIZE];
|
||
|
|
||
|
qsocket_t *NET_Connect (char *host)
|
||
|
{
|
||
|
qsocket_t *ret;
|
||
|
int n;
|
||
|
int numdrivers = net_numdrivers;
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
if (host && *host == 0)
|
||
|
host = NULL;
|
||
|
|
||
|
if (host)
|
||
|
{
|
||
|
if (Q_strcasecmp (host, "local") == 0)
|
||
|
{
|
||
|
numdrivers = 1;
|
||
|
goto JustDoIt;
|
||
|
}
|
||
|
|
||
|
if (hostCacheCount)
|
||
|
{
|
||
|
for (n = 0; n < hostCacheCount; n++)
|
||
|
if (Q_strcasecmp (host, hostcache[n].name) == 0)
|
||
|
{
|
||
|
host = hostcache[n].cname;
|
||
|
break;
|
||
|
}
|
||
|
if (n < hostCacheCount)
|
||
|
goto JustDoIt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
slistSilent = host ? true : false;
|
||
|
NET_Slist_f ();
|
||
|
|
||
|
while(slistInProgress)
|
||
|
NET_Poll();
|
||
|
|
||
|
if (host == NULL)
|
||
|
{
|
||
|
if (hostCacheCount != 1)
|
||
|
return NULL;
|
||
|
host = hostcache[0].cname;
|
||
|
Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
|
||
|
}
|
||
|
|
||
|
if (hostCacheCount)
|
||
|
for (n = 0; n < hostCacheCount; n++)
|
||
|
if (Q_strcasecmp (host, hostcache[n].name) == 0)
|
||
|
{
|
||
|
host = hostcache[n].cname;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
JustDoIt:
|
||
|
for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
|
||
|
{
|
||
|
if (net_drivers[net_driverlevel].initialized == false)
|
||
|
continue;
|
||
|
ret = dfunc.Connect (host);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
if (host)
|
||
|
{
|
||
|
Con_Printf("\n");
|
||
|
PrintSlistHeader();
|
||
|
PrintSlist();
|
||
|
PrintSlistTrailer();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
NET_CheckNewConnections
|
||
|
===================
|
||
|
*/
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
double time;
|
||
|
int op;
|
||
|
long session;
|
||
|
} vcrConnect;
|
||
|
|
||
|
qsocket_t *NET_CheckNewConnections (void)
|
||
|
{
|
||
|
qsocket_t *ret;
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
|
||
|
{
|
||
|
if (net_drivers[net_driverlevel].initialized == false)
|
||
|
continue;
|
||
|
if (net_driverlevel && listening == false)
|
||
|
continue;
|
||
|
ret = dfunc.CheckNewConnections ();
|
||
|
if (ret)
|
||
|
{
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrConnect.time = host_time;
|
||
|
vcrConnect.op = VCR_OP_CONNECT;
|
||
|
vcrConnect.session = (long)ret;
|
||
|
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
|
||
|
Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrConnect.time = host_time;
|
||
|
vcrConnect.op = VCR_OP_CONNECT;
|
||
|
vcrConnect.session = 0;
|
||
|
Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===================
|
||
|
NET_Close
|
||
|
===================
|
||
|
*/
|
||
|
void NET_Close (qsocket_t *sock)
|
||
|
{
|
||
|
if (!sock)
|
||
|
return;
|
||
|
|
||
|
if (sock->disconnected)
|
||
|
return;
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
// call the driver_Close function
|
||
|
sfunc.Close (sock);
|
||
|
|
||
|
NET_FreeQSocket(sock);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
NET_GetMessage
|
||
|
|
||
|
If there is a complete message, return it in net_message
|
||
|
|
||
|
returns 0 if no data is waiting
|
||
|
returns 1 if a message was received
|
||
|
returns -1 if connection is invalid
|
||
|
=================
|
||
|
*/
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
double time;
|
||
|
int op;
|
||
|
long session;
|
||
|
int ret;
|
||
|
int len;
|
||
|
} vcrGetMessage;
|
||
|
|
||
|
extern void PrintStats(qsocket_t *s);
|
||
|
|
||
|
int NET_GetMessage (qsocket_t *sock)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
if (!sock)
|
||
|
return -1;
|
||
|
|
||
|
if (sock->disconnected)
|
||
|
{
|
||
|
Con_Printf("NET_GetMessage: disconnected socket\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
ret = sfunc.QGetMessage(sock);
|
||
|
|
||
|
// see if this connection has timed out
|
||
|
if (ret == 0 && sock->driver)
|
||
|
{
|
||
|
if (net_time - sock->lastMessageTime > net_messagetimeout.value)
|
||
|
{
|
||
|
NET_Close(sock);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (ret > 0)
|
||
|
{
|
||
|
if (sock->driver)
|
||
|
{
|
||
|
sock->lastMessageTime = net_time;
|
||
|
if (ret == 1)
|
||
|
messagesReceived++;
|
||
|
else if (ret == 2)
|
||
|
unreliableMessagesReceived++;
|
||
|
}
|
||
|
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrGetMessage.time = host_time;
|
||
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
||
|
vcrGetMessage.session = (long)sock;
|
||
|
vcrGetMessage.ret = ret;
|
||
|
vcrGetMessage.len = net_message.cursize;
|
||
|
Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
|
||
|
Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrGetMessage.time = host_time;
|
||
|
vcrGetMessage.op = VCR_OP_GETMESSAGE;
|
||
|
vcrGetMessage.session = (long)sock;
|
||
|
vcrGetMessage.ret = ret;
|
||
|
Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
NET_SendMessage
|
||
|
|
||
|
Try to send a complete length+message unit over the reliable stream.
|
||
|
returns 0 if the message cannot be delivered reliably, but the connection
|
||
|
is still considered valid
|
||
|
returns 1 if the message was sent properly
|
||
|
returns -1 if the connection died
|
||
|
==================
|
||
|
*/
|
||
|
struct
|
||
|
{
|
||
|
double time;
|
||
|
int op;
|
||
|
long session;
|
||
|
int r;
|
||
|
} vcrSendMessage;
|
||
|
|
||
|
int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
|
||
|
{
|
||
|
int r;
|
||
|
|
||
|
if (!sock)
|
||
|
return -1;
|
||
|
|
||
|
if (sock->disconnected)
|
||
|
{
|
||
|
Con_Printf("NET_SendMessage: disconnected socket\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
SetNetTime();
|
||
|
r = sfunc.QSendMessage(sock, data);
|
||
|
if (r == 1 && sock->driver)
|
||
|
messagesSent++;
|
||
|
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrSendMessage.time = host_time;
|
||
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
||
|
vcrSendMessage.session = (long)sock;
|
||
|
vcrSendMessage.r = r;
|
||
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
|
||
|
int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
|
||
|
{
|
||
|
int r;
|
||
|
|
||
|
if (!sock)
|
||
|
return -1;
|
||
|
|
||
|
if (sock->disconnected)
|
||
|
{
|
||
|
Con_Printf("NET_SendMessage: disconnected socket\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
SetNetTime();
|
||
|
r = sfunc.SendUnreliableMessage(sock, data);
|
||
|
if (r == 1 && sock->driver)
|
||
|
unreliableMessagesSent++;
|
||
|
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrSendMessage.time = host_time;
|
||
|
vcrSendMessage.op = VCR_OP_SENDMESSAGE;
|
||
|
vcrSendMessage.session = (long)sock;
|
||
|
vcrSendMessage.r = r;
|
||
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
NET_CanSendMessage
|
||
|
|
||
|
Returns true or false if the given qsocket can currently accept a
|
||
|
message to be transmitted.
|
||
|
==================
|
||
|
*/
|
||
|
qboolean NET_CanSendMessage (qsocket_t *sock)
|
||
|
{
|
||
|
int r;
|
||
|
|
||
|
if (!sock)
|
||
|
return false;
|
||
|
|
||
|
if (sock->disconnected)
|
||
|
return false;
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
r = sfunc.CanSendMessage(sock);
|
||
|
|
||
|
if (recording)
|
||
|
{
|
||
|
vcrSendMessage.time = host_time;
|
||
|
vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
|
||
|
vcrSendMessage.session = (long)sock;
|
||
|
vcrSendMessage.r = r;
|
||
|
Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
|
||
|
int NET_SendToAll(sizebuf_t *data, int blocktime)
|
||
|
{
|
||
|
double start;
|
||
|
int i;
|
||
|
int count = 0;
|
||
|
qboolean state1 [MAX_SCOREBOARD];
|
||
|
qboolean state2 [MAX_SCOREBOARD];
|
||
|
|
||
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
||
|
{
|
||
|
if (!host_client->netconnection)
|
||
|
continue;
|
||
|
if (host_client->active)
|
||
|
{
|
||
|
if (host_client->netconnection->driver == 0)
|
||
|
{
|
||
|
NET_SendMessage(host_client->netconnection, data);
|
||
|
state1[i] = true;
|
||
|
state2[i] = true;
|
||
|
continue;
|
||
|
}
|
||
|
count++;
|
||
|
state1[i] = false;
|
||
|
state2[i] = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
state1[i] = true;
|
||
|
state2[i] = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
start = Sys_FloatTime();
|
||
|
while (count)
|
||
|
{
|
||
|
count = 0;
|
||
|
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
|
||
|
{
|
||
|
if (! state1[i])
|
||
|
{
|
||
|
if (NET_CanSendMessage (host_client->netconnection))
|
||
|
{
|
||
|
state1[i] = true;
|
||
|
NET_SendMessage(host_client->netconnection, data);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NET_GetMessage (host_client->netconnection);
|
||
|
}
|
||
|
count++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (! state2[i])
|
||
|
{
|
||
|
if (NET_CanSendMessage (host_client->netconnection))
|
||
|
{
|
||
|
state2[i] = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NET_GetMessage (host_client->netconnection);
|
||
|
}
|
||
|
count++;
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
if ((Sys_FloatTime() - start) > blocktime)
|
||
|
break;
|
||
|
}
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
|
||
|
//=============================================================================
|
||
|
|
||
|
/*
|
||
|
====================
|
||
|
NET_Init
|
||
|
====================
|
||
|
*/
|
||
|
|
||
|
void NET_Init (void)
|
||
|
{
|
||
|
int i;
|
||
|
int controlSocket;
|
||
|
qsocket_t *s;
|
||
|
|
||
|
if (COM_CheckParm("-playback"))
|
||
|
{
|
||
|
net_numdrivers = 1;
|
||
|
net_drivers[0].Init = VCR_Init;
|
||
|
}
|
||
|
|
||
|
if (COM_CheckParm("-record"))
|
||
|
recording = true;
|
||
|
|
||
|
i = COM_CheckParm ("-port");
|
||
|
if (!i)
|
||
|
i = COM_CheckParm ("-udpport");
|
||
|
if (!i)
|
||
|
i = COM_CheckParm ("-ipxport");
|
||
|
|
||
|
if (i)
|
||
|
{
|
||
|
if (i < com_argc-1)
|
||
|
DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
|
||
|
else
|
||
|
Sys_Error ("NET_Init: you must specify a number after -port");
|
||
|
}
|
||
|
net_hostport = DEFAULTnet_hostport;
|
||
|
|
||
|
if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
|
||
|
listening = true;
|
||
|
net_numsockets = svs.maxclientslimit;
|
||
|
if (cls.state != ca_dedicated)
|
||
|
net_numsockets++;
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
for (i = 0; i < net_numsockets; i++)
|
||
|
{
|
||
|
s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
|
||
|
s->next = net_freeSockets;
|
||
|
net_freeSockets = s;
|
||
|
s->disconnected = true;
|
||
|
}
|
||
|
|
||
|
// allocate space for network message buffer
|
||
|
SZ_Alloc (&net_message, NET_MAXMESSAGE);
|
||
|
|
||
|
Cvar_RegisterVariable (&net_messagetimeout);
|
||
|
Cvar_RegisterVariable (&hostname);
|
||
|
Cvar_RegisterVariable (&config_com_port);
|
||
|
Cvar_RegisterVariable (&config_com_irq);
|
||
|
Cvar_RegisterVariable (&config_com_baud);
|
||
|
Cvar_RegisterVariable (&config_com_modem);
|
||
|
Cvar_RegisterVariable (&config_modem_dialtype);
|
||
|
Cvar_RegisterVariable (&config_modem_clear);
|
||
|
Cvar_RegisterVariable (&config_modem_init);
|
||
|
Cvar_RegisterVariable (&config_modem_hangup);
|
||
|
#ifdef IDGODS
|
||
|
Cvar_RegisterVariable (&idgods);
|
||
|
#endif
|
||
|
|
||
|
Cmd_AddCommand ("slist", NET_Slist_f);
|
||
|
Cmd_AddCommand ("listen", NET_Listen_f);
|
||
|
Cmd_AddCommand ("maxplayers", MaxPlayers_f);
|
||
|
Cmd_AddCommand ("port", NET_Port_f);
|
||
|
|
||
|
// initialize all the drivers
|
||
|
for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
|
||
|
{
|
||
|
controlSocket = net_drivers[net_driverlevel].Init();
|
||
|
if (controlSocket == -1)
|
||
|
continue;
|
||
|
net_drivers[net_driverlevel].initialized = true;
|
||
|
net_drivers[net_driverlevel].controlSock = controlSocket;
|
||
|
if (listening)
|
||
|
net_drivers[net_driverlevel].Listen (true);
|
||
|
}
|
||
|
|
||
|
if (*my_ipx_address)
|
||
|
Con_DPrintf("IPX address %s\n", my_ipx_address);
|
||
|
if (*my_tcpip_address)
|
||
|
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
====================
|
||
|
NET_Shutdown
|
||
|
====================
|
||
|
*/
|
||
|
|
||
|
void NET_Shutdown (void)
|
||
|
{
|
||
|
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 != -1)
|
||
|
{
|
||
|
Con_Printf ("Closing vcrfile.\n");
|
||
|
Sys_FileClose(vcrFile);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static PollProcedure *pollProcedureList = NULL;
|
||
|
|
||
|
void NET_Poll(void)
|
||
|
{
|
||
|
PollProcedure *pp;
|
||
|
qboolean useModem;
|
||
|
|
||
|
if (!configRestored)
|
||
|
{
|
||
|
if (serialAvailable)
|
||
|
{
|
||
|
if (config_com_modem.value == 1.0)
|
||
|
useModem = true;
|
||
|
else
|
||
|
useModem = false;
|
||
|
SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
|
||
|
SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
|
||
|
}
|
||
|
configRestored = true;
|
||
|
}
|
||
|
|
||
|
SetNetTime();
|
||
|
|
||
|
for (pp = pollProcedureList; pp; pp = pp->next)
|
||
|
{
|
||
|
if (pp->nextTime > net_time)
|
||
|
break;
|
||
|
pollProcedureList = pp->next;
|
||
|
pp->procedure(pp->arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
|
||
|
{
|
||
|
PollProcedure *pp, *prev;
|
||
|
|
||
|
proc->nextTime = Sys_FloatTime() + timeOffset;
|
||
|
for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
|
||
|
{
|
||
|
if (pp->nextTime >= proc->nextTime)
|
||
|
break;
|
||
|
prev = pp;
|
||
|
}
|
||
|
|
||
|
if (prev == NULL)
|
||
|
{
|
||
|
proc->next = pollProcedureList;
|
||
|
pollProcedureList = proc;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
proc->next = pp;
|
||
|
prev->next = proc;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef IDGODS
|
||
|
#define IDNET 0xc0f62800
|
||
|
|
||
|
qboolean IsID(struct qsockaddr *addr)
|
||
|
{
|
||
|
if (idgods.value == 0.0)
|
||
|
return false;
|
||
|
|
||
|
if (addr->sa_family != 2)
|
||
|
return false;
|
||
|
|
||
|
if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|