]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
do multiple queries over TCP.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 8 Feb 2008 10:59:18 +0000 (10:59 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 8 Feb 2008 10:59:18 +0000 (10:59 +0000)
git-svn-id: file:///svn/unbound/trunk@935 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
doc/Changelog
testcode/streamtcp.c [new file with mode: 0644]
testdata/stream_tcp.tpkg [new file with mode: 0644]
util/netevent.c

index 0a2341ea2938b147d25359d7c4b94976da9e46c3..fc3aefb2e972ab679a277b7f5116744174b2ea32 100644 (file)
@@ -92,13 +92,15 @@ MEMSTATS_SRC=testcode/memstats.c smallapp/worker_cb.c $(COMMON_SRC)
 MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
 ASYNCLOOK_SRC=testcode/asynclook.c
 ASYNCLOOK_OBJ=$(addprefix $(BUILD),$(ASYNCLOOK_SRC:.c=.o)) $(COMPAT_OBJ)
+STREAMTCP_SRC=testcode/streamtcp.c smallapp/worker_cb.c $(COMMON_SRC)
+STREAMTCP_OBJ=$(addprefix $(BUILD),$(STREAMTCP_SRC:.c=.o)) $(COMPAT_OBJ)
 LIBUNBOUND_SRC=$(patsubst $(srcdir)/%,%, \
        $(wildcard $(srcdir)/libunbound/*.c) $(COMMON_SRC))
 LIBUNBOUND_OBJ=$(addprefix $(BUILD),$(LIBUNBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
-ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
+ALL_SRC=$(sort $(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
        $(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
        $(MEMSTATS_SRC) $(CHECKCONF_SRC) $(LIBUNBOUND_SRC) $(HOST_SRC) \
-       $(ASYNCLOOK_SRC)
+       $(ASYNCLOOK_SRC) $(STREAMTCP_SRC))
 ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.o) \
        $(addprefix compat/,$(LIBOBJS))) $(COMPAT_OBJ)
 
@@ -117,7 +119,8 @@ $(BUILD)%.o:    $(srcdir)/%.c
 
 all:   $(COMMON_OBJ) unbound unbound-checkconf lib unbound-host
 
-tests: all unittest testbound lock-verify pktview signit memstats asynclook
+tests: all unittest testbound lock-verify pktview signit memstats \
+       asynclook streamtcp
 
 test:  tests
        bash testcode/do-tests.sh
@@ -177,6 +180,10 @@ asynclook: $(ASYNCLOOK_OBJ) $(ldnslib) libunbound.la
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(ASYNCLOOK_OBJ)) $(LIBS) -L. -L.libs -lunbound
 
+streamtcp:     $(STREAMTCP_OBJ) $(ldnslib)
+       $(INFO) Link $@
+       $Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) $(LIBS)
+
 #testcode/ldns-testpkts.c:     $(ldnsdir)/examples/ldns-testpkts.c \
 #                      $(ldnsdir)/examples/ldns-testpkts.h
 #      cp $(ldnsdir)/examples/ldns-testpkts.c testcode/ldns-testpkts.c
index 76dcc069173f9b483aa356663d9b19045e91e8db..ff85eb9a95d6173adf2a9b8aafe283ca1f91fdf5 100644 (file)
@@ -1,3 +1,8 @@
+8 February 2008: Wouter
+       - test program for multiple queries over a TCP channel.
+       - tpkg test for stream tcp queries.
+       - unbound replies to multiple TCP queries on a TCP channel.
+
 7 February 2008: Wouter
        - moved up all current level 2 to be level 3. And 3 to 4.
          to make room for new debug level 2 for detailed information 
diff --git a/testcode/streamtcp.c b/testcode/streamtcp.c
new file mode 100644 (file)
index 0000000..6fbeb39
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp.
+ *
+ * Copyright (c) 2008, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This program performs multiple DNS queries on a TCP stream.
+ */
+
+#include "config.h"
+#include <signal.h>
+#include "util/locks.h"
+#include "util/log.h"
+#include "util/net_help.h"
+#include "util/data/msgencode.h"
+#include "util/data/msgreply.h"
+#include "util/data/dname.h"
+
+/** usage information for streamtcp */
+void usage(char* argv[])
+{
+       printf("usage: %s [options] name type class ...\n", argv[0]);
+       printf("        sends the name-type-class queries over TCP.\n");
+       printf("-f server       what ipaddr@portnr to send the queries to\n");
+       printf("-h              this help text\n");
+       exit(1);
+}
+
+/** open TCP socket to svr */
+static int
+open_svr(char* svr)
+{
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int fd = -1;
+       /* svr can be ip@port */
+       if(!extstrtoaddr(svr, &addr, &addrlen)) {
+               printf("fatal: bad server specs '%s'\n", svr);
+               exit(1);
+       }
+       fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
+               SOCK_STREAM, 0);
+       if(fd == -1) {
+               perror("socket() error");
+               exit(1);
+       }
+       if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
+               perror("connect() error");
+               exit(1);
+       }
+       return fd;
+}
+
+/** write a query over the TCP fd */
+static void
+write_q(int fd, ldns_buffer* buf, int id, 
+       char* strname, char* strtype, char* strclass)
+{
+       struct query_info qinfo;
+       ldns_rdf* rdf;
+       int labs;
+       uint16_t len;
+       /* qname */
+       rdf = ldns_dname_new_frm_str(strname);
+       if(!rdf) {
+               printf("cannot parse query name: '%s'\n", strname);
+               exit(1);
+       }
+       qinfo.qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
+       labs = dname_count_size_labels(qinfo.qname, &qinfo.qname_len);
+       ldns_rdf_deep_free(rdf);
+       if(!qinfo.qname) fatal_exit("out of memory");
+
+       /* qtype and qclass */
+       qinfo.qtype = ldns_get_rr_type_by_name(strtype);
+       qinfo.qclass = ldns_get_rr_class_by_name(strclass);
+
+       /* make query */
+       qinfo_query_encode(buf, &qinfo);
+       ldns_buffer_write_u16_at(buf, 0, (uint16_t)id);
+       ldns_buffer_write_u16_at(buf, 2, BIT_RD);
+
+       /* send it */
+       len = (uint16_t)ldns_buffer_limit(buf);
+       len = htons(len);
+       if(write(fd, &len, sizeof(len)) < (ssize_t)sizeof(len)) {
+               perror("write() len failed");
+               exit(1);
+       }
+       if(write(fd, ldns_buffer_begin(buf), ldns_buffer_limit(buf)) < 
+               (ssize_t)ldns_buffer_limit(buf)) {
+               perror("write() data failed");
+               exit(1);
+       }
+
+       free(qinfo.qname);
+}
+
+/** receive DNS datagram over TCP and print it */
+static void
+recv_one(int fd, ldns_buffer* buf)
+{
+       uint16_t len;
+       ldns_pkt* pkt;
+       ldns_status status;
+       if(read(fd, &len, sizeof(len)) < (ssize_t)sizeof(len)) {
+               perror("read() len failed");
+               exit(1);
+       }
+       len = ntohs(len);
+       ldns_buffer_clear(buf);
+       ldns_buffer_set_limit(buf, len);
+       if(read(fd, ldns_buffer_begin(buf), len) < (ssize_t)len) {
+               perror("read() data failed");
+               exit(1);
+       }
+       printf("\nnext received packet\n");
+       log_buf(0, "data", buf);
+
+       status = ldns_wire2pkt(&pkt, ldns_buffer_begin(buf), len);
+       if(status != LDNS_STATUS_OK) {
+               printf("could not parse incoming packet: %s\n",
+                       ldns_get_errorstr_by_id(status));
+               log_buf(0, "data was", buf);
+               exit(1);
+       }
+       ldns_pkt_print(stdout, pkt);
+       ldns_pkt_free(pkt);
+}
+
+/** send the TCP queries and print answers */
+static void
+send_em(char* svr, int num, char** qs)
+{
+       ldns_buffer* buf = ldns_buffer_new(65553);
+       int fd = open_svr(svr);
+       int i;
+       if(!buf) fatal_exit("out of memory");
+       for(i=0; i<num; i+=3) {
+               printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
+               write_q(fd, buf, i, qs[i], qs[i+1], qs[i+2]);
+               /* print at least one result */
+               recv_one(fd, buf);
+       }
+
+       close(fd);
+       ldns_buffer_free(buf);
+       printf("orderly exit\n");
+}
+
+/** SIGPIPE handler */
+static RETSIGTYPE sigh(int sig)
+{
+       if(sig == SIGPIPE) {
+               printf("got SIGPIPE, remote connection gone\n");
+               exit(1);
+       }
+       printf("Got unhandled signal %d\n", sig);
+       exit(1);
+}
+
+/** getopt global, in case header files fail to declare it. */
+extern int optind;
+/** getopt global, in case header files fail to declare it. */
+extern char* optarg;
+
+/** main program for streamtcp */
+int main(int argc, char** argv) 
+{
+       int c;
+       char* svr = "127.0.0.1";
+
+       /* lock debug start (if any) */
+       log_init(0, 0, 0);
+       checklock_start();
+
+       if(signal(SIGPIPE, &sigh) == SIG_ERR) {
+               perror("could not install signal handler");
+               return 1;
+       }
+
+       /* command line options */
+       if(argc == 1) {
+               usage(argv);
+       }
+       while( (c=getopt(argc, argv, "f:h")) != -1) {
+               switch(c) {
+                       case 'f':
+                               svr = optarg;
+                               break;
+                       case 'h':
+                       case '?':
+                       default:
+                               usage(argv);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if(argc % 3 != 0) {
+               printf("queries must be multiples of name,type,class\n");
+               return 1;
+       }
+       send_em(svr, argc, argv);
+       checklock_stop();
+       return 0;
+}
diff --git a/testdata/stream_tcp.tpkg b/testdata/stream_tcp.tpkg
new file mode 100644 (file)
index 0000000..f489ecb
Binary files /dev/null and b/testdata/stream_tcp.tpkg differ
index 832cf948ae5bb6a5db623a8978c4a16d0db10db0..c72dc9d116449fd43eb80523efa3714d9379a98f 100644 (file)
@@ -521,11 +521,9 @@ tcp_callback_writer(struct comm_point* c)
        if(c->tcp_do_toggle_rw)
                c->tcp_is_reading = 1;
        c->tcp_byte_count = 0;
+       /* switch from listening(write) to listening(read) */
        comm_point_stop_listening(c);
-       if(c->tcp_parent) /* for listening socket */
-               reclaim_tcp_handler(c);
-       else    /* its outgoing socket, start listening for reading */
-               comm_point_start_listening(c, -1, -1);
+       comm_point_start_listening(c, -1, -1);
 }
 
 /** do the callback when reading is done */