#define HARD_TIMEOUT_EXTRA 5 /* in seconds */
#define RESPONSE_BLOCKING_WAIT_TIME 0.1 /* in seconds */
#define EDNSLEN 11
+#define DNS_HEADERLEN 12
#define FALSE 0
#define TRUE 1
unsigned short int id;
struct timeval sent_timestamp;
char *desc;
+ int qtype;
+ char qname[MAX_DOMAIN_LEN + 1];
+};
+
+struct query_mininfo { /* minimum info for timeout queries */
+ int qtype; /* use -1 if N/A */
+ struct timeval sent_timestamp;
+ char qname[MAX_DOMAIN_LEN + 1];
};
/*
unsigned int *rttarray_interval = NULL;
unsigned int rtt_overflows;
unsigned int rtt_overflows_interval;
+unsigned int rtt_counted;
+unsigned int rtt_counted_interval;
char *rtt_histogram_file = NULL;
struct query_status *status; /* init NULL */
static char *rcode_strings[] = RCODE_STRINGS;
+static struct query_mininfo *timeout_queries;
+
/*
* get_uint16:
* Get an unsigned short integer from a buffer (in network order)
* Return a non-negative integer otherwise
*/
int
-parse_query(char *input, char *qname, int qnlen, int *qtype) {
+parse_query(char *input, char *qname, unsigned int qnlen, int *qtype) {
static char *qtype_strings[] = QTYPE_STRINGS;
static int qtype_codes[] = QTYPE_CODES;
- int num_types, index;
+ unsigned int num_types, index;
int found = FALSE;
char incopy[MAX_INPUT_LEN + 1];
char *domain_str, *type_str;
* Return a non-negative integer otherwise
*/
int
-dispatch_query(unsigned short int id, char *dom, int qt) {
+dispatch_query(unsigned short int id, char *dom, int qt, u_char **pktp,
+ int *pktlenp)
+{
static u_char packet_buffer[PACKETSZ + 1];
int buffer_len = PACKETSZ;
int bytes_sent;
fprintf(stderr, "Warning: incomplete packet sent: %s %d\n",
dom, qt);
+ *pktp = packet_buffer;
+ *pktlenp = buffer_len;
+
return (0);
}
static unsigned short int use_query_id = 0;
static int qname_len = MAX_DOMAIN_LEN;
static char domain[MAX_DOMAIN_LEN + 1];
+ u_char *qpkt;
char serveraddr[NI_MAXHOST];
- int query_type;
+ int query_type, qpkt_len;
unsigned int count;
use_query_id++;
return;
}
- if (dispatch_query(use_query_id, domain, query_type) == -1) {
+ if (dispatch_query(use_query_id, domain, query_type,
+ &qpkt, &qpkt_len) == -1) {
char *addrstr;
if (getnameinfo(server_ai->ai_addr, server_ai->ai_addrlen,
}
/* Register the query in status[] */
- status[count].in_use = TRUE;
status[count].id = use_query_id;
if (verbose)
status[count].desc = strdup(query_desc);
set_timenow(&status[count].sent_timestamp);
+ status[count].qtype = query_type;
+ if (dn_expand(qpkt, qpkt + qpkt_len, qpkt + DNS_HEADERLEN,
+ status[count].qname, MAX_DOMAIN_LEN) == -1) {
+ fprintf(stderr, "Unexpected error: "
+ "query message doesn't have qname?\n");
+ return;
+ }
+ status[count].in_use = TRUE;
if (num_queries_sent_interval == 0)
set_timenow(&time_of_first_query_interval);
}
void
-register_rtt(struct timeval *timestamp) {
+register_rtt(struct timeval *timestamp, char *qname, int qtype,
+ unsigned int rcode)
+{
int i;
int oldquery = FALSE;
struct timeval now;
rtt_min = rtt;
rtt_total += rtt;
+ rtt_counted++;
if (!oldquery) {
if (rtt_max_interval < 0 || rtt_max_interval < rtt)
rtt_min_interval = rtt;
rtt_total_interval += rtt;
+ rtt_counted_interval++;
}
if (rttarray == NULL)
if (!oldquery)
rttarray_interval[i]++;
} else {
- fprintf(stderr, "Warning: RTT is out of range: %.6lf\n",
- rtt);
+ fprintf(stderr, "Warning: RTT is out of range: %.6lf "
+ "[query=%s/%d, rcode=%u]\n", rtt, qname, qtype, rcode);
rtt_overflows++;
if (!oldquery)
rtt_overflows_interval++;
* status[] if any exists.
*/
void
-register_response(unsigned short int id, unsigned int rcode) {
+register_response(unsigned short int id, unsigned int rcode, char *qname,
+ int qtype)
+{
unsigned int ct = 0;
int found = FALSE;
struct timeval now;
double rtt;
+ if (timeout_queries != NULL) {
+ struct query_mininfo *qi = &timeout_queries[id];
+
+ if (qi->qtype == qtype && strcasecmp(qi->qname, qname) == 0) {
+ register_rtt(&qi->sent_timestamp, qname, qtype, rcode);
+ qi->qtype = -1;
+ found = TRUE;
+ }
+ }
+
for (; (ct < query_status_allocated) && (found == FALSE); ct++) {
- if ((status[ct].in_use == TRUE) && (status[ct].id == id)) {
+ if (status[ct].in_use == TRUE && status[ct].id == id &&
+ status[ct].qtype == qtype &&
+ strcasecmp(status[ct].qname, qname) == 0) {
status[ct].in_use = FALSE;
num_queries_outstanding--;
found = TRUE;
- register_rtt(&status[ct].sent_timestamp);
+ register_rtt(&status[ct].sent_timestamp, qname, qtype,
+ rcode);
if (status[ct].desc) {
printf("> %s %s\n", rcode_strings[rcode],
status[ct].desc);
free(status[ct].desc);
}
- if (countrcodes)
- rcodecounts[rcode]++;
}
}
+ if (countrcodes && (found == TRUE || target_qps > 0))
+ rcodecounts[rcode]++;
+
if (found == FALSE) {
if (target_qps > 0) {
num_queries_possiblydelayed++;
num_queries_possiblydelayed_interval++;
} else {
- fprintf(stderr, "Warning: Received a response with an "
+ fprintf(stderr,
+ "Warning: Received a response with an "
"unexpected (maybe timed out) id: %u\n", id);
}
}
struct sockaddr_storage from_addr_ss;
struct sockaddr *from_addr;
static unsigned char in_buf[MAX_BUFFER_LEN];
- int numbytes, resp_id;
- socklen_t addr_len;
- int flags;
+ char qname[MAX_DOMAIN_LEN + 1];
+ int numbytes, addr_len, resp_id, qnamelen;
+ int qtype, flags;
memset(&from_addr_ss, 0, sizeof(from_addr_ss));
from_addr = (struct sockaddr *)&from_addr_ss;
return;
}
+ if (numbytes < DNS_HEADERLEN) {
+ if (verbose)
+ fprintf(stderr, "Malformed response\n");
+ return;
+ }
resp_id = get_uint16(in_buf);
flags = get_uint16(in_buf + 2);
+ qnamelen = dn_expand(in_buf, in_buf + numbytes, in_buf + DNS_HEADERLEN,
+ qname, MAX_DOMAIN_LEN);
+ if (qnamelen == -1) {
+ if (verbose)
+ fprintf(stderr,
+ "Failed to retrieve qname from response\n");
+ return;
+ }
+ if (numbytes < DNS_HEADERLEN + qnamelen + 2) {
+ if (verbose)
+ fprintf(stderr, "Malformed response\n");
+ return;
+ }
+ qtype = get_uint16(in_buf + DNS_HEADERLEN + qnamelen);
- register_response(resp_id, flags & 0xF);
+ register_response(resp_id, flags & 0xF, qname, qtype);
}
/*
set_timenow(&curr_time);
for (; count < query_status_allocated; count++) {
-
- if ((status[count].in_use == TRUE)
- && (difftv(curr_time, status[count].sent_timestamp)
- >= (double)timeout)) {
-
+ if ((status[count].in_use == TRUE) &&
+ (difftv(curr_time,
+ status[count].sent_timestamp) >= (double)timeout))
+ {
status[count].in_use = FALSE;
num_queries_outstanding--;
- num_queries_timed_out++;
- num_queries_timed_out_interval++;
+
+ if (timeout_queries != NULL) {
+ struct query_mininfo *qi;
+
+ qi = &timeout_queries[status[count].id];
+ if (qi->qtype != -1) {
+ /* now really retire this query */
+ num_queries_timed_out++;
+ num_queries_timed_out_interval++;
+ }
+ qi->qtype = status[count].qtype;
+ qi->sent_timestamp =
+ status[count].sent_timestamp;
+ strcpy(qi->qname, status[count].qname);
+ } else {
+ num_queries_timed_out++;
+ num_queries_timed_out_interval++;
+ }
if (timeout_reduced == FALSE) {
if (status[count].desc) {
struct timeval *first_query,
struct timeval *program_start,
struct timeval *end_perf, struct timeval *end_query,
- double rmax, double rmin, double rtotal,
+ unsigned int rcounted, double rmax, double rmin, double rtotal,
unsigned int roverflows, unsigned int *rarray)
{
unsigned int num_queries_completed;
difftv(*end_query, *first_query);
}
- if (num_queries_completed > 0) {
+ if (rcounted > 0) {
int i;
double sum = 0;
- rtt_average = rtt_total / (double)num_queries_completed;
+ rtt_average = rtotal / (double)rcounted;
for (i = 0; i < rttarray_size; i++) {
if (rarray[i] != 0) {
double mean, diff;
sum += (diff * diff) * rarray[i];
}
}
- rtt_stddev = sqrt(sum / (double)num_queries_completed);
+ rtt_stddev = sqrt(sum / (double)rcounted);
} else {
rtt_average = 0.0;
rtt_stddev = 0.0;
num_queries_possiblydelayed_interval,
&time_of_first_query_interval,
&time_of_first_query_interval, &time_now, &time_now,
- rtt_max_interval, rtt_min_interval,
- rtt_total_interval, rtt_overflows_interval,
- rttarray_interval);
+ rtt_counted_interval, rtt_max_interval,
+ rtt_min_interval, rtt_total_interval,
+ rtt_overflows_interval, rttarray_interval);
/* Reset intermediate counters */
num_queries_sent_interval = 0;
rtt_max_interval = -1;
rtt_min_interval = -1;
rtt_total_interval = 0.0;
+ rtt_counted_interval = 0.0;
rtt_overflows_interval = 0;
if (rttarray_interval != NULL) {
memset(rttarray_interval, 0,
if (setup(argc, argv) == -1)
return (-1);
+ /* XXX: move this to setup: */
+ timeout_queries = malloc(sizeof(struct query_mininfo) * 65536);
+ if (timeout_queries == NULL) {
+ fprintf(stderr,
+ "failed to allocate memory for timeout queries\n");
+ return (-1);
+ } else {
+ int i;
+ for (i = 0; i < 65536; i++)
+ timeout_queries[i].qtype = -1;
+ }
+
printf("[Status] Processing input data\n");
while ((sending = keep_sending(&got_eof)) == TRUE ||
num_queries_possiblydelayed,
&time_of_first_query, &time_of_program_start,
&time_of_end_of_run, &time_of_stop_sending,
- rtt_max, rtt_min, rtt_total, rtt_overflows, rttarray);
+ rtt_counted, rtt_max, rtt_min, rtt_total,
+ rtt_overflows, rttarray);
return (0);
}