]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- streamtcp option -a send queries consecutively and prints answers
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 14 Jan 2019 15:52:50 +0000 (15:52 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 14 Jan 2019 15:52:50 +0000 (15:52 +0000)
  as they arrive.
- Fix for out of order processing administration quit cleanup.
- unit test for tcp out of order processing.

git-svn-id: file:///svn/unbound/trunk@5033 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/listen_dnsport.c
services/mesh.c
testcode/streamtcp.1
testcode/streamtcp.c
testdata/tcp_req_order.tdir/tcp_req_order.conf [new file with mode: 0644]
testdata/tcp_req_order.tdir/tcp_req_order.dsc [new file with mode: 0644]
testdata/tcp_req_order.tdir/tcp_req_order.post [new file with mode: 0644]
testdata/tcp_req_order.tdir/tcp_req_order.pre [new file with mode: 0644]
testdata/tcp_req_order.tdir/tcp_req_order.test [new file with mode: 0644]
testdata/tcp_req_order.tdir/tcp_req_order.testns [new file with mode: 0644]

index 45e187e4c352ea6cca042bffb236e93e81b23a27..2959b7f0e59c11ab964e328018fe7eb27d664ab6 100644 (file)
@@ -1,3 +1,9 @@
+14 January 2018: Wouter
+       - streamtcp option -a send queries consecutively and prints answers
+         as they arrive.
+       - Fix for out of order processing administration quit cleanup.
+       - unit test for tcp out of order processing.
+
 11 January 2018: Wouter
        - Initial commit for out-of-order processing for TCP and TLS.
 
index 311cf2dda865ab665be247d6f2ce634ade702bc4..9cfc65b6a1d403ef4a8ae753129bc71c09b42697 100644 (file)
@@ -72,6 +72,9 @@
 /** number of queued TCP connections for listen() */
 #define TCP_BACKLOG 256 
 
+/** number of simultaneous requests a client can have */
+#define TCP_MAX_REQ_SIMULTANEOUS 32
+
 /**
  * Debug print of the getaddrinfo returned address.
  * @param addr: the address returned.
@@ -1591,9 +1594,6 @@ tcp_req_info_remove_mesh_state(struct tcp_req_info* req, struct mesh_state* m)
        }
 }
 
-/** number of simultaneous requests a client can have */
-#define TCP_MAX_REQ_SIMULTANEOUS 10
-
 /** setup listening for read or write */
 static void
 tcp_req_info_setup_listen(struct tcp_req_info* req)
@@ -1669,13 +1669,16 @@ int
 tcp_req_info_handle_read_close(struct tcp_req_info* req)
 {
        verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd);
+       /* if we still have results to write, pick up next and write it */
        if(req->num_done_req != 0) {
                tcp_req_pickup_next_result(req);
                tcp_req_info_setup_listen(req);
                return 1;
        }
+       /* if nothing to do, this closes the connection */
        if(req->num_open_req == 0 && req->num_done_req == 0)
                return 0;
+       /* otherwise, we must be waiting for dns resolve, wait with timeout */
        req->read_is_closed = 1;
        tcp_req_info_setup_listen(req);
        return 1;
index 01771af35733bffaaca556bb1a61562c7e5a70d9..5ffef7714e617b2e4662cbd2d2d370eb67a8fb82 100644 (file)
@@ -740,9 +740,13 @@ mesh_state_cleanup(struct mesh_state* mstate)
        mesh = mstate->s.env->mesh;
        /* drop unsent replies */
        if(!mstate->replies_sent) {
-               struct mesh_reply* rep;
+               struct mesh_reply* rep = mstate->reply_list;
                struct mesh_cb* cb;
-               for(rep=mstate->reply_list; rep; rep=rep->next) {
+               /* in tcp_req_info, the mstates linked are removed, but
+                * the reply_list is now NULL, so the remove-from-empty-list
+                * takes no time and also it does not do the mesh accounting */
+               mstate->reply_list = NULL;
+               for(; rep; rep=rep->next) {
                        comm_point_drop_reply(&rep->query_reply);
                        mesh->num_reply_addrs--;
                }
index 526c8e1699d448d47c2cf5d56578f6fd059ac238..f02b168d2ac8142fd4cac951b33387b39eb7283b 100644 (file)
@@ -44,6 +44,11 @@ Use UDP instead of TCP. No retries are attempted.
 .B \-n
 Do not wait for the answer.
 .TP
+.B \-a
+Print answers on arrival.  This mean queries are sent in sequence without
+waiting for answer but if answers arrive in this time they are printed out. 
+After sending queries the program waits and prints the remainder.
+.TP
 .B \-s
 Use SSL.
 .TP
index 497e3d2888feb7aa202a7355c81da6d9841db4a6..668d6360bb9a435793a57163367fd94d556cdf68 100644 (file)
@@ -73,6 +73,7 @@ static void usage(char* argv[])
        printf("-f server       what ipaddr@portnr to send the queries to\n");
        printf("-u              use UDP. No retries are attempted.\n");
        printf("-n              do not wait for an answer.\n");
+       printf("-a              print answers as they arrive.\n");
        printf("-d secs         delay after connection before sending query\n");
        printf("-s              use ssl\n");
        printf("-h              this help text\n");
@@ -203,13 +204,22 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
        uint16_t len;
        if(!udp) {
                if(ssl) {
-                       if(SSL_read(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
+                       int sr = SSL_read(ssl, (void*)&len, (int)sizeof(len));
+                       if(sr == 0) {
+                               printf("ssl: stream closed\n");
+                               exit(1);
+                       }
+                       if(sr < 0) {
                                log_crypto_err("could not SSL_read");
                                exit(1);
                        }
                } else {
-                       if(recv(fd, (void*)&len, sizeof(len), 0) <
-                               (ssize_t)sizeof(len)) {
+                       ssize_t r = recv(fd, (void*)&len, sizeof(len), 0);
+                       if(r == 0) {
+                               printf("recv: stream closed\n");
+                               exit(1);
+                       }       
+                       if(r < (ssize_t)sizeof(len)) {
 #ifndef USE_WINSOCK
                                perror("read() len failed");
 #else
@@ -267,6 +277,37 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
        free(pktstr);
 }
 
+/** see if we can receive any results */
+static void
+print_any_answers(int fd, int udp, SSL* ssl, sldns_buffer* buf,
+       int* num_answers, int wait_all)
+{
+       /* see if the fd can read, if so, print one answer, repeat */
+       int ret;
+       struct timeval tv, *waittv;
+       fd_set rfd;
+       while(*num_answers > 0) {
+               memset(&rfd, 0, sizeof(rfd));
+               memset(&tv, 0, sizeof(tv));
+               FD_ZERO(&rfd);
+               FD_SET(fd, &rfd);
+               if(wait_all) waittv = NULL;
+               else waittv = &tv;
+               ret = select(fd+1, &rfd, NULL, NULL, waittv);
+               if(ret < 0) {
+                       if(errno == EINTR || errno == EAGAIN) continue;
+                       perror("select() failed");
+                       exit(1);
+               }
+               if(ret == 0) {
+                       if(wait_all) continue;
+                       return;
+               }
+               (*num_answers) -= 1;
+               recv_one(fd, udp, ssl, buf);
+       }
+}
+
 static int get_random(void)
 {
        int r;
@@ -278,12 +319,12 @@ static int get_random(void)
 
 /** send the TCP queries and print answers */
 static void
-send_em(const char* svr, int udp, int usessl, int noanswer, int delay,
-       int num, char** qs)
+send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
+       int delay, int num, char** qs)
 {
        sldns_buffer* buf = sldns_buffer_new(65553);
        int fd = open_svr(svr, udp);
-       int i;
+       int i, wait_results = 0;
        SSL_CTX* ctx = NULL;
        SSL* ssl = NULL;
        if(!buf) fatal_exit("out of memory");
@@ -325,9 +366,15 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int delay,
                write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
                        qs[i+1], qs[i+2]);
                /* print at least one result */
-               if(!noanswer)
+               if(onarrival) {
+                       wait_results += 1; /* one more answer to fetch */
+                       print_any_answers(fd, udp, ssl, buf, &wait_results, 0);
+               } else if(!noanswer) {
                        recv_one(fd, udp, ssl, buf);
+               }
        }
+       if(onarrival)
+               print_any_answers(fd, udp, ssl, buf, &wait_results, 1);
 
        if(usessl) {
                SSL_shutdown(ssl);
@@ -368,6 +415,7 @@ int main(int argc, char** argv)
        const char* svr = "127.0.0.1";
        int udp = 0;
        int noanswer = 0;
+       int onarrival = 0;
        int usessl = 0;
        int delay = 0;
 
@@ -394,11 +442,14 @@ int main(int argc, char** argv)
        if(argc == 1) {
                usage(argv);
        }
-       while( (c=getopt(argc, argv, "f:hnsud:")) != -1) {
+       while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
                switch(c) {
                        case 'f':
                                svr = optarg;
                                break;
+                       case 'a':
+                               onarrival = 1;
+                               break;
                        case 'n':
                                noanswer = 1;
                                break;
@@ -446,7 +497,7 @@ int main(int argc, char** argv)
                (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
 #endif
        }
-       send_em(svr, udp, usessl, noanswer, delay, argc, argv);
+       send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
        checklock_stop();
 #ifdef USE_WINSOCK
        WSACleanup();
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.conf b/testdata/tcp_req_order.tdir/tcp_req_order.conf
new file mode 100644 (file)
index 0000000..40d6f55
--- /dev/null
@@ -0,0 +1,22 @@
+server:
+       verbosity: 2
+       # num-threads: 1
+       interface: 127.0.0.1
+       port: @PORT@
+       use-syslog: no
+       directory: .
+       pidfile: "unbound.pid"
+       chroot: ""
+       username: ""
+       do-not-query-localhost: no
+
+       local-zone: "example.net" static
+       local-data: "www1.example.net. IN A 1.2.3.1"
+       local-data: "www2.example.net. IN A 1.2.3.2"
+       local-data: "www3.example.net. IN A 1.2.3.3"
+       tcp-upstream: yes
+       local-zone: "drop.net" deny
+
+forward-zone:
+       name: "."
+       forward-addr: "127.0.0.1@@TOPORT@"
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.dsc b/testdata/tcp_req_order.tdir/tcp_req_order.dsc
new file mode 100644 (file)
index 0000000..f24e900
--- /dev/null
@@ -0,0 +1,16 @@
+BaseName: tcp_req_order
+Version: 1.0
+Description: Test tcp request order processing.
+CreationDate: Mon Jan 14 13:34:00 CET 2018
+Maintainer: Wouter Wijngaards
+Category: 
+Component:
+CmdDepends: 
+Depends: 
+Help:
+Pre: tcp_req_order.pre
+Post: tcp_req_order.post
+Test: tcp_req_order.test
+AuxFiles: 
+Passed:
+Failure:
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.post b/testdata/tcp_req_order.tdir/tcp_req_order.post
new file mode 100644 (file)
index 0000000..4337276
--- /dev/null
@@ -0,0 +1,11 @@
+# #-- tcp_req_order.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
+cat unbound.log
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.pre b/testdata/tcp_req_order.tdir/tcp_req_order.pre
new file mode 100644 (file)
index 0000000..b2191f0
--- /dev/null
@@ -0,0 +1,31 @@
+# #-- tcp_req_order.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+. ../common.sh
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT tcp_req_order.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < tcp_req_order.conf > ub.conf
+# start unbound in the background
+PRE="../.."
+$PRE/unbound -vvvv -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+wait_ldns_testns_up fwd.log
+wait_unbound_up unbound.log
+
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.test b/testdata/tcp_req_order.tdir/tcp_req_order.test
new file mode 100644 (file)
index 0000000..ecbde30
--- /dev/null
@@ -0,0 +1,341 @@
+# #-- tcp_req_order.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+. ../common.sh
+get_make
+(cd $PRE; $MAKE streamtcp)
+
+# this test query should just work (server is up)
+echo "> query www1.example.net."
+$PRE/streamtcp -f 127.0.0.1@$UNBOUND_PORT www1.example.net. A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www1.example.net" outfile | grep "1.2.3.1"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+echo "OK"
+
+# multiple requests (from localdata)
+echo "> query www1.example.net. www2.example.net. www3.example.net."
+$PRE/streamtcp -f 127.0.0.1@$UNBOUND_PORT www1.example.net. A IN www2.example.net A IN www3.example.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www1.example.net" outfile | grep "1.2.3.1"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www2.example.net" outfile | grep "1.2.3.2"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www3.example.net" outfile | grep "1.2.3.3"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+
+# out of order requests, the example.com elements take 2 seconds to wait.
+echo ""
+echo "> query www1.example.net. www.example.com. www2.example.net. www2.example.com. www3.example.net."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www1.example.net. A IN www.example.com. A IN www2.example.net A IN www2.example.com. A IN www3.example.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www1.example.net" outfile | grep "1.2.3.1"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www2.example.net" outfile | grep "1.2.3.2"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www3.example.net" outfile | grep "1.2.3.3"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www.example.com" outfile | grep "10.20.30.40"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www2.example.com" outfile | grep "10.20.30.42"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+
+# out of order requests, the example.com elements take 2 seconds to wait.
+# www.example.com present twice, answered twice.
+echo ""
+echo "> query www1.example.net. www.example.com. www2.example.net. www.example.com. www3.example.net."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www1.example.net. A IN www.example.com. A IN www2.example.net A IN www.example.com. A IN www3.example.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www1.example.net" outfile | grep "1.2.3.1"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www2.example.net" outfile | grep "1.2.3.2"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www3.example.net" outfile | grep "1.2.3.3"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www.example.com" outfile | grep "10.20.30.40"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+
+# out of order requests, the example.com elements take 2 seconds to wait.
+# www3.example.com present twice, answered twice.
+echo ""
+echo "> query www1.example.net. www3.example.com. www2.example.net. www3.example.com. www3.example.net."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www1.example.net. A IN www3.example.com. A IN www2.example.net A IN www3.example.com. A IN www3.example.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www1.example.net" outfile | grep "1.2.3.1"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www2.example.net" outfile | grep "1.2.3.2"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www3.example.net" outfile | grep "1.2.3.3"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www3.example.com" outfile | grep "10.20.30.43"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+
+echo ""
+echo "> query www4.example.com. www3.example.net."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www4.example.com. A IN www3.example.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+if grep "www3.example.net" outfile | grep "1.2.3.3"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+if grep "www4.example.com" outfile | grep "10.20.30.44"; then
+       echo "content OK"
+else
+       echo "result contents not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "result contents not OK"
+       exit 1
+fi
+
+echo ""
+echo "> query a1.example.com. - a100.example.com."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www6.example.com. A IN a1.a.example.com. A IN a2.a.example.com. A IN a3.a.example.com. A IN a4.a.example.com. A IN a5.a.example.com. A IN a6.a.example.com. A IN a7.a.example.com. A IN a8.a.example.com. A IN a9.a.example.com. A IN a10.a.example.com. A IN a11.a.example.com. A IN a12.a.example.com. A IN a13.a.example.com. A IN a14.a.example.com. A IN a15.a.example.com. A IN a16.a.example.com. A IN a17.a.example.com. A IN a18.a.example.com. A IN a19.a.example.com. A IN a20.a.example.com. A IN a21.a.example.com. A IN a22.a.example.com. A IN a23.a.example.com. A IN a24.a.example.com. A IN a25.a.example.com. A IN a26.a.example.com. A IN a27.a.example.com. A IN a28.a.example.com. A IN a29.a.example.com. A IN a30.a.example.com. A IN a31.a.example.com. A IN a32.a.example.com. A IN a33.a.example.com. A IN a34.a.example.com. A IN a35.a.example.com. A IN a36.a.example.com. A IN a37.a.example.com. A IN a38.a.example.com. A IN a39.a.example.com. A IN a40.a.example.com. A IN a41.a.example.com. A IN a42.a.example.com. A IN a43.a.example.com. A IN a44.a.example.com. A IN a45.a.example.com. A IN a46.a.example.com. A IN a47.a.example.com. A IN a48.a.example.com. A IN a49.a.example.com. A IN a50.a.example.com. A IN a51.a.example.com. A IN a52.a.example.com. A IN a53.a.example.com. A IN a54.a.example.com. A IN a55.a.example.com. A IN a56.a.example.com. A IN a57.a.example.com. A IN a58.a.example.com. A IN a59.a.example.com. A IN a60.a.example.com. A IN a61.a.example.com. A IN a62.a.example.com. A IN a63.a.example.com. A IN a64.a.example.com. A IN a65.a.example.com. A IN a66.a.example.com. A IN a67.a.example.com. A IN a68.a.example.com. A IN a69.a.example.com. A IN a70.a.example.com. A IN a71.a.example.com. A IN a72.a.example.com. A IN a73.a.example.com. A IN a74.a.example.com. A IN a75.a.example.com. A IN a76.a.example.com. A IN a77.a.example.com. A IN a78.a.example.com. A IN a79.a.example.com. A IN a80.a.example.com. A IN a81.a.example.com. A IN a82.a.example.com. A IN a83.a.example.com. A IN a84.a.example.com. A IN a85.a.example.com. A IN a86.a.example.com. A IN a87.a.example.com. A IN a88.a.example.com. A IN a89.a.example.com. A IN a90.a.example.com. A IN a91.a.example.com. A IN a92.a.example.com. A IN a93.a.example.com. A IN a94.a.example.com. A IN a95.a.example.com. A IN a96.a.example.com. A IN a97.a.example.com. A IN a98.a.example.com. A IN a99.a.example.com. A IN a100.a.example.com. A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+grep "a.example.com.   IN      A" outfile
+
+echo ""
+echo "> query www5.example.net. www3.example.net. www.drop.net."
+$PRE/streamtcp -a -f 127.0.0.1@$UNBOUND_PORT www5.example.com. A IN www3.example.net A IN www.drop.net A IN >outfile 2>&1
+cat outfile
+if test "$?" -ne 0; then
+       echo "exit status not OK"
+       echo "> cat logfiles"
+       cat outfile
+       cat fwd.log 
+       cat unbound.log
+       echo "Not OK"
+       exit 1
+fi
+
+echo "OK"
+exit 0
diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.testns b/testdata/tcp_req_order.tdir/tcp_req_order.testns
new file mode 100644 (file)
index 0000000..c53941b
--- /dev/null
@@ -0,0 +1,74 @@
+; nameserver test file
+$ORIGIN example.com.
+$TTL 3600
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id sleep=2
+SECTION QUESTION
+www    IN      A
+SECTION ANSWER
+www    IN      A       10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+www2   IN      A
+SECTION ANSWER
+www2   IN      A       10.20.30.42
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+www3   IN      A
+SECTION ANSWER
+www3   IN      A       10.20.30.43
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id sleep=2
+SECTION QUESTION
+www4   IN      A
+SECTION ANSWER
+www4   IN      A       10.20.30.44
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id sleep=2
+SECTION QUESTION
+www5   IN      A
+SECTION ANSWER
+www5   IN      A       10.20.30.45
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id sleep=2
+SECTION QUESTION
+www6   IN      A
+SECTION ANSWER
+www6   IN      A       10.20.30.46
+ENTRY_END
+
+; lots of noerror/nodata answers for other queries (a.. queries)
+ENTRY_BEGIN
+MATCH opcode qtype subdomain
+REPLY QR AA NOERROR
+ADJUST copy_id copy_query
+SECTION QUESTION
+a.example.com. IN      A
+SECTION AUTHORITY
+example.com.   IN SOA ns hostmaster 2019 28800 7200 604800 3600
+ENTRY_END