From 2eeeadf6e177ea478b7f58c3d087b29f25cee6ff Mon Sep 17 00:00:00 2001 From: pdw <> Date: Sat, 6 Sep 2003 13:52:36 +0000 Subject: [PATCH] Added forking resolver (chris) --- configure.in | 36 ++++++++++++++-------- resolver.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/configure.in b/configure.in index b7ff9cc..2169825 100644 --- a/configure.in +++ b/configure.in @@ -37,8 +37,9 @@ AC_ARG_WITH(resolver, [ --with-resolver=TYPE Technique iftop should use for name resolution. Valid options are netdb, netdb_1thread (for systems without working gethostbyaddr_r), ares for the MIT ARES - asynchronous resolver library, or none if you don't - need any name resolution. + asynchronous resolver library, forking for the REALLY SUCKY + forking resolver, or none if you don't need any name + resolution. [default=netdb]], [resolver=$withval], [resolver=netdb]) @@ -164,7 +165,7 @@ if test x$resolver = xnetdb ; then AC_DEFINE(USE_GETNAMEINFO, 1, [use getnameinfo for name resolution]) else dnl Now see if we can use gethostbyaddr_r. - AC_SEARCH_LIBS(gethostbyaddr_r, [nsl], , [resolver=netdb_1thread]) + AC_SEARCH_LIBS(gethostbyaddr_r, [nsl], , [resolver=forking]) dnl Still want gethostbyaddr_r.... if test x$resolver = xnetdb ; then @@ -185,8 +186,8 @@ if test x$resolver = xnetdb ; then [7-argument gethostbyaddr_r returns struct hostent*]) ], [ dnl neither - AC_MSG_RESULT([no idea; dropping back to gethostbyaddr]) - resolver=netdb_1thread + AC_MSG_RESULT([no idea; dropping back to the forking resolver]) + resolver=forking ]) ]) @@ -209,24 +210,33 @@ if test x$resolver = xares ; then AC_DEFINE(USE_ARES, 1, [use ARES for name resolution]) ], [ dnl no ares - AC_MSG_RESULT([can't find ARES; dropping back to gethostbyaddr]) - resolver=netdb_1thread]) + AC_MSG_RESULT([can't find ARES; dropping back to the forking resolver]) + resolver=forking]) fi -dnl Ugh. gethostbyaddr. -if test x$resolver = xnetdb_1thread ; then +dnl Ugh. Both the single-threaded and the forking resolvers use gethostbyaddr. +if test x$resolver = xnetdb_1thread || test x$resolver = xforking ; then AC_SEARCH_LIBS(gethostbyaddr, [nsl], , [ AC_MSG_ERROR([not even gethostbyaddr is available - What sort of UNIX system is this, anyway?]) + What sort of UNIX system is this, anyway? + + You will have to recompile with no name resolution at all. +]) + ] ) - dnl Oh dear, just use gethostbyaddr; but whine about it - AC_MSG_WARN([using single-threaded resolver with gethostbyaddr + if test x$resolver = xnetdb_1thread ; then + dnl Oh dear, just use gethostbyaddr; but whine about it + + AC_MSG_WARN([using single-threaded resolver with gethostbyaddr Consider obtaining ARES or a machine with a working gethostbyaddr_r.]) - AC_DEFINE(USE_GETHOSTBYADDR, 1, [use gethostbyaddr for name resolution]) + AC_DEFINE(USE_GETHOSTBYADDR, 1, [use gethostbyaddr for name resolution]) + else + AC_DEFINE(USE_FORKING_RESOLVER, 1, [use a REALLY SUCKY forking resolver for name resolution]) + fi fi dnl Otherwise, no resolver at all. Boo hoo. diff --git a/resolver.c b/resolver.c index 3762311..1cec32d 100644 --- a/resolver.c +++ b/resolver.c @@ -265,6 +265,93 @@ char *do_resolve(struct in_addr * addr) { } } +#elif defined(USE_FORKING_RESOLVER) + +/** + * Resolver which forks a process, then uses gethostbyname. + */ + +#include + +#define NAMESIZE 64 + +int forking_resolver_worker(int fd) { + while (1) { + struct in_addr a; + struct hostent *he; + char buf[NAMESIZE] = {0}; + if (read(fd, &a, sizeof a) != sizeof a) + return -1; + + he = gethostbyaddr((char*)&a, sizeof a, AF_INET); + if (he) + strncpy(buf, he->h_name, NAMESIZE - 1); + + if (write(fd, buf, NAMESIZE) != NAMESIZE) + return -1; + } +} + +char *do_resolve(struct in_addr *addr) { + struct { + int fd; + pid_t child; + } *workerinfo; + char name[NAMESIZE]; + static pthread_mutex_t worker_init_mtx = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t worker_key; + static int gotkey; + + /* If no process exists, we need to spawn one. */ + pthread_mutex_lock(&worker_init_mtx); + if (!gotkey) { + pthread_key_create(&worker_key, NULL); + gotkey = 1; + } + pthread_mutex_unlock(&worker_init_mtx); + + workerinfo = pthread_getspecific(worker_key); + if (!workerinfo) { + int p[2]; + + if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNSPEC, p) == -1) + return NULL; + + workerinfo = xmalloc(sizeof *workerinfo); + pthread_setspecific(worker_key, workerinfo); + workerinfo->fd = p[0]; + + switch (workerinfo->child = fork()) { + case 0: + close(p[0]); + _exit(forking_resolver_worker(p[1])); + + case -1: + close(p[0]); + close(p[1]); + return NULL; + + default: + close(p[1]); + } + } + + /* Now have a worker to which we can write requests. */ + if (write(workerinfo->fd, addr, sizeof *addr) != sizeof *addr + || read(workerinfo->fd, name, NAMESIZE) != NAMESIZE) { + /* Something went wrong. Just kill the child and get on with it. */ + kill(workerinfo->child, SIGKILL); + wait(); + close(workerinfo->fd); + xfree(workerinfo); + pthread_setspecific(worker_key, NULL); + } + if (!*name) + return NULL; + else + return xstrdup(name); +} + #else # warning No name resolution method specified; name resolution will not work