]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
TCP fallback if forwarder sends TC bit.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 9 May 2007 07:00:10 +0000 (07:00 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 9 May 2007 07:00:10 +0000 (07:00 +0000)
git-svn-id: file:///svn/unbound/trunk@295 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/Changelog
services/outside_network.c
testcode/fake_event.c
util/data/msgreply.c
util/data/msgreply.h
util/netevent.c
util/netevent.h

index 4e78104f4e80ab769f8a6606878707d9d573d18d..9fbd1e5bd90ff67b3464df20167a41cb0c806e38 100644 (file)
@@ -63,6 +63,8 @@
 #define DNS_ID_AND_FLAGS 4
 /** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */
 #define UDP_QUERY_TIMEOUT 4
+/** timeout in seconds for TCP queries to auth servers. TODO: proper rtt */
+#define TCP_QUERY_TIMEOUT 30 
 /** Advertised version of EDNS capabilities */
 #define EDNS_ADVERTISED_VERSION        0
 /** Advertised size of EDNS capabilities */
@@ -237,6 +239,11 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
        /* see if it is truncated */
        if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) && c->type == comm_udp) {
                log_info("TC: truncated. retry in TCP mode.");
+               qinfo_query_encode(w->worker->back->udp_buff, &w->qinfo);
+               pending_tcp_query(w->worker->back, w->worker->back->udp_buff, 
+                       &w->worker->fwd_addr, w->worker->fwd_addrlen, 
+                       TCP_QUERY_TIMEOUT, worker_handle_reply, w, 
+                       w->worker->rndstate);
                return 0;
        }
        /* woohoo a reply! */
index 7acb5cf8f5cc85b748dde7dd8c401f92479173a4..8b914e8a9468c24fdc73bf08e2537783542a6556 100644 (file)
@@ -1,3 +1,7 @@
+9 May 2007: Wouter
+       - outside network cleans up waiting tcp queries on exit.
+       - fallback to TCP.
+
 8 May 2007: Wouter
        - outgoing network keeps list of available tcp buffers for outgoing 
          tcp queries.
index c2a738891c7921f51b0ce0b483964bda37cc7ee1..bd39b7daa484169a11880d5f54734e4062cb2f6d 100644 (file)
@@ -109,6 +109,18 @@ pending_cmp(const void* key1, const void* key2)
        }
 }
 
+/** delete waiting_tcp entry. Does not unlink from waiting list. 
+ * @param w: to delete.
+ */
+static void
+waiting_tcp_delete(struct waiting_tcp* w)
+{
+       if(!w) return;
+       if(w->timer)
+               comm_timer_delete(w->timer);
+       free(w);
+}
+
 /** use next free buffer to service a tcp query */
 static void
 outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
@@ -128,7 +140,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
                log_err("outgoing tcp: socket: %s", strerror(errno));
                log_addr(&w->addr, w->addrlen);
                (void)(*w->cb)(NULL, w->cb_arg, NETEVENT_CLOSED, NULL);
-               free(w);
+               waiting_tcp_delete(w);
                return;
        }
        fd_set_nonblock(s);
@@ -138,13 +150,13 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
                        log_addr(&w->addr, w->addrlen);
                        close(s);
                        (void)(*w->cb)(NULL, w->cb_arg, NETEVENT_CLOSED, NULL);
-                       free(w);
+                       waiting_tcp_delete(w);
                        return;
                }
        }
        w->pkt = NULL;
        w->next_waiting = (void*)pend;
-       memmove(&pend->id, pkt, sizeof(uint16_t));
+       pend->id = LDNS_ID_WIRE(pkt);
        w->outnet->tcp_free = pend->next_free;
        pend->next_free = NULL;
        pend->query = w;
@@ -186,7 +198,7 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
                /* check ID */
                if(ldns_buffer_limit(c->buffer) < sizeof(uint16_t) ||
                        LDNS_ID_WIRE(ldns_buffer_begin(c->buffer))!=pend->id) {
-                       log_info("outnettcp: bad ID in reply");
+                       log_info("outnettcp: bad ID in reply, from:");
                        log_addr(&pend->query->addr, pend->query->addrlen);
                        error = NETEVENT_CLOSED;
                }
@@ -195,7 +207,7 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
        comm_point_close(c);
        pend->next_free = outnet->tcp_free;
        outnet->tcp_free = pend;
-       free(pend->query);
+       waiting_tcp_delete(pend->query);
        pend->query = NULL;
        use_free_buffer(outnet);
        return 0;
@@ -380,7 +392,8 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
                outnet->tcp_conns[i]->next_free = outnet->tcp_free;
                outnet->tcp_free = outnet->tcp_conns[i];
                outnet->tcp_conns[i]->c = comm_point_create_tcp_out(
-                       bufsize, outnet_tcp_cb, outnet->tcp_conns[i]);
+                       outnet->base, bufsize, outnet_tcp_cb, 
+                       outnet->tcp_conns[i]);
                if(!outnet->tcp_conns[i]->c)
                        return 0;
        }
@@ -499,10 +512,20 @@ outside_network_delete(struct outside_network* outnet)
                for(i=0; i<outnet->num_tcp; i++)
                        if(outnet->tcp_conns[i]) {
                                comm_point_delete(outnet->tcp_conns[i]->c);
+                               waiting_tcp_delete(outnet->tcp_conns[i]->query);
                                free(outnet->tcp_conns[i]);
                        }
                free(outnet->tcp_conns);
        }
+       if(outnet->tcp_wait_first) {
+               struct waiting_tcp* p = outnet->tcp_wait_first, *np;
+               while(p) {
+                       np = p->next_waiting;
+                       waiting_tcp_delete(p);
+                       p = np;
+               }
+       }
+
        free(outnet);
 }
 
@@ -687,7 +710,7 @@ outnet_tcptimer(void* arg)
                outnet->tcp_free = pend;
        }
        (void)(*w->cb)(NULL, w->cb_arg, NETEVENT_TIMEOUT, NULL);
-       free(w);
+       waiting_tcp_delete(w);
        use_free_buffer(outnet);
 }
 
index 9368bb9789031b2b55b17b894261296efa9e1e32..97f8f00a38ae6465fdda7aec88cbc15a62dc8815 100644 (file)
@@ -703,6 +703,53 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
        runtime->pending_list = pend;
 }
 
+void 
+pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
+       struct sockaddr_storage* addr, socklen_t addrlen, int timeout,
+       comm_point_callback_t* callback, void* callback_arg,
+       struct ub_randstate* ATTR_UNUSED(rnd))
+{
+       struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
+       struct fake_pending* pend = (struct fake_pending*)calloc(1,
+               sizeof(struct fake_pending));
+       ldns_status status;
+       log_assert(pend);
+       pend->buffer = ldns_buffer_new(ldns_buffer_capacity(packet));
+       log_assert(pend->buffer);
+       ldns_buffer_write(pend->buffer, ldns_buffer_begin(packet),
+               ldns_buffer_limit(packet));
+       ldns_buffer_flip(pend->buffer);
+       memcpy(&pend->addr, addr, addrlen);
+       pend->addrlen = addrlen;
+       pend->callback = callback;
+       pend->cb_arg = callback_arg;
+       pend->timeout = timeout;
+       pend->transport = transport_tcp;
+       pend->pkt = NULL;
+       status = ldns_buffer2pkt_wire(&pend->pkt, packet);
+       if(status != LDNS_STATUS_OK) {
+               log_err("ldns error parsing tcp output packet: %s",
+                       ldns_get_errorstr_by_id(status));
+               fatal_exit("Sending unparseable DNS packets to servers!");
+       }
+       log_pkt("pending tcp pkt: ", pend->pkt);
+
+       /* see if it matches the current moment */
+       if(runtime->now && runtime->now->evt_type == repevt_back_query &&
+               find_match(runtime->now->match, pend->pkt, pend->transport)) {
+               log_info("testbound: matched pending to event. "
+                       "advance time between events.");
+               log_info("testbound: do STEP %d %s", runtime->now->time_step,
+                       repevt_string(runtime->now->evt_type));
+               advance_moment(runtime);
+               /* still create the pending, because we need it to callback */
+       } 
+       log_info("testbound: created fake pending");
+       /* add to list */
+       pend->next = runtime->pending_list;
+       runtime->pending_list = pend;
+}
+
 struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
 {
        return calloc(1, 1);
index 7c09f89ab9af08b62442efb32848974a66196941..a93f4518db88f4dddc725c70e9ad1377b4a0b534 100644 (file)
@@ -1145,3 +1145,21 @@ query_info_entrysetup(struct query_info* q, struct reply_info* r,
        q->qname = NULL;
        return e;
 }
+
+void 
+qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo)
+{
+       uint16_t flags = 0; /* QUERY, NOERROR */
+       if(qinfo->has_cd)
+               flags |= BIT_CD;
+       ldns_buffer_clear(pkt);
+       log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
+       ldns_buffer_skip(pkt, 2); /* id done later */
+       ldns_buffer_write_u16(pkt, flags);
+       ldns_buffer_write_u16(pkt, 1); /* query count */
+       ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
+       ldns_buffer_write(pkt, qinfo->qname, qinfo->qnamesize);
+       ldns_buffer_write_u16(pkt, qinfo->qtype);
+       ldns_buffer_write_u16(pkt, qinfo->qclass);
+       ldns_buffer_flip(pkt);
+}
index d8e6c94de337058a1e6a778dc683d430cad1565b..4e712d6615e58c40c332e94fa1187e029480e356 100644 (file)
@@ -288,6 +288,13 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
        uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, 
        struct region* region, uint16_t udpsize);
 
+/**
+ * Encode query packet. Assumes the buffer is large enough.
+ * @param pkt: where to store the packet.
+ * @param qinfo: query info.
+ */
+void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo);
+
 /**
  * Setup query info entry
  * @param q: query info to copy. Emptied as if clear is called.
index 184998658d78232b0283721b77f732630b4ae4b1..befa2b7596987ffd2ba6b504d023108e4a142ba4 100644 (file)
@@ -712,11 +712,12 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
 }
 
 struct comm_point* 
-comm_point_create_tcp_out(size_t bufsize,
+comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
         comm_point_callback_t* callback, void* callback_arg)
 {
        struct comm_point* c = (struct comm_point*)calloc(1,
                sizeof(struct comm_point));
+       short evbits;
        if(!c)
                return NULL;
        c->ev = (struct internal_event*)calloc(1,
@@ -746,6 +747,17 @@ comm_point_create_tcp_out(size_t bufsize,
        c->tcp_check_nb_connect = 1;
        c->callback = callback;
        c->cb_arg = callback_arg;
+       evbits = EV_PERSIST | EV_WRITE;
+       event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
+       if(event_base_set(base->eb->base, &c->ev->ev) != 0)
+       {
+               log_err("could not basetset tcpout event");
+               ldns_buffer_free(c->buffer);
+               free(c->ev);
+               free(c);
+               return NULL;
+       }
+
        return c;
 }
 
index 4e031d7cbea3887b4fe0dc58634d11a3cb92b74d..83b5d52979d67d78ac1ad53e0f89fb5d39971193 100644 (file)
@@ -293,13 +293,14 @@ struct comm_point* comm_point_create_tcp(struct comm_base* base,
 
 /**
  * Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.
+ * @param base: in which base to alloc the commpoint.
  * @param bufsize: size of buffer to create for handlers.
  * @param callback: callback function pointer for the handler.
  * @param callback_arg: will be passed to your callback function.
  * @return: the commpoint or NULL on error.
  */
-struct comm_point* comm_point_create_tcp_out(size_t bufsize, 
-       comm_point_callback_t* callback, void* callback_arg);
+struct comm_point* comm_point_create_tcp_out(struct comm_base* base,
+       size_t bufsize, comm_point_callback_t* callback, void* callback_arg);
 
 /**
  * Create commpoint to listen to a local domain file descriptor.