mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-11 07:42:18 +00:00
577 lines
11 KiB
C
577 lines
11 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "QF/cbuf.h"
|
|
#include "QF/cmd.h"
|
|
#include "QF/console.h"
|
|
#include "QF/cvar.h"
|
|
#include "QF/idparse.h"
|
|
#include "QF/msg.h"
|
|
#include "QF/plugin.h"
|
|
#include "QF/qargs.h"
|
|
#include "QF/sizebuf.h"
|
|
#include "QF/sys.h"
|
|
#include "netchan.h"
|
|
#include "defs.h"
|
|
|
|
int sv_mode;
|
|
|
|
qboolean is_server = true;
|
|
|
|
static cbuf_t *mst_cbuf;
|
|
|
|
cvar_t *sv_console_plugin;
|
|
|
|
SERVER_PLUGIN_PROTOS
|
|
static plugin_list_t server_plugin_list[] = {
|
|
SERVER_PLUGIN_LIST
|
|
};
|
|
|
|
|
|
typedef struct filter_s {
|
|
netadr_t from;
|
|
netadr_t to;
|
|
struct filter_s *next;
|
|
struct filter_s *previous;
|
|
} filter_t;
|
|
|
|
filter_t *filter_list = NULL;
|
|
|
|
static void
|
|
FL_Remove (filter_t * filter)
|
|
{
|
|
if (filter->previous)
|
|
filter->previous->next = filter->next;
|
|
if (filter->next)
|
|
filter->next->previous = filter->previous;
|
|
filter->next = NULL;
|
|
filter->previous = NULL;
|
|
if (filter_list == filter)
|
|
filter_list = NULL;
|
|
}
|
|
|
|
static void
|
|
FL_Clear (void)
|
|
{
|
|
filter_t *filter;
|
|
|
|
for (filter = filter_list; filter;) {
|
|
if (filter) {
|
|
filter_t *next = filter->next;
|
|
|
|
FL_Remove (filter);
|
|
free (filter);
|
|
filter = NULL;
|
|
filter = next;
|
|
}
|
|
}
|
|
filter_list = NULL;
|
|
}
|
|
|
|
static filter_t *
|
|
FL_New (netadr_t *adr1, netadr_t *adr2)
|
|
{
|
|
filter_t *filter;
|
|
|
|
filter = (filter_t *) calloc (1, sizeof (filter_t));
|
|
if (adr1)
|
|
NET_CopyAdr (&filter->from, adr1);
|
|
if (adr2)
|
|
NET_CopyAdr (&filter->to, adr2);
|
|
return filter;
|
|
}
|
|
|
|
static void
|
|
FL_Add (filter_t * filter)
|
|
{
|
|
filter->next = filter_list;
|
|
filter->previous = NULL;
|
|
if (filter_list)
|
|
filter_list->previous = filter;
|
|
filter_list = filter;
|
|
}
|
|
|
|
static filter_t *
|
|
FL_Find (netadr_t adr)
|
|
{
|
|
filter_t *filter;
|
|
|
|
for (filter = filter_list; filter; filter = filter->next) {
|
|
if (NET_CompareBaseAdr (filter->from, adr))
|
|
return filter;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
server_t *sv_list = NULL;
|
|
|
|
void
|
|
SVL_Clear (void)
|
|
{
|
|
server_t *sv;
|
|
|
|
for (sv = sv_list; sv;) {
|
|
if (sv) {
|
|
server_t *next = sv->next;
|
|
|
|
SVL_Remove (sv);
|
|
free (sv);
|
|
sv = NULL;
|
|
sv = next;
|
|
}
|
|
} sv_list = NULL;
|
|
}
|
|
|
|
server_t *
|
|
SVL_New (netadr_t *adr)
|
|
{
|
|
server_t *sv;
|
|
|
|
sv = (server_t *) calloc (1, sizeof (server_t));
|
|
sv->heartbeat = 0;
|
|
sv->info[0] = 0;
|
|
sv->ip.ip[0] = sv->ip.ip[1] = sv->ip.ip[2] = sv->ip.ip[3] = 0;
|
|
sv->ip.port = 0;
|
|
sv->next = NULL;
|
|
sv->previous = NULL;
|
|
sv->players = 0;
|
|
if (adr)
|
|
NET_CopyAdr (&sv->ip, adr);
|
|
return sv;
|
|
}
|
|
|
|
void
|
|
SVL_Add (server_t *sv)
|
|
{
|
|
sv->next = sv_list;
|
|
sv->previous = NULL;
|
|
if (sv_list)
|
|
sv_list->previous = sv;
|
|
sv_list = sv;
|
|
}
|
|
|
|
void
|
|
SVL_Remove (server_t *sv)
|
|
{
|
|
if (sv_list == sv)
|
|
sv_list = sv->next;
|
|
if (sv->previous)
|
|
sv->previous->next = sv->next;
|
|
if (sv->next)
|
|
sv->next->previous = sv->previous;
|
|
sv->next = NULL;
|
|
sv->previous = NULL;
|
|
}
|
|
|
|
server_t *
|
|
SVL_Find (netadr_t adr)
|
|
{
|
|
server_t *sv;
|
|
|
|
for (sv = sv_list; sv; sv = sv->next) {
|
|
if (NET_CompareAdr (sv->ip, adr))
|
|
return sv;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
NET_Filter (void)
|
|
{
|
|
int hold_port;
|
|
netadr_t filter_adr;
|
|
filter_t *filter;
|
|
|
|
hold_port = net_from.port;
|
|
NET_StringToAdr ("127.0.0.1:26950", &filter_adr);
|
|
if (NET_CompareBaseAdr (net_from, filter_adr)) {
|
|
NET_StringToAdr ("0.0.0.0:26950", &filter_adr);
|
|
if (!NET_CompareBaseAdr (net_local_adr, filter_adr)) {
|
|
NET_CopyAdr (&net_from, &net_local_adr);
|
|
net_from.port = hold_port;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// if no compare with filter list
|
|
if ((filter = FL_Find (net_from))) {
|
|
NET_CopyAdr (&net_from, &filter->to);
|
|
net_from.port = hold_port;
|
|
}
|
|
}
|
|
|
|
void
|
|
SV_InitNet (void)
|
|
{
|
|
char str[64];
|
|
int port, p;
|
|
FILE *filters;
|
|
|
|
port = PORT_MASTER;
|
|
p = COM_CheckParm ("-port");
|
|
if (p && p < com_argc) {
|
|
port = atoi (com_argv[p + 1]);
|
|
Con_Printf ("Port: %i\n", port);
|
|
}
|
|
NET_Init (port);
|
|
|
|
// Add filters
|
|
if ((filters = fopen ("filters.ini", "rt"))) {
|
|
while (fgets (str, 64, filters)) {
|
|
Cbuf_AddText (mst_cbuf, "filter add ");
|
|
Cbuf_AddText (mst_cbuf, str);
|
|
Cbuf_AddText (mst_cbuf, "\n");
|
|
}
|
|
fclose (filters);
|
|
}
|
|
}
|
|
|
|
void
|
|
NET_CopyAdr (netadr_t *a, netadr_t *b)
|
|
{
|
|
a->ip[0] = b->ip[0];
|
|
a->ip[1] = b->ip[1];
|
|
a->ip[2] = b->ip[2];
|
|
a->ip[3] = b->ip[3];
|
|
a->port = b->port;
|
|
}
|
|
|
|
static void
|
|
AnalysePacket (void)
|
|
{
|
|
byte c;
|
|
byte *p;
|
|
int i;
|
|
|
|
Con_Printf ("%s sending packet:\n", NET_AdrToString (net_from));
|
|
p = net_message->message->data;
|
|
for (i = 0; i < net_message->message->cursize; i++, p++) {
|
|
c = p[0];
|
|
Con_Printf (" %3i ", c);
|
|
if (i % 8 == 7)
|
|
Con_Printf ("\n");
|
|
}
|
|
Con_Printf ("\n");
|
|
Con_Printf ("\n");
|
|
p = net_message->message->data;
|
|
for (i = 0; i < net_message->message->cursize; i++, p++) {
|
|
c = p[0];
|
|
if (c == '\n')
|
|
Con_Printf (" \\n ");
|
|
else if (c >= 32 && c <= 127)
|
|
Con_Printf (" %c ", c);
|
|
else if (c < 10)
|
|
Con_Printf (" \\%1i ", c);
|
|
else if (c < 100)
|
|
Con_Printf (" \\%2i ", c);
|
|
else
|
|
Con_Printf ("\\%3i ", c);
|
|
|
|
if (i % 8 == 7)
|
|
Con_Printf ("\n");
|
|
}
|
|
Con_Printf ("\n");
|
|
}
|
|
|
|
static void
|
|
Mst_SendList (void)
|
|
{
|
|
byte buf[MAX_DATAGRAM];
|
|
sizebuf_t msg;
|
|
server_t *sv;
|
|
short int sv_num = 0;
|
|
|
|
msg.data = buf;
|
|
msg.maxsize = sizeof (buf);
|
|
msg.cursize = 0;
|
|
msg.allowoverflow = true;
|
|
msg.overflowed = false;
|
|
|
|
// number of servers:
|
|
for (sv = sv_list; sv; sv = sv->next)
|
|
sv_num++;
|
|
MSG_WriteByte (&msg, 255);
|
|
MSG_WriteByte (&msg, 255);
|
|
MSG_WriteByte (&msg, 255);
|
|
MSG_WriteByte (&msg, 255);
|
|
MSG_WriteByte (&msg, 255);
|
|
MSG_WriteByte (&msg, 'd');
|
|
MSG_WriteByte (&msg, '\n');
|
|
if (sv_num > 0)
|
|
for (sv = sv_list; sv; sv = sv->next) {
|
|
MSG_WriteByte (&msg, sv->ip.ip[0]);
|
|
MSG_WriteByte (&msg, sv->ip.ip[1]);
|
|
MSG_WriteByte (&msg, sv->ip.ip[2]);
|
|
MSG_WriteByte (&msg, sv->ip.ip[3]);
|
|
MSG_WriteShort (&msg, sv->ip.port);
|
|
}
|
|
NET_SendPacket (msg.cursize, msg.data, net_from);
|
|
}
|
|
|
|
static void
|
|
Mst_Packet (void)
|
|
{
|
|
char msg;
|
|
server_t *sv;
|
|
|
|
// NET_Filter();
|
|
msg = net_message->message->data[1];
|
|
if (msg == A2A_PING) {
|
|
NET_Filter ();
|
|
Con_Printf ("%s >> A2A_PING\n", NET_AdrToString (net_from));
|
|
if (!(sv = SVL_Find (net_from))) {
|
|
sv = SVL_New (&net_from);
|
|
SVL_Add (sv);
|
|
}
|
|
sv->timeout = Sys_DoubleTime ();
|
|
} else if (msg == S2M_HEARTBEAT) {
|
|
NET_Filter ();
|
|
Con_Printf ("%s >> S2M_HEARTBEAT\n", NET_AdrToString (net_from));
|
|
if (!(sv = SVL_Find (net_from))) {
|
|
sv = SVL_New (&net_from);
|
|
SVL_Add (sv);
|
|
}
|
|
sv->timeout = Sys_DoubleTime ();
|
|
} else if (msg == S2M_SHUTDOWN) {
|
|
NET_Filter ();
|
|
Con_Printf ("%s >> S2M_SHUTDOWN\n", NET_AdrToString (net_from));
|
|
if ((sv = SVL_Find (net_from))) {
|
|
SVL_Remove (sv);
|
|
free (sv);
|
|
}
|
|
} else if (msg == 'c') {
|
|
Con_Printf ("%s >> ", NET_AdrToString (net_from));
|
|
Con_Printf ("Gamespy server list request\n");
|
|
Mst_SendList ();
|
|
} else {
|
|
byte *p;
|
|
|
|
p = net_message->message->data;
|
|
Con_Printf ("%s >> ", NET_AdrToString (net_from));
|
|
Con_Printf ("Pingtool server list request\n");
|
|
if (p[0] == 0 && p[1] == 'y') {
|
|
Mst_SendList ();
|
|
} else {
|
|
Con_Printf ("%s >> ", NET_AdrToString (net_from));
|
|
Con_Printf ("%c\n", net_message->message->data[1]);
|
|
AnalysePacket ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SV_ReadPackets (void)
|
|
{
|
|
while (NET_GetPacket ()) {
|
|
Mst_Packet ();
|
|
}
|
|
}
|
|
|
|
void
|
|
SV_ConnectionlessPacket (void)
|
|
{
|
|
Con_Printf ("%s>>%s\n", NET_AdrToString (net_from),
|
|
net_message->message->data);
|
|
}
|
|
|
|
int argv_index_add;
|
|
|
|
static void
|
|
Cmd_FilterAdd (void)
|
|
{
|
|
filter_t *filter;
|
|
netadr_t to, from;
|
|
|
|
if (Cmd_Argc () < 4 + argv_index_add) {
|
|
Con_Printf ("Invalid command parameters. "
|
|
"Usage:\nfilter add x.x.x.x:port x.x.x.x:port\n\n");
|
|
return;
|
|
}
|
|
NET_StringToAdr (Cmd_Argv (2 + argv_index_add), &from);
|
|
NET_StringToAdr (Cmd_Argv (3 + argv_index_add), &to);
|
|
if (to.port == 0)
|
|
from.port = BigShort (PORT_SERVER);
|
|
if (from.port == 0)
|
|
from.port = BigShort (PORT_SERVER);
|
|
if (!(filter = FL_Find (from))) {
|
|
Con_Printf ("Added filter %s\t\t%s\n", Cmd_Argv (2 + argv_index_add),
|
|
Cmd_Argv (3 + argv_index_add));
|
|
filter = FL_New (&from, &to);
|
|
FL_Add (filter);
|
|
} else
|
|
Con_Printf ("%s already defined\n\n", Cmd_Argv (2 + argv_index_add));
|
|
}
|
|
|
|
static void
|
|
Cmd_FilterRemove (void)
|
|
{
|
|
filter_t *filter;
|
|
netadr_t from;
|
|
|
|
if (Cmd_Argc () < 3 + argv_index_add) {
|
|
Con_Printf ("Invalid command parameters. Usage:\n"
|
|
"filter remove x.x.x.x:port\n\n");
|
|
return;
|
|
}
|
|
NET_StringToAdr (Cmd_Argv (2 + argv_index_add), &from);
|
|
if ((filter = FL_Find (from))) {
|
|
Con_Printf ("Removed %s\n\n", Cmd_Argv (2 + argv_index_add));
|
|
FL_Remove (filter);
|
|
free (filter);
|
|
} else
|
|
Con_Printf ("Cannot find %s\n\n", Cmd_Argv (2 + argv_index_add));
|
|
}
|
|
|
|
static void
|
|
Cmd_FilterList (void)
|
|
{
|
|
filter_t *filter;
|
|
|
|
for (filter = filter_list; filter; filter = filter->next) {
|
|
Con_Printf ("%s", NET_AdrToString (filter->from));
|
|
Con_Printf ("\t\t%s\n", NET_AdrToString (filter->to));
|
|
}
|
|
if (filter_list == NULL)
|
|
Con_Printf ("No filter\n");
|
|
Con_Printf ("\n");
|
|
}
|
|
|
|
static void
|
|
Cmd_FilterClear (void)
|
|
{
|
|
Con_Printf ("Removed all filters\n\n");
|
|
FL_Clear ();
|
|
}
|
|
|
|
void
|
|
Cmd_Filter_f (void)
|
|
{
|
|
argv_index_add = 0;
|
|
if (!strcmp (Cmd_Argv (1), "add"))
|
|
Cmd_FilterAdd ();
|
|
else if (!strcmp (Cmd_Argv (1), "remove"))
|
|
Cmd_FilterRemove ();
|
|
else if (!strcmp (Cmd_Argv (1), "clear"))
|
|
Cmd_FilterClear ();
|
|
else if (Cmd_Argc () == 3) {
|
|
argv_index_add = -1;
|
|
Cmd_FilterAdd ();
|
|
} else if (Cmd_Argc () == 2) {
|
|
argv_index_add = -1;
|
|
Cmd_FilterRemove ();
|
|
} else
|
|
Cmd_FilterList ();
|
|
}
|
|
|
|
static void
|
|
SV_WriteFilterList (void)
|
|
{
|
|
FILE *filters;
|
|
|
|
if ((filters = fopen ("filters.ini", "wt"))) {
|
|
filter_t *filter;
|
|
|
|
if (filter_list == NULL) {
|
|
fclose (filters);
|
|
return;
|
|
}
|
|
|
|
for (filter = filter_list; filter; filter = filter->next) {
|
|
fprintf (filters, "%s", NET_AdrToString (filter->from));
|
|
fprintf (filters, " %s\n", NET_AdrToString (filter->to));
|
|
}
|
|
fclose (filters);
|
|
}
|
|
}
|
|
|
|
void
|
|
SV_Shutdown (void)
|
|
{
|
|
NET_Shutdown ();
|
|
|
|
// write filter list
|
|
SV_WriteFilterList ();
|
|
Con_Shutdown ();
|
|
}
|
|
|
|
#define SV_TIMEOUT 450
|
|
static void
|
|
SV_TimeOut (void)
|
|
{
|
|
// Remove listed severs that havnt sent a heartbeat for some time
|
|
double time = Sys_DoubleTime ();
|
|
server_t *sv;
|
|
server_t *next;
|
|
|
|
if (sv_list == NULL)
|
|
return;
|
|
|
|
for (sv = sv_list; sv;) {
|
|
if (sv->timeout + SV_TIMEOUT < time) {
|
|
next = sv->next;
|
|
Con_Printf ("%s timed out\n", NET_AdrToString (sv->ip));
|
|
SVL_Remove (sv);
|
|
free (sv);
|
|
sv = next;
|
|
} else
|
|
sv = sv->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
SV_Frame ()
|
|
{
|
|
Sys_CheckInput (1, net_socket);
|
|
Con_ProcessInput ();
|
|
Cbuf_Execute_Stack (mst_cbuf);
|
|
SV_TimeOut ();
|
|
SV_ReadPackets ();
|
|
}
|
|
|
|
static void
|
|
MST_Quit_f (void)
|
|
{
|
|
Con_Printf ("HW master shutdown\n");
|
|
Sys_Quit ();
|
|
}
|
|
|
|
int
|
|
main (int argc, const char **argv)
|
|
{
|
|
COM_InitArgv (argc, argv);
|
|
|
|
mst_cbuf = Cbuf_New (&id_interp);
|
|
|
|
Sys_RegisterShutdown (SV_Shutdown);
|
|
|
|
Cvar_Init_Hash ();
|
|
Cmd_Init_Hash ();
|
|
Cvar_Init ();
|
|
Sys_Init_Cvars ();
|
|
Sys_Init ();
|
|
Cmd_Init ();
|
|
|
|
Cmd_AddCommand ("quit", MST_Quit_f, "Shut down the master server");
|
|
|
|
Cmd_StuffCmds (mst_cbuf);
|
|
Cbuf_Execute_Sets (mst_cbuf);
|
|
|
|
PI_Init ();
|
|
|
|
sv_console_plugin = Cvar_Get ("sv_console_plugin", "server",
|
|
CVAR_ROM, 0, "Plugin used for the console");
|
|
PI_RegisterPlugins (server_plugin_list);
|
|
Con_Init (sv_console_plugin->string);
|
|
if (con_module)
|
|
con_module->data->console->cbuf = mst_cbuf;
|
|
con_list_print = Sys_Printf;
|
|
|
|
SV_InitNet ();
|
|
Con_Printf ("Exe: " __TIME__ " " __DATE__ "\n");
|
|
Con_Printf ("======== HW master initialized ========\n\n");
|
|
while (1) {
|
|
SV_Frame ();
|
|
}
|
|
return 0;
|
|
}
|