From 5f6eb6d58e340939aeb39c29cb04d4437b347e5a Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Tue, 10 Feb 2009 15:11:54 +0000 Subject: [PATCH] dump_requestlist feature. git-svn-id: file:///svn/unbound/trunk@1473 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/remote.c | 121 +++++++++++++++++++++++++++++++++++++ doc/Changelog | 1 + doc/unbound-control.8.in | 5 ++ smallapp/unbound-control.c | 1 + 4 files changed, 128 insertions(+) diff --git a/daemon/remote.c b/daemon/remote.c index 2b39eead0..b7de708fc 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -62,6 +62,9 @@ #include "validator/validator.h" #include "validator/val_kcache.h" #include "validator/val_kentry.h" +#include "iterator/iterator.h" +#include "services/outbound_list.h" +#include "services/outside_network.h" #ifdef HAVE_SYS_TYPES_H # include @@ -1228,6 +1231,122 @@ do_status(SSL* ssl, struct worker* worker) return; } +/** get age for the mesh state */ +static void +get_mesh_age(struct mesh_state* m, char* buf, size_t len, + struct module_env* env) +{ + if(m->reply_list) { + struct timeval d; + struct mesh_reply* r = m->reply_list; + /* last reply is the oldest */ + while(r && r->next) + r = r->next; + timeval_subtract(&d, env->now_tv, &r->start_time); + snprintf(buf, len, "%d.%6.6d", (int)d.tv_sec, (int)d.tv_usec); + } else { + snprintf(buf, len, "-"); + } +} + +/** get status of a mesh state */ +static void +get_mesh_status(struct mesh_area* mesh, struct mesh_state* m, + char* buf, size_t len) +{ + enum module_ext_state s = m->s.ext_state[m->s.curmod]; + const char *modname = mesh->mods.mod[m->s.curmod]->name; + size_t l; + if(strcmp(modname, "iterator") == 0 && s == module_wait_reply && + m->s.minfo[m->s.curmod]) { + /* break into iterator to find out who its waiting for */ + struct iter_qstate* qstate = (struct iter_qstate*) + m->s.minfo[m->s.curmod]; + struct outbound_list* ol = &qstate->outlist; + struct outbound_entry* e; + snprintf(buf, len, "%s wait for", modname); + l = strlen(buf); + buf += l; len -= l; + if(ol->first == NULL) + snprintf(buf, len, " (empty_list)"); + for(e = ol->first; e; e = e->next) { + int af = (int)((struct sockaddr_in*)&e->qsent->addr) + ->sin_family; + void* sinaddr = &((struct sockaddr_in*)&e->qsent->addr) + ->sin_addr; + if(addr_is_ip6(&e->qsent->addr, e->qsent->addrlen)) + sinaddr = &((struct sockaddr_in6*) + &e->qsent->addr)->sin6_addr; + + snprintf(buf, len, " "); + l = strlen(buf); + buf += l; len -= l; + + if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) { + snprintf(buf, len, "(inet_ntop_error)"); + } + l = strlen(buf); + buf += l; len -= l; + } + } else if(s == module_wait_subquery) { + /* look in subs from mesh state to see what */ + char nm[257]; + struct mesh_state_ref* sub; + snprintf(buf, len, "%s wants", modname); + l = strlen(buf); + buf += l; len -= l; + if(m->sub_set.count == 0) + snprintf(buf, len, " (empty_list)"); + RBTREE_FOR(sub, struct mesh_state_ref*, &m->sub_set) { + char* t = ldns_rr_type2str(sub->s->s.qinfo.qtype); + char* c = ldns_rr_class2str(sub->s->s.qinfo.qclass); + dname_str(sub->s->s.qinfo.qname, nm); + snprintf(buf, len, " %s %s %s", t, c, nm); + l = strlen(buf); + buf += l; len -= l; + free(t); + free(c); + } + } else { + snprintf(buf, len, "%s is %s", modname, strextstate(s)); + } +} + +/** do the dump_requestlist command */ +static void +do_dump_requestlist(SSL* ssl, struct worker* worker) +{ + struct mesh_area* mesh; + struct mesh_state* m; + int num = 0; + char buf[257]; + char timebuf[32]; + char statbuf[10240]; + if(!ssl_printf(ssl, "thread #%d\n", worker->thread_num)) + return; + if(!ssl_printf(ssl, "# type cl name seconds module status\n")) + return; + /* show worker mesh contents */ + mesh = worker->env.mesh; + if(!mesh) return; + RBTREE_FOR(m, struct mesh_state*, &mesh->all) { + char* t = ldns_rr_type2str(m->s.qinfo.qtype); + char* c = ldns_rr_class2str(m->s.qinfo.qclass); + dname_str(m->s.qinfo.qname, buf); + get_mesh_age(m, timebuf, sizeof(timebuf), &worker->env); + get_mesh_status(mesh, m, statbuf, sizeof(statbuf)); + if(!ssl_printf(ssl, "%3d %4s %2s %s %s %s\n", + num, t, c, buf, timebuf, statbuf)) { + free(t); + free(c); + return; + } + num++; + free(t); + free(c); + } +} + /** tell other processes to execute the command */ void distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) @@ -1301,6 +1420,8 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, do_flush_type(ssl, worker, skipwhite(p+10)); } else if(strncmp(p, "flush", 5) == 0) { do_flush_name(ssl, worker, skipwhite(p+5)); + } else if(strncmp(p, "dump_requestlist", 16) == 0) { + do_dump_requestlist(ssl, worker); } else { (void)ssl_printf(ssl, "error unknown command '%s'\n", p); } diff --git a/doc/Changelog b/doc/Changelog index 65987b8be..f411b6995 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,7 @@ - keys with rfc5011 REVOKE flag are skipped and not considered when validating data. - iana portlist updated + - #226: dump_requestlist feature for unbound-control. 6 February 2009: Wouter - contrib contains specfile for fedora 1.2.1 (from Paul Wouters). diff --git a/doc/unbound-control.8.in b/doc/unbound-control.8.in index ede6de346..578312b4e 100644 --- a/doc/unbound-control.8.in +++ b/doc/unbound-control.8.in @@ -115,6 +115,11 @@ Remove the name, type information from the cache. Remove all information at or below the name from the cache. The rrsets and key entries are removed so that new lookups will be performed. This needs to walk and inspect the entire cache, and is a slow operation. +.TP +.B dump_requestlist +Show what is worked on. Prints all queries that the server is currently +working on. Prints the time that users have been waiting. For internal +requests, no time is printed. And then prints out the module status. .SH "EXIT CODE" The unbound-control program exits with status code 1 on error, 0 on success. .SH "SET UP" diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c index e248ddec4..ea18903e1 100644 --- a/smallapp/unbound-control.c +++ b/smallapp/unbound-control.c @@ -78,6 +78,7 @@ usage() printf(" flush_type [name] [type] flush name, type from cache\n"); printf(" flush_zone [name] flush everything at or under name\n"); printf(" from rr and dnssec caches\n"); + printf(" dump_requestlist show what is worked on\n"); printf("Version %s\n", PACKAGE_VERSION); printf("BSD licensed, see LICENSE in source package for details.\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); -- 2.47.3