1 /* XQF - Quake server browser and launcher
2 * Copyright (C) 1998-2000 Roman Pozlevich <roma@botik.ru>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17 */
18
19 #include <sys/types.h>
20 #include <stdio.h> /* fprintf */
21 #include <string.h> /* strchr, strncpy */
22 #include <stdlib.h> /* strtol */
23 #include <sys/socket.h> /* inet_ntoa */
24 #include <netinet/in.h> /* inet_ntoa */
25 #include <arpa/inet.h> /* inet_ntoa */
26
27 #include <glib.h>
28
29 #include "xqf.h"
30 #include "game.h"
31 #include "host.h"
32 #include "utils.h"
33 #include "server.h"
34
35 #ifdef USE_GEOIP
36 #include "country-filter.h"
37 #endif
38
39
40 struct server_hash {
41 int num;
42 GSList **nodes;
43 };
44
45 static struct server_hash servers = { 2333, NULL };
46 static struct server_hash uservers = { 251, NULL };
47
48
server_hash_func(const struct host * h,unsigned short port)49 static int server_hash_func (const struct host *h, unsigned short port) {
50 unsigned char *ptr;
51
52 if (!h)
53 return 0;
54
55 ptr = (unsigned char *) &h->ip.s_addr;
56 return (ptr[0] + (ptr[1] << 2) + (ptr[2] << 4) + (ptr[3] << 6) + port) %
57 servers.num;
58 }
59
60
userver_hash_func(const char * hostname,unsigned short port)61 static int userver_hash_func (const char *hostname, unsigned short port) {
62 int sum = 0;
63
64 while (*hostname) {
65 sum += *hostname;
66 hostname++;
67 }
68 return (sum + port) % uservers.num;
69 }
70
71
72
73 /*
74 server_new -- Create (malloc) a new server structure with
75 all of the values set at zero except the reference count which
76 should be at one.
77 */
78
server_new(struct host * h,unsigned short port,enum server_type type)79 static struct server *server_new (struct host *h, unsigned short port,
80 enum server_type type) {
81 struct server *server;
82
83 if (port == 0 || type == UNKNOWN_SERVER)
84 return NULL;
85
86 server = g_malloc0 (sizeof (struct server));
87 debug (6, "server_new() -- Server %lx", server);
88
89 server_ref (server);
90
91 server->host = h;
92 host_ref (h); /* Increse the refernece count on the host struct */
93
94 server->port = port;
95 server->type = type;
96 server->ping = -1;
97 server->retries = -1;
98
99 #ifdef USE_GEOIP
100 server->country_id = geoip_id_by_ip(h->ip);
101 #endif
102
103 return server;
104 }
105
106
userver_new(const char * hostname,unsigned short port,enum server_type type)107 static struct userver *userver_new (const char *hostname, unsigned short port,
108 enum server_type type) {
109 struct userver *userver;
110
111 if (port == 0 || type == UNKNOWN_SERVER)
112 return NULL;
113
114 userver = g_malloc0 (sizeof (struct userver));
115 userver_ref (userver); /* baa -- Needed? FIX ME */
116 userver->hostname = g_strdup (hostname);
117 userver->port = port;
118 userver->type = type;
119
120 return userver;
121 }
122
123
124
125 /*
126 server_add -- See if a host/port is in our list. If it is not
127 then add one. If it is then we increase the reference count.
128 */
server_add(struct host * h,unsigned short port,enum server_type type)129 struct server *server_add (struct host *h, unsigned short port,
130 enum server_type type) {
131 struct server *server;
132 GSList *ptr;
133 int node;
134
135 if (!h || type == UNKNOWN_SERVER)
136 return NULL;
137
138 if (port == 0)
139 port = games[type].default_port;
140
141 node = server_hash_func (h, port);
142
143 debug (6, "server_add() -- Add/Get a server");
144
145 if (!servers.nodes) {
146 servers.nodes = g_malloc0 (sizeof (GSList *) * servers.num);
147 }
148 else {
149 /* Go through each of the servers in the list (each node)
150 and see if we have a matching (by reference) entry.
151 */
152 for (ptr = servers.nodes[node]; ptr; ptr = ptr->next) {
153 server = (struct server *) ptr->data;
154 if (server->host == h && server->port == port) {
155 server_ref (server); /* baa -- added Dec-27, 2000 CORE FIX? */
156 return server;
157 }
158 }
159 }
160
161 server = server_new (h, port, type);
162 if (server) {
163 servers.nodes[node] = g_slist_prepend (servers.nodes[node], server);
164
165 if (games[type].analyze_serverinfo)
166 (*games[type].analyze_serverinfo) (server);
167 }
168 return server;
169 }
170
userver_add(const char * hostname,unsigned short port,enum server_type type)171 struct userver *userver_add (const char *hostname, unsigned short port,
172 enum server_type type) {
173 GSList *ptr;
174 struct userver *s;
175 int node;
176
177 if (!hostname || type == UNKNOWN_SERVER)
178 return NULL;
179
180 if (port == 0)
181 port = games[type].default_port;
182
183 node = userver_hash_func (hostname, port);
184
185 if (!uservers.nodes) {
186 uservers.nodes = g_malloc0 (sizeof (GSList *) * uservers.num);
187 }
188 else {
189 for (ptr = uservers.nodes[node]; ptr; ptr = ptr->next) {
190 s = (struct userver *) ptr->data;
191 if (strcmp (s->hostname, hostname) == 0 && s->port == port)
192 return s;
193 }
194 }
195
196 s = userver_new (hostname, port, type);
197 if (s)
198 uservers.nodes[node] = g_slist_prepend (uservers.nodes[node], s);
199 return s;
200 }
201
202
server_free_info(struct server * s)203 void server_free_info (struct server *s) {
204 if (s->name) {
205 g_free (s->name);
206 s->name = NULL;
207 }
208 if (s->map) {
209 g_free (s->map);
210 s->map = NULL;
211 }
212 if (s->info) {
213 g_free (s->info);
214 s->info = NULL;
215 s->game = NULL;
216 }
217
218 if (s->gametype) { /* Added by baa */
219 s->gametype = NULL;
220 }
221
222 if (s->players) {
223 g_slist_foreach (s->players, (GFunc) g_free, NULL);
224 g_slist_free (s->players);
225 s->players = NULL;
226 }
227
228 s->flags = 0;
229 s->maxplayers = 0;
230 s->curplayers = 0;
231 s->curbots = 0;
232
233 s->filters = 0;
234 s->flt_mask = 0;
235 s->flt_last = 0;
236 }
237
238
239 // return NULL if refcount dropped to zero, server otherwise
server_unref(struct server * server)240 struct server* server_unref (struct server *server) {
241 int node;
242
243 if (!server)
244 return NULL;
245
246 server->ref_count--;
247
248 debug (7, "server_unref() -- Server %lx ref now at %d",
249 server, server->ref_count);
250
251 if (server->ref_count <= 0) {
252 node = server_hash_func (server->host, server->port);
253 servers.nodes[node] = g_slist_remove (servers.nodes[node], server);
254 /*
255 Oops, it seems that we were freeing the server info before
256 freeing the host info. Bad. To free the host info w/o a memory
257 leak we need to do that before freeing the server info. --baa
258 */
259 host_unref (server->host);
260 server_free_info (server);
261 g_free (server);
262 return NULL;
263 }
264 return server;
265 }
266
267
userver_unref(struct userver * s)268 void userver_unref (struct userver *s) {
269 int node;
270
271 if (!s)
272 return;
273
274 s->ref_count--;
275
276 debug (6, "userver_unref() -- UServer %lx ref now at %d",
277 s, s->ref_count);
278
279 if (s->ref_count <= 0) {
280 node = userver_hash_func (s->hostname, s->port);
281 uservers.nodes[node] = g_slist_remove (uservers.nodes[node], s);
282 if (s->s) server_unref (s->s);
283 g_free (s->hostname);
284 g_free (s);
285 }
286 }
287
288 // change the server port to newport. this function is required as the server
289 // needs to get a new position in the servers hash
server_change_port(struct server * s,int newport)290 struct server* server_change_port (struct server* s, int newport) {
291 int node;
292
293 if (!newport || !s)
294 return s;
295
296 node = server_hash_func (s->host, s->port);
297 servers.nodes[node] = g_slist_remove (servers.nodes[node], s);
298 s->port = newport;
299 node = server_hash_func (s->host, s->port);
300 // FIXME: there could be already a server with that port
301 servers.nodes[node] = g_slist_prepend (servers.nodes[node], s);
302 return s;
303 }
304
server_list_copy(GSList * list)305 GSList *server_list_copy (GSList *list) {
306 debug (3, "server_list_copy() -- list %ld copying all servers", list);
307 g_slist_foreach (list, (GFunc) server_ref, NULL);
308 return g_slist_copy (list);
309 }
310
311
userver_list_copy(GSList * list)312 GSList *userver_list_copy (GSList *list) {
313 g_slist_foreach (list, (GFunc) userver_ref, NULL);
314 return g_slist_copy (list);
315 }
316
317
server_list_append_list(GSList * list,GSList * server_list,enum server_type type)318 GSList *server_list_append_list (GSList *list, GSList *server_list,
319 enum server_type type) {
320 struct server *server;
321 GSList *add = NULL;
322 debug (6, "server_list_append_list() -- list %lx", list);
323 while (server_list) {
324 server = (struct server *) server_list->data;
325 if (type == UNKNOWN_SERVER || type == server->type) {
326 if (g_slist_find (list, server) == NULL) {
327 add = g_slist_prepend (add, server);
328 server_ref (server);
329 }
330 }
331 server_list = g_slist_next (server_list);
332 }
333
334 return g_slist_concat (list, g_slist_reverse (add));
335 }
336
337
userver_list_append_list(GSList * list,GSList * uservers,enum server_type type)338 GSList *userver_list_append_list (GSList *list, GSList *uservers,
339 enum server_type type) {
340 struct userver *us;
341 GSList *add = NULL;
342
343 while (uservers) {
344 us = (struct userver *) uservers->data;
345 if (type == UNKNOWN_SERVER || type == us->type) {
346 if (g_slist_find (list, us) == NULL) {
347 add = g_slist_prepend (add, us);
348 userver_ref (us);
349 }
350 }
351 uservers = g_slist_next (uservers);
352 }
353
354 return g_slist_concat (list, g_slist_reverse (add));
355 }
356
357
servers_total(void)358 int servers_total (void) {
359 int i;
360 int size = 0, len;
361 int min=-1, max=0;
362
363 if (!servers.nodes)
364 return 0;
365
366 for (i = 0; i < servers.num; i++) {
367 len = g_slist_length (servers.nodes[i]);
368 size += len;
369 if (min == -1 || len < min) min=len;
370 if (len > max) max=len;
371 }
372
373 debug(1,"server hash (min/max/avg) %d/%d/%5.2f",min,max,size/(servers.num*1.0));
374
375 return size;
376 }
377
378
uservers_total(void)379 int uservers_total (void) {
380 int i;
381 int size = 0;
382
383 if (!uservers.nodes)
384 return 0;
385
386 for (i = 0; i < uservers.num; i++)
387 size += g_slist_length (uservers.nodes[i]);
388
389 return size;
390 }
391
392
393
394 /*
395 all_servers -- Get a list of all servers. This is called from
396 two functions source.c:free_masters and statistics.c:collect_statistics
397 both of which call server_free_list afterwards.
398 */
all_servers(void)399 GSList *all_servers (void) {
400 GSList *list = NULL;
401 GSList *tmp;
402 struct server *server;
403 int i;
404
405 if (!servers.nodes)
406 return NULL;
407 debug (6, "all_servers() -- Get all servers");
408 for (i = 0; i < servers.num; i++) {
409 for (tmp = servers.nodes[i]; tmp; tmp = tmp->next) {
410 server = (struct server *) tmp->data;
411 list = g_slist_prepend (list, server);
412 server_ref (server);
413 }
414 }
415
416 return list;
417 }
418
419
parse_address(char * str,char ** addr,unsigned short * port)420 int parse_address (char *str, char **addr, unsigned short *port) {
421 long tmp;
422 char *ptr;
423 char *endptr;
424
425 if (!str || !addr || !port)
426 return FALSE;
427
428 *port = 0;
429 *addr = NULL;
430
431 ptr = strchr (str, ':');
432 if (!ptr) {
433 if (hostname_is_valid (str)) {
434 *addr = g_strdup (str);
435 return TRUE;
436 }
437 return FALSE;
438 }
439
440 if (ptr == str)
441 return FALSE;
442
443 tmp = strtol (ptr + 1, &endptr, 10);
444
445 if (*endptr != '\0' || tmp <= 0 || tmp > 65535)
446 return FALSE;
447
448 *port = (unsigned short) tmp;
449
450 /* malloc(strlen("addr:port") - strlen(":port") + strlen("\0")); */
451 *addr = g_malloc (strlen(str) - strlen(ptr) + 1);
452 strncpy (*addr, str, ptr - str);
453 (*addr) [ptr - str] = '\0';
454
455 if (hostname_is_valid (*addr))
456 return TRUE;
457
458 g_free (*addr);
459 *addr = NULL;
460 *port = 0;
461 return FALSE;
462 }
463
464
userver_set_host(struct userver * us,struct host * h)465 struct server *userver_set_host (struct userver *us, struct host *h) {
466 struct server *server;
467
468 if (!us || !h) return NULL;
469 if (us->s) return us->s;
470
471 /* Since server_add increases the reference count for us,
472 we do not do it here. */
473 server = server_add (h, us->port, us->type);
474 if (server) {
475 us->s = server;
476 }
477
478 return server;
479 }
480
481
uservers_to_servers(GSList ** uservers,GSList ** servers)482 void uservers_to_servers (GSList **uservers, GSList **servers) {
483 struct userver *us;
484 GSList *tmp = *uservers;
485
486 debug (6, "uservers_to_servers() -- uservers %lx tmp %lx", uservers, tmp);
487 while (tmp) {
488 us = (struct userver *) tmp->data;
489 debug (7, "uservers_to_servers() -- Check userver %lx", us);
490 if (us->s) {
491 debug (7, "uservers_to_servers() -- server %lx userver %lx", us->s, us);
492 *servers = server_list_append (*servers, us->s);
493
494 *uservers = g_slist_remove (*uservers, us);
495 userver_unref (us);
496
497 tmp = *uservers;
498 continue;
499 }
500 tmp = tmp->next;
501 }
502 debug (6, "uservers_to_servers() -- Done.");
503 }
504
505
506 /*
507 server_lists_intersect() -- Find servers that are
508 in two lists (by reference). The first arg gets a list
509 of servers not in both lists. The second list gets servers
510 removed that are in both lists.
511 */
512
server_lists_intersect(GSList ** list1,GSList ** list2)513 void server_lists_intersect (GSList **list1, GSList **list2) {
514 GSList *list3 = NULL;
515 GSList *tmp;
516 struct server *s;
517
518 debug (6, "server_lists_intersect() -- ");
519 for (tmp = *list1; tmp; tmp = tmp->next) {
520 s = (struct server *) tmp->data;
521 if (g_slist_find (*list2, s)) {
522 *list2 = g_slist_remove (*list2, s);
523 server_unref (s);
524 }
525 else {
526 list3 = g_slist_prepend (list3, s);
527 server_ref (s);
528 }
529 }
530
531 server_list_free (*list1);
532 *list1 = list3;
533 }
534
535
server_list_fprintf(FILE * f,GSList * servers)536 void server_list_fprintf (FILE *f, GSList *servers) {
537 struct server *s;
538 int i;
539
540 for (i = 0; servers; i++) {
541 s = (struct server *) servers->data;
542 fprintf (f, "%d> [%s:%d](%d) %s \"%s\"\n", i, inet_ntoa (s->host->ip),
543 s->port, s->ref_count, games[s->type].id, s->name);
544 servers = servers->next;
545 }
546 }
547
548
userver_list_fprintf(FILE * f,GSList * uservers)549 void userver_list_fprintf (FILE *f, GSList *uservers) {
550 struct userver *us;
551 int i;
552
553 for (i = 0; uservers; i++) {
554 us = (struct userver *) uservers->data;
555 fprintf (f, "%d> [%s:%d](%d) %s\n", i, us->hostname, us->port,
556 us->ref_count, games[us->type].id);
557 if (us->s) {
558 fprintf (f, " --> [%s:%d](%d) %s \"%s\"\n",
559 inet_ntoa (us->s->host->ip), us->s->port,
560 us->s->ref_count, games[us->type].id, us->s->name);
561 }
562
563 uservers = uservers->next;
564 }
565 }
566
server_set_env(const struct server * s)567 void server_set_env(const struct server* s) {
568 char buf[256];
569
570 if (!s) return;
571
572 if (s->flags & SERVER_PUNKBUSTER)
573 setenv("XQF_SERVER_ANTICHEAT", "1", 1);
574
575 if (s->name)
576 setenv("XQF_SERVER_NAME", s->name, 1);
577
578 if (s->map)
579 setenv("XQF_SERVER_MAP", s->map, 1);
580
581 if (s->host->name)
582 setenv("XQF_SERVER_HOSTNAME", s->host->name, 1);
583
584 if (s->game)
585 setenv("XQF_SERVER_GAME", s->game, 1);
586
587 setenv("XQF_SERVER_IP", inet_ntoa (s->host->ip), 1);
588
589 snprintf(buf, sizeof(buf), "%d", s->port);
590 setenv("XQF_SERVER_PORT", buf, 1);
591
592 setenv("XQF_GAME_TYPE", games[s->type].id, 1);
593
594 if (games[s->type].flags & GAME_LAUNCH_HOSTPORT) {
595 char **info_ptr;
596 // go through all server rules
597 for (info_ptr = s->info; info_ptr && *info_ptr; info_ptr += 2) {
598 if (!strcmp (*info_ptr, "hostport")) {
599 setenv("XQF_SERVER_HOSTPORT", info_ptr[1], 1);
600 }
601 }
602 }
603 }
604