diff --git a/daemon/worker.c b/daemon/worker.c index 611781ace..2aa64a44c 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1163,6 +1163,7 @@ worker_delete(struct worker* worker) mesh_stats(worker->env.mesh, "mesh has"); worker_mem_report(worker, NULL); } + outside_network_quit_prepare(worker->back); mesh_delete(worker->env.mesh); ldns_buffer_free(worker->env.scratch_buffer); forwards_delete(worker->env.fwds); diff --git a/doc/Changelog b/doc/Changelog index ac25ecdb4..a8d1de135 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,11 @@ +27 May 2009: Wouter + - detect lack of IPv6 support on XP (with a different error code). + - Fixup a crash-on-exit which was triggered by a very long queue. + Unbound would try to re-use ports that came free, but this is + of course not really possible because everything is deleted. + Most easily triggered on XP (not Vista), maybe because of the + network stack encouraging large messages backlogs. + 26 May 2009: Wouter - Thanks again to Brett Carr, found an assertion that was not true. Assertion checked if recursion parent query still existed. diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 63fd0082d..c17dc56e8 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -72,6 +72,7 @@ libworker_delete(struct libworker* w) { if(!w) return; if(w->env) { + outside_network_quit_prepare(w->back); mesh_delete(w->env->mesh); context_release_alloc(w->ctx, w->env->alloc, !w->is_bg || w->is_bg_thread); diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index a82fa48c8..f0bec69a7 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -295,6 +295,12 @@ make_sock(int stype, const char* ifname, const char* port, hints->ai_socktype = stype; *noip6 = 0; if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) { +#ifdef USE_WINSOCK + if(r == EAI_NONAME && hints->ai_family == AF_INET6){ + *noip6 = 1; /* 'Host not found' for IP6 on winXP */ + return -1; + } +#endif log_err("node %s:%s getaddrinfo: %s %s", ifname?ifname:"default", port, gai_strerror(r), #ifdef EAI_SYSTEM diff --git a/services/outside_network.c b/services/outside_network.c index 34cc6db3e..d8033035c 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -194,7 +194,8 @@ static void use_free_buffer(struct outside_network* outnet) { struct waiting_tcp* w; - while(outnet->tcp_free && outnet->tcp_wait_first) { + while(outnet->tcp_free && outnet->tcp_wait_first + && !outnet->want_to_quit) { w = outnet->tcp_wait_first; outnet->tcp_wait_first = w->next_waiting; if(outnet->tcp_wait_last == w) @@ -276,7 +277,8 @@ outnet_send_wait_udp(struct outside_network* outnet) { struct pending* pend; /* process waiting queries */ - while(outnet->udp_wait_first && outnet->unused_fds) { + while(outnet->udp_wait_first && outnet->unused_fds + && !outnet->want_to_quit) { pend = outnet->udp_wait_first; outnet->udp_wait_first = pend->next_waiting; if(!pend->next_waiting) outnet->udp_wait_last = NULL; @@ -483,6 +485,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, outnet->infra = infra; outnet->rnd = rnd; outnet->svcd_overhead = 0; + outnet->want_to_quit = 0; outnet->unwanted_threshold = unwanted_threshold; outnet->unwanted_action = unwanted_action; outnet->unwanted_param = unwanted_param; @@ -608,11 +611,21 @@ serviced_node_del(rbnode_t* node, void* ATTR_UNUSED(arg)) free(sq); } +void +outside_network_quit_prepare(struct outside_network* outnet) +{ + if(!outnet) + return; + /* prevent queued items from being sent */ + outnet->want_to_quit = 1; +} + void outside_network_delete(struct outside_network* outnet) { if(!outnet) return; + outnet->want_to_quit = 1; /* check every element, since we can be called on malloc error */ if(outnet->pending) { /* free pending elements, but do no unlink from tree. */ diff --git a/services/outside_network.h b/services/outside_network.h index 30f31f451..584f13a9b 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -75,6 +75,8 @@ struct outside_network { size_t svcd_overhead; /** use x20 bits to encode additional ID random bits */ int use_caps_for_id; + /** outside network wants to quit. Stop queued msgs from sent. */ + int want_to_quit; /** number of unwanted replies received (for statistics) */ size_t unwanted_replies; @@ -360,6 +362,12 @@ struct outside_network* outside_network_create(struct comm_base* base, */ void outside_network_delete(struct outside_network* outnet); +/** + * Prepare for quit. Sends no more queries, even if queued up. + * @param outnet: object to prepare for removal + */ +void outside_network_quit_prepare(struct outside_network* outnet); + /** * Send UDP query, create pending answer. * Changes the ID for the query to be random and unique for that destination. diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 217746262..118fd0e8a 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -749,6 +749,11 @@ outside_network_delete(struct outside_network* outnet) free(outnet); } +void +outside_network_quit_prepare(struct outside_network* ATTR_UNUSED(outnet)) +{ +} + struct pending* pending_udp_query(struct outside_network* outnet, ldns_buffer* packet, struct sockaddr_storage* addr, socklen_t addrlen, int timeout,