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