1 /*
2  * qstat
3  * by Steve Jankowski
4  * steve@qstat.org
5  * http://www.qstat.org
6  *
7  * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk)
8  * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net)
9  * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com)
10  * Thanks to Simon Garner for the XML patch (sgarner@gameplanet.co.nz)
11  * Thanks to Bob Marriott for the Ghost Recon code (bmarriott@speakeasy.net)
12  *
13  * Inspired by QuakePing by Len Norton
14  *
15  * Copyright 1996,1997,1998,1999,2000,2001,2002,2003,2004 by Steve Jankowski
16  *
17  * Licensed under the Artistic License, see LICENSE.txt for license terms
18  */
19 
20 #define RECV_BUF    204800
21 
22 /* OS/2 defines */
23 #ifdef __OS2__
24 	#define BSD_SELECT
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <assert.h>
36 
37 #define QUERY_PACKETS
38 #include "qstat.h"
39 #include "packet_manip.h"
40 #include "config.h"
41 #include "xform.h"
42 
43 #ifndef _WIN32
44  #include <signal.h>
45  #include <unistd.h>
46  #include <sys/socket.h>
47  #ifndef VMS
48   #include <sys/param.h>
49  #endif
50  #include <sys/time.h>
51  #include <netinet/in.h>
52  #include <netinet/tcp.h>
53  #include <netdb.h>
54  #include <arpa/inet.h>
55 
56  #ifndef F_SETFL
57   #include <fcntl.h>
58  #endif
59 
60  #ifdef DragonFly
61 		extern int h_errno;
62 		#define STATIC    static
63  #else
64 		#define STATIC
65  #endif
66 
67 	#define INVALID_SOCKET		-1
68  #ifndef INADDR_NONE
69 		#define INADDR_NONE	~0
70  #endif
71 	#define sockerr()    errno
72 #else   /* _WIN32 */
73  #include "utils.h"
74 #endif  /* !_WIN32 */
75 
76 #ifdef __OS2__
77  #include <sys/socket.h>
78  #include <sys/select.h>
79  #include <sys/time.h>
80  #include <netinet/in.h>
81  #include <netdb.h>
82  #include <utils.h>
83 
84 	#define INVALID_SOCKET		-1
85 	#define SOCKET_ERROR		-1
86 	#define close(a)    soclose(a)
87 #endif  /* __OS2__ */
88 
89 #ifndef FD_SETSIZE
90 	#define FD_SETSIZE    64
91 #endif
92 
93 /* Figure out whether to use poll() or select()
94  */
95 #ifndef USE_POLL
96  #ifndef USE_SELECT
97 
98   #ifdef sun
99 			#define USE_POLL
100   #endif
101   #ifdef linux
102 			#define USE_POLL
103    #include <poll.h>
104   #endif
105   #ifdef __linux__
106 			#define USE_POLL
107    #include <poll.h>
108   #endif
109   #ifdef __linux
110 			#define USE_POLL
111    #include <poll.h>
112   #endif
113   #ifdef DragonFly
114 			#define USE_POLL
115    #include <sys/poll.h>
116   #endif
117   #ifdef __OpenBSD__
118 			#define USE_POLL
119    #include <sys/poll.h>
120   #endif
121   #ifdef _AIX
122 			#define USE_POLL
123    #include <poll.h>
124   #endif
125   #ifdef _WIN32
126 			#define USE_SELECT
127   #endif
128   #ifdef __EMX__
129 			#define USE_SELECT
130   #endif
131 
132  #endif         /* USE_SELECT */
133 #endif  /* USE_POLL */
134 
135 /* If did not chose, then use select()
136  */
137 #ifndef USE_POLL
138  #ifndef USE_SELECT
139 		#define USE_SELECT
140  #endif
141 #endif
142 
143 #include "debug.h"
144 
145 server_type *types;
146 int n_server_types;
147 char *qstat_version = QSTAT_VERSION;
148 
149 /*
150  * Values set by command-line arguments
151  */
152 
153 int hostname_lookup = 0;        /* set if -H was specified */
154 int new_style = 1;              /* unset if -old was specified */
155 int n_retries = DEFAULT_RETRIES;
156 int retry_interval = DEFAULT_RETRY_INTERVAL;
157 int master_retry_interval = DEFAULT_RETRY_INTERVAL * 4;
158 int syncconnect = 0;
159 int get_player_info = 0;
160 int get_server_rules = 0;
161 int up_servers_only = 0;
162 int no_full_servers = 0;
163 int no_empty_servers = 0;
164 int no_header_display = 0;
165 int raw_display = 0;
166 char *raw_delimiter = "\t";
167 char *multi_delimiter = "|";
168 int player_address = 0;
169 int max_simultaneous = MAXFD_DEFAULT;
170 int sendinterval = 5;
171 extern int xform_names;
172 extern int xform_strip_unprintable;
173 extern int xform_hex_player_names;
174 extern int xform_hex_server_names;
175 extern int xform_strip_carets;
176 extern int xform_html_names;
177 extern int html_mode;
178 int raw_arg = 0;
179 int show_game_in_raw = 0;
180 int progress = 0;
181 int num_servers_total = 0;
182 int num_players_total = 0;
183 int max_players_total = 0;
184 int num_servers_returned = 0;
185 int num_servers_timed_out = 0;
186 int num_servers_down = 0;
187 server_type *default_server_type = NULL;
188 FILE *OF;       /* output file */
189 unsigned int source_ip = INADDR_ANY;
190 unsigned short source_port_low = 0;
191 unsigned short source_port_high = 0;
192 unsigned short source_port = 0;
193 int show_game_port = 0;
194 int no_port_offset = 0;
195 
196 int output_bom = 0;
197 int xml_display = 0;
198 int xml_encoding = ENCODING_LATIN_1;
199 
200 #define SUPPORTED_SERVER_SORT		"pgihn"
201 #define SUPPORTED_PLAYER_SORT		"PFTNS"
202 #define SUPPORTED_SORT_KEYS		"l" SUPPORTED_SERVER_SORT SUPPORTED_PLAYER_SORT
203 char sort_keys[32];
204 int player_sort = 0;
205 int server_sort = 0;
206 
207 int qpartition(void **array, int i, int j, int (*compare)(void *, void *));
208 void sort_servers(struct qserver **array, int size);
209 void sort_players(struct qserver *server);
210 int server_compare(struct qserver *one, struct qserver *two);
211 int player_compare(struct player *one, struct player *two);
212 int process_func_ret(struct qserver *server, int ret);
213 int connection_inprogress();
214 void clear_socketerror();
215 
216 int show_errors = 0;
217 static int noserverdups = 1;
218 
219 #define DEFAULT_COLOR_NAMES_RAW		0
220 #define DEFAULT_COLOR_NAMES_DISPLAY	1
221 int color_names = -1;
222 
223 #define SECONDS				0
224 #define CLOCK_TIME			1
225 #define STOPWATCH_TIME			2
226 #define DEFAULT_TIME_FMT_RAW		SECONDS
227 #define DEFAULT_TIME_FMT_DISPLAY	CLOCK_TIME
228 int time_format = -1;
229 
230 struct qserver *servers = NULL;
231 struct qserver **last_server = &servers;
232 struct qserver **connmap = NULL;
233 int max_connmap;
234 struct qserver *last_server_bind = NULL;
235 struct qserver *first_server_bind = NULL;
236 int connected = 0;
237 time_t run_timeout = 0;
238 time_t start_time;
239 int waiting_for_masters;
240 
241 #define ADDRESS_HASH_LENGTH    2999
242 static unsigned num_servers;/* current number of servers in memory */
243 static struct qserver **server_hash[ADDRESS_HASH_LENGTH];
244 static unsigned int server_hash_len[ADDRESS_HASH_LENGTH];
245 static void free_server_hash();
246 static void xml_display_player_info_info(struct player *player);
247 
248 char *DOWN = "DOWN";
249 char *SYSERROR = "SYSERROR";
250 char *TIMEOUT = "TIMEOUT";
251 char *MASTER = "MASTER";
252 char *SERVERERROR = "ERROR";
253 char *HOSTNOTFOUND = "HOSTNOTFOUND";
254 char *BFRIS_SERVER_NAME = "BFRIS Server";
255 char *GAMESPY_MASTER_NAME = "Gamespy Master";
256 
257 int display_prefix = 0;
258 char *current_filename;
259 int current_fileline;
260 
261 int count_bits(int n);
262 
263 static int qserver_get_timeout(struct qserver *server, struct timeval *now);
264 static int wait_for_timeout(unsigned int ms);
265 static void finish_output();
266 static int decode_stefmaster_packet(struct qserver *server, char *pkt, int pktlen);
267 static int decode_q3master_packet(struct qserver *server, char *ikt, int pktlen);
268 
269 char *ut2003_strdup(const char *string, const char *end, char **next);
270 
271 void free_server(struct qserver *server);
272 void free_player(struct player *player);
273 void free_rule(struct rule *rule);
274 void standard_display_server(struct qserver *server);
275 
276 /* MODIFY HERE
277  * Change these functions to display however you want
278  */
279 void
display_server(struct qserver * server)280 display_server(struct qserver *server)
281 {
282 	if (player_sort) {
283 		sort_players(server);
284 	}
285 
286 	if (raw_display) {
287 		raw_display_server(server);
288 	} else if (xml_display) {
289 		xml_display_server(server);
290 	} else if (json_display) {
291 		json_display_server(server);
292 	} else if (have_server_template()) {
293 		template_display_server(server);
294 	} else {
295 		standard_display_server(server);
296 	}
297 
298 	free_server(server);
299 }
300 
301 
302 void
standard_display_server(struct qserver * server)303 standard_display_server(struct qserver *server)
304 {
305 	char prefix[64];
306 
307 	if (display_prefix) {
308 		sprintf(prefix, "%-4s ", server->type->type_prefix);
309 	} else {
310 		prefix[0] = '\0';
311 	}
312 
313 	if ((server->server_name == DOWN) || (server->server_name == SYSERROR)) {
314 		if (!up_servers_only) {
315 			xform_printf(OF, "%s%-16s %10s\n", prefix, (hostname_lookup) ? server->host_name : server->arg, server->server_name);
316 		}
317 		return;
318 	}
319 
320 	if (server->server_name == TIMEOUT) {
321 		if (server->flags & FLAG_BROADCAST && server->n_servers) {
322 			xform_printf(OF, "%s%-16s %d servers\n", prefix, server->arg, server->n_servers);
323 		} else if (!up_servers_only) {
324 			xform_printf(OF, "%s%-16s no response\n", prefix, (hostname_lookup) ? server->host_name : server->arg);
325 		}
326 		return;
327 	}
328 
329 	if (server->type->master) {
330 		display_qwmaster(server);
331 		return;
332 	}
333 
334 	if (no_full_servers && (server->num_players >= server->max_players)) {
335 		return;
336 	}
337 
338 	if (no_empty_servers && (server->num_players == 0)) {
339 		return;
340 	}
341 
342 	if (server->error != NULL) {
343 		xform_printf(OF, "%s%-21s ERROR <%s>\n", prefix, (hostname_lookup) ? server->host_name : server->arg, server->error);
344 		return;
345 	}
346 
347 	if (new_style) {
348 		char *game = get_qw_game(server);
349 		int map_name_width = 8, game_width = 0;
350 		switch (server->type->id) {
351 		case QW_SERVER:
352 		case Q2_SERVER:
353 		case Q3_SERVER:
354 			game_width = 9;
355 			break;
356 
357 		case TRIBES2_SERVER:
358 			map_name_width = 14;
359 			game_width = 8;
360 			break;
361 
362 		case GHOSTRECON_SERVER:
363 			map_name_width = 15;
364 			game_width = 15;
365 			break;
366 
367 		case HL_SERVER:
368 			map_name_width = 12;
369 			break;
370 
371 		default:
372 			break;
373 		}
374 		xform_printf(OF,
375 		    "%s%-21s %2d/%-2d %2d/%-2d %*s %6d / %1d  %*s %s\n",
376 		    prefix,
377 		    (hostname_lookup) ? server->host_name : server->arg,
378 		    server->num_players,
379 		    server->max_players,
380 		    server->num_spectators,
381 		    server->max_spectators,
382 		    map_name_width,
383 		    (server->map_name) ? xform_name(server->map_name, server) : "?",
384 		    server->n_requests ? server->ping_total / server->n_requests : 999,
385 		    server->n_retries,
386 		    game_width,
387 		    game,
388 		    xform_name(server->server_name, server)
389 		    );
390 		if (get_server_rules && (NULL != server->type->display_rule_func)) {
391 			server->type->display_rule_func(server);
392 		}
393 		if (get_player_info && (NULL != server->type->display_player_func)) {
394 			server->type->display_player_func(server);
395 		}
396 	} else {
397 		char name[512];
398 		sprintf(name, "\"%s\"", server->server_name);
399 		xform_printf(OF,
400 		    "%-16s %10s map %s at %22s %d/%d players %d ms\n",
401 		    (hostname_lookup) ? server->host_name : server->arg,
402 		    name,
403 		    server->map_name,
404 		    server->address,
405 		    server->num_players,
406 		    server->max_players,
407 		    server->n_requests ? server->ping_total / server->n_requests : 999
408 		    );
409 	}
410 }
411 
412 
413 void
display_qwmaster(struct qserver * server)414 display_qwmaster(struct qserver *server)
415 {
416 	char *prefix;
417 
418 	prefix = server->type->type_prefix;
419 
420 	if (server->error != NULL) {
421 		xform_printf(OF,
422 		    "%s %-17s ERROR <%s>\n",
423 		    prefix,
424 		    (hostname_lookup) ? server->host_name : server->arg,
425 		    server->error
426 		    );
427 	} else {
428 		xform_printf(OF,
429 		    "%s %-17s %d servers %6d / %1d\n",
430 		    prefix,
431 		    (hostname_lookup) ? server->host_name : server->arg,
432 		    server->n_servers,
433 		    server->n_requests ? server->ping_total / server->n_requests : 999,
434 		    server->n_retries
435 		    );
436 	}
437 }
438 
439 
440 void
display_header()441 display_header()
442 {
443 	if (!no_header_display) {
444 		xform_printf(OF, "%-16s %8s %8s %15s    %s\n", "ADDRESS", "PLAYERS", "MAP", "RESPONSE TIME", "NAME");
445 	}
446 }
447 
448 
449 void
display_server_rules(struct qserver * server)450 display_server_rules(struct qserver *server)
451 {
452 	struct rule *rule;
453 	int printed = 0;
454 
455 	rule = server->rules;
456 	for ( ; rule != NULL; rule = rule->next) {
457 		if (((server->type->id != Q_SERVER) && (server->type->id != H2_SERVER)) || !is_default_rule(rule)) {
458 			xform_printf(OF, "%c%s=%s", (printed) ? ',' : '\t', rule->name, rule->value);
459 			printed++;
460 		}
461 	}
462 	if (printed) {
463 		fputs("\n", OF);
464 	}
465 }
466 
467 
468 void
display_q_player_info(struct qserver * server)469 display_q_player_info(struct qserver *server)
470 {
471 	char fmt[128];
472 	struct player *player;
473 
474 	strcpy(fmt, "\t#%-2d %3d frags %9s ");
475 
476 	if (color_names) {
477 		strcat(fmt, "%9s:%-9s ");
478 	} else {
479 		strcat(fmt, "%2s:%-2s ");
480 	}
481 	if (player_address) {
482 		strcat(fmt, "%22s ");
483 	} else {
484 		strcat(fmt, "%s");
485 	}
486 	strcat(fmt, "%s\n");
487 
488 	player = server->players;
489 	for ( ; player != NULL; player = player->next) {
490 		xform_printf(OF, fmt,
491 		    player->number,
492 		    player->frags,
493 		    play_time(player->connect_time, 1),
494 		    quake_color(player->shirt_color),
495 		    quake_color(player->pants_color),
496 		    (player_address) ? player->address : "",
497 		    xform_name(player->name, server)
498 		    );
499 	}
500 }
501 
502 
503 void
display_qw_player_info(struct qserver * server)504 display_qw_player_info(struct qserver *server)
505 {
506 	char fmt[128];
507 	struct player *player;
508 
509 	strcpy(fmt, "\t#%-6d %5d frags %6s@%-5s %8s");
510 
511 	if (color_names) {
512 		strcat(fmt, "%9s:%-9s ");
513 	} else {
514 		strcat(fmt, "%2s:%-2s ");
515 	}
516 	strcat(fmt, "%12s %s\n");
517 
518 	player = server->players;
519 	for ( ; player != NULL; player = player->next) {
520 		xform_printf(OF, fmt,
521 		    player->number,
522 		    player->frags,
523 		    play_time(player->connect_time, 0),
524 		    ping_time(player->ping),
525 		    player->skin ? player->skin : "",
526 		    quake_color(player->shirt_color),
527 		    quake_color(player->pants_color),
528 		    xform_name(player->name, server),
529 		    xform_name(player->team_name, server)
530 		    );
531 	}
532 }
533 
534 
535 void
display_q2_player_info(struct qserver * server)536 display_q2_player_info(struct qserver *server)
537 {
538 	struct player *player;
539 
540 	player = server->players;
541 	for ( ; player != NULL; player = player->next) {
542 		if (server->flags & FLAG_PLAYER_TEAMS) {
543 			xform_printf(OF, "\t%3d frags team#%d %8s  %s\n", player->frags, player->team, ping_time(player->ping), xform_name(player->name, server));
544 		} else {
545 			xform_printf(OF, "\t%3d frags %8s  %s\n", player->frags, ping_time(player->ping), xform_name(player->name, server));
546 		}
547 	}
548 }
549 
550 
551 void
display_unreal_player_info(struct qserver * server)552 display_unreal_player_info(struct qserver *server)
553 {
554 	struct player *player;
555 	static const char *fmt_team_number = "\t%3d frags team#%-3d %7s %s\n";
556 	static const char *fmt_team_name = "\t%3d frags %8s %7s %s\n";
557 	static const char *fmt_no_team = "\t%3d frags %8s  %s\n";
558 
559 	player = server->players;
560 	for ( ; player != NULL; player = player->next) {
561 		if (server->flags & FLAG_PLAYER_TEAMS) {
562 			// we use (player->score) ? player->score : player->frags,
563 			// so we get details from halo
564 			if (player->team_name) {
565 				xform_printf(OF, fmt_team_name,
566 				    (player->score && NA_INT != player->score) ? player->score : player->frags,
567 				    player->team_name,
568 				    ping_time(player->ping),
569 				    xform_name(player->name, server)
570 				    );
571 			} else {
572 				xform_printf(OF, fmt_team_number,
573 				    (player->score && NA_INT != player->score) ? player->score : player->frags,
574 				    player->team,
575 				    ping_time(player->ping),
576 				    xform_name(player->name, server)
577 				    );
578 			}
579 		} else {
580 			xform_printf(OF, fmt_no_team, player->frags, ping_time(player->ping), xform_name(player->name, server));
581 		}
582 	}
583 }
584 
585 
586 void
display_shogo_player_info(struct qserver * server)587 display_shogo_player_info(struct qserver *server)
588 {
589 	struct player *player;
590 
591 	player = server->players;
592 	for ( ; player != NULL; player = player->next) {
593 		xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, ping_time(player->ping), xform_name(player->name, server));
594 	}
595 }
596 
597 
598 void
display_halflife_player_info(struct qserver * server)599 display_halflife_player_info(struct qserver *server)
600 {
601 	struct player *player;
602 
603 	player = server->players;
604 	for ( ; player != NULL; player = player->next) {
605 		xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server));
606 	}
607 }
608 
609 
610 void
display_fl_player_info(struct qserver * server)611 display_fl_player_info(struct qserver *server)
612 {
613 	struct player *player;
614 
615 	player = server->players;
616 	for ( ; player != NULL; player = player->next) {
617 		xform_printf(OF, "\t%3d frags %8s %8s %s\n", player->frags, ping_time(player->ping), play_time(player->connect_time, 1), xform_name(player->name, server));
618 	}
619 }
620 
621 
622 void
display_tribes_player_info(struct qserver * server)623 display_tribes_player_info(struct qserver *server)
624 {
625 	struct player *player;
626 
627 	player = server->players;
628 	for ( ; player != NULL; player = player->next) {
629 		xform_printf(OF, "\t%4d score team#%d %8s %s\n", player->frags, player->team, ping_time(player->ping), xform_name(player->name, server)
630 		    );
631 	}
632 }
633 
634 
635 void
display_tribes2_player_info(struct qserver * server)636 display_tribes2_player_info(struct qserver *server)
637 {
638 	struct player *player;
639 
640 	player = server->players;
641 	for ( ; player != NULL; player = player->next) {
642 		xform_printf(OF, "\tscore %4d %14s %s\n",
643 		    player->frags,
644 		    player->team_name ? player->team_name : (player->number == TRIBES_TEAM ? "TEAM" : "?"),
645 		    xform_name(player->name, server)
646 		    );
647 	}
648 }
649 
650 
651 void
display_bfris_player_info(struct qserver * server)652 display_bfris_player_info(struct qserver *server)
653 {
654 	struct player *player;
655 
656 	player = server->players;
657 	for ( ; player != NULL; player = player->next) {
658 		xform_printf(OF, "\ttid: %d, ship: %d, team: %s, ping: %d, score: %d, kills: %d, name: %s\n",
659 		    player->number,
660 		    player->ship,
661 		    player->team_name,
662 		    player->ping,
663 		    player->score,
664 		    player->frags,
665 		    xform_name(player->name, server)
666 		    );
667 	}
668 }
669 
670 
671 void
display_descent3_player_info(struct qserver * server)672 display_descent3_player_info(struct qserver *server)
673 {
674 	struct player *player;
675 
676 	player = server->players;
677 	for ( ; player != NULL; player = player->next) {
678 		xform_printf(OF, "\t%3d frags %3d deaths team#%-3d %7s %s\n",
679 		    player->frags,
680 		    player->deaths,
681 		    player->team,
682 		    ping_time(player->ping),
683 		    xform_name(player->name, server)
684 		    );
685 	}
686 }
687 
688 
689 void
display_ghostrecon_player_info(struct qserver * server)690 display_ghostrecon_player_info(struct qserver *server)
691 {
692 	struct player *player;
693 
694 	player = server->players;
695 	for ( ; player != NULL; player = player->next) {
696 		xform_printf(OF, "\tdead=%3d team#%-3d %s\n", player->deaths, player->team, xform_name(player->name, server));
697 	}
698 }
699 
700 
701 void
display_eye_player_info(struct qserver * server)702 display_eye_player_info(struct qserver *server)
703 {
704 	struct player *player;
705 
706 	player = server->players;
707 	for ( ; player != NULL; player = player->next) {
708 		if (player->team_name) {
709 			xform_printf(OF, "\tscore %4d %6s team %12s %s\n",
710 			    player->score,
711 			    ping_time(player->ping),
712 			    player->team_name,
713 			    xform_name(player->name, server)
714 			    );
715 		} else {
716 			xform_printf(OF, "\tscore %4d %6s team#%d %s\n",
717 			    player->score,
718 			    ping_time(player->ping),
719 			    player->team,
720 			    xform_name(player->name, server)
721 			    );
722 		}
723 	}
724 }
725 
726 
727 int
calculate_armyops_score(struct player * player)728 calculate_armyops_score(struct player *player)
729 {
730 	/* Calculates a player's score for ArmyOps from the basic components */
731 
732 	int score = 0;
733 	int kill_score = 0;
734 	struct info *info;
735 
736 	for (info = player->info; info; info = info->next) {
737 		if ((0 == strcmp(info->name, "leader")) || (0 == strcmp(info->name, "goal")) || (0 == strcmp(info->name, "roe"))) {
738 			score += atoi(info->value);
739 		} else if ((0 == strcmp(info->name, "kia")) || (0 == strcmp(info->name, "enemy"))) {
740 			kill_score += atoi(info->value);
741 		}
742 	}
743 
744 	if (kill_score > 0) {
745 		score += kill_score;
746 	}
747 
748 	return (score);
749 }
750 
751 
752 void
display_gs2_player_info(struct qserver * server)753 display_gs2_player_info(struct qserver *server)
754 {
755 	struct player *player;
756 
757 	player = server->players;
758 	for ( ; player != NULL; player = player->next) {
759 		if (player->team_name) {
760 			xform_printf(OF, "\tscore %4d %6s team %12s %s\n",
761 			    player->score,
762 			    ping_time(player->ping),
763 			    player->team_name,
764 			    xform_name(player->name, server)
765 			    );
766 		} else {
767 			xform_printf(OF, "\tscore %4d %6s team#%d %s\n",
768 			    player->score,
769 			    ping_time(player->ping),
770 			    player->team,
771 			    xform_name(player->name, server)
772 			    );
773 		}
774 	}
775 }
776 
777 
778 void
display_armyops_player_info(struct qserver * server)779 display_armyops_player_info(struct qserver *server)
780 {
781 	struct player *player;
782 
783 	player = server->players;
784 	for ( ; player != NULL; player = player->next) {
785 		player->score = calculate_armyops_score(player);
786 	}
787 
788 	display_gs2_player_info(server);
789 }
790 
791 
792 void
display_ts2_player_info(struct qserver * server)793 display_ts2_player_info(struct qserver *server)
794 {
795 	struct player *player;
796 
797 	player = server->players;
798 	for ( ; player != NULL; player = player->next) {
799 		xform_printf(OF, "\t%6s %s\n", ping_time(player->ping), xform_name(player->name, server));
800 	}
801 }
802 
803 
804 void
display_ts3_player_info(struct qserver * server)805 display_ts3_player_info(struct qserver *server)
806 {
807 	struct player *player;
808 
809 	player = server->players;
810 	for ( ; player != NULL; player = player->next) {
811 		xform_printf(OF, "\t%s\n", xform_name(player->name, server));
812 	}
813 }
814 
815 
816 void
display_starmade_player_info(struct qserver * server)817 display_starmade_player_info(struct qserver *server)
818 {
819 	struct player *player;
820 
821 	player = server->players;
822 	for ( ; player != NULL; player = player->next) {
823 		xform_printf(OF, "\t%s\n", xform_name(player->name, server));
824 	}
825 }
826 
827 
828 void
display_bfbc2_player_info(struct qserver * server)829 display_bfbc2_player_info(struct qserver *server)
830 {
831 	struct player *player;
832 
833 	player = server->players;
834 	for ( ; player != NULL; player = player->next) {
835 		xform_printf(OF, "\t%s\n", xform_name(player->name, server));
836 	}
837 }
838 
839 
840 void
display_wic_player_info(struct qserver * server)841 display_wic_player_info(struct qserver *server)
842 {
843 	struct player *player;
844 
845 	player = server->players;
846 	for ( ; player != NULL; player = player->next) {
847 		xform_printf(OF, "\t#%-4d score %4d team %12s role %12s %s\n",
848 		    player->number,
849 		    player->score,
850 		    player->team_name,
851 		    player->tribe_tag ? player->tribe_tag : "",
852 		    xform_name(player->name, server)
853 		    );
854 	}
855 }
856 
857 
858 void
display_ventrilo_player_info(struct qserver * server)859 display_ventrilo_player_info(struct qserver *server)
860 {
861 	struct player *player;
862 
863 	player = server->players;
864 	for ( ; player != NULL; player = player->next) {
865 		xform_printf(OF, "\t# %d ping %s time %d cid %i ch %s name %s\n",
866 		    player->number,
867 		    ping_time(player->ping),
868 		    player->connect_time,
869 		    player->team,
870 		    player->team_name,
871 		    xform_name(player->name, server)
872 		    );
873 	}
874 }
875 
876 
877 void
display_tm_player_info(struct qserver * server)878 display_tm_player_info(struct qserver *server)
879 {
880 	struct player *player;
881 
882 	player = server->players;
883 	for ( ; player != NULL; player = player->next) {
884 		xform_printf(OF, "\t%6s %s\n", ping_time(player->ping), xform_name(player->name, server));
885 	}
886 }
887 
888 
889 void
display_doom3_player_info(struct qserver * server)890 display_doom3_player_info(struct qserver *server)
891 {
892 	struct player *player;
893 
894 	player = server->players;
895 	for ( ; player != NULL; player = player->next) {
896 		if (player->tribe_tag) {
897 			xform_printf(OF, "\t#%-4d score %4d %6s team %12s %s\n",
898 			    player->number,
899 			    player->score,
900 			    ping_time(player->ping),
901 			    player->tribe_tag,
902 			    xform_name(player->name, server)
903 			    );
904 		} else {
905 			xform_printf(OF, "\t#%-4d score %4d %6s team#%d %s\n",
906 			    player->number,
907 			    player->score,
908 			    ping_time(player->ping),
909 			    player->team,
910 			    xform_name(player->name, server)
911 			    );
912 		}
913 	}
914 }
915 
916 
917 void
display_ravenshield_player_info(struct qserver * server)918 display_ravenshield_player_info(struct qserver *server)
919 {
920 	struct player *player = server->players;
921 
922 	for ( ; player != NULL; player = player->next) {
923 		xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server));
924 	}
925 }
926 
927 
928 void
display_savage_player_info(struct qserver * server)929 display_savage_player_info(struct qserver *server)
930 {
931 	struct player *player = server->players;
932 
933 	for ( ; player != NULL; player = player->next) {
934 		xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server));
935 	}
936 }
937 
938 
939 void
display_farcry_player_info(struct qserver * server)940 display_farcry_player_info(struct qserver *server)
941 {
942 	struct player *player = server->players;
943 
944 	for ( ; player != NULL; player = player->next) {
945 		xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server));
946 	}
947 }
948 
949 
950 void
display_tee_player_info(struct qserver * server)951 display_tee_player_info(struct qserver *server)
952 {
953 	struct player *player;
954 
955 	player = server->players;
956 	for ( ; player != NULL; player = player->next) {
957 		xform_printf(OF, "\t%4d score %s\n", player->score, xform_name(player->name, server));
958 	}
959 }
960 
961 
962 char *
get_qw_game(struct qserver * server)963 get_qw_game(struct qserver *server)
964 {
965 	struct rule *rule;
966 	char *game_rule = server->type->game_rule;
967 
968 	if ((game_rule == NULL) || (*game_rule == '\0')) {
969 		return ("");
970 	}
971 	rule = server->rules;
972 	for ( ; rule != NULL; rule = rule->next) {
973 		if (strcmp(rule->name, game_rule) == 0) {
974 			if ((server->type->id == Q3_SERVER) && (strcmp(rule->value, "baseq3") == 0)) {
975 				return ("");
976 			}
977 			return (rule->value);
978 		}
979 	}
980 	rule = server->rules;
981 	for ( ; rule != NULL; rule = rule->next) {
982 		if ((0 == strcmp(rule->name, "game")) || (0 == strcmp(rule->name, "fs_game"))) {
983 			return (rule->value);
984 		}
985 	}
986 	return ("");
987 }
988 
989 
990 /* Raw output for web master types
991  */
992 
993 #define RD    raw_delimiter
994 
995 void
raw_display_server(struct qserver * server)996 raw_display_server(struct qserver *server)
997 {
998 	char *prefix;
999 	int ping_time;
1000 
1001 	prefix = server->type->type_prefix;
1002 
1003 	if (server->n_requests) {
1004 		ping_time = server->ping_total / server->n_requests;
1005 	} else {
1006 		ping_time = 999;
1007 	}
1008 
1009 	if ((server->server_name == DOWN) || (server->server_name == SYSERROR)) {
1010 		if (!up_servers_only) {
1011 			xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n",
1012 			    prefix,
1013 			    raw_arg, RD,
1014 			    raw_arg,
1015 			    server->arg, RD,
1016 			    (hostname_lookup) ? server->host_name : server->arg, RD,
1017 			    server->server_name
1018 			    );
1019 		}
1020 		return;
1021 	}
1022 
1023 	if (server->server_name == TIMEOUT) {
1024 		if (server->flags & FLAG_BROADCAST && server->n_servers) {
1025 			xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%d\n", prefix, raw_arg, RD, raw_arg, server->arg, RD, server->arg, RD, server->n_servers);
1026 		} else if (!up_servers_only) {
1027 			xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s\n\n", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name : server->arg, RD, TIMEOUT);
1028 		}
1029 		return;
1030 	}
1031 
1032 	if (server->error != NULL) {
1033 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s",
1034 		    prefix,
1035 		    raw_arg, RD,
1036 		    raw_arg,
1037 		    server->arg, RD,
1038 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1039 		    "ERROR", RD,
1040 		    server->error
1041 		    );
1042 	} else if (server->type->flags & TF_RAW_STYLE_QUAKE) {
1043 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
1044 		    prefix,
1045 		    raw_arg, RD,
1046 		    raw_arg,
1047 		    server->arg, RD,
1048 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1049 		    xform_name(server->server_name, server), RD,
1050 		    server->address, RD,
1051 		    server->protocol_version, RD,
1052 		    server->map_name, RD,
1053 		    server->max_players, RD,
1054 		    server->num_players, RD,
1055 		    server->max_spectators, RD,
1056 		    server->num_spectators, RD,
1057 		    ping_time, RD,
1058 		    server->n_retries,
1059 		    show_game_in_raw ? RD : "",
1060 		    show_game_in_raw ? get_qw_game(server) : ""
1061 		    );
1062 	} else if (server->type->flags & TF_RAW_STYLE_TRIBES) {
1063 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d",
1064 		    prefix,
1065 		    raw_arg, RD,
1066 		    raw_arg,
1067 		    server->arg, RD,
1068 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1069 		    xform_name(server->server_name, server), RD,
1070 		    (server->map_name) ? server->map_name : "?", RD,
1071 		    server->num_players, RD,
1072 		    server->max_players
1073 		    );
1074 	} else if (server->type->flags & TF_RAW_STYLE_GHOSTRECON) {
1075 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d",
1076 		    prefix,
1077 		    raw_arg, RD,
1078 		    raw_arg,
1079 		    server->arg, RD,
1080 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1081 		    xform_name(server->server_name, server), RD,
1082 		    (server->map_name) ? server->map_name : "?", RD,
1083 		    server->num_players, RD,
1084 		    server->max_players
1085 		    );
1086 	} else if (server->type->master) {
1087 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%d",
1088 		    prefix,
1089 		    raw_arg, RD,
1090 		    raw_arg,
1091 		    server->arg, RD,
1092 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1093 		    server->n_servers
1094 		    );
1095 	} else {
1096 		xform_printf(OF, "%s" "%.*s%.*s" "%s%s" "%s%s" "%s%s" "%s%d" "%s%d" "%s%d" "%s%d" "%s%s",
1097 		    prefix,
1098 		    raw_arg, RD,
1099 		    raw_arg,
1100 		    server->arg, RD,
1101 		    (hostname_lookup) ? server->host_name : server->arg, RD,
1102 		    xform_name(server->server_name, server), RD,
1103 		    (server->map_name) ? xform_name(server->map_name, server) : "?", RD,
1104 		    server->max_players, RD,
1105 		    server->num_players, RD,
1106 		    ping_time, RD,
1107 		    server->n_retries,
1108 		    show_game_in_raw ? RD : "",
1109 		    show_game_in_raw ? get_qw_game(server) : ""
1110 		    );
1111 	}
1112 	fputs("\n", OF);
1113 
1114 	if (server->type->master || (server->error != NULL)) {
1115 		fputs("\n", OF);
1116 		return;
1117 	}
1118 
1119 	if (get_server_rules && (NULL != server->type->display_raw_rule_func)) {
1120 		server->type->display_raw_rule_func(server);
1121 	}
1122 	if (get_player_info && (NULL != server->type->display_raw_player_func)) {
1123 		server->type->display_raw_player_func(server);
1124 	}
1125 	fputs("\n", OF);
1126 }
1127 
1128 
1129 void
raw_display_server_rules(struct qserver * server)1130 raw_display_server_rules(struct qserver *server)
1131 {
1132 	struct rule *rule;
1133 	int printed = 0;
1134 
1135 	rule = server->rules;
1136 	for ( ; rule != NULL; rule = rule->next) {
1137 		if (server->type->id == TRIBES2_SERVER) {
1138 			char *v;
1139 			for (v = rule->value; *v; v++) {
1140 				if (*v == '\n') {
1141 					*v = ' ';
1142 				}
1143 			}
1144 		}
1145 
1146 		xform_printf(OF, "%s%s=%s", (printed) ? RD : "", rule->name, rule->value);
1147 		printed++;
1148 	}
1149 	if (server->missing_rules) {
1150 		xform_printf(OF, "%s?", (printed) ? RD : "");
1151 	}
1152 	fputs("\n", OF);
1153 }
1154 
1155 
1156 void
raw_display_q_player_info(struct qserver * server)1157 raw_display_q_player_info(struct qserver *server)
1158 {
1159 	char fmt[] = "%d" "%s%s" "%s%s" "%s%d" "%s%s" "%s%s" "%s%s";
1160 	struct player *player;
1161 
1162 	player = server->players;
1163 	for ( ; player != NULL; player = player->next) {
1164 		xform_printf(OF, fmt,
1165 		    player->number, RD,
1166 		    xform_name(player->name, server), RD,
1167 		    player->address, RD,
1168 		    player->frags, RD,
1169 		    play_time(player->connect_time, 1), RD,
1170 		    quake_color(player->shirt_color), RD,
1171 		    quake_color(player->pants_color)
1172 		    );
1173 		fputs("\n", OF);
1174 	}
1175 }
1176 
1177 
1178 void
raw_display_qw_player_info(struct qserver * server)1179 raw_display_qw_player_info(struct qserver *server)
1180 {
1181 	char fmt[128];
1182 	struct player *player;
1183 
1184 	strcpy(fmt, "%d" "%s%s" "%s%d" "%s%s" "%s%s" "%s%s");
1185 	strcat(fmt, "%s%d" "%s%s" "%s%s");
1186 
1187 	player = server->players;
1188 	for ( ; player != NULL; player = player->next) {
1189 		xform_printf(OF, fmt,
1190 		    player->number, RD,
1191 		    xform_name(player->name, server), RD,
1192 		    player->frags, RD,
1193 		    play_time(player->connect_time, 1), RD,
1194 		    quake_color(player->shirt_color), RD,
1195 		    quake_color(player->pants_color), RD,
1196 		    player->ping, RD,
1197 		    player->skin ? player->skin : "", RD,
1198 		    player->team_name ? player->team_name : ""
1199 		    );
1200 		fputs("\n", OF);
1201 	}
1202 }
1203 
1204 
1205 void
raw_display_q2_player_info(struct qserver * server)1206 raw_display_q2_player_info(struct qserver *server)
1207 {
1208 	static const char *fmt = "%s" "%s%d" "%s%d";
1209 	static const char *fmt_team = "%s" "%s%d" "%s%d" "%s%d";
1210 	struct player *player;
1211 
1212 	player = server->players;
1213 	for ( ; player != NULL; player = player->next) {
1214 		if (server->flags & FLAG_PLAYER_TEAMS) {
1215 			xform_printf(OF, fmt_team, xform_name(player->name, server), RD, player->frags, RD, player->ping, RD, player->team);
1216 		} else {
1217 			xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->ping);
1218 		}
1219 		fputs("\n", OF);
1220 	}
1221 }
1222 
1223 
1224 void
raw_display_unreal_player_info(struct qserver * server)1225 raw_display_unreal_player_info(struct qserver *server)
1226 {
1227 	static const char *fmt = "%s" "%s%d" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
1228 	static const char *fmt_team_name = "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s" "%s%s";
1229 	struct player *player;
1230 
1231 	player = server->players;
1232 	for ( ; player != NULL; player = player->next) {
1233 		if (player->team_name) {
1234 			xform_printf(OF, fmt_team_name,
1235 			    xform_name(player->name, server), RD,
1236 			    player->frags, RD,
1237 			    player->ping, RD,
1238 			    player->team_name, RD,
1239 			    player->skin ? player->skin : "", RD,
1240 			    player->mesh ? player->mesh : "", RD,
1241 			    player->face ? player->face : ""
1242 			    );
1243 		} else {
1244 			xform_printf(OF, fmt,
1245 			    xform_name(player->name, server), RD,
1246 			    player->frags, RD,
1247 			    player->ping, RD,
1248 			    player->team, RD,
1249 			    player->skin ? player->skin : "", RD,
1250 			    player->mesh ? player->mesh : "", RD,
1251 			    player->face ? player->face : ""
1252 			    );
1253 		}
1254 		fputs("\n", OF);
1255 	}
1256 }
1257 
1258 
1259 void
raw_display_halflife_player_info(struct qserver * server)1260 raw_display_halflife_player_info(struct qserver *server)
1261 {
1262 	static char fmt[24] = "%s" "%s%d" "%s%s";
1263 	struct player *player;
1264 
1265 	player = server->players;
1266 	for ( ; player != NULL; player = player->next) {
1267 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1));
1268 		fputs("\n", OF);
1269 	}
1270 }
1271 
1272 
1273 void
raw_display_fl_player_info(struct qserver * server)1274 raw_display_fl_player_info(struct qserver *server)
1275 {
1276 	static char fmt[24] = "%s" "%s%d" "%s%s" "%s%d" "%s%d";
1277 	struct player *player;
1278 
1279 	player = server->players;
1280 	for ( ; player != NULL; player = player->next) {
1281 		fprintf(
1282 			OF, fmt,
1283 			xform_name(player->name, server), RD,
1284 			player->frags, RD,
1285 			play_time(player->connect_time, 1), RD,
1286 			player->ping, RD,
1287 			player->team
1288 			);
1289 		fputs("\n", OF);
1290 	}
1291 }
1292 
1293 
1294 void
raw_display_tribes_player_info(struct qserver * server)1295 raw_display_tribes_player_info(struct qserver *server)
1296 {
1297 	static char fmt[24] = "%s" "%s%d" "%s%d" "%s%d" "%s%d";
1298 	struct player *player;
1299 
1300 	player = server->players;
1301 	for ( ; player != NULL; player = player->next) {
1302 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->ping, RD, player->team, RD, player->packet_loss);
1303 		fputs("\n", OF);
1304 	}
1305 }
1306 
1307 
1308 void
raw_display_tribes2_player_info(struct qserver * server)1309 raw_display_tribes2_player_info(struct qserver *server)
1310 {
1311 	static char fmt[] = "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
1312 	struct player *player;
1313 	char *type;
1314 
1315 	player = server->players;
1316 	for ( ; player != NULL; player = player->next) {
1317 		switch (player->type_flag) {
1318 		case PLAYER_TYPE_BOT:
1319 			type = "Bot";
1320 			break;
1321 
1322 		case PLAYER_TYPE_ALIAS:
1323 			type = "Alias";
1324 			break;
1325 
1326 		default:
1327 			type = "";
1328 			break;
1329 		}
1330 		xform_printf(OF, fmt,
1331 		    xform_name(player->name, server), RD,
1332 		    player->frags, RD,
1333 		    player->team, RD,
1334 		    player->team_name ? player->team_name : "TEAM", RD,
1335 		    type, RD,
1336 		    player->tribe_tag ? xform_name(player->tribe_tag, server) : ""
1337 		    );
1338 		fputs("\n", OF);
1339 	}
1340 }
1341 
1342 
1343 void
raw_display_bfris_player_info(struct qserver * server)1344 raw_display_bfris_player_info(struct qserver *server)
1345 {
1346 	static char fmt[] = "%d" "%s%d" "%s%s" "%s%d" "%s%d" "%s%d" "%s%s";
1347 	struct player *player;
1348 
1349 	player = server->players;
1350 	for ( ; player != NULL; player = player->next) {
1351 		xform_printf(OF, fmt,
1352 		    player->number, RD,
1353 		    player->ship, RD,
1354 		    player->team_name, RD,
1355 		    player->ping, RD,
1356 		    player->score, RD,
1357 		    player->frags, RD,
1358 		    xform_name(player->name, server)
1359 		    );
1360 		fputs("\n", OF);
1361 	}
1362 }
1363 
1364 
1365 void
raw_display_descent3_player_info(struct qserver * server)1366 raw_display_descent3_player_info(struct qserver *server)
1367 {
1368 	static char fmt[] = "%s" "%s%d" "%s%d" "%s%d" "%s%d";
1369 	struct player *player;
1370 
1371 	player = server->players;
1372 	for ( ; player != NULL; player = player->next) {
1373 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->deaths, RD, player->ping, RD, player->team);
1374 		fputs("\n", OF);
1375 	}
1376 }
1377 
1378 
1379 void
raw_display_ghostrecon_player_info(struct qserver * server)1380 raw_display_ghostrecon_player_info(struct qserver *server)
1381 {
1382 	static char fmt[28] = "%s" "%s%d" "%s%d";
1383 	struct player *player;
1384 
1385 	player = server->players;
1386 	for ( ; player != NULL; player = player->next) {
1387 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->deaths, RD, player->team);
1388 		fputs("\n", OF);
1389 	}
1390 }
1391 
1392 
1393 void
raw_display_eye_player_info(struct qserver * server)1394 raw_display_eye_player_info(struct qserver *server)
1395 {
1396 	static const char *fmt = "%s" "%s%d" "%s%d" "%s%d" "%s%s" "%s%s";
1397 	static const char *fmt_team_name = "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
1398 	struct player *player;
1399 
1400 	player = server->players;
1401 	for ( ; player != NULL; player = player->next) {
1402 		if (player->team_name) {
1403 			xform_printf(OF, fmt_team_name,
1404 			    xform_name(player->name, server), RD,
1405 			    player->score, RD,
1406 			    player->ping, RD,
1407 			    player->team_name, RD,
1408 			    player->skin ? player->skin : "", RD,
1409 			    play_time(player->connect_time, 1)
1410 			    );
1411 		} else {
1412 			xform_printf(OF, fmt,
1413 			    xform_name(player->name, server), RD,
1414 			    player->score, RD,
1415 			    player->ping, RD,
1416 			    player->team, RD,
1417 			    player->skin ? player->skin : "", RD,
1418 			    play_time(player->connect_time, 1)
1419 			    );
1420 		}
1421 		fputs("\n", OF);
1422 	}
1423 }
1424 
1425 
1426 void
raw_display_doom3_player_info(struct qserver * server)1427 raw_display_doom3_player_info(struct qserver *server)
1428 {
1429 	static const char *fmt = "%s" "%s%d" "%s%d" "%s%d" "%s%u";
1430 	static const char *fmt_team_name = "%s" "%s%d" "%s%d" "%s%s" "%s%u";
1431 	struct player *player;
1432 
1433 	player = server->players;
1434 	for ( ; player != NULL; player = player->next) {
1435 		if (player->tribe_tag) {
1436 			xform_printf(OF, fmt_team_name, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->tribe_tag, RD, player->number);
1437 		} else {
1438 			xform_printf(OF, fmt, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->team, RD, player->number);
1439 		}
1440 		fputs("\n", OF);
1441 	}
1442 }
1443 
1444 
1445 void
raw_display_gs2_player_info(struct qserver * server)1446 raw_display_gs2_player_info(struct qserver *server)
1447 {
1448 	static const char *fmt = "%s" "%s%d" "%s%d" "%s%d" "%s%s" "%s%s";
1449 	static const char *fmt_team_name = "%s" "%s%d" "%s%d" "%s%s" "%s%s" "%s%s";
1450 	struct player *player;
1451 
1452 	player = server->players;
1453 	for ( ; player != NULL; player = player->next) {
1454 		if (player->team_name) {
1455 			xform_printf(OF, fmt_team_name, xform_name(player->name, server), RD,
1456 			    player->score, RD,
1457 			    player->ping, RD,
1458 			    player->team_name, RD,
1459 			    player->skin ? player->skin : "", RD,
1460 			    play_time(player->connect_time, 1)
1461 			    );
1462 		} else {
1463 			xform_printf(OF, fmt,
1464 			    xform_name(player->name, server), RD,
1465 			    player->score, RD,
1466 			    player->ping, RD,
1467 			    player->team, RD,
1468 			    player->skin ? player->skin : "", RD,
1469 			    play_time(player->connect_time, 1)
1470 			    );
1471 		}
1472 		fputs("\n", OF);
1473 	}
1474 }
1475 
1476 
1477 void
raw_display_armyops_player_info(struct qserver * server)1478 raw_display_armyops_player_info(struct qserver *server)
1479 {
1480 	struct player *player;
1481 
1482 	player = server->players;
1483 	for ( ; player != NULL; player = player->next) {
1484 		player->score = calculate_armyops_score(player);
1485 	}
1486 
1487 	raw_display_gs2_player_info(server);
1488 }
1489 
1490 
1491 void
raw_display_ts2_player_info(struct qserver * server)1492 raw_display_ts2_player_info(struct qserver *server)
1493 {
1494 	static const char *fmt = "%s" "%s%d" "%s%s" "%s%s";
1495 	struct player *player;
1496 
1497 	player = server->players;
1498 	for ( ; player != NULL; player = player->next) {
1499 		xform_printf(OF, fmt,
1500 		    xform_name(player->name, server), RD,
1501 		    player->ping, RD,
1502 		    player->skin ? player->skin : "", RD,
1503 		    play_time(player->connect_time, 1)
1504 		    );
1505 		fputs("\n", OF);
1506 	}
1507 }
1508 
1509 
1510 void
raw_display_ts3_player_info(struct qserver * server)1511 raw_display_ts3_player_info(struct qserver *server)
1512 {
1513 	static const char *fmt = "%s" "%s%s" "%s%s";
1514 	struct player *player;
1515 
1516 	player = server->players;
1517 	for ( ; player != NULL; player = player->next) {
1518 		xform_printf(OF, fmt,
1519 		    xform_name(player->name, server), RD,
1520 		    player->skin ? player->skin : "", RD,
1521 		    play_time(player->connect_time, 1)
1522 		    );
1523 		fputs("\n", OF);
1524 	}
1525 }
1526 
1527 
1528 void
raw_display_starmade_player_info(struct qserver * server)1529 raw_display_starmade_player_info(struct qserver *server)
1530 {
1531 	static const char *fmt = "%s" "%s%s" "%s%s";
1532 	struct player *player;
1533 
1534 	player = server->players;
1535 	for ( ; player != NULL; player = player->next) {
1536 		xform_printf(OF, fmt,
1537 		    xform_name(player->name, server), RD,
1538 		    player->skin ? player->skin : "", RD,
1539 		    play_time(player->connect_time, 1)
1540 		    );
1541 		fputs("\n", OF);
1542 	}
1543 }
1544 
1545 
1546 void
raw_display_bfbc2_player_info(struct qserver * server)1547 raw_display_bfbc2_player_info(struct qserver *server)
1548 {
1549 	static const char *fmt = "%s" "%s%s" "%s%s";
1550 	struct player *player;
1551 
1552 	player = server->players;
1553 	for ( ; player != NULL; player = player->next) {
1554 		xform_printf(OF, fmt,
1555 		    xform_name(player->name, server), RD,
1556 		    player->skin ? player->skin : "", RD,
1557 		    play_time(player->connect_time, 1)
1558 		    );
1559 		fputs("\n", OF);
1560 	}
1561 }
1562 
1563 
1564 void
raw_display_wic_player_info(struct qserver * server)1565 raw_display_wic_player_info(struct qserver *server)
1566 {
1567 	static const char *fmt = "%s" "%s%d" "%s%s" "%s%s";
1568 	struct player *player;
1569 
1570 	player = server->players;
1571 	for ( ; player != NULL; player = player->next) {
1572 		xform_printf(OF, fmt,
1573 		    xform_name(player->name, server), RD,
1574 		    player->score, RD,
1575 		    player->team_name, RD,
1576 		    player->tribe_tag ? player->tribe_tag : ""
1577 		    );
1578 		fputs("\n", OF);
1579 	}
1580 }
1581 
1582 
1583 void
raw_display_ventrilo_player_info(struct qserver * server)1584 raw_display_ventrilo_player_info(struct qserver *server)
1585 {
1586 	static const char *fmt = "%s" "%s%d" "%s%s" "%s%s";
1587 	struct player *player;
1588 
1589 	player = server->players;
1590 	for ( ; player != NULL; player = player->next) {
1591 		fprintf(
1592 			OF, fmt,
1593 			xform_name(player->name, server),
1594 			RD, player->team,
1595 			RD, player->team_name,
1596 			RD, play_time(player->connect_time, 1)
1597 			);
1598 		fputs("\n", OF);
1599 	}
1600 }
1601 
1602 
1603 void
raw_display_tm_player_info(struct qserver * server)1604 raw_display_tm_player_info(struct qserver *server)
1605 {
1606 	static const char *fmt = "%s" "%s%d" "%s%s" "%s%s";
1607 	struct player *player;
1608 
1609 	player = server->players;
1610 	for ( ; player != NULL; player = player->next) {
1611 		xform_printf(OF, fmt,
1612 		    xform_name(player->name, server), RD,
1613 		    player->ping, RD,
1614 		    player->skin ? player->skin : "", RD,
1615 		    play_time(player->connect_time, 1)
1616 		    );
1617 		fputs("\n", OF);
1618 	}
1619 }
1620 
1621 
1622 void
raw_display_tee_player_info(struct qserver * server)1623 raw_display_tee_player_info(struct qserver *server)
1624 {
1625 	static const char *fmt = "%s";
1626 	struct player *player;
1627 
1628 	player = server->players;
1629 	for ( ; player != NULL; player = player->next) {
1630 		xform_printf(OF, fmt, xform_name(player->name, server));
1631 		fputs("\n", OF);
1632 	}
1633 }
1634 
1635 
1636 void
raw_display_ravenshield_player_info(struct qserver * server)1637 raw_display_ravenshield_player_info(struct qserver *server)
1638 {
1639 	static char fmt[24] = "%s" "%s%d" "%s%s";
1640 	struct player *player = server->players;
1641 
1642 	for ( ; player != NULL; player = player->next) {
1643 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1));
1644 		fputs("\n", OF);
1645 	}
1646 }
1647 
1648 
1649 void
raw_display_savage_player_info(struct qserver * server)1650 raw_display_savage_player_info(struct qserver *server)
1651 {
1652 	static char fmt[24] = "%s" "%s%d" "%s%s";
1653 	struct player *player = server->players;
1654 
1655 	for ( ; player != NULL; player = player->next) {
1656 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1));
1657 		fputs("\n", OF);
1658 	}
1659 }
1660 
1661 
1662 void
raw_display_farcry_player_info(struct qserver * server)1663 raw_display_farcry_player_info(struct qserver *server)
1664 {
1665 	static char fmt[24] = "%s" "%s%d" "%s%s";
1666 	struct player *player = server->players;
1667 
1668 	for ( ; player != NULL; player = player->next) {
1669 		xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1));
1670 		fputs("\n", OF);
1671 	}
1672 }
1673 
1674 
1675 /* XML output
1676  * Contributed by <sgarner@gameplanet.co.nz> :-)
1677  */
1678 void
xml_display_server(struct qserver * server)1679 xml_display_server(struct qserver *server)
1680 {
1681 	char *prefix;
1682 
1683 	prefix = server->type->type_prefix;
1684 
1685 	if (server->server_name == DOWN) {
1686 		if (!up_servers_only) {
1687 			xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n", xml_escape(prefix), xml_escape(server->arg), xml_escape(DOWN));
1688 			xform_printf(OF, "\t\t<hostname>%s</hostname>\n", xml_escape((hostname_lookup) ? server->host_name : server->arg));
1689 			xform_printf(OF, "\t</server>\n");
1690 		}
1691 		return;
1692 	}
1693 	if (server->server_name == TIMEOUT) {
1694 		if (server->flags & FLAG_BROADCAST && server->n_servers) {
1695 			xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n",
1696 			    xml_escape(prefix),
1697 			    xml_escape(server->arg),
1698 			    xml_escape(TIMEOUT),
1699 			    server->n_servers
1700 			    );
1701 			xform_printf(OF, "\t</server>\n");
1702 		} else if (!up_servers_only) {
1703 			xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n", xml_escape(prefix), xml_escape(server->arg), xml_escape(TIMEOUT));
1704 			xform_printf(OF, "\t\t<hostname>%s</hostname>\n", xml_escape((hostname_lookup) ? server->host_name : server->arg));
1705 			xform_printf(OF, "\t</server>\n");
1706 		}
1707 		return;
1708 	}
1709 
1710 	if (server->error != NULL) {
1711 		xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n", xml_escape(prefix), xml_escape(server->arg), "ERROR");
1712 		xform_printf(OF, "\t\t<hostname>%s</hostname>\n", xml_escape((hostname_lookup) ? server->host_name : server->arg));
1713 		xform_printf(OF, "\t\t<error>%s</error>\n", xml_escape(server->error));
1714 	} else if (server->type->master) {
1715 		xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\" servers=\"%d\">\n", xml_escape(prefix), xml_escape(server->arg), "UP", server->n_servers);
1716 	} else {
1717 		xform_printf(OF, "\t<server type=\"%s\" address=\"%s\" status=\"%s\">\n", xml_escape(prefix), xml_escape(server->arg), "UP");
1718 		xform_printf(OF, "\t\t<hostname>%s</hostname>\n", xml_escape((hostname_lookup) ? server->host_name : server->arg));
1719 		xform_printf(OF, "\t\t<name>%s</name>\n", xml_escape(xform_name(server->server_name, server)));
1720 		xform_printf(OF, "\t\t<gametype>%s</gametype>\n", xml_escape(get_qw_game(server)));
1721 		xform_printf(OF, "\t\t<map>%s</map>\n", xml_escape(xform_name(server->map_name, server)));
1722 		xform_printf(OF, "\t\t<numplayers>%d</numplayers>\n", server->num_players);
1723 		xform_printf(OF, "\t\t<maxplayers>%d</maxplayers>\n", server->max_players);
1724 		xform_printf(OF, "\t\t<numspectators>%d</numspectators>\n", server->num_spectators);
1725 		xform_printf(OF, "\t\t<maxspectators>%d</maxspectators>\n", server->max_spectators);
1726 
1727 		if (!(server->type->flags & TF_RAW_STYLE_TRIBES)) {
1728 			xform_printf(OF, "\t\t<ping>%d</ping>\n", server->n_requests ? server->ping_total / server->n_requests : 999);
1729 			xform_printf(OF, "\t\t<retries>%d</retries>\n", server->n_retries);
1730 		}
1731 
1732 		if (server->type->flags & TF_RAW_STYLE_QUAKE) {
1733 			xform_printf(OF, "\t\t<address>%s</address>\n", xml_escape(server->address));
1734 			xform_printf(OF, "\t\t<protocolversion>%d</protocolversion>\n", server->protocol_version);
1735 		}
1736 	}
1737 
1738 	if (!server->type->master && (server->error == NULL)) {
1739 		if (get_server_rules && (NULL != server->type->display_xml_rule_func)) {
1740 			server->type->display_xml_rule_func(server);
1741 		}
1742 		if (get_player_info && (NULL != server->type->display_xml_player_func)) {
1743 			server->type->display_xml_player_func(server);
1744 		}
1745 	}
1746 
1747 	xform_printf(OF, "\t</server>\n");
1748 }
1749 
1750 
1751 void
xml_header()1752 xml_header()
1753 {
1754 	if (xml_encoding == ENCODING_LATIN_1) {
1755 		xform_printf(OF, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<qstat>\n");
1756 	} else if (output_bom) {
1757 		xform_printf(OF, "%c%c%c<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<qstat>\n", 0xEF, 0xBB, 0xBF);
1758 	} else {
1759 		xform_printf(OF, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<qstat>\n");
1760 	}
1761 }
1762 
1763 
1764 void
xml_footer()1765 xml_footer()
1766 {
1767 	xform_printf(OF, "</qstat>\n");
1768 }
1769 
1770 
1771 void
xml_display_server_rules(struct qserver * server)1772 xml_display_server_rules(struct qserver *server)
1773 {
1774 	struct rule *rule;
1775 
1776 	rule = server->rules;
1777 
1778 	xform_printf(OF, "\t\t<rules>\n");
1779 	for ( ; rule != NULL; rule = rule->next) {
1780 		xform_printf(OF, "\t\t\t<rule name=\"%s\">%s</rule>\n", xml_escape(rule->name), xml_escape(rule->value));
1781 	}
1782 	xform_printf(OF, "\t\t</rules>\n");
1783 }
1784 
1785 
1786 void
xml_display_q_player_info(struct qserver * server)1787 xml_display_q_player_info(struct qserver *server)
1788 {
1789 	struct player *player;
1790 
1791 	xform_printf(OF, "\t\t<players>\n");
1792 
1793 	player = server->players;
1794 	for ( ; player != NULL; player = player->next) {
1795 		xform_printf(OF, "\t\t\t<player number=\"%d\">\n", player->number);
1796 
1797 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1798 		xform_printf(OF, "\t\t\t\t<address>%s</address>\n", xml_escape(player->address));
1799 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1800 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
1801 
1802 		if (color_names) {
1803 			xform_printf(OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n", xml_escape(quake_color(player->shirt_color)));
1804 			xform_printf(OF, "\t\t\t\t<color for=\"pants\">%s</color>\n", xml_escape(quake_color(player->pants_color)));
1805 		} else {
1806 			xform_printf(OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n", quake_color(player->shirt_color));
1807 			xform_printf(OF, "\t\t\t\t<color for=\"pants\">%s</color>\n", quake_color(player->pants_color));
1808 		}
1809 
1810 		xform_printf(OF, "\t\t\t</player>\n");
1811 	}
1812 
1813 	xform_printf(OF, "\t\t</players>\n");
1814 }
1815 
1816 
1817 void
xml_display_qw_player_info(struct qserver * server)1818 xml_display_qw_player_info(struct qserver *server)
1819 {
1820 	struct player *player;
1821 
1822 	xform_printf(OF, "\t\t<players>\n");
1823 
1824 	player = server->players;
1825 	for ( ; player != NULL; player = player->next) {
1826 		xform_printf(OF, "\t\t\t<player number=\"%d\">\n", player->number);
1827 
1828 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1829 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1830 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
1831 
1832 		if (color_names) {
1833 			xform_printf(OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n", xml_escape(quake_color(player->shirt_color)));
1834 			xform_printf(OF, "\t\t\t\t<color for=\"pants\">%s</color>\n", xml_escape(quake_color(player->pants_color)));
1835 		} else {
1836 			xform_printf(OF, "\t\t\t\t<color for=\"shirt\">%s</color>\n", quake_color(player->shirt_color));
1837 			xform_printf(OF, "\t\t\t\t<color for=\"pants\">%s</color>\n", quake_color(player->pants_color));
1838 		}
1839 
1840 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
1841 		xform_printf(OF, "\t\t\t\t<skin>%s</skin>\n", player->skin ? xml_escape(player->skin) : "");
1842 		xform_printf(OF, "\t\t\t\t<team>%s</team>\n", player->team_name ? xml_escape(player->team_name) : "");
1843 
1844 		xform_printf(OF, "\t\t\t</player>\n");
1845 	}
1846 
1847 	xform_printf(OF, "\t\t</players>\n");
1848 }
1849 
1850 
1851 void
xml_display_q2_player_info(struct qserver * server)1852 xml_display_q2_player_info(struct qserver *server)
1853 {
1854 	struct player *player;
1855 
1856 	xform_printf(OF, "\t\t<players>\n");
1857 
1858 	player = server->players;
1859 	for ( ; player != NULL; player = player->next) {
1860 		xform_printf(OF, "\t\t\t<player>\n");
1861 
1862 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1863 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1864 		if (server->flags & FLAG_PLAYER_TEAMS) {
1865 			xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
1866 		}
1867 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
1868 
1869 		xform_printf(OF, "\t\t\t</player>\n");
1870 	}
1871 
1872 	xform_printf(OF, "\t\t</players>\n");
1873 }
1874 
1875 
1876 void
xml_display_player_info_info(struct player * player)1877 xml_display_player_info_info(struct player *player)
1878 {
1879 	struct info *info;
1880 
1881 	for (info = player->info; info; info = info->next) {
1882 		if (info->name) {
1883 			char *name = xml_escape(info->name);
1884 			char *value = xml_escape(info->value);
1885 			xform_printf(OF, "\t\t\t\t<%s>%s</%s>\n", name, value, name);
1886 		}
1887 	}
1888 }
1889 
1890 
1891 void
xml_display_unreal_player_info(struct qserver * server)1892 xml_display_unreal_player_info(struct qserver *server)
1893 {
1894 	struct player *player;
1895 
1896 	xform_printf(OF, "\t\t<players>\n");
1897 
1898 	player = server->players;
1899 	for ( ; player != NULL; player = player->next) {
1900 		xform_printf(OF, "\t\t\t<player>\n");
1901 
1902 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1903 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1904 		if (-999 != player->deaths) {
1905 			xform_printf(OF, "\t\t\t\t<deaths>%d</deaths>\n", player->deaths);
1906 		}
1907 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
1908 
1909 		if (player->team_name) {
1910 			xform_printf(OF, "\t\t\t\t<team>%s</team>\n", xml_escape(player->team_name));
1911 		} else if (-1 != player->team) {
1912 			xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
1913 		}
1914 
1915 		// Some games dont provide
1916 		// so only display if they do
1917 		if (player->skin) {
1918 			xform_printf(OF, "\t\t\t\t<skin>%s</skin>\n", player->skin ? xml_escape(player->skin) : "");
1919 		}
1920 		if (player->mesh) {
1921 			xform_printf(OF, "\t\t\t\t<mesh>%s</mesh>\n", player->mesh ? xml_escape(player->mesh) : "");
1922 		}
1923 		if (player->face) {
1924 			xform_printf(OF, "\t\t\t\t<face>%s</face>\n", player->face ? xml_escape(player->face) : "");
1925 		}
1926 
1927 		xml_display_player_info_info(player);
1928 		xform_printf(OF, "\t\t\t</player>\n");
1929 	}
1930 
1931 	xform_printf(OF, "\t\t</players>\n");
1932 }
1933 
1934 
1935 void
xml_display_halflife_player_info(struct qserver * server)1936 xml_display_halflife_player_info(struct qserver *server)
1937 {
1938 	struct player *player;
1939 
1940 	xform_printf(OF, "\t\t<players>\n");
1941 
1942 	player = server->players;
1943 	for ( ; player != NULL; player = player->next) {
1944 		xform_printf(OF, "\t\t\t<player>\n");
1945 
1946 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1947 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1948 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
1949 
1950 		xform_printf(OF, "\t\t\t</player>\n");
1951 	}
1952 
1953 	xform_printf(OF, "\t\t</players>\n");
1954 }
1955 
1956 
1957 void
xml_display_fl_player_info(struct qserver * server)1958 xml_display_fl_player_info(struct qserver *server)
1959 {
1960 	struct player *player;
1961 
1962 	xform_printf(OF, "\t\t<players>\n");
1963 
1964 	player = server->players;
1965 	for ( ; player != NULL; player = player->next) {
1966 		xform_printf(OF, "\t\t\t<player>\n");
1967 
1968 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1969 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1970 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
1971 		xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
1972 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
1973 
1974 		xform_printf(OF, "\t\t\t</player>\n");
1975 	}
1976 
1977 	xform_printf(OF, "\t\t</players>\n");
1978 }
1979 
1980 
1981 void
xml_display_tribes_player_info(struct qserver * server)1982 xml_display_tribes_player_info(struct qserver *server)
1983 {
1984 	struct player *player;
1985 
1986 	xform_printf(OF, "\t\t<players>\n");
1987 
1988 	player = server->players;
1989 	for ( ; player != NULL; player = player->next) {
1990 		xform_printf(OF, "\t\t\t<player>\n");
1991 
1992 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
1993 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
1994 		xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
1995 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
1996 		xform_printf(OF, "\t\t\t\t<packetloss>%d</packetloss>\n", player->packet_loss);
1997 
1998 		xform_printf(OF, "\t\t\t</player>\n");
1999 	}
2000 
2001 	xform_printf(OF, "\t\t</players>\n");
2002 }
2003 
2004 
2005 void
xml_display_tribes2_player_info(struct qserver * server)2006 xml_display_tribes2_player_info(struct qserver *server)
2007 {
2008 	struct player *player;
2009 	char *type;
2010 
2011 	xform_printf(OF, "\t\t<players>\n");
2012 
2013 	player = server->players;
2014 	for ( ; player != NULL; player = player->next) {
2015 		if (player->team_name) {
2016 			switch (player->type_flag) {
2017 			case PLAYER_TYPE_BOT:
2018 				type = "Bot";
2019 				break;
2020 
2021 			case PLAYER_TYPE_ALIAS:
2022 				type = "Alias";
2023 				break;
2024 
2025 			default:
2026 				type = "";
2027 				break;
2028 			}
2029 
2030 			xform_printf(OF, "\t\t\t<player>\n");
2031 
2032 			xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2033 			xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
2034 			xform_printf(OF, "\t\t\t\t<team number=\"%d\">%s</team>\n", player->team, xml_escape(player->team_name));
2035 			xform_printf(OF, "\t\t\t\t<type>%s</type>\n", xml_escape(type));
2036 			xform_printf(OF, "\t\t\t\t<clan>%s</clan>\n", player->tribe_tag ? xml_escape(xform_name(player->tribe_tag, server)) : "");
2037 
2038 			xform_printf(OF, "\t\t\t</player>\n");
2039 		}
2040 	}
2041 
2042 	xform_printf(OF, "\t\t</players>\n");
2043 }
2044 
2045 
2046 void
xml_display_bfris_player_info(struct qserver * server)2047 xml_display_bfris_player_info(struct qserver *server)
2048 {
2049 	struct player *player;
2050 
2051 	xform_printf(OF, "\t\t<players>\n");
2052 
2053 	player = server->players;
2054 	for ( ; player != NULL; player = player->next) {
2055 		xform_printf(OF, "\t\t\t<player number=\"%d\">\n", player->number);
2056 
2057 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2058 		xform_printf(OF, "\t\t\t\t<score type=\"score\">%d</score>\n", player->score);
2059 		xform_printf(OF, "\t\t\t\t<score type=\"frags\">%d</score>\n", player->frags);
2060 		xform_printf(OF, "\t\t\t\t<team>%s</team>\n", xml_escape(player->team_name));
2061 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2062 		xform_printf(OF, "\t\t\t\t<ship>%d</ship>\n", player->ship);
2063 
2064 		xform_printf(OF, "\t\t\t</player>\n");
2065 	}
2066 
2067 	xform_printf(OF, "\t\t</players>\n");
2068 }
2069 
2070 
2071 void
xml_display_descent3_player_info(struct qserver * server)2072 xml_display_descent3_player_info(struct qserver *server)
2073 {
2074 	struct player *player;
2075 
2076 	xform_printf(OF, "\t\t<players>\n");
2077 
2078 	player = server->players;
2079 	for ( ; player != NULL; player = player->next) {
2080 		xform_printf(OF, "\t\t\t<player>\n");
2081 
2082 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2083 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
2084 		xform_printf(OF, "\t\t\t\t<deaths>%d</deaths>\n", player->deaths);
2085 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2086 		xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
2087 
2088 		xform_printf(OF, "\t\t\t</player>\n");
2089 	}
2090 
2091 	xform_printf(OF, "\t\t</players>\n");
2092 }
2093 
2094 
2095 void
xml_display_ravenshield_player_info(struct qserver * server)2096 xml_display_ravenshield_player_info(struct qserver *server)
2097 {
2098 	struct player *player;
2099 
2100 	xform_printf(OF, "\t\t<players>\n");
2101 
2102 	player = server->players;
2103 	for ( ; player != NULL; player = player->next) {
2104 		xform_printf(OF, "\t\t\t<player>\n");
2105 
2106 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2107 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
2108 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2109 
2110 		xform_printf(OF, "\t\t\t</player>\n");
2111 	}
2112 
2113 	xform_printf(OF, "\t\t</players>\n");
2114 }
2115 
2116 
2117 void
xml_display_ghostrecon_player_info(struct qserver * server)2118 xml_display_ghostrecon_player_info(struct qserver *server)
2119 {
2120 	struct player *player;
2121 
2122 	xform_printf(OF, "\t\t<players>\n");
2123 
2124 	player = server->players;
2125 	for ( ; player != NULL; player = player->next) {
2126 		xform_printf(OF, "\t\t\t<player>\n");
2127 
2128 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2129 		xform_printf(OF, "\t\t\t\t<deaths>%d</deaths>\n", player->deaths);
2130 		xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
2131 
2132 		xform_printf(OF, "\t\t\t</player>\n");
2133 	}
2134 
2135 	xform_printf(OF, "\t\t</players>\n");
2136 }
2137 
2138 
2139 void
xml_display_eye_player_info(struct qserver * server)2140 xml_display_eye_player_info(struct qserver *server)
2141 {
2142 	struct player *player;
2143 
2144 	xform_printf(OF, "\t\t<players>\n");
2145 
2146 	player = server->players;
2147 	for ( ; player != NULL; player = player->next) {
2148 		xform_printf(OF, "\t\t\t<player>\n");
2149 
2150 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2151 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->score);
2152 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2153 		if (player->team_name) {
2154 			xform_printf(OF, "\t\t\t\t<team>%s</team>\n", xml_escape(player->team_name));
2155 		} else {
2156 			xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
2157 		}
2158 		if (player->skin) {
2159 			xform_printf(OF, "\t\t\t\t<skin>%s</skin>\n", xml_escape(player->skin));
2160 		}
2161 		if (player->connect_time) {
2162 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 1)));
2163 		}
2164 
2165 		xform_printf(OF, "\t\t\t</player>\n");
2166 	}
2167 
2168 	xform_printf(OF, "\t\t</players>\n");
2169 }
2170 
2171 
2172 void
xml_display_doom3_player_info(struct qserver * server)2173 xml_display_doom3_player_info(struct qserver *server)
2174 {
2175 	struct player *player;
2176 
2177 	xform_printf(OF, "\t\t<players>\n");
2178 
2179 	player = server->players;
2180 	for ( ; player != NULL; player = player->next) {
2181 		xform_printf(OF, "\t\t\t<player>\n");
2182 
2183 		xform_printf(OF, "\t\t\t\t<number>%u</number>\n", player->number);
2184 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2185 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->score);
2186 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2187 		if (player->tribe_tag) {
2188 			xform_printf(OF, "\t\t\t\t<clan>%s</clan>\n", player->tribe_tag ? xml_escape(xform_name(player->tribe_tag, server)) : "");
2189 		} else {
2190 			xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
2191 		}
2192 		if (player->skin) {
2193 			xform_printf(OF, "\t\t\t\t<skin>%s</skin>\n", xml_escape(player->skin));
2194 		}
2195 		if (player->type_flag) {
2196 			xform_printf(OF, "\t\t\t\t<type>bot</type>\n");
2197 		} else {
2198 			xform_printf(OF, "\t\t\t\t<type>player</type>\n");
2199 		}
2200 
2201 		if (player->connect_time) {
2202 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2203 		}
2204 
2205 		xml_display_player_info_info(player);
2206 
2207 		xform_printf(OF, "\t\t\t</player>\n");
2208 	}
2209 
2210 	xform_printf(OF, "\t\t</players>\n");
2211 }
2212 
2213 
2214 void
xml_display_player_info(struct qserver * server)2215 xml_display_player_info(struct qserver *server)
2216 {
2217 	struct player *player;
2218 
2219 	xform_printf(OF, "\t\t<players>\n");
2220 
2221 	player = server->players;
2222 	for ( ; player != NULL; player = player->next) {
2223 		xform_printf(OF, "\t\t\t<player>\n");
2224 
2225 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2226 		if (NA_INT != player->ping) {
2227 			xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2228 		}
2229 		if (NA_INT != player->score) {
2230 			xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->score);
2231 		}
2232 		if (NA_INT != player->deaths) {
2233 			xform_printf(OF, "\t\t\t\t<deaths>%d</deaths>\n", player->deaths);
2234 		}
2235 		if (NA_INT != player->frags) {
2236 			xform_printf(OF, "\t\t\t\t<frags>%d</frags>\n", player->frags);
2237 		}
2238 		if (player->team_name) {
2239 			xform_printf(OF, "\t\t\t\t<team>%s</team>\n", xml_escape(player->team_name));
2240 		} else if (NA_INT != player->team) {
2241 			xform_printf(OF, "\t\t\t\t<team>%d</team>\n", player->team);
2242 		}
2243 
2244 		if (player->skin) {
2245 			xform_printf(OF, "\t\t\t\t<skin>%s</skin>\n", xml_escape(player->skin));
2246 		}
2247 
2248 		if (player->connect_time) {
2249 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 1)));
2250 		}
2251 
2252 		if (player->address) {
2253 			xform_printf(OF, "\t\t\t\t<address>%s</address>\n", xml_escape(player->address));
2254 		}
2255 
2256 		xml_display_player_info_info(player);
2257 
2258 		xform_printf(OF, "\t\t\t</player>\n");
2259 	}
2260 
2261 	xform_printf(OF, "\t\t</players>\n");
2262 }
2263 
2264 
2265 void
xml_display_armyops_player_info(struct qserver * server)2266 xml_display_armyops_player_info(struct qserver *server)
2267 {
2268 	struct player *player;
2269 
2270 	player = server->players;
2271 	for ( ; player != NULL; player = player->next) {
2272 		player->score = calculate_armyops_score(player);
2273 	}
2274 
2275 	xml_display_player_info(server);
2276 }
2277 
2278 
2279 void
xml_display_ts2_player_info(struct qserver * server)2280 xml_display_ts2_player_info(struct qserver *server)
2281 {
2282 	struct player *player;
2283 
2284 	xform_printf(OF, "\t\t<players>\n");
2285 
2286 	player = server->players;
2287 	for ( ; player != NULL; player = player->next) {
2288 		xform_printf(OF, "\t\t\t<player>\n");
2289 
2290 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2291 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2292 
2293 		if (player->connect_time) {
2294 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2295 		}
2296 
2297 		xml_display_player_info_info(player);
2298 		xform_printf(OF, "\t\t\t</player>\n");
2299 	}
2300 
2301 	xform_printf(OF, "\t\t</players>\n");
2302 }
2303 
2304 
2305 void
xml_display_ts3_player_info(struct qserver * server)2306 xml_display_ts3_player_info(struct qserver *server)
2307 {
2308 	struct player *player;
2309 
2310 	xform_printf(OF, "\t\t<players>\n");
2311 
2312 	player = server->players;
2313 	for ( ; player != NULL; player = player->next) {
2314 		xform_printf(OF, "\t\t\t<player>\n");
2315 
2316 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2317 
2318 		if (player->connect_time) {
2319 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2320 		}
2321 
2322 		xml_display_player_info_info(player);
2323 		xform_printf(OF, "\t\t\t</player>\n");
2324 	}
2325 
2326 	xform_printf(OF, "\t\t</players>\n");
2327 }
2328 
2329 
2330 void
xml_display_starmade_player_info(struct qserver * server)2331 xml_display_starmade_player_info(struct qserver *server)
2332 {
2333 	struct player *player;
2334 
2335 	xform_printf(OF, "\t\t<players>\n");
2336 
2337 	player = server->players;
2338 	for ( ; player != NULL; player = player->next) {
2339 		xform_printf(OF, "\t\t\t<player>\n");
2340 
2341 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2342 
2343 		if (player->connect_time) {
2344 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2345 		}
2346 
2347 		xml_display_player_info_info(player);
2348 		xform_printf(OF, "\t\t\t</player>\n");
2349 	}
2350 
2351 	xform_printf(OF, "\t\t</players>\n");
2352 }
2353 
2354 
2355 void
xml_display_bfbc2_player_info(struct qserver * server)2356 xml_display_bfbc2_player_info(struct qserver *server)
2357 {
2358 	struct player *player;
2359 
2360 	xform_printf(OF, "\t\t<players>\n");
2361 
2362 	player = server->players;
2363 	for ( ; player != NULL; player = player->next) {
2364 		xform_printf(OF, "\t\t\t<player>\n");
2365 
2366 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2367 
2368 		if (player->connect_time) {
2369 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2370 		}
2371 
2372 		xml_display_player_info_info(player);
2373 		xform_printf(OF, "\t\t\t</player>\n");
2374 	}
2375 
2376 	xform_printf(OF, "\t\t</players>\n");
2377 }
2378 
2379 
2380 void
xml_display_wic_player_info(struct qserver * server)2381 xml_display_wic_player_info(struct qserver *server)
2382 {
2383 	struct player *player;
2384 
2385 	xform_printf(OF, "\t\t<players>\n");
2386 
2387 	player = server->players;
2388 	for ( ; player != NULL; player = player->next) {
2389 		xform_printf(OF, "\t\t\t<player>\n");
2390 
2391 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2392 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->score);
2393 		xform_printf(OF, "\t\t\t\t<team>%s</team>\n", player->team_name);
2394 		xform_printf(OF, "\t\t\t\t<bot>%d</bot>\n", player->type_flag);
2395 		if (player->tribe_tag) {
2396 			xform_printf(OF, "\t\t\t\t<role>%s</role>\n", player->tribe_tag);
2397 		}
2398 
2399 		xml_display_player_info_info(player);
2400 		xform_printf(OF, "\t\t\t</player>\n");
2401 	}
2402 
2403 	xform_printf(OF, "\t\t</players>\n");
2404 }
2405 
2406 
2407 void
xml_display_ventrilo_player_info(struct qserver * server)2408 xml_display_ventrilo_player_info(struct qserver *server)
2409 {
2410 	struct player *player;
2411 
2412 	xform_printf(OF, "\t\t<players>\n");
2413 
2414 	player = server->players;
2415 	for ( ; player != NULL; player = player->next) {
2416 		xform_printf(OF, "\t\t\t<player>\n");
2417 
2418 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2419 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2420 		xform_printf(OF, "\t\t\t\t<team>%s</team>\n", xml_escape(player->team_name));
2421 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2422 		xform_printf(OF, "\t\t\t</player>\n");
2423 	}
2424 
2425 	xform_printf(OF, "\t\t</players>\n");
2426 }
2427 
2428 
2429 void
xml_display_tm_player_info(struct qserver * server)2430 xml_display_tm_player_info(struct qserver *server)
2431 {
2432 	struct player *player;
2433 
2434 	xform_printf(OF, "\t\t<players>\n");
2435 
2436 	player = server->players;
2437 	for ( ; player != NULL; player = player->next) {
2438 		xform_printf(OF, "\t\t\t<player>\n");
2439 
2440 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2441 		xform_printf(OF, "\t\t\t\t<ping>%d</ping>\n", player->ping);
2442 
2443 		if (player->connect_time) {
2444 			xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2445 		}
2446 
2447 		xml_display_player_info_info(player);
2448 		xform_printf(OF, "\t\t\t</player>\n");
2449 	}
2450 
2451 	xform_printf(OF, "\t\t</players>\n");
2452 }
2453 
2454 
2455 void
xml_display_savage_player_info(struct qserver * server)2456 xml_display_savage_player_info(struct qserver *server)
2457 {
2458 	struct player *player;
2459 
2460 	xform_printf(OF, "\t\t<players>\n");
2461 
2462 	player = server->players;
2463 	for ( ; player != NULL; player = player->next) {
2464 		xform_printf(OF, "\t\t\t<player>\n");
2465 
2466 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2467 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
2468 		xform_printf(OF, "\t\t\t\t<time>%s</time>\n", xml_escape(play_time(player->connect_time, 2)));
2469 
2470 		xform_printf(OF, "\t\t\t</player>\n");
2471 	}
2472 
2473 	xform_printf(OF, "\t\t</players>\n");
2474 }
2475 
2476 
2477 void
xml_display_farcry_player_info(struct qserver * server)2478 xml_display_farcry_player_info(struct qserver *server)
2479 {
2480 	struct player *player;
2481 
2482 	xform_printf(OF, "\t\t<players>\n");
2483 
2484 	player = server->players;
2485 	for ( ; player != NULL; player = player->next) {
2486 		xform_printf(OF, "\t\t\t<player>\n");
2487 
2488 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2489 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->frags);
2490 		xform_printf(OF, "\t\t\t\t<time>%su</time>\n", xml_escape(play_time(player->connect_time, 2)));
2491 
2492 		xform_printf(OF, "\t\t\t</player>\n");
2493 	}
2494 
2495 	xform_printf(OF, "\t\t</players>\n");
2496 }
2497 
2498 
2499 void
xml_display_tee_player_info(struct qserver * server)2500 xml_display_tee_player_info(struct qserver *server)
2501 {
2502 	struct player *player;
2503 
2504 	xform_printf(OF, "\t\t<players>\n");
2505 
2506 	player = server->players;
2507 	for ( ; player != NULL; player = player->next) {
2508 		xform_printf(OF, "\t\t\t<player>\n");
2509 
2510 		xform_printf(OF, "\t\t\t\t<name>%s</name>\n", xml_escape(xform_name(player->name, server)));
2511 		xform_printf(OF, "\t\t\t\t<score>%d</score>\n", player->score);
2512 
2513 		xform_printf(OF, "\t\t\t</player>\n");
2514 	}
2515 
2516 	xform_printf(OF, "\t\t</players>\n");
2517 }
2518 
2519 
2520 void
display_progress()2521 display_progress()
2522 {
2523 	static struct timeval rate_start =
2524 	{
2525 		0, 0
2526 	};
2527 	char rate[32];
2528 	struct timeval now;
2529 
2530 	gettimeofday(&now, NULL);
2531 
2532 	if (!rate_start.tv_sec) {
2533 		rate_start = now;
2534 		rate[0] = '\0';
2535 	} else {
2536 		int delta = time_delta(&now, &rate_start);
2537 		if (delta > 1500) {
2538 			sprintf(rate, "  %d servers/sec  ", (num_servers_returned + num_servers_timed_out) * 1000 / delta);
2539 		} else {
2540 			rate[0] = '\0';
2541 		}
2542 	}
2543 
2544 	// only print out every 'progress' number of servers.
2545 	if ((0 != num_servers_returned + num_servers_timed_out) && ((progress == 1) || ((num_servers_returned + num_servers_timed_out) % progress == 0))) {
2546 		fprintf(stderr, "\r%d/%d (%d timed out, %d down)%s", num_servers_returned + num_servers_timed_out, num_servers_total, num_servers_timed_out, num_servers_down, rate);
2547 	}
2548 }
2549 
2550 
2551 /* ----- END MODIFICATION ----- Don't need to change anything below here. */
2552 
2553 void set_non_blocking(int fd);
2554 int set_fds(fd_set *fds);
2555 void get_next_timeout(struct timeval *timeout);
2556 
2557 void set_file_descriptors();
2558 int wait_for_file_descriptors(struct timeval *timeout);
2559 struct qserver *get_next_ready_server();
2560 
2561 /* Misc flags
2562  */
2563 
2564 struct timeval packet_recv_time;
2565 int one_server_type_id = ~MASTER_SERVER;
2566 static int one = 1;
2567 static int little_endian;
2568 static int big_endian;
2569 unsigned int swap_long(void *);
2570 unsigned short swap_short(void *);
2571 float swap_float_from_little(void *f);
2572 
2573 #define FORCE    1
2574 
2575 /* Print an argument definition
2576  */
2577 void
printf_opt(const char * opt,const char * desc_format,...)2578 printf_opt(const char *opt, const char *desc_format, ...)
2579 {
2580 	va_list args;
2581 	int i;
2582 
2583 	printf("    %s", opt);
2584 
2585 	for (i = strlen(opt); i < 20; i++) {
2586 		printf(" ");
2587 	}
2588 	printf(" ");
2589 
2590 	va_start(args, desc_format);
2591 	vprintf(desc_format, args);
2592 	va_end(args);
2593 	printf("\n");
2594 }
2595 
2596 
2597 /* Print an error message and the program usage notes
2598  */
2599 void
usage(char * msg,char ** argv,char * a1)2600 usage(char *msg, char **argv, char *a1)
2601 {
2602 	int i;
2603 	server_type *type;
2604 	server_type **sorted_types;
2605 
2606 	if (msg) {
2607 		fprintf(stderr, msg, a1);
2608 	}
2609 
2610 	printf("Usage: %s ", argv[0]);
2611 	printf("[options] [-default server-type] [-cfg file] [-f file] [host[:port]] ...\n");
2612 	printf("Where host is an IP address or host name\n\n");
2613 
2614 	printf("Configuration options:\n");
2615 	printf_opt("-cfg", "Read the extended types from given file not the default one");
2616 	printf_opt("-nocfg", "Ignore qstat configuration loaded from any default location. Must be the first option on the command-line.");
2617 	printf("\n");
2618 
2619 	printf("Game query options:\n");
2620 
2621 	sorted_types = (server_type **)malloc(sizeof(server_type *) * n_server_types);
2622 	type = &types[0];
2623 	for (i = 0; type->id != Q_UNKNOWN_TYPE && i < n_server_types; type++, i++) {
2624 		sorted_types[i] = type;
2625 	}
2626 
2627 	quicksort((void **)sorted_types, 0, n_server_types - 1, (int (*)(void *, void *))type_option_compare);
2628 	for (i = 0; i < n_server_types; i++) {
2629 		type = sorted_types[i];
2630 		printf_opt(type->type_option, "Query %s server", type->game_name);
2631 	}
2632 	printf_opt("-default", "Set default server type");
2633 	printf("\n");
2634 
2635 	printf("-default\tset default server type:");
2636 	for (i = 0; i < n_server_types; i++) {
2637 		type = sorted_types[i];
2638 		printf(" %s", type->type_string);
2639 	}
2640 	printf("\n\n");
2641 
2642 	printf("Content options:\n");
2643 	printf_opt("-sort", "Sort servers and/or players");
2644 	printf_opt("-u", "Only display servers that are up");
2645 	printf_opt("-nf", "Do not display full servers");
2646 	printf_opt("-ne", "Do not display empty servers");
2647 	printf_opt("-R", "Fetch and display server rules");
2648 	printf_opt("-P", "Fetch and display player info");
2649 	printf("\n");
2650 
2651 	printf("Format options:\n");
2652 	printf_opt("-cn", "Display color names instead of numbers");
2653 	printf_opt("-ncn", "Display color numbers instead of names");
2654 	printf_opt("-hc", "Display colors in #rrggbb format");
2655 	printf_opt("-htmlmode", "Convert <, >, and & to the equivalent HTML entities");
2656 	printf_opt("-htmlnames", "Colorize Quake 3 and Tribes 2 player names using html font tags");
2657 	printf_opt("-nohtmlnames", "Do not colorize Quake 3 and Tribes 2 player names even if $HTML is used in an output template.");
2658 	printf_opt("-carets", "Display carets in Quake 3 player names");
2659 	printf_opt("-hpn", "Display player names in hex");
2660 	printf_opt("-hsn", "Display server names in hex");
2661 	printf_opt("-tc", "Display time in clock format (DhDDmDDs)");
2662 	printf_opt("-tsw", "Display time in stop-watch format (DD:DD:DD)");
2663 	printf_opt("-ts", "Display time in seconds");
2664 	printf_opt("-pa", "Display player address");
2665 	printf("\n");
2666 
2667 	printf("Display options:\n");
2668 	printf_opt("-raw <delim>", "Output in raw format using <delim> as delimiter");
2669 	printf_opt("-raw-arg", "When used with -raw, always display the server address as it appeared in a file or on the command-line.");
2670 	printf_opt("-old", "Old style display");
2671 	printf_opt("-nh", "Do not display header");
2672 	printf_opt("-nx", "Enable name transformations, -nx is set by default");
2673 	printf_opt("-nnx", "Disable name transformations, -utf8 option implies -nnx");
2674 	printf_opt("-xml", "Output status data as an XML document");
2675 	printf_opt("-bom", "Output Byte-Order-Mark for XML output.");
2676 	printf_opt("-utf8", "Use the UTF-8 character encoding for XML output");
2677 	printf_opt("-json", "Output status data as an UTF-8 JSON document");
2678 	printf_opt("-Th,-Ts,-Tpt", "Output templates: header, server and player");
2679 	printf_opt("-Tr,-Tt", "Output templates: rule, and trailer");
2680 	printf_opt("-showgameport", "Always display the game port in QStat output.");
2681 	printf_opt("-stripunprintable", "Disable stripping of unprintable characters.");
2682 	printf_opt("-errors", "Display errors");
2683 	printf_opt("-progress", "Display progress meter on stderr (text only)");
2684 	printf("\n");
2685 
2686 	printf("Output options:\n");
2687 	printf_opt("-of", "Output file");
2688 	printf_opt("-af", "Like -of, but append to the file");
2689 	printf("\n");
2690 
2691 	printf("Query options:\n");
2692 	printf_opt("-f", "Read hosts from file");
2693 	printf_opt("-mdelim <delim>", "For rules with multi values use <delim> as delimiter");
2694 	printf_opt("-retry", "Number of retries, default is %d", DEFAULT_RETRIES);
2695 	printf_opt("-interval", "Interval between retries, default is %.2f seconds", DEFAULT_RETRY_INTERVAL / 1000.0);
2696 	printf_opt("-mi", "Interval between master server retries, default is %.2f seconds", (DEFAULT_RETRY_INTERVAL * 4) / 1000.0);
2697 	printf_opt("-timeout", "Total time in seconds before giving up");
2698 	printf_opt("-maxsim", "Set maximum simultaneous queries");
2699 	printf_opt("-sendinterval", "Set time in ms between sending packets, default %u", sendinterval);
2700 	printf_opt("-allowserverdups", "Allow adding multiple servers with same ip:port (needed for ts2)");
2701 	printf_opt("-srcport <range>", "Send packets from these network ports");
2702 	printf_opt("-srcip <IP>", "Send packets using this IP address");
2703 	printf_opt("-H", "Resolve host names");
2704 	printf_opt("-Hcache", "Host name cache file");
2705 	printf("\n");
2706 
2707 	printf("Advanced options:\n");
2708 	printf_opt("-d", "Enable debug options. Specify multiple times to increase debug level.");
2709 #ifdef ENABLE_DUMP
2710 		printf_opt("-dump", "Write received raw packets to dumpNNN files which must not exist before");
2711 		printf_opt("-pkt <file>", "Use file as server reply instead of quering the server. Works only with TF_SINGLE_QUERY servers");
2712 #endif
2713 	printf_opt("-syncconnect", "Process connect initialisation synchronously.");
2714 	printf_opt("-noportoffset", "Dont use builtin status port offsets (assume query port was specified).");
2715 #ifdef _WIN32
2716 		printf_opt("-noconsole", "Free the console");
2717 #endif
2718 	printf("\n");
2719 
2720 	printf("Help options:\n");
2721 	printf_opt("-h, --help", "Print this help");
2722 	printf_opt("-protocols", "Print the protocol list (json display format only)");
2723 	printf_opt("-v", "Print qstat version (can be displayed with -json format)");
2724 	printf("\n");
2725 
2726 	printf("Sort keys:\n");
2727 	printf("  servers: p=by-ping, g=by-game, i=by-IP-address, h=by-hostname, n=by-#-players, l=by-list-order\n");
2728 	printf("  players: P=by-ping, F=by-frags, T=by-team, N=by-name\n");
2729 	printf("\nqstat version %s\n", QSTAT_VERSION);
2730 	exit(0);
2731 }
2732 
2733 
2734 struct server_arg {
2735 	int type_id;
2736 	server_type *type;
2737 	char *arg;
2738 	char *outfilename;
2739 	char *query_arg;
2740 };
2741 
2742 server_type *
find_server_type_id(int type_id)2743 find_server_type_id(int type_id)
2744 {
2745 	server_type *type = &types[0];
2746 
2747 	for ( ; type->id != Q_UNKNOWN_TYPE; type++) {
2748 		if (type->id == type_id) {
2749 			return (type);
2750 		}
2751 	}
2752 	return (NULL);
2753 }
2754 
2755 
2756 server_type *
find_server_type_string(char * type_string)2757 find_server_type_string(char *type_string)
2758 {
2759 	server_type *type = &types[0];
2760 	char *t = type_string;
2761 
2762 	for ( ; *t; t++) {
2763 		*t = tolower(*t);
2764 	}
2765 
2766 	for ( ; type->id != Q_UNKNOWN_TYPE; type++) {
2767 		if (strcmp(type->type_string, type_string) == 0) {
2768 			return (type);
2769 		}
2770 	}
2771 	return (NULL);
2772 }
2773 
2774 
2775 server_type *
find_server_type_option(char * option)2776 find_server_type_option(char *option)
2777 {
2778 	server_type *type = &types[0];
2779 
2780 	for ( ; type->id != Q_UNKNOWN_TYPE; type++) {
2781 		if (strcmp(type->type_option, option) == 0) {
2782 			return (type);
2783 		}
2784 	}
2785 	return (NULL);
2786 }
2787 
2788 
2789 server_type *
parse_server_type_option(char * option,int * outfile,char ** query_arg)2790 parse_server_type_option(char *option, int *outfile, char **query_arg)
2791 {
2792 	server_type *type = &types[0];
2793 	char *comma, *arg;
2794 	int len;
2795 
2796 	*outfile = 0;
2797 	*query_arg = 0;
2798 
2799 	comma = strchr(option, ',');
2800 	if (comma) {
2801 		*comma++ = '\0';
2802 	}
2803 
2804 	for ( ; type->id != Q_UNKNOWN_TYPE; type++) {
2805 		if (strcmp(type->type_option, option) == 0) {
2806 			break;
2807 		}
2808 	}
2809 
2810 	if (type->id == Q_UNKNOWN_TYPE) {
2811 		return (NULL);
2812 	}
2813 
2814 	if (!comma) {
2815 		return (type);
2816 	}
2817 
2818 	if (strcmp(comma, "outfile") == 0) {
2819 		*outfile = 1;
2820 		comma = strchr(comma, ',');
2821 		if (!comma) {
2822 			return (type);
2823 		}
2824 		*comma++ = '\0';
2825 	}
2826 
2827 	*query_arg = strdup(comma);
2828 	arg = comma;
2829 	do {
2830 		comma = strchr(arg, ',');
2831 		if (comma) {
2832 			len = comma - arg;
2833 		} else {
2834 			len = strlen(arg);
2835 		}
2836 		if (strncmp(arg, "outfile", len) == 0) {
2837 			*outfile = 1;
2838 		}
2839 		arg = comma + 1;
2840 	} while (comma);
2841 	return (type);
2842 }
2843 
2844 
2845 void
add_server_arg(char * arg,int type,char * outfilename,char * query_arg,struct server_arg ** args,int * n,int * max)2846 add_server_arg(char *arg, int type, char *outfilename, char *query_arg, struct server_arg **args, int *n, int *max)
2847 {
2848 	if (*n == *max) {
2849 		if (*max == 0) {
2850 			*max = 4;
2851 			*args = (struct server_arg *)malloc(sizeof(struct server_arg) * (*max));
2852 		} else {
2853 			(*max) *= 2;
2854 			*args = (struct server_arg *)realloc(*args, sizeof(struct server_arg) * (*max));
2855 		}
2856 	}
2857 	(*args)[*n].type_id = type;
2858 	/*    (*args)[*n].type= find_server_type_id( type); */
2859 	(*args)[*n].type = NULL;
2860 	(*args)[*n].arg = arg;
2861 	(*args)[*n].outfilename = outfilename;
2862 	(*args)[*n].query_arg = query_arg;
2863 	(*n)++;
2864 }
2865 
2866 
2867 void
add_query_param(struct qserver * server,char * arg)2868 add_query_param(struct qserver *server, char *arg)
2869 {
2870 	char *equal;
2871 	struct query_param *param;
2872 
2873 	equal = strchr(arg, '=');
2874 	*equal++ = '\0';
2875 
2876 	param = (struct query_param *)malloc(sizeof(struct query_param));
2877 	param->key = arg;
2878 	param->value = equal;
2879 	sscanf(equal, "%i", &param->i_value);
2880 	sscanf(equal, "%i", &param->ui_value);
2881 	param->next = server->params;
2882 	server->params = param;
2883 }
2884 
2885 
2886 char *
get_param_value(struct qserver * server,const char * key,char * default_value)2887 get_param_value(struct qserver *server, const char *key, char *default_value)
2888 {
2889 	struct query_param *p = server->params;
2890 
2891 	for ( ; p; p = p->next) {
2892 		if (strcasecmp(key, p->key) == 0) {
2893 			return (p->value);
2894 		}
2895 	}
2896 	return (default_value);
2897 }
2898 
2899 
2900 int
get_param_i_value(struct qserver * server,char * key,int default_value)2901 get_param_i_value(struct qserver *server, char *key, int default_value)
2902 {
2903 	struct query_param *p = server->params;
2904 
2905 	for ( ; p; p = p->next) {
2906 		if (strcasecmp(key, p->key) == 0) {
2907 			return (p->i_value);
2908 		}
2909 	}
2910 	return (default_value);
2911 }
2912 
2913 
2914 unsigned int
get_param_ui_value(struct qserver * server,char * key,unsigned int default_value)2915 get_param_ui_value(struct qserver *server, char *key, unsigned int default_value)
2916 {
2917 	struct query_param *p = server->params;
2918 
2919 	for ( ; p; p = p->next) {
2920 		if (strcasecmp(key, p->key) == 0) {
2921 			return (p->ui_value);
2922 		}
2923 	}
2924 	return (default_value);
2925 }
2926 
2927 
2928 int
parse_source_address(char * addr,unsigned int * ip,unsigned short * port)2929 parse_source_address(char *addr, unsigned int *ip, unsigned short *port)
2930 {
2931 	char *colon;
2932 
2933 	colon = strchr(addr, ':');
2934 	if (colon) {
2935 		*colon = '\0';
2936 		*port = atoi(colon + 1);
2937 		if (colon == addr) {
2938 			return (0);
2939 		}
2940 	} else {
2941 		*port = 0;
2942 	}
2943 
2944 	*ip = inet_addr(addr);
2945 	if ((*ip == INADDR_NONE) && !isdigit((unsigned char)*ip)) {
2946 		*ip = hcache_lookup_hostname(addr);
2947 	}
2948 	if (*ip == INADDR_NONE) {
2949 		fprintf(stderr, "%s: Not an IP address or unknown host name\n", addr);
2950 		return (-1);
2951 	}
2952 	*ip = ntohl(*ip);
2953 	return (0);
2954 }
2955 
2956 
2957 int
parse_source_port(char * port,unsigned short * low,unsigned short * high)2958 parse_source_port(char *port, unsigned short *low, unsigned short *high)
2959 {
2960 	char *dash;
2961 
2962 	*low = atoi(port);
2963 	dash = strchr(port, '-');
2964 	*high = 0;
2965 	if (dash) {
2966 		*high = atoi(dash + 1);
2967 	}
2968 	if (*high == 0) {
2969 		*high = *low;
2970 	}
2971 
2972 	if (*high < *low) {
2973 		fprintf(stderr, "%s: Invalid port range\n", port);
2974 		return (-1);
2975 	}
2976 	return (0);
2977 }
2978 
2979 
2980 void
add_config_server_types()2981 add_config_server_types()
2982 {
2983 	int n_config_types, n_builtin_types, i;
2984 	server_type **config_types;
2985 	server_type *new_types, *type;
2986 
2987 	config_types = qsc_get_config_server_types(&n_config_types);
2988 
2989 	if (n_config_types == 0) {
2990 		return;
2991 	}
2992 
2993 	n_builtin_types = (sizeof(builtin_types) / sizeof(server_type)) - 1;
2994 	new_types = (server_type *)malloc(sizeof(server_type) * (n_builtin_types + n_config_types + 1));
2995 
2996 	memcpy(new_types, &builtin_types[0], n_builtin_types * sizeof(server_type));
2997 	type = &new_types[n_builtin_types];
2998 	for (i = n_config_types; i; i--, config_types++, type++) {
2999 		*type = **config_types;
3000 	}
3001 	n_server_types = n_builtin_types + n_config_types;
3002 	new_types[n_server_types].id = Q_UNKNOWN_TYPE;
3003 	if (types != &builtin_types[0]) {
3004 		free(types);
3005 	}
3006 	types = new_types;
3007 }
3008 
3009 
3010 void
revert_server_types()3011 revert_server_types()
3012 {
3013 	if (types != &builtin_types[0]) {
3014 		free(types);
3015 	}
3016 	n_server_types = (sizeof(builtin_types) / sizeof(server_type)) - 1;
3017 	types = &builtin_types[0];
3018 }
3019 
3020 
3021 #ifdef ENABLE_DUMP
3022 	unsigned pkt_dump_pos = 0;
3023 	const char *pkt_dumps[64] = { 0 };
3024 	static void
add_pkt_from_file(const char * file)3025 	add_pkt_from_file(const char *file)
3026 	{
3027 		if (pkt_dump_pos >= sizeof(pkt_dumps) / sizeof(pkt_dumps[0])) {
3028 			return;
3029 		}
3030 		pkt_dumps[pkt_dump_pos++] = file;
3031 	}
3032 
3033 
3034 	static void
replay_pkt_dumps()3035 	replay_pkt_dumps()
3036 	{
3037 		struct qserver *server = servers;
3038 		char *pkt = NULL;
3039 		int fd;
3040 		int bytes_read = 0; // should be ssize_t but for ease with win32
3041 		int i;
3042 		struct stat statbuf;
3043 
3044 		gettimeofday(&packet_recv_time, NULL);
3045 
3046 		for (i = 0; i < pkt_dump_pos; i++) {
3047 			if ((fd = open(pkt_dumps[i], O_RDONLY)) == -1) {
3048 				goto err;
3049 			}
3050 
3051 			if (fstat(fd, &statbuf) == -1) {
3052 				goto err;
3053 			}
3054 			pkt = malloc(statbuf.st_size);
3055 			if (NULL == pkt) {
3056 				goto err;
3057 			}
3058 			bytes_read = read(fd, pkt, statbuf.st_size);
3059 			if (bytes_read != statbuf.st_size) {
3060 				fprintf(stderr, "Failed to read entire packet from disk got %d of %ld bytes\n", bytes_read, (long)statbuf.st_size);
3061 				goto err;
3062 			}
3063 			close(fd);
3064 			fd = 0;
3065 
3066 			debug(2, "replay, pre-packet_func");
3067 			process_func_ret(server, server->type->packet_func(server, pkt, statbuf.st_size));
3068 			debug(2, "replay, post-packet_func");
3069 		}
3070 		goto out;
3071 
3072 err:            perror(__FUNCTION__);
3073 		close(fd);
3074 out:            fd = 0; // NOP
3075 	}
3076 
3077 
3078 #endif  // ENABLE_DUMP
3079 
3080 struct rcv_pkt {
3081 	struct qserver *server;
3082 	struct sockaddr_in addr;
3083 	struct timeval recv_time;
3084 	char data[PACKET_LEN];
3085 	int len;
3086 	int _errno;
3087 };
3088 
3089 void
do_work(void)3090 do_work(void)
3091 {
3092 	int pktlen, rc;
3093 	char *pkt = NULL;
3094 	int bind_retry = 0;
3095 	struct timeval timeout;
3096 	struct rcv_pkt *buffer;
3097 	unsigned buffill = 0, i = 0;
3098 	unsigned bufsize = max_simultaneous * 2;
3099 
3100 	struct timeval t, ts;
3101 
3102 	gettimeofday(&t, NULL);
3103 	ts = t;
3104 
3105 	buffer = malloc(sizeof(struct rcv_pkt) * bufsize);
3106 
3107 	if (!buffer) {
3108 		return;
3109 	}
3110 
3111 #ifdef ENABLE_DUMP
3112 		if (pkt_dump_pos) {
3113 			replay_pkt_dumps();
3114 		} else
3115 #endif
3116 	{
3117 		bind_retry = bind_sockets();
3118 	}
3119 
3120 	send_packets();
3121 
3122 	debug(2, "connected: %d", connected);
3123 
3124 	while (connected || (!connected && bind_retry == -2)) {
3125 		if (!connected && (bind_retry == -2)) {
3126 			rc = wait_for_timeout(60);
3127 			bind_retry = bind_sockets();
3128 			continue;
3129 		}
3130 		bind_retry = 0;
3131 
3132 		set_file_descriptors();
3133 
3134 		if (progress) {
3135 			display_progress();
3136 		}
3137 
3138 		get_next_timeout(&timeout);
3139 
3140 		rc = wait_for_file_descriptors(&timeout);
3141 
3142 		debug(2, "rc %d", rc);
3143 
3144 		if (rc == SOCKET_ERROR) {
3145 #ifndef _WIN32
3146 				if (errno == EINTR) {
3147 					continue;
3148 				}
3149 #endif
3150 			perror("select");
3151 			break;
3152 		}
3153 
3154 		for ( ; rc && buffill < bufsize; rc--) {
3155 			int addrlen = sizeof(buffer[buffill].addr);
3156 			struct qserver *server = get_next_ready_server();
3157 			if (server == NULL) {
3158 				break;
3159 			}
3160 
3161 			gettimeofday(&buffer[buffill].recv_time, NULL);
3162 
3163 			pktlen = recvfrom(server->fd, buffer[buffill].data, sizeof(buffer[buffill].data), 0, (struct sockaddr *)&buffer[buffill].addr, (void *)&addrlen);
3164 
3165 			debug(2, "recvfrom: %d", pktlen);
3166 
3167 			// pktlen == 0 is no error condition! happens on remote tcp socket close
3168 			if (pktlen == SOCKET_ERROR) {
3169 				if (connection_would_block()) {
3170 					malformed_packet(server, "EAGAIN on UDP socket, probably incorrect checksum");
3171 				} else if (connection_refused() || connection_reset()) {
3172 					server->server_name = DOWN;
3173 					num_servers_down++;
3174 					cleanup_qserver(server, FORCE);
3175 				}
3176 				continue;
3177 			}
3178 
3179 			debug(1, "recv %3d %3d %d.%d.%d.%d:%hu\n",
3180 			    time_delta(&buffer[buffill].recv_time, &ts),
3181 			    time_delta(&buffer[buffill].recv_time, &t),
3182 			    server->ipaddr & 0xff,
3183 			    (server->ipaddr >> 8) & 0xff,
3184 			    (server->ipaddr >> 16) & 0xff,
3185 			    (server->ipaddr >> 24) & 0xff,
3186 			    server->port
3187 			    );
3188 
3189 			t = buffer[buffill].recv_time;
3190 
3191 			buffer[buffill].server = server;
3192 			buffer[buffill].len = pktlen;
3193 			++buffill;
3194 		}
3195 
3196 		debug(2, "fill: %d < %d", buffill, bufsize);
3197 
3198 		for (i = 0; i < buffill; ++i) {
3199 			struct qserver *server = buffer[i].server;
3200 			pkt = buffer[i].data;
3201 			pktlen = buffer[i].len;
3202 			memcpy(&packet_recv_time, &buffer[i].recv_time, sizeof(packet_recv_time));
3203 
3204 			if (get_debug_level() > 2) {
3205 				print_packet(server, pkt, pktlen);
3206 			}
3207 
3208 #ifdef ENABLE_DUMP
3209 				if (do_dump) {
3210 					dump_packet(pkt, pktlen);
3211 				}
3212 #endif
3213 			if (server->flags & FLAG_BROADCAST) {
3214 				struct qserver *broadcast = server;
3215 				unsigned short port = ntohs(buffer[i].addr.sin_port);
3216 				/* create new server and init */
3217 				if (!(no_port_offset || server->flags & TF_NO_PORT_OFFSET)) {
3218 					port -= server->type->port_offset;
3219 				}
3220 				server = add_qserver_byaddr(ntohl(buffer[i].addr.sin_addr.s_addr), port, server->type, NULL);
3221 				if (server == NULL) {
3222 					server = find_server_by_address(buffer[i].addr.sin_addr.s_addr, ntohs(buffer[i].addr.sin_port));
3223 					if (server == NULL) {
3224 						continue;
3225 					}
3226 
3227 					/*
3228 					 * if ( show_errors)
3229 					 * {
3230 					 * fprintf(stderr,
3231 					 * "duplicate or invalid packet received from 0x%08x:%hu\n",
3232 					 * ntohl(buffer[i].addr.sin_addr.s_addr), ntohs(buffer[i].addr.sin_port));
3233 					 * print_packet( NULL, pkt, pktlen);
3234 					 * }
3235 					 * continue;
3236 					 */
3237 				} else {
3238 					server->packet_time1 = broadcast->packet_time1;
3239 					server->packet_time2 = broadcast->packet_time2;
3240 					server->ping_total = broadcast->ping_total;
3241 					server->n_requests = broadcast->n_requests;
3242 					server->n_packets = broadcast->n_packets;
3243 					broadcast->n_servers++;
3244 				}
3245 			}
3246 
3247 			debug(2, "connected, pre-packet_func: %d", connected);
3248 			process_func_ret(server, server->type->packet_func(server, pkt, pktlen));
3249 			debug(2, "connected, post-packet_func: %d", connected);
3250 		}
3251 		buffill = 0;
3252 
3253 		if (run_timeout && (time(0) - start_time >= run_timeout)) {
3254 			debug(2, "run timeout reached");
3255 			break;
3256 		}
3257 
3258 		send_packets();
3259 		if (connected < max_simultaneous) {
3260 			bind_retry = bind_sockets();
3261 		}
3262 
3263 		debug(2, "connected: %d", connected);
3264 	}
3265 
3266 	free(buffer);
3267 }
3268 
3269 
3270 int
main(int argc,char * argv[])3271 main(int argc, char *argv[])
3272 {
3273 	int arg, n_files, i;
3274 	char **files, *outfilename, *query_arg;
3275 	struct server_arg *server_args = NULL;
3276 	int n_server_args = 0, max_server_args = 0;
3277 	int default_server_type_id;
3278 
3279 #ifdef _WIN32
3280 		WORD version = MAKEWORD(1, 1);
3281 		WSADATA wsa_data;
3282 		if (WSAStartup(version, &wsa_data) != 0) {
3283 			fprintf(stderr, "Could not open winsock\n");
3284 			exit(1);
3285 		}
3286 #else
3287 		signal(SIGPIPE, SIG_IGN);
3288 #endif
3289 
3290 	types = &builtin_types[0];
3291 	n_server_types = (sizeof(builtin_types) / sizeof(server_type)) - 1;
3292 
3293 	i = qsc_load_default_config_files();
3294 	if (i == -1) {
3295 		return (1);
3296 	} else if (i == 0) {
3297 		add_config_server_types();
3298 	}
3299 
3300 	if (argc == 1) {
3301 		usage(NULL, argv, NULL);
3302 	}
3303 
3304 	OF = stdout;
3305 
3306 	files = (char **)malloc(sizeof(char *) * (argc / 2));
3307 	n_files = 0;
3308 
3309 	default_server_type_id = Q_SERVER;
3310 	little_endian = ((char *)&one)[0];
3311 	big_endian = !little_endian;
3312 
3313 	for (arg = 1; arg < argc; arg++) {
3314 		if (argv[arg][0] != '-') {
3315 			break;
3316 		}
3317 		outfilename = NULL;
3318 		if ((strcmp(argv[arg], "-nocfg") == 0) && (arg == 1)) {
3319 			revert_server_types();
3320 		} else if (strcmp(argv[arg], "--help") == 0) {
3321 			usage(NULL, argv, NULL);
3322 		} else if (strcmp(argv[arg], "-h") == 0) {
3323 			usage(NULL, argv, NULL);
3324 		} else if (strcmp(argv[arg], "-protocols") == 0) {
3325 			if (json_display == 1) {
3326 				json_protocols();
3327 			} else {
3328 				fprintf(stderr, "must be used with -json\n");
3329 				exit(1);
3330 			}
3331 		} else if (strcmp(argv[arg], "-v") == 0) {
3332 			if (json_display == 1) {
3333 				json_version();
3334 			} else {
3335 				printf("%s\n", QSTAT_VERSION);
3336 			}
3337 		} else if (strcmp(argv[arg], "-f") == 0) {
3338 			arg++;
3339 			if (arg >= argc) {
3340 				usage("missing argument for -f\n", argv, NULL);
3341 			}
3342 			files[n_files++] = argv[arg];
3343 		} else if (strcmp(argv[arg], "-retry") == 0) {
3344 			arg++;
3345 			if (arg >= argc) {
3346 				usage("missing argument for -retry\n", argv, NULL);
3347 			}
3348 			n_retries = atoi(argv[arg]);
3349 			if (n_retries <= 0) {
3350 				fprintf(stderr, "retries must be greater than zero\n");
3351 				exit(1);
3352 			}
3353 		} else if (strcmp(argv[arg], "-interval") == 0) {
3354 			double value = 0.0;
3355 			arg++;
3356 			if (arg >= argc) {
3357 				usage("missing argument for -interval\n", argv, NULL);
3358 			}
3359 			sscanf(argv[arg], "%lf", &value);
3360 			if (value < 0.1) {
3361 				fprintf(stderr, "retry interval must be greater than 0.1\n");
3362 				exit(1);
3363 			}
3364 			retry_interval = (int)(value * 1000);
3365 		} else if (strcmp(argv[arg], "-mi") == 0) {
3366 			double value = 0.0;
3367 			arg++;
3368 			if (arg >= argc) {
3369 				usage("missing argument for -mi\n", argv, NULL);
3370 			}
3371 			sscanf(argv[arg], "%lf", &value);
3372 			if (value < 0.1) {
3373 				fprintf(stderr, "interval must be greater than 0.1\n");
3374 				exit(1);
3375 			}
3376 			master_retry_interval = (int)(value * 1000);
3377 		} else if (strcmp(argv[arg], "-H") == 0) {
3378 			hostname_lookup = 1;
3379 		} else if (strcmp(argv[arg], "-u") == 0) {
3380 			up_servers_only = 1;
3381 		} else if (strcmp(argv[arg], "-nf") == 0) {
3382 			no_full_servers = 1;
3383 		} else if (strcmp(argv[arg], "-ne") == 0) {
3384 			no_empty_servers = 1;
3385 		} else if (strcmp(argv[arg], "-nh") == 0) {
3386 			no_header_display = 1;
3387 		} else if (strcmp(argv[arg], "-old") == 0) {
3388 			new_style = 0;
3389 		} else if (strcmp(argv[arg], "-P") == 0) {
3390 			get_player_info = 1;
3391 		} else if (strcmp(argv[arg], "-R") == 0) {
3392 			get_server_rules = 1;
3393 		} else if (strncmp(argv[arg], "-raw", 4) == 0) {
3394 			if (json_display == 1) {
3395 				usage("cannot specify both -json and -raw\n", argv, NULL);
3396 			}
3397 			if (xml_display == 1) {
3398 				usage("cannot specify both -xml and -raw\n", argv, NULL);
3399 			}
3400 			if (argv[arg][4] == ',') {
3401 				if (strcmp(&argv[arg][5], "game") == 0) {
3402 					show_game_in_raw = 1;
3403 				} else {
3404 					usage("Unknown -raw option\n", argv, NULL);
3405 				}
3406 			}
3407 			arg++;
3408 			if (arg >= argc) {
3409 				usage("missing argument for -raw\n", argv, NULL);
3410 			}
3411 			raw_delimiter = argv[arg];
3412 
3413 			// Check the multi rule delimiter isnt the same
3414 			// If it is fix to maintain backwards compatibility
3415 			if ((0 == strcmp(raw_delimiter, multi_delimiter)) && (0 == strcmp(raw_delimiter, "|"))) {
3416 				multi_delimiter = ":";
3417 			}
3418 			raw_display = 1;
3419 		} else if (strcmp(argv[arg], "-mdelim") == 0) {
3420 			arg++;
3421 			if (arg >= argc) {
3422 				usage("missing argument for -mdelim\n", argv, NULL);
3423 			}
3424 			multi_delimiter = argv[arg];
3425 		} else if (strcmp(argv[arg], "-xml") == 0) {
3426 			xml_display = 1;
3427 			if (raw_display == 1) {
3428 				usage("cannot specify both -raw and -xml\n", argv, NULL);
3429 			}
3430 			if (json_display == 1) {
3431 				usage("cannot specify both -json and -xml\n", argv, NULL);
3432 			}
3433 		} else if (strcmp(argv[arg], "-json") == 0) {
3434 			json_display = 1;
3435 			if (raw_display == 1) {
3436 				usage("cannot specify both -raw and -json\n", argv, NULL);
3437 			}
3438 			if (xml_display == 1) {
3439 				usage("cannot specify both -xml and -json\n", argv, NULL);
3440 			}
3441 		} else if (strcmp(argv[arg], "-utf8") == 0) {
3442 			xml_encoding = ENCODING_UTF_8;
3443 			xform_names = 0;
3444 		} else if (strcmp(argv[arg], "-ncn") == 0) {
3445 			color_names = 0;
3446 		} else if (strcmp(argv[arg], "-cn") == 0) {
3447 			color_names = 1;
3448 		} else if (strcmp(argv[arg], "-hc") == 0) {
3449 			color_names = 2;
3450 		} else if (strcmp(argv[arg], "-nx") == 0) {
3451 			xform_names = 1;
3452 		} else if (strcmp(argv[arg], "-nnx") == 0) {
3453 			xform_names = 0;
3454 		} else if (strcmp(argv[arg], "-tc") == 0) {
3455 			time_format = CLOCK_TIME;
3456 		} else if (strcmp(argv[arg], "-tsw") == 0) {
3457 			time_format = STOPWATCH_TIME;
3458 		} else if (strcmp(argv[arg], "-ts") == 0) {
3459 			time_format = SECONDS;
3460 		} else if (strcmp(argv[arg], "-pa") == 0) {
3461 			player_address = 1;
3462 		} else if (strcmp(argv[arg], "-hpn") == 0) {
3463 			xform_hex_player_names = 1;
3464 		} else if (strcmp(argv[arg], "-hsn") == 0) {
3465 			xform_hex_server_names = 1;
3466 		} else if (strncmp(argv[arg], "-maxsimultaneous", 7) == 0) {
3467 			arg++;
3468 			if (arg >= argc) {
3469 				usage("missing argument for -maxsimultaneous\n", argv, NULL);
3470 			}
3471 			max_simultaneous = atoi(argv[arg]);
3472 			if (max_simultaneous <= 0) {
3473 				usage("value for -maxsimultaneous must be > 0\n", argv, NULL);
3474 			}
3475 			if (max_simultaneous > FD_SETSIZE) {
3476 				max_simultaneous = FD_SETSIZE;
3477 			}
3478 		} else if (strcmp(argv[arg], "-sendinterval") == 0) {
3479 			arg++;
3480 			if (arg >= argc) {
3481 				usage("missing argument for -sendinterval\n", argv, NULL);
3482 			}
3483 			sendinterval = atoi(argv[arg]);
3484 			if (sendinterval < 0) {
3485 				usage("value for -sendinterval must be >= 0\n", argv, NULL);
3486 			}
3487 		} else if (strcmp(argv[arg], "-raw-arg") == 0) {
3488 			raw_arg = 1000;
3489 		} else if (strcmp(argv[arg], "-timeout") == 0) {
3490 			arg++;
3491 			if (arg >= argc) {
3492 				usage("missing argument for -timeout\n", argv, NULL);
3493 			}
3494 			run_timeout = atoi(argv[arg]);
3495 			if (run_timeout <= 0) {
3496 				usage("value for -timeout must be > 0\n", argv, NULL);
3497 			}
3498 		} else if (strncmp(argv[arg], "-progress", sizeof("-progress") - 1) == 0) {
3499 			char *p = argv[arg] + sizeof("-progress") - 1;
3500 			progress = 1;
3501 			if (*p == ',') {
3502 				progress = atoi(p + 1);
3503 			}
3504 		} else if (strcmp(argv[arg], "-Hcache") == 0) {
3505 			arg++;
3506 			if (arg >= argc) {
3507 				usage("missing argument for -Hcache\n", argv, NULL);
3508 			}
3509 			if (hcache_open(argv[arg], 0) == -1) {
3510 				return (1);
3511 			}
3512 		} else if (strcmp(argv[arg], "-default") == 0) {
3513 			arg++;
3514 			if (arg >= argc) {
3515 				usage("missing argument for -default\n", argv, NULL);
3516 			}
3517 			default_server_type = find_server_type_string(argv[arg]);
3518 			if (default_server_type == NULL) {
3519 				char opt[256], *o = &opt[0];
3520 				sprintf(opt, "-%s", argv[arg]);
3521 				for ( ; *o; o++) {
3522 					*o = tolower(*o);
3523 				}
3524 				default_server_type = find_server_type_option(opt);
3525 			}
3526 			if (default_server_type == NULL) {
3527 				fprintf(stderr, "unknown server type \"%s\"\n", argv[arg]);
3528 				usage(NULL, argv, NULL);
3529 			}
3530 			default_server_type_id = default_server_type->id;
3531 			default_server_type = NULL;
3532 		} else if (strncmp(argv[arg], "-Tserver", 3) == 0) {
3533 			arg++;
3534 			if (arg >= argc) {
3535 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3536 			}
3537 			if (read_qserver_template(argv[arg]) == -1) {
3538 				return (1);
3539 			}
3540 		} else if (strncmp(argv[arg], "-Trule", 3) == 0) {
3541 			arg++;
3542 			if (arg >= argc) {
3543 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3544 			}
3545 			if (read_rule_template(argv[arg]) == -1) {
3546 				return (1);
3547 			}
3548 		} else if (strncmp(argv[arg], "-Theader", 3) == 0) {
3549 			arg++;
3550 			if (arg >= argc) {
3551 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3552 			}
3553 			if (read_header_template(argv[arg]) == -1) {
3554 				return (1);
3555 			}
3556 		} else if (strncmp(argv[arg], "-Ttrailer", 3) == 0) {
3557 			arg++;
3558 			if (arg >= argc) {
3559 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3560 			}
3561 			if (read_trailer_template(argv[arg]) == -1) {
3562 				return (1);
3563 			}
3564 		} else if (strncmp(argv[arg], "-Tplayer", 3) == 0) {
3565 			arg++;
3566 			if (arg >= argc) {
3567 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3568 			}
3569 			if (read_player_template(argv[arg]) == -1) {
3570 				return (1);
3571 			}
3572 		} else if (strcmp(argv[arg], "-sort") == 0) {
3573 			size_t pos;
3574 			arg++;
3575 			if (arg >= argc) {
3576 				usage("missing argument for -sort\n", argv, NULL);
3577 			}
3578 			strncpy(sort_keys, argv[arg], sizeof(sort_keys) - 1);
3579 			pos = strspn(sort_keys, SUPPORTED_SORT_KEYS);
3580 			if (pos != strlen(sort_keys)) {
3581 				fprintf(stderr, "Unknown sort key \"%c\", valid keys are \"%s\"\n", sort_keys[pos], SUPPORTED_SORT_KEYS);
3582 				return (1);
3583 			}
3584 			server_sort = strpbrk(sort_keys, SUPPORTED_SERVER_SORT) != NULL;
3585 			if (strchr(sort_keys, 'l')) {
3586 				server_sort = 1;
3587 			}
3588 			player_sort = strpbrk(sort_keys, SUPPORTED_PLAYER_SORT) != NULL;
3589 		} else if (strcmp(argv[arg], "-errors") == 0) {
3590 			show_errors++;
3591 		} else if (strcmp(argv[arg], "-of") == 0) {
3592 			arg++;
3593 			if (arg >= argc) {
3594 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3595 			}
3596 			if ((argv[arg][0] == '-') && (argv[arg][1] == '\0')) {
3597 				OF = stdout;
3598 			} else {
3599 				OF = fopen(argv[arg], "w");
3600 			}
3601 			if (OF == NULL) {
3602 				perror(argv[arg]);
3603 				return (1);
3604 			}
3605 		} else if (strcmp(argv[arg], "-af") == 0) {
3606 			arg++;
3607 			if (arg >= argc) {
3608 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3609 			}
3610 			if ((argv[arg][0] == '-') && (argv[arg][1] == '\0')) {
3611 				OF = stdout;
3612 			} else {
3613 				OF = fopen(argv[arg], "a");
3614 			}
3615 			if (OF == NULL) {
3616 				perror(argv[arg]);
3617 				return (1);
3618 			}
3619 		} else if (strcmp(argv[arg], "-htmlnames") == 0) {
3620 			xform_html_names = 1;
3621 		} else if (strcmp(argv[arg], "-nohtmlnames") == 0) {
3622 			xform_html_names = 0;
3623 		} else if (strcmp(argv[arg], "-htmlmode") == 0) {
3624 			html_mode = 1;
3625 		} else if (strcmp(argv[arg], "-carets") == 0) {
3626 			xform_strip_carets = 0;
3627 		} else if (strcmp(argv[arg], "-d") == 0) {
3628 			set_debug_level(get_debug_level() + 1);
3629 		} else if (strcmp(argv[arg], "-showgameport") == 0) {
3630 			show_game_port = 1;
3631 		} else if (strcmp(argv[arg], "-noportoffset") == 0) {
3632 			no_port_offset = 1;
3633 		} else if (strcmp(argv[arg], "-srcip") == 0) {
3634 			arg++;
3635 			if (arg >= argc) {
3636 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3637 			}
3638 			if (parse_source_address(argv[arg], &source_ip, &source_port) == -1) {
3639 				return (1);
3640 			}
3641 			if (source_port) {
3642 				source_port_low = source_port;
3643 				source_port_high = source_port;
3644 			}
3645 		} else if (strcmp(argv[arg], "-syncconnect") == 0) {
3646 			syncconnect = 1;
3647 		} else if (strcmp(argv[arg], "-stripunprintable") == 0) {
3648 			xform_strip_unprintable = 1;
3649 		} else if (strcmp(argv[arg], "-srcport") == 0) {
3650 			arg++;
3651 			if (arg >= argc) {
3652 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3653 			}
3654 			if (parse_source_port(argv[arg], &source_port_low, &source_port_high) == -1) {
3655 				return (1);
3656 			}
3657 			source_port = source_port_low;
3658 		} else if (strcmp(argv[arg], "-cfg") == 0) {
3659 			arg++;
3660 			if (arg >= argc) {
3661 				usage("missing argument for %s\n", argv, argv[arg - 1]);
3662 			}
3663 			if (qsc_load_config_file(argv[arg]) == -1) {
3664 				return (1);
3665 			}
3666 			add_config_server_types();
3667 		} else if (strcmp(argv[arg], "-allowserverdups") == 0) {
3668 			noserverdups = 0;
3669 		} else if (strcmp(argv[arg], "-bom") == 0) {
3670 			output_bom = 1;
3671 		}
3672 #ifdef ENABLE_DUMP
3673 			else if (strcmp(argv[arg], "-dump") == 0) {
3674 				do_dump = 1;
3675 			} else if (strcmp(argv[arg], "-pkt") == 0) {
3676 				arg++;
3677 				if (arg >= argc) {
3678 					usage("missing argument for %s\n", argv, argv[arg - 1]);
3679 				}
3680 				add_pkt_from_file(argv[arg]);
3681 			}
3682 #endif
3683 #ifdef _WIN32
3684 			else if (strcmp(argv[arg], "-noconsole") == 0) {
3685 				FreeConsole();
3686 			}
3687 #endif
3688 		else {
3689 			int outfile;
3690 			server_type *type;
3691 			arg++;
3692 			if (arg >= argc) {
3693 				fprintf(stderr, "missing argument for \"%s\"\n", argv[arg - 1]);
3694 				return (1);
3695 			}
3696 			type = parse_server_type_option(argv[arg - 1], &outfile, &query_arg);
3697 			if (type == NULL) {
3698 				fprintf(stderr, "unknown option \"%s\"\n", argv[arg - 1]);
3699 				return (1);
3700 			}
3701 			outfilename = NULL;
3702 			if (outfile) {
3703 				outfilename = strchr(argv[arg], ',');
3704 				if (outfilename == NULL) {
3705 					fprintf(stderr, "missing file name for \"%s,outfile\"\n", argv[arg - 1]);
3706 					return (1);
3707 				}
3708 				*outfilename++ = '\0';
3709 			}
3710 
3711 			/*
3712 			 * if ( query_arg && !(type->flags & TF_QUERY_ARG)) {
3713 			 * fprintf( stderr, "option flag \"%s\" not allowed for this server type\n",
3714 			 * query_arg);
3715 			 * return 1;
3716 			 * }
3717 			 */
3718 			if (type->flags & TF_QUERY_ARG_REQUIRED && !query_arg) {
3719 				fprintf(stderr, "option flag missing for server type \"%s\"\n", argv[arg - 1]);
3720 				return (1);
3721 			}
3722 			add_server_arg(argv[arg], type->id, outfilename, query_arg, &server_args, &n_server_args, &max_server_args);
3723 		}
3724 	}
3725 
3726 	start_time = time(0);
3727 
3728 	default_server_type = find_server_type_id(default_server_type_id);
3729 
3730 	for (i = 0; i < n_files; i++) {
3731 		add_file(files[i]);
3732 	}
3733 
3734 	for ( ; arg < argc; arg++) {
3735 		add_qserver(argv[arg], default_server_type, NULL, NULL);
3736 	}
3737 
3738 	for (i = 0; i < n_server_args; i++) {
3739 		server_type *server_type = find_server_type_id(server_args[i].type_id);
3740 		add_qserver(server_args[i].arg, server_type, server_args[i].outfilename, server_args[i].query_arg);
3741 	}
3742 
3743 	free(server_args);
3744 
3745 	if (servers == NULL) {
3746 		exit(1);
3747 	}
3748 
3749 	max_connmap = max_simultaneous + 10;
3750 	connmap = (struct qserver **)calloc(1, sizeof(struct qserver *) * max_connmap);
3751 
3752 	if (color_names == -1) {
3753 		color_names = (raw_display) ? DEFAULT_COLOR_NAMES_RAW : DEFAULT_COLOR_NAMES_DISPLAY;
3754 	}
3755 
3756 	if (time_format == -1) {
3757 		time_format = (raw_display) ? DEFAULT_TIME_FMT_RAW : DEFAULT_TIME_FMT_DISPLAY;
3758 	}
3759 
3760 	if ((one_server_type_id & MASTER_SERVER) || (one_server_type_id == 0)) {
3761 		display_prefix = 1;
3762 	}
3763 
3764 	if (xml_display) {
3765 		xml_header();
3766 	} else if (json_display) {
3767 		json_header();
3768 	} else if (new_style && !raw_display && !have_server_template()) {
3769 		display_header();
3770 	} else if (have_header_template()) {
3771 		template_display_header();
3772 	}
3773 
3774 	q_serverinfo.length = htons(q_serverinfo.length);
3775 	h2_serverinfo.length = htons(h2_serverinfo.length);
3776 	q_player.length = htons(q_player.length);
3777 
3778 	do_work();
3779 
3780 	finish_output();
3781 	free_server_hash();
3782 	free(files);
3783 	free(connmap);
3784 
3785 	return (0);
3786 }
3787 
3788 
3789 void
finish_output()3790 finish_output()
3791 {
3792 	int i;
3793 
3794 	hcache_update_file();
3795 
3796 	if (progress) {
3797 		display_progress();
3798 		fputs("\n", stderr);
3799 	}
3800 
3801 	if (server_sort) {
3802 		struct qserver **array, *server, *next_server;
3803 		if (strchr(sort_keys, 'l') && (strpbrk(sort_keys, SUPPORTED_SERVER_SORT) == NULL)) {
3804 			server = servers;
3805 			for ( ; server; server = next_server) {
3806 				next_server = server->next;
3807 				display_server(server);
3808 			}
3809 		} else {
3810 			array = (struct qserver **)malloc(sizeof(struct qserver *) * num_servers_total);
3811 			server = servers;
3812 			for (i = 0; server != NULL; i++) {
3813 				array[i] = server;
3814 				server = server->next;
3815 			}
3816 			sort_servers(array, num_servers_total);
3817 			if (progress) {
3818 				fprintf(stderr, "\n");
3819 			}
3820 			for (i = 0; i < num_servers_total; i++) {
3821 				display_server(array[i]);
3822 			}
3823 			free(array);
3824 		}
3825 	} else {
3826 		struct qserver *server, *next_server;
3827 		server = servers;
3828 		for ( ; server; server = next_server) {
3829 			next_server = server->next;
3830 			if (server->server_name == HOSTNOTFOUND) {
3831 				display_server(server);
3832 			}
3833 		}
3834 	}
3835 
3836 	if (xml_display) {
3837 		xml_footer();
3838 	} else if (json_display) {
3839 		json_footer();
3840 	} else if (have_trailer_template()) {
3841 		template_display_trailer();
3842 	}
3843 
3844 	if (OF != stdout) {
3845 		fclose(OF);
3846 	}
3847 }
3848 
3849 
3850 void
add_file(char * filename)3851 add_file(char *filename)
3852 {
3853 	FILE *file;
3854 	char name[200], *comma, *query_arg = NULL;
3855 	server_type *type;
3856 
3857 	debug(4, "Loading servers from '%s'...\n", filename);
3858 
3859 	if (strcmp(filename, "-") == 0) {
3860 		file = stdin;
3861 		current_filename = NULL;
3862 	} else {
3863 		file = fopen(filename, "r");
3864 		current_filename = filename;
3865 	}
3866 	current_fileline = 1;
3867 
3868 	if (file == NULL) {
3869 		perror(filename);
3870 		return;
3871 	}
3872 	for ( ; fscanf(file, "%s", name) == 1; current_fileline++) {
3873 		comma = strchr(name, ',');
3874 		if (comma) {
3875 			*comma++ = '\0';
3876 			query_arg = strdup(comma);
3877 		}
3878 		type = find_server_type_string(name);
3879 		if (type == NULL) {
3880 			add_qserver(name, default_server_type, NULL, NULL);
3881 		} else if (fscanf(file, "%s", name) == 1) {
3882 			if (type->flags & TF_QUERY_ARG && comma && *query_arg) {
3883 				add_qserver(name, type, NULL, query_arg);
3884 			} else {
3885 				add_qserver(name, type, NULL, NULL);
3886 			}
3887 		}
3888 	}
3889 
3890 	if (file != stdin) {
3891 		fclose(file);
3892 	}
3893 	debug(4, "Loaded servers from '%s'\n", filename);
3894 
3895 	current_fileline = 0;
3896 }
3897 
3898 
3899 void
print_file_location()3900 print_file_location()
3901 {
3902 	if (current_fileline != 0) {
3903 		fprintf(stderr, "%s:%d: ", current_filename ? current_filename : "<stdin>", current_fileline);
3904 	}
3905 }
3906 
3907 
3908 void
parse_query_params(struct qserver * server,char * params)3909 parse_query_params(struct qserver *server, char *params)
3910 {
3911 	char *comma, *arg = params;
3912 
3913 	do {
3914 		comma = strchr(arg, ',');
3915 		if (comma) {
3916 			*comma = '\0';
3917 		}
3918 		if (strchr(arg, '=')) {
3919 			add_query_param(server, arg);
3920 		} else if ((strcmp(arg, "noportoffset") == 0) || (strcmp(arg, "qp") == 0)) {
3921 			server->flags |= TF_NO_PORT_OFFSET;
3922 		} else if ((strcmp(arg, "showgameport") == 0) || (strcmp(arg, "gp") == 0)) {
3923 			server->flags |= TF_SHOW_GAME_PORT;
3924 		}
3925 		arg = comma + 1;
3926 	} while (comma);
3927 }
3928 
3929 
3930 int
add_qserver(char * arg,server_type * type,char * outfilename,char * query_arg)3931 add_qserver(char *arg, server_type *type, char *outfilename, char *query_arg)
3932 {
3933 	struct qserver *server, *prev_server;
3934 	int flags = 0;
3935 	char *colon = NULL, *arg_copy, *hostname = NULL;
3936 	unsigned int ipaddr;
3937 	unsigned short port, port_max;
3938 	int portrange = 0;
3939 	unsigned colonpos = 0;
3940 
3941 	debug(4, "%s, %s, %s, %s\n", arg, (NULL != type) ? type->type_string : "unknown", outfilename, query_arg);
3942 
3943 	if (run_timeout && (time(0) - start_time >= run_timeout)) {
3944 		finish_output();
3945 		exit(0);
3946 	}
3947 
3948 	port = port_max = type->default_port;
3949 
3950 	if (outfilename && (strcmp(outfilename, "-") != 0)) {
3951 		FILE *outfile = fopen(outfilename, "r+");
3952 		if ((outfile == NULL) && ((errno == EACCES) || (errno == EISDIR) || (errno == ENOSPC) || (errno == ENOTDIR))) {
3953 			perror(outfilename);
3954 			return (-1);
3955 		}
3956 		if (outfile) {
3957 			fclose(outfile);
3958 		}
3959 	}
3960 
3961 	arg_copy = strdup(arg);
3962 
3963 	colon = strchr(arg, ':');
3964 	if (colon != NULL) {
3965 		if (sscanf(colon + 1, "%hu-%hu", &port, &port_max) == 2) {
3966 			portrange = 1;
3967 		} else {
3968 			port_max = port;
3969 		}
3970 		*colon = '\0';
3971 		colonpos = colon - arg;
3972 	}
3973 
3974 	if (*arg == '+') {
3975 		flags |= FLAG_BROADCAST;
3976 		arg++;
3977 	}
3978 
3979 	ipaddr = inet_addr(arg);
3980 	if (ipaddr == INADDR_NONE) {
3981 		if (strcmp(arg, "255.255.255.255") != 0) {
3982 			ipaddr = htonl(hcache_lookup_hostname(arg));
3983 		}
3984 	} else if (hostname_lookup && !(flags & FLAG_BROADCAST)) {
3985 		hostname = hcache_lookup_ipaddr(ntohl(ipaddr));
3986 	}
3987 
3988 	if (((ipaddr == INADDR_NONE) || (ipaddr == 0)) && (strcmp(arg, "255.255.255.255") != 0)) {
3989 		if (show_errors) {
3990 			print_file_location();
3991 			fprintf(stderr, "%s: %s\n", arg, strherror(h_errno));
3992 		}
3993 		server = (struct qserver *)calloc(1, sizeof(struct qserver));
3994 		// NOTE: 0 != port to prevent infinite loop due to lack of range on unsigned short
3995 		for ( ; port <= port_max && 0 != port; ++port) {
3996 			init_qserver(server, type);
3997 			if (portrange) {
3998 				server->arg = (port == port_max) ? arg_copy : strdup(arg_copy);
3999 				// NOTE: arg_copy and therefore server->arg will always have enough space as it was a port range
4000 				sprintf(server->arg + colonpos + 1, "%hu", port);
4001 			} else {
4002 				server->arg = arg_copy;
4003 			}
4004 			server->server_name = HOSTNOTFOUND;
4005 			server->error = strdup(strherror(h_errno));
4006 			server->orig_port = server->query_port = server->port = port;
4007 			if (last_server != &servers) {
4008 				prev_server = (struct qserver *)((char *)last_server - ((char *)&server->next - (char *)server));
4009 				server->prev = prev_server;
4010 			}
4011 			*last_server = server;
4012 			last_server = &server->next;
4013 			if (one_server_type_id == ~MASTER_SERVER) {
4014 				one_server_type_id = type->id;
4015 			} else if (one_server_type_id != type->id) {
4016 				one_server_type_id = 0;
4017 			}
4018 		}
4019 		return (-1);
4020 	}
4021 
4022 	// NOTE: 0 != port to prevent infinite loop due to lack of range on unsigned short
4023 	for ( ; port <= port_max && 0 != port; ++port) {
4024 		if (noserverdups && (find_server_by_address(ipaddr, port) != NULL)) {
4025 			continue;
4026 		}
4027 
4028 		server = (struct qserver *)calloc(1, sizeof(struct qserver));
4029 		server->arg = port == port_max ? arg_copy : strdup(arg_copy);
4030 		if (portrange) {
4031 			sprintf(server->arg + colonpos + 1, "%hu", port);
4032 		}
4033 		if (hostname && colon) {
4034 			server->host_name = (char *)malloc(strlen(hostname) + 5 + 2);
4035 			sprintf(server->host_name, "%s:%hu", hostname, port);
4036 		} else {
4037 			server->host_name = strdup((hostname) ? hostname : arg);
4038 		}
4039 
4040 		server->ipaddr = ipaddr;
4041 		server->orig_port = server->query_port = server->port = port;
4042 		server->type = type;
4043 		server->outfilename = outfilename;
4044 		server->flags = flags;
4045 		server->state = STATE_INIT;
4046 		if (query_arg) {
4047 			server->query_arg = (port == port_max) ? query_arg : strdup(query_arg);
4048 			parse_query_params(server, server->query_arg);
4049 		} else {
4050 			server->query_arg = NULL;
4051 		}
4052 		init_qserver(server, type);
4053 
4054 		if (server->type->master) {
4055 			waiting_for_masters++;
4056 		}
4057 
4058 		if (num_servers_total % 10 == 0) {
4059 			hcache_update_file();
4060 		}
4061 
4062 		if (last_server != &servers) {
4063 			prev_server = (struct qserver *)((char *)last_server - ((char *)&server->next - (char *)server));
4064 			server->prev = prev_server;
4065 		}
4066 		*last_server = server;
4067 		last_server = &server->next;
4068 
4069 		add_server_to_hash(server);
4070 
4071 		if (one_server_type_id == ~MASTER_SERVER) {
4072 			one_server_type_id = type->id;
4073 		} else if (one_server_type_id != type->id) {
4074 			one_server_type_id = 0;
4075 		}
4076 
4077 		++num_servers;
4078 	}
4079 	return (0);
4080 }
4081 
4082 
4083 struct qserver *
add_qserver_byaddr(unsigned int ipaddr,unsigned short port,server_type * type,int * new_server)4084 add_qserver_byaddr(unsigned int ipaddr, unsigned short port, server_type *type, int *new_server)
4085 {
4086 	char arg[36];
4087 	struct qserver *server, *prev_server;
4088 	char *hostname = NULL;
4089 
4090 	if (run_timeout && (time(0) - start_time >= run_timeout)) {
4091 		finish_output();
4092 		exit(0);
4093 	}
4094 
4095 	if (new_server) {
4096 		*new_server = 0;
4097 	}
4098 	ipaddr = htonl(ipaddr);
4099 	if (ipaddr == 0) {
4100 		return (0);
4101 	}
4102 
4103 	// TODO: this prevents servers with the same ip:port being queried
4104 	// and hence breaks virtual servers support e.g. Teamspeak 2
4105 	if (find_server_by_address(ipaddr, port) != NULL) {
4106 		return (0);
4107 	}
4108 
4109 	if (new_server) {
4110 		*new_server = 1;
4111 	}
4112 
4113 	server = (struct qserver *)calloc(1, sizeof(struct qserver));
4114 	server->ipaddr = ipaddr;
4115 	ipaddr = ntohl(ipaddr);
4116 	sprintf(arg, "%d.%d.%d.%d:%hu", ipaddr >> 24, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff, port);
4117 	server->arg = strdup(arg);
4118 
4119 	if (hostname_lookup) {
4120 		hostname = hcache_lookup_ipaddr(ipaddr);
4121 	}
4122 
4123 	if (hostname) {
4124 		server->host_name = (char *)malloc(strlen(hostname) + 6 + 2);
4125 		sprintf(server->host_name, "%s:%hu", hostname, port);
4126 	} else {
4127 		server->host_name = strdup(arg);
4128 	}
4129 
4130 	server->orig_port = server->query_port = server->port = port;
4131 	init_qserver(server, type);
4132 
4133 	if (num_servers_total % 10 == 0) {
4134 		hcache_update_file();
4135 	}
4136 
4137 	if (last_server != &servers) {
4138 		prev_server = (struct qserver *)((char *)last_server - ((char *)&server->next - (char *)server));
4139 		server->prev = prev_server;
4140 	}
4141 	*last_server = server;
4142 	last_server = &server->next;
4143 
4144 	add_server_to_hash(server);
4145 
4146 	++num_servers;
4147 
4148 	return (server);
4149 }
4150 
4151 
4152 void
add_servers_from_masters()4153 add_servers_from_masters()
4154 {
4155 	struct qserver *server;
4156 	unsigned int ipaddr, i;
4157 	unsigned short port;
4158 	int n_servers, new_server, port_adjust = 0;
4159 	char *pkt;
4160 	server_type *server_type;
4161 	FILE *outfile;
4162 
4163 	for (server = servers; server != NULL; server = server->next) {
4164 		if (!server->type->master || (server->master_pkt == NULL)) {
4165 			continue;
4166 		}
4167 		pkt = server->master_pkt;
4168 
4169 		if (server->query_arg && (server->type->id == GAMESPY_MASTER)) {
4170 			server_type = find_server_type_string(server->query_arg);
4171 			if (server_type == NULL) {
4172 				server_type = find_server_type_id(server->type->master);
4173 			}
4174 		} else {
4175 			server_type = find_server_type_id(server->type->master);
4176 		}
4177 
4178 		if ((server->type->id == GAMESPY_MASTER) && server_type) {
4179 			if (server_type->id == UN_SERVER) {
4180 				port_adjust = -1;
4181 			} else if (server_type->id == KINGPIN_SERVER) {
4182 				port_adjust = 10;
4183 			}
4184 		}
4185 
4186 		outfile = NULL;
4187 		if (server->outfilename) {
4188 			if (strcmp(server->outfilename, "-") == 0) {
4189 				outfile = stdout;
4190 			} else {
4191 				outfile = fopen(server->outfilename, "w");
4192 			}
4193 			if (outfile == NULL) {
4194 				perror(server->outfilename);
4195 				continue;
4196 			}
4197 		}
4198 		n_servers = 0;
4199 		for (i = 0; i < server->master_pkt_len; i += 6) {
4200 			memcpy(&ipaddr, &pkt[i], 4);
4201 			memcpy(&port, &pkt[i + 4], 2);
4202 			ipaddr = ntohl(ipaddr);
4203 			port = ntohs(port) + port_adjust;
4204 			new_server = 1;
4205 			if (outfile) {
4206 				fprintf(outfile, "%s %d.%d.%d.%d:%hu\n",
4207 				    server_type ? server_type->type_string : "",
4208 				    (ipaddr >> 24) & 0xff,
4209 				    (ipaddr >> 16) & 0xff,
4210 				    (ipaddr >> 8) & 0xff,
4211 				    ipaddr & 0xff, port
4212 				    );
4213 			} else if (server_type == NULL) {
4214 				xform_printf(OF, "%d.%d.%d.%d:%hu\n", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff, port);
4215 			} else {
4216 				add_qserver_byaddr(ipaddr, port, server_type, &new_server);
4217 			}
4218 			n_servers += new_server;
4219 		}
4220 		free(server->master_pkt);
4221 		server->master_pkt = NULL;
4222 		server->master_pkt_len = 0;
4223 		server->n_servers = n_servers;
4224 		if (outfile) {
4225 			fclose(outfile);
4226 		}
4227 	}
4228 	if (hostname_lookup) {
4229 		hcache_update_file();
4230 	}
4231 	bind_sockets();
4232 }
4233 
4234 
4235 void
init_qserver(struct qserver * server,server_type * type)4236 init_qserver(struct qserver *server, server_type *type)
4237 {
4238 	server->server_name = NULL;
4239 	server->map_name = NULL;
4240 	server->game = NULL;
4241 	server->num_players = 0;
4242 	server->num_spectators = 0;
4243 	server->fd = -1;
4244 	server->state = STATE_INIT;
4245 	if (server->flags & FLAG_BROADCAST) {
4246 		server->retry1 = 1;
4247 		server->retry2 = 1;
4248 	} else {
4249 		server->retry1 = n_retries;
4250 		server->retry2 = n_retries;
4251 	}
4252 	server->n_retries = 0;
4253 	server->ping_total = 0;
4254 	server->n_packets = 0;
4255 	server->n_requests = 0;
4256 
4257 	server->n_servers = 0;
4258 	server->master_pkt_len = 0;
4259 	server->master_pkt = NULL;
4260 	server->error = NULL;
4261 
4262 	server->saved_data.data = NULL;
4263 	server->saved_data.datalen = 0;
4264 	server->saved_data.pkt_index = -1;
4265 	server->saved_data.pkt_max = 0;
4266 	server->saved_data.next = NULL;
4267 
4268 	server->type = type;
4269 	server->next_rule = (get_server_rules) ? "" : NO_SERVER_RULES;
4270 	server->next_player_info = (get_player_info && type->player_packet) ? 0 : NO_PLAYER_INFO;
4271 
4272 	server->n_player_info = 0;
4273 	server->players = NULL;
4274 	server->n_rules = 0;
4275 	server->rules = NULL;
4276 	server->last_rule = &server->rules;
4277 	server->missing_rules = 0;
4278 
4279 	num_servers_total++;
4280 }
4281 
4282 
4283 // ipaddr should be network byte-order
4284 // port should be host byte-order
4285 // NOTE: This will return the first matching server, which is not nessacarily correct
4286 // depending on if duplicate ports are allowed
4287 struct qserver *
find_server_by_address(unsigned int ipaddr,unsigned short port)4288 find_server_by_address(unsigned int ipaddr, unsigned short port)
4289 {
4290 	struct qserver **hashed;
4291 	unsigned int hash, i;
4292 
4293 	if (!noserverdups && show_errors) {
4294 		fprintf(stderr, "error: find_server_by_address while duplicates are allowed, this is unsafe!");
4295 	}
4296 
4297 	hash = (ipaddr + port) % ADDRESS_HASH_LENGTH;
4298 
4299 	if (ipaddr == 0) {
4300 		for (hash = 0; hash < ADDRESS_HASH_LENGTH; hash++) {
4301 			printf("%3d %d\n", hash, server_hash_len[hash]);
4302 		}
4303 		return (NULL);
4304 	}
4305 
4306 	hashed = server_hash[hash];
4307 	for (i = server_hash_len[hash]; i; i--, hashed++) {
4308 		if (*hashed && ((*hashed)->ipaddr == ipaddr) && ((*hashed)->port == port)) {
4309 			return (*hashed);
4310 		}
4311 	}
4312 	return (NULL);
4313 }
4314 
4315 
4316 void
add_server_to_hash(struct qserver * server)4317 add_server_to_hash(struct qserver *server)
4318 {
4319 	unsigned int hash;
4320 
4321 	hash = (server->ipaddr + server->port) % ADDRESS_HASH_LENGTH;
4322 
4323 	if (server_hash_len[hash] % 16 == 0) {
4324 		server_hash[hash] = (struct qserver **)realloc(server_hash[hash], sizeof(struct qserver **) * (server_hash_len[hash] + 16));
4325 		memset(&server_hash[hash][server_hash_len[hash]], 0, sizeof(struct qserver **) * 16);
4326 	}
4327 	server_hash[hash][server_hash_len[hash]] = server;
4328 	server_hash_len[hash]++;
4329 }
4330 
4331 
4332 void
remove_server_from_hash(struct qserver * server)4333 remove_server_from_hash(struct qserver *server)
4334 {
4335 	struct qserver **hashed;
4336 	unsigned int hash, i, ipaddr = server->ipaddr;
4337 	unsigned short port = server->orig_port;
4338 
4339 	hash = (ipaddr + port) % ADDRESS_HASH_LENGTH;
4340 
4341 	hashed = server_hash[hash];
4342 	for (i = server_hash_len[hash]; i; i--, hashed++) {
4343 		// NOTE: we use direct pointer checks here to prevent issues with duplicate port servers e.g. teamspeak 2 and 3
4344 		if (*hashed == server) {
4345 			*hashed = NULL;
4346 			break;
4347 		}
4348 	}
4349 }
4350 
4351 
4352 void
free_server_hash()4353 free_server_hash()
4354 {
4355 	int i;
4356 
4357 	for (i = 0; i < ADDRESS_HASH_LENGTH; i++) {
4358 		if (server_hash[i]) {
4359 			free(server_hash[i]);
4360 		}
4361 	}
4362 }
4363 
4364 
4365 /*
4366  * Functions for binding sockets to Quake servers
4367  */
4368 int
bind_qserver_post(struct qserver * server)4369 bind_qserver_post(struct qserver *server)
4370 {
4371 	server->state = STATE_CONNECTED;
4372 
4373 	if (server->type->flags & TF_TCP_CONNECT) {
4374 		int one = 1;
4375 		if (-1 == setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one))) {
4376 			perror("Failed to set TCP no delay");
4377 		}
4378 	}
4379 
4380 	if (server->type->id & MASTER_SERVER) {
4381 		// Use a large buffer so we dont miss packets
4382 		int sockbuf = RECV_BUF;
4383 		if (-1 == setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF, (void *)&sockbuf, sizeof(sockbuf))) {
4384 			perror("Failed to set socket buffer");
4385 		}
4386 	}
4387 
4388 #ifndef _WIN32
4389 		if (server->fd >= max_connmap) {
4390 			int old_max = max_connmap;
4391 			max_connmap = server->fd + 32;
4392 			connmap = (struct qserver **)realloc(connmap, max_connmap * sizeof(struct qserver *));
4393 			memset(&connmap[old_max], 0, (max_connmap - old_max) * sizeof(struct qserver *));
4394 		}
4395 		connmap[server->fd] = server;
4396 #endif
4397 #ifdef _WIN32
4398 		{
4399 			int i;
4400 			for (i = 0; i < max_connmap; i++) {
4401 				if (connmap[i] == NULL) {
4402 					connmap[i] = server;
4403 					break;
4404 				}
4405 			}
4406 			if (i >= max_connmap) {
4407 				printf("could not put server in connmap\n");
4408 			}
4409 		}
4410 #endif
4411 
4412 	return (0);
4413 }
4414 
4415 
4416 void
add_ms_to_timeval(struct timeval * a,unsigned long interval_ms,struct timeval * result)4417 add_ms_to_timeval(struct timeval *a, unsigned long interval_ms, struct timeval *result)
4418 {
4419 	result->tv_sec = a->tv_sec + (interval_ms / 1000);
4420 	result->tv_usec = a->tv_usec + ((interval_ms % 1000) * 1000);
4421 	if (result->tv_usec > 1000000) {
4422 		result->tv_usec -= 1000000;
4423 		result->tv_sec++;
4424 	}
4425 }
4426 
4427 
4428 void
qserver_sockaddr(struct qserver * server,struct sockaddr_in * addr)4429 qserver_sockaddr(struct qserver *server, struct sockaddr_in *addr)
4430 {
4431 	addr->sin_family = AF_INET;
4432 	addr->sin_port = (no_port_offset || server->flags & TF_NO_PORT_OFFSET) ?
4433 	    htons(server->port) :
4434 	    htons((unsigned short)(server->port + server->type->port_offset));
4435 	addr->sin_addr.s_addr = server->ipaddr;
4436 	memset(&(addr->sin_zero), 0, sizeof(addr->sin_zero));
4437 }
4438 
4439 
4440 int
connected_qserver(struct qserver * server,int polling)4441 connected_qserver(struct qserver *server, int polling)
4442 {
4443 	struct sockaddr_in addr;
4444 	char error[50];
4445 	int ret;
4446 	struct timeval tv, now, to;
4447 	fd_set connect_set;
4448 
4449 	error[0] = '\0';
4450 	gettimeofday(&now, NULL);
4451 	add_ms_to_timeval(&server->packet_time1, retry_interval * server->retry1, &to);
4452 
4453 	if (polling) {
4454 		// No delay
4455 		tv.tv_sec = 0;
4456 		tv.tv_usec = 0;
4457 	} else {
4458 		// Wait until the server would timeout
4459 		tv.tv_sec = to.tv_sec;
4460 		tv.tv_usec = to.tv_usec;
4461 	}
4462 
4463 	while (1) {
4464 		FD_ZERO(&connect_set);
4465 		FD_SET(server->fd, &connect_set);
4466 
4467 		// NOTE: We may need to check exceptfds here on windows instead of writefds
4468 		ret = select(server->fd + 1, NULL, &connect_set, NULL, &tv);
4469 		if (0 == ret) {
4470 			// Time limit expired
4471 			if (polling) {
4472 				// Check if we have run out of time to connect
4473 				gettimeofday(&now, NULL);
4474 				if (0 < time_delta(&to, &now)) {
4475 					// We still have time to connect
4476 					return (-2);
4477 				}
4478 			}
4479 
4480 			qserver_sockaddr(server, &addr);
4481 			sprintf(error, "connect:%s:%u - timeout", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
4482 			server->server_name = TIMEOUT;
4483 			server->state = STATE_TIMEOUT;
4484 			goto connect_error;
4485 		} else if (0 < ret) {
4486 			// Socket selected for write so either connected or error
4487 			int sockerr, orig_errno;
4488 			unsigned int lon = sizeof(int);
4489 
4490 			orig_errno = errno;
4491 			if (0 != getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (void *)(&sockerr), &lon)) {
4492 				// Restore the original error
4493 				errno = orig_errno;
4494 				goto connect_error;
4495 			}
4496 
4497 			if (sockerr) {
4498 				// set the real error
4499 				errno = sockerr;
4500 				goto connect_error;
4501 			}
4502 
4503 			// Connection success
4504 			break;
4505 		} else {
4506 			// select failed
4507 			if (errno != EINTR) {
4508 				goto connect_error;
4509 			}
4510 		}
4511 	}
4512 
4513 	return (bind_qserver_post(server));
4514 
4515 connect_error:
4516 	if (STATE_CONNECTING == server->state) {
4517 		// Default error case
4518 		if (0 == strlen(error)) {
4519 			qserver_sockaddr(server, &addr);
4520 			sprintf(error, "connect: %s:%u", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
4521 		}
4522 		server->server_name = SYSERROR;
4523 		server->state = STATE_SYS_ERROR;
4524 	}
4525 
4526 	if (show_errors) {
4527 		perror(error);
4528 	}
4529 	close(server->fd);
4530 	server->fd = -1;
4531 	connected--;
4532 
4533 	return (-1);
4534 }
4535 
4536 
4537 int
bind_qserver2(struct qserver * server,int wait)4538 bind_qserver2(struct qserver *server, int wait)
4539 {
4540 	struct sockaddr_in addr;
4541 	static int one = 1;
4542 
4543 	debug(1, "start %p @ %d.%d.%d.%d:%hu\n",
4544 	    server,
4545 	    server->ipaddr & 0xff,
4546 	    (server->ipaddr >> 8) & 0xff,
4547 	    (server->ipaddr >> 16) & 0xff,
4548 	    (server->ipaddr >> 24) & 0xff,
4549 	    server->port
4550 	    );
4551 
4552 	if (server->type->flags & TF_TCP_CONNECT) {
4553 		server->fd = socket(AF_INET, SOCK_STREAM, 0);
4554 	} else {
4555 		server->fd = socket(AF_INET, SOCK_DGRAM, 0);
4556 	}
4557 
4558 	if (server->fd == INVALID_SOCKET) {
4559 		if (sockerr() == EMFILE) {
4560 			// Per process descriptor table is full - retry
4561 			server->fd = -1;
4562 			return (-2);
4563 		}
4564 
4565 		perror("socket");
4566 		server->server_name = SYSERROR;
4567 		server->state = STATE_SYS_ERROR;
4568 		return (-1);
4569 	}
4570 
4571 	addr.sin_family = AF_INET;
4572 	addr.sin_addr.s_addr = htonl(source_ip);
4573 	if (server->type->id == Q2_MASTER) {
4574 		addr.sin_port = htons(26500);
4575 	} else if (source_port == 0) {
4576 		addr.sin_port = 0;
4577 	} else {
4578 		addr.sin_port = htons(source_port);
4579 		source_port++;
4580 		if (source_port > source_port_high) {
4581 			source_port = source_port_low;
4582 		}
4583 	}
4584 	memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
4585 
4586 	if (bind(server->fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == SOCKET_ERROR) {
4587 		perror("bind");
4588 		server->server_name = SYSERROR;
4589 		server->state = STATE_SYS_ERROR;
4590 		close(server->fd);
4591 		server->fd = -1;
4592 		return (-1);
4593 	}
4594 
4595 	if (server->flags & FLAG_BROADCAST) {
4596 		if (-1 == setsockopt(server->fd, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one))) {
4597 			perror("Failed to set broadcast");
4598 			server->server_name = SYSERROR;
4599 			server->state = STATE_SYS_ERROR;
4600 			close(server->fd);
4601 			server->fd = -1;
4602 			return (-1);
4603 		}
4604 	}
4605 
4606 	// we need nonblocking always. poll on an udp socket would wake
4607 	// up and recv blocks if a packet with incorrect checksum is
4608 	// received
4609 	set_non_blocking(server->fd);
4610 
4611 	if ((server->type->id != Q2_MASTER) && !(server->flags & FLAG_BROADCAST)) {
4612 		if (server->type->flags & TF_TCP_CONNECT) {
4613 			// TCP set packet_time1 so it can be used for ping calculations for protocols with an initial response
4614 			gettimeofday(&server->packet_time1, NULL);
4615 		}
4616 
4617 		qserver_sockaddr(server, &addr);
4618 		server->state = STATE_CONNECTING;
4619 
4620 		if (connect(server->fd, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
4621 			if (connection_inprogress()) {
4622 				int ret;
4623 
4624 				// Ensure we don't detect the same error twice, specifically on a different server
4625 				clear_socketerror();
4626 
4627 				if (!wait) {
4628 					debug(2, "connect:%s:%u - in progress", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
4629 					return (-3);
4630 				}
4631 				ret = connected_qserver(server, 0);
4632 				if (0 != ret) {
4633 					return (ret);
4634 				}
4635 			} else {
4636 				if (show_errors) {
4637 					char error[50];
4638 					sprintf(error, "connect:%s:%u", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
4639 					perror(error);
4640 				}
4641 				server->server_name = SYSERROR;
4642 				server->state = STATE_SYS_ERROR;
4643 				close(server->fd);
4644 				server->fd = -1;
4645 				return (-1);
4646 			}
4647 		}
4648 	}
4649 
4650 	return (bind_qserver_post(server));
4651 }
4652 
4653 
4654 int
bind_qserver(struct qserver * server)4655 bind_qserver(struct qserver *server)
4656 {
4657 	return (bind_qserver2(server, 1));
4658 }
4659 
4660 
4661 static struct timeval t_lastsend = { 0, 0 };
4662 
4663 int
bind_sockets()4664 bind_sockets()
4665 {
4666 	struct qserver *server, *next_server, *first_server, *last_server;
4667 	struct timeval now;
4668 	int rc, retry_count = 0, inprogress = 0;
4669 
4670 	gettimeofday(&now, NULL);
4671 	if (connected && sendinterval && (time_delta(&now, &t_lastsend) < sendinterval)) {
4672 		server = NULL;
4673 	} else if (!waiting_for_masters) {
4674 		if (last_server_bind == NULL) {
4675 			last_server_bind = servers;
4676 		}
4677 		server = last_server_bind;
4678 	} else {
4679 		server = servers;
4680 	}
4681 
4682 	first_server = server;
4683 
4684 	for ( ; server != NULL && connected < max_simultaneous; ) {
4685 		// note the next server for use as process_func can free the server
4686 		next_server = server->next;
4687 		if ((server->server_name == NULL) && (server->fd == -1)) {
4688 			if (waiting_for_masters && !server->type->master) {
4689 				server = next_server;
4690 				continue;
4691 			}
4692 
4693 			if ((rc = bind_qserver2(server, syncconnect ? 1 : 0)) == 0) {
4694 				debug(1, "send %d.%d.%d.%d:%hu\n",
4695 				    server->ipaddr & 0xff,
4696 				    (server->ipaddr >> 8) & 0xff,
4697 				    (server->ipaddr >> 16) & 0xff,
4698 				    (server->ipaddr >> 24) & 0xff,
4699 				    server->port
4700 				    );
4701 
4702 				gettimeofday(&t_lastsend, NULL);
4703 				debug(2, "calling status_query_func for %p - connect", server);
4704 				process_func_ret(server, server->type->status_query_func(server));
4705 
4706 				connected++;
4707 				if (!waiting_for_masters) {
4708 					last_server_bind = server;
4709 				}
4710 				break;
4711 			} else if (rc == -3) {
4712 				// Connect in progress
4713 
4714 				// We add to increment connected as we need to know the total
4715 				// amount of connections in progress not just those that have
4716 				// successfuly completed their connection otherwise we could
4717 				// blow FD_SETSIZE
4718 				connected++;
4719 				inprogress++;
4720 			} else if ((rc == -2) && (++retry_count > 2)) {
4721 				return (-2);
4722 			} else if (-1 == rc) {
4723 				cleanup_qserver(server, FORCE);
4724 			}
4725 		}
4726 
4727 		server = next_server;
4728 	}
4729 
4730 	// Wait for all connections to succeed or fail
4731 	last_server = server;
4732 	while (inprogress) {
4733 		inprogress = 0;
4734 		server = first_server;
4735 		for ( ; server != last_server; ) {
4736 			next_server = server->next;
4737 			if (STATE_CONNECTING == server->state) {
4738 				rc = connected_qserver(server, 1);
4739 				switch (rc) {
4740 				case 0:
4741 					// Connected
4742 					gettimeofday(&t_lastsend, NULL);
4743 					debug(2, "calling status_query_func for %p - in progress", server);
4744 					process_func_ret(server, server->type->status_query_func(server));
4745 
4746 					// NOTE: connected is already incremented
4747 					if (!waiting_for_masters) {
4748 						last_server_bind = server;
4749 					}
4750 					break;
4751 
4752 				case -2:
4753 					// In progress
4754 					inprogress++;
4755 					break;
4756 
4757 				case -1:
4758 					cleanup_qserver(server, FORCE);
4759 					break;
4760 				}
4761 			}
4762 			server = next_server;
4763 		}
4764 	}
4765 
4766 	if ((NULL != last_server) || (!connected && retry_count)) {
4767 		// Retry later, more to process
4768 		return (-2);
4769 	}
4770 
4771 	return (0);
4772 }
4773 
4774 
4775 int
process_func_ret(struct qserver * server,int ret)4776 process_func_ret(struct qserver *server, int ret)
4777 {
4778 	debug(3, "%p, %d", server, ret);
4779 	switch (ret) {
4780 	case INPROGRESS:
4781 		return (ret);
4782 
4783 	case DONE_AUTO:
4784 		cleanup_qserver(server, NO_FORCE);
4785 		return (ret);
4786 
4787 	case DONE_FORCE:
4788 	case SYS_ERROR:
4789 	case MEM_ERROR:
4790 	case PKT_ERROR:
4791 	case ORD_ERROR:
4792 	case REQ_ERROR:
4793 		cleanup_qserver(server, FORCE);
4794 		return (ret);
4795 	}
4796 
4797 	debug(0, "unhandled return code %d, please report!", ret);
4798 
4799 	return (ret);
4800 }
4801 
4802 
4803 /*
4804  * Functions for sending packets
4805  */
4806 // this is so broken, someone please rewrite the timeout handling
4807 void
send_packets()4808 send_packets()
4809 {
4810 	struct qserver *server;
4811 	struct timeval now;
4812 	int interval, n_sent = 0, prev_n_sent;
4813 	unsigned i;
4814 
4815 	debug(3, "processing...");
4816 
4817 	gettimeofday(&now, NULL);
4818 
4819 	if (!t_lastsend.tv_sec) {
4820 		// nothing
4821 	} else if (connected && sendinterval && (time_delta(&now, &t_lastsend) < sendinterval)) {
4822 		return;
4823 	}
4824 
4825 	for (i = 0; i < max_connmap; ++i) {
4826 		server = connmap[i];
4827 		if (!server) {
4828 			continue;
4829 		}
4830 
4831 		if (server->fd == -1) {
4832 			debug(0, "invalid entry in connmap\n");
4833 		}
4834 
4835 		if (server->type->id & MASTER_SERVER) {
4836 			interval = master_retry_interval;
4837 		} else {
4838 			interval = retry_interval;
4839 		}
4840 
4841 		debug(2, "server %p, name %s, retry1 %d, next_rule %p, next_player_info %d, num_players %d, n_retries %d",
4842 		    server,
4843 		    server->server_name,
4844 		    server->retry1,
4845 		    server->next_rule,
4846 		    server->next_player_info,
4847 		    server->num_players,
4848 		    n_retries
4849 		    );
4850 		prev_n_sent = n_sent;
4851 		if (server->server_name == NULL) {
4852 			// We havent seen the server yet?
4853 			if ((server->retry1 != n_retries) && (time_delta(&now, &server->packet_time1) < (interval * (n_retries - server->retry1 + 1)))) {
4854 				continue;
4855 			}
4856 
4857 			if (server->retry1 < 1) {
4858 				// No more retries
4859 				cleanup_qserver(server, FORCE);
4860 				continue;
4861 			}
4862 
4863 			if ((qserver_get_timeout(server, &now) <= 0) && !(server->type->flags & TF_TCP_CONNECT)) {
4864 				// Query status
4865 				debug(2, "calling status_query_func for %p", server);
4866 				process_func_ret(server, server->type->status_query_func(server));
4867 				gettimeofday(&t_lastsend, NULL);
4868 				n_sent++;
4869 				continue;
4870 			}
4871 		}
4872 
4873 		if (server->next_rule != NO_SERVER_RULES) {
4874 			// We want server rules
4875 			if ((server->retry1 != n_retries) && (time_delta(&now, &server->packet_time1) < (interval * (n_retries - server->retry1 + 1)))) {
4876 				continue;
4877 			}
4878 
4879 			if (server->retry1 < 1) {
4880 				// no more retries
4881 				server->next_rule = NULL;
4882 				server->missing_rules = 1;
4883 				cleanup_qserver(server, NO_FORCE);
4884 				continue;
4885 			}
4886 			debug(3, "send_rule_request_packet1");
4887 			send_rule_request_packet(server);
4888 			gettimeofday(&t_lastsend, NULL);
4889 			n_sent++;
4890 		}
4891 
4892 		if (server->next_player_info < server->num_players) {
4893 			// Expecting player details
4894 			if ((server->retry2 != n_retries) && (time_delta(&now, &server->packet_time2) < (interval * (n_retries - server->retry2 + 1)))) {
4895 				continue;
4896 			}
4897 			if (!server->retry2) {
4898 				server->next_player_info++;
4899 				if (server->next_player_info >= server->num_players) {
4900 					// no more retries
4901 					cleanup_qserver(server, FORCE);
4902 					continue;
4903 				}
4904 				server->retry2 = n_retries;
4905 			}
4906 			send_player_request_packet(server);
4907 			gettimeofday(&t_lastsend, NULL);
4908 			n_sent++;
4909 		}
4910 
4911 		if (prev_n_sent == n_sent) {
4912 			// we didnt send any additional queries
4913 			debug(2, "no queries sent: %d %d", time_delta(&now, &server->packet_time1), (interval * (n_retries + 1)));
4914 			if (server->retry1 < 1) {
4915 				// no retries left
4916 				if (time_delta(&now, &server->packet_time1) > (interval * (n_retries + 1))) {
4917 					cleanup_qserver(server, FORCE);
4918 				}
4919 			} else {
4920 				// decrement as we didnt send any packets
4921 				server->retry1--;
4922 			}
4923 		}
4924 	}
4925 
4926 	debug(3, "done");
4927 }
4928 
4929 
4930 /* server starts sending data immediately, so we need not do anything */
4931 query_status_t
send_bfris_request_packet(struct qserver * server)4932 send_bfris_request_packet(struct qserver *server)
4933 {
4934 	return (register_send(server));
4935 }
4936 
4937 
4938 /* First packet for a normal Quake server
4939  */
4940 query_status_t
send_qserver_request_packet(struct qserver * server)4941 send_qserver_request_packet(struct qserver *server)
4942 {
4943 	return (send_packet(server, server->type->status_packet, server->type->status_len));
4944 }
4945 
4946 
4947 /* First packet for a QuakeWorld server
4948  */
4949 query_status_t
send_qwserver_request_packet(struct qserver * server)4950 send_qwserver_request_packet(struct qserver *server)
4951 {
4952 	int rc;
4953 
4954 	if (server->flags & FLAG_BROADCAST) {
4955 		rc = send_broadcast(server, server->type->status_packet, server->type->status_len);
4956 	} else if (server->server_name == NULL) {
4957 		rc = send(server->fd, server->type->status_packet, server->type->status_len, 0);
4958 	} else if ((server->server_name != NULL) && server->type->rule_packet) {
4959 		rc = send(server->fd, server->type->rule_packet, server->type->rule_len, 0);
4960 	} else {
4961 		rc = SOCKET_ERROR;
4962 	}
4963 
4964 	if (rc == SOCKET_ERROR) {
4965 		return (send_error(server, rc));
4966 	}
4967 
4968 	if ((server->retry1 == n_retries) || server->flags & FLAG_BROADCAST) {
4969 		gettimeofday(&server->packet_time1, NULL);
4970 		server->n_requests++;
4971 	} else if (server->server_name == NULL) {
4972 		server->n_retries++;
4973 	}
4974 	server->retry1--;
4975 	if (server->server_name == NULL) {
4976 		server->n_packets++;
4977 	}
4978 	server->next_player_info = NO_PLAYER_INFO;      // we don't have a player packet
4979 
4980 	return (INPROGRESS);
4981 }
4982 
4983 
4984 // First packet for an Unreal Tournament 2003 server
4985 query_status_t
send_ut2003_request_packet(struct qserver * server)4986 send_ut2003_request_packet(struct qserver *server)
4987 {
4988 	int ret = send_packet(server, server->type->status_packet, server->type->status_len);
4989 
4990 	server->next_player_info = NO_PLAYER_INFO;
4991 
4992 	return (ret);
4993 }
4994 
4995 
4996 // First packet for an Half-Life 2 server
4997 query_status_t
send_hl2_request_packet(struct qserver * server)4998 send_hl2_request_packet(struct qserver *server)
4999 {
5000 	return (send_packet(server, server->type->status_packet, server->type->status_len));
5001 }
5002 
5003 
5004 /* First packet for an Unreal master
5005  */
5006 query_status_t
send_unrealmaster_request_packet(struct qserver * server)5007 send_unrealmaster_request_packet(struct qserver *server)
5008 {
5009 	return (send_packet(server, server->type->status_packet, server->type->status_len));
5010 }
5011 
5012 
5013 static const char *steam_region[] =
5014 {
5015 	"US East Coast", "US West Coast", "South America", "Europe", "Asia", "Australia", "Middle East", "Africa", NULL
5016 };
5017 
5018 char *
build_hlmaster_packet(struct qserver * server,int * len)5019 build_hlmaster_packet(struct qserver *server, int *len)
5020 {
5021 	static char packet[1600];
5022 	char *pkt, *r, *sep = "";
5023 	char *gamedir, *map, *flags;
5024 	int flen;
5025 
5026 	pkt = &packet[0];
5027 	memcpy(pkt, server->type->master_packet, *len);
5028 
5029 	if (server->type->flags & TF_MASTER_STEAM) {
5030 		// default the region to 0xff
5031 		const char *regionstring = get_param_value(server, "region", NULL);
5032 		int region = 0xFF;
5033 		if (regionstring) {
5034 			char *tmp = NULL;
5035 			region = strtol(regionstring, &tmp, 10);
5036 			if (tmp == regionstring) {
5037 				int i = 0;
5038 				region = 0xFF;
5039 				for ( ; steam_region[i]; ++i) {
5040 					if (!strcmp(regionstring, steam_region[i])) {
5041 						region = i;
5042 						break;
5043 					}
5044 				}
5045 			}
5046 		}
5047 		*(pkt + 1) = region;
5048 	}
5049 
5050 	pkt += *len;
5051 
5052 	gamedir = get_param_value(server, "game", NULL);
5053 	if (gamedir) {
5054 		pkt += sprintf(pkt, "\\gamedir\\%s", gamedir);
5055 	}
5056 
5057 	// not valid for steam?
5058 	map = get_param_value(server, "map", NULL);
5059 	if (map) {
5060 		pkt += sprintf(pkt, "\\map\\%s", map);
5061 	}
5062 
5063 	// steam
5064 	flags = get_param_value(server, "napp", NULL);
5065 	if (flags) {
5066 		pkt += sprintf(pkt, "\\napp\\%s", flags);
5067 	}
5068 
5069 	// not valid for steam?
5070 	flags = get_param_value(server, "status", NULL);
5071 	r = flags;
5072 	while (flags && sep) {
5073 		sep = strchr(r, ':');
5074 		if (sep) {
5075 			flen = sep - r;
5076 		} else {
5077 			flen = strlen(r);
5078 		}
5079 
5080 		if (strncmp(r, "notempty", flen) == 0) {
5081 			pkt += sprintf(pkt, "\\empty\\1");
5082 		} else if (strncmp(r, "notfull", flen) == 0) {
5083 			pkt += sprintf(pkt, "\\full\\1");
5084 		} else if (strncmp(r, "dedicated", flen) == 0) {
5085 			if (server->type->flags & TF_MASTER_STEAM) {
5086 				pkt += sprintf(pkt, "\\type\\d");
5087 			} else {
5088 				pkt += sprintf(pkt, "\\dedicated\\1");
5089 			}
5090 		} else if (strncmp(r, "linux", flen) == 0) {
5091 			pkt += sprintf(pkt, "\\linux\\1");
5092 		} else if (strncmp(r, "proxy", flen) == 0) {
5093 			// steam
5094 			pkt += sprintf(pkt, "\\proxy\\1");
5095 		} else if (strncmp(r, "secure", flen) == 0) {
5096 			// steam
5097 			pkt += sprintf(pkt, "\\secure\\1");
5098 		}
5099 		r = sep + 1;
5100 	}
5101 
5102 	// always need null terminator
5103 	*pkt = 0x00;
5104 	pkt++;
5105 
5106 	*len = pkt - packet;
5107 
5108 	return (packet);
5109 }
5110 
5111 
5112 /* First packet for a QuakeWorld master server
5113  */
5114 query_status_t
send_qwmaster_request_packet(struct qserver * server)5115 send_qwmaster_request_packet(struct qserver *server)
5116 {
5117 	int rc = 0;
5118 
5119 	server->next_player_info = NO_PLAYER_INFO;
5120 
5121 	if (server->type->id == Q2_MASTER) {
5122 		struct sockaddr_in addr;
5123 		addr.sin_family = AF_INET;
5124 		if (no_port_offset || server->flags & TF_NO_PORT_OFFSET) {
5125 			addr.sin_port = htons(server->port);
5126 		} else {
5127 			addr.sin_port = htons((unsigned short)(server->port + server->type->port_offset));
5128 		}
5129 		addr.sin_addr.s_addr = server->ipaddr;
5130 		memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
5131 		rc = sendto(server->fd, server->type->master_packet, server->type->master_len, 0, (struct sockaddr *)&addr, sizeof(addr));
5132 	} else {
5133 		char *packet;
5134 		int packet_len;
5135 		char query_buf[4096] = { 0 };
5136 
5137 		packet = server->type->master_packet;
5138 		packet_len = server->type->master_len;
5139 
5140 		if (server->type->id == HL_MASTER) {
5141 			memcpy(server->type->master_packet + 1, server->master_query_tag, 3);
5142 			if (server->query_arg) {
5143 				packet_len = server->type->master_len;
5144 				packet = build_hlmaster_packet(server, &packet_len);
5145 			}
5146 		} else if (server->type->flags & TF_MASTER_STEAM) {
5147 			// region
5148 			int tag_len = strlen(server->master_query_tag);
5149 			if (tag_len < 9) {
5150 				// initial case
5151 				tag_len = 9;
5152 				strcpy(server->master_query_tag, "0.0.0.0:0");
5153 			}
5154 
5155 			// 1 byte packet id
5156 			// 1 byte region
5157 			// ip:port
5158 			// 1 byte null
5159 			packet_len = 2 + tag_len + 1;
5160 
5161 			if (server->query_arg) {
5162 				// build_hlmaster_packet uses server->type->master_packet
5163 				// as the basis so copy from server->master_query_tag
5164 				strcpy(server->type->master_packet + 2, server->master_query_tag);
5165 				packet = build_hlmaster_packet(server, &packet_len);
5166 			} else {
5167 				// default region
5168 				*(packet + 1) = 0xff;
5169 				memcpy(packet + 2, server->master_query_tag, tag_len);
5170 
5171 				// filter null
5172 				*(packet + packet_len) = 0x00;
5173 				packet_len++;
5174 			}
5175 		} else if (server->type->flags & TF_QUERY_ARG) {
5176 			// fill in the master protocol details
5177 			char *master_protocol = server->query_arg;
5178 			if (master_protocol == NULL) {
5179 				master_protocol = server->type->master_protocol;
5180 			}
5181 			packet_len = sprintf(query_buf, server->type->master_packet,
5182 				master_protocol ? master_protocol : "",
5183 				server->type->master_query  ? server->type->master_query : ""
5184 				);
5185 			packet = query_buf;
5186 		}
5187 
5188 		rc = send(server->fd, packet, packet_len, 0);
5189 	}
5190 
5191 	if (rc == SOCKET_ERROR) {
5192 		return (send_error(server, rc));
5193 	}
5194 
5195 	if (server->retry1 == n_retries) {
5196 		gettimeofday(&server->packet_time1, NULL);
5197 		server->n_requests++;
5198 	} else {
5199 		server->n_retries++;
5200 	}
5201 	server->retry1--;
5202 	server->n_packets++;
5203 
5204 	return (INPROGRESS);
5205 }
5206 
5207 
5208 query_status_t
send_tribes_request_packet(struct qserver * server)5209 send_tribes_request_packet(struct qserver *server)
5210 {
5211 	return (send_packet(server, server->type->player_packet, server->type->player_len));
5212 }
5213 
5214 
5215 query_status_t
send_tribes2_request_packet(struct qserver * server)5216 send_tribes2_request_packet(struct qserver *server)
5217 {
5218 	int rc;
5219 
5220 	if (server->flags & FLAG_BROADCAST && (server->server_name == NULL)) {
5221 		rc = send_broadcast(server, server->type->status_packet, server->type->status_len);
5222 	} else if (server->server_name == NULL) {
5223 		rc = send(server->fd, server->type->status_packet, server->type->status_len, 0);
5224 	} else {
5225 		rc = send(server->fd, server->type->player_packet, server->type->player_len, 0);
5226 	}
5227 
5228 	if (rc == SOCKET_ERROR) {
5229 		return (send_error(server, rc));
5230 	}
5231 
5232 	register_send(server);
5233 
5234 	return (rc);
5235 }
5236 
5237 
5238 query_status_t
send_savage_request_packet(struct qserver * server)5239 send_savage_request_packet(struct qserver *server)
5240 {
5241 	int len;
5242 	char *pkt;
5243 
5244 	if (get_player_info) {
5245 		pkt = server->type->player_packet;
5246 		len = server->type->player_len;
5247 	} else {
5248 		pkt = server->type->status_packet;
5249 		len = server->type->status_len;
5250 	}
5251 
5252 	return (send_packet(server, pkt, len));
5253 }
5254 
5255 
5256 query_status_t
send_farcry_request_packet(struct qserver * server)5257 send_farcry_request_packet(struct qserver *server)
5258 {
5259 	int len;
5260 	char *pkt;
5261 
5262 	if (get_player_info) {
5263 		pkt = server->type->player_packet;
5264 		len = server->type->player_len;
5265 	} else {
5266 		pkt = server->type->status_packet;
5267 		len = server->type->status_len;
5268 	}
5269 
5270 	return (send_packet(server, pkt, len));
5271 }
5272 
5273 
5274 query_status_t
send_tribes2master_request_packet(struct qserver * server)5275 send_tribes2master_request_packet(struct qserver *server)
5276 {
5277 	int rc;
5278 	unsigned char packet[1600], *pkt;
5279 	unsigned int len, min_players, max_players, region_mask = 0;
5280 	unsigned int build_version, max_bots, min_cpu, status;
5281 	char *game, *mission, *buddies;
5282 	static char *region_list[] =
5283 	{
5284 		"naeast", "nawest", "sa", "aus", "asia", "eur", NULL
5285 	};
5286 	static char *status_list[] =
5287 	{
5288 		"dedicated", "nopassword", "linux"
5289 	};
5290 
5291 	if (strcmp(get_param_value(server, "query", ""), "types") == 0) {
5292 		rc = send(server->fd, tribes2_game_types_request, sizeof(tribes2_game_types_request), 0);
5293 		goto send_done;
5294 	}
5295 
5296 	memcpy(packet, server->type->master_packet, server->type->master_len);
5297 
5298 	pkt = packet + 7;
5299 
5300 	game = get_param_value(server, "game", "any");
5301 	len = strlen(game);
5302 	if (len > 255) {
5303 		len = 255;
5304 	}
5305 	*pkt++ = len;
5306 	memcpy(pkt, game, len);
5307 	pkt += len;
5308 
5309 	mission = get_param_value(server, "mission", "any");
5310 	len = strlen(mission);
5311 	if (len > 255) {
5312 		len = 255;
5313 	}
5314 	*pkt++ = len;
5315 	memcpy(pkt, mission, len);
5316 	pkt += len;
5317 
5318 	min_players = get_param_ui_value(server, "minplayers", 0);
5319 	max_players = get_param_ui_value(server, "maxplayers", 255);
5320 	*pkt++ = min_players;
5321 	*pkt++ = max_players;
5322 
5323 	region_mask = get_param_ui_value(server, "regions", 0xffffffff);
5324 	if (region_mask == 0) {
5325 		char *regions = get_param_value(server, "regions", "");
5326 		char *r = regions;
5327 		char **list, *sep;
5328 		do {
5329 			sep = strchr(r, ':');
5330 			if (sep) {
5331 				len = sep - r;
5332 			} else {
5333 				len = strlen(r);
5334 			}
5335 			for (list = region_list; *list; list++) {
5336 				if (strncasecmp(r, *list, len) == 0) {
5337 					break;
5338 				}
5339 			}
5340 			if (*list) {
5341 				region_mask |= 1 << (list - region_list);
5342 			}
5343 			r = sep + 1;
5344 		} while (sep);
5345 	}
5346 	if (little_endian) {
5347 		memcpy(pkt, &region_mask, 4);
5348 	} else {
5349 		pkt[0] = region_mask & 0xff;
5350 		pkt[1] = (region_mask >> 8) & 0xff;
5351 		pkt[2] = (region_mask >> 16) & 0xff;
5352 		pkt[3] = (region_mask >> 24) & 0xff;
5353 	}
5354 	pkt += 4;
5355 
5356 	build_version = get_param_ui_value(server, "build", 0);
5357 
5358 	/*
5359 	 * if ( build_version && build_version < 22337) {
5360 	 * packet[1]= 0;
5361 	 * build_version= 0;
5362 	 * }
5363 	 */
5364 	if (little_endian) {
5365 		memcpy(pkt, &build_version, 4);
5366 	} else {
5367 		pkt[0] = build_version & 0xff;
5368 		pkt[1] = (build_version >> 8) & 0xff;
5369 		pkt[2] = (build_version >> 16) & 0xff;
5370 		pkt[3] = (build_version >> 24) & 0xff;
5371 	}
5372 	pkt += 4;
5373 
5374 	status = get_param_ui_value(server, "status", -1);
5375 	if (status == 0) {
5376 		char *flags = get_param_value(server, "status", "");
5377 		char *r = flags;
5378 		char **list, *sep;
5379 		do {
5380 			sep = strchr(r, ':');
5381 			if (sep) {
5382 				len = sep - r;
5383 			} else {
5384 				len = strlen(r);
5385 			}
5386 			for (list = status_list; *list; list++) {
5387 				if (strncasecmp(r, *list, len) == 0) {
5388 					break;
5389 				}
5390 			}
5391 			if (*list) {
5392 				status |= 1 << (list - status_list);
5393 			}
5394 			r = sep + 1;
5395 		} while (sep);
5396 	} else if (status == -1) {
5397 		status = 0;
5398 	}
5399 	*pkt++ = status;
5400 
5401 	max_bots = get_param_ui_value(server, "maxbots", 255);
5402 	*pkt++ = max_bots;
5403 
5404 	min_cpu = get_param_ui_value(server, "mincpu", 0);
5405 	if (little_endian) {
5406 		memcpy(pkt, &min_cpu, 2);
5407 	} else {
5408 		pkt[0] = min_cpu & 0xff;
5409 		pkt[1] = (min_cpu >> 8) & 0xff;
5410 	}
5411 	pkt += 2;
5412 
5413 	buddies = get_param_value(server, "buddies", NULL);
5414 	if (buddies) {
5415 		char *b = buddies, *sep;
5416 		unsigned int buddy, n_buddies = 0;
5417 		unsigned char *n_loc = pkt++;
5418 		do {
5419 			sep = strchr(b, ':');
5420 			if (sscanf(b, "%u", &buddy)) {
5421 				n_buddies++;
5422 				if (little_endian) {
5423 					memcpy(pkt, &buddy, 4);
5424 				} else {
5425 					pkt[0] = buddy & 0xff;
5426 					pkt[1] = (buddy >> 8) & 0xff;
5427 					pkt[2] = (buddy >> 16) & 0xff;
5428 					pkt[3] = (buddy >> 24) & 0xff;
5429 				}
5430 				pkt += 4;
5431 			}
5432 			b = sep + 1;
5433 		} while (sep && n_buddies < 255);
5434 		*n_loc = n_buddies;
5435 	} else {
5436 		*pkt++ = 0;
5437 	}
5438 
5439 	rc = send(server->fd, (char *)packet, pkt - packet, 0);
5440 
5441 send_done:
5442 	if (rc == SOCKET_ERROR) {
5443 		return (send_error(server, rc));
5444 	}
5445 
5446 	if (server->retry1 == n_retries) {
5447 		gettimeofday(&server->packet_time1, NULL);
5448 		server->n_requests++;
5449 	} else {
5450 		server->n_retries++;
5451 	}
5452 	server->retry1--;
5453 	server->n_packets++;
5454 
5455 	return (INPROGRESS);
5456 }
5457 
5458 
5459 static struct _gamespy_query_map {
5460 	char *qstat_type;
5461 	char *gamespy_type;
5462 }
5463 
5464 gamespy_query_map[] =
5465 {
5466 	{ "qws", "quakeworld" },
5467 	{ "q2s", "quake2"     },
5468 	{ "q3s", "quake3"     },
5469 	{ "tbs", "tribes"     },
5470 	{ "uns", "ut"	      },
5471 	{ "sgs", "shogo"      },
5472 	{ "hls", "halflife"   },
5473 	{ "kps", "kingpin"    },
5474 	{ "hrs", "heretic2"   },
5475 	{ "sfs", "sofretail"  },
5476 	{ NULL,	 NULL	      }
5477 };
5478 
5479 query_status_t
send_gamespy_master_request(struct qserver * server)5480 send_gamespy_master_request(struct qserver *server)
5481 {
5482 	int rc, i;
5483 	char request[1024];
5484 
5485 	if (server->n_packets) {
5486 		return (DONE_AUTO);
5487 	}
5488 
5489 	// WARNING: This only works for masters which don't check the value of validate
5490 	// e.g. unreal.epicgames.com
5491 	//
5492 	// What we should be doing here is recieving the challenge from the master
5493 	// processing the secure key and then using that as the value for validate.
5494 	//
5495 	// The details of this can be seen in gslist:
5496 	// http://aluigi.altervista.org/papers.htm#gslist
5497 	rc = send(server->fd, server->type->master_packet, server->type->master_len, 0);
5498 	if (rc != server->type->master_len) {
5499 		return (send_error(server, rc));
5500 	}
5501 
5502 	strcpy(request, server->type->status_packet);
5503 
5504 	for (i = 0; gamespy_query_map[i].qstat_type; i++) {
5505 		if (strcasecmp(server->query_arg, gamespy_query_map[i].qstat_type) == 0) {
5506 			break;
5507 		}
5508 	}
5509 
5510 	if (gamespy_query_map[i].gamespy_type == NULL) {
5511 		strcat(request, server->query_arg);
5512 	} else {
5513 		strcat(request, gamespy_query_map[i].gamespy_type);
5514 	}
5515 	strcat(request, "\\final\\");
5516 	assert(strlen(request) < sizeof(request));
5517 
5518 	rc = send(server->fd, request, strlen(request), 0);
5519 	if (rc != strlen(request)) {
5520 		return (send_error(server, rc));
5521 	}
5522 
5523 	if (server->retry1 == n_retries) {
5524 		gettimeofday(&server->packet_time1, NULL);
5525 		server->n_requests++;
5526 	}
5527 
5528 	server->n_packets++;
5529 
5530 	return (INPROGRESS);
5531 }
5532 
5533 
5534 query_status_t
send_rule_request_packet(struct qserver * server)5535 send_rule_request_packet(struct qserver *server)
5536 {
5537 	int rc, len;
5538 
5539 	debug(3, "send_rule_request_packet: %p", server);
5540 
5541 	/* Server created via broadcast, so bind it */
5542 	if (server->fd == -1) {
5543 		if (bind_qserver(server) < 0) {
5544 			goto setup_retry;
5545 		}
5546 	}
5547 
5548 	if (server->type->rule_query_func && (server->type->rule_query_func != send_rule_request_packet)) {
5549 		return (server->type->rule_query_func(server));
5550 	}
5551 
5552 	if (server->type->id == Q_SERVER) {
5553 		strcpy((char *)q_rule.data, server->next_rule);
5554 		len = Q_HEADER_LEN + strlen((char *)q_rule.data) + 1;
5555 		q_rule.length = htons((short)len);
5556 	} else {
5557 		len = server->type->rule_len;
5558 	}
5559 
5560 	rc = send(server->fd, (const char *)server->type->rule_packet, len, 0);
5561 	if (rc == SOCKET_ERROR) {
5562 		return (send_error(server, rc));
5563 	}
5564 
5565 setup_retry:
5566 	if (server->retry1 == n_retries) {
5567 		gettimeofday(&server->packet_time1, NULL);
5568 		server->n_requests++;
5569 	} else if (server->server_name == NULL) {
5570 		server->n_retries++;
5571 	}
5572 	server->retry1--;
5573 	if (server->server_name == NULL) {
5574 		server->n_packets++;
5575 	}
5576 
5577 	return (DONE_AUTO);
5578 }
5579 
5580 
5581 query_status_t
send_player_request_packet(struct qserver * server)5582 send_player_request_packet(struct qserver *server)
5583 {
5584 	int rc;
5585 
5586 	debug(3, "send_player_request_packet %p", server);
5587 
5588 	if (!server->type->player_packet) {
5589 		return (0);
5590 	}
5591 
5592 	/* Server created via broadcast, so bind it */
5593 	if (server->fd == -1) {
5594 		if (bind_qserver(server) < 0) {
5595 			goto setup_retry;
5596 		}
5597 	}
5598 
5599 	if (server->type->player_query_func && (server->type->player_query_func != send_player_request_packet)) {
5600 		return (server->type->player_query_func(server));
5601 	}
5602 
5603 	if (!server->type->player_packet) {
5604 		debug(0, "error: server %p has no player_packet", server);
5605 		return (0);
5606 	}
5607 
5608 	if (server->type->id == Q_SERVER) {
5609 		q_player.data[0] = server->next_player_info;
5610 	}
5611 	rc = send(server->fd, (const char *)server->type->player_packet, server->type->player_len, 0);
5612 	if (rc == SOCKET_ERROR) {
5613 		return (send_error(server, rc));
5614 	}
5615 
5616 setup_retry:
5617 	if (server->retry2 == n_retries) {
5618 		gettimeofday(&server->packet_time2, NULL);
5619 		server->n_requests++;
5620 	} else {
5621 		server->n_retries++;
5622 	}
5623 	server->retry2--;
5624 	server->n_packets++;
5625 
5626 	return (1);
5627 }
5628 
5629 
5630 void
qserver_disconnect(struct qserver * server)5631 qserver_disconnect(struct qserver *server)
5632 {
5633 #ifdef _WIN32
5634 		int i;
5635 #endif
5636 	if (server->fd != -1) {
5637 		close(server->fd);
5638 #ifndef _WIN32
5639 			connmap[server->fd] = NULL;
5640 #else
5641 			for (i = 0; i < max_connmap; i++) {
5642 				if (connmap[i] == server) {
5643 					connmap[i] = NULL;
5644 					break;
5645 				}
5646 			}
5647 #endif
5648 		server->fd = -1;
5649 		connected--;
5650 	}
5651 }
5652 
5653 
5654 /* Functions for figuring timeouts and when to give up
5655  * Returns 1 if the query is done (server may be freed) and 0 if not.
5656  */
5657 int
cleanup_qserver(struct qserver * server,int force)5658 cleanup_qserver(struct qserver *server, int force)
5659 {
5660 	int close_it = force;
5661 
5662 	debug(3, "cleanup_qserver %p, %d", server, force);
5663 	if (server->server_name == NULL) {
5664 		debug(3, "server has no name, forcing close");
5665 		close_it = 1;
5666 		if (server->type->id & MASTER_SERVER && (server->master_pkt != NULL)) {
5667 			server->server_name = MASTER;
5668 		} else {
5669 			server->server_name = TIMEOUT;
5670 			num_servers_timed_out++;
5671 		}
5672 	} else if (server->type->flags & TF_SINGLE_QUERY) {
5673 		debug(3, "TF_SINGLE_QUERY, forcing close");
5674 		close_it = 1;
5675 	} else if ((server->next_rule == NO_SERVER_RULES) && (server->next_player_info >= server->num_players)) {
5676 		debug(3, "no server rules and next_player_info >= num_players, forcing close");
5677 		close_it = 1;
5678 	}
5679 
5680 	debug(3, "close_it %d", close_it);
5681 	if (close_it) {
5682 		if (server->saved_data.data) {
5683 			SavedData *sdata = server->saved_data.next;
5684 			free(server->saved_data.data);
5685 			server->saved_data.data = NULL;
5686 			while (sdata != NULL) {
5687 				SavedData *next;
5688 				free(sdata->data);
5689 				next = sdata->next;
5690 				free(sdata);
5691 				sdata = next;
5692 			}
5693 			server->saved_data.next = NULL;
5694 		}
5695 
5696 		qserver_disconnect(server);
5697 
5698 		if (server->server_name != TIMEOUT) {
5699 			num_servers_returned++;
5700 			if (server->server_name != DOWN) {
5701 				num_players_total += server->num_players;
5702 				max_players_total += server->max_players;
5703 			}
5704 		}
5705 		if ((server->server_name == TIMEOUT) || (server->server_name == DOWN)) {
5706 			server->ping_total = 999999;
5707 		}
5708 		if (server->type->master) {
5709 			waiting_for_masters--;
5710 			if (waiting_for_masters == 0) {
5711 				add_servers_from_masters();
5712 			}
5713 		}
5714 		if (!server_sort) {
5715 			display_server(server);
5716 		}
5717 		return (1);
5718 	}
5719 	return (0);
5720 }
5721 
5722 
5723 /** must be called only on connected servers
5724  * @returns time in ms until server needs timeout handling. timeout handling is needed if <= zero
5725  */
5726 static int
qserver_get_timeout(struct qserver * server,struct timeval * now)5727 qserver_get_timeout(struct qserver *server, struct timeval *now)
5728 {
5729 	int diff, diff1, diff2, interval;
5730 
5731 	if (server->type->id & MASTER_SERVER) {
5732 		interval = master_retry_interval;
5733 	} else {
5734 		interval = retry_interval;
5735 	}
5736 
5737 	diff2 = 0xffff;
5738 
5739 	diff1 = interval * (n_retries - server->retry1 + 1) - time_delta(now, &server->packet_time1);
5740 
5741 	if (server->next_player_info < server->num_players) {
5742 		diff2 = interval * (n_retries - server->retry2 + 1) - time_delta(now, &server->packet_time2);
5743 	}
5744 
5745 	debug(2, "timeout for %p is diff1 %d diff2 %d", server, diff1, diff2);
5746 
5747 	diff = (diff1 < diff2) ? diff1 : diff2;
5748 
5749 	return (diff);
5750 }
5751 
5752 
5753 void
get_next_timeout(struct timeval * timeout)5754 get_next_timeout(struct timeval *timeout)
5755 {
5756 	struct qserver *server = servers;
5757 	struct timeval now;
5758 	int diff, smallest = retry_interval + master_retry_interval;
5759 	int bind_count = 0;
5760 
5761 	if (first_server_bind == NULL) {
5762 		first_server_bind = servers;
5763 	}
5764 
5765 	server = first_server_bind;
5766 
5767 	for ( ; server != NULL && server->fd == -1; server = server->next) {
5768 	}
5769 
5770 	/* if there are unconnected servers and slots left we retry in 10ms */
5771 	if ((server == NULL) || ((num_servers > connected) && (connected < max_simultaneous))) {
5772 		timeout->tv_sec = 0;
5773 		timeout->tv_usec = 10 * 1000;
5774 		return;
5775 	}
5776 
5777 	first_server_bind = server;
5778 
5779 	gettimeofday(&now, NULL);
5780 	for ( ; server != NULL && bind_count < connected; server = server->next) {
5781 		if (server->fd == -1) {
5782 			continue;
5783 		}
5784 
5785 		diff = qserver_get_timeout(server, &now);
5786 		if (diff < smallest) {
5787 			smallest = diff;
5788 		}
5789 		bind_count++;
5790 	}
5791 
5792 	if (smallest < 10) {
5793 		smallest = 10;
5794 	}
5795 
5796 	timeout->tv_sec = smallest / 1000;
5797 	timeout->tv_usec = (smallest % 1000) * 1000;
5798 }
5799 
5800 
5801 #ifdef USE_SELECT
5802 	static fd_set select_read_fds;
5803 	static int select_maxfd;
5804 	static int select_cursor;
5805 
5806 	int
set_fds(fd_set * fds)5807 	set_fds(fd_set *fds)
5808 	{
5809 		int maxfd = -1, i;
5810 
5811 		for (i = 0; i < max_connmap; i++) {
5812 			if (connmap[i] != NULL) {
5813 				FD_SET(connmap[i]->fd, fds);
5814 				if (connmap[i]->fd > maxfd) {
5815 					maxfd = connmap[i]->fd;
5816 				}
5817 			}
5818 		}
5819 
5820 		return (maxfd);
5821 	}
5822 
5823 
5824 	void
set_file_descriptors()5825 	set_file_descriptors()
5826 	{
5827 		FD_ZERO(&select_read_fds);
5828 		select_maxfd = set_fds(&select_read_fds);
5829 	}
5830 
5831 
5832 	int
wait_for_file_descriptors(struct timeval * timeout)5833 	wait_for_file_descriptors(struct timeval *timeout)
5834 	{
5835 		select_cursor = 0;
5836 		return (select(select_maxfd + 1, &select_read_fds, NULL, NULL, timeout));
5837 	}
5838 
5839 
5840 	struct qserver *
get_next_ready_server()5841 	get_next_ready_server()
5842 	{
5843 		while (select_cursor < max_connmap && (connmap[select_cursor] == NULL || !FD_ISSET(connmap[select_cursor]->fd, &select_read_fds))) {
5844 			select_cursor++;
5845 		}
5846 
5847 		if (select_cursor >= max_connmap) {
5848 			return (NULL);
5849 		}
5850 		return (connmap[select_cursor++]);
5851 	}
5852 
5853 
5854 	int
wait_for_timeout(unsigned int ms)5855 	wait_for_timeout(unsigned int ms)
5856 	{
5857 		struct timeval timeout;
5858 
5859 		timeout.tv_sec = ms / 1000;
5860 		timeout.tv_usec = (ms % 1000) * 1000;
5861 		return (select(0, 0, NULL, NULL, &timeout));
5862 	}
5863 
5864 
5865 #endif  /* USE_SELECT */
5866 
5867 #ifdef USE_POLL
5868 	static struct pollfd *pollfds;
5869 	static int n_pollfds;
5870 	static int max_pollfds = 0;
5871 	static int poll_cursor;
5872 
5873 	void
set_file_descriptors()5874 	set_file_descriptors()
5875 	{
5876 		struct pollfd *p;
5877 		int i;
5878 
5879 		if (max_connmap > max_pollfds) {
5880 			max_pollfds = max_connmap;
5881 			pollfds = (struct pollfd *)realloc(pollfds, max_pollfds * sizeof(struct pollfd));
5882 		}
5883 
5884 		p = pollfds;
5885 		for (i = 0; i < max_connmap; i++) {
5886 			if (connmap[i] != NULL) {
5887 				p->fd = connmap[i]->fd;
5888 				p->events = POLLIN;
5889 				p->revents = 0;
5890 				p++;
5891 			}
5892 		}
5893 		n_pollfds = p - pollfds;
5894 	}
5895 
5896 
5897 	int
wait_for_file_descriptors(struct timeval * timeout)5898 	wait_for_file_descriptors(struct timeval *timeout)
5899 	{
5900 		poll_cursor = 0;
5901 		return (poll(pollfds, n_pollfds, timeout->tv_sec * 1000 + timeout->tv_usec / 1000));
5902 	}
5903 
5904 
5905 	struct qserver *
get_next_ready_server()5906 	get_next_ready_server()
5907 	{
5908 		for ( ; poll_cursor < n_pollfds; poll_cursor++) {
5909 			if (pollfds[poll_cursor].revents) {
5910 				break;
5911 			}
5912 		}
5913 
5914 		if (poll_cursor >= n_pollfds) {
5915 			return (NULL);
5916 		}
5917 		return (connmap[pollfds[poll_cursor++].fd]);
5918 	}
5919 
5920 
5921 	int
wait_for_timeout(unsigned int ms)5922 	wait_for_timeout(unsigned int ms)
5923 	{
5924 		return (poll(0, 0, ms));
5925 	}
5926 
5927 
5928 #endif  /* USE_POLL */
5929 
5930 void
free_server(struct qserver * server)5931 free_server(struct qserver *server)
5932 {
5933 	struct player *player, *next_player;
5934 	struct rule *rule, *next_rule;
5935 
5936 	/* remove from servers list */
5937 	if (server == servers) {
5938 		servers = server->next;
5939 		if (servers) {
5940 			servers->prev = NULL;
5941 		}
5942 	}
5943 
5944 	if ((void *)&server->next == (void *)last_server) {
5945 		if (server->prev) {
5946 			last_server = &server->prev->next;
5947 		} else {
5948 			last_server = &servers;
5949 		}
5950 	}
5951 	if (server == first_server_bind) {
5952 		first_server_bind = server->next;
5953 	}
5954 	if (server == last_server_bind) {
5955 		last_server_bind = server->next;
5956 	}
5957 
5958 	if (server->prev) {
5959 		server->prev->next = server->next;
5960 	}
5961 	if (server->next) {
5962 		server->next->prev = server->prev;
5963 	}
5964 
5965 	/* remove from server hash table */
5966 	remove_server_from_hash(server);
5967 
5968 	/* free all the data */
5969 	for (player = server->players; player; player = next_player) {
5970 		next_player = player->next;
5971 		free_player(player);
5972 	}
5973 
5974 	for (rule = server->rules; rule; rule = next_rule) {
5975 		next_rule = rule->next;
5976 		free_rule(rule);
5977 	}
5978 
5979 	if (server->arg) {
5980 		free(server->arg);
5981 	}
5982 	if (server->host_name) {
5983 		free(server->host_name);
5984 	}
5985 	if (server->error) {
5986 		free(server->error);
5987 	}
5988 	if (server->address) {
5989 		free(server->address);
5990 	}
5991 	if (server->map_name) {
5992 		free(server->map_name);
5993 	}
5994 	if (!(server->flags & FLAG_DO_NOT_FREE_GAME) && server->game) {
5995 		free(server->game);
5996 	}
5997 	if (server->master_pkt) {
5998 		free(server->master_pkt);
5999 	}
6000 	if (server->query_arg) {
6001 		free(server->query_arg);
6002 	}
6003 	if (server->challenge_string) {
6004 		free(server->challenge_string);
6005 	}
6006 
6007 	/* These fields are never malloc'd: outfilename
6008 	 */
6009 
6010 	if (
6011 		(server->server_name != NULL) &&
6012 		(server->server_name != DOWN) &&
6013 		(server->server_name != HOSTNOTFOUND) &&
6014 		(server->server_name != SYSERROR) &&
6015 		(server->server_name != MASTER) &&
6016 		(server->server_name != SERVERERROR) &&
6017 		(server->server_name != TIMEOUT) &&
6018 		(server->server_name != GAMESPY_MASTER_NAME) &&
6019 		(server->server_name != BFRIS_SERVER_NAME)
6020 		) {
6021 		free(server->server_name);
6022 	}
6023 
6024 	/*
6025 	 * params ...
6026 	 * saved_data ...
6027 	 */
6028 
6029 	free(server);
6030 	--num_servers;
6031 }
6032 
6033 
6034 void
free_player(struct player * player)6035 free_player(struct player *player)
6036 {
6037 	if (player->name) {
6038 		free(player->name);
6039 	}
6040 	if (!(player->flags & PLAYER_FLAG_DO_NOT_FREE_TEAM) && player->team_name) {
6041 		free(player->team_name);
6042 	}
6043 	if (player->address) {
6044 		free(player->address);
6045 	}
6046 	if (player->tribe_tag) {
6047 		free(player->tribe_tag);
6048 	}
6049 	if (player->skin) {
6050 		free(player->skin);
6051 	}
6052 	if (player->mesh) {
6053 		free(player->mesh);
6054 	}
6055 	if (player->face) {
6056 		free(player->face);
6057 	}
6058 	free(player);
6059 }
6060 
6061 
6062 void
free_rule(struct rule * rule)6063 free_rule(struct rule *rule)
6064 {
6065 	if (rule->name) {
6066 		free(rule->name);
6067 	}
6068 
6069 	if (rule->value) {
6070 		free(rule->value);
6071 	}
6072 	free(rule);
6073 }
6074 
6075 
6076 /* Functions for handling response packets
6077  */
6078 
6079 /* Packet from normal Quake server
6080  */
6081 query_status_t
deal_with_q_packet(struct qserver * server,char * rawpkt,int pktlen)6082 deal_with_q_packet(struct qserver *server, char *rawpkt, int pktlen)
6083 {
6084 	struct q_packet *pkt = (struct q_packet *)rawpkt;
6085 	int rc;
6086 
6087 	debug(2, "deal_with_q_packet %p, %d", server, pktlen);
6088 
6089 	if (ntohs(pkt->length) != pktlen) {
6090 		fprintf(stderr, "%s Ignoring bogus packet; length %d != %d\n", server->arg, ntohs(pkt->length), pktlen);
6091 		return (PKT_ERROR);
6092 	}
6093 
6094 	rawpkt[pktlen] = '\0';
6095 
6096 	switch (pkt->op_code) {
6097 	case Q_CCREP_ACCEPT:
6098 	case Q_CCREP_REJECT:
6099 		return (0);
6100 
6101 	case Q_CCREP_SERVER_INFO:
6102 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
6103 		rc = server_info_packet(server, pkt, pktlen - Q_HEADER_LEN);
6104 		break;
6105 
6106 	case Q_CCREP_PLAYER_INFO:
6107 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time2);
6108 		rc = player_info_packet(server, pkt, pktlen - Q_HEADER_LEN);
6109 		break;
6110 
6111 	case Q_CCREP_RULE_INFO:
6112 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
6113 		rc = rule_info_packet(server, pkt, pktlen - Q_HEADER_LEN);
6114 		break;
6115 
6116 	case Q_CCREQ_CONNECT:
6117 	case Q_CCREQ_SERVER_INFO:
6118 	case Q_CCREQ_PLAYER_INFO:
6119 	case Q_CCREQ_RULE_INFO:
6120 	default:
6121 		return (0);
6122 	}
6123 
6124 	if (SOCKET_ERROR == rc) {
6125 		fprintf(stderr, "%s error on packet opcode %x\n", server->arg, (int)pkt->op_code);
6126 	}
6127 
6128 	return (rc);
6129 }
6130 
6131 
6132 /* Packet from QuakeWorld server
6133  */
6134 query_status_t
deal_with_qw_packet(struct qserver * server,char * rawpkt,int pktlen)6135 deal_with_qw_packet(struct qserver *server, char *rawpkt, int pktlen)
6136 {
6137 	debug(2, "deal_with_qw_packet %p, %d", server, pktlen);
6138 	if (server->server_name == NULL) {
6139 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
6140 	}
6141 
6142 	if ((((rawpkt[0] != '\377') && (rawpkt[0] != '\376')) || (rawpkt[1] != '\377') || (rawpkt[2] != '\377') || (rawpkt[3] != '\377')) && show_errors) {
6143 		unsigned int ipaddr = ntohl(server->ipaddr);
6144 		fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
6145 		    (ipaddr >> 24) & 0xff,
6146 		    (ipaddr >> 16) & 0xff,
6147 		    (ipaddr >> 8) & 0xff,
6148 		    ipaddr & 0xff,
6149 		    ntohs(server->port)
6150 		    );
6151 		print_packet(server, rawpkt, pktlen);
6152 	}
6153 
6154 	rawpkt[pktlen] = '\0';
6155 
6156 	if (rawpkt[4] == 'n') {
6157 		if (server->type->id != QW_SERVER) {
6158 			server->type = find_server_type_id(QW_SERVER);
6159 		}
6160 		return (deal_with_q1qw_packet(server, rawpkt, pktlen));
6161 	} else if ((rawpkt[4] == '\377') && (rawpkt[5] == 'n')) {
6162 		if (server->type->id != HW_SERVER) {
6163 			server->type = find_server_type_id(HW_SERVER);
6164 		}
6165 		return (deal_with_q1qw_packet(server, rawpkt, pktlen));
6166 	} else if (strncmp(&rawpkt[4], "print\n\\", 7) == 0) {
6167 		return (deal_with_q2_packet(server, rawpkt + 10, pktlen - 10));
6168 	} else if (strncmp(&rawpkt[4], "print\n", 6) == 0) {
6169 		/* work-around for occasional bug in Quake II status packets
6170 		 */
6171 		char *c, *p;
6172 		p = c = &rawpkt[10];
6173 		while (*p != '\\' && (c = strchr(p, '\n'))) {
6174 			p = c + 1;
6175 		}
6176 		if ((*p == '\\') && (c != NULL)) {
6177 			return (deal_with_q2_packet(server, p, pktlen - (p - rawpkt)));
6178 		}
6179 	} else if ((strncmp(&rawpkt[4], "infoResponse", 12) == 0) || ((rawpkt[4] == '\001') && (strncmp(&rawpkt[5], "infoResponse", 12) == 0))) {
6180 		/* quake3 info response */
6181 		int ret;
6182 		if (rawpkt[4] == '\001') {
6183 			rawpkt++;
6184 			pktlen--;
6185 		}
6186 		rawpkt += 12;
6187 		pktlen -= 12;
6188 		for ( ; pktlen && *rawpkt != '\\'; pktlen--, rawpkt++) {
6189 		}
6190 		if (!pktlen) {
6191 			return (INPROGRESS);
6192 		}
6193 		if (rawpkt[pktlen - 1] == '"') {
6194 			rawpkt[pktlen - 1] = '\0';
6195 			pktlen--;
6196 		}
6197 		if (get_player_info || get_server_rules) {
6198 			server->next_rule = "";
6199 		}
6200 
6201 		ret = deal_with_q2_packet(server, rawpkt, pktlen);
6202 		if ((DONE_AUTO == ret) && (get_player_info || get_server_rules)) {
6203 			debug(3, "send_rule_request_packet2");
6204 			send_rule_request_packet(server);
6205 			server->retry1 = n_retries - 1;
6206 			return (INPROGRESS);
6207 		}
6208 
6209 		return (ret);
6210 	} else if ((strncmp(&rawpkt[4], "statusResponse\n", 15) == 0) || ((rawpkt[4] == '\001') && (strncmp(&rawpkt[5], "statusResponse\n", 15) == 0))) {
6211 		/* quake3 status response */
6212 		server->next_rule = NO_SERVER_RULES;
6213 		server->retry1 = 0;
6214 		if (rawpkt[4] == '\001') {
6215 			rawpkt++;
6216 			pktlen--;
6217 		}
6218 		server->flags |= CHECK_DUPLICATE_RULES;
6219 		return (deal_with_q2_packet(server, rawpkt + 19, pktlen - 19));
6220 	} else if (strncmp(&rawpkt[4], "infostringresponse", 19) == 0) {
6221 		return (deal_with_q2_packet(server, rawpkt + 23, pktlen - 23));
6222 	}
6223 
6224 	if (show_errors) {
6225 		unsigned int ipaddr = ntohl(server->ipaddr);
6226 		fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, ignoring ...\n",
6227 		    (ipaddr >> 24) & 0xff,
6228 		    (ipaddr >> 16) & 0xff,
6229 		    (ipaddr >>  8) & 0xff,
6230 		    ipaddr & 0xff,
6231 		    ntohs(server->port)
6232 		    );
6233 		print_packet(server, rawpkt, pktlen);
6234 		return (PKT_ERROR);
6235 	}
6236 
6237 	return (DONE_AUTO);
6238 }
6239 
6240 
6241 query_status_t
deal_with_q1qw_packet(struct qserver * server,char * rawpkt,int pktlen)6242 deal_with_q1qw_packet(struct qserver *server, char *rawpkt, int pktlen)
6243 {
6244 	char *key, *value, *end, *users;
6245 	struct player *player = NULL, **last_player = &server->players;
6246 	int len, rc, complete = 0;
6247 	int number, frags, connect_time, ping;
6248 	char *pkt = &rawpkt[5];
6249 
6250 	debug(2, "deal_with_q1qw_packet %p, %d", server, pktlen);
6251 
6252 	if (server->type->id == HW_SERVER) {
6253 		pkt = &rawpkt[6];
6254 	}
6255 
6256 	*(users = strchr(pkt, '\n')) = '\0';
6257 	while (*pkt && pkt - rawpkt < pktlen) {
6258 		if (*pkt == '\\') {
6259 			pkt++;
6260 			end = strchr(pkt, '\\');
6261 			if (end == NULL) {
6262 				break;
6263 			}
6264 			*end = '\0';
6265 			key = pkt;
6266 			pkt += strlen(pkt) + 1;
6267 			end = strchr(pkt, '\\');
6268 			if (end == NULL) {
6269 				end = users;
6270 			}
6271 			value = (char *)malloc(end - pkt + 1);
6272 			memcpy(value, pkt, end - pkt);
6273 			value[end - pkt] = '\0';
6274 			pkt = end;
6275 			if (strcmp(key, "hostname") == 0) {
6276 				server->server_name = value;
6277 			} else if (strcmp(key, "map") == 0) {
6278 				server->map_name = value;
6279 			} else if (strcmp(key, "maxclients") == 0) {
6280 				server->max_players = atoi(value);
6281 				free(value);
6282 			} else if (strcmp(key, "maxspectators") == 0) {
6283 				server->max_spectators = atoi(value);
6284 				free(value);
6285 			} else if (get_server_rules || (strncmp(key, "*game", 5) == 0)) {
6286 				add_rule(server, key, value, NO_VALUE_COPY);
6287 				if (strcmp(key, "*gamedir") == 0) {
6288 					server->game = value;
6289 					server->flags |= FLAG_DO_NOT_FREE_GAME;
6290 				}
6291 			}
6292 		} else {
6293 			pkt++;
6294 		}
6295 		complete = 1;
6296 	}
6297 	*pkt = '\n';
6298 	while (*pkt && pkt - rawpkt < pktlen) {
6299 		if (*pkt == '\n') {
6300 			pkt++;
6301 			if ((pkt - rawpkt >= pktlen) || (*pkt == '\0')) {
6302 				break;
6303 			}
6304 			rc = sscanf(pkt, "%d %d %d %d %n", &number, &frags, &connect_time, &ping, &len);
6305 			if (rc != 4) {
6306 				char *nl;       /* assume it's an error packet */
6307 				server->error = (char *)malloc(pktlen + 1);
6308 				nl = strchr(pkt, '\n');
6309 				if (nl != NULL) {
6310 					strncpy(server->error, pkt, nl - pkt);
6311 					server->error[nl - pkt] = '\0';
6312 				} else {
6313 					strcpy(server->error, pkt);
6314 				}
6315 				server->server_name = SERVERERROR;
6316 				complete = 1;
6317 				break;
6318 			}
6319 			if (get_player_info) {
6320 				player = (struct player *)calloc(1, sizeof(struct player));
6321 				player->number = number;
6322 				player->frags = frags;
6323 				player->connect_time = connect_time * 60;
6324 				player->ping = ping > 0 ? ping : -ping;
6325 			} else {
6326 				player = NULL;
6327 			}
6328 
6329 			pkt += len;
6330 
6331 			if (*pkt != '"') {
6332 				break;
6333 			}
6334 			pkt += ping > 0 ? 1 : 4;// if 4 then no "\s\" in spectators name
6335 			// protocol "under construction"
6336 			end = strchr(pkt, '"');
6337 			if (end == NULL) {
6338 				break;
6339 			}
6340 			if (player != NULL) {
6341 				player->name = (char *)malloc(end - pkt + 1);
6342 				memcpy(player->name, pkt, end - pkt);
6343 				player->name[end - pkt] = '\0';
6344 			}
6345 
6346 			pkt = end + 2;
6347 
6348 			if (*pkt != '"') {
6349 				break;
6350 			}
6351 			pkt++;
6352 			end = strchr(pkt, '"');
6353 			if (end == NULL) {
6354 				break;
6355 			}
6356 			if (player != NULL) {
6357 				player->skin = (char *)malloc(end - pkt + 1);
6358 				memcpy(player->skin, pkt, end - pkt);
6359 				player->skin[end - pkt] = '\0';
6360 			}
6361 			pkt = end + 2;
6362 
6363 			if (player != NULL) {
6364 				sscanf(pkt, "%d %d%n", &player->shirt_color, &player->pants_color, &len);
6365 				*last_player = player;
6366 				last_player = &player->next;
6367 			} else {
6368 				sscanf(pkt, "%*d %*d%n", &len);
6369 			}
6370 			pkt += len;
6371 
6372 			if ((pkt + 3 < rawpkt + pktlen) && (*pkt == ' ')) {
6373 				// mvdsv is at last rev 377, 23.06.2006
6374 				pkt++;
6375 
6376 				if (*pkt != '"') {
6377 					break;
6378 				}
6379 				pkt++;
6380 				end = strchr(pkt, '"');
6381 				if (end == NULL) {
6382 					break;
6383 				}
6384 
6385 				if (player != NULL) {
6386 					player->team_name = (char *)malloc(end - pkt + 1);
6387 					memcpy(player->team_name, pkt, end - pkt);
6388 					player->team_name[end - pkt] = '\0';
6389 				}
6390 				pkt = end + 1;
6391 			}
6392 
6393 			if (ping > 0) {
6394 				server->num_players++;
6395 			} else {
6396 				server->num_spectators++;
6397 			}
6398 		} else {
6399 			pkt++;
6400 		}
6401 		complete = 1;
6402 	}
6403 
6404 	if (!complete) {
6405 		if ((rawpkt[4] != 'n') || (rawpkt[5] != '\0')) {
6406 			fprintf(stderr, "Odd packet from QW server %d.%d.%d.%d:%hu ...\n",
6407 			    (server->ipaddr >> 24) & 0xff,
6408 			    (server->ipaddr >> 16) & 0xff,
6409 			    (server->ipaddr >> 8) & 0xff,
6410 			    server->ipaddr & 0xff,
6411 			    ntohs(server->port)
6412 			    );
6413 			print_packet(server, rawpkt, pktlen);
6414 		}
6415 	} else if (server->server_name == NULL) {
6416 		server->server_name = strdup("");
6417 	}
6418 
6419 	return (DONE_AUTO);
6420 }
6421 
6422 
6423 query_status_t
deal_with_q2_packet(struct qserver * server,char * rawpkt,int pktlen)6424 deal_with_q2_packet(struct qserver *server, char *rawpkt, int pktlen)
6425 {
6426 	char *key, *value, *end;
6427 	struct player *player = NULL;
6428 	struct player **last_player = &server->players;
6429 	int len, rc, complete = 0;
6430 	int frags = 0, ping = 0, num_players = 0;
6431 	char *pkt = rawpkt;
6432 
6433 	debug(2, "deal_with_q2_packet %p, %d", server, pktlen);
6434 
6435 	while (*pkt && pkt - rawpkt < pktlen) {
6436 		// we have variable, value pairs separated by slash
6437 		if (*pkt == '\\') {
6438 			pkt++;
6439 			if ((*pkt == '\n') && (server->type->id == SOF_SERVER)) {
6440 				goto player_info;
6441 			}
6442 
6443 			// Find the key
6444 			end = strchr(pkt, '\\');
6445 			if (NULL == end) {
6446 				break;
6447 			}
6448 			*end = '\0';
6449 			key = pkt;
6450 			pkt += strlen(key) + 1;
6451 
6452 			// Find the value
6453 			end = strpbrk(pkt, "\\\n");
6454 			if (NULL == end) {
6455 				// Last value
6456 				end = rawpkt + pktlen;
6457 			}
6458 
6459 			// Make a copy of the value
6460 			value = (char *)malloc(end - pkt + 1);
6461 			memcpy(value, pkt, end - pkt);
6462 			value[end - pkt] = '\0';
6463 			pkt = end;
6464 			debug(3, "%s = %s", key, value);
6465 			if ((server->server_name == NULL) && ((strcmp(key, "hostname") == 0) || (strcmp(key, "sv_hostname") == 0))) {
6466 				// Server name
6467 				server->server_name = value;
6468 			} else if ((strcmp(key, "mapname") == 0) || (strcmp(key, "map_name") == 0) || ((strcmp(key, "map") == 0) && (server->map_name == NULL))) {
6469 				// Map name
6470 				if (NULL != server->map_name) {
6471 					free(server->map_name);
6472 				}
6473 				server->map_name = value;
6474 			} else if ((strcmp(key, "maxclients") == 0) || (strcmp(key, "sv_maxclients") == 0) || (strcmp(key, "sv_max_clients") == 0) || (strcmp(key, "max") == 0)) {
6475 				// Max Players
6476 				server->max_players = atoi(value);
6477 				// Note: COD 4 infoResponse returns max as sv_maxclients - sv_privateClients where as statusResponse returns the true max
6478 				// MOHAA Q3 protocol max players is always 0
6479 				if (0 == server->max_players) {
6480 					server->max_players = -1;
6481 				}
6482 				free(value);
6483 			} else if ((strcmp(key, "clients") == 0) || (strcmp(key, "players") == 0)) {
6484 				// Num Players
6485 				server->num_players = atoi(value);
6486 				free(value);
6487 			} else if ((server->server_name == NULL) && (strcmp(key, "pure") == 0)) {
6488 				add_rule(server, key, value, NO_VALUE_COPY);
6489 			} else if (get_server_rules || (strncmp(key, "game", 4) == 0)) {
6490 				int dofree = 0;
6491 				int flags = (server->flags & CHECK_DUPLICATE_RULES) ? CHECK_DUPLICATE_RULES | NO_VALUE_COPY : NO_VALUE_COPY;
6492 				if (add_rule(server, key, value, flags) == NULL) {
6493 					// duplicate, so free value
6494 					dofree = 1;
6495 				}
6496 
6497 				if ((server->game == NULL) && (strcmp(key, server->type->game_rule) == 0)) {
6498 					server->game = value;
6499 					if (0 == dofree) {
6500 						server->flags |= FLAG_DO_NOT_FREE_GAME;
6501 					}
6502 				} else if (1 == dofree) {
6503 					free(value);
6504 				}
6505 			} else {
6506 				free(value);
6507 			}
6508 		} else if (*pkt == '\n') {
6509 player_info:            debug(3, "player info");
6510 			pkt++;
6511 			if (*pkt == '\0') {
6512 				break;
6513 			}
6514 
6515 			if (0 == strncmp(pkt, "\\challenge\\", 11)) {
6516 				// qfusion
6517 				// This doesnt support getstatus looking at warsow source:
6518 				// server/sv_main.c: SV_ConnectionlessPacket
6519 				server->next_rule = NO_SERVER_RULES;
6520 				debug(3, "no more server rules");
6521 				break;
6522 			}
6523 
6524 			// Detect if we have a leading float or int?
6525 			rc = sscanf(pkt, "%d.%d %n", &frags, &ping, &len);
6526 			ping = 0; // Just a temp variable so reset.
6527 			if (rc == 2) {
6528 				// Xonotic in CA mode shows damage (float) instead of frags (int)
6529 				// 1.0 == 100 dmg.
6530 				float frags_f;
6531 
6532 				if ((rc = sscanf(pkt, "%f %n", &frags_f, &len)) == 1) {
6533 					frags = (int)(frags_f*100);
6534 				}
6535 			} else {
6536 				// Just an int.
6537 				rc = sscanf(pkt, "%d %n", &frags, &len);
6538 			}
6539 
6540 			if ((rc == 1) && (pkt[len] != '"')) {
6541 				pkt += len;
6542 				rc = sscanf(pkt, "%d %n", &ping, &len);
6543 			} else if (rc == 1) {
6544 				/* MOHAA Q3 protocol only provides player ping */
6545 				ping = frags;
6546 				frags = 0;
6547 			}
6548 
6549 			if (rc != 1) {
6550 				char *nl;       /* assume it's an error packet */
6551 				server->error = (char *)malloc(pktlen + 1);
6552 				nl = strchr(pkt, '\n');
6553 				if (nl != NULL) {
6554 					strncpy(server->error, pkt, nl - pkt);
6555 				} else {
6556 					strcpy(server->error, pkt);
6557 				}
6558 				server->server_name = SERVERERROR;
6559 				complete = 1;
6560 				break;
6561 			}
6562 
6563 			if (get_player_info) {
6564 				player = (struct player *)calloc(1, sizeof(struct player));
6565 				player->number = 0;
6566 				player->connect_time = -1;
6567 				player->frags = frags;
6568 				player->ping = ping;
6569 			} else {
6570 				player = NULL;
6571 			}
6572 
6573 			pkt += len;
6574 
6575 			if (isdigit((unsigned char)*pkt)) {
6576 				/* probably an SOF2 1.01 server, includes team # */
6577 				int team;
6578 				rc = sscanf(pkt, "%d %n", &team, &len);
6579 				if (rc == 1) {
6580 					pkt += len;
6581 					if (player) {
6582 						player->team = team;
6583 						server->flags |= FLAG_PLAYER_TEAMS;
6584 					}
6585 				}
6586 			}
6587 
6588 			if (*pkt != '"') {
6589 				break;
6590 			}
6591 
6592 			pkt++;
6593 			end = strchr(pkt, '"');
6594 			if (end == NULL) {
6595 				break;
6596 			}
6597 			if (player != NULL) {
6598 				player->name = (char *)malloc(end - pkt + 1);
6599 				memcpy(player->name, pkt, end - pkt);
6600 				player->name[end - pkt] = '\0';
6601 			}
6602 			pkt = end + 1;
6603 
6604 			//WarSoW team number
6605 			if (*pkt != '\n') {
6606 				int team;
6607 				rc = sscanf(pkt, "%d%n", &team, &len);
6608 				if (rc == 1) {
6609 					pkt += len;
6610 					if (player) {
6611 						player->team = team;
6612 						server->flags |= FLAG_PLAYER_TEAMS;
6613 					}
6614 				}
6615 			}
6616 
6617 			if (player != NULL) {
6618 				player->skin = NULL;
6619 				player->shirt_color = -1;
6620 				player->pants_color = -1;
6621 				*last_player = player;
6622 				last_player = &player->next;
6623 			}
6624 			num_players++;
6625 		} else {
6626 			pkt++;
6627 		}
6628 		complete = 1;
6629 	}
6630 
6631 	if ((server->num_players == 0) || (num_players > server->num_players)) {
6632 		server->num_players = num_players;
6633 	}
6634 
6635 	if (!complete) {
6636 		return (PKT_ERROR);
6637 	} else if (server->server_name == NULL) {
6638 		server->server_name = strdup("");
6639 	}
6640 
6641 	return (DONE_AUTO);
6642 }
6643 
6644 
6645 int
ack_descent3master_packet(struct qserver * server,char * curtok)6646 ack_descent3master_packet(struct qserver *server, char *curtok)
6647 {
6648 	int rc;
6649 	char packet[0x1e];
6650 
6651 	memcpy(packet, descent3_masterquery, 0x1a);
6652 	packet[1] = 0x1d;
6653 	packet[0x16] = 1;
6654 	memcpy(packet + 0x1a, curtok, 4);
6655 	rc = send(server->fd, packet, sizeof(packet), 0);
6656 	if (rc == SOCKET_ERROR) {
6657 		return (send_error(server, rc));
6658 	}
6659 
6660 	return (rc);
6661 }
6662 
6663 
6664 /* Packet from Descent3 master server (PXO)
6665  */
6666 query_status_t
deal_with_descent3master_packet(struct qserver * server,char * rawpkt,int pktlen)6667 deal_with_descent3master_packet(struct qserver *server, char *rawpkt, int pktlen)
6668 {
6669 	int i = 0, lastpacket = 0;
6670 	char *names = rawpkt + 0x1f;
6671 	char *ips = rawpkt + 0x29f;
6672 	char *ports = rawpkt + 0x2ef;
6673 
6674 	debug(2, "deal_with_descent3master_packet %p, %d", server, pktlen);
6675 
6676 	while (i < 20) {
6677 		if (*names) {
6678 			char *c;
6679 			server->master_pkt_len += 6;
6680 			server->master_pkt = (char *)realloc(server->master_pkt, server->master_pkt_len);
6681 			c = server->master_pkt + server->master_pkt_len - 6;
6682 			memcpy(c, ips, 4);
6683 			memcpy(c + 4, ports, 2);
6684 		} else if (i > 0) {
6685 			lastpacket = 1;
6686 		}
6687 		names += 0x20;
6688 		ips += 4;
6689 		ports += 2;
6690 		i++;
6691 	}
6692 
6693 	ack_descent3master_packet(server, rawpkt + 0x1a);
6694 
6695 	server->n_servers = server->master_pkt_len / 6;
6696 
6697 	server->next_player_info = -1;
6698 	server->retry1 = 0;
6699 
6700 	if (lastpacket) {
6701 		return (DONE_AUTO);
6702 	}
6703 
6704 	return (INPROGRESS);
6705 }
6706 
6707 
6708 /* Packet from QuakeWorld master server
6709  */
6710 query_status_t
deal_with_qwmaster_packet(struct qserver * server,char * rawpkt,int pktlen)6711 deal_with_qwmaster_packet(struct qserver *server, char *rawpkt, int pktlen)
6712 {
6713 	int ret = 0;
6714 
6715 	debug(2, "deal_with_qwmaster_packet %p, %d", server, pktlen);
6716 
6717 	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
6718 
6719 	if (rawpkt[0] == QW_NACK) {
6720 		server->error = strdup(&rawpkt[2]);
6721 		server->server_name = SERVERERROR;
6722 		return (PKT_ERROR);
6723 	}
6724 
6725 	if (*((unsigned int *)rawpkt) == 0xffffffff) {
6726 		rawpkt += 4;/* QW 1.5 */
6727 		pktlen -= 4;
6728 		if ((rawpkt[0] == '\377') && (rawpkt[1] == QW_SERVERS)) {
6729 			rawpkt++;       /* hwmaster */
6730 			pktlen--;
6731 		}
6732 	}
6733 
6734 	if ((rawpkt[0] == QW_SERVERS) && (rawpkt[1] == QW_NEWLINE)) {
6735 		rawpkt += 2;
6736 		pktlen -= 2;
6737 	} else if ((rawpkt[0] == HL_SERVERS) && (rawpkt[1] == 0x0d)) {
6738 		// 2 byte id + 4 byte sequence
6739 		memcpy(server->master_query_tag, rawpkt + 2, 3);
6740 		rawpkt += 6;
6741 		pktlen -= 6;
6742 	} else if ((rawpkt[0] == HL_SERVERS) && (rawpkt[1] == 0x0a)) {
6743 		// no sequence id for steam
6744 		// instead we use the ip:port of the last recieved server
6745 		struct in_addr *sin_addr = (struct in_addr *)(rawpkt + pktlen - 6);
6746 		char *ip = inet_ntoa(*sin_addr);
6747 		unsigned short port = htons(*((unsigned short *)(rawpkt + pktlen - 2)));
6748 
6749 		//fprintf( stderr, "NEXT IP=%s:%u\n", ip, port );
6750 		sprintf(server->master_query_tag, "%s:%u", ip, port);
6751 
6752 		// skip over the 2 byte id
6753 		rawpkt += 2;
6754 		pktlen -= 2;
6755 	} else if (strncmp(rawpkt, "servers", 7) == 0) {
6756 		rawpkt += 8;
6757 		pktlen -= 8;
6758 	} else if (strncmp(rawpkt, "getserversResponse", 18) == 0) {
6759 		rawpkt += 18;
6760 		pktlen -= 18;
6761 
6762 		for ( ; *rawpkt != '\\' && pktlen; pktlen--, rawpkt++) {
6763 		}
6764 
6765 		if (!pktlen) {
6766 			return (1);
6767 		}
6768 		rawpkt++;
6769 		pktlen--;
6770 
6771 		debug(2, "q3m pktlen %d lastchar %x\n", pktlen, (unsigned int)rawpkt[pktlen - 1]);
6772 
6773 		server->master_pkt = (char *)realloc(server->master_pkt, server->master_pkt_len + pktlen + 1);
6774 
6775 		if (server->type->id == STEF_MASTER) {
6776 			ret = decode_stefmaster_packet(server, rawpkt, pktlen);
6777 		} else {
6778 			ret = decode_q3master_packet(server, rawpkt, pktlen);
6779 		}
6780 		debug(2, "q3m %d servers\n", server->n_servers);
6781 
6782 		return (ret);
6783 	} else if (show_errors) {
6784 		unsigned int ipaddr = ntohl(server->ipaddr);
6785 		fprintf(stderr, "Odd packet from QW master %d.%d.%d.%d, processing ...\n",
6786 		    (ipaddr >> 24) & 0xff,
6787 		    (ipaddr >> 16) & 0xff,
6788 		    (ipaddr >>  8) & 0xff,
6789 		    ipaddr & 0xff
6790 		    );
6791 		print_packet(server, rawpkt, pktlen);
6792 	}
6793 
6794 	server->master_pkt = (char *)realloc(server->master_pkt, server->master_pkt_len + pktlen + 1);
6795 	rawpkt[pktlen] = '\0';
6796 	memcpy(server->master_pkt + server->master_pkt_len, rawpkt, pktlen + 1);
6797 	server->master_pkt_len += pktlen;
6798 
6799 	server->n_servers = server->master_pkt_len / 6;
6800 
6801 	if (server->type->flags & TF_MASTER_MULTI_RESPONSE) {
6802 		server->next_player_info = -1;
6803 		server->retry1 = 0;
6804 	} else if (server->type->id == HL_MASTER) {
6805 		if ((server->master_query_tag[0] == 0) && (server->master_query_tag[1] == 0) && (server->master_query_tag[2] == 0)) {
6806 			// all done
6807 			server->server_name = MASTER;
6808 			bind_sockets();
6809 			ret = DONE_FORCE;
6810 		} else {
6811 			// more to come
6812 			server->retry1++;
6813 			send_qwmaster_request_packet(server);
6814 		}
6815 	} else if (server->type->flags & TF_MASTER_STEAM) {
6816 		// should the HL_MASTER be the same as this?
6817 		int i;
6818 		for (i = pktlen - 6; i < pktlen && 0x00 == rawpkt[i]; i++) {
6819 		}
6820 
6821 		if (i == pktlen) {
6822 			// last 6 bytes where 0x00 so we have reached the last packet
6823 			server->n_servers--;
6824 			server->master_pkt_len -= 6;
6825 			server->server_name = MASTER;
6826 			bind_sockets();
6827 			ret = DONE_FORCE;
6828 		} else {
6829 			// more to come
6830 			server->retry1++;
6831 			send_qwmaster_request_packet(server);
6832 		}
6833 	} else {
6834 		server->server_name = MASTER;
6835 		ret = DONE_AUTO;
6836 		bind_sockets();
6837 	}
6838 
6839 	return (ret);
6840 }
6841 
6842 
6843 int
decode_q3master_packet(struct qserver * server,char * pkt,int pktlen)6844 decode_q3master_packet(struct qserver *server, char *pkt, int pktlen)
6845 {
6846 	char *p;
6847 	char *end = pkt + pktlen;
6848 	char *last = end - 6;
6849 
6850 	pkt[pktlen] = 0;
6851 	p = pkt;
6852 
6853 	while (p < last) {
6854 		// IP & Port
6855 		memcpy(server->master_pkt + server->master_pkt_len, &p[0], 6);
6856 		server->master_pkt_len += 6;
6857 		p += 6;
6858 		// Sometimes we get some bad IP's so we search for the entry terminator '\' to avoid issues with this
6859 		while (p < end && *p != '\\') {
6860 			p++;
6861 		}
6862 
6863 		if (p < end) {
6864 			// Skip over the '\'
6865 			p++;
6866 		}
6867 
6868 		if (*p && (p + 3 == end) && (0 == strncmp("EOF", p, 3))) {
6869 			// Last packet ID ( seen in COD4 )
6870 			server->n_servers = server->master_pkt_len / 6;
6871 			server->retry1 = 0;     // received at least one packet so no need to retry
6872 			return (DONE_FORCE);
6873 		}
6874 	}
6875 
6876 	server->n_servers = server->master_pkt_len / 6;
6877 	//  server->next_player_info= -1; evil, causes busy loop!
6878 	server->retry1 = 0;     // received at least one packet so no need to retry
6879 
6880 	return (INPROGRESS);
6881 }
6882 
6883 
6884 int
decode_stefmaster_packet(struct qserver * server,char * pkt,int pktlen)6885 decode_stefmaster_packet(struct qserver *server, char *pkt, int pktlen)
6886 {
6887 	unsigned char *p, *m, *end;
6888 	unsigned int i, b;
6889 
6890 	pkt[pktlen] = 0;
6891 
6892 	p = (unsigned char *)pkt;
6893 	m = (unsigned char *)server->master_pkt + server->master_pkt_len;
6894 	end = (unsigned char *)&pkt[pktlen - 12];
6895 	while (*p && p < end) {
6896 		for (i = 6; i; i--) {
6897 			sscanf((char *)p, "%2x", &b);
6898 			p += 2;
6899 			*m++ = b;
6900 		}
6901 		server->master_pkt_len += 6;
6902 		while (*p && *p == '\\') {
6903 			p++;
6904 		}
6905 	}
6906 	server->n_servers = server->master_pkt_len / 6;
6907 	server->next_player_info = -1;
6908 	server->retry1 = 0;
6909 
6910 	return (1);
6911 }
6912 
6913 
6914 /* Packet from Tribes master server
6915  */
6916 query_status_t
deal_with_tribesmaster_packet(struct qserver * server,char * rawpkt,int pktlen)6917 deal_with_tribesmaster_packet(struct qserver *server, char *rawpkt, int pktlen)
6918 {
6919 	unsigned char *upkt = (unsigned char *)rawpkt;
6920 	int packet_number = upkt[2];
6921 	int n_packets = upkt[3];
6922 	unsigned char *p;
6923 	char *mpkt;
6924 	int len;
6925 	unsigned int ipaddr;
6926 
6927 	debug(2, "deal_with_tribesmaster_packet %p, %d", server, pktlen);
6928 
6929 	if (memcmp(rawpkt, tribes_master_response, sizeof(tribes_master_response)) != 0) {
6930 		fprintf(stderr, "Odd packet from Tribes master server\n");
6931 		print_packet(server, rawpkt, pktlen);
6932 	}
6933 
6934 	/*	0x1006
6935 	 *  01		packet number
6936 	 *  08		# packets
6937 	 *  02
6938 	 *  0000
6939 	 *  66
6940 	 *  0d		length of following string
6941 	 *  "Tribes Master"
6942 	 *  3c		length of following string
6943 	 *  "Check out the Starsiege demo now!   www.starsiegeplayers.com"
6944 	 *  0035
6945 	 *  06 d143 4764 812c
6946 	 *  06 d1e2 8df3 616d
6947 	 *  06 1804 6d50 616d
6948 	 *  06 d81c 6dc0 616d
6949 	 */
6950 
6951 	/*	0x1006
6952 	 *  02
6953 	 *  08
6954 	 *  02 0000
6955 	 *  66
6956 	 *  00 3f
6957 	 *  06 cf88 344c 1227
6958 	 */
6959 
6960 	/* printf( "packet_number %d n_packets %d\n", packet_number, n_packets);
6961 	 */
6962 
6963 	len = upkt[8];
6964 	if (len > 0) {
6965 		p = (unsigned char *)rawpkt + 9;
6966 		// printf( "%.*s\n", len, p);
6967 		p += len;
6968 		len = upkt[8 + len + 1];
6969 		// printf( "%.*s\n", len, p+1);
6970 		p += len + 1;
6971 		p += 2;
6972 	} else {
6973 		p = (unsigned char *)rawpkt + 10;
6974 	}
6975 
6976 	if (server->master_pkt == NULL) {
6977 		server->master_pkt = (char *)malloc(n_packets * 64 * 6);
6978 		mpkt = server->master_pkt;
6979 	} else {
6980 		mpkt = server->master_pkt + server->n_servers * 6;
6981 	}
6982 
6983 	while ((char *)p < rawpkt + pktlen) {
6984 		if (*p != 0x6) {
6985 			printf("*p %u\n", (unsigned)*p);
6986 		}
6987 		memcpy(mpkt, p + 1, sizeof(ipaddr));
6988 		if (0) {
6989 			mpkt[4] = p[5];
6990 			mpkt[5] = p[6];
6991 		} else {
6992 			mpkt[5] = p[5];
6993 			mpkt[4] = p[6];
6994 		}
6995 		//printf( "%08x:%hu %u.%u.%u.%u:%hu\n", ipaddr, port, ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, port);
6996 		p += 7;
6997 		mpkt += 6;
6998 	}
6999 
7000 	/*
7001 	 * if ( (char*)p != rawpkt+pktlen)
7002 	 * printf( "%x %x\n", p, rawpkt+pktlen);
7003 	 */
7004 	server->master_pkt_len = mpkt - server->master_pkt;
7005 	server->n_servers = server->master_pkt_len / 6;
7006 	server->server_name = MASTER;
7007 	server->next_player_info = -1;
7008 
7009 	if (packet_number >= n_packets) {
7010 		return (DONE_FORCE);
7011 	} else {
7012 		return (DONE_AUTO);
7013 	}
7014 }
7015 
7016 
7017 char *
display_tribes2_string_list(unsigned char * pkt)7018 display_tribes2_string_list(unsigned char *pkt)
7019 {
7020 	char *delim = "";
7021 	unsigned int count, len;
7022 
7023 	count = *pkt;
7024 	pkt++;
7025 	for ( ; count; count--) {
7026 		len = *pkt;
7027 		pkt++;
7028 		if (len > 0) {
7029 			if (raw_display) {
7030 				xform_printf(OF, "%s%.*s", delim, (int)len, pkt);
7031 				delim = raw_delimiter;
7032 			} else {
7033 				xform_printf(OF, "%.*s\n", (int)len, pkt);
7034 			}
7035 		}
7036 		pkt += len;
7037 	}
7038 	if (raw_display) {
7039 		fputs("\n", OF);
7040 	}
7041 	return ((char *)pkt);
7042 }
7043 
7044 
7045 query_status_t
deal_with_tribes2master_packet(struct qserver * server,char * pkt,int pktlen)7046 deal_with_tribes2master_packet(struct qserver *server, char *pkt, int pktlen)
7047 {
7048 	unsigned int n_servers, index, total, server_limit;
7049 	char *p, *mpkt;
7050 
7051 	debug(2, "deal_with_tribes2master_packet %p, %d", server, pktlen);
7052 
7053 	if (pkt[0] == TRIBES2_RESPONSE_GAME_TYPES) {
7054 		pkt += 6;
7055 		if (raw_display) {
7056 			xform_printf(OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter, server->arg, raw_delimiter);
7057 		} else {
7058 			xform_printf(OF, "Game Types\n");
7059 			xform_printf(OF, "----------\n");
7060 		}
7061 		pkt = display_tribes2_string_list((unsigned char *)pkt);
7062 		if (raw_display) {
7063 			xform_printf(OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter, server->arg, raw_delimiter);
7064 		} else {
7065 			xform_printf(OF, "\nMission Types\n");
7066 			xform_printf(OF, "-------------\n");
7067 		}
7068 		display_tribes2_string_list((unsigned char *)pkt);
7069 
7070 		server->master_pkt_len = 0;
7071 		server->n_servers = 0;
7072 		server->server_name = MASTER;
7073 		server->next_player_info = -1;
7074 		return (DONE_FORCE);
7075 	}
7076 
7077 	if (pkt[0] != TRIBES2_RESPONSE_MASTER) {
7078 		/* error */
7079 		return (PKT_ERROR);
7080 	}
7081 
7082 	server_limit = get_param_ui_value(server, "limit", ~0);
7083 
7084 	n_servers = little_endian ? *(unsigned short *)(pkt + 8) : swap_short(pkt + 8);
7085 	index = *(unsigned char *)(pkt + 6);
7086 	total = *(unsigned char *)(pkt + 7);
7087 	if (server->master_pkt == NULL) {
7088 		server->master_pkt = (char *)malloc(total * n_servers * 6);
7089 		mpkt = server->master_pkt;
7090 	} else {
7091 		mpkt = server->master_pkt + server->n_servers * 6;
7092 	}
7093 
7094 	p = pkt + 10;
7095 	for ( ; n_servers && ((char *)mpkt - server->master_pkt) / 6 < server_limit; n_servers--, p += 6, mpkt += 6) {
7096 		memcpy(mpkt, p, 4);
7097 		mpkt[4] = p[5];
7098 		mpkt[5] = p[4];
7099 	}
7100 	server->master_pkt_len = (char *)mpkt - server->master_pkt;
7101 	server->n_servers = server->master_pkt_len / 6;
7102 	server->server_name = MASTER;
7103 	server->next_player_info = -1;
7104 
7105 	if ((index >= total - 1) || (server->n_servers >= server_limit)) {
7106 		return (PKT_ERROR);
7107 	}
7108 
7109 	return (DONE_AUTO);
7110 }
7111 
7112 
7113 int
server_info_packet(struct qserver * server,struct q_packet * pkt,int datalen)7114 server_info_packet(struct qserver *server, struct q_packet *pkt, int datalen)
7115 {
7116 	int off = 0;
7117 
7118 	/* ignore duplicate packets */
7119 	if (server->server_name != NULL) {
7120 		return (0);
7121 	}
7122 
7123 	server->address = strdup((char *)&pkt->data[off]);
7124 	off += strlen(server->address) + 1;
7125 	if (off >= datalen) {
7126 		return (-1);
7127 	}
7128 
7129 	server->server_name = strdup((char *)&pkt->data[off]);
7130 	off += strlen(server->server_name) + 1;
7131 	if (off >= datalen) {
7132 		return (-1);
7133 	}
7134 
7135 	server->map_name = strdup((char *)&pkt->data[off]);
7136 	off += strlen(server->map_name) + 1;
7137 	if (off > datalen) {
7138 		return (-1);
7139 	}
7140 
7141 	server->num_players = pkt->data[off++];
7142 	server->max_players = pkt->data[off++];
7143 	server->protocol_version = pkt->data[off++];
7144 
7145 	server->retry1 = n_retries;
7146 
7147 	if (get_server_rules) {
7148 		debug(3, "send_rule_request_packet3");
7149 		send_rule_request_packet(server);
7150 	}
7151 	if (get_player_info) {
7152 		send_player_request_packet(server);
7153 	}
7154 
7155 	return (0);
7156 }
7157 
7158 
7159 int
player_info_packet(struct qserver * server,struct q_packet * pkt,int datalen)7160 player_info_packet(struct qserver *server, struct q_packet *pkt, int datalen)
7161 {
7162 	char *name, *address;
7163 	int off, colors, frags, connect_time, player_number;
7164 	struct player *player, *last;
7165 
7166 	off = 0;
7167 	player_number = pkt->data[off++];
7168 	name = (char *)&pkt->data[off];
7169 	off += strlen(name) + 1;
7170 	if (off >= datalen) {
7171 		return (-1);
7172 	}
7173 
7174 	colors = pkt->data[off + 3];
7175 	colors = (colors << 8) + pkt->data[off + 2];
7176 	colors = (colors << 8) + pkt->data[off + 1];
7177 	colors = (colors << 8) + pkt->data[off];
7178 	off += sizeof(colors);
7179 
7180 	frags = pkt->data[off + 3];
7181 	frags = (frags << 8) + pkt->data[off + 2];
7182 	frags = (frags << 8) + pkt->data[off + 1];
7183 	frags = (frags << 8) + pkt->data[off];
7184 	off += sizeof(frags);
7185 
7186 	connect_time = pkt->data[off + 3];
7187 	connect_time = (connect_time << 8) + pkt->data[off + 2];
7188 	connect_time = (connect_time << 8) + pkt->data[off + 1];
7189 	connect_time = (connect_time << 8) + pkt->data[off];
7190 	off += sizeof(connect_time);
7191 
7192 	address = (char *)&pkt->data[off];
7193 	off += strlen(address) + 1;
7194 	if (off > datalen) {
7195 		return (-1);
7196 	}
7197 
7198 	last = server->players;
7199 	while (last != NULL && last->next != NULL) {
7200 		if (last->number == player_number) {
7201 			return (0);
7202 		}
7203 		last = last->next;
7204 	}
7205 
7206 	if ((last != NULL) && (last->number == player_number)) {
7207 		return (0);
7208 	}
7209 
7210 	player = (struct player *)calloc(1, sizeof(struct player));
7211 	player->number = player_number;
7212 	player->name = strdup(name);
7213 	player->address = strdup(address);
7214 	player->connect_time = connect_time;
7215 	player->frags = frags;
7216 	player->shirt_color = colors >> 4;
7217 	player->pants_color = colors & 0xf;
7218 	player->next = NULL;
7219 
7220 	if (last == NULL) {
7221 		server->players = player;
7222 	} else {
7223 		last->next = player;
7224 	}
7225 
7226 	server->next_player_info++;
7227 	server->retry2 = n_retries;
7228 	if (server->next_player_info < server->num_players) {
7229 		send_player_request_packet(server);
7230 	}
7231 
7232 	return (0);
7233 }
7234 
7235 
7236 int
rule_info_packet(struct qserver * server,struct q_packet * pkt,int datalen)7237 rule_info_packet(struct qserver *server, struct q_packet *pkt, int datalen)
7238 {
7239 	int off = 0;
7240 	struct rule *rule, *last;
7241 	char *name, *value;
7242 
7243 	/* Straggler packet after we've already given up fetching rules */
7244 	if (server->next_rule == NULL) {
7245 		return (0);
7246 	}
7247 
7248 	if (ntohs(pkt->length) == Q_HEADER_LEN) {
7249 		server->next_rule = NULL;
7250 		return (0);
7251 	}
7252 
7253 	name = (char *)&pkt->data[off];
7254 	off += strlen(name) + 1;
7255 	if (off >= datalen) {
7256 		return (-1);
7257 	}
7258 
7259 	value = (char *)&pkt->data[off];
7260 	off += strlen(value) + 1;
7261 	if (off > datalen) {
7262 		return (-1);
7263 	}
7264 
7265 	last = server->rules;
7266 	while (last != NULL && last->next != NULL) {
7267 		if (strcmp(last->name, name) == 0) {
7268 			return (0);
7269 		}
7270 		last = last->next;
7271 	}
7272 	if ((last != NULL) && (strcmp(last->name, name) == 0)) {
7273 		return (0);
7274 	}
7275 
7276 	rule = (struct rule *)malloc(sizeof(struct rule));
7277 	rule->name = strdup(name);
7278 	rule->value = strdup(value);
7279 	rule->next = NULL;
7280 
7281 	if (last == NULL) {
7282 		server->rules = rule;
7283 	} else {
7284 		last->next = rule;
7285 	}
7286 
7287 	server->n_rules++;
7288 	server->next_rule = rule->name;
7289 	server->retry1 = n_retries;
7290 	debug(3, "send_rule_request_packet4");
7291 	send_rule_request_packet(server);
7292 
7293 	return (0);
7294 }
7295 
7296 
7297 struct info *
player_add_info(struct player * player,char * key,char * value,int flags)7298 player_add_info(struct player *player, char *key, char *value, int flags)
7299 {
7300 	struct info *info;
7301 
7302 	if (flags & OVERWITE_DUPLICATES) {
7303 		for (info = player->info; info; info = info->next) {
7304 			if (0 == strcmp(info->name, key)) {
7305 				// We should be able to free this
7306 				free(info->value);
7307 				if (flags & NO_VALUE_COPY) {
7308 					info->value = value;
7309 				} else {
7310 					info->value = strdup(value);
7311 				}
7312 
7313 				return (info);
7314 			}
7315 		}
7316 	}
7317 
7318 	if (flags & CHECK_DUPLICATE_RULES) {
7319 		for (info = player->info; info; info = info->next) {
7320 			if (0 == strcmp(info->name, key)) {
7321 				return (NULL);
7322 			}
7323 		}
7324 	}
7325 
7326 	if (flags & COMBINE_VALUES) {
7327 		for (info = player->info; info; info = info->next) {
7328 			if (0 == strcmp(info->name, key)) {
7329 				char *full_value = (char *)calloc(sizeof(char), strlen(info->value) + strlen(value) + 2);
7330 				if (NULL == full_value) {
7331 					fprintf(stderr, "Failed to malloc combined value\n");
7332 					exit(1);
7333 				}
7334 				sprintf(full_value, "%s%s%s", info->value, multi_delimiter, value);
7335 
7336 				// We should be able to free this
7337 				free(info->value);
7338 				info->value = full_value;
7339 
7340 				return (info);
7341 			}
7342 		}
7343 	}
7344 
7345 	info = (struct info *)malloc(sizeof(struct info));
7346 	if (flags & NO_KEY_COPY) {
7347 		info->name = key;
7348 	} else {
7349 		info->name = strdup(key);
7350 	}
7351 	if (flags & NO_VALUE_COPY) {
7352 		info->value = value;
7353 	} else {
7354 		info->value = strdup(value);
7355 	}
7356 	info->next = NULL;
7357 
7358 	if (NULL == player->info) {
7359 		player->info = info;
7360 	} else {
7361 		*player->last_info = info;
7362 	}
7363 	player->last_info = &info->next;
7364 	player->n_info++;
7365 
7366 	return (info);
7367 }
7368 
7369 
7370 struct rule *
add_rule(struct qserver * server,char * key,char * value,int flags)7371 add_rule(struct qserver *server, char *key, char *value, int flags)
7372 {
7373 	struct rule *rule;
7374 
7375 	debug(3, "key: %s, value: %s, flags: %d", key, value, flags);
7376 	if (flags & OVERWITE_DUPLICATES) {
7377 		for (rule = server->rules; rule; rule = rule->next) {
7378 			if (0 == strcmp(rule->name, key)) {
7379 				// We should be able to free this
7380 				free(rule->value);
7381 				if (flags & NO_VALUE_COPY) {
7382 					rule->value = value;
7383 				} else {
7384 					rule->value = strdup(value);
7385 				}
7386 
7387 				return (rule);
7388 			}
7389 		}
7390 	}
7391 
7392 	if (flags & CHECK_DUPLICATE_RULES) {
7393 		for (rule = server->rules; rule; rule = rule->next) {
7394 			if (0 == strcmp(rule->name, key)) {
7395 				return (NULL);
7396 			}
7397 		}
7398 	}
7399 
7400 	if (flags & COMBINE_VALUES) {
7401 		for (rule = server->rules; rule; rule = rule->next) {
7402 			if (0 == strcmp(rule->name, key)) {
7403 				char *full_value = (char *)calloc(sizeof(char), strlen(rule->value) + strlen(value) + strlen(multi_delimiter) + 1);
7404 				if (NULL == full_value) {
7405 					fprintf(stderr, "Failed to malloc combined value\n");
7406 					exit(1);
7407 				}
7408 				sprintf(full_value, "%s%s%s", rule->value, multi_delimiter, value);
7409 
7410 				// We should be able to free this
7411 				free(rule->value);
7412 				rule->value = full_value;
7413 
7414 				return (rule);
7415 			}
7416 		}
7417 	}
7418 
7419 	rule = (struct rule *)malloc(sizeof(struct rule));
7420 	if (flags & NO_KEY_COPY) {
7421 		rule->name = key;
7422 	} else {
7423 		rule->name = strdup(key);
7424 	}
7425 
7426 	if (flags & NO_VALUE_COPY) {
7427 		rule->value = value;
7428 	} else {
7429 		rule->value = strdup(value);
7430 	}
7431 	rule->next = NULL;
7432 	*server->last_rule = rule;
7433 	server->last_rule = &rule->next;
7434 	server->n_rules++;
7435 
7436 	return (rule);
7437 }
7438 
7439 
7440 void
add_nrule(struct qserver * server,char * key,char * value,int len)7441 add_nrule(struct qserver *server, char *key, char *value, int len)
7442 {
7443 	struct rule *rule;
7444 
7445 	for (rule = server->rules; rule; rule = rule->next) {
7446 		if (strcmp(rule->name, key) == 0) {
7447 			return;
7448 		}
7449 	}
7450 
7451 	rule = (struct rule *)malloc(sizeof(struct rule));
7452 	rule->name = strdup(key);
7453 	rule->value = strndup(value, len);
7454 	rule->next = NULL;
7455 	*server->last_rule = rule;
7456 	server->last_rule = &rule->next;
7457 	server->n_rules++;
7458 }
7459 
7460 
7461 struct player *
add_player(struct qserver * server,int player_number)7462 add_player(struct qserver *server, int player_number)
7463 {
7464 	struct player *player;
7465 
7466 	for (player = server->players; player; player = player->next) {
7467 		if (player->number == player_number) {
7468 			return (NULL);
7469 		}
7470 	}
7471 
7472 	player = (struct player *)calloc(1, sizeof(struct player));
7473 	player->number = player_number;
7474 	player->next = server->players;
7475 	player->n_info = 0;
7476 	player->ping = NA_INT;
7477 	player->team = NA_INT;
7478 	player->score = NA_INT;
7479 	player->deaths = NA_INT;
7480 	player->frags = NA_INT;
7481 	player->last_info = NULL;
7482 	server->players = player;
7483 	server->n_player_info++;
7484 	return (player);
7485 }
7486 
7487 
7488 STATIC struct player *
get_player_by_number(struct qserver * server,int player_number)7489 get_player_by_number(struct qserver *server, int player_number)
7490 {
7491 	struct player *player;
7492 
7493 	for (player = server->players; player; player = player->next) {
7494 		if (player->number == player_number) {
7495 			return (player);
7496 		}
7497 	}
7498 	return (NULL);
7499 }
7500 
7501 
7502 // Updates a servers port information.
7503 // Sets the rules:
7504 // _queryport <queryport>
7505 // hostport <port>
7506 void
change_server_port(struct qserver * server,unsigned short port,int force)7507 change_server_port(struct qserver *server, unsigned short port, int force)
7508 {
7509 	if ((port > 0) && (port != server->port)) {
7510 		// valid port and changing
7511 		char arg[64];
7512 		unsigned int ipaddr = ntohl(server->ipaddr);
7513 
7514 		// Update the servers hostname as required
7515 		sprintf(arg, "%d.%d.%d.%d:%hu", ipaddr >> 24, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff, port);
7516 
7517 		if (show_game_port || force || server->flags & TF_SHOW_GAME_PORT) {
7518 			// Update the server arg
7519 			free(server->arg);
7520 			server->arg = strdup(arg);
7521 
7522 			// Add a rule noting the previous query port
7523 			sprintf(arg, "%hu", server->port);
7524 			add_rule(server, "_queryport", arg, NO_FLAGS);
7525 
7526 			// Update the servers port
7527 			server->port = port;
7528 		}
7529 
7530 		if (0 != strcmp(server->arg, server->host_name)) {
7531 			// hostname isnt the query arg
7532 			char *colon = strchr(server->host_name, ':');
7533 			// dns hostname or hostname:port
7534 			char *hostname = malloc(strlen(server->host_name) + 7);
7535 			if (NULL == hostname) {
7536 				fprintf(stderr, "Failed to malloc hostname memory\n");
7537 			} else {
7538 				if (colon) {
7539 					*colon = '\0';
7540 				}
7541 				sprintf(hostname, "%s:%hu", server->host_name, port);
7542 				free(server->host_name);
7543 				server->host_name = hostname;
7544 			}
7545 		}
7546 
7547 		// Add a rule noting the servers hostport
7548 		sprintf(arg, "%hu", port);
7549 		add_rule(server, "hostport", arg, OVERWITE_DUPLICATES);
7550 	}
7551 }
7552 
7553 
7554 STATIC void
players_set_teamname(struct qserver * server,int teamid,char * teamname)7555 players_set_teamname(struct qserver *server, int teamid, char *teamname)
7556 {
7557 	struct player *player;
7558 
7559 	for (player = server->players; player; player = player->next) {
7560 		if (player->team == teamid) {
7561 			player->team_name = strdup(teamname);
7562 		}
7563 	}
7564 }
7565 
7566 
7567 STATIC char *
dup_nstring(const char * pkt,const char * end,char ** next)7568 dup_nstring(const char *pkt, const char *end, char **next)
7569 {
7570 	char *pt = (char *)pkt;
7571 	int len = ((unsigned char *)pkt)[0];
7572 
7573 	pt++;
7574 	if (*pt == '\1') {
7575 		len++;
7576 	}
7577 	if (pt + len > end) {
7578 		return (NULL);
7579 	}
7580 
7581 	*next = pt + len;
7582 	return (strndup(pt, len));
7583 }
7584 
7585 
7586 STATIC char *
dup_n1string(char * pkt,char * end,char ** next)7587 dup_n1string(char *pkt, char *end, char **next)
7588 {
7589 	unsigned len;
7590 
7591 	if (!pkt || (pkt >= end)) {
7592 		return (NULL);
7593 	}
7594 
7595 	len = (unsigned char)pkt[0] - 1;
7596 	pkt++;
7597 	if (pkt + len > end) {
7598 		return (NULL);
7599 	}
7600 
7601 	*next = pkt + len;
7602 	return (strndup(pkt, len));
7603 }
7604 
7605 
7606 STATIC int
pariah_basic_packet(struct qserver * server,char * rawpkt,char * end)7607 pariah_basic_packet(struct qserver *server, char *rawpkt, char *end)
7608 {
7609 	char *next;
7610 	char *string;
7611 
7612 	change_server_port(server, swap_short_from_little(&rawpkt[14]), 0);
7613 	if (NULL == (string = ut2003_strdup(&rawpkt[18], end, &next))) {
7614 		return (-1);
7615 	}
7616 
7617 	if (server->server_name == NULL) {
7618 		server->server_name = string;
7619 	} else {
7620 		free(string);
7621 	}
7622 
7623 	if (NULL == (string = ut2003_strdup(next, end, &next))) {
7624 		return (-1);
7625 	}
7626 
7627 	if (server->map_name == NULL) {
7628 		server->map_name = string;
7629 	} else {
7630 		free(string);
7631 	}
7632 
7633 	if (NULL == (string = ut2003_strdup(next, end, &next))) {
7634 		return (-1);
7635 	}
7636 
7637 	if (server->game == NULL) {
7638 		server->game = string;
7639 		add_rule(server, "gametype", server->game, NO_FLAGS | CHECK_DUPLICATE_RULES);
7640 	} else {
7641 		free(string);
7642 	}
7643 
7644 	server->num_players = (unsigned char)next[0];
7645 	server->max_players = (unsigned char)next[1];
7646 
7647 	return (0);
7648 }
7649 
7650 
7651 STATIC int
ut2003_basic_packet(struct qserver * server,char * rawpkt,char * end)7652 ut2003_basic_packet(struct qserver *server, char *rawpkt, char *end)
7653 {
7654 	char *next;
7655 	char *string;
7656 
7657 	change_server_port(server, swap_short_from_little(&rawpkt[6]), 0);
7658 
7659 	if (NULL == (string = ut2003_strdup(&rawpkt[14], end, &next))) {
7660 		return (-1);
7661 	}
7662 
7663 	if (server->server_name == NULL) {
7664 		server->server_name = string;
7665 	} else {
7666 		free(string);
7667 	}
7668 
7669 	if (NULL == (string = ut2003_strdup(next, end, &next))) {
7670 		return (-1);
7671 	}
7672 
7673 	if (server->map_name == NULL) {
7674 		server->map_name = string;
7675 	} else {
7676 		free(string);
7677 	}
7678 
7679 	if (NULL == (string = ut2003_strdup(next, end, &next))) {
7680 		return (-1);
7681 	}
7682 
7683 	if (server->game == NULL) {
7684 		server->game = string;
7685 		add_rule(server, "gametype", server->game, NO_FLAGS | CHECK_DUPLICATE_RULES);
7686 	} else {
7687 		free(string);
7688 	}
7689 
7690 	server->num_players = swap_long_from_little(next);
7691 	next += 4;
7692 	server->max_players = swap_long_from_little(next);
7693 	return (0);
7694 }
7695 
7696 
7697 STATIC int
pariah_rule_packet(struct qserver * server,char * rawpkt,char * end)7698 pariah_rule_packet(struct qserver *server, char *rawpkt, char *end)
7699 {
7700 	char *key, *value;
7701 
7702 	unsigned char no_rules = (unsigned char)rawpkt[1];
7703 	unsigned char seen = 0;
7704 
7705 	// type + no_rules
7706 	rawpkt += 2;
7707 
7708 	// we get size encoded key = value pairs
7709 	while (rawpkt < end && no_rules > seen) {
7710 		// first byte is the rule count
7711 		seen = (unsigned char)rawpkt[0];
7712 		rawpkt++;
7713 		if (NULL == (key = ut2003_strdup(rawpkt, end, &rawpkt))) {
7714 			break;
7715 		}
7716 
7717 		if ('\0' == rawpkt[0]) {
7718 			value = strdup("");
7719 			rawpkt++;
7720 		} else if (NULL == (value = ut2003_strdup(rawpkt, end, &rawpkt))) {
7721 			break;
7722 		}
7723 
7724 		if (NULL == add_rule(server, key, value, NO_KEY_COPY | NO_VALUE_COPY | COMBINE_VALUES)) {
7725 			/* duplicate, so free key and value */
7726 			free(value);
7727 			free(key);
7728 		}
7729 
7730 		seen++;
7731 	}
7732 
7733 	if (no_rules == seen) {
7734 		// all done
7735 		server->next_rule = NULL;
7736 		return (1);
7737 	}
7738 
7739 	return (0);
7740 }
7741 
7742 
7743 STATIC int
ut2003_rule_packet(struct qserver * server,char * rawpkt,char * end)7744 ut2003_rule_packet(struct qserver *server, char *rawpkt, char *end)
7745 {
7746 	char *key, *value;
7747 	int result = 0;
7748 
7749 	// Packet Type
7750 	rawpkt++;
7751 
7752 	// we get size encoded key = value pairs
7753 	while (rawpkt < end) {
7754 		if (NULL == (key = ut2003_strdup(rawpkt, end, &rawpkt))) {
7755 			break;
7756 		}
7757 
7758 		if (NULL == (value = ut2003_strdup(rawpkt, end, &rawpkt))) {
7759 			break;
7760 		}
7761 
7762 		if (strcmp(key, "minplayers") == 0) {
7763 			result = atoi(value);
7764 		}
7765 
7766 		if (NULL == add_rule(server, key, value, NO_KEY_COPY | NO_VALUE_COPY | COMBINE_VALUES)) {
7767 			/* duplicate, so free key and value */
7768 			free(value);
7769 			free(key);
7770 		}
7771 	}
7772 
7773 	return (result);
7774 }
7775 
7776 
7777 char *
ut2003_strdup(const char * string,const char * end,char ** next)7778 ut2003_strdup(const char *string, const char *end, char **next)
7779 {
7780 	unsigned char len = string[0];
7781 	char *result = NULL;
7782 
7783 	if (len < 128) {
7784 		// type 1 string
7785 		//fprintf( stderr, "Type 1:" );
7786 		result = dup_nstring(string, end, next);
7787 	} else {
7788 		// type 2 string
7789 		//fprintf( stderr, "Type 2:\n" );
7790 		const char *last;
7791 		char *resp, *pos;
7792 		// minus indicator
7793 		len -= 128;
7794 		// double byte chars so * 2
7795 		len = len * 2;
7796 		last = string + len;
7797 		if (last > end) {
7798 			*next = (char *)end;
7799 			fprintf(stderr, "Type 2 string format error ( too short )\n");
7800 			return (NULL);
7801 		}
7802 
7803 		*next = (char *)last + 1;
7804 		if (NULL == (result = (char *)calloc(last - string, sizeof(char)))) {
7805 			fprintf(stderr, "Failed to malloc string memory\n");
7806 			return (NULL);
7807 		}
7808 		resp = result;
7809 		pos = (char *)string + 1;
7810 		while (pos <= last) {
7811 			// check for a color code
7812 			if ((pos + 6 <= last) && (0 == memcmp(pos, "^\0#\0", 4))) {
7813 				// we have a color code
7814 				//fprintf( stderr, "color:%02hhx%02hhx\n", pos[4], pos[5] );
7815 				// indicator transformed to ^\1
7816 				*resp = *pos;
7817 				resp++;
7818 				pos++;
7819 				*resp = '\1';
7820 				resp++;
7821 				pos += 3;
7822 				// color byte
7823 				*resp = *pos;
7824 				resp++;
7825 				pos += 2;
7826 				//pos += 6;
7827 			}
7828 
7829 			// standard char
7830 			//fprintf( stderr, "char: %02hhx\n", *pos );
7831 			*resp = *pos;
7832 			resp++;
7833 			pos += 2;
7834 		}
7835 	}
7836 
7837 	//fprintf( stderr, "'%s'\n", result );
7838 
7839 	return (result);
7840 }
7841 
7842 
7843 STATIC int
pariah_player_packet(struct qserver * server,char * rawpkt,char * end)7844 pariah_player_packet(struct qserver *server, char *rawpkt, char *end)
7845 {
7846 	unsigned char no_players = rawpkt[1];
7847 	unsigned char seen = 0; /* XXX: cannot work this way, it takes only
7848 	                         *                         this packet into consideration. What if
7849 	                         *                         player info is spread across multiple
7850 	                         *                         packets? */
7851 
7852 	// type + no_players + some unknown preamble
7853 	rawpkt += 3;
7854 	while (rawpkt < end && seen < no_players) {
7855 		struct player *player;
7856 
7857 		// Player Number
7858 		rawpkt += 4;
7859 
7860 		// Create a player
7861 		if (NULL == (player = add_player(server, server->n_player_info))) {
7862 			return (0);
7863 		}
7864 
7865 		// Name ( min 3 bytes )
7866 		player->name = ut2003_strdup(rawpkt, end, &rawpkt);
7867 
7868 		// Ping
7869 		player->ping = swap_long_from_little(rawpkt);
7870 		rawpkt += 4;
7871 
7872 		// Frags
7873 		player->frags = (unsigned char)rawpkt[0];
7874 		rawpkt++;
7875 
7876 		// unknown
7877 		rawpkt++;
7878 
7879 		seen++;
7880 	}
7881 
7882 	if (no_players == seen) {
7883 		// all done
7884 		server->num_players = server->n_player_info;
7885 		return (1);
7886 	}
7887 
7888 	// possibly more to come
7889 
7890 	return (0);
7891 }
7892 
7893 
7894 STATIC int
ut2003_player_packet(struct qserver * server,char * rawpkt,char * end)7895 ut2003_player_packet(struct qserver *server, char *rawpkt, char *end)
7896 {
7897 	// skip type
7898 	rawpkt++;
7899 	switch (server->protocol_version) {
7900 	case 0x7e:
7901 		// XMP packet
7902 		//fprintf( stderr, "XMP packet\n" );
7903 		while (rawpkt < end) {
7904 			struct player *player;
7905 			char *var, *val;
7906 			unsigned char no_props;
7907 			if (rawpkt + 24 > end) {
7908 				malformed_packet(server, "player info too short");
7909 				rawpkt = end;
7910 				return (1);
7911 			}
7912 
7913 			// Player Number never set
7914 			rawpkt += 4;
7915 
7916 			// Player ID never set
7917 			rawpkt += 4;
7918 
7919 			if (NULL == (player = add_player(server, server->n_player_info))) {
7920 				return (0);
7921 			}
7922 
7923 			// Name ( min 3 bytes )
7924 			player->name = ut2003_strdup(rawpkt, end, &rawpkt);
7925 
7926 			// Ping
7927 			player->ping = swap_long_from_little(rawpkt);
7928 			rawpkt += 4;
7929 
7930 			// Frags
7931 			player->frags = swap_long_from_little(rawpkt);
7932 			rawpkt += 4;
7933 
7934 			// Stat ID never set
7935 			rawpkt += 4;
7936 
7937 			// Player properties
7938 			no_props = rawpkt[0];
7939 			//fprintf( stderr, "noprops %d\n", no_props );
7940 			rawpkt++;
7941 			while (rawpkt < end && no_props > 0) {
7942 				if (NULL == (var = ut2003_strdup(rawpkt, end, &rawpkt))) {
7943 					break;
7944 				}
7945 				if (NULL == (val = ut2003_strdup(rawpkt, end, &rawpkt))) {
7946 					break;
7947 				}
7948 				//fprintf( stderr, "attrib: %s = %s\n", var, val );
7949 
7950 				// Things we can use
7951 				if (0 == strcmp(var, "team")) {
7952 					player->team_name = val;
7953 				} else if (0 == strcmp(var, "class")) {
7954 					player->skin = val;
7955 				} else {
7956 					free(val);
7957 				}
7958 
7959 				free(var);
7960 				no_props--;
7961 			}
7962 		}
7963 		break;
7964 
7965 	default:
7966 		while (rawpkt < end) {
7967 			struct player *player;
7968 
7969 			if (rawpkt + 4 > end) {
7970 				malformed_packet(server, "player packet too short");
7971 				return (1);
7972 			}
7973 
7974 			if (NULL == (player = add_player(server, swap_long_from_little(rawpkt)))) {
7975 				return (0);
7976 			}
7977 
7978 			player->name = ut2003_strdup(rawpkt + 4, end, &rawpkt);
7979 			if (rawpkt + 8 > end) {
7980 				malformed_packet(server, "player packet too short");
7981 				return (1);
7982 			}
7983 			player->ping = swap_long_from_little(rawpkt);
7984 			rawpkt += 4;
7985 			player->frags = swap_long_from_little(rawpkt);
7986 			rawpkt += 4;
7987 			{
7988 				unsigned team = swap_long_from_little(rawpkt);
7989 				rawpkt += 4;
7990 				player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
7991 				if (team & 1 << 29) {
7992 					player->team_name = "red";
7993 				} else if (team & 1 << 30) {
7994 					player->team_name = "blue";
7995 				}
7996 			}
7997 		}
7998 	}
7999 
8000 	return (0);
8001 }
8002 
8003 
8004 char *
get_rule(struct qserver * server,char * name)8005 get_rule(struct qserver *server, char *name)
8006 {
8007 	struct rule *rule;
8008 
8009 	rule = server->rules;
8010 	for ( ; rule != NULL; rule = rule->next) {
8011 		if (strcmp(name, rule->name) == 0) {
8012 			return (rule->value);
8013 		}
8014 	}
8015 
8016 	return (NULL);
8017 }
8018 
8019 
8020 query_status_t
deal_with_ut2003_packet(struct qserver * server,char * rawpkt,int pktlen)8021 deal_with_ut2003_packet(struct qserver *server, char *rawpkt, int pktlen)
8022 {
8023 	// For protocol spec see:
8024 	// http://unreal.student.utwente.nl/UT2003-queryspec.html
8025 
8026 	char *end;
8027 	int error = 0, before;
8028 	unsigned int packet_header;
8029 
8030 	debug(2, "deal_with_ut2003_packet %p, %d", server, pktlen);
8031 
8032 	rawpkt[pktlen] = '\0';
8033 	end = &rawpkt[pktlen];
8034 
8035 	packet_header = swap_long_from_little(&rawpkt[0]);
8036 	rawpkt += 4;
8037 
8038 	server->protocol_version = packet_header;
8039 	if (
8040 		(packet_header != 0x77) &&      // Pariah Demo?
8041 		(packet_header != 0x78) &&      // UT2003 Demo
8042 		(packet_header != 0x79) &&      // UT2003 Retail
8043 		(packet_header != 0x7e) &&      // Unreal2 XMP
8044 		(packet_header != 0x7f) &&      // UT2004 Demo
8045 		(packet_header != 0x80)         // UT2004 Retail
8046 		) {
8047 		malformed_packet(server, "Unknown type 0x%x", packet_header);
8048 	}
8049 
8050 	switch (rawpkt[0]) {
8051 	case 0x00:
8052 		// Server info
8053 		if (server->server_name == NULL) {
8054 			server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8055 		}
8056 
8057 		error = ut2003_basic_packet(server, rawpkt, end);
8058 		if (!error) {
8059 			if (get_server_rules || get_player_info) {
8060 				int requests = server->n_requests;
8061 				server->next_rule = "";
8062 				server->retry1 = n_retries;
8063 				server->retry2 = 0;             // don't wait for player packet
8064 				debug(3, "send_rule_request_packet5");
8065 				send_rule_request_packet(server);
8066 				server->n_requests = requests;          // would produce wrong ping
8067 			}
8068 		}
8069 		break;
8070 
8071 	case 0x01:
8072 		// Game info
8073 		ut2003_rule_packet(server, rawpkt, end);
8074 		server->next_rule = "";
8075 		server->retry1 = 0;             /* we received at least one rule packet so
8076 		                                 *                 no need to retry. We'd get double
8077 		                                 *                 entries otherwise. */
8078 		break;
8079 
8080 	case 0x02:
8081 		// Player info
8082 		before = server->n_player_info;
8083 		error = ut2003_player_packet(server, rawpkt, end);
8084 		if (before == server->n_player_info) {
8085 			error = 1;
8086 		}
8087 		break;
8088 
8089 	case 0x10:
8090 		// Pariah Server info
8091 		if (server->server_name == NULL) {
8092 			server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8093 		}
8094 
8095 		error = pariah_basic_packet(server, rawpkt, end);
8096 		if (!error) {
8097 			// N.B. pariah always sends a rules and players packet
8098 			int requests = server->n_requests;
8099 			server->next_rule = "";
8100 			server->retry1 = n_retries;
8101 			server->retry2 = 0;
8102 			server->n_requests = requests;          // would produce wrong ping
8103 		}
8104 		break;
8105 
8106 	case 0x11:
8107 		// Game info
8108 		pariah_rule_packet(server, rawpkt, end);
8109 		server->retry1 = 0;             /* we received at least one rule packet so
8110 		                                 *                 no need to retry. We'd get double
8111 		                                 *                 entries otherwise. */
8112 		break;
8113 
8114 	case 0x12:
8115 		// Player info
8116 		before = server->n_player_info;
8117 		pariah_player_packet(server, rawpkt, end);
8118 		if (before == server->n_player_info) {
8119 			error = 1;
8120 		}
8121 		break;
8122 
8123 	default:
8124 		malformed_packet(server, "Unknown packet type 0x%x", (unsigned)rawpkt[0]);
8125 		break;
8126 	}
8127 
8128 	/* don't cleanup if we fetch server rules. We would lose
8129 	 * rule packets as we don't know how many we get
8130 	 * We do clean up if we don't fetch server rules so we don't
8131 	 * need to wait for timeout.
8132 	 */
8133 	if (
8134 		error ||
8135 		(!get_server_rules && !get_player_info) ||
8136 		(!get_server_rules && (server->num_players == server->n_player_info)) ||
8137 		((server->next_rule == NULL) && (server->num_players == server->n_player_info))
8138 		) {
8139 		return (DONE_FORCE);
8140 	}
8141 
8142 	return (INPROGRESS);
8143 }
8144 
8145 
8146 int
deal_with_unrealmaster_packet(struct qserver * server,char * rawpkt,int pktlen)8147 deal_with_unrealmaster_packet(struct qserver *server, char *rawpkt, int pktlen)
8148 {
8149 	debug(2, "deal_with_unrealmaster_packet %p, %d", server, pktlen);
8150 
8151 	if (pktlen == 0) {
8152 		return (PKT_ERROR);
8153 	}
8154 	print_packet(server, rawpkt, pktlen);
8155 	puts("--");
8156 	return (0);
8157 }
8158 
8159 
8160 /* Returns 1 if the query is done (server may be freed) and 0 if not.
8161  */
8162 query_status_t
deal_with_halflife_packet(struct qserver * server,char * rawpkt,int pktlen)8163 deal_with_halflife_packet(struct qserver *server, char *rawpkt, int pktlen)
8164 {
8165 	char *pkt;
8166 	char *end = &rawpkt[pktlen];
8167 	int pkt_index = 0, pkt_max = 0;
8168 	char number[16];
8169 	short pkt_id;
8170 
8171 	debug(2, "deal_with_halflife_packet %p, %d", server, pktlen);
8172 
8173 	if (server->server_name == NULL) {
8174 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8175 	}
8176 
8177 	if (pktlen < 5) {
8178 		return (PKT_ERROR);
8179 	}
8180 
8181 	if ((((rawpkt[0] != '\377') && (rawpkt[0] != '\376')) || (rawpkt[1] != '\377') || (rawpkt[2] != '\377') || (rawpkt[3] != '\377')) && show_errors) {
8182 		unsigned int ipaddr = ntohl(server->ipaddr);
8183 		fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n",
8184 		    (ipaddr >> 24) & 0xff,
8185 		    (ipaddr >> 16) & 0xff,
8186 		    (ipaddr >> 8) & 0xff,
8187 		    ipaddr & 0xff,
8188 		    ntohs(server->port)
8189 		    );
8190 		print_packet(server, rawpkt, pktlen);
8191 	}
8192 
8193 	if (((unsigned char *)rawpkt)[0] == 0xfe) {
8194 		SavedData *sdata;
8195 		pkt_index = ((unsigned char *)rawpkt)[8] >> 4;
8196 		pkt_max = ((unsigned char *)rawpkt)[8] & 0xf;
8197 		memcpy(&pkt_id, &rawpkt[4], 2);
8198 
8199 		if (server->saved_data.data == NULL) {
8200 			sdata = &server->saved_data;
8201 		} else {
8202 			sdata = (SavedData *)calloc(1, sizeof(SavedData));
8203 			sdata->next = server->saved_data.next;
8204 			server->saved_data.next = sdata;
8205 		}
8206 
8207 		sdata->pkt_index = pkt_index;
8208 		sdata->pkt_max = pkt_max;
8209 		sdata->pkt_id = pkt_id;
8210 		sdata->datalen = pktlen - 9;
8211 		sdata->data = (char *)malloc(pktlen - 9);
8212 		memcpy(sdata->data, &rawpkt[9], pktlen - 9);
8213 
8214 		/* combine_packets will call us recursively */
8215 		return (combine_packets(server));
8216 
8217 		/*
8218 		 * fprintf( OF, "pkt_index %d pkt_max %d\n", pkt_index, pkt_max);
8219 		 * rawpkt+= 9;
8220 		 * pktlen-= 9;
8221 		 */
8222 	}
8223 
8224 	/* 'info' response */
8225 	if ((rawpkt[4] == 'C') || (rawpkt[4] == 'm')) {
8226 		if (server->server_name != NULL) {
8227 			return (0);
8228 		}
8229 		pkt = &rawpkt[5];
8230 		server->address = strdup(pkt);
8231 		pkt += strlen(pkt) + 1;
8232 		server->server_name = strdup(pkt);
8233 		pkt += strlen(pkt) + 1;
8234 		server->map_name = strdup(pkt);
8235 		pkt += strlen(pkt) + 1;
8236 
8237 		if (*pkt) {
8238 			add_rule(server, "gamedir", pkt, NO_FLAGS);
8239 		}
8240 		if (*pkt && (strcmp(pkt, "valve") != 0)) {
8241 			server->game = add_rule(server, "game", pkt, NO_FLAGS)->value;
8242 			server->flags |= FLAG_DO_NOT_FREE_GAME;
8243 		}
8244 		pkt += strlen(pkt) + 1;
8245 		if (*pkt) {
8246 			add_rule(server, "gamename", pkt, NO_FLAGS);
8247 		}
8248 		pkt += strlen(pkt) + 1;
8249 
8250 		server->num_players = (unsigned int)pkt[0];
8251 		server->max_players = (unsigned int)pkt[1];
8252 		pkt += 2;
8253 		if (pkt < end) {
8254 			int protocol = *((unsigned char *)pkt);
8255 			sprintf(number, "%d", protocol);
8256 			add_rule(server, "protocol", number, NO_FLAGS);
8257 			pkt++;
8258 		}
8259 
8260 		if (rawpkt[4] == 'm') {
8261 			if (*pkt == 'd') {
8262 				add_rule(server, "sv_type", "dedicated", NO_FLAGS);
8263 			} else if (*pkt == 'l') {
8264 				add_rule(server, "sv_type", "listen", NO_FLAGS);
8265 			} else {
8266 				add_rule(server, "sv_type", "?", NO_FLAGS);
8267 			}
8268 			pkt++;
8269 			if (*pkt == 'w') {
8270 				add_rule(server, "sv_os", "windows", NO_FLAGS);
8271 			} else if (*pkt == 'l') {
8272 				add_rule(server, "sv_os", "linux", NO_FLAGS);
8273 			} else {
8274 				char str[2] = "\0";
8275 				str[0] = *pkt;
8276 				add_rule(server, "sv_os", str, NO_FLAGS);
8277 			}
8278 			pkt++;
8279 			add_rule(server, "sv_password", *pkt ? "1" : "0", NO_FLAGS);
8280 			pkt++;
8281 			add_rule(server, "mod", *pkt ? "1" : "0", NO_FLAGS);
8282 			if (*pkt) {
8283 				int n;
8284 				/* pull out the mod infomation */
8285 				pkt++;
8286 				add_rule(server, "mod_info_url", pkt, NO_FLAGS);
8287 				pkt += strlen(pkt) + 1;
8288 				if (*pkt) {
8289 					add_rule(server, "mod_download_url", pkt, NO_FLAGS);
8290 				}
8291 				pkt += strlen(pkt) + 1;
8292 				if (*pkt) {
8293 					add_rule(server, "mod_detail", pkt, NO_FLAGS);
8294 				}
8295 				pkt += strlen(pkt) + 1;
8296 				n = swap_long_from_little(pkt);
8297 				sprintf(number, "%d", n);
8298 				add_rule(server, "modversion", number, NO_FLAGS);
8299 				pkt += 4;
8300 				n = swap_long_from_little(pkt);
8301 				sprintf(number, "%d", n);
8302 				add_rule(server, "modsize", number, NO_FLAGS);
8303 				pkt += 4;
8304 				add_rule(server, "svonly", *pkt ? "1" : "0", NO_FLAGS);
8305 				pkt++;
8306 				add_rule(server, "cldll", *pkt ? "1" : "0", NO_FLAGS);
8307 				pkt++;
8308 				if (pkt < end) {
8309 					add_rule(server, "secure", *pkt ? "1" : "0", NO_FLAGS);
8310 				}
8311 			}
8312 		}
8313 
8314 		if (get_player_info && server->num_players) {
8315 			int requests = server->n_requests;
8316 			server->next_player_info = server->num_players - 1;
8317 			send_player_request_packet(server);
8318 			server->n_requests = requests;  // prevent wrong ping
8319 		}
8320 		if (get_server_rules) {
8321 			int requests = server->n_requests;
8322 			server->next_rule = "";
8323 			server->retry1 = n_retries;
8324 			debug(3, "send_rule_request_packet6");
8325 			send_rule_request_packet(server);
8326 			server->n_requests = requests;  // prevent wrong ping
8327 		}
8328 	}
8329 	/* 'players' response */
8330 	else if ((rawpkt[4] == 'D') && (server->players == NULL)) {
8331 		unsigned int n = 0, temp;
8332 		struct player *player;
8333 		struct player **last_player = &server->players;
8334 		if ((unsigned int)rawpkt[5] > server->num_players) {
8335 			server->num_players = (unsigned int)rawpkt[5];
8336 		}
8337 		pkt = &rawpkt[6];
8338 		rawpkt[pktlen] = '\0';
8339 		while (1) {
8340 			if (*pkt != n + 1) {
8341 				break;
8342 			}
8343 			n++;
8344 			pkt++;
8345 			player = (struct player *)calloc(1, sizeof(struct player));
8346 			player->name = strdup(pkt);
8347 			pkt += strlen(pkt) + 1;
8348 			memcpy(&player->frags, pkt, 4);
8349 			pkt += 4;
8350 			memcpy(&temp, pkt, 4);
8351 			pkt += 4;
8352 			if (big_endian) {
8353 				player->frags = swap_long(&player->frags);
8354 			}
8355 			player->connect_time = swap_float_from_little(&temp);
8356 			*last_player = player;
8357 			last_player = &player->next;
8358 		}
8359 		if (n > server->num_players) {
8360 			server->num_players = n;
8361 		}
8362 		server->next_player_info = server->num_players;
8363 	}
8364 	/* 'rules' response */
8365 	else if ((rawpkt[4] == 'E') && (server->next_rule != NULL)) {
8366 		int n = 0;
8367 		n = ((unsigned char *)rawpkt)[5] + ((unsigned char *)rawpkt)[6] * 256;
8368 		pkt = &rawpkt[7];
8369 		while (n) {
8370 			char *key = pkt;
8371 			char *value;
8372 			pkt += strlen(pkt) + 1;
8373 			if (pkt > end) {
8374 				break;
8375 			}
8376 			value = pkt;
8377 			pkt += strlen(pkt) + 1;
8378 			if (pkt > end) {
8379 				break;
8380 			}
8381 			if ((key[0] == 's') && (strcmp(key, "sv_password") == 0)) {
8382 				add_rule(server, key, value, CHECK_DUPLICATE_RULES);
8383 			} else {
8384 				add_rule(server, key, value, NO_FLAGS);
8385 			}
8386 			n--;
8387 		}
8388 		server->next_rule = NULL;
8389 	} else if ((rawpkt[4] != 'E') && (rawpkt[4] != 'D') && (rawpkt[4] != 'm') && (rawpkt[4] != 'C') && show_errors) {
8390 		/*	if ( pkt_count) { rawpkt-= 9; pktlen+= 9; } */
8391 		fprintf(stderr, "Odd packet from HL server %s (packet len %d)\n", server->arg, pktlen);
8392 		print_packet(server, rawpkt, pktlen);
8393 	}
8394 
8395 	return (DONE_AUTO);
8396 }
8397 
8398 
8399 query_status_t
deal_with_tribes_packet(struct qserver * server,char * rawpkt,int pktlen)8400 deal_with_tribes_packet(struct qserver *server, char *rawpkt, int pktlen)
8401 {
8402 	unsigned char *pkt, *end;
8403 	int len, pnum, ping, packet_loss, n_teams, t;
8404 	struct player *player;
8405 	struct player **teams = NULL;
8406 	struct player **last_player = &server->players;
8407 	char buf[24];
8408 
8409 	debug(2, "deal_with_tribes_packet %p, %d", server, pktlen);
8410 
8411 	if (server->server_name == NULL) {
8412 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8413 	} else {
8414 		gettimeofday(&server->packet_time1, NULL);
8415 	}
8416 
8417 	if (pktlen < sizeof(tribes_info_reponse)) {
8418 		return (PKT_ERROR);
8419 	}
8420 
8421 	if (strncmp(rawpkt, tribes_players_reponse, sizeof(tribes_players_reponse)) != 0) {
8422 		return (PKT_ERROR);
8423 	}
8424 
8425 	pkt = (unsigned char *)&rawpkt[sizeof(tribes_info_reponse)];
8426 
8427 	len = *pkt;     /* game name: "Tribes" */
8428 	add_nrule(server, "gamename", (char *)pkt + 1, len);
8429 	pkt += len + 1;
8430 	len = *pkt;     /* version */
8431 	add_nrule(server, "version", (char *)pkt + 1, len);
8432 	pkt += len + 1;
8433 	len = *pkt;     /* server name */
8434 	server->server_name = strndup((char *)pkt + 1, len);
8435 	pkt += len + 1;
8436 	add_rule(server, "dedicated", *pkt ? "1" : "0", NO_FLAGS);
8437 	pkt++;  /* flag: dedicated server */
8438 	add_rule(server, "needpass", *pkt ? "1" : "0", NO_FLAGS);
8439 	pkt++;  /* flag: password on server */
8440 	server->num_players = *pkt++;
8441 	server->max_players = *pkt++;
8442 
8443 	sprintf(buf, "%u", (unsigned int)pkt[0] + (unsigned int)pkt[1] * 256);
8444 	add_rule(server, "cpu", buf, NO_FLAGS);
8445 	pkt++;          /* cpu speed, lsb */
8446 	pkt++;          /* cpu speed, msb */
8447 
8448 	len = *pkt;     /* Mod (game) */
8449 	add_nrule(server, "mods", (char *)pkt + 1, len);
8450 	pkt += len + 1;
8451 
8452 	len = *pkt;     /* game (mission): "C&H" */
8453 	add_nrule(server, "game", (char *)pkt + 1, len);
8454 	pkt += len + 1;
8455 
8456 	len = *pkt;     /* Mission (map) */
8457 	server->map_name = strndup((char *)pkt + 1, len);
8458 	pkt += len + 1;
8459 
8460 	len = *pkt;     /* description (contains Admin: and Email: ) */
8461 	debug(2, "%.*s\n", len, pkt + 1);
8462 	pkt += len + 1;
8463 
8464 	n_teams = *pkt++;       /* number of teams */
8465 	if (n_teams == 255) {
8466 		return (PKT_ERROR);
8467 	}
8468 	sprintf(buf, "%d", n_teams);
8469 	add_rule(server, "numteams", buf, NO_FLAGS);
8470 
8471 	len = *pkt;     /* first title */
8472 	debug(2, "%.*s\n", len, pkt + 1);
8473 	pkt += len + 1;
8474 
8475 	len = *pkt;     /* second title */
8476 	debug(2, "%.*s\n", len, pkt + 1);
8477 	pkt += len + 1;
8478 
8479 	if (n_teams > 1) {
8480 		teams = (struct player **)calloc(1, sizeof(struct player *) * n_teams);
8481 		for (t = 0; t < n_teams; t++) {
8482 			teams[t] = (struct player *)calloc(1, sizeof(struct player));
8483 			teams[t]->number = TRIBES_TEAM;
8484 			teams[t]->team = t;
8485 			len = *pkt;     /* team name */
8486 			teams[t]->name = strndup((char *)pkt + 1, len);
8487 			debug(2, "team#0 <%.*s>\n", len, pkt + 1);
8488 			pkt += len + 1;
8489 
8490 			len = *pkt;     /* team score */
8491 			if (len > 2) {
8492 				strncpy(buf, (char *)pkt + 1 + 3, len - 3);
8493 				buf[len - 3] = '\0';
8494 			} else {
8495 				debug(2, "%s score len %d\n", server->arg, len);
8496 				buf[0] = '\0';
8497 			}
8498 			teams[t]->frags = atoi(buf);
8499 			debug(2, "team#0 <%.*s>\n", len - 3, pkt + 1 + 3);
8500 			pkt += len + 1;
8501 		}
8502 	} else {
8503 		len = *pkt;     /* DM team? */
8504 		debug(2, "%.*s\n", len, pkt + 1);
8505 		pkt += len + 1;
8506 		pkt++;
8507 		n_teams = 0;
8508 	}
8509 
8510 	pnum = 0;
8511 	while ((char *)pkt < (rawpkt + pktlen)) {
8512 		ping = (unsigned int)*pkt << 2;
8513 		pkt++;
8514 		packet_loss = *pkt;
8515 		pkt++;
8516 		debug(2, "player#%d, team #%d\n", pnum, (int)*pkt);
8517 		pkt++;
8518 		len = *pkt;
8519 		if ((char *)pkt + len > (rawpkt + pktlen)) {
8520 			break;
8521 		}
8522 		player = (struct player *)calloc(1, sizeof(struct player));
8523 		player->team = pkt[-1];
8524 		if (n_teams && (player->team < n_teams)) {
8525 			player->team_name = teams[player->team]->name;
8526 		} else if ((player->team == 255) && n_teams) {
8527 			player->team_name = "Unknown";
8528 		}
8529 		player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
8530 		player->ping = ping;
8531 		player->packet_loss = packet_loss;
8532 		player->name = strndup((char *)pkt + 1, len);
8533 		debug(2, "player#%d, name %.*s\n", pnum, len, pkt + 1);
8534 		pkt += len + 1;
8535 		len = *pkt;
8536 		debug(2, "player#%d, info <%.*s>\n", pnum, len, pkt + 1);
8537 		end = (unsigned char *)strchr((char *)pkt + 9, 0x9);
8538 		if (end) {
8539 			strncpy(buf, (char *)pkt + 9, end - (pkt + 9));
8540 			buf[end - (pkt + 9)] = '\0';
8541 			player->frags = atoi(buf);
8542 			debug(2, "player#%d, score <%.*s>\n", pnum, (unsigned)(end - (pkt + 9)), pkt + 9);
8543 		}
8544 
8545 		*last_player = player;
8546 		last_player = &player->next;
8547 
8548 		pkt += len + 1;
8549 		pnum++;
8550 	}
8551 
8552 	for (t = n_teams; t; ) {
8553 		t--;
8554 		teams[t]->next = server->players;
8555 		server->players = teams[t];
8556 	}
8557 	free(teams);
8558 
8559 	return (DONE_AUTO);
8560 }
8561 
8562 
8563 void
get_tribes2_player_type(struct player * player)8564 get_tribes2_player_type(struct player *player)
8565 {
8566 	char *name = player->name;
8567 
8568 	for ( ; *name; name++) {
8569 		switch (*name) {
8570 		case 0x8:
8571 			player->type_flag = PLAYER_TYPE_NORMAL;
8572 			continue;
8573 
8574 		case 0xc:
8575 			player->type_flag = PLAYER_TYPE_ALIAS;
8576 			continue;
8577 
8578 		case 0xe:
8579 			player->type_flag = PLAYER_TYPE_BOT;
8580 			continue;
8581 
8582 		case 0xb:
8583 			break;
8584 
8585 		default:
8586 			continue;
8587 		}
8588 		name++;
8589 		if (isprint(*name)) {
8590 			char *n = name;
8591 			for ( ; isprint(*n); n++) {
8592 			}
8593 			player->tribe_tag = strndup(name, n - name);
8594 			name = n;
8595 		}
8596 		if (!*name) {
8597 			break;
8598 		}
8599 	}
8600 }
8601 
8602 
8603 query_status_t
deal_with_tribes2_packet(struct qserver * server,char * pkt,int pktlen)8604 deal_with_tribes2_packet(struct qserver *server, char *pkt, int pktlen)
8605 {
8606 	char str[256], *pktstart = pkt, *term, *start;
8607 	unsigned int minimum_net_protocol, build_version, i, t, len, s, status;
8608 	unsigned int net_protocol;
8609 	unsigned short cpu_speed;
8610 	int n_teams = 0, n_players;
8611 	struct player **teams = NULL, *player;
8612 	struct player **last_player = &server->players;
8613 	int query_version;
8614 
8615 	debug(2, "deal_with_tribes2_packet %p, %d", server, pktlen);
8616 
8617 	pkt[pktlen] = '\0';
8618 
8619 	if (server->server_name == NULL) {
8620 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8621 	}
8622 
8623 	/*
8624 	 * else
8625 	 * gettimeofday( &server->packet_time1, NULL);
8626 	 */
8627 
8628 	if (pkt[0] == TRIBES2_RESPONSE_PING) {
8629 		if ((pkt[6] < 4) || (pkt[6] > 12) || (strncmp(pkt + 7, "VER", 3) != 0)) {
8630 			return (PKT_ERROR);
8631 		}
8632 
8633 		strncpy(str, pkt + 10, pkt[6] - 3);
8634 		str[pkt[6] - 3] = '\0';
8635 		query_version = atoi(str);
8636 		add_nrule(server, "queryversion", pkt + 7, pkt[6]);
8637 		pkt += 7 + pkt[6];
8638 
8639 		server->protocol_version = query_version;
8640 		if ((query_version != 3) && (query_version != 5)) {
8641 			server->server_name = strdup("Unknown query version");
8642 			return (PKT_ERROR);
8643 		}
8644 
8645 		if (query_version == 5) {
8646 			net_protocol = swap_long_from_little(pkt);
8647 			sprintf(str, "%u", net_protocol);
8648 			add_rule(server, "net_protocol", str, NO_FLAGS);
8649 			pkt += 4;
8650 		}
8651 		minimum_net_protocol = swap_long_from_little(pkt);
8652 		sprintf(str, "%u", minimum_net_protocol);
8653 		add_rule(server, "minimum_net_protocol", str, NO_FLAGS);
8654 		pkt += 4;
8655 		build_version = swap_long_from_little(pkt);
8656 		sprintf(str, "%u", build_version);
8657 		add_rule(server, "build_version", str, NO_FLAGS);
8658 		pkt += 4;
8659 
8660 		server->server_name = strndup(pkt + 1, *(unsigned char *)(pkt));
8661 
8662 		/* Always send the player request because the ping packet
8663 		 * contains very little information */
8664 		send_player_request_packet(server);
8665 		return (0);
8666 	} else if (pkt[0] != TRIBES2_RESPONSE_INFO) {
8667 		return (PKT_ERROR);
8668 	}
8669 
8670 	pkt += 6;
8671 	for (i = 0; i < *(unsigned char *)pkt; i++) {
8672 		if (!isprint(pkt[i + 1])) {
8673 			return (PKT_ERROR);
8674 		}
8675 	}
8676 	add_nrule(server, server->type->game_rule, pkt + 1, *(unsigned char *)pkt);
8677 	server->game = strndup(pkt + 1, *(unsigned char *)pkt);
8678 	pkt += *pkt + 1;
8679 	add_nrule(server, "mission", pkt + 1, *(unsigned char *)pkt);
8680 	pkt += *pkt + 1;
8681 	server->map_name = strndup(pkt + 1, *(unsigned char *)pkt);
8682 	pkt += *pkt + 1;
8683 
8684 	status = *(unsigned char *)pkt;
8685 	sprintf(str, "%u", status);
8686 	add_rule(server, "status", str, NO_FLAGS);
8687 	if (status & TRIBES2_STATUS_DEDICATED) {
8688 		add_rule(server, "dedicated", "1", NO_FLAGS);
8689 	}
8690 	if (status & TRIBES2_STATUS_PASSWORD) {
8691 		add_rule(server, "password", "1", NO_FLAGS);
8692 	}
8693 	if (status & TRIBES2_STATUS_LINUX) {
8694 		add_rule(server, "linux", "1", NO_FLAGS);
8695 	}
8696 	if (status & TRIBES2_STATUS_TEAMDAMAGE) {
8697 		add_rule(server, "teamdamage", "1", NO_FLAGS);
8698 	}
8699 	if (server->protocol_version == 3) {
8700 		if (status & TRIBES2_STATUS_TOURNAMENT_VER3) {
8701 			add_rule(server, "tournament", "1", NO_FLAGS);
8702 		}
8703 		if (status & TRIBES2_STATUS_NOALIAS_VER3) {
8704 			add_rule(server, "no_aliases", "1", NO_FLAGS);
8705 		}
8706 	} else {
8707 		if (status & TRIBES2_STATUS_TOURNAMENT) {
8708 			add_rule(server, "tournament", "1", NO_FLAGS);
8709 		}
8710 		if (status & TRIBES2_STATUS_NOALIAS) {
8711 			add_rule(server, "no_aliases", "1", NO_FLAGS);
8712 		}
8713 	}
8714 	pkt++;
8715 	server->num_players = *(unsigned char *)pkt;
8716 	pkt++;
8717 	server->max_players = *(unsigned char *)pkt;
8718 	pkt++;
8719 	sprintf(str, "%u", *(unsigned char *)pkt);
8720 	add_rule(server, "bot_count", str, NO_FLAGS);
8721 	pkt++;
8722 	cpu_speed = swap_short_from_little(pkt);
8723 	sprintf(str, "%hu", cpu_speed);
8724 	add_rule(server, "cpu_speed", str, NO_FLAGS);
8725 	pkt += 2;
8726 
8727 	if (strcmp(server->server_name, "VER3") == 0) {
8728 		free(server->server_name);
8729 		server->server_name = strndup(pkt + 1, *(unsigned char *)pkt);
8730 	} else {
8731 		add_nrule(server, "info", pkt + 1, *(unsigned char *)pkt);
8732 	}
8733 
8734 	pkt += *(unsigned char *)pkt + 1;
8735 	len = swap_short_from_little(pkt);
8736 	pkt += 2;
8737 	start = pkt;
8738 	if (len + (pkt - pktstart) > pktlen) {
8739 		len -= (len + (pkt - pktstart)) - pktlen;
8740 	}
8741 
8742 	if ((len == 0) || (pkt - pktstart >= pktlen)) {
8743 		goto info_done;
8744 	}
8745 
8746 	term = strchr(pkt, 0xa);
8747 	if (!term) {
8748 		goto info_done;
8749 	}
8750 	*term = '\0';
8751 	n_teams = atoi(pkt);
8752 	sprintf(str, "%d", n_teams);
8753 	add_rule(server, "numteams", str, NO_FLAGS);
8754 	pkt = term + 1;
8755 
8756 	if (pkt - pktstart >= pktlen) {
8757 		goto info_done;
8758 	}
8759 
8760 	teams = (struct player **)calloc(1, sizeof(struct player *) * n_teams);
8761 	for (t = 0; t < n_teams; t++) {
8762 		teams[t] = (struct player *)calloc(1, sizeof(struct player));
8763 		teams[t]->number = TRIBES_TEAM;
8764 		teams[t]->team = t;
8765 		/* team name */
8766 		term = strchr(pkt, 0x9);
8767 		if (!term) {
8768 			n_teams = t;
8769 			goto info_done;
8770 		}
8771 		teams[t]->name = strndup(pkt, term - pkt);
8772 		pkt = term + 1;
8773 		term = strchr(pkt, 0xa);
8774 		if (!term) {
8775 			n_teams = t;
8776 			goto info_done;
8777 		}
8778 		*term = '\0';
8779 		teams[t]->frags = atoi(pkt);
8780 		pkt = term + 1;
8781 		if (pkt - pktstart >= pktlen) {
8782 			goto info_done;
8783 		}
8784 	}
8785 
8786 	term = strchr(pkt, 0xa);
8787 	if (!term || (term - start >= len)) {
8788 		goto info_done;
8789 	}
8790 	*term = '\0';
8791 	n_players = atoi(pkt);
8792 	pkt = term + 1;
8793 
8794 	for (i = 0; i < n_players && pkt - start < len; i++) {
8795 		pkt++;  /* skip first byte (0x10) */
8796 		if (pkt - start >= len) {
8797 			break;
8798 		}
8799 		player = (struct player *)calloc(1, sizeof(struct player));
8800 		term = strchr(pkt, 0x11);
8801 		if (!term || (term - start >= len)) {
8802 			free(player);
8803 			break;
8804 		}
8805 		player->name = strndup(pkt, term - pkt);
8806 		get_tribes2_player_type(player);
8807 		pkt = term + 1;
8808 		pkt++;  /* skip 0x9 */
8809 		if (pkt - start >= len) {
8810 			break;
8811 		}
8812 		term = strchr(pkt, 0x9);
8813 		if (!term || (term - start >= len)) {
8814 			free(player->name);
8815 			free(player);
8816 			break;
8817 		}
8818 		for (t = 0; t < n_teams; t++) {
8819 			if ((term - pkt == strlen(teams[t]->name)) && (strncmp(pkt, teams[t]->name, term - pkt) == 0)) {
8820 				break;
8821 			}
8822 		}
8823 		if (t == n_teams) {
8824 			player->team = -1;
8825 			player->team_name = "Unassigned";
8826 		} else {
8827 			player->team = t;
8828 			player->team_name = teams[t]->name;
8829 		}
8830 		player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
8831 		pkt = term + 1;
8832 		for (s = 0; *pkt != 0xa && pkt - start < len; pkt++) {
8833 			str[s++] = *pkt;
8834 		}
8835 		str[s] = '\0';
8836 		player->frags = atoi(str);
8837 		if (*pkt == 0xa) {
8838 			pkt++;
8839 		}
8840 
8841 		*last_player = player;
8842 		last_player = &player->next;
8843 	}
8844 
8845 info_done:
8846 	for (t = n_teams; t; ) {
8847 		t--;
8848 		teams[t]->next = server->players;
8849 		server->players = teams[t];
8850 	}
8851 	if (teams) {
8852 		free(teams);
8853 	}
8854 
8855 	return (DONE_FORCE);
8856 }
8857 
8858 
8859 static const char GrPacketHead[] =
8860 {
8861 	'\xc0', '\xde', '\xf1', '\x11'
8862 };
8863 static char Dat2Reply1_2_10[] =
8864 {
8865 	'\xf4', '\x03', '\x14', '\x02', '\x0a', '\x41', '\x02', '\x0a', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63'
8866 };
8867 static char Dat2Reply1_3[] =
8868 {
8869 	'\xf4', '\x03', '\x14', '\x03', '\x05', '\x41', '\x03', '\x05', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63'
8870 };
8871 static char Dat2Reply1_4[] =
8872 {
8873 	'\xf4', '\x03', '\x14', '\x04', '\x00', '\x41', '\x04', '\x00', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63'
8874 };
8875 //static char HDat2[]={'\xea','\x03','\x02','\x00','\x14'};
8876 
8877 #define SHORT_GR_LEN		75
8878 #define LONG_GR_LEN		500
8879 #define UNKNOWN_VERSION		0
8880 #define VERSION_1_2_10		1
8881 #define VERSION_1_3		2
8882 #define VERSION_1_4		3
8883 
8884 query_status_t
deal_with_ghostrecon_packet(struct qserver * server,char * pkt,int pktlen)8885 deal_with_ghostrecon_packet(struct qserver *server, char *pkt, int pktlen)
8886 {
8887 	char str[256], StartFlag, *lpszIgnoreServerPlayer;
8888 	char *lpszMission;
8889 	unsigned int iIgnoreServerPlayer, iDedicatedServer, iUseStartTimer;
8890 	unsigned short GrPayloadLen;
8891 	int i;
8892 	struct player *player;
8893 	int iLen, iTemp;
8894 	short sLen;
8895 	int iSecsPlayed;
8896 	long iSpawnType;
8897 	int ServerVersion = UNKNOWN_VERSION;
8898 	float flStartTimerSetPoint;
8899 
8900 	debug(2, "deal_with_ghostrecon_packet %p, %d", server, pktlen);
8901 
8902 	pkt[pktlen] = '\0';
8903 
8904 	/*
8905 	 * This function walks a packet that is recieved from a ghost recon server - default from port 2348. It does quite a few
8906 	 * sanity checks along the way as the structure is not documented. The packet is mostly binary in nature with many string
8907 	 * fields being variable in length, ie the length is listed foloowed by that many bytes. There are two structure arrays
8908 	 * that have an array size followed by structure size * number of elements (player name and player data). This routine
8909 	 * walks this packet and increments a pointer "pkt" to extract the info.
8910 	 */
8911 
8912 	if (server->server_name == NULL) {
8913 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
8914 	}
8915 
8916 	/* sanity check against packet */
8917 	if (memcmp(pkt, GrPacketHead, sizeof(GrPacketHead)) != 0) {
8918 		server->server_name = strdup("Unknown Packet Header");
8919 		return (PKT_ERROR);
8920 	}
8921 
8922 	pkt += sizeof(GrPacketHead);
8923 	StartFlag = pkt[0];
8924 	pkt += 1;
8925 	if (StartFlag != 0x42) {
8926 		server->server_name = strdup("Unknown Start Flag");
8927 		return (PKT_ERROR);
8928 	}
8929 
8930 	/* compare packet length recieved to included size - header info */
8931 	sLen = swap_short_from_little(pkt);
8932 	pkt += 2;
8933 	GrPayloadLen = pktlen - sizeof(GrPacketHead) - 3;
8934 	// 3 = size slen + size start flag
8935 
8936 	if (sLen != GrPayloadLen) {
8937 		server->server_name = strdup("Packet Size Mismatch");
8938 		return (PKT_ERROR);
8939 	}
8940 
8941 	/*
8942 	 * Will likely need to verify and add to this "if" construct with every patch / add-on.
8943 	 */
8944 	if (memcmp(pkt, Dat2Reply1_2_10, sizeof(Dat2Reply1_2_10)) == 0) {
8945 		ServerVersion = VERSION_1_2_10;
8946 	} else if (memcmp(pkt, Dat2Reply1_3, sizeof(Dat2Reply1_3)) == 0) {
8947 		ServerVersion = VERSION_1_3;
8948 	} else if (memcmp(pkt, Dat2Reply1_4, sizeof(Dat2Reply1_4)) == 0) {
8949 		ServerVersion = VERSION_1_4;
8950 	}
8951 
8952 	if (ServerVersion == UNKNOWN_VERSION) {
8953 		server->server_name = strdup("Unknown GR Version");
8954 		return (PKT_ERROR);
8955 	}
8956 
8957 	switch (ServerVersion) {
8958 	case VERSION_1_2_10:
8959 		strcpy(str, "1.2.10");
8960 		pkt += sizeof(Dat2Reply1_2_10);
8961 		break;
8962 
8963 	case VERSION_1_3:
8964 		strcpy(str, "1.3");
8965 		pkt += sizeof(Dat2Reply1_3);
8966 		break;
8967 
8968 	case VERSION_1_4:
8969 		strcpy(str, "1.4");
8970 		pkt += sizeof(Dat2Reply1_4);
8971 		break;
8972 	}
8973 	add_rule(server, "patch", str, NO_FLAGS);
8974 
8975 	/* have player packet */
8976 
8977 	// Ghost recon has one of the player slots filled up with the server program itself. By default we will
8978 	// drop the first player listed. This causes a bit of a mess here and below but makes for the best display
8979 	// a user can specify -grs,ignoreserverplayer=no to override this behaviour.
8980 
8981 	lpszIgnoreServerPlayer = get_param_value(server, "ignoreserverplayer", "yes");
8982 	for (i = 0; i < 4; i++) {
8983 		str[i] = tolower(lpszIgnoreServerPlayer[i]);
8984 	}
8985 	if (strcmp(str, "yes") == 0) {
8986 		iIgnoreServerPlayer = 1;
8987 	} else {
8988 		iIgnoreServerPlayer = 0;
8989 	}
8990 
8991 	pkt += 4;       /* unknown */
8992 
8993 	// this is the first of many variable strings. get the length,
8994 	// increment pointer over length, check for sanity,
8995 	// get the string, increment the pointer over string (using length)
8996 
8997 	iLen = swap_long_from_little(pkt);
8998 	pkt += 4;
8999 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9000 		server->server_name = strdup("Server Name too Long");
9001 		return (PKT_ERROR);
9002 	}
9003 	server->server_name = strndup(pkt, iLen);
9004 	pkt += iLen;
9005 
9006 	iLen = swap_long_from_little(pkt);
9007 	pkt += 4;
9008 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9009 		add_rule(server, "error", "Map Name too Long", NO_FLAGS);
9010 		return (PKT_ERROR);
9011 	}
9012 	server->map_name = strndup(pkt, iLen);
9013 	pkt += iLen;
9014 
9015 	iLen = swap_long_from_little(pkt);
9016 	pkt += 4;
9017 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9018 		add_rule(server, "error", "Mission Name too Long", NO_FLAGS);
9019 		return (PKT_ERROR);
9020 	}
9021 
9022 	/* mission does not make sense unless a coop game type. Since
9023 	 * we dont know that now, we will save the mission and set
9024 	 * the rule and free memory below when we know game type */
9025 	lpszMission = strndup(pkt, iLen);
9026 	pkt += iLen;
9027 
9028 	iLen = swap_long_from_little(pkt);
9029 	pkt += 4;
9030 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9031 		add_rule(server, "error", "Mission Type too Long", NO_FLAGS);
9032 		return (PKT_ERROR);
9033 	}
9034 	add_nrule(server, "missiontype", pkt, iLen);
9035 	pkt += iLen;
9036 
9037 	if (pkt[1]) {
9038 		add_rule(server, "password", "Yes", NO_FLAGS);
9039 	} else {
9040 		add_rule(server, "password", "No", NO_FLAGS);
9041 	}
9042 	pkt += 2;
9043 
9044 	server->max_players = swap_long_from_little(pkt);
9045 	pkt += 4;
9046 	if (server->max_players > 36) {
9047 		add_rule(server, "error", "Max players more then 36", NO_FLAGS);
9048 		return (PKT_ERROR);
9049 	}
9050 
9051 	server->num_players = swap_long_from_little(pkt);
9052 	pkt += 4;
9053 	if (server->num_players > server->max_players) {
9054 		add_rule(server, "error", "More then MAX Players", NO_FLAGS);
9055 		return (PKT_ERROR);
9056 	}
9057 
9058 	if (iIgnoreServerPlayer) {
9059 		// skip past first player
9060 		server->num_players--;
9061 		server->max_players--;
9062 		iLen = swap_long_from_little(pkt);
9063 		pkt += 4;
9064 		pkt += iLen;
9065 	}
9066 
9067 	for (i = 0; i < server->num_players; i++) {
9068 		// read each player name
9069 		iLen = swap_long_from_little(pkt);
9070 		pkt += 4;
9071 
9072 		player = (struct player *)calloc(1, sizeof(struct player));
9073 
9074 		if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9075 			add_rule(server, "error", "Player Name too Long", NO_FLAGS);
9076 			return (PKT_ERROR);
9077 		}
9078 		player->name = strndup(pkt, iLen);
9079 		pkt += iLen;            /* player name */
9080 		player->team = i;       // tag so we can find this record when we have player dat.
9081 		player->team_name = "Unassigned";
9082 		player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
9083 		player->frags = 0;
9084 
9085 		player->next = server->players;
9086 		server->players = player;
9087 	}
9088 
9089 	pkt += 17;
9090 
9091 	iLen = swap_long_from_little(pkt);
9092 	pkt += 4;
9093 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9094 		add_rule(server, "error", "Version too Long", NO_FLAGS);
9095 		return (PKT_ERROR);
9096 	}
9097 	strncpy(str, pkt, iLen);
9098 	add_rule(server, "version", str, NO_FLAGS);
9099 	pkt += iLen;/* version */
9100 
9101 	iLen = swap_long_from_little(pkt);
9102 	pkt += 4;
9103 	if ((iLen < 1) || (iLen > LONG_GR_LEN)) {
9104 		add_rule(server, "error", "Mods too Long", NO_FLAGS);
9105 		return (PKT_ERROR);
9106 	}
9107 	server->game = strndup(pkt, iLen);
9108 
9109 	for (i = 0; i < (int)strlen(server->game) - 5; i++) {
9110 		// clean the "/mods/" part from every entry
9111 		if (memcmp(&server->game[i], "\\mods\\", 6) == 0) {
9112 			server->game[i] = ' ';
9113 			strcpy(&server->game[i + 1], &server->game[i + 6]);
9114 		}
9115 	}
9116 	add_rule(server, "game", server->game, NO_FLAGS);
9117 
9118 	pkt += iLen;/* mods */
9119 
9120 	iDedicatedServer = pkt[0];
9121 	if (iDedicatedServer) {
9122 		add_rule(server, "dedicated", "Yes", NO_FLAGS);
9123 	} else {
9124 		add_rule(server, "dedicated", "No", NO_FLAGS);
9125 	}
9126 
9127 	pkt += 1;       /* unknown */
9128 
9129 	iSecsPlayed = swap_float_from_little(pkt);
9130 
9131 	add_rule(server, "timeplayed", play_time(iSecsPlayed, 2), NO_FLAGS);
9132 
9133 	pkt += 4;       /* time played */
9134 
9135 	switch (pkt[0]) {
9136 	case 3:
9137 		strcpy(str, "Joining");
9138 		break;
9139 
9140 	case 4:
9141 		strcpy(str, "Playing");
9142 		break;
9143 
9144 	case 5:
9145 		strcpy(str, "Debrief");
9146 		break;
9147 
9148 	default:
9149 		strcpy(str, "Undefined");
9150 	}
9151 	add_rule(server, "status", str, NO_FLAGS);
9152 
9153 	pkt += 1;
9154 
9155 	pkt += 3;       /* unknown */
9156 
9157 	switch (pkt[0]) {
9158 	case 2:
9159 		strcpy(str, "COOP");
9160 		break;
9161 
9162 	case 3:
9163 		strcpy(str, "SOLO");
9164 		break;
9165 
9166 	case 4:
9167 		strcpy(str, "TEAM");
9168 		break;
9169 
9170 	default:
9171 		sprintf(str, "UNKOWN %u", pkt[0]);
9172 		break;
9173 	}
9174 
9175 	add_rule(server, "gamemode", str, NO_FLAGS);
9176 
9177 	if (pkt[0] == 2) {
9178 		add_rule(server, "mission", lpszMission, NO_FLAGS);
9179 	} else {
9180 		add_rule(server, "mission", "No Mission", NO_FLAGS);
9181 	}
9182 
9183 	free(lpszMission);
9184 
9185 	pkt += 1;       /* Game Mode */
9186 
9187 	pkt += 3;       /* unknown */
9188 
9189 	iLen = swap_long_from_little(pkt);
9190 	pkt += 4;
9191 	if ((iLen < 1) || (iLen > LONG_GR_LEN)) {
9192 		add_rule(server, "error", "MOTD too Long", NO_FLAGS);
9193 		return (PKT_ERROR);
9194 	}
9195 	strncpy(str, pkt, sizeof(str));
9196 	str[sizeof(str) - 1] = 0;
9197 	add_rule(server, "motd", str, NO_FLAGS);
9198 	pkt += iLen;/* MOTD */
9199 
9200 	iSpawnType = swap_long_from_little(pkt);
9201 
9202 	switch (iSpawnType) {
9203 	case 0:
9204 		strcpy(str, "None");
9205 		break;
9206 
9207 	case 1:
9208 		strcpy(str, "Individual");
9209 		break;
9210 
9211 	case 2:
9212 		strcpy(str, "Team");
9213 		break;
9214 
9215 	case 3:
9216 		strcpy(str, "Infinite");
9217 		break;
9218 
9219 	default:
9220 		strcpy(str, "Unknown");
9221 	}
9222 
9223 	add_rule(server, "spawntype", str, NO_FLAGS);
9224 	pkt += 4;       /* spawn type */
9225 
9226 	iTemp = swap_float_from_little(pkt);
9227 	add_rule(server, "gametime", play_time(iTemp, 2), NO_FLAGS);
9228 
9229 	iTemp = iTemp - iSecsPlayed;
9230 
9231 	if (iTemp <= 0) {
9232 		iTemp = 0;
9233 	}
9234 	add_rule(server, "remainingtime", play_time(iTemp, 2), NO_FLAGS);
9235 	pkt += 4;       /* Game time */
9236 
9237 	iTemp = swap_long_from_little(pkt);
9238 	if (iIgnoreServerPlayer) {
9239 		iTemp--;
9240 	}
9241 	if (iTemp != server->num_players) {
9242 		add_rule(server, "error", "Number of Players Mismatch", NO_FLAGS);
9243 	}
9244 
9245 	pkt += 4;       /* player count 2 */
9246 
9247 	if (iIgnoreServerPlayer) {
9248 		pkt += 5;       // skip first player data
9249 	}
9250 
9251 	for (i = 0; i < server->num_players; i++) {
9252 		// for each player get binary data
9253 		player = server->players;
9254 		// first we must find the player - lets look for the tag
9255 		while (player && (player->team != i)) {
9256 			player = player->next;
9257 		}
9258 		/* get to player - linked list is in reverse order */
9259 
9260 		if (player) {
9261 			player->team = pkt[2];
9262 			switch (player->team) {
9263 			case 1:
9264 				player->team_name = "Red";
9265 				break;
9266 
9267 			case 2:
9268 				player->team_name = "Blue";
9269 				break;
9270 
9271 			case 3:
9272 				player->team_name = "Yellow";
9273 				break;
9274 
9275 			case 4:
9276 				player->team_name = "Green";
9277 				break;
9278 
9279 			case 5:
9280 				player->team_name = "Unassigned";
9281 				break;
9282 
9283 			default:
9284 				player->team_name = "Not Known";
9285 				break;
9286 			}
9287 			player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
9288 			player->deaths = pkt[1];
9289 		}
9290 		pkt += 5;       /* player data*/
9291 	}
9292 
9293 	for (i = 0; i < 5; i++) {
9294 		pkt += 8;       /* team data who knows what they have in here */
9295 	}
9296 
9297 	pkt += 1;
9298 	iUseStartTimer = pkt[0];// UseStartTimer
9299 
9300 	pkt += 1;
9301 
9302 	iTemp = flStartTimerSetPoint = swap_float_from_little(pkt);
9303 	// Start Timer Set Point
9304 	pkt += 4;
9305 
9306 	if (iUseStartTimer) {
9307 		add_rule(server, "usestarttime", "Yes", NO_FLAGS);
9308 		add_rule(server, "starttimeset", play_time(iTemp, 2), NO_FLAGS);
9309 	} else {
9310 		add_rule(server, "usestarttime", "No", NO_FLAGS);
9311 		add_rule(server, "starttimeset", play_time(0, 2), NO_FLAGS);
9312 	}
9313 
9314 	if ((ServerVersion == VERSION_1_3) ||           // stuff added in patch 1.3
9315 	    (ServerVersion == VERSION_1_4)) {
9316 		iTemp = swap_float_from_little(pkt);    // Debrief Time
9317 		add_rule(server, "debrieftime", play_time(iTemp, 2), NO_FLAGS);
9318 		pkt += 4;
9319 
9320 		iTemp = swap_float_from_little(pkt);// Respawn Min
9321 		add_rule(server, "respawnmin", play_time(iTemp, 2), NO_FLAGS);
9322 		pkt += 4;
9323 
9324 		iTemp = swap_float_from_little(pkt);// Respawn Max
9325 		add_rule(server, "respawnmax", play_time(iTemp, 2), NO_FLAGS);
9326 		pkt += 4;
9327 
9328 		iTemp = swap_float_from_little(pkt);// Respawn Invulnerable
9329 		add_rule(server, "respawnsafe", play_time(iTemp, 2), NO_FLAGS);
9330 		pkt += 4;
9331 	} else {
9332 		add_rule(server, "debrieftime", "Undefined", NO_FLAGS);
9333 		add_rule(server, "respawnmin", "Undefined", NO_FLAGS);
9334 		add_rule(server, "respawnmax", "Undefined", NO_FLAGS);
9335 		add_rule(server, "respawnsafe", "Undefined", NO_FLAGS);
9336 	}
9337 
9338 	pkt += 4;       // 4
9339 	iTemp = pkt[0]; // Spawn Count
9340 
9341 	if ((iSpawnType == 1) || (iSpawnType == 2)) {
9342 		/* Individual or team */
9343 		sprintf(str, "%u", iTemp);
9344 	} else {
9345 		/* else not used */
9346 		sprintf(str, "%u", 0);
9347 	}
9348 	add_rule(server, "spawncount", str, NO_FLAGS);
9349 	pkt += 1;       // 5
9350 
9351 	pkt += 4;       // 9
9352 
9353 	iTemp = pkt[0]; // Allow Observers
9354 	if (iTemp) {
9355 		strcpy(str, "Yes");
9356 	} else {
9357 		/* else not used */
9358 		strcpy(str, "No");
9359 	}
9360 	add_rule(server, "allowobservers", str, NO_FLAGS);
9361 	pkt += 1;       // 10
9362 
9363 	pkt += 3;       // 13
9364 
9365 	//	pkt += 13;
9366 
9367 	if (iUseStartTimer) {
9368 		iTemp = swap_float_from_little(pkt);// Start Timer Count
9369 		add_rule(server, "startwait", play_time(iTemp, 2), NO_FLAGS);
9370 	} else {
9371 		add_rule(server, "startwait", play_time(0, 2), NO_FLAGS);
9372 	}
9373 	pkt += 4;       //17
9374 
9375 	iTemp = pkt[0]; // IFF
9376 	switch (iTemp) {
9377 	case 0:
9378 		strcpy(str, "None");
9379 		break;
9380 
9381 	case 1:
9382 		strcpy(str, "Reticule");
9383 		break;
9384 
9385 	case 2:
9386 		strcpy(str, "Names");
9387 		break;
9388 
9389 	default:
9390 		strcpy(str, "Unknown");
9391 		break;
9392 	}
9393 	add_rule(server, "iff", str, NO_FLAGS);
9394 	pkt += 1;       // 18
9395 
9396 	iTemp = pkt[0]; // Threat Indicator
9397 	if (iTemp) {
9398 		add_rule(server, "ti", "ON ", NO_FLAGS);
9399 	} else {
9400 		add_rule(server, "ti", "OFF", NO_FLAGS);
9401 	}
9402 
9403 	pkt += 1;       // 19
9404 
9405 	pkt += 5;       // 24
9406 
9407 	iLen = swap_long_from_little(pkt);
9408 	pkt += 4;
9409 	if ((iLen < 1) || (iLen > SHORT_GR_LEN)) {
9410 		add_rule(server, "error", "Restrictions too Long", NO_FLAGS);
9411 		return (PKT_ERROR);
9412 	}
9413 	add_rule(server, "restrict", pkt, NO_FLAGS);
9414 	pkt += iLen;/* restrictions */
9415 
9416 	pkt += 23;
9417 
9418 	/*
9419 	 * if ( ghostrecon_debug) print_packet( pkt, GrPayloadLen);
9420 	 */
9421 
9422 	return (DONE_FORCE);
9423 }
9424 
9425 
9426 char *
find_ravenshield_game(char * gameno)9427 find_ravenshield_game(char *gameno)
9428 {
9429 	switch (atoi(gameno)) {
9430 	case 8:
9431 		return (strdup("Team Deathmatch"));
9432 
9433 		break;
9434 
9435 	case 13:
9436 		return (strdup("Deathmatch"));
9437 
9438 		break;
9439 
9440 	case 14:
9441 		return (strdup("Team Deathmatch"));
9442 
9443 		break;
9444 
9445 	case 15:
9446 		return (strdup("Bomb"));
9447 
9448 		break;
9449 
9450 	case 16:
9451 		return (strdup("Escort Pilot"));
9452 
9453 		break;
9454 
9455 	default:
9456 		// 1.50 and above actually uses a string so
9457 		// return that
9458 		return (strdup(gameno));
9459 
9460 		break;
9461 	}
9462 }
9463 
9464 
9465 char *
find_savage_game(char * gametype)9466 find_savage_game(char *gametype)
9467 {
9468 	if (0 == strcmp("RTSS", gametype)) {
9469 		return (strdup("RTSS"));
9470 	} else {
9471 		return (strdup("Unknown"));
9472 	}
9473 }
9474 
9475 
9476 query_status_t
deal_with_ravenshield_packet(struct qserver * server,char * rawpkt,int pktlen)9477 deal_with_ravenshield_packet(struct qserver *server, char *rawpkt, int pktlen)
9478 {
9479 	char *s, *key, *value;
9480 
9481 	debug(2, "deal_with_ravenshield_packet %p, %d", server, pktlen);
9482 
9483 	server->n_servers++;
9484 	if (NULL == server->server_name) {
9485 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
9486 	} else {
9487 		gettimeofday(&server->packet_time1, NULL);
9488 	}
9489 
9490 	rawpkt[pktlen] = '\0';
9491 
9492 	s = rawpkt;
9493 	while (*s) {
9494 		// Find the seperator
9495 		while (*s && *s != '\xB6') {
9496 			s++;
9497 		}
9498 
9499 		if (!*s) {
9500 			// Hit the end no more
9501 			break;
9502 		}
9503 
9504 		// key start
9505 		key = ++s;
9506 		while (*s && *s != ' ') {
9507 			s++;
9508 		}
9509 		if (*s != ' ') {
9510 			// malformed
9511 			break;
9512 		}
9513 		*s++ = '\0';
9514 		// key end
9515 		// value start
9516 		value = s;
9517 
9518 		while (*s && *s != '\xB6') {
9519 			s++;
9520 		}
9521 
9522 		if (*s == '\xB6') {
9523 			*(s - 1) = '\0';
9524 		}
9525 
9526 		// Decode current key par
9527 		if (0 == strcmp("A1", key)) {
9528 			// Max players
9529 			server->max_players = atoi(value);
9530 		} else if (0 == strcmp("A2", key)) {
9531 			// TeamKillerPenalty
9532 			add_rule(server, "TeamKillerPenalty", value, NO_FLAGS);
9533 		} else if (0 == strcmp("B1", key)) {
9534 			// Current players
9535 			server->num_players = atoi(value);
9536 		} else if (0 == strcmp("B2", key)) {
9537 			// AllowRadar
9538 			add_rule(server, "AllowRadar", value, NO_FLAGS);
9539 		} else if (0 == strcmp("D2", key)) {
9540 			// Version info
9541 			add_rule(server, "Version", value, NO_FLAGS);
9542 		} else if (0 == strcmp("E1", key)) {
9543 			// Current map
9544 			server->map_name = strdup(value);
9545 		} else if (0 == strcmp("E2", key)) {
9546 			// Unknown
9547 		} else if (0 == strcmp("F1", key)) {
9548 			// Game type
9549 			server->game = find_ravenshield_game(value);
9550 			add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
9551 		} else if (0 == strcmp("F2", key)) {
9552 			// Unknown
9553 		} else if (0 == strcmp("G1", key)) {
9554 			// Password
9555 			add_rule(server, "Password", value, NO_FLAGS);
9556 		} else if (0 == strcmp("G2", key)) {
9557 			// Query port
9558 		} else if (0 == strcmp("H1", key)) {
9559 			// Unknown
9560 		} else if (0 == strcmp("H2", key)) {
9561 			// Number of Terrorists
9562 			add_rule(server, "nbTerro", value, NO_FLAGS);
9563 		} else if (0 == strcmp("I1", key)) {
9564 			// Server name
9565 			server->server_name = strdup(value);
9566 		} else if (0 == strcmp("I2", key)) {
9567 			// Unknown
9568 		} else if (0 == strcmp("J1", key)) {
9569 			// Game Type Order
9570 			// Not pretty ignore for now
9571 			//add_rule( server, "Game Type Order", value, NO_FLAGS );
9572 		} else if (0 == strcmp("J2", key)) {
9573 			// RotateMap
9574 			add_rule(server, "RotateMap", value, NO_FLAGS);
9575 		} else if (0 == strcmp("K1", key)) {
9576 			// Map Cycle
9577 			// Not pretty ignore for now
9578 			//add_rule( server, "Map Cycle", value, NO_FLAGS );
9579 		} else if (0 == strcmp("K2", key)) {
9580 			// Force First Person Weapon
9581 			add_rule(server, "ForceFPersonWeapon", value, NO_FLAGS);
9582 		} else if (0 == strcmp("L1", key)) {
9583 			// Players names
9584 			int player_number = 0;
9585 			char *n = value;
9586 
9587 			if (*n == '/') {
9588 				// atleast 1 player
9589 				n++;
9590 				while (*n && *n != '\xB6') {
9591 					char *player_name = n;
9592 					while (*n && *n != '/' && *n != '\xB6') {
9593 						n++;
9594 					}
9595 
9596 					if (*n == '/') {
9597 						*n++ = '\0';
9598 					} else if (*n == '\xB6') {
9599 						*(n - 1) = '\0';
9600 					}
9601 
9602 					if (0 != strlen(player_name)) {
9603 						struct player *player = add_player(server, player_number);
9604 						if (NULL != player) {
9605 							player->name = strdup(player_name);
9606 						}
9607 						player_number++;
9608 					}
9609 				}
9610 			}
9611 		} else if (0 == strcmp("L3", key)) {
9612 			// PunkBuster state
9613 			add_rule(server, "PunkBuster", value, NO_FLAGS);
9614 		} else if (0 == strcmp("M1", key)) {
9615 			// Players times
9616 			int player_number = 0;
9617 			char *n = value;
9618 			if (*n == '/') {
9619 				// atleast 1 player
9620 				n++;
9621 				while (*n && *n != '\xB6') {
9622 					char *time = n;
9623 					while (*n && *n != '/' && *n != '\xB6') {
9624 						n++;
9625 					}
9626 
9627 					if (*n == '/') {
9628 						*n++ = '\0';
9629 					} else if (*n == '\xB6') {
9630 						*(n - 1) = '\0';
9631 					}
9632 
9633 					if (0 != strlen(time)) {
9634 						int mins, seconds;
9635 						if (2 == sscanf(time, "%d:%d", &mins, &seconds)) {
9636 							struct player *player = get_player_by_number(server, player_number);
9637 							if (NULL != player) {
9638 								player->connect_time = mins * 60 + seconds;
9639 							}
9640 						}
9641 						player_number++;
9642 					}
9643 				}
9644 			}
9645 		} else if (0 == strcmp("N1", key)) {
9646 			// Players ping
9647 			int player_number = 0;
9648 			char *n = value;
9649 			if (*n == '/') {
9650 				// atleast 1 player
9651 				n++;
9652 				while (*n && *n != '\xB6') {
9653 					char *ping = n;
9654 					while (*n && *n != '/' && *n != '\xB6') {
9655 						n++;
9656 					}
9657 
9658 					if (*n == '/') {
9659 						*n++ = '\0';
9660 					} else if (*n == '\xB6') {
9661 						*(n - 1) = '\0';
9662 					}
9663 
9664 					if (0 != strlen(ping)) {
9665 						struct player *player = get_player_by_number(server, player_number);
9666 						if (NULL != player) {
9667 							player->ping = atoi(ping);
9668 						}
9669 						player_number++;
9670 					}
9671 				}
9672 			}
9673 		} else if (0 == strcmp("O1", key)) {
9674 			// Players fags
9675 			int player_number = 0;
9676 			char *n = value;
9677 			if (*n == '/') {
9678 				// atleast 1 player
9679 				n++;
9680 				while (*n && *n != '\xB6') {
9681 					char *frags = n;
9682 					while (*n && *n != '/' && *n != '\xB6') {
9683 						n++;
9684 					}
9685 
9686 					if (*n == '/') {
9687 						*n++ = '\0';
9688 					} else if (*n == '\xB6') {
9689 						*(n - 1) = '\0';
9690 					}
9691 
9692 					if (0 != strlen(frags)) {
9693 						struct player *player = get_player_by_number(server, player_number);
9694 						if (NULL != player) {
9695 							player->frags = atoi(frags);
9696 						}
9697 						player_number++;
9698 					}
9699 				}
9700 			}
9701 		} else if (0 == strcmp("P1", key)) {
9702 			// Game port
9703 			// Not pretty ignore for now
9704 
9705 			/*
9706 			 * change_server_port( server, atoi( value ), 0 );
9707 			 */
9708 		} else if (0 == strcmp("Q1", key)) {
9709 			// RoundsPerMatch
9710 			add_rule(server, "RoundsPerMatch", value, NO_FLAGS);
9711 		} else if (0 == strcmp("R1", key)) {
9712 			// RoundTime
9713 			add_rule(server, "RoundTime", value, NO_FLAGS);
9714 		} else if (0 == strcmp("S1", key)) {
9715 			// BetweenRoundTime
9716 			add_rule(server, "BetweenRoundTime", value, NO_FLAGS);
9717 		} else if (0 == strcmp("T1", key)) {
9718 			// BombTime
9719 			add_rule(server, "BombTime", value, NO_FLAGS);
9720 		} else if (0 == strcmp("W1", key)) {
9721 			// ShowNames
9722 			add_rule(server, "ShowNames", value, NO_FLAGS);
9723 		} else if (0 == strcmp("X1", key)) {
9724 			// InternetServer
9725 			add_rule(server, "InternetServer", value, NO_FLAGS);
9726 		} else if (0 == strcmp("Y1", key)) {
9727 			// FriendlyFire
9728 			add_rule(server, "FriendlyFire", value, NO_FLAGS);
9729 		} else if (0 == strcmp("Z1", key)) {
9730 			// Autobalance
9731 			add_rule(server, "Autobalance", value, NO_FLAGS);
9732 		}
9733 	}
9734 
9735 	return (DONE_FORCE);
9736 }
9737 
9738 
9739 query_status_t
deal_with_savage_packet(struct qserver * server,char * rawpkt,int pktlen)9740 deal_with_savage_packet(struct qserver *server, char *rawpkt, int pktlen)
9741 {
9742 	char *s, *key, *value, *end;
9743 
9744 	debug(2, "deal_with_savage_packet %p, %d", server, pktlen);
9745 
9746 	server->n_servers++;
9747 	if (NULL == server->server_name) {
9748 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
9749 	} else {
9750 		gettimeofday(&server->packet_time1, NULL);
9751 	}
9752 
9753 	rawpkt[pktlen] = '\0';
9754 
9755 	end = s = rawpkt;
9756 	end += pktlen;
9757 	while (*s) {
9758 		// Find the seperator
9759 		while (s <= end && *s != '\xFF') {
9760 			s++;
9761 		}
9762 
9763 		if (s >= end) {
9764 			// Hit the end no more
9765 			break;
9766 		}
9767 
9768 		// key start
9769 		key = ++s;
9770 		while (s < end && *s != '\xFE') {
9771 			s++;
9772 		}
9773 		if (*s != '\xFE') {
9774 			// malformed
9775 			break;
9776 		}
9777 		*s++ = '\0';
9778 		// key end
9779 		// value start
9780 		value = s;
9781 
9782 		while (s < end && *s != '\xFF') {
9783 			s++;
9784 		}
9785 
9786 		if (*s == '\xFF') {
9787 			*s = '\0';
9788 		}
9789 		//fprintf( stderr, "'%s' = '%s'\n", key, value );
9790 
9791 		// Decode current key par
9792 		if (0 == strcmp("cmax", key)) {
9793 			// Max players
9794 			server->max_players = atoi(value);
9795 		} else if (0 == strcmp("cnum", key)) {
9796 			// Current players
9797 			server->num_players = atoi(value);
9798 		} else if (0 == strcmp("bal", key)) {
9799 			// Balance
9800 			add_rule(server, "Balance", value, NO_FLAGS);
9801 		} else if (0 == strcmp("world", key)) {
9802 			// Current map
9803 			server->map_name = strdup(value);
9804 		} else if (0 == strcmp("gametype", key)) {
9805 			// Game type
9806 			server->game = find_savage_game(value);
9807 			add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
9808 		} else if (0 == strcmp("pure", key)) {
9809 			// Pure
9810 			add_rule(server, "Pure", value, NO_FLAGS);
9811 		} else if (0 == strcmp("time", key)) {
9812 			// Current game time
9813 			add_rule(server, "Time", value, NO_FLAGS);
9814 		} else if (0 == strcmp("notes", key)) {
9815 			// Notes
9816 			add_rule(server, "Notes", value, NO_FLAGS);
9817 		} else if (0 == strcmp("needcmdr", key)) {
9818 			// Need Commander
9819 			add_rule(server, "Need Commander", value, NO_FLAGS);
9820 		} else if (0 == strcmp("name", key)) {
9821 			// Server name
9822 			server->server_name = strdup(value);
9823 		} else if (0 == strcmp("fw", key)) {
9824 			// Firewalled
9825 			add_rule(server, "Firewalled", value, NO_FLAGS);
9826 		} else if (0 == strcmp("players", key)) {
9827 			// Players names
9828 			int player_number = 0;
9829 			int team_number = 1;
9830 			char *team_name, *player_name, *n;
9831 			n = team_name = value;
9832 
9833 			// team name
9834 			n++;
9835 			while (*n && *n != '\x0a') {
9836 				n++;
9837 			}
9838 
9839 			if (*n != '\x0a') {
9840 				// Broken data
9841 				break;
9842 			}
9843 			*n = '\0';
9844 
9845 			player_name = ++n;
9846 			while (*n) {
9847 				while (*n && *n != '\x0a') {
9848 					n++;
9849 				}
9850 
9851 				if (*n != '\x0a') {
9852 					// Broken data
9853 					break;
9854 				}
9855 				*n = '\0';
9856 				n++;
9857 
9858 				if (0 == strncmp("Team ", player_name, 5)) {
9859 					team_name = player_name;
9860 					team_number++;
9861 				} else {
9862 					if (0 != strlen(player_name)) {
9863 						struct player *player = add_player(server, player_number);
9864 						if (NULL != player) {
9865 							player->name = strdup(player_name);
9866 							player->team = team_number;
9867 							player->team_name = strdup(team_name);
9868 						}
9869 						player_number++;
9870 					}
9871 				}
9872 				player_name = n;
9873 			}
9874 		}
9875 
9876 		*s = '\xFF';
9877 	}
9878 
9879 	return (DONE_FORCE);
9880 }
9881 
9882 
9883 query_status_t
deal_with_farcry_packet(struct qserver * server,char * rawpkt,int pktlen)9884 deal_with_farcry_packet(struct qserver *server, char *rawpkt, int pktlen)
9885 {
9886 	char *s, *key, *value, *end;
9887 
9888 	debug(2, "deal_with_farcry_packet %p, %d", server, pktlen);
9889 
9890 	server->n_servers++;
9891 	if (NULL == server->server_name) {
9892 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
9893 	} else {
9894 		gettimeofday(&server->packet_time1, NULL);
9895 	}
9896 
9897 	rawpkt[pktlen] = '\0';
9898 
9899 	end = s = rawpkt;
9900 	end += pktlen;
9901 	while (*s) {
9902 		// Find the seperator
9903 		while (s <= end && *s != '\xFF') {
9904 			s++;
9905 		}
9906 
9907 		if (s >= end) {
9908 			// Hit the end no more
9909 			break;
9910 		}
9911 
9912 		// key start
9913 		key = ++s;
9914 		while (s < end && *s != '\xFE') {
9915 			s++;
9916 		}
9917 		if (*s != '\xFE') {
9918 			// malformed
9919 			break;
9920 		}
9921 		*s++ = '\0';
9922 		// key end
9923 		// value start
9924 		value = s;
9925 
9926 		while (s < end && *s != '\xFF') {
9927 			s++;
9928 		}
9929 
9930 		if (*s == '\xFF') {
9931 			*s = '\0';
9932 		}
9933 		//fprintf( stderr, "'%s' = '%s'\n", key, value );
9934 
9935 		// Decode current key par
9936 		if (0 == strcmp("cmax", key)) {
9937 			// Max players
9938 			server->max_players = atoi(value);
9939 		} else if (0 == strcmp("cnum", key)) {
9940 			// Current players
9941 			server->num_players = atoi(value);
9942 		} else if (0 == strcmp("bal", key)) {
9943 			// Balance
9944 			add_rule(server, "Balance", value, NO_FLAGS);
9945 		} else if (0 == strcmp("world", key)) {
9946 			// Current map
9947 			server->map_name = strdup(value);
9948 		} else if (0 == strcmp("gametype", key)) {
9949 			// Game type
9950 			server->game = find_savage_game(value);
9951 			add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
9952 		} else if (0 == strcmp("pure", key)) {
9953 			// Pure
9954 			add_rule(server, "Pure", value, NO_FLAGS);
9955 		} else if (0 == strcmp("time", key)) {
9956 			// Current game time
9957 			add_rule(server, "Time", value, NO_FLAGS);
9958 		} else if (0 == strcmp("notes", key)) {
9959 			// Notes
9960 			add_rule(server, "Notes", value, NO_FLAGS);
9961 		} else if (0 == strcmp("needcmdr", key)) {
9962 			// Need Commander
9963 			add_rule(server, "Need Commander", value, NO_FLAGS);
9964 		} else if (0 == strcmp("name", key)) {
9965 			// Server name
9966 			server->server_name = strdup(value);
9967 		} else if (0 == strcmp("fw", key)) {
9968 			// Firewalled
9969 			add_rule(server, "Firewalled", value, NO_FLAGS);
9970 		} else if (0 == strcmp("players", key)) {
9971 			// Players names
9972 			int player_number = 0;
9973 			int team_number = 1;
9974 			char *team_name, *player_name, *n;
9975 			n = team_name = value;
9976 
9977 			// team name
9978 			n++;
9979 			while (*n && *n != '\x0a') {
9980 				n++;
9981 			}
9982 
9983 			if (*n != '\x0a') {
9984 				// Broken data
9985 				break;
9986 			}
9987 			*n = '\0';
9988 
9989 			player_name = ++n;
9990 			while (*n) {
9991 				while (*n && *n != '\x0a') {
9992 					n++;
9993 				}
9994 
9995 				if (*n != '\x0a') {
9996 					// Broken data
9997 					break;
9998 				}
9999 				*n = '\0';
10000 				n++;
10001 
10002 				if (0 == strncmp("Team ", player_name, 5)) {
10003 					team_name = player_name;
10004 					team_number++;
10005 				} else {
10006 					if (0 != strlen(player_name)) {
10007 						struct player *player = add_player(server, player_number);
10008 						if (NULL != player) {
10009 							player->name = strdup(player_name);
10010 							player->team = team_number;
10011 							player->team_name = strdup(team_name);
10012 						}
10013 						player_number++;
10014 					}
10015 				}
10016 				player_name = n;
10017 			}
10018 		}
10019 
10020 		*s = '\xFF';
10021 	}
10022 
10023 	return (DONE_FORCE);
10024 }
10025 
10026 
10027 /* postions of map name, player name (in player substring), zero-based */
10028 #define BFRIS_MAP_POS		18
10029 #define BFRIS_PNAME_POS		11
10030 query_status_t
deal_with_bfris_packet(struct qserver * server,char * rawpkt,int pktlen)10031 deal_with_bfris_packet(struct qserver *server, char *rawpkt, int pktlen)
10032 {
10033 	int i, player_data_pos, nplayers;
10034 	SavedData *sdata;
10035 	unsigned char *saved_data;
10036 	int saved_data_size;
10037 
10038 	debug(2, "deal_with_bfris_packet %p, %d", server, pktlen);
10039 
10040 	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
10041 
10042 	/* add to the data previously saved */
10043 	sdata = &server->saved_data;
10044 	if (!sdata->data) {
10045 		sdata->data = (char *)malloc(pktlen);
10046 	} else {
10047 		sdata->data = (char *)realloc(sdata->data, sdata->datalen + pktlen);
10048 	}
10049 
10050 	memcpy(sdata->data + sdata->datalen, rawpkt, pktlen);
10051 	sdata->datalen += pktlen;
10052 
10053 	saved_data = (unsigned char *)sdata->data;
10054 	saved_data_size = sdata->datalen;
10055 
10056 	/* after we get the server portion of the data, server->game != NULL */
10057 	if (!server->game) {
10058 		/* server data goes up to map name */
10059 		if (sdata->datalen <= BFRIS_MAP_POS) {
10060 			return (INPROGRESS);
10061 		}
10062 
10063 		/* see if map name is complete */
10064 		player_data_pos = 0;
10065 		for (i = BFRIS_MAP_POS; i < saved_data_size; i++) {
10066 			if (saved_data[i] == '\0') {
10067 				player_data_pos = i + 1;
10068 				/* data must extend beyond map name */
10069 				if (saved_data_size <= player_data_pos) {
10070 					return (INPROGRESS);
10071 				}
10072 				break;
10073 			}
10074 		}
10075 
10076 		/* did we find beginning of player data? */
10077 		if (!player_data_pos) {
10078 			return (INPROGRESS);
10079 		}
10080 
10081 		/* now we can go ahead and fill in server data */
10082 		server->map_name = strdup((char *)saved_data + BFRIS_MAP_POS);
10083 		server->max_players = saved_data[12];
10084 		server->protocol_version = saved_data[11];
10085 
10086 		/* save game type */
10087 		switch (saved_data[13] & 15) {
10088 		case 0:
10089 			server->game = "FFA";
10090 			break;
10091 
10092 		case 5:
10093 			server->game = "Rover";
10094 			break;
10095 
10096 		case 6:
10097 			server->game = "Occupation";
10098 			break;
10099 
10100 		case 7:
10101 			server->game = "SPAAL";
10102 			break;
10103 
10104 		case 8:
10105 			server->game = "CTF";
10106 			break;
10107 
10108 		default:
10109 			server->game = "unknown";
10110 			break;
10111 		}
10112 		server->flags |= FLAG_DO_NOT_FREE_GAME;
10113 		add_rule(server, server->type->game_rule, server->game, NO_FLAGS);
10114 
10115 		if (get_server_rules) {
10116 			char buf[24];
10117 
10118 			/* server revision */
10119 			sprintf(buf, "%d", (unsigned int)saved_data[11]);
10120 			add_rule(server, "Revision", buf, NO_FLAGS);
10121 
10122 			/* latency */
10123 			sprintf(buf, "%d", (unsigned int)saved_data[10]);
10124 			add_rule(server, "Latency", buf, NO_FLAGS);
10125 
10126 			/* player allocation */
10127 			add_rule(server, "Allocation", saved_data[13] & 16 ? "Automatic" : "Manual", NO_FLAGS);
10128 		}
10129 	}
10130 
10131 	/* If we got this far, we know the data saved goes at least to the start of
10132 	 * the player information, and that the server data is taken care of.
10133 	 */
10134 
10135 	/* start of player data */
10136 	player_data_pos = BFRIS_MAP_POS + strlen((char *)saved_data + BFRIS_MAP_POS) + 1;
10137 
10138 	/* ensure all player data have arrived */
10139 	nplayers = 0;
10140 	while (saved_data[player_data_pos] != '\0') {
10141 		player_data_pos += BFRIS_PNAME_POS;
10142 
10143 		/* does player data extend to player name? */
10144 		if (saved_data_size <= player_data_pos + 1) {
10145 			return (INPROGRESS);
10146 		}
10147 
10148 		/* does player data extend to end of player name? */
10149 		for (i = 0; player_data_pos + i < saved_data_size; i++) {
10150 			if (saved_data_size == player_data_pos + i + 1) {
10151 				return (INPROGRESS);
10152 			}
10153 
10154 			if (saved_data[player_data_pos + i] == '\0') {
10155 				player_data_pos += i + 1;
10156 				nplayers++;
10157 				break;
10158 			}
10159 		}
10160 	}
10161 	/* all player data are complete */
10162 
10163 	server->num_players = nplayers;
10164 
10165 	if (get_player_info) {
10166 		/* start of player data */
10167 		player_data_pos = BFRIS_MAP_POS + strlen((char *)saved_data + BFRIS_MAP_POS) + 1;
10168 
10169 		for (i = 0; i < nplayers; i++) {
10170 			struct player *player;
10171 			player = add_player(server, saved_data[player_data_pos]);
10172 
10173 			player->ship = saved_data[player_data_pos + 1];
10174 			player->ping = saved_data[player_data_pos + 2];
10175 			player->frags = saved_data[player_data_pos + 3];
10176 			player->team = saved_data[player_data_pos + 4];
10177 			switch (player->team) {
10178 			case 0:
10179 				player->team_name = "silver";
10180 				break;
10181 
10182 			case 1:
10183 				player->team_name = "red";
10184 				break;
10185 
10186 			case 2:
10187 				player->team_name = "blue";
10188 				break;
10189 
10190 			case 3:
10191 				player->team_name = "green";
10192 				break;
10193 
10194 			case 4:
10195 				player->team_name = "purple";
10196 				break;
10197 
10198 			case 5:
10199 				player->team_name = "yellow";
10200 				break;
10201 
10202 			case 6:
10203 				player->team_name = "cyan";
10204 				break;
10205 
10206 			default:
10207 				player->team_name = "unknown";
10208 				break;
10209 			}
10210 			player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
10211 			player->room = saved_data[player_data_pos + 5];
10212 
10213 			/* score is little-endian integer */
10214 			player->score = saved_data[player_data_pos + 7] +
10215 			    (saved_data[player_data_pos + 8] << 8) +
10216 			    (saved_data[player_data_pos + 9] << 16) +
10217 			    (saved_data[player_data_pos + 10] << 24);
10218 
10219 			/* for archs with > 4-byte int */
10220 			if (player->score & 0x80000000) {
10221 				player->score = -(~(player->score)) - 1;
10222 			}
10223 
10224 			player_data_pos += BFRIS_PNAME_POS;
10225 			player->name = strdup((char *)saved_data + player_data_pos);
10226 
10227 			player_data_pos += strlen(player->name) + 1;
10228 		}
10229 	}
10230 
10231 	server->server_name = BFRIS_SERVER_NAME;
10232 
10233 	return (DONE_FORCE);
10234 }
10235 
10236 
10237 struct rule *
add_uchar_rule(struct qserver * server,char * key,unsigned char value)10238 add_uchar_rule(struct qserver *server, char *key, unsigned char value)
10239 {
10240 	char buf[24];
10241 
10242 	sprintf(buf, "%u", (unsigned)value);
10243 	return (add_rule(server, key, buf, NO_FLAGS));
10244 }
10245 
10246 
10247 query_status_t
deal_with_descent3_packet(struct qserver * server,char * rawpkt,int pktlen)10248 deal_with_descent3_packet(struct qserver *server, char *rawpkt, int pktlen)
10249 {
10250 	char *pkt;
10251 	char buf[24];
10252 
10253 	debug(2, "deal_with_descent3_packet %p, %d", server, pktlen);
10254 
10255 	if (server->server_name == NULL) {
10256 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
10257 	}
10258 
10259 	if (pktlen < 4) {
10260 		fprintf(stderr, "short descent3 packet\n");
10261 		print_packet(server, rawpkt, pktlen);
10262 		return (PKT_ERROR);
10263 	}
10264 
10265 	/* 'info' response */
10266 	if (rawpkt[1] == 0x1f) {
10267 		if (server->server_name != NULL) {
10268 			return (PKT_ERROR);
10269 		}
10270 
10271 		pkt = &rawpkt[0x15];
10272 		server->server_name = strdup(pkt);
10273 		pkt += strlen(pkt) + 2;
10274 		server->map_name = strdup(pkt); /* mission name (blah.mn3) */
10275 		pkt += strlen(pkt) + 2;
10276 		add_rule(server, "level_name", pkt, NO_FLAGS);
10277 		pkt += strlen(pkt) + 2;
10278 		add_rule(server, "gametype", pkt, NO_FLAGS);
10279 		pkt += strlen(pkt) + 1;
10280 
10281 		sprintf(buf, "%hu", swap_short_from_little(pkt));
10282 		add_rule(server, "level_num", buf, NO_FLAGS);
10283 		pkt += 2;
10284 		server->num_players = swap_short_from_little(pkt);
10285 		pkt += 2;
10286 		server->max_players = swap_short_from_little(pkt);
10287 		pkt += 2;
10288 
10289 		/* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */
10290 		add_uchar_rule(server, "u0", pkt[0]);
10291 		add_uchar_rule(server, "u1", pkt[1]);
10292 		add_uchar_rule(server, "u2", pkt[2]);
10293 		add_uchar_rule(server, "u3", pkt[3]);
10294 		add_uchar_rule(server, "u4", pkt[4]);
10295 		add_uchar_rule(server, "u5", pkt[5]);
10296 		add_uchar_rule(server, "u6", pkt[6]);
10297 		add_uchar_rule(server, "u7", pkt[7]);
10298 		add_uchar_rule(server, "u8", pkt[8]);
10299 
10300 		add_uchar_rule(server, "randpowerup", (unsigned char)!(pkt[4] & 1));/*
10301 		                                                                     *                                                                     randomize powerup spawn */
10302 		add_uchar_rule(server, "acccollisions", (unsigned char)((pkt[5] & 4) > 0));
10303 		/* accurate collision detection */
10304 		add_uchar_rule(server, "brightships", (unsigned char)((pkt[5] & 16) > 0));
10305 		/* bright player ships */
10306 		add_uchar_rule(server, "mouselook", (unsigned char)((pkt[6] & 1) > 0)); /*
10307 		                                                                         *                                                                         mouselook enabled */
10308 		sprintf(buf, "%s%s", (pkt[4] & 16) ? "PP" : "CS", (pkt[6] & 1) ? "-ML" : "");
10309 		add_rule(server, "servertype", buf, NO_FLAGS);
10310 
10311 		sprintf(buf, "%hhu", pkt[9]);
10312 		add_rule(server, "difficulty", buf, NO_FLAGS);
10313 
10314 		/* unknown/undecoded fields after known flags removed */
10315 		add_uchar_rule(server, "x4", (unsigned char)(pkt[4] & ~(1 + 16)));
10316 		add_uchar_rule(server, "x5", (unsigned char)(pkt[5] & ~(4 + 16)));
10317 		add_uchar_rule(server, "x6", (unsigned char)(pkt[6] & ~1));
10318 
10319 		if (get_player_info && server->num_players) {
10320 			server->next_player_info = 0;
10321 			send_player_request_packet(server);
10322 			return (INPROGRESS);
10323 		}
10324 	}
10325 	/* MP_PLAYERLIST_DATA */
10326 	else if (rawpkt[1] == 0x73) {
10327 		struct player *player;
10328 		struct player **last_player = &server->players;
10329 
10330 		if (server->players != NULL) {
10331 			return (PKT_ERROR);
10332 		}
10333 
10334 		pkt = &rawpkt[0x4];
10335 		while (*pkt) {
10336 			player = (struct player *)calloc(1, sizeof(struct player));
10337 			player->name = strdup(pkt);
10338 			pkt += strlen(pkt) + 1;
10339 			*last_player = player;
10340 			last_player = &player->next;
10341 		}
10342 		server->next_player_info = NO_PLAYER_INFO;
10343 	} else {
10344 		fprintf(stderr, "unknown d3 packet\n");
10345 		print_packet(server, rawpkt, pktlen);
10346 	}
10347 
10348 	return (DONE_FORCE);
10349 }
10350 
10351 
10352 #define EYE_NAME_MASK		1
10353 #define EYE_TEAM_MASK		2
10354 #define EYE_SKIN_MASK		4
10355 #define EYE_SCORE_MASK		8
10356 #define EYE_PING_MASK		16
10357 #define EYE_TIME_MASK		32
10358 
10359 query_status_t
deal_with_eye_packet(struct qserver * server,char * rawpkt,int pktlen)10360 deal_with_eye_packet(struct qserver *server, char *rawpkt, int pktlen)
10361 {
10362 	char *next, *end, *value, *key;
10363 	struct player **last_player;
10364 	unsigned char pkt_index, pkt_max;
10365 	unsigned int pkt_id;
10366 
10367 	debug(2, "deal_with_eye_packet %p, %d", server, pktlen);
10368 
10369 	if (pktlen < 4) {
10370 		return (PKT_ERROR);
10371 	}
10372 
10373 	if ((rawpkt[0] != 'E') || (rawpkt[1] != 'Y') || (rawpkt[2] != 'E')) {
10374 		return (PKT_ERROR);
10375 	}
10376 
10377 	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
10378 
10379 	end = rawpkt + pktlen;
10380 	pkt_index = rawpkt[3] - '0';
10381 
10382 	if ((pktlen == 1364) || (pkt_index != 1)) {
10383 		/* fragmented packet */
10384 		SavedData *sdata;
10385 
10386 		/* EYE doesn't tell us how many packets to expect. Two packets
10387 		 * is enough for 100+ players on a BF1942 server with standard
10388 		 * server rules.
10389 		 */
10390 		pkt_max = 2;
10391 		memcpy(&pkt_id, &rawpkt[pktlen - 4], 4);
10392 
10393 		if (server->saved_data.data == NULL) {
10394 			sdata = &server->saved_data;
10395 		} else {
10396 			sdata = (SavedData *)calloc(1, sizeof(SavedData));
10397 			sdata->next = server->saved_data.next;
10398 			server->saved_data.next = sdata;
10399 		}
10400 
10401 		sdata->pkt_index = pkt_index - 1;
10402 		sdata->pkt_max = pkt_max;
10403 		sdata->pkt_id = pkt_id;
10404 		if (pkt_index == 1) {
10405 			sdata->datalen = pktlen - 4;
10406 		} else {
10407 			sdata->datalen = pktlen - 8;
10408 		}
10409 		sdata->data = (char *)malloc(sdata->datalen);
10410 
10411 		if (NULL == sdata->data) {
10412 			return (MEM_ERROR);
10413 		}
10414 
10415 		if (pkt_index == 1) {
10416 			memcpy(sdata->data, &rawpkt[0], sdata->datalen);
10417 		} else {
10418 			memcpy(sdata->data, &rawpkt[4], sdata->datalen);
10419 		}
10420 
10421 		/* combine_packets will call us recursively */
10422 		return (combine_packets(server));
10423 	}
10424 
10425 	value = dup_n1string(&rawpkt[4], end, &next);
10426 	if (value == NULL) {
10427 		return (MEM_ERROR);
10428 	}
10429 	add_rule(server, "gamename", value, NO_VALUE_COPY);
10430 
10431 	value = dup_n1string(next, end, &next);
10432 	if (value == NULL) {
10433 		return (MEM_ERROR);
10434 	}
10435 	add_rule(server, "hostport", value, NO_VALUE_COPY);
10436 
10437 	value = dup_n1string(next, end, &next);
10438 	if (value == NULL) {
10439 		return (MEM_ERROR);
10440 	}
10441 	server->server_name = value;
10442 
10443 	value = dup_n1string(next, end, &next);
10444 	if (value == NULL) {
10445 		return (MEM_ERROR);
10446 	}
10447 	server->game = value;
10448 	add_rule(server, server->type->game_rule, value, NO_FLAGS);
10449 
10450 	value = dup_n1string(next, end, &next);
10451 	if (value == NULL) {
10452 		return (MEM_ERROR);
10453 	}
10454 	server->map_name = value;
10455 
10456 	value = dup_n1string(next, end, &next);
10457 	if (value == NULL) {
10458 		return (MEM_ERROR);
10459 	}
10460 	add_rule(server, "_version", value, NO_VALUE_COPY);
10461 
10462 	value = dup_n1string(next, end, &next);
10463 	if (value == NULL) {
10464 		return (MEM_ERROR);
10465 	}
10466 	add_rule(server, "_password", value, NO_VALUE_COPY);
10467 
10468 	value = dup_n1string(next, end, &next);
10469 	if (value == NULL) {
10470 		return (MEM_ERROR);
10471 	}
10472 	server->num_players = atoi(value);
10473 	free(value);
10474 
10475 	value = dup_n1string(next, end, &next);
10476 	if (value == NULL) {
10477 		return (MEM_ERROR);
10478 	}
10479 	server->max_players = atoi(value);
10480 	free(value);
10481 
10482 	/* rule1,value1,rule2,value2, ... empty string */
10483 
10484 	do {
10485 		key = dup_n1string(next, end, &next);
10486 		if (key == NULL) {
10487 			break;
10488 		} else if (key[0] == '\0') {
10489 			free(key);
10490 			break;
10491 		}
10492 
10493 		value = dup_n1string(next, end, &next);
10494 		if (value == NULL) {
10495 			free(key);
10496 			break;
10497 		}
10498 
10499 		add_rule(server, key, value, NO_VALUE_COPY | NO_KEY_COPY);
10500 	} while (1);
10501 
10502 	/* [mask1]<name1><team1><skin1><score1><ping1><time1>[mask2]... */
10503 
10504 	last_player = &server->players;
10505 	while (next && next < end) {
10506 		struct player *player;
10507 		unsigned mask = *((unsigned char *)next);
10508 		next++;
10509 		if (next >= end) {
10510 			break;
10511 		}
10512 		if (mask == 0) {
10513 			break;
10514 		}
10515 		player = (struct player *)calloc(1, sizeof(struct player));
10516 		if (player == NULL) {
10517 			break;
10518 		}
10519 		if (mask & EYE_NAME_MASK) {
10520 			player->name = dup_n1string(next, end, &next);
10521 			//fprintf( stderr, "Player '%s'\n", player->name );
10522 			if (player->name == NULL) {
10523 				break;
10524 			}
10525 		}
10526 		if (mask & EYE_TEAM_MASK) {
10527 			value = dup_n1string(next, end, &next);
10528 			if (value == NULL) {
10529 				break;
10530 			}
10531 			if (isdigit((unsigned char)value[0])) {
10532 				player->team = atoi(value);
10533 				free(value);
10534 			} else {
10535 				player->team_name = value;
10536 			}
10537 		}
10538 		if (mask & EYE_SKIN_MASK) {
10539 			player->skin = dup_n1string(next, end, &next);
10540 			if (player->skin == NULL) {
10541 				break;
10542 			}
10543 		}
10544 		if (mask & EYE_SCORE_MASK) {
10545 			value = dup_n1string(next, end, &next);
10546 			if (value == NULL) {
10547 				break;
10548 			}
10549 			player->score = atoi(value);
10550 			player->frags = player->score;
10551 			free(value);
10552 		}
10553 		if (mask & EYE_PING_MASK) {
10554 			value = dup_n1string(next, end, &next);
10555 			if (value == NULL) {
10556 				break;
10557 			}
10558 			player->ping = atoi(value);
10559 			free(value);
10560 		}
10561 		if (mask & EYE_TIME_MASK) {
10562 			value = dup_n1string(next, end, &next);
10563 			if (value == NULL) {
10564 				break;
10565 			}
10566 			player->connect_time = atoi(value);
10567 			free(value);
10568 		}
10569 		*last_player = player;
10570 		last_player = &player->next;
10571 		//fprintf( stderr, "Player '%s'\n", player->name );
10572 	}
10573 
10574 	return (DONE_FORCE);
10575 }
10576 
10577 
10578 static const char hl2_statusresponse[] = "\xFF\xFF\xFF\xFF\x49";
10579 static const char hl2_playersresponse[] = "\xFF\xFF\xFF\xFF\x44";
10580 static const char hl2_rulesresponse[] = "\xFF\xFF\xFF\xFF\x45";
10581 static const int hl2_response_size = sizeof(hl2_statusresponse) - 1;
10582 #define HL2_STATUS	1
10583 #define HL2_PLAYERS	2
10584 #define HL2_RULES	3
10585 query_status_t
deal_with_hl2_packet(struct qserver * server,char * rawpkt,int pktlen)10586 deal_with_hl2_packet(struct qserver *server, char *rawpkt, int pktlen)
10587 {
10588 	char *ptr = rawpkt;
10589 	char *end = rawpkt + pktlen;
10590 	char temp[512];
10591 	int type = 0;
10592 	unsigned char protocolver = 0;
10593 	int n_sent = 0;
10594 
10595 	debug(2, "deal_with_hl2_packet %p, %d", server, pktlen);
10596 
10597 	server->n_servers++;
10598 	if (server->server_name == NULL) {
10599 		server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
10600 	} else {
10601 		gettimeofday(&server->packet_time1, NULL);
10602 	}
10603 
10604 	// Check if correct reply
10605 	if (pktlen < hl2_response_size) {
10606 		malformed_packet(server, "short response type");
10607 		return (PKT_ERROR);
10608 	} else {
10609 		if (0 == memcmp(hl2_statusresponse, ptr, hl2_response_size)) {
10610 			if (pktlen < hl2_response_size + 20) {
10611 				malformed_packet(server, "short packet");
10612 				return (PKT_ERROR);
10613 			}
10614 			type = HL2_STATUS;
10615 		} else if (0 == memcmp(hl2_playersresponse, ptr, hl2_response_size)) {
10616 			type = HL2_PLAYERS;
10617 		} else if (0 == memcmp(hl2_rulesresponse, ptr, hl2_response_size)) {
10618 			type = HL2_RULES;
10619 		} else {
10620 			malformed_packet(server, "unknown response");
10621 			return (PKT_ERROR);
10622 		}
10623 	}
10624 
10625 	// header
10626 	ptr += hl2_response_size;
10627 
10628 	switch (type) {
10629 	case HL2_STATUS:
10630 
10631 		// protocol version
10632 		protocolver = *ptr;
10633 		ptr++;
10634 
10635 		debug(2, "protocol: 0x%02X", protocolver);
10636 		// Commented out till out of beta
10637 
10638 		/*
10639 		 * if( '\x02' != protocolver )
10640 		 * {
10641 		 *  malformed_packet(server, "protocol version != 0x02");
10642 		 *  return PKT_ERROR;
10643 		 * }
10644 		 */
10645 
10646 		server->protocol_version = protocolver;
10647 		sprintf(temp, "%d", protocolver);
10648 		add_rule(server, "protocol", temp, NO_FLAGS);
10649 
10650 		// server name
10651 		server->server_name = strdup(ptr);
10652 		ptr += strlen(ptr) + 1;
10653 
10654 		// map
10655 		server->map_name = strdup(ptr);
10656 		ptr += strlen(ptr) + 1;
10657 
10658 		// gamedir
10659 		server->game = strdup(ptr);
10660 		add_rule(server, "gamedir", ptr, NO_FLAGS);
10661 		ptr += strlen(ptr) + 1;
10662 
10663 		// description
10664 		add_rule(server, "description", ptr, NO_FLAGS);
10665 		ptr += strlen(ptr) + 1;
10666 
10667 		// appid
10668 		ptr += 2;
10669 
10670 		// num players
10671 		server->num_players = *ptr;
10672 		ptr++;
10673 
10674 		// max players
10675 		server->max_players = *ptr;
10676 		ptr++;
10677 
10678 		// bot players
10679 		sprintf(temp, "%hhu", (*ptr));
10680 		add_rule(server, "bot_players", temp, NO_FLAGS);
10681 		ptr++;
10682 
10683 		// dedicated
10684 		if ('d' == *ptr) {
10685 			add_rule(server, "sv_type", "dedicated", NO_FLAGS);
10686 		} else if ('l' == *ptr) {
10687 			add_rule(server, "sv_type", "listen", NO_FLAGS);
10688 		} else {
10689 			char tmp[2] =
10690 			{
10691 				*ptr, '\0'
10692 			}
10693 
10694 
10695 			;
10696 			add_rule(server, "sv_type", tmp, NO_FLAGS);
10697 		}
10698 		ptr++;
10699 
10700 		// OS
10701 		if ('l' == *ptr) {
10702 			add_rule(server, "sv_os", "linux", NO_FLAGS);
10703 		} else if ('w' == *ptr) {
10704 			add_rule(server, "sv_os", "windows", NO_FLAGS);
10705 		} else {
10706 			char tmp[2] =
10707 			{
10708 				*ptr, '\0'
10709 			}
10710 
10711 
10712 			;
10713 			add_rule(server, "sv_os", tmp, NO_FLAGS);
10714 		}
10715 		ptr++;
10716 
10717 		// passworded
10718 		add_rule(server, "sv_password", *ptr ? "1" : "0", NO_FLAGS);
10719 		ptr++;
10720 
10721 		// secure
10722 		add_rule(server, "secure", *ptr ? "1" : "0", NO_FLAGS);
10723 		ptr++;
10724 
10725 		// send the other request packets if wanted
10726 		if (get_server_rules) {
10727 			int requests = server->n_requests;
10728 			debug(3, "send_rule_request_packet7");
10729 			send_rule_request_packet(server);
10730 			server->n_requests = requests;          // prevent wrong ping
10731 			n_sent++;
10732 		} else if (get_player_info) {
10733 			int requests = server->n_requests;
10734 			send_player_request_packet(server);
10735 			server->n_requests = requests;          // prevent wrong ping
10736 			n_sent++;
10737 		}
10738 		break;
10739 
10740 	case HL2_RULES:
10741 		// num_players
10742 		ptr++;
10743 
10744 		// max_players
10745 		ptr++;
10746 		while (ptr < end) {
10747 			char *var = ptr;
10748 			char *val;
10749 			ptr += strlen(var) + 1;
10750 			val = ptr;
10751 			ptr += strlen(val) + 1;
10752 			add_rule(server, var, val, NO_FLAGS);
10753 		}
10754 
10755 		if (get_player_info) {
10756 			send_player_request_packet(server);
10757 			n_sent++;
10758 		}
10759 		break;
10760 
10761 	case HL2_PLAYERS:
10762 		// num_players
10763 		ptr++;
10764 
10765 		while (ptr < end) {
10766 			struct player *player = add_player(server, server->n_player_info);
10767 
10768 			// player no
10769 			ptr++;
10770 
10771 			// name
10772 			player->name = strdup(ptr);
10773 			ptr += strlen(ptr) + 1;
10774 
10775 			// frags
10776 			player->frags = swap_long_from_little(ptr);
10777 			ptr += 4;
10778 
10779 			// time
10780 			player->connect_time = swap_float_from_little(ptr);
10781 			ptr += 4;
10782 		}
10783 
10784 		break;
10785 
10786 	default:
10787 		malformed_packet(server, "unknown response");
10788 		return (PKT_ERROR);
10789 	}
10790 
10791 	return ((0 == n_sent) ? DONE_FORCE : INPROGRESS);
10792 }
10793 
10794 
10795 query_status_t
deal_with_gamespy_master_response(struct qserver * server,char * rawpkt,int pktlen)10796 deal_with_gamespy_master_response(struct qserver *server, char *rawpkt, int pktlen)
10797 {
10798 	char *data;
10799 	int len;
10800 	int is_binary_packet = 0;
10801 
10802 	char *ipptr, *portptr;
10803 	char ipstr[16];
10804 	char portstr[6];
10805 	unsigned int ipaddr;
10806 	unsigned short port;
10807 
10808 	server->master_pkt_len = 0;
10809 	server->master_pkt = NULL;
10810 
10811 	debug(2, "deal_with_gamespy_master_response %p, %d", server, pktlen);
10812 
10813 	if (server->saved_data.data == NULL) {
10814 		debug(2, "gamespy master response first packet");
10815 		server->saved_data.data = (char *)malloc(pktlen);
10816 		if (server->saved_data.data == NULL) {
10817 			debug(0, "Failed to malloc memory for saved data");
10818 			return (MEM_ERROR);
10819 		}
10820 	} else {
10821 		debug(2, "gamespy master response intermediate packet");
10822 		server->saved_data.data = (char *)realloc(server->saved_data.data, server->saved_data.datalen + pktlen);
10823 		if (server->saved_data.data == NULL) {
10824 			debug(0, "Failed to realloc memory for saved data");
10825 			return (MEM_ERROR);
10826 		}
10827 	}
10828 
10829 	memcpy(server->saved_data.data + server->saved_data.datalen, rawpkt, pktlen);
10830 	server->saved_data.datalen += pktlen;
10831 
10832 	if ((pktlen == 0) || ((pktlen > 7) && (strncmp(rawpkt + pktlen - 7, "\\final\\", 7) == 0))) {
10833 		debug(2, "gamespy master response final packet");
10834 
10835 		// the header is in the form \basic\\secure\XXXXXX
10836 		if (strncmp(server->saved_data.data, "\\basic\\\\secure\\", 15) != 0) {
10837 			malformed_packet(server, "gamespy master response unknown header");
10838 			return (PKT_ERROR);
10839 		}
10840 
10841 		server->server_name = GAMESPY_MASTER_NAME;
10842 
10843 		data = server->saved_data.data + 21;
10844 		len = server->saved_data.datalen - 28;
10845 
10846 		if (strncmp(data, "\\ip\\", 4) != 0) {
10847 			is_binary_packet = 1;
10848 		}
10849 
10850 		if (is_binary_packet) {
10851 			debug(1, "gamespy master response uses binary packet format");
10852 			server->master_pkt_len = len;
10853 			server->master_pkt = (char *)malloc(len);
10854 			if (server->master_pkt == NULL) {
10855 				debug(0, "Failed to malloc memory for internal master packet");
10856 				return (MEM_ERROR);
10857 			}
10858 			memcpy(server->master_pkt, data, server->master_pkt_len);
10859 			return (DONE_FORCE);
10860 		}
10861 
10862 		debug(1, "gamespy master response uses text packet format");
10863 
10864 		while (len != 0) {
10865 			// ip entry
10866 			if (strncmp(data, "\\ip\\", 4) == 0) {
10867 				debug(1, "gamespy master response address entry");
10868 				data += 4;
10869 				len -= 4;
10870 
10871 				server->master_pkt_len += 6;
10872 				if (server->master_pkt == NULL) {
10873 					server->master_pkt = (char *)malloc(server->master_pkt_len);
10874 					if (server->master_pkt == NULL) {
10875 						debug(0, "Failed to malloc memory for internal master packet");
10876 						return (MEM_ERROR);
10877 					}
10878 				} else {
10879 					server->master_pkt = (char *)realloc(server->master_pkt, server->master_pkt_len);
10880 					if (server->master_pkt == NULL) {
10881 						debug(0, "Failed to realloc memory for internal master packet");
10882 						return (MEM_ERROR);
10883 					}
10884 				}
10885 
10886 				ipptr = data;
10887 				portptr = NULL;
10888 
10889 				// walk to next entry
10890 				for ( ; len && *data != '\\'; data++, len--) {
10891 					// port found (ip end)
10892 					if (*data == ':') {
10893 						portptr = data + 1;
10894 					}
10895 				}
10896 				if (portptr != NULL) {
10897 					strncpy(ipstr, ipptr, portptr - 1 - ipptr);
10898 					ipstr[portptr - 1 - ipptr] = '\0';
10899 
10900 					strncpy(portstr, portptr, data - portptr);
10901 					portstr[data - portptr] = '\0';
10902 
10903 					ipaddr = inet_addr(ipstr);
10904 					port = htons((unsigned short)atoi(portstr));
10905 				} else {
10906 					strncpy(ipstr, ipptr, data - 1 - ipptr);
10907 					ipstr[portptr - ipptr] = '\0';
10908 
10909 					ipaddr = inet_addr(ipstr);
10910 					port = htons(28000); // default port
10911 				}
10912 				memcpy(server->master_pkt + server->master_pkt_len - 6, &ipaddr, 4);
10913 				memcpy(server->master_pkt + server->master_pkt_len - 2, &port, 2);
10914 			} else {
10915 				malformed_packet(server, "gamespy master response unknown entry");
10916 				return (PKT_ERROR);
10917 			}
10918 		}
10919 
10920 		server->n_servers = server->master_pkt_len / 6;
10921 		server->next_player_info = -1;
10922 		server->retry1 = 0;
10923 
10924 		return (DONE_FORCE);
10925 	}
10926 
10927 	return (INPROGRESS);
10928 }
10929 
10930 
10931 /* Misc utility functions
10932  */
10933 unsigned int
swap_long(void * l)10934 swap_long(void *l)
10935 {
10936 	unsigned char *b = (unsigned char *)l;
10937 
10938 	return (b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24));
10939 }
10940 
10941 
10942 unsigned short
swap_short(void * l)10943 swap_short(void *l)
10944 {
10945 	unsigned char *b = (unsigned char *)l;
10946 
10947 	return ((unsigned short)b[0] | (b[1] << 8));
10948 }
10949 
10950 
10951 unsigned int
swap_long_from_little(void * l)10952 swap_long_from_little(void *l)
10953 {
10954 	unsigned char *b = (unsigned char *)l;
10955 	unsigned int result;
10956 
10957 	if (little_endian) {
10958 		memcpy(&result, l, 4);
10959 	} else {
10960 		result = (unsigned int)b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
10961 	}
10962 	return (result);
10963 }
10964 
10965 
10966 float
swap_float_from_little(void * f)10967 swap_float_from_little(void *f)
10968 {
10969 	union {
10970 		int i;
10971 		float fl;
10972 	}
10973 	temp;
10974 
10975 	temp.i = swap_long_from_little(f);
10976 	return (temp.fl);
10977 }
10978 
10979 
10980 unsigned short
swap_short_from_little(void * l)10981 swap_short_from_little(void *l)
10982 {
10983 	unsigned char *b = (unsigned char *)l;
10984 	unsigned short result;
10985 
10986 	if (little_endian) {
10987 		memcpy(&result, l, 2);
10988 	} else {
10989 		result = (unsigned short)b[0] | ((unsigned short)b[1] << 8);
10990 	}
10991 	return (result);
10992 }
10993 
10994 
10995 /** write four byte to buf */
10996 void
put_long_little(unsigned val,char * buf)10997 put_long_little(unsigned val, char *buf)
10998 {
10999 	buf[0] = val & 0xFF;
11000 	buf[1] = (val >> 8) & 0xFF;
11001 	buf[2] = (val >> 16) & 0xFF;
11002 	buf[3] = (val >> 24) & 0xFF;
11003 }
11004 
11005 
11006 char *
xml_escape(char * string)11007 xml_escape(char *string)
11008 {
11009 	static unsigned char _buf[4][MAXSTRLEN + 8];
11010 	static int _buf_index = 0;
11011 	unsigned char *result, *b, *end;
11012 	unsigned int c;
11013 
11014 	if (string == NULL) {
11015 		return ("");
11016 	}
11017 
11018 	result = &_buf[_buf_index][0];
11019 	_buf_index = (_buf_index + 1) % 4;
11020 
11021 	end = &result[MAXSTRLEN];
11022 
11023 	b = result;
11024 	for ( ; *string && b < end; string++) {
11025 		c = *string;
11026 		switch (c) {
11027 		case '&':
11028 			*b++ = '&';
11029 			*b++ = 'a';
11030 			*b++ = 'm';
11031 			*b++ = 'p';
11032 			*b++ = ';';
11033 			continue;
11034 
11035 		case '\'':
11036 			*b++ = '&';
11037 			*b++ = 'a';
11038 			*b++ = 'p';
11039 			*b++ = 'o';
11040 			*b++ = 's';
11041 			*b++ = ';';
11042 			continue;
11043 
11044 		case '"':
11045 			*b++ = '&';
11046 			*b++ = 'q';
11047 			*b++ = 'u';
11048 			*b++ = 'o';
11049 			*b++ = 't';
11050 			*b++ = ';';
11051 			continue;
11052 
11053 		case '<':
11054 			*b++ = '&';
11055 			*b++ = 'l';
11056 			*b++ = 't';
11057 			*b++ = ';';
11058 			continue;
11059 
11060 		case '>':
11061 			*b++ = '&';
11062 			*b++ = 'g';
11063 			*b++ = 't';
11064 			*b++ = ';';
11065 			continue;
11066 
11067 		default:
11068 			break;
11069 		}
11070 
11071 		// Validate character
11072 		// http://www.w3.org/TR/2000/REC-xml-20001006#charsets
11073 		if (!
11074 		    (
11075 			    (0x09 == c) ||
11076 			    (0xA == c) ||
11077 			    (0xD == c) ||
11078 			    ((0x20 <= c) && (0xD7FF >= c)) ||
11079 			    ((0xE000 <= c) && (0xFFFD >= c)) ||
11080 			    ((0x10000 <= c) && (0x10FFFF >= c))
11081 		    )
11082 		    ) {
11083 			if (show_errors) {
11084 				fprintf(stderr, "Encoding error (%d) for U+%x, D+%d\n", 1, c, c);
11085 			}
11086 		} else if (xml_encoding == ENCODING_LATIN_1) {
11087 			if (!xform_names) {
11088 				*b++ = c;
11089 			} else {
11090 				if (isprint(c)) {
11091 					*b++ = c;
11092 				} else {
11093 					b += sprintf((char *)b, "&#%u;", c);
11094 				}
11095 			}
11096 		} else if (xml_encoding == ENCODING_UTF_8) {
11097 			unsigned char tempbuf[10] =
11098 			{
11099 				0
11100 			};
11101 			unsigned char *buf = &tempbuf[0];
11102 			int bytes = 0;
11103 			int error = 1;
11104 
11105 			// Valid character ranges
11106 			if (
11107 				(0x09 == c) ||
11108 				(0xA == c) ||
11109 				(0xD == c) ||
11110 				((0x20 <= c) && (0xD7FF >= c)) ||
11111 				((0xE000 <= c) && (0xFFFD >= c)) ||
11112 				((0x10000 <= c) && (0x10FFFF >= c))
11113 				) {
11114 				error = 0;
11115 			}
11116 
11117 			if (c < 0x80) {
11118 				/* 0XXX XXXX one byte */
11119 				buf[0] = c;
11120 				bytes = 1;
11121 			} else if (c < 0x0800) {
11122 				/* 110X XXXX two bytes */
11123 				buf[0] = 0xC0 | (0x03 & (c >> 6));
11124 				buf[1] = 0x80 | (0x3F & c);
11125 				bytes = 2;
11126 			} else if (c < 0x10000) {
11127 				/* 1110 XXXX three bytes */
11128 				buf[0] = 0xE0 | (c >> 12);
11129 				buf[1] = 0x80 | ((c >> 6) & 0x3F);
11130 				buf[2] = 0x80 | (c & 0x3F);
11131 
11132 				bytes = 3;
11133 				if ((c == UTF8BYTESWAPNOTACHAR) || (c == UTF8NOTACHAR)) {
11134 					error = 3;
11135 				}
11136 			} else if (c < 0x10FFFF) {
11137 				/* 1111 0XXX four bytes */
11138 				buf[0] = 0xF0 | (c >> 18);
11139 				buf[1] = 0x80 | ((c >> 12) & 0x3F);
11140 				buf[2] = 0x80 | ((c >> 6) & 0x3F);
11141 				buf[3] = 0x80 | (c & 0x3F);
11142 				bytes = 4;
11143 				if (c > UTF8MAXFROMUCS4) {
11144 					error = 4;
11145 				}
11146 			} else if (c < 0x4000000) {
11147 				/* 1111 10XX five bytes */
11148 				buf[0] = 0xF8 | (c >> 24);
11149 				buf[1] = 0x80 | (c >> 18);
11150 				buf[2] = 0x80 | ((c >> 12) & 0x3F);
11151 				buf[3] = 0x80 | ((c >> 6) & 0x3F);
11152 				buf[4] = 0x80 | (c & 0x3F);
11153 				bytes = 5;
11154 				error = 5;
11155 			} else if (c < 0x80000000) {
11156 				/* 1111 110X six bytes */
11157 				buf[0] = 0xFC | (c >> 30);
11158 				buf[1] = 0x80 | ((c >> 24) & 0x3F);
11159 				buf[2] = 0x80 | ((c >> 18) & 0x3F);
11160 				buf[3] = 0x80 | ((c >> 12) & 0x3F);
11161 				buf[4] = 0x80 | ((c >> 6) & 0x3F);
11162 				buf[5] = 0x80 | (c & 0x3F);
11163 				bytes = 6;
11164 				error = 6;
11165 			} else {
11166 				error = 7;
11167 			}
11168 
11169 			if (error) {
11170 				int i;
11171 				fprintf(stderr, "UTF-8 encoding error (%d) for U+%x, D+%d : ", error, c, c);
11172 				for (i = 0; i < bytes; i++) {
11173 					fprintf(stderr, "0x%02x ", buf[i]);
11174 				}
11175 				fprintf(stderr, "\n");
11176 			} else {
11177 				int i;
11178 				for (i = 0; i < bytes; ++i) {
11179 					*b++ = buf[i];
11180 				}
11181 			}
11182 		}
11183 	}
11184 	*b = '\0';
11185 	return ((char *)result);
11186 }
11187 
11188 
11189 int
is_default_rule(struct rule * rule)11190 is_default_rule(struct rule *rule)
11191 {
11192 	if (strcmp(rule->name, "sv_maxspeed") == 0) {
11193 		return (strcmp(rule->value, Q_DEFAULT_SV_MAXSPEED) == 0);
11194 	}
11195 	if (strcmp(rule->name, "sv_friction") == 0) {
11196 		return (strcmp(rule->value, Q_DEFAULT_SV_FRICTION) == 0);
11197 	}
11198 	if (strcmp(rule->name, "sv_gravity") == 0) {
11199 		return (strcmp(rule->value, Q_DEFAULT_SV_GRAVITY) == 0);
11200 	}
11201 	if (strcmp(rule->name, "noexit") == 0) {
11202 		return (strcmp(rule->value, Q_DEFAULT_NOEXIT) == 0);
11203 	}
11204 	if (strcmp(rule->name, "teamplay") == 0) {
11205 		return (strcmp(rule->value, Q_DEFAULT_TEAMPLAY) == 0);
11206 	}
11207 	if (strcmp(rule->name, "timelimit") == 0) {
11208 		return (strcmp(rule->value, Q_DEFAULT_TIMELIMIT) == 0);
11209 	}
11210 	if (strcmp(rule->name, "fraglimit") == 0) {
11211 		return (strcmp(rule->value, Q_DEFAULT_FRAGLIMIT) == 0);
11212 	}
11213 	return (0);
11214 }
11215 
11216 
11217 char *
strherror(int h_err)11218 strherror(int h_err)
11219 {
11220 	static char msg[100];
11221 
11222 	switch (h_err) {
11223 	case HOST_NOT_FOUND:
11224 		return ("host not found");
11225 
11226 	case TRY_AGAIN:
11227 		return ("try again");
11228 
11229 	case NO_RECOVERY:
11230 		return ("no recovery");
11231 
11232 	case NO_ADDRESS:
11233 		return ("no address");
11234 
11235 	default:
11236 		sprintf(msg, "%d", h_err);
11237 		return (msg);
11238 	}
11239 }
11240 
11241 
11242 int
time_delta(struct timeval * later,struct timeval * past)11243 time_delta(struct timeval *later, struct timeval *past)
11244 {
11245 	if (later->tv_usec < past->tv_usec) {
11246 		later->tv_sec--;
11247 		later->tv_usec += 1000000;
11248 	}
11249 	return ((later->tv_sec - past->tv_sec) * 1000 + (later->tv_usec - past->tv_usec) / 1000);
11250 }
11251 
11252 
11253 int
connection_inprogress()11254 connection_inprogress()
11255 {
11256 #ifdef _WIN32
11257 		return (WSAGetLastError() == WSAEWOULDBLOCK);
11258 #else
11259 		return (errno == EINPROGRESS);
11260 #endif
11261 }
11262 
11263 
11264 int
connection_refused()11265 connection_refused()
11266 {
11267 #ifdef _WIN32
11268 		return (WSAGetLastError() == WSAECONNABORTED);
11269 #else
11270 		return (errno == ECONNREFUSED);
11271 #endif
11272 }
11273 
11274 
11275 int
connection_would_block()11276 connection_would_block()
11277 {
11278 #ifdef _WIN32
11279 		return (WSAGetLastError() == WSAEWOULDBLOCK);
11280 #else
11281 		return (errno == EAGAIN);
11282 #endif
11283 }
11284 
11285 
11286 int
connection_reset()11287 connection_reset()
11288 {
11289 #ifdef _WIN32
11290 		return (WSAGetLastError() == WSAECONNRESET);
11291 #else
11292 		return (errno == ECONNRESET);
11293 #endif
11294 }
11295 
11296 
11297 void
clear_socketerror()11298 clear_socketerror()
11299 {
11300 #ifdef _WIN32
11301 		WSASetLastError(0);
11302 #else
11303 		errno = 0;
11304 #endif
11305 }
11306 
11307 
11308 void
set_non_blocking(int fd)11309 set_non_blocking(int fd)
11310 {
11311 #ifdef _WIN32
11312 		int one = 1;
11313 		ioctlsocket(fd, FIONBIO, (unsigned long *)&one);
11314 #else
11315  #ifdef O_NONBLOCK
11316 			fcntl(fd, F_SETFL, O_NONBLOCK);
11317  #else
11318 			fcntl(fd, F_SETFL, O_NDELAY);
11319  #endif         // O_NONBLOCK
11320 #endif  // _WIN32
11321 }
11322 
11323 
11324 char *
quake_color(int color)11325 quake_color(int color)
11326 {
11327 	static char *colors[] =
11328 	{
11329 		"White",        /* 0 */
11330 		"Brown",        /* 1 */
11331 		"Lavender",     /* 2 */
11332 		"Khaki",        /* 3 */
11333 		"Red",          /* 4 */
11334 		"Lt Brown",     /* 5 */
11335 		"Peach",        /* 6 */
11336 		"Lt Peach",     /* 7 */
11337 		"Purple",       /* 8 */
11338 		"Dk Purple",    /* 9 */
11339 		"Tan",          /* 10 */
11340 		"Green",        /* 11 */
11341 		"Yellow",       /* 12 */
11342 		"Blue",         /* 13 */
11343 		"Blue",         /* 14 */
11344 		"Blue"          /* 15 */
11345 	};
11346 
11347 	static char *rgb_colors[] =
11348 	{
11349 		"#ffffff",      /* 0 */
11350 		"#8b4513",      /* 1 */
11351 		"#e6e6fa",      /* 2 */
11352 		"#f0e68c",      /* 3 */
11353 		"#ff0000",      /* 4 */
11354 		"#deb887",      /* 5 */
11355 		"#eecbad",      /* 6 */
11356 		"#ffdab9",      /* 7 */
11357 		"#9370db",      /* 8 */
11358 		"#5d478b",      /* 9 */
11359 		"#d2b48c",      /* 10 */
11360 		"#00ff00",      /* 11 */
11361 		"#ffff00",      /* 12 */
11362 		"#0000ff",      /* 13 */
11363 		"#0000ff",      /* 14 */
11364 		"#0000ff"       /* 15 */
11365 	};
11366 
11367 	static char *color_nr[] =
11368 	{
11369 		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"
11370 	};
11371 
11372 	if (color_names) {
11373 		if (color_names == 1) {
11374 			return (colors[color & 0xf]);
11375 		} else {
11376 			return (rgb_colors[color & 0xf]);
11377 		}
11378 	} else {
11379 		return (color_nr[color & 0xf]);
11380 	}
11381 }
11382 
11383 
11384 #define FMT_HOUR_1	"%2dh"
11385 #define FMT_HOUR_2	"%dh"
11386 #define FMT_MINUTE_1	"%2dm"
11387 #define FMT_MINUTE_2	"%dm"
11388 #define FMT_SECOND_1	"%2ds"
11389 #define FMT_SECOND_2	"%ds"
11390 
11391 char *
play_time(int seconds,int show_seconds)11392 play_time(int seconds, int show_seconds)
11393 {
11394 	static char time_string[24];
11395 
11396 	if (time_format == CLOCK_TIME) {
11397 		char *fmt_hour = show_seconds == 2 ? FMT_HOUR_2 : FMT_HOUR_1;
11398 		char *fmt_minute = show_seconds == 2 ? FMT_MINUTE_2 : FMT_MINUTE_1;
11399 		char *fmt_second = show_seconds == 2 ? FMT_SECOND_2 : FMT_SECOND_1;
11400 		time_string[0] = '\0';
11401 		if (seconds / 3600) {
11402 			sprintf(time_string, fmt_hour, seconds / 3600);
11403 		} else if (show_seconds < 2) {
11404 			strcat(time_string, "   ");
11405 		}
11406 		if ((seconds % 3600) / 60 || seconds / 3600) {
11407 			sprintf(time_string + strlen(time_string), fmt_minute, (seconds % 3600) / 60);
11408 		} else if (!show_seconds) {
11409 			sprintf(time_string + strlen(time_string), " 0m");
11410 		} else if (show_seconds < 2) {
11411 			strcat(time_string, "   ");
11412 		}
11413 		if (show_seconds) {
11414 			sprintf(time_string + strlen(time_string), fmt_second, seconds % 60);
11415 		}
11416 	} else if (time_format == STOPWATCH_TIME) {
11417 		if (show_seconds) {
11418 			sprintf(time_string, "%02d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, seconds % 60);
11419 		} else {
11420 			sprintf(time_string, "%02d:%02d", seconds / 3600, (seconds % 3600) / 60);
11421 		}
11422 	} else {
11423 		sprintf(time_string, "%d", seconds);
11424 	}
11425 
11426 	return (time_string);
11427 }
11428 
11429 
11430 char *
ping_time(int ms)11431 ping_time(int ms)
11432 {
11433 	static char time_string[24];
11434 
11435 	if (ms < 1000) {
11436 		sprintf(time_string, "%dms", ms);
11437 	} else if (ms < 1000000) {
11438 		sprintf(time_string, "%ds", ms / 1000);
11439 	} else {
11440 		sprintf(time_string, "%dm", ms / 1000 / 60);
11441 	}
11442 	return (time_string);
11443 }
11444 
11445 
11446 int
count_bits(int n)11447 count_bits(int n)
11448 {
11449 	int b = 0;
11450 
11451 	for ( ; n; n >>= 1) {
11452 		if (n & 1) {
11453 			b++;
11454 		}
11455 	}
11456 	return (b);
11457 }
11458 
11459 
11460 int
strcmp_withnull(char * one,char * two)11461 strcmp_withnull(char *one, char *two)
11462 {
11463 	if ((one == NULL) && (two == NULL)) {
11464 		return (0);
11465 	}
11466 	if ((one != NULL) && (two == NULL)) {
11467 		return (-1);
11468 	}
11469 	if (one == NULL) {
11470 		return (1);
11471 	}
11472 	return (strcasecmp(one, two));
11473 }
11474 
11475 
11476 /*
11477  * Sorting functions
11478  */
11479 void
sort_servers(struct qserver ** array,int size)11480 sort_servers(struct qserver **array, int size)
11481 {
11482 	quicksort((void **)array, 0, size - 1, (int (*)(void *, void *))server_compare);
11483 }
11484 
11485 
11486 void
sort_players(struct qserver * server)11487 sort_players(struct qserver *server)
11488 {
11489 	struct player **array, *player, *last_team = NULL, **next;
11490 	int np, i;
11491 
11492 	if ((server->num_players == 0) || (server->players == NULL)) {
11493 		return;
11494 	}
11495 
11496 	player = server->players;
11497 	for ( ; player != NULL && player->number == TRIBES_TEAM; ) {
11498 		last_team = player;
11499 		player = player->next;
11500 	}
11501 
11502 	if (player == NULL) {
11503 		return;
11504 	}
11505 
11506 	array = (struct player **)malloc(sizeof(struct player *) * (server->num_players + server->num_spectators));
11507 	for (np = 0; player != NULL && np < server->num_players + server->num_spectators; np++) {
11508 		array[np] = player;
11509 		player = player->next;
11510 	}
11511 	quicksort((void **)array, 0, np - 1, (int (*)(void *, void *))player_compare);
11512 
11513 	if (last_team) {
11514 		next = &last_team->next;
11515 	} else {
11516 		next = &server->players;
11517 	}
11518 
11519 	for (i = 0; i < np; i++) {
11520 		*next = array[i];
11521 		array[i]->next = NULL;
11522 		next = &array[i]->next;
11523 	}
11524 
11525 	free(array);
11526 }
11527 
11528 
11529 int
server_compare(struct qserver * one,struct qserver * two)11530 server_compare(struct qserver *one, struct qserver *two)
11531 {
11532 	int rc;
11533 
11534 	char *key = sort_keys;
11535 
11536 	for ( ; *key; key++) {
11537 		switch (*key) {
11538 		case 'g':
11539 			rc = strcmp_withnull(one->game, two->game);
11540 			if (rc) {
11541 				return (rc);
11542 			}
11543 			break;
11544 
11545 		case 'p':
11546 			if (one->n_requests == 0) {
11547 				return (two->n_requests);
11548 			} else if (two->n_requests == 0) {
11549 				return (-1);
11550 			}
11551 			rc = one->ping_total / one->n_requests - two->ping_total / two->n_requests;
11552 			if (rc) {
11553 				return (rc);
11554 			}
11555 			break;
11556 
11557 		case 'i':
11558 			if (one->ipaddr > two->ipaddr) {
11559 				return (1);
11560 			} else if (one->ipaddr < two->ipaddr) {
11561 				return (-1);
11562 			} else if (one->port > two->port) {
11563 				return (1);
11564 			} else if (one->port < two->port) {
11565 				return (-1);
11566 			}
11567 			break;
11568 
11569 		case 'h':
11570 			rc = strcmp_withnull(one->host_name, two->host_name);
11571 			if (rc) {
11572 				return (rc);
11573 			}
11574 			break;
11575 
11576 		case 'n':
11577 			rc = two->num_players - one->num_players;
11578 			if (rc) {
11579 				return (rc);
11580 			}
11581 			break;
11582 		}
11583 	}
11584 
11585 	return (0);
11586 }
11587 
11588 
11589 int
type_option_compare(server_type * one,server_type * two)11590 type_option_compare(server_type *one, server_type *two)
11591 {
11592 	return (strcmp_withnull(one->type_option, two->type_option));
11593 }
11594 
11595 
11596 int
type_string_compare(server_type * one,server_type * two)11597 type_string_compare(server_type *one, server_type *two)
11598 {
11599 	return (strcmp_withnull(one->type_string, two->type_string));
11600 }
11601 
11602 
11603 int
player_compare(struct player * one,struct player * two)11604 player_compare(struct player *one, struct player *two)
11605 {
11606 	int rc;
11607 
11608 	char *key = sort_keys;
11609 
11610 	for ( ; *key; key++) {
11611 		switch (*key) {
11612 		case 'P':
11613 			rc = one->ping - two->ping;
11614 			if (rc) {
11615 				return (rc);
11616 			}
11617 			break;
11618 
11619 		case 'F':
11620 			rc = two->frags - one->frags;
11621 			if (rc) {
11622 				return (rc);
11623 			}
11624 			break;
11625 
11626 		case 'S':
11627 			rc = two->score - one->score;
11628 			if (rc) {
11629 				return (rc);
11630 			}
11631 			break;
11632 
11633 		case 'T':
11634 			rc = one->team - two->team;
11635 			if (rc) {
11636 				return (rc);
11637 			}
11638 			rc = strcmp_withnull(one->team_name, two->team_name);
11639 			if (rc) {
11640 				return (rc);
11641 			}
11642 			break;
11643 
11644 		case 'N':
11645 			rc = strcmp_withnull(one->name, two->name);
11646 			if (rc) {
11647 				return (rc);
11648 			}
11649 			return (one->number - two->number);
11650 
11651 			break;
11652 		}
11653 	}
11654 	return (0);
11655 }
11656 
11657 
11658 void
quicksort(void ** array,int i,int j,int (* compare)(void *,void *))11659 quicksort(void **array, int i, int j, int (*compare)(void *, void *))
11660 {
11661 	int q = 0;
11662 
11663 	if (i < j) {
11664 		q = qpartition(array, i, j, compare);
11665 		quicksort(array, i, q, compare);
11666 		quicksort(array, q + 1, j, compare);
11667 	}
11668 }
11669 
11670 
11671 int
qpartition(void ** array,int a,int b,int (* compare)(void *,void *))11672 qpartition(void **array, int a, int b, int (*compare)(void *, void *))
11673 {
11674 	/* this is our comparison point. when we are done
11675 	 * splitting this array into 2 parts, we want all the
11676 	 * elements on the left side to be less then or equal
11677 	 * to this, all the elements on the right side need to
11678 	 * be greater then or equal to this
11679 	 */
11680 	void *z;
11681 
11682 	/* indicies into the array to sort. Used to calculate a partition
11683 	 * point
11684 	 */
11685 	int i = a - 1;
11686 	int j = b + 1;
11687 
11688 	/* temp pointer used to swap two array elements */
11689 	void *tmp = NULL;
11690 
11691 	z = array[a];
11692 
11693 	while (1) {
11694 		/* move the right indice over until the value of that array
11695 		 * elem is less than or equal to z. Stop if we hit the left
11696 		 * side of the array (ie, j == a);
11697 		 */
11698 		do {
11699 			j--;
11700 		} while (j > a && compare(array[j], z) > 0);
11701 
11702 		/* move the left indice over until the value of that
11703 		 * array elem is greater than or equal to z, or until
11704 		 * we hit the right side of the array (ie i == j)
11705 		 */
11706 		do {
11707 			i++;
11708 		} while (i <= j && compare(array[i], z) < 0);
11709 
11710 		/* if i is less then j, we need to switch those two array
11711 		 * elements, if not then we are done partitioning this array
11712 		 * section
11713 		 */
11714 		if (i < j) {
11715 			tmp = array[i];
11716 			array[i] = array[j];
11717 			array[j] = tmp;
11718 		} else {
11719 			return (j);
11720 		}
11721 	}
11722 }
11723