1 /*
2  * qstat
3  * by Steve Jankowski
4  *
5  * Teamspeak 2 query protocol
6  * Copyright 2005 Steven Hartland
7  *
8  * Licensed under the Artistic License, see LICENSE.txt for license terms
9  *
10  */
11 
12 #include <sys/types.h>
13 #ifndef _WIN32
14  #include <sys/socket.h>
15 #endif
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 
20 #include "debug.h"
21 #include "qstat.h"
22 #include "packet_manip.h"
23 
24 query_status_t
send_ts2_request_packet(struct qserver * server)25 send_ts2_request_packet(struct qserver *server)
26 {
27 	char buf[256];
28 
29 	int serverport = get_param_i_value(server, "port", 0);
30 
31 	change_server_port(server, serverport, 1);
32 
33 	if (get_player_info) {
34 		server->flags |= TF_PLAYER_QUERY | TF_RULES_QUERY;
35 		sprintf(buf, "si %d\npl %d\nquit\n", serverport, serverport);
36 		server->saved_data.pkt_index = 2;
37 	} else {
38 		server->flags |= TF_STATUS_QUERY;
39 		sprintf(buf, "si %d\nquit\n", serverport);
40 		server->saved_data.pkt_index = 1;
41 	}
42 
43 	return (send_packet(server, buf, strlen(buf)));
44 }
45 
46 
47 query_status_t
deal_with_ts2_packet(struct qserver * server,char * rawpkt,int pktlen)48 deal_with_ts2_packet(struct qserver *server, char *rawpkt, int pktlen)
49 {
50 	char *s;
51 	int ping, connect_time, mode = 0;
52 	char name[256];
53 
54 	debug(2, "processing...");
55 
56 	server->n_servers++;
57 	server->n_requests++;
58 	server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
59 
60 	if (0 == pktlen) {
61 		// Invalid password
62 		return (REQ_ERROR);
63 	}
64 
65 	rawpkt[pktlen] = '\0';
66 
67 	s = rawpkt;
68 	s = strtok(rawpkt, "\015\012");
69 
70 	while (NULL != s) {
71 		if (0 == mode) {
72 			// Rules
73 			char *key = s;
74 			char *value = strchr(key, '=');
75 			if (NULL != value) {
76 				// Server Rule
77 				*value = '\0';
78 				value++;
79 				if (0 == strcmp("server_name", key)) {
80 					server->server_name = strdup(value);
81 				} else if (0 == strcmp("server_udpport", key)) {
82 					change_server_port(server, atoi(value), 0);
83 					add_rule(server, key, value, NO_FLAGS);
84 				} else if (0 == strcmp("server_maxusers", key)) {
85 					server->max_players = atoi(value);
86 				} else if (0 == strcmp("server_currentusers", key)) {
87 					server->num_players = atoi(value);
88 				} else {
89 					add_rule(server, key, value, NO_FLAGS);
90 				}
91 			} else if (0 == strcmp("OK", s)) {
92 				// end of rules request
93 				server->saved_data.pkt_index--;
94 				mode++;
95 			} else if (0 == strcmp("[TS]", s)) {
96 				// nothing to do
97 			} else if (0 == strcmp("ERROR, invalid id", s)) {
98 				// bad server
99 				server->server_name = DOWN;
100 				server->saved_data.pkt_index = 0;
101 			}
102 		} else if (1 == mode) {
103 			// Player info
104 			if (3 == sscanf(s, "%*d %*d %*d %*d %*d %*d %*d %d %d %*d %*d %*d %*d \"0.0.0.0\" \"%255[^\"]", &ping, &connect_time, name)) {
105 				// Player info
106 				struct player *player = add_player(server, server->n_player_info);
107 				if (NULL != player) {
108 					player->name = strdup(name);
109 					player->ping = ping;
110 					player->connect_time = connect_time;
111 				}
112 			} else if (0 == strcmp("OK", s)) {
113 				// end of rules request
114 				server->saved_data.pkt_index--;
115 				mode++;
116 			} else if (0 == strcmp("[TS]", s)) {
117 				// nothing to do
118 			} else if (0 == strcmp("ERROR, invalid id", s)) {
119 				// bad server
120 				server->server_name = DOWN;
121 				server->saved_data.pkt_index = 0;
122 			}
123 		}
124 		s = strtok(NULL, "\015\012");
125 	}
126 
127 	gettimeofday(&server->packet_time1, NULL);
128 
129 	if (0 == server->saved_data.pkt_index) {
130 		server->map_name = strdup("N/A");
131 		return (DONE_FORCE);
132 	}
133 
134 	return (INPROGRESS);
135 }
136