Added forking resolver (chris)
This commit is contained in:
30
configure.in
30
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.
|
||||
])
|
||||
|
||||
]
|
||||
)
|
||||
|
||||
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])
|
||||
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.
|
||||
|
||||
87
resolver.c
87
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 <signal.h>
|
||||
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user