spingle/source/net_main.c

908 lines
17 KiB
C
Raw Normal View History

2019-11-24 20:45:15 -08:00
/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2010-2014 QuakeSpasm developers
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.
*/
#include "q_stdinc.h"
#include "net_sys.h"
2019-12-02 07:07:37 -08:00
#include "q_defs.h"
2019-11-24 20:45:15 -08:00
#include "net_defs.h"
2019-11-25 17:40:18 -08:00
qsocket_t *net_activeSockets = NULL;
qsocket_t *net_freeSockets = NULL;
int32_t net_numsockets = 0;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
bool ipxAvailable = false;
bool tcpipAvailable = false;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
int32_t net_hostport;
int32_t DEFAULTnet_hostport = 26000;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
char my_ipx_address[NET_NAMELEN];
char my_tcpip_address[NET_NAMELEN];
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
static bool listening = false;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
bool slistInProgress = false;
bool slistSilent = false;
bool slistLocal = true;
static double slistStartTime;
static int32_t slistLastShown;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
static void Slist_Send(void *);
static void Slist_Poll(void *);
static PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
static PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
sizebuf_t net_message;
int32_t net_activeconnections = 0;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
int32_t messagesSent = 0;
int32_t messagesReceived = 0;
int32_t unreliableMessagesSent = 0;
int32_t unreliableMessagesReceived = 0;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
static cvar_t net_messagetimeout = {"net_messagetimeout", "300", CVAR_NONE};
cvar_t hostname = {"hostname", "UNNAMED", CVAR_NONE};
2019-11-24 20:45:15 -08:00
// these two macros are to make the code more readable
2019-11-25 17:40:18 -08:00
#define sfunc net_drivers[sock->driver]
#define dfunc net_drivers[net_driverlevel]
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
int32_t net_driverlevel;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
double net_time;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
double SetNetTime(void)
2019-11-24 20:45:15 -08:00
{
net_time = Sys_DoubleTime();
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
===================
*/
2019-11-25 17:40:18 -08:00
qsocket_t *NET_NewQSocket(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
qsocket_t *sock;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(net_freeSockets == NULL)
2019-11-24 20:45:15 -08:00
return NULL;
2019-11-25 17:40:18 -08:00
if(net_activeconnections >= svs.maxclients)
2019-11-24 20:45:15 -08:00
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;
2019-11-25 17:40:18 -08:00
Q_strcpy(sock->address, "UNSET ADDRESS");
2019-11-24 20:45:15 -08: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;
}
void NET_FreeQSocket(qsocket_t *sock)
{
2019-11-25 17:40:18 -08:00
qsocket_t *s;
2019-11-24 20:45:15 -08:00
// remove it from active list
2019-11-25 17:40:18 -08:00
if(sock == net_activeSockets)
2019-11-24 20:45:15 -08:00
net_activeSockets = net_activeSockets->next;
else
{
2019-11-25 17:40:18 -08:00
for(s = net_activeSockets; s; s = s->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(s->next == sock)
2019-11-24 20:45:15 -08:00
{
s->next = sock->next;
break;
}
}
2019-11-25 17:40:18 -08:00
if(!s)
Sys_Error("NET_FreeQSocket: not active");
2019-11-24 20:45:15 -08:00
}
// add it to free list
sock->next = net_freeSockets;
net_freeSockets = sock;
sock->disconnected = true;
}
2019-11-25 17:40:18 -08:00
double NET_QSocketGetTime(const qsocket_t *s)
2019-11-24 20:45:15 -08:00
{
return s->connecttime;
}
2019-11-25 17:40:18 -08:00
const char *NET_QSocketGetAddressString(const qsocket_t *s)
2019-11-24 20:45:15 -08:00
{
return s->address;
}
2019-11-25 17:40:18 -08:00
static void NET_Listen_f(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(Cmd_Argc() != 2)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf("\"listen\" is \"%" PRIi32 "\"\n", listening ? 1 : 0);
2019-11-24 20:45:15 -08:00
return;
}
listening = Q_atoi(Cmd_Argv(1)) ? true : false;
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
dfunc.Listen(listening);
2019-11-24 20:45:15 -08:00
}
}
2019-11-25 17:40:18 -08:00
static void MaxPlayers_f(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t n;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(Cmd_Argc() != 2)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf("\"maxplayers\" is \"%" PRIi32 "\"\n", svs.maxclients);
2019-11-24 20:45:15 -08:00
return;
}
2019-11-25 17:40:18 -08:00
if(sv.active)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf("maxplayers can not be changed while a server is running.\n");
2019-11-24 20:45:15 -08:00
return;
}
n = Q_atoi(Cmd_Argv(1));
2019-11-25 17:40:18 -08:00
if(n < 1)
2019-11-24 20:45:15 -08:00
n = 1;
2019-11-25 17:40:18 -08:00
if(n > svs.maxclientslimit)
2019-11-24 20:45:15 -08:00
{
n = svs.maxclientslimit;
2019-11-25 17:40:18 -08:00
Con_Printf("\"maxplayers\" set to \"%" PRIi32 "\"\n", n);
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
if((n == 1) && listening)
Cbuf_AddText("listen 0\n");
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if((n > 1) && (!listening))
Cbuf_AddText("listen 1\n");
2019-11-24 20:45:15 -08:00
svs.maxclients = n;
2019-11-25 17:40:18 -08:00
if(n == 1)
Cvar_Set("deathmatch", "0");
2019-11-24 20:45:15 -08:00
else
2019-11-25 17:40:18 -08:00
Cvar_Set("deathmatch", "1");
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
static void NET_Port_f(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t n;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(Cmd_Argc() != 2)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf("\"port\" is \"%" PRIi32 "\"\n", net_hostport);
2019-11-24 20:45:15 -08:00
return;
}
n = Q_atoi(Cmd_Argv(1));
2019-11-25 17:40:18 -08:00
if(n < 1 || n > 65534)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
Con_Printf("Bad value, must be between 1 and 65534\n");
2019-11-24 20:45:15 -08:00
return;
}
DEFAULTnet_hostport = n;
net_hostport = n;
2019-11-25 17:40:18 -08:00
if(listening)
2019-11-24 20:45:15 -08:00
{
// force a change to the new port
2019-11-25 17:40:18 -08:00
Cbuf_AddText("listen 0\n");
Cbuf_AddText("listen 1\n");
2019-11-24 20:45:15 -08:00
}
}
static void PrintSlistHeader(void)
{
Con_Printf("Server Map Users\n");
Con_Printf("--------------- --------------- -----\n");
slistLastShown = 0;
}
static void PrintSlist(void)
{
2019-11-25 17:40:18 -08:00
int32_t n;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(n = slistLastShown; n < hostCacheCount; n++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(hostcache[n].maxusers)
2019-11-25 17:29:41 -08:00
Con_Printf("%-15.15s %-15.15s %2" PRIu32 "/%2" PRIu32 "\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
2019-11-24 20:45:15 -08:00
else
Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
}
slistLastShown = n;
}
static void PrintSlistTrailer(void)
{
2019-11-25 17:40:18 -08:00
if(hostCacheCount)
2019-11-24 20:45:15 -08:00
Con_Printf("== end list ==\n\n");
else
Con_Printf("No Quake servers found.\n\n");
}
2019-11-25 17:40:18 -08:00
void NET_Slist_f(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(slistInProgress)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
if(! slistSilent)
2019-11-24 20:45:15 -08:00
{
Con_Printf("Looking for Quake servers...\n");
PrintSlistHeader();
}
slistInProgress = true;
slistStartTime = Sys_DoubleTime();
SchedulePollProcedure(&slistSendProcedure, 0.0);
SchedulePollProcedure(&slistPollProcedure, 0.1);
hostCacheCount = 0;
}
2019-11-25 17:40:18 -08:00
void NET_SlistSort(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(hostCacheCount > 1)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i, j;
2019-11-24 20:45:15 -08:00
hostcache_t temp;
2019-11-25 17:40:18 -08:00
for(i = 0; i < hostCacheCount; i++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(j = i + 1; j < hostCacheCount; j++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(strcmp(hostcache[j].name, hostcache[i].name) < 0)
2019-11-24 20:45:15 -08:00
{
memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
}
}
}
}
}
2019-11-25 17:40:18 -08:00
const char *NET_SlistPrintServer(int32_t idx)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
static char string[64];
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(idx < 0 || idx >= hostCacheCount)
2019-11-24 20:45:15 -08:00
return "";
2019-11-25 17:40:18 -08:00
if(hostcache[idx].maxusers)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:29:41 -08:00
q_snprintf(string, sizeof(string), "%-15.15s %-15.15s %2" PRIu32 "/%2" PRIu32 "\n",
2019-11-25 17:40:18 -08:00
hostcache[idx].name, hostcache[idx].map,
hostcache[idx].users, hostcache[idx].maxusers);
2019-11-24 20:45:15 -08:00
}
else
{
q_snprintf(string, sizeof(string), "%-15.15s %-15.15s\n",
2019-11-25 17:40:18 -08:00
hostcache[idx].name, hostcache[idx].map);
2019-11-24 20:45:15 -08:00
}
return string;
}
2019-11-25 17:40:18 -08:00
const char *NET_SlistPrintServerName(int32_t idx)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(idx < 0 || idx >= hostCacheCount)
2019-11-24 20:45:15 -08:00
return "";
return hostcache[idx].cname;
}
2019-11-25 17:40:18 -08:00
static void Slist_Send(void *unused)
2019-11-24 20:45:15 -08:00
{
2019-11-25 13:20:03 -08:00
(void)unused;
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!slistLocal && IS_LOOP_DRIVER(net_driverlevel))
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
dfunc.SearchForHosts(true);
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
if((Sys_DoubleTime() - slistStartTime) < 0.5)
2019-11-24 20:45:15 -08:00
SchedulePollProcedure(&slistSendProcedure, 0.75);
}
2019-11-25 17:40:18 -08:00
static void Slist_Poll(void *unused)
2019-11-24 20:45:15 -08:00
{
2019-11-25 13:20:03 -08:00
(void)unused;
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!slistLocal && IS_LOOP_DRIVER(net_driverlevel))
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
dfunc.SearchForHosts(false);
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
if(! slistSilent)
2019-11-24 20:45:15 -08:00
PrintSlist();
2019-11-25 17:40:18 -08:00
if((Sys_DoubleTime() - slistStartTime) < 1.5)
2019-11-24 20:45:15 -08:00
{
SchedulePollProcedure(&slistPollProcedure, 0.1);
return;
}
2019-11-25 17:40:18 -08:00
if(! slistSilent)
2019-11-24 20:45:15 -08:00
PrintSlistTrailer();
slistInProgress = false;
slistSilent = false;
slistLocal = true;
}
/*
===================
NET_Connect
===================
*/
2019-11-25 16:49:58 -08:00
int32_t hostCacheCount = 0;
2019-11-24 20:45:15 -08:00
hostcache_t hostcache[HOSTCACHESIZE];
2019-11-25 17:40:18 -08:00
qsocket_t *NET_Connect(const char *host)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
qsocket_t *ret;
int32_t n;
int32_t numdrivers = net_numdrivers;
2019-11-24 20:45:15 -08:00
SetNetTime();
2019-11-25 17:40:18 -08:00
if(host && *host == 0)
2019-11-24 20:45:15 -08:00
host = NULL;
2019-11-25 17:40:18 -08:00
if(host)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(q_strcasecmp(host, "local") == 0)
2019-11-24 20:45:15 -08:00
{
numdrivers = 1;
goto JustDoIt;
}
2019-11-25 17:40:18 -08:00
if(hostCacheCount)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(n = 0; n < hostCacheCount; n++)
if(q_strcasecmp(host, hostcache[n].name) == 0)
2019-11-24 20:45:15 -08:00
{
host = hostcache[n].cname;
break;
}
2019-11-25 17:40:18 -08:00
if(n < hostCacheCount)
2019-11-24 20:45:15 -08:00
goto JustDoIt;
}
}
slistSilent = host ? true : false;
2019-11-25 17:40:18 -08:00
NET_Slist_f();
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
while(slistInProgress)
2019-11-24 20:45:15 -08:00
NET_Poll();
2019-11-25 17:40:18 -08:00
if(host == NULL)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(hostCacheCount != 1)
2019-11-24 20:45:15 -08:00
return NULL;
host = hostcache[0].cname;
Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
}
2019-11-25 17:40:18 -08:00
if(hostCacheCount)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(n = 0; n < hostCacheCount; n++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(q_strcasecmp(host, hostcache[n].name) == 0)
2019-11-24 20:45:15 -08:00
{
host = hostcache[n].cname;
break;
}
}
}
JustDoIt:
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
ret = dfunc.Connect(host);
if(ret)
2019-11-24 20:45:15 -08:00
return ret;
}
2019-11-25 17:40:18 -08:00
if(host)
2019-11-24 20:45:15 -08:00
{
Con_Printf("\n");
PrintSlistHeader();
PrintSlist();
PrintSlistTrailer();
}
return NULL;
}
/*
===================
NET_CheckNewConnections
===================
*/
2019-11-25 17:40:18 -08:00
qsocket_t *NET_CheckNewConnections(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
qsocket_t *ret;
2019-11-24 20:45:15 -08:00
SetNetTime();
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
if(!IS_LOOP_DRIVER(net_driverlevel) && listening == false)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
ret = dfunc.CheckNewConnections();
if(ret)
2019-11-24 20:45:15 -08:00
{
return ret;
}
}
return NULL;
}
/*
===================
NET_Close
===================
*/
2019-11-25 17:40:18 -08:00
void NET_Close(qsocket_t *sock)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!sock)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
if(sock->disconnected)
2019-11-24 20:45:15 -08:00
return;
SetNetTime();
// call the driver_Close function
2019-11-25 17:40:18 -08:00
sfunc.Close(sock);
2019-11-24 20:45:15 -08:00
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
=================
*/
2019-11-25 17:40:18 -08:00
int32_t NET_GetMessage(qsocket_t *sock)
2019-11-24 20:45:15 -08:00
{
2019-11-25 16:49:58 -08:00
int32_t ret;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(!sock)
2019-11-24 20:45:15 -08:00
return -1;
2019-11-25 17:40:18 -08:00
if(sock->disconnected)
2019-11-24 20:45:15 -08:00
{
Con_Printf("NET_GetMessage: disconnected socket\n");
return -1;
}
SetNetTime();
ret = sfunc.QGetMessage(sock);
// see if this connection has timed out
2019-11-25 17:40:18 -08:00
if(ret == 0 && !IS_LOOP_DRIVER(sock->driver))
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_time - sock->lastMessageTime > net_messagetimeout.value)
2019-11-24 20:45:15 -08:00
{
NET_Close(sock);
return -1;
}
}
2019-11-25 17:40:18 -08:00
if(ret > 0)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!IS_LOOP_DRIVER(sock->driver))
2019-11-24 20:45:15 -08:00
{
sock->lastMessageTime = net_time;
2019-11-25 17:40:18 -08:00
if(ret == 1)
2019-11-24 20:45:15 -08:00
messagesReceived++;
2019-11-25 17:40:18 -08:00
else if(ret == 2)
2019-11-24 20:45:15 -08:00
unreliableMessagesReceived++;
}
}
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
2019-11-25 17:40:18 -08:00
is still considered valid
2019-11-24 20:45:15 -08:00
returns 1 if the message was sent properly
returns -1 if the connection died
==================
*/
2019-11-25 17:40:18 -08:00
int32_t NET_SendMessage(qsocket_t *sock, sizebuf_t *data)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t r;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(!sock)
2019-11-24 20:45:15 -08:00
return -1;
2019-11-25 17:40:18 -08:00
if(sock->disconnected)
2019-11-24 20:45:15 -08:00
{
Con_Printf("NET_SendMessage: disconnected socket\n");
return -1;
}
SetNetTime();
r = sfunc.QSendMessage(sock, data);
2019-11-25 17:40:18 -08:00
if(r == 1 && !IS_LOOP_DRIVER(sock->driver))
2019-11-24 20:45:15 -08:00
messagesSent++;
return r;
}
2019-11-25 17:40:18 -08:00
int32_t NET_SendUnreliableMessage(qsocket_t *sock, sizebuf_t *data)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t r;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(!sock)
2019-11-24 20:45:15 -08:00
return -1;
2019-11-25 17:40:18 -08:00
if(sock->disconnected)
2019-11-24 20:45:15 -08:00
{
Con_Printf("NET_SendMessage: disconnected socket\n");
return -1;
}
SetNetTime();
r = sfunc.SendUnreliableMessage(sock, data);
2019-11-25 17:40:18 -08:00
if(r == 1 && !IS_LOOP_DRIVER(sock->driver))
2019-11-24 20:45:15 -08:00
unreliableMessagesSent++;
return r;
}
/*
==================
NET_CanSendMessage
Returns true or false if the given qsocket can currently accept a
message to be transmitted.
==================
*/
2019-11-25 17:40:18 -08:00
bool NET_CanSendMessage(qsocket_t *sock)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!sock)
2019-11-24 20:45:15 -08:00
return false;
2019-11-25 17:40:18 -08:00
if(sock->disconnected)
2019-11-24 20:45:15 -08:00
return false;
SetNetTime();
return sfunc.CanSendMessage(sock);
}
2019-11-25 17:40:18 -08:00
int32_t NET_SendToAll(sizebuf_t *data, double blocktime)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
double start;
int32_t i;
int32_t count = 0;
bool msg_init[MAX_SCOREBOARD]; /* did we write the message to the client's connection */
bool msg_sent[MAX_SCOREBOARD]; /* did the msg arrive its destination (canSend state). */
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
2019-11-24 20:45:15 -08:00
{
/*
if (!host_client->netconnection)
2019-11-25 17:40:18 -08:00
continue;
2019-11-24 20:45:15 -08:00
if (host_client->active)
*/
2019-11-25 17:40:18 -08:00
if(host_client->netconnection && host_client->active)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(IS_LOOP_DRIVER(host_client->netconnection->driver))
2019-11-24 20:45:15 -08:00
{
NET_SendMessage(host_client->netconnection, data);
msg_init[i] = true;
msg_sent[i] = true;
continue;
}
count++;
msg_init[i] = false;
msg_sent[i] = false;
}
else
{
msg_init[i] = true;
msg_sent[i] = true;
}
}
start = Sys_DoubleTime();
2019-11-25 17:40:18 -08:00
while(count)
2019-11-24 20:45:15 -08:00
{
count = 0;
2019-11-25 17:40:18 -08:00
for(i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(! msg_init[i])
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(NET_CanSendMessage(host_client->netconnection))
2019-11-24 20:45:15 -08:00
{
msg_init[i] = true;
NET_SendMessage(host_client->netconnection, data);
}
else
{
2019-11-25 17:40:18 -08:00
NET_GetMessage(host_client->netconnection);
2019-11-24 20:45:15 -08:00
}
count++;
continue;
}
2019-11-25 17:40:18 -08:00
if(! msg_sent[i])
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(NET_CanSendMessage(host_client->netconnection))
2019-11-24 20:45:15 -08:00
{
msg_sent[i] = true;
}
else
{
2019-11-25 17:40:18 -08:00
NET_GetMessage(host_client->netconnection);
2019-11-24 20:45:15 -08:00
}
count++;
continue;
}
}
2019-11-25 17:40:18 -08:00
if((Sys_DoubleTime() - start) > blocktime)
2019-11-24 20:45:15 -08:00
break;
}
return count;
}
//=============================================================================
/*
====================
NET_Init
====================
*/
2019-11-25 17:40:18 -08:00
void NET_Init(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
qsocket_t *s;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
i = COM_CheckParm("-port");
if(!i)
i = COM_CheckParm("-udpport");
if(!i)
i = COM_CheckParm("-ipxport");
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(i)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(i < com_argc - 1)
DEFAULTnet_hostport = Q_atoi(com_argv[i + 1]);
2019-11-24 20:45:15 -08:00
else
2019-11-25 17:40:18 -08:00
Sys_Error("NET_Init: you must specify a number after -port");
2019-11-24 20:45:15 -08:00
}
net_hostport = DEFAULTnet_hostport;
net_numsockets = svs.maxclientslimit;
2019-11-25 17:40:18 -08:00
if(cls.state != ca_dedicated)
2019-11-24 20:45:15 -08:00
net_numsockets++;
2019-11-25 17:40:18 -08:00
if(COM_CheckParm("-listen") || cls.state == ca_dedicated)
2019-11-24 20:45:15 -08:00
listening = true;
SetNetTime();
2019-11-25 17:40:18 -08:00
for(i = 0; i < net_numsockets; i++)
2019-11-24 20:45:15 -08:00
{
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
2019-11-25 17:40:18 -08:00
SZ_Alloc(&net_message, NET_MAXMESSAGE);
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
Cvar_RegisterVariable(&net_messagetimeout);
Cvar_RegisterVariable(&hostname);
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
Cmd_AddCommand("slist", NET_Slist_f);
Cmd_AddCommand("listen", NET_Listen_f);
Cmd_AddCommand("maxplayers", MaxPlayers_f);
Cmd_AddCommand("port", NET_Port_f);
2019-11-24 20:45:15 -08:00
// initialize all the drivers
2019-11-25 17:40:18 -08:00
for(i = net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].Init() == -1)
2019-11-24 20:45:15 -08:00
continue;
i++;
net_drivers[net_driverlevel].initialized = true;
2019-11-25 17:40:18 -08:00
if(listening)
net_drivers[net_driverlevel].Listen(true);
2019-11-24 20:45:15 -08:00
}
/* Loop_Init() returns -1 for dedicated server case,
* therefore the i == 0 check is correct */
2019-11-25 17:40:18 -08:00
if(i == 0
&& cls.state == ca_dedicated
)
2019-11-24 20:45:15 -08:00
{
Sys_Error("Network not available!");
}
2019-11-25 17:40:18 -08:00
if(*my_ipx_address)
2019-11-24 20:45:15 -08:00
{
Con_DPrintf("IPX address %s\n", my_ipx_address);
}
2019-11-25 17:40:18 -08:00
if(*my_tcpip_address)
2019-11-24 20:45:15 -08:00
{
Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
}
}
/*
====================
NET_Shutdown
====================
*/
2019-11-25 17:40:18 -08:00
void NET_Shutdown(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
qsocket_t *sock;
2019-11-24 20:45:15 -08:00
SetNetTime();
2019-11-25 17:40:18 -08:00
for(sock = net_activeSockets; sock; sock = sock->next)
2019-11-24 20:45:15 -08:00
NET_Close(sock);
//
// shutdown the drivers
//
2019-11-25 17:40:18 -08:00
for(net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(net_drivers[net_driverlevel].initialized == true)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
net_drivers[net_driverlevel].Shutdown();
2019-11-24 20:45:15 -08:00
net_drivers[net_driverlevel].initialized = false;
}
}
}
static PollProcedure *pollProcedureList = NULL;
void NET_Poll(void)
{
PollProcedure *pp;
SetNetTime();
2019-11-25 17:40:18 -08:00
for(pp = pollProcedureList; pp; pp = pp->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(pp->nextTime > net_time)
2019-11-24 20:45:15 -08:00
break;
pollProcedureList = pp->next;
pp->procedure(pp->arg);
}
}
void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
{
PollProcedure *pp, *prev;
proc->nextTime = Sys_DoubleTime() + timeOffset;
2019-11-25 17:40:18 -08:00
for(pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(pp->nextTime >= proc->nextTime)
2019-11-24 20:45:15 -08:00
break;
prev = pp;
}
2019-11-25 17:40:18 -08:00
if(prev == NULL)
2019-11-24 20:45:15 -08:00
{
proc->next = pollProcedureList;
pollProcedureList = proc;
return;
}
proc->next = pp;
prev->next = proc;
}