1*00b67f09SDavid van Moolenbroek /* $NetBSD: queryperf.c,v 1.6 2014/12/10 04:37:56 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2000, 2001 Nominum, Inc.
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek *
10*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
11*00b67f09SDavid van Moolenbroek * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
12*00b67f09SDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
13*00b67f09SDavid van Moolenbroek * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
15*00b67f09SDavid van Moolenbroek * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
16*00b67f09SDavid van Moolenbroek * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
17*00b67f09SDavid van Moolenbroek * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /***
21*00b67f09SDavid van Moolenbroek *** DNS Query Performance Testing Tool (queryperf.c)
22*00b67f09SDavid van Moolenbroek ***
23*00b67f09SDavid van Moolenbroek *** Version Id: queryperf.c,v 1.12 2007/09/05 07:36:04 marka Exp
24*00b67f09SDavid van Moolenbroek ***
25*00b67f09SDavid van Moolenbroek *** Stephen Jacob <sj@nominum.com>
26*00b67f09SDavid van Moolenbroek ***/
27*00b67f09SDavid van Moolenbroek
28*00b67f09SDavid van Moolenbroek #define BIND_8_COMPAT /* Pull in <arpa/nameser_compat.h> */
29*00b67f09SDavid van Moolenbroek
30*00b67f09SDavid van Moolenbroek #include <sys/time.h>
31*00b67f09SDavid van Moolenbroek #include <sys/types.h>
32*00b67f09SDavid van Moolenbroek #include <sys/socket.h>
33*00b67f09SDavid van Moolenbroek #include <stdio.h>
34*00b67f09SDavid van Moolenbroek #include <stdlib.h>
35*00b67f09SDavid van Moolenbroek #include <string.h>
36*00b67f09SDavid van Moolenbroek #include <limits.h>
37*00b67f09SDavid van Moolenbroek #include <time.h>
38*00b67f09SDavid van Moolenbroek #include <unistd.h>
39*00b67f09SDavid van Moolenbroek #include <netdb.h>
40*00b67f09SDavid van Moolenbroek #include <netinet/in.h>
41*00b67f09SDavid van Moolenbroek #include <arpa/nameser.h>
42*00b67f09SDavid van Moolenbroek #include <resolv.h>
43*00b67f09SDavid van Moolenbroek #include <math.h>
44*00b67f09SDavid van Moolenbroek #include <errno.h>
45*00b67f09SDavid van Moolenbroek
46*00b67f09SDavid van Moolenbroek #ifdef HAVE_CONFIG_H
47*00b67f09SDavid van Moolenbroek #include "config.h"
48*00b67f09SDavid van Moolenbroek #ifndef HAVE_GETADDRINFO
49*00b67f09SDavid van Moolenbroek #include "missing/addrinfo.h"
50*00b67f09SDavid van Moolenbroek #endif
51*00b67f09SDavid van Moolenbroek #endif
52*00b67f09SDavid van Moolenbroek
53*00b67f09SDavid van Moolenbroek /*
54*00b67f09SDavid van Moolenbroek * Configuration defaults
55*00b67f09SDavid van Moolenbroek */
56*00b67f09SDavid van Moolenbroek
57*00b67f09SDavid van Moolenbroek #define DEF_MAX_QUERIES_OUTSTANDING 20
58*00b67f09SDavid van Moolenbroek #define DEF_QUERY_TIMEOUT 5 /* in seconds */
59*00b67f09SDavid van Moolenbroek #define DEF_SERVER_TO_QUERY "127.0.0.1"
60*00b67f09SDavid van Moolenbroek #define DEF_SERVER_PORT "53"
61*00b67f09SDavid van Moolenbroek #define DEF_BUFFER_SIZE 32 /* in k */
62*00b67f09SDavid van Moolenbroek
63*00b67f09SDavid van Moolenbroek #define DEF_RTTARRAY_SIZE 50000
64*00b67f09SDavid van Moolenbroek #define DEF_RTTARRAY_UNIT 100 /* in usec */
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek /*
67*00b67f09SDavid van Moolenbroek * Other constants / definitions
68*00b67f09SDavid van Moolenbroek */
69*00b67f09SDavid van Moolenbroek
70*00b67f09SDavid van Moolenbroek #define COMMENT_CHAR ';'
71*00b67f09SDavid van Moolenbroek #define CONFIG_CHAR '#'
72*00b67f09SDavid van Moolenbroek #define MAX_PORT 65535
73*00b67f09SDavid van Moolenbroek #define MAX_INPUT_LEN 512
74*00b67f09SDavid van Moolenbroek #define MAX_DOMAIN_LEN 255
75*00b67f09SDavid van Moolenbroek #define MAX_BUFFER_LEN 8192 /* in bytes */
76*00b67f09SDavid van Moolenbroek #define HARD_TIMEOUT_EXTRA 5 /* in seconds */
77*00b67f09SDavid van Moolenbroek #define RESPONSE_BLOCKING_WAIT_TIME 0.1 /* in seconds */
78*00b67f09SDavid van Moolenbroek #define EDNSLEN 11
79*00b67f09SDavid van Moolenbroek #define DNS_HEADERLEN 12
80*00b67f09SDavid van Moolenbroek
81*00b67f09SDavid van Moolenbroek #define FALSE 0
82*00b67f09SDavid van Moolenbroek #define TRUE 1
83*00b67f09SDavid van Moolenbroek
84*00b67f09SDavid van Moolenbroek #define WHITESPACE " \t\n"
85*00b67f09SDavid van Moolenbroek
86*00b67f09SDavid van Moolenbroek enum directives_enum { V_SERVER, V_PORT, V_MAXQUERIES, V_MAXWAIT };
87*00b67f09SDavid van Moolenbroek #define DIRECTIVES { "server", "port", "maxqueries", "maxwait" }
88*00b67f09SDavid van Moolenbroek #define DIR_VALUES { V_SERVER, V_PORT, V_MAXQUERIES, V_MAXWAIT }
89*00b67f09SDavid van Moolenbroek
90*00b67f09SDavid van Moolenbroek #define QTYPE_STRINGS { \
91*00b67f09SDavid van Moolenbroek "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", \
92*00b67f09SDavid van Moolenbroek "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", \
93*00b67f09SDavid van Moolenbroek "AFSDB", "X25", "ISDN", "RT", "NSAP", "NSAP-PTR", "SIG", \
94*00b67f09SDavid van Moolenbroek "KEY", "PX", "GPOS", "AAAA", "LOC", "NXT", "EID", "NIMLOC", \
95*00b67f09SDavid van Moolenbroek "SRV", "ATMA", "NAPTR", "KX", "CERT", "A6", "DNAME", "SINK", \
96*00b67f09SDavid van Moolenbroek "OPT", "APL", "DS", "SSHFP", "IPSECKEY", "RRSIG", "NSEC", \
97*00b67f09SDavid van Moolenbroek "DNSKEY", "DHCID", "NSEC3", "NSEC3PARAM", "TLSA", "HIP", \
98*00b67f09SDavid van Moolenbroek "NINFO", "RKEY", "TALINK", "CDS", "SPF", "UINFO", "UID", \
99*00b67f09SDavid van Moolenbroek "GID", "UNSPEC", "NID", "L32", "L64", "LP", "TKEY", "TSIG", \
100*00b67f09SDavid van Moolenbroek "IXFR", "AXFR", "MAILB", "MAILA", "URI", "CAA", "*", "ANY", \
101*00b67f09SDavid van Moolenbroek "TA", "DLV" \
102*00b67f09SDavid van Moolenbroek }
103*00b67f09SDavid van Moolenbroek
104*00b67f09SDavid van Moolenbroek #define QTYPE_CODES { \
105*00b67f09SDavid van Moolenbroek 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, \
106*00b67f09SDavid van Moolenbroek 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, \
107*00b67f09SDavid van Moolenbroek 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, \
108*00b67f09SDavid van Moolenbroek 49, 50, 51, 52, 55, 56, 57, 58, 59, 99, 100, 101, 102, 103, \
109*00b67f09SDavid van Moolenbroek 104, 105, 106, 107, 249, 250, 251, 252, 253, 254, 255, 255, \
110*00b67f09SDavid van Moolenbroek 256, 257, 32768, 32769 \
111*00b67f09SDavid van Moolenbroek }
112*00b67f09SDavid van Moolenbroek
113*00b67f09SDavid van Moolenbroek #define RCODE_STRINGS { \
114*00b67f09SDavid van Moolenbroek "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", \
115*00b67f09SDavid van Moolenbroek "NOTIMP", "REFUSED", "YXDOMAIN", "YXRRSET", \
116*00b67f09SDavid van Moolenbroek "NXRRSET", "NOTAUTH", "NOTZONE", "rcode11", \
117*00b67f09SDavid van Moolenbroek "rcode12", "rcode13", "rcode14", "rcode15" \
118*00b67f09SDavid van Moolenbroek }
119*00b67f09SDavid van Moolenbroek
120*00b67f09SDavid van Moolenbroek /*
121*00b67f09SDavid van Moolenbroek * Data type definitions
122*00b67f09SDavid van Moolenbroek */
123*00b67f09SDavid van Moolenbroek
124*00b67f09SDavid van Moolenbroek #define QUERY_STATUS_MAGIC 0x51535441U /* QSTA */
125*00b67f09SDavid van Moolenbroek #define VALID_QUERY_STATUS(q) ((q) != NULL && \
126*00b67f09SDavid van Moolenbroek (q)->magic == QUERY_STATUS_MAGIC)
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek struct query_status {
129*00b67f09SDavid van Moolenbroek unsigned int magic;
130*00b67f09SDavid van Moolenbroek int in_use;
131*00b67f09SDavid van Moolenbroek unsigned short int id;
132*00b67f09SDavid van Moolenbroek struct timeval sent_timestamp;
133*00b67f09SDavid van Moolenbroek char *desc;
134*00b67f09SDavid van Moolenbroek int qtype;
135*00b67f09SDavid van Moolenbroek char qname[MAX_DOMAIN_LEN + 1];
136*00b67f09SDavid van Moolenbroek };
137*00b67f09SDavid van Moolenbroek
138*00b67f09SDavid van Moolenbroek struct query_mininfo { /* minimum info for timeout queries */
139*00b67f09SDavid van Moolenbroek int qtype; /* use -1 if N/A */
140*00b67f09SDavid van Moolenbroek struct timeval sent_timestamp;
141*00b67f09SDavid van Moolenbroek char qname[MAX_DOMAIN_LEN + 1];
142*00b67f09SDavid van Moolenbroek };
143*00b67f09SDavid van Moolenbroek
144*00b67f09SDavid van Moolenbroek /*
145*00b67f09SDavid van Moolenbroek * Forward declarations.
146*00b67f09SDavid van Moolenbroek */
147*00b67f09SDavid van Moolenbroek int is_uint(char *test_int, unsigned int *result);
148*00b67f09SDavid van Moolenbroek
149*00b67f09SDavid van Moolenbroek /*
150*00b67f09SDavid van Moolenbroek * Configuration options (global)
151*00b67f09SDavid van Moolenbroek */
152*00b67f09SDavid van Moolenbroek
153*00b67f09SDavid van Moolenbroek unsigned int max_queries_outstanding; /* init 0 */
154*00b67f09SDavid van Moolenbroek unsigned int query_timeout = DEF_QUERY_TIMEOUT;
155*00b67f09SDavid van Moolenbroek int ignore_config_changes = FALSE;
156*00b67f09SDavid van Moolenbroek unsigned int socket_bufsize = DEF_BUFFER_SIZE;
157*00b67f09SDavid van Moolenbroek
158*00b67f09SDavid van Moolenbroek int family = AF_UNSPEC;
159*00b67f09SDavid van Moolenbroek int use_stdin = TRUE;
160*00b67f09SDavid van Moolenbroek char *datafile_name; /* init NULL */
161*00b67f09SDavid van Moolenbroek
162*00b67f09SDavid van Moolenbroek char *server_to_query; /* init NULL */
163*00b67f09SDavid van Moolenbroek char *server_port; /* init NULL */
164*00b67f09SDavid van Moolenbroek struct addrinfo *server_ai; /* init NULL */
165*00b67f09SDavid van Moolenbroek
166*00b67f09SDavid van Moolenbroek int run_only_once = FALSE;
167*00b67f09SDavid van Moolenbroek int use_timelimit = FALSE;
168*00b67f09SDavid van Moolenbroek unsigned int run_timelimit; /* init 0 */
169*00b67f09SDavid van Moolenbroek unsigned int print_interval; /* init 0 */
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek unsigned int target_qps; /* init 0 */
172*00b67f09SDavid van Moolenbroek
173*00b67f09SDavid van Moolenbroek int serverset = FALSE, portset = FALSE;
174*00b67f09SDavid van Moolenbroek int queriesset = FALSE, timeoutset = FALSE;
175*00b67f09SDavid van Moolenbroek int edns = FALSE, dnssec = FALSE;
176*00b67f09SDavid van Moolenbroek int countrcodes = FALSE;
177*00b67f09SDavid van Moolenbroek int rcodecounts[16] = {0};
178*00b67f09SDavid van Moolenbroek
179*00b67f09SDavid van Moolenbroek int verbose = FALSE;
180*00b67f09SDavid van Moolenbroek int recurse = 1;
181*00b67f09SDavid van Moolenbroek
182*00b67f09SDavid van Moolenbroek /*
183*00b67f09SDavid van Moolenbroek * Other global stuff
184*00b67f09SDavid van Moolenbroek */
185*00b67f09SDavid van Moolenbroek
186*00b67f09SDavid van Moolenbroek int setup_phase = TRUE;
187*00b67f09SDavid van Moolenbroek
188*00b67f09SDavid van Moolenbroek FILE *datafile_ptr; /* init NULL */
189*00b67f09SDavid van Moolenbroek unsigned int runs_through_file; /* init 0 */
190*00b67f09SDavid van Moolenbroek
191*00b67f09SDavid van Moolenbroek unsigned int num_queries_sent; /* init 0 */
192*00b67f09SDavid van Moolenbroek unsigned int num_queries_sent_interval;
193*00b67f09SDavid van Moolenbroek unsigned int num_queries_outstanding; /* init 0 */
194*00b67f09SDavid van Moolenbroek unsigned int num_queries_timed_out; /* init 0 */
195*00b67f09SDavid van Moolenbroek unsigned int num_queries_possiblydelayed; /* init 0 */
196*00b67f09SDavid van Moolenbroek unsigned int num_queries_timed_out_interval;
197*00b67f09SDavid van Moolenbroek unsigned int num_queries_possiblydelayed_interval;
198*00b67f09SDavid van Moolenbroek
199*00b67f09SDavid van Moolenbroek struct timeval time_of_program_start;
200*00b67f09SDavid van Moolenbroek struct timeval time_of_first_query;
201*00b67f09SDavid van Moolenbroek double time_of_first_query_sec;
202*00b67f09SDavid van Moolenbroek struct timeval time_of_first_query_interval;
203*00b67f09SDavid van Moolenbroek struct timeval time_of_end_of_run;
204*00b67f09SDavid van Moolenbroek struct timeval time_of_stop_sending;
205*00b67f09SDavid van Moolenbroek
206*00b67f09SDavid van Moolenbroek struct timeval time_of_queryset_start;
207*00b67f09SDavid van Moolenbroek double query_interval;
208*00b67f09SDavid van Moolenbroek struct timeval time_of_next_queryset;
209*00b67f09SDavid van Moolenbroek
210*00b67f09SDavid van Moolenbroek double rtt_max = -1;
211*00b67f09SDavid van Moolenbroek double rtt_max_interval = -1;
212*00b67f09SDavid van Moolenbroek double rtt_min = -1;
213*00b67f09SDavid van Moolenbroek double rtt_min_interval = -1;
214*00b67f09SDavid van Moolenbroek double rtt_total;
215*00b67f09SDavid van Moolenbroek double rtt_total_interval;
216*00b67f09SDavid van Moolenbroek int rttarray_size = DEF_RTTARRAY_SIZE;
217*00b67f09SDavid van Moolenbroek int rttarray_unit = DEF_RTTARRAY_UNIT;
218*00b67f09SDavid van Moolenbroek unsigned int *rttarray = NULL;
219*00b67f09SDavid van Moolenbroek unsigned int *rttarray_interval = NULL;
220*00b67f09SDavid van Moolenbroek unsigned int rtt_overflows;
221*00b67f09SDavid van Moolenbroek unsigned int rtt_overflows_interval;
222*00b67f09SDavid van Moolenbroek unsigned int rtt_counted;
223*00b67f09SDavid van Moolenbroek unsigned int rtt_counted_interval;
224*00b67f09SDavid van Moolenbroek char *rtt_histogram_file = NULL;
225*00b67f09SDavid van Moolenbroek
226*00b67f09SDavid van Moolenbroek struct query_status *status; /* init NULL */
227*00b67f09SDavid van Moolenbroek unsigned int query_status_allocated; /* init 0 */
228*00b67f09SDavid van Moolenbroek
229*00b67f09SDavid van Moolenbroek int query_socket = -1;
230*00b67f09SDavid van Moolenbroek int socket4 = -1, socket6 = -1;
231*00b67f09SDavid van Moolenbroek
232*00b67f09SDavid van Moolenbroek static char *rcode_strings[] = RCODE_STRINGS;
233*00b67f09SDavid van Moolenbroek
234*00b67f09SDavid van Moolenbroek static struct query_mininfo *timeout_queries;
235*00b67f09SDavid van Moolenbroek
236*00b67f09SDavid van Moolenbroek /*
237*00b67f09SDavid van Moolenbroek * get_uint16:
238*00b67f09SDavid van Moolenbroek * Get an unsigned short integer from a buffer (in network order)
239*00b67f09SDavid van Moolenbroek */
240*00b67f09SDavid van Moolenbroek static unsigned short
get_uint16(unsigned char * buf)241*00b67f09SDavid van Moolenbroek get_uint16(unsigned char *buf) {
242*00b67f09SDavid van Moolenbroek unsigned short ret;
243*00b67f09SDavid van Moolenbroek
244*00b67f09SDavid van Moolenbroek ret = buf[0] * 256 + buf[1];
245*00b67f09SDavid van Moolenbroek
246*00b67f09SDavid van Moolenbroek return (ret);
247*00b67f09SDavid van Moolenbroek }
248*00b67f09SDavid van Moolenbroek
249*00b67f09SDavid van Moolenbroek /*
250*00b67f09SDavid van Moolenbroek * show_startup_info:
251*00b67f09SDavid van Moolenbroek * Show name/version
252*00b67f09SDavid van Moolenbroek */
253*00b67f09SDavid van Moolenbroek void
show_startup_info(void)254*00b67f09SDavid van Moolenbroek show_startup_info(void) {
255*00b67f09SDavid van Moolenbroek printf("\n"
256*00b67f09SDavid van Moolenbroek "DNS Query Performance Testing Tool\n"
257*00b67f09SDavid van Moolenbroek "Version: Id: queryperf.c,v 1.12 2007/09/05 07:36:04 marka Exp \n"
258*00b67f09SDavid van Moolenbroek "\n");
259*00b67f09SDavid van Moolenbroek }
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek /*
262*00b67f09SDavid van Moolenbroek * show_usage:
263*00b67f09SDavid van Moolenbroek * Print out usage/syntax information
264*00b67f09SDavid van Moolenbroek */
265*00b67f09SDavid van Moolenbroek void
show_usage(void)266*00b67f09SDavid van Moolenbroek show_usage(void) {
267*00b67f09SDavid van Moolenbroek fprintf(stderr,
268*00b67f09SDavid van Moolenbroek "\n"
269*00b67f09SDavid van Moolenbroek "Usage: queryperf [-d datafile] [-s server_addr] [-p port] [-q num_queries]\n"
270*00b67f09SDavid van Moolenbroek " [-b bufsize] [-t timeout] [-n] [-l limit] [-f family] [-1]\n"
271*00b67f09SDavid van Moolenbroek " [-i interval] [-r arraysize] [-u unit] [-H histfile]\n"
272*00b67f09SDavid van Moolenbroek " [-T qps] [-e] [-D] [-R] [-c] [-v] [-h]\n"
273*00b67f09SDavid van Moolenbroek " -d specifies the input data file (default: stdin)\n"
274*00b67f09SDavid van Moolenbroek " -s sets the server to query (default: %s)\n"
275*00b67f09SDavid van Moolenbroek " -p sets the port on which to query the server (default: %s)\n"
276*00b67f09SDavid van Moolenbroek " -q specifies the maximum number of queries outstanding (default: %d)\n"
277*00b67f09SDavid van Moolenbroek " -t specifies the timeout for query completion in seconds (default: %d)\n"
278*00b67f09SDavid van Moolenbroek " -n causes configuration changes to be ignored\n"
279*00b67f09SDavid van Moolenbroek " -l specifies how a limit for how long to run tests in seconds (no default)\n"
280*00b67f09SDavid van Moolenbroek " -1 run through input only once (default: multiple iff limit given)\n"
281*00b67f09SDavid van Moolenbroek " -b set input/output buffer size in kilobytes (default: %d k)\n"
282*00b67f09SDavid van Moolenbroek " -i specifies interval of intermediate outputs in seconds (default: 0=none)\n"
283*00b67f09SDavid van Moolenbroek " -f specify address family of DNS transport, inet or inet6 (default: any)\n"
284*00b67f09SDavid van Moolenbroek " -r set RTT statistics array size (default: %d)\n"
285*00b67f09SDavid van Moolenbroek " -u set RTT statistics time unit in usec (default: %d)\n"
286*00b67f09SDavid van Moolenbroek " -H specifies RTT histogram data file (default: none)\n"
287*00b67f09SDavid van Moolenbroek " -T specify the target qps (default: 0=unspecified)\n"
288*00b67f09SDavid van Moolenbroek " -e enable EDNS 0\n"
289*00b67f09SDavid van Moolenbroek " -D set the DNSSEC OK bit (implies EDNS)\n"
290*00b67f09SDavid van Moolenbroek " -R disable recursion\n"
291*00b67f09SDavid van Moolenbroek " -c print the number of packets with each rcode\n"
292*00b67f09SDavid van Moolenbroek " -v verbose: report the RCODE of each response on stdout\n"
293*00b67f09SDavid van Moolenbroek " -h print this usage\n"
294*00b67f09SDavid van Moolenbroek "\n",
295*00b67f09SDavid van Moolenbroek DEF_SERVER_TO_QUERY, DEF_SERVER_PORT,
296*00b67f09SDavid van Moolenbroek DEF_MAX_QUERIES_OUTSTANDING, DEF_QUERY_TIMEOUT,
297*00b67f09SDavid van Moolenbroek DEF_BUFFER_SIZE, DEF_RTTARRAY_SIZE, DEF_RTTARRAY_UNIT);
298*00b67f09SDavid van Moolenbroek }
299*00b67f09SDavid van Moolenbroek
300*00b67f09SDavid van Moolenbroek /*
301*00b67f09SDavid van Moolenbroek * set_datafile:
302*00b67f09SDavid van Moolenbroek * Set the datafile to read
303*00b67f09SDavid van Moolenbroek *
304*00b67f09SDavid van Moolenbroek * Return -1 on failure
305*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
306*00b67f09SDavid van Moolenbroek */
307*00b67f09SDavid van Moolenbroek int
set_datafile(char * new_file)308*00b67f09SDavid van Moolenbroek set_datafile(char *new_file) {
309*00b67f09SDavid van Moolenbroek char *dfname_tmp;
310*00b67f09SDavid van Moolenbroek
311*00b67f09SDavid van Moolenbroek if ((new_file == NULL) || (new_file[0] == '\0')) {
312*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: null datafile name\n");
313*00b67f09SDavid van Moolenbroek return (-1);
314*00b67f09SDavid van Moolenbroek }
315*00b67f09SDavid van Moolenbroek
316*00b67f09SDavid van Moolenbroek if ((dfname_tmp = malloc(strlen(new_file) + 1)) == NULL) {
317*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error allocating memory for datafile name: "
318*00b67f09SDavid van Moolenbroek "%s\n", new_file);
319*00b67f09SDavid van Moolenbroek return (-1);
320*00b67f09SDavid van Moolenbroek }
321*00b67f09SDavid van Moolenbroek
322*00b67f09SDavid van Moolenbroek free(datafile_name);
323*00b67f09SDavid van Moolenbroek datafile_name = dfname_tmp;
324*00b67f09SDavid van Moolenbroek
325*00b67f09SDavid van Moolenbroek strcpy(datafile_name, new_file);
326*00b67f09SDavid van Moolenbroek use_stdin = FALSE;
327*00b67f09SDavid van Moolenbroek
328*00b67f09SDavid van Moolenbroek return (0);
329*00b67f09SDavid van Moolenbroek }
330*00b67f09SDavid van Moolenbroek
331*00b67f09SDavid van Moolenbroek /*
332*00b67f09SDavid van Moolenbroek * set_input_stdin:
333*00b67f09SDavid van Moolenbroek * Set the input to be stdin (instead of a datafile)
334*00b67f09SDavid van Moolenbroek */
335*00b67f09SDavid van Moolenbroek void
set_input_stdin(void)336*00b67f09SDavid van Moolenbroek set_input_stdin(void) {
337*00b67f09SDavid van Moolenbroek use_stdin = TRUE;
338*00b67f09SDavid van Moolenbroek free(datafile_name);
339*00b67f09SDavid van Moolenbroek datafile_name = NULL;
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek
342*00b67f09SDavid van Moolenbroek /*
343*00b67f09SDavid van Moolenbroek * set_server:
344*00b67f09SDavid van Moolenbroek * Set the server to be queried
345*00b67f09SDavid van Moolenbroek *
346*00b67f09SDavid van Moolenbroek * Return -1 on failure
347*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
348*00b67f09SDavid van Moolenbroek */
349*00b67f09SDavid van Moolenbroek int
set_server(char * new_name)350*00b67f09SDavid van Moolenbroek set_server(char *new_name) {
351*00b67f09SDavid van Moolenbroek static struct hostent *server_he;
352*00b67f09SDavid van Moolenbroek
353*00b67f09SDavid van Moolenbroek /* If no change in server name, don't do anything... */
354*00b67f09SDavid van Moolenbroek if ((server_to_query != NULL) && (new_name != NULL))
355*00b67f09SDavid van Moolenbroek if (strcmp(new_name, server_to_query) == 0)
356*00b67f09SDavid van Moolenbroek return (0);
357*00b67f09SDavid van Moolenbroek
358*00b67f09SDavid van Moolenbroek if ((new_name == NULL) || (new_name[0] == '\0')) {
359*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: null server name\n");
360*00b67f09SDavid van Moolenbroek return (-1);
361*00b67f09SDavid van Moolenbroek }
362*00b67f09SDavid van Moolenbroek
363*00b67f09SDavid van Moolenbroek free(server_to_query);
364*00b67f09SDavid van Moolenbroek server_to_query = NULL;
365*00b67f09SDavid van Moolenbroek
366*00b67f09SDavid van Moolenbroek if ((server_to_query = malloc(strlen(new_name) + 1)) == NULL) {
367*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error allocating memory for server name: "
368*00b67f09SDavid van Moolenbroek "%s\n", new_name);
369*00b67f09SDavid van Moolenbroek return (-1);
370*00b67f09SDavid van Moolenbroek }
371*00b67f09SDavid van Moolenbroek
372*00b67f09SDavid van Moolenbroek strcpy(server_to_query, new_name);
373*00b67f09SDavid van Moolenbroek
374*00b67f09SDavid van Moolenbroek return (0);
375*00b67f09SDavid van Moolenbroek }
376*00b67f09SDavid van Moolenbroek
377*00b67f09SDavid van Moolenbroek /*
378*00b67f09SDavid van Moolenbroek * set_server_port:
379*00b67f09SDavid van Moolenbroek * Set the port on which to contact the server
380*00b67f09SDavid van Moolenbroek *
381*00b67f09SDavid van Moolenbroek * Return -1 if port is invalid
382*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
383*00b67f09SDavid van Moolenbroek */
384*00b67f09SDavid van Moolenbroek int
set_server_port(char * new_port)385*00b67f09SDavid van Moolenbroek set_server_port(char *new_port) {
386*00b67f09SDavid van Moolenbroek unsigned int uint_val;
387*00b67f09SDavid van Moolenbroek
388*00b67f09SDavid van Moolenbroek if ((is_uint(new_port, &uint_val)) != TRUE)
389*00b67f09SDavid van Moolenbroek return (-1);
390*00b67f09SDavid van Moolenbroek
391*00b67f09SDavid van Moolenbroek if (uint_val && uint_val > MAX_PORT)
392*00b67f09SDavid van Moolenbroek return (-1);
393*00b67f09SDavid van Moolenbroek else {
394*00b67f09SDavid van Moolenbroek if (server_port != NULL && new_port != NULL &&
395*00b67f09SDavid van Moolenbroek strcmp(server_port, new_port) == 0)
396*00b67f09SDavid van Moolenbroek return (0);
397*00b67f09SDavid van Moolenbroek
398*00b67f09SDavid van Moolenbroek free(server_port);
399*00b67f09SDavid van Moolenbroek server_port = NULL;
400*00b67f09SDavid van Moolenbroek
401*00b67f09SDavid van Moolenbroek if ((server_port = malloc(strlen(new_port) + 1)) == NULL) {
402*00b67f09SDavid van Moolenbroek fprintf(stderr,
403*00b67f09SDavid van Moolenbroek "Error allocating memory for server port: "
404*00b67f09SDavid van Moolenbroek "%s\n", new_port);
405*00b67f09SDavid van Moolenbroek return (-1);
406*00b67f09SDavid van Moolenbroek }
407*00b67f09SDavid van Moolenbroek
408*00b67f09SDavid van Moolenbroek strcpy(server_port, new_port);
409*00b67f09SDavid van Moolenbroek
410*00b67f09SDavid van Moolenbroek return (0);
411*00b67f09SDavid van Moolenbroek }
412*00b67f09SDavid van Moolenbroek }
413*00b67f09SDavid van Moolenbroek
414*00b67f09SDavid van Moolenbroek int
set_server_sa(void)415*00b67f09SDavid van Moolenbroek set_server_sa(void) {
416*00b67f09SDavid van Moolenbroek struct addrinfo hints, *res;
417*00b67f09SDavid van Moolenbroek static struct protoent *proto;
418*00b67f09SDavid van Moolenbroek int error;
419*00b67f09SDavid van Moolenbroek
420*00b67f09SDavid van Moolenbroek if (proto == NULL && (proto = getprotobyname("udp")) == NULL) {
421*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: getprotobyname call failed");
422*00b67f09SDavid van Moolenbroek return (-1);
423*00b67f09SDavid van Moolenbroek }
424*00b67f09SDavid van Moolenbroek
425*00b67f09SDavid van Moolenbroek memset(&hints, 0, sizeof(hints));
426*00b67f09SDavid van Moolenbroek hints.ai_family = family;
427*00b67f09SDavid van Moolenbroek hints.ai_socktype = SOCK_DGRAM;
428*00b67f09SDavid van Moolenbroek hints.ai_protocol = proto->p_proto;
429*00b67f09SDavid van Moolenbroek if ((error = getaddrinfo(server_to_query, server_port,
430*00b67f09SDavid van Moolenbroek &hints, &res)) != 0) {
431*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: getaddrinfo(%s, %s) failed\n",
432*00b67f09SDavid van Moolenbroek server_to_query, server_port);
433*00b67f09SDavid van Moolenbroek return (-1);
434*00b67f09SDavid van Moolenbroek }
435*00b67f09SDavid van Moolenbroek
436*00b67f09SDavid van Moolenbroek /* replace the server's addrinfo */
437*00b67f09SDavid van Moolenbroek if (server_ai != NULL)
438*00b67f09SDavid van Moolenbroek freeaddrinfo(server_ai);
439*00b67f09SDavid van Moolenbroek server_ai = res;
440*00b67f09SDavid van Moolenbroek return (0);
441*00b67f09SDavid van Moolenbroek }
442*00b67f09SDavid van Moolenbroek
443*00b67f09SDavid van Moolenbroek /*
444*00b67f09SDavid van Moolenbroek * is_digit:
445*00b67f09SDavid van Moolenbroek * Tests if a character is a digit
446*00b67f09SDavid van Moolenbroek *
447*00b67f09SDavid van Moolenbroek * Return TRUE if it is
448*00b67f09SDavid van Moolenbroek * Return FALSE if it is not
449*00b67f09SDavid van Moolenbroek */
450*00b67f09SDavid van Moolenbroek int
is_digit(char d)451*00b67f09SDavid van Moolenbroek is_digit(char d) {
452*00b67f09SDavid van Moolenbroek if (d < '0' || d > '9')
453*00b67f09SDavid van Moolenbroek return (FALSE);
454*00b67f09SDavid van Moolenbroek else
455*00b67f09SDavid van Moolenbroek return (TRUE);
456*00b67f09SDavid van Moolenbroek }
457*00b67f09SDavid van Moolenbroek
458*00b67f09SDavid van Moolenbroek /*
459*00b67f09SDavid van Moolenbroek * is_uint:
460*00b67f09SDavid van Moolenbroek * Tests if a string, test_int, is a valid unsigned integer
461*00b67f09SDavid van Moolenbroek *
462*00b67f09SDavid van Moolenbroek * Sets *result to be the unsigned integer if it is valid
463*00b67f09SDavid van Moolenbroek *
464*00b67f09SDavid van Moolenbroek * Return TRUE if it is
465*00b67f09SDavid van Moolenbroek * Return FALSE if it is not
466*00b67f09SDavid van Moolenbroek */
467*00b67f09SDavid van Moolenbroek int
is_uint(char * test_int,unsigned int * result)468*00b67f09SDavid van Moolenbroek is_uint(char *test_int, unsigned int *result) {
469*00b67f09SDavid van Moolenbroek unsigned long int value;
470*00b67f09SDavid van Moolenbroek char *end;
471*00b67f09SDavid van Moolenbroek
472*00b67f09SDavid van Moolenbroek if (test_int == NULL)
473*00b67f09SDavid van Moolenbroek return (FALSE);
474*00b67f09SDavid van Moolenbroek
475*00b67f09SDavid van Moolenbroek if (is_digit(test_int[0]) == FALSE)
476*00b67f09SDavid van Moolenbroek return (FALSE);
477*00b67f09SDavid van Moolenbroek
478*00b67f09SDavid van Moolenbroek value = strtoul(test_int, &end, 10);
479*00b67f09SDavid van Moolenbroek
480*00b67f09SDavid van Moolenbroek if ((errno == ERANGE) || (*end != '\0') || (value > UINT_MAX))
481*00b67f09SDavid van Moolenbroek return (FALSE);
482*00b67f09SDavid van Moolenbroek
483*00b67f09SDavid van Moolenbroek *result = (unsigned int)value;
484*00b67f09SDavid van Moolenbroek return (TRUE);
485*00b67f09SDavid van Moolenbroek }
486*00b67f09SDavid van Moolenbroek
487*00b67f09SDavid van Moolenbroek /*
488*00b67f09SDavid van Moolenbroek * set_max_queries:
489*00b67f09SDavid van Moolenbroek * Set the maximum number of outstanding queries
490*00b67f09SDavid van Moolenbroek *
491*00b67f09SDavid van Moolenbroek * Returns -1 on failure
492*00b67f09SDavid van Moolenbroek * Returns a non-negative integer otherwise
493*00b67f09SDavid van Moolenbroek */
494*00b67f09SDavid van Moolenbroek int
set_max_queries(unsigned int new_max)495*00b67f09SDavid van Moolenbroek set_max_queries(unsigned int new_max) {
496*00b67f09SDavid van Moolenbroek static unsigned int size_qs = sizeof(struct query_status);
497*00b67f09SDavid van Moolenbroek struct query_status *temp_stat;
498*00b67f09SDavid van Moolenbroek unsigned int count;
499*00b67f09SDavid van Moolenbroek
500*00b67f09SDavid van Moolenbroek if (new_max > query_status_allocated) {
501*00b67f09SDavid van Moolenbroek temp_stat = realloc(status, new_max * size_qs);
502*00b67f09SDavid van Moolenbroek
503*00b67f09SDavid van Moolenbroek if (temp_stat == NULL) {
504*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error resizing query_status\n");
505*00b67f09SDavid van Moolenbroek return (-1);
506*00b67f09SDavid van Moolenbroek } else {
507*00b67f09SDavid van Moolenbroek status = temp_stat;
508*00b67f09SDavid van Moolenbroek
509*00b67f09SDavid van Moolenbroek /*
510*00b67f09SDavid van Moolenbroek * Be careful to only initialise between above
511*00b67f09SDavid van Moolenbroek * the previously allocated space. Note that the
512*00b67f09SDavid van Moolenbroek * allocation may be larger than the current
513*00b67f09SDavid van Moolenbroek * max_queries_outstanding. We don't want to
514*00b67f09SDavid van Moolenbroek * "forget" any outstanding queries! We might
515*00b67f09SDavid van Moolenbroek * still have some above the bounds of the max.
516*00b67f09SDavid van Moolenbroek */
517*00b67f09SDavid van Moolenbroek count = query_status_allocated;
518*00b67f09SDavid van Moolenbroek for (; count < new_max; count++) {
519*00b67f09SDavid van Moolenbroek status[count].in_use = FALSE;
520*00b67f09SDavid van Moolenbroek status[count].magic = QUERY_STATUS_MAGIC;
521*00b67f09SDavid van Moolenbroek status[count].desc = NULL;
522*00b67f09SDavid van Moolenbroek }
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek query_status_allocated = new_max;
525*00b67f09SDavid van Moolenbroek }
526*00b67f09SDavid van Moolenbroek }
527*00b67f09SDavid van Moolenbroek
528*00b67f09SDavid van Moolenbroek max_queries_outstanding = new_max;
529*00b67f09SDavid van Moolenbroek
530*00b67f09SDavid van Moolenbroek return (0);
531*00b67f09SDavid van Moolenbroek }
532*00b67f09SDavid van Moolenbroek
533*00b67f09SDavid van Moolenbroek /*
534*00b67f09SDavid van Moolenbroek * parse_args:
535*00b67f09SDavid van Moolenbroek * Parse program arguments and set configuration options
536*00b67f09SDavid van Moolenbroek *
537*00b67f09SDavid van Moolenbroek * Return -1 on failure
538*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
539*00b67f09SDavid van Moolenbroek */
540*00b67f09SDavid van Moolenbroek int
parse_args(int argc,char ** argv)541*00b67f09SDavid van Moolenbroek parse_args(int argc, char **argv) {
542*00b67f09SDavid van Moolenbroek int c;
543*00b67f09SDavid van Moolenbroek unsigned int uint_arg_val;
544*00b67f09SDavid van Moolenbroek
545*00b67f09SDavid van Moolenbroek while ((c = getopt(argc, argv,
546*00b67f09SDavid van Moolenbroek "f:q:t:i:nd:s:p:1l:b:eDcvr:RT:u:H:h")) != -1) {
547*00b67f09SDavid van Moolenbroek switch (c) {
548*00b67f09SDavid van Moolenbroek case 'f':
549*00b67f09SDavid van Moolenbroek if (strcmp(optarg, "inet") == 0)
550*00b67f09SDavid van Moolenbroek family = AF_INET;
551*00b67f09SDavid van Moolenbroek #ifdef AF_INET6
552*00b67f09SDavid van Moolenbroek else if (strcmp(optarg, "inet6") == 0)
553*00b67f09SDavid van Moolenbroek family = AF_INET6;
554*00b67f09SDavid van Moolenbroek #endif
555*00b67f09SDavid van Moolenbroek else if (strcmp(optarg, "any") == 0)
556*00b67f09SDavid van Moolenbroek family = AF_UNSPEC;
557*00b67f09SDavid van Moolenbroek else {
558*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid address family: %s\n",
559*00b67f09SDavid van Moolenbroek optarg);
560*00b67f09SDavid van Moolenbroek return (-1);
561*00b67f09SDavid van Moolenbroek }
562*00b67f09SDavid van Moolenbroek break;
563*00b67f09SDavid van Moolenbroek case 'q':
564*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE) {
565*00b67f09SDavid van Moolenbroek set_max_queries(uint_arg_val);
566*00b67f09SDavid van Moolenbroek queriesset = TRUE;
567*00b67f09SDavid van Moolenbroek } else {
568*00b67f09SDavid van Moolenbroek fprintf(stderr, "Option requires a positive "
569*00b67f09SDavid van Moolenbroek "integer value: -%c %s\n",
570*00b67f09SDavid van Moolenbroek c, optarg);
571*00b67f09SDavid van Moolenbroek return (-1);
572*00b67f09SDavid van Moolenbroek }
573*00b67f09SDavid van Moolenbroek break;
574*00b67f09SDavid van Moolenbroek
575*00b67f09SDavid van Moolenbroek case 't':
576*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE) {
577*00b67f09SDavid van Moolenbroek query_timeout = uint_arg_val;
578*00b67f09SDavid van Moolenbroek timeoutset = TRUE;
579*00b67f09SDavid van Moolenbroek } else {
580*00b67f09SDavid van Moolenbroek fprintf(stderr, "Option requires a positive "
581*00b67f09SDavid van Moolenbroek "integer value: -%c %s\n",
582*00b67f09SDavid van Moolenbroek c, optarg);
583*00b67f09SDavid van Moolenbroek return (-1);
584*00b67f09SDavid van Moolenbroek }
585*00b67f09SDavid van Moolenbroek break;
586*00b67f09SDavid van Moolenbroek
587*00b67f09SDavid van Moolenbroek case 'n':
588*00b67f09SDavid van Moolenbroek ignore_config_changes = TRUE;
589*00b67f09SDavid van Moolenbroek break;
590*00b67f09SDavid van Moolenbroek
591*00b67f09SDavid van Moolenbroek case 'd':
592*00b67f09SDavid van Moolenbroek if (set_datafile(optarg) == -1) {
593*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error setting datafile "
594*00b67f09SDavid van Moolenbroek "name: %s\n", optarg);
595*00b67f09SDavid van Moolenbroek return (-1);
596*00b67f09SDavid van Moolenbroek }
597*00b67f09SDavid van Moolenbroek break;
598*00b67f09SDavid van Moolenbroek
599*00b67f09SDavid van Moolenbroek case 's':
600*00b67f09SDavid van Moolenbroek if (set_server(optarg) == -1) {
601*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error setting server "
602*00b67f09SDavid van Moolenbroek "name: %s\n", optarg);
603*00b67f09SDavid van Moolenbroek return (-1);
604*00b67f09SDavid van Moolenbroek }
605*00b67f09SDavid van Moolenbroek serverset = TRUE;
606*00b67f09SDavid van Moolenbroek break;
607*00b67f09SDavid van Moolenbroek
608*00b67f09SDavid van Moolenbroek case 'p':
609*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE &&
610*00b67f09SDavid van Moolenbroek uint_arg_val < MAX_PORT)
611*00b67f09SDavid van Moolenbroek {
612*00b67f09SDavid van Moolenbroek set_server_port(optarg);
613*00b67f09SDavid van Moolenbroek portset = TRUE;
614*00b67f09SDavid van Moolenbroek } else {
615*00b67f09SDavid van Moolenbroek fprintf(stderr, "Option requires a positive "
616*00b67f09SDavid van Moolenbroek "integer between 0 and %d: -%c %s\n",
617*00b67f09SDavid van Moolenbroek MAX_PORT - 1, c, optarg);
618*00b67f09SDavid van Moolenbroek return (-1);
619*00b67f09SDavid van Moolenbroek }
620*00b67f09SDavid van Moolenbroek break;
621*00b67f09SDavid van Moolenbroek
622*00b67f09SDavid van Moolenbroek case '1':
623*00b67f09SDavid van Moolenbroek run_only_once = TRUE;
624*00b67f09SDavid van Moolenbroek break;
625*00b67f09SDavid van Moolenbroek
626*00b67f09SDavid van Moolenbroek case 'l':
627*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE) {
628*00b67f09SDavid van Moolenbroek use_timelimit = TRUE;
629*00b67f09SDavid van Moolenbroek run_timelimit = uint_arg_val;
630*00b67f09SDavid van Moolenbroek } else {
631*00b67f09SDavid van Moolenbroek fprintf(stderr, "Option requires a positive "
632*00b67f09SDavid van Moolenbroek "integer: -%c %s\n",
633*00b67f09SDavid van Moolenbroek c, optarg);
634*00b67f09SDavid van Moolenbroek return (-1);
635*00b67f09SDavid van Moolenbroek }
636*00b67f09SDavid van Moolenbroek break;
637*00b67f09SDavid van Moolenbroek
638*00b67f09SDavid van Moolenbroek case 'b':
639*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE) {
640*00b67f09SDavid van Moolenbroek socket_bufsize = uint_arg_val;
641*00b67f09SDavid van Moolenbroek } else {
642*00b67f09SDavid van Moolenbroek fprintf(stderr, "Option requires a positive "
643*00b67f09SDavid van Moolenbroek "integer: -%c %s\n",
644*00b67f09SDavid van Moolenbroek c, optarg);
645*00b67f09SDavid van Moolenbroek return (-1);
646*00b67f09SDavid van Moolenbroek }
647*00b67f09SDavid van Moolenbroek break;
648*00b67f09SDavid van Moolenbroek case 'e':
649*00b67f09SDavid van Moolenbroek edns = TRUE;
650*00b67f09SDavid van Moolenbroek break;
651*00b67f09SDavid van Moolenbroek case 'D':
652*00b67f09SDavid van Moolenbroek dnssec = TRUE;
653*00b67f09SDavid van Moolenbroek edns = TRUE;
654*00b67f09SDavid van Moolenbroek break;
655*00b67f09SDavid van Moolenbroek case 'c':
656*00b67f09SDavid van Moolenbroek countrcodes = TRUE;
657*00b67f09SDavid van Moolenbroek break;
658*00b67f09SDavid van Moolenbroek case 'v':
659*00b67f09SDavid van Moolenbroek verbose = 1;
660*00b67f09SDavid van Moolenbroek break;
661*00b67f09SDavid van Moolenbroek case 'i':
662*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE)
663*00b67f09SDavid van Moolenbroek print_interval = uint_arg_val;
664*00b67f09SDavid van Moolenbroek else {
665*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid interval: %s\n",
666*00b67f09SDavid van Moolenbroek optarg);
667*00b67f09SDavid van Moolenbroek return (-1);
668*00b67f09SDavid van Moolenbroek }
669*00b67f09SDavid van Moolenbroek break;
670*00b67f09SDavid van Moolenbroek case 'R':
671*00b67f09SDavid van Moolenbroek recurse = 0;
672*00b67f09SDavid van Moolenbroek break;
673*00b67f09SDavid van Moolenbroek case 'r':
674*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE)
675*00b67f09SDavid van Moolenbroek rttarray_size = uint_arg_val;
676*00b67f09SDavid van Moolenbroek else {
677*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid RTT array size: %s\n",
678*00b67f09SDavid van Moolenbroek optarg);
679*00b67f09SDavid van Moolenbroek return (-1);
680*00b67f09SDavid van Moolenbroek }
681*00b67f09SDavid van Moolenbroek break;
682*00b67f09SDavid van Moolenbroek case 'u':
683*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE)
684*00b67f09SDavid van Moolenbroek rttarray_unit = uint_arg_val;
685*00b67f09SDavid van Moolenbroek else {
686*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid RTT unit: %s\n",
687*00b67f09SDavid van Moolenbroek optarg);
688*00b67f09SDavid van Moolenbroek return (-1);
689*00b67f09SDavid van Moolenbroek }
690*00b67f09SDavid van Moolenbroek break;
691*00b67f09SDavid van Moolenbroek case 'H':
692*00b67f09SDavid van Moolenbroek rtt_histogram_file = optarg;
693*00b67f09SDavid van Moolenbroek break;
694*00b67f09SDavid van Moolenbroek case 'T':
695*00b67f09SDavid van Moolenbroek if (is_uint(optarg, &uint_arg_val) == TRUE)
696*00b67f09SDavid van Moolenbroek target_qps = uint_arg_val;
697*00b67f09SDavid van Moolenbroek else {
698*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid target qps: %s\n",
699*00b67f09SDavid van Moolenbroek optarg);
700*00b67f09SDavid van Moolenbroek return (-1);
701*00b67f09SDavid van Moolenbroek }
702*00b67f09SDavid van Moolenbroek break;
703*00b67f09SDavid van Moolenbroek case 'h':
704*00b67f09SDavid van Moolenbroek return (-1);
705*00b67f09SDavid van Moolenbroek default:
706*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid option: -%c\n", optopt);
707*00b67f09SDavid van Moolenbroek return (-1);
708*00b67f09SDavid van Moolenbroek }
709*00b67f09SDavid van Moolenbroek }
710*00b67f09SDavid van Moolenbroek
711*00b67f09SDavid van Moolenbroek if (run_only_once == FALSE && use_timelimit == FALSE)
712*00b67f09SDavid van Moolenbroek run_only_once = TRUE;
713*00b67f09SDavid van Moolenbroek
714*00b67f09SDavid van Moolenbroek return (0);
715*00b67f09SDavid van Moolenbroek }
716*00b67f09SDavid van Moolenbroek
717*00b67f09SDavid van Moolenbroek /*
718*00b67f09SDavid van Moolenbroek * open_datafile:
719*00b67f09SDavid van Moolenbroek * Open the data file ready for reading
720*00b67f09SDavid van Moolenbroek *
721*00b67f09SDavid van Moolenbroek * Return -1 on failure
722*00b67f09SDavid van Moolenbroek * Return non-negative integer on success
723*00b67f09SDavid van Moolenbroek */
724*00b67f09SDavid van Moolenbroek int
open_datafile(void)725*00b67f09SDavid van Moolenbroek open_datafile(void) {
726*00b67f09SDavid van Moolenbroek if (use_stdin == TRUE) {
727*00b67f09SDavid van Moolenbroek datafile_ptr = stdin;
728*00b67f09SDavid van Moolenbroek return (0);
729*00b67f09SDavid van Moolenbroek } else {
730*00b67f09SDavid van Moolenbroek if ((datafile_ptr = fopen(datafile_name, "r")) == NULL) {
731*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: unable to open datafile: %s\n",
732*00b67f09SDavid van Moolenbroek datafile_name);
733*00b67f09SDavid van Moolenbroek return (-1);
734*00b67f09SDavid van Moolenbroek } else
735*00b67f09SDavid van Moolenbroek return (0);
736*00b67f09SDavid van Moolenbroek }
737*00b67f09SDavid van Moolenbroek }
738*00b67f09SDavid van Moolenbroek
739*00b67f09SDavid van Moolenbroek /*
740*00b67f09SDavid van Moolenbroek * close_datafile:
741*00b67f09SDavid van Moolenbroek * Close the data file if any is open
742*00b67f09SDavid van Moolenbroek *
743*00b67f09SDavid van Moolenbroek * Return -1 on failure
744*00b67f09SDavid van Moolenbroek * Return non-negative integer on success, including if not needed
745*00b67f09SDavid van Moolenbroek */
746*00b67f09SDavid van Moolenbroek int
close_datafile(void)747*00b67f09SDavid van Moolenbroek close_datafile(void) {
748*00b67f09SDavid van Moolenbroek if ((use_stdin == FALSE) && (datafile_ptr != NULL)) {
749*00b67f09SDavid van Moolenbroek if (fclose(datafile_ptr) != 0) {
750*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: unable to close datafile\n");
751*00b67f09SDavid van Moolenbroek return (-1);
752*00b67f09SDavid van Moolenbroek }
753*00b67f09SDavid van Moolenbroek }
754*00b67f09SDavid van Moolenbroek
755*00b67f09SDavid van Moolenbroek return (0);
756*00b67f09SDavid van Moolenbroek }
757*00b67f09SDavid van Moolenbroek
758*00b67f09SDavid van Moolenbroek /*
759*00b67f09SDavid van Moolenbroek * open_socket:
760*00b67f09SDavid van Moolenbroek * Open a socket for the queries. When we have an active socket already,
761*00b67f09SDavid van Moolenbroek * close it and open a new one.
762*00b67f09SDavid van Moolenbroek *
763*00b67f09SDavid van Moolenbroek * Return -1 on failure
764*00b67f09SDavid van Moolenbroek * Return the socket identifier
765*00b67f09SDavid van Moolenbroek */
766*00b67f09SDavid van Moolenbroek int
open_socket(void)767*00b67f09SDavid van Moolenbroek open_socket(void) {
768*00b67f09SDavid van Moolenbroek int sock;
769*00b67f09SDavid van Moolenbroek int ret;
770*00b67f09SDavid van Moolenbroek int bufsize;
771*00b67f09SDavid van Moolenbroek struct addrinfo hints, *res;
772*00b67f09SDavid van Moolenbroek
773*00b67f09SDavid van Moolenbroek memset(&hints, 0, sizeof(hints));
774*00b67f09SDavid van Moolenbroek hints.ai_family = server_ai->ai_family;
775*00b67f09SDavid van Moolenbroek hints.ai_socktype = server_ai->ai_socktype;
776*00b67f09SDavid van Moolenbroek hints.ai_protocol = server_ai->ai_protocol;
777*00b67f09SDavid van Moolenbroek hints.ai_flags = AI_PASSIVE;
778*00b67f09SDavid van Moolenbroek
779*00b67f09SDavid van Moolenbroek if ((ret = getaddrinfo(NULL, "0", &hints, &res)) != 0) {
780*00b67f09SDavid van Moolenbroek fprintf(stderr,
781*00b67f09SDavid van Moolenbroek "Error: getaddrinfo for bind socket failed: %s\n",
782*00b67f09SDavid van Moolenbroek gai_strerror(ret));
783*00b67f09SDavid van Moolenbroek return (-1);
784*00b67f09SDavid van Moolenbroek }
785*00b67f09SDavid van Moolenbroek
786*00b67f09SDavid van Moolenbroek if ((sock = socket(res->ai_family, SOCK_DGRAM,
787*00b67f09SDavid van Moolenbroek res->ai_protocol)) == -1) {
788*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: socket call failed");
789*00b67f09SDavid van Moolenbroek goto fail;
790*00b67f09SDavid van Moolenbroek }
791*00b67f09SDavid van Moolenbroek
792*00b67f09SDavid van Moolenbroek #if defined(AF_INET6) && defined(IPV6_V6ONLY)
793*00b67f09SDavid van Moolenbroek if (res->ai_family == AF_INET6) {
794*00b67f09SDavid van Moolenbroek int on = 1;
795*00b67f09SDavid van Moolenbroek
796*00b67f09SDavid van Moolenbroek if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
797*00b67f09SDavid van Moolenbroek &on, sizeof(on)) == -1) {
798*00b67f09SDavid van Moolenbroek fprintf(stderr,
799*00b67f09SDavid van Moolenbroek "Warning: setsockopt(IPV6_V6ONLY) failed\n");
800*00b67f09SDavid van Moolenbroek }
801*00b67f09SDavid van Moolenbroek }
802*00b67f09SDavid van Moolenbroek #endif
803*00b67f09SDavid van Moolenbroek
804*00b67f09SDavid van Moolenbroek if (bind(sock, res->ai_addr, res->ai_addrlen) == -1)
805*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error: bind call failed");
806*00b67f09SDavid van Moolenbroek
807*00b67f09SDavid van Moolenbroek freeaddrinfo(res);
808*00b67f09SDavid van Moolenbroek
809*00b67f09SDavid van Moolenbroek bufsize = 1024 * socket_bufsize;
810*00b67f09SDavid van Moolenbroek
811*00b67f09SDavid van Moolenbroek ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
812*00b67f09SDavid van Moolenbroek (char *) &bufsize, sizeof(bufsize));
813*00b67f09SDavid van Moolenbroek if (ret < 0)
814*00b67f09SDavid van Moolenbroek fprintf(stderr, "Warning: setsockbuf(SO_RCVBUF) failed\n");
815*00b67f09SDavid van Moolenbroek
816*00b67f09SDavid van Moolenbroek ret = setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
817*00b67f09SDavid van Moolenbroek (char *) &bufsize, sizeof(bufsize));
818*00b67f09SDavid van Moolenbroek if (ret < 0)
819*00b67f09SDavid van Moolenbroek fprintf(stderr, "Warning: setsockbuf(SO_SNDBUF) failed\n");
820*00b67f09SDavid van Moolenbroek
821*00b67f09SDavid van Moolenbroek return (sock);
822*00b67f09SDavid van Moolenbroek
823*00b67f09SDavid van Moolenbroek fail:
824*00b67f09SDavid van Moolenbroek if (res)
825*00b67f09SDavid van Moolenbroek freeaddrinfo(res);
826*00b67f09SDavid van Moolenbroek return (-1);
827*00b67f09SDavid van Moolenbroek }
828*00b67f09SDavid van Moolenbroek
829*00b67f09SDavid van Moolenbroek /*
830*00b67f09SDavid van Moolenbroek * close_socket:
831*00b67f09SDavid van Moolenbroek * Close the query socket(s)
832*00b67f09SDavid van Moolenbroek *
833*00b67f09SDavid van Moolenbroek * Return -1 on failure
834*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
835*00b67f09SDavid van Moolenbroek */
836*00b67f09SDavid van Moolenbroek int
close_socket(void)837*00b67f09SDavid van Moolenbroek close_socket(void) {
838*00b67f09SDavid van Moolenbroek if (socket4 != -1) {
839*00b67f09SDavid van Moolenbroek if (close(socket4) != 0) {
840*00b67f09SDavid van Moolenbroek fprintf(stderr,
841*00b67f09SDavid van Moolenbroek "Error: unable to close IPv4 socket\n");
842*00b67f09SDavid van Moolenbroek return (-1);
843*00b67f09SDavid van Moolenbroek }
844*00b67f09SDavid van Moolenbroek }
845*00b67f09SDavid van Moolenbroek
846*00b67f09SDavid van Moolenbroek if (socket6 != -1) {
847*00b67f09SDavid van Moolenbroek if (close(socket6) != 0) {
848*00b67f09SDavid van Moolenbroek fprintf(stderr,
849*00b67f09SDavid van Moolenbroek "Error: unable to close IPv6 socket\n");
850*00b67f09SDavid van Moolenbroek return (-1);
851*00b67f09SDavid van Moolenbroek }
852*00b67f09SDavid van Moolenbroek }
853*00b67f09SDavid van Moolenbroek
854*00b67f09SDavid van Moolenbroek query_socket = -1;
855*00b67f09SDavid van Moolenbroek
856*00b67f09SDavid van Moolenbroek return (0);
857*00b67f09SDavid van Moolenbroek }
858*00b67f09SDavid van Moolenbroek
859*00b67f09SDavid van Moolenbroek /*
860*00b67f09SDavid van Moolenbroek * change_socket:
861*00b67f09SDavid van Moolenbroek * Choose an appropriate socket according to the address family of the
862*00b67f09SDavid van Moolenbroek * current server. Open a new socket if necessary.
863*00b67f09SDavid van Moolenbroek *
864*00b67f09SDavid van Moolenbroek * Return -1 on failure
865*00b67f09SDavid van Moolenbroek * Return the socket identifier
866*00b67f09SDavid van Moolenbroek */
867*00b67f09SDavid van Moolenbroek int
change_socket(void)868*00b67f09SDavid van Moolenbroek change_socket(void) {
869*00b67f09SDavid van Moolenbroek int s, *sockp;
870*00b67f09SDavid van Moolenbroek
871*00b67f09SDavid van Moolenbroek switch (server_ai->ai_family) {
872*00b67f09SDavid van Moolenbroek case AF_INET:
873*00b67f09SDavid van Moolenbroek sockp = &socket4;
874*00b67f09SDavid van Moolenbroek break;
875*00b67f09SDavid van Moolenbroek #ifdef AF_INET6
876*00b67f09SDavid van Moolenbroek case AF_INET6:
877*00b67f09SDavid van Moolenbroek sockp = &socket6;
878*00b67f09SDavid van Moolenbroek break;
879*00b67f09SDavid van Moolenbroek #endif
880*00b67f09SDavid van Moolenbroek default:
881*00b67f09SDavid van Moolenbroek fprintf(stderr, "unexpected address family: %d\n",
882*00b67f09SDavid van Moolenbroek server_ai->ai_family);
883*00b67f09SDavid van Moolenbroek exit(1);
884*00b67f09SDavid van Moolenbroek }
885*00b67f09SDavid van Moolenbroek
886*00b67f09SDavid van Moolenbroek if (*sockp == -1) {
887*00b67f09SDavid van Moolenbroek if ((s = open_socket()) == -1)
888*00b67f09SDavid van Moolenbroek return (-1);
889*00b67f09SDavid van Moolenbroek *sockp = s;
890*00b67f09SDavid van Moolenbroek }
891*00b67f09SDavid van Moolenbroek
892*00b67f09SDavid van Moolenbroek return (*sockp);
893*00b67f09SDavid van Moolenbroek }
894*00b67f09SDavid van Moolenbroek
895*00b67f09SDavid van Moolenbroek /*
896*00b67f09SDavid van Moolenbroek * reset_rttarray:
897*00b67f09SDavid van Moolenbroek * (re)allocate RTT array and zero-clear the whole buffer.
898*00b67f09SDavid van Moolenbroek * if array is being used, it is freed.
899*00b67f09SDavid van Moolenbroek * Returns -1 on failure
900*00b67f09SDavid van Moolenbroek * Returns a non-negative integer otherwise
901*00b67f09SDavid van Moolenbroek */
902*00b67f09SDavid van Moolenbroek int
reset_rttarray(int size)903*00b67f09SDavid van Moolenbroek reset_rttarray(int size) {
904*00b67f09SDavid van Moolenbroek if (rttarray != NULL)
905*00b67f09SDavid van Moolenbroek free(rttarray);
906*00b67f09SDavid van Moolenbroek if (rttarray_interval != NULL)
907*00b67f09SDavid van Moolenbroek free(rttarray_interval);
908*00b67f09SDavid van Moolenbroek
909*00b67f09SDavid van Moolenbroek rttarray = NULL;
910*00b67f09SDavid van Moolenbroek rttarray_interval = NULL;
911*00b67f09SDavid van Moolenbroek rtt_max = -1;
912*00b67f09SDavid van Moolenbroek rtt_min = -1;
913*00b67f09SDavid van Moolenbroek
914*00b67f09SDavid van Moolenbroek if (size > 0) {
915*00b67f09SDavid van Moolenbroek rttarray = malloc(size * sizeof(rttarray[0]));
916*00b67f09SDavid van Moolenbroek if (rttarray == NULL) {
917*00b67f09SDavid van Moolenbroek fprintf(stderr,
918*00b67f09SDavid van Moolenbroek "Error: allocating memory for RTT array\n");
919*00b67f09SDavid van Moolenbroek return (-1);
920*00b67f09SDavid van Moolenbroek }
921*00b67f09SDavid van Moolenbroek memset(rttarray, 0, size * sizeof(rttarray[0]));
922*00b67f09SDavid van Moolenbroek
923*00b67f09SDavid van Moolenbroek rttarray_interval = malloc(size *
924*00b67f09SDavid van Moolenbroek sizeof(rttarray_interval[0]));
925*00b67f09SDavid van Moolenbroek if (rttarray_interval == NULL) {
926*00b67f09SDavid van Moolenbroek fprintf(stderr,
927*00b67f09SDavid van Moolenbroek "Error: allocating memory for RTT array\n");
928*00b67f09SDavid van Moolenbroek return (-1);
929*00b67f09SDavid van Moolenbroek }
930*00b67f09SDavid van Moolenbroek
931*00b67f09SDavid van Moolenbroek memset(rttarray_interval, 0,
932*00b67f09SDavid van Moolenbroek size * sizeof(rttarray_interval[0]));
933*00b67f09SDavid van Moolenbroek }
934*00b67f09SDavid van Moolenbroek
935*00b67f09SDavid van Moolenbroek return (0);
936*00b67f09SDavid van Moolenbroek }
937*00b67f09SDavid van Moolenbroek
938*00b67f09SDavid van Moolenbroek /*
939*00b67f09SDavid van Moolenbroek * set_query_interval:
940*00b67f09SDavid van Moolenbroek * set the interval of consecutive queries if the target qps are specified.
941*00b67f09SDavid van Moolenbroek * Returns -1 on failure
942*00b67f09SDavid van Moolenbroek * Returns a non-negative integer otherwise
943*00b67f09SDavid van Moolenbroek */
944*00b67f09SDavid van Moolenbroek int
set_query_interval(unsigned int qps)945*00b67f09SDavid van Moolenbroek set_query_interval(unsigned int qps) {
946*00b67f09SDavid van Moolenbroek if (qps == 0)
947*00b67f09SDavid van Moolenbroek return (0);
948*00b67f09SDavid van Moolenbroek
949*00b67f09SDavid van Moolenbroek query_interval = (1.0 / (double)qps);
950*00b67f09SDavid van Moolenbroek
951*00b67f09SDavid van Moolenbroek return (0);
952*00b67f09SDavid van Moolenbroek }
953*00b67f09SDavid van Moolenbroek
954*00b67f09SDavid van Moolenbroek /*
955*00b67f09SDavid van Moolenbroek * setup:
956*00b67f09SDavid van Moolenbroek * Set configuration options from command line arguments
957*00b67f09SDavid van Moolenbroek * Open datafile ready for reading
958*00b67f09SDavid van Moolenbroek *
959*00b67f09SDavid van Moolenbroek * Return -1 on failure
960*00b67f09SDavid van Moolenbroek * Return non-negative integer on success
961*00b67f09SDavid van Moolenbroek */
962*00b67f09SDavid van Moolenbroek int
setup(int argc,char ** argv)963*00b67f09SDavid van Moolenbroek setup(int argc, char **argv) {
964*00b67f09SDavid van Moolenbroek set_input_stdin();
965*00b67f09SDavid van Moolenbroek
966*00b67f09SDavid van Moolenbroek if (set_max_queries(DEF_MAX_QUERIES_OUTSTANDING) == -1) {
967*00b67f09SDavid van Moolenbroek fprintf(stderr, "%s: Unable to set default max outstanding "
968*00b67f09SDavid van Moolenbroek "queries\n", argv[0]);
969*00b67f09SDavid van Moolenbroek return (-1);
970*00b67f09SDavid van Moolenbroek }
971*00b67f09SDavid van Moolenbroek
972*00b67f09SDavid van Moolenbroek if (set_server(DEF_SERVER_TO_QUERY) == -1) {
973*00b67f09SDavid van Moolenbroek fprintf(stderr, "%s: Error setting default server name\n",
974*00b67f09SDavid van Moolenbroek argv[0]);
975*00b67f09SDavid van Moolenbroek return (-1);
976*00b67f09SDavid van Moolenbroek }
977*00b67f09SDavid van Moolenbroek
978*00b67f09SDavid van Moolenbroek if (set_server_port(DEF_SERVER_PORT) == -1) {
979*00b67f09SDavid van Moolenbroek fprintf(stderr, "%s: Error setting default server port\n",
980*00b67f09SDavid van Moolenbroek argv[0]);
981*00b67f09SDavid van Moolenbroek return (-1);
982*00b67f09SDavid van Moolenbroek }
983*00b67f09SDavid van Moolenbroek
984*00b67f09SDavid van Moolenbroek if (parse_args(argc, argv) == -1) {
985*00b67f09SDavid van Moolenbroek show_usage();
986*00b67f09SDavid van Moolenbroek return (-1);
987*00b67f09SDavid van Moolenbroek }
988*00b67f09SDavid van Moolenbroek
989*00b67f09SDavid van Moolenbroek if (open_datafile() == -1)
990*00b67f09SDavid van Moolenbroek return (-1);
991*00b67f09SDavid van Moolenbroek
992*00b67f09SDavid van Moolenbroek if (set_server_sa() == -1)
993*00b67f09SDavid van Moolenbroek return (-1);
994*00b67f09SDavid van Moolenbroek
995*00b67f09SDavid van Moolenbroek if ((query_socket = change_socket()) == -1)
996*00b67f09SDavid van Moolenbroek return (-1);
997*00b67f09SDavid van Moolenbroek
998*00b67f09SDavid van Moolenbroek if (reset_rttarray(rttarray_size) == -1)
999*00b67f09SDavid van Moolenbroek return (-1);
1000*00b67f09SDavid van Moolenbroek
1001*00b67f09SDavid van Moolenbroek if (set_query_interval(target_qps) == -1)
1002*00b67f09SDavid van Moolenbroek return (-1);
1003*00b67f09SDavid van Moolenbroek
1004*00b67f09SDavid van Moolenbroek return (0);
1005*00b67f09SDavid van Moolenbroek }
1006*00b67f09SDavid van Moolenbroek
1007*00b67f09SDavid van Moolenbroek /*
1008*00b67f09SDavid van Moolenbroek * set_timenow:
1009*00b67f09SDavid van Moolenbroek * Set a timeval struct to indicate the current time
1010*00b67f09SDavid van Moolenbroek */
1011*00b67f09SDavid van Moolenbroek void
set_timenow(struct timeval * tv)1012*00b67f09SDavid van Moolenbroek set_timenow(struct timeval *tv) {
1013*00b67f09SDavid van Moolenbroek if (gettimeofday(tv, NULL) == -1) {
1014*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error in gettimeofday(). Using inaccurate "
1015*00b67f09SDavid van Moolenbroek "time() instead\n");
1016*00b67f09SDavid van Moolenbroek tv->tv_sec = time(NULL);
1017*00b67f09SDavid van Moolenbroek tv->tv_usec = 0;
1018*00b67f09SDavid van Moolenbroek }
1019*00b67f09SDavid van Moolenbroek }
1020*00b67f09SDavid van Moolenbroek
1021*00b67f09SDavid van Moolenbroek /*
1022*00b67f09SDavid van Moolenbroek * addtv:
1023*00b67f09SDavid van Moolenbroek * add tv1 and tv2, store the result in tv_result.
1024*00b67f09SDavid van Moolenbroek */
1025*00b67f09SDavid van Moolenbroek void
addtv(struct timeval * tv1,struct timeval * tv2,struct timeval * tv_result)1026*00b67f09SDavid van Moolenbroek addtv(struct timeval *tv1, struct timeval *tv2, struct timeval *tv_result) {
1027*00b67f09SDavid van Moolenbroek tv_result->tv_sec = tv1->tv_sec + tv2->tv_sec;
1028*00b67f09SDavid van Moolenbroek tv_result->tv_usec = tv1->tv_usec + tv2->tv_usec;
1029*00b67f09SDavid van Moolenbroek if (tv_result->tv_usec > 1000000) {
1030*00b67f09SDavid van Moolenbroek tv_result->tv_sec++;
1031*00b67f09SDavid van Moolenbroek tv_result->tv_usec -= 1000000;
1032*00b67f09SDavid van Moolenbroek }
1033*00b67f09SDavid van Moolenbroek }
1034*00b67f09SDavid van Moolenbroek
1035*00b67f09SDavid van Moolenbroek /*
1036*00b67f09SDavid van Moolenbroek * difftv:
1037*00b67f09SDavid van Moolenbroek * Find the difference in seconds between two timeval structs.
1038*00b67f09SDavid van Moolenbroek *
1039*00b67f09SDavid van Moolenbroek * Return the difference between tv1 and tv2 in seconds in a double.
1040*00b67f09SDavid van Moolenbroek */
1041*00b67f09SDavid van Moolenbroek double
difftv(struct timeval tv1,struct timeval tv2)1042*00b67f09SDavid van Moolenbroek difftv(struct timeval tv1, struct timeval tv2) {
1043*00b67f09SDavid van Moolenbroek long diff_sec, diff_usec;
1044*00b67f09SDavid van Moolenbroek double diff;
1045*00b67f09SDavid van Moolenbroek
1046*00b67f09SDavid van Moolenbroek diff_sec = tv1.tv_sec - tv2.tv_sec;
1047*00b67f09SDavid van Moolenbroek diff_usec = tv1.tv_usec - tv2.tv_usec;
1048*00b67f09SDavid van Moolenbroek
1049*00b67f09SDavid van Moolenbroek diff = (double)diff_sec + ((double)diff_usec / 1000000.0);
1050*00b67f09SDavid van Moolenbroek
1051*00b67f09SDavid van Moolenbroek return (diff);
1052*00b67f09SDavid van Moolenbroek }
1053*00b67f09SDavid van Moolenbroek
1054*00b67f09SDavid van Moolenbroek /*
1055*00b67f09SDavid van Moolenbroek * timelimit_reached:
1056*00b67f09SDavid van Moolenbroek * Have we reached the time limit (if any)?
1057*00b67f09SDavid van Moolenbroek *
1058*00b67f09SDavid van Moolenbroek * Returns FALSE if there is no time limit or if we have not reached it
1059*00b67f09SDavid van Moolenbroek * Returns TRUE otherwise
1060*00b67f09SDavid van Moolenbroek */
1061*00b67f09SDavid van Moolenbroek int
timelimit_reached(void)1062*00b67f09SDavid van Moolenbroek timelimit_reached(void) {
1063*00b67f09SDavid van Moolenbroek struct timeval time_now;
1064*00b67f09SDavid van Moolenbroek
1065*00b67f09SDavid van Moolenbroek set_timenow(&time_now);
1066*00b67f09SDavid van Moolenbroek
1067*00b67f09SDavid van Moolenbroek if (use_timelimit == FALSE)
1068*00b67f09SDavid van Moolenbroek return (FALSE);
1069*00b67f09SDavid van Moolenbroek
1070*00b67f09SDavid van Moolenbroek if (setup_phase == TRUE) {
1071*00b67f09SDavid van Moolenbroek if (difftv(time_now, time_of_program_start)
1072*00b67f09SDavid van Moolenbroek < (double)(run_timelimit + HARD_TIMEOUT_EXTRA))
1073*00b67f09SDavid van Moolenbroek return (FALSE);
1074*00b67f09SDavid van Moolenbroek else
1075*00b67f09SDavid van Moolenbroek return (TRUE);
1076*00b67f09SDavid van Moolenbroek } else {
1077*00b67f09SDavid van Moolenbroek if (difftv(time_now, time_of_first_query)
1078*00b67f09SDavid van Moolenbroek < (double)run_timelimit)
1079*00b67f09SDavid van Moolenbroek return (FALSE);
1080*00b67f09SDavid van Moolenbroek else
1081*00b67f09SDavid van Moolenbroek return (TRUE);
1082*00b67f09SDavid van Moolenbroek }
1083*00b67f09SDavid van Moolenbroek }
1084*00b67f09SDavid van Moolenbroek
1085*00b67f09SDavid van Moolenbroek /*
1086*00b67f09SDavid van Moolenbroek * keep_sending:
1087*00b67f09SDavid van Moolenbroek * Should we keep sending queries or stop here?
1088*00b67f09SDavid van Moolenbroek *
1089*00b67f09SDavid van Moolenbroek * Return TRUE if we should keep on sending queries
1090*00b67f09SDavid van Moolenbroek * Return FALSE if we should stop
1091*00b67f09SDavid van Moolenbroek *
1092*00b67f09SDavid van Moolenbroek * Side effects:
1093*00b67f09SDavid van Moolenbroek * Rewinds the input and clears reached_end_input if we have reached the
1094*00b67f09SDavid van Moolenbroek * end of the input, but we are meant to run through it multiple times
1095*00b67f09SDavid van Moolenbroek * and have not hit the time limit yet (if any is set).
1096*00b67f09SDavid van Moolenbroek */
1097*00b67f09SDavid van Moolenbroek int
keep_sending(int * reached_end_input)1098*00b67f09SDavid van Moolenbroek keep_sending(int *reached_end_input) {
1099*00b67f09SDavid van Moolenbroek static int stop = FALSE;
1100*00b67f09SDavid van Moolenbroek
1101*00b67f09SDavid van Moolenbroek if (stop == TRUE)
1102*00b67f09SDavid van Moolenbroek return (FALSE);
1103*00b67f09SDavid van Moolenbroek
1104*00b67f09SDavid van Moolenbroek if ((*reached_end_input == FALSE) && (timelimit_reached() == FALSE))
1105*00b67f09SDavid van Moolenbroek return (TRUE);
1106*00b67f09SDavid van Moolenbroek else if ((*reached_end_input == TRUE) && (run_only_once == FALSE)
1107*00b67f09SDavid van Moolenbroek && (timelimit_reached() == FALSE)) {
1108*00b67f09SDavid van Moolenbroek rewind(datafile_ptr);
1109*00b67f09SDavid van Moolenbroek *reached_end_input = FALSE;
1110*00b67f09SDavid van Moolenbroek runs_through_file++;
1111*00b67f09SDavid van Moolenbroek return (TRUE);
1112*00b67f09SDavid van Moolenbroek } else {
1113*00b67f09SDavid van Moolenbroek if (*reached_end_input == TRUE)
1114*00b67f09SDavid van Moolenbroek runs_through_file++;
1115*00b67f09SDavid van Moolenbroek set_timenow(&time_of_stop_sending);
1116*00b67f09SDavid van Moolenbroek stop = TRUE;
1117*00b67f09SDavid van Moolenbroek return (FALSE);
1118*00b67f09SDavid van Moolenbroek }
1119*00b67f09SDavid van Moolenbroek }
1120*00b67f09SDavid van Moolenbroek
1121*00b67f09SDavid van Moolenbroek /*
1122*00b67f09SDavid van Moolenbroek * queries_outstanding:
1123*00b67f09SDavid van Moolenbroek * How many queries are outstanding?
1124*00b67f09SDavid van Moolenbroek *
1125*00b67f09SDavid van Moolenbroek * Returns the number of outstanding queries
1126*00b67f09SDavid van Moolenbroek */
1127*00b67f09SDavid van Moolenbroek unsigned int
queries_outstanding(void)1128*00b67f09SDavid van Moolenbroek queries_outstanding(void) {
1129*00b67f09SDavid van Moolenbroek return (num_queries_outstanding);
1130*00b67f09SDavid van Moolenbroek }
1131*00b67f09SDavid van Moolenbroek
1132*00b67f09SDavid van Moolenbroek /*
1133*00b67f09SDavid van Moolenbroek * next_input_line:
1134*00b67f09SDavid van Moolenbroek * Get the next non-comment line from the input file
1135*00b67f09SDavid van Moolenbroek *
1136*00b67f09SDavid van Moolenbroek * Put text in line, up to max of n chars. Skip comment lines.
1137*00b67f09SDavid van Moolenbroek * Skip empty lines.
1138*00b67f09SDavid van Moolenbroek *
1139*00b67f09SDavid van Moolenbroek * Return line length on success
1140*00b67f09SDavid van Moolenbroek * Return 0 if cannot read a non-comment line (EOF or error)
1141*00b67f09SDavid van Moolenbroek */
1142*00b67f09SDavid van Moolenbroek int
next_input_line(char * line,int n)1143*00b67f09SDavid van Moolenbroek next_input_line(char *line, int n) {
1144*00b67f09SDavid van Moolenbroek char *result;
1145*00b67f09SDavid van Moolenbroek
1146*00b67f09SDavid van Moolenbroek do {
1147*00b67f09SDavid van Moolenbroek result = fgets(line, n, datafile_ptr);
1148*00b67f09SDavid van Moolenbroek } while ((result != NULL) &&
1149*00b67f09SDavid van Moolenbroek ((line[0] == COMMENT_CHAR) || (line[0] == '\n')));
1150*00b67f09SDavid van Moolenbroek
1151*00b67f09SDavid van Moolenbroek if (result == NULL)
1152*00b67f09SDavid van Moolenbroek return (0);
1153*00b67f09SDavid van Moolenbroek else
1154*00b67f09SDavid van Moolenbroek return (strlen(line));
1155*00b67f09SDavid van Moolenbroek }
1156*00b67f09SDavid van Moolenbroek
1157*00b67f09SDavid van Moolenbroek /*
1158*00b67f09SDavid van Moolenbroek * identify_directive:
1159*00b67f09SDavid van Moolenbroek * Gives us a numerical value equivelant for a directive string
1160*00b67f09SDavid van Moolenbroek *
1161*00b67f09SDavid van Moolenbroek * Returns the value for the directive
1162*00b67f09SDavid van Moolenbroek * Returns -1 if not a valid directive
1163*00b67f09SDavid van Moolenbroek */
1164*00b67f09SDavid van Moolenbroek int
identify_directive(char * dir)1165*00b67f09SDavid van Moolenbroek identify_directive(char *dir) {
1166*00b67f09SDavid van Moolenbroek static char *directives[] = DIRECTIVES;
1167*00b67f09SDavid van Moolenbroek static int dir_values[] = DIR_VALUES;
1168*00b67f09SDavid van Moolenbroek unsigned int index, num_directives;
1169*00b67f09SDavid van Moolenbroek
1170*00b67f09SDavid van Moolenbroek num_directives = sizeof(directives) / sizeof(directives[0]);
1171*00b67f09SDavid van Moolenbroek
1172*00b67f09SDavid van Moolenbroek if (num_directives > (sizeof(dir_values) / sizeof(int)))
1173*00b67f09SDavid van Moolenbroek num_directives = sizeof(dir_values) / sizeof(int);
1174*00b67f09SDavid van Moolenbroek
1175*00b67f09SDavid van Moolenbroek for (index = 0; index < num_directives; index++) {
1176*00b67f09SDavid van Moolenbroek if (strcmp(dir, directives[index]) == 0)
1177*00b67f09SDavid van Moolenbroek return (dir_values[index]);
1178*00b67f09SDavid van Moolenbroek }
1179*00b67f09SDavid van Moolenbroek
1180*00b67f09SDavid van Moolenbroek return (-1);
1181*00b67f09SDavid van Moolenbroek }
1182*00b67f09SDavid van Moolenbroek
1183*00b67f09SDavid van Moolenbroek /*
1184*00b67f09SDavid van Moolenbroek * update_config:
1185*00b67f09SDavid van Moolenbroek * Update configuration options from a line from the input file
1186*00b67f09SDavid van Moolenbroek */
1187*00b67f09SDavid van Moolenbroek void
update_config(char * config_change_desc)1188*00b67f09SDavid van Moolenbroek update_config(char *config_change_desc) {
1189*00b67f09SDavid van Moolenbroek char *directive, *config_value, *trailing_garbage;
1190*00b67f09SDavid van Moolenbroek char conf_copy[MAX_INPUT_LEN + 1];
1191*00b67f09SDavid van Moolenbroek unsigned int uint_val;
1192*00b67f09SDavid van Moolenbroek int directive_number;
1193*00b67f09SDavid van Moolenbroek int check;
1194*00b67f09SDavid van Moolenbroek int old_af;
1195*00b67f09SDavid van Moolenbroek
1196*00b67f09SDavid van Moolenbroek if (ignore_config_changes == TRUE) {
1197*00b67f09SDavid van Moolenbroek fprintf(stderr, "Ignoring configuration change: %s",
1198*00b67f09SDavid van Moolenbroek config_change_desc);
1199*00b67f09SDavid van Moolenbroek return;
1200*00b67f09SDavid van Moolenbroek }
1201*00b67f09SDavid van Moolenbroek
1202*00b67f09SDavid van Moolenbroek strcpy(conf_copy, config_change_desc);
1203*00b67f09SDavid van Moolenbroek
1204*00b67f09SDavid van Moolenbroek ++config_change_desc;
1205*00b67f09SDavid van Moolenbroek
1206*00b67f09SDavid van Moolenbroek if (*config_change_desc == '\0') {
1207*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: No directive present: %s\n",
1208*00b67f09SDavid van Moolenbroek conf_copy);
1209*00b67f09SDavid van Moolenbroek return;
1210*00b67f09SDavid van Moolenbroek }
1211*00b67f09SDavid van Moolenbroek
1212*00b67f09SDavid van Moolenbroek if (index(WHITESPACE, *config_change_desc) != NULL) {
1213*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Space before directive or "
1214*00b67f09SDavid van Moolenbroek "no directive present: %s\n", conf_copy);
1215*00b67f09SDavid van Moolenbroek return;
1216*00b67f09SDavid van Moolenbroek }
1217*00b67f09SDavid van Moolenbroek
1218*00b67f09SDavid van Moolenbroek directive = strtok(config_change_desc, WHITESPACE);
1219*00b67f09SDavid van Moolenbroek config_value = strtok(NULL, WHITESPACE);
1220*00b67f09SDavid van Moolenbroek trailing_garbage = strtok(NULL, WHITESPACE);
1221*00b67f09SDavid van Moolenbroek
1222*00b67f09SDavid van Moolenbroek if ((directive_number = identify_directive(directive)) == -1) {
1223*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad directive: %s\n",
1224*00b67f09SDavid van Moolenbroek conf_copy);
1225*00b67f09SDavid van Moolenbroek return;
1226*00b67f09SDavid van Moolenbroek }
1227*00b67f09SDavid van Moolenbroek
1228*00b67f09SDavid van Moolenbroek if (config_value == NULL) {
1229*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: No value present: %s\n",
1230*00b67f09SDavid van Moolenbroek conf_copy);
1231*00b67f09SDavid van Moolenbroek return;
1232*00b67f09SDavid van Moolenbroek }
1233*00b67f09SDavid van Moolenbroek
1234*00b67f09SDavid van Moolenbroek if (trailing_garbage != NULL) {
1235*00b67f09SDavid van Moolenbroek fprintf(stderr, "Config warning: "
1236*00b67f09SDavid van Moolenbroek "trailing garbage: %s\n", conf_copy);
1237*00b67f09SDavid van Moolenbroek }
1238*00b67f09SDavid van Moolenbroek
1239*00b67f09SDavid van Moolenbroek switch(directive_number) {
1240*00b67f09SDavid van Moolenbroek
1241*00b67f09SDavid van Moolenbroek case V_SERVER:
1242*00b67f09SDavid van Moolenbroek if (serverset && (setup_phase == TRUE)) {
1243*00b67f09SDavid van Moolenbroek fprintf(stderr, "Config change overridden by command "
1244*00b67f09SDavid van Moolenbroek "line: %s\n", directive);
1245*00b67f09SDavid van Moolenbroek return;
1246*00b67f09SDavid van Moolenbroek }
1247*00b67f09SDavid van Moolenbroek
1248*00b67f09SDavid van Moolenbroek if (set_server(config_value) == -1) {
1249*00b67f09SDavid van Moolenbroek fprintf(stderr, "Set server error: unable to change "
1250*00b67f09SDavid van Moolenbroek "the server name to '%s'\n", config_value);
1251*00b67f09SDavid van Moolenbroek return;
1252*00b67f09SDavid van Moolenbroek }
1253*00b67f09SDavid van Moolenbroek
1254*00b67f09SDavid van Moolenbroek old_af = server_ai->ai_family;
1255*00b67f09SDavid van Moolenbroek if (set_server_sa() == -1) {
1256*00b67f09SDavid van Moolenbroek fprintf(stderr, "Set server error: unable to resolve "
1257*00b67f09SDavid van Moolenbroek "a new server '%s'\n",
1258*00b67f09SDavid van Moolenbroek config_value);
1259*00b67f09SDavid van Moolenbroek return;
1260*00b67f09SDavid van Moolenbroek }
1261*00b67f09SDavid van Moolenbroek if (old_af != server_ai->ai_family) {
1262*00b67f09SDavid van Moolenbroek if ((query_socket = change_socket()) == -1) {
1263*00b67f09SDavid van Moolenbroek /* XXX: this is fatal */
1264*00b67f09SDavid van Moolenbroek fprintf(stderr, "Set server error: "
1265*00b67f09SDavid van Moolenbroek "unable to open a new socket "
1266*00b67f09SDavid van Moolenbroek "for '%s'\n", config_value);
1267*00b67f09SDavid van Moolenbroek exit(1);
1268*00b67f09SDavid van Moolenbroek }
1269*00b67f09SDavid van Moolenbroek }
1270*00b67f09SDavid van Moolenbroek
1271*00b67f09SDavid van Moolenbroek break;
1272*00b67f09SDavid van Moolenbroek
1273*00b67f09SDavid van Moolenbroek case V_PORT:
1274*00b67f09SDavid van Moolenbroek if (portset && (setup_phase == TRUE)) {
1275*00b67f09SDavid van Moolenbroek fprintf(stderr, "Config change overridden by command "
1276*00b67f09SDavid van Moolenbroek "line: %s\n", directive);
1277*00b67f09SDavid van Moolenbroek return;
1278*00b67f09SDavid van Moolenbroek }
1279*00b67f09SDavid van Moolenbroek
1280*00b67f09SDavid van Moolenbroek check = is_uint(config_value, &uint_val);
1281*00b67f09SDavid van Moolenbroek
1282*00b67f09SDavid van Moolenbroek if ((check == TRUE) && (uint_val > 0)) {
1283*00b67f09SDavid van Moolenbroek if (set_server_port(config_value) == -1) {
1284*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad value for"
1285*00b67f09SDavid van Moolenbroek " %s: %s\n", directive, config_value);
1286*00b67f09SDavid van Moolenbroek } else {
1287*00b67f09SDavid van Moolenbroek if (set_server_sa() == -1) {
1288*00b67f09SDavid van Moolenbroek fprintf(stderr,
1289*00b67f09SDavid van Moolenbroek "Failed to set a new port\n");
1290*00b67f09SDavid van Moolenbroek return;
1291*00b67f09SDavid van Moolenbroek }
1292*00b67f09SDavid van Moolenbroek }
1293*00b67f09SDavid van Moolenbroek } else
1294*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad value for "
1295*00b67f09SDavid van Moolenbroek "%s: %s\n", directive, config_value);
1296*00b67f09SDavid van Moolenbroek break;
1297*00b67f09SDavid van Moolenbroek
1298*00b67f09SDavid van Moolenbroek case V_MAXQUERIES:
1299*00b67f09SDavid van Moolenbroek if (queriesset && (setup_phase == TRUE)) {
1300*00b67f09SDavid van Moolenbroek fprintf(stderr, "Config change overridden by command "
1301*00b67f09SDavid van Moolenbroek "line: %s\n", directive);
1302*00b67f09SDavid van Moolenbroek return;
1303*00b67f09SDavid van Moolenbroek }
1304*00b67f09SDavid van Moolenbroek
1305*00b67f09SDavid van Moolenbroek check = is_uint(config_value, &uint_val);
1306*00b67f09SDavid van Moolenbroek
1307*00b67f09SDavid van Moolenbroek if ((check == TRUE) && (uint_val > 0)) {
1308*00b67f09SDavid van Moolenbroek set_max_queries(uint_val);
1309*00b67f09SDavid van Moolenbroek } else
1310*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad value for "
1311*00b67f09SDavid van Moolenbroek "%s: %s\n", directive, config_value);
1312*00b67f09SDavid van Moolenbroek break;
1313*00b67f09SDavid van Moolenbroek
1314*00b67f09SDavid van Moolenbroek case V_MAXWAIT:
1315*00b67f09SDavid van Moolenbroek if (timeoutset && (setup_phase == TRUE)) {
1316*00b67f09SDavid van Moolenbroek fprintf(stderr, "Config change overridden by command "
1317*00b67f09SDavid van Moolenbroek "line: %s\n", directive);
1318*00b67f09SDavid van Moolenbroek return;
1319*00b67f09SDavid van Moolenbroek }
1320*00b67f09SDavid van Moolenbroek
1321*00b67f09SDavid van Moolenbroek check = is_uint(config_value, &uint_val);
1322*00b67f09SDavid van Moolenbroek
1323*00b67f09SDavid van Moolenbroek if ((check == TRUE) && (uint_val > 0)) {
1324*00b67f09SDavid van Moolenbroek query_timeout = uint_val;
1325*00b67f09SDavid van Moolenbroek } else
1326*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad value for "
1327*00b67f09SDavid van Moolenbroek "%s: %s\n", directive, config_value);
1328*00b67f09SDavid van Moolenbroek break;
1329*00b67f09SDavid van Moolenbroek
1330*00b67f09SDavid van Moolenbroek default:
1331*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid config: Bad directive: %s\n",
1332*00b67f09SDavid van Moolenbroek directive);
1333*00b67f09SDavid van Moolenbroek break;
1334*00b67f09SDavid van Moolenbroek }
1335*00b67f09SDavid van Moolenbroek }
1336*00b67f09SDavid van Moolenbroek
1337*00b67f09SDavid van Moolenbroek /*
1338*00b67f09SDavid van Moolenbroek * parse_query:
1339*00b67f09SDavid van Moolenbroek * Parse a query line from the input file
1340*00b67f09SDavid van Moolenbroek *
1341*00b67f09SDavid van Moolenbroek * Set qname to be the domain to query (up to a max of qnlen chars)
1342*00b67f09SDavid van Moolenbroek * Set qtype to be the type of the query
1343*00b67f09SDavid van Moolenbroek *
1344*00b67f09SDavid van Moolenbroek * Return -1 on failure
1345*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
1346*00b67f09SDavid van Moolenbroek */
1347*00b67f09SDavid van Moolenbroek int
parse_query(char * input,char * qname,unsigned int qnlen,int * qtype)1348*00b67f09SDavid van Moolenbroek parse_query(char *input, char *qname, unsigned int qnlen, int *qtype) {
1349*00b67f09SDavid van Moolenbroek static char *qtype_strings[] = QTYPE_STRINGS;
1350*00b67f09SDavid van Moolenbroek static int qtype_codes[] = QTYPE_CODES;
1351*00b67f09SDavid van Moolenbroek unsigned int num_types, index;
1352*00b67f09SDavid van Moolenbroek int found = FALSE;
1353*00b67f09SDavid van Moolenbroek char incopy[MAX_INPUT_LEN + 1];
1354*00b67f09SDavid van Moolenbroek char *domain_str, *type_str;
1355*00b67f09SDavid van Moolenbroek
1356*00b67f09SDavid van Moolenbroek num_types = sizeof(qtype_strings) / sizeof(qtype_strings[0]);
1357*00b67f09SDavid van Moolenbroek if (num_types > (sizeof(qtype_codes) / sizeof(int)))
1358*00b67f09SDavid van Moolenbroek num_types = sizeof(qtype_codes) / sizeof(int);
1359*00b67f09SDavid van Moolenbroek
1360*00b67f09SDavid van Moolenbroek strcpy(incopy, input);
1361*00b67f09SDavid van Moolenbroek
1362*00b67f09SDavid van Moolenbroek domain_str = strtok(incopy, WHITESPACE);
1363*00b67f09SDavid van Moolenbroek type_str = strtok(NULL, WHITESPACE);
1364*00b67f09SDavid van Moolenbroek
1365*00b67f09SDavid van Moolenbroek if ((domain_str == NULL) || (type_str == NULL)) {
1366*00b67f09SDavid van Moolenbroek fprintf(stderr, "Invalid query input format: %s\n", input);
1367*00b67f09SDavid van Moolenbroek return (-1);
1368*00b67f09SDavid van Moolenbroek }
1369*00b67f09SDavid van Moolenbroek
1370*00b67f09SDavid van Moolenbroek if (strlen(domain_str) > qnlen) {
1371*00b67f09SDavid van Moolenbroek fprintf(stderr, "Query domain too long: %s\n", domain_str);
1372*00b67f09SDavid van Moolenbroek return (-1);
1373*00b67f09SDavid van Moolenbroek }
1374*00b67f09SDavid van Moolenbroek
1375*00b67f09SDavid van Moolenbroek for (index = 0; (index < num_types) && (found == FALSE); index++) {
1376*00b67f09SDavid van Moolenbroek if (strcasecmp(type_str, qtype_strings[index]) == 0) {
1377*00b67f09SDavid van Moolenbroek *qtype = qtype_codes[index];
1378*00b67f09SDavid van Moolenbroek found = TRUE;
1379*00b67f09SDavid van Moolenbroek }
1380*00b67f09SDavid van Moolenbroek }
1381*00b67f09SDavid van Moolenbroek
1382*00b67f09SDavid van Moolenbroek if (found == FALSE) {
1383*00b67f09SDavid van Moolenbroek fprintf(stderr, "Query type not understood: %s\n", type_str);
1384*00b67f09SDavid van Moolenbroek return (-1);
1385*00b67f09SDavid van Moolenbroek }
1386*00b67f09SDavid van Moolenbroek
1387*00b67f09SDavid van Moolenbroek strcpy(qname, domain_str);
1388*00b67f09SDavid van Moolenbroek
1389*00b67f09SDavid van Moolenbroek return (0);
1390*00b67f09SDavid van Moolenbroek }
1391*00b67f09SDavid van Moolenbroek
1392*00b67f09SDavid van Moolenbroek /*
1393*00b67f09SDavid van Moolenbroek * dispatch_query:
1394*00b67f09SDavid van Moolenbroek * Send the query packet for the entry
1395*00b67f09SDavid van Moolenbroek *
1396*00b67f09SDavid van Moolenbroek * Return -1 on failure
1397*00b67f09SDavid van Moolenbroek * Return a non-negative integer otherwise
1398*00b67f09SDavid van Moolenbroek */
1399*00b67f09SDavid van Moolenbroek int
dispatch_query(unsigned short int id,char * dom,int qt,u_char ** pktp,int * pktlenp)1400*00b67f09SDavid van Moolenbroek dispatch_query(unsigned short int id, char *dom, int qt, u_char **pktp,
1401*00b67f09SDavid van Moolenbroek int *pktlenp)
1402*00b67f09SDavid van Moolenbroek {
1403*00b67f09SDavid van Moolenbroek static u_char packet_buffer[PACKETSZ + 1];
1404*00b67f09SDavid van Moolenbroek int buffer_len = PACKETSZ;
1405*00b67f09SDavid van Moolenbroek int bytes_sent;
1406*00b67f09SDavid van Moolenbroek unsigned short int net_id = htons(id);
1407*00b67f09SDavid van Moolenbroek char *id_ptr = (char *)&net_id;
1408*00b67f09SDavid van Moolenbroek HEADER *hp = (HEADER *)packet_buffer;
1409*00b67f09SDavid van Moolenbroek
1410*00b67f09SDavid van Moolenbroek buffer_len = res_mkquery(QUERY, dom, C_IN, qt, NULL, 0,
1411*00b67f09SDavid van Moolenbroek NULL, packet_buffer, PACKETSZ);
1412*00b67f09SDavid van Moolenbroek if (buffer_len == -1) {
1413*00b67f09SDavid van Moolenbroek fprintf(stderr, "Failed to create query packet: %s %d\n",
1414*00b67f09SDavid van Moolenbroek dom, qt);
1415*00b67f09SDavid van Moolenbroek return (-1);
1416*00b67f09SDavid van Moolenbroek }
1417*00b67f09SDavid van Moolenbroek hp->rd = recurse;
1418*00b67f09SDavid van Moolenbroek if (edns) {
1419*00b67f09SDavid van Moolenbroek unsigned char *p;
1420*00b67f09SDavid van Moolenbroek if (buffer_len + EDNSLEN >= PACKETSZ) {
1421*00b67f09SDavid van Moolenbroek fprintf(stderr, "Failed to add OPT to query packet\n");
1422*00b67f09SDavid van Moolenbroek return (-1);
1423*00b67f09SDavid van Moolenbroek }
1424*00b67f09SDavid van Moolenbroek packet_buffer[11] = 1;
1425*00b67f09SDavid van Moolenbroek p = &packet_buffer[buffer_len];
1426*00b67f09SDavid van Moolenbroek *p++ = 0; /* root name */
1427*00b67f09SDavid van Moolenbroek *p++ = 0;
1428*00b67f09SDavid van Moolenbroek *p++ = 41; /* OPT */
1429*00b67f09SDavid van Moolenbroek *p++ = 16;
1430*00b67f09SDavid van Moolenbroek *p++ = 0; /* UDP payload size (4K) */
1431*00b67f09SDavid van Moolenbroek *p++ = 0; /* extended rcode */
1432*00b67f09SDavid van Moolenbroek *p++ = 0; /* version */
1433*00b67f09SDavid van Moolenbroek if (dnssec)
1434*00b67f09SDavid van Moolenbroek *p++ = 0x80; /* upper flag bits - DO set */
1435*00b67f09SDavid van Moolenbroek else
1436*00b67f09SDavid van Moolenbroek *p++ = 0; /* upper flag bits */
1437*00b67f09SDavid van Moolenbroek *p++ = 0; /* lower flag bit */
1438*00b67f09SDavid van Moolenbroek *p++ = 0;
1439*00b67f09SDavid van Moolenbroek *p++ = 0; /* rdlen == 0 */
1440*00b67f09SDavid van Moolenbroek buffer_len += EDNSLEN;
1441*00b67f09SDavid van Moolenbroek }
1442*00b67f09SDavid van Moolenbroek
1443*00b67f09SDavid van Moolenbroek packet_buffer[0] = id_ptr[0];
1444*00b67f09SDavid van Moolenbroek packet_buffer[1] = id_ptr[1];
1445*00b67f09SDavid van Moolenbroek
1446*00b67f09SDavid van Moolenbroek bytes_sent = sendto(query_socket, packet_buffer, buffer_len, 0,
1447*00b67f09SDavid van Moolenbroek server_ai->ai_addr, server_ai->ai_addrlen);
1448*00b67f09SDavid van Moolenbroek if (bytes_sent == -1) {
1449*00b67f09SDavid van Moolenbroek fprintf(stderr, "Failed to send query packet: %s %d\n",
1450*00b67f09SDavid van Moolenbroek dom, qt);
1451*00b67f09SDavid van Moolenbroek return (-1);
1452*00b67f09SDavid van Moolenbroek }
1453*00b67f09SDavid van Moolenbroek
1454*00b67f09SDavid van Moolenbroek if (bytes_sent != buffer_len)
1455*00b67f09SDavid van Moolenbroek fprintf(stderr, "Warning: incomplete packet sent: %s %d\n",
1456*00b67f09SDavid van Moolenbroek dom, qt);
1457*00b67f09SDavid van Moolenbroek
1458*00b67f09SDavid van Moolenbroek *pktp = packet_buffer;
1459*00b67f09SDavid van Moolenbroek *pktlenp = buffer_len;
1460*00b67f09SDavid van Moolenbroek
1461*00b67f09SDavid van Moolenbroek return (0);
1462*00b67f09SDavid van Moolenbroek }
1463*00b67f09SDavid van Moolenbroek
1464*00b67f09SDavid van Moolenbroek /*
1465*00b67f09SDavid van Moolenbroek * send_query:
1466*00b67f09SDavid van Moolenbroek * Send a query based on a line of input
1467*00b67f09SDavid van Moolenbroek */
1468*00b67f09SDavid van Moolenbroek void
send_query(char * query_desc)1469*00b67f09SDavid van Moolenbroek send_query(char *query_desc) {
1470*00b67f09SDavid van Moolenbroek static unsigned short int use_query_id = 0;
1471*00b67f09SDavid van Moolenbroek static int qname_len = MAX_DOMAIN_LEN;
1472*00b67f09SDavid van Moolenbroek static char domain[MAX_DOMAIN_LEN + 1];
1473*00b67f09SDavid van Moolenbroek u_char *qpkt;
1474*00b67f09SDavid van Moolenbroek char serveraddr[NI_MAXHOST];
1475*00b67f09SDavid van Moolenbroek int query_type, qpkt_len;
1476*00b67f09SDavid van Moolenbroek unsigned int count;
1477*00b67f09SDavid van Moolenbroek
1478*00b67f09SDavid van Moolenbroek use_query_id++;
1479*00b67f09SDavid van Moolenbroek
1480*00b67f09SDavid van Moolenbroek if (parse_query(query_desc, domain, qname_len, &query_type) == -1) {
1481*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error parsing query: %s\n", query_desc);
1482*00b67f09SDavid van Moolenbroek return;
1483*00b67f09SDavid van Moolenbroek }
1484*00b67f09SDavid van Moolenbroek
1485*00b67f09SDavid van Moolenbroek if (dispatch_query(use_query_id, domain, query_type,
1486*00b67f09SDavid van Moolenbroek &qpkt, &qpkt_len) == -1) {
1487*00b67f09SDavid van Moolenbroek char *addrstr;
1488*00b67f09SDavid van Moolenbroek
1489*00b67f09SDavid van Moolenbroek if (getnameinfo(server_ai->ai_addr, server_ai->ai_addrlen,
1490*00b67f09SDavid van Moolenbroek serveraddr, sizeof(serveraddr), NULL, 0,
1491*00b67f09SDavid van Moolenbroek NI_NUMERICHOST) == 0) {
1492*00b67f09SDavid van Moolenbroek addrstr = serveraddr;
1493*00b67f09SDavid van Moolenbroek } else
1494*00b67f09SDavid van Moolenbroek addrstr = "???"; /* XXX: this should not happen */
1495*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error sending query to %s: %s\n",
1496*00b67f09SDavid van Moolenbroek addrstr, query_desc);
1497*00b67f09SDavid van Moolenbroek return;
1498*00b67f09SDavid van Moolenbroek }
1499*00b67f09SDavid van Moolenbroek
1500*00b67f09SDavid van Moolenbroek if (setup_phase == TRUE) {
1501*00b67f09SDavid van Moolenbroek set_timenow(&time_of_first_query);
1502*00b67f09SDavid van Moolenbroek time_of_first_query_sec = (double)time_of_first_query.tv_sec +
1503*00b67f09SDavid van Moolenbroek ((double)time_of_first_query.tv_usec / 1000000.0);
1504*00b67f09SDavid van Moolenbroek setup_phase = FALSE;
1505*00b67f09SDavid van Moolenbroek if (getnameinfo(server_ai->ai_addr, server_ai->ai_addrlen,
1506*00b67f09SDavid van Moolenbroek serveraddr, sizeof(serveraddr), NULL, 0,
1507*00b67f09SDavid van Moolenbroek NI_NUMERICHOST) != 0) {
1508*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error printing server address\n");
1509*00b67f09SDavid van Moolenbroek return;
1510*00b67f09SDavid van Moolenbroek }
1511*00b67f09SDavid van Moolenbroek printf("[Status] Sending queries (beginning with %s)\n",
1512*00b67f09SDavid van Moolenbroek serveraddr);
1513*00b67f09SDavid van Moolenbroek }
1514*00b67f09SDavid van Moolenbroek
1515*00b67f09SDavid van Moolenbroek /* Find the first slot in status[] that is not in use */
1516*00b67f09SDavid van Moolenbroek for (count = 0; (status[count].in_use == TRUE)
1517*00b67f09SDavid van Moolenbroek && (count < max_queries_outstanding); count++);
1518*00b67f09SDavid van Moolenbroek
1519*00b67f09SDavid van Moolenbroek if (status[count].in_use == TRUE) {
1520*00b67f09SDavid van Moolenbroek fprintf(stderr, "Unexpected error: We have run out of "
1521*00b67f09SDavid van Moolenbroek "status[] space!\n");
1522*00b67f09SDavid van Moolenbroek return;
1523*00b67f09SDavid van Moolenbroek }
1524*00b67f09SDavid van Moolenbroek
1525*00b67f09SDavid van Moolenbroek /* Register the query in status[] */
1526*00b67f09SDavid van Moolenbroek status[count].id = use_query_id;
1527*00b67f09SDavid van Moolenbroek if (verbose)
1528*00b67f09SDavid van Moolenbroek status[count].desc = strdup(query_desc);
1529*00b67f09SDavid van Moolenbroek set_timenow(&status[count].sent_timestamp);
1530*00b67f09SDavid van Moolenbroek status[count].qtype = query_type;
1531*00b67f09SDavid van Moolenbroek if (dn_expand(qpkt, qpkt + qpkt_len, qpkt + DNS_HEADERLEN,
1532*00b67f09SDavid van Moolenbroek status[count].qname, MAX_DOMAIN_LEN) == -1) {
1533*00b67f09SDavid van Moolenbroek fprintf(stderr, "Unexpected error: "
1534*00b67f09SDavid van Moolenbroek "query message doesn't have qname?\n");
1535*00b67f09SDavid van Moolenbroek return;
1536*00b67f09SDavid van Moolenbroek }
1537*00b67f09SDavid van Moolenbroek status[count].in_use = TRUE;
1538*00b67f09SDavid van Moolenbroek
1539*00b67f09SDavid van Moolenbroek if (num_queries_sent_interval == 0)
1540*00b67f09SDavid van Moolenbroek set_timenow(&time_of_first_query_interval);
1541*00b67f09SDavid van Moolenbroek
1542*00b67f09SDavid van Moolenbroek num_queries_sent++;
1543*00b67f09SDavid van Moolenbroek num_queries_sent_interval++;
1544*00b67f09SDavid van Moolenbroek num_queries_outstanding++;
1545*00b67f09SDavid van Moolenbroek }
1546*00b67f09SDavid van Moolenbroek
1547*00b67f09SDavid van Moolenbroek void
register_rtt(struct timeval * timestamp,char * qname,int qtype,unsigned int rcode)1548*00b67f09SDavid van Moolenbroek register_rtt(struct timeval *timestamp, char *qname, int qtype,
1549*00b67f09SDavid van Moolenbroek unsigned int rcode)
1550*00b67f09SDavid van Moolenbroek {
1551*00b67f09SDavid van Moolenbroek int i;
1552*00b67f09SDavid van Moolenbroek int oldquery = FALSE;
1553*00b67f09SDavid van Moolenbroek struct timeval now;
1554*00b67f09SDavid van Moolenbroek double rtt;
1555*00b67f09SDavid van Moolenbroek
1556*00b67f09SDavid van Moolenbroek set_timenow(&now);
1557*00b67f09SDavid van Moolenbroek rtt = difftv(now, *timestamp);
1558*00b67f09SDavid van Moolenbroek
1559*00b67f09SDavid van Moolenbroek if (difftv(*timestamp, time_of_first_query_interval) < 0)
1560*00b67f09SDavid van Moolenbroek oldquery = TRUE;
1561*00b67f09SDavid van Moolenbroek
1562*00b67f09SDavid van Moolenbroek if (rtt_max < 0 || rtt_max < rtt)
1563*00b67f09SDavid van Moolenbroek rtt_max = rtt;
1564*00b67f09SDavid van Moolenbroek
1565*00b67f09SDavid van Moolenbroek if (rtt_min < 0 || rtt_min > rtt)
1566*00b67f09SDavid van Moolenbroek rtt_min = rtt;
1567*00b67f09SDavid van Moolenbroek
1568*00b67f09SDavid van Moolenbroek rtt_total += rtt;
1569*00b67f09SDavid van Moolenbroek rtt_counted++;
1570*00b67f09SDavid van Moolenbroek
1571*00b67f09SDavid van Moolenbroek if (!oldquery) {
1572*00b67f09SDavid van Moolenbroek if (rtt_max_interval < 0 || rtt_max_interval < rtt)
1573*00b67f09SDavid van Moolenbroek rtt_max_interval = rtt;
1574*00b67f09SDavid van Moolenbroek
1575*00b67f09SDavid van Moolenbroek if (rtt_min_interval < 0 || rtt_min_interval > rtt)
1576*00b67f09SDavid van Moolenbroek rtt_min_interval = rtt;
1577*00b67f09SDavid van Moolenbroek
1578*00b67f09SDavid van Moolenbroek rtt_total_interval += rtt;
1579*00b67f09SDavid van Moolenbroek rtt_counted_interval++;
1580*00b67f09SDavid van Moolenbroek }
1581*00b67f09SDavid van Moolenbroek
1582*00b67f09SDavid van Moolenbroek if (rttarray == NULL)
1583*00b67f09SDavid van Moolenbroek return;
1584*00b67f09SDavid van Moolenbroek
1585*00b67f09SDavid van Moolenbroek i = (int)(rtt * (1000000.0 / rttarray_unit));
1586*00b67f09SDavid van Moolenbroek if (i < rttarray_size) {
1587*00b67f09SDavid van Moolenbroek rttarray[i]++;
1588*00b67f09SDavid van Moolenbroek if (!oldquery)
1589*00b67f09SDavid van Moolenbroek rttarray_interval[i]++;
1590*00b67f09SDavid van Moolenbroek } else {
1591*00b67f09SDavid van Moolenbroek fprintf(stderr, "Warning: RTT is out of range: %.6lf "
1592*00b67f09SDavid van Moolenbroek "[query=%s/%d, rcode=%u]\n", rtt, qname, qtype, rcode);
1593*00b67f09SDavid van Moolenbroek rtt_overflows++;
1594*00b67f09SDavid van Moolenbroek if (!oldquery)
1595*00b67f09SDavid van Moolenbroek rtt_overflows_interval++;
1596*00b67f09SDavid van Moolenbroek }
1597*00b67f09SDavid van Moolenbroek }
1598*00b67f09SDavid van Moolenbroek
1599*00b67f09SDavid van Moolenbroek /*
1600*00b67f09SDavid van Moolenbroek * register_response:
1601*00b67f09SDavid van Moolenbroek * Register receipt of a query
1602*00b67f09SDavid van Moolenbroek *
1603*00b67f09SDavid van Moolenbroek * Removes (sets in_use = FALSE) the record for the given query id in
1604*00b67f09SDavid van Moolenbroek * status[] if any exists.
1605*00b67f09SDavid van Moolenbroek */
1606*00b67f09SDavid van Moolenbroek void
register_response(unsigned short int id,unsigned int rcode,char * qname,int qtype)1607*00b67f09SDavid van Moolenbroek register_response(unsigned short int id, unsigned int rcode, char *qname,
1608*00b67f09SDavid van Moolenbroek int qtype)
1609*00b67f09SDavid van Moolenbroek {
1610*00b67f09SDavid van Moolenbroek unsigned int ct = 0;
1611*00b67f09SDavid van Moolenbroek int found = FALSE;
1612*00b67f09SDavid van Moolenbroek struct timeval now;
1613*00b67f09SDavid van Moolenbroek double rtt;
1614*00b67f09SDavid van Moolenbroek
1615*00b67f09SDavid van Moolenbroek if (timeout_queries != NULL) {
1616*00b67f09SDavid van Moolenbroek struct query_mininfo *qi = &timeout_queries[id];
1617*00b67f09SDavid van Moolenbroek
1618*00b67f09SDavid van Moolenbroek if (qi->qtype == qtype && strcasecmp(qi->qname, qname) == 0) {
1619*00b67f09SDavid van Moolenbroek register_rtt(&qi->sent_timestamp, qname, qtype, rcode);
1620*00b67f09SDavid van Moolenbroek qi->qtype = -1;
1621*00b67f09SDavid van Moolenbroek found = TRUE;
1622*00b67f09SDavid van Moolenbroek }
1623*00b67f09SDavid van Moolenbroek }
1624*00b67f09SDavid van Moolenbroek
1625*00b67f09SDavid van Moolenbroek for (; (ct < query_status_allocated) && (found == FALSE); ct++) {
1626*00b67f09SDavid van Moolenbroek if (status[ct].in_use == TRUE && status[ct].id == id &&
1627*00b67f09SDavid van Moolenbroek status[ct].qtype == qtype &&
1628*00b67f09SDavid van Moolenbroek strcasecmp(status[ct].qname, qname) == 0) {
1629*00b67f09SDavid van Moolenbroek status[ct].in_use = FALSE;
1630*00b67f09SDavid van Moolenbroek num_queries_outstanding--;
1631*00b67f09SDavid van Moolenbroek found = TRUE;
1632*00b67f09SDavid van Moolenbroek
1633*00b67f09SDavid van Moolenbroek register_rtt(&status[ct].sent_timestamp, qname, qtype,
1634*00b67f09SDavid van Moolenbroek rcode);
1635*00b67f09SDavid van Moolenbroek
1636*00b67f09SDavid van Moolenbroek if (status[ct].desc) {
1637*00b67f09SDavid van Moolenbroek printf("> %s %s\n", rcode_strings[rcode],
1638*00b67f09SDavid van Moolenbroek status[ct].desc);
1639*00b67f09SDavid van Moolenbroek free(status[ct].desc);
1640*00b67f09SDavid van Moolenbroek }
1641*00b67f09SDavid van Moolenbroek }
1642*00b67f09SDavid van Moolenbroek }
1643*00b67f09SDavid van Moolenbroek
1644*00b67f09SDavid van Moolenbroek if (countrcodes && (found == TRUE || target_qps > 0))
1645*00b67f09SDavid van Moolenbroek rcodecounts[rcode]++;
1646*00b67f09SDavid van Moolenbroek
1647*00b67f09SDavid van Moolenbroek if (found == FALSE) {
1648*00b67f09SDavid van Moolenbroek if (target_qps > 0) {
1649*00b67f09SDavid van Moolenbroek num_queries_possiblydelayed++;
1650*00b67f09SDavid van Moolenbroek num_queries_possiblydelayed_interval++;
1651*00b67f09SDavid van Moolenbroek } else {
1652*00b67f09SDavid van Moolenbroek fprintf(stderr,
1653*00b67f09SDavid van Moolenbroek "Warning: Received a response with an "
1654*00b67f09SDavid van Moolenbroek "unexpected (maybe timed out) id: %u\n", id);
1655*00b67f09SDavid van Moolenbroek }
1656*00b67f09SDavid van Moolenbroek }
1657*00b67f09SDavid van Moolenbroek }
1658*00b67f09SDavid van Moolenbroek
1659*00b67f09SDavid van Moolenbroek /*
1660*00b67f09SDavid van Moolenbroek * process_single_response:
1661*00b67f09SDavid van Moolenbroek * Receive from the given socket & process an invididual response packet.
1662*00b67f09SDavid van Moolenbroek * Remove it from the list of open queries (status[]) and decrement the
1663*00b67f09SDavid van Moolenbroek * number of outstanding queries if it matches an open query.
1664*00b67f09SDavid van Moolenbroek */
1665*00b67f09SDavid van Moolenbroek void
process_single_response(int sockfd)1666*00b67f09SDavid van Moolenbroek process_single_response(int sockfd) {
1667*00b67f09SDavid van Moolenbroek struct sockaddr_storage from_addr_ss;
1668*00b67f09SDavid van Moolenbroek struct sockaddr *from_addr;
1669*00b67f09SDavid van Moolenbroek static unsigned char in_buf[MAX_BUFFER_LEN];
1670*00b67f09SDavid van Moolenbroek char qname[MAX_DOMAIN_LEN + 1];
1671*00b67f09SDavid van Moolenbroek int numbytes, addr_len, resp_id, qnamelen;
1672*00b67f09SDavid van Moolenbroek int qtype, flags;
1673*00b67f09SDavid van Moolenbroek
1674*00b67f09SDavid van Moolenbroek memset(&from_addr_ss, 0, sizeof(from_addr_ss));
1675*00b67f09SDavid van Moolenbroek from_addr = (struct sockaddr *)&from_addr_ss;
1676*00b67f09SDavid van Moolenbroek addr_len = sizeof(from_addr_ss);
1677*00b67f09SDavid van Moolenbroek
1678*00b67f09SDavid van Moolenbroek if ((numbytes = recvfrom(sockfd, in_buf, MAX_BUFFER_LEN,
1679*00b67f09SDavid van Moolenbroek 0, from_addr, &addr_len)) == -1) {
1680*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error receiving datagram\n");
1681*00b67f09SDavid van Moolenbroek return;
1682*00b67f09SDavid van Moolenbroek }
1683*00b67f09SDavid van Moolenbroek
1684*00b67f09SDavid van Moolenbroek if (numbytes < DNS_HEADERLEN) {
1685*00b67f09SDavid van Moolenbroek if (verbose)
1686*00b67f09SDavid van Moolenbroek fprintf(stderr, "Malformed response\n");
1687*00b67f09SDavid van Moolenbroek return;
1688*00b67f09SDavid van Moolenbroek }
1689*00b67f09SDavid van Moolenbroek resp_id = get_uint16(in_buf);
1690*00b67f09SDavid van Moolenbroek flags = get_uint16(in_buf + 2);
1691*00b67f09SDavid van Moolenbroek qnamelen = dn_expand(in_buf, in_buf + numbytes, in_buf + DNS_HEADERLEN,
1692*00b67f09SDavid van Moolenbroek qname, MAX_DOMAIN_LEN);
1693*00b67f09SDavid van Moolenbroek if (qnamelen == -1) {
1694*00b67f09SDavid van Moolenbroek if (verbose)
1695*00b67f09SDavid van Moolenbroek fprintf(stderr,
1696*00b67f09SDavid van Moolenbroek "Failed to retrieve qname from response\n");
1697*00b67f09SDavid van Moolenbroek return;
1698*00b67f09SDavid van Moolenbroek }
1699*00b67f09SDavid van Moolenbroek if (numbytes < DNS_HEADERLEN + qnamelen + 2) {
1700*00b67f09SDavid van Moolenbroek if (verbose)
1701*00b67f09SDavid van Moolenbroek fprintf(stderr, "Malformed response\n");
1702*00b67f09SDavid van Moolenbroek return;
1703*00b67f09SDavid van Moolenbroek }
1704*00b67f09SDavid van Moolenbroek qtype = get_uint16(in_buf + DNS_HEADERLEN + qnamelen);
1705*00b67f09SDavid van Moolenbroek
1706*00b67f09SDavid van Moolenbroek register_response(resp_id, flags & 0xF, qname, qtype);
1707*00b67f09SDavid van Moolenbroek }
1708*00b67f09SDavid van Moolenbroek
1709*00b67f09SDavid van Moolenbroek /*
1710*00b67f09SDavid van Moolenbroek * data_available:
1711*00b67f09SDavid van Moolenbroek * Is there data available on the given file descriptor?
1712*00b67f09SDavid van Moolenbroek *
1713*00b67f09SDavid van Moolenbroek * Return TRUE if there is
1714*00b67f09SDavid van Moolenbroek * Return FALSE otherwise
1715*00b67f09SDavid van Moolenbroek */
1716*00b67f09SDavid van Moolenbroek int
data_available(double wait)1717*00b67f09SDavid van Moolenbroek data_available(double wait) {
1718*00b67f09SDavid van Moolenbroek fd_set read_fds;
1719*00b67f09SDavid van Moolenbroek struct timeval tv;
1720*00b67f09SDavid van Moolenbroek int retval;
1721*00b67f09SDavid van Moolenbroek int available = FALSE;
1722*00b67f09SDavid van Moolenbroek int maxfd = -1;
1723*00b67f09SDavid van Moolenbroek
1724*00b67f09SDavid van Moolenbroek /* Set list of file descriptors */
1725*00b67f09SDavid van Moolenbroek FD_ZERO(&read_fds);
1726*00b67f09SDavid van Moolenbroek if (socket4 != -1) {
1727*00b67f09SDavid van Moolenbroek FD_SET(socket4, &read_fds);
1728*00b67f09SDavid van Moolenbroek maxfd = socket4;
1729*00b67f09SDavid van Moolenbroek }
1730*00b67f09SDavid van Moolenbroek if (socket6 != -1) {
1731*00b67f09SDavid van Moolenbroek FD_SET(socket6, &read_fds);
1732*00b67f09SDavid van Moolenbroek if (maxfd == -1 || maxfd < socket6)
1733*00b67f09SDavid van Moolenbroek maxfd = socket6;
1734*00b67f09SDavid van Moolenbroek }
1735*00b67f09SDavid van Moolenbroek
1736*00b67f09SDavid van Moolenbroek if ((wait > 0.0) && (wait < (double)LONG_MAX)) {
1737*00b67f09SDavid van Moolenbroek tv.tv_sec = (long)floor(wait);
1738*00b67f09SDavid van Moolenbroek tv.tv_usec = (long)(1000000.0 * (wait - floor(wait)));
1739*00b67f09SDavid van Moolenbroek } else {
1740*00b67f09SDavid van Moolenbroek tv.tv_sec = 0;
1741*00b67f09SDavid van Moolenbroek tv.tv_usec = 0;
1742*00b67f09SDavid van Moolenbroek }
1743*00b67f09SDavid van Moolenbroek
1744*00b67f09SDavid van Moolenbroek retval = select(maxfd + 1, &read_fds, NULL, NULL, &tv);
1745*00b67f09SDavid van Moolenbroek
1746*00b67f09SDavid van Moolenbroek if (socket4 != -1 && FD_ISSET(socket4, &read_fds)) {
1747*00b67f09SDavid van Moolenbroek available = TRUE;
1748*00b67f09SDavid van Moolenbroek process_single_response(socket4);
1749*00b67f09SDavid van Moolenbroek }
1750*00b67f09SDavid van Moolenbroek if (socket6 != -1 && FD_ISSET(socket6, &read_fds)) {
1751*00b67f09SDavid van Moolenbroek available = TRUE;
1752*00b67f09SDavid van Moolenbroek process_single_response(socket6);
1753*00b67f09SDavid van Moolenbroek }
1754*00b67f09SDavid van Moolenbroek
1755*00b67f09SDavid van Moolenbroek return (available);
1756*00b67f09SDavid van Moolenbroek }
1757*00b67f09SDavid van Moolenbroek
1758*00b67f09SDavid van Moolenbroek /*
1759*00b67f09SDavid van Moolenbroek * process_responses:
1760*00b67f09SDavid van Moolenbroek * Go through any/all received responses and remove them from the list of
1761*00b67f09SDavid van Moolenbroek * open queries (set in_use = FALSE for their entry in status[]), also
1762*00b67f09SDavid van Moolenbroek * decrementing the number of outstanding queries.
1763*00b67f09SDavid van Moolenbroek */
1764*00b67f09SDavid van Moolenbroek void
process_responses(int adjust_rate)1765*00b67f09SDavid van Moolenbroek process_responses(int adjust_rate) {
1766*00b67f09SDavid van Moolenbroek double wait;
1767*00b67f09SDavid van Moolenbroek struct timeval now, waituntil;
1768*00b67f09SDavid van Moolenbroek double first_packet_wait = RESPONSE_BLOCKING_WAIT_TIME;
1769*00b67f09SDavid van Moolenbroek unsigned int outstanding = queries_outstanding();
1770*00b67f09SDavid van Moolenbroek
1771*00b67f09SDavid van Moolenbroek if (adjust_rate == TRUE) {
1772*00b67f09SDavid van Moolenbroek double u;
1773*00b67f09SDavid van Moolenbroek
1774*00b67f09SDavid van Moolenbroek u = time_of_first_query_sec +
1775*00b67f09SDavid van Moolenbroek query_interval * num_queries_sent;
1776*00b67f09SDavid van Moolenbroek waituntil.tv_sec = (long)floor(u);
1777*00b67f09SDavid van Moolenbroek waituntil.tv_usec = (long)(1000000.0 * (u - waituntil.tv_sec));
1778*00b67f09SDavid van Moolenbroek
1779*00b67f09SDavid van Moolenbroek /*
1780*00b67f09SDavid van Moolenbroek * Wait until a response arrives or the specified limit is
1781*00b67f09SDavid van Moolenbroek * reached.
1782*00b67f09SDavid van Moolenbroek */
1783*00b67f09SDavid van Moolenbroek while (1) {
1784*00b67f09SDavid van Moolenbroek set_timenow(&now);
1785*00b67f09SDavid van Moolenbroek wait = difftv(waituntil, now);
1786*00b67f09SDavid van Moolenbroek if (wait <= 0)
1787*00b67f09SDavid van Moolenbroek wait = 0.0;
1788*00b67f09SDavid van Moolenbroek if (data_available(wait) != TRUE)
1789*00b67f09SDavid van Moolenbroek break;
1790*00b67f09SDavid van Moolenbroek
1791*00b67f09SDavid van Moolenbroek /*
1792*00b67f09SDavid van Moolenbroek * We have reached the limit. Read as many responses
1793*00b67f09SDavid van Moolenbroek * as possible without waiting, and exit.
1794*00b67f09SDavid van Moolenbroek */
1795*00b67f09SDavid van Moolenbroek if (wait == 0) {
1796*00b67f09SDavid van Moolenbroek while (data_available(0.0) == TRUE)
1797*00b67f09SDavid van Moolenbroek ;
1798*00b67f09SDavid van Moolenbroek break;
1799*00b67f09SDavid van Moolenbroek }
1800*00b67f09SDavid van Moolenbroek }
1801*00b67f09SDavid van Moolenbroek } else {
1802*00b67f09SDavid van Moolenbroek /*
1803*00b67f09SDavid van Moolenbroek * Don't block waiting for packets at all if we aren't
1804*00b67f09SDavid van Moolenbroek * looking for any responses or if we are now able to send new
1805*00b67f09SDavid van Moolenbroek * queries.
1806*00b67f09SDavid van Moolenbroek */
1807*00b67f09SDavid van Moolenbroek if ((outstanding == 0) ||
1808*00b67f09SDavid van Moolenbroek (outstanding < max_queries_outstanding)) {
1809*00b67f09SDavid van Moolenbroek first_packet_wait = 0.0;
1810*00b67f09SDavid van Moolenbroek }
1811*00b67f09SDavid van Moolenbroek
1812*00b67f09SDavid van Moolenbroek if (data_available(first_packet_wait) == TRUE) {
1813*00b67f09SDavid van Moolenbroek while (data_available(0.0) == TRUE)
1814*00b67f09SDavid van Moolenbroek ;
1815*00b67f09SDavid van Moolenbroek }
1816*00b67f09SDavid van Moolenbroek }
1817*00b67f09SDavid van Moolenbroek }
1818*00b67f09SDavid van Moolenbroek
1819*00b67f09SDavid van Moolenbroek /*
1820*00b67f09SDavid van Moolenbroek * retire_old_queries:
1821*00b67f09SDavid van Moolenbroek * Go through the list of open queries (status[]) and remove any queries
1822*00b67f09SDavid van Moolenbroek * (i.e. set in_use = FALSE) which are older than the timeout, decrementing
1823*00b67f09SDavid van Moolenbroek * the number of queries outstanding for each one removed.
1824*00b67f09SDavid van Moolenbroek */
1825*00b67f09SDavid van Moolenbroek void
retire_old_queries(int sending)1826*00b67f09SDavid van Moolenbroek retire_old_queries(int sending) {
1827*00b67f09SDavid van Moolenbroek unsigned int count = 0;
1828*00b67f09SDavid van Moolenbroek struct timeval curr_time;
1829*00b67f09SDavid van Moolenbroek double timeout = query_timeout;
1830*00b67f09SDavid van Moolenbroek int timeout_reduced = FALSE;
1831*00b67f09SDavid van Moolenbroek
1832*00b67f09SDavid van Moolenbroek /*
1833*00b67f09SDavid van Moolenbroek * If we have target qps and would not be able to send any packets
1834*00b67f09SDavid van Moolenbroek * due to buffer full, check whether we are behind the schedule.
1835*00b67f09SDavid van Moolenbroek * If we are, purge some queries more aggressively.
1836*00b67f09SDavid van Moolenbroek */
1837*00b67f09SDavid van Moolenbroek if (target_qps > 0 && sending == TRUE && count == 0 &&
1838*00b67f09SDavid van Moolenbroek queries_outstanding() == max_queries_outstanding) {
1839*00b67f09SDavid van Moolenbroek struct timeval next, now;
1840*00b67f09SDavid van Moolenbroek double n;
1841*00b67f09SDavid van Moolenbroek
1842*00b67f09SDavid van Moolenbroek n = time_of_first_query_sec +
1843*00b67f09SDavid van Moolenbroek query_interval * num_queries_sent;
1844*00b67f09SDavid van Moolenbroek next.tv_sec = (long)floor(n);
1845*00b67f09SDavid van Moolenbroek next.tv_usec = (long)(1000000.0 * (n - next.tv_sec));
1846*00b67f09SDavid van Moolenbroek
1847*00b67f09SDavid van Moolenbroek set_timenow(&now);
1848*00b67f09SDavid van Moolenbroek if (difftv(next, now) <= 0) {
1849*00b67f09SDavid van Moolenbroek timeout_reduced = TRUE;
1850*00b67f09SDavid van Moolenbroek timeout = 0.001; /* XXX: ad-hoc value */
1851*00b67f09SDavid van Moolenbroek }
1852*00b67f09SDavid van Moolenbroek }
1853*00b67f09SDavid van Moolenbroek
1854*00b67f09SDavid van Moolenbroek set_timenow(&curr_time);
1855*00b67f09SDavid van Moolenbroek
1856*00b67f09SDavid van Moolenbroek for (; count < query_status_allocated; count++) {
1857*00b67f09SDavid van Moolenbroek if ((status[count].in_use == TRUE) &&
1858*00b67f09SDavid van Moolenbroek (difftv(curr_time,
1859*00b67f09SDavid van Moolenbroek status[count].sent_timestamp) >= (double)timeout))
1860*00b67f09SDavid van Moolenbroek {
1861*00b67f09SDavid van Moolenbroek status[count].in_use = FALSE;
1862*00b67f09SDavid van Moolenbroek num_queries_outstanding--;
1863*00b67f09SDavid van Moolenbroek
1864*00b67f09SDavid van Moolenbroek if (timeout_queries != NULL) {
1865*00b67f09SDavid van Moolenbroek struct query_mininfo *qi;
1866*00b67f09SDavid van Moolenbroek
1867*00b67f09SDavid van Moolenbroek qi = &timeout_queries[status[count].id];
1868*00b67f09SDavid van Moolenbroek if (qi->qtype != -1) {
1869*00b67f09SDavid van Moolenbroek /* now really retire this query */
1870*00b67f09SDavid van Moolenbroek num_queries_timed_out++;
1871*00b67f09SDavid van Moolenbroek num_queries_timed_out_interval++;
1872*00b67f09SDavid van Moolenbroek }
1873*00b67f09SDavid van Moolenbroek qi->qtype = status[count].qtype;
1874*00b67f09SDavid van Moolenbroek qi->sent_timestamp =
1875*00b67f09SDavid van Moolenbroek status[count].sent_timestamp;
1876*00b67f09SDavid van Moolenbroek strcpy(qi->qname, status[count].qname);
1877*00b67f09SDavid van Moolenbroek } else {
1878*00b67f09SDavid van Moolenbroek num_queries_timed_out++;
1879*00b67f09SDavid van Moolenbroek num_queries_timed_out_interval++;
1880*00b67f09SDavid van Moolenbroek }
1881*00b67f09SDavid van Moolenbroek
1882*00b67f09SDavid van Moolenbroek if (timeout_reduced == FALSE) {
1883*00b67f09SDavid van Moolenbroek if (status[count].desc) {
1884*00b67f09SDavid van Moolenbroek printf("> T %s\n", status[count].desc);
1885*00b67f09SDavid van Moolenbroek free(status[count].desc);
1886*00b67f09SDavid van Moolenbroek } else {
1887*00b67f09SDavid van Moolenbroek printf("[Timeout] Query timed out: "
1888*00b67f09SDavid van Moolenbroek "msg id %u\n",
1889*00b67f09SDavid van Moolenbroek status[count].id);
1890*00b67f09SDavid van Moolenbroek }
1891*00b67f09SDavid van Moolenbroek }
1892*00b67f09SDavid van Moolenbroek }
1893*00b67f09SDavid van Moolenbroek }
1894*00b67f09SDavid van Moolenbroek }
1895*00b67f09SDavid van Moolenbroek
1896*00b67f09SDavid van Moolenbroek /*
1897*00b67f09SDavid van Moolenbroek * print_histogram
1898*00b67f09SDavid van Moolenbroek * Print RTT histogram to the specified file in the gnuplot format
1899*00b67f09SDavid van Moolenbroek */
1900*00b67f09SDavid van Moolenbroek void
print_histogram(unsigned int total)1901*00b67f09SDavid van Moolenbroek print_histogram(unsigned int total) {
1902*00b67f09SDavid van Moolenbroek int i;
1903*00b67f09SDavid van Moolenbroek double ratio;
1904*00b67f09SDavid van Moolenbroek FILE *fp;
1905*00b67f09SDavid van Moolenbroek
1906*00b67f09SDavid van Moolenbroek if (rtt_histogram_file == NULL || rttarray == NULL)
1907*00b67f09SDavid van Moolenbroek return;
1908*00b67f09SDavid van Moolenbroek
1909*00b67f09SDavid van Moolenbroek fp = fopen((const char *)rtt_histogram_file, "w+");
1910*00b67f09SDavid van Moolenbroek if (fp == NULL) {
1911*00b67f09SDavid van Moolenbroek fprintf(stderr, "Error opening RTT histogram file: %s\n",
1912*00b67f09SDavid van Moolenbroek rtt_histogram_file);
1913*00b67f09SDavid van Moolenbroek return;
1914*00b67f09SDavid van Moolenbroek }
1915*00b67f09SDavid van Moolenbroek
1916*00b67f09SDavid van Moolenbroek for (i = 0; i < rttarray_size; i++) {
1917*00b67f09SDavid van Moolenbroek ratio = ((double)rttarray[i] / (double)total) * 100;
1918*00b67f09SDavid van Moolenbroek fprintf(fp, "%.6lf %.3lf\n",
1919*00b67f09SDavid van Moolenbroek (double)(i * rttarray_unit) +
1920*00b67f09SDavid van Moolenbroek (double)rttarray_unit / 2,
1921*00b67f09SDavid van Moolenbroek ratio);
1922*00b67f09SDavid van Moolenbroek }
1923*00b67f09SDavid van Moolenbroek
1924*00b67f09SDavid van Moolenbroek (void)fclose(fp);
1925*00b67f09SDavid van Moolenbroek }
1926*00b67f09SDavid van Moolenbroek
1927*00b67f09SDavid van Moolenbroek /*
1928*00b67f09SDavid van Moolenbroek * print_statistics:
1929*00b67f09SDavid van Moolenbroek * Print out statistics based on the results of the test
1930*00b67f09SDavid van Moolenbroek */
1931*00b67f09SDavid van Moolenbroek void
print_statistics(int intermediate,unsigned int sent,unsigned int timed_out,unsigned int possibly_delayed,struct timeval * first_query,struct timeval * program_start,struct timeval * end_perf,struct timeval * end_query,unsigned int rcounted,double rmax,double rmin,double rtotal,unsigned int roverflows,unsigned int * rarray)1932*00b67f09SDavid van Moolenbroek print_statistics(int intermediate, unsigned int sent, unsigned int timed_out,
1933*00b67f09SDavid van Moolenbroek unsigned int possibly_delayed,
1934*00b67f09SDavid van Moolenbroek struct timeval *first_query,
1935*00b67f09SDavid van Moolenbroek struct timeval *program_start,
1936*00b67f09SDavid van Moolenbroek struct timeval *end_perf, struct timeval *end_query,
1937*00b67f09SDavid van Moolenbroek unsigned int rcounted, double rmax, double rmin, double rtotal,
1938*00b67f09SDavid van Moolenbroek unsigned int roverflows, unsigned int *rarray)
1939*00b67f09SDavid van Moolenbroek {
1940*00b67f09SDavid van Moolenbroek unsigned int num_queries_completed;
1941*00b67f09SDavid van Moolenbroek double per_lost, per_completed, per_lost2, per_completed2;
1942*00b67f09SDavid van Moolenbroek double run_time, queries_per_sec, queries_per_sec2;
1943*00b67f09SDavid van Moolenbroek double queries_per_sec_total;
1944*00b67f09SDavid van Moolenbroek double rtt_average, rtt_stddev;
1945*00b67f09SDavid van Moolenbroek struct timeval start_time;
1946*00b67f09SDavid van Moolenbroek
1947*00b67f09SDavid van Moolenbroek num_queries_completed = sent - timed_out;
1948*00b67f09SDavid van Moolenbroek
1949*00b67f09SDavid van Moolenbroek if (num_queries_completed == 0) {
1950*00b67f09SDavid van Moolenbroek per_lost = 0.0;
1951*00b67f09SDavid van Moolenbroek per_completed = 0.0;
1952*00b67f09SDavid van Moolenbroek
1953*00b67f09SDavid van Moolenbroek per_lost2 = 0.0;
1954*00b67f09SDavid van Moolenbroek per_completed2 = 0.0;
1955*00b67f09SDavid van Moolenbroek } else {
1956*00b67f09SDavid van Moolenbroek per_lost = (100.0 * (double)timed_out) / (double)sent;
1957*00b67f09SDavid van Moolenbroek per_completed = 100.0 - per_lost;
1958*00b67f09SDavid van Moolenbroek
1959*00b67f09SDavid van Moolenbroek per_lost2 = (100.0 * (double)(timed_out - possibly_delayed))
1960*00b67f09SDavid van Moolenbroek / (double)sent;
1961*00b67f09SDavid van Moolenbroek per_completed2 = 100 - per_lost2;
1962*00b67f09SDavid van Moolenbroek }
1963*00b67f09SDavid van Moolenbroek
1964*00b67f09SDavid van Moolenbroek if (sent == 0) {
1965*00b67f09SDavid van Moolenbroek start_time.tv_sec = program_start->tv_sec;
1966*00b67f09SDavid van Moolenbroek start_time.tv_usec = program_start->tv_usec;
1967*00b67f09SDavid van Moolenbroek run_time = 0.0;
1968*00b67f09SDavid van Moolenbroek queries_per_sec = 0.0;
1969*00b67f09SDavid van Moolenbroek queries_per_sec2 = 0.0;
1970*00b67f09SDavid van Moolenbroek queries_per_sec_total = 0.0;
1971*00b67f09SDavid van Moolenbroek } else {
1972*00b67f09SDavid van Moolenbroek start_time.tv_sec = first_query->tv_sec;
1973*00b67f09SDavid van Moolenbroek start_time.tv_usec = first_query->tv_usec;
1974*00b67f09SDavid van Moolenbroek run_time = difftv(*end_perf, *first_query);
1975*00b67f09SDavid van Moolenbroek queries_per_sec = (double)num_queries_completed / run_time;
1976*00b67f09SDavid van Moolenbroek queries_per_sec2 = (double)(num_queries_completed +
1977*00b67f09SDavid van Moolenbroek possibly_delayed) / run_time;
1978*00b67f09SDavid van Moolenbroek
1979*00b67f09SDavid van Moolenbroek queries_per_sec_total = (double)sent /
1980*00b67f09SDavid van Moolenbroek difftv(*end_query, *first_query);
1981*00b67f09SDavid van Moolenbroek }
1982*00b67f09SDavid van Moolenbroek
1983*00b67f09SDavid van Moolenbroek if (rcounted > 0) {
1984*00b67f09SDavid van Moolenbroek int i;
1985*00b67f09SDavid van Moolenbroek double sum = 0;
1986*00b67f09SDavid van Moolenbroek
1987*00b67f09SDavid van Moolenbroek rtt_average = rtotal / (double)rcounted;
1988*00b67f09SDavid van Moolenbroek for (i = 0; i < rttarray_size; i++) {
1989*00b67f09SDavid van Moolenbroek if (rarray[i] != 0) {
1990*00b67f09SDavid van Moolenbroek double mean, diff;
1991*00b67f09SDavid van Moolenbroek
1992*00b67f09SDavid van Moolenbroek mean = (double)(i * rttarray_unit) +
1993*00b67f09SDavid van Moolenbroek (double)rttarray_unit / 2;
1994*00b67f09SDavid van Moolenbroek diff = rtt_average - (mean / 1000000.0);
1995*00b67f09SDavid van Moolenbroek sum += (diff * diff) * rarray[i];
1996*00b67f09SDavid van Moolenbroek }
1997*00b67f09SDavid van Moolenbroek }
1998*00b67f09SDavid van Moolenbroek rtt_stddev = sqrt(sum / (double)rcounted);
1999*00b67f09SDavid van Moolenbroek } else {
2000*00b67f09SDavid van Moolenbroek rtt_average = 0.0;
2001*00b67f09SDavid van Moolenbroek rtt_stddev = 0.0;
2002*00b67f09SDavid van Moolenbroek }
2003*00b67f09SDavid van Moolenbroek
2004*00b67f09SDavid van Moolenbroek printf("\n");
2005*00b67f09SDavid van Moolenbroek
2006*00b67f09SDavid van Moolenbroek printf("%sStatistics:\n", intermediate ? "Intermediate " : "");
2007*00b67f09SDavid van Moolenbroek
2008*00b67f09SDavid van Moolenbroek printf("\n");
2009*00b67f09SDavid van Moolenbroek
2010*00b67f09SDavid van Moolenbroek if (!intermediate) {
2011*00b67f09SDavid van Moolenbroek printf(" Parse input file: %s\n",
2012*00b67f09SDavid van Moolenbroek ((run_only_once == TRUE) ? "once" : "multiple times"));
2013*00b67f09SDavid van Moolenbroek if (use_timelimit)
2014*00b67f09SDavid van Moolenbroek printf(" Run time limit: %u seconds\n",
2015*00b67f09SDavid van Moolenbroek run_timelimit);
2016*00b67f09SDavid van Moolenbroek if (run_only_once == FALSE)
2017*00b67f09SDavid van Moolenbroek printf(" Ran through file: %u times\n",
2018*00b67f09SDavid van Moolenbroek runs_through_file);
2019*00b67f09SDavid van Moolenbroek else
2020*00b67f09SDavid van Moolenbroek printf(" Ended due to: reaching %s\n",
2021*00b67f09SDavid van Moolenbroek ((runs_through_file == 0) ? "time limit"
2022*00b67f09SDavid van Moolenbroek : "end of file"));
2023*00b67f09SDavid van Moolenbroek
2024*00b67f09SDavid van Moolenbroek printf("\n");
2025*00b67f09SDavid van Moolenbroek }
2026*00b67f09SDavid van Moolenbroek
2027*00b67f09SDavid van Moolenbroek printf(" Queries sent: %u queries\n", sent);
2028*00b67f09SDavid van Moolenbroek printf(" Queries completed: %u queries\n", num_queries_completed);
2029*00b67f09SDavid van Moolenbroek printf(" Queries lost: %u queries\n", timed_out);
2030*00b67f09SDavid van Moolenbroek printf(" Queries delayed(?): %u queries\n", possibly_delayed);
2031*00b67f09SDavid van Moolenbroek
2032*00b67f09SDavid van Moolenbroek printf("\n");
2033*00b67f09SDavid van Moolenbroek
2034*00b67f09SDavid van Moolenbroek printf(" RTT max: %3.6lf sec\n", rmax);
2035*00b67f09SDavid van Moolenbroek printf(" RTT min: %3.6lf sec\n", rmin);
2036*00b67f09SDavid van Moolenbroek printf(" RTT average: %3.6lf sec\n", rtt_average);
2037*00b67f09SDavid van Moolenbroek printf(" RTT std deviation: %3.6lf sec\n", rtt_stddev);
2038*00b67f09SDavid van Moolenbroek printf(" RTT out of range: %u queries\n", roverflows);
2039*00b67f09SDavid van Moolenbroek
2040*00b67f09SDavid van Moolenbroek if (!intermediate) /* XXX should we print this case also? */
2041*00b67f09SDavid van Moolenbroek print_histogram(num_queries_completed);
2042*00b67f09SDavid van Moolenbroek
2043*00b67f09SDavid van Moolenbroek printf("\n");
2044*00b67f09SDavid van Moolenbroek
2045*00b67f09SDavid van Moolenbroek if (countrcodes) {
2046*00b67f09SDavid van Moolenbroek unsigned int i;
2047*00b67f09SDavid van Moolenbroek
2048*00b67f09SDavid van Moolenbroek for (i = 0; i < 16; i++) {
2049*00b67f09SDavid van Moolenbroek if (rcodecounts[i] == 0)
2050*00b67f09SDavid van Moolenbroek continue;
2051*00b67f09SDavid van Moolenbroek printf(" Returned %8s: %u queries\n",
2052*00b67f09SDavid van Moolenbroek rcode_strings[i], rcodecounts[i]);
2053*00b67f09SDavid van Moolenbroek }
2054*00b67f09SDavid van Moolenbroek printf("\n");
2055*00b67f09SDavid van Moolenbroek }
2056*00b67f09SDavid van Moolenbroek
2057*00b67f09SDavid van Moolenbroek printf(" Percentage completed: %6.2lf%%\n", per_completed);
2058*00b67f09SDavid van Moolenbroek if (possibly_delayed > 0)
2059*00b67f09SDavid van Moolenbroek printf(" (w/ delayed qrys): %6.2lf%%\n", per_completed2);
2060*00b67f09SDavid van Moolenbroek printf(" Percentage lost: %6.2lf%%\n", per_lost);
2061*00b67f09SDavid van Moolenbroek if (possibly_delayed > 0)
2062*00b67f09SDavid van Moolenbroek printf(" (w/o delayed qrys): %6.2lf%%\n", per_lost2);
2063*00b67f09SDavid van Moolenbroek
2064*00b67f09SDavid van Moolenbroek printf("\n");
2065*00b67f09SDavid van Moolenbroek
2066*00b67f09SDavid van Moolenbroek printf(" Started at: %s",
2067*00b67f09SDavid van Moolenbroek ctime((const time_t *)&start_time.tv_sec));
2068*00b67f09SDavid van Moolenbroek printf(" Finished at: %s",
2069*00b67f09SDavid van Moolenbroek ctime((const time_t *)&end_perf->tv_sec));
2070*00b67f09SDavid van Moolenbroek printf(" Ran for: %.6lf seconds\n", run_time);
2071*00b67f09SDavid van Moolenbroek
2072*00b67f09SDavid van Moolenbroek printf("\n");
2073*00b67f09SDavid van Moolenbroek
2074*00b67f09SDavid van Moolenbroek printf(" Queries per second: %.6lf qps\n", queries_per_sec);
2075*00b67f09SDavid van Moolenbroek if (possibly_delayed > 0) {
2076*00b67f09SDavid van Moolenbroek printf(" (w/ delayed qrys): %.6lf qps\n",
2077*00b67f09SDavid van Moolenbroek queries_per_sec2);
2078*00b67f09SDavid van Moolenbroek }
2079*00b67f09SDavid van Moolenbroek if (target_qps > 0) {
2080*00b67f09SDavid van Moolenbroek printf(" Total QPS/target: %.6lf/%d qps\n",
2081*00b67f09SDavid van Moolenbroek queries_per_sec_total, target_qps);
2082*00b67f09SDavid van Moolenbroek }
2083*00b67f09SDavid van Moolenbroek
2084*00b67f09SDavid van Moolenbroek printf("\n");
2085*00b67f09SDavid van Moolenbroek }
2086*00b67f09SDavid van Moolenbroek
2087*00b67f09SDavid van Moolenbroek void
print_interval_statistics()2088*00b67f09SDavid van Moolenbroek print_interval_statistics() {
2089*00b67f09SDavid van Moolenbroek struct timeval time_now;
2090*00b67f09SDavid van Moolenbroek
2091*00b67f09SDavid van Moolenbroek if (use_timelimit == FALSE)
2092*00b67f09SDavid van Moolenbroek return;
2093*00b67f09SDavid van Moolenbroek
2094*00b67f09SDavid van Moolenbroek if (setup_phase == TRUE)
2095*00b67f09SDavid van Moolenbroek return;
2096*00b67f09SDavid van Moolenbroek
2097*00b67f09SDavid van Moolenbroek if (print_interval == 0)
2098*00b67f09SDavid van Moolenbroek return;
2099*00b67f09SDavid van Moolenbroek
2100*00b67f09SDavid van Moolenbroek if (timelimit_reached() == TRUE)
2101*00b67f09SDavid van Moolenbroek return;
2102*00b67f09SDavid van Moolenbroek
2103*00b67f09SDavid van Moolenbroek set_timenow(&time_now);
2104*00b67f09SDavid van Moolenbroek if (difftv(time_now, time_of_first_query_interval)
2105*00b67f09SDavid van Moolenbroek <= (double)print_interval)
2106*00b67f09SDavid van Moolenbroek return;
2107*00b67f09SDavid van Moolenbroek
2108*00b67f09SDavid van Moolenbroek /* Don't count currently outstanding queries */
2109*00b67f09SDavid van Moolenbroek num_queries_sent_interval -= queries_outstanding();
2110*00b67f09SDavid van Moolenbroek print_statistics(TRUE, num_queries_sent_interval,
2111*00b67f09SDavid van Moolenbroek num_queries_timed_out_interval,
2112*00b67f09SDavid van Moolenbroek num_queries_possiblydelayed_interval,
2113*00b67f09SDavid van Moolenbroek &time_of_first_query_interval,
2114*00b67f09SDavid van Moolenbroek &time_of_first_query_interval, &time_now, &time_now,
2115*00b67f09SDavid van Moolenbroek rtt_counted_interval, rtt_max_interval,
2116*00b67f09SDavid van Moolenbroek rtt_min_interval, rtt_total_interval,
2117*00b67f09SDavid van Moolenbroek rtt_overflows_interval, rttarray_interval);
2118*00b67f09SDavid van Moolenbroek
2119*00b67f09SDavid van Moolenbroek /* Reset intermediate counters */
2120*00b67f09SDavid van Moolenbroek num_queries_sent_interval = 0;
2121*00b67f09SDavid van Moolenbroek num_queries_timed_out_interval = 0;
2122*00b67f09SDavid van Moolenbroek num_queries_possiblydelayed_interval = 0;
2123*00b67f09SDavid van Moolenbroek rtt_max_interval = -1;
2124*00b67f09SDavid van Moolenbroek rtt_min_interval = -1;
2125*00b67f09SDavid van Moolenbroek rtt_total_interval = 0.0;
2126*00b67f09SDavid van Moolenbroek rtt_counted_interval = 0.0;
2127*00b67f09SDavid van Moolenbroek rtt_overflows_interval = 0;
2128*00b67f09SDavid van Moolenbroek if (rttarray_interval != NULL) {
2129*00b67f09SDavid van Moolenbroek memset(rttarray_interval, 0,
2130*00b67f09SDavid van Moolenbroek sizeof(rttarray_interval[0]) * rttarray_size);
2131*00b67f09SDavid van Moolenbroek }
2132*00b67f09SDavid van Moolenbroek }
2133*00b67f09SDavid van Moolenbroek
2134*00b67f09SDavid van Moolenbroek /*
2135*00b67f09SDavid van Moolenbroek * queryperf Program Mainline
2136*00b67f09SDavid van Moolenbroek */
2137*00b67f09SDavid van Moolenbroek int
main(int argc,char ** argv)2138*00b67f09SDavid van Moolenbroek main(int argc, char **argv) {
2139*00b67f09SDavid van Moolenbroek int adjust_rate;
2140*00b67f09SDavid van Moolenbroek int sending = FALSE;
2141*00b67f09SDavid van Moolenbroek int got_eof = FALSE;
2142*00b67f09SDavid van Moolenbroek int input_length = MAX_INPUT_LEN;
2143*00b67f09SDavid van Moolenbroek char input_line[MAX_INPUT_LEN + 1];
2144*00b67f09SDavid van Moolenbroek
2145*00b67f09SDavid van Moolenbroek set_timenow(&time_of_program_start);
2146*00b67f09SDavid van Moolenbroek time_of_first_query.tv_sec = 0;
2147*00b67f09SDavid van Moolenbroek time_of_first_query.tv_usec = 0;
2148*00b67f09SDavid van Moolenbroek time_of_first_query_interval.tv_sec = 0;
2149*00b67f09SDavid van Moolenbroek time_of_first_query_interval.tv_usec = 0;
2150*00b67f09SDavid van Moolenbroek time_of_end_of_run.tv_sec = 0;
2151*00b67f09SDavid van Moolenbroek time_of_end_of_run.tv_usec = 0;
2152*00b67f09SDavid van Moolenbroek
2153*00b67f09SDavid van Moolenbroek input_line[0] = '\0';
2154*00b67f09SDavid van Moolenbroek
2155*00b67f09SDavid van Moolenbroek show_startup_info();
2156*00b67f09SDavid van Moolenbroek
2157*00b67f09SDavid van Moolenbroek if (setup(argc, argv) == -1)
2158*00b67f09SDavid van Moolenbroek return (-1);
2159*00b67f09SDavid van Moolenbroek
2160*00b67f09SDavid van Moolenbroek /* XXX: move this to setup: */
2161*00b67f09SDavid van Moolenbroek timeout_queries = malloc(sizeof(struct query_mininfo) * 65536);
2162*00b67f09SDavid van Moolenbroek if (timeout_queries == NULL) {
2163*00b67f09SDavid van Moolenbroek fprintf(stderr,
2164*00b67f09SDavid van Moolenbroek "failed to allocate memory for timeout queries\n");
2165*00b67f09SDavid van Moolenbroek return (-1);
2166*00b67f09SDavid van Moolenbroek } else {
2167*00b67f09SDavid van Moolenbroek int i;
2168*00b67f09SDavid van Moolenbroek for (i = 0; i < 65536; i++)
2169*00b67f09SDavid van Moolenbroek timeout_queries[i].qtype = -1;
2170*00b67f09SDavid van Moolenbroek }
2171*00b67f09SDavid van Moolenbroek
2172*00b67f09SDavid van Moolenbroek printf("[Status] Processing input data\n");
2173*00b67f09SDavid van Moolenbroek
2174*00b67f09SDavid van Moolenbroek while ((sending = keep_sending(&got_eof)) == TRUE ||
2175*00b67f09SDavid van Moolenbroek queries_outstanding() > 0)
2176*00b67f09SDavid van Moolenbroek {
2177*00b67f09SDavid van Moolenbroek if (num_queries_sent_interval > 0){
2178*00b67f09SDavid van Moolenbroek /*
2179*00b67f09SDavid van Moolenbroek * After statistics are printed, send_query()
2180*00b67f09SDavid van Moolenbroek * needs to be called at least once so that
2181*00b67f09SDavid van Moolenbroek * time_of_first_query_interval is reset
2182*00b67f09SDavid van Moolenbroek */
2183*00b67f09SDavid van Moolenbroek print_interval_statistics();
2184*00b67f09SDavid van Moolenbroek }
2185*00b67f09SDavid van Moolenbroek adjust_rate = FALSE;
2186*00b67f09SDavid van Moolenbroek
2187*00b67f09SDavid van Moolenbroek while ((sending = keep_sending(&got_eof)) == TRUE &&
2188*00b67f09SDavid van Moolenbroek queries_outstanding() < max_queries_outstanding)
2189*00b67f09SDavid van Moolenbroek {
2190*00b67f09SDavid van Moolenbroek int len = next_input_line(input_line, input_length);
2191*00b67f09SDavid van Moolenbroek if (len == 0) {
2192*00b67f09SDavid van Moolenbroek got_eof = TRUE;
2193*00b67f09SDavid van Moolenbroek } else {
2194*00b67f09SDavid van Moolenbroek /* Zap the trailing newline */
2195*00b67f09SDavid van Moolenbroek if (input_line[len - 1] == '\n')
2196*00b67f09SDavid van Moolenbroek input_line[len - 1] = '\0';
2197*00b67f09SDavid van Moolenbroek
2198*00b67f09SDavid van Moolenbroek /*
2199*00b67f09SDavid van Moolenbroek * TODO: Should test if we got a whole line
2200*00b67f09SDavid van Moolenbroek * and flush to the next \n in input if not
2201*00b67f09SDavid van Moolenbroek * here... Add this later. Only do the next
2202*00b67f09SDavid van Moolenbroek * few lines if we got a whole line, else
2203*00b67f09SDavid van Moolenbroek * print a warning. Alternative: Make the
2204*00b67f09SDavid van Moolenbroek * max line size really big. BAD! :)
2205*00b67f09SDavid van Moolenbroek */
2206*00b67f09SDavid van Moolenbroek
2207*00b67f09SDavid van Moolenbroek if (input_line[0] == CONFIG_CHAR)
2208*00b67f09SDavid van Moolenbroek update_config(input_line);
2209*00b67f09SDavid van Moolenbroek else {
2210*00b67f09SDavid van Moolenbroek send_query(input_line);
2211*00b67f09SDavid van Moolenbroek if (target_qps > 0 &&
2212*00b67f09SDavid van Moolenbroek (num_queries_sent %
2213*00b67f09SDavid van Moolenbroek max_queries_outstanding) == 0) {
2214*00b67f09SDavid van Moolenbroek adjust_rate = TRUE;
2215*00b67f09SDavid van Moolenbroek }
2216*00b67f09SDavid van Moolenbroek }
2217*00b67f09SDavid van Moolenbroek }
2218*00b67f09SDavid van Moolenbroek }
2219*00b67f09SDavid van Moolenbroek
2220*00b67f09SDavid van Moolenbroek process_responses(adjust_rate);
2221*00b67f09SDavid van Moolenbroek retire_old_queries(sending);
2222*00b67f09SDavid van Moolenbroek }
2223*00b67f09SDavid van Moolenbroek
2224*00b67f09SDavid van Moolenbroek set_timenow(&time_of_end_of_run);
2225*00b67f09SDavid van Moolenbroek
2226*00b67f09SDavid van Moolenbroek printf("[Status] Testing complete\n");
2227*00b67f09SDavid van Moolenbroek
2228*00b67f09SDavid van Moolenbroek close_socket();
2229*00b67f09SDavid van Moolenbroek close_datafile();
2230*00b67f09SDavid van Moolenbroek
2231*00b67f09SDavid van Moolenbroek print_statistics(FALSE, num_queries_sent, num_queries_timed_out,
2232*00b67f09SDavid van Moolenbroek num_queries_possiblydelayed,
2233*00b67f09SDavid van Moolenbroek &time_of_first_query, &time_of_program_start,
2234*00b67f09SDavid van Moolenbroek &time_of_end_of_run, &time_of_stop_sending,
2235*00b67f09SDavid van Moolenbroek rtt_counted, rtt_max, rtt_min, rtt_total,
2236*00b67f09SDavid van Moolenbroek rtt_overflows, rttarray);
2237*00b67f09SDavid van Moolenbroek
2238*00b67f09SDavid van Moolenbroek return (0);
2239*00b67f09SDavid van Moolenbroek }
2240