📄 queryperf.c
字号:
break; default: fprintf(stderr, "Invalid config: Bad directive: %s\n", directive); break; }}/* * parse_query: * Parse a query line from the input file * * Set qname to be the domain to query (up to a max of qnlen chars) * Set qtype to be the type of the query * * Return -1 on failure * Return a non-negative integer otherwise */intparse_query(char *input, char *qname, int qnlen, int *qtype) { static char *qtype_strings[] = QTYPE_STRINGS; static int qtype_codes[] = QTYPE_CODES; int num_types, index; int found = FALSE; char incopy[MAX_INPUT_LEN + 1]; char *domain_str, *type_str; num_types = sizeof(qtype_strings) / sizeof(qtype_strings[0]); if (num_types > (sizeof(qtype_codes) / sizeof(int))) num_types = sizeof(qtype_codes) / sizeof(int); strcpy(incopy, input); domain_str = strtok(incopy, WHITESPACE); type_str = strtok(NULL, WHITESPACE); if ((domain_str == NULL) || (type_str == NULL)) { fprintf(stderr, "Invalid query input format: %s\n", input); return (-1); } if (strlen(domain_str) > qnlen) { fprintf(stderr, "Query domain too long: %s\n", domain_str); return (-1); } for (index = 0; (index < num_types) && (found == FALSE); index++) { if (strcasecmp(type_str, qtype_strings[index]) == 0) { *qtype = qtype_codes[index]; found = TRUE; } } if (found == FALSE) { fprintf(stderr, "Query type not understood: %s\n", type_str); return (-1); } strcpy(qname, domain_str); return (0);}/* * dispatch_query: * Send the query packet for the entry * * Return -1 on failure * Return a non-negative integer otherwise */intdispatch_query(unsigned short int id, char *dom, int qt) { static u_char packet_buffer[PACKETSZ + 1]; static socklen_t sockaddrlen = sizeof(struct sockaddr); int buffer_len = PACKETSZ; int bytes_sent; unsigned short int net_id = htons(id); char *id_ptr = (char *)&net_id; buffer_len = res_mkquery(QUERY, dom, C_IN, qt, NULL, 0, NULL, packet_buffer, PACKETSZ); if (buffer_len == -1) { fprintf(stderr, "Failed to create query packet: %s %d\n", dom, qt); return (-1); } if (edns) { unsigned char *p; if (buffer_len + EDNSLEN >= PACKETSZ) { fprintf(stderr, "Failed to add OPT to query packet\n"); return (-1); } packet_buffer[11] = 1; p = &packet_buffer[buffer_len]; *p++ = 0; /* root name */ *p++ = 0; *p++ = 41; /* OPT */ *p++ = 16; *p++ = 0; /* UDP payload size (4K) */ *p++ = 0; /* extended rcode */ *p++ = 0; /* version */ if (dnssec) *p++ = 0x80; /* upper flag bits - DO set */ else *p++ = 0; /* upper flag bits */ *p++ = 0; /* lower flag bit */ *p++ = 0; *p++ = 0; /* rdlen == 0 */ buffer_len += EDNSLEN; } packet_buffer[0] = id_ptr[0]; packet_buffer[1] = id_ptr[1]; bytes_sent = sendto(query_socket, packet_buffer, buffer_len, 0, (struct sockaddr *)&qaddr, sockaddrlen); if (bytes_sent == -1) { fprintf(stderr, "Failed to send query packet: %s %d\n", dom, qt); return (-1); } if (bytes_sent != buffer_len) fprintf(stderr, "Warning: incomplete packet sent: %s %d\n", dom, qt); return (0);}/* * send_query: * Send a query based on a line of input */voidsend_query(char *query_desc) { static unsigned short int use_query_id = 0; static int qname_len = MAX_DOMAIN_LEN; static char domain[MAX_DOMAIN_LEN + 1]; int query_type; unsigned int count; use_query_id++; if (parse_query(query_desc, domain, qname_len, &query_type) == -1) { fprintf(stderr, "Error parsing query: %s\n", query_desc); return; } if (dispatch_query(use_query_id, domain, query_type) == -1) { fprintf(stderr, "Error sending query: %s\n", query_desc); return; } if (setup_phase == TRUE) { set_timenow(&time_of_first_query); setup_phase = FALSE; printf("[Status] Sending queries\n"); } /* Find the first slot in status[] that is not in use */ for(count = 0; (status[count].in_use == TRUE) && (count < max_queries_outstanding); count++); if (status[count].in_use == TRUE) { fprintf(stderr, "Unexpected error: We have run out of " "status[] space!\n"); return; } /* 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); num_queries_sent++; num_queries_outstanding++;}/* * data_available: * Is there data available on the given file descriptor? * * Return TRUE if there is * Return FALSE otherwise */intdata_available(int fd, double wait) { fd_set read_fds; struct timeval tv; int retval; /* Set list of file descriptors */ FD_ZERO(&read_fds); FD_SET(fd, &read_fds); if ((wait > 0.0) && (wait < (double)LONG_MAX)) { tv.tv_sec = (long)floor(wait); tv.tv_usec = (long)(1000000.0 * (wait - floor(wait))); } else { tv.tv_sec = 0; tv.tv_usec = 0; } retval = select(fd + 1, &read_fds, NULL, NULL, &tv); if (FD_ISSET(fd, &read_fds)) return (TRUE); else return (FALSE);}/* * register_response: * Register receipt of a query * * Removes (sets in_use = FALSE) the record for the given query id in * status[] if any exists. */voidregister_response(unsigned short int id, unsigned int rcode) { unsigned int ct = 0; int found = FALSE; for(; (ct < query_status_allocated) && (found == FALSE); ct++) { if ((status[ct].in_use == TRUE) && (status[ct].id == id)) { status[ct].in_use = FALSE; num_queries_outstanding--; found = TRUE; if (status[ct].desc) { printf("> %s %s\n", rcode_strings[rcode], status[ct].desc); free(status[ct].desc); } if (countrcodes) rcodecounts[rcode]++; } } if (found == FALSE) fprintf(stderr, "Warning: Received a response with an " "unexpected (maybe timed out) id: %u\n", id);}/* * process_single_response: * Receive from the given socket & process an invididual response packet. * Remove it from the list of open queries (status[]) and decrement the * number of outstanding queries if it matches an open query. */voidprocess_single_response(int sockfd) { static struct sockaddr_in from_addr; static unsigned char in_buf[MAX_BUFFER_LEN]; int numbytes, addr_len, resp_id; int flags; addr_len = sizeof(struct sockaddr); if ((numbytes = recvfrom(sockfd, in_buf, MAX_BUFFER_LEN, 0, (struct sockaddr *)&from_addr, &addr_len)) == -1) { fprintf(stderr, "Error receiving datagram\n"); return; } resp_id = get_uint16(in_buf); flags = get_uint16(in_buf + 2); register_response(resp_id, flags & 0xF);}/* * process_responses: * Go through any/all received responses and remove them from the list of * open queries (set in_use = FALSE for their entry in status[]), also * decrementing the number of outstanding queries. */voidprocess_responses(void) { double first_packet_wait = RESPONSE_BLOCKING_WAIT_TIME; unsigned int outstanding = queries_outstanding(); /* * Don't block waiting for packets at all if we aren't looking for * any responses or if we are now able to send new queries. */ if ((outstanding == 0) || (outstanding < max_queries_outstanding)) { first_packet_wait = 0.0; } if (data_available(query_socket, first_packet_wait) == TRUE) { process_single_response(query_socket); while (data_available(query_socket, 0.0) == TRUE) process_single_response(query_socket); }}/* * retire_old_queries: * Go through the list of open queries (status[]) and remove any queries * (i.e. set in_use = FALSE) which are older than the timeout, decrementing * the number of queries outstanding for each one removed. */voidretire_old_queries(void) { unsigned int count = 0; struct timeval curr_time; set_timenow(&curr_time); for(; count < query_status_allocated; count++) { if ((status[count].in_use == TRUE) && (difftv(curr_time, status[count].sent_timestamp) >= (double)query_timeout)) { status[count].in_use = FALSE; num_queries_outstanding--; num_queries_timed_out++; if (status[count].desc) { printf("> T %s\n", status[count].desc); free(status[count].desc); } else { printf("[Timeout] Query timed out: msg id %u\n", status[count].id); } } }}/* * print_statistics: * Print out statistics based on the results of the test */voidprint_statistics(void) { unsigned int num_queries_completed; double per_lost, per_completed; double run_time, queries_per_sec; struct timeval start_time; num_queries_completed = num_queries_sent - num_queries_timed_out; if (num_queries_completed == 0) { per_lost = 0.0; per_completed = 0.0; } else { per_lost = 100.0 * (double)num_queries_timed_out / (double)num_queries_sent; per_completed = 100.0 - per_lost; } if (num_queries_sent == 0) { start_time.tv_sec = time_of_program_start.tv_sec; start_time.tv_usec = time_of_program_start.tv_usec; run_time = 0.0; queries_per_sec = 0.0; } else { start_time.tv_sec = time_of_first_query.tv_sec; start_time.tv_usec = time_of_first_query.tv_usec; run_time = difftv(time_of_end_of_run, time_of_first_query); queries_per_sec = (double)num_queries_completed / run_time; } printf("\n"); printf("Statistics:\n"); printf("\n"); printf(" Parse input file: %s\n", ((run_only_once == TRUE) ? "once" : "multiple times")); if (use_timelimit) printf(" Run time limit: %u seconds\n", run_timelimit); if (run_only_once == FALSE) printf(" Ran through file: %u times\n", runs_through_file); else printf(" Ended due to: reaching %s\n", ((runs_through_file == 0) ? "time limit" : "end of file")); printf("\n"); printf(" Queries sent: %u queries\n", num_queries_sent); printf(" Queries completed: %u queries\n", num_queries_completed); printf(" Queries lost: %u queries\n", num_queries_timed_out); printf("\n"); if (countrcodes) { unsigned int i; for (i = 0; i < 16; i++) { if (rcodecounts[i] == 0) continue; printf(" Returned %8s: %u queries\n", rcode_strings[i], rcodecounts[i]); } printf("\n"); } printf(" Percentage completed: %6.2lf%%\n", per_completed); printf(" Percentage lost: %6.2lf%%\n", per_lost); printf("\n"); printf(" Started at: %s", ctime(&start_time.tv_sec)); printf(" Finished at: %s", ctime(&time_of_end_of_run.tv_sec)); printf(" Ran for: %.6lf seconds\n", run_time); printf("\n"); printf(" Queries per second: %.6lf qps\n", queries_per_sec); printf("\n");}/* * dnsqtest Program Mainline */intmain(int argc, char **argv) { int got_eof = FALSE; int input_length = MAX_INPUT_LEN; char input_line[MAX_INPUT_LEN + 1]; set_timenow(&time_of_program_start); time_of_first_query.tv_sec = 0; time_of_first_query.tv_usec = 0; time_of_end_of_run.tv_sec = 0; time_of_end_of_run.tv_usec = 0; input_line[0] = '\0'; show_startup_info(); if (setup(argc, argv) == -1) return (-1); printf("[Status] Processing input data\n"); while (keep_sending(&got_eof) == TRUE || queries_outstanding() > 0) { while (keep_sending(&got_eof) == TRUE && queries_outstanding() < max_queries_outstanding) { int len = next_input_line(input_line, input_length); if (len == 0) { got_eof = TRUE; } else { /* Zap the trailing newline */ if (input_line[len - 1] == '\n') input_line[len - 1] = '\0'; /* * TODO: Should test if we got a whole line * and flush to the next \n in input if not * here... Add this later. Only do the next * few lines if we got a whole line, else * print a warning. Alternative: Make the * max line size really big. BAD! :) */ if (input_line[0] == CONFIG_CHAR) update_config(input_line); else { send_query(input_line); } } } retire_old_queries(); process_responses(); } set_timenow(&time_of_end_of_run); printf("[Status] Testing complete\n"); close_socket(); close_datafile(); print_statistics(); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -