c2d2c5
From 4d55e959839e1bc8e43124648742056ac2c802e7 Mon Sep 17 00:00:00 2001
c2d2c5
From: Evan Hunt <each@isc.org>
c2d2c5
Date: Tue, 20 Jan 2015 16:10:30 -0800
c2d2c5
Subject: [PATCH] add TCP pipelining support
c2d2c5
c2d2c5
4040.	[func]		Added server-side support for pipelined TCP
c2d2c5
			queries. TCP connections are no longer closed after
c2d2c5
			the first query received from a client. (The new
c2d2c5
			"keep-response-order" option allows clients to be
c2d2c5
			specified for which the old behavior will still be
c2d2c5
			used.) [RT #37821]
c2d2c5
c2d2c5
(cherry picked from commit 761d135ed686601f36fe3d0d4aaa6bf41287bb0f)
c2d2c5
c2d2c5
Modified default value of keep-response-order ACL to any, for best backward
c2d2c5
compatibility. Upstream default is none;
c2d2c5
---
c2d2c5
 bin/named/client.c                            | 123 ++++++-
c2d2c5
 bin/named/config.c                            |   3 +-
c2d2c5
 bin/named/include/named/client.h              |   1 +
c2d2c5
 bin/named/include/named/server.h              |   1 +
c2d2c5
 bin/named/named.conf.docbook                  |   1 +
c2d2c5
 bin/named/server.c                            |   8 +
c2d2c5
 bin/tests/named.conf                          |   3 +-
c2d2c5
 bin/tests/system/Makefile.in                  |   4 +-
c2d2c5
 .../checkconf/bad-keep-response-order.conf    |  21 ++
c2d2c5
 bin/tests/system/checkconf/bad-many.conf      |   3 +-
c2d2c5
 bin/tests/system/checkconf/good.conf          |   3 +
c2d2c5
 bin/tests/system/conf.sh.in                   |   2 +-
c2d2c5
 bin/tests/system/pipelined/Makefile.in        |  51 +++
c2d2c5
 bin/tests/system/pipelined/clean.sh           |  19 +
c2d2c5
 bin/tests/system/pipelined/input              |   8 +
c2d2c5
 bin/tests/system/pipelined/inputb             |   8 +
c2d2c5
 bin/tests/system/pipelined/ns1/named.conf     |  43 +++
c2d2c5
 bin/tests/system/pipelined/ns1/root.db        |  30 ++
c2d2c5
 bin/tests/system/pipelined/ns2/examplea.db    |  35 ++
c2d2c5
 bin/tests/system/pipelined/ns2/named.conf     |  49 +++
c2d2c5
 bin/tests/system/pipelined/ns3/exampleb.db    |  35 ++
c2d2c5
 bin/tests/system/pipelined/ns3/named.args     |   1 +
c2d2c5
 bin/tests/system/pipelined/ns3/named.conf     |  49 +++
c2d2c5
 bin/tests/system/pipelined/ns4/named.conf     |  45 +++
c2d2c5
 bin/tests/system/pipelined/pipequeries.c      | 346 ++++++++++++++++++
c2d2c5
 bin/tests/system/pipelined/ref                |   8 +
c2d2c5
 bin/tests/system/pipelined/refb               |   8 +
c2d2c5
 bin/tests/system/pipelined/setup.sh           |  22 ++
c2d2c5
 bin/tests/system/pipelined/tests.sh           |  41 +++
c2d2c5
 configure                                     |   1 +
c2d2c5
 configure.in                                  |   1 +
c2d2c5
 doc/arm/Bv9ARM-book.xml                       |  19 +-
c2d2c5
 doc/misc/options                              |   1 +
c2d2c5
 lib/bind9/check.c                             |   4 +-
c2d2c5
 lib/dns/dispatch.c                            |  22 +-
c2d2c5
 lib/isccfg/namedconf.c                        |   1 +
c2d2c5
 36 files changed, 985 insertions(+), 35 deletions(-)
c2d2c5
 create mode 100644 bin/tests/system/checkconf/bad-keep-response-order.conf
c2d2c5
 create mode 100644 bin/tests/system/pipelined/Makefile.in
c2d2c5
 create mode 100644 bin/tests/system/pipelined/clean.sh
c2d2c5
 create mode 100644 bin/tests/system/pipelined/input
c2d2c5
 create mode 100644 bin/tests/system/pipelined/inputb
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns1/named.conf
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns1/root.db
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns2/examplea.db
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns2/named.conf
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns3/exampleb.db
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns3/named.args
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns3/named.conf
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ns4/named.conf
c2d2c5
 create mode 100644 bin/tests/system/pipelined/pipequeries.c
c2d2c5
 create mode 100644 bin/tests/system/pipelined/ref
c2d2c5
 create mode 100644 bin/tests/system/pipelined/refb
c2d2c5
 create mode 100644 bin/tests/system/pipelined/setup.sh
c2d2c5
 create mode 100644 bin/tests/system/pipelined/tests.sh
c2d2c5
c2d2c5
diff --git a/bin/named/client.c b/bin/named/client.c
c2d2c5
index 9adf36b..f014b61 100644
c2d2c5
--- a/bin/named/client.c
c2d2c5
+++ b/bin/named/client.c
c2d2c5
@@ -233,6 +233,8 @@ static void client_request(isc_task_t *task, isc_event_t *event);
c2d2c5
 static void ns_client_dumpmessage(ns_client_t *client, const char *reason);
c2d2c5
 static isc_result_t get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
c2d2c5
 			       dns_dispatch_t *disp, isc_boolean_t tcp);
c2d2c5
+static isc_result_t get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp,
c2d2c5
+			       isc_socket_t *socket);
c2d2c5
 
c2d2c5
 void
c2d2c5
 ns_client_recursing(ns_client_t *client) {
c2d2c5
@@ -367,9 +369,13 @@ exit_check(ns_client_t *client) {
c2d2c5
 		INSIST(client->recursionquota == NULL);
c2d2c5
 
c2d2c5
 		if (NS_CLIENTSTATE_READING == client->newstate) {
c2d2c5
-			client_read(client);
c2d2c5
-			client->newstate = NS_CLIENTSTATE_MAX;
c2d2c5
-			return (ISC_TRUE); /* We're done. */
c2d2c5
+			if (!client->pipelined) {
c2d2c5
+				client_read(client);
c2d2c5
+				client->newstate = NS_CLIENTSTATE_MAX;
c2d2c5
+				return (ISC_TRUE); /* We're done. */
c2d2c5
+			} else if (client->mortal) {
c2d2c5
+				client->newstate = NS_CLIENTSTATE_INACTIVE;
c2d2c5
+			}
c2d2c5
 		}
c2d2c5
 	}
c2d2c5
 
c2d2c5
@@ -406,6 +412,8 @@ exit_check(ns_client_t *client) {
c2d2c5
 			client->timerset = ISC_FALSE;
c2d2c5
 		}
c2d2c5
 
c2d2c5
+		client->pipelined = ISC_FALSE;
c2d2c5
+
c2d2c5
 		client->peeraddr_valid = ISC_FALSE;
c2d2c5
 
c2d2c5
 		client->state = NS_CLIENTSTATE_READY;
c2d2c5
@@ -605,7 +613,11 @@ client_start(isc_task_t *task, isc_event_t *event) {
c2d2c5
 		return;
c2d2c5
 
c2d2c5
 	if (TCP_CLIENT(client)) {
c2d2c5
-		client_accept(client);
c2d2c5
+		if (client->pipelined) {
c2d2c5
+			client_read(client);
c2d2c5
+		} else {
c2d2c5
+			client_accept(client);
c2d2c5
+		}
c2d2c5
 	} else {
c2d2c5
 		client_udprecv(client);
c2d2c5
 	}
c2d2c5
@@ -1638,6 +1650,24 @@ client_request(isc_task_t *task, isc_event_t *event) {
c2d2c5
 		goto cleanup;
c2d2c5
 	}
c2d2c5
 
c2d2c5
+	/*
c2d2c5
+	 * Pipeline TCP query processing.
c2d2c5
+	 */
c2d2c5
+	if (client->message->opcode != dns_opcode_query)
c2d2c5
+		client->pipelined = ISC_FALSE;
c2d2c5
+	if (TCP_CLIENT(client) && client->pipelined) {
c2d2c5
+		result = isc_quota_reserve(&ns_g_server->tcpquota);
c2d2c5
+		if (result == ISC_R_SUCCESS)
c2d2c5
+			result = ns_client_replace(client);
c2d2c5
+		if (result != ISC_R_SUCCESS) {
c2d2c5
+			ns_client_log(client, NS_LOGCATEGORY_CLIENT,
c2d2c5
+				      NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
c2d2c5
+				      "no more TCP clients(read): %s",
c2d2c5
+				      isc_result_totext(result));
c2d2c5
+			client->pipelined = ISC_FALSE;
c2d2c5
+		}
c2d2c5
+	}
c2d2c5
+
c2d2c5
 	dns_opcodestats_increment(ns_g_server->opcodestats,
c2d2c5
 				  client->message->opcode);
c2d2c5
 	switch (client->message->opcode) {
c2d2c5
@@ -2138,6 +2168,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) {
c2d2c5
 	client->signer = NULL;
c2d2c5
 	dns_name_init(&client->signername, NULL);
c2d2c5
 	client->mortal = ISC_FALSE;
c2d2c5
+	client->pipelined = ISC_FALSE;
c2d2c5
 	client->tcpquota = NULL;
c2d2c5
 	client->recursionquota = NULL;
c2d2c5
 	client->interface = NULL;
c2d2c5
@@ -2326,6 +2357,7 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
c2d2c5
 		 * telnetting to port 53 (once per CPU) will
c2d2c5
 		 * deny service to legitimate TCP clients.
c2d2c5
 		 */
c2d2c5
+		client->pipelined = ISC_FALSE;
c2d2c5
 		result = isc_quota_attach(&ns_g_server->tcpquota,
c2d2c5
 					  &client->tcpquota);
c2d2c5
 		if (result == ISC_R_SUCCESS)
c2d2c5
@@ -2333,8 +2365,12 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
c2d2c5
 		if (result != ISC_R_SUCCESS) {
c2d2c5
 			ns_client_log(client, NS_LOGCATEGORY_CLIENT,
c2d2c5
 				      NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
c2d2c5
-				      "no more TCP clients: %s",
c2d2c5
+				      "no more TCP clients(accept): %s",
c2d2c5
 				      isc_result_totext(result));
c2d2c5
+		} else if (ns_g_server->keepresporder == NULL ||
c2d2c5
+			   !allowed(&netaddr, NULL, NULL, 0, NULL,
c2d2c5
+				    ns_g_server->keepresporder)) {
c2d2c5
+			client->pipelined = ISC_TRUE;
c2d2c5
 		}
c2d2c5
 
c2d2c5
 		client_read(client);
c2d2c5
@@ -2432,14 +2468,21 @@ ns_client_shuttingdown(ns_client_t *client) {
c2d2c5
 isc_result_t
c2d2c5
 ns_client_replace(ns_client_t *client) {
c2d2c5
 	isc_result_t result;
c2d2c5
+	isc_boolean_t tcp;
c2d2c5
 
c2d2c5
 	CTRACE("replace");
c2d2c5
 
c2d2c5
 	REQUIRE(client != NULL);
c2d2c5
 	REQUIRE(client->manager != NULL);
c2d2c5
 
c2d2c5
-	result = get_client(client->manager, client->interface,
c2d2c5
-			    client->dispatch, TCP_CLIENT(client));
c2d2c5
+	tcp = TCP_CLIENT(client);
c2d2c5
+	if (tcp && client->pipelined) {
c2d2c5
+		result = get_worker(client->manager, client->interface,
c2d2c5
+				    client->tcpsocket);
c2d2c5
+	} else {
c2d2c5
+		result = get_client(client->manager, client->interface,
c2d2c5
+				    client->dispatch, tcp);
c2d2c5
+	}
c2d2c5
 	if (result != ISC_R_SUCCESS)
c2d2c5
 		return (result);
c2d2c5
 
c2d2c5
@@ -2644,6 +2687,72 @@ get_client(ns_clientmgr_t *manager, ns_interface_t *ifp,
c2d2c5
 	return (ISC_R_SUCCESS);
c2d2c5
 }
c2d2c5
 
c2d2c5
+static isc_result_t
c2d2c5
+get_worker(ns_clientmgr_t *manager, ns_interface_t *ifp, isc_socket_t *socket)
c2d2c5
+{
c2d2c5
+	isc_result_t result = ISC_R_SUCCESS;
c2d2c5
+	isc_event_t *ev;
c2d2c5
+	ns_client_t *client;
c2d2c5
+	MTRACE("get worker");
c2d2c5
+
c2d2c5
+	REQUIRE(manager != NULL);
c2d2c5
+
c2d2c5
+	if (manager->exiting)
c2d2c5
+		return (ISC_R_SHUTTINGDOWN);
c2d2c5
+
c2d2c5
+	/*
c2d2c5
+	 * Allocate a client.  First try to get a recycled one;
c2d2c5
+	 * if that fails, make a new one.
c2d2c5
+	 */
c2d2c5
+	client = NULL;
c2d2c5
+	if (!ns_g_clienttest)
c2d2c5
+		ISC_QUEUE_POP(manager->inactive, ilink, client);
c2d2c5
+
c2d2c5
+	if (client != NULL)
c2d2c5
+		MTRACE("recycle");
c2d2c5
+	else {
c2d2c5
+		MTRACE("create new");
c2d2c5
+
c2d2c5
+		LOCK(&manager->lock);
c2d2c5
+		result = client_create(manager, &client);
c2d2c5
+		UNLOCK(&manager->lock);
c2d2c5
+		if (result != ISC_R_SUCCESS)
c2d2c5
+			return (result);
c2d2c5
+
c2d2c5
+		LOCK(&manager->listlock);
c2d2c5
+		ISC_LIST_APPEND(manager->clients, client, link);
c2d2c5
+		UNLOCK(&manager->listlock);
c2d2c5
+	}
c2d2c5
+
c2d2c5
+	client->manager = manager;
c2d2c5
+	ns_interface_attach(ifp, &client->interface);
c2d2c5
+	client->newstate = client->state = NS_CLIENTSTATE_WORKING;
c2d2c5
+	INSIST(client->recursionquota == NULL);
c2d2c5
+	client->tcpquota = &ns_g_server->tcpquota;
c2d2c5
+
c2d2c5
+	client->dscp = ifp->dscp;
c2d2c5
+
c2d2c5
+	client->attributes |= NS_CLIENTATTR_TCP;
c2d2c5
+	client->pipelined = ISC_TRUE;
c2d2c5
+
c2d2c5
+	isc_socket_attach(ifp->tcpsocket, &client->tcplistener);
c2d2c5
+	isc_socket_attach(socket, &client->tcpsocket);
c2d2c5
+	isc_socket_setname(client->tcpsocket, "worker-tcp", NULL);
c2d2c5
+	(void)isc_socket_getpeername(client->tcpsocket, &client->peeraddr);
c2d2c5
+	client->peeraddr_valid = ISC_TRUE;
c2d2c5
+
c2d2c5
+	INSIST(client->tcpmsg_valid == ISC_FALSE);
c2d2c5
+	dns_tcpmsg_init(client->mctx, client->tcpsocket, &client->tcpmsg);
c2d2c5
+	client->tcpmsg_valid = ISC_TRUE;
c2d2c5
+
c2d2c5
+	INSIST(client->nctls == 0);
c2d2c5
+	client->nctls++;
c2d2c5
+	ev = &client->ctlevent;
c2d2c5
+	isc_task_send(client->task, &ev;;
c2d2c5
+
c2d2c5
+	return (ISC_R_SUCCESS);
c2d2c5
+}
c2d2c5
+
c2d2c5
 isc_result_t
c2d2c5
 ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
c2d2c5
 			   ns_interface_t *ifp, isc_boolean_t tcp)
c2d2c5
diff --git a/bin/named/config.c b/bin/named/config.c
c2d2c5
index 22d8a85..f0db926 100644
c2d2c5
--- a/bin/named/config.c
c2d2c5
+++ b/bin/named/config.c
c2d2c5
@@ -72,6 +72,7 @@ options {\n\
c2d2c5
 	heartbeat-interval 60;\n\
c2d2c5
 	host-statistics no;\n\
c2d2c5
 	interface-interval 60;\n\
c2d2c5
+#	keep-response-order {any;};\n\
c2d2c5
 	listen-on {any;};\n\
c2d2c5
 	listen-on-v6 {none;};\n\
c2d2c5
 	match-mapped-addresses no;\n\
c2d2c5
@@ -101,7 +102,7 @@ options {\n\
c2d2c5
 	server-id none;\n\
c2d2c5
 	statistics-file \"named.stats\";\n\
c2d2c5
 	statistics-interval 60;\n\
c2d2c5
-	tcp-clients 100;\n\
c2d2c5
+	tcp-clients 150;\n\
c2d2c5
 	tcp-listen-queue 10;\n\
c2d2c5
 #	tkey-dhkey <none>\n\
c2d2c5
 #	tkey-gssapi-credential <none>\n\
c2d2c5
diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h
c2d2c5
index 98e79df..bf4d201 100644
c2d2c5
--- a/bin/named/include/named/client.h
c2d2c5
+++ b/bin/named/include/named/client.h
c2d2c5
@@ -133,6 +133,7 @@ struct ns_client {
c2d2c5
 	dns_name_t		signername;   /*%< [T]SIG key name */
c2d2c5
 	dns_name_t *		signer;	      /*%< NULL if not valid sig */
c2d2c5
 	isc_boolean_t		mortal;	      /*%< Die after handling request */
c2d2c5
+	isc_boolean_t		pipelined;   /*%< TCP queries not in sequence */
c2d2c5
 	isc_quota_t		*tcpquota;
c2d2c5
 	isc_quota_t		*recursionquota;
c2d2c5
 	ns_interface_t		*interface;
c2d2c5
diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h
c2d2c5
index 0107b51..5f36177 100644
c2d2c5
--- a/bin/named/include/named/server.h
c2d2c5
+++ b/bin/named/include/named/server.h
c2d2c5
@@ -53,6 +53,7 @@ struct ns_server {
c2d2c5
 	isc_quota_t		tcpquota;
c2d2c5
 	isc_quota_t		recursionquota;
c2d2c5
 	dns_acl_t		*blackholeacl;
c2d2c5
+	dns_acl_t		*keepresporder;
c2d2c5
 	char *			statsfile;	/*%< Statistics file name */
c2d2c5
 	char *			dumpfile;	/*%< Dump file name */
c2d2c5
 	char *			secrootsfile;	/*%< Secroots file name */
c2d2c5
diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook
c2d2c5
index a8cd31e..4d502ac 100644
c2d2c5
--- a/bin/named/named.conf.docbook
c2d2c5
+++ b/bin/named/named.conf.docbook
c2d2c5
@@ -209,6 +209,7 @@ options {
c2d2c5
 	host-statistics-max <replaceable>number</replaceable>; // not implemented
c2d2c5
 	hostname ( <replaceable>quoted_string</replaceable> | none );
c2d2c5
 	interface-interval <replaceable>integer</replaceable>;
c2d2c5
+	keep-response-order { <replaceable>address_match_element</replaceable>; ... };
c2d2c5
 	listen-on <optional> port <replaceable>integer</replaceable> </optional> { <replaceable>address_match_element</replaceable>; ... };
c2d2c5
 	listen-on-v6 <optional> port <replaceable>integer</replaceable> </optional> { <replaceable>address_match_element</replaceable>; ... };
c2d2c5
 	match-mapped-addresses <replaceable>boolean</replaceable>;
c2d2c5
diff --git a/bin/named/server.c b/bin/named/server.c
c2d2c5
index e8f19d3..e30bf16 100644
c2d2c5
--- a/bin/named/server.c
c2d2c5
+++ b/bin/named/server.c
c2d2c5
@@ -5207,6 +5207,10 @@ load_configuration(const char *filename, ns_server_t *server,
c2d2c5
 		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr,
c2d2c5
 					     server->blackholeacl);
c2d2c5
 
c2d2c5
+	CHECK(configure_view_acl(NULL, config, "keep-response-order", NULL,
c2d2c5
+				 ns_g_aclconfctx, ns_g_mctx,
c2d2c5
+				 &server->keepresporder));
c2d2c5
+
c2d2c5
 	obj = NULL;
c2d2c5
 	result = ns_config_get(maps, "match-mapped-addresses", &obj);
c2d2c5
 	INSIST(result == ISC_R_SUCCESS);
c2d2c5
@@ -6208,6 +6212,9 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
c2d2c5
 		dns_name_free(&ns_g_sessionkeyname, server->mctx);
c2d2c5
 	}
c2d2c5
 
c2d2c5
+	if (server->keepresporder != NULL)
c2d2c5
+		dns_acl_detach(&server->keepresporder);
c2d2c5
+
c2d2c5
 	if (server->blackholeacl != NULL)
c2d2c5
 		dns_acl_detach(&server->blackholeacl);
c2d2c5
 
c2d2c5
@@ -6259,6 +6266,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
c2d2c5
 	ISC_LIST_INIT(server->viewlist);
c2d2c5
 	server->in_roothints = NULL;
c2d2c5
 	server->blackholeacl = NULL;
c2d2c5
+	server->keepresporder = NULL;
c2d2c5
 
c2d2c5
 	/* Must be first. */
c2d2c5
 	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
c2d2c5
diff --git a/bin/tests/named.conf b/bin/tests/named.conf
c2d2c5
index 722d262..5b40045 100644
c2d2c5
--- a/bin/tests/named.conf
c2d2c5
+++ b/bin/tests/named.conf
c2d2c5
@@ -1,5 +1,5 @@
c2d2c5
 /*
c2d2c5
- * Copyright (C) 2004, 2007, 2011  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ * Copyright (C) 2004, 2007, 2011, 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
  * Copyright (C) 1999-2001  Internet Software Consortium.
c2d2c5
  *
c2d2c5
  * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
@@ -116,6 +116,7 @@ options {
c2d2c5
 	allow-transfer { any; };
c2d2c5
 	allow-recursion { !any; };
c2d2c5
 	blackhole { 45/24; };
c2d2c5
+	keep-response-order { 46/24; };
c2d2c5
 
c2d2c5
 	listen-on {
c2d2c5
 		10/24;
c2d2c5
diff --git a/bin/tests/system/Makefile.in b/bin/tests/system/Makefile.in
c2d2c5
index afee71b..e7eaef7 100644
c2d2c5
--- a/bin/tests/system/Makefile.in
c2d2c5
+++ b/bin/tests/system/Makefile.in
c2d2c5
@@ -21,8 +21,8 @@ top_srcdir =	@top_srcdir@
c2d2c5
 
c2d2c5
 @BIND9_MAKE_INCLUDES@
c2d2c5
 
c2d2c5
-SUBDIRS =	dlzexternal dyndb filter-aaaa geoip lwresd rpz rrl \
c2d2c5
-		rsabigexponent tkey tsiggss
c2d2c5
+SUBDIRS =	dlzexternal dyndb filter-aaaa geoip lwresd pipelined \
c2d2c5
+		rpz rrl rsabigexponent tkey tsiggss
c2d2c5
 CINCLUDES =	${ISC_INCLUDES} ${DNS_INCLUDES}
c2d2c5
 
c2d2c5
 CDEFINES =	@USE_GSSAPI@
c2d2c5
diff --git a/bin/tests/system/checkconf/bad-keep-response-order.conf b/bin/tests/system/checkconf/bad-keep-response-order.conf
c2d2c5
new file mode 100644
c2d2c5
index 0000000..24c1f6c
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/checkconf/bad-keep-response-order.conf
c2d2c5
@@ -0,0 +1,21 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2015  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+options {
c2d2c5
+	keep-response-order {
c2d2c5
+		does_not_exist;
c2d2c5
+	};
c2d2c5
+};
c2d2c5
diff --git a/bin/tests/system/checkconf/bad-many.conf b/bin/tests/system/checkconf/bad-many.conf
c2d2c5
index cfc4d02..09add87 100644
c2d2c5
--- a/bin/tests/system/checkconf/bad-many.conf
c2d2c5
+++ b/bin/tests/system/checkconf/bad-many.conf
c2d2c5
@@ -1,5 +1,5 @@
c2d2c5
 /*
c2d2c5
- * Copyright (C) 2005, 2012  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ * Copyright (C) 2005, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
  *
c2d2c5
  * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
  * purpose with or without fee is hereby granted, provided that the above
c2d2c5
@@ -33,6 +33,7 @@ options {
c2d2c5
 	host-statistics-max 100;
c2d2c5
 	hostname none;
c2d2c5
 	interface-interval 30;
c2d2c5
+	keep-response-order { 10.0.0.10/24; };
c2d2c5
 	listen-on port 90 { any; };
c2d2c5
 	listen-on port 100 { 127.0.0.1; };
c2d2c5
 	listen-on-v6 port 53 { none; };
c2d2c5
diff --git a/bin/tests/system/checkconf/good.conf b/bin/tests/system/checkconf/good.conf
c2d2c5
index cf7c745..43b0638 100644
c2d2c5
--- a/bin/tests/system/checkconf/good.conf
c2d2c5
+++ b/bin/tests/system/checkconf/good.conf
c2d2c5
@@ -44,6 +44,9 @@ options {
c2d2c5
 	host-statistics-max 100;
c2d2c5
 	hostname none;
c2d2c5
 	interface-interval 30;
c2d2c5
+	keep-response-order {
c2d2c5
+		10.0.0.10/24;
c2d2c5
+	};
c2d2c5
 	listen-on port 90 {
c2d2c5
 		"any";
c2d2c5
 	};
c2d2c5
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
c2d2c5
index 420320c..0d966b3 100644
c2d2c5
--- a/bin/tests/system/conf.sh.in
c2d2c5
+++ b/bin/tests/system/conf.sh.in
c2d2c5
@@ -68,7 +68,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
c2d2c5
 	 cacheclean checkconf @CHECKDS@ checknames checkzone @COVERAGE@ @KEYMGR@
c2d2c5
          database digdelv dlv dlvauto dlz dlzexternal dname dns64 dnssec dyndb
c2d2c5
          ecdsa formerr forward glue gost ixfr inline limits logfileconfig
c2d2c5
-         lwresd masterfile masterformat metadata notify nsupdate pending
c2d2c5
+         lwresd masterfile masterformat metadata notify nsupdate pending pipelined
c2d2c5
 	 @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent
c2d2c5
 	 smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown
c2d2c5
 	 upforwd verify views wildcard xfer xferquota zero zonechecks geoip filter-aaaa"
c2d2c5
diff --git a/bin/tests/system/pipelined/Makefile.in b/bin/tests/system/pipelined/Makefile.in
c2d2c5
new file mode 100644
c2d2c5
index 0000000..4d16d78
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/Makefile.in
c2d2c5
@@ -0,0 +1,51 @@
c2d2c5
+# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+#
c2d2c5
+# Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+# purpose with or without fee is hereby granted, provided that the above
c2d2c5
+# copyright notice and this permission notice appear in all copies.
c2d2c5
+#
c2d2c5
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+# PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+srcdir =	@srcdir@
c2d2c5
+VPATH =		@srcdir@
c2d2c5
+top_srcdir =	@top_srcdir@
c2d2c5
+
c2d2c5
+@BIND9_VERSION@
c2d2c5
+
c2d2c5
+@BIND9_MAKE_INCLUDES@
c2d2c5
+
c2d2c5
+CINCLUDES =	${DNS_INCLUDES} ${ISC_INCLUDES}
c2d2c5
+
c2d2c5
+CDEFINES =
c2d2c5
+CWARNINGS =
c2d2c5
+
c2d2c5
+DNSLIBS =	../../../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
c2d2c5
+ISCLIBS =	../../../../lib/isc/libisc.@A@
c2d2c5
+
c2d2c5
+DNSDEPLIBS =	../../../../lib/dns/libdns.@A@
c2d2c5
+ISCDEPLIBS =	../../../../lib/isc/libisc.@A@
c2d2c5
+
c2d2c5
+DEPLIBS =	${DNSDEPLIBS} ${ISCDEPLIBS}
c2d2c5
+
c2d2c5
+LIBS =		${DNSLIBS} ${ISCLIBS} @LIBS@
c2d2c5
+
c2d2c5
+TARGETS =	pipequeries@EXEEXT@
c2d2c5
+
c2d2c5
+SRCS =		pipequeries.c
c2d2c5
+
c2d2c5
+@BIND9_MAKE_RULES@
c2d2c5
+
c2d2c5
+all: pipequeries@EXEEXT@
c2d2c5
+
c2d2c5
+pipequeries@EXEEXT@: pipequeries.@O@ ${DEPLIBS}
c2d2c5
+	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ pipequeries.@O@ ${LIBS}
c2d2c5
+
c2d2c5
+clean distclean::
c2d2c5
+	rm -f ${TARGETS}
c2d2c5
+
c2d2c5
diff --git a/bin/tests/system/pipelined/clean.sh b/bin/tests/system/pipelined/clean.sh
c2d2c5
new file mode 100644
c2d2c5
index 0000000..1cca633
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/clean.sh
c2d2c5
@@ -0,0 +1,19 @@
c2d2c5
+#!/bin/sh
c2d2c5
+#
c2d2c5
+# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+#
c2d2c5
+# Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+# purpose with or without fee is hereby granted, provided that the above
c2d2c5
+# copyright notice and this permission notice appear in all copies.
c2d2c5
+#
c2d2c5
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+# PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+rm -f */named.memstats
c2d2c5
+rm -f */named.run
c2d2c5
+rm -f raw* output*
c2d2c5
diff --git a/bin/tests/system/pipelined/input b/bin/tests/system/pipelined/input
c2d2c5
new file mode 100644
c2d2c5
index 0000000..485cf81
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/input
c2d2c5
@@ -0,0 +1,8 @@
c2d2c5
+a.examplea
c2d2c5
+a.exampleb
c2d2c5
+b.examplea
c2d2c5
+b.exampleb
c2d2c5
+c.examplea
c2d2c5
+c.exampleb
c2d2c5
+d.examplea
c2d2c5
+d.exampleb
c2d2c5
diff --git a/bin/tests/system/pipelined/inputb b/bin/tests/system/pipelined/inputb
c2d2c5
new file mode 100644
c2d2c5
index 0000000..6ea367e
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/inputb
c2d2c5
@@ -0,0 +1,8 @@
c2d2c5
+e.examplea
c2d2c5
+e.exampleb
c2d2c5
+f.examplea
c2d2c5
+f.exampleb
c2d2c5
+g.examplea
c2d2c5
+g.exampleb
c2d2c5
+h.examplea
c2d2c5
+h.exampleb
c2d2c5
diff --git a/bin/tests/system/pipelined/ns1/named.conf b/bin/tests/system/pipelined/ns1/named.conf
c2d2c5
new file mode 100644
c2d2c5
index 0000000..1bbf401
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns1/named.conf
c2d2c5
@@ -0,0 +1,43 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+controls { /* empty */ };
c2d2c5
+
c2d2c5
+options {
c2d2c5
+	query-source address 10.53.0.1;
c2d2c5
+	notify-source 10.53.0.1;
c2d2c5
+	transfer-source 10.53.0.1;
c2d2c5
+	port 5300;
c2d2c5
+	pid-file "named.pid";
c2d2c5
+	listen-on { 10.53.0.1; };
c2d2c5
+	listen-on-v6 { none; };
c2d2c5
+	recursion no;
c2d2c5
+	notify yes;
c2d2c5
+};
c2d2c5
+
c2d2c5
+key rndc_key {
c2d2c5
+	secret "1234abcd8765";
c2d2c5
+	algorithm hmac-sha256;
c2d2c5
+};
c2d2c5
+
c2d2c5
+controls {
c2d2c5
+	inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "." {
c2d2c5
+	type master;
c2d2c5
+	file "root.db";
c2d2c5
+};
c2d2c5
diff --git a/bin/tests/system/pipelined/ns1/root.db b/bin/tests/system/pipelined/ns1/root.db
c2d2c5
new file mode 100644
c2d2c5
index 0000000..b5186e5
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns1/root.db
c2d2c5
@@ -0,0 +1,30 @@
c2d2c5
+; Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+;
c2d2c5
+; Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+; purpose with or without fee is hereby granted, provided that the above
c2d2c5
+; copyright notice and this permission notice appear in all copies.
c2d2c5
+;
c2d2c5
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+; PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+$TTL 300
c2d2c5
+. 			IN SOA	gson.nominum.com. a.root.servers.nil. (
c2d2c5
+				2000042100   	; serial
c2d2c5
+				600         	; refresh
c2d2c5
+				600         	; retry
c2d2c5
+				1200    	; expire
c2d2c5
+				600       	; minimum
c2d2c5
+				)
c2d2c5
+.			NS	a.root-servers.nil.
c2d2c5
+a.root-servers.nil.	A	10.53.0.1
c2d2c5
+
c2d2c5
+examplea.		NS	ns2.examplea.
c2d2c5
+ns2.examplea.		A	10.53.0.2
c2d2c5
+
c2d2c5
+exampleb.		NS	ns3.exampleb.
c2d2c5
+ns3.exampleb.		A	10.53.0.3
c2d2c5
diff --git a/bin/tests/system/pipelined/ns2/examplea.db b/bin/tests/system/pipelined/ns2/examplea.db
c2d2c5
new file mode 100644
c2d2c5
index 0000000..678034a
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns2/examplea.db
c2d2c5
@@ -0,0 +1,35 @@
c2d2c5
+; Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+;
c2d2c5
+; Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+; purpose with or without fee is hereby granted, provided that the above
c2d2c5
+; copyright notice and this permission notice appear in all copies.
c2d2c5
+;
c2d2c5
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+; PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+$ORIGIN .
c2d2c5
+$TTL 300	; 5 minutes
c2d2c5
+examplea		IN SOA	mname1. . (
c2d2c5
+				1          ; serial
c2d2c5
+				20         ; refresh (20 seconds)
c2d2c5
+				20         ; retry (20 seconds)
c2d2c5
+				1814400    ; expire (3 weeks)
c2d2c5
+				3600       ; minimum (1 hour)
c2d2c5
+				)
c2d2c5
+examplea.		NS	ns2.examplea.
c2d2c5
+ns2.examplea.		A	10.53.0.2
c2d2c5
+
c2d2c5
+$ORIGIN examplea.
c2d2c5
+a			A	10.0.1.1
c2d2c5
+b			A	10.0.1.2
c2d2c5
+c			A	10.0.1.3
c2d2c5
+d			A	10.0.1.4
c2d2c5
+e			A	10.0.1.5
c2d2c5
+f			A	10.0.1.6
c2d2c5
+g			A	10.0.1.7
c2d2c5
+h			A	10.0.1.8
c2d2c5
diff --git a/bin/tests/system/pipelined/ns2/named.conf b/bin/tests/system/pipelined/ns2/named.conf
c2d2c5
new file mode 100644
c2d2c5
index 0000000..83a9ec7
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns2/named.conf
c2d2c5
@@ -0,0 +1,49 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+controls { /* empty */ };
c2d2c5
+
c2d2c5
+options {
c2d2c5
+	query-source address 10.53.0.2;
c2d2c5
+	notify-source 10.53.0.2;
c2d2c5
+	transfer-source 10.53.0.2;
c2d2c5
+	port 5300;
c2d2c5
+	pid-file "named.pid";
c2d2c5
+	listen-on { 10.53.0.2; };
c2d2c5
+	listen-on-v6 { none; };
c2d2c5
+	recursion yes;
c2d2c5
+	notify yes;
c2d2c5
+};
c2d2c5
+
c2d2c5
+key rndc_key {
c2d2c5
+	secret "1234abcd8765";
c2d2c5
+	algorithm hmac-sha256;
c2d2c5
+};
c2d2c5
+
c2d2c5
+controls {
c2d2c5
+	inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "." {
c2d2c5
+	type hint;
c2d2c5
+	file "../../common/root.hint";
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "examplea" {
c2d2c5
+	type master;
c2d2c5
+	file "examplea.db";
c2d2c5
+	allow-update { any; };
c2d2c5
+};
c2d2c5
diff --git a/bin/tests/system/pipelined/ns3/exampleb.db b/bin/tests/system/pipelined/ns3/exampleb.db
c2d2c5
new file mode 100644
c2d2c5
index 0000000..7d10493
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns3/exampleb.db
c2d2c5
@@ -0,0 +1,35 @@
c2d2c5
+; Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+;
c2d2c5
+; Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+; purpose with or without fee is hereby granted, provided that the above
c2d2c5
+; copyright notice and this permission notice appear in all copies.
c2d2c5
+;
c2d2c5
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+; PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+$ORIGIN .
c2d2c5
+$TTL 300	; 5 minutes
c2d2c5
+exampleb		IN SOA	mname1. . (
c2d2c5
+				1          ; serial
c2d2c5
+				20         ; refresh (20 seconds)
c2d2c5
+				20         ; retry (20 seconds)
c2d2c5
+				1814400    ; expire (3 weeks)
c2d2c5
+				3600       ; minimum (1 hour)
c2d2c5
+				)
c2d2c5
+exampleb.		NS	ns3.exampleb.
c2d2c5
+ns3.exampleb.		A	10.53.0.3
c2d2c5
+
c2d2c5
+$ORIGIN exampleb.
c2d2c5
+a			A	10.0.2.1
c2d2c5
+b			A	10.0.2.2
c2d2c5
+c			A	10.0.2.3
c2d2c5
+d			A	10.0.2.4
c2d2c5
+e			A	10.0.2.5
c2d2c5
+f			A	10.0.2.6
c2d2c5
+g			A	10.0.2.7
c2d2c5
+h			A	10.0.2.8
c2d2c5
diff --git a/bin/tests/system/pipelined/ns3/named.args b/bin/tests/system/pipelined/ns3/named.args
c2d2c5
new file mode 100644
c2d2c5
index 0000000..a6b0f54
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns3/named.args
c2d2c5
@@ -0,0 +1 @@
c2d2c5
+-m record,size,mctx -c named.conf -d 99 -g -T delay=200
c2d2c5
diff --git a/bin/tests/system/pipelined/ns3/named.conf b/bin/tests/system/pipelined/ns3/named.conf
c2d2c5
new file mode 100644
c2d2c5
index 0000000..8b15622
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns3/named.conf
c2d2c5
@@ -0,0 +1,49 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+controls { /* empty */ };
c2d2c5
+
c2d2c5
+options {
c2d2c5
+	query-source address 10.53.0.3;
c2d2c5
+	notify-source 10.53.0.3;
c2d2c5
+	transfer-source 10.53.0.3;
c2d2c5
+	port 5300;
c2d2c5
+	pid-file "named.pid";
c2d2c5
+	listen-on { 10.53.0.3; };
c2d2c5
+	listen-on-v6 { none; };
c2d2c5
+	recursion yes;
c2d2c5
+	notify yes;
c2d2c5
+};
c2d2c5
+
c2d2c5
+key rndc_key {
c2d2c5
+	secret "1234abcd8765";
c2d2c5
+	algorithm hmac-sha256;
c2d2c5
+};
c2d2c5
+
c2d2c5
+controls {
c2d2c5
+	inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; };
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "." {
c2d2c5
+	type hint;
c2d2c5
+	file "../../common/root.hint";
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "exampleb" {
c2d2c5
+	type master;
c2d2c5
+	file "exampleb.db";
c2d2c5
+	allow-update { any; };
c2d2c5
+};
c2d2c5
diff --git a/bin/tests/system/pipelined/ns4/named.conf b/bin/tests/system/pipelined/ns4/named.conf
c2d2c5
new file mode 100644
c2d2c5
index 0000000..7e7923a
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ns4/named.conf
c2d2c5
@@ -0,0 +1,45 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+controls { /* empty */ };
c2d2c5
+
c2d2c5
+options {
c2d2c5
+	query-source address 10.53.0.4;
c2d2c5
+	notify-source 10.53.0.4;
c2d2c5
+	transfer-source 10.53.0.4;
c2d2c5
+	port 5300;
c2d2c5
+	directory ".";
c2d2c5
+	pid-file "named.pid";
c2d2c5
+	listen-on { 10.53.0.4; };
c2d2c5
+	listen-on-v6 { none; };
c2d2c5
+	keep-response-order { 10.53.0.7/32; };
c2d2c5
+	recursion yes;
c2d2c5
+	notify yes;
c2d2c5
+};
c2d2c5
+
c2d2c5
+key rndc_key {
c2d2c5
+	secret "1234abcd8765";
c2d2c5
+	algorithm hmac-sha256;
c2d2c5
+};
c2d2c5
+
c2d2c5
+controls {
c2d2c5
+	inet 10.53.0.4 port 9953 allow { any; } keys { rndc_key; };
c2d2c5
+};
c2d2c5
+
c2d2c5
+zone "." {
c2d2c5
+	type hint;
c2d2c5
+	file "../../common/root.hint";
c2d2c5
+};
c2d2c5
diff --git a/bin/tests/system/pipelined/pipequeries.c b/bin/tests/system/pipelined/pipequeries.c
c2d2c5
new file mode 100644
c2d2c5
index 0000000..d34dedd
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/pipequeries.c
c2d2c5
@@ -0,0 +1,346 @@
c2d2c5
+/*
c2d2c5
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+ *
c2d2c5
+ * Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+ * purpose with or without fee is hereby granted, provided that the above
c2d2c5
+ * copyright notice and this permission notice appear in all copies.
c2d2c5
+ *
c2d2c5
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+ * PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+ */
c2d2c5
+
c2d2c5
+#include <config.h>
c2d2c5
+
c2d2c5
+#include <stdlib.h>
c2d2c5
+#include <string.h>
c2d2c5
+#include <unistd.h>
c2d2c5
+
c2d2c5
+#include <isc/app.h>
c2d2c5
+#include <isc/base64.h>
c2d2c5
+#include <isc/entropy.h>
c2d2c5
+#include <isc/hash.h>
c2d2c5
+#include <isc/log.h>
c2d2c5
+#include <isc/mem.h>
c2d2c5
+#include <isc/sockaddr.h>
c2d2c5
+#include <isc/socket.h>
c2d2c5
+#include <isc/task.h>
c2d2c5
+#include <isc/timer.h>
c2d2c5
+#include <isc/util.h>
c2d2c5
+
c2d2c5
+#include <dns/dispatch.h>
c2d2c5
+#include <dns/fixedname.h>
c2d2c5
+#include <dns/message.h>
c2d2c5
+#include <dns/name.h>
c2d2c5
+#include <dns/request.h>
c2d2c5
+#include <dns/result.h>
c2d2c5
+#include <dns/view.h>
c2d2c5
+
c2d2c5
+#include <dns/events.h>
c2d2c5
+#include <dns/rdataset.h>
c2d2c5
+#include <dns/resolver.h>
c2d2c5
+#include <dns/types.h>
c2d2c5
+
c2d2c5
+#include <dst/result.h>
c2d2c5
+
c2d2c5
+#define CHECK(str, x) { \
c2d2c5
+	if ((x) != ISC_R_SUCCESS) { \
c2d2c5
+		fprintf(stderr, "I:%s: %s\n", (str), isc_result_totext(x)); \
c2d2c5
+		exit(-1); \
c2d2c5
+	} \
c2d2c5
+}
c2d2c5
+
c2d2c5
+#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
c2d2c5
+
c2d2c5
+#define PORT 5300
c2d2c5
+#define TIMEOUT 30
c2d2c5
+
c2d2c5
+static isc_mem_t *mctx;
c2d2c5
+static dns_requestmgr_t *requestmgr;
c2d2c5
+isc_sockaddr_t address;
c2d2c5
+static int onfly;
c2d2c5
+
c2d2c5
+static void
c2d2c5
+recvresponse(isc_task_t *task, isc_event_t *event) {
c2d2c5
+	dns_requestevent_t *reqev = (dns_requestevent_t *)event;
c2d2c5
+	isc_result_t result;
c2d2c5
+	dns_message_t *query, *response;
c2d2c5
+	isc_buffer_t outbuf;
c2d2c5
+	char output[1024];
c2d2c5
+
c2d2c5
+	UNUSED(task);
c2d2c5
+
c2d2c5
+	REQUIRE(reqev != NULL);
c2d2c5
+
c2d2c5
+	if (reqev->result != ISC_R_SUCCESS) {
c2d2c5
+		fprintf(stderr, "I:request event result: %s\n",
c2d2c5
+			isc_result_totext(reqev->result));
c2d2c5
+		exit(-1);
c2d2c5
+	}
c2d2c5
+
c2d2c5
+	query = reqev->ev_arg;
c2d2c5
+
c2d2c5
+	response = NULL;
c2d2c5
+	result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
c2d2c5
+	CHECK("dns_message_create", result);
c2d2c5
+
c2d2c5
+	result = dns_request_getresponse(reqev->request, response,
c2d2c5
+					 DNS_MESSAGEPARSE_PRESERVEORDER);
c2d2c5
+	CHECK("dns_request_getresponse", result);
c2d2c5
+
c2d2c5
+	if (response->rcode != dns_rcode_noerror) {
c2d2c5
+		result = ISC_RESULTCLASS_DNSRCODE + response->rcode;
c2d2c5
+		fprintf(stderr, "I:response rcode: %s\n",
c2d2c5
+			isc_result_totext(result));
c2d2c5
+			exit(-1);
c2d2c5
+	}
c2d2c5
+	if (response->counts[DNS_SECTION_ANSWER] != 1U) {
c2d2c5
+		fprintf(stderr, "I:response answer count (%u!=1)\n",
c2d2c5
+			response->counts[DNS_SECTION_ANSWER]);
c2d2c5
+	}
c2d2c5
+
c2d2c5
+	isc_buffer_init(&outbuf, output, sizeof(output));
c2d2c5
+	result = dns_message_sectiontotext(response, DNS_SECTION_ANSWER,
c2d2c5
+					   &dns_master_style_simple,
c2d2c5
+					   DNS_MESSAGETEXTFLAG_NOCOMMENTS,
c2d2c5
+					   &outbuf);
c2d2c5
+	CHECK("dns_message_sectiontotext", result);
c2d2c5
+	printf("%.*s", (int)isc_buffer_usedlength(&outbuf),
c2d2c5
+	       (char *)isc_buffer_base(&outbuf));
c2d2c5
+	fflush(stdout);
c2d2c5
+
c2d2c5
+	dns_message_destroy(&query);
c2d2c5
+	dns_message_destroy(&response);
c2d2c5
+	dns_request_destroy(&reqev->request);
c2d2c5
+	isc_event_free(&event);
c2d2c5
+
c2d2c5
+	if (--onfly == 0)
c2d2c5
+		isc_app_shutdown();
c2d2c5
+	return;
c2d2c5
+}
c2d2c5
+
c2d2c5
+static isc_result_t
c2d2c5
+sendquery(isc_task_t *task)
c2d2c5
+{
c2d2c5
+	dns_request_t *request;
c2d2c5
+	dns_message_t *message;
c2d2c5
+	dns_name_t *qname;
c2d2c5
+	dns_rdataset_t *qrdataset;
c2d2c5
+	isc_result_t result;
c2d2c5
+	dns_fixedname_t queryname;
c2d2c5
+	isc_buffer_t buf;
c2d2c5
+	static char host[256];
c2d2c5
+	int c;
c2d2c5
+
c2d2c5
+	c = scanf("%255s", host);
c2d2c5
+	if (c == EOF)
c2d2c5
+		return ISC_R_NOMORE;
c2d2c5
+
c2d2c5
+	onfly++;
c2d2c5
+
c2d2c5
+	dns_fixedname_init(&queryname);
c2d2c5
+	isc_buffer_init(&buf, host, strlen(host));
c2d2c5
+	isc_buffer_add(&buf, strlen(host));
c2d2c5
+	result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
c2d2c5
+				   dns_rootname, 0, NULL);
c2d2c5
+	CHECK("dns_name_fromtext", result);
c2d2c5
+
c2d2c5
+	message = NULL;
c2d2c5
+	result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
c2d2c5
+	CHECK("dns_message_create", result);
c2d2c5
+
c2d2c5
+	message->opcode = dns_opcode_query;
c2d2c5
+	message->flags |= DNS_MESSAGEFLAG_RD;
c2d2c5
+	message->rdclass = dns_rdataclass_in;
c2d2c5
+	message->id = (unsigned short)(random() & 0xFFFF);
c2d2c5
+
c2d2c5
+	qname = NULL;
c2d2c5
+	result = dns_message_gettempname(message, &qname);
c2d2c5
+	CHECK("dns_message_gettempname", result);
c2d2c5
+
c2d2c5
+	qrdataset = NULL;
c2d2c5
+	result = dns_message_gettemprdataset(message, &qrdataset);
c2d2c5
+	CHECK("dns_message_gettemprdataset", result);
c2d2c5
+
c2d2c5
+	dns_name_init(qname, NULL);
c2d2c5
+	dns_name_clone(dns_fixedname_name(&queryname), qname);
c2d2c5
+	dns_rdataset_init(qrdataset);
c2d2c5
+	dns_rdataset_makequestion(qrdataset, dns_rdataclass_in,
c2d2c5
+				  dns_rdatatype_a);
c2d2c5
+	ISC_LIST_APPEND(qname->list, qrdataset, link);
c2d2c5
+	dns_message_addname(message, qname, DNS_SECTION_QUESTION);
c2d2c5
+
c2d2c5
+	request = NULL;
c2d2c5
+	result = dns_request_create(requestmgr, message, &address,
c2d2c5
+				    DNS_REQUESTOPT_TCP, NULL,
c2d2c5
+				    TIMEOUT, task, recvresponse,
c2d2c5
+				    message, &request);
c2d2c5
+	CHECK("dns_request_create", result);
c2d2c5
+
c2d2c5
+	return ISC_R_SUCCESS;
c2d2c5
+}
c2d2c5
+
c2d2c5
+static void
c2d2c5
+sendqueries(isc_task_t *task, isc_event_t *event)
c2d2c5
+{
c2d2c5
+	isc_result_t result;
c2d2c5
+
c2d2c5
+	isc_event_free(&event);
c2d2c5
+
c2d2c5
+	do {
c2d2c5
+		result = sendquery(task);
c2d2c5
+	} while (result == ISC_R_SUCCESS);
c2d2c5
+
c2d2c5
+	if (onfly == 0)
c2d2c5
+		isc_app_shutdown();
c2d2c5
+	return;
c2d2c5
+}
c2d2c5
+
c2d2c5
+static void
c2d2c5
+connecting(isc_task_t *task, isc_event_t *event)
c2d2c5
+{
c2d2c5
+	isc_socket_t *sock = (isc_socket_t *)(event->ev_arg);
c2d2c5
+
c2d2c5
+	RUNCHECK(isc_socket_connect(sock, &address, task, sendqueries, NULL));
c2d2c5
+
c2d2c5
+	isc_event_free(&event);
c2d2c5
+}
c2d2c5
+
c2d2c5
+int
c2d2c5
+main(int argc, char *argv[])
c2d2c5
+{
c2d2c5
+	isc_taskmgr_t *taskmgr;
c2d2c5
+	isc_timermgr_t *timermgr;
c2d2c5
+	isc_socketmgr_t *socketmgr;
c2d2c5
+	isc_socket_t *sock;
c2d2c5
+	unsigned int attrs, attrmask;
c2d2c5
+	isc_sockaddr_t bind_addr;
c2d2c5
+	dns_dispatchmgr_t *dispatchmgr;
c2d2c5
+	dns_dispatch_t *dispatchv4;
c2d2c5
+	dns_dispatch_t *tcpdispatch;
c2d2c5
+	dns_view_t *view;
c2d2c5
+	isc_entropy_t *ectx;
c2d2c5
+	isc_task_t *task;
c2d2c5
+	isc_log_t *lctx;
c2d2c5
+	isc_logconfig_t *lcfg;
c2d2c5
+	struct in_addr inaddr;
c2d2c5
+	isc_result_t result;
c2d2c5
+
c2d2c5
+	UNUSED(argv);
c2d2c5
+
c2d2c5
+	RUNCHECK(isc_app_start());
c2d2c5
+
c2d2c5
+	dns_result_register();
c2d2c5
+
c2d2c5
+	mctx = NULL;
c2d2c5
+	RUNCHECK(isc_mem_create(0, 0, &mctx));
c2d2c5
+
c2d2c5
+	lctx = NULL;
c2d2c5
+	lcfg = NULL;
c2d2c5
+	RUNCHECK(isc_log_create(mctx, &lctx, &lcfg));
c2d2c5
+
c2d2c5
+	ectx = NULL;
c2d2c5
+	RUNCHECK(isc_entropy_create(mctx, &ectx));
c2d2c5
+	RUNCHECK(isc_entropy_createfilesource(ectx, "../random.data"));
c2d2c5
+	RUNCHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE));
c2d2c5
+
c2d2c5
+	RUNCHECK(dst_lib_init(mctx, ectx, ISC_ENTROPY_GOODONLY));
c2d2c5
+
c2d2c5
+	taskmgr = NULL;
c2d2c5
+	RUNCHECK(isc_taskmgr_create(mctx, 1, 0, &taskmgr));
c2d2c5
+	task = NULL;
c2d2c5
+	RUNCHECK(isc_task_create(taskmgr, 0, &task));
c2d2c5
+	timermgr = NULL;
c2d2c5
+
c2d2c5
+	RUNCHECK(isc_timermgr_create(mctx, &timermgr));
c2d2c5
+	socketmgr = NULL;
c2d2c5
+	RUNCHECK(isc_socketmgr_create(mctx, &socketmgr));
c2d2c5
+	dispatchmgr = NULL;
c2d2c5
+	RUNCHECK(dns_dispatchmgr_create(mctx, ectx, &dispatchmgr));
c2d2c5
+	if (argc == 1) {
c2d2c5
+		isc_sockaddr_any(&bind_addr);
c2d2c5
+	} else {
c2d2c5
+		result = ISC_R_FAILURE;
c2d2c5
+		if (inet_pton(AF_INET, "10.53.0.7", &inaddr) != 1)
c2d2c5
+			CHECK("inet_pton", result);
c2d2c5
+		isc_sockaddr_fromin(&bind_addr, &inaddr, 0);
c2d2c5
+	}
c2d2c5
+	attrs = DNS_DISPATCHATTR_UDP |
c2d2c5
+		DNS_DISPATCHATTR_MAKEQUERY |
c2d2c5
+		DNS_DISPATCHATTR_IPV4;
c2d2c5
+	attrmask = DNS_DISPATCHATTR_UDP |
c2d2c5
+		   DNS_DISPATCHATTR_TCP |
c2d2c5
+		   DNS_DISPATCHATTR_IPV4 |
c2d2c5
+		   DNS_DISPATCHATTR_IPV6;
c2d2c5
+	dispatchv4 = NULL;
c2d2c5
+	RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr,
c2d2c5
+					  &bind_addr, 4096, 4, 2, 3, 5,
c2d2c5
+					  attrs, attrmask, &dispatchv4));
c2d2c5
+	requestmgr = NULL;
c2d2c5
+	RUNCHECK(dns_requestmgr_create(mctx, timermgr, socketmgr, taskmgr,
c2d2c5
+					    dispatchmgr, dispatchv4, NULL,
c2d2c5
+					    &requestmgr));
c2d2c5
+
c2d2c5
+	view = NULL;
c2d2c5
+	RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
c2d2c5
+
c2d2c5
+	sock = NULL;
c2d2c5
+	RUNCHECK(isc_socket_create(socketmgr, PF_INET, isc_sockettype_tcp,
c2d2c5
+				   &sock));
c2d2c5
+	RUNCHECK(isc_socket_bind(sock, &bind_addr, 0));
c2d2c5
+
c2d2c5
+	result = ISC_R_FAILURE;
c2d2c5
+	if (inet_pton(AF_INET, "10.53.0.4", &inaddr) != 1)
c2d2c5
+		CHECK("inet_pton", result);
c2d2c5
+	isc_sockaddr_fromin(&address, &inaddr, PORT);
c2d2c5
+
c2d2c5
+	attrs = 0;
c2d2c5
+	attrs |= DNS_DISPATCHATTR_TCP;
c2d2c5
+	attrs |= DNS_DISPATCHATTR_IPV4;
c2d2c5
+	attrs |= DNS_DISPATCHATTR_MAKEQUERY;
c2d2c5
+	attrs |= DNS_DISPATCHATTR_CONNECTED;
c2d2c5
+	tcpdispatch = NULL;
c2d2c5
+	RUNCHECK(dns_dispatch_createtcp2(dispatchmgr, sock, taskmgr,
c2d2c5
+					 &bind_addr, &address,
c2d2c5
+					 4096, 20, 10, 3, 5,
c2d2c5
+					 attrs, &tcpdispatch));
c2d2c5
+
c2d2c5
+	RUNCHECK(isc_app_onrun(mctx, task, connecting, sock));
c2d2c5
+
c2d2c5
+	isc_socket_detach(&sock);
c2d2c5
+
c2d2c5
+	(void)isc_app_run();
c2d2c5
+
c2d2c5
+	dns_view_detach(&view);
c2d2c5
+
c2d2c5
+	dns_requestmgr_shutdown(requestmgr);
c2d2c5
+	dns_requestmgr_detach(&requestmgr);
c2d2c5
+
c2d2c5
+	dns_dispatch_detach(&dispatchv4);
c2d2c5
+	dns_dispatch_detach(&tcpdispatch);
c2d2c5
+	dns_dispatchmgr_destroy(&dispatchmgr);
c2d2c5
+
c2d2c5
+	isc_socketmgr_destroy(&socketmgr);
c2d2c5
+	isc_timermgr_destroy(&timermgr);
c2d2c5
+
c2d2c5
+	isc_task_shutdown(task);
c2d2c5
+	isc_task_detach(&task);
c2d2c5
+	isc_taskmgr_destroy(&taskmgr);
c2d2c5
+
c2d2c5
+	dst_lib_destroy();
c2d2c5
+	isc_hash_destroy();
c2d2c5
+	isc_entropy_detach(&ectx);
c2d2c5
+
c2d2c5
+	isc_log_destroy(&lctx);
c2d2c5
+
c2d2c5
+	isc_mem_destroy(&mctx);
c2d2c5
+
c2d2c5
+	isc_app_finish();
c2d2c5
+
c2d2c5
+	return (0);
c2d2c5
+}
c2d2c5
+
c2d2c5
diff --git a/bin/tests/system/pipelined/ref b/bin/tests/system/pipelined/ref
c2d2c5
new file mode 100644
c2d2c5
index 0000000..fe123f6
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/ref
c2d2c5
@@ -0,0 +1,8 @@
c2d2c5
+a.examplea. 10.0.1.1
c2d2c5
+a.exampleb. 10.0.2.1
c2d2c5
+b.examplea. 10.0.1.2
c2d2c5
+b.exampleb. 10.0.2.2
c2d2c5
+c.examplea. 10.0.1.3
c2d2c5
+c.exampleb. 10.0.2.3
c2d2c5
+d.examplea. 10.0.1.4
c2d2c5
+d.exampleb. 10.0.2.4
c2d2c5
diff --git a/bin/tests/system/pipelined/refb b/bin/tests/system/pipelined/refb
c2d2c5
new file mode 100644
c2d2c5
index 0000000..a24c6bc
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/refb
c2d2c5
@@ -0,0 +1,8 @@
c2d2c5
+e.examplea. 10.0.1.5
c2d2c5
+e.exampleb. 10.0.2.5
c2d2c5
+f.examplea. 10.0.1.6
c2d2c5
+f.exampleb. 10.0.2.6
c2d2c5
+g.examplea. 10.0.1.7
c2d2c5
+g.exampleb. 10.0.2.7
c2d2c5
+h.examplea. 10.0.1.8
c2d2c5
+h.exampleb. 10.0.2.8
c2d2c5
diff --git a/bin/tests/system/pipelined/setup.sh b/bin/tests/system/pipelined/setup.sh
c2d2c5
new file mode 100644
c2d2c5
index 0000000..6fc981d
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/setup.sh
c2d2c5
@@ -0,0 +1,22 @@
c2d2c5
+#!/bin/sh
c2d2c5
+#
c2d2c5
+# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+#
c2d2c5
+# Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+# purpose with or without fee is hereby granted, provided that the above
c2d2c5
+# copyright notice and this permission notice appear in all copies.
c2d2c5
+#
c2d2c5
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+# PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+SYSTEMTESTTOP=..
c2d2c5
+. $SYSTEMTESTTOP/conf.sh
c2d2c5
+
c2d2c5
+$SHELL clean.sh
c2d2c5
+
c2d2c5
+test -r $RANDFILE || $GENRANDOM 400 $RANDFILE
c2d2c5
diff --git a/bin/tests/system/pipelined/tests.sh b/bin/tests/system/pipelined/tests.sh
c2d2c5
new file mode 100644
c2d2c5
index 0000000..a34e573
c2d2c5
--- /dev/null
c2d2c5
+++ b/bin/tests/system/pipelined/tests.sh
c2d2c5
@@ -0,0 +1,41 @@
c2d2c5
+#!/bin/sh
c2d2c5
+#
c2d2c5
+# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
c2d2c5
+#
c2d2c5
+# Permission to use, copy, modify, and/or distribute this software for any
c2d2c5
+# purpose with or without fee is hereby granted, provided that the above
c2d2c5
+# copyright notice and this permission notice appear in all copies.
c2d2c5
+#
c2d2c5
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
c2d2c5
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
c2d2c5
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
c2d2c5
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
c2d2c5
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
c2d2c5
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
c2d2c5
+# PERFORMANCE OF THIS SOFTWARE.
c2d2c5
+
c2d2c5
+SYSTEMTESTTOP=..
c2d2c5
+. $SYSTEMTESTTOP/conf.sh
c2d2c5
+
c2d2c5
+status=0
c2d2c5
+
c2d2c5
+echo "I:check pipelined TCP queries"
c2d2c5
+ret=0
c2d2c5
+./pipequeries < input > raw || ret=1
c2d2c5
+awk '{ print $1 " " $5 }' < raw > output
c2d2c5
+sort < output > output-sorted
c2d2c5
+diff ref output-sorted || { ret=1 ; echo "I: diff sorted failed"; }
c2d2c5
+diff ref output > /dev/null && { ret=1 ; echo "I: diff out of order failed"; }
c2d2c5
+if [ $ret != 0 ]; then echo "I:failed"; fi
c2d2c5
+status=`expr $status + $ret`
c2d2c5
+
c2d2c5
+echo "I:check keep response order"
c2d2c5
+ret=0
c2d2c5
+./pipequeries ++ < inputb > rawb || ret=1
c2d2c5
+awk '{ print $1 " " $5 }' < rawb > outputb
c2d2c5
+diff refb outputb || ret=1
c2d2c5
+if [ $ret != 0 ]; then echo "I:failed"; fi
c2d2c5
+status=`expr $status + $ret`
c2d2c5
+
c2d2c5
+echo "I:exit status: $status"
c2d2c5
+exit $status
c2d2c5
diff --git a/configure b/configure
c2d2c5
index a299aac..7f5c7da 100755
c2d2c5
--- a/configure
c2d2c5
+++ b/configure
c2d2c5
@@ -22330,6 +22330,7 @@ do
c2d2c5
     "bin/tests/system/geoip/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/geoip/Makefile" ;;
c2d2c5
     "bin/tests/system/gost/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/gost/prereq.sh" ;;
c2d2c5
     "bin/tests/system/lwresd/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/lwresd/Makefile" ;;
c2d2c5
+    "bin/tests/system/pipelined/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/pipelined/Makefile" ;;
c2d2c5
     "bin/tests/system/rpz/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rpz/Makefile" ;;
c2d2c5
     "bin/tests/system/rrl/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rrl/Makefile" ;;
c2d2c5
     "bin/tests/system/rsabigexponent/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/rsabigexponent/Makefile" ;;
c2d2c5
diff --git a/configure.in b/configure.in
c2d2c5
index ee38901..9c5a9db 100644
c2d2c5
--- a/configure.in
c2d2c5
+++ b/configure.in
c2d2c5
@@ -4099,6 +4099,7 @@ AC_CONFIG_FILES([
c2d2c5
 	bin/tests/system/geoip/Makefile
c2d2c5
 	bin/tests/system/gost/prereq.sh
c2d2c5
 	bin/tests/system/lwresd/Makefile
c2d2c5
+	bin/tests/system/pipelined/Makefile
c2d2c5
 	bin/tests/system/rpz/Makefile
c2d2c5
 	bin/tests/system/rrl/Makefile
c2d2c5
 	bin/tests/system/rsabigexponent/Makefile
c2d2c5
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
c2d2c5
index af194d9..74394a0 100644
c2d2c5
--- a/doc/arm/Bv9ARM-book.xml
c2d2c5
+++ b/doc/arm/Bv9ARM-book.xml
c2d2c5
@@ -3025,8 +3025,9 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
c2d2c5
 	    <command>allow-query-cache-on</command>,
c2d2c5
 	    <command>allow-transfer</command>,
c2d2c5
 	    <command>allow-update</command>,
c2d2c5
-	    <command>allow-update-forwarding</command>, and
c2d2c5
-	    <command>blackhole</command> all use address match
c2d2c5
+	    <command>allow-update-forwarding</command>,
c2d2c5
+	    <command>blackhole</command>, and
c2d2c5
+	    <command>keep-response-order</command> all use address match
c2d2c5
 	    lists.  Similarly, the <command>listen-on</command> option will cause the
c2d2c5
 	    server to refuse queries on any of the machine's
c2d2c5
 	    addresses which do not match the list.
c2d2c5
@@ -4829,6 +4830,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
c2d2c5
     <optional> try-tcp-refresh <replaceable>yes_or_no</replaceable>; </optional>
c2d2c5
     <optional> allow-v6-synthesis { <replaceable>address_match_list</replaceable> }; </optional>
c2d2c5
     <optional> blackhole { <replaceable>address_match_list</replaceable> }; </optional>
c2d2c5
+    <optional> keep-response-order { <replaceable>address_match_list</replaceable> }; </optional>
c2d2c5
     <optional> use-v4-udp-ports { <replaceable>port_list</replaceable> }; </optional>
c2d2c5
     <optional> avoid-v4-udp-ports { <replaceable>port_list</replaceable> }; </optional>
c2d2c5
     <optional> use-v6-udp-ports { <replaceable>port_list</replaceable> }; </optional>
c2d2c5
@@ -7248,6 +7250,19 @@ options {
c2d2c5
                   Specifies a list of addresses to which
c2d2c5
 		  <command>filter-aaaa-on-v4</command>
c2d2c5
                   is applies.  The default is <userinput>any</userinput>.
c2d2c5
+		</para>
c2d2c5
+	      </listitem>
c2d2c5
+	    </varlistentry>
c2d2c5
+
c2d2c5
+	    <varlistentry>
c2d2c5
+	      <term><command>keep-response-order</command></term>
c2d2c5
+	      <listitem>
c2d2c5
+		<para>
c2d2c5
+		  Specifies a list of addresses to which the server
c2d2c5
+		  will send responses to TCP queries in the same order
c2d2c5
+		  in which they were received.  This disables the
c2d2c5
+		  processing of TCP queries in parallel. The default
c2d2c5
+		  is <userinput>any</userinput>.
c2d2c5
                 </para>
c2d2c5
               </listitem>
c2d2c5
             </varlistentry>
c2d2c5
diff --git a/doc/misc/options b/doc/misc/options
c2d2c5
index 1827bd7..3c0f01f 100644
c2d2c5
--- a/doc/misc/options
c2d2c5
+++ b/doc/misc/options
c2d2c5
@@ -147,6 +147,7 @@ options {
c2d2c5
         inline-signing <boolean>;
c2d2c5
         interface-interval <integer>;
c2d2c5
         ixfr-from-differences <ixfrdiff>;
c2d2c5
+	keep-response-order { <address_match_element>; ... };
c2d2c5
         key-directory <quoted_string>;
c2d2c5
         lame-ttl <integer>;
c2d2c5
         listen-on [ port <integer> ] { <address_match_element>; ... };
c2d2c5
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
c2d2c5
index 00c4b3e..d4803e2 100644
c2d2c5
--- a/lib/bind9/check.c
c2d2c5
+++ b/lib/bind9/check.c
c2d2c5
@@ -403,8 +403,8 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
c2d2c5
 
c2d2c5
 	static const char *acls[] = { "allow-query", "allow-query-on",
c2d2c5
 		"allow-query-cache", "allow-query-cache-on",
c2d2c5
-		"blackhole", "match-clients", "match-destinations",
c2d2c5
-		"sortlist", "filter-aaaa", NULL };
c2d2c5
+		"blackhole", "keep-response-order", "match-clients",
c2d2c5
+		"match-destinations", "sortlist", "filter-aaaa", NULL };
c2d2c5
 
c2d2c5
 	while (acls[i] != NULL) {
c2d2c5
 		tresult = checkacl(acls[i++], actx, NULL, voptions, config,
c2d2c5
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
c2d2c5
index b9f34eb..088c500 100644
c2d2c5
--- a/lib/dns/dispatch.c
c2d2c5
+++ b/lib/dns/dispatch.c
c2d2c5
@@ -2831,7 +2831,6 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
c2d2c5
 	isc_result_t result;
c2d2c5
 	isc_sockaddr_t peeraddr;
c2d2c5
 	isc_sockaddr_t sockname;
c2d2c5
-	isc_sockaddr_t any;
c2d2c5
 	unsigned int attributes, mask;
c2d2c5
 	isc_boolean_t match = ISC_FALSE;
c2d2c5
 
c2d2c5
@@ -2839,23 +2838,9 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
c2d2c5
 	REQUIRE(destaddr != NULL);
c2d2c5
 	REQUIRE(dispp != NULL && *dispp == NULL);
c2d2c5
 
c2d2c5
-	attributes = DNS_DISPATCHATTR_TCP;
c2d2c5
+	attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
c2d2c5
 	mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
c2d2c5
-	       DNS_DISPATCHATTR_EXCLUSIVE;
c2d2c5
-
c2d2c5
-	if (localaddr == NULL) {
c2d2c5
-		switch (isc_sockaddr_pf(destaddr)) {
c2d2c5
-		case AF_INET:
c2d2c5
-			isc_sockaddr_any(&any;;
c2d2c5
-			break;
c2d2c5
-		case AF_INET6:
c2d2c5
-			isc_sockaddr_any6(&any;;
c2d2c5
-			break;
c2d2c5
-		default:
c2d2c5
-			return (ISC_R_NOTFOUND);
c2d2c5
-		}
c2d2c5
-		localaddr = &any;
c2d2c5
-	}
c2d2c5
+	       DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
c2d2c5
 
c2d2c5
 	LOCK(&mgr->lock);
c2d2c5
 	disp = ISC_LIST_HEAD(mgr->list);
c2d2c5
@@ -2872,7 +2857,8 @@ dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
c2d2c5
 								&peeraddr);
c2d2c5
 			if (result == ISC_R_SUCCESS &&
c2d2c5
 			    isc_sockaddr_equal(destaddr, &peeraddr) &&
c2d2c5
-			    isc_sockaddr_eqaddr(localaddr, &sockname)) {
c2d2c5
+			    (localaddr == NULL ||
c2d2c5
+			     isc_sockaddr_eqaddr(localaddr, &sockname))) {
c2d2c5
 				/* attach */
c2d2c5
 				disp->refcount++;
c2d2c5
 				*dispp = disp;
c2d2c5
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
c2d2c5
index d9b1df1..f357c63 100644
c2d2c5
--- a/lib/isccfg/namedconf.c
c2d2c5
+++ b/lib/isccfg/namedconf.c
c2d2c5
@@ -959,6 +959,7 @@ options_clauses[] = {
c2d2c5
 	{ "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
c2d2c5
 	{ "hostname", &cfg_type_qstringornone, 0 },
c2d2c5
 	{ "interface-interval", &cfg_type_uint32, 0 },
c2d2c5
+	{ "keep-response-order", &cfg_type_bracketed_aml, 0 },
c2d2c5
 	{ "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
c2d2c5
 	{ "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
c2d2c5
 	{ "managed-keys-directory", &cfg_type_qstring, 0 },
c2d2c5
-- 
c2d2c5
2.20.1
c2d2c5