1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 #ifdef HAVE_STRING_H
5 # include <string.h>
6 #endif
7 #ifdef HAVE_STRINGS_H
8 # include <strings.h>
9 #endif
10 #include <stdlib.h>
11 
12 #include "QF/cbuf.h"
13 #include "QF/cmd.h"
14 #include "QF/console.h"
15 #include "QF/cvar.h"
16 #include "QF/idparse.h"
17 #include "QF/mathlib.h"
18 #include "QF/msg.h"
19 #include "QF/qargs.h"
20 #include "QF/qendian.h"
21 #include "QF/sizebuf.h"
22 #include "QF/sys.h"
23 
24 #include "QF/plugin/console.h"
25 
26 #include "compat.h"
27 #include "netchan.h"
28 
29 #define SV_TIMEOUT 450
30 
31 #define PORT_MASTER 26900
32 #define PORT_SERVER 26950
33 
34 // M = master, S = server, C = client, A = any
35 // the second character will allways be \n if the message isn't a single
36 // byte long (?? not true anymore?)
37 
38 #define S2C_CHALLENGE       'c'
39 #define A2A_PING            'k'
40 
41 #define S2M_HEARTBEAT       'a' // + serverinfo + userlist + fraglist
42 #define S2M_SHUTDOWN        'C'
43 
44 typedef struct filter_s {
45 	netadr_t    from;
46 	netadr_t    to;
47 	struct filter_s *next;
48 	struct filter_s *previous;
49 } filter_t;
50 
51 typedef struct server_s {
52 	netadr_t    ip;
53 	struct server_s *next;
54 	struct server_s *previous;
55 	double timeout;
56 } server_t;
57 
58 static cvar_t *sv_console_plugin;
59 SERVER_PLUGIN_PROTOS
60 static plugin_list_t server_plugin_list[] = {
61 	SERVER_PLUGIN_LIST
62 };
63 
64 qboolean is_server = true;
65 
66 static cbuf_t *mst_cbuf;
67 
68 static server_t   *sv_list = NULL;
69 static filter_t   *filter_list = NULL;
70 
71 static void
FL_Remove(filter_t * filter)72 FL_Remove (filter_t * filter)
73 {
74 	if (filter->previous)
75 		filter->previous->next = filter->next;
76 	if (filter->next)
77 		filter->next->previous = filter->previous;
78 	filter->next = NULL;
79 	filter->previous = NULL;
80 	if (filter_list == filter)
81 		filter_list = NULL;
82 }
83 
84 static void
FL_Clear(void)85 FL_Clear (void)
86 {
87 	filter_t   *filter;
88 
89 	for (filter = filter_list; filter;) {
90 		if (filter) {
91 			filter_t   *next = filter->next;
92 
93 			FL_Remove (filter);
94 			free (filter);
95 			filter = next;
96 		}
97 	}
98 	filter_list = NULL;
99 }
100 
101 static filter_t *
FL_New(netadr_t * adr1,netadr_t * adr2)102 FL_New (netadr_t *adr1, netadr_t *adr2)
103 {
104 	filter_t   *filter;
105 
106 	filter = (filter_t *) calloc (1, sizeof (filter_t));
107 	if (adr1)
108 		filter->from = *adr1;
109 	if (adr2)
110 		filter->to = *adr2;
111 	return filter;
112 }
113 
114 static void
FL_Add(filter_t * filter)115 FL_Add (filter_t * filter)
116 {
117 	filter->next = filter_list;
118 	filter->previous = NULL;
119 	if (filter_list)
120 		filter_list->previous = filter;
121 	filter_list = filter;
122 }
123 
124 static filter_t *
FL_Find(netadr_t adr)125 FL_Find (netadr_t adr)
126 {
127 	filter_t   *filter;
128 
129 	for (filter = filter_list; filter; filter = filter->next) {
130 		if (NET_CompareBaseAdr (filter->from, adr))
131 			return filter;
132 	}
133 	return NULL;
134 }
135 
136 static void
Filter(void)137 Filter (void)
138 {
139 	int         hold_port;
140 	netadr_t    filter_adr;
141 	filter_t   *filter;
142 
143 	hold_port = net_from.port;
144 	NET_StringToAdr ("127.0.0.1:26950", &filter_adr);
145 	if (NET_CompareBaseAdr (net_from, filter_adr)) {
146 		NET_StringToAdr ("0.0.0.0:26950", &filter_adr);
147 		if (!NET_CompareBaseAdr (net_local_adr, filter_adr)) {
148 			net_from = net_local_adr;
149 			net_from.port = hold_port;
150 		}
151 		return;
152 	}
153 
154 	// if no compare with filter list
155 	if ((filter = FL_Find (net_from))) {
156 		net_from = filter->to;
157 		net_from.port = hold_port;
158 	}
159 }
160 
161 static void
SVL_Remove(server_t * sv)162 SVL_Remove (server_t *sv)
163 {
164 	if (sv_list == sv)
165 		sv_list = sv->next;
166 	if (sv->previous)
167 		sv->previous->next = sv->next;
168 	if (sv->next)
169 		sv->next->previous = sv->previous;
170 	sv->next = NULL;
171 	sv->previous = NULL;
172 }
173 
174 static void
SVL_Clear(void)175 SVL_Clear (void)
176 {
177 	server_t   *sv;
178 
179 	for (sv = sv_list; sv;) {
180 		if (sv) {
181 			server_t   *next = sv->next;
182 
183 			SVL_Remove (sv);
184 			free (sv);
185 			sv = next;
186 		}
187 	}
188 	sv_list = NULL;
189 }
190 
191 static server_t *
SVL_New(netadr_t * adr)192 SVL_New (netadr_t *adr)
193 {
194 	server_t   *sv;
195 
196 	sv = (server_t *) calloc (1, sizeof (server_t));
197 	if (adr)
198 		sv->ip = *adr;
199 	return sv;
200 }
201 
202 static void
SVL_Add(server_t * sv)203 SVL_Add (server_t *sv)
204 {
205 	sv->next = sv_list;
206 	sv->previous = NULL;
207 	if (sv_list)
208 		sv_list->previous = sv;
209 	sv_list = sv;
210 }
211 
212 static server_t *
SVL_Find(netadr_t adr)213 SVL_Find (netadr_t adr)
214 {
215 	server_t   *sv;
216 
217 	for (sv = sv_list; sv; sv = sv->next) {
218 		if (NET_CompareAdr (sv->ip, adr))
219 			return sv;
220 	}
221 	return NULL;
222 }
223 
224 static void
SV_InitNet(void)225 SV_InitNet (void)
226 {
227 	const char *str;
228 	int         port, p;
229 	QFile      *filters;
230 
231 	port = PORT_MASTER;
232 	p = COM_CheckParm ("-port");
233 	if (p && p < com_argc) {
234 		port = atoi (com_argv[p + 1]);
235 		Sys_Printf ("Port: %i\n", port);
236 	}
237 	NET_Init (port);
238 
239 	// Add filters
240 	if ((filters = Qopen ("filters.ini", "rt"))) {
241 		while ((str = Qgetline (filters))) {
242 			Cbuf_AddText (mst_cbuf, "filter add ");
243 			Cbuf_AddText (mst_cbuf, str);
244 			Cbuf_AddText (mst_cbuf, "\n");
245 		}
246 		Qclose (filters);
247 	}
248 }
249 
250 static void
AnalysePacket(void)251 AnalysePacket (void)
252 {
253 	byte        buf[16];
254 	byte       *p, *data;
255 	int         i, size, rsize;
256 
257 	Sys_Printf ("%s >> unknown packet:\n", NET_AdrToString (net_from));
258 
259 	data = net_message->message->data;
260 	size = net_message->message->cursize;
261 
262 	for (p = data; (rsize = min (size - (p - data), 16)); p += rsize) {
263 		Sys_Printf ("%04X:", (unsigned) (p - data));
264 		memcpy (buf, p, rsize);
265 		for (i = 0; i < rsize; i++) {
266 			Sys_Printf (" %02X", buf[i]);
267 			if (buf[i] < ' ' || buf [i] > '~')
268 				buf[i] = '.';
269 		}
270 		Sys_Printf ("%*.*s\n", 1 + (16 - rsize) * 3 + rsize, rsize, buf);
271 	}
272 }
273 
274 static void
Mst_SendList(void)275 Mst_SendList (void)
276 {
277 	byte        buf[MAX_DATAGRAM];
278 	sizebuf_t   msg;
279 	server_t   *sv;
280 	short int   sv_num = 0;
281 
282 	msg.data = buf;
283 	msg.maxsize = sizeof (buf);
284 	msg.cursize = 0;
285 	msg.allowoverflow = true;
286 	msg.overflowed = false;
287 
288 	// number of servers:
289 	for (sv = sv_list; sv; sv = sv->next)
290 		sv_num++;
291 	MSG_WriteByte (&msg, 255);
292 	MSG_WriteByte (&msg, 255);
293 	MSG_WriteByte (&msg, 255);
294 	MSG_WriteByte (&msg, 255);
295 	MSG_WriteByte (&msg, 255);
296 	MSG_WriteByte (&msg, 'd');
297 	MSG_WriteByte (&msg, '\n');
298 	if (sv_num > 0)
299 		for (sv = sv_list; sv; sv = sv->next) {
300 			MSG_WriteByte (&msg, sv->ip.ip[0]);
301 			MSG_WriteByte (&msg, sv->ip.ip[1]);
302 			MSG_WriteByte (&msg, sv->ip.ip[2]);
303 			MSG_WriteByte (&msg, sv->ip.ip[3]);
304 			MSG_WriteShort (&msg, sv->ip.port);
305 		}
306 	NET_SendPacket (msg.cursize, msg.data, net_from);
307 }
308 
309 static void
Mst_Packet(void)310 Mst_Packet (void)
311 {
312 	char        msg;
313 	server_t   *sv;
314 
315 //	Filter ();
316 	msg = net_message->message->data[1];
317 	if (msg == A2A_PING) {
318 		Filter ();
319 		Sys_Printf ("%s >> A2A_PING\n", NET_AdrToString (net_from));
320 		if (!(sv = SVL_Find (net_from))) {
321 			sv = SVL_New (&net_from);
322 			SVL_Add (sv);
323 		}
324 		sv->timeout = Sys_DoubleTime ();
325 	} else if (msg == S2M_HEARTBEAT) {
326 		Filter ();
327 		Sys_Printf ("%s >> S2M_HEARTBEAT\n", NET_AdrToString (net_from));
328 		if (!(sv = SVL_Find (net_from))) {
329 			sv = SVL_New (&net_from);
330 			SVL_Add (sv);
331 		}
332 		sv->timeout = Sys_DoubleTime ();
333 	} else if (msg == S2M_SHUTDOWN) {
334 		Filter ();
335 		Sys_Printf ("%s >> S2M_SHUTDOWN\n", NET_AdrToString (net_from));
336 		if ((sv = SVL_Find (net_from))) {
337 			SVL_Remove (sv);
338 			free (sv);
339 		}
340 	} else if (msg == S2C_CHALLENGE) {
341 		Sys_Printf ("%s >> ", NET_AdrToString (net_from));
342 		Sys_Printf ("Gamespy server list request\n");
343 		Mst_SendList ();
344 	} else {
345 		byte       *p;
346 
347 		p = net_message->message->data;
348 		if (p[0] == 0 && p[1] == 'y') {
349 			Sys_Printf ("%s >> ", NET_AdrToString (net_from));
350 			Sys_Printf ("Pingtool server list request\n");
351 			Mst_SendList ();
352 		} else {
353 			AnalysePacket ();
354 		}
355 	}
356 }
357 
358 static void
SV_ReadPackets(void)359 SV_ReadPackets (void)
360 {
361 	while (NET_GetPacket ()) {
362 		Mst_Packet ();
363 	}
364 }
365 
366 static void
FilterAdd(int arg)367 FilterAdd (int arg)
368 {
369 	filter_t   *filter;
370 	netadr_t    to, from;
371 
372 	if (Cmd_Argc () - arg != 2) {
373 		Sys_Printf ("Invalid command parameters. "
374 					"Usage:\nfilter add x.x.x.x:port x.x.x.x:port\n\n");
375 		return;
376 	}
377 	NET_StringToAdr (Cmd_Argv (arg), &from);
378 	NET_StringToAdr (Cmd_Argv (arg + 1), &to);
379 	if (to.port == 0)
380 		from.port = BigShort (PORT_SERVER);
381 	if (from.port == 0)
382 		from.port = BigShort (PORT_SERVER);
383 	if (!(filter = FL_Find (from))) {
384 		Sys_Printf ("Added filter %s\t\t%s\n", Cmd_Argv (arg),
385 					Cmd_Argv (arg + 1));
386 		filter = FL_New (&from, &to);
387 		FL_Add (filter);
388 	} else
389 		Sys_Printf ("%s already defined\n\n", Cmd_Argv (arg));
390 }
391 
392 static void
FilterRemove(int arg)393 FilterRemove (int arg)
394 {
395 	filter_t   *filter;
396 	netadr_t    from;
397 
398 	if (Cmd_Argc () - arg != 1) {
399 		Sys_Printf ("Invalid command parameters. Usage:\n"
400 					"filter remove x.x.x.x:port\n\n");
401 		return;
402 	}
403 	NET_StringToAdr (Cmd_Argv (arg), &from);
404 	if ((filter = FL_Find (from))) {
405 		Sys_Printf ("Removed %s\n\n", Cmd_Argv (arg));
406 		FL_Remove (filter);
407 		free (filter);
408 	} else
409 		Sys_Printf ("Cannot find %s\n\n", Cmd_Argv (arg));
410 }
411 
412 static void
FilterList(void)413 FilterList (void)
414 {
415 	filter_t   *filter;
416 
417 	for (filter = filter_list; filter; filter = filter->next) {
418 		Sys_Printf ("%s", NET_AdrToString (filter->from));
419 		Sys_Printf ("\t\t%s\n", NET_AdrToString (filter->to));
420 	}
421 	if (filter_list == NULL)
422 		Sys_Printf ("No filter\n");
423 	Sys_Printf ("\n");
424 }
425 
426 static void
FilterClear(void)427 FilterClear (void)
428 {
429 	Sys_Printf ("Removed all filters\n\n");
430 	FL_Clear ();
431 }
432 
433 static void
Filter_f(void)434 Filter_f (void)
435 {
436 	if (!strcmp (Cmd_Argv (1), "add"))
437 		FilterAdd (2);
438 	else if (!strcmp (Cmd_Argv (1), "remove"))
439 		FilterRemove (2);
440 	else if (!strcmp (Cmd_Argv (1), "clear"))
441 		FilterClear ();
442 	else if (Cmd_Argc () == 3) {
443 		FilterAdd (1);
444 	} else if (Cmd_Argc () == 2) {
445 		FilterRemove (1);
446 	} else
447 		FilterList ();
448 }
449 
450 static void
SV_WriteFilterList(void)451 SV_WriteFilterList (void)
452 {
453 	QFile      *filters;
454 
455 	if ((filters = Qopen ("filters.ini", "wt"))) {
456 		filter_t   *filter;
457 
458 		if (filter_list == NULL) {
459 			Qclose (filters);
460 			return;
461 		}
462 
463 		for (filter = filter_list; filter; filter = filter->next) {
464 			Qprintf (filters, "%s", NET_AdrToString (filter->from));
465 			Qprintf (filters, " %s\n", NET_AdrToString (filter->to));
466 		}
467 		Qclose (filters);
468 	}
469 }
470 
471 static void
SV_Shutdown(void)472 SV_Shutdown (void)
473 {
474 	NET_Shutdown ();
475 
476 	// write filter list
477 	SV_WriteFilterList ();
478 	Con_Shutdown ();
479 }
480 
481 static void
SV_TimeOut(void)482 SV_TimeOut (void)
483 {
484 	// Remove listed severs that havnt sent a heartbeat for some time
485 	double      time = Sys_DoubleTime ();
486 	server_t   *sv;
487 	server_t   *next;
488 
489 	if (sv_list == NULL)
490 		return;
491 
492 	for (sv = sv_list; sv;) {
493 		if (sv->timeout + SV_TIMEOUT < time) {
494 			next = sv->next;
495 			Sys_Printf ("%s timed out\n", NET_AdrToString (sv->ip));
496 			SVL_Remove (sv);
497 			free (sv);
498 			sv = next;
499 		} else
500 			sv = sv->next;
501 	}
502 }
503 
504 static void
SV_Frame(void)505 SV_Frame (void)
506 {
507 	Sys_CheckInput (1, net_socket);
508 	Con_ProcessInput ();
509 	Cbuf_Execute_Stack (mst_cbuf);
510 	SV_TimeOut ();
511 	SV_ReadPackets ();
512 }
513 
514 static void
MST_Quit_f(void)515 MST_Quit_f (void)
516 {
517 	Sys_Printf ("HW master shutdown\n");
518 	Sys_Quit ();
519 }
520 
521 int
main(int argc,const char ** argv)522 main (int argc, const char **argv)
523 {
524 	COM_InitArgv (argc, argv);
525 
526 	mst_cbuf = Cbuf_New (&id_interp);
527 
528 	Sys_RegisterShutdown (SV_Shutdown);
529 
530 	Sys_Init ();
531 
532 	Cmd_AddCommand ("quit", MST_Quit_f, "Shut down the master server");
533 	Cmd_AddCommand ("clear", SVL_Clear, "Clear the server list");
534 	Cmd_AddCommand ("filter", Filter_f, "Manipulate filtering");
535 
536 	Cmd_StuffCmds (mst_cbuf);
537 	Cbuf_Execute_Sets (mst_cbuf);
538 
539 	PI_Init ();
540 
541 	sv_console_plugin = Cvar_Get ("sv_console_plugin", "server",
542 								  CVAR_ROM, 0, "Plugin used for the console");
543 	PI_RegisterPlugins (server_plugin_list);
544 	Con_Init (sv_console_plugin->string);
545 	if (con_module)
546 		con_module->data->console->cbuf = mst_cbuf;
547 	con_list_print = Sys_Printf;
548 
549 	SV_InitNet ();
550 	Sys_Printf ("Exe: " __TIME__ " " __DATE__ "\n");
551 	Sys_Printf ("======== HW master initialized ========\n\n");
552 	while (1) {
553 		SV_Frame ();
554 	}
555 	return 0;
556 }
557