multi-protocol support of queryperf

JINMEI Tatuya / 神明達哉 jinmei at isl.rdc.toshiba.co.jp
Thu Jul 4 05:40:01 UTC 2002


The attached patch will add an ability to support multiple protocols
(particularly IPv6) to bind9/contrib/queryperf.  The patch is for
bind-9.3.0s20020618.

I believe the patch does not affect the current behavior in a single
protocol environment.  If the patch is reasonable, please merge it to
the bind9 kit.

					JINMEI, Tatuya
					Communication Platform Lab.
					Corporate R&D Center, Toshiba Corp.
					jinmei at isl.rdc.toshiba.co.jp

--- queryperf.c.orig	Thu Jul  4 14:21:44 2002
+++ queryperf.c	Thu Jul  4 14:21:53 2002
@@ -46,7 +46,7 @@
 #define DEF_MAX_QUERIES_OUTSTANDING	20
 #define DEF_QUERY_TIMEOUT		5		/* in seconds */
 #define DEF_SERVER_TO_QUERY		"localhost"
-#define DEF_SERVER_PORT			53
+#define DEF_SERVER_PORT			"53"
 #define DEF_BUFFER_SIZE			32		/* in k */
 
 /*
@@ -113,7 +113,8 @@
 char *datafile_name;					/* init NULL */
 
 char *server_to_query;					/* init NULL */
-unsigned int server_port = DEF_SERVER_PORT;
+char *server_port = DEF_SERVER_PORT;
+struct addrinfo *server_ai;
 
 int run_only_once = FALSE;
 int use_timelimit = FALSE;
@@ -145,8 +146,7 @@
 struct query_status *status;				/* init NULL */
 unsigned int query_status_allocated;			/* init 0 */
 
-int query_socket;					/* init 0 */
-struct sockaddr_in qaddr;
+int query_socket = -1;
 
 /*
  * get_uint16:
@@ -185,7 +185,7 @@
 "                 [-b bufsize] [-t timeout] [-n] [-l limit] [-1]\n"
 "  -d specifies the input data file (default: stdin)\n"
 "  -s sets the server to query (default: %s)\n"
-"  -p sets the port on which to query the server (default: %u)\n"
+"  -p sets the port on which to query the server (default: %s)\n"
 "  -q specifies the maximum number of queries outstanding (default: %d)\n"
 "  -t specifies the timeout for query completion in seconds (default: %d)\n"
 "  -n causes configuration changes to be ignored\n"
@@ -273,14 +273,7 @@
 		return (-1);
 	}
 
-	if ((server_he = gethostbyname(new_name)) == NULL) {
-		fprintf(stderr, "Error: gethostbyname(\"%s\") failed\n",
-		        new_name);
-		return (-1);
-	}
-
 	strcpy(server_to_query, new_name);
-	qaddr.sin_addr = *((struct in_addr *)server_he->h_addr);
 
 	return (0);
 }
@@ -293,16 +286,48 @@
  *   Return a non-negative integer otherwise
  */
 int
-set_server_port(unsigned int new_port) {
-	if (new_port > MAX_PORT)
+set_server_port(char *new_port) {
+	unsigned int uint_val;
+
+	if ((is_uint(new_port, &uint_val)) != TRUE)
+		return (-1);
+
+	if (uint_val && uint_val > MAX_PORT)
 		return (-1);
 	else {
 		server_port = new_port;
-		qaddr.sin_port = htons(server_port);
 		return (0);
 	}
 }
 
+int
+set_server_sa() {
+	struct addrinfo hints, *res;
+	static struct protoent *proto;
+	int error;
+
+	if (proto == NULL && (proto = getprotobyname("udp")) == NULL) {
+		fprintf(stderr, "Error: getprotobyname call failed");
+		return (-1);
+	}
+
+	bzero(&hints, sizeof(hints));
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_protocol = proto->p_proto;
+	if ((error = getaddrinfo(server_to_query, server_port,
+				 &hints, &res)) != 0) {
+		fprintf(stderr, "Error: getaddrinfo(%s, %s) failed\n",
+			server_to_query, server_port);
+		return(-1);
+	}
+
+	/* replace the server's addrinfo */
+	if (server_ai)
+		freeaddrinfo(server_ai);
+	server_ai = res;
+	return(0);
+}
+
 /*
  * is_digit:
  *   Tests if a character is a digit
@@ -462,7 +487,7 @@
 			if (is_uint(optarg, &uint_arg_val) == TRUE &&
 			    uint_arg_val < MAX_PORT)
 			{
-				set_server_port(uint_arg_val);
+				set_server_port(optarg);
 				portset = TRUE;
 			} else {
 				fprintf(stderr, "Option requires a positive "
@@ -564,7 +589,8 @@
 
 /*
  * open_socket:
- *   Open a socket for the queries
+ *   Open a socket for the queries.  When we have an active socket already,
+ *   close it and open a new one.
  *
  *   Return -1 on failure
  *   Return a non-negative integer otherwise
@@ -572,32 +598,37 @@
 int
 open_socket(void) {
 	int sock;
-	struct protoent *proto;
-	struct sockaddr_in bind_addr;
 	int ret;
 	int bufsize;
+	struct addrinfo hints, *res;
 
-	bind_addr.sin_family = AF_INET;
-	bind_addr.sin_port = htons(0); /* Have bind allocate a random port */
-	bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-	bzero(&(bind_addr.sin_zero), 8);
-
-	if ((proto = getprotobyname("udp")) == NULL) {
-		fprintf(stderr, "Error: getprotobyname call failed");
-		return (-1);
+	bzero(&hints, sizeof(hints));
+	hints.ai_family = server_ai->ai_family;
+	hints.ai_socktype = server_ai->ai_socktype;
+	hints.ai_protocol = server_ai->ai_protocol;
+	hints.ai_flags = AI_PASSIVE;
+
+	if ((ret = getaddrinfo(NULL, "0", &hints, &res)) != 0) {
+		fprintf(stderr,
+			"Error: getaddrinfo for bind socket failed: %s\n",
+			gai_strerror(ret));
+		return(-1);
+		
 	}
 
-	if ((sock = socket(PF_INET, SOCK_DGRAM, proto->p_proto)) == -1) {
+	if ((sock = socket(res->ai_family, SOCK_DGRAM,
+			   res->ai_protocol)) == -1) {
 		fprintf(stderr, "Error: socket call failed");
-		return (-1);
+		goto fail;
 	}
 
-	if (bind(sock, (struct sockaddr *)&bind_addr, sizeof(struct sockaddr))
-	    == -1) {
+	if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
 		fprintf(stderr, "Error: bind call failed");
-		return (-1);
+		goto fail;
 	}
 
+	freeaddrinfo(res);
+
 	bufsize = 1024 * socket_bufsize;
 
 	ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
@@ -610,9 +641,16 @@
 	if (ret < 0)
 		fprintf(stderr, "Warning:  setsockbuf(SO_SNDBUF) failed\n");
 
+	close_socket();
+
 	query_socket = sock;
 	
 	return (0);
+
+ fail:
+	if (res)
+		freeaddrinfo(res);
+	return (-1);
 }
 
 /*
@@ -624,14 +662,14 @@
  */
 int
 close_socket(void) {
-	if (query_socket != 0) {
+	if (query_socket != -1) {
 		if (close(query_socket) != 0) {
 			fprintf(stderr, "Error: unable to close socket\n");
 			return (-1);
 		}
 	}
 
-	query_socket = 0;
+	query_socket = -1;
 
 	return (0);
 }
@@ -646,11 +684,6 @@
  */
 int
 setup(int argc, char **argv) {
-	qaddr.sin_family = AF_INET;
-	qaddr.sin_port = htons(0);
-	qaddr.sin_addr.s_addr = htonl(INADDR_ANY);
-	bzero(&(qaddr.sin_zero), 8);
-
 	set_input_stdin();
 
 	if (set_max_queries(DEF_MAX_QUERIES_OUTSTANDING) == -1) {
@@ -679,6 +712,9 @@
 	if (open_datafile() == -1)
 		return (-1);
 
+	if (set_server_sa() == -1)
+		return (-1);
+
 	if (open_socket() == -1)
 		return (-1);
 
@@ -857,6 +893,7 @@
 	unsigned int uint_val;
 	int directive_number;
 	int check;
+	int old_af;
 
 	if (ignore_config_changes == TRUE) {
 		fprintf(stderr, "Ignoring configuration change: %s",
@@ -910,9 +947,26 @@
 			return;
 		}
 
-		if (set_server(config_value) == -1)
+		if (set_server(config_value) == -1) {
 			fprintf(stderr, "Set server error: unable to change "
 			        "the server name to '%s'\n", config_value);
+			return;
+		}
+
+		old_af = server_ai->ai_family;
+		if (set_server_sa() == -1) {
+			fprintf(stderr, "Set server error: unable to resolve "
+				"a new server '%s'\n",
+				config_value);
+			return;
+		}
+		if (old_af != server_ai->ai_family && open_socket() == -1) {
+			/* XXX: this is fatal */
+			fprintf(stderr, "Set server error: unable to open a "
+				"new socket for '%s'\n", config_value);
+			exit(1);
+		}
+
 		break;
 
 	case V_PORT:
@@ -925,7 +979,7 @@
 		check = is_uint(config_value, &uint_val);
 
 		if ((check == TRUE) && (uint_val > 0)) {
-			if (set_server_port(uint_val) == -1) {
+			if (set_server_port(config_value) == -1) {
 				fprintf(stderr, "Invalid config: Bad value for"
 				        " %s: %s\n", directive, config_value);
 			}
@@ -971,6 +1025,14 @@
 		        directive);
 		break;
 	}
+
+	if (directive_number == V_SERVER || directive_number == V_PORT) {
+		if (set_server_sa() == -1) {
+			fprintf(stderr,
+				"Failed to set a new server or port\n");
+			return;
+		}
+	}
 }
 
 /*
@@ -1080,7 +1142,7 @@
 	packet_buffer[1] = id_ptr[1];
 
 	bytes_sent = sendto(query_socket, packet_buffer, buffer_len, 0,
-			    (struct sockaddr *)&qaddr, sockaddrlen);
+			    server_ai->ai_addr, server_ai->ai_addrlen);
 	if (bytes_sent == -1) {
 		fprintf(stderr, "Failed to send query packet: %s %d\n",
 		        dom, qt);
@@ -1215,15 +1277,18 @@
  */
 void
 process_single_response(int sockfd) {
-	static struct sockaddr_in from_addr;
+	struct sockaddr_storage from_addr_ss;
+	struct sockaddr *from_addr;
 	static unsigned char in_buf[MAX_BUFFER_LEN];
 	int numbytes, addr_len, resp_id;
 	int flags;
 
-	addr_len = sizeof(struct sockaddr);
+	memset(&from_addr_ss, 0, sizeof(from_addr_ss));
+	from_addr = (struct sockaddr *)&from_addr_ss;
+	addr_len = sizeof(from_addr_ss);
 
 	if ((numbytes = recvfrom(sockfd, in_buf, MAX_BUFFER_LEN,
-	     0, (struct sockaddr *)&from_addr, &addr_len)) == -1) {
+	     0, from_addr, &addr_len)) == -1) {
 		fprintf(stderr, "Error receiving datagram\n");
 		return;
 	}


More information about the bind-workers mailing list