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", ¶m->i_value);
2880 sscanf(equal, "%i", ¶m->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, ®ion_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