1 /*
2  * qstat
3  * by Steve Jankowski
4  *
5  * qserver functions
6  * Copyright 2004 Ludwig Nussel
7  *
8  * Licensed under the Artistic License, see LICENSE.txt for license terms
9  */
10 
11 #include "qstat.h"
12 #include "qserver.h"
13 #include "debug.h"
14 
15 #ifndef _WIN32
16  #include <sys/socket.h>
17  #include <netinet/in.h>
18 #endif
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/types.h>
24 
25 // TODO: get rid of this and use send_packet instead, remove n_requests hack from a2s
26 query_status_t
qserver_send_initial(struct qserver * server,const char * data,size_t len)27 qserver_send_initial(struct qserver *server, const char *data, size_t len)
28 {
29 	int status = INPROGRESS;
30 
31 	if (data) {
32 		int ret;
33 		debug(2, "[%s] send", server->type->type_prefix);
34 		if (4 <= get_debug_level()) {
35 			output_packet(server, data, len, 1);
36 		}
37 
38 		if (server->flags & FLAG_BROADCAST) {
39 			ret = send_broadcast(server, data, len);
40 		} else {
41 			ret = send(server->fd, data, len, 0);
42 		}
43 
44 		if (ret == SOCKET_ERROR) {
45 			send_error(server, ret);
46 			status = SYS_ERROR;
47 		}
48 	}
49 
50 	if ((server->retry1 == n_retries) || server->flags & FLAG_BROADCAST) {
51 		gettimeofday(&server->packet_time1, NULL);
52 	} else {
53 		server->n_retries++;
54 	}
55 
56 	server->retry1--;
57 	server->n_packets++;
58 
59 	return (status);
60 }
61 
62 
63 query_status_t
qserver_send(struct qserver * server,const char * data,size_t len)64 qserver_send(struct qserver *server, const char *data, size_t len)
65 {
66 	int status = INPROGRESS;
67 
68 	if (data) {
69 		int ret;
70 		if (server->flags & FLAG_BROADCAST) {
71 			ret = send_broadcast(server, data, len);
72 		} else {
73 			ret = send(server->fd, data, len, 0);
74 		}
75 
76 		if (ret == SOCKET_ERROR) {
77 			send_error(server, ret);
78 			status = SYS_ERROR;
79 		}
80 	}
81 
82 	server->retry1 = n_retries - 1;
83 	gettimeofday(&server->packet_time1, NULL);
84 	server->n_requests++;
85 	server->n_packets++;
86 
87 	return (status);
88 }
89 
90 
91 int
send_broadcast(struct qserver * server,const char * pkt,size_t pktlen)92 send_broadcast(struct qserver *server, const char *pkt, size_t pktlen)
93 {
94 	struct sockaddr_in addr;
95 
96 	addr.sin_family = AF_INET;
97 	if (no_port_offset || server->flags & TF_NO_PORT_OFFSET) {
98 		addr.sin_port = htons(server->port);
99 	} else {
100 		addr.sin_port = htons((unsigned short)(server->port + server->type->port_offset));
101 	}
102 	addr.sin_addr.s_addr = server->ipaddr;
103 	memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero));
104 
105 	return (sendto(server->fd, (const char *)pkt, pktlen, 0, (struct sockaddr *)&addr, sizeof(addr)));
106 }
107 
108 
109 int
register_send(struct qserver * server)110 register_send(struct qserver *server)
111 {
112 	if ((server->retry1 == n_retries) || server->flags & FLAG_BROADCAST) {
113 		server->n_requests++;
114 	} else {
115 		server->n_retries++;
116 	}
117 
118 	// New request so reset the sent time. This ensures
119 	// that we record an accurate ping time even on retry
120 	gettimeofday(&server->packet_time1, NULL);
121 	server->retry1--;
122 	server->n_packets++;
123 
124 	return (INPROGRESS);
125 }
126 
127 
128 query_status_t
send_packet(struct qserver * server,const char * data,size_t len)129 send_packet(struct qserver *server, const char *data, size_t len)
130 {
131 	debug(2, "[%s] send", server->type->type_prefix);
132 	if (4 <= get_debug_level()) {
133 		output_packet(server, data, len, 1);
134 	}
135 
136 	if (data) {
137 		int ret;
138 		if (server->flags & FLAG_BROADCAST) {
139 			ret = send_broadcast(server, data, len);
140 		} else {
141 			ret = send(server->fd, data, len, 0);
142 		}
143 
144 		if (ret == SOCKET_ERROR) {
145 			return (send_error(server, ret));
146 		}
147 	}
148 
149 	register_send(server);
150 
151 	return (INPROGRESS);
152 }
153 
154 
155 query_status_t
send_error(struct qserver * server,int rc)156 send_error(struct qserver *server, int rc)
157 {
158 	unsigned int ipaddr = ntohl(server->ipaddr);
159 	const char *errstr = strerror(errno);
160 
161 	fprintf(stderr, "Error on %d.%d.%d.%d: %s, skipping ...\n",
162 	    (ipaddr >> 24) & 0xff,
163 	    (ipaddr >> 16) & 0xff,
164 	    (ipaddr >> 8) & 0xff,
165 	    ipaddr & 0xff,
166 	    errstr
167 	    );
168 	return (SYS_ERROR);
169 }
170