mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-27 14:12:25 +00:00
259 lines
5 KiB
C
259 lines
5 KiB
C
|
#include "qwsvdef.h"
|
||
|
|
||
|
#ifdef SV_MASTER
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#include "winquake.h"
|
||
|
#ifdef _MSC_VER
|
||
|
#include "wsipx.h"
|
||
|
#endif
|
||
|
|
||
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||
|
#define EMSGSIZE WSAEMSGSIZE
|
||
|
#define ECONNRESET WSAECONNRESET
|
||
|
#define ECONNABORTED WSAECONNABORTED
|
||
|
#define ECONNREFUSED WSAECONNREFUSED
|
||
|
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
||
|
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
||
|
|
||
|
#else
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <netdb.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <sys/uio.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#if defined(sun)
|
||
|
#include <unistd.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef sun
|
||
|
#include <sys/filio.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef NeXT
|
||
|
#include <libc.h>
|
||
|
#endif
|
||
|
|
||
|
#define closesocket close
|
||
|
#define ioctlsocket ioctl
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//quake1 protocol
|
||
|
//
|
||
|
//
|
||
|
|
||
|
//quake2 protocol
|
||
|
//client sends "query\0"
|
||
|
//server sends "0xff0xff0xff0xffservers" follwed by lots of ips.
|
||
|
|
||
|
#define SVM_Q1HEARTBEATTIME 330
|
||
|
#define SVM_Q2HEARTBEATTIME 330
|
||
|
|
||
|
typedef struct svm_server_s {
|
||
|
netadr_t adr;
|
||
|
int clients;
|
||
|
float expiretime;
|
||
|
struct svm_server_s *next;
|
||
|
} svm_server_t;
|
||
|
|
||
|
typedef struct {
|
||
|
float time;
|
||
|
int port;
|
||
|
int socketudp;
|
||
|
|
||
|
svm_server_t *firstserver;
|
||
|
int numservers;
|
||
|
} masterserver_t;
|
||
|
|
||
|
masterserver_t svm;
|
||
|
|
||
|
void SVM_RemoveOldServers(void)
|
||
|
{
|
||
|
svm_server_t *server, *next, *prev=NULL;
|
||
|
for (server = svm.firstserver; server; server = next)
|
||
|
{
|
||
|
next = server->next;
|
||
|
if (server->expiretime < svm.time)
|
||
|
{
|
||
|
BZ_Free(server);
|
||
|
if (prev)
|
||
|
prev->next = next;
|
||
|
else
|
||
|
svm.firstserver = next;
|
||
|
}
|
||
|
else
|
||
|
prev = server;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int SVM_AddIPAddresses(sizebuf_t *sb, int first)
|
||
|
{
|
||
|
int number = 0;
|
||
|
svm_server_t *server;
|
||
|
|
||
|
for (server = svm.firstserver; server; server = server->next)
|
||
|
{
|
||
|
if (number == first)
|
||
|
break;
|
||
|
|
||
|
first--;
|
||
|
}
|
||
|
|
||
|
for (; server; server = server->next)
|
||
|
{
|
||
|
if (sb->cursize + 6 >= sb->maxsize)
|
||
|
break;
|
||
|
|
||
|
MSG_WriteByte(sb, server->adr.ip[0]);
|
||
|
MSG_WriteByte(sb, server->adr.ip[1]);
|
||
|
MSG_WriteByte(sb, server->adr.ip[2]);
|
||
|
MSG_WriteByte(sb, server->adr.ip[3]);
|
||
|
MSG_WriteShort(sb, server->adr.port);
|
||
|
|
||
|
number++;
|
||
|
}
|
||
|
|
||
|
return number;
|
||
|
}
|
||
|
|
||
|
void SVM_Heartbeat(netadr_t *adr, int numclients, float validuntil)
|
||
|
{
|
||
|
svm_server_t *server;
|
||
|
|
||
|
for (server = svm.firstserver; server; server = server->next)
|
||
|
{
|
||
|
if (NET_CompareAdr(server->adr , *adr))
|
||
|
break;
|
||
|
}
|
||
|
if (!server) //not found
|
||
|
{
|
||
|
server = Z_Malloc(sizeof(svm_server_t));
|
||
|
server->next = svm.firstserver;
|
||
|
svm.firstserver = server;
|
||
|
|
||
|
server->adr = *adr;
|
||
|
}
|
||
|
|
||
|
server->clients = numclients;
|
||
|
server->expiretime = validuntil;
|
||
|
}
|
||
|
|
||
|
|
||
|
void SVM_Init(int port)
|
||
|
{
|
||
|
if (!svm.socketudp)
|
||
|
svm.socketudp = UDP_OpenSocket(port, false);
|
||
|
}
|
||
|
|
||
|
void SVM_ShutDown (void)
|
||
|
{
|
||
|
if (svm.socketudp)
|
||
|
UDP_CloseSocket(svm.socketudp);
|
||
|
}
|
||
|
|
||
|
void SVM_Think(int port)
|
||
|
{
|
||
|
char *s;
|
||
|
struct sockaddr_qstorage addr;
|
||
|
int addrlen;
|
||
|
netadr_t netaddr;
|
||
|
if (!port)
|
||
|
{
|
||
|
SVM_ShutDown();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (port != svm.port)
|
||
|
{
|
||
|
SVM_ShutDown(); //shut down (to cause a restart)
|
||
|
svm.port = port;
|
||
|
}
|
||
|
|
||
|
SVM_Init(port);
|
||
|
|
||
|
addrlen = sizeof(addr);
|
||
|
net_message.cursize = recvfrom(svm.socketudp, net_message_buffer, sizeof(net_message_buffer)-1, 0, (struct sockaddr *)&addr, &addrlen);
|
||
|
net_message.data[net_message.cursize] = '\0'; //null term all strings.
|
||
|
if (net_message.cursize < 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
SockadrToNetadr(&addr, &netaddr);
|
||
|
svm.time = Sys_DoubleTime();
|
||
|
|
||
|
SVM_RemoveOldServers();
|
||
|
|
||
|
MSG_BeginReading();
|
||
|
if (MSG_ReadLong() != -1 || msg_badread)
|
||
|
{ //go back to start...
|
||
|
MSG_BeginReading();
|
||
|
}
|
||
|
s = MSG_ReadStringLine();
|
||
|
s = COM_Parse(s);
|
||
|
if (!strcmp(com_token, "getservers"))
|
||
|
{
|
||
|
sizebuf_t sb;
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
sb.maxsize = sizeof(net_message_buffer)-2;
|
||
|
sb.data = net_message_buffer;
|
||
|
MSG_WriteLong(&sb, -1);
|
||
|
MSG_WriteString(&sb, "getserversResponse\\");
|
||
|
sb.cursize--;
|
||
|
SVM_AddIPAddresses(&sb, 0);
|
||
|
sb.maxsize+=2;
|
||
|
MSG_WriteShort(&sb, 0);
|
||
|
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||
|
}
|
||
|
else if (!strcmp(com_token, "heartbeat"))
|
||
|
{ //quake2 heartbeat. Serverinfo and players follow.
|
||
|
SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q2HEARTBEATTIME);
|
||
|
}
|
||
|
else if (!strcmp(com_token, "query"))
|
||
|
{ //quake2 server listing request
|
||
|
sizebuf_t sb;
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
sb.maxsize = sizeof(net_message_buffer);
|
||
|
sb.data = net_message_buffer;
|
||
|
MSG_WriteLong(&sb, -1);
|
||
|
MSG_WriteString(&sb, "servers\n");
|
||
|
sb.cursize--;
|
||
|
// MSG_WriteLong(&sb, 0);
|
||
|
// MSG_WriteShort(&sb, 0);
|
||
|
SVM_AddIPAddresses(&sb, 0);
|
||
|
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||
|
}
|
||
|
else if (*com_token == S2M_HEARTBEAT) //sequence, players
|
||
|
{ //quakeworld heartbeat
|
||
|
SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q1HEARTBEATTIME);
|
||
|
}
|
||
|
else if (*com_token == S2C_CHALLENGE)
|
||
|
{ //quakeworld server listing request
|
||
|
sizebuf_t sb;
|
||
|
memset(&sb, 0, sizeof(sb));
|
||
|
sb.maxsize = sizeof(net_message_buffer);
|
||
|
sb.data = net_message_buffer;
|
||
|
MSG_WriteLong(&sb, -1);
|
||
|
MSG_WriteByte(&sb, M2C_MASTER_REPLY);
|
||
|
MSG_WriteByte(&sb, '\n');
|
||
|
SVM_AddIPAddresses(&sb, 0);
|
||
|
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr));
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
void SVM_Think(int port){}
|
||
|
#endif
|