[tor-commits] [tor/master] Move all externally maintained source files into src/ext

andrea at torproject.org andrea at torproject.org
Thu Oct 11 22:59:26 UTC 2012


commit 63f542a5c21103946177b5377cdf5d08e2e68849
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Oct 11 17:19:37 2012 -0400

    Move all externally maintained source files into src/ext
    
    The rationale for treating these files differently is that we should
    be checking upstream for changes as applicable, and merging changes
    upstream as warranted.
---
 changes/src_ext                   |    3 +
 src/common/OpenBSD_malloc_Linux.c | 2057 ----------------------
 src/common/ht.h                   |  490 ------
 src/common/include.am             |    3 +-
 src/ext/OpenBSD_malloc_Linux.c    | 2057 ++++++++++++++++++++++
 src/ext/eventdns.c                | 3505 +++++++++++++++++++++++++++++++++++++
 src/ext/eventdns.h                |  337 ++++
 src/ext/ht.h                      |  490 ++++++
 src/ext/include.am                |   12 +
 src/ext/tinytest.c                |  387 ++++
 src/ext/tinytest.h                |   87 +
 src/ext/tinytest_demo.c           |  215 +++
 src/ext/tinytest_macros.h         |  184 ++
 src/include.am                    |    3 +-
 src/or/eventdns.c                 | 3505 -------------------------------------
 src/or/eventdns.h                 |  337 ----
 src/or/include.am                 |    3 +-
 src/test/include.am               |    7 +-
 src/test/tinytest.c               |  387 ----
 src/test/tinytest.h               |   87 -
 src/test/tinytest_demo.c          |  215 ---
 src/test/tinytest_macros.h        |  184 --
 22 files changed, 7283 insertions(+), 7272 deletions(-)

diff --git a/changes/src_ext b/changes/src_ext
new file mode 100644
index 0000000..a1b2a21
--- /dev/null
+++ b/changes/src_ext
@@ -0,0 +1,3 @@
+  o Code refactoring:
+    - Source files taken from other packages now reside in src/ext;
+      previously they were scattered around the rest of Tor.
diff --git a/src/common/OpenBSD_malloc_Linux.c b/src/common/OpenBSD_malloc_Linux.c
deleted file mode 100644
index da82729..0000000
--- a/src/common/OpenBSD_malloc_Linux.c
+++ /dev/null
@@ -1,2057 +0,0 @@
-/* Version 1.83 for Linux.
- * Compilation: gcc -shared -fPIC -O2 OpenBSD_malloc_Linux.c -o malloc.so
- * Launching: LD_PRELOAD=/path/to/malloc.so firefox
- */
-
-/*	$OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $	*/
-
-/*
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk at FreeBSD.ORG> wrote this file.  As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- */
-
-/* We use this macro to remove some code that we don't actually want,
- * rather than to fix its warnings. */
-#define BUILDING_FOR_TOR
-
-/*
- * Defining MALLOC_EXTRA_SANITY will enable extra checks which are
- * related to internal conditions and consistency in malloc.c. This has
- * a noticeable runtime performance hit, and generally will not do you
- * any good unless you fiddle with the internals of malloc or want
- * to catch random pointer corruption as early as possible.
- */
-#ifndef	MALLOC_EXTRA_SANITY
-#undef	MALLOC_EXTRA_SANITY
-#endif
-
-/*
- * Defining MALLOC_STATS will enable you to call malloc_dump() and set
- * the [dD] options in the MALLOC_OPTIONS environment variable.
- * It has no run-time performance hit, but does pull in stdio...
- */
-#ifndef	MALLOC_STATS
-#undef	MALLOC_STATS
-#endif
-
-/*
- * What to use for Junk.  This is the byte value we use to fill with
- * when the 'J' option is enabled.
- */
-#define SOME_JUNK	0xd0	/* as in "Duh" :-) */
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/param.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <errno.h>
-#include <err.h>
-/* For SIZE_T_MAX */
-#include "torint.h"
-
-//#include "thread_private.h"
-
-/*
- * The basic parameters you can tweak.
- *
- * malloc_pageshift	pagesize = 1 << malloc_pageshift
- *			It's probably best if this is the native
- *			page size, but it shouldn't have to be.
- *
- * malloc_minsize	minimum size of an allocation in bytes.
- *			If this is too small it's too much work
- *			to manage them.  This is also the smallest
- *			unit of alignment used for the storage
- *			returned by malloc/realloc.
- *
- */
-
-static int align = 0;
-static size_t g_alignment = 0;
-
-extern int __libc_enable_secure;
-
-#ifndef HAVE_ISSETUGID
-static int issetugid(void)
-{
-	if (__libc_enable_secure) return 1;
-	if (getuid() != geteuid()) return 1;
-	if (getgid() != getegid()) return 1;
-	return 0;
-}
-#endif
-
-#define PGSHIFT 12
-#undef MADV_FREE
-#define MADV_FREE MADV_DONTNEED
-#include <pthread.h>
-static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-#define _MALLOC_LOCK_INIT() {;}
-#define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
-#define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
-
-#if defined(__sparc__) || defined(__alpha__)
-#define	malloc_pageshift	13U
-#endif
-#if defined(__ia64__)
-#define	malloc_pageshift	14U
-#endif
-
-#ifndef malloc_pageshift
-#define malloc_pageshift	(PGSHIFT)
-#endif
-
-/*
- * No user serviceable parts behind this point.
- *
- * This structure describes a page worth of chunks.
- */
-struct pginfo {
-	struct pginfo	*next;	/* next on the free list */
-	void		*page;	/* Pointer to the page */
-	u_short		size;	/* size of this page's chunks */
-	u_short		shift;	/* How far to shift for this size chunks */
-	u_short		free;	/* How many free chunks */
-	u_short		total;	/* How many chunk */
-	u_long		bits[1];/* Which chunks are free */
-};
-
-/* How many bits per u_long in the bitmap */
-#define	MALLOC_BITS	(int)((NBBY * sizeof(u_long)))
-
-/*
- * This structure describes a number of free pages.
- */
-struct pgfree {
-	struct pgfree	*next;	/* next run of free pages */
-	struct pgfree	*prev;	/* prev run of free pages */
-	void		*page;	/* pointer to free pages */
-	void		*pdir;	/* pointer to the base page's dir */
-	size_t		size;	/* number of bytes free */
-};
-
-/*
- * Magic values to put in the page_directory
- */
-#define MALLOC_NOT_MINE	((struct pginfo*) 0)
-#define MALLOC_FREE	((struct pginfo*) 1)
-#define MALLOC_FIRST	((struct pginfo*) 2)
-#define MALLOC_FOLLOW	((struct pginfo*) 3)
-#define MALLOC_MAGIC	((struct pginfo*) 4)
-
-#ifndef malloc_minsize
-#define malloc_minsize			16UL
-#endif
-
-#if !defined(malloc_pagesize)
-#define malloc_pagesize			(1UL<<malloc_pageshift)
-#endif
-
-#if ((1UL<<malloc_pageshift) != malloc_pagesize)
-#error	"(1UL<<malloc_pageshift) != malloc_pagesize"
-#endif
-
-#ifndef malloc_maxsize
-#define malloc_maxsize			((malloc_pagesize)>>1)
-#endif
-
-/* A mask for the offset inside a page. */
-#define malloc_pagemask	((malloc_pagesize)-1)
-
-#define	pageround(foo)	(((foo) + (malloc_pagemask)) & ~malloc_pagemask)
-#define	ptr2index(foo)	(((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
-#define	index2ptr(idx)	((void*)(((idx)-malloc_pageshift)<<malloc_pageshift))
-
-/* Set when initialization has been done */
-static unsigned int	malloc_started;
-
-/* Number of free pages we cache */
-static unsigned int	malloc_cache = 16;
-
-/* Structure used for linking discrete directory pages. */
-struct pdinfo {
-	struct pginfo	**base;
-	struct pdinfo	*prev;
-	struct pdinfo	*next;
-	u_long		dirnum;
-};
-static struct pdinfo *last_dir;	/* Caches to the last and previous */
-static struct pdinfo *prev_dir;	/* referenced directory pages. */
-
-static size_t	pdi_off;
-static u_long	pdi_mod;
-#define	PD_IDX(num)	((num) / (malloc_pagesize/sizeof(struct pginfo *)))
-#define	PD_OFF(num)	((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1))
-#define	PI_IDX(index)	((index) / pdi_mod)
-#define	PI_OFF(index)	((index) % pdi_mod)
-
-/* The last index in the page directory we care about */
-static u_long	last_index;
-
-/* Pointer to page directory. Allocated "as if with" malloc */
-static struct pginfo **page_dir;
-
-/* Free pages line up here */
-static struct pgfree free_list;
-
-/* Abort(), user doesn't handle problems. */
-static int	malloc_abort = 2;
-
-/* Are we trying to die ? */
-static int	suicide;
-
-#ifdef MALLOC_STATS
-/* dump statistics */
-static int	malloc_stats;
-#endif
-
-/* avoid outputting warnings? */
-static int	malloc_silent;
-
-/* always realloc ? */
-static int	malloc_realloc;
-
-/* mprotect free pages PROT_NONE? */
-static int	malloc_freeprot;
-
-/* use guard pages after allocations? */
-static size_t	malloc_guard = 0;
-static size_t	malloc_guarded;
-/* align pointers to end of page? */
-static int	malloc_ptrguard;
-
-static int	malloc_hint = 1;
-
-/* xmalloc behaviour ? */
-static int	malloc_xmalloc;
-
-/* zero fill ? */
-static int	malloc_zero;
-
-/* junk fill ? */
-static int	malloc_junk;
-
-#ifdef __FreeBSD__
-/* utrace ? */
-static int	malloc_utrace;
-
-struct ut {
-	void		*p;
-	size_t		s;
-	void		*r;
-};
-
-void		utrace(struct ut *, int);
-
-#define UTRACE(a, b, c) \
-	if (malloc_utrace) \
-		{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
-#else				/* !__FreeBSD__ */
-#define UTRACE(a,b,c)
-#endif
-
-/* Status of malloc. */
-static int	malloc_active;
-
-/* Allocated memory. */
-static size_t	malloc_used;
-
-/* My last break. */
-static caddr_t	malloc_brk;
-
-/* One location cache for free-list holders. */
-static struct pgfree *px;
-
-/* Compile-time options. */
-char		*malloc_options;
-
-/* Name of the current public function. */
-static const char	*malloc_func;
-
-#define MMAP(size) \
-	mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
-	    -1, (off_t)0)
-
-/*
- * Necessary function declarations.
- */
-static void	*imalloc(size_t size);
-static void	ifree(void *ptr);
-static void	*irealloc(void *ptr, size_t size);
-static void	*malloc_bytes(size_t size);
-void *memalign(size_t boundary, size_t size);
-size_t malloc_good_size(size_t size);
-
-/*
- * Function for page directory lookup.
- */
-static int
-pdir_lookup(u_long index, struct pdinfo ** pdi)
-{
-	struct pdinfo	*spi;
-	u_long		pidx = PI_IDX(index);
-
-	if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx)
-		*pdi = last_dir;
-	else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx)
-		*pdi = prev_dir;
-	else if (last_dir != NULL && prev_dir != NULL) {
-		if ((PD_IDX(last_dir->dirnum) > pidx) ?
-		    (PD_IDX(last_dir->dirnum) - pidx) :
-		    (pidx - PD_IDX(last_dir->dirnum))
-		    < (PD_IDX(prev_dir->dirnum) > pidx) ?
-		    (PD_IDX(prev_dir->dirnum) - pidx) :
-		    (pidx - PD_IDX(prev_dir->dirnum)))
-			*pdi = last_dir;
-		else
-			*pdi = prev_dir;
-
-		if (PD_IDX((*pdi)->dirnum) > pidx) {
-			for (spi = (*pdi)->prev;
-			    spi != NULL && PD_IDX(spi->dirnum) > pidx;
-			    spi = spi->prev)
-				*pdi = spi;
-			if (spi != NULL)
-				*pdi = spi;
-		} else
-			for (spi = (*pdi)->next;
-			    spi != NULL && PD_IDX(spi->dirnum) <= pidx;
-			    spi = spi->next)
-				*pdi = spi;
-	} else {
-		*pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
-		for (spi = *pdi;
-		    spi != NULL && PD_IDX(spi->dirnum) <= pidx;
-		    spi = spi->next)
-			*pdi = spi;
-	}
-
-	return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
-	    (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
-}
-
-#ifdef MALLOC_STATS
-void
-malloc_dump(int fd)
-{
-	char		buf[1024];
-	struct pginfo	**pd;
-	struct pgfree	*pf;
-	struct pdinfo	*pi;
-	u_long		j;
-
-	pd = page_dir;
-	pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
-
-	/* print out all the pages */
-	for (j = 0; j <= last_index;) {
-		snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j);
-		write(fd, buf, strlen(buf));
-		if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
-			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
-				if (!PI_OFF(++j)) {
-					if ((pi = pi->next) == NULL ||
-					    PD_IDX(pi->dirnum) != PI_IDX(j))
-						break;
-					pd = pi->base;
-					j += pdi_mod;
-				}
-			}
-			j--;
-			snprintf(buf, sizeof buf, ".. %5lu not mine\n", j);
-			write(fd, buf, strlen(buf));
-		} else if (pd[PI_OFF(j)] == MALLOC_FREE) {
-			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
-				if (!PI_OFF(++j)) {
-					if ((pi = pi->next) == NULL ||
-					    PD_IDX(pi->dirnum) != PI_IDX(j))
-						break;
-					pd = pi->base;
-					j += pdi_mod;
-				}
-			}
-			j--;
-			snprintf(buf, sizeof buf, ".. %5lu free\n", j);
-			write(fd, buf, strlen(buf));
-		} else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
-			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
-				if (!PI_OFF(++j)) {
-					if ((pi = pi->next) == NULL ||
-					    PD_IDX(pi->dirnum) != PI_IDX(j))
-						break;
-					pd = pi->base;
-					j += pdi_mod;
-				}
-			}
-			j--;
-			snprintf(buf, sizeof buf, ".. %5lu in use\n", j);
-			write(fd, buf, strlen(buf));
-		} else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
-			snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]);
-			write(fd, buf, strlen(buf));
-		} else {
-			snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n",
-			    pd[PI_OFF(j)], pd[PI_OFF(j)]->free,
-			    pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size,
-			    pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next);
-			write(fd, buf, strlen(buf));
-		}
-		if (!PI_OFF(++j)) {
-			if ((pi = pi->next) == NULL)
-				break;
-			pd = pi->base;
-			j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod;
-		}
-	}
-
-	for (pf = free_list.next; pf; pf = pf->next) {
-		snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
-		    pf, pf->page, (char *)pf->page + pf->size,
-		    pf->size, pf->prev, pf->next);
-		write(fd, buf, strlen(buf));
-		if (pf == pf->next) {
-			snprintf(buf, sizeof buf, "Free_list loops\n");
-			write(fd, buf, strlen(buf));
-			break;
-		}
-	}
-
-	/* print out various info */
-	snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize);
-	write(fd, buf, strlen(buf));
-	snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize);
-	write(fd, buf, strlen(buf));
-	snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize);
-	write(fd, buf, strlen(buf));
-	snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift);
-	write(fd, buf, strlen(buf));
-	snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used);
-	write(fd, buf, strlen(buf));
-	snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded);
-	write(fd, buf, strlen(buf));
-}
-#endif /* MALLOC_STATS */
-
-extern char	*__progname;
-
-static void
-wrterror(const char *p)
-{
-#ifndef BUILDING_FOR_TOR
-	const char		*q = " error: ";
-	struct iovec	iov[5];
-
-	iov[0].iov_base = __progname;
-	iov[0].iov_len = strlen(__progname);
-	iov[1].iov_base = (char*)malloc_func;
-	iov[1].iov_len = strlen(malloc_func);
-	iov[2].iov_base = (char*)q;
-	iov[2].iov_len = strlen(q);
-	iov[3].iov_base = (char*)p;
-	iov[3].iov_len = strlen(p);
-	iov[4].iov_base = (char*)"\n";
-	iov[4].iov_len = 1;
-	writev(STDERR_FILENO, iov, 5);
-#else
-        (void)p;
-#endif
-	suicide = 1;
-#ifdef MALLOC_STATS
-	if (malloc_stats)
-		malloc_dump(STDERR_FILENO);
-#endif /* MALLOC_STATS */
-	malloc_active--;
-	if (malloc_abort)
-		abort();
-}
-
-static void
-wrtwarning(const char *p)
-{
-#ifndef BUILDING_FOR_TOR
-	const char		*q = " warning: ";
-	struct iovec	iov[5];
-#endif
-
-	if (malloc_abort)
-		wrterror(p);
-	else if (malloc_silent)
-		return;
-
-#ifndef BUILDING_FOR_TOR
-	iov[0].iov_base = __progname;
-	iov[0].iov_len = strlen(__progname);
-	iov[1].iov_base = (char*)malloc_func;
-	iov[1].iov_len = strlen(malloc_func);
-	iov[2].iov_base = (char*)q;
-	iov[2].iov_len = strlen(q);
-	iov[3].iov_base = (char*)p;
-	iov[3].iov_len = strlen(p);
-	iov[4].iov_base = (char*)"\n";
-	iov[4].iov_len = 1;
-
-	(void) writev(STDERR_FILENO, iov, 5);
-#else
-        (void)p;
-#endif
-}
-
-#ifdef MALLOC_STATS
-static void
-malloc_exit(void)
-{
-	char	*q = "malloc() warning: Couldn't dump stats\n";
-	int	save_errno = errno, fd;
-
-	fd = open("malloc.out", O_RDWR|O_APPEND);
-	if (fd != -1) {
-		malloc_dump(fd);
-		close(fd);
-	} else
-		write(STDERR_FILENO, q, strlen(q));
-	errno = save_errno;
-}
-#endif /* MALLOC_STATS */
-
-/*
- * Allocate aligned mmaped chunk
- */
-
-static void *MMAP_A(size_t pages, size_t alignment)
-{
-	void *j, *p;
-	size_t first_size, rest, begin, end;
-	if (pages%malloc_pagesize != 0)
-		pages = pages - pages%malloc_pagesize + malloc_pagesize;
-	first_size = pages + alignment - malloc_pagesize;
-	p = MMAP(first_size);
-	rest = ((size_t)p) % alignment;
-	j = (rest == 0) ? p : (void*) ((size_t)p + alignment - rest);
-	begin = (size_t)j - (size_t)p;
-	if (begin != 0) munmap(p, begin);
-	end = (size_t)p + first_size - ((size_t)j + pages);
-	if(end != 0) munmap( (void*) ((size_t)j + pages), end);
-
-	return j;
-}
-
-
-/*
- * Allocate a number of pages from the OS
- */
-static void *
-map_pages(size_t pages)
-{
-	struct pdinfo	*pi, *spi;
-	struct pginfo	**pd;
-	u_long		idx, pidx, lidx;
-	caddr_t		result, tail;
-	u_long		index, lindex;
-	void 		*pdregion = NULL;
-	size_t		dirs, cnt;
-
-	pages <<= malloc_pageshift;
-	if (!align)
-		result = MMAP(pages + malloc_guard);
-	else {
-		result = MMAP_A(pages + malloc_guard, g_alignment);
-	}
-	if (result == MAP_FAILED) {
-#ifdef MALLOC_EXTRA_SANITY
-		wrtwarning("(ES): map_pages fails");
-#endif /* MALLOC_EXTRA_SANITY */
-		errno = ENOMEM;
-		return (NULL);
-	}
-	index = ptr2index(result);
-	tail = result + pages + malloc_guard;
-	lindex = ptr2index(tail) - 1;
-	if (malloc_guard)
-		mprotect(result + pages, malloc_guard, PROT_NONE);
-
-	pidx = PI_IDX(index);
-	lidx = PI_IDX(lindex);
-
-	if (tail > malloc_brk) {
-		malloc_brk = tail;
-		last_index = lindex;
-	}
-
-	dirs = lidx - pidx;
-
-	/* Insert directory pages, if needed. */
-	if (pdir_lookup(index, &pi) != 0)
-		dirs++;
-
-	if (dirs > 0) {
-		pdregion = MMAP(malloc_pagesize * dirs);
-		if (pdregion == MAP_FAILED) {
-			munmap(result, tail - result);
-#ifdef MALLOC_EXTRA_SANITY
-		wrtwarning("(ES): map_pages fails");
-#endif
-			errno = ENOMEM;
-			return (NULL);
-		}
-	}
-
-	cnt = 0;
-	for (idx = pidx, spi = pi; idx <= lidx; idx++) {
-		if (pi == NULL || PD_IDX(pi->dirnum) != idx) {
-			pd = (struct pginfo **)((char *)pdregion +
-			    cnt * malloc_pagesize);
-			cnt++;
-			memset(pd, 0, malloc_pagesize);
-			pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
-			pi->base = pd;
-			pi->prev = spi;
-			pi->next = spi->next;
-			pi->dirnum = idx * (malloc_pagesize /
-			    sizeof(struct pginfo *));
-
-			if (spi->next != NULL)
-				spi->next->prev = pi;
-			spi->next = pi;
-		}
-		if (idx > pidx && idx < lidx) {
-			pi->dirnum += pdi_mod;
-		} else if (idx == pidx) {
-			if (pidx == lidx) {
-				pi->dirnum += (u_long)(tail - result) >>
-				    malloc_pageshift;
-			} else {
-				pi->dirnum += pdi_mod - PI_OFF(index);
-			}
-		} else {
-			pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
-		}
-#ifdef MALLOC_EXTRA_SANITY
-		if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > idx) {
-			wrterror("(ES): pages directory overflow");
-			errno = EFAULT;
-			return (NULL);
-		}
-#endif /* MALLOC_EXTRA_SANITY */
-		if (idx == pidx && pi != last_dir) {
-			prev_dir = last_dir;
-			last_dir = pi;
-		}
-		spi = pi;
-		pi = spi->next;
-	}
-#ifdef MALLOC_EXTRA_SANITY
-	if (cnt > dirs)
-		wrtwarning("(ES): cnt > dirs");
-#endif /* MALLOC_EXTRA_SANITY */
-	if (cnt < dirs)
-		munmap((char *)pdregion + cnt * malloc_pagesize,
-		    (dirs - cnt) * malloc_pagesize);
-
-	return (result);
-}
-
-/*
- * Initialize the world
- */
-static void
-malloc_init(void)
-{
-	char		*p, b[64];
-	int		i, j, save_errno = errno;
-
-	_MALLOC_LOCK_INIT();
-
-#ifdef MALLOC_EXTRA_SANITY
-	malloc_junk = 1;
-#endif /* MALLOC_EXTRA_SANITY */
-
-	for (i = 0; i < 3; i++) {
-		switch (i) {
-		case 0:
-			j = (int) readlink("/etc/malloc.conf", b, sizeof b - 1);
-			if (j <= 0)
-				continue;
-			b[j] = '\0';
-			p = b;
-			break;
-		case 1:
-			if (issetugid() == 0)
-				p = getenv("MALLOC_OPTIONS");
-			else
-				continue;
-			break;
-		case 2:
-			p = malloc_options;
-			break;
-		default:
-			p = NULL;
-		}
-
-		for (; p != NULL && *p != '\0'; p++) {
-			switch (*p) {
-			case '>':
-				malloc_cache <<= 1;
-				break;
-			case '<':
-				malloc_cache >>= 1;
-				break;
-			case 'a':
-				malloc_abort = 0;
-				break;
-			case 'A':
-				malloc_abort = 1;
-				break;
-#ifdef MALLOC_STATS
-			case 'd':
-				malloc_stats = 0;
-				break;
-			case 'D':
-				malloc_stats = 1;
-				break;
-#endif /* MALLOC_STATS */
-			case 'f':
-				malloc_freeprot = 0;
-				break;
-			case 'F':
-				malloc_freeprot = 1;
-				break;
-			case 'g':
-				malloc_guard = 0;
-				break;
-			case 'G':
-				malloc_guard = malloc_pagesize;
-				break;
-			case 'h':
-				malloc_hint = 0;
-				break;
-			case 'H':
-				malloc_hint = 1;
-				break;
-			case 'j':
-				malloc_junk = 0;
-				break;
-			case 'J':
-				malloc_junk = 1;
-				break;
-			case 'n':
-				malloc_silent = 0;
-				break;
-			case 'N':
-				malloc_silent = 1;
-				break;
-			case 'p':
-				malloc_ptrguard = 0;
-				break;
-			case 'P':
-				malloc_ptrguard = 1;
-				break;
-			case 'r':
-				malloc_realloc = 0;
-				break;
-			case 'R':
-				malloc_realloc = 1;
-				break;
-#ifdef __FreeBSD__
-			case 'u':
-				malloc_utrace = 0;
-				break;
-			case 'U':
-				malloc_utrace = 1;
-				break;
-#endif /* __FreeBSD__ */
-			case 'x':
-				malloc_xmalloc = 0;
-				break;
-			case 'X':
-				malloc_xmalloc = 1;
-				break;
-			case 'z':
-				malloc_zero = 0;
-				break;
-			case 'Z':
-				malloc_zero = 1;
-				break;
-			default:
-				j = malloc_abort;
-				malloc_abort = 0;
-				wrtwarning("unknown char in MALLOC_OPTIONS");
-				malloc_abort = j;
-				break;
-			}
-		}
-	}
-
-	UTRACE(0, 0, 0);
-
-	/*
-	 * We want junk in the entire allocation, and zero only in the part
-	 * the user asked for.
-	 */
-	if (malloc_zero)
-		malloc_junk = 1;
-
-#ifdef MALLOC_STATS
-	if (malloc_stats && (atexit(malloc_exit) == -1))
-		wrtwarning("atexit(2) failed."
-		    "  Will not be able to dump malloc stats on exit");
-#endif /* MALLOC_STATS */
-
-	if (malloc_pagesize != getpagesize()) {
-		wrterror("malloc() replacement compiled with a different "
-			 "page size from what we're running with.  Failing.");
-		errno = ENOMEM;
-		return;
-	}
-
-	/* Allocate one page for the page directory. */
-	page_dir = (struct pginfo **)MMAP(malloc_pagesize);
-
-	if (page_dir == MAP_FAILED) {
-		wrterror("mmap(2) failed, check limits");
-		errno = ENOMEM;
-		return;
-	}
-	pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
-	pdi_mod = pdi_off / sizeof(struct pginfo *);
-
-	last_dir = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
-	last_dir->base = page_dir;
-	last_dir->prev = last_dir->next = NULL;
-	last_dir->dirnum = malloc_pageshift;
-
-	/* Been here, done that. */
-	malloc_started++;
-
-	/* Recalculate the cache size in bytes, and make sure it's nonzero. */
-	if (!malloc_cache)
-		malloc_cache++;
-	malloc_cache <<= malloc_pageshift;
-	errno = save_errno;
-}
-
-/*
- * Allocate a number of complete pages
- */
-static void *
-malloc_pages(size_t size)
-{
-	void		*p, *delay_free = NULL, *tp;
-	size_t		i;
-	struct pginfo	**pd;
-	struct pdinfo	*pi;
-	u_long		pidx, index;
-	struct pgfree	*pf;
-
-	size = pageround(size) + malloc_guard;
-
-	p = NULL;
-	/* Look for free pages before asking for more */
-	if (!align)
-	for (pf = free_list.next; pf; pf = pf->next) {
-
-#ifdef MALLOC_EXTRA_SANITY
-		if (pf->size & malloc_pagemask) {
-			wrterror("(ES): junk length entry on free_list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		if (!pf->size) {
-			wrterror("(ES): zero length entry on free_list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		if (pf->page > (pf->page + pf->size)) {
-			wrterror("(ES): sick entry on free_list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		if ((pi = pf->pdir) == NULL) {
-			wrterror("(ES): invalid page directory on free-list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) {
-			wrterror("(ES): directory index mismatch on free-list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		pd = pi->base;
-		if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) {
-			wrterror("(ES): non-free first page on free-list");
-			errno = EFAULT;
-			return (NULL);
-		}
-		pidx = PI_IDX(ptr2index((pf->page) + (pf->size)) - 1);
-		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
-		    pi = pi->next)
-			;
-		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-			wrterror("(ES): last page not referenced in page directory");
-			errno = EFAULT;
-			return (NULL);
-		}
-		pd = pi->base;
-		if (pd[PI_OFF(ptr2index((pf->page) + (pf->size)) - 1)] != MALLOC_FREE) {
-			wrterror("(ES): non-free last page on free-list");
-			errno = EFAULT;
-			return (NULL);
-		}
-#endif /* MALLOC_EXTRA_SANITY */
-
-		if (pf->size < size)
-			continue;
-
-		if (pf->size == size) {
-			p = pf->page;
-			pi = pf->pdir;
-			if (pf->next != NULL)
-				pf->next->prev = pf->prev;
-			pf->prev->next = pf->next;
-			delay_free = pf;
-			break;
-		}
-		p = pf->page;
-		pf->page = (char *) pf->page + size;
-		pf->size -= size;
-		pidx = PI_IDX(ptr2index(pf->page));
-		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
-		    pi = pi->next)
-			;
-		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-			wrterror("(ES): hole in directories");
-			errno = EFAULT;
-			return (NULL);
-		}
-		tp = pf->pdir;
-		pf->pdir = pi;
-		pi = tp;
-		break;
-	}
-
-	size -= malloc_guard;
-
-#ifdef MALLOC_EXTRA_SANITY
-	if (p != NULL && pi != NULL) {
-		pidx = PD_IDX(pi->dirnum);
-		pd = pi->base;
-	}
-	if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) {
-		wrterror("(ES): allocated non-free page on free-list");
-		errno = EFAULT;
-		return (NULL);
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-
-	if (p != NULL && (malloc_guard || malloc_freeprot))
-		mprotect(p, size, PROT_READ | PROT_WRITE);
-
-	size >>= malloc_pageshift;
-
-	/* Map new pages */
-	if (p == NULL)
-		p = map_pages(size);
-
-	if (p != NULL) {
-		index = ptr2index(p);
-		pidx = PI_IDX(index);
-		pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
-		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-			wrterror("(ES): mapped pages not found in directory");
-			errno = EFAULT;
-			return (NULL);
-		}
-#endif /* MALLOC_EXTRA_SANITY */
-		if (pi != last_dir) {
-			prev_dir = last_dir;
-			last_dir = pi;
-		}
-		pd = pi->base;
-		pd[PI_OFF(index)] = MALLOC_FIRST;
-
-		for (i = 1; i < size; i++) {
-			if (!PI_OFF(index + i)) {
-				pidx++;
-				pi = pi->next;
-#ifdef MALLOC_EXTRA_SANITY
-				if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-					wrterror("(ES): hole in mapped pages directory");
-					errno = EFAULT;
-					return (NULL);
-				}
-#endif /* MALLOC_EXTRA_SANITY */
-				pd = pi->base;
-			}
-			pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
-		}
-		if (malloc_guard) {
-			if (!PI_OFF(index + i)) {
-				pidx++;
-				pi = pi->next;
-#ifdef MALLOC_EXTRA_SANITY
-				if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-					wrterror("(ES): hole in mapped pages directory");
-					errno = EFAULT;
-					return (NULL);
-				}
-#endif /* MALLOC_EXTRA_SANITY */
-				pd = pi->base;
-			}
-			pd[PI_OFF(index + i)] = MALLOC_FIRST;
-		}
-
-		malloc_used += size << malloc_pageshift;
-		malloc_guarded += malloc_guard;
-
-		if (malloc_junk)
-			memset(p, SOME_JUNK, size << malloc_pageshift);
-	}
-	if (delay_free) {
-		if (px == NULL)
-			px = delay_free;
-		else
-			ifree(delay_free);
-	}
-	return (p);
-}
-
-/*
- * Allocate a page of fragments
- */
-
-static __inline__ int
-malloc_make_chunks(int bits)
-{
-	struct pginfo	*bp, **pd;
-	struct pdinfo	*pi;
-#ifdef	MALLOC_EXTRA_SANITY
-	u_long		pidx;
-#endif	/* MALLOC_EXTRA_SANITY */
-	void		*pp;
-	long		i, k;
-	size_t		l;
-
-	/* Allocate a new bucket */
-	pp = malloc_pages((size_t) malloc_pagesize);
-	if (pp == NULL)
-		return (0);
-
-	/* Find length of admin structure */
-	l = sizeof *bp - sizeof(u_long);
-	l += sizeof(u_long) *
-	    (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
-
-	/* Don't waste more than two chunks on this */
-
-	/*
-	 * If we are to allocate a memory protected page for the malloc(0)
-	 * case (when bits=0), it must be from a different page than the
-	 * pginfo page.
-	 * --> Treat it like the big chunk alloc, get a second data page.
-	 */
-	if (bits != 0 && (1UL << (bits)) <= l + l) {
-		bp = (struct pginfo *) pp;
-	} else {
-		bp = (struct pginfo *) imalloc(l);
-		if (bp == NULL) {
-			ifree(pp);
-			return (0);
-		}
-	}
-
-	/* memory protect the page allocated in the malloc(0) case */
-	if (bits == 0) {
-		bp->size = 0;
-		bp->shift = 1;
-		i = malloc_minsize - 1;
-		while (i >>= 1)
-			bp->shift++;
-		bp->total = bp->free = malloc_pagesize >> bp->shift;
-		bp->page = pp;
-
-		k = mprotect(pp, malloc_pagesize, PROT_NONE);
-		if (k < 0) {
-			ifree(pp);
-			ifree(bp);
-			return (0);
-		}
-	} else {
-		bp->size = (1UL << bits);
-		bp->shift = bits;
-		bp->total = bp->free = malloc_pagesize >> bits;
-		bp->page = pp;
-	}
-
-	/* set all valid bits in the bitmap */
-	k = bp->total;
-	i = 0;
-
-	/* Do a bunch at a time */
-	for (; (k - i) >= MALLOC_BITS; i += MALLOC_BITS)
-		bp->bits[i / MALLOC_BITS] = ~0UL;
-
-	for (; i < k; i++)
-		bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
-
-	k = (long)l;
-	if (bp == bp->page) {
-		/* Mark the ones we stole for ourselves */
-		for (i = 0; k > 0; i++) {
-			bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS));
-			bp->free--;
-			bp->total--;
-			k -= (1 << bits);
-		}
-	}
-	/* MALLOC_LOCK */
-
-	pdir_lookup(ptr2index(pp), &pi);
-#ifdef MALLOC_EXTRA_SANITY
-	pidx = PI_IDX(ptr2index(pp));
-	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-		wrterror("(ES): mapped pages not found in directory");
-		errno = EFAULT;
-		return (0);
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-	if (pi != last_dir) {
-		prev_dir = last_dir;
-		last_dir = pi;
-	}
-	pd = pi->base;
-	pd[PI_OFF(ptr2index(pp))] = bp;
-
-	bp->next = page_dir[bits];
-	page_dir[bits] = bp;
-
-	/* MALLOC_UNLOCK */
-	return (1);
-}
-
-/*
- * Allocate a fragment
- */
-static void *
-malloc_bytes(size_t size)
-{
-	int		i, j;
-	size_t		k;
-	u_long		u, *lp;
-	struct pginfo	*bp;
-
-	/* Don't bother with anything less than this */
-	/* unless we have a malloc(0) requests */
-	if (size != 0 && size < malloc_minsize)
-		size = malloc_minsize;
-
-	/* Find the right bucket */
-	if (size == 0)
-		j = 0;
-	else {
-		size_t ii;
-		j = 1;
-		ii = size - 1;
-		while (ii >>= 1)
-			j++;
-	}
-
-	/* If it's empty, make a page more of that size chunks */
-	if (page_dir[j] == NULL && !malloc_make_chunks(j))
-		return (NULL);
-
-	bp = page_dir[j];
-
-	/* Find first word of bitmap which isn't empty */
-	for (lp = bp->bits; !*lp; lp++);
-
-	/* Find that bit, and tweak it */
-	u = 1;
-	k = 0;
-	while (!(*lp & u)) {
-		u += u;
-		k++;
-	}
-
-	if (malloc_guard) {
-		/* Walk to a random position. */
-//		i = arc4random() % bp->free;
-		i = rand() % bp->free;
-		while (i > 0) {
-			u += u;
-			k++;
-			if (k >= MALLOC_BITS) {
-				lp++;
-				u = 1;
-				k = 0;
-			}
-#ifdef MALLOC_EXTRA_SANITY
-			if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) {
-				wrterror("chunk overflow");
-				errno = EFAULT;
-				return (NULL);
-			}
-#endif /* MALLOC_EXTRA_SANITY */
-			if (*lp & u)
-				i--;
-		}
-	}
-	*lp ^= u;
-
-	/* If there are no more free, remove from free-list */
-	if (!--bp->free) {
-		page_dir[j] = bp->next;
-		bp->next = NULL;
-	}
-	/* Adjust to the real offset of that chunk */
-	k += (lp - bp->bits) * MALLOC_BITS;
-	k <<= bp->shift;
-
-	if (malloc_junk && bp->size != 0)
-		memset((char *)bp->page + k, SOME_JUNK, (size_t)bp->size);
-
-	return ((u_char *) bp->page + k);
-}
-
-/*
- * Magic so that malloc(sizeof(ptr)) is near the end of the page.
- */
-#define	PTR_GAP		(malloc_pagesize - sizeof(void *))
-#define	PTR_SIZE	(sizeof(void *))
-#define	PTR_ALIGNED(p)	(((unsigned long)p & malloc_pagemask) == PTR_GAP)
-
-/*
- * Allocate a piece of memory
- */
-static void *
-imalloc(size_t size)
-{
-	void		*result;
-	int		ptralloc = 0;
-
-	if (!malloc_started)
-		malloc_init();
-
-	if (suicide)
-		abort();
-
-	/* does not matter if malloc_bytes fails */
-	if (px == NULL)
-		px = malloc_bytes(sizeof *px);
-
-	if (malloc_ptrguard && size == PTR_SIZE) {
-		ptralloc = 1;
-		size = malloc_pagesize;
-	}
-	if (size > SIZE_MAX - malloc_pagesize) { /* Check for overflow */
-		result = NULL;
-		errno = ENOMEM;
-	} else if (size <= malloc_maxsize)
-		result = malloc_bytes(size);
-	else
-		result = malloc_pages(size);
-
-	if (malloc_abort == 1 && result == NULL)
-		wrterror("allocation failed");
-
-	if (malloc_zero && result != NULL)
-		memset(result, 0, size);
-
-	if (result && ptralloc)
-		return ((char *) result + PTR_GAP);
-	return (result);
-}
-
-/*
- * Change the size of an allocation.
- */
-static void *
-irealloc(void *ptr, size_t size)
-{
-	void		*p;
-	size_t		osize;
-	u_long		index, i;
-	struct pginfo	**mp;
-	struct pginfo	**pd;
-	struct pdinfo	*pi;
-#ifdef	MALLOC_EXTRA_SANITY
-	u_long		pidx;
-#endif	/* MALLOC_EXTRA_SANITY */
-
-	if (suicide)
-		abort();
-
-	if (!malloc_started) {
-		wrtwarning("malloc() has never been called");
-		return (NULL);
-	}
-	if (malloc_ptrguard && PTR_ALIGNED(ptr)) {
-		if (size <= PTR_SIZE)
-			return (ptr);
-
-		p = imalloc(size);
-		if (p)
-			memcpy(p, ptr, PTR_SIZE);
-		ifree(ptr);
-		return (p);
-	}
-	index = ptr2index(ptr);
-
-	if (index < malloc_pageshift) {
-		wrtwarning("junk pointer, too low to make sense");
-		return (NULL);
-	}
-	if (index > last_index) {
-		wrtwarning("junk pointer, too high to make sense");
-		return (NULL);
-	}
-	pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
-	pidx = PI_IDX(index);
-	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-		wrterror("(ES): mapped pages not found in directory");
-		errno = EFAULT;
-		return (NULL);
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-	if (pi != last_dir) {
-		prev_dir = last_dir;
-		last_dir = pi;
-	}
-	pd = pi->base;
-	mp = &pd[PI_OFF(index)];
-
-	if (*mp == MALLOC_FIRST) {	/* Page allocation */
-
-		/* Check the pointer */
-		if ((u_long) ptr & malloc_pagemask) {
-			wrtwarning("modified (page-) pointer");
-			return (NULL);
-		}
-		/* Find the size in bytes */
-		i = index;
-		if (!PI_OFF(++i)) {
-			pi = pi->next;
-			if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
-				pi = NULL;
-			if (pi != NULL)
-				pd = pi->base;
-		}
-		for (osize = malloc_pagesize;
-		    pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) {
-			osize += malloc_pagesize;
-			if (!PI_OFF(++i)) {
-				pi = pi->next;
-				if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
-					pi = NULL;
-				if (pi != NULL)
-					pd = pi->base;
-			}
-		}
-
-		if (!malloc_realloc && size <= osize &&
-		    size > osize - malloc_pagesize) {
-			if (malloc_junk)
-				memset((char *)ptr + size, SOME_JUNK, osize - size);
-			return (ptr);	/* ..don't do anything else. */
-		}
-	} else if (*mp >= MALLOC_MAGIC) {	/* Chunk allocation */
-
-		/* Check the pointer for sane values */
-		if ((u_long) ptr & ((1UL << ((*mp)->shift)) - 1)) {
-			wrtwarning("modified (chunk-) pointer");
-			return (NULL);
-		}
-		/* Find the chunk index in the page */
-		i = ((u_long) ptr & malloc_pagemask) >> (*mp)->shift;
-
-		/* Verify that it isn't a free chunk already */
-		if ((*mp)->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
-			wrtwarning("chunk is already free");
-			return (NULL);
-		}
-		osize = (*mp)->size;
-
-		if (!malloc_realloc && size <= osize &&
-		    (size > osize / 2 || osize == malloc_minsize)) {
-			if (malloc_junk)
-				memset((char *) ptr + size, SOME_JUNK, osize - size);
-			return (ptr);	/* ..don't do anything else. */
-		}
-	} else {
-		wrtwarning("irealloc: pointer to wrong page");
-		return (NULL);
-	}
-
-	p = imalloc(size);
-
-	if (p != NULL) {
-		/* copy the lesser of the two sizes, and free the old one */
-		/* Don't move from/to 0 sized region !!! */
-		if (osize != 0 && size != 0) {
-			if (osize < size)
-				memcpy(p, ptr, osize);
-			else
-				memcpy(p, ptr, size);
-		}
-		ifree(ptr);
-	}
-	return (p);
-}
-
-/*
- * Free a sequence of pages
- */
-static __inline__ void
-free_pages(void *ptr, u_long index, struct pginfo * info)
-{
-	u_long		i, pidx, lidx;
-	size_t		l, cachesize = 0;
-	struct pginfo	**pd;
-	struct pdinfo	*pi, *spi;
-	struct pgfree	*pf, *pt = NULL;
-	caddr_t		tail;
-
-	if (info == MALLOC_FREE) {
-		wrtwarning("page is already free");
-		return;
-	}
-	if (info != MALLOC_FIRST) {
-		wrtwarning("free_pages: pointer to wrong page");
-		return;
-	}
-	if ((u_long) ptr & malloc_pagemask) {
-		wrtwarning("modified (page-) pointer");
-		return;
-	}
-	/* Count how many pages and mark them free at the same time */
-	pidx = PI_IDX(index);
-	pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
-	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-		wrterror("(ES): mapped pages not found in directory");
-		errno = EFAULT;
-		return;
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-
-	spi = pi;		/* Save page index for start of region. */
-
-	pd = pi->base;
-	pd[PI_OFF(index)] = MALLOC_FREE;
-	i = 1;
-	if (!PI_OFF(index + i)) {
-		pi = pi->next;
-		if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i))
-			pi = NULL;
-		else
-			pd = pi->base;
-	}
-	while (pi != NULL && pd[PI_OFF(index + i)] == MALLOC_FOLLOW) {
-		pd[PI_OFF(index + i)] = MALLOC_FREE;
-		i++;
-		if (!PI_OFF(index + i)) {
-			if ((pi = pi->next) == NULL ||
-			    PD_IDX(pi->dirnum) != PI_IDX(index + i))
-				pi = NULL;
-			else
-				pd = pi->base;
-		}
-	}
-
-	l = i << malloc_pageshift;
-
-	if (malloc_junk)
-		memset(ptr, SOME_JUNK, l);
-
-	malloc_used -= l;
-	malloc_guarded -= malloc_guard;
-	if (malloc_guard) {
-#ifdef MALLOC_EXTRA_SANITY
-		if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i)) {
-			wrterror("(ES): hole in mapped pages directory");
-			errno = EFAULT;
-			return;
-		}
-#endif /* MALLOC_EXTRA_SANITY */
-		pd[PI_OFF(index + i)] = MALLOC_FREE;
-		l += malloc_guard;
-	}
-	tail = (caddr_t)ptr + l;
-
-	if (malloc_hint)
-		madvise(ptr, l, MADV_FREE);
-
-	if (malloc_freeprot)
-		mprotect(ptr, l, PROT_NONE);
-
-	/* Add to free-list. */
-	if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL)
-			goto not_return;
-	px->page = ptr;
-	px->pdir = spi;
-	px->size = l;
-
-	if (free_list.next == NULL) {
-		/* Nothing on free list, put this at head. */
-		px->next = NULL;
-		px->prev = &free_list;
-		free_list.next = px;
-		pf = px;
-		px = NULL;
-	} else {
-		/*
-		 * Find the right spot, leave pf pointing to the modified
-		 * entry.
-		 */
-
-		/* Race ahead here, while calculating cache size. */
-		for (pf = free_list.next;
-		    (caddr_t)ptr > ((caddr_t)pf->page + pf->size)
-		    && pf->next != NULL;
-		    pf = pf->next)
-			cachesize += pf->size;
-
-		/* Finish cache size calculation. */
-		pt = pf;
-		while (pt) {
-			cachesize += pt->size;
-			pt = pt->next;
-		}
-
-		if ((caddr_t)pf->page > tail) {
-			/* Insert before entry */
-			px->next = pf;
-			px->prev = pf->prev;
-			pf->prev = px;
-			px->prev->next = px;
-			pf = px;
-			px = NULL;
-		} else if (((caddr_t)pf->page + pf->size) == ptr) {
-			/* Append to the previous entry. */
-			cachesize -= pf->size;
-			pf->size += l;
-			if (pf->next != NULL &&
-			    pf->next->page == ((caddr_t)pf->page + pf->size)) {
-				/* And collapse the next too. */
-				pt = pf->next;
-				pf->size += pt->size;
-				pf->next = pt->next;
-				if (pf->next != NULL)
-					pf->next->prev = pf;
-			}
-		} else if (pf->page == tail) {
-			/* Prepend to entry. */
-			cachesize -= pf->size;
-			pf->size += l;
-			pf->page = ptr;
-			pf->pdir = spi;
-		} else if (pf->next == NULL) {
-			/* Append at tail of chain. */
-			px->next = NULL;
-			px->prev = pf;
-			pf->next = px;
-			pf = px;
-			px = NULL;
-		} else {
-			wrterror("freelist is destroyed");
-			errno = EFAULT;
-			return;
-		}
-	}
-
-	if (pf->pdir != last_dir) {
-		prev_dir = last_dir;
-		last_dir = pf->pdir;
-	}
-
-	/* Return something to OS ? */
-	if (pf->size > (malloc_cache - cachesize)) {
-
-		/*
-		 * Keep the cache intact.  Notice that the '>' above guarantees that
-		 * the pf will always have at least one page afterwards.
-		 */
-		if (munmap((char *) pf->page + (malloc_cache - cachesize),
-		    pf->size - (malloc_cache - cachesize)) != 0)
-			goto not_return;
-		tail = (caddr_t)pf->page + pf->size;
-		lidx = ptr2index(tail) - 1;
-		pf->size = malloc_cache - cachesize;
-
-		index = ptr2index((caddr_t)pf->page + pf->size);
-
-		pidx = PI_IDX(index);
-		if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) >= pidx)
-			prev_dir = NULL;	/* Will be wiped out below ! */
-
-		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
-		    pi = pi->next)
-			;
-
-		spi = pi;
-		if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
-			pd = pi->base;
-
-			for (i = index; i <= lidx;) {
-				if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) {
-					pd[PI_OFF(i)] = MALLOC_NOT_MINE;
-#ifdef MALLOC_EXTRA_SANITY
-					if (!PD_OFF(pi->dirnum)) {
-						wrterror("(ES): pages directory underflow");
-						errno = EFAULT;
-						return;
-					}
-#endif /* MALLOC_EXTRA_SANITY */
-					pi->dirnum--;
-				}
-#ifdef MALLOC_EXTRA_SANITY
-				else
-					wrtwarning("(ES): page already unmapped");
-#endif /* MALLOC_EXTRA_SANITY */
-				i++;
-				if (!PI_OFF(i)) {
-					/*
-					 * If no page in that dir, free
-					 * directory page.
-					 */
-					if (!PD_OFF(pi->dirnum)) {
-						/* Remove from list. */
-						if (spi == pi)
-							spi = pi->prev;
-						if (pi->prev != NULL)
-							pi->prev->next = pi->next;
-						if (pi->next != NULL)
-							pi->next->prev = pi->prev;
-						pi = pi->next;
-						munmap(pd, malloc_pagesize);
-					} else
-						pi = pi->next;
-					if (pi == NULL ||
-					    PD_IDX(pi->dirnum) != PI_IDX(i))
-						break;
-					pd = pi->base;
-				}
-			}
-			if (pi && !PD_OFF(pi->dirnum)) {
-				/* Resulting page dir is now empty. */
-				/* Remove from list. */
-				if (spi == pi)	/* Update spi only if first. */
-					spi = pi->prev;
-				if (pi->prev != NULL)
-					pi->prev->next = pi->next;
-				if (pi->next != NULL)
-					pi->next->prev = pi->prev;
-				pi = pi->next;
-				munmap(pd, malloc_pagesize);
-			}
-		}
-		if (pi == NULL && malloc_brk == tail) {
-			/* Resize down the malloc upper boundary. */
-			last_index = index - 1;
-			malloc_brk = index2ptr(index);
-		}
-
-		/* XXX: We could realloc/shrink the pagedir here I guess. */
-		if (pf->size == 0) {	/* Remove from free-list as well. */
-			if (px)
-				ifree(px);
-			if ((px = pf->prev) != &free_list) {
-				if (pi == NULL && last_index == (index - 1)) {
-					if (spi == NULL) {
-						malloc_brk = NULL;
-						i = 11;
-					} else {
-						pd = spi->base;
-						if (PD_IDX(spi->dirnum) < pidx)
-							index =
-							    ((PD_IDX(spi->dirnum) + 1) *
-							    pdi_mod) - 1;
-						for (pi = spi, i = index;
-						    pd[PI_OFF(i)] == MALLOC_NOT_MINE;
-						    i--)
-#ifdef MALLOC_EXTRA_SANITY
-							if (!PI_OFF(i)) {
-								pi = pi->prev;
-								if (pi == NULL || i == 0)
-									break;
-								pd = pi->base;
-								i = (PD_IDX(pi->dirnum) + 1) * pdi_mod;
-							}
-#else /* !MALLOC_EXTRA_SANITY */
-						{
-						}
-#endif /* MALLOC_EXTRA_SANITY */
-						malloc_brk = index2ptr(i + 1);
-					}
-					last_index = i;
-				}
-				if ((px->next = pf->next) != NULL)
-					px->next->prev = px;
-			} else {
-				if ((free_list.next = pf->next) != NULL)
-					free_list.next->prev = &free_list;
-			}
-			px = pf;
-			last_dir = prev_dir;
-			prev_dir = NULL;
-		}
-	}
-not_return:
-	if (pt != NULL)
-		ifree(pt);
-}
-
-/*
- * Free a chunk, and possibly the page it's on, if the page becomes empty.
- */
-
-/* ARGSUSED */
-static __inline__ void
-free_bytes(void *ptr, u_long index, struct pginfo * info)
-{
-	struct pginfo	**mp, **pd;
-	struct pdinfo	*pi;
-#ifdef	MALLOC_EXTRA_SANITY
-	u_long		pidx;
-#endif	/* MALLOC_EXTRA_SANITY */
-	void		*vp;
-	long		i;
-	(void) index;
-
-	/* Find the chunk number on the page */
-	i = ((u_long) ptr & malloc_pagemask) >> info->shift;
-
-	if ((u_long) ptr & ((1UL << (info->shift)) - 1)) {
-		wrtwarning("modified (chunk-) pointer");
-		return;
-	}
-	if (info->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
-		wrtwarning("chunk is already free");
-		return;
-	}
-	if (malloc_junk && info->size != 0)
-		memset(ptr, SOME_JUNK, (size_t)info->size);
-
-	info->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
-	info->free++;
-
-	if (info->size != 0)
-		mp = page_dir + info->shift;
-	else
-		mp = page_dir;
-
-	if (info->free == 1) {
-		/* Page became non-full */
-
-		/* Insert in address order */
-		while (*mp != NULL && (*mp)->next != NULL &&
-		    (*mp)->next->page < info->page)
-			mp = &(*mp)->next;
-		info->next = *mp;
-		*mp = info;
-		return;
-	}
-	if (info->free != info->total)
-		return;
-
-	/* Find & remove this page in the queue */
-	while (*mp != info) {
-		mp = &((*mp)->next);
-#ifdef MALLOC_EXTRA_SANITY
-		if (!*mp) {
-			wrterror("(ES): Not on queue");
-			errno = EFAULT;
-			return;
-		}
-#endif /* MALLOC_EXTRA_SANITY */
-	}
-	*mp = info->next;
-
-	/* Free the page & the info structure if need be */
-	pdir_lookup(ptr2index(info->page), &pi);
-#ifdef MALLOC_EXTRA_SANITY
-	pidx = PI_IDX(ptr2index(info->page));
-	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-		wrterror("(ES): mapped pages not found in directory");
-		errno = EFAULT;
-		return;
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-	if (pi != last_dir) {
-		prev_dir = last_dir;
-		last_dir = pi;
-	}
-	pd = pi->base;
-	pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
-
-	/* If the page was mprotected, unprotect it before releasing it */
-	if (info->size == 0)
-		mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE);
-
-	vp = info->page;	/* Order is important ! */
-	if (vp != (void *) info)
-		ifree(info);
-	ifree(vp);
-}
-
-static void
-ifree(void *ptr)
-{
-	struct pginfo	*info, **pd;
-	u_long		index;
-#ifdef	MALLOC_EXTRA_SANITY
-	u_long		pidx;
-#endif	/* MALLOC_EXTRA_SANITY */
-	struct pdinfo	*pi;
-
-	if (!malloc_started) {
-		wrtwarning("malloc() has never been called");
-		return;
-	}
-	/* If we're already sinking, don't make matters any worse. */
-	if (suicide)
-		return;
-
-	if (malloc_ptrguard && PTR_ALIGNED(ptr))
-		ptr = (char *) ptr - PTR_GAP;
-
-	index = ptr2index(ptr);
-
-	if (index < malloc_pageshift) {
-		warnx("(%p)", ptr);
-		wrtwarning("ifree: junk pointer, too low to make sense");
-		return;
-	}
-	if (index > last_index) {
-		warnx("(%p)", ptr);
-		wrtwarning("ifree: junk pointer, too high to make sense");
-		return;
-	}
-	pdir_lookup(index, &pi);
-#ifdef MALLOC_EXTRA_SANITY
-	pidx = PI_IDX(index);
-	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
-		wrterror("(ES): mapped pages not found in directory");
-		errno = EFAULT;
-		return;
-	}
-#endif /* MALLOC_EXTRA_SANITY */
-	if (pi != last_dir) {
-		prev_dir = last_dir;
-		last_dir = pi;
-	}
-	pd = pi->base;
-	info = pd[PI_OFF(index)];
-
-	if (info < MALLOC_MAGIC)
-		free_pages(ptr, index, info);
-	else
-		free_bytes(ptr, index, info);
-
-	/* does not matter if malloc_bytes fails */
-	if (px == NULL)
-		px = malloc_bytes(sizeof *px);
-
-	return;
-}
-
-/*
- * Common function for handling recursion.  Only
- * print the error message once, to avoid making the problem
- * potentially worse.
- */
-static void
-malloc_recurse(void)
-{
-	static int	noprint;
-
-	if (noprint == 0) {
-		noprint = 1;
-		wrtwarning("recursive call");
-	}
-	malloc_active--;
-	_MALLOC_UNLOCK();
-	errno = EDEADLK;
-}
-
-/*
- * These are the public exported interface routines.
- */
-void *
-malloc(size_t size)
-{
-	void		*r;
-
-	if (!align)
-	_MALLOC_LOCK();
-	malloc_func = " in malloc():";
-	if (malloc_active++) {
-		malloc_recurse();
-		return (NULL);
-	}
-	r = imalloc(size);
-	UTRACE(0, size, r);
-	malloc_active--;
-	if (!align)
-	_MALLOC_UNLOCK();
-	if (malloc_xmalloc && r == NULL) {
-		wrterror("out of memory");
-		errno = ENOMEM;
-	}
-	return (r);
-}
-
-void
-free(void *ptr)
-{
-	/* This is legal. XXX quick path */
-	if (ptr == NULL)
-		return;
-
-	_MALLOC_LOCK();
-	malloc_func = " in free():";
-	if (malloc_active++) {
-		malloc_recurse();
-		return;
-	}
-	ifree(ptr);
-	UTRACE(ptr, 0, 0);
-	malloc_active--;
-	_MALLOC_UNLOCK();
-	return;
-}
-
-void *
-realloc(void *ptr, size_t size)
-{
-	void		*r;
-
-	_MALLOC_LOCK();
-	malloc_func = " in realloc():";
-	if (malloc_active++) {
-		malloc_recurse();
-		return (NULL);
-	}
-
-	if (ptr == NULL)
-		r = imalloc(size);
-	else
-		r = irealloc(ptr, size);
-
-	UTRACE(ptr, size, r);
-	malloc_active--;
-	_MALLOC_UNLOCK();
-	if (malloc_xmalloc && r == NULL) {
-		wrterror("out of memory");
-		errno = ENOMEM;
-	}
-	return (r);
-}
-
-#ifndef SIZE_MAX
-//#if defined(__i386__)||defined(__arm__)||defined(__powerpc__)
-//#define SIZE_MAX 0xffffffff
-//#endif
-//#if defined(__x86_64__)
-//#define SIZE_MAX 0xffffffffffffffff
-//#endif
-#define SIZE_MAX SIZE_T_MAX
-#endif
-
-void *
-calloc(size_t num, size_t size)
-{
-	void *p;
-	
-	if (num && SIZE_MAX / num < size) {
-		fprintf(stderr,"OOOOPS");
-		errno = ENOMEM;
-		return NULL;
-	}
-	size *= num;
-	p = malloc(size);
-	if (p)
-		memset(p, 0, size);
-	return(p);
-}
-
-#ifndef BUILDING_FOR_TOR
-static int ispowerof2 (size_t a) {
-	size_t b;
-	for (b = 1ULL << (sizeof(size_t)*NBBY - 1); b > 1; b >>= 1)
-	  if (b == a)
-		return 1;
-	return 0;
-}
-#endif
-
-#ifndef BUILDING_FOR_TOR
-int posix_memalign(void **memptr, size_t alignment, size_t size)
-{
-	void *r;
-	size_t max;
-	if ((alignment < PTR_SIZE) || (alignment%PTR_SIZE != 0)) return EINVAL;
-	if (!ispowerof2(alignment)) return EINVAL;
-	if (alignment < malloc_minsize) alignment = malloc_minsize;
-	max = alignment > size ? alignment : size;
-	if (alignment <= malloc_pagesize)
-		r = malloc(max);
-	else {
-		_MALLOC_LOCK();
-		align = 1;
-		g_alignment = alignment;
-		r = malloc(size);
-		align=0;
-		_MALLOC_UNLOCK();
-	}
-	*memptr = r;
-	if (!r) return ENOMEM;
-	return 0;
-}
-
-void *memalign(size_t boundary, size_t size)
-{
-	void *r;
-	posix_memalign(&r, boundary, size);
-	return r;
-}
-
-void *valloc(size_t size)
-{
-	void *r;
-	posix_memalign(&r, malloc_pagesize, size);
-	return r;
-}
-#endif
-
-size_t malloc_good_size(size_t size)
-{
-	if (size == 0) {
-		return 1;
-	} else if (size <= malloc_maxsize) {
-		int j;
-		size_t ii;
-		/* round up to the nearest power of 2, with same approach
-		 * as malloc_bytes() uses. */
-		j = 1;
-		ii = size - 1;
-		while (ii >>= 1)
-			j++;
-		return ((size_t)1) << j;
-	} else {
-		return pageround(size);
-	}
-}
diff --git a/src/common/ht.h b/src/common/ht.h
deleted file mode 100644
index 25156c4..0000000
--- a/src/common/ht.h
+++ /dev/null
@@ -1,490 +0,0 @@
-/* Copyright (c) 2002, Christopher Clark.
- * Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
-/* See license at end. */
-
-/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
-
-#ifndef _TOR_HT_H
-#define _TOR_HT_H
-
-#define HT_HEAD(name, type)                                             \
-  struct name {                                                         \
-    /* The hash table itself. */                                        \
-    struct type **hth_table;                                            \
-    /* How long is the hash table? */                                   \
-    unsigned hth_table_length;                                          \
-    /* How many elements does the table contain? */                     \
-    unsigned hth_n_entries;                                             \
-    /* How many elements will we allow in the table before resizing it? */ \
-    unsigned hth_load_limit;                                            \
-    /* Position of hth_table_length in the primes table. */             \
-    int hth_prime_idx;                                                  \
-  }
-
-#define HT_INITIALIZER()                        \
-  { NULL, 0, 0, 0, -1 }
-
-#ifdef HT_NO_CACHE_HASH_VALUES
-#define HT_ENTRY(type)                          \
-  struct {                                      \
-    struct type *hte_next;                      \
-  }
-#else
-#define HT_ENTRY(type)                          \
-  struct {                                      \
-    struct type *hte_next;                      \
-    unsigned hte_hash;                          \
-  }
-#endif
-
-#define HT_EMPTY(head)                          \
-  ((head)->hth_n_entries == 0)
-
-/* How many elements in 'head'? */
-#define HT_SIZE(head)                           \
-  ((head)->hth_n_entries)
-
-/* Return memory usage for a hashtable (not counting the entries themselves) */
-#define HT_MEM_USAGE(head)                         \
-  (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
-
-#define HT_FIND(name, head, elm)     name##_HT_FIND((head), (elm))
-#define HT_INSERT(name, head, elm)   name##_HT_INSERT((head), (elm))
-#define HT_REPLACE(name, head, elm)  name##_HT_REPLACE((head), (elm))
-#define HT_REMOVE(name, head, elm)   name##_HT_REMOVE((head), (elm))
-#define HT_START(name, head)         name##_HT_START(head)
-#define HT_NEXT(name, head, elm)     name##_HT_NEXT((head), (elm))
-#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
-#define HT_CLEAR(name, head)         name##_HT_CLEAR(head)
-#define HT_INIT(name, head)          name##_HT_INIT(head)
-/* Helper: */
-static INLINE unsigned
-ht_improve_hash(unsigned h)
-{
-  /* Aim to protect against poor hash functions by adding logic here
-   * - logic taken from java 1.4 hashtable source */
-  h += ~(h << 9);
-  h ^=  ((h >> 14) | (h << 18)); /* >>> */
-  h +=  (h << 4);
-  h ^=  ((h >> 10) | (h << 22)); /* >>> */
-  return h;
-}
-
-#if 0
-/** Basic string hash function, from Java standard String.hashCode(). */
-static INLINE unsigned
-ht_string_hash(const char *s)
-{
-  unsigned h = 0;
-  int m = 1;
-  while (*s) {
-    h += ((signed char)*s++)*m;
-    m = (m<<5)-1; /* m *= 31 */
-  }
-  return h;
-}
-#endif
-
-/** Basic string hash function, from Python's str.__hash__() */
-static INLINE unsigned
-ht_string_hash(const char *s)
-{
-  unsigned h;
-  const unsigned char *cp = (const unsigned char *)s;
-  h = *cp << 7;
-  while (*cp) {
-    h = (1000003*h) ^ *cp++;
-  }
-  /* This conversion truncates the length of the string, but that's ok. */
-  h ^= (unsigned)(cp-(const unsigned char*)s);
-  return h;
-}
-
-#ifndef HT_NO_CACHE_HASH_VALUES
-#define HT_SET_HASH_(elm, field, hashfn)        \
-    do { (elm)->field.hte_hash = hashfn(elm); } while (0)
-#define HT_SET_HASHVAL_(elm, field, val)        \
-    do { (elm)->field.hte_hash = (val); } while (0)
-#define HT_ELT_HASH_(elm, field, hashfn)        \
-    ((elm)->field.hte_hash)
-#else
-#define HT_SET_HASH_(elm, field, hashfn)        \
-    ((void)0)
-#define HT_ELT_HASH_(elm, field, hashfn)        \
-    (hashfn(elm))
-#define HT_SET_HASHVAL_(elm, field, val)        \
-        ((void)0)
-#endif
-
-/* Helper: alias for the bucket containing 'elm'. */
-#define HT_BUCKET_(head, field, elm, hashfn)                            \
-    ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn)                   \
-        % head->hth_table_length])
-
-#define HT_FOREACH(x, name, head)                 \
-  for ((x) = HT_START(name, head);                \
-       (x) != NULL;                               \
-       (x) = HT_NEXT(name, head, x))
-
-#define HT_PROTOTYPE(name, type, field, hashfn, eqfn)                   \
-  int name##_HT_GROW(struct name *ht, unsigned min_capacity);           \
-  void name##_HT_CLEAR(struct name *ht);                                \
-  int name##_HT_REP_IS_BAD_(const struct name *ht);                     \
-  static INLINE void                                                    \
-  name##_HT_INIT(struct name *head) {                                   \
-    head->hth_table_length = 0;                                         \
-    head->hth_table = NULL;                                             \
-    head->hth_n_entries = 0;                                            \
-    head->hth_load_limit = 0;                                           \
-    head->hth_prime_idx = -1;                                           \
-  }                                                                     \
-  /* Helper: returns a pointer to the right location in the table       \
-   * 'head' to find or insert the element 'elm'. */                     \
-  static INLINE struct type **                                          \
-  name##_HT_FIND_P_(struct name *head, struct type *elm)                \
-  {                                                                     \
-    struct type **p;                                                    \
-    if (!head->hth_table)                                               \
-      return NULL;                                                      \
-    p = &HT_BUCKET_(head, field, elm, hashfn);                          \
-    while (*p) {                                                        \
-      if (eqfn(*p, elm))                                                \
-        return p;                                                       \
-      p = &(*p)->field.hte_next;                                        \
-    }                                                                   \
-    return p;                                                           \
-  }                                                                     \
-  /* Return a pointer to the element in the table 'head' matching 'elm', \
-   * or NULL if no such element exists */                               \
-  static INLINE struct type *                                           \
-  name##_HT_FIND(const struct name *head, struct type *elm)             \
-  {                                                                     \
-    struct type **p;                                                    \
-    struct name *h = (struct name *) head;                              \
-    HT_SET_HASH_(elm, field, hashfn);                                   \
-    p = name##_HT_FIND_P_(h, elm);                                      \
-    return p ? *p : NULL;                                               \
-  }                                                                     \
-  /* Insert the element 'elm' into the table 'head'.  Do not call this  \
-   * function if the table might already contain a matching element. */ \
-  static INLINE void                                                    \
-  name##_HT_INSERT(struct name *head, struct type *elm)                 \
-  {                                                                     \
-    struct type **p;                                                    \
-    if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
-      name##_HT_GROW(head, head->hth_n_entries+1);                      \
-    ++head->hth_n_entries;                                              \
-    HT_SET_HASH_(elm, field, hashfn);                                   \
-    p = &HT_BUCKET_(head, field, elm, hashfn);                          \
-    elm->field.hte_next = *p;                                           \
-    *p = elm;                                                           \
-  }                                                                     \
-  /* Insert the element 'elm' into the table 'head'. If there already   \
-   * a matching element in the table, replace that element and return   \
-   * it. */                                                             \
-  static INLINE struct type *                                           \
-  name##_HT_REPLACE(struct name *head, struct type *elm)                \
-  {                                                                     \
-    struct type **p, *r;                                                \
-    if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
-      name##_HT_GROW(head, head->hth_n_entries+1);                      \
-    HT_SET_HASH_(elm, field, hashfn);                                   \
-    p = name##_HT_FIND_P_(head, elm);                                   \
-    r = *p;                                                             \
-    *p = elm;                                                           \
-    if (r && (r!=elm)) {                                                \
-      elm->field.hte_next = r->field.hte_next;                          \
-      r->field.hte_next = NULL;                                         \
-      return r;                                                         \
-    } else {                                                            \
-      ++head->hth_n_entries;                                            \
-      return NULL;                                                      \
-    }                                                                   \
-  }                                                                     \
-  /* Remove any element matching 'elm' from the table 'head'.  If such  \
-   * an element is found, return it; otherwise return NULL. */          \
-  static INLINE struct type *                                           \
-  name##_HT_REMOVE(struct name *head, struct type *elm)                 \
-  {                                                                     \
-    struct type **p, *r;                                                \
-    HT_SET_HASH_(elm, field, hashfn);                                   \
-    p = name##_HT_FIND_P_(head,elm);                                    \
-    if (!p || !*p)                                                      \
-      return NULL;                                                      \
-    r = *p;                                                             \
-    *p = r->field.hte_next;                                             \
-    r->field.hte_next = NULL;                                           \
-    --head->hth_n_entries;                                              \
-    return r;                                                           \
-  }                                                                     \
-  /* Invoke the function 'fn' on every element of the table 'head',     \
-   * using 'data' as its second argument.  If the function returns      \
-   * nonzero, remove the most recently examined element before invoking \
-   * the function again. */                                             \
-  static INLINE void                                                    \
-  name##_HT_FOREACH_FN(struct name *head,                               \
-                       int (*fn)(struct type *, void *),                \
-                       void *data)                                      \
-  {                                                                     \
-    unsigned idx;                                                       \
-    struct type **p, **nextp, *next;                                    \
-    if (!head->hth_table)                                               \
-      return;                                                           \
-    for (idx=0; idx < head->hth_table_length; ++idx) {                  \
-      p = &head->hth_table[idx];                                        \
-      while (*p) {                                                      \
-        nextp = &(*p)->field.hte_next;                                  \
-        next = *nextp;                                                  \
-        if (fn(*p, data)) {                                             \
-          --head->hth_n_entries;                                        \
-          *p = next;                                                    \
-        } else {                                                        \
-          p = nextp;                                                    \
-        }                                                               \
-      }                                                                 \
-    }                                                                   \
-  }                                                                     \
-  /* Return a pointer to the first element in the table 'head', under   \
-   * an arbitrary order.  This order is stable under remove operations, \
-   * but not under others. If the table is empty, return NULL. */       \
-  static INLINE struct type **                                          \
-  name##_HT_START(struct name *head)                                    \
-  {                                                                     \
-    unsigned b = 0;                                                     \
-    while (b < head->hth_table_length) {                                \
-      if (head->hth_table[b])                                           \
-        return &head->hth_table[b];                                     \
-      ++b;                                                              \
-    }                                                                   \
-    return NULL;                                                        \
-  }                                                                     \
-  /* Return the next element in 'head' after 'elm', under the arbitrary \
-   * order used by HT_START.  If there are no more elements, return     \
-   * NULL.  If 'elm' is to be removed from the table, you must call     \
-   * this function for the next value before you remove it.             \
-   */                                                                   \
-  static INLINE struct type **                                          \
-  name##_HT_NEXT(struct name *head, struct type **elm)                  \
-  {                                                                     \
-    if ((*elm)->field.hte_next) {                                       \
-      return &(*elm)->field.hte_next;                                   \
-    } else {                                                            \
-      unsigned b = (HT_ELT_HASH_(*elm, field, hashfn)                   \
-      % head->hth_table_length)+1;                                      \
-      while (b < head->hth_table_length) {                              \
-        if (head->hth_table[b])                                         \
-          return &head->hth_table[b];                                   \
-        ++b;                                                            \
-      }                                                                 \
-      return NULL;                                                      \
-    }                                                                   \
-  }                                                                     \
-  static INLINE struct type **                                          \
-  name##_HT_NEXT_RMV(struct name *head, struct type **elm)              \
-  {                                                                     \
-    unsigned h = HT_ELT_HASH_(*elm, field, hashfn);                     \
-    *elm = (*elm)->field.hte_next;                                      \
-    --head->hth_n_entries;                                              \
-    if (*elm) {                                                         \
-      return elm;                                                       \
-    } else {                                                            \
-      unsigned b = (h % head->hth_table_length)+1;                      \
-      while (b < head->hth_table_length) {                              \
-        if (head->hth_table[b])                                         \
-          return &head->hth_table[b];                                   \
-        ++b;                                                            \
-      }                                                                 \
-      return NULL;                                                      \
-    }                                                                   \
-  }
-
-#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn,    \
-                    reallocfn, freefn)                                  \
-  static unsigned name##_PRIMES[] = {                                   \
-    53, 97, 193, 389,                                                   \
-    769, 1543, 3079, 6151,                                              \
-    12289, 24593, 49157, 98317,                                         \
-    196613, 393241, 786433, 1572869,                                    \
-    3145739, 6291469, 12582917, 25165843,                               \
-    50331653, 100663319, 201326611, 402653189,                          \
-    805306457, 1610612741                                               \
-  };                                                                    \
-  static unsigned name##_N_PRIMES =                                     \
-    (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0]));         \
-  /* Expand the internal table of 'head' until it is large enough to    \
-   * hold 'size' elements.  Return 0 on success, -1 on allocation       \
-   * failure. */                                                        \
-  int                                                                   \
-  name##_HT_GROW(struct name *head, unsigned size)                      \
-  {                                                                     \
-    unsigned new_len, new_load_limit;                                   \
-    int prime_idx;                                                      \
-    struct type **new_table;                                            \
-    if (head->hth_prime_idx == (int)name##_N_PRIMES - 1)                \
-      return 0;                                                         \
-    if (head->hth_load_limit > size)                                    \
-      return 0;                                                         \
-    prime_idx = head->hth_prime_idx;                                    \
-    do {                                                                \
-      new_len = name##_PRIMES[++prime_idx];                             \
-      new_load_limit = (unsigned)(load*new_len);                        \
-    } while (new_load_limit <= size &&                                  \
-             prime_idx < (int)name##_N_PRIMES);                         \
-    if ((new_table = mallocfn(new_len*sizeof(struct type*)))) {         \
-      unsigned b;                                                       \
-      memset(new_table, 0, new_len*sizeof(struct type*));               \
-      for (b = 0; b < head->hth_table_length; ++b) {                    \
-        struct type *elm, *next;                                        \
-        unsigned b2;                                                    \
-        elm = head->hth_table[b];                                       \
-        while (elm) {                                                   \
-          next = elm->field.hte_next;                                   \
-          b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len;              \
-          elm->field.hte_next = new_table[b2];                          \
-          new_table[b2] = elm;                                          \
-          elm = next;                                                   \
-        }                                                               \
-      }                                                                 \
-      if (head->hth_table)                                              \
-        freefn(head->hth_table);                                        \
-      head->hth_table = new_table;                                      \
-    } else {                                                            \
-      unsigned b, b2;                                                   \
-      new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
-      if (!new_table) return -1;                                        \
-      memset(new_table + head->hth_table_length, 0,                     \
-             (new_len - head->hth_table_length)*sizeof(struct type*));  \
-      for (b=0; b < head->hth_table_length; ++b) {                      \
-        struct type *e, **pE;                                           \
-        for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) {         \
-          b2 = HT_ELT_HASH_(e, field, hashfn) % new_len;                \
-          if (b2 == b) {                                                \
-            pE = &e->field.hte_next;                                    \
-          } else {                                                      \
-            *pE = e->field.hte_next;                                    \
-            e->field.hte_next = new_table[b2];                          \
-            new_table[b2] = e;                                          \
-          }                                                             \
-        }                                                               \
-      }                                                                 \
-      head->hth_table = new_table;                                      \
-    }                                                                   \
-    head->hth_table_length = new_len;                                   \
-    head->hth_prime_idx = prime_idx;                                    \
-    head->hth_load_limit = new_load_limit;                              \
-    return 0;                                                           \
-  }                                                                     \
-  /* Free all storage held by 'head'.  Does not free 'head' itself, or  \
-   * individual elements. */                                            \
-  void                                                                  \
-  name##_HT_CLEAR(struct name *head)                                    \
-  {                                                                     \
-    if (head->hth_table)                                                \
-      freefn(head->hth_table);                                          \
-    head->hth_table_length = 0;                                         \
-    name##_HT_INIT(head);                                               \
-  }                                                                     \
-  /* Debugging helper: return false iff the representation of 'head' is \
-   * internally consistent. */                                          \
-  int                                                                   \
-  name##_HT_REP_IS_BAD_(const struct name *head)                        \
-  {                                                                     \
-    unsigned n, i;                                                      \
-    struct type *elm;                                                   \
-    if (!head->hth_table_length) {                                      \
-      if (!head->hth_table && !head->hth_n_entries &&                   \
-          !head->hth_load_limit && head->hth_prime_idx == -1)           \
-        return 0;                                                       \
-      else                                                              \
-        return 1;                                                       \
-    }                                                                   \
-    if (!head->hth_table || head->hth_prime_idx < 0 ||                  \
-        !head->hth_load_limit)                                          \
-      return 2;                                                         \
-    if (head->hth_n_entries > head->hth_load_limit)                     \
-      return 3;                                                         \
-    if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx])   \
-      return 4;                                                         \
-    if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
-      return 5;                                                         \
-    for (n = i = 0; i < head->hth_table_length; ++i) {                  \
-      for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) {  \
-        if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm))            \
-          return 1000 + i;                                              \
-        if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
-          return 10000 + i;                                             \
-        ++n;                                                            \
-      }                                                                 \
-    }                                                                   \
-    if (n != head->hth_n_entries)                                       \
-      return 6;                                                         \
-    return 0;                                                           \
-  }
-
-/** Implements an over-optimized "find and insert if absent" block;
- * not meant for direct usage by typical code, or usage outside the critical
- * path.*/
-#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
-  {                                                                     \
-    struct name *var##_head_ = head;                                    \
-    struct eltype **var;                                                \
-    if (!var##_head_->hth_table ||                                      \
-        var##_head_->hth_n_entries >= var##_head_->hth_load_limit)      \
-      name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1);        \
-    HT_SET_HASH_((elm), field, hashfn);                                 \
-    var = name##_HT_FIND_P_(var##_head_, (elm));                        \
-    if (*var) {                                                         \
-      y;                                                                \
-    } else {                                                            \
-      n;                                                                \
-    }                                                                   \
-  }
-#define HT_FOI_INSERT_(field, head, elm, newent, var)       \
-  {                                                         \
-    HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash);  \
-    newent->field.hte_next = NULL;                          \
-    *var = newent;                                          \
-    ++((head)->hth_n_entries);                              \
-  }
-
-/*
- * Copyright 2005, Nick Mathewson.  Implementation logic is adapted from code
- * by Christopher Clark, retrofit to allow drop-in memory management, and to
- * use the same interface as Niels Provos's tree.h.  This is probably still
- * a derived work, so the original license below still applies.
- *
- * Copyright (c) 2002, Christopher Clark
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of the original author; nor the names of any contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#endif
-
diff --git a/src/common/include.am b/src/common/include.am
index ba08aa7..7299a47 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -9,7 +9,7 @@ EXTRA_DIST+= \
 AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
 
 if USE_OPENBSD_MALLOC
-libor_extra_source=src/common/OpenBSD_malloc_Linux.c
+libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
 else
 libor_extra_source=
 endif
@@ -44,7 +44,6 @@ COMMONHEADERS = \
   src/common/container.h			\
   src/common/crypto.h				\
   src/common/di_ops.h				\
-  src/common/ht.h				\
   src/common/memarea.h				\
   src/common/mempool.h				\
   src/common/procmon.h				\
diff --git a/src/ext/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c
new file mode 100644
index 0000000..da82729
--- /dev/null
+++ b/src/ext/OpenBSD_malloc_Linux.c
@@ -0,0 +1,2057 @@
+/* Version 1.83 for Linux.
+ * Compilation: gcc -shared -fPIC -O2 OpenBSD_malloc_Linux.c -o malloc.so
+ * Launching: LD_PRELOAD=/path/to/malloc.so firefox
+ */
+
+/*	$OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $	*/
+
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk at FreeBSD.ORG> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+/* We use this macro to remove some code that we don't actually want,
+ * rather than to fix its warnings. */
+#define BUILDING_FOR_TOR
+
+/*
+ * Defining MALLOC_EXTRA_SANITY will enable extra checks which are
+ * related to internal conditions and consistency in malloc.c. This has
+ * a noticeable runtime performance hit, and generally will not do you
+ * any good unless you fiddle with the internals of malloc or want
+ * to catch random pointer corruption as early as possible.
+ */
+#ifndef	MALLOC_EXTRA_SANITY
+#undef	MALLOC_EXTRA_SANITY
+#endif
+
+/*
+ * Defining MALLOC_STATS will enable you to call malloc_dump() and set
+ * the [dD] options in the MALLOC_OPTIONS environment variable.
+ * It has no run-time performance hit, but does pull in stdio...
+ */
+#ifndef	MALLOC_STATS
+#undef	MALLOC_STATS
+#endif
+
+/*
+ * What to use for Junk.  This is the byte value we use to fill with
+ * when the 'J' option is enabled.
+ */
+#define SOME_JUNK	0xd0	/* as in "Duh" :-) */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <err.h>
+/* For SIZE_T_MAX */
+#include "torint.h"
+
+//#include "thread_private.h"
+
+/*
+ * The basic parameters you can tweak.
+ *
+ * malloc_pageshift	pagesize = 1 << malloc_pageshift
+ *			It's probably best if this is the native
+ *			page size, but it shouldn't have to be.
+ *
+ * malloc_minsize	minimum size of an allocation in bytes.
+ *			If this is too small it's too much work
+ *			to manage them.  This is also the smallest
+ *			unit of alignment used for the storage
+ *			returned by malloc/realloc.
+ *
+ */
+
+static int align = 0;
+static size_t g_alignment = 0;
+
+extern int __libc_enable_secure;
+
+#ifndef HAVE_ISSETUGID
+static int issetugid(void)
+{
+	if (__libc_enable_secure) return 1;
+	if (getuid() != geteuid()) return 1;
+	if (getgid() != getegid()) return 1;
+	return 0;
+}
+#endif
+
+#define PGSHIFT 12
+#undef MADV_FREE
+#define MADV_FREE MADV_DONTNEED
+#include <pthread.h>
+static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define _MALLOC_LOCK_INIT() {;}
+#define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
+#define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
+
+#if defined(__sparc__) || defined(__alpha__)
+#define	malloc_pageshift	13U
+#endif
+#if defined(__ia64__)
+#define	malloc_pageshift	14U
+#endif
+
+#ifndef malloc_pageshift
+#define malloc_pageshift	(PGSHIFT)
+#endif
+
+/*
+ * No user serviceable parts behind this point.
+ *
+ * This structure describes a page worth of chunks.
+ */
+struct pginfo {
+	struct pginfo	*next;	/* next on the free list */
+	void		*page;	/* Pointer to the page */
+	u_short		size;	/* size of this page's chunks */
+	u_short		shift;	/* How far to shift for this size chunks */
+	u_short		free;	/* How many free chunks */
+	u_short		total;	/* How many chunk */
+	u_long		bits[1];/* Which chunks are free */
+};
+
+/* How many bits per u_long in the bitmap */
+#define	MALLOC_BITS	(int)((NBBY * sizeof(u_long)))
+
+/*
+ * This structure describes a number of free pages.
+ */
+struct pgfree {
+	struct pgfree	*next;	/* next run of free pages */
+	struct pgfree	*prev;	/* prev run of free pages */
+	void		*page;	/* pointer to free pages */
+	void		*pdir;	/* pointer to the base page's dir */
+	size_t		size;	/* number of bytes free */
+};
+
+/*
+ * Magic values to put in the page_directory
+ */
+#define MALLOC_NOT_MINE	((struct pginfo*) 0)
+#define MALLOC_FREE	((struct pginfo*) 1)
+#define MALLOC_FIRST	((struct pginfo*) 2)
+#define MALLOC_FOLLOW	((struct pginfo*) 3)
+#define MALLOC_MAGIC	((struct pginfo*) 4)
+
+#ifndef malloc_minsize
+#define malloc_minsize			16UL
+#endif
+
+#if !defined(malloc_pagesize)
+#define malloc_pagesize			(1UL<<malloc_pageshift)
+#endif
+
+#if ((1UL<<malloc_pageshift) != malloc_pagesize)
+#error	"(1UL<<malloc_pageshift) != malloc_pagesize"
+#endif
+
+#ifndef malloc_maxsize
+#define malloc_maxsize			((malloc_pagesize)>>1)
+#endif
+
+/* A mask for the offset inside a page. */
+#define malloc_pagemask	((malloc_pagesize)-1)
+
+#define	pageround(foo)	(((foo) + (malloc_pagemask)) & ~malloc_pagemask)
+#define	ptr2index(foo)	(((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
+#define	index2ptr(idx)	((void*)(((idx)-malloc_pageshift)<<malloc_pageshift))
+
+/* Set when initialization has been done */
+static unsigned int	malloc_started;
+
+/* Number of free pages we cache */
+static unsigned int	malloc_cache = 16;
+
+/* Structure used for linking discrete directory pages. */
+struct pdinfo {
+	struct pginfo	**base;
+	struct pdinfo	*prev;
+	struct pdinfo	*next;
+	u_long		dirnum;
+};
+static struct pdinfo *last_dir;	/* Caches to the last and previous */
+static struct pdinfo *prev_dir;	/* referenced directory pages. */
+
+static size_t	pdi_off;
+static u_long	pdi_mod;
+#define	PD_IDX(num)	((num) / (malloc_pagesize/sizeof(struct pginfo *)))
+#define	PD_OFF(num)	((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1))
+#define	PI_IDX(index)	((index) / pdi_mod)
+#define	PI_OFF(index)	((index) % pdi_mod)
+
+/* The last index in the page directory we care about */
+static u_long	last_index;
+
+/* Pointer to page directory. Allocated "as if with" malloc */
+static struct pginfo **page_dir;
+
+/* Free pages line up here */
+static struct pgfree free_list;
+
+/* Abort(), user doesn't handle problems. */
+static int	malloc_abort = 2;
+
+/* Are we trying to die ? */
+static int	suicide;
+
+#ifdef MALLOC_STATS
+/* dump statistics */
+static int	malloc_stats;
+#endif
+
+/* avoid outputting warnings? */
+static int	malloc_silent;
+
+/* always realloc ? */
+static int	malloc_realloc;
+
+/* mprotect free pages PROT_NONE? */
+static int	malloc_freeprot;
+
+/* use guard pages after allocations? */
+static size_t	malloc_guard = 0;
+static size_t	malloc_guarded;
+/* align pointers to end of page? */
+static int	malloc_ptrguard;
+
+static int	malloc_hint = 1;
+
+/* xmalloc behaviour ? */
+static int	malloc_xmalloc;
+
+/* zero fill ? */
+static int	malloc_zero;
+
+/* junk fill ? */
+static int	malloc_junk;
+
+#ifdef __FreeBSD__
+/* utrace ? */
+static int	malloc_utrace;
+
+struct ut {
+	void		*p;
+	size_t		s;
+	void		*r;
+};
+
+void		utrace(struct ut *, int);
+
+#define UTRACE(a, b, c) \
+	if (malloc_utrace) \
+		{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
+#else				/* !__FreeBSD__ */
+#define UTRACE(a,b,c)
+#endif
+
+/* Status of malloc. */
+static int	malloc_active;
+
+/* Allocated memory. */
+static size_t	malloc_used;
+
+/* My last break. */
+static caddr_t	malloc_brk;
+
+/* One location cache for free-list holders. */
+static struct pgfree *px;
+
+/* Compile-time options. */
+char		*malloc_options;
+
+/* Name of the current public function. */
+static const char	*malloc_func;
+
+#define MMAP(size) \
+	mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
+	    -1, (off_t)0)
+
+/*
+ * Necessary function declarations.
+ */
+static void	*imalloc(size_t size);
+static void	ifree(void *ptr);
+static void	*irealloc(void *ptr, size_t size);
+static void	*malloc_bytes(size_t size);
+void *memalign(size_t boundary, size_t size);
+size_t malloc_good_size(size_t size);
+
+/*
+ * Function for page directory lookup.
+ */
+static int
+pdir_lookup(u_long index, struct pdinfo ** pdi)
+{
+	struct pdinfo	*spi;
+	u_long		pidx = PI_IDX(index);
+
+	if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx)
+		*pdi = last_dir;
+	else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx)
+		*pdi = prev_dir;
+	else if (last_dir != NULL && prev_dir != NULL) {
+		if ((PD_IDX(last_dir->dirnum) > pidx) ?
+		    (PD_IDX(last_dir->dirnum) - pidx) :
+		    (pidx - PD_IDX(last_dir->dirnum))
+		    < (PD_IDX(prev_dir->dirnum) > pidx) ?
+		    (PD_IDX(prev_dir->dirnum) - pidx) :
+		    (pidx - PD_IDX(prev_dir->dirnum)))
+			*pdi = last_dir;
+		else
+			*pdi = prev_dir;
+
+		if (PD_IDX((*pdi)->dirnum) > pidx) {
+			for (spi = (*pdi)->prev;
+			    spi != NULL && PD_IDX(spi->dirnum) > pidx;
+			    spi = spi->prev)
+				*pdi = spi;
+			if (spi != NULL)
+				*pdi = spi;
+		} else
+			for (spi = (*pdi)->next;
+			    spi != NULL && PD_IDX(spi->dirnum) <= pidx;
+			    spi = spi->next)
+				*pdi = spi;
+	} else {
+		*pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
+		for (spi = *pdi;
+		    spi != NULL && PD_IDX(spi->dirnum) <= pidx;
+		    spi = spi->next)
+			*pdi = spi;
+	}
+
+	return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
+	    (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
+}
+
+#ifdef MALLOC_STATS
+void
+malloc_dump(int fd)
+{
+	char		buf[1024];
+	struct pginfo	**pd;
+	struct pgfree	*pf;
+	struct pdinfo	*pi;
+	u_long		j;
+
+	pd = page_dir;
+	pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
+
+	/* print out all the pages */
+	for (j = 0; j <= last_index;) {
+		snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j);
+		write(fd, buf, strlen(buf));
+		if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
+			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
+				if (!PI_OFF(++j)) {
+					if ((pi = pi->next) == NULL ||
+					    PD_IDX(pi->dirnum) != PI_IDX(j))
+						break;
+					pd = pi->base;
+					j += pdi_mod;
+				}
+			}
+			j--;
+			snprintf(buf, sizeof buf, ".. %5lu not mine\n", j);
+			write(fd, buf, strlen(buf));
+		} else if (pd[PI_OFF(j)] == MALLOC_FREE) {
+			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
+				if (!PI_OFF(++j)) {
+					if ((pi = pi->next) == NULL ||
+					    PD_IDX(pi->dirnum) != PI_IDX(j))
+						break;
+					pd = pi->base;
+					j += pdi_mod;
+				}
+			}
+			j--;
+			snprintf(buf, sizeof buf, ".. %5lu free\n", j);
+			write(fd, buf, strlen(buf));
+		} else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
+			for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
+				if (!PI_OFF(++j)) {
+					if ((pi = pi->next) == NULL ||
+					    PD_IDX(pi->dirnum) != PI_IDX(j))
+						break;
+					pd = pi->base;
+					j += pdi_mod;
+				}
+			}
+			j--;
+			snprintf(buf, sizeof buf, ".. %5lu in use\n", j);
+			write(fd, buf, strlen(buf));
+		} else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
+			snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]);
+			write(fd, buf, strlen(buf));
+		} else {
+			snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n",
+			    pd[PI_OFF(j)], pd[PI_OFF(j)]->free,
+			    pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size,
+			    pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next);
+			write(fd, buf, strlen(buf));
+		}
+		if (!PI_OFF(++j)) {
+			if ((pi = pi->next) == NULL)
+				break;
+			pd = pi->base;
+			j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod;
+		}
+	}
+
+	for (pf = free_list.next; pf; pf = pf->next) {
+		snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
+		    pf, pf->page, (char *)pf->page + pf->size,
+		    pf->size, pf->prev, pf->next);
+		write(fd, buf, strlen(buf));
+		if (pf == pf->next) {
+			snprintf(buf, sizeof buf, "Free_list loops\n");
+			write(fd, buf, strlen(buf));
+			break;
+		}
+	}
+
+	/* print out various info */
+	snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize);
+	write(fd, buf, strlen(buf));
+	snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize);
+	write(fd, buf, strlen(buf));
+	snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize);
+	write(fd, buf, strlen(buf));
+	snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift);
+	write(fd, buf, strlen(buf));
+	snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used);
+	write(fd, buf, strlen(buf));
+	snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded);
+	write(fd, buf, strlen(buf));
+}
+#endif /* MALLOC_STATS */
+
+extern char	*__progname;
+
+static void
+wrterror(const char *p)
+{
+#ifndef BUILDING_FOR_TOR
+	const char		*q = " error: ";
+	struct iovec	iov[5];
+
+	iov[0].iov_base = __progname;
+	iov[0].iov_len = strlen(__progname);
+	iov[1].iov_base = (char*)malloc_func;
+	iov[1].iov_len = strlen(malloc_func);
+	iov[2].iov_base = (char*)q;
+	iov[2].iov_len = strlen(q);
+	iov[3].iov_base = (char*)p;
+	iov[3].iov_len = strlen(p);
+	iov[4].iov_base = (char*)"\n";
+	iov[4].iov_len = 1;
+	writev(STDERR_FILENO, iov, 5);
+#else
+        (void)p;
+#endif
+	suicide = 1;
+#ifdef MALLOC_STATS
+	if (malloc_stats)
+		malloc_dump(STDERR_FILENO);
+#endif /* MALLOC_STATS */
+	malloc_active--;
+	if (malloc_abort)
+		abort();
+}
+
+static void
+wrtwarning(const char *p)
+{
+#ifndef BUILDING_FOR_TOR
+	const char		*q = " warning: ";
+	struct iovec	iov[5];
+#endif
+
+	if (malloc_abort)
+		wrterror(p);
+	else if (malloc_silent)
+		return;
+
+#ifndef BUILDING_FOR_TOR
+	iov[0].iov_base = __progname;
+	iov[0].iov_len = strlen(__progname);
+	iov[1].iov_base = (char*)malloc_func;
+	iov[1].iov_len = strlen(malloc_func);
+	iov[2].iov_base = (char*)q;
+	iov[2].iov_len = strlen(q);
+	iov[3].iov_base = (char*)p;
+	iov[3].iov_len = strlen(p);
+	iov[4].iov_base = (char*)"\n";
+	iov[4].iov_len = 1;
+
+	(void) writev(STDERR_FILENO, iov, 5);
+#else
+        (void)p;
+#endif
+}
+
+#ifdef MALLOC_STATS
+static void
+malloc_exit(void)
+{
+	char	*q = "malloc() warning: Couldn't dump stats\n";
+	int	save_errno = errno, fd;
+
+	fd = open("malloc.out", O_RDWR|O_APPEND);
+	if (fd != -1) {
+		malloc_dump(fd);
+		close(fd);
+	} else
+		write(STDERR_FILENO, q, strlen(q));
+	errno = save_errno;
+}
+#endif /* MALLOC_STATS */
+
+/*
+ * Allocate aligned mmaped chunk
+ */
+
+static void *MMAP_A(size_t pages, size_t alignment)
+{
+	void *j, *p;
+	size_t first_size, rest, begin, end;
+	if (pages%malloc_pagesize != 0)
+		pages = pages - pages%malloc_pagesize + malloc_pagesize;
+	first_size = pages + alignment - malloc_pagesize;
+	p = MMAP(first_size);
+	rest = ((size_t)p) % alignment;
+	j = (rest == 0) ? p : (void*) ((size_t)p + alignment - rest);
+	begin = (size_t)j - (size_t)p;
+	if (begin != 0) munmap(p, begin);
+	end = (size_t)p + first_size - ((size_t)j + pages);
+	if(end != 0) munmap( (void*) ((size_t)j + pages), end);
+
+	return j;
+}
+
+
+/*
+ * Allocate a number of pages from the OS
+ */
+static void *
+map_pages(size_t pages)
+{
+	struct pdinfo	*pi, *spi;
+	struct pginfo	**pd;
+	u_long		idx, pidx, lidx;
+	caddr_t		result, tail;
+	u_long		index, lindex;
+	void 		*pdregion = NULL;
+	size_t		dirs, cnt;
+
+	pages <<= malloc_pageshift;
+	if (!align)
+		result = MMAP(pages + malloc_guard);
+	else {
+		result = MMAP_A(pages + malloc_guard, g_alignment);
+	}
+	if (result == MAP_FAILED) {
+#ifdef MALLOC_EXTRA_SANITY
+		wrtwarning("(ES): map_pages fails");
+#endif /* MALLOC_EXTRA_SANITY */
+		errno = ENOMEM;
+		return (NULL);
+	}
+	index = ptr2index(result);
+	tail = result + pages + malloc_guard;
+	lindex = ptr2index(tail) - 1;
+	if (malloc_guard)
+		mprotect(result + pages, malloc_guard, PROT_NONE);
+
+	pidx = PI_IDX(index);
+	lidx = PI_IDX(lindex);
+
+	if (tail > malloc_brk) {
+		malloc_brk = tail;
+		last_index = lindex;
+	}
+
+	dirs = lidx - pidx;
+
+	/* Insert directory pages, if needed. */
+	if (pdir_lookup(index, &pi) != 0)
+		dirs++;
+
+	if (dirs > 0) {
+		pdregion = MMAP(malloc_pagesize * dirs);
+		if (pdregion == MAP_FAILED) {
+			munmap(result, tail - result);
+#ifdef MALLOC_EXTRA_SANITY
+		wrtwarning("(ES): map_pages fails");
+#endif
+			errno = ENOMEM;
+			return (NULL);
+		}
+	}
+
+	cnt = 0;
+	for (idx = pidx, spi = pi; idx <= lidx; idx++) {
+		if (pi == NULL || PD_IDX(pi->dirnum) != idx) {
+			pd = (struct pginfo **)((char *)pdregion +
+			    cnt * malloc_pagesize);
+			cnt++;
+			memset(pd, 0, malloc_pagesize);
+			pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
+			pi->base = pd;
+			pi->prev = spi;
+			pi->next = spi->next;
+			pi->dirnum = idx * (malloc_pagesize /
+			    sizeof(struct pginfo *));
+
+			if (spi->next != NULL)
+				spi->next->prev = pi;
+			spi->next = pi;
+		}
+		if (idx > pidx && idx < lidx) {
+			pi->dirnum += pdi_mod;
+		} else if (idx == pidx) {
+			if (pidx == lidx) {
+				pi->dirnum += (u_long)(tail - result) >>
+				    malloc_pageshift;
+			} else {
+				pi->dirnum += pdi_mod - PI_OFF(index);
+			}
+		} else {
+			pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
+		}
+#ifdef MALLOC_EXTRA_SANITY
+		if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > idx) {
+			wrterror("(ES): pages directory overflow");
+			errno = EFAULT;
+			return (NULL);
+		}
+#endif /* MALLOC_EXTRA_SANITY */
+		if (idx == pidx && pi != last_dir) {
+			prev_dir = last_dir;
+			last_dir = pi;
+		}
+		spi = pi;
+		pi = spi->next;
+	}
+#ifdef MALLOC_EXTRA_SANITY
+	if (cnt > dirs)
+		wrtwarning("(ES): cnt > dirs");
+#endif /* MALLOC_EXTRA_SANITY */
+	if (cnt < dirs)
+		munmap((char *)pdregion + cnt * malloc_pagesize,
+		    (dirs - cnt) * malloc_pagesize);
+
+	return (result);
+}
+
+/*
+ * Initialize the world
+ */
+static void
+malloc_init(void)
+{
+	char		*p, b[64];
+	int		i, j, save_errno = errno;
+
+	_MALLOC_LOCK_INIT();
+
+#ifdef MALLOC_EXTRA_SANITY
+	malloc_junk = 1;
+#endif /* MALLOC_EXTRA_SANITY */
+
+	for (i = 0; i < 3; i++) {
+		switch (i) {
+		case 0:
+			j = (int) readlink("/etc/malloc.conf", b, sizeof b - 1);
+			if (j <= 0)
+				continue;
+			b[j] = '\0';
+			p = b;
+			break;
+		case 1:
+			if (issetugid() == 0)
+				p = getenv("MALLOC_OPTIONS");
+			else
+				continue;
+			break;
+		case 2:
+			p = malloc_options;
+			break;
+		default:
+			p = NULL;
+		}
+
+		for (; p != NULL && *p != '\0'; p++) {
+			switch (*p) {
+			case '>':
+				malloc_cache <<= 1;
+				break;
+			case '<':
+				malloc_cache >>= 1;
+				break;
+			case 'a':
+				malloc_abort = 0;
+				break;
+			case 'A':
+				malloc_abort = 1;
+				break;
+#ifdef MALLOC_STATS
+			case 'd':
+				malloc_stats = 0;
+				break;
+			case 'D':
+				malloc_stats = 1;
+				break;
+#endif /* MALLOC_STATS */
+			case 'f':
+				malloc_freeprot = 0;
+				break;
+			case 'F':
+				malloc_freeprot = 1;
+				break;
+			case 'g':
+				malloc_guard = 0;
+				break;
+			case 'G':
+				malloc_guard = malloc_pagesize;
+				break;
+			case 'h':
+				malloc_hint = 0;
+				break;
+			case 'H':
+				malloc_hint = 1;
+				break;
+			case 'j':
+				malloc_junk = 0;
+				break;
+			case 'J':
+				malloc_junk = 1;
+				break;
+			case 'n':
+				malloc_silent = 0;
+				break;
+			case 'N':
+				malloc_silent = 1;
+				break;
+			case 'p':
+				malloc_ptrguard = 0;
+				break;
+			case 'P':
+				malloc_ptrguard = 1;
+				break;
+			case 'r':
+				malloc_realloc = 0;
+				break;
+			case 'R':
+				malloc_realloc = 1;
+				break;
+#ifdef __FreeBSD__
+			case 'u':
+				malloc_utrace = 0;
+				break;
+			case 'U':
+				malloc_utrace = 1;
+				break;
+#endif /* __FreeBSD__ */
+			case 'x':
+				malloc_xmalloc = 0;
+				break;
+			case 'X':
+				malloc_xmalloc = 1;
+				break;
+			case 'z':
+				malloc_zero = 0;
+				break;
+			case 'Z':
+				malloc_zero = 1;
+				break;
+			default:
+				j = malloc_abort;
+				malloc_abort = 0;
+				wrtwarning("unknown char in MALLOC_OPTIONS");
+				malloc_abort = j;
+				break;
+			}
+		}
+	}
+
+	UTRACE(0, 0, 0);
+
+	/*
+	 * We want junk in the entire allocation, and zero only in the part
+	 * the user asked for.
+	 */
+	if (malloc_zero)
+		malloc_junk = 1;
+
+#ifdef MALLOC_STATS
+	if (malloc_stats && (atexit(malloc_exit) == -1))
+		wrtwarning("atexit(2) failed."
+		    "  Will not be able to dump malloc stats on exit");
+#endif /* MALLOC_STATS */
+
+	if (malloc_pagesize != getpagesize()) {
+		wrterror("malloc() replacement compiled with a different "
+			 "page size from what we're running with.  Failing.");
+		errno = ENOMEM;
+		return;
+	}
+
+	/* Allocate one page for the page directory. */
+	page_dir = (struct pginfo **)MMAP(malloc_pagesize);
+
+	if (page_dir == MAP_FAILED) {
+		wrterror("mmap(2) failed, check limits");
+		errno = ENOMEM;
+		return;
+	}
+	pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
+	pdi_mod = pdi_off / sizeof(struct pginfo *);
+
+	last_dir = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
+	last_dir->base = page_dir;
+	last_dir->prev = last_dir->next = NULL;
+	last_dir->dirnum = malloc_pageshift;
+
+	/* Been here, done that. */
+	malloc_started++;
+
+	/* Recalculate the cache size in bytes, and make sure it's nonzero. */
+	if (!malloc_cache)
+		malloc_cache++;
+	malloc_cache <<= malloc_pageshift;
+	errno = save_errno;
+}
+
+/*
+ * Allocate a number of complete pages
+ */
+static void *
+malloc_pages(size_t size)
+{
+	void		*p, *delay_free = NULL, *tp;
+	size_t		i;
+	struct pginfo	**pd;
+	struct pdinfo	*pi;
+	u_long		pidx, index;
+	struct pgfree	*pf;
+
+	size = pageround(size) + malloc_guard;
+
+	p = NULL;
+	/* Look for free pages before asking for more */
+	if (!align)
+	for (pf = free_list.next; pf; pf = pf->next) {
+
+#ifdef MALLOC_EXTRA_SANITY
+		if (pf->size & malloc_pagemask) {
+			wrterror("(ES): junk length entry on free_list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		if (!pf->size) {
+			wrterror("(ES): zero length entry on free_list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		if (pf->page > (pf->page + pf->size)) {
+			wrterror("(ES): sick entry on free_list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		if ((pi = pf->pdir) == NULL) {
+			wrterror("(ES): invalid page directory on free-list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) {
+			wrterror("(ES): directory index mismatch on free-list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		pd = pi->base;
+		if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) {
+			wrterror("(ES): non-free first page on free-list");
+			errno = EFAULT;
+			return (NULL);
+		}
+		pidx = PI_IDX(ptr2index((pf->page) + (pf->size)) - 1);
+		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
+		    pi = pi->next)
+			;
+		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+			wrterror("(ES): last page not referenced in page directory");
+			errno = EFAULT;
+			return (NULL);
+		}
+		pd = pi->base;
+		if (pd[PI_OFF(ptr2index((pf->page) + (pf->size)) - 1)] != MALLOC_FREE) {
+			wrterror("(ES): non-free last page on free-list");
+			errno = EFAULT;
+			return (NULL);
+		}
+#endif /* MALLOC_EXTRA_SANITY */
+
+		if (pf->size < size)
+			continue;
+
+		if (pf->size == size) {
+			p = pf->page;
+			pi = pf->pdir;
+			if (pf->next != NULL)
+				pf->next->prev = pf->prev;
+			pf->prev->next = pf->next;
+			delay_free = pf;
+			break;
+		}
+		p = pf->page;
+		pf->page = (char *) pf->page + size;
+		pf->size -= size;
+		pidx = PI_IDX(ptr2index(pf->page));
+		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
+		    pi = pi->next)
+			;
+		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+			wrterror("(ES): hole in directories");
+			errno = EFAULT;
+			return (NULL);
+		}
+		tp = pf->pdir;
+		pf->pdir = pi;
+		pi = tp;
+		break;
+	}
+
+	size -= malloc_guard;
+
+#ifdef MALLOC_EXTRA_SANITY
+	if (p != NULL && pi != NULL) {
+		pidx = PD_IDX(pi->dirnum);
+		pd = pi->base;
+	}
+	if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) {
+		wrterror("(ES): allocated non-free page on free-list");
+		errno = EFAULT;
+		return (NULL);
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+
+	if (p != NULL && (malloc_guard || malloc_freeprot))
+		mprotect(p, size, PROT_READ | PROT_WRITE);
+
+	size >>= malloc_pageshift;
+
+	/* Map new pages */
+	if (p == NULL)
+		p = map_pages(size);
+
+	if (p != NULL) {
+		index = ptr2index(p);
+		pidx = PI_IDX(index);
+		pdir_lookup(index, &pi);
+#ifdef MALLOC_EXTRA_SANITY
+		if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+			wrterror("(ES): mapped pages not found in directory");
+			errno = EFAULT;
+			return (NULL);
+		}
+#endif /* MALLOC_EXTRA_SANITY */
+		if (pi != last_dir) {
+			prev_dir = last_dir;
+			last_dir = pi;
+		}
+		pd = pi->base;
+		pd[PI_OFF(index)] = MALLOC_FIRST;
+
+		for (i = 1; i < size; i++) {
+			if (!PI_OFF(index + i)) {
+				pidx++;
+				pi = pi->next;
+#ifdef MALLOC_EXTRA_SANITY
+				if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+					wrterror("(ES): hole in mapped pages directory");
+					errno = EFAULT;
+					return (NULL);
+				}
+#endif /* MALLOC_EXTRA_SANITY */
+				pd = pi->base;
+			}
+			pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
+		}
+		if (malloc_guard) {
+			if (!PI_OFF(index + i)) {
+				pidx++;
+				pi = pi->next;
+#ifdef MALLOC_EXTRA_SANITY
+				if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+					wrterror("(ES): hole in mapped pages directory");
+					errno = EFAULT;
+					return (NULL);
+				}
+#endif /* MALLOC_EXTRA_SANITY */
+				pd = pi->base;
+			}
+			pd[PI_OFF(index + i)] = MALLOC_FIRST;
+		}
+
+		malloc_used += size << malloc_pageshift;
+		malloc_guarded += malloc_guard;
+
+		if (malloc_junk)
+			memset(p, SOME_JUNK, size << malloc_pageshift);
+	}
+	if (delay_free) {
+		if (px == NULL)
+			px = delay_free;
+		else
+			ifree(delay_free);
+	}
+	return (p);
+}
+
+/*
+ * Allocate a page of fragments
+ */
+
+static __inline__ int
+malloc_make_chunks(int bits)
+{
+	struct pginfo	*bp, **pd;
+	struct pdinfo	*pi;
+#ifdef	MALLOC_EXTRA_SANITY
+	u_long		pidx;
+#endif	/* MALLOC_EXTRA_SANITY */
+	void		*pp;
+	long		i, k;
+	size_t		l;
+
+	/* Allocate a new bucket */
+	pp = malloc_pages((size_t) malloc_pagesize);
+	if (pp == NULL)
+		return (0);
+
+	/* Find length of admin structure */
+	l = sizeof *bp - sizeof(u_long);
+	l += sizeof(u_long) *
+	    (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
+
+	/* Don't waste more than two chunks on this */
+
+	/*
+	 * If we are to allocate a memory protected page for the malloc(0)
+	 * case (when bits=0), it must be from a different page than the
+	 * pginfo page.
+	 * --> Treat it like the big chunk alloc, get a second data page.
+	 */
+	if (bits != 0 && (1UL << (bits)) <= l + l) {
+		bp = (struct pginfo *) pp;
+	} else {
+		bp = (struct pginfo *) imalloc(l);
+		if (bp == NULL) {
+			ifree(pp);
+			return (0);
+		}
+	}
+
+	/* memory protect the page allocated in the malloc(0) case */
+	if (bits == 0) {
+		bp->size = 0;
+		bp->shift = 1;
+		i = malloc_minsize - 1;
+		while (i >>= 1)
+			bp->shift++;
+		bp->total = bp->free = malloc_pagesize >> bp->shift;
+		bp->page = pp;
+
+		k = mprotect(pp, malloc_pagesize, PROT_NONE);
+		if (k < 0) {
+			ifree(pp);
+			ifree(bp);
+			return (0);
+		}
+	} else {
+		bp->size = (1UL << bits);
+		bp->shift = bits;
+		bp->total = bp->free = malloc_pagesize >> bits;
+		bp->page = pp;
+	}
+
+	/* set all valid bits in the bitmap */
+	k = bp->total;
+	i = 0;
+
+	/* Do a bunch at a time */
+	for (; (k - i) >= MALLOC_BITS; i += MALLOC_BITS)
+		bp->bits[i / MALLOC_BITS] = ~0UL;
+
+	for (; i < k; i++)
+		bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
+
+	k = (long)l;
+	if (bp == bp->page) {
+		/* Mark the ones we stole for ourselves */
+		for (i = 0; k > 0; i++) {
+			bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS));
+			bp->free--;
+			bp->total--;
+			k -= (1 << bits);
+		}
+	}
+	/* MALLOC_LOCK */
+
+	pdir_lookup(ptr2index(pp), &pi);
+#ifdef MALLOC_EXTRA_SANITY
+	pidx = PI_IDX(ptr2index(pp));
+	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+		wrterror("(ES): mapped pages not found in directory");
+		errno = EFAULT;
+		return (0);
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+	if (pi != last_dir) {
+		prev_dir = last_dir;
+		last_dir = pi;
+	}
+	pd = pi->base;
+	pd[PI_OFF(ptr2index(pp))] = bp;
+
+	bp->next = page_dir[bits];
+	page_dir[bits] = bp;
+
+	/* MALLOC_UNLOCK */
+	return (1);
+}
+
+/*
+ * Allocate a fragment
+ */
+static void *
+malloc_bytes(size_t size)
+{
+	int		i, j;
+	size_t		k;
+	u_long		u, *lp;
+	struct pginfo	*bp;
+
+	/* Don't bother with anything less than this */
+	/* unless we have a malloc(0) requests */
+	if (size != 0 && size < malloc_minsize)
+		size = malloc_minsize;
+
+	/* Find the right bucket */
+	if (size == 0)
+		j = 0;
+	else {
+		size_t ii;
+		j = 1;
+		ii = size - 1;
+		while (ii >>= 1)
+			j++;
+	}
+
+	/* If it's empty, make a page more of that size chunks */
+	if (page_dir[j] == NULL && !malloc_make_chunks(j))
+		return (NULL);
+
+	bp = page_dir[j];
+
+	/* Find first word of bitmap which isn't empty */
+	for (lp = bp->bits; !*lp; lp++);
+
+	/* Find that bit, and tweak it */
+	u = 1;
+	k = 0;
+	while (!(*lp & u)) {
+		u += u;
+		k++;
+	}
+
+	if (malloc_guard) {
+		/* Walk to a random position. */
+//		i = arc4random() % bp->free;
+		i = rand() % bp->free;
+		while (i > 0) {
+			u += u;
+			k++;
+			if (k >= MALLOC_BITS) {
+				lp++;
+				u = 1;
+				k = 0;
+			}
+#ifdef MALLOC_EXTRA_SANITY
+			if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) {
+				wrterror("chunk overflow");
+				errno = EFAULT;
+				return (NULL);
+			}
+#endif /* MALLOC_EXTRA_SANITY */
+			if (*lp & u)
+				i--;
+		}
+	}
+	*lp ^= u;
+
+	/* If there are no more free, remove from free-list */
+	if (!--bp->free) {
+		page_dir[j] = bp->next;
+		bp->next = NULL;
+	}
+	/* Adjust to the real offset of that chunk */
+	k += (lp - bp->bits) * MALLOC_BITS;
+	k <<= bp->shift;
+
+	if (malloc_junk && bp->size != 0)
+		memset((char *)bp->page + k, SOME_JUNK, (size_t)bp->size);
+
+	return ((u_char *) bp->page + k);
+}
+
+/*
+ * Magic so that malloc(sizeof(ptr)) is near the end of the page.
+ */
+#define	PTR_GAP		(malloc_pagesize - sizeof(void *))
+#define	PTR_SIZE	(sizeof(void *))
+#define	PTR_ALIGNED(p)	(((unsigned long)p & malloc_pagemask) == PTR_GAP)
+
+/*
+ * Allocate a piece of memory
+ */
+static void *
+imalloc(size_t size)
+{
+	void		*result;
+	int		ptralloc = 0;
+
+	if (!malloc_started)
+		malloc_init();
+
+	if (suicide)
+		abort();
+
+	/* does not matter if malloc_bytes fails */
+	if (px == NULL)
+		px = malloc_bytes(sizeof *px);
+
+	if (malloc_ptrguard && size == PTR_SIZE) {
+		ptralloc = 1;
+		size = malloc_pagesize;
+	}
+	if (size > SIZE_MAX - malloc_pagesize) { /* Check for overflow */
+		result = NULL;
+		errno = ENOMEM;
+	} else if (size <= malloc_maxsize)
+		result = malloc_bytes(size);
+	else
+		result = malloc_pages(size);
+
+	if (malloc_abort == 1 && result == NULL)
+		wrterror("allocation failed");
+
+	if (malloc_zero && result != NULL)
+		memset(result, 0, size);
+
+	if (result && ptralloc)
+		return ((char *) result + PTR_GAP);
+	return (result);
+}
+
+/*
+ * Change the size of an allocation.
+ */
+static void *
+irealloc(void *ptr, size_t size)
+{
+	void		*p;
+	size_t		osize;
+	u_long		index, i;
+	struct pginfo	**mp;
+	struct pginfo	**pd;
+	struct pdinfo	*pi;
+#ifdef	MALLOC_EXTRA_SANITY
+	u_long		pidx;
+#endif	/* MALLOC_EXTRA_SANITY */
+
+	if (suicide)
+		abort();
+
+	if (!malloc_started) {
+		wrtwarning("malloc() has never been called");
+		return (NULL);
+	}
+	if (malloc_ptrguard && PTR_ALIGNED(ptr)) {
+		if (size <= PTR_SIZE)
+			return (ptr);
+
+		p = imalloc(size);
+		if (p)
+			memcpy(p, ptr, PTR_SIZE);
+		ifree(ptr);
+		return (p);
+	}
+	index = ptr2index(ptr);
+
+	if (index < malloc_pageshift) {
+		wrtwarning("junk pointer, too low to make sense");
+		return (NULL);
+	}
+	if (index > last_index) {
+		wrtwarning("junk pointer, too high to make sense");
+		return (NULL);
+	}
+	pdir_lookup(index, &pi);
+#ifdef MALLOC_EXTRA_SANITY
+	pidx = PI_IDX(index);
+	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+		wrterror("(ES): mapped pages not found in directory");
+		errno = EFAULT;
+		return (NULL);
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+	if (pi != last_dir) {
+		prev_dir = last_dir;
+		last_dir = pi;
+	}
+	pd = pi->base;
+	mp = &pd[PI_OFF(index)];
+
+	if (*mp == MALLOC_FIRST) {	/* Page allocation */
+
+		/* Check the pointer */
+		if ((u_long) ptr & malloc_pagemask) {
+			wrtwarning("modified (page-) pointer");
+			return (NULL);
+		}
+		/* Find the size in bytes */
+		i = index;
+		if (!PI_OFF(++i)) {
+			pi = pi->next;
+			if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
+				pi = NULL;
+			if (pi != NULL)
+				pd = pi->base;
+		}
+		for (osize = malloc_pagesize;
+		    pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) {
+			osize += malloc_pagesize;
+			if (!PI_OFF(++i)) {
+				pi = pi->next;
+				if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
+					pi = NULL;
+				if (pi != NULL)
+					pd = pi->base;
+			}
+		}
+
+		if (!malloc_realloc && size <= osize &&
+		    size > osize - malloc_pagesize) {
+			if (malloc_junk)
+				memset((char *)ptr + size, SOME_JUNK, osize - size);
+			return (ptr);	/* ..don't do anything else. */
+		}
+	} else if (*mp >= MALLOC_MAGIC) {	/* Chunk allocation */
+
+		/* Check the pointer for sane values */
+		if ((u_long) ptr & ((1UL << ((*mp)->shift)) - 1)) {
+			wrtwarning("modified (chunk-) pointer");
+			return (NULL);
+		}
+		/* Find the chunk index in the page */
+		i = ((u_long) ptr & malloc_pagemask) >> (*mp)->shift;
+
+		/* Verify that it isn't a free chunk already */
+		if ((*mp)->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
+			wrtwarning("chunk is already free");
+			return (NULL);
+		}
+		osize = (*mp)->size;
+
+		if (!malloc_realloc && size <= osize &&
+		    (size > osize / 2 || osize == malloc_minsize)) {
+			if (malloc_junk)
+				memset((char *) ptr + size, SOME_JUNK, osize - size);
+			return (ptr);	/* ..don't do anything else. */
+		}
+	} else {
+		wrtwarning("irealloc: pointer to wrong page");
+		return (NULL);
+	}
+
+	p = imalloc(size);
+
+	if (p != NULL) {
+		/* copy the lesser of the two sizes, and free the old one */
+		/* Don't move from/to 0 sized region !!! */
+		if (osize != 0 && size != 0) {
+			if (osize < size)
+				memcpy(p, ptr, osize);
+			else
+				memcpy(p, ptr, size);
+		}
+		ifree(ptr);
+	}
+	return (p);
+}
+
+/*
+ * Free a sequence of pages
+ */
+static __inline__ void
+free_pages(void *ptr, u_long index, struct pginfo * info)
+{
+	u_long		i, pidx, lidx;
+	size_t		l, cachesize = 0;
+	struct pginfo	**pd;
+	struct pdinfo	*pi, *spi;
+	struct pgfree	*pf, *pt = NULL;
+	caddr_t		tail;
+
+	if (info == MALLOC_FREE) {
+		wrtwarning("page is already free");
+		return;
+	}
+	if (info != MALLOC_FIRST) {
+		wrtwarning("free_pages: pointer to wrong page");
+		return;
+	}
+	if ((u_long) ptr & malloc_pagemask) {
+		wrtwarning("modified (page-) pointer");
+		return;
+	}
+	/* Count how many pages and mark them free at the same time */
+	pidx = PI_IDX(index);
+	pdir_lookup(index, &pi);
+#ifdef MALLOC_EXTRA_SANITY
+	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+		wrterror("(ES): mapped pages not found in directory");
+		errno = EFAULT;
+		return;
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+
+	spi = pi;		/* Save page index for start of region. */
+
+	pd = pi->base;
+	pd[PI_OFF(index)] = MALLOC_FREE;
+	i = 1;
+	if (!PI_OFF(index + i)) {
+		pi = pi->next;
+		if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i))
+			pi = NULL;
+		else
+			pd = pi->base;
+	}
+	while (pi != NULL && pd[PI_OFF(index + i)] == MALLOC_FOLLOW) {
+		pd[PI_OFF(index + i)] = MALLOC_FREE;
+		i++;
+		if (!PI_OFF(index + i)) {
+			if ((pi = pi->next) == NULL ||
+			    PD_IDX(pi->dirnum) != PI_IDX(index + i))
+				pi = NULL;
+			else
+				pd = pi->base;
+		}
+	}
+
+	l = i << malloc_pageshift;
+
+	if (malloc_junk)
+		memset(ptr, SOME_JUNK, l);
+
+	malloc_used -= l;
+	malloc_guarded -= malloc_guard;
+	if (malloc_guard) {
+#ifdef MALLOC_EXTRA_SANITY
+		if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i)) {
+			wrterror("(ES): hole in mapped pages directory");
+			errno = EFAULT;
+			return;
+		}
+#endif /* MALLOC_EXTRA_SANITY */
+		pd[PI_OFF(index + i)] = MALLOC_FREE;
+		l += malloc_guard;
+	}
+	tail = (caddr_t)ptr + l;
+
+	if (malloc_hint)
+		madvise(ptr, l, MADV_FREE);
+
+	if (malloc_freeprot)
+		mprotect(ptr, l, PROT_NONE);
+
+	/* Add to free-list. */
+	if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL)
+			goto not_return;
+	px->page = ptr;
+	px->pdir = spi;
+	px->size = l;
+
+	if (free_list.next == NULL) {
+		/* Nothing on free list, put this at head. */
+		px->next = NULL;
+		px->prev = &free_list;
+		free_list.next = px;
+		pf = px;
+		px = NULL;
+	} else {
+		/*
+		 * Find the right spot, leave pf pointing to the modified
+		 * entry.
+		 */
+
+		/* Race ahead here, while calculating cache size. */
+		for (pf = free_list.next;
+		    (caddr_t)ptr > ((caddr_t)pf->page + pf->size)
+		    && pf->next != NULL;
+		    pf = pf->next)
+			cachesize += pf->size;
+
+		/* Finish cache size calculation. */
+		pt = pf;
+		while (pt) {
+			cachesize += pt->size;
+			pt = pt->next;
+		}
+
+		if ((caddr_t)pf->page > tail) {
+			/* Insert before entry */
+			px->next = pf;
+			px->prev = pf->prev;
+			pf->prev = px;
+			px->prev->next = px;
+			pf = px;
+			px = NULL;
+		} else if (((caddr_t)pf->page + pf->size) == ptr) {
+			/* Append to the previous entry. */
+			cachesize -= pf->size;
+			pf->size += l;
+			if (pf->next != NULL &&
+			    pf->next->page == ((caddr_t)pf->page + pf->size)) {
+				/* And collapse the next too. */
+				pt = pf->next;
+				pf->size += pt->size;
+				pf->next = pt->next;
+				if (pf->next != NULL)
+					pf->next->prev = pf;
+			}
+		} else if (pf->page == tail) {
+			/* Prepend to entry. */
+			cachesize -= pf->size;
+			pf->size += l;
+			pf->page = ptr;
+			pf->pdir = spi;
+		} else if (pf->next == NULL) {
+			/* Append at tail of chain. */
+			px->next = NULL;
+			px->prev = pf;
+			pf->next = px;
+			pf = px;
+			px = NULL;
+		} else {
+			wrterror("freelist is destroyed");
+			errno = EFAULT;
+			return;
+		}
+	}
+
+	if (pf->pdir != last_dir) {
+		prev_dir = last_dir;
+		last_dir = pf->pdir;
+	}
+
+	/* Return something to OS ? */
+	if (pf->size > (malloc_cache - cachesize)) {
+
+		/*
+		 * Keep the cache intact.  Notice that the '>' above guarantees that
+		 * the pf will always have at least one page afterwards.
+		 */
+		if (munmap((char *) pf->page + (malloc_cache - cachesize),
+		    pf->size - (malloc_cache - cachesize)) != 0)
+			goto not_return;
+		tail = (caddr_t)pf->page + pf->size;
+		lidx = ptr2index(tail) - 1;
+		pf->size = malloc_cache - cachesize;
+
+		index = ptr2index((caddr_t)pf->page + pf->size);
+
+		pidx = PI_IDX(index);
+		if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) >= pidx)
+			prev_dir = NULL;	/* Will be wiped out below ! */
+
+		for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
+		    pi = pi->next)
+			;
+
+		spi = pi;
+		if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
+			pd = pi->base;
+
+			for (i = index; i <= lidx;) {
+				if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) {
+					pd[PI_OFF(i)] = MALLOC_NOT_MINE;
+#ifdef MALLOC_EXTRA_SANITY
+					if (!PD_OFF(pi->dirnum)) {
+						wrterror("(ES): pages directory underflow");
+						errno = EFAULT;
+						return;
+					}
+#endif /* MALLOC_EXTRA_SANITY */
+					pi->dirnum--;
+				}
+#ifdef MALLOC_EXTRA_SANITY
+				else
+					wrtwarning("(ES): page already unmapped");
+#endif /* MALLOC_EXTRA_SANITY */
+				i++;
+				if (!PI_OFF(i)) {
+					/*
+					 * If no page in that dir, free
+					 * directory page.
+					 */
+					if (!PD_OFF(pi->dirnum)) {
+						/* Remove from list. */
+						if (spi == pi)
+							spi = pi->prev;
+						if (pi->prev != NULL)
+							pi->prev->next = pi->next;
+						if (pi->next != NULL)
+							pi->next->prev = pi->prev;
+						pi = pi->next;
+						munmap(pd, malloc_pagesize);
+					} else
+						pi = pi->next;
+					if (pi == NULL ||
+					    PD_IDX(pi->dirnum) != PI_IDX(i))
+						break;
+					pd = pi->base;
+				}
+			}
+			if (pi && !PD_OFF(pi->dirnum)) {
+				/* Resulting page dir is now empty. */
+				/* Remove from list. */
+				if (spi == pi)	/* Update spi only if first. */
+					spi = pi->prev;
+				if (pi->prev != NULL)
+					pi->prev->next = pi->next;
+				if (pi->next != NULL)
+					pi->next->prev = pi->prev;
+				pi = pi->next;
+				munmap(pd, malloc_pagesize);
+			}
+		}
+		if (pi == NULL && malloc_brk == tail) {
+			/* Resize down the malloc upper boundary. */
+			last_index = index - 1;
+			malloc_brk = index2ptr(index);
+		}
+
+		/* XXX: We could realloc/shrink the pagedir here I guess. */
+		if (pf->size == 0) {	/* Remove from free-list as well. */
+			if (px)
+				ifree(px);
+			if ((px = pf->prev) != &free_list) {
+				if (pi == NULL && last_index == (index - 1)) {
+					if (spi == NULL) {
+						malloc_brk = NULL;
+						i = 11;
+					} else {
+						pd = spi->base;
+						if (PD_IDX(spi->dirnum) < pidx)
+							index =
+							    ((PD_IDX(spi->dirnum) + 1) *
+							    pdi_mod) - 1;
+						for (pi = spi, i = index;
+						    pd[PI_OFF(i)] == MALLOC_NOT_MINE;
+						    i--)
+#ifdef MALLOC_EXTRA_SANITY
+							if (!PI_OFF(i)) {
+								pi = pi->prev;
+								if (pi == NULL || i == 0)
+									break;
+								pd = pi->base;
+								i = (PD_IDX(pi->dirnum) + 1) * pdi_mod;
+							}
+#else /* !MALLOC_EXTRA_SANITY */
+						{
+						}
+#endif /* MALLOC_EXTRA_SANITY */
+						malloc_brk = index2ptr(i + 1);
+					}
+					last_index = i;
+				}
+				if ((px->next = pf->next) != NULL)
+					px->next->prev = px;
+			} else {
+				if ((free_list.next = pf->next) != NULL)
+					free_list.next->prev = &free_list;
+			}
+			px = pf;
+			last_dir = prev_dir;
+			prev_dir = NULL;
+		}
+	}
+not_return:
+	if (pt != NULL)
+		ifree(pt);
+}
+
+/*
+ * Free a chunk, and possibly the page it's on, if the page becomes empty.
+ */
+
+/* ARGSUSED */
+static __inline__ void
+free_bytes(void *ptr, u_long index, struct pginfo * info)
+{
+	struct pginfo	**mp, **pd;
+	struct pdinfo	*pi;
+#ifdef	MALLOC_EXTRA_SANITY
+	u_long		pidx;
+#endif	/* MALLOC_EXTRA_SANITY */
+	void		*vp;
+	long		i;
+	(void) index;
+
+	/* Find the chunk number on the page */
+	i = ((u_long) ptr & malloc_pagemask) >> info->shift;
+
+	if ((u_long) ptr & ((1UL << (info->shift)) - 1)) {
+		wrtwarning("modified (chunk-) pointer");
+		return;
+	}
+	if (info->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
+		wrtwarning("chunk is already free");
+		return;
+	}
+	if (malloc_junk && info->size != 0)
+		memset(ptr, SOME_JUNK, (size_t)info->size);
+
+	info->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
+	info->free++;
+
+	if (info->size != 0)
+		mp = page_dir + info->shift;
+	else
+		mp = page_dir;
+
+	if (info->free == 1) {
+		/* Page became non-full */
+
+		/* Insert in address order */
+		while (*mp != NULL && (*mp)->next != NULL &&
+		    (*mp)->next->page < info->page)
+			mp = &(*mp)->next;
+		info->next = *mp;
+		*mp = info;
+		return;
+	}
+	if (info->free != info->total)
+		return;
+
+	/* Find & remove this page in the queue */
+	while (*mp != info) {
+		mp = &((*mp)->next);
+#ifdef MALLOC_EXTRA_SANITY
+		if (!*mp) {
+			wrterror("(ES): Not on queue");
+			errno = EFAULT;
+			return;
+		}
+#endif /* MALLOC_EXTRA_SANITY */
+	}
+	*mp = info->next;
+
+	/* Free the page & the info structure if need be */
+	pdir_lookup(ptr2index(info->page), &pi);
+#ifdef MALLOC_EXTRA_SANITY
+	pidx = PI_IDX(ptr2index(info->page));
+	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+		wrterror("(ES): mapped pages not found in directory");
+		errno = EFAULT;
+		return;
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+	if (pi != last_dir) {
+		prev_dir = last_dir;
+		last_dir = pi;
+	}
+	pd = pi->base;
+	pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
+
+	/* If the page was mprotected, unprotect it before releasing it */
+	if (info->size == 0)
+		mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE);
+
+	vp = info->page;	/* Order is important ! */
+	if (vp != (void *) info)
+		ifree(info);
+	ifree(vp);
+}
+
+static void
+ifree(void *ptr)
+{
+	struct pginfo	*info, **pd;
+	u_long		index;
+#ifdef	MALLOC_EXTRA_SANITY
+	u_long		pidx;
+#endif	/* MALLOC_EXTRA_SANITY */
+	struct pdinfo	*pi;
+
+	if (!malloc_started) {
+		wrtwarning("malloc() has never been called");
+		return;
+	}
+	/* If we're already sinking, don't make matters any worse. */
+	if (suicide)
+		return;
+
+	if (malloc_ptrguard && PTR_ALIGNED(ptr))
+		ptr = (char *) ptr - PTR_GAP;
+
+	index = ptr2index(ptr);
+
+	if (index < malloc_pageshift) {
+		warnx("(%p)", ptr);
+		wrtwarning("ifree: junk pointer, too low to make sense");
+		return;
+	}
+	if (index > last_index) {
+		warnx("(%p)", ptr);
+		wrtwarning("ifree: junk pointer, too high to make sense");
+		return;
+	}
+	pdir_lookup(index, &pi);
+#ifdef MALLOC_EXTRA_SANITY
+	pidx = PI_IDX(index);
+	if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
+		wrterror("(ES): mapped pages not found in directory");
+		errno = EFAULT;
+		return;
+	}
+#endif /* MALLOC_EXTRA_SANITY */
+	if (pi != last_dir) {
+		prev_dir = last_dir;
+		last_dir = pi;
+	}
+	pd = pi->base;
+	info = pd[PI_OFF(index)];
+
+	if (info < MALLOC_MAGIC)
+		free_pages(ptr, index, info);
+	else
+		free_bytes(ptr, index, info);
+
+	/* does not matter if malloc_bytes fails */
+	if (px == NULL)
+		px = malloc_bytes(sizeof *px);
+
+	return;
+}
+
+/*
+ * Common function for handling recursion.  Only
+ * print the error message once, to avoid making the problem
+ * potentially worse.
+ */
+static void
+malloc_recurse(void)
+{
+	static int	noprint;
+
+	if (noprint == 0) {
+		noprint = 1;
+		wrtwarning("recursive call");
+	}
+	malloc_active--;
+	_MALLOC_UNLOCK();
+	errno = EDEADLK;
+}
+
+/*
+ * These are the public exported interface routines.
+ */
+void *
+malloc(size_t size)
+{
+	void		*r;
+
+	if (!align)
+	_MALLOC_LOCK();
+	malloc_func = " in malloc():";
+	if (malloc_active++) {
+		malloc_recurse();
+		return (NULL);
+	}
+	r = imalloc(size);
+	UTRACE(0, size, r);
+	malloc_active--;
+	if (!align)
+	_MALLOC_UNLOCK();
+	if (malloc_xmalloc && r == NULL) {
+		wrterror("out of memory");
+		errno = ENOMEM;
+	}
+	return (r);
+}
+
+void
+free(void *ptr)
+{
+	/* This is legal. XXX quick path */
+	if (ptr == NULL)
+		return;
+
+	_MALLOC_LOCK();
+	malloc_func = " in free():";
+	if (malloc_active++) {
+		malloc_recurse();
+		return;
+	}
+	ifree(ptr);
+	UTRACE(ptr, 0, 0);
+	malloc_active--;
+	_MALLOC_UNLOCK();
+	return;
+}
+
+void *
+realloc(void *ptr, size_t size)
+{
+	void		*r;
+
+	_MALLOC_LOCK();
+	malloc_func = " in realloc():";
+	if (malloc_active++) {
+		malloc_recurse();
+		return (NULL);
+	}
+
+	if (ptr == NULL)
+		r = imalloc(size);
+	else
+		r = irealloc(ptr, size);
+
+	UTRACE(ptr, size, r);
+	malloc_active--;
+	_MALLOC_UNLOCK();
+	if (malloc_xmalloc && r == NULL) {
+		wrterror("out of memory");
+		errno = ENOMEM;
+	}
+	return (r);
+}
+
+#ifndef SIZE_MAX
+//#if defined(__i386__)||defined(__arm__)||defined(__powerpc__)
+//#define SIZE_MAX 0xffffffff
+//#endif
+//#if defined(__x86_64__)
+//#define SIZE_MAX 0xffffffffffffffff
+//#endif
+#define SIZE_MAX SIZE_T_MAX
+#endif
+
+void *
+calloc(size_t num, size_t size)
+{
+	void *p;
+	
+	if (num && SIZE_MAX / num < size) {
+		fprintf(stderr,"OOOOPS");
+		errno = ENOMEM;
+		return NULL;
+	}
+	size *= num;
+	p = malloc(size);
+	if (p)
+		memset(p, 0, size);
+	return(p);
+}
+
+#ifndef BUILDING_FOR_TOR
+static int ispowerof2 (size_t a) {
+	size_t b;
+	for (b = 1ULL << (sizeof(size_t)*NBBY - 1); b > 1; b >>= 1)
+	  if (b == a)
+		return 1;
+	return 0;
+}
+#endif
+
+#ifndef BUILDING_FOR_TOR
+int posix_memalign(void **memptr, size_t alignment, size_t size)
+{
+	void *r;
+	size_t max;
+	if ((alignment < PTR_SIZE) || (alignment%PTR_SIZE != 0)) return EINVAL;
+	if (!ispowerof2(alignment)) return EINVAL;
+	if (alignment < malloc_minsize) alignment = malloc_minsize;
+	max = alignment > size ? alignment : size;
+	if (alignment <= malloc_pagesize)
+		r = malloc(max);
+	else {
+		_MALLOC_LOCK();
+		align = 1;
+		g_alignment = alignment;
+		r = malloc(size);
+		align=0;
+		_MALLOC_UNLOCK();
+	}
+	*memptr = r;
+	if (!r) return ENOMEM;
+	return 0;
+}
+
+void *memalign(size_t boundary, size_t size)
+{
+	void *r;
+	posix_memalign(&r, boundary, size);
+	return r;
+}
+
+void *valloc(size_t size)
+{
+	void *r;
+	posix_memalign(&r, malloc_pagesize, size);
+	return r;
+}
+#endif
+
+size_t malloc_good_size(size_t size)
+{
+	if (size == 0) {
+		return 1;
+	} else if (size <= malloc_maxsize) {
+		int j;
+		size_t ii;
+		/* round up to the nearest power of 2, with same approach
+		 * as malloc_bytes() uses. */
+		j = 1;
+		ii = size - 1;
+		while (ii >>= 1)
+			j++;
+		return ((size_t)1) << j;
+	} else {
+		return pageround(size);
+	}
+}
diff --git a/src/ext/eventdns.c b/src/ext/eventdns.c
new file mode 100644
index 0000000..768693a
--- /dev/null
+++ b/src/ext/eventdns.c
@@ -0,0 +1,3505 @@
+/* READ THIS COMMENT BEFORE HACKING THIS FILE.
+ *
+ * This eventdns.c copy has diverged a bit from Libevent's version, and it's
+ * no longer easy to resynchronize them.  Once Tor requires Libevent 2.0, we
+ * will just dump this file and use Libevent's evdns code.
+ *
+ * Therefore, you probably shouldn't make any change here without making it to
+ * Libevent as well: it's not good for the implementation to diverge even
+ * more.  Also, we can't shouldn't wantonly the API here (since Libevent APIs
+ * can't change in ways that break user behavior).  Also, we shouldn't bother
+ * with cosmetic changes: the whole module is slated for demolition, so
+ * there's no point dusting the linebreaks or re-painting the parser.
+ *
+ * (We can't just drop the Libevent 2.0 evdns implementation in here instead,
+ * since it depends pretty heavily on parts of Libevent 2.0.)
+ */
+
+/* Async DNS Library
+ * Adam Langley <agl at imperialviolet.org>
+ * Public Domain code
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ *	Parts developed by Adam Langley <agl at imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ *
+ * Version: 0.1b
+ */
+
+#include "eventdns_tor.h"
+#include "../common/util.h"
+#include <sys/types.h>
+/* #define NDEBUG */
+
+#ifndef DNS_USE_CPU_CLOCK_FOR_ID
+#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
+#ifndef DNS_USE_OPENSSL_FOR_ID
+#error Must configure at least one id generation method.
+#error Please see the documentation.
+#endif
+#endif
+#endif
+
+/* #define _POSIX_C_SOURCE 200507 */
+#define _GNU_SOURCE
+
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#error Multiple id options selected
+#endif
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <time.h>
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <openssl/rand.h>
+#endif
+
+#include <string.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "eventdns.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock2.h>
+#include <iphlpapi.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#ifdef _WIN32
+typedef int socklen_t;
+#endif
+
+#define EVDNS_LOG_DEBUG 0
+#define EVDNS_LOG_WARN 1
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+/* for debugging possible memory leaks. */
+#define mm_malloc(x) tor_malloc(x)
+#define mm_realloc(x,y) tor_realloc((x),(y))
+#define mm_free(x) tor_free(x)
+#define mm_strdup(x) tor_strdup(x)
+#define _mm_free(x) _tor_free(x)
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#if 0
+#ifdef __USE_ISOC99B
+/* libevent doesn't work without this */
+typedef uint8_t u_char;
+typedef unsigned int uint;
+#endif
+#endif
+#include <event.h>
+
+#define u64 uint64_t
+#define u32 uint32_t
+#define u16 uint16_t
+#define u8	uint8_t
+
+#define MAX_ADDRS 4	 /* maximum number of addresses from a single packet */
+/* which we bother recording */
+
+#define TYPE_A		EVDNS_TYPE_A
+#define TYPE_CNAME	5
+#define TYPE_PTR	EVDNS_TYPE_PTR
+#define TYPE_AAAA	EVDNS_TYPE_AAAA
+
+#define CLASS_INET	EVDNS_CLASS_INET
+
+#define CLEAR(x) do { memset((x), 0xF0, sizeof(*(x))); } while(0)
+
+struct evdns_request {
+	u8 *request; /* the dns packet data */
+	unsigned int request_len;
+	int reissue_count;
+	int tx_count;  /* the number of times that this packet has been sent */
+	unsigned int request_type; /* TYPE_PTR or TYPE_A */
+	void *user_pointer;	 /* the pointer given to us for this request */
+	evdns_callback_type user_callback;
+	struct nameserver *ns;	/* the server which we last sent it */
+
+	/* elements used by the searching code */
+	int search_index;
+	struct search_state *search_state;
+	char *search_origname;	/* needs to be mm_free()ed */
+	int search_flags;
+
+	/* these objects are kept in a circular list */
+	struct evdns_request *next, *prev;
+
+	struct event timeout_event;
+
+	u16 trans_id;  /* the transaction id */
+	char request_appended;	/* true if the request pointer is data which follows this struct */
+	char transmit_me;  /* needs to be transmitted */
+};
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+	u8 s6_addr[16];
+};
+#endif
+
+struct reply {
+	unsigned int type;
+	unsigned int have_answer;
+	union {
+		struct {
+			u32 addrcount;
+			u32 addresses[MAX_ADDRS];
+		} a;
+		struct {
+			u32 addrcount;
+			struct in6_addr addresses[MAX_ADDRS];
+		} aaaa;
+		struct {
+			char name[HOST_NAME_MAX];
+		} ptr;
+	} data;
+};
+
+struct nameserver {
+	int socket;	 /* a connected UDP socket */
+	struct sockaddr_storage address;
+	int failed_times;  /* number of times which we have given this server a chance */
+	int timedout;  /* number of times in a row a request has timed out */
+	struct event event;
+	/* these objects are kept in a circular list */
+	struct nameserver *next, *prev;
+	struct event timeout_event; /* used to keep the timeout for */
+								/* when we next probe this server. */
+								/* Valid if state == 0 */
+	char state;	 /* zero if we think that this server is down */
+	char choked;  /* true if we have an EAGAIN from this server's socket */
+	char write_waiting;	 /* true if we are waiting for EV_WRITE events */
+};
+
+static struct evdns_request *req_head = NULL, *req_waiting_head = NULL;
+static struct nameserver *server_head = NULL;
+
+/* Represents a local port where we're listening for DNS requests. Right now, */
+/* only UDP is supported. */
+struct evdns_server_port {
+	int socket; /* socket we use to read queries and write replies. */
+	int refcnt; /* reference count. */
+	char choked; /* Are we currently blocked from writing? */
+	char closing; /* Are we trying to close this port, pending writes? */
+	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
+	void *user_data; /* Opaque pointer passed to user_callback */
+	struct event event; /* Read/write event */
+	/* circular list of replies that we want to write. */
+	struct server_request *pending_replies;
+};
+
+/* Represents part of a reply being built.	(That is, a single RR.) */
+struct server_reply_item {
+	struct server_reply_item *next; /* next item in sequence. */
+	char *name; /* name part of the RR */
+	u16 type : 16; /* The RR type */
+	u16 class : 16; /* The RR class (usually CLASS_INET) */
+	u32 ttl; /* The RR TTL */
+	char is_name; /* True iff data is a label */
+	u16 datalen; /* Length of data; -1 if data is a label */
+	void *data; /* The contents of the RR */
+};
+
+/* Represents a request that we've received as a DNS server, and holds */
+/* the components of the reply as we're constructing it. */
+struct server_request {
+	/* Pointers to the next and previous entries on the list of replies */
+	/* that we're waiting to write.	 Only set if we have tried to respond */
+	/* and gotten EAGAIN. */
+	struct server_request *next_pending;
+	struct server_request *prev_pending;
+
+	u16 trans_id; /* Transaction id. */
+	struct evdns_server_port *port; /* Which port received this request on? */
+	struct sockaddr_storage addr; /* Where to send the response */
+	socklen_t addrlen; /* length of addr */
+
+	int n_answer; /* how many answer RRs have been set? */
+	int n_authority; /* how many authority RRs have been set? */
+	int n_additional; /* how many additional RRs have been set? */
+
+	struct server_reply_item *answer; /* linked list of answer RRs */
+	struct server_reply_item *authority; /* linked list of authority RRs */
+	struct server_reply_item *additional; /* linked list of additional RRs */
+
+	/* Constructed response.  Only set once we're ready to send a reply. */
+	/* Once this is set, the RR fields are cleared, and no more should be set. */
+	char *response;
+	size_t response_len;
+
+	/* Caller-visible fields: flags, questions. */
+	struct evdns_server_request base;
+};
+
+/* helper macro */
+#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
+
+/* Given a pointer to an evdns_server_request, get the corresponding */
+/* server_request. */
+#define TO_SERVER_REQUEST(base_ptr)										\
+	((struct server_request*)											\
+	 (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
+
+/* The number of good nameservers that we have */
+static int global_good_nameservers = 0;
+
+/* inflight requests are contained in the req_head list */
+/* and are actually going out across the network */
+static int global_requests_inflight = 0;
+/* requests which aren't inflight are in the waiting list */
+/* and are counted here */
+static int global_requests_waiting = 0;
+
+static int global_max_requests_inflight = 64;
+
+static struct timeval global_timeout = {5, 0};	/* 5 seconds */
+static int global_max_reissues = 1;	/* a reissue occurs when we get some errors from the server */
+static int global_max_retransmits = 3;	/* number of times we'll retransmit a request which timed out */
+/* number of timeouts in a row before we consider this server to be down */
+static int global_max_nameserver_timeout = 3;
+
+/* true iff we should use the 0x20 hack. */
+static int global_randomize_case = 1;
+
+/* These are the timeout values for nameservers. If we find a nameserver is down */
+/* we try to probe it at intervals as given below. Values are in seconds. */
+static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
+static const int global_nameserver_timeouts_length = (int)(sizeof(global_nameserver_timeouts)/sizeof(struct timeval));
+
+static struct nameserver *nameserver_pick(void);
+static void evdns_request_insert(struct evdns_request *req, struct evdns_request **head);
+static void nameserver_ready_callback(int fd, short events, void *arg);
+static int evdns_transmit(void);
+static int evdns_request_transmit(struct evdns_request *req);
+static void nameserver_send_probe(struct nameserver *const ns);
+static void search_request_finished(struct evdns_request *const);
+static int search_try_next(struct evdns_request *const req);
+static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
+static void evdns_requests_pump_waiting_queue(void);
+static u16 transaction_id_pick(void);
+static struct evdns_request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
+static void request_submit(struct evdns_request *req);
+
+static int server_request_free(struct server_request *req);
+static void server_request_free_answers(struct server_request *req);
+static void server_port_free(struct evdns_server_port *port);
+static void server_port_ready_callback(int fd, short events, void *arg);
+
+static int strtoint(const char *const str);
+
+#ifdef _WIN32
+static int
+last_error(int sock)
+{
+	int optval, optvallen=sizeof(optval);
+	int err = WSAGetLastError();
+	if (err == WSAEWOULDBLOCK && sock >= 0) {
+		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
+					   &optvallen))
+			return err;
+		if (optval)
+			return optval;
+	}
+	return err;
+
+}
+static int
+error_is_eagain(int err)
+{
+	return err == EAGAIN || err == WSAEWOULDBLOCK;
+}
+#define inet_aton(c, addr) tor_inet_aton((c), (addr))
+#define CLOSE_SOCKET(x) closesocket(x)
+#else
+#define last_error(sock) (errno)
+#define error_is_eagain(err) ((err) == EAGAIN)
+#define CLOSE_SOCKET(x) close(x)
+#endif
+
+#define ISSPACE(c) TOR_ISSPACE(c)
+#define ISDIGIT(c) TOR_ISDIGIT(c)
+#define ISALPHA(c) TOR_ISALPHA(c)
+#define TOLOWER(c) TOR_TOLOWER(c)
+#define TOUPPER(c) TOR_TOUPPER(c)
+
+#ifndef NDEBUG
+static const char *
+debug_ntoa(u32 address)
+{
+	static char buf[32];
+	u32 a = ntohl(address);
+	snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
+			(int)(u8)((a>>24)&0xff),
+			(int)(u8)((a>>16)&0xff),
+			(int)(u8)((a>>8 )&0xff),
+			(int)(u8)((a	)&0xff));
+	return buf;
+}
+static const char *
+debug_ntop(const struct sockaddr *sa)
+{
+	if (sa->sa_family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+		return debug_ntoa(sin->sin_addr.s_addr);
+	}
+	if (sa->sa_family == AF_INET6) {
+		/* Tor-specific.  In libevent, add more check code. */
+		static char buf[128];
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *) sa;
+		tor_inet_ntop(AF_INET6, &sin->sin6_addr, buf, sizeof(buf));
+		return buf;
+	}
+	return "<unknown>";
+}
+#endif
+
+static evdns_debug_log_fn_type evdns_log_fn = NULL;
+
+void
+evdns_set_log_fn(evdns_debug_log_fn_type fn)
+{
+	evdns_log_fn = fn;
+}
+
+#ifdef __GNUC__
+#define EVDNS_LOG_CHECK	__attribute__ ((format(printf, 2, 3)))
+#else
+#define EVDNS_LOG_CHECK
+#endif
+
+static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
+static void
+_evdns_log(int warn, const char *fmt, ...)
+{
+	va_list args;
+	static char buf[512];
+	if (!evdns_log_fn)
+		return;
+	va_start(args,fmt);
+#ifdef _WIN32
+	_vsnprintf(buf, sizeof(buf), fmt, args);
+#else
+	vsnprintf(buf, sizeof(buf), fmt, args);
+#endif
+	buf[sizeof(buf)-1] = '\0';
+	evdns_log_fn(warn, buf);
+	va_end(args);
+}
+
+#define log _evdns_log
+
+static int
+sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2,
+			int include_port)
+{
+	if (sa1->sa_family != sa2->sa_family)
+		return 0;
+	if (sa1->sa_family == AF_INET) {
+		const struct sockaddr_in *sin1, *sin2;
+		sin1 = (const struct sockaddr_in *)sa1;
+		sin2 = (const struct sockaddr_in *)sa2;
+		if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr)
+			return 0;
+		else if (include_port && sin1->sin_port != sin2->sin_port)
+			return 0;
+		else
+			return 1;
+	}
+#ifdef AF_INET6
+	if (sa1->sa_family == AF_INET6) {
+		const struct sockaddr_in6 *sin1, *sin2;
+		sin1 = (const struct sockaddr_in6 *)sa1;
+		sin2 = (const struct sockaddr_in6 *)sa2;
+		if (tor_memneq(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16))
+			return 0;
+		else if (include_port && sin1->sin6_port != sin2->sin6_port)
+			return 0;
+		else
+			return 1;
+	}
+#endif
+	return 1;
+}
+
+#define add_timeout_event(s, to)				\
+	(event_add(&(s)->timeout_event, (to)))
+#define del_timeout_event(s)					\
+	(event_del(&(s)->timeout_event))
+
+/* This walks the list of inflight requests to find the */
+/* one with a matching transaction id. Returns NULL on */
+/* failure */
+static struct evdns_request *
+request_find_from_trans_id(u16 trans_id) {
+	struct evdns_request *req = req_head, *const started_at = req_head;
+
+	if (req) {
+		do {
+			if (req->trans_id == trans_id) return req;
+			req = req->next;
+		} while (req != started_at);
+	}
+
+	return NULL;
+}
+
+/* a libevent callback function which is called when a nameserver */
+/* has gone down and we want to test if it has came back to life yet */
+static void
+nameserver_prod_callback(int fd, short events, void *arg) {
+	struct nameserver *const ns = (struct nameserver *) arg;
+	(void)fd;
+	(void)events;
+
+	nameserver_send_probe(ns);
+}
+
+/* a libevent callback which is called when a nameserver probe (to see if */
+/* it has come back to life) times out. We increment the count of failed_times */
+/* and wait longer to send the next probe packet. */
+static void
+nameserver_probe_failed(struct nameserver *const ns) {
+	const struct timeval * timeout;
+	del_timeout_event(ns);
+
+	if (ns->state == 1) {
+		/* This can happen if the nameserver acts in a way which makes us mark */
+		/* it as bad and then starts sending good replies. */
+		return;
+	}
+
+	timeout =
+		&global_nameserver_timeouts[MIN(ns->failed_times,
+										global_nameserver_timeouts_length - 1)];
+	ns->failed_times++;
+
+	if (add_timeout_event(ns, (struct timeval *) timeout) < 0) {
+		log(EVDNS_LOG_WARN,
+			"Error from libevent when adding timer event for %s",
+			debug_ntop((struct sockaddr *)&ns->address));
+		/* ???? Do more? */
+	}
+}
+
+/* called when a nameserver has been deemed to have failed. For example, too */
+/* many packets have timed out etc */
+static void
+nameserver_failed(struct nameserver *const ns, const char *msg) {
+	struct evdns_request *req, *started_at;
+	/* if this nameserver has already been marked as failed */
+	/* then don't do anything */
+	if (!ns->state) return;
+
+	log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
+		debug_ntop((struct sockaddr *)&ns->address), msg);
+	global_good_nameservers--;
+	assert(global_good_nameservers >= 0);
+	if (global_good_nameservers == 0) {
+		log(EVDNS_LOG_WARN, "All nameservers have failed");
+	}
+
+	ns->state = 0;
+	ns->failed_times = 1;
+
+	if (add_timeout_event(ns, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
+		log(EVDNS_LOG_WARN,
+			"Error from libevent when adding timer event for %s",
+			debug_ntop((struct sockaddr *)&ns->address));
+		/* ???? Do more? */
+	}
+
+	/* walk the list of inflight requests to see if any can be reassigned to */
+	/* a different server. Requests in the waiting queue don't have a */
+	/* nameserver assigned yet */
+
+	/* if we don't have *any* good nameservers then there's no point */
+	/* trying to reassign requests to one */
+	if (!global_good_nameservers) return;
+
+	req = req_head;
+	started_at = req_head;
+	if (req) {
+		do {
+			if (req->tx_count == 0 && req->ns == ns) {
+				/* still waiting to go out, can be moved */
+				/* to another server */
+				req->ns = nameserver_pick();
+			}
+			req = req->next;
+		} while (req != started_at);
+	}
+}
+
+static void
+nameserver_up(struct nameserver *const ns) {
+	if (ns->state) return;
+	log(EVDNS_LOG_WARN, "Nameserver %s is back up",
+		debug_ntop((struct sockaddr *)&ns->address));
+	del_timeout_event(ns);
+	ns->state = 1;
+	ns->failed_times = 0;
+	ns->timedout = 0;
+	global_good_nameservers++;
+}
+
+static void
+request_trans_id_set(struct evdns_request *const req, const u16 trans_id) {
+	req->trans_id = trans_id;
+	*((u16 *) req->request) = htons(trans_id);
+}
+
+/* Called to remove a request from a list and dealloc it. */
+/* head is a pointer to the head of the list it should be */
+/* removed from or NULL if the request isn't in a list. */
+static void
+request_finished(struct evdns_request *const req, struct evdns_request **head) {
+	if (head) {
+		if (req->next == req) {
+			/* only item in the list */
+			*head = NULL;
+		} else {
+			req->next->prev = req->prev;
+			req->prev->next = req->next;
+			if (*head == req) *head = req->next;
+		}
+	}
+
+	log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
+		(unsigned long) req);
+	del_timeout_event(req);
+
+	search_request_finished(req);
+	global_requests_inflight--;
+
+	if (!req->request_appended) {
+		/* need to free the request data on it's own */
+		mm_free(req->request);
+	} else {
+		/* the request data is appended onto the header */
+		/* so everything gets mm_free()ed when we: */
+	}
+
+	CLEAR(req);
+	_mm_free(req);
+
+	evdns_requests_pump_waiting_queue();
+}
+
+/* This is called when a server returns a funny error code. */
+/* We try the request again with another server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed/reissue is pointless */
+static int
+request_reissue(struct evdns_request *req) {
+	const struct nameserver *const last_ns = req->ns;
+	/* the last nameserver should have been marked as failing */
+	/* by the caller of this function, therefore pick will try */
+	/* not to return it */
+	req->ns = nameserver_pick();
+	if (req->ns == last_ns) {
+		/* ... but pick did return it */
+		/* not a lot of point in trying again with the */
+		/* same server */
+		return 1;
+	}
+
+	req->reissue_count++;
+	req->tx_count = 0;
+	req->transmit_me = 1;
+
+	return 0;
+}
+
+/* this function looks for space on the inflight queue and promotes */
+/* requests from the waiting queue if it can. */
+static void
+evdns_requests_pump_waiting_queue(void) {
+	while (global_requests_inflight < global_max_requests_inflight &&
+		global_requests_waiting) {
+		struct evdns_request *req;
+		/* move a request from the waiting queue to the inflight queue */
+		assert(req_waiting_head);
+		if (req_waiting_head->next == req_waiting_head) {
+			/* only one item in the queue */
+			req = req_waiting_head;
+			req_waiting_head = NULL;
+		} else {
+			req = req_waiting_head;
+			req->next->prev = req->prev;
+			req->prev->next = req->next;
+			req_waiting_head = req->next;
+		}
+
+		global_requests_waiting--;
+		global_requests_inflight++;
+
+		req->ns = nameserver_pick();
+		request_trans_id_set(req, transaction_id_pick());
+
+		evdns_request_insert(req, &req_head);
+		evdns_request_transmit(req);
+		evdns_transmit();
+	}
+}
+
+static void
+reply_callback(struct evdns_request *const req, u32 ttl, u32 err, struct reply *reply) {
+	switch (req->request_type) {
+	case TYPE_A:
+		if (reply)
+			req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
+							   reply->data.a.addrcount, ttl,
+							   reply->data.a.addresses,
+							   req->user_pointer);
+		else
+			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+		return;
+	case TYPE_PTR:
+		if (reply) {
+			char *name = reply->data.ptr.name;
+			req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
+							   &name, req->user_pointer);
+		} else {
+			req->user_callback(err, 0, 0, 0, NULL,
+							   req->user_pointer);
+		}
+		return;
+	case TYPE_AAAA:
+		if (reply)
+			req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
+							   reply->data.aaaa.addrcount, ttl,
+							   reply->data.aaaa.addresses,
+							   req->user_pointer);
+		else
+			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+		return;
+	}
+	assert(0);
+}
+
+/* this processes a parsed reply packet */
+static void
+reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *reply) {
+	int error;
+	static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED};
+
+	if (flags & 0x020f || !reply || !reply->have_answer) {
+		/* there was an error */
+		if (flags & 0x0200) {
+			error = DNS_ERR_TRUNCATED;
+		} else {
+			u16 error_code = (flags & 0x000f) - 1;
+			if (error_code > 4) {
+				error = DNS_ERR_UNKNOWN;
+			} else {
+				error = error_codes[error_code];
+			}
+		}
+
+		switch(error) {
+		case DNS_ERR_NOTIMPL:
+		case DNS_ERR_REFUSED:
+			/* we regard these errors as marking a bad nameserver */
+			if (req->reissue_count < global_max_reissues) {
+				char msg[64];
+				snprintf(msg, sizeof(msg), "Bad response %d (%s)",
+						 error, evdns_err_to_string(error));
+				nameserver_failed(req->ns, msg);
+				if (!request_reissue(req)) return;
+			}
+			break;
+		case DNS_ERR_SERVERFAILED:
+			/* rcode 2 (servfailed) sometimes means "we are broken" and
+			 * sometimes (with some binds) means "that request was very
+			 * confusing."  Treat this as a timeout, not a failure.
+			 */
+			/*XXXX refactor the parts of */
+			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
+				"will allow the request to time out.",
+				debug_ntop((struct sockaddr *)&req->ns->address));
+			break;
+		default:
+			/* we got a good reply from the nameserver */
+			nameserver_up(req->ns);
+		}
+
+		if (req->search_state && req->request_type != TYPE_PTR) {
+			/* if we have a list of domains to search in, try the next one */
+			if (!search_try_next(req)) {
+				/* a new request was issued so this request is finished and */
+				/* the user callback will be made when that request (or a */
+				/* child of it) finishes. */
+				request_finished(req, &req_head);
+				return;
+			}
+		}
+
+		/* all else failed. Pass the failure up */
+		reply_callback(req, 0, error, NULL);
+		request_finished(req, &req_head);
+	} else {
+		/* all ok, tell the user */
+		reply_callback(req, ttl, 0, reply);
+		nameserver_up(req->ns);
+		request_finished(req, &req_head);
+	}
+}
+
+static INLINE int
+name_parse(u8 *packet, int length, int *idx, char *name_out, size_t name_out_len) {
+	int name_end = -1;
+	int j = *idx;
+	int ptr_count = 0;
+#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
+#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
+#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
+
+	char *cp = name_out;
+	const char *const end = name_out + name_out_len;
+
+	/* Normally, names are a series of length prefixed strings terminated */
+	/* with a length of 0 (the lengths are u8's < 63). */
+	/* However, the length can start with a pair of 1 bits and that */
+	/* means that the next 14 bits are a pointer within the current */
+	/* packet. */
+
+	for(;;) {
+		u8 label_len;
+		if (j >= length) return -1;
+		GET8(label_len);
+		if (!label_len) break;
+		if (label_len & 0xc0) {
+			u8 ptr_low;
+			GET8(ptr_low);
+			if (name_end < 0) name_end = j;
+			j = (((int)label_len & 0x3f) << 8) + ptr_low;
+			/* Make sure that the target offset is in-bounds. */
+			if (j < 0 || j >= length) return -1;
+			/* If we've jumped more times than there are characters in the
+			 * message, we must have a loop. */
+			if (++ptr_count > length) return -1;
+			continue;
+		}
+		if (label_len > 63) return -1;
+		if (cp != name_out) {
+			if (cp + 1 >= end) return -1;
+			*cp++ = '.';
+		}
+		if (cp + label_len >= end) return -1;
+		memcpy(cp, packet + j, label_len);
+		cp += label_len;
+		j += label_len;
+	}
+	if (cp >= end) return -1;
+	*cp = '\0';
+	if (name_end < 0)
+		*idx = j;
+	else
+		*idx = name_end;
+	return 0;
+ err:
+	return -1;
+}
+
+/* parses a raw reply from a nameserver. */
+static int
+reply_parse(u8 *packet, int length) {
+	int j = 0;	/* index into packet */
+	int k;
+	u16 _t;	 /* used by the macros */
+	u32 _t32;  /* used by the macros */
+	char tmp_name[256], cmp_name[256]; /* used by the macros */
+
+	u16 trans_id, questions, answers, authority, additional, datalength;
+	u16 flags = 0;
+	u32 ttl, ttl_r = 0xffffffff;
+	struct reply reply;
+	struct evdns_request *req = NULL;
+	unsigned int i;
+	int name_matches = 0;
+
+	GET16(trans_id);
+	GET16(flags);
+	GET16(questions);
+	GET16(answers);
+	GET16(authority);
+	GET16(additional);
+	(void) authority; /* suppress "unused variable" warnings. */
+	(void) additional; /* suppress "unused variable" warnings. */
+
+	req = request_find_from_trans_id(trans_id);
+	/* if no request, can't do anything. */
+	if (!req) return -1;
+
+	memset(&reply, 0, sizeof(reply));
+
+	/* If it's not an answer, it doesn't go with any of our requests. */
+	if (!(flags & 0x8000)) return -1;  /* must be an answer */
+	if (flags & 0x020f) {
+		/* there was an error */
+		goto err;
+	}
+	/* if (!answers) return; */  /* must have an answer of some form */
+
+	/* This macro skips a name in the DNS reply. */
+#define GET_NAME \
+	do { tmp_name[0] = '\0';				\
+		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+			goto err;				\
+	} while(0)
+#define TEST_NAME \
+	do { tmp_name[0] = '\0';				\
+		cmp_name[0] = '\0';				\
+		k = j;						\
+		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+			goto err;					\
+		if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0)	\
+			goto err;				\
+		if (global_randomize_case) {							\
+			if (strcmp(tmp_name, cmp_name) == 0)				\
+				name_matches = 1; /* we ignore mismatching names */	\
+		} else {													\
+			if (strcasecmp(tmp_name, cmp_name) == 0)				\
+				name_matches = 1;									\
+		}															\
+	} while(0)
+
+	reply.type = req->request_type;
+
+	/* skip over each question in the reply */
+	for (i = 0; i < questions; ++i) {
+		/* the question looks like
+		 * <label:name><u16:type><u16:class>
+		 */
+		TEST_NAME;
+		j += 4;
+		if (j >= length) goto err;
+	}
+
+	if (!name_matches)
+		goto err;
+
+	/* now we have the answer section which looks like
+	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
+	 */
+
+	for (i = 0; i < answers; ++i) {
+		u16 type, class;
+
+		GET_NAME;
+		GET16(type);
+		GET16(class);
+		GET32(ttl);
+		GET16(datalength);
+
+		if (type == TYPE_A && class == CLASS_INET) {
+			int addrcount, addrtocopy;
+			if (req->request_type != TYPE_A) {
+				j += datalength; continue;
+			}
+			if ((datalength & 3) != 0) /* not an even number of As. */
+				goto err;
+			addrcount = datalength >> 2;
+			addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
+
+			ttl_r = MIN(ttl_r, ttl);
+			/* we only bother with the first four addresses. */
+			if (j + 4*addrtocopy > length) goto err;
+			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
+				   packet + j, 4*addrtocopy);
+			reply.data.a.addrcount += addrtocopy;
+			reply.have_answer = 1;
+			if (reply.data.a.addrcount == MAX_ADDRS) break;
+			j += 4*addrtocopy;
+		} else if (type == TYPE_PTR && class == CLASS_INET) {
+			if (req->request_type != TYPE_PTR) {
+				j += datalength; continue;
+			}
+			GET_NAME;
+			strlcpy(reply.data.ptr.name, tmp_name,
+					sizeof(reply.data.ptr.name));
+			ttl_r = MIN(ttl_r, ttl);
+			reply.have_answer = 1;
+			break;
+		} else if (type == TYPE_AAAA && class == CLASS_INET) {
+			int addrcount, addrtocopy;
+			if (req->request_type != TYPE_AAAA) {
+				j += datalength; continue;
+			}
+			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
+				goto err;
+			addrcount = datalength >> 4;  /* each address is 16 bytes long */
+			addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
+			ttl_r = MIN(ttl_r, ttl);
+
+			/* we only bother with the first four addresses. */
+			if (j + 16*addrtocopy > length) goto err;
+			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
+				   packet + j, 16*addrtocopy);
+			reply.data.aaaa.addrcount += addrtocopy;
+			reply.have_answer = 1;
+			if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
+			j += 16*addrtocopy;
+		} else {
+			/* skip over any other type of resource */
+			j += datalength;
+		}
+	}
+
+	reply_handle(req, flags, ttl_r, &reply);
+	return 0;
+ err:
+	if (req)
+		reply_handle(req, flags, 0, NULL);
+	return -1;
+}
+
+/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
+/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
+/* callback. */
+static int
+request_parse(u8 *packet, ssize_t length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
+{
+	int j = 0;	/* index into packet */
+	u16 _t;	 /* used by the macros */
+	char tmp_name[256]; /* used by the macros */
+
+	int i;
+	u16 trans_id, flags, questions, answers, authority, additional;
+	struct server_request *server_req = NULL;
+
+	/* Get the header fields */
+	GET16(trans_id);
+	GET16(flags);
+	GET16(questions);
+	GET16(answers);
+	GET16(authority);
+	GET16(additional);
+	(void)additional;
+	(void)authority;
+	(void)answers;
+
+	if (flags & 0x8000) return -1; /* Must not be an answer. */
+	flags &= 0x0110; /* Only RD and CD get preserved. */
+
+    if (length > INT_MAX)
+        return -1;
+
+	server_req = mm_malloc(sizeof(struct server_request));
+	if (server_req == NULL) return -1;
+	memset(server_req, 0, sizeof(struct server_request));
+
+	server_req->trans_id = trans_id;
+	memcpy(&server_req->addr, addr, addrlen);
+	server_req->addrlen = addrlen;
+
+	server_req->base.flags = flags;
+	server_req->base.nquestions = 0;
+	server_req->base.questions = mm_malloc(sizeof(struct evdns_server_question *) * questions);
+	if (server_req->base.questions == NULL)
+		goto err;
+
+	for (i = 0; i < questions; ++i) {
+		u16 type, class;
+		struct evdns_server_question *q;
+		size_t namelen;
+		if (name_parse(packet, (int)length, &j, tmp_name, sizeof(tmp_name))<0)
+			goto err;
+		GET16(type);
+		GET16(class);
+		namelen = strlen(tmp_name);
+		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
+		if (!q)
+			goto err;
+		q->type = type;
+		q->dns_question_class = class;
+		memcpy(q->name, tmp_name, namelen+1);
+		server_req->base.questions[server_req->base.nquestions++] = q;
+	}
+
+	/* Ignore answers, authority, and additional. */
+
+	server_req->port = port;
+	port->refcnt++;
+
+	/* Only standard queries are supported. */
+	if (flags & 0x7800) {
+		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+		return -1;
+	}
+
+	port->user_callback(&(server_req->base), port->user_data);
+
+	return 0;
+err:
+	if (server_req) {
+		if (server_req->base.questions) {
+			for (i = 0; i < server_req->base.nquestions; ++i)
+				mm_free(server_req->base.questions[i]);
+			mm_free(server_req->base.questions);
+		}
+		CLEAR(server_req);
+		mm_free(server_req);
+	}
+	return -1;
+
+#undef SKIP_NAME
+#undef GET32
+#undef GET16
+#undef GET8
+}
+
+static uint16_t
+default_transaction_id_fn(void)
+{
+	u16 trans_id;
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+	struct timespec ts;
+#ifdef CLOCK_MONOTONIC
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+#else
+	if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+#endif
+	event_err(1, "clock_gettime");
+	trans_id = ts.tv_nsec & 0xffff;
+#endif
+
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	trans_id = tv.tv_usec & 0xffff;
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+	if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+		/* in the case that the RAND call fails we back */
+		/* down to using gettimeofday. */
+		/*
+		  struct timeval tv;
+		  gettimeofday(&tv, NULL);
+		  trans_id = tv.tv_usec & 0xffff;
+		*/
+		abort();
+	}
+#endif
+	return (unsigned short) trans_id;
+}
+
+static uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
+
+static void
+default_random_bytes_fn(char *buf, size_t n)
+{
+	unsigned i;
+	for (i = 0; i < n; i += 2) {
+		u16 tid = trans_id_function();
+		buf[i] = (tid >> 8) & 0xff;
+		if (i+1<n)
+			buf[i+1] = tid & 0xff;
+	}
+}
+
+static void (*rand_bytes_function)(char *buf, size_t n) =
+	default_random_bytes_fn;
+
+static u16
+trans_id_from_random_bytes_fn(void)
+{
+	u16 tid;
+	rand_bytes_function((char*) &tid, sizeof(tid));
+	return tid;
+}
+
+void
+evdns_set_transaction_id_fn(uint16_t (*fn)(void))
+{
+	if (fn)
+		trans_id_function = fn;
+	else
+		trans_id_function = default_transaction_id_fn;
+	rand_bytes_function = default_random_bytes_fn;
+}
+
+void
+evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
+{
+	rand_bytes_function = fn;
+	trans_id_function = trans_id_from_random_bytes_fn;
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(void) {
+	for (;;) {
+		const struct evdns_request *req = req_head, *started_at;
+		u16 trans_id = trans_id_function();
+
+		if (trans_id == 0xffff) continue;
+		/* now check to see if that id is already inflight */
+		req = started_at = req_head;
+		if (req) {
+			do {
+				if (req->trans_id == trans_id) break;
+				req = req->next;
+			} while (req != started_at);
+		}
+		/* we didn't find it, so this is a good id */
+		if (req == started_at) return trans_id;
+	}
+}
+
+/* choose a namesever to use. This function will try to ignore */
+/* nameservers which we think are down and load balance across the rest */
+/* by updating the server_head global each time. */
+static struct nameserver *
+nameserver_pick(void) {
+	struct nameserver *started_at = server_head, *picked;
+	if (!server_head) return NULL;
+
+	/* if we don't have any good nameservers then there's no */
+	/* point in trying to find one. */
+	if (!global_good_nameservers) {
+		server_head = server_head->next;
+		return server_head;
+	}
+
+	/* remember that nameservers are in a circular list */
+	for (;;) {
+		if (server_head->state) {
+			/* we think this server is currently good */
+			picked = server_head;
+			server_head = server_head->next;
+			return picked;
+		}
+
+		server_head = server_head->next;
+		if (server_head == started_at) {
+			/* all the nameservers seem to be down */
+			/* so we just return this one and hope for the */
+			/* best */
+			assert(global_good_nameservers == 0);
+			picked = server_head;
+			server_head = server_head->next;
+			return picked;
+		}
+	}
+}
+
+/* this is called when a namesever socket is ready for reading */
+static void
+nameserver_read(struct nameserver *ns) {
+	struct sockaddr_storage ss;
+	struct sockaddr *sa = (struct sockaddr *) &ss;
+	socklen_t addrlen = sizeof(ss);
+	u8 packet[1500];
+
+	for (;;) {
+		const int r =
+            (int)recvfrom(ns->socket, (void*)packet,
+						  (socklen_t)sizeof(packet), 0,
+						  sa, &addrlen);
+		if (r < 0) {
+			int err = last_error(ns->socket);
+			if (error_is_eagain(err)) return;
+			nameserver_failed(ns, tor_socket_strerror(err));
+			return;
+		}
+		/* XXX Match port too? */
+		if (!sockaddr_eq(sa, (struct sockaddr*)&ns->address, 0)) {
+			log(EVDNS_LOG_WARN,
+				"Address mismatch on received DNS packet.  Address was %s",
+				debug_ntop(sa));
+			return;
+		}
+		ns->timedout = 0;
+		reply_parse(packet, r);
+	}
+}
+
+/* Read a packet from a DNS client on a server port s, parse it, and */
+/* act accordingly. */
+static void
+server_port_read(struct evdns_server_port *s) {
+	u8 packet[1500];
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+	ssize_t r;
+
+	for (;;) {
+		addrlen = (socklen_t)sizeof(struct sockaddr_storage);
+		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
+					 (struct sockaddr*) &addr, &addrlen);
+		if (r < 0) {
+			int err = last_error(s->socket);
+			if (error_is_eagain(err)) return;
+			log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
+				tor_socket_strerror(err), err);
+			return;
+		}
+		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
+	}
+}
+
+/* Try to write all pending replies on a given DNS server port. */
+static void
+server_port_flush(struct evdns_server_port *port)
+{
+	struct server_request *req = port->pending_replies;
+	while (req) {
+		ssize_t r = sendto(port->socket, req->response, req->response_len, 0,
+                       (struct sockaddr*) &req->addr, (socklen_t)req->addrlen);
+		if (r < 0) {
+			int err = last_error(port->socket);
+			if (error_is_eagain(err))
+				return;
+			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err);
+		}
+		if (server_request_free(req)) {
+			/* we released the last reference to req->port. */
+			return;
+		} else {
+			assert(port->pending_replies != req);
+			req = port->pending_replies;
+		}
+	}
+
+	/* We have no more pending requests; stop listening for 'writeable' events. */
+	(void) event_del(&port->event);
+	CLEAR(&port->event);
+	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+			  server_port_ready_callback, port);
+	if (event_add(&port->event, NULL) < 0) {
+		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
+		/* ???? Do more? */
+	}
+}
+
+/* set if we are waiting for the ability to write to this server. */
+/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
+/* we stop these events. */
+static void
+nameserver_write_waiting(struct nameserver *ns, char waiting) {
+	if (ns->write_waiting == waiting) return;
+
+	ns->write_waiting = waiting;
+	(void) event_del(&ns->event);
+	CLEAR(&ns->event);
+	event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
+			  nameserver_ready_callback, ns);
+	if (event_add(&ns->event, NULL) < 0) {
+		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
+			debug_ntop((struct sockaddr *)&ns->address));
+		/* ???? Do more? */
+	}
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a nameserver socket is ready for writing or reading */
+static void
+nameserver_ready_callback(int fd, short events, void *arg) {
+	struct nameserver *ns = (struct nameserver *) arg;
+	(void)fd;
+
+	if (events & EV_WRITE) {
+		ns->choked = 0;
+		if (!evdns_transmit()) {
+			nameserver_write_waiting(ns, 0);
+		}
+	}
+	if (events & EV_READ) {
+		nameserver_read(ns);
+	}
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a server socket is ready for writing or reading. */
+static void
+server_port_ready_callback(int fd, short events, void *arg) {
+	struct evdns_server_port *port = (struct evdns_server_port *) arg;
+	(void) fd;
+
+	if (events & EV_WRITE) {
+		port->choked = 0;
+		server_port_flush(port);
+	}
+	if (events & EV_READ) {
+		server_port_read(port);
+	}
+}
+
+/* This is an inefficient representation; only use it via the dnslabel_table_*
+ * functions, so that is can be safely replaced with something smarter later. */
+#define MAX_LABELS 128
+/* Structures used to implement name compression */
+struct dnslabel_entry { char *v; off_t pos; };
+struct dnslabel_table {
+	int n_labels; /* number of current entries */
+	/* map from name to position in message */
+	struct dnslabel_entry labels[MAX_LABELS];
+};
+
+/* Initialize dnslabel_table. */
+static void
+dnslabel_table_init(struct dnslabel_table *table)
+{
+	table->n_labels = 0;
+}
+
+/* Free all storage held by table, but not the table itself. */
+static void
+dnslabel_clear(struct dnslabel_table *table)
+{
+	int i;
+	for (i = 0; i < table->n_labels; ++i)
+		mm_free(table->labels[i].v);
+	table->n_labels = 0;
+}
+
+/* return the position of the label in the current message, or -1 if the label */
+/* hasn't been used yet. */
+static int
+dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
+{
+	int i;
+	for (i = 0; i < table->n_labels; ++i) {
+		if (!strcmp(label, table->labels[i].v)) {
+			off_t pos = table->labels[i].pos;
+            if (pos > 65535)
+                return -1;
+            return (int)pos;
+        }
+	}
+	return -1;
+}
+
+/* remember that we've used the label at position pos */
+static int
+dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
+{
+	char *v;
+	int p;
+	if (table->n_labels == MAX_LABELS)
+		return (-1);
+	v = mm_strdup(label);
+	if (v == NULL)
+		return (-1);
+	p = table->n_labels++;
+	table->labels[p].v = v;
+	table->labels[p].pos = pos;
+
+	return (0);
+}
+
+/* Converts a string to a length-prefixed set of DNS labels, starting */
+/* at buf[j]. name and buf must not overlap. name_len should be the length */
+/* of name.	 table is optional, and is used for compression. */
+/* */
+/* Input: abc.def */
+/* Output: <3>abc<3>def<0> */
+/* */
+/* Returns the first index after the encoded name, or negative on error. */
+/* -1	 label was > 63 bytes */
+/* -2	 name too long to fit in buffer. */
+/* */
+static off_t
+dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
+				  const char *name, const size_t name_len,
+				  struct dnslabel_table *table) {
+	const char *end = name + name_len;
+	int ref = 0;
+	u16 _t;
+
+#define APPEND16(x) do {						   \
+		if (j + 2 > (off_t)buf_len)				   \
+			goto overflow;						   \
+		_t = htons(x);							   \
+		memcpy(buf + j, &_t, 2);				   \
+		j += 2;									   \
+	} while (0)
+#define APPEND32(x) do {						   \
+		if (j + 4 > (off_t)buf_len)				   \
+			goto overflow;						   \
+		_t32 = htonl(x);						   \
+		memcpy(buf + j, &_t32, 4);				   \
+		j += 4;									   \
+	} while (0)
+
+	if (name_len > 255) return -2;
+
+	for (;;) {
+		const char *const start = name;
+		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
+			APPEND16(ref | 0xc000);
+			return j;
+		}
+		name = strchr(name, '.');
+		if (!name) {
+			const size_t label_len = end - start;
+			if (label_len > 63) return -1;
+			if ((size_t)(j+label_len+1) > buf_len) return -2;
+			if (table) dnslabel_table_add(table, start, j);
+			buf[j++] = (uint8_t)label_len;
+
+			memcpy(buf + j, start, label_len);
+			j += end - start;
+			break;
+		} else {
+			/* append length of the label. */
+			const size_t label_len = name - start;
+			if (label_len > 63) return -1;
+			if ((size_t)(j+label_len+1) > buf_len) return -2;
+			if (table) dnslabel_table_add(table, start, j);
+			buf[j++] = (uint8_t)label_len;
+
+			memcpy(buf + j, start, name - start);
+			j += name - start;
+			/* hop over the '.' */
+			name++;
+		}
+	}
+
+	/* the labels must be terminated by a 0. */
+	/* It's possible that the name ended in a . */
+	/* in which case the zero is already there */
+	if (!j || buf[j-1]) buf[j++] = 0;
+	return j;
+ overflow:
+	return (-2);
+}
+
+/* Finds the length of a dns request for a DNS name of the given */
+/* length. The actual request may be smaller than the value returned */
+/* here */
+static size_t
+evdns_request_len(const size_t name_len) {
+	return 96 + /* length of the DNS standard header */
+		name_len + 2 +
+		4;	/* space for the resource type */
+}
+
+/* build a dns request packet into buf. buf should be at least as long */
+/* as evdns_request_len told you it should be. */
+/* */
+/* Returns the amount of space used. Negative on error. */
+static int
+evdns_request_data_build(const char *const name, const size_t name_len,
+						 const u16 trans_id, const u16 type, const u16 class,
+						 u8 *const buf, size_t buf_len) {
+	off_t j = 0;	/* current offset into buf */
+	u16 _t;	 /* used by the macros */
+
+	APPEND16(trans_id);
+	APPEND16(0x0100);  /* standard query, recusion needed */
+	APPEND16(1);  /* one question */
+	APPEND16(0);  /* no answers */
+	APPEND16(0);  /* no authority */
+	APPEND16(0);  /* no additional */
+
+	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
+	if (j < 0) {
+		return (int)j;
+	}
+
+	APPEND16(type);
+	APPEND16(class);
+
+	return (int)j;
+ overflow:
+	return (-1);
+}
+
+/* exported function */
+struct evdns_server_port *
+evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
+{
+	struct evdns_server_port *port;
+	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
+		return NULL;
+	memset(port, 0, sizeof(struct evdns_server_port));
+
+	assert(!is_tcp); /* TCP sockets not yet implemented */
+	port->socket = socket;
+	port->refcnt = 1;
+	port->choked = 0;
+	port->closing = 0;
+	port->user_callback = cb;
+	port->user_data = user_data;
+	port->pending_replies = NULL;
+
+	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+			  server_port_ready_callback, port);
+	if (event_add(&port->event, NULL)<0) {
+		mm_free(port);
+		return NULL;
+	}
+	return port;
+}
+
+/* exported function */
+void
+evdns_close_server_port(struct evdns_server_port *port)
+{
+	port->closing = 1;
+	if (--port->refcnt == 0)
+		server_port_free(port);
+}
+
+/* exported function */
+int
+evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	struct server_reply_item **itemp, *item;
+	int *countp;
+
+	if (req->response) /* have we already answered? */
+		return (-1);
+
+	switch (section) {
+	case EVDNS_ANSWER_SECTION:
+		itemp = &req->answer;
+		countp = &req->n_answer;
+		break;
+	case EVDNS_AUTHORITY_SECTION:
+		itemp = &req->authority;
+		countp = &req->n_authority;
+		break;
+	case EVDNS_ADDITIONAL_SECTION:
+		itemp = &req->additional;
+		countp = &req->n_additional;
+		break;
+	default:
+		return (-1);
+	}
+	while (*itemp) {
+		itemp = &((*itemp)->next);
+	}
+	item = mm_malloc(sizeof(struct server_reply_item));
+	if (!item)
+		return -1;
+	CLEAR(item);
+	item->next = NULL;
+	if (!(item->name = mm_strdup(name))) {
+		CLEAR(item);
+		mm_free(item);
+		return -1;
+	}
+	item->type = type;
+	item->class = class;
+	item->ttl = ttl;
+	item->is_name = is_name != 0;
+	item->datalen = 0;
+	item->data = NULL;
+	if (data) {
+		if (item->is_name) {
+			if (!(item->data = mm_strdup(data))) {
+				mm_free(item->name);
+				CLEAR(item);
+				mm_free(item);
+				return -1;
+			}
+			item->datalen = (u16)-1;
+		} else {
+			if (!(item->data = mm_malloc(datalen))) {
+				mm_free(item->name);
+				CLEAR(item);
+				mm_free(item);
+				return -1;
+			}
+			item->datalen = datalen;
+			memcpy(item->data, data, datalen);
+		}
+	}
+
+	*itemp = item;
+	++(*countp);
+	return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+		  ttl, n*4, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
+		  ttl, n*16, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
+{
+	u32 a;
+	char buf[32];
+	assert(in || inaddr_name);
+	assert(!(in && inaddr_name));
+	if (in) {
+		a = ntohl(in->s_addr);
+		snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+				(int)(u8)((a	)&0xff),
+				(int)(u8)((a>>8 )&0xff),
+				(int)(u8)((a>>16)&0xff),
+				(int)(u8)((a>>24)&0xff));
+		inaddr_name = buf;
+	}
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
+		  ttl, -1, 1, hostname);
+}
+
+/* exported function */
+int
+evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
+{
+	return evdns_server_request_add_reply(
+		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
+		  ttl, -1, 1, cname);
+}
+
+
+static int
+evdns_server_request_format_response(struct server_request *req, int err)
+{
+	unsigned char buf[1500];
+	size_t buf_len = sizeof(buf);
+	off_t j = 0, r;
+	u16 _t;
+	u32 _t32;
+	int i;
+	u16 flags;
+	struct dnslabel_table table;
+
+	if (err < 0 || err > 15) return -1;
+
+	/* Set response bit and error code; copy OPCODE and RD fields from
+	 * question; copy RA and AA if set by caller. */
+	flags = req->base.flags;
+	flags |= (0x8000 | err);
+
+	dnslabel_table_init(&table);
+	APPEND16(req->trans_id);
+	APPEND16(flags);
+	APPEND16(req->base.nquestions);
+	APPEND16(req->n_answer);
+	APPEND16(req->n_authority);
+	APPEND16(req->n_additional);
+
+	/* Add questions. */
+	for (i=0; i < req->base.nquestions; ++i) {
+		const char *s = req->base.questions[i]->name;
+		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
+		if (j < 0) {
+			dnslabel_clear(&table);
+			return (int) j;
+		}
+		APPEND16(req->base.questions[i]->type);
+		APPEND16(req->base.questions[i]->dns_question_class);
+	}
+
+	/* Add answer, authority, and additional sections. */
+	for (i=0; i<3; ++i) {
+		struct server_reply_item *item;
+		if (i==0)
+			item = req->answer;
+		else if (i==1)
+			item = req->authority;
+		else
+			item = req->additional;
+		while (item) {
+			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
+			if (r < 0)
+				goto overflow;
+			j = r;
+
+			APPEND16(item->type);
+			APPEND16(item->class);
+			APPEND32(item->ttl);
+			if (item->is_name) {
+				off_t len_idx = j, name_start;
+				j += 2;
+				name_start = j;
+				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
+				if (r < 0)
+					goto overflow;
+				j = r;
+				_t = htons( (j-name_start) );
+				memcpy(buf+len_idx, &_t, 2);
+			} else {
+				APPEND16(item->datalen);
+				if (j+item->datalen > (off_t)buf_len)
+					goto overflow;
+				memcpy(buf+j, item->data, item->datalen);
+				j += item->datalen;
+			}
+			item = item->next;
+		}
+	}
+
+	if (j > 512) {
+overflow:
+		j = 512;
+		buf[2] |= 0x02; /* set the truncated bit. */
+	}
+
+	req->response_len = (size_t)j;
+
+	if (!(req->response = mm_malloc(req->response_len))) {
+		server_request_free_answers(req);
+		dnslabel_clear(&table);
+		return (-1);
+	}
+	memcpy(req->response, buf, req->response_len);
+	server_request_free_answers(req);
+	dnslabel_clear(&table);
+	return (0);
+}
+
+/* exported function */
+int
+evdns_server_request_respond(struct evdns_server_request *_req, int err)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	struct evdns_server_port *port = req->port;
+	ssize_t r;
+	if (!req->response) {
+		if ((r = evdns_server_request_format_response(req, err))<0)
+			return (int)r;
+	}
+
+	r = sendto(port->socket, req->response, req->response_len, 0,
+			   (struct sockaddr*) &req->addr, req->addrlen);
+	if (r<0) {
+		int error = last_error(port->socket);
+		if (! error_is_eagain(error))
+			return -1;
+
+		if (port->pending_replies) {
+			req->prev_pending = port->pending_replies->prev_pending;
+			req->next_pending = port->pending_replies;
+			req->prev_pending->next_pending =
+				req->next_pending->prev_pending = req;
+		} else {
+			req->prev_pending = req->next_pending = req;
+			port->pending_replies = req;
+			port->choked = 1;
+
+			(void) event_del(&port->event);
+			CLEAR(&port->event);
+			event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
+
+			if (event_add(&port->event, NULL) < 0) {
+				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
+			}
+
+		}
+
+		return 1;
+	}
+	if (server_request_free(req))
+		return 0;
+
+	if (port->pending_replies)
+		server_port_flush(port);
+
+	return 0;
+}
+
+/* Free all storage held by RRs in req. */
+static void
+server_request_free_answers(struct server_request *req)
+{
+	struct server_reply_item *victim, *next, **list;
+	int i;
+	for (i = 0; i < 3; ++i) {
+		if (i==0)
+			list = &req->answer;
+		else if (i==1)
+			list = &req->authority;
+		else
+			list = &req->additional;
+
+		victim = *list;
+		while (victim) {
+			next = victim->next;
+			mm_free(victim->name);
+			if (victim->data)
+				mm_free(victim->data);
+			mm_free(victim);
+			victim = next;
+		}
+		*list = NULL;
+	}
+}
+
+/* Free all storage held by req, and remove links to it. */
+/* return true iff we just wound up freeing the server_port. */
+static int
+server_request_free(struct server_request *req)
+{
+	int i, rc=1;
+	if (req->base.questions) {
+		for (i = 0; i < req->base.nquestions; ++i)
+			mm_free(req->base.questions[i]);
+		mm_free(req->base.questions);
+	}
+
+	if (req->port) {
+		if (req->port->pending_replies == req) {
+			if (req->next_pending && req->next_pending != req)
+				req->port->pending_replies = req->next_pending;
+			else
+				req->port->pending_replies = NULL;
+		}
+		rc = --req->port->refcnt;
+	}
+
+	if (req->response) {
+		mm_free(req->response);
+	}
+
+	server_request_free_answers(req);
+
+	if (req->next_pending && req->next_pending != req) {
+		req->next_pending->prev_pending = req->prev_pending;
+		req->prev_pending->next_pending = req->next_pending;
+	}
+
+	if (rc == 0) {
+		server_port_free(req->port);
+		CLEAR(req);
+		mm_free(req);
+		return (1);
+	}
+	CLEAR(req);
+	mm_free(req);
+	return (0);
+}
+
+/* Free all storage held by an evdns_server_port.  Only called when the
+ * reference count is down to 0. */
+static void
+server_port_free(struct evdns_server_port *port)
+{
+	assert(port);
+	assert(!port->refcnt);
+	assert(!port->pending_replies);
+	if (port->socket > 0) {
+		CLOSE_SOCKET(port->socket);
+		port->socket = -1;
+	}
+	(void) event_del(&port->event);
+	CLEAR(&port->event);
+	CLEAR(port);
+	mm_free(port);
+}
+
+/* exported function */
+int
+evdns_server_request_drop(struct evdns_server_request *_req)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	server_request_free(req);
+	return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
+{
+	struct server_request *req = TO_SERVER_REQUEST(_req);
+	if (addr_len < (int)req->addrlen)
+		return -1;
+	memcpy(sa, &(req->addr), req->addrlen);
+	return req->addrlen;
+}
+
+#undef APPEND16
+#undef APPEND32
+
+/* this is a libevent callback function which is called when a request */
+/* has timed out. */
+static void
+evdns_request_timeout_callback(int fd, short events, void *arg) {
+	struct evdns_request *const req = (struct evdns_request *) arg;
+	(void) fd;
+	(void) events;
+
+	log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
+
+	req->ns->timedout++;
+	if (req->ns->timedout > global_max_nameserver_timeout) {
+		req->ns->timedout = 0;
+		nameserver_failed(req->ns, "request timed out.");
+	}
+
+	if (req->tx_count >= global_max_retransmits) {
+		/* this request has failed */
+		reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
+		request_finished(req, &req_head);
+	} else {
+		/* retransmit it */
+		/* Stop waiting for the timeout.  No need to do this in
+		 * request_finished; that one already deletes the timeout event.
+		 * XXXX023 port this change to libevent. */
+		del_timeout_event(req);
+		evdns_request_transmit(req);
+	}
+}
+
+/* try to send a request to a given server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 temporary failure */
+/* 2 other failure */
+static int
+evdns_request_transmit_to(struct evdns_request *req, struct nameserver *server) {
+	const ssize_t r = send(server->socket, (void*)req->request,
+                         req->request_len, 0);
+	if (r < 0) {
+		int err = last_error(server->socket);
+		if (error_is_eagain(err)) return 1;
+		nameserver_failed(req->ns, tor_socket_strerror(err));
+		return 2;
+	} else if (r != (ssize_t)req->request_len) {
+		return 1;  /* short write */
+	} else {
+		return 0;
+	}
+}
+
+/* try to send a request, updating the fields of the request */
+/* as needed */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed */
+static int
+evdns_request_transmit(struct evdns_request *req) {
+	int retcode = 0, r;
+
+	/* if we fail to send this packet then this flag marks it */
+	/* for evdns_transmit */
+	req->transmit_me = 1;
+	if (req->trans_id == 0xffff) abort();
+
+	if (req->ns->choked) {
+		/* don't bother trying to write to a socket */
+		/* which we have had EAGAIN from */
+		return 1;
+	}
+
+	r = evdns_request_transmit_to(req, req->ns);
+	switch (r) {
+	case 1:
+		/* temp failure */
+		req->ns->choked = 1;
+		nameserver_write_waiting(req->ns, 1);
+		return 1;
+	case 2:
+		/* failed to transmit the request entirely. */
+		retcode = 1;
+		/* fall through: we'll set a timeout, which will time out,
+		 * and make us retransmit the request anyway. */
+	default:
+		/* transmitted; we need to check for timeout. */
+		log(EVDNS_LOG_DEBUG,
+			"Setting timeout for request %lx", (unsigned long) req);
+
+		if (add_timeout_event(req, &global_timeout) < 0) {
+			log(EVDNS_LOG_WARN,
+				"Error from libevent when adding timer for request %lx",
+				(unsigned long) req);
+			/* ???? Do more? */
+		}
+		req->tx_count++;
+		req->transmit_me = 0;
+		return retcode;
+	}
+}
+
+static void
+nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
+	struct sockaddr *addr = arg;
+	struct nameserver *server;
+	(void) type;
+	(void) count;
+	(void) ttl;
+	(void) addresses;
+
+	for (server = server_head; server; server = server->next) {
+		if (sockaddr_eq(addr, (struct sockaddr*) &server->address, 1)) {
+			if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+				/* this is a good reply */
+				nameserver_up(server);
+			} else {
+				nameserver_probe_failed(server);
+			}
+		}
+		if (server->next == server_head)
+			break;
+	}
+
+	mm_free(addr);
+}
+
+static void
+nameserver_send_probe(struct nameserver *const ns) {
+	struct evdns_request *req;
+	struct sockaddr_storage *addr;
+	/* here we need to send a probe to a given nameserver */
+	/* in the hope that it is up now. */
+
+	/* We identify the nameserver by its address, in case it is removed before
+	 * our probe comes back. */
+	addr = mm_malloc(sizeof(struct sockaddr_storage));
+	memcpy(addr, &ns->address, sizeof(struct sockaddr_storage));
+
+	log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address));
+
+	req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, addr);
+	if (!req) {
+		mm_free(addr);
+		return;
+	}
+	/* we force this into the inflight queue no matter what */
+	request_trans_id_set(req, transaction_id_pick());
+	req->ns = ns;
+	request_submit(req);
+}
+
+/* returns: */
+/* 0 didn't try to transmit anything */
+/* 1 tried to transmit something */
+static int
+evdns_transmit(void) {
+	char did_try_to_transmit = 0;
+
+	if (req_head) {
+		struct evdns_request *const started_at = req_head, *req = req_head;
+		/* first transmit all the requests which are currently waiting */
+		do {
+			if (req->transmit_me) {
+				did_try_to_transmit = 1;
+				evdns_request_transmit(req);
+			}
+
+			req = req->next;
+		} while (req != started_at);
+	}
+
+	return did_try_to_transmit;
+}
+
+/* exported function */
+int
+evdns_count_nameservers(void)
+{
+	const struct nameserver *server = server_head;
+	int n = 0;
+	if (!server)
+		return 0;
+	do {
+		++n;
+		server = server->next;
+	} while (server != server_head);
+	return n;
+}
+
+/* exported function */
+int
+evdns_clear_nameservers_and_suspend(void)
+{
+	struct nameserver *server = server_head, *started_at = server_head;
+	struct evdns_request *req = req_head, *req_started_at = req_head;
+
+	if (!server)
+		return 0;
+	while (1) {
+		struct nameserver *next = server->next;
+		(void) event_del(&server->event);
+		CLEAR(&server->event);
+		del_timeout_event(server);
+		if (server->socket >= 0)
+			CLOSE_SOCKET(server->socket);
+		CLEAR(server);
+		mm_free(server);
+		if (next == started_at)
+			break;
+		server = next;
+	}
+	server_head = NULL;
+	global_good_nameservers = 0;
+
+	while (req) {
+		struct evdns_request *next = req->next;
+		req->tx_count = req->reissue_count = 0;
+		req->ns = NULL;
+		/* ???? What to do about searches? */
+		del_timeout_event(req);
+		req->trans_id = 0;
+		req->transmit_me = 0;
+
+		global_requests_waiting++;
+		evdns_request_insert(req, &req_waiting_head);
+		/* We want to insert these suspended elements at the front of
+		 * the waiting queue, since they were pending before any of
+		 * the waiting entries were added.	This is a circular list,
+		 * so we can just shift the start back by one.*/
+		req_waiting_head = req_waiting_head->prev;
+
+		if (next == req_started_at)
+			break;
+		req = next;
+	}
+	req_head = NULL;
+	global_requests_inflight = 0;
+
+	return 0;
+}
+
+static struct sockaddr_storage global_bind_address;
+static socklen_t global_bind_addrlen = 0;
+static int global_bind_addr_is_set = 0;
+void
+evdns_set_default_outgoing_bind_address(const struct sockaddr *addr,
+										socklen_t addrlen)
+{
+	memset(&global_bind_address, 0, sizeof(global_bind_address));
+	if (addr) {
+		assert(addrlen <= (socklen_t)sizeof(global_bind_address));
+		memcpy(&global_bind_address, addr, addrlen);
+		global_bind_addrlen = addrlen;
+		global_bind_addr_is_set = 1;
+	} else {
+		global_bind_addr_is_set = 0;
+	}
+}
+
+/* exported function */
+int
+evdns_resume(void)
+{
+	evdns_requests_pump_waiting_queue();
+	return 0;
+}
+
+static int
+sockaddr_is_loopback(const struct sockaddr *addr)
+{
+	static const char LOOPBACK_S6[16] =
+	    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
+	if (addr->sa_family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+		return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
+	} else if (addr->sa_family == AF_INET6) {
+		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+		return fast_memeq(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
+	}
+	return 0;
+}
+
+static int
+_evdns_nameserver_add_impl(const struct sockaddr *address,
+						   socklen_t addrlen) {
+	/* first check to see if we already have this nameserver */
+
+	const struct nameserver *server = server_head, *const started_at = server_head;
+	struct nameserver *ns;
+
+	int err = 0;
+	if (server) {
+		do {
+			if (sockaddr_eq(address, (struct sockaddr *)&server->address, 1)) {
+				log(EVDNS_LOG_DEBUG, "Duplicate nameserver.");
+				return 3;
+			}
+			server = server->next;
+		} while (server != started_at);
+	}
+	if (addrlen > (int)sizeof(ns->address)) {
+		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
+		return 2;
+	}
+
+	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
+	if (!ns) return -1;
+
+	memset(ns, 0, sizeof(struct nameserver));
+
+	evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
+
+	ns->socket = tor_open_socket(address->sa_family, SOCK_DGRAM, 0);
+	if (ns->socket < 0) { err = 1; goto out1; }
+#ifdef _WIN32
+	{
+		u_long nonblocking = 1;
+		ioctlsocket(ns->socket, FIONBIO, &nonblocking);
+	}
+#else
+	fcntl(ns->socket, F_SETFL, O_NONBLOCK);
+#endif
+
+	if (global_bind_addr_is_set &&
+	    !sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) {
+		if (bind(ns->socket, (struct sockaddr *)&global_bind_address,
+				 global_bind_addrlen) < 0) {
+			log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address.");
+			err = 2;
+			goto out2;
+		}
+	}
+
+	if (connect(ns->socket, address, addrlen) != 0) {
+		log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver.");
+		err = 2;
+		goto out2;
+	}
+
+	memcpy(&ns->address, address, addrlen);
+	ns->state = 1;
+	event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
+	if (event_add(&ns->event, NULL) < 0) {
+		log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver.");
+		err = 2;
+		goto out2;
+	}
+
+	log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address));
+
+	/* insert this nameserver into the list of them */
+	if (!server_head) {
+		ns->next = ns->prev = ns;
+		server_head = ns;
+	} else {
+		ns->next = server_head->next;
+		ns->prev = server_head;
+		server_head->next = ns;
+		if (server_head->prev == server_head) {
+			server_head->prev = ns;
+		}
+	}
+
+	global_good_nameservers++;
+
+	return 0;
+
+out2:
+	CLOSE_SOCKET(ns->socket);
+out1:
+	CLEAR(ns);
+	mm_free(ns);
+	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err);
+	return err;
+}
+
+/* exported function */
+int
+evdns_nameserver_add(uint32_t address) {
+	struct sockaddr_in sin;
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+	sin.sin_len = sizeof(sin);
+#endif
+	sin.sin_addr.s_addr = htonl(address);
+	sin.sin_port = 53;
+	return _evdns_nameserver_add_impl((struct sockaddr*) &sin, sizeof(sin));
+}
+
+/* exported function */
+int
+evdns_nameserver_ip_add(const char *ip_as_string) {
+	int port;
+	char buf[128];
+	const char *cp, *addr_part, *port_part;
+	int is_ipv6;
+	/* recognized formats are:
+	 * [ipv6]:port
+	 * ipv6
+	 * [ipv6]
+	 * ipv4:port
+	 * ipv4
+	 */
+
+	log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string);
+
+	cp = strchr(ip_as_string, ':');
+	if (*ip_as_string == '[') {
+		size_t len;
+		if (!(cp = strchr(ip_as_string, ']'))) {
+			log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]");
+			return 4;
+		}
+		len = cp-(ip_as_string + 1);
+		if (len > sizeof(buf)-1) {
+			log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer.");
+			return 4;
+		}
+		memcpy(buf, ip_as_string+1, len);
+		buf[len] = '\0';
+		addr_part = buf;
+		if (cp[1] == ':')
+			port_part = cp+2;
+		else
+			port_part = NULL;
+		is_ipv6 = 1;
+	} else if (cp && strchr(cp+1, ':')) {
+		is_ipv6 = 1;
+		addr_part = ip_as_string;
+		port_part = NULL;
+	} else if (cp) {
+		is_ipv6 = 0;
+		if (cp - ip_as_string > (int)sizeof(buf)-1) {
+			log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer.");
+			return 4;
+		}
+		memcpy(buf, ip_as_string, cp-ip_as_string);
+		buf[cp-ip_as_string] = '\0';
+		addr_part = buf;
+		port_part = cp+1;
+	} else {
+		addr_part = ip_as_string;
+		port_part = NULL;
+		is_ipv6 = 0;
+	}
+
+	if (port_part == NULL) {
+		port = 53;
+	} else {
+		port = strtoint(port_part);
+		if (port <= 0 || port > 65535) {
+			log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range",
+				port_part);
+			return 4;
+		}
+	}
+
+	/* Tor-only.  needs a more general fix. */
+	assert(addr_part);
+	if (is_ipv6) {
+		struct sockaddr_in6 sin6;
+		memset(&sin6, 0, sizeof(sin6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
+		sin6.sin6_len = sizeof(sin6);
+#endif
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_port = htons(port);
+		if (1 != tor_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr)) {
+			log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
+			return 4;
+		}
+		return _evdns_nameserver_add_impl((struct sockaddr*)&sin6,
+										  sizeof(sin6));
+	} else {
+		struct sockaddr_in sin;
+		memset(&sin, 0, sizeof(sin));
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+		sin.sin_len = sizeof(sin);
+#endif
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(port);
+		if (!inet_aton(addr_part, &sin.sin_addr)) {
+			log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
+			return 4;
+		}
+		return _evdns_nameserver_add_impl((struct sockaddr*)&sin,
+										  sizeof(sin));
+	}
+}
+
+int
+evdns_nameserver_sockaddr_add(const struct sockaddr *sa, socklen_t len)
+{
+	return _evdns_nameserver_add_impl(sa, len);
+}
+
+/* insert into the tail of the queue */
+static void
+evdns_request_insert(struct evdns_request *req, struct evdns_request **head) {
+	if (!*head) {
+		*head = req;
+		req->next = req->prev = req;
+		return;
+	}
+
+	req->prev = (*head)->prev;
+	req->prev->next = req;
+	req->next = *head;
+	(*head)->prev = req;
+}
+
+static int
+string_num_dots(const char *s) {
+	int count = 0;
+	while ((s = strchr(s, '.'))) {
+		s++;
+		count++;
+	}
+	return count;
+}
+
+static struct evdns_request *
+request_new(int type, const char *name, int flags,
+	evdns_callback_type callback, void *user_ptr) {
+	const char issuing_now =
+		(global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
+
+	const size_t name_len = strlen(name);
+	const size_t request_max_len = evdns_request_len(name_len);
+	const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
+	/* the request data is alloced in a single block with the header */
+	struct evdns_request *const req =
+		(struct evdns_request *) mm_malloc(sizeof(struct evdns_request) + request_max_len);
+	char namebuf[256];
+	int rlen;
+	(void) flags;
+
+	if (!req) return NULL;
+
+	if (name_len >= sizeof(namebuf)) {
+		_mm_free(req);
+		return NULL;
+	}
+
+	memset(req, 0, sizeof(struct evdns_request));
+
+	evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
+
+	if (global_randomize_case) {
+		unsigned i;
+		char randbits[32];
+		strlcpy(namebuf, name, sizeof(namebuf));
+		rand_bytes_function(randbits, (name_len+7)/8);
+		for (i = 0; i < name_len; ++i) {
+			if (ISALPHA(namebuf[i])) {
+				if ((randbits[i >> 3] & (1<<(i%7))))
+					namebuf[i] = TOLOWER(namebuf[i]);
+				else
+					namebuf[i] = TOUPPER(namebuf[i]);
+			}
+		}
+		name = namebuf;
+	}
+
+	/* request data lives just after the header */
+	req->request = ((u8 *) req) + sizeof(struct evdns_request);
+	/* denotes that the request data shouldn't be mm_free()ed */
+	req->request_appended = 1;
+	rlen = evdns_request_data_build(name, name_len, trans_id,
+							type, CLASS_INET, req->request, request_max_len);
+	if (rlen < 0)
+		goto err1;
+	req->request_len = rlen;
+	req->trans_id = trans_id;
+	req->tx_count = 0;
+	req->request_type = type;
+	req->user_pointer = user_ptr;
+	req->user_callback = callback;
+	req->ns = issuing_now ? nameserver_pick() : NULL;
+	req->next = req->prev = NULL;
+
+	return req;
+err1:
+	CLEAR(req);
+	_mm_free(req);
+	return NULL;
+}
+
+static void
+request_submit(struct evdns_request *const req) {
+	if (req->ns) {
+		/* if it has a nameserver assigned then this is going */
+		/* straight into the inflight queue */
+		evdns_request_insert(req, &req_head);
+		global_requests_inflight++;
+		evdns_request_transmit(req);
+	} else {
+		evdns_request_insert(req, &req_waiting_head);
+		global_requests_waiting++;
+	}
+}
+
+/* exported function */
+int evdns_resolve_ipv4(const char *name, int flags,
+					   evdns_callback_type callback, void *ptr) {
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+	if (flags & DNS_QUERY_NO_SEARCH) {
+		struct evdns_request *const req =
+			request_new(TYPE_A, name, flags, callback, ptr);
+		if (req == NULL)
+			return (1);
+		request_submit(req);
+		return (0);
+	} else {
+		return (search_request_new(TYPE_A, name, flags, callback, ptr));
+	}
+}
+
+/* exported function */
+int evdns_resolve_ipv6(const char *name, int flags,
+					   evdns_callback_type callback, void *ptr) {
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+	if (flags & DNS_QUERY_NO_SEARCH) {
+		struct evdns_request *const req =
+			request_new(TYPE_AAAA, name, flags, callback, ptr);
+		if (req == NULL)
+			return (1);
+		request_submit(req);
+		return (0);
+	} else {
+		return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
+	}
+}
+
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+	char buf[32];
+	struct evdns_request *req;
+	u32 a;
+	assert(in);
+	a = ntohl(in->s_addr);
+	snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+			(int)(u8)((a	)&0xff),
+			(int)(u8)((a>>8 )&0xff),
+			(int)(u8)((a>>16)&0xff),
+			(int)(u8)((a>>24)&0xff));
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+	if (!req) return 1;
+	request_submit(req);
+	return 0;
+}
+
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+	char buf[73];
+	char *cp;
+	struct evdns_request *req;
+	int i;
+	assert(in);
+	cp = buf;
+	for (i=15; i >= 0; --i) {
+		u8 byte = in->s6_addr[i];
+		*cp++ = "0123456789abcdef"[byte & 0x0f];
+		*cp++ = '.';
+		*cp++ = "0123456789abcdef"[byte >> 4];
+		*cp++ = '.';
+	}
+	assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
+	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+	if (!req) return 1;
+	request_submit(req);
+	return 0;
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Search support */
+/* */
+/* the libc resolver has support for searching a number of domains */
+/* to find a name. If nothing else then it takes the single domain */
+/* from the gethostname() call. */
+/* */
+/* It can also be configured via the domain and search options in a */
+/* resolv.conf. */
+/* */
+/* The ndots option controls how many dots it takes for the resolver */
+/* to decide that a name is non-local and so try a raw lookup first. */
+
+struct search_domain {
+	size_t len;
+	struct search_domain *next;
+	/* the text string is appended to this structure */
+};
+
+struct search_state {
+	int refcount;
+	int ndots;
+	int num_domains;
+	struct search_domain *head;
+};
+
+static struct search_state *global_search_state = NULL;
+
+static void
+search_state_decref(struct search_state *const state) {
+	if (!state) return;
+	state->refcount--;
+	if (!state->refcount) {
+		struct search_domain *next, *dom;
+		for (dom = state->head; dom; dom = next) {
+			next = dom->next;
+			CLEAR(dom);
+			_mm_free(dom);
+		}
+		CLEAR(state);
+		_mm_free(state);
+	}
+}
+
+static struct search_state *
+search_state_new(void) {
+	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
+	if (!state) return NULL;
+	memset(state, 0, sizeof(struct search_state));
+	state->refcount = 1;
+	state->ndots = 1;
+
+	return state;
+}
+
+static void
+search_postfix_clear(void) {
+	search_state_decref(global_search_state);
+
+	global_search_state = search_state_new();
+}
+
+/* exported function */
+void
+evdns_search_clear(void) {
+	search_postfix_clear();
+}
+
+static void
+search_postfix_add(const char *domain) {
+	size_t domain_len;
+	struct search_domain *sdomain;
+	while (domain[0] == '.') domain++;
+	domain_len = strlen(domain);
+
+	if (!global_search_state) global_search_state = search_state_new();
+		if (!global_search_state) return;
+	global_search_state->num_domains++;
+
+	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
+		if (!sdomain) return;
+	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
+	sdomain->next = global_search_state->head;
+	sdomain->len = domain_len;
+
+	global_search_state->head = sdomain;
+}
+
+/* reverse the order of members in the postfix list. This is needed because, */
+/* when parsing resolv.conf we push elements in the wrong order */
+static void
+search_reverse(void) {
+	struct search_domain *cur, *prev = NULL, *next;
+	cur = global_search_state->head;
+	while (cur) {
+		next = cur->next;
+		cur->next = prev;
+		prev = cur;
+		cur = next;
+	}
+
+	global_search_state->head = prev;
+}
+
+/* exported function */
+void
+evdns_search_add(const char *domain) {
+	search_postfix_add(domain);
+}
+
+/* exported function */
+void
+evdns_search_ndots_set(const int ndots) {
+	if (!global_search_state) global_search_state = search_state_new();
+		if (!global_search_state) return;
+	global_search_state->ndots = ndots;
+}
+
+static void
+search_set_from_hostname(void) {
+	char hostname[HOST_NAME_MAX + 1], *domainname;
+
+	search_postfix_clear();
+	if (gethostname(hostname, sizeof(hostname))) return;
+	domainname = strchr(hostname, '.');
+	if (!domainname) return;
+	search_postfix_add(domainname);
+}
+
+/* warning: returns malloced string */
+static char *
+search_make_new(const struct search_state *const state, int n, const char *const base_name) {
+	const size_t base_len = strlen(base_name);
+	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+	struct search_domain *dom;
+
+	for (dom = state->head; dom; dom = dom->next) {
+		if (!n--) {
+			/* this is the postfix we want */
+			/* the actual postfix string is kept at the end of the structure */
+			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
+			const size_t postfix_len = dom->len;
+			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
+			if (!newname) return NULL;
+			memcpy(newname, base_name, base_len);
+			if (need_to_append_dot) newname[base_len] = '.';
+			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
+			newname[base_len + need_to_append_dot + postfix_len] = 0;
+			return newname;
+		}
+	}
+
+	/* we ran off the end of the list and still didn't find the requested string */
+	abort();
+	return NULL; /* unreachable; stops warnings in some compilers. */
+}
+
+static int
+search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
+	assert(type == TYPE_A || type == TYPE_AAAA);
+	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
+		 global_search_state &&
+		 global_search_state->num_domains) {
+		/* we have some domains to search */
+		struct evdns_request *req;
+		if (string_num_dots(name) >= global_search_state->ndots) {
+			req = request_new(type, name, flags, user_callback, user_arg);
+			if (!req) return 1;
+			req->search_index = -1;
+		} else {
+			char *const new_name = search_make_new(global_search_state, 0, name);
+						if (!new_name) return 1;
+			req = request_new(type, new_name, flags, user_callback, user_arg);
+			_mm_free(new_name);
+			if (!req) return 1;
+			req->search_index = 0;
+		}
+		req->search_origname = mm_strdup(name);
+		req->search_state = global_search_state;
+		req->search_flags = flags;
+		global_search_state->refcount++;
+		request_submit(req);
+		return 0;
+	} else {
+		struct evdns_request *const req = request_new(type, name, flags, user_callback, user_arg);
+		if (!req) return 1;
+		request_submit(req);
+		return 0;
+	}
+}
+
+/* this is called when a request has failed to find a name. We need to check */
+/* if it is part of a search and, if so, try the next name in the list */
+/* returns: */
+/* 0 another request has been submitted */
+/* 1 no more requests needed */
+static int
+search_try_next(struct evdns_request *const req) {
+	if (req->search_state) {
+		/* it is part of a search */
+		char *new_name;
+		struct evdns_request *newreq;
+		req->search_index++;
+		if (req->search_index >= req->search_state->num_domains) {
+			/* no more postfixes to try, however we may need to try */
+			/* this name without a postfix */
+			if (string_num_dots(req->search_origname) < req->search_state->ndots) {
+				/* yep, we need to try it raw */
+				struct evdns_request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
+				if (newreq) {
+					request_submit(newreq);
+					return 0;
+				}
+			}
+			return 1;
+		}
+
+		new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
+				if (!new_name) return 1;
+		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
+		newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
+		mm_free(new_name);
+		if (!newreq) return 1;
+		newreq->search_origname = req->search_origname;
+		req->search_origname = NULL;
+		newreq->search_state = req->search_state;
+		newreq->search_flags = req->search_flags;
+		newreq->search_index = req->search_index;
+		newreq->search_state->refcount++;
+		request_submit(newreq);
+		return 0;
+	}
+	return 1;
+}
+
+static void
+search_request_finished(struct evdns_request *const req) {
+	if (req->search_state) {
+		search_state_decref(req->search_state);
+		req->search_state = NULL;
+	}
+	if (req->search_origname) {
+		mm_free(req->search_origname);
+		req->search_origname = NULL;
+	}
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Parsing resolv.conf files */
+
+static void
+evdns_resolv_set_defaults(int flags) {
+	/* if the file isn't found then we assume a local resolver */
+	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
+	if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
+}
+
+/* helper version of atoi which returns -1 on error */
+static int
+strtoint(const char *const str) {
+	char *endptr;
+	const long r = strtol(str, &endptr, 10);
+	if (*endptr || r > INT_MAX) return -1;
+	return (int)r;
+}
+
+/* helper version of atoi that returns -1 on error and clips to bounds. */
+static int
+strtoint_clipped(const char *const str, int min, int max)
+{
+	int r = strtoint(str);
+	if (r == -1)
+		return r;
+	else if (r<min)
+		return min;
+	else if (r>max)
+		return max;
+	else
+		return r;
+}
+
+/* exported function */
+int
+evdns_set_option(const char *option, const char *val, int flags)
+{
+	if (!strncmp(option, "ndots:", 6)) {
+		const int ndots = strtoint(val);
+		if (ndots == -1) return -1;
+		if (!(flags & DNS_OPTION_SEARCH)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
+		if (!global_search_state) global_search_state = search_state_new();
+		if (!global_search_state) return -1;
+		global_search_state->ndots = ndots;
+	} else if (!strncmp(option, "timeout:", 8)) {
+		const int timeout = strtoint(val);
+		if (timeout == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
+		global_timeout.tv_sec = timeout;
+	} else if (!strncmp(option, "max-timeouts:", 12)) {
+		const int maxtimeout = strtoint_clipped(val, 1, 255);
+		if (maxtimeout == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
+			maxtimeout);
+		global_max_nameserver_timeout = maxtimeout;
+	} else if (!strncmp(option, "max-inflight:", 13)) {
+		const int maxinflight = strtoint_clipped(val, 1, 65000);
+		if (maxinflight == -1) return -1;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
+			maxinflight);
+		global_max_requests_inflight = maxinflight;
+	} else if (!strncmp(option, "attempts:", 9)) {
+		int retries = strtoint(val);
+		if (retries == -1) return -1;
+		if (retries > 255) retries = 255;
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
+		global_max_retransmits = retries;
+	} else if (!strncmp(option, "randomize-case:", 15)) {
+		int randcase = strtoint(val);
+		if (!(flags & DNS_OPTION_MISC)) return 0;
+		log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase);
+		global_randomize_case = randcase;
+	}
+	return 0;
+}
+
+static void
+resolv_conf_parse_line(char *const start, int flags) {
+	char *strtok_state;
+	static const char *const delims = " \t";
+#define NEXT_TOKEN tor_strtok_r(NULL, delims, &strtok_state)
+
+	char *const first_token = tor_strtok_r(start, delims, &strtok_state);
+	if (!first_token) return;
+
+	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
+		const char *const nameserver = NEXT_TOKEN;
+		evdns_nameserver_ip_add(nameserver);
+	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
+		const char *const domain = NEXT_TOKEN;
+		if (domain) {
+			search_postfix_clear();
+			search_postfix_add(domain);
+		}
+	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
+		const char *domain;
+		search_postfix_clear();
+
+		while ((domain = NEXT_TOKEN)) {
+			search_postfix_add(domain);
+		}
+		search_reverse();
+	} else if (!strcmp(first_token, "options")) {
+		const char *option;
+		while ((option = NEXT_TOKEN)) {
+			const char *val = strchr(option, ':');
+			evdns_set_option(option, val ? val+1 : "", flags);
+		}
+	}
+#undef NEXT_TOKEN
+}
+
+/* exported function */
+/* returns: */
+/* 0 no errors */
+/* 1 failed to open file */
+/* 2 failed to stat file */
+/* 3 file too large */
+/* 4 out of memory */
+/* 5 short read from file */
+int
+evdns_resolv_conf_parse(int flags, const char *const filename) {
+	struct stat st;
+	int fd, n, r;
+	u8 *resolv;
+	char *start;
+	int err = 0;
+
+	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
+
+	fd = tor_open_cloexec(filename, O_RDONLY, 0);
+	if (fd < 0) {
+		evdns_resolv_set_defaults(flags);
+		return 1;
+	}
+
+	if (fstat(fd, &st)) { err = 2; goto out1; }
+	if (!st.st_size) {
+		evdns_resolv_set_defaults(flags);
+		err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
+		goto out1;
+	}
+	if (st.st_size > 65535) { err = 3; goto out1; }	 /* no resolv.conf should be any bigger */
+
+	resolv = (u8 *) mm_malloc((size_t)st.st_size + 1);
+	if (!resolv) { err = 4; goto out1; }
+
+    n = 0;
+	while ((r = (int)read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
+		n += r;
+		if (n == st.st_size)
+			break;
+		assert(n < st.st_size);
+	}
+	if (r < 0) { err = 5; goto out2; }
+	resolv[n] = 0;	 /* we malloced an extra byte; this should be fine. */
+
+	start = (char *) resolv;
+	for (;;) {
+		char *const newline = strchr(start, '\n');
+		if (!newline) {
+			resolv_conf_parse_line(start, flags);
+			break;
+		} else {
+			*newline = 0;
+			resolv_conf_parse_line(start, flags);
+			start = newline + 1;
+		}
+	}
+
+	if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+		/* no nameservers were configured. */
+		evdns_nameserver_ip_add("127.0.0.1");
+		err = 6;
+	}
+	if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
+		search_set_from_hostname();
+	}
+
+out2:
+	mm_free(resolv);
+out1:
+	close(fd);
+	return err;
+}
+
+#ifdef _WIN32
+/* Add multiple nameservers from a space-or-comma-separated list. */
+static int
+evdns_nameserver_ip_add_line(const char *ips) {
+	const char *addr;
+	char *buf;
+	int r;
+	while (*ips) {
+		while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
+			++ips;
+		addr = ips;
+		while (ISDIGIT(*ips) || *ips == '.' || *ips == ':' || *ips == '[' || *ips == ']')
+			++ips;
+		buf = mm_malloc(ips-addr+1);
+		if (!buf) return 4;
+		memcpy(buf, addr, ips-addr);
+		buf[ips-addr] = '\0';
+		r = evdns_nameserver_ip_add(buf);
+		mm_free(buf);
+		if (r) return r;
+	}
+	return 0;
+}
+
+typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
+
+/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
+/* figure out what our nameservers are. */
+static int
+load_nameservers_with_getnetworkparams(void)
+{
+	/* Based on MSDN examples and inspection of	 c-ares code. */
+	FIXED_INFO *fixed;
+	HMODULE handle = 0;
+	ULONG size = sizeof(FIXED_INFO);
+	void *buf = NULL;
+	int status = 0, r, added_any;
+	IP_ADDR_STRING *ns;
+	GetNetworkParams_fn_t fn;
+
+	if (!(handle = load_windows_system_library(TEXT("iphlpapi.dll")))) {
+		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
+		/* right now status = 0, doesn't that mean "good" - mikec */
+		status = -1;
+		goto done;
+	}
+	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, TEXT("GetNetworkParams")))) {
+		log(EVDNS_LOG_WARN, "Could not get address of function.");
+		/* same as above */
+		status = -1;
+		goto done;
+	}
+
+	buf = mm_malloc(size);
+	if (!buf) { status = 4; goto done; }
+	fixed = buf;
+	r = fn(fixed, &size);
+	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
+		status = -1;
+		goto done;
+	}
+	if (r != ERROR_SUCCESS) {
+		mm_free(buf);
+		buf = mm_malloc(size);
+		if (!buf) { status = 4; goto done; }
+		fixed = buf;
+		r = fn(fixed, &size);
+		if (r != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG, "fn() failed.");
+			status = -1;
+			goto done;
+		}
+	}
+
+	assert(fixed);
+	added_any = 0;
+	ns = &(fixed->DnsServerList);
+	while (ns) {
+		r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
+		if (r) {
+			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, "
+				"error: %d; status: %d",
+				(ns->IpAddress.String),(int)GetLastError(), r);
+			status = r;
+		} else {
+			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
+			added_any++;
+		}
+
+		ns = ns->Next;
+	}
+
+	if (!added_any) {
+		log(EVDNS_LOG_DEBUG, "No nameservers added.");
+		if (status == 0)
+			status = -1;
+	} else {
+		status = 0;
+	}
+
+ done:
+	if (buf)
+		mm_free(buf);
+	if (handle)
+		FreeLibrary(handle);
+	return status;
+}
+
+static int
+config_nameserver_from_reg_key(HKEY key, const TCHAR *subkey)
+{
+	char *buf;
+	char ansibuf[MAX_PATH] = {0};
+	DWORD bufsz = 0, type = 0;
+	int status = 0;
+
+	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
+		!= ERROR_MORE_DATA)
+		return -1;
+	if (!(buf = mm_malloc(bufsz)))
+		return -1;
+
+	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
+		== ERROR_SUCCESS && bufsz > 1) {
+		wcstombs(ansibuf,(wchar_t*)buf,MAX_PATH);/*XXXX UNICODE */
+		abuf[MAX_PATH-1] = '\0';
+		status = evdns_nameserver_ip_add_line(ansibuf);
+	}
+
+	mm_free(buf);
+	return status;
+}
+
+#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
+#define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
+#define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
+
+static int
+load_nameservers_from_registry(void)
+{
+	int found = 0;
+	int r;
+	OSVERSIONINFO info;
+	memset(&info, 0, sizeof(info));
+	info.dwOSVersionInfoSize = sizeof (info);
+	GetVersionEx(&info);
+
+#define TRY(k, name)													\
+	if (!found && config_nameserver_from_reg_key(k,TEXT(name)) == 0) {	\
+		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name);		\
+		found = 1;														\
+	} else if (!found) {												\
+		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s",			\
+			#k,#name);													\
+	}
+
+	if (info.dwMajorVersion >= 5) { /* NT */
+		HKEY nt_key = 0, interfaces_key = 0;
+
+		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+						 KEY_READ, &nt_key) != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+			return -1;
+		}
+		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
+						 KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
+						 &interfaces_key);
+		if (r != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+			return -1;
+		}
+		TRY(nt_key, "NameServer");
+		TRY(nt_key, "DhcpNameServer");
+		TRY(interfaces_key, "NameServer");
+		TRY(interfaces_key, "DhcpNameServer");
+		RegCloseKey(interfaces_key);
+		RegCloseKey(nt_key);
+	} else {
+		HKEY win_key = 0;
+		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+						 KEY_READ, &win_key) != ERROR_SUCCESS) {
+			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
+			return -1;
+		}
+		TRY(win_key, "NameServer");
+		RegCloseKey(win_key);
+	}
+
+	if (found == 0) {
+		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
+	}
+
+	return found ? 0 : -1;
+#undef TRY
+}
+
+int
+evdns_config_windows_nameservers(void)
+{
+	if (load_nameservers_with_getnetworkparams() == 0)
+		return 0;
+	return load_nameservers_from_registry();
+}
+#endif
+
+int
+evdns_init(void)
+{
+		int res = 0;
+#ifdef _WIN32
+		evdns_config_windows_nameservers();
+#else
+		res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+#endif
+
+		return (res);
+}
+
+const char *
+evdns_err_to_string(int err)
+{
+	switch (err) {
+	case DNS_ERR_NONE: return "no error";
+	case DNS_ERR_FORMAT: return "misformatted query";
+	case DNS_ERR_SERVERFAILED: return "server failed";
+	case DNS_ERR_NOTEXIST: return "name does not exist";
+	case DNS_ERR_NOTIMPL: return "query not implemented";
+	case DNS_ERR_REFUSED: return "refused";
+
+	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
+	case DNS_ERR_UNKNOWN: return "unknown";
+	case DNS_ERR_TIMEOUT: return "request timed out";
+	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
+	default: return "[Unknown error code]";
+	}
+}
+
+void
+evdns_shutdown(int fail_requests)
+{
+	struct nameserver *server, *server_next;
+	struct search_domain *dom, *dom_next;
+
+	while (req_head) {
+		if (fail_requests)
+			reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
+		request_finished(req_head, &req_head);
+	}
+	while (req_waiting_head) {
+		if (fail_requests)
+			reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
+		request_finished(req_waiting_head, &req_waiting_head);
+	}
+	global_requests_inflight = global_requests_waiting = 0;
+
+	for (server = server_head; server; server = server_next) {
+		server_next = server->next;
+		if (server->socket >= 0)
+			CLOSE_SOCKET(server->socket);
+		(void) event_del(&server->event);
+		del_timeout_event(server);
+		CLEAR(server);
+		mm_free(server);
+		if (server_next == server_head)
+			break;
+	}
+	server_head = NULL;
+	global_good_nameservers = 0;
+
+	if (global_search_state) {
+		for (dom = global_search_state->head; dom; dom = dom_next) {
+			dom_next = dom->next;
+			CLEAR(dom);
+			mm_free(dom);
+		}
+		CLEAR(global_search_state);
+		mm_free(global_search_state);
+		global_search_state = NULL;
+	}
+	evdns_log_fn = NULL;
+}
+
+#ifdef EVDNS_MAIN
+void
+main_callback(int result, char type, int count, int ttl,
+			  void *addrs, void *orig) {
+	char *n = (char*)orig;
+	int i;
+	for (i = 0; i < count; ++i) {
+		if (type == DNS_IPv4_A) {
+			printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
+		} else if (type == DNS_PTR) {
+			printf("%s: %s\n", n, ((char**)addrs)[i]);
+		}
+	}
+	if (!count) {
+		printf("%s: No answer (%d)\n", n, result);
+	}
+	fflush(stdout);
+}
+void
+evdns_server_callback(struct evdns_server_request *req, void *data)
+{
+	int i, r;
+	(void)data;
+	/* dummy; give 192.168.11.11 as an answer for all A questions,
+	 *	give foo.bar.example.com as an answer for all PTR questions. */
+	for (i = 0; i < req->nquestions; ++i) {
+		u32 ans = htonl(0xc0a80b0bUL);
+		if (req->questions[i]->type == EVDNS_TYPE_A &&
+			req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+			printf(" -- replying for %s (A)\n", req->questions[i]->name);
+			r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
+										  1, &ans, 10);
+			if (r<0)
+				printf("eeep, didn't work.\n");
+		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
+				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+			printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
+			r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
+											"foo.bar.example.com", 10);
+		} else {
+			printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
+				   req->questions[i]->type, req->questions[i]->dns_question_class);
+		}
+	}
+
+	r = evdns_server_request_respond(req, 0);
+	if (r<0)
+		printf("eeek, couldn't send reply.\n");
+}
+
+void
+logfn(int is_warn, const char *msg) {
+	(void) is_warn;
+	fprintf(stderr, "%s\n", msg);
+}
+int
+main(int c, char **v) {
+	int idx;
+	int reverse = 0, verbose = 1, servertest = 0;
+	if (c<2) {
+		fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
+		fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
+		return 1;
+	}
+	idx = 1;
+	while (idx < c && v[idx][0] == '-') {
+		if (!strcmp(v[idx], "-x"))
+			reverse = 1;
+		else if (!strcmp(v[idx], "-v"))
+			verbose = 1;
+		else if (!strcmp(v[idx], "-servertest"))
+			servertest = 1;
+		else
+			fprintf(stderr, "Unknown option %s\n", v[idx]);
+		++idx;
+	}
+	event_init();
+	if (verbose)
+		evdns_set_log_fn(logfn);
+	evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
+	if (servertest) {
+		int sock;
+		struct sockaddr_in my_addr;
+		sock = tor_open_socket(PF_INET, SOCK_DGRAM, 0);
+		fcntl(sock, F_SETFL, O_NONBLOCK);
+		my_addr.sin_family = AF_INET;
+		my_addr.sin_port = htons(10053);
+		my_addr.sin_addr.s_addr = INADDR_ANY;
+		if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
+			perror("bind");
+			exit(1);
+		}
+		evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
+	}
+	for (; idx < c; ++idx) {
+		if (reverse) {
+			struct in_addr addr;
+			if (!inet_aton(v[idx], &addr)) {
+				fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
+				continue;
+			}
+			fprintf(stderr, "resolving %s...\n",v[idx]);
+			evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
+		} else {
+			fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
+			evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
+		}
+	}
+	fflush(stdout);
+	event_dispatch();
+	return 0;
+}
+#endif
+
+/* Local Variables: */
+/* tab-width: 4 */
+/* c-basic-offset: 4 */
+/* indent-tabs-mode: t */
+/* End: */
+
diff --git a/src/ext/eventdns.h b/src/ext/eventdns.h
new file mode 100644
index 0000000..1c130b2
--- /dev/null
+++ b/src/ext/eventdns.h
@@ -0,0 +1,337 @@
+
+/*
+ * The original DNS code is due to Adam Langley with heavy
+ * modifications by Nick Mathewson.  Adam put his DNS software in the
+ * public domain.  You can find his original copyright below.  Please,
+ * aware that the code as part of libevent is governed by the 3-clause
+ * BSD license above.
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ *	Parts developed by Adam Langley <agl at imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ */
+
+/*
+ * Welcome, gentle reader
+ *
+ * Async DNS lookups are really a whole lot harder than they should be,
+ * mostly stemming from the fact that the libc resolver has never been
+ * very good at them. Before you use this library you should see if libc
+ * can do the job for you with the modern async call getaddrinfo_a
+ * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+ * please continue.
+ *
+ * This code is based on libevent and you must call event_init before
+ * any of the APIs in this file. You must also seed the OpenSSL random
+ * source if you are using OpenSSL for ids (see below).
+ *
+ * This library is designed to be included and shipped with your source
+ * code. You statically link with it. You should also test for the
+ * existence of strtok_r and define HAVE_STRTOK_R if you have it.
+ *
+ * The DNS protocol requires a good source of id numbers and these
+ * numbers should be unpredictable for spoofing reasons. There are
+ * three methods for generating them here and you must define exactly
+ * one of them. In increasing order of preference:
+ *
+ * DNS_USE_GETTIMEOFDAY_FOR_ID:
+ *   Using the bottom 16 bits of the usec result from gettimeofday. This
+ *   is a pretty poor solution but should work anywhere.
+ * DNS_USE_CPU_CLOCK_FOR_ID:
+ *  Using the bottom 16 bits of the nsec result from the CPU's time
+ *  counter. This is better, but may not work everywhere. Requires
+ *  POSIX realtime support and you'll need to link against -lrt on
+ *  glibc systems at least.
+ * DNS_USE_OPENSSL_FOR_ID:
+ *  Uses the OpenSSL RAND_bytes call to generate the data. You must
+ *  have seeded the pool before making any calls to this library.
+ *
+ * The library keeps track of the state of nameservers and will avoid
+ * them when they go down. Otherwise it will round robin between them.
+ *
+ * Quick start guide:
+ *	 #include "evdns.h"
+ *	 void callback(int result, char type, int count, int ttl,
+ *     void *addresses, void *arg);
+ *	 evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ *	 evdns_resolve("www.hostname.com", 0, callback, NULL);
+ *
+ * When the lookup is complete the callback function is called. The
+ * first argument will be one of the DNS_ERR_* defines in evdns.h.
+ * Hopefully it will be DNS_ERR_NONE, in which case type will be
+ * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+ * which the data can be cached for (in seconds), addresses will point
+ * to an array of uint32_t's and arg will be whatever you passed to
+ * evdns_resolve.
+ *
+ * Searching:
+ *
+ * In order for this library to be a good replacement for glibc's resolver it
+ * supports searching. This involves setting a list of default domains, in
+ * which names will be queried for. The number of dots in the query name
+ * determines the order in which this list is used.
+ *
+ * Searching appears to be a single lookup from the point of view of the API,
+ * although many DNS queries may be generated from a single call to
+ * evdns_resolve. Searching can also drastically slow down the resolution
+ * of names.
+ *
+ * To disable searching:
+ *	 1. Never set it up. If you never call evdns_resolv_conf_parse or
+ *   evdns_search_add then no searching will occur.
+ *
+ *	 2. If you do call evdns_resolv_conf_parse then don't pass
+ *   DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
+ *
+ *	 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
+ *
+ * The order of searches depends on the number of dots in the name. If the
+ * number is greater than the ndots setting then the names is first tried
+ * globally. Otherwise each search domain is appended in turn.
+ *
+ * The ndots setting can either be set from a resolv.conf, or by calling
+ * evdns_search_ndots_set.
+ *
+ * For example, with ndots set to 1 (the default) and a search domain list of
+ * ["myhome.net"]:
+ *	Query: www
+ *	Order: www.myhome.net, www.
+ *
+ *	Query: www.abc
+ *	Order: www.abc., www.abc.myhome.net
+ *
+ * API reference:
+ *
+ * int evdns_nameserver_add(uint32_t address)
+ *	 Add a nameserver. The address should be an IP address in
+ *	 network byte order. The type of address is chosen so that
+ *	 it matches in_addr.s_addr.
+ *	 Returns non-zero on error.
+ *
+ * int evdns_nameserver_ip_add(const char *ip_as_string)
+ *	 This wraps the above function by parsing a string as an IP
+ *	 address and adds it as a nameserver.
+ *	 Returns non-zero on error
+ *
+ * int evdns_resolve(const char *name, int flags,
+ *	      evdns_callback_type callback,
+ *	      void *ptr)
+ *	 Resolve a name. The name parameter should be a DNS name.
+ *	 The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
+ *	 which disables searching for this query. (see defn of
+ *	 searching above).
+ *
+ *	 The callback argument is a function which is called when
+ *	 this query completes and ptr is an argument which is passed
+ *	 to that callback function.
+ *
+ *	 Returns non-zero on error
+ *
+ * void evdns_search_clear()
+ *	 Clears the list of search domains
+ *
+ * void evdns_search_add(const char *domain)
+ *	 Add a domain to the list of search domains
+ *
+ * void evdns_search_ndots_set(int ndots)
+ *	 Set the number of dots which, when found in a name, causes
+ *	 the first query to be without any search domain.
+ *
+ * int evdns_count_nameservers(void)
+ *	 Return the number of configured nameservers (not necessarily the
+ *	 number of running nameservers).  This is useful for double-checking
+ *	 whether our calls to the various nameserver configuration functions
+ *	 have been successful.
+ *
+ * int evdns_clear_nameservers_and_suspend(void)
+ *	 Remove all currently configured nameservers, and suspend all pending
+ *	 resolves.	Resolves will not necessarily be re-attempted until
+ *	 evdns_resume() is called.
+ *
+ * int evdns_resume(void)
+ *	 Re-attempt resolves left in limbo after an earlier call to
+ *	 evdns_clear_nameservers_and_suspend().
+ *
+ * int evdns_config_windows_nameservers(void)
+ *	 Attempt to configure a set of nameservers based on platform settings on
+ *	 a win32 host.	Preferentially tries to use GetNetworkParams; if that fails,
+ *	 looks in the registry.	 Returns 0 on success, nonzero on failure.
+ *
+ * int evdns_resolv_conf_parse(int flags, const char *filename)
+ *	 Parse a resolv.conf like file from the given filename.
+ *
+ *	 See the man page for resolv.conf for the format of this file.
+ *	 The flags argument determines what information is parsed from
+ *	 this file:
+ *	   DNS_OPTION_SEARCH - domain, search and ndots options
+ *	   DNS_OPTION_NAMESERVERS - nameserver lines
+ *	   DNS_OPTION_MISC - timeout and attempts options
+ *	   DNS_OPTIONS_ALL - all of the above
+ *	 The following directives are not parsed from the file:
+ *	   sortlist, rotate, no-check-names, inet6, debug
+ *
+ *	 Returns non-zero on error:
+ *	  0 no errors
+ *	  1 failed to open file
+ *	  2 failed to stat file
+ *	  3 file too large
+ *	  4 out of memory
+ *	  5 short read from file
+ *        6 no nameservers in file
+ *
+ * Internals:
+ *
+ * Requests are kept in two queues. The first is the inflight queue. In
+ * this queue requests have an allocated transaction id and nameserver.
+ * They will soon be transmitted if they haven't already been.
+ *
+ * The second is the waiting queue. The size of the inflight ring is
+ * limited and all other requests wait in waiting queue for space. This
+ * bounds the number of concurrent requests so that we don't flood the
+ * nameserver. Several algorithms require a full walk of the inflight
+ * queue and so bounding its size keeps thing going nicely under huge
+ * (many thousands of requests) loads.
+ *
+ * If a nameserver loses too many requests it is considered down and we
+ * try not to use it. After a while we send a probe to that nameserver
+ * (a lookup for google.com) and, if it replies, we consider it working
+ * again. If the nameserver fails a probe we wait longer to try again
+ * with the next probe.
+ */
+
+#ifndef _TOR_EVENTDNS_H
+#define _TOR_EVENTDNS_H
+
+/* Error codes 0-5 are as described in RFC 1035. */
+#define DNS_ERR_NONE 0
+/* The name server was unable to interpret the query */
+#define DNS_ERR_FORMAT 1
+/* The name server was unable to process this query due to a problem with the
+ * name server */
+#define DNS_ERR_SERVERFAILED 2
+/* The domain name does not exist */
+#define DNS_ERR_NOTEXIST 3
+/* The name server does not support the requested kind of query */
+#define DNS_ERR_NOTIMPL 4
+/* The name server refuses to reform the specified operation for policy
+ * reasons */
+#define DNS_ERR_REFUSED 5
+/* The reply was truncated or ill-formated */
+#define DNS_ERR_TRUNCATED 65
+/* An unknown error occurred */
+#define DNS_ERR_UNKNOWN 66
+/* Communication with the server timed out */
+#define DNS_ERR_TIMEOUT 67
+/* The request was canceled because the DNS subsystem was shut down. */
+#define DNS_ERR_SHUTDOWN 68
+
+#define DNS_IPv4_A 1
+#define DNS_PTR 2
+#define DNS_IPv6_AAAA 3
+
+#define DNS_QUERY_NO_SEARCH 1
+
+#define DNS_OPTION_SEARCH 1
+#define DNS_OPTION_NAMESERVERS 2
+#define DNS_OPTION_MISC 4
+#define DNS_OPTIONS_ALL 7
+
+/*
+ * The callback that contains the results from a lookup.
+ * - type is either DNS_IPv4_A or DNS_IPv6_AAAA or DNS_PTR
+ * - count contains the number of addresses of form type
+ * - ttl is the number of seconds the resolution may be cached for.
+ * - addresses needs to be cast according to type
+ */
+typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+
+int evdns_init(void);
+void evdns_shutdown(int fail_requests);
+const char *evdns_err_to_string(int err);
+int evdns_nameserver_add(uint32_t address);
+int evdns_count_nameservers(void);
+int evdns_clear_nameservers_and_suspend(void);
+int evdns_resume(void);
+int evdns_nameserver_ip_add(const char *ip_as_string);
+int evdns_nameserver_sockaddr_add(const struct sockaddr *sa, socklen_t len);
+void evdns_set_default_outgoing_bind_address(const struct sockaddr *addr, socklen_t addrlen);
+int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+struct in_addr;
+struct in6_addr;
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+int evdns_set_option(const char *option, const char *val, int flags);
+int evdns_resolv_conf_parse(int flags, const char *);
+#ifdef _WIN32
+int evdns_config_windows_nameservers(void);
+#endif
+void evdns_search_clear(void);
+void evdns_search_add(const char *domain);
+void evdns_search_ndots_set(const int ndots);
+
+typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+void evdns_set_log_fn(evdns_debug_log_fn_type fn);
+
+void evdns_set_transaction_id_fn(uint16_t (*fn)(void));
+void evdns_set_random_bytes_fn(void (*fn)(char *, size_t));
+
+#define DNS_NO_SEARCH 1
+
+/* Structures and functions used to implement a DNS server. */
+
+struct evdns_server_request {
+	int flags;
+	int nquestions;
+	struct evdns_server_question **questions;
+};
+struct evdns_server_question {
+	int type;
+	int dns_question_class;
+	char name[1];
+};
+typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
+#define EVDNS_ANSWER_SECTION 0
+#define EVDNS_AUTHORITY_SECTION 1
+#define EVDNS_ADDITIONAL_SECTION 2
+
+#define EVDNS_TYPE_A	   1
+#define EVDNS_TYPE_NS	   2
+#define EVDNS_TYPE_CNAME   5
+#define EVDNS_TYPE_SOA	   6
+#define EVDNS_TYPE_PTR	  12
+#define EVDNS_TYPE_MX	  15
+#define EVDNS_TYPE_TXT	  16
+#define EVDNS_TYPE_AAAA	  28
+
+#define EVDNS_QTYPE_AXFR 252
+#define EVDNS_QTYPE_ALL	 255
+
+#define EVDNS_CLASS_INET   1
+
+struct evdns_server_port *evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
+void evdns_close_server_port(struct evdns_server_port *port);
+
+int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
+int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
+int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
+int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
+
+struct sockaddr;
+int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len);
+
+int evdns_server_request_respond(struct evdns_server_request *req, int err);
+int evdns_server_request_drop(struct evdns_server_request *req);
+
+#endif	// !EVENTDNS_H
diff --git a/src/ext/ht.h b/src/ext/ht.h
new file mode 100644
index 0000000..25156c4
--- /dev/null
+++ b/src/ext/ht.h
@@ -0,0 +1,490 @@
+/* Copyright (c) 2002, Christopher Clark.
+ * Copyright (c) 2005-2006, Nick Mathewson.
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
+/* See license at end. */
+
+/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
+
+#ifndef _TOR_HT_H
+#define _TOR_HT_H
+
+#define HT_HEAD(name, type)                                             \
+  struct name {                                                         \
+    /* The hash table itself. */                                        \
+    struct type **hth_table;                                            \
+    /* How long is the hash table? */                                   \
+    unsigned hth_table_length;                                          \
+    /* How many elements does the table contain? */                     \
+    unsigned hth_n_entries;                                             \
+    /* How many elements will we allow in the table before resizing it? */ \
+    unsigned hth_load_limit;                                            \
+    /* Position of hth_table_length in the primes table. */             \
+    int hth_prime_idx;                                                  \
+  }
+
+#define HT_INITIALIZER()                        \
+  { NULL, 0, 0, 0, -1 }
+
+#ifdef HT_NO_CACHE_HASH_VALUES
+#define HT_ENTRY(type)                          \
+  struct {                                      \
+    struct type *hte_next;                      \
+  }
+#else
+#define HT_ENTRY(type)                          \
+  struct {                                      \
+    struct type *hte_next;                      \
+    unsigned hte_hash;                          \
+  }
+#endif
+
+#define HT_EMPTY(head)                          \
+  ((head)->hth_n_entries == 0)
+
+/* How many elements in 'head'? */
+#define HT_SIZE(head)                           \
+  ((head)->hth_n_entries)
+
+/* Return memory usage for a hashtable (not counting the entries themselves) */
+#define HT_MEM_USAGE(head)                         \
+  (sizeof(*head) + (head)->hth_table_length * sizeof(void*))
+
+#define HT_FIND(name, head, elm)     name##_HT_FIND((head), (elm))
+#define HT_INSERT(name, head, elm)   name##_HT_INSERT((head), (elm))
+#define HT_REPLACE(name, head, elm)  name##_HT_REPLACE((head), (elm))
+#define HT_REMOVE(name, head, elm)   name##_HT_REMOVE((head), (elm))
+#define HT_START(name, head)         name##_HT_START(head)
+#define HT_NEXT(name, head, elm)     name##_HT_NEXT((head), (elm))
+#define HT_NEXT_RMV(name, head, elm) name##_HT_NEXT_RMV((head), (elm))
+#define HT_CLEAR(name, head)         name##_HT_CLEAR(head)
+#define HT_INIT(name, head)          name##_HT_INIT(head)
+/* Helper: */
+static INLINE unsigned
+ht_improve_hash(unsigned h)
+{
+  /* Aim to protect against poor hash functions by adding logic here
+   * - logic taken from java 1.4 hashtable source */
+  h += ~(h << 9);
+  h ^=  ((h >> 14) | (h << 18)); /* >>> */
+  h +=  (h << 4);
+  h ^=  ((h >> 10) | (h << 22)); /* >>> */
+  return h;
+}
+
+#if 0
+/** Basic string hash function, from Java standard String.hashCode(). */
+static INLINE unsigned
+ht_string_hash(const char *s)
+{
+  unsigned h = 0;
+  int m = 1;
+  while (*s) {
+    h += ((signed char)*s++)*m;
+    m = (m<<5)-1; /* m *= 31 */
+  }
+  return h;
+}
+#endif
+
+/** Basic string hash function, from Python's str.__hash__() */
+static INLINE unsigned
+ht_string_hash(const char *s)
+{
+  unsigned h;
+  const unsigned char *cp = (const unsigned char *)s;
+  h = *cp << 7;
+  while (*cp) {
+    h = (1000003*h) ^ *cp++;
+  }
+  /* This conversion truncates the length of the string, but that's ok. */
+  h ^= (unsigned)(cp-(const unsigned char*)s);
+  return h;
+}
+
+#ifndef HT_NO_CACHE_HASH_VALUES
+#define HT_SET_HASH_(elm, field, hashfn)        \
+    do { (elm)->field.hte_hash = hashfn(elm); } while (0)
+#define HT_SET_HASHVAL_(elm, field, val)        \
+    do { (elm)->field.hte_hash = (val); } while (0)
+#define HT_ELT_HASH_(elm, field, hashfn)        \
+    ((elm)->field.hte_hash)
+#else
+#define HT_SET_HASH_(elm, field, hashfn)        \
+    ((void)0)
+#define HT_ELT_HASH_(elm, field, hashfn)        \
+    (hashfn(elm))
+#define HT_SET_HASHVAL_(elm, field, val)        \
+        ((void)0)
+#endif
+
+/* Helper: alias for the bucket containing 'elm'. */
+#define HT_BUCKET_(head, field, elm, hashfn)                            \
+    ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn)                   \
+        % head->hth_table_length])
+
+#define HT_FOREACH(x, name, head)                 \
+  for ((x) = HT_START(name, head);                \
+       (x) != NULL;                               \
+       (x) = HT_NEXT(name, head, x))
+
+#define HT_PROTOTYPE(name, type, field, hashfn, eqfn)                   \
+  int name##_HT_GROW(struct name *ht, unsigned min_capacity);           \
+  void name##_HT_CLEAR(struct name *ht);                                \
+  int name##_HT_REP_IS_BAD_(const struct name *ht);                     \
+  static INLINE void                                                    \
+  name##_HT_INIT(struct name *head) {                                   \
+    head->hth_table_length = 0;                                         \
+    head->hth_table = NULL;                                             \
+    head->hth_n_entries = 0;                                            \
+    head->hth_load_limit = 0;                                           \
+    head->hth_prime_idx = -1;                                           \
+  }                                                                     \
+  /* Helper: returns a pointer to the right location in the table       \
+   * 'head' to find or insert the element 'elm'. */                     \
+  static INLINE struct type **                                          \
+  name##_HT_FIND_P_(struct name *head, struct type *elm)                \
+  {                                                                     \
+    struct type **p;                                                    \
+    if (!head->hth_table)                                               \
+      return NULL;                                                      \
+    p = &HT_BUCKET_(head, field, elm, hashfn);                          \
+    while (*p) {                                                        \
+      if (eqfn(*p, elm))                                                \
+        return p;                                                       \
+      p = &(*p)->field.hte_next;                                        \
+    }                                                                   \
+    return p;                                                           \
+  }                                                                     \
+  /* Return a pointer to the element in the table 'head' matching 'elm', \
+   * or NULL if no such element exists */                               \
+  static INLINE struct type *                                           \
+  name##_HT_FIND(const struct name *head, struct type *elm)             \
+  {                                                                     \
+    struct type **p;                                                    \
+    struct name *h = (struct name *) head;                              \
+    HT_SET_HASH_(elm, field, hashfn);                                   \
+    p = name##_HT_FIND_P_(h, elm);                                      \
+    return p ? *p : NULL;                                               \
+  }                                                                     \
+  /* Insert the element 'elm' into the table 'head'.  Do not call this  \
+   * function if the table might already contain a matching element. */ \
+  static INLINE void                                                    \
+  name##_HT_INSERT(struct name *head, struct type *elm)                 \
+  {                                                                     \
+    struct type **p;                                                    \
+    if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
+      name##_HT_GROW(head, head->hth_n_entries+1);                      \
+    ++head->hth_n_entries;                                              \
+    HT_SET_HASH_(elm, field, hashfn);                                   \
+    p = &HT_BUCKET_(head, field, elm, hashfn);                          \
+    elm->field.hte_next = *p;                                           \
+    *p = elm;                                                           \
+  }                                                                     \
+  /* Insert the element 'elm' into the table 'head'. If there already   \
+   * a matching element in the table, replace that element and return   \
+   * it. */                                                             \
+  static INLINE struct type *                                           \
+  name##_HT_REPLACE(struct name *head, struct type *elm)                \
+  {                                                                     \
+    struct type **p, *r;                                                \
+    if (!head->hth_table || head->hth_n_entries >= head->hth_load_limit) \
+      name##_HT_GROW(head, head->hth_n_entries+1);                      \
+    HT_SET_HASH_(elm, field, hashfn);                                   \
+    p = name##_HT_FIND_P_(head, elm);                                   \
+    r = *p;                                                             \
+    *p = elm;                                                           \
+    if (r && (r!=elm)) {                                                \
+      elm->field.hte_next = r->field.hte_next;                          \
+      r->field.hte_next = NULL;                                         \
+      return r;                                                         \
+    } else {                                                            \
+      ++head->hth_n_entries;                                            \
+      return NULL;                                                      \
+    }                                                                   \
+  }                                                                     \
+  /* Remove any element matching 'elm' from the table 'head'.  If such  \
+   * an element is found, return it; otherwise return NULL. */          \
+  static INLINE struct type *                                           \
+  name##_HT_REMOVE(struct name *head, struct type *elm)                 \
+  {                                                                     \
+    struct type **p, *r;                                                \
+    HT_SET_HASH_(elm, field, hashfn);                                   \
+    p = name##_HT_FIND_P_(head,elm);                                    \
+    if (!p || !*p)                                                      \
+      return NULL;                                                      \
+    r = *p;                                                             \
+    *p = r->field.hte_next;                                             \
+    r->field.hte_next = NULL;                                           \
+    --head->hth_n_entries;                                              \
+    return r;                                                           \
+  }                                                                     \
+  /* Invoke the function 'fn' on every element of the table 'head',     \
+   * using 'data' as its second argument.  If the function returns      \
+   * nonzero, remove the most recently examined element before invoking \
+   * the function again. */                                             \
+  static INLINE void                                                    \
+  name##_HT_FOREACH_FN(struct name *head,                               \
+                       int (*fn)(struct type *, void *),                \
+                       void *data)                                      \
+  {                                                                     \
+    unsigned idx;                                                       \
+    struct type **p, **nextp, *next;                                    \
+    if (!head->hth_table)                                               \
+      return;                                                           \
+    for (idx=0; idx < head->hth_table_length; ++idx) {                  \
+      p = &head->hth_table[idx];                                        \
+      while (*p) {                                                      \
+        nextp = &(*p)->field.hte_next;                                  \
+        next = *nextp;                                                  \
+        if (fn(*p, data)) {                                             \
+          --head->hth_n_entries;                                        \
+          *p = next;                                                    \
+        } else {                                                        \
+          p = nextp;                                                    \
+        }                                                               \
+      }                                                                 \
+    }                                                                   \
+  }                                                                     \
+  /* Return a pointer to the first element in the table 'head', under   \
+   * an arbitrary order.  This order is stable under remove operations, \
+   * but not under others. If the table is empty, return NULL. */       \
+  static INLINE struct type **                                          \
+  name##_HT_START(struct name *head)                                    \
+  {                                                                     \
+    unsigned b = 0;                                                     \
+    while (b < head->hth_table_length) {                                \
+      if (head->hth_table[b])                                           \
+        return &head->hth_table[b];                                     \
+      ++b;                                                              \
+    }                                                                   \
+    return NULL;                                                        \
+  }                                                                     \
+  /* Return the next element in 'head' after 'elm', under the arbitrary \
+   * order used by HT_START.  If there are no more elements, return     \
+   * NULL.  If 'elm' is to be removed from the table, you must call     \
+   * this function for the next value before you remove it.             \
+   */                                                                   \
+  static INLINE struct type **                                          \
+  name##_HT_NEXT(struct name *head, struct type **elm)                  \
+  {                                                                     \
+    if ((*elm)->field.hte_next) {                                       \
+      return &(*elm)->field.hte_next;                                   \
+    } else {                                                            \
+      unsigned b = (HT_ELT_HASH_(*elm, field, hashfn)                   \
+      % head->hth_table_length)+1;                                      \
+      while (b < head->hth_table_length) {                              \
+        if (head->hth_table[b])                                         \
+          return &head->hth_table[b];                                   \
+        ++b;                                                            \
+      }                                                                 \
+      return NULL;                                                      \
+    }                                                                   \
+  }                                                                     \
+  static INLINE struct type **                                          \
+  name##_HT_NEXT_RMV(struct name *head, struct type **elm)              \
+  {                                                                     \
+    unsigned h = HT_ELT_HASH_(*elm, field, hashfn);                     \
+    *elm = (*elm)->field.hte_next;                                      \
+    --head->hth_n_entries;                                              \
+    if (*elm) {                                                         \
+      return elm;                                                       \
+    } else {                                                            \
+      unsigned b = (h % head->hth_table_length)+1;                      \
+      while (b < head->hth_table_length) {                              \
+        if (head->hth_table[b])                                         \
+          return &head->hth_table[b];                                   \
+        ++b;                                                            \
+      }                                                                 \
+      return NULL;                                                      \
+    }                                                                   \
+  }
+
+#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn,    \
+                    reallocfn, freefn)                                  \
+  static unsigned name##_PRIMES[] = {                                   \
+    53, 97, 193, 389,                                                   \
+    769, 1543, 3079, 6151,                                              \
+    12289, 24593, 49157, 98317,                                         \
+    196613, 393241, 786433, 1572869,                                    \
+    3145739, 6291469, 12582917, 25165843,                               \
+    50331653, 100663319, 201326611, 402653189,                          \
+    805306457, 1610612741                                               \
+  };                                                                    \
+  static unsigned name##_N_PRIMES =                                     \
+    (unsigned)(sizeof(name##_PRIMES)/sizeof(name##_PRIMES[0]));         \
+  /* Expand the internal table of 'head' until it is large enough to    \
+   * hold 'size' elements.  Return 0 on success, -1 on allocation       \
+   * failure. */                                                        \
+  int                                                                   \
+  name##_HT_GROW(struct name *head, unsigned size)                      \
+  {                                                                     \
+    unsigned new_len, new_load_limit;                                   \
+    int prime_idx;                                                      \
+    struct type **new_table;                                            \
+    if (head->hth_prime_idx == (int)name##_N_PRIMES - 1)                \
+      return 0;                                                         \
+    if (head->hth_load_limit > size)                                    \
+      return 0;                                                         \
+    prime_idx = head->hth_prime_idx;                                    \
+    do {                                                                \
+      new_len = name##_PRIMES[++prime_idx];                             \
+      new_load_limit = (unsigned)(load*new_len);                        \
+    } while (new_load_limit <= size &&                                  \
+             prime_idx < (int)name##_N_PRIMES);                         \
+    if ((new_table = mallocfn(new_len*sizeof(struct type*)))) {         \
+      unsigned b;                                                       \
+      memset(new_table, 0, new_len*sizeof(struct type*));               \
+      for (b = 0; b < head->hth_table_length; ++b) {                    \
+        struct type *elm, *next;                                        \
+        unsigned b2;                                                    \
+        elm = head->hth_table[b];                                       \
+        while (elm) {                                                   \
+          next = elm->field.hte_next;                                   \
+          b2 = HT_ELT_HASH_(elm, field, hashfn) % new_len;              \
+          elm->field.hte_next = new_table[b2];                          \
+          new_table[b2] = elm;                                          \
+          elm = next;                                                   \
+        }                                                               \
+      }                                                                 \
+      if (head->hth_table)                                              \
+        freefn(head->hth_table);                                        \
+      head->hth_table = new_table;                                      \
+    } else {                                                            \
+      unsigned b, b2;                                                   \
+      new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
+      if (!new_table) return -1;                                        \
+      memset(new_table + head->hth_table_length, 0,                     \
+             (new_len - head->hth_table_length)*sizeof(struct type*));  \
+      for (b=0; b < head->hth_table_length; ++b) {                      \
+        struct type *e, **pE;                                           \
+        for (pE = &new_table[b], e = *pE; e != NULL; e = *pE) {         \
+          b2 = HT_ELT_HASH_(e, field, hashfn) % new_len;                \
+          if (b2 == b) {                                                \
+            pE = &e->field.hte_next;                                    \
+          } else {                                                      \
+            *pE = e->field.hte_next;                                    \
+            e->field.hte_next = new_table[b2];                          \
+            new_table[b2] = e;                                          \
+          }                                                             \
+        }                                                               \
+      }                                                                 \
+      head->hth_table = new_table;                                      \
+    }                                                                   \
+    head->hth_table_length = new_len;                                   \
+    head->hth_prime_idx = prime_idx;                                    \
+    head->hth_load_limit = new_load_limit;                              \
+    return 0;                                                           \
+  }                                                                     \
+  /* Free all storage held by 'head'.  Does not free 'head' itself, or  \
+   * individual elements. */                                            \
+  void                                                                  \
+  name##_HT_CLEAR(struct name *head)                                    \
+  {                                                                     \
+    if (head->hth_table)                                                \
+      freefn(head->hth_table);                                          \
+    head->hth_table_length = 0;                                         \
+    name##_HT_INIT(head);                                               \
+  }                                                                     \
+  /* Debugging helper: return false iff the representation of 'head' is \
+   * internally consistent. */                                          \
+  int                                                                   \
+  name##_HT_REP_IS_BAD_(const struct name *head)                        \
+  {                                                                     \
+    unsigned n, i;                                                      \
+    struct type *elm;                                                   \
+    if (!head->hth_table_length) {                                      \
+      if (!head->hth_table && !head->hth_n_entries &&                   \
+          !head->hth_load_limit && head->hth_prime_idx == -1)           \
+        return 0;                                                       \
+      else                                                              \
+        return 1;                                                       \
+    }                                                                   \
+    if (!head->hth_table || head->hth_prime_idx < 0 ||                  \
+        !head->hth_load_limit)                                          \
+      return 2;                                                         \
+    if (head->hth_n_entries > head->hth_load_limit)                     \
+      return 3;                                                         \
+    if (head->hth_table_length != name##_PRIMES[head->hth_prime_idx])   \
+      return 4;                                                         \
+    if (head->hth_load_limit != (unsigned)(load*head->hth_table_length)) \
+      return 5;                                                         \
+    for (n = i = 0; i < head->hth_table_length; ++i) {                  \
+      for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) {  \
+        if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm))            \
+          return 1000 + i;                                              \
+        if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
+          return 10000 + i;                                             \
+        ++n;                                                            \
+      }                                                                 \
+    }                                                                   \
+    if (n != head->hth_n_entries)                                       \
+      return 6;                                                         \
+    return 0;                                                           \
+  }
+
+/** Implements an over-optimized "find and insert if absent" block;
+ * not meant for direct usage by typical code, or usage outside the critical
+ * path.*/
+#define HT_FIND_OR_INSERT_(name, field, hashfn, head, eltype, elm, var, y, n) \
+  {                                                                     \
+    struct name *var##_head_ = head;                                    \
+    struct eltype **var;                                                \
+    if (!var##_head_->hth_table ||                                      \
+        var##_head_->hth_n_entries >= var##_head_->hth_load_limit)      \
+      name##_HT_GROW(var##_head_, var##_head_->hth_n_entries+1);        \
+    HT_SET_HASH_((elm), field, hashfn);                                 \
+    var = name##_HT_FIND_P_(var##_head_, (elm));                        \
+    if (*var) {                                                         \
+      y;                                                                \
+    } else {                                                            \
+      n;                                                                \
+    }                                                                   \
+  }
+#define HT_FOI_INSERT_(field, head, elm, newent, var)       \
+  {                                                         \
+    HT_SET_HASHVAL_(newent, field, (elm)->field.hte_hash);  \
+    newent->field.hte_next = NULL;                          \
+    *var = newent;                                          \
+    ++((head)->hth_n_entries);                              \
+  }
+
+/*
+ * Copyright 2005, Nick Mathewson.  Implementation logic is adapted from code
+ * by Christopher Clark, retrofit to allow drop-in memory management, and to
+ * use the same interface as Niels Provos's tree.h.  This is probably still
+ * a derived work, so the original license below still applies.
+ *
+ * Copyright (c) 2002, Christopher Clark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#endif
+
diff --git a/src/ext/include.am b/src/ext/include.am
new file mode 100644
index 0000000..97e7e46
--- /dev/null
+++ b/src/ext/include.am
@@ -0,0 +1,12 @@
+
+AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext
+
+EXTHEADERS = \
+  src/ext/ht.h		\
+  src/ext/eventdns.h	\
+  src/ext/tinytest.h	\
+  src/ext/tinytest_macros.h
+
+noinst_HEADERS+= $(EXTHEADERS)
+
+
diff --git a/src/ext/tinytest.c b/src/ext/tinytest.c
new file mode 100644
index 0000000..4d9afac
--- /dev/null
+++ b/src/ext/tinytest.c
@@ -0,0 +1,387 @@
+/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef TINYTEST_LOCAL
+#include "tinytest_local.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#define LONGEST_TEST_NAME 16384
+
+static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
+static int n_ok = 0; /**< Number of tests that have passed */
+static int n_bad = 0; /**< Number of tests that have failed. */
+static int n_skipped = 0; /**< Number of tests that have been skipped. */
+
+static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
+static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
+static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
+const char *verbosity_flag = "";
+
+enum outcome { SKIP=2, OK=1, FAIL=0 };
+static enum outcome cur_test_outcome = 0;
+const char *cur_test_prefix = NULL; /**< prefix of the current test group */
+/** Name of the current test, if we haven't logged is yet. Used for --quiet */
+const char *cur_test_name = NULL;
+
+#ifdef _WIN32
+/* Copy of argv[0] for win32. */
+static char commandname[MAX_PATH+1];
+#endif
+
+static void usage(struct testgroup_t *groups, int list_groups)
+  __attribute__((noreturn));
+
+static enum outcome
+testcase_run_bare_(const struct testcase_t *testcase)
+{
+	void *env = NULL;
+	int outcome;
+	if (testcase->setup) {
+		env = testcase->setup->setup_fn(testcase);
+		if (!env)
+			return FAIL;
+		else if (env == (void*)TT_SKIP)
+			return SKIP;
+	}
+
+	cur_test_outcome = OK;
+	testcase->fn(env);
+	outcome = cur_test_outcome;
+
+	if (testcase->setup) {
+		if (testcase->setup->cleanup_fn(testcase, env) == 0)
+			outcome = FAIL;
+	}
+
+	return outcome;
+}
+
+#define MAGIC_EXITCODE 42
+
+static enum outcome
+testcase_run_forked_(const struct testgroup_t *group,
+		     const struct testcase_t *testcase)
+{
+#ifdef _WIN32
+	/* Fork? On Win32?  How primitive!  We'll do what the smart kids do:
+	   we'll invoke our own exe (whose name we recall from the command
+	   line) with a command line that tells it to run just the test we
+	   want, and this time without forking.
+
+	   (No, threads aren't an option.  The whole point of forking is to
+	   share no state between tests.)
+	 */
+	int ok;
+	char buffer[LONGEST_TEST_NAME+256];
+	STARTUPINFOA si;
+	PROCESS_INFORMATION info;
+	DWORD exitcode;
+
+	if (!in_tinytest_main) {
+		printf("\nERROR.  On Windows, testcase_run_forked_ must be"
+		       " called from within tinytest_main.\n");
+		abort();
+	}
+	if (opt_verbosity>0)
+		printf("[forking] ");
+
+	snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
+		 commandname, verbosity_flag, group->prefix, testcase->name);
+
+	memset(&si, 0, sizeof(si));
+	memset(&info, 0, sizeof(info));
+	si.cb = sizeof(si);
+
+	ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
+			   0, NULL, NULL, &si, &info);
+	if (!ok) {
+		printf("CreateProcess failed!\n");
+		return 0;
+	}
+	WaitForSingleObject(info.hProcess, INFINITE);
+	GetExitCodeProcess(info.hProcess, &exitcode);
+	CloseHandle(info.hProcess);
+	CloseHandle(info.hThread);
+	if (exitcode == 0)
+		return OK;
+	else if (exitcode == MAGIC_EXITCODE)
+		return SKIP;
+	else
+		return FAIL;
+#else
+	int outcome_pipe[2];
+	pid_t pid;
+	(void)group;
+
+	if (pipe(outcome_pipe))
+		perror("opening pipe");
+
+	if (opt_verbosity>0)
+		printf("[forking] ");
+	pid = fork();
+	if (!pid) {
+		/* child. */
+		int test_r, write_r;
+		char b[1];
+		close(outcome_pipe[0]);
+		test_r = testcase_run_bare_(testcase);
+		assert(0<=(int)test_r && (int)test_r<=2);
+		b[0] = "NYS"[test_r];
+		write_r = (int)write(outcome_pipe[1], b, 1);
+		if (write_r != 1) {
+			perror("write outcome to pipe");
+			exit(1);
+		}
+		exit(0);
+		return FAIL; /* unreachable */
+	} else {
+		/* parent */
+		int status, r;
+		char b[1];
+		/* Close this now, so that if the other side closes it,
+		 * our read fails. */
+		close(outcome_pipe[1]);
+		r = (int)read(outcome_pipe[0], b, 1);
+		if (r == 0) {
+			printf("[Lost connection!] ");
+			return 0;
+		} else if (r != 1) {
+			perror("read outcome from pipe");
+		}
+		waitpid(pid, &status, 0);
+		close(outcome_pipe[0]);
+		return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
+	}
+#endif
+}
+
+int
+testcase_run_one(const struct testgroup_t *group,
+		 const struct testcase_t *testcase)
+{
+	enum outcome outcome;
+
+	if (testcase->flags & TT_SKIP) {
+		if (opt_verbosity>0)
+			printf("%s%s: SKIPPED\n",
+			    group->prefix, testcase->name);
+		++n_skipped;
+		return SKIP;
+	}
+
+	if (opt_verbosity>0 && !opt_forked) {
+		printf("%s%s: ", group->prefix, testcase->name);
+	} else {
+		if (opt_verbosity==0) printf(".");
+		cur_test_prefix = group->prefix;
+		cur_test_name = testcase->name;
+	}
+
+	if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
+		outcome = testcase_run_forked_(group, testcase);
+	} else {
+		outcome = testcase_run_bare_(testcase);
+	}
+
+	if (outcome == OK) {
+		++n_ok;
+		if (opt_verbosity>0 && !opt_forked)
+			puts(opt_verbosity==1?"OK":"");
+	} else if (outcome == SKIP) {
+		++n_skipped;
+		if (opt_verbosity>0 && !opt_forked)
+			puts("SKIPPED");
+	} else {
+		++n_bad;
+		if (!opt_forked)
+			printf("\n  [%s FAILED]\n", testcase->name);
+	}
+
+	if (opt_forked) {
+		exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
+		return 1; /* unreachable */
+	} else {
+		return (int)outcome;
+	}
+}
+
+int
+tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag)
+{
+	int i, j;
+	size_t length = LONGEST_TEST_NAME;
+	char fullname[LONGEST_TEST_NAME];
+	int found=0;
+	if (strstr(arg, ".."))
+		length = strstr(arg,"..")-arg;
+	for (i=0; groups[i].prefix; ++i) {
+		for (j=0; groups[i].cases[j].name; ++j) {
+			snprintf(fullname, sizeof(fullname), "%s%s",
+				 groups[i].prefix, groups[i].cases[j].name);
+			if (!flag) /* Hack! */
+				printf("    %s\n", fullname);
+			if (!strncmp(fullname, arg, length)) {
+				groups[i].cases[j].flags |= flag;
+				++found;
+			}
+		}
+	}
+	return found;
+}
+
+static void
+usage(struct testgroup_t *groups, int list_groups)
+{
+	puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
+	puts("  Specify tests by name, or using a prefix ending with '..'");
+	puts("  To skip a test, list give its name prefixed with a colon.");
+	puts("  Use --list-tests for a list of tests.");
+	if (list_groups) {
+		puts("Known tests are:");
+		tinytest_set_flag_(groups, "..", 0);
+	}
+	exit(0);
+}
+
+int
+tinytest_main(int c, const char **v, struct testgroup_t *groups)
+{
+	int i, j, n=0;
+
+#ifdef _WIN32
+	const char *sp = strrchr(v[0], '.');
+	const char *extension = "";
+	if (!sp || stricmp(sp, ".exe"))
+		extension = ".exe"; /* Add an exe so CreateProcess will work */
+	snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
+	commandname[MAX_PATH]='\0';
+#endif
+	for (i=1; i<c; ++i) {
+		if (v[i][0] == '-') {
+			if (!strcmp(v[i], "--RUNNING-FORKED")) {
+				opt_forked = 1;
+			} else if (!strcmp(v[i], "--no-fork")) {
+				opt_nofork = 1;
+			} else if (!strcmp(v[i], "--quiet")) {
+				opt_verbosity = -1;
+				verbosity_flag = "--quiet";
+			} else if (!strcmp(v[i], "--verbose")) {
+				opt_verbosity = 2;
+				verbosity_flag = "--verbose";
+			} else if (!strcmp(v[i], "--terse")) {
+				opt_verbosity = 0;
+				verbosity_flag = "--terse";
+			} else if (!strcmp(v[i], "--help")) {
+				usage(groups, 0);
+			} else if (!strcmp(v[i], "--list-tests")) {
+				usage(groups, 1);
+			} else {
+				printf("Unknown option %s.  Try --help\n",v[i]);
+				return -1;
+			}
+		} else {
+			const char *test = v[i];
+			int flag = TT_ENABLED_;
+			if (test[0] == ':') {
+				++test;
+				flag = TT_SKIP;
+			} else {
+				++n;
+			}
+			if (!tinytest_set_flag_(groups, test, flag)) {
+				printf("No such test as %s!\n", v[i]);
+				return -1;
+			}
+		}
+	}
+	if (!n)
+		tinytest_set_flag_(groups, "..", TT_ENABLED_);
+
+	setvbuf(stdout, NULL, _IONBF, 0);
+
+	++in_tinytest_main;
+	for (i=0; groups[i].prefix; ++i)
+		for (j=0; groups[i].cases[j].name; ++j)
+			if (groups[i].cases[j].flags & TT_ENABLED_)
+				testcase_run_one(&groups[i],
+						 &groups[i].cases[j]);
+
+	--in_tinytest_main;
+
+	if (opt_verbosity==0)
+		puts("");
+
+	if (n_bad)
+		printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
+		       n_bad+n_ok,n_skipped);
+	else if (opt_verbosity >= 1)
+		printf("%d tests ok.  (%d skipped)\n", n_ok, n_skipped);
+
+	return (n_bad == 0) ? 0 : 1;
+}
+
+int
+tinytest_get_verbosity_(void)
+{
+	return opt_verbosity;
+}
+
+void
+tinytest_set_test_failed_(void)
+{
+	if (opt_verbosity <= 0 && cur_test_name) {
+		if (opt_verbosity==0) puts("");
+		printf("%s%s: ", cur_test_prefix, cur_test_name);
+		cur_test_name = NULL;
+	}
+	cur_test_outcome = 0;
+}
+
+void
+tinytest_set_test_skipped_(void)
+{
+	if (cur_test_outcome==OK)
+		cur_test_outcome = SKIP;
+}
+
diff --git a/src/ext/tinytest.h b/src/ext/tinytest.h
new file mode 100644
index 0000000..bcac9f0
--- /dev/null
+++ b/src/ext/tinytest.h
@@ -0,0 +1,87 @@
+/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TINYTEST_H_INCLUDED_
+#define TINYTEST_H_INCLUDED_
+
+/** Flag for a test that needs to run in a subprocess. */
+#define TT_FORK  (1<<0)
+/** Runtime flag for a test we've decided to skip. */
+#define TT_SKIP  (1<<1)
+/** Internal runtime flag for a test we've decided to run. */
+#define TT_ENABLED_  (1<<2)
+/** If you add your own flags, make them start at this point. */
+#define TT_FIRST_USER_FLAG (1<<3)
+
+typedef void (*testcase_fn)(void *);
+
+struct testcase_t;
+
+/** Functions to initialize/teardown a structure for a testcase. */
+struct testcase_setup_t {
+	/** Return a new structure for use by a given testcase. */
+	void *(*setup_fn)(const struct testcase_t *);
+	/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
+	int (*cleanup_fn)(const struct testcase_t *, void *);
+};
+
+/** A single test-case that you can run. */
+struct testcase_t {
+	const char *name; /**< An identifier for this case. */
+	testcase_fn fn; /**< The function to run to implement this case. */
+	unsigned long flags; /**< Bitfield of TT_* flags. */
+	const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
+	void *setup_data; /**< Extra data usable by setup function */
+};
+#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
+
+/** A group of tests that are selectable together. */
+struct testgroup_t {
+	const char *prefix; /**< Prefix to prepend to testnames. */
+	struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
+};
+#define END_OF_GROUPS { NULL, NULL}
+
+/** Implementation: called from a test to indicate failure, before logging. */
+void tinytest_set_test_failed_(void);
+/** Implementation: called from a test to indicate that we're skipping. */
+void tinytest_set_test_skipped_(void);
+/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
+int tinytest_get_verbosity_(void);
+/** Implementation: Set a flag on tests matching a name; returns number
+ * of tests that matched. */
+int tinytest_set_flag_(struct testgroup_t *, const char *, unsigned long);
+
+/** Set all tests in 'groups' matching the name 'named' to be skipped. */
+#define tinytest_skip(groups, named) \
+	tinytest_set_flag_(groups, named, TT_SKIP)
+
+/** Run a single testcase in a single group. */
+int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
+/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
+    as selected from the command line. */
+int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
+
+#endif
diff --git a/src/ext/tinytest_demo.c b/src/ext/tinytest_demo.c
new file mode 100644
index 0000000..be95ce4
--- /dev/null
+++ b/src/ext/tinytest_demo.c
@@ -0,0 +1,215 @@
+/* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/* Welcome to the example file for tinytest!  I'll show you how to set up
+ * some simple and not-so-simple testcases. */
+
+/* Make sure you include these headers. */
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* ============================================================ */
+
+/* First, let's see if strcmp is working.  (All your test cases should be
+ * functions declared to take a single void * as an argument.) */
+void
+test_strcmp(void *data)
+{
+	(void)data; /* This testcase takes no data. */
+
+	/* Let's make sure the empty string is equal to itself */
+	if (strcmp("","")) {
+		/* This macro tells tinytest to stop the current test
+		 * and go straight to the "end" label. */
+		tt_abort_msg("The empty string was not equal to itself");
+	}
+
+	/* Pretty often, calling tt_abort_msg to indicate failure is more
+	   heavy-weight than you want.	Instead, just say: */
+	tt_assert(strcmp("testcase", "testcase") == 0);
+
+	/* Occasionally, you don't want to stop the current testcase just
+	   because a single assertion has failed.  In that case, use
+	   tt_want: */
+	tt_want(strcmp("tinytest", "testcase") > 0);
+
+	/* You can use the tt_*_op family of macros to compare values and to
+	   fail unless they have the relationship you want.  They produce
+	   more useful output than tt_assert, since they display the actual
+	   values of the failing things.
+
+	   Fail unless strcmp("abc, "abc") == 0 */
+	tt_int_op(strcmp("abc", "abc"), ==, 0);
+
+	/* Fail unless strcmp("abc, "abcd") is less than 0 */
+	tt_int_op(strcmp("abc", "abcd"), < , 0);
+
+	/* Incidentally, there's a test_str_op that uses strcmp internally. */
+	tt_str_op("abc", <, "abcd");
+
+
+	/* Every test-case function needs to finish with an "end:"
+	   label and (optionally) code to clean up local variables. */
+ end:
+	;
+}
+
+/* ============================================================ */
+
+/* Now let's mess with setup and teardown functions!  These are handy if
+   you have a bunch of tests that all need a similar environment, and you
+   want to reconstruct that environment freshly for each one. */
+
+/* First you declare a type to hold the environment info, and functions to
+   set it up and tear it down. */
+struct data_buffer {
+	/* We're just going to have couple of character buffer.	 Using
+	   setup/teardown functions is probably overkill for this case.
+
+	   You could also do file descriptors, complicated handles, temporary
+	   files, etc. */
+	char buffer1[512];
+	char buffer2[512];
+};
+/* The setup function needs to take a const struct testcase_t and return
+   void* */
+void *
+setup_data_buffer(const struct testcase_t *testcase)
+{
+	struct data_buffer *db = malloc(sizeof(struct data_buffer));
+
+	/* If you had a complicated set of setup rules, you might behave
+	   differently here depending on testcase->flags or
+	   testcase->setup_data or even or testcase->name. */
+
+	/* Returning a NULL here would mean that we couldn't set up for this
+	   test, so we don't need to test db for null. */
+	return db;
+}
+/* The clean function deallocates storage carefully and returns true on
+   success. */
+int
+clean_data_buffer(const struct testcase_t *testcase, void *ptr)
+{
+	struct data_buffer *db = ptr;
+
+	if (db) {
+		free(db);
+		return 1;
+	}
+	return 0;
+}
+/* Finally, declare a testcase_setup_t with these functions. */
+struct testcase_setup_t data_buffer_setup = {
+	setup_data_buffer, clean_data_buffer
+};
+
+
+/* Now let's write our test. */
+void
+test_memcpy(void *ptr)
+{
+	/* This time, we use the argument. */
+	struct data_buffer *db = ptr;
+
+	/* We'll also introduce a local variable that might need cleaning up. */
+	char *mem = NULL;
+
+	/* Let's make sure that memcpy does what we'd like. */
+	strcpy(db->buffer1, "String 0");
+	memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
+	tt_str_op(db->buffer1, ==, db->buffer2);
+
+	/* Now we've allocated memory that's referenced by a local variable.
+	   The end block of the function will clean it up. */
+	mem = strdup("Hello world.");
+	tt_assert(mem);
+
+	/* Another rather trivial test. */
+	tt_str_op(db->buffer1, !=, mem);
+
+ end:
+	/* This time our end block has something to do. */
+	if (mem)
+		free(mem);
+}
+
+/* ============================================================ */
+
+/* Now we need to make sure that our tests get invoked.	  First, you take
+   a bunch of related tests and put them into an array of struct testcase_t.
+*/
+
+struct testcase_t demo_tests[] = {
+	/* Here's a really simple test: it has a name you can refer to it
+	   with, and a function to invoke it. */
+	{ "strcmp", test_strcmp, },
+
+	/* The second test has a flag, "TT_FORK", to make it run in a
+	   subprocess, and a pointer to the testcase_setup_t that configures
+	   its environment. */
+	{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
+
+	/* The array has to end with END_OF_TESTCASES. */
+	END_OF_TESTCASES
+};
+
+/* Next, we make an array of testgroups.  This is mandatory.  Unlike more
+   heavy-duty testing frameworks, groups can't nest. */
+struct testgroup_t groups[] = {
+
+	/* Every group has a 'prefix', and an array of tests.  That's it. */
+	{ "demo/", demo_tests },
+
+	END_OF_GROUPS
+};
+
+
+int
+main(int c, const char **v)
+{
+	/* Finally, just call tinytest_main().	It lets you specify verbose
+	   or quiet output with --verbose and --quiet.	You can list
+	   specific tests:
+
+	       tinytest-demo demo/memcpy
+
+	   or use a ..-wildcard to select multiple tests with a common
+	   prefix:
+
+	       tinytest-demo demo/..
+
+	   If you list no tests, you get them all by default, so that
+	   "tinytest-demo" and "tinytest-demo .." mean the same thing.
+
+	*/
+	return tinytest_main(c, v, groups);
+}
diff --git a/src/ext/tinytest_macros.h b/src/ext/tinytest_macros.h
new file mode 100644
index 0000000..9ff69b1
--- /dev/null
+++ b/src/ext/tinytest_macros.h
@@ -0,0 +1,184 @@
+/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TINYTEST_MACROS_H_INCLUDED_
+#define TINYTEST_MACROS_H_INCLUDED_
+
+/* Helpers for defining statement-like macros */
+#define TT_STMT_BEGIN do {
+#define TT_STMT_END } while (0)
+
+/* Redefine this if your test functions want to abort with something besides
+ * "goto end;" */
+#ifndef TT_EXIT_TEST_FUNCTION
+#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
+#endif
+
+/* Redefine this if you want to note success/failure in some different way. */
+#ifndef TT_DECLARE
+#define TT_DECLARE(prefix, args)				\
+	TT_STMT_BEGIN						\
+	printf("\n  %s %s:%d: ",prefix,__FILE__,__LINE__);	\
+	printf args ;						\
+	TT_STMT_END
+#endif
+
+/* Announce a failure. Args are parenthesized printf args. */
+#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
+
+/* Announce a non-failure if we're verbose. */
+#define TT_BLATHER(args)						\
+	TT_STMT_BEGIN							\
+	if (tinytest_get_verbosity_()>1) TT_DECLARE("  OK", args);	\
+	TT_STMT_END
+
+#define TT_DIE(args)						\
+	TT_STMT_BEGIN						\
+	tinytest_set_test_failed_();				\
+	TT_GRIPE(args);						\
+	TT_EXIT_TEST_FUNCTION;					\
+	TT_STMT_END
+
+#define TT_FAIL(args)				\
+	TT_STMT_BEGIN						\
+	tinytest_set_test_failed_();				\
+	TT_GRIPE(args);						\
+	TT_STMT_END
+
+/* Fail and abort the current test for the reason in msg */
+#define tt_abort_printf(msg) TT_DIE(msg)
+#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_abort_msg(msg) TT_DIE(("%s", msg))
+#define tt_abort() TT_DIE(("%s", "(Failed.)"))
+
+/* Fail but do not abort the current test for the reason in msg. */
+#define tt_failprint_f(msg) TT_FAIL(msg)
+#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
+#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
+#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
+
+/* End the current test, and indicate we are skipping it. */
+#define tt_skip()						\
+	TT_STMT_BEGIN						\
+	tinytest_set_test_skipped_();				\
+	TT_EXIT_TEST_FUNCTION;					\
+	TT_STMT_END
+
+#define tt_want_(b, msg, fail)				\
+	TT_STMT_BEGIN					\
+	if (!(b)) {					\
+		tinytest_set_test_failed_();		\
+		TT_GRIPE(("%s",msg));			\
+		fail;					\
+	} else {					\
+		TT_BLATHER(("%s",msg));			\
+	}						\
+	TT_STMT_END
+
+/* Assert b, but do not stop the test if b fails.  Log msg on failure. */
+#define tt_want_msg(b, msg)			\
+	tt_want_(b, msg, );
+
+/* Assert b and stop the test if b fails.  Log msg on failure. */
+#define tt_assert_msg(b, msg)			\
+	tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
+
+/* Assert b, but do not stop the test if b fails. */
+#define tt_want(b)   tt_want_msg( (b), "want("#b")")
+/* Assert b, and stop the test if b fails. */
+#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
+
+#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
+    setup_block,cleanup_block,die_on_fail)				\
+	TT_STMT_BEGIN							\
+	type val1_ = (type)(a);						\
+	type val2_ = (type)(b);						\
+	int tt_status_ = (test);					\
+	if (!tt_status_ || tinytest_get_verbosity_()>1)	{		\
+		printf_type print_;					\
+		printf_type print1_;					\
+		printf_type print2_;					\
+		type value_ = val1_;					\
+		setup_block;						\
+		print1_ = print_;					\
+		value_ = val2_;						\
+		setup_block;						\
+		print2_ = print_;					\
+		TT_DECLARE(tt_status_?"	 OK":"FAIL",			\
+			   ("assert(%s): "printf_fmt" vs "printf_fmt,	\
+			    str_test, print1_, print2_));		\
+		print_ = print1_;					\
+		cleanup_block;						\
+		print_ = print2_;					\
+		cleanup_block;						\
+		if (!tt_status_) {					\
+			tinytest_set_test_failed_();			\
+			die_on_fail ;					\
+		}							\
+	}								\
+	TT_STMT_END
+
+#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail)	\
+	tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt,	\
+	    {print_=value_;},{},die_on_fail)
+
+/* Helper: assert that a op b, when cast to type.  Format the values with
+ * printf format fmt on failure. */
+#define tt_assert_op_type(a,op,b,type,fmt)				\
+	tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
+	    TT_EXIT_TEST_FUNCTION)
+
+#define tt_int_op(a,op,b)			\
+	tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
+	    "%ld",TT_EXIT_TEST_FUNCTION)
+
+#define tt_uint_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long,		\
+	    (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
+
+#define tt_ptr_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,void*,			\
+	    (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
+
+#define tt_str_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,const char *,		\
+	    (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
+
+#define tt_want_int_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
+
+#define tt_want_uint_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long,		\
+	    (val1_ op val2_),"%lu",(void)0)
+
+#define tt_want_ptr_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,void*,			\
+	    (val1_ op val2_),"%p",(void)0)
+
+#define tt_want_str_op(a,op,b)						\
+	tt_assert_test_type(a,b,#a" "#op" "#b,const char *,		\
+	    (strcmp(val1_,val2_) op 0),"<%s>",(void)0)
+
+#endif
diff --git a/src/include.am b/src/include.am
index 965a494..d0693e2 100644
--- a/src/include.am
+++ b/src/include.am
@@ -1,6 +1,7 @@
+include src/ext/include.am
 include src/common/include.am
 include src/or/include.am
 include src/test/include.am
 include src/tools/include.am
 include src/win32/include.am
-include src/config/include.am
\ No newline at end of file
+include src/config/include.am
diff --git a/src/or/eventdns.c b/src/or/eventdns.c
deleted file mode 100644
index 768693a..0000000
--- a/src/or/eventdns.c
+++ /dev/null
@@ -1,3505 +0,0 @@
-/* READ THIS COMMENT BEFORE HACKING THIS FILE.
- *
- * This eventdns.c copy has diverged a bit from Libevent's version, and it's
- * no longer easy to resynchronize them.  Once Tor requires Libevent 2.0, we
- * will just dump this file and use Libevent's evdns code.
- *
- * Therefore, you probably shouldn't make any change here without making it to
- * Libevent as well: it's not good for the implementation to diverge even
- * more.  Also, we can't shouldn't wantonly the API here (since Libevent APIs
- * can't change in ways that break user behavior).  Also, we shouldn't bother
- * with cosmetic changes: the whole module is slated for demolition, so
- * there's no point dusting the linebreaks or re-painting the parser.
- *
- * (We can't just drop the Libevent 2.0 evdns implementation in here instead,
- * since it depends pretty heavily on parts of Libevent 2.0.)
- */
-
-/* Async DNS Library
- * Adam Langley <agl at imperialviolet.org>
- * Public Domain code
- *
- * This software is Public Domain. To view a copy of the public domain dedication,
- * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
- * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
- *
- * I ask and expect, but do not require, that all derivative works contain an
- * attribution similar to:
- *	Parts developed by Adam Langley <agl at imperialviolet.org>
- *
- * You may wish to replace the word "Parts" with something else depending on
- * the amount of original code.
- *
- * (Derivative works does not include programs which link against, run or include
- * the source verbatim in their source distributions)
- *
- * Version: 0.1b
- */
-
-#include "eventdns_tor.h"
-#include "../common/util.h"
-#include <sys/types.h>
-/* #define NDEBUG */
-
-#ifndef DNS_USE_CPU_CLOCK_FOR_ID
-#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
-#ifndef DNS_USE_OPENSSL_FOR_ID
-#error Must configure at least one id generation method.
-#error Please see the documentation.
-#endif
-#endif
-#endif
-
-/* #define _POSIX_C_SOURCE 200507 */
-#define _GNU_SOURCE
-
-#ifdef DNS_USE_CPU_CLOCK_FOR_ID
-#ifdef DNS_USE_OPENSSL_FOR_ID
-#error Multiple id options selected
-#endif
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-#error Multiple id options selected
-#endif
-#include <time.h>
-#endif
-
-#ifdef DNS_USE_OPENSSL_FOR_ID
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-#error Multiple id options selected
-#endif
-#include <openssl/rand.h>
-#endif
-
-#include <string.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdlib.h>
-#include <errno.h>
-#include <assert.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#include <sys/stat.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "eventdns.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#include <winsock2.h>
-#include <iphlpapi.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
-#ifdef HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif
-
-#ifdef _WIN32
-typedef int socklen_t;
-#endif
-
-#define EVDNS_LOG_DEBUG 0
-#define EVDNS_LOG_WARN 1
-
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX 255
-#endif
-
-#ifndef NDEBUG
-#include <stdio.h>
-#endif
-
-/* for debugging possible memory leaks. */
-#define mm_malloc(x) tor_malloc(x)
-#define mm_realloc(x,y) tor_realloc((x),(y))
-#define mm_free(x) tor_free(x)
-#define mm_strdup(x) tor_strdup(x)
-#define _mm_free(x) _tor_free(x)
-
-#undef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-#if 0
-#ifdef __USE_ISOC99B
-/* libevent doesn't work without this */
-typedef uint8_t u_char;
-typedef unsigned int uint;
-#endif
-#endif
-#include <event.h>
-
-#define u64 uint64_t
-#define u32 uint32_t
-#define u16 uint16_t
-#define u8	uint8_t
-
-#define MAX_ADDRS 4	 /* maximum number of addresses from a single packet */
-/* which we bother recording */
-
-#define TYPE_A		EVDNS_TYPE_A
-#define TYPE_CNAME	5
-#define TYPE_PTR	EVDNS_TYPE_PTR
-#define TYPE_AAAA	EVDNS_TYPE_AAAA
-
-#define CLASS_INET	EVDNS_CLASS_INET
-
-#define CLEAR(x) do { memset((x), 0xF0, sizeof(*(x))); } while(0)
-
-struct evdns_request {
-	u8 *request; /* the dns packet data */
-	unsigned int request_len;
-	int reissue_count;
-	int tx_count;  /* the number of times that this packet has been sent */
-	unsigned int request_type; /* TYPE_PTR or TYPE_A */
-	void *user_pointer;	 /* the pointer given to us for this request */
-	evdns_callback_type user_callback;
-	struct nameserver *ns;	/* the server which we last sent it */
-
-	/* elements used by the searching code */
-	int search_index;
-	struct search_state *search_state;
-	char *search_origname;	/* needs to be mm_free()ed */
-	int search_flags;
-
-	/* these objects are kept in a circular list */
-	struct evdns_request *next, *prev;
-
-	struct event timeout_event;
-
-	u16 trans_id;  /* the transaction id */
-	char request_appended;	/* true if the request pointer is data which follows this struct */
-	char transmit_me;  /* needs to be transmitted */
-};
-
-#ifndef HAVE_STRUCT_IN6_ADDR
-struct in6_addr {
-	u8 s6_addr[16];
-};
-#endif
-
-struct reply {
-	unsigned int type;
-	unsigned int have_answer;
-	union {
-		struct {
-			u32 addrcount;
-			u32 addresses[MAX_ADDRS];
-		} a;
-		struct {
-			u32 addrcount;
-			struct in6_addr addresses[MAX_ADDRS];
-		} aaaa;
-		struct {
-			char name[HOST_NAME_MAX];
-		} ptr;
-	} data;
-};
-
-struct nameserver {
-	int socket;	 /* a connected UDP socket */
-	struct sockaddr_storage address;
-	int failed_times;  /* number of times which we have given this server a chance */
-	int timedout;  /* number of times in a row a request has timed out */
-	struct event event;
-	/* these objects are kept in a circular list */
-	struct nameserver *next, *prev;
-	struct event timeout_event; /* used to keep the timeout for */
-								/* when we next probe this server. */
-								/* Valid if state == 0 */
-	char state;	 /* zero if we think that this server is down */
-	char choked;  /* true if we have an EAGAIN from this server's socket */
-	char write_waiting;	 /* true if we are waiting for EV_WRITE events */
-};
-
-static struct evdns_request *req_head = NULL, *req_waiting_head = NULL;
-static struct nameserver *server_head = NULL;
-
-/* Represents a local port where we're listening for DNS requests. Right now, */
-/* only UDP is supported. */
-struct evdns_server_port {
-	int socket; /* socket we use to read queries and write replies. */
-	int refcnt; /* reference count. */
-	char choked; /* Are we currently blocked from writing? */
-	char closing; /* Are we trying to close this port, pending writes? */
-	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
-	void *user_data; /* Opaque pointer passed to user_callback */
-	struct event event; /* Read/write event */
-	/* circular list of replies that we want to write. */
-	struct server_request *pending_replies;
-};
-
-/* Represents part of a reply being built.	(That is, a single RR.) */
-struct server_reply_item {
-	struct server_reply_item *next; /* next item in sequence. */
-	char *name; /* name part of the RR */
-	u16 type : 16; /* The RR type */
-	u16 class : 16; /* The RR class (usually CLASS_INET) */
-	u32 ttl; /* The RR TTL */
-	char is_name; /* True iff data is a label */
-	u16 datalen; /* Length of data; -1 if data is a label */
-	void *data; /* The contents of the RR */
-};
-
-/* Represents a request that we've received as a DNS server, and holds */
-/* the components of the reply as we're constructing it. */
-struct server_request {
-	/* Pointers to the next and previous entries on the list of replies */
-	/* that we're waiting to write.	 Only set if we have tried to respond */
-	/* and gotten EAGAIN. */
-	struct server_request *next_pending;
-	struct server_request *prev_pending;
-
-	u16 trans_id; /* Transaction id. */
-	struct evdns_server_port *port; /* Which port received this request on? */
-	struct sockaddr_storage addr; /* Where to send the response */
-	socklen_t addrlen; /* length of addr */
-
-	int n_answer; /* how many answer RRs have been set? */
-	int n_authority; /* how many authority RRs have been set? */
-	int n_additional; /* how many additional RRs have been set? */
-
-	struct server_reply_item *answer; /* linked list of answer RRs */
-	struct server_reply_item *authority; /* linked list of authority RRs */
-	struct server_reply_item *additional; /* linked list of additional RRs */
-
-	/* Constructed response.  Only set once we're ready to send a reply. */
-	/* Once this is set, the RR fields are cleared, and no more should be set. */
-	char *response;
-	size_t response_len;
-
-	/* Caller-visible fields: flags, questions. */
-	struct evdns_server_request base;
-};
-
-/* helper macro */
-#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
-
-/* Given a pointer to an evdns_server_request, get the corresponding */
-/* server_request. */
-#define TO_SERVER_REQUEST(base_ptr)										\
-	((struct server_request*)											\
-	 (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
-
-/* The number of good nameservers that we have */
-static int global_good_nameservers = 0;
-
-/* inflight requests are contained in the req_head list */
-/* and are actually going out across the network */
-static int global_requests_inflight = 0;
-/* requests which aren't inflight are in the waiting list */
-/* and are counted here */
-static int global_requests_waiting = 0;
-
-static int global_max_requests_inflight = 64;
-
-static struct timeval global_timeout = {5, 0};	/* 5 seconds */
-static int global_max_reissues = 1;	/* a reissue occurs when we get some errors from the server */
-static int global_max_retransmits = 3;	/* number of times we'll retransmit a request which timed out */
-/* number of timeouts in a row before we consider this server to be down */
-static int global_max_nameserver_timeout = 3;
-
-/* true iff we should use the 0x20 hack. */
-static int global_randomize_case = 1;
-
-/* These are the timeout values for nameservers. If we find a nameserver is down */
-/* we try to probe it at intervals as given below. Values are in seconds. */
-static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
-static const int global_nameserver_timeouts_length = (int)(sizeof(global_nameserver_timeouts)/sizeof(struct timeval));
-
-static struct nameserver *nameserver_pick(void);
-static void evdns_request_insert(struct evdns_request *req, struct evdns_request **head);
-static void nameserver_ready_callback(int fd, short events, void *arg);
-static int evdns_transmit(void);
-static int evdns_request_transmit(struct evdns_request *req);
-static void nameserver_send_probe(struct nameserver *const ns);
-static void search_request_finished(struct evdns_request *const);
-static int search_try_next(struct evdns_request *const req);
-static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
-static void evdns_requests_pump_waiting_queue(void);
-static u16 transaction_id_pick(void);
-static struct evdns_request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
-static void request_submit(struct evdns_request *req);
-
-static int server_request_free(struct server_request *req);
-static void server_request_free_answers(struct server_request *req);
-static void server_port_free(struct evdns_server_port *port);
-static void server_port_ready_callback(int fd, short events, void *arg);
-
-static int strtoint(const char *const str);
-
-#ifdef _WIN32
-static int
-last_error(int sock)
-{
-	int optval, optvallen=sizeof(optval);
-	int err = WSAGetLastError();
-	if (err == WSAEWOULDBLOCK && sock >= 0) {
-		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
-					   &optvallen))
-			return err;
-		if (optval)
-			return optval;
-	}
-	return err;
-
-}
-static int
-error_is_eagain(int err)
-{
-	return err == EAGAIN || err == WSAEWOULDBLOCK;
-}
-#define inet_aton(c, addr) tor_inet_aton((c), (addr))
-#define CLOSE_SOCKET(x) closesocket(x)
-#else
-#define last_error(sock) (errno)
-#define error_is_eagain(err) ((err) == EAGAIN)
-#define CLOSE_SOCKET(x) close(x)
-#endif
-
-#define ISSPACE(c) TOR_ISSPACE(c)
-#define ISDIGIT(c) TOR_ISDIGIT(c)
-#define ISALPHA(c) TOR_ISALPHA(c)
-#define TOLOWER(c) TOR_TOLOWER(c)
-#define TOUPPER(c) TOR_TOUPPER(c)
-
-#ifndef NDEBUG
-static const char *
-debug_ntoa(u32 address)
-{
-	static char buf[32];
-	u32 a = ntohl(address);
-	snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
-			(int)(u8)((a>>24)&0xff),
-			(int)(u8)((a>>16)&0xff),
-			(int)(u8)((a>>8 )&0xff),
-			(int)(u8)((a	)&0xff));
-	return buf;
-}
-static const char *
-debug_ntop(const struct sockaddr *sa)
-{
-	if (sa->sa_family == AF_INET) {
-		struct sockaddr_in *sin = (struct sockaddr_in *) sa;
-		return debug_ntoa(sin->sin_addr.s_addr);
-	}
-	if (sa->sa_family == AF_INET6) {
-		/* Tor-specific.  In libevent, add more check code. */
-		static char buf[128];
-		struct sockaddr_in6 *sin = (struct sockaddr_in6 *) sa;
-		tor_inet_ntop(AF_INET6, &sin->sin6_addr, buf, sizeof(buf));
-		return buf;
-	}
-	return "<unknown>";
-}
-#endif
-
-static evdns_debug_log_fn_type evdns_log_fn = NULL;
-
-void
-evdns_set_log_fn(evdns_debug_log_fn_type fn)
-{
-	evdns_log_fn = fn;
-}
-
-#ifdef __GNUC__
-#define EVDNS_LOG_CHECK	__attribute__ ((format(printf, 2, 3)))
-#else
-#define EVDNS_LOG_CHECK
-#endif
-
-static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
-static void
-_evdns_log(int warn, const char *fmt, ...)
-{
-	va_list args;
-	static char buf[512];
-	if (!evdns_log_fn)
-		return;
-	va_start(args,fmt);
-#ifdef _WIN32
-	_vsnprintf(buf, sizeof(buf), fmt, args);
-#else
-	vsnprintf(buf, sizeof(buf), fmt, args);
-#endif
-	buf[sizeof(buf)-1] = '\0';
-	evdns_log_fn(warn, buf);
-	va_end(args);
-}
-
-#define log _evdns_log
-
-static int
-sockaddr_eq(const struct sockaddr *sa1, const struct sockaddr *sa2,
-			int include_port)
-{
-	if (sa1->sa_family != sa2->sa_family)
-		return 0;
-	if (sa1->sa_family == AF_INET) {
-		const struct sockaddr_in *sin1, *sin2;
-		sin1 = (const struct sockaddr_in *)sa1;
-		sin2 = (const struct sockaddr_in *)sa2;
-		if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr)
-			return 0;
-		else if (include_port && sin1->sin_port != sin2->sin_port)
-			return 0;
-		else
-			return 1;
-	}
-#ifdef AF_INET6
-	if (sa1->sa_family == AF_INET6) {
-		const struct sockaddr_in6 *sin1, *sin2;
-		sin1 = (const struct sockaddr_in6 *)sa1;
-		sin2 = (const struct sockaddr_in6 *)sa2;
-		if (tor_memneq(sin1->sin6_addr.s6_addr, sin2->sin6_addr.s6_addr, 16))
-			return 0;
-		else if (include_port && sin1->sin6_port != sin2->sin6_port)
-			return 0;
-		else
-			return 1;
-	}
-#endif
-	return 1;
-}
-
-#define add_timeout_event(s, to)				\
-	(event_add(&(s)->timeout_event, (to)))
-#define del_timeout_event(s)					\
-	(event_del(&(s)->timeout_event))
-
-/* This walks the list of inflight requests to find the */
-/* one with a matching transaction id. Returns NULL on */
-/* failure */
-static struct evdns_request *
-request_find_from_trans_id(u16 trans_id) {
-	struct evdns_request *req = req_head, *const started_at = req_head;
-
-	if (req) {
-		do {
-			if (req->trans_id == trans_id) return req;
-			req = req->next;
-		} while (req != started_at);
-	}
-
-	return NULL;
-}
-
-/* a libevent callback function which is called when a nameserver */
-/* has gone down and we want to test if it has came back to life yet */
-static void
-nameserver_prod_callback(int fd, short events, void *arg) {
-	struct nameserver *const ns = (struct nameserver *) arg;
-	(void)fd;
-	(void)events;
-
-	nameserver_send_probe(ns);
-}
-
-/* a libevent callback which is called when a nameserver probe (to see if */
-/* it has come back to life) times out. We increment the count of failed_times */
-/* and wait longer to send the next probe packet. */
-static void
-nameserver_probe_failed(struct nameserver *const ns) {
-	const struct timeval * timeout;
-	del_timeout_event(ns);
-
-	if (ns->state == 1) {
-		/* This can happen if the nameserver acts in a way which makes us mark */
-		/* it as bad and then starts sending good replies. */
-		return;
-	}
-
-	timeout =
-		&global_nameserver_timeouts[MIN(ns->failed_times,
-										global_nameserver_timeouts_length - 1)];
-	ns->failed_times++;
-
-	if (add_timeout_event(ns, (struct timeval *) timeout) < 0) {
-		log(EVDNS_LOG_WARN,
-			"Error from libevent when adding timer event for %s",
-			debug_ntop((struct sockaddr *)&ns->address));
-		/* ???? Do more? */
-	}
-}
-
-/* called when a nameserver has been deemed to have failed. For example, too */
-/* many packets have timed out etc */
-static void
-nameserver_failed(struct nameserver *const ns, const char *msg) {
-	struct evdns_request *req, *started_at;
-	/* if this nameserver has already been marked as failed */
-	/* then don't do anything */
-	if (!ns->state) return;
-
-	log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
-		debug_ntop((struct sockaddr *)&ns->address), msg);
-	global_good_nameservers--;
-	assert(global_good_nameservers >= 0);
-	if (global_good_nameservers == 0) {
-		log(EVDNS_LOG_WARN, "All nameservers have failed");
-	}
-
-	ns->state = 0;
-	ns->failed_times = 1;
-
-	if (add_timeout_event(ns, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
-		log(EVDNS_LOG_WARN,
-			"Error from libevent when adding timer event for %s",
-			debug_ntop((struct sockaddr *)&ns->address));
-		/* ???? Do more? */
-	}
-
-	/* walk the list of inflight requests to see if any can be reassigned to */
-	/* a different server. Requests in the waiting queue don't have a */
-	/* nameserver assigned yet */
-
-	/* if we don't have *any* good nameservers then there's no point */
-	/* trying to reassign requests to one */
-	if (!global_good_nameservers) return;
-
-	req = req_head;
-	started_at = req_head;
-	if (req) {
-		do {
-			if (req->tx_count == 0 && req->ns == ns) {
-				/* still waiting to go out, can be moved */
-				/* to another server */
-				req->ns = nameserver_pick();
-			}
-			req = req->next;
-		} while (req != started_at);
-	}
-}
-
-static void
-nameserver_up(struct nameserver *const ns) {
-	if (ns->state) return;
-	log(EVDNS_LOG_WARN, "Nameserver %s is back up",
-		debug_ntop((struct sockaddr *)&ns->address));
-	del_timeout_event(ns);
-	ns->state = 1;
-	ns->failed_times = 0;
-	ns->timedout = 0;
-	global_good_nameservers++;
-}
-
-static void
-request_trans_id_set(struct evdns_request *const req, const u16 trans_id) {
-	req->trans_id = trans_id;
-	*((u16 *) req->request) = htons(trans_id);
-}
-
-/* Called to remove a request from a list and dealloc it. */
-/* head is a pointer to the head of the list it should be */
-/* removed from or NULL if the request isn't in a list. */
-static void
-request_finished(struct evdns_request *const req, struct evdns_request **head) {
-	if (head) {
-		if (req->next == req) {
-			/* only item in the list */
-			*head = NULL;
-		} else {
-			req->next->prev = req->prev;
-			req->prev->next = req->next;
-			if (*head == req) *head = req->next;
-		}
-	}
-
-	log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
-		(unsigned long) req);
-	del_timeout_event(req);
-
-	search_request_finished(req);
-	global_requests_inflight--;
-
-	if (!req->request_appended) {
-		/* need to free the request data on it's own */
-		mm_free(req->request);
-	} else {
-		/* the request data is appended onto the header */
-		/* so everything gets mm_free()ed when we: */
-	}
-
-	CLEAR(req);
-	_mm_free(req);
-
-	evdns_requests_pump_waiting_queue();
-}
-
-/* This is called when a server returns a funny error code. */
-/* We try the request again with another server. */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 failed/reissue is pointless */
-static int
-request_reissue(struct evdns_request *req) {
-	const struct nameserver *const last_ns = req->ns;
-	/* the last nameserver should have been marked as failing */
-	/* by the caller of this function, therefore pick will try */
-	/* not to return it */
-	req->ns = nameserver_pick();
-	if (req->ns == last_ns) {
-		/* ... but pick did return it */
-		/* not a lot of point in trying again with the */
-		/* same server */
-		return 1;
-	}
-
-	req->reissue_count++;
-	req->tx_count = 0;
-	req->transmit_me = 1;
-
-	return 0;
-}
-
-/* this function looks for space on the inflight queue and promotes */
-/* requests from the waiting queue if it can. */
-static void
-evdns_requests_pump_waiting_queue(void) {
-	while (global_requests_inflight < global_max_requests_inflight &&
-		global_requests_waiting) {
-		struct evdns_request *req;
-		/* move a request from the waiting queue to the inflight queue */
-		assert(req_waiting_head);
-		if (req_waiting_head->next == req_waiting_head) {
-			/* only one item in the queue */
-			req = req_waiting_head;
-			req_waiting_head = NULL;
-		} else {
-			req = req_waiting_head;
-			req->next->prev = req->prev;
-			req->prev->next = req->next;
-			req_waiting_head = req->next;
-		}
-
-		global_requests_waiting--;
-		global_requests_inflight++;
-
-		req->ns = nameserver_pick();
-		request_trans_id_set(req, transaction_id_pick());
-
-		evdns_request_insert(req, &req_head);
-		evdns_request_transmit(req);
-		evdns_transmit();
-	}
-}
-
-static void
-reply_callback(struct evdns_request *const req, u32 ttl, u32 err, struct reply *reply) {
-	switch (req->request_type) {
-	case TYPE_A:
-		if (reply)
-			req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
-							   reply->data.a.addrcount, ttl,
-							   reply->data.a.addresses,
-							   req->user_pointer);
-		else
-			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
-		return;
-	case TYPE_PTR:
-		if (reply) {
-			char *name = reply->data.ptr.name;
-			req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
-							   &name, req->user_pointer);
-		} else {
-			req->user_callback(err, 0, 0, 0, NULL,
-							   req->user_pointer);
-		}
-		return;
-	case TYPE_AAAA:
-		if (reply)
-			req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
-							   reply->data.aaaa.addrcount, ttl,
-							   reply->data.aaaa.addresses,
-							   req->user_pointer);
-		else
-			req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
-		return;
-	}
-	assert(0);
-}
-
-/* this processes a parsed reply packet */
-static void
-reply_handle(struct evdns_request *const req, u16 flags, u32 ttl, struct reply *reply) {
-	int error;
-	static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED};
-
-	if (flags & 0x020f || !reply || !reply->have_answer) {
-		/* there was an error */
-		if (flags & 0x0200) {
-			error = DNS_ERR_TRUNCATED;
-		} else {
-			u16 error_code = (flags & 0x000f) - 1;
-			if (error_code > 4) {
-				error = DNS_ERR_UNKNOWN;
-			} else {
-				error = error_codes[error_code];
-			}
-		}
-
-		switch(error) {
-		case DNS_ERR_NOTIMPL:
-		case DNS_ERR_REFUSED:
-			/* we regard these errors as marking a bad nameserver */
-			if (req->reissue_count < global_max_reissues) {
-				char msg[64];
-				snprintf(msg, sizeof(msg), "Bad response %d (%s)",
-						 error, evdns_err_to_string(error));
-				nameserver_failed(req->ns, msg);
-				if (!request_reissue(req)) return;
-			}
-			break;
-		case DNS_ERR_SERVERFAILED:
-			/* rcode 2 (servfailed) sometimes means "we are broken" and
-			 * sometimes (with some binds) means "that request was very
-			 * confusing."  Treat this as a timeout, not a failure.
-			 */
-			/*XXXX refactor the parts of */
-			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
-				"will allow the request to time out.",
-				debug_ntop((struct sockaddr *)&req->ns->address));
-			break;
-		default:
-			/* we got a good reply from the nameserver */
-			nameserver_up(req->ns);
-		}
-
-		if (req->search_state && req->request_type != TYPE_PTR) {
-			/* if we have a list of domains to search in, try the next one */
-			if (!search_try_next(req)) {
-				/* a new request was issued so this request is finished and */
-				/* the user callback will be made when that request (or a */
-				/* child of it) finishes. */
-				request_finished(req, &req_head);
-				return;
-			}
-		}
-
-		/* all else failed. Pass the failure up */
-		reply_callback(req, 0, error, NULL);
-		request_finished(req, &req_head);
-	} else {
-		/* all ok, tell the user */
-		reply_callback(req, ttl, 0, reply);
-		nameserver_up(req->ns);
-		request_finished(req, &req_head);
-	}
-}
-
-static INLINE int
-name_parse(u8 *packet, int length, int *idx, char *name_out, size_t name_out_len) {
-	int name_end = -1;
-	int j = *idx;
-	int ptr_count = 0;
-#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
-#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
-#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
-
-	char *cp = name_out;
-	const char *const end = name_out + name_out_len;
-
-	/* Normally, names are a series of length prefixed strings terminated */
-	/* with a length of 0 (the lengths are u8's < 63). */
-	/* However, the length can start with a pair of 1 bits and that */
-	/* means that the next 14 bits are a pointer within the current */
-	/* packet. */
-
-	for(;;) {
-		u8 label_len;
-		if (j >= length) return -1;
-		GET8(label_len);
-		if (!label_len) break;
-		if (label_len & 0xc0) {
-			u8 ptr_low;
-			GET8(ptr_low);
-			if (name_end < 0) name_end = j;
-			j = (((int)label_len & 0x3f) << 8) + ptr_low;
-			/* Make sure that the target offset is in-bounds. */
-			if (j < 0 || j >= length) return -1;
-			/* If we've jumped more times than there are characters in the
-			 * message, we must have a loop. */
-			if (++ptr_count > length) return -1;
-			continue;
-		}
-		if (label_len > 63) return -1;
-		if (cp != name_out) {
-			if (cp + 1 >= end) return -1;
-			*cp++ = '.';
-		}
-		if (cp + label_len >= end) return -1;
-		memcpy(cp, packet + j, label_len);
-		cp += label_len;
-		j += label_len;
-	}
-	if (cp >= end) return -1;
-	*cp = '\0';
-	if (name_end < 0)
-		*idx = j;
-	else
-		*idx = name_end;
-	return 0;
- err:
-	return -1;
-}
-
-/* parses a raw reply from a nameserver. */
-static int
-reply_parse(u8 *packet, int length) {
-	int j = 0;	/* index into packet */
-	int k;
-	u16 _t;	 /* used by the macros */
-	u32 _t32;  /* used by the macros */
-	char tmp_name[256], cmp_name[256]; /* used by the macros */
-
-	u16 trans_id, questions, answers, authority, additional, datalength;
-	u16 flags = 0;
-	u32 ttl, ttl_r = 0xffffffff;
-	struct reply reply;
-	struct evdns_request *req = NULL;
-	unsigned int i;
-	int name_matches = 0;
-
-	GET16(trans_id);
-	GET16(flags);
-	GET16(questions);
-	GET16(answers);
-	GET16(authority);
-	GET16(additional);
-	(void) authority; /* suppress "unused variable" warnings. */
-	(void) additional; /* suppress "unused variable" warnings. */
-
-	req = request_find_from_trans_id(trans_id);
-	/* if no request, can't do anything. */
-	if (!req) return -1;
-
-	memset(&reply, 0, sizeof(reply));
-
-	/* If it's not an answer, it doesn't go with any of our requests. */
-	if (!(flags & 0x8000)) return -1;  /* must be an answer */
-	if (flags & 0x020f) {
-		/* there was an error */
-		goto err;
-	}
-	/* if (!answers) return; */  /* must have an answer of some form */
-
-	/* This macro skips a name in the DNS reply. */
-#define GET_NAME \
-	do { tmp_name[0] = '\0';				\
-		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
-			goto err;				\
-	} while(0)
-#define TEST_NAME \
-	do { tmp_name[0] = '\0';				\
-		cmp_name[0] = '\0';				\
-		k = j;						\
-		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
-			goto err;					\
-		if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0)	\
-			goto err;				\
-		if (global_randomize_case) {							\
-			if (strcmp(tmp_name, cmp_name) == 0)				\
-				name_matches = 1; /* we ignore mismatching names */	\
-		} else {													\
-			if (strcasecmp(tmp_name, cmp_name) == 0)				\
-				name_matches = 1;									\
-		}															\
-	} while(0)
-
-	reply.type = req->request_type;
-
-	/* skip over each question in the reply */
-	for (i = 0; i < questions; ++i) {
-		/* the question looks like
-		 * <label:name><u16:type><u16:class>
-		 */
-		TEST_NAME;
-		j += 4;
-		if (j >= length) goto err;
-	}
-
-	if (!name_matches)
-		goto err;
-
-	/* now we have the answer section which looks like
-	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
-	 */
-
-	for (i = 0; i < answers; ++i) {
-		u16 type, class;
-
-		GET_NAME;
-		GET16(type);
-		GET16(class);
-		GET32(ttl);
-		GET16(datalength);
-
-		if (type == TYPE_A && class == CLASS_INET) {
-			int addrcount, addrtocopy;
-			if (req->request_type != TYPE_A) {
-				j += datalength; continue;
-			}
-			if ((datalength & 3) != 0) /* not an even number of As. */
-				goto err;
-			addrcount = datalength >> 2;
-			addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
-
-			ttl_r = MIN(ttl_r, ttl);
-			/* we only bother with the first four addresses. */
-			if (j + 4*addrtocopy > length) goto err;
-			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
-				   packet + j, 4*addrtocopy);
-			reply.data.a.addrcount += addrtocopy;
-			reply.have_answer = 1;
-			if (reply.data.a.addrcount == MAX_ADDRS) break;
-			j += 4*addrtocopy;
-		} else if (type == TYPE_PTR && class == CLASS_INET) {
-			if (req->request_type != TYPE_PTR) {
-				j += datalength; continue;
-			}
-			GET_NAME;
-			strlcpy(reply.data.ptr.name, tmp_name,
-					sizeof(reply.data.ptr.name));
-			ttl_r = MIN(ttl_r, ttl);
-			reply.have_answer = 1;
-			break;
-		} else if (type == TYPE_AAAA && class == CLASS_INET) {
-			int addrcount, addrtocopy;
-			if (req->request_type != TYPE_AAAA) {
-				j += datalength; continue;
-			}
-			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
-				goto err;
-			addrcount = datalength >> 4;  /* each address is 16 bytes long */
-			addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
-			ttl_r = MIN(ttl_r, ttl);
-
-			/* we only bother with the first four addresses. */
-			if (j + 16*addrtocopy > length) goto err;
-			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
-				   packet + j, 16*addrtocopy);
-			reply.data.aaaa.addrcount += addrtocopy;
-			reply.have_answer = 1;
-			if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
-			j += 16*addrtocopy;
-		} else {
-			/* skip over any other type of resource */
-			j += datalength;
-		}
-	}
-
-	reply_handle(req, flags, ttl_r, &reply);
-	return 0;
- err:
-	if (req)
-		reply_handle(req, flags, 0, NULL);
-	return -1;
-}
-
-/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
-/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
-/* callback. */
-static int
-request_parse(u8 *packet, ssize_t length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
-{
-	int j = 0;	/* index into packet */
-	u16 _t;	 /* used by the macros */
-	char tmp_name[256]; /* used by the macros */
-
-	int i;
-	u16 trans_id, flags, questions, answers, authority, additional;
-	struct server_request *server_req = NULL;
-
-	/* Get the header fields */
-	GET16(trans_id);
-	GET16(flags);
-	GET16(questions);
-	GET16(answers);
-	GET16(authority);
-	GET16(additional);
-	(void)additional;
-	(void)authority;
-	(void)answers;
-
-	if (flags & 0x8000) return -1; /* Must not be an answer. */
-	flags &= 0x0110; /* Only RD and CD get preserved. */
-
-    if (length > INT_MAX)
-        return -1;
-
-	server_req = mm_malloc(sizeof(struct server_request));
-	if (server_req == NULL) return -1;
-	memset(server_req, 0, sizeof(struct server_request));
-
-	server_req->trans_id = trans_id;
-	memcpy(&server_req->addr, addr, addrlen);
-	server_req->addrlen = addrlen;
-
-	server_req->base.flags = flags;
-	server_req->base.nquestions = 0;
-	server_req->base.questions = mm_malloc(sizeof(struct evdns_server_question *) * questions);
-	if (server_req->base.questions == NULL)
-		goto err;
-
-	for (i = 0; i < questions; ++i) {
-		u16 type, class;
-		struct evdns_server_question *q;
-		size_t namelen;
-		if (name_parse(packet, (int)length, &j, tmp_name, sizeof(tmp_name))<0)
-			goto err;
-		GET16(type);
-		GET16(class);
-		namelen = strlen(tmp_name);
-		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
-		if (!q)
-			goto err;
-		q->type = type;
-		q->dns_question_class = class;
-		memcpy(q->name, tmp_name, namelen+1);
-		server_req->base.questions[server_req->base.nquestions++] = q;
-	}
-
-	/* Ignore answers, authority, and additional. */
-
-	server_req->port = port;
-	port->refcnt++;
-
-	/* Only standard queries are supported. */
-	if (flags & 0x7800) {
-		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
-		return -1;
-	}
-
-	port->user_callback(&(server_req->base), port->user_data);
-
-	return 0;
-err:
-	if (server_req) {
-		if (server_req->base.questions) {
-			for (i = 0; i < server_req->base.nquestions; ++i)
-				mm_free(server_req->base.questions[i]);
-			mm_free(server_req->base.questions);
-		}
-		CLEAR(server_req);
-		mm_free(server_req);
-	}
-	return -1;
-
-#undef SKIP_NAME
-#undef GET32
-#undef GET16
-#undef GET8
-}
-
-static uint16_t
-default_transaction_id_fn(void)
-{
-	u16 trans_id;
-#ifdef DNS_USE_CPU_CLOCK_FOR_ID
-	struct timespec ts;
-#ifdef CLOCK_MONOTONIC
-	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
-#else
-	if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
-#endif
-	event_err(1, "clock_gettime");
-	trans_id = ts.tv_nsec & 0xffff;
-#endif
-
-#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	trans_id = tv.tv_usec & 0xffff;
-#endif
-
-#ifdef DNS_USE_OPENSSL_FOR_ID
-	if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
-		/* in the case that the RAND call fails we back */
-		/* down to using gettimeofday. */
-		/*
-		  struct timeval tv;
-		  gettimeofday(&tv, NULL);
-		  trans_id = tv.tv_usec & 0xffff;
-		*/
-		abort();
-	}
-#endif
-	return (unsigned short) trans_id;
-}
-
-static uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
-
-static void
-default_random_bytes_fn(char *buf, size_t n)
-{
-	unsigned i;
-	for (i = 0; i < n; i += 2) {
-		u16 tid = trans_id_function();
-		buf[i] = (tid >> 8) & 0xff;
-		if (i+1<n)
-			buf[i+1] = tid & 0xff;
-	}
-}
-
-static void (*rand_bytes_function)(char *buf, size_t n) =
-	default_random_bytes_fn;
-
-static u16
-trans_id_from_random_bytes_fn(void)
-{
-	u16 tid;
-	rand_bytes_function((char*) &tid, sizeof(tid));
-	return tid;
-}
-
-void
-evdns_set_transaction_id_fn(uint16_t (*fn)(void))
-{
-	if (fn)
-		trans_id_function = fn;
-	else
-		trans_id_function = default_transaction_id_fn;
-	rand_bytes_function = default_random_bytes_fn;
-}
-
-void
-evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
-{
-	rand_bytes_function = fn;
-	trans_id_function = trans_id_from_random_bytes_fn;
-}
-
-/* Try to choose a strong transaction id which isn't already in flight */
-static u16
-transaction_id_pick(void) {
-	for (;;) {
-		const struct evdns_request *req = req_head, *started_at;
-		u16 trans_id = trans_id_function();
-
-		if (trans_id == 0xffff) continue;
-		/* now check to see if that id is already inflight */
-		req = started_at = req_head;
-		if (req) {
-			do {
-				if (req->trans_id == trans_id) break;
-				req = req->next;
-			} while (req != started_at);
-		}
-		/* we didn't find it, so this is a good id */
-		if (req == started_at) return trans_id;
-	}
-}
-
-/* choose a namesever to use. This function will try to ignore */
-/* nameservers which we think are down and load balance across the rest */
-/* by updating the server_head global each time. */
-static struct nameserver *
-nameserver_pick(void) {
-	struct nameserver *started_at = server_head, *picked;
-	if (!server_head) return NULL;
-
-	/* if we don't have any good nameservers then there's no */
-	/* point in trying to find one. */
-	if (!global_good_nameservers) {
-		server_head = server_head->next;
-		return server_head;
-	}
-
-	/* remember that nameservers are in a circular list */
-	for (;;) {
-		if (server_head->state) {
-			/* we think this server is currently good */
-			picked = server_head;
-			server_head = server_head->next;
-			return picked;
-		}
-
-		server_head = server_head->next;
-		if (server_head == started_at) {
-			/* all the nameservers seem to be down */
-			/* so we just return this one and hope for the */
-			/* best */
-			assert(global_good_nameservers == 0);
-			picked = server_head;
-			server_head = server_head->next;
-			return picked;
-		}
-	}
-}
-
-/* this is called when a namesever socket is ready for reading */
-static void
-nameserver_read(struct nameserver *ns) {
-	struct sockaddr_storage ss;
-	struct sockaddr *sa = (struct sockaddr *) &ss;
-	socklen_t addrlen = sizeof(ss);
-	u8 packet[1500];
-
-	for (;;) {
-		const int r =
-            (int)recvfrom(ns->socket, (void*)packet,
-						  (socklen_t)sizeof(packet), 0,
-						  sa, &addrlen);
-		if (r < 0) {
-			int err = last_error(ns->socket);
-			if (error_is_eagain(err)) return;
-			nameserver_failed(ns, tor_socket_strerror(err));
-			return;
-		}
-		/* XXX Match port too? */
-		if (!sockaddr_eq(sa, (struct sockaddr*)&ns->address, 0)) {
-			log(EVDNS_LOG_WARN,
-				"Address mismatch on received DNS packet.  Address was %s",
-				debug_ntop(sa));
-			return;
-		}
-		ns->timedout = 0;
-		reply_parse(packet, r);
-	}
-}
-
-/* Read a packet from a DNS client on a server port s, parse it, and */
-/* act accordingly. */
-static void
-server_port_read(struct evdns_server_port *s) {
-	u8 packet[1500];
-	struct sockaddr_storage addr;
-	socklen_t addrlen;
-	ssize_t r;
-
-	for (;;) {
-		addrlen = (socklen_t)sizeof(struct sockaddr_storage);
-		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
-					 (struct sockaddr*) &addr, &addrlen);
-		if (r < 0) {
-			int err = last_error(s->socket);
-			if (error_is_eagain(err)) return;
-			log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
-				tor_socket_strerror(err), err);
-			return;
-		}
-		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
-	}
-}
-
-/* Try to write all pending replies on a given DNS server port. */
-static void
-server_port_flush(struct evdns_server_port *port)
-{
-	struct server_request *req = port->pending_replies;
-	while (req) {
-		ssize_t r = sendto(port->socket, req->response, req->response_len, 0,
-                       (struct sockaddr*) &req->addr, (socklen_t)req->addrlen);
-		if (r < 0) {
-			int err = last_error(port->socket);
-			if (error_is_eagain(err))
-				return;
-			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", tor_socket_strerror(err), err);
-		}
-		if (server_request_free(req)) {
-			/* we released the last reference to req->port. */
-			return;
-		} else {
-			assert(port->pending_replies != req);
-			req = port->pending_replies;
-		}
-	}
-
-	/* We have no more pending requests; stop listening for 'writeable' events. */
-	(void) event_del(&port->event);
-	CLEAR(&port->event);
-	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
-			  server_port_ready_callback, port);
-	if (event_add(&port->event, NULL) < 0) {
-		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
-		/* ???? Do more? */
-	}
-}
-
-/* set if we are waiting for the ability to write to this server. */
-/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
-/* we stop these events. */
-static void
-nameserver_write_waiting(struct nameserver *ns, char waiting) {
-	if (ns->write_waiting == waiting) return;
-
-	ns->write_waiting = waiting;
-	(void) event_del(&ns->event);
-	CLEAR(&ns->event);
-	event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
-			  nameserver_ready_callback, ns);
-	if (event_add(&ns->event, NULL) < 0) {
-		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
-			debug_ntop((struct sockaddr *)&ns->address));
-		/* ???? Do more? */
-	}
-}
-
-/* a callback function. Called by libevent when the kernel says that */
-/* a nameserver socket is ready for writing or reading */
-static void
-nameserver_ready_callback(int fd, short events, void *arg) {
-	struct nameserver *ns = (struct nameserver *) arg;
-	(void)fd;
-
-	if (events & EV_WRITE) {
-		ns->choked = 0;
-		if (!evdns_transmit()) {
-			nameserver_write_waiting(ns, 0);
-		}
-	}
-	if (events & EV_READ) {
-		nameserver_read(ns);
-	}
-}
-
-/* a callback function. Called by libevent when the kernel says that */
-/* a server socket is ready for writing or reading. */
-static void
-server_port_ready_callback(int fd, short events, void *arg) {
-	struct evdns_server_port *port = (struct evdns_server_port *) arg;
-	(void) fd;
-
-	if (events & EV_WRITE) {
-		port->choked = 0;
-		server_port_flush(port);
-	}
-	if (events & EV_READ) {
-		server_port_read(port);
-	}
-}
-
-/* This is an inefficient representation; only use it via the dnslabel_table_*
- * functions, so that is can be safely replaced with something smarter later. */
-#define MAX_LABELS 128
-/* Structures used to implement name compression */
-struct dnslabel_entry { char *v; off_t pos; };
-struct dnslabel_table {
-	int n_labels; /* number of current entries */
-	/* map from name to position in message */
-	struct dnslabel_entry labels[MAX_LABELS];
-};
-
-/* Initialize dnslabel_table. */
-static void
-dnslabel_table_init(struct dnslabel_table *table)
-{
-	table->n_labels = 0;
-}
-
-/* Free all storage held by table, but not the table itself. */
-static void
-dnslabel_clear(struct dnslabel_table *table)
-{
-	int i;
-	for (i = 0; i < table->n_labels; ++i)
-		mm_free(table->labels[i].v);
-	table->n_labels = 0;
-}
-
-/* return the position of the label in the current message, or -1 if the label */
-/* hasn't been used yet. */
-static int
-dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
-{
-	int i;
-	for (i = 0; i < table->n_labels; ++i) {
-		if (!strcmp(label, table->labels[i].v)) {
-			off_t pos = table->labels[i].pos;
-            if (pos > 65535)
-                return -1;
-            return (int)pos;
-        }
-	}
-	return -1;
-}
-
-/* remember that we've used the label at position pos */
-static int
-dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
-{
-	char *v;
-	int p;
-	if (table->n_labels == MAX_LABELS)
-		return (-1);
-	v = mm_strdup(label);
-	if (v == NULL)
-		return (-1);
-	p = table->n_labels++;
-	table->labels[p].v = v;
-	table->labels[p].pos = pos;
-
-	return (0);
-}
-
-/* Converts a string to a length-prefixed set of DNS labels, starting */
-/* at buf[j]. name and buf must not overlap. name_len should be the length */
-/* of name.	 table is optional, and is used for compression. */
-/* */
-/* Input: abc.def */
-/* Output: <3>abc<3>def<0> */
-/* */
-/* Returns the first index after the encoded name, or negative on error. */
-/* -1	 label was > 63 bytes */
-/* -2	 name too long to fit in buffer. */
-/* */
-static off_t
-dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
-				  const char *name, const size_t name_len,
-				  struct dnslabel_table *table) {
-	const char *end = name + name_len;
-	int ref = 0;
-	u16 _t;
-
-#define APPEND16(x) do {						   \
-		if (j + 2 > (off_t)buf_len)				   \
-			goto overflow;						   \
-		_t = htons(x);							   \
-		memcpy(buf + j, &_t, 2);				   \
-		j += 2;									   \
-	} while (0)
-#define APPEND32(x) do {						   \
-		if (j + 4 > (off_t)buf_len)				   \
-			goto overflow;						   \
-		_t32 = htonl(x);						   \
-		memcpy(buf + j, &_t32, 4);				   \
-		j += 4;									   \
-	} while (0)
-
-	if (name_len > 255) return -2;
-
-	for (;;) {
-		const char *const start = name;
-		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
-			APPEND16(ref | 0xc000);
-			return j;
-		}
-		name = strchr(name, '.');
-		if (!name) {
-			const size_t label_len = end - start;
-			if (label_len > 63) return -1;
-			if ((size_t)(j+label_len+1) > buf_len) return -2;
-			if (table) dnslabel_table_add(table, start, j);
-			buf[j++] = (uint8_t)label_len;
-
-			memcpy(buf + j, start, label_len);
-			j += end - start;
-			break;
-		} else {
-			/* append length of the label. */
-			const size_t label_len = name - start;
-			if (label_len > 63) return -1;
-			if ((size_t)(j+label_len+1) > buf_len) return -2;
-			if (table) dnslabel_table_add(table, start, j);
-			buf[j++] = (uint8_t)label_len;
-
-			memcpy(buf + j, start, name - start);
-			j += name - start;
-			/* hop over the '.' */
-			name++;
-		}
-	}
-
-	/* the labels must be terminated by a 0. */
-	/* It's possible that the name ended in a . */
-	/* in which case the zero is already there */
-	if (!j || buf[j-1]) buf[j++] = 0;
-	return j;
- overflow:
-	return (-2);
-}
-
-/* Finds the length of a dns request for a DNS name of the given */
-/* length. The actual request may be smaller than the value returned */
-/* here */
-static size_t
-evdns_request_len(const size_t name_len) {
-	return 96 + /* length of the DNS standard header */
-		name_len + 2 +
-		4;	/* space for the resource type */
-}
-
-/* build a dns request packet into buf. buf should be at least as long */
-/* as evdns_request_len told you it should be. */
-/* */
-/* Returns the amount of space used. Negative on error. */
-static int
-evdns_request_data_build(const char *const name, const size_t name_len,
-						 const u16 trans_id, const u16 type, const u16 class,
-						 u8 *const buf, size_t buf_len) {
-	off_t j = 0;	/* current offset into buf */
-	u16 _t;	 /* used by the macros */
-
-	APPEND16(trans_id);
-	APPEND16(0x0100);  /* standard query, recusion needed */
-	APPEND16(1);  /* one question */
-	APPEND16(0);  /* no answers */
-	APPEND16(0);  /* no authority */
-	APPEND16(0);  /* no additional */
-
-	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
-	if (j < 0) {
-		return (int)j;
-	}
-
-	APPEND16(type);
-	APPEND16(class);
-
-	return (int)j;
- overflow:
-	return (-1);
-}
-
-/* exported function */
-struct evdns_server_port *
-evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
-{
-	struct evdns_server_port *port;
-	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
-		return NULL;
-	memset(port, 0, sizeof(struct evdns_server_port));
-
-	assert(!is_tcp); /* TCP sockets not yet implemented */
-	port->socket = socket;
-	port->refcnt = 1;
-	port->choked = 0;
-	port->closing = 0;
-	port->user_callback = cb;
-	port->user_data = user_data;
-	port->pending_replies = NULL;
-
-	event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
-			  server_port_ready_callback, port);
-	if (event_add(&port->event, NULL)<0) {
-		mm_free(port);
-		return NULL;
-	}
-	return port;
-}
-
-/* exported function */
-void
-evdns_close_server_port(struct evdns_server_port *port)
-{
-	port->closing = 1;
-	if (--port->refcnt == 0)
-		server_port_free(port);
-}
-
-/* exported function */
-int
-evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
-{
-	struct server_request *req = TO_SERVER_REQUEST(_req);
-	struct server_reply_item **itemp, *item;
-	int *countp;
-
-	if (req->response) /* have we already answered? */
-		return (-1);
-
-	switch (section) {
-	case EVDNS_ANSWER_SECTION:
-		itemp = &req->answer;
-		countp = &req->n_answer;
-		break;
-	case EVDNS_AUTHORITY_SECTION:
-		itemp = &req->authority;
-		countp = &req->n_authority;
-		break;
-	case EVDNS_ADDITIONAL_SECTION:
-		itemp = &req->additional;
-		countp = &req->n_additional;
-		break;
-	default:
-		return (-1);
-	}
-	while (*itemp) {
-		itemp = &((*itemp)->next);
-	}
-	item = mm_malloc(sizeof(struct server_reply_item));
-	if (!item)
-		return -1;
-	CLEAR(item);
-	item->next = NULL;
-	if (!(item->name = mm_strdup(name))) {
-		CLEAR(item);
-		mm_free(item);
-		return -1;
-	}
-	item->type = type;
-	item->class = class;
-	item->ttl = ttl;
-	item->is_name = is_name != 0;
-	item->datalen = 0;
-	item->data = NULL;
-	if (data) {
-		if (item->is_name) {
-			if (!(item->data = mm_strdup(data))) {
-				mm_free(item->name);
-				CLEAR(item);
-				mm_free(item);
-				return -1;
-			}
-			item->datalen = (u16)-1;
-		} else {
-			if (!(item->data = mm_malloc(datalen))) {
-				mm_free(item->name);
-				CLEAR(item);
-				mm_free(item);
-				return -1;
-			}
-			item->datalen = datalen;
-			memcpy(item->data, data, datalen);
-		}
-	}
-
-	*itemp = item;
-	++(*countp);
-	return 0;
-}
-
-/* exported function */
-int
-evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
-{
-	return evdns_server_request_add_reply(
-		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
-		  ttl, n*4, 0, addrs);
-}
-
-/* exported function */
-int
-evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
-{
-	return evdns_server_request_add_reply(
-		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
-		  ttl, n*16, 0, addrs);
-}
-
-/* exported function */
-int
-evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
-{
-	u32 a;
-	char buf[32];
-	assert(in || inaddr_name);
-	assert(!(in && inaddr_name));
-	if (in) {
-		a = ntohl(in->s_addr);
-		snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
-				(int)(u8)((a	)&0xff),
-				(int)(u8)((a>>8 )&0xff),
-				(int)(u8)((a>>16)&0xff),
-				(int)(u8)((a>>24)&0xff));
-		inaddr_name = buf;
-	}
-	return evdns_server_request_add_reply(
-		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
-		  ttl, -1, 1, hostname);
-}
-
-/* exported function */
-int
-evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
-{
-	return evdns_server_request_add_reply(
-		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
-		  ttl, -1, 1, cname);
-}
-
-
-static int
-evdns_server_request_format_response(struct server_request *req, int err)
-{
-	unsigned char buf[1500];
-	size_t buf_len = sizeof(buf);
-	off_t j = 0, r;
-	u16 _t;
-	u32 _t32;
-	int i;
-	u16 flags;
-	struct dnslabel_table table;
-
-	if (err < 0 || err > 15) return -1;
-
-	/* Set response bit and error code; copy OPCODE and RD fields from
-	 * question; copy RA and AA if set by caller. */
-	flags = req->base.flags;
-	flags |= (0x8000 | err);
-
-	dnslabel_table_init(&table);
-	APPEND16(req->trans_id);
-	APPEND16(flags);
-	APPEND16(req->base.nquestions);
-	APPEND16(req->n_answer);
-	APPEND16(req->n_authority);
-	APPEND16(req->n_additional);
-
-	/* Add questions. */
-	for (i=0; i < req->base.nquestions; ++i) {
-		const char *s = req->base.questions[i]->name;
-		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
-		if (j < 0) {
-			dnslabel_clear(&table);
-			return (int) j;
-		}
-		APPEND16(req->base.questions[i]->type);
-		APPEND16(req->base.questions[i]->dns_question_class);
-	}
-
-	/* Add answer, authority, and additional sections. */
-	for (i=0; i<3; ++i) {
-		struct server_reply_item *item;
-		if (i==0)
-			item = req->answer;
-		else if (i==1)
-			item = req->authority;
-		else
-			item = req->additional;
-		while (item) {
-			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
-			if (r < 0)
-				goto overflow;
-			j = r;
-
-			APPEND16(item->type);
-			APPEND16(item->class);
-			APPEND32(item->ttl);
-			if (item->is_name) {
-				off_t len_idx = j, name_start;
-				j += 2;
-				name_start = j;
-				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
-				if (r < 0)
-					goto overflow;
-				j = r;
-				_t = htons( (j-name_start) );
-				memcpy(buf+len_idx, &_t, 2);
-			} else {
-				APPEND16(item->datalen);
-				if (j+item->datalen > (off_t)buf_len)
-					goto overflow;
-				memcpy(buf+j, item->data, item->datalen);
-				j += item->datalen;
-			}
-			item = item->next;
-		}
-	}
-
-	if (j > 512) {
-overflow:
-		j = 512;
-		buf[2] |= 0x02; /* set the truncated bit. */
-	}
-
-	req->response_len = (size_t)j;
-
-	if (!(req->response = mm_malloc(req->response_len))) {
-		server_request_free_answers(req);
-		dnslabel_clear(&table);
-		return (-1);
-	}
-	memcpy(req->response, buf, req->response_len);
-	server_request_free_answers(req);
-	dnslabel_clear(&table);
-	return (0);
-}
-
-/* exported function */
-int
-evdns_server_request_respond(struct evdns_server_request *_req, int err)
-{
-	struct server_request *req = TO_SERVER_REQUEST(_req);
-	struct evdns_server_port *port = req->port;
-	ssize_t r;
-	if (!req->response) {
-		if ((r = evdns_server_request_format_response(req, err))<0)
-			return (int)r;
-	}
-
-	r = sendto(port->socket, req->response, req->response_len, 0,
-			   (struct sockaddr*) &req->addr, req->addrlen);
-	if (r<0) {
-		int error = last_error(port->socket);
-		if (! error_is_eagain(error))
-			return -1;
-
-		if (port->pending_replies) {
-			req->prev_pending = port->pending_replies->prev_pending;
-			req->next_pending = port->pending_replies;
-			req->prev_pending->next_pending =
-				req->next_pending->prev_pending = req;
-		} else {
-			req->prev_pending = req->next_pending = req;
-			port->pending_replies = req;
-			port->choked = 1;
-
-			(void) event_del(&port->event);
-			CLEAR(&port->event);
-			event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
-
-			if (event_add(&port->event, NULL) < 0) {
-				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
-			}
-
-		}
-
-		return 1;
-	}
-	if (server_request_free(req))
-		return 0;
-
-	if (port->pending_replies)
-		server_port_flush(port);
-
-	return 0;
-}
-
-/* Free all storage held by RRs in req. */
-static void
-server_request_free_answers(struct server_request *req)
-{
-	struct server_reply_item *victim, *next, **list;
-	int i;
-	for (i = 0; i < 3; ++i) {
-		if (i==0)
-			list = &req->answer;
-		else if (i==1)
-			list = &req->authority;
-		else
-			list = &req->additional;
-
-		victim = *list;
-		while (victim) {
-			next = victim->next;
-			mm_free(victim->name);
-			if (victim->data)
-				mm_free(victim->data);
-			mm_free(victim);
-			victim = next;
-		}
-		*list = NULL;
-	}
-}
-
-/* Free all storage held by req, and remove links to it. */
-/* return true iff we just wound up freeing the server_port. */
-static int
-server_request_free(struct server_request *req)
-{
-	int i, rc=1;
-	if (req->base.questions) {
-		for (i = 0; i < req->base.nquestions; ++i)
-			mm_free(req->base.questions[i]);
-		mm_free(req->base.questions);
-	}
-
-	if (req->port) {
-		if (req->port->pending_replies == req) {
-			if (req->next_pending && req->next_pending != req)
-				req->port->pending_replies = req->next_pending;
-			else
-				req->port->pending_replies = NULL;
-		}
-		rc = --req->port->refcnt;
-	}
-
-	if (req->response) {
-		mm_free(req->response);
-	}
-
-	server_request_free_answers(req);
-
-	if (req->next_pending && req->next_pending != req) {
-		req->next_pending->prev_pending = req->prev_pending;
-		req->prev_pending->next_pending = req->next_pending;
-	}
-
-	if (rc == 0) {
-		server_port_free(req->port);
-		CLEAR(req);
-		mm_free(req);
-		return (1);
-	}
-	CLEAR(req);
-	mm_free(req);
-	return (0);
-}
-
-/* Free all storage held by an evdns_server_port.  Only called when the
- * reference count is down to 0. */
-static void
-server_port_free(struct evdns_server_port *port)
-{
-	assert(port);
-	assert(!port->refcnt);
-	assert(!port->pending_replies);
-	if (port->socket > 0) {
-		CLOSE_SOCKET(port->socket);
-		port->socket = -1;
-	}
-	(void) event_del(&port->event);
-	CLEAR(&port->event);
-	CLEAR(port);
-	mm_free(port);
-}
-
-/* exported function */
-int
-evdns_server_request_drop(struct evdns_server_request *_req)
-{
-	struct server_request *req = TO_SERVER_REQUEST(_req);
-	server_request_free(req);
-	return 0;
-}
-
-/* exported function */
-int
-evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
-{
-	struct server_request *req = TO_SERVER_REQUEST(_req);
-	if (addr_len < (int)req->addrlen)
-		return -1;
-	memcpy(sa, &(req->addr), req->addrlen);
-	return req->addrlen;
-}
-
-#undef APPEND16
-#undef APPEND32
-
-/* this is a libevent callback function which is called when a request */
-/* has timed out. */
-static void
-evdns_request_timeout_callback(int fd, short events, void *arg) {
-	struct evdns_request *const req = (struct evdns_request *) arg;
-	(void) fd;
-	(void) events;
-
-	log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
-
-	req->ns->timedout++;
-	if (req->ns->timedout > global_max_nameserver_timeout) {
-		req->ns->timedout = 0;
-		nameserver_failed(req->ns, "request timed out.");
-	}
-
-	if (req->tx_count >= global_max_retransmits) {
-		/* this request has failed */
-		reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
-		request_finished(req, &req_head);
-	} else {
-		/* retransmit it */
-		/* Stop waiting for the timeout.  No need to do this in
-		 * request_finished; that one already deletes the timeout event.
-		 * XXXX023 port this change to libevent. */
-		del_timeout_event(req);
-		evdns_request_transmit(req);
-	}
-}
-
-/* try to send a request to a given server. */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 temporary failure */
-/* 2 other failure */
-static int
-evdns_request_transmit_to(struct evdns_request *req, struct nameserver *server) {
-	const ssize_t r = send(server->socket, (void*)req->request,
-                         req->request_len, 0);
-	if (r < 0) {
-		int err = last_error(server->socket);
-		if (error_is_eagain(err)) return 1;
-		nameserver_failed(req->ns, tor_socket_strerror(err));
-		return 2;
-	} else if (r != (ssize_t)req->request_len) {
-		return 1;  /* short write */
-	} else {
-		return 0;
-	}
-}
-
-/* try to send a request, updating the fields of the request */
-/* as needed */
-/* */
-/* return: */
-/* 0 ok */
-/* 1 failed */
-static int
-evdns_request_transmit(struct evdns_request *req) {
-	int retcode = 0, r;
-
-	/* if we fail to send this packet then this flag marks it */
-	/* for evdns_transmit */
-	req->transmit_me = 1;
-	if (req->trans_id == 0xffff) abort();
-
-	if (req->ns->choked) {
-		/* don't bother trying to write to a socket */
-		/* which we have had EAGAIN from */
-		return 1;
-	}
-
-	r = evdns_request_transmit_to(req, req->ns);
-	switch (r) {
-	case 1:
-		/* temp failure */
-		req->ns->choked = 1;
-		nameserver_write_waiting(req->ns, 1);
-		return 1;
-	case 2:
-		/* failed to transmit the request entirely. */
-		retcode = 1;
-		/* fall through: we'll set a timeout, which will time out,
-		 * and make us retransmit the request anyway. */
-	default:
-		/* transmitted; we need to check for timeout. */
-		log(EVDNS_LOG_DEBUG,
-			"Setting timeout for request %lx", (unsigned long) req);
-
-		if (add_timeout_event(req, &global_timeout) < 0) {
-			log(EVDNS_LOG_WARN,
-				"Error from libevent when adding timer for request %lx",
-				(unsigned long) req);
-			/* ???? Do more? */
-		}
-		req->tx_count++;
-		req->transmit_me = 0;
-		return retcode;
-	}
-}
-
-static void
-nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
-	struct sockaddr *addr = arg;
-	struct nameserver *server;
-	(void) type;
-	(void) count;
-	(void) ttl;
-	(void) addresses;
-
-	for (server = server_head; server; server = server->next) {
-		if (sockaddr_eq(addr, (struct sockaddr*) &server->address, 1)) {
-			if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
-				/* this is a good reply */
-				nameserver_up(server);
-			} else {
-				nameserver_probe_failed(server);
-			}
-		}
-		if (server->next == server_head)
-			break;
-	}
-
-	mm_free(addr);
-}
-
-static void
-nameserver_send_probe(struct nameserver *const ns) {
-	struct evdns_request *req;
-	struct sockaddr_storage *addr;
-	/* here we need to send a probe to a given nameserver */
-	/* in the hope that it is up now. */
-
-	/* We identify the nameserver by its address, in case it is removed before
-	 * our probe comes back. */
-	addr = mm_malloc(sizeof(struct sockaddr_storage));
-	memcpy(addr, &ns->address, sizeof(struct sockaddr_storage));
-
-	log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntop((struct sockaddr *)&ns->address));
-
-	req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, addr);
-	if (!req) {
-		mm_free(addr);
-		return;
-	}
-	/* we force this into the inflight queue no matter what */
-	request_trans_id_set(req, transaction_id_pick());
-	req->ns = ns;
-	request_submit(req);
-}
-
-/* returns: */
-/* 0 didn't try to transmit anything */
-/* 1 tried to transmit something */
-static int
-evdns_transmit(void) {
-	char did_try_to_transmit = 0;
-
-	if (req_head) {
-		struct evdns_request *const started_at = req_head, *req = req_head;
-		/* first transmit all the requests which are currently waiting */
-		do {
-			if (req->transmit_me) {
-				did_try_to_transmit = 1;
-				evdns_request_transmit(req);
-			}
-
-			req = req->next;
-		} while (req != started_at);
-	}
-
-	return did_try_to_transmit;
-}
-
-/* exported function */
-int
-evdns_count_nameservers(void)
-{
-	const struct nameserver *server = server_head;
-	int n = 0;
-	if (!server)
-		return 0;
-	do {
-		++n;
-		server = server->next;
-	} while (server != server_head);
-	return n;
-}
-
-/* exported function */
-int
-evdns_clear_nameservers_and_suspend(void)
-{
-	struct nameserver *server = server_head, *started_at = server_head;
-	struct evdns_request *req = req_head, *req_started_at = req_head;
-
-	if (!server)
-		return 0;
-	while (1) {
-		struct nameserver *next = server->next;
-		(void) event_del(&server->event);
-		CLEAR(&server->event);
-		del_timeout_event(server);
-		if (server->socket >= 0)
-			CLOSE_SOCKET(server->socket);
-		CLEAR(server);
-		mm_free(server);
-		if (next == started_at)
-			break;
-		server = next;
-	}
-	server_head = NULL;
-	global_good_nameservers = 0;
-
-	while (req) {
-		struct evdns_request *next = req->next;
-		req->tx_count = req->reissue_count = 0;
-		req->ns = NULL;
-		/* ???? What to do about searches? */
-		del_timeout_event(req);
-		req->trans_id = 0;
-		req->transmit_me = 0;
-
-		global_requests_waiting++;
-		evdns_request_insert(req, &req_waiting_head);
-		/* We want to insert these suspended elements at the front of
-		 * the waiting queue, since they were pending before any of
-		 * the waiting entries were added.	This is a circular list,
-		 * so we can just shift the start back by one.*/
-		req_waiting_head = req_waiting_head->prev;
-
-		if (next == req_started_at)
-			break;
-		req = next;
-	}
-	req_head = NULL;
-	global_requests_inflight = 0;
-
-	return 0;
-}
-
-static struct sockaddr_storage global_bind_address;
-static socklen_t global_bind_addrlen = 0;
-static int global_bind_addr_is_set = 0;
-void
-evdns_set_default_outgoing_bind_address(const struct sockaddr *addr,
-										socklen_t addrlen)
-{
-	memset(&global_bind_address, 0, sizeof(global_bind_address));
-	if (addr) {
-		assert(addrlen <= (socklen_t)sizeof(global_bind_address));
-		memcpy(&global_bind_address, addr, addrlen);
-		global_bind_addrlen = addrlen;
-		global_bind_addr_is_set = 1;
-	} else {
-		global_bind_addr_is_set = 0;
-	}
-}
-
-/* exported function */
-int
-evdns_resume(void)
-{
-	evdns_requests_pump_waiting_queue();
-	return 0;
-}
-
-static int
-sockaddr_is_loopback(const struct sockaddr *addr)
-{
-	static const char LOOPBACK_S6[16] =
-	    "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1";
-	if (addr->sa_family == AF_INET) {
-		struct sockaddr_in *sin = (struct sockaddr_in *)addr;
-		return (ntohl(sin->sin_addr.s_addr) & 0xff000000) == 0x7f000000;
-	} else if (addr->sa_family == AF_INET6) {
-		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
-		return fast_memeq(sin6->sin6_addr.s6_addr, LOOPBACK_S6, 16);
-	}
-	return 0;
-}
-
-static int
-_evdns_nameserver_add_impl(const struct sockaddr *address,
-						   socklen_t addrlen) {
-	/* first check to see if we already have this nameserver */
-
-	const struct nameserver *server = server_head, *const started_at = server_head;
-	struct nameserver *ns;
-
-	int err = 0;
-	if (server) {
-		do {
-			if (sockaddr_eq(address, (struct sockaddr *)&server->address, 1)) {
-				log(EVDNS_LOG_DEBUG, "Duplicate nameserver.");
-				return 3;
-			}
-			server = server->next;
-		} while (server != started_at);
-	}
-	if (addrlen > (int)sizeof(ns->address)) {
-		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
-		return 2;
-	}
-
-	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
-	if (!ns) return -1;
-
-	memset(ns, 0, sizeof(struct nameserver));
-
-	evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
-
-	ns->socket = tor_open_socket(address->sa_family, SOCK_DGRAM, 0);
-	if (ns->socket < 0) { err = 1; goto out1; }
-#ifdef _WIN32
-	{
-		u_long nonblocking = 1;
-		ioctlsocket(ns->socket, FIONBIO, &nonblocking);
-	}
-#else
-	fcntl(ns->socket, F_SETFL, O_NONBLOCK);
-#endif
-
-	if (global_bind_addr_is_set &&
-	    !sockaddr_is_loopback((struct sockaddr*)&global_bind_address)) {
-		if (bind(ns->socket, (struct sockaddr *)&global_bind_address,
-				 global_bind_addrlen) < 0) {
-			log(EVDNS_LOG_DEBUG, "Couldn't bind to outgoing address.");
-			err = 2;
-			goto out2;
-		}
-	}
-
-	if (connect(ns->socket, address, addrlen) != 0) {
-		log(EVDNS_LOG_DEBUG, "Couldn't open socket to nameserver.");
-		err = 2;
-		goto out2;
-	}
-
-	memcpy(&ns->address, address, addrlen);
-	ns->state = 1;
-	event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
-	if (event_add(&ns->event, NULL) < 0) {
-		log(EVDNS_LOG_DEBUG, "Couldn't add event for nameserver.");
-		err = 2;
-		goto out2;
-	}
-
-	log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntop(address));
-
-	/* insert this nameserver into the list of them */
-	if (!server_head) {
-		ns->next = ns->prev = ns;
-		server_head = ns;
-	} else {
-		ns->next = server_head->next;
-		ns->prev = server_head;
-		server_head->next = ns;
-		if (server_head->prev == server_head) {
-			server_head->prev = ns;
-		}
-	}
-
-	global_good_nameservers++;
-
-	return 0;
-
-out2:
-	CLOSE_SOCKET(ns->socket);
-out1:
-	CLEAR(ns);
-	mm_free(ns);
-	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntop(address), err);
-	return err;
-}
-
-/* exported function */
-int
-evdns_nameserver_add(uint32_t address) {
-	struct sockaddr_in sin;
-	memset(&sin, 0, sizeof(sin));
-	sin.sin_family = AF_INET;
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
-	sin.sin_len = sizeof(sin);
-#endif
-	sin.sin_addr.s_addr = htonl(address);
-	sin.sin_port = 53;
-	return _evdns_nameserver_add_impl((struct sockaddr*) &sin, sizeof(sin));
-}
-
-/* exported function */
-int
-evdns_nameserver_ip_add(const char *ip_as_string) {
-	int port;
-	char buf[128];
-	const char *cp, *addr_part, *port_part;
-	int is_ipv6;
-	/* recognized formats are:
-	 * [ipv6]:port
-	 * ipv6
-	 * [ipv6]
-	 * ipv4:port
-	 * ipv4
-	 */
-
-	log(EVDNS_LOG_DEBUG, "Trying to add nameserver <%s>", ip_as_string);
-
-	cp = strchr(ip_as_string, ':');
-	if (*ip_as_string == '[') {
-		size_t len;
-		if (!(cp = strchr(ip_as_string, ']'))) {
-			log(EVDNS_LOG_DEBUG, "Nameserver missing closing ]");
-			return 4;
-		}
-		len = cp-(ip_as_string + 1);
-		if (len > sizeof(buf)-1) {
-			log(EVDNS_LOG_DEBUG, "[Nameserver] does not fit in buffer.");
-			return 4;
-		}
-		memcpy(buf, ip_as_string+1, len);
-		buf[len] = '\0';
-		addr_part = buf;
-		if (cp[1] == ':')
-			port_part = cp+2;
-		else
-			port_part = NULL;
-		is_ipv6 = 1;
-	} else if (cp && strchr(cp+1, ':')) {
-		is_ipv6 = 1;
-		addr_part = ip_as_string;
-		port_part = NULL;
-	} else if (cp) {
-		is_ipv6 = 0;
-		if (cp - ip_as_string > (int)sizeof(buf)-1) {
-			log(EVDNS_LOG_DEBUG, "Nameserver does not fit in buffer.");
-			return 4;
-		}
-		memcpy(buf, ip_as_string, cp-ip_as_string);
-		buf[cp-ip_as_string] = '\0';
-		addr_part = buf;
-		port_part = cp+1;
-	} else {
-		addr_part = ip_as_string;
-		port_part = NULL;
-		is_ipv6 = 0;
-	}
-
-	if (port_part == NULL) {
-		port = 53;
-	} else {
-		port = strtoint(port_part);
-		if (port <= 0 || port > 65535) {
-			log(EVDNS_LOG_DEBUG, "Nameserver port <%s> out of range",
-				port_part);
-			return 4;
-		}
-	}
-
-	/* Tor-only.  needs a more general fix. */
-	assert(addr_part);
-	if (is_ipv6) {
-		struct sockaddr_in6 sin6;
-		memset(&sin6, 0, sizeof(sin6));
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
-		sin6.sin6_len = sizeof(sin6);
-#endif
-		sin6.sin6_family = AF_INET6;
-		sin6.sin6_port = htons(port);
-		if (1 != tor_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr)) {
-			log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
-			return 4;
-		}
-		return _evdns_nameserver_add_impl((struct sockaddr*)&sin6,
-										  sizeof(sin6));
-	} else {
-		struct sockaddr_in sin;
-		memset(&sin, 0, sizeof(sin));
-#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
-		sin.sin_len = sizeof(sin);
-#endif
-		sin.sin_family = AF_INET;
-		sin.sin_port = htons(port);
-		if (!inet_aton(addr_part, &sin.sin_addr)) {
-			log(EVDNS_LOG_DEBUG, "inet_pton(%s) failed", addr_part);
-			return 4;
-		}
-		return _evdns_nameserver_add_impl((struct sockaddr*)&sin,
-										  sizeof(sin));
-	}
-}
-
-int
-evdns_nameserver_sockaddr_add(const struct sockaddr *sa, socklen_t len)
-{
-	return _evdns_nameserver_add_impl(sa, len);
-}
-
-/* insert into the tail of the queue */
-static void
-evdns_request_insert(struct evdns_request *req, struct evdns_request **head) {
-	if (!*head) {
-		*head = req;
-		req->next = req->prev = req;
-		return;
-	}
-
-	req->prev = (*head)->prev;
-	req->prev->next = req;
-	req->next = *head;
-	(*head)->prev = req;
-}
-
-static int
-string_num_dots(const char *s) {
-	int count = 0;
-	while ((s = strchr(s, '.'))) {
-		s++;
-		count++;
-	}
-	return count;
-}
-
-static struct evdns_request *
-request_new(int type, const char *name, int flags,
-	evdns_callback_type callback, void *user_ptr) {
-	const char issuing_now =
-		(global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
-
-	const size_t name_len = strlen(name);
-	const size_t request_max_len = evdns_request_len(name_len);
-	const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
-	/* the request data is alloced in a single block with the header */
-	struct evdns_request *const req =
-		(struct evdns_request *) mm_malloc(sizeof(struct evdns_request) + request_max_len);
-	char namebuf[256];
-	int rlen;
-	(void) flags;
-
-	if (!req) return NULL;
-
-	if (name_len >= sizeof(namebuf)) {
-		_mm_free(req);
-		return NULL;
-	}
-
-	memset(req, 0, sizeof(struct evdns_request));
-
-	evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
-
-	if (global_randomize_case) {
-		unsigned i;
-		char randbits[32];
-		strlcpy(namebuf, name, sizeof(namebuf));
-		rand_bytes_function(randbits, (name_len+7)/8);
-		for (i = 0; i < name_len; ++i) {
-			if (ISALPHA(namebuf[i])) {
-				if ((randbits[i >> 3] & (1<<(i%7))))
-					namebuf[i] = TOLOWER(namebuf[i]);
-				else
-					namebuf[i] = TOUPPER(namebuf[i]);
-			}
-		}
-		name = namebuf;
-	}
-
-	/* request data lives just after the header */
-	req->request = ((u8 *) req) + sizeof(struct evdns_request);
-	/* denotes that the request data shouldn't be mm_free()ed */
-	req->request_appended = 1;
-	rlen = evdns_request_data_build(name, name_len, trans_id,
-							type, CLASS_INET, req->request, request_max_len);
-	if (rlen < 0)
-		goto err1;
-	req->request_len = rlen;
-	req->trans_id = trans_id;
-	req->tx_count = 0;
-	req->request_type = type;
-	req->user_pointer = user_ptr;
-	req->user_callback = callback;
-	req->ns = issuing_now ? nameserver_pick() : NULL;
-	req->next = req->prev = NULL;
-
-	return req;
-err1:
-	CLEAR(req);
-	_mm_free(req);
-	return NULL;
-}
-
-static void
-request_submit(struct evdns_request *const req) {
-	if (req->ns) {
-		/* if it has a nameserver assigned then this is going */
-		/* straight into the inflight queue */
-		evdns_request_insert(req, &req_head);
-		global_requests_inflight++;
-		evdns_request_transmit(req);
-	} else {
-		evdns_request_insert(req, &req_waiting_head);
-		global_requests_waiting++;
-	}
-}
-
-/* exported function */
-int evdns_resolve_ipv4(const char *name, int flags,
-					   evdns_callback_type callback, void *ptr) {
-	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
-	if (flags & DNS_QUERY_NO_SEARCH) {
-		struct evdns_request *const req =
-			request_new(TYPE_A, name, flags, callback, ptr);
-		if (req == NULL)
-			return (1);
-		request_submit(req);
-		return (0);
-	} else {
-		return (search_request_new(TYPE_A, name, flags, callback, ptr));
-	}
-}
-
-/* exported function */
-int evdns_resolve_ipv6(const char *name, int flags,
-					   evdns_callback_type callback, void *ptr) {
-	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
-	if (flags & DNS_QUERY_NO_SEARCH) {
-		struct evdns_request *const req =
-			request_new(TYPE_AAAA, name, flags, callback, ptr);
-		if (req == NULL)
-			return (1);
-		request_submit(req);
-		return (0);
-	} else {
-		return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
-	}
-}
-
-int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
-	char buf[32];
-	struct evdns_request *req;
-	u32 a;
-	assert(in);
-	a = ntohl(in->s_addr);
-	snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
-			(int)(u8)((a	)&0xff),
-			(int)(u8)((a>>8 )&0xff),
-			(int)(u8)((a>>16)&0xff),
-			(int)(u8)((a>>24)&0xff));
-	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
-	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
-	if (!req) return 1;
-	request_submit(req);
-	return 0;
-}
-
-int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
-	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
-	char buf[73];
-	char *cp;
-	struct evdns_request *req;
-	int i;
-	assert(in);
-	cp = buf;
-	for (i=15; i >= 0; --i) {
-		u8 byte = in->s6_addr[i];
-		*cp++ = "0123456789abcdef"[byte & 0x0f];
-		*cp++ = '.';
-		*cp++ = "0123456789abcdef"[byte >> 4];
-		*cp++ = '.';
-	}
-	assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
-	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
-	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
-	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
-	if (!req) return 1;
-	request_submit(req);
-	return 0;
-}
-
-/*/////////////////////////////////////////////////////////////////// */
-/* Search support */
-/* */
-/* the libc resolver has support for searching a number of domains */
-/* to find a name. If nothing else then it takes the single domain */
-/* from the gethostname() call. */
-/* */
-/* It can also be configured via the domain and search options in a */
-/* resolv.conf. */
-/* */
-/* The ndots option controls how many dots it takes for the resolver */
-/* to decide that a name is non-local and so try a raw lookup first. */
-
-struct search_domain {
-	size_t len;
-	struct search_domain *next;
-	/* the text string is appended to this structure */
-};
-
-struct search_state {
-	int refcount;
-	int ndots;
-	int num_domains;
-	struct search_domain *head;
-};
-
-static struct search_state *global_search_state = NULL;
-
-static void
-search_state_decref(struct search_state *const state) {
-	if (!state) return;
-	state->refcount--;
-	if (!state->refcount) {
-		struct search_domain *next, *dom;
-		for (dom = state->head; dom; dom = next) {
-			next = dom->next;
-			CLEAR(dom);
-			_mm_free(dom);
-		}
-		CLEAR(state);
-		_mm_free(state);
-	}
-}
-
-static struct search_state *
-search_state_new(void) {
-	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
-	if (!state) return NULL;
-	memset(state, 0, sizeof(struct search_state));
-	state->refcount = 1;
-	state->ndots = 1;
-
-	return state;
-}
-
-static void
-search_postfix_clear(void) {
-	search_state_decref(global_search_state);
-
-	global_search_state = search_state_new();
-}
-
-/* exported function */
-void
-evdns_search_clear(void) {
-	search_postfix_clear();
-}
-
-static void
-search_postfix_add(const char *domain) {
-	size_t domain_len;
-	struct search_domain *sdomain;
-	while (domain[0] == '.') domain++;
-	domain_len = strlen(domain);
-
-	if (!global_search_state) global_search_state = search_state_new();
-		if (!global_search_state) return;
-	global_search_state->num_domains++;
-
-	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
-		if (!sdomain) return;
-	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
-	sdomain->next = global_search_state->head;
-	sdomain->len = domain_len;
-
-	global_search_state->head = sdomain;
-}
-
-/* reverse the order of members in the postfix list. This is needed because, */
-/* when parsing resolv.conf we push elements in the wrong order */
-static void
-search_reverse(void) {
-	struct search_domain *cur, *prev = NULL, *next;
-	cur = global_search_state->head;
-	while (cur) {
-		next = cur->next;
-		cur->next = prev;
-		prev = cur;
-		cur = next;
-	}
-
-	global_search_state->head = prev;
-}
-
-/* exported function */
-void
-evdns_search_add(const char *domain) {
-	search_postfix_add(domain);
-}
-
-/* exported function */
-void
-evdns_search_ndots_set(const int ndots) {
-	if (!global_search_state) global_search_state = search_state_new();
-		if (!global_search_state) return;
-	global_search_state->ndots = ndots;
-}
-
-static void
-search_set_from_hostname(void) {
-	char hostname[HOST_NAME_MAX + 1], *domainname;
-
-	search_postfix_clear();
-	if (gethostname(hostname, sizeof(hostname))) return;
-	domainname = strchr(hostname, '.');
-	if (!domainname) return;
-	search_postfix_add(domainname);
-}
-
-/* warning: returns malloced string */
-static char *
-search_make_new(const struct search_state *const state, int n, const char *const base_name) {
-	const size_t base_len = strlen(base_name);
-	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
-	struct search_domain *dom;
-
-	for (dom = state->head; dom; dom = dom->next) {
-		if (!n--) {
-			/* this is the postfix we want */
-			/* the actual postfix string is kept at the end of the structure */
-			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
-			const size_t postfix_len = dom->len;
-			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
-			if (!newname) return NULL;
-			memcpy(newname, base_name, base_len);
-			if (need_to_append_dot) newname[base_len] = '.';
-			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
-			newname[base_len + need_to_append_dot + postfix_len] = 0;
-			return newname;
-		}
-	}
-
-	/* we ran off the end of the list and still didn't find the requested string */
-	abort();
-	return NULL; /* unreachable; stops warnings in some compilers. */
-}
-
-static int
-search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
-	assert(type == TYPE_A || type == TYPE_AAAA);
-	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
-		 global_search_state &&
-		 global_search_state->num_domains) {
-		/* we have some domains to search */
-		struct evdns_request *req;
-		if (string_num_dots(name) >= global_search_state->ndots) {
-			req = request_new(type, name, flags, user_callback, user_arg);
-			if (!req) return 1;
-			req->search_index = -1;
-		} else {
-			char *const new_name = search_make_new(global_search_state, 0, name);
-						if (!new_name) return 1;
-			req = request_new(type, new_name, flags, user_callback, user_arg);
-			_mm_free(new_name);
-			if (!req) return 1;
-			req->search_index = 0;
-		}
-		req->search_origname = mm_strdup(name);
-		req->search_state = global_search_state;
-		req->search_flags = flags;
-		global_search_state->refcount++;
-		request_submit(req);
-		return 0;
-	} else {
-		struct evdns_request *const req = request_new(type, name, flags, user_callback, user_arg);
-		if (!req) return 1;
-		request_submit(req);
-		return 0;
-	}
-}
-
-/* this is called when a request has failed to find a name. We need to check */
-/* if it is part of a search and, if so, try the next name in the list */
-/* returns: */
-/* 0 another request has been submitted */
-/* 1 no more requests needed */
-static int
-search_try_next(struct evdns_request *const req) {
-	if (req->search_state) {
-		/* it is part of a search */
-		char *new_name;
-		struct evdns_request *newreq;
-		req->search_index++;
-		if (req->search_index >= req->search_state->num_domains) {
-			/* no more postfixes to try, however we may need to try */
-			/* this name without a postfix */
-			if (string_num_dots(req->search_origname) < req->search_state->ndots) {
-				/* yep, we need to try it raw */
-				struct evdns_request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
-				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
-				if (newreq) {
-					request_submit(newreq);
-					return 0;
-				}
-			}
-			return 1;
-		}
-
-		new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
-				if (!new_name) return 1;
-		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
-		newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
-		mm_free(new_name);
-		if (!newreq) return 1;
-		newreq->search_origname = req->search_origname;
-		req->search_origname = NULL;
-		newreq->search_state = req->search_state;
-		newreq->search_flags = req->search_flags;
-		newreq->search_index = req->search_index;
-		newreq->search_state->refcount++;
-		request_submit(newreq);
-		return 0;
-	}
-	return 1;
-}
-
-static void
-search_request_finished(struct evdns_request *const req) {
-	if (req->search_state) {
-		search_state_decref(req->search_state);
-		req->search_state = NULL;
-	}
-	if (req->search_origname) {
-		mm_free(req->search_origname);
-		req->search_origname = NULL;
-	}
-}
-
-/*/////////////////////////////////////////////////////////////////// */
-/* Parsing resolv.conf files */
-
-static void
-evdns_resolv_set_defaults(int flags) {
-	/* if the file isn't found then we assume a local resolver */
-	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
-	if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
-}
-
-/* helper version of atoi which returns -1 on error */
-static int
-strtoint(const char *const str) {
-	char *endptr;
-	const long r = strtol(str, &endptr, 10);
-	if (*endptr || r > INT_MAX) return -1;
-	return (int)r;
-}
-
-/* helper version of atoi that returns -1 on error and clips to bounds. */
-static int
-strtoint_clipped(const char *const str, int min, int max)
-{
-	int r = strtoint(str);
-	if (r == -1)
-		return r;
-	else if (r<min)
-		return min;
-	else if (r>max)
-		return max;
-	else
-		return r;
-}
-
-/* exported function */
-int
-evdns_set_option(const char *option, const char *val, int flags)
-{
-	if (!strncmp(option, "ndots:", 6)) {
-		const int ndots = strtoint(val);
-		if (ndots == -1) return -1;
-		if (!(flags & DNS_OPTION_SEARCH)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
-		if (!global_search_state) global_search_state = search_state_new();
-		if (!global_search_state) return -1;
-		global_search_state->ndots = ndots;
-	} else if (!strncmp(option, "timeout:", 8)) {
-		const int timeout = strtoint(val);
-		if (timeout == -1) return -1;
-		if (!(flags & DNS_OPTION_MISC)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
-		global_timeout.tv_sec = timeout;
-	} else if (!strncmp(option, "max-timeouts:", 12)) {
-		const int maxtimeout = strtoint_clipped(val, 1, 255);
-		if (maxtimeout == -1) return -1;
-		if (!(flags & DNS_OPTION_MISC)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
-			maxtimeout);
-		global_max_nameserver_timeout = maxtimeout;
-	} else if (!strncmp(option, "max-inflight:", 13)) {
-		const int maxinflight = strtoint_clipped(val, 1, 65000);
-		if (maxinflight == -1) return -1;
-		if (!(flags & DNS_OPTION_MISC)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
-			maxinflight);
-		global_max_requests_inflight = maxinflight;
-	} else if (!strncmp(option, "attempts:", 9)) {
-		int retries = strtoint(val);
-		if (retries == -1) return -1;
-		if (retries > 255) retries = 255;
-		if (!(flags & DNS_OPTION_MISC)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
-		global_max_retransmits = retries;
-	} else if (!strncmp(option, "randomize-case:", 15)) {
-		int randcase = strtoint(val);
-		if (!(flags & DNS_OPTION_MISC)) return 0;
-		log(EVDNS_LOG_DEBUG, "Setting randomize_case to %d", randcase);
-		global_randomize_case = randcase;
-	}
-	return 0;
-}
-
-static void
-resolv_conf_parse_line(char *const start, int flags) {
-	char *strtok_state;
-	static const char *const delims = " \t";
-#define NEXT_TOKEN tor_strtok_r(NULL, delims, &strtok_state)
-
-	char *const first_token = tor_strtok_r(start, delims, &strtok_state);
-	if (!first_token) return;
-
-	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
-		const char *const nameserver = NEXT_TOKEN;
-		evdns_nameserver_ip_add(nameserver);
-	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
-		const char *const domain = NEXT_TOKEN;
-		if (domain) {
-			search_postfix_clear();
-			search_postfix_add(domain);
-		}
-	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
-		const char *domain;
-		search_postfix_clear();
-
-		while ((domain = NEXT_TOKEN)) {
-			search_postfix_add(domain);
-		}
-		search_reverse();
-	} else if (!strcmp(first_token, "options")) {
-		const char *option;
-		while ((option = NEXT_TOKEN)) {
-			const char *val = strchr(option, ':');
-			evdns_set_option(option, val ? val+1 : "", flags);
-		}
-	}
-#undef NEXT_TOKEN
-}
-
-/* exported function */
-/* returns: */
-/* 0 no errors */
-/* 1 failed to open file */
-/* 2 failed to stat file */
-/* 3 file too large */
-/* 4 out of memory */
-/* 5 short read from file */
-int
-evdns_resolv_conf_parse(int flags, const char *const filename) {
-	struct stat st;
-	int fd, n, r;
-	u8 *resolv;
-	char *start;
-	int err = 0;
-
-	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
-
-	fd = tor_open_cloexec(filename, O_RDONLY, 0);
-	if (fd < 0) {
-		evdns_resolv_set_defaults(flags);
-		return 1;
-	}
-
-	if (fstat(fd, &st)) { err = 2; goto out1; }
-	if (!st.st_size) {
-		evdns_resolv_set_defaults(flags);
-		err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
-		goto out1;
-	}
-	if (st.st_size > 65535) { err = 3; goto out1; }	 /* no resolv.conf should be any bigger */
-
-	resolv = (u8 *) mm_malloc((size_t)st.st_size + 1);
-	if (!resolv) { err = 4; goto out1; }
-
-    n = 0;
-	while ((r = (int)read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
-		n += r;
-		if (n == st.st_size)
-			break;
-		assert(n < st.st_size);
-	}
-	if (r < 0) { err = 5; goto out2; }
-	resolv[n] = 0;	 /* we malloced an extra byte; this should be fine. */
-
-	start = (char *) resolv;
-	for (;;) {
-		char *const newline = strchr(start, '\n');
-		if (!newline) {
-			resolv_conf_parse_line(start, flags);
-			break;
-		} else {
-			*newline = 0;
-			resolv_conf_parse_line(start, flags);
-			start = newline + 1;
-		}
-	}
-
-	if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
-		/* no nameservers were configured. */
-		evdns_nameserver_ip_add("127.0.0.1");
-		err = 6;
-	}
-	if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
-		search_set_from_hostname();
-	}
-
-out2:
-	mm_free(resolv);
-out1:
-	close(fd);
-	return err;
-}
-
-#ifdef _WIN32
-/* Add multiple nameservers from a space-or-comma-separated list. */
-static int
-evdns_nameserver_ip_add_line(const char *ips) {
-	const char *addr;
-	char *buf;
-	int r;
-	while (*ips) {
-		while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
-			++ips;
-		addr = ips;
-		while (ISDIGIT(*ips) || *ips == '.' || *ips == ':' || *ips == '[' || *ips == ']')
-			++ips;
-		buf = mm_malloc(ips-addr+1);
-		if (!buf) return 4;
-		memcpy(buf, addr, ips-addr);
-		buf[ips-addr] = '\0';
-		r = evdns_nameserver_ip_add(buf);
-		mm_free(buf);
-		if (r) return r;
-	}
-	return 0;
-}
-
-typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
-
-/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
-/* figure out what our nameservers are. */
-static int
-load_nameservers_with_getnetworkparams(void)
-{
-	/* Based on MSDN examples and inspection of	 c-ares code. */
-	FIXED_INFO *fixed;
-	HMODULE handle = 0;
-	ULONG size = sizeof(FIXED_INFO);
-	void *buf = NULL;
-	int status = 0, r, added_any;
-	IP_ADDR_STRING *ns;
-	GetNetworkParams_fn_t fn;
-
-	if (!(handle = load_windows_system_library(TEXT("iphlpapi.dll")))) {
-		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
-		/* right now status = 0, doesn't that mean "good" - mikec */
-		status = -1;
-		goto done;
-	}
-	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, TEXT("GetNetworkParams")))) {
-		log(EVDNS_LOG_WARN, "Could not get address of function.");
-		/* same as above */
-		status = -1;
-		goto done;
-	}
-
-	buf = mm_malloc(size);
-	if (!buf) { status = 4; goto done; }
-	fixed = buf;
-	r = fn(fixed, &size);
-	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
-		status = -1;
-		goto done;
-	}
-	if (r != ERROR_SUCCESS) {
-		mm_free(buf);
-		buf = mm_malloc(size);
-		if (!buf) { status = 4; goto done; }
-		fixed = buf;
-		r = fn(fixed, &size);
-		if (r != ERROR_SUCCESS) {
-			log(EVDNS_LOG_DEBUG, "fn() failed.");
-			status = -1;
-			goto done;
-		}
-	}
-
-	assert(fixed);
-	added_any = 0;
-	ns = &(fixed->DnsServerList);
-	while (ns) {
-		r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
-		if (r) {
-			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list, "
-				"error: %d; status: %d",
-				(ns->IpAddress.String),(int)GetLastError(), r);
-			status = r;
-		} else {
-			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
-			added_any++;
-		}
-
-		ns = ns->Next;
-	}
-
-	if (!added_any) {
-		log(EVDNS_LOG_DEBUG, "No nameservers added.");
-		if (status == 0)
-			status = -1;
-	} else {
-		status = 0;
-	}
-
- done:
-	if (buf)
-		mm_free(buf);
-	if (handle)
-		FreeLibrary(handle);
-	return status;
-}
-
-static int
-config_nameserver_from_reg_key(HKEY key, const TCHAR *subkey)
-{
-	char *buf;
-	char ansibuf[MAX_PATH] = {0};
-	DWORD bufsz = 0, type = 0;
-	int status = 0;
-
-	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
-		!= ERROR_MORE_DATA)
-		return -1;
-	if (!(buf = mm_malloc(bufsz)))
-		return -1;
-
-	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
-		== ERROR_SUCCESS && bufsz > 1) {
-		wcstombs(ansibuf,(wchar_t*)buf,MAX_PATH);/*XXXX UNICODE */
-		abuf[MAX_PATH-1] = '\0';
-		status = evdns_nameserver_ip_add_line(ansibuf);
-	}
-
-	mm_free(buf);
-	return status;
-}
-
-#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
-#define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
-#define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
-
-static int
-load_nameservers_from_registry(void)
-{
-	int found = 0;
-	int r;
-	OSVERSIONINFO info;
-	memset(&info, 0, sizeof(info));
-	info.dwOSVersionInfoSize = sizeof (info);
-	GetVersionEx(&info);
-
-#define TRY(k, name)													\
-	if (!found && config_nameserver_from_reg_key(k,TEXT(name)) == 0) {	\
-		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name);		\
-		found = 1;														\
-	} else if (!found) {												\
-		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s",			\
-			#k,#name);													\
-	}
-
-	if (info.dwMajorVersion >= 5) { /* NT */
-		HKEY nt_key = 0, interfaces_key = 0;
-
-		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
-						 KEY_READ, &nt_key) != ERROR_SUCCESS) {
-			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
-			return -1;
-		}
-		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
-						 KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
-						 &interfaces_key);
-		if (r != ERROR_SUCCESS) {
-			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
-			return -1;
-		}
-		TRY(nt_key, "NameServer");
-		TRY(nt_key, "DhcpNameServer");
-		TRY(interfaces_key, "NameServer");
-		TRY(interfaces_key, "DhcpNameServer");
-		RegCloseKey(interfaces_key);
-		RegCloseKey(nt_key);
-	} else {
-		HKEY win_key = 0;
-		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
-						 KEY_READ, &win_key) != ERROR_SUCCESS) {
-			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
-			return -1;
-		}
-		TRY(win_key, "NameServer");
-		RegCloseKey(win_key);
-	}
-
-	if (found == 0) {
-		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
-	}
-
-	return found ? 0 : -1;
-#undef TRY
-}
-
-int
-evdns_config_windows_nameservers(void)
-{
-	if (load_nameservers_with_getnetworkparams() == 0)
-		return 0;
-	return load_nameservers_from_registry();
-}
-#endif
-
-int
-evdns_init(void)
-{
-		int res = 0;
-#ifdef _WIN32
-		evdns_config_windows_nameservers();
-#else
-		res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
-#endif
-
-		return (res);
-}
-
-const char *
-evdns_err_to_string(int err)
-{
-	switch (err) {
-	case DNS_ERR_NONE: return "no error";
-	case DNS_ERR_FORMAT: return "misformatted query";
-	case DNS_ERR_SERVERFAILED: return "server failed";
-	case DNS_ERR_NOTEXIST: return "name does not exist";
-	case DNS_ERR_NOTIMPL: return "query not implemented";
-	case DNS_ERR_REFUSED: return "refused";
-
-	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
-	case DNS_ERR_UNKNOWN: return "unknown";
-	case DNS_ERR_TIMEOUT: return "request timed out";
-	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
-	default: return "[Unknown error code]";
-	}
-}
-
-void
-evdns_shutdown(int fail_requests)
-{
-	struct nameserver *server, *server_next;
-	struct search_domain *dom, *dom_next;
-
-	while (req_head) {
-		if (fail_requests)
-			reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
-		request_finished(req_head, &req_head);
-	}
-	while (req_waiting_head) {
-		if (fail_requests)
-			reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
-		request_finished(req_waiting_head, &req_waiting_head);
-	}
-	global_requests_inflight = global_requests_waiting = 0;
-
-	for (server = server_head; server; server = server_next) {
-		server_next = server->next;
-		if (server->socket >= 0)
-			CLOSE_SOCKET(server->socket);
-		(void) event_del(&server->event);
-		del_timeout_event(server);
-		CLEAR(server);
-		mm_free(server);
-		if (server_next == server_head)
-			break;
-	}
-	server_head = NULL;
-	global_good_nameservers = 0;
-
-	if (global_search_state) {
-		for (dom = global_search_state->head; dom; dom = dom_next) {
-			dom_next = dom->next;
-			CLEAR(dom);
-			mm_free(dom);
-		}
-		CLEAR(global_search_state);
-		mm_free(global_search_state);
-		global_search_state = NULL;
-	}
-	evdns_log_fn = NULL;
-}
-
-#ifdef EVDNS_MAIN
-void
-main_callback(int result, char type, int count, int ttl,
-			  void *addrs, void *orig) {
-	char *n = (char*)orig;
-	int i;
-	for (i = 0; i < count; ++i) {
-		if (type == DNS_IPv4_A) {
-			printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
-		} else if (type == DNS_PTR) {
-			printf("%s: %s\n", n, ((char**)addrs)[i]);
-		}
-	}
-	if (!count) {
-		printf("%s: No answer (%d)\n", n, result);
-	}
-	fflush(stdout);
-}
-void
-evdns_server_callback(struct evdns_server_request *req, void *data)
-{
-	int i, r;
-	(void)data;
-	/* dummy; give 192.168.11.11 as an answer for all A questions,
-	 *	give foo.bar.example.com as an answer for all PTR questions. */
-	for (i = 0; i < req->nquestions; ++i) {
-		u32 ans = htonl(0xc0a80b0bUL);
-		if (req->questions[i]->type == EVDNS_TYPE_A &&
-			req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
-			printf(" -- replying for %s (A)\n", req->questions[i]->name);
-			r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
-										  1, &ans, 10);
-			if (r<0)
-				printf("eeep, didn't work.\n");
-		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
-				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
-			printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
-			r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
-											"foo.bar.example.com", 10);
-		} else {
-			printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
-				   req->questions[i]->type, req->questions[i]->dns_question_class);
-		}
-	}
-
-	r = evdns_server_request_respond(req, 0);
-	if (r<0)
-		printf("eeek, couldn't send reply.\n");
-}
-
-void
-logfn(int is_warn, const char *msg) {
-	(void) is_warn;
-	fprintf(stderr, "%s\n", msg);
-}
-int
-main(int c, char **v) {
-	int idx;
-	int reverse = 0, verbose = 1, servertest = 0;
-	if (c<2) {
-		fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
-		fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
-		return 1;
-	}
-	idx = 1;
-	while (idx < c && v[idx][0] == '-') {
-		if (!strcmp(v[idx], "-x"))
-			reverse = 1;
-		else if (!strcmp(v[idx], "-v"))
-			verbose = 1;
-		else if (!strcmp(v[idx], "-servertest"))
-			servertest = 1;
-		else
-			fprintf(stderr, "Unknown option %s\n", v[idx]);
-		++idx;
-	}
-	event_init();
-	if (verbose)
-		evdns_set_log_fn(logfn);
-	evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
-	if (servertest) {
-		int sock;
-		struct sockaddr_in my_addr;
-		sock = tor_open_socket(PF_INET, SOCK_DGRAM, 0);
-		fcntl(sock, F_SETFL, O_NONBLOCK);
-		my_addr.sin_family = AF_INET;
-		my_addr.sin_port = htons(10053);
-		my_addr.sin_addr.s_addr = INADDR_ANY;
-		if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
-			perror("bind");
-			exit(1);
-		}
-		evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
-	}
-	for (; idx < c; ++idx) {
-		if (reverse) {
-			struct in_addr addr;
-			if (!inet_aton(v[idx], &addr)) {
-				fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
-				continue;
-			}
-			fprintf(stderr, "resolving %s...\n",v[idx]);
-			evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
-		} else {
-			fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
-			evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
-		}
-	}
-	fflush(stdout);
-	event_dispatch();
-	return 0;
-}
-#endif
-
-/* Local Variables: */
-/* tab-width: 4 */
-/* c-basic-offset: 4 */
-/* indent-tabs-mode: t */
-/* End: */
-
diff --git a/src/or/eventdns.h b/src/or/eventdns.h
deleted file mode 100644
index 1c130b2..0000000
--- a/src/or/eventdns.h
+++ /dev/null
@@ -1,337 +0,0 @@
-
-/*
- * The original DNS code is due to Adam Langley with heavy
- * modifications by Nick Mathewson.  Adam put his DNS software in the
- * public domain.  You can find his original copyright below.  Please,
- * aware that the code as part of libevent is governed by the 3-clause
- * BSD license above.
- *
- * This software is Public Domain. To view a copy of the public domain dedication,
- * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
- * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
- *
- * I ask and expect, but do not require, that all derivative works contain an
- * attribution similar to:
- *	Parts developed by Adam Langley <agl at imperialviolet.org>
- *
- * You may wish to replace the word "Parts" with something else depending on
- * the amount of original code.
- *
- * (Derivative works does not include programs which link against, run or include
- * the source verbatim in their source distributions)
- */
-
-/*
- * Welcome, gentle reader
- *
- * Async DNS lookups are really a whole lot harder than they should be,
- * mostly stemming from the fact that the libc resolver has never been
- * very good at them. Before you use this library you should see if libc
- * can do the job for you with the modern async call getaddrinfo_a
- * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
- * please continue.
- *
- * This code is based on libevent and you must call event_init before
- * any of the APIs in this file. You must also seed the OpenSSL random
- * source if you are using OpenSSL for ids (see below).
- *
- * This library is designed to be included and shipped with your source
- * code. You statically link with it. You should also test for the
- * existence of strtok_r and define HAVE_STRTOK_R if you have it.
- *
- * The DNS protocol requires a good source of id numbers and these
- * numbers should be unpredictable for spoofing reasons. There are
- * three methods for generating them here and you must define exactly
- * one of them. In increasing order of preference:
- *
- * DNS_USE_GETTIMEOFDAY_FOR_ID:
- *   Using the bottom 16 bits of the usec result from gettimeofday. This
- *   is a pretty poor solution but should work anywhere.
- * DNS_USE_CPU_CLOCK_FOR_ID:
- *  Using the bottom 16 bits of the nsec result from the CPU's time
- *  counter. This is better, but may not work everywhere. Requires
- *  POSIX realtime support and you'll need to link against -lrt on
- *  glibc systems at least.
- * DNS_USE_OPENSSL_FOR_ID:
- *  Uses the OpenSSL RAND_bytes call to generate the data. You must
- *  have seeded the pool before making any calls to this library.
- *
- * The library keeps track of the state of nameservers and will avoid
- * them when they go down. Otherwise it will round robin between them.
- *
- * Quick start guide:
- *	 #include "evdns.h"
- *	 void callback(int result, char type, int count, int ttl,
- *     void *addresses, void *arg);
- *	 evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
- *	 evdns_resolve("www.hostname.com", 0, callback, NULL);
- *
- * When the lookup is complete the callback function is called. The
- * first argument will be one of the DNS_ERR_* defines in evdns.h.
- * Hopefully it will be DNS_ERR_NONE, in which case type will be
- * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
- * which the data can be cached for (in seconds), addresses will point
- * to an array of uint32_t's and arg will be whatever you passed to
- * evdns_resolve.
- *
- * Searching:
- *
- * In order for this library to be a good replacement for glibc's resolver it
- * supports searching. This involves setting a list of default domains, in
- * which names will be queried for. The number of dots in the query name
- * determines the order in which this list is used.
- *
- * Searching appears to be a single lookup from the point of view of the API,
- * although many DNS queries may be generated from a single call to
- * evdns_resolve. Searching can also drastically slow down the resolution
- * of names.
- *
- * To disable searching:
- *	 1. Never set it up. If you never call evdns_resolv_conf_parse or
- *   evdns_search_add then no searching will occur.
- *
- *	 2. If you do call evdns_resolv_conf_parse then don't pass
- *   DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
- *
- *	 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
- *
- * The order of searches depends on the number of dots in the name. If the
- * number is greater than the ndots setting then the names is first tried
- * globally. Otherwise each search domain is appended in turn.
- *
- * The ndots setting can either be set from a resolv.conf, or by calling
- * evdns_search_ndots_set.
- *
- * For example, with ndots set to 1 (the default) and a search domain list of
- * ["myhome.net"]:
- *	Query: www
- *	Order: www.myhome.net, www.
- *
- *	Query: www.abc
- *	Order: www.abc., www.abc.myhome.net
- *
- * API reference:
- *
- * int evdns_nameserver_add(uint32_t address)
- *	 Add a nameserver. The address should be an IP address in
- *	 network byte order. The type of address is chosen so that
- *	 it matches in_addr.s_addr.
- *	 Returns non-zero on error.
- *
- * int evdns_nameserver_ip_add(const char *ip_as_string)
- *	 This wraps the above function by parsing a string as an IP
- *	 address and adds it as a nameserver.
- *	 Returns non-zero on error
- *
- * int evdns_resolve(const char *name, int flags,
- *	      evdns_callback_type callback,
- *	      void *ptr)
- *	 Resolve a name. The name parameter should be a DNS name.
- *	 The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
- *	 which disables searching for this query. (see defn of
- *	 searching above).
- *
- *	 The callback argument is a function which is called when
- *	 this query completes and ptr is an argument which is passed
- *	 to that callback function.
- *
- *	 Returns non-zero on error
- *
- * void evdns_search_clear()
- *	 Clears the list of search domains
- *
- * void evdns_search_add(const char *domain)
- *	 Add a domain to the list of search domains
- *
- * void evdns_search_ndots_set(int ndots)
- *	 Set the number of dots which, when found in a name, causes
- *	 the first query to be without any search domain.
- *
- * int evdns_count_nameservers(void)
- *	 Return the number of configured nameservers (not necessarily the
- *	 number of running nameservers).  This is useful for double-checking
- *	 whether our calls to the various nameserver configuration functions
- *	 have been successful.
- *
- * int evdns_clear_nameservers_and_suspend(void)
- *	 Remove all currently configured nameservers, and suspend all pending
- *	 resolves.	Resolves will not necessarily be re-attempted until
- *	 evdns_resume() is called.
- *
- * int evdns_resume(void)
- *	 Re-attempt resolves left in limbo after an earlier call to
- *	 evdns_clear_nameservers_and_suspend().
- *
- * int evdns_config_windows_nameservers(void)
- *	 Attempt to configure a set of nameservers based on platform settings on
- *	 a win32 host.	Preferentially tries to use GetNetworkParams; if that fails,
- *	 looks in the registry.	 Returns 0 on success, nonzero on failure.
- *
- * int evdns_resolv_conf_parse(int flags, const char *filename)
- *	 Parse a resolv.conf like file from the given filename.
- *
- *	 See the man page for resolv.conf for the format of this file.
- *	 The flags argument determines what information is parsed from
- *	 this file:
- *	   DNS_OPTION_SEARCH - domain, search and ndots options
- *	   DNS_OPTION_NAMESERVERS - nameserver lines
- *	   DNS_OPTION_MISC - timeout and attempts options
- *	   DNS_OPTIONS_ALL - all of the above
- *	 The following directives are not parsed from the file:
- *	   sortlist, rotate, no-check-names, inet6, debug
- *
- *	 Returns non-zero on error:
- *	  0 no errors
- *	  1 failed to open file
- *	  2 failed to stat file
- *	  3 file too large
- *	  4 out of memory
- *	  5 short read from file
- *        6 no nameservers in file
- *
- * Internals:
- *
- * Requests are kept in two queues. The first is the inflight queue. In
- * this queue requests have an allocated transaction id and nameserver.
- * They will soon be transmitted if they haven't already been.
- *
- * The second is the waiting queue. The size of the inflight ring is
- * limited and all other requests wait in waiting queue for space. This
- * bounds the number of concurrent requests so that we don't flood the
- * nameserver. Several algorithms require a full walk of the inflight
- * queue and so bounding its size keeps thing going nicely under huge
- * (many thousands of requests) loads.
- *
- * If a nameserver loses too many requests it is considered down and we
- * try not to use it. After a while we send a probe to that nameserver
- * (a lookup for google.com) and, if it replies, we consider it working
- * again. If the nameserver fails a probe we wait longer to try again
- * with the next probe.
- */
-
-#ifndef _TOR_EVENTDNS_H
-#define _TOR_EVENTDNS_H
-
-/* Error codes 0-5 are as described in RFC 1035. */
-#define DNS_ERR_NONE 0
-/* The name server was unable to interpret the query */
-#define DNS_ERR_FORMAT 1
-/* The name server was unable to process this query due to a problem with the
- * name server */
-#define DNS_ERR_SERVERFAILED 2
-/* The domain name does not exist */
-#define DNS_ERR_NOTEXIST 3
-/* The name server does not support the requested kind of query */
-#define DNS_ERR_NOTIMPL 4
-/* The name server refuses to reform the specified operation for policy
- * reasons */
-#define DNS_ERR_REFUSED 5
-/* The reply was truncated or ill-formated */
-#define DNS_ERR_TRUNCATED 65
-/* An unknown error occurred */
-#define DNS_ERR_UNKNOWN 66
-/* Communication with the server timed out */
-#define DNS_ERR_TIMEOUT 67
-/* The request was canceled because the DNS subsystem was shut down. */
-#define DNS_ERR_SHUTDOWN 68
-
-#define DNS_IPv4_A 1
-#define DNS_PTR 2
-#define DNS_IPv6_AAAA 3
-
-#define DNS_QUERY_NO_SEARCH 1
-
-#define DNS_OPTION_SEARCH 1
-#define DNS_OPTION_NAMESERVERS 2
-#define DNS_OPTION_MISC 4
-#define DNS_OPTIONS_ALL 7
-
-/*
- * The callback that contains the results from a lookup.
- * - type is either DNS_IPv4_A or DNS_IPv6_AAAA or DNS_PTR
- * - count contains the number of addresses of form type
- * - ttl is the number of seconds the resolution may be cached for.
- * - addresses needs to be cast according to type
- */
-typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
-
-int evdns_init(void);
-void evdns_shutdown(int fail_requests);
-const char *evdns_err_to_string(int err);
-int evdns_nameserver_add(uint32_t address);
-int evdns_count_nameservers(void);
-int evdns_clear_nameservers_and_suspend(void);
-int evdns_resume(void);
-int evdns_nameserver_ip_add(const char *ip_as_string);
-int evdns_nameserver_sockaddr_add(const struct sockaddr *sa, socklen_t len);
-void evdns_set_default_outgoing_bind_address(const struct sockaddr *addr, socklen_t addrlen);
-int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
-int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
-struct in_addr;
-struct in6_addr;
-int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
-int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
-int evdns_set_option(const char *option, const char *val, int flags);
-int evdns_resolv_conf_parse(int flags, const char *);
-#ifdef _WIN32
-int evdns_config_windows_nameservers(void);
-#endif
-void evdns_search_clear(void);
-void evdns_search_add(const char *domain);
-void evdns_search_ndots_set(const int ndots);
-
-typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
-void evdns_set_log_fn(evdns_debug_log_fn_type fn);
-
-void evdns_set_transaction_id_fn(uint16_t (*fn)(void));
-void evdns_set_random_bytes_fn(void (*fn)(char *, size_t));
-
-#define DNS_NO_SEARCH 1
-
-/* Structures and functions used to implement a DNS server. */
-
-struct evdns_server_request {
-	int flags;
-	int nquestions;
-	struct evdns_server_question **questions;
-};
-struct evdns_server_question {
-	int type;
-	int dns_question_class;
-	char name[1];
-};
-typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
-#define EVDNS_ANSWER_SECTION 0
-#define EVDNS_AUTHORITY_SECTION 1
-#define EVDNS_ADDITIONAL_SECTION 2
-
-#define EVDNS_TYPE_A	   1
-#define EVDNS_TYPE_NS	   2
-#define EVDNS_TYPE_CNAME   5
-#define EVDNS_TYPE_SOA	   6
-#define EVDNS_TYPE_PTR	  12
-#define EVDNS_TYPE_MX	  15
-#define EVDNS_TYPE_TXT	  16
-#define EVDNS_TYPE_AAAA	  28
-
-#define EVDNS_QTYPE_AXFR 252
-#define EVDNS_QTYPE_ALL	 255
-
-#define EVDNS_CLASS_INET   1
-
-struct evdns_server_port *evdns_add_server_port(tor_socket_t socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
-void evdns_close_server_port(struct evdns_server_port *port);
-
-int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
-int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
-int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl);
-int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
-int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
-
-struct sockaddr;
-int evdns_server_request_get_requesting_addr(struct evdns_server_request *req, struct sockaddr *sa, int addr_len);
-
-int evdns_server_request_respond(struct evdns_server_request *req, int err);
-int evdns_server_request_drop(struct evdns_server_request *req);
-
-#endif	// !EVENTDNS_H
diff --git a/src/or/include.am b/src/or/include.am
index 90dea44..7492061 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -12,7 +12,7 @@ EXTRA_DIST+= src/or/ntmain.c src/or/or_sha1.i src/or/Makefile.nmake
 if USE_EXTERNAL_EVDNS
 evdns_source=
 else
-evdns_source=src/or/eventdns.c
+evdns_source=src/ext/eventdns.c
 endif
 
 src_or_libtor_a_SOURCES = \
@@ -110,7 +110,6 @@ ORHEADERS = \
 	src/or/dirvote.h				\
 	src/or/dns.h					\
 	src/or/dnsserv.h				\
-	src/or/eventdns.h				\
 	src/or/eventdns_tor.h				\
 	src/or/geoip.h					\
 	src/or/hibernate.h				\
diff --git a/src/test/include.am b/src/test/include.am
index 03fef23..bdfe498 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -5,7 +5,7 @@ noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench
 src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
         -DLOCALSTATEDIR="\"$(localstatedir)\"" \
         -DBINDIR="\"$(bindir)\""	       \
-	-I"$(top_srcdir)/src/or"
+	-I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext"
 
 # -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
 # This seems to matter nowhere but on Windows, but I assure you that it
@@ -24,7 +24,7 @@ src_test_test_SOURCES = \
 	src/test/test_replay.c \
 	src/test/test_util.c \
 	src/test/test_config.c \
-	src/test/tinytest.c
+	src/ext/tinytest.c
 
 src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
 
@@ -48,8 +48,5 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypt
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
 
 noinst_HEADERS+= \
-	src/test/tinytest.h \
-	src/test/tinytest_macros.h \
 	src/test/test.h
 
-
diff --git a/src/test/tinytest.c b/src/test/tinytest.c
deleted file mode 100644
index 4d9afac..0000000
--- a/src/test/tinytest.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifdef TINYTEST_LOCAL
-#include "tinytest_local.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#endif
-
-#ifndef __GNUC__
-#define __attribute__(x)
-#endif
-
-#include "tinytest.h"
-#include "tinytest_macros.h"
-
-#define LONGEST_TEST_NAME 16384
-
-static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
-static int n_ok = 0; /**< Number of tests that have passed */
-static int n_bad = 0; /**< Number of tests that have failed. */
-static int n_skipped = 0; /**< Number of tests that have been skipped. */
-
-static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
-static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
-static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
-const char *verbosity_flag = "";
-
-enum outcome { SKIP=2, OK=1, FAIL=0 };
-static enum outcome cur_test_outcome = 0;
-const char *cur_test_prefix = NULL; /**< prefix of the current test group */
-/** Name of the current test, if we haven't logged is yet. Used for --quiet */
-const char *cur_test_name = NULL;
-
-#ifdef _WIN32
-/* Copy of argv[0] for win32. */
-static char commandname[MAX_PATH+1];
-#endif
-
-static void usage(struct testgroup_t *groups, int list_groups)
-  __attribute__((noreturn));
-
-static enum outcome
-testcase_run_bare_(const struct testcase_t *testcase)
-{
-	void *env = NULL;
-	int outcome;
-	if (testcase->setup) {
-		env = testcase->setup->setup_fn(testcase);
-		if (!env)
-			return FAIL;
-		else if (env == (void*)TT_SKIP)
-			return SKIP;
-	}
-
-	cur_test_outcome = OK;
-	testcase->fn(env);
-	outcome = cur_test_outcome;
-
-	if (testcase->setup) {
-		if (testcase->setup->cleanup_fn(testcase, env) == 0)
-			outcome = FAIL;
-	}
-
-	return outcome;
-}
-
-#define MAGIC_EXITCODE 42
-
-static enum outcome
-testcase_run_forked_(const struct testgroup_t *group,
-		     const struct testcase_t *testcase)
-{
-#ifdef _WIN32
-	/* Fork? On Win32?  How primitive!  We'll do what the smart kids do:
-	   we'll invoke our own exe (whose name we recall from the command
-	   line) with a command line that tells it to run just the test we
-	   want, and this time without forking.
-
-	   (No, threads aren't an option.  The whole point of forking is to
-	   share no state between tests.)
-	 */
-	int ok;
-	char buffer[LONGEST_TEST_NAME+256];
-	STARTUPINFOA si;
-	PROCESS_INFORMATION info;
-	DWORD exitcode;
-
-	if (!in_tinytest_main) {
-		printf("\nERROR.  On Windows, testcase_run_forked_ must be"
-		       " called from within tinytest_main.\n");
-		abort();
-	}
-	if (opt_verbosity>0)
-		printf("[forking] ");
-
-	snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
-		 commandname, verbosity_flag, group->prefix, testcase->name);
-
-	memset(&si, 0, sizeof(si));
-	memset(&info, 0, sizeof(info));
-	si.cb = sizeof(si);
-
-	ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
-			   0, NULL, NULL, &si, &info);
-	if (!ok) {
-		printf("CreateProcess failed!\n");
-		return 0;
-	}
-	WaitForSingleObject(info.hProcess, INFINITE);
-	GetExitCodeProcess(info.hProcess, &exitcode);
-	CloseHandle(info.hProcess);
-	CloseHandle(info.hThread);
-	if (exitcode == 0)
-		return OK;
-	else if (exitcode == MAGIC_EXITCODE)
-		return SKIP;
-	else
-		return FAIL;
-#else
-	int outcome_pipe[2];
-	pid_t pid;
-	(void)group;
-
-	if (pipe(outcome_pipe))
-		perror("opening pipe");
-
-	if (opt_verbosity>0)
-		printf("[forking] ");
-	pid = fork();
-	if (!pid) {
-		/* child. */
-		int test_r, write_r;
-		char b[1];
-		close(outcome_pipe[0]);
-		test_r = testcase_run_bare_(testcase);
-		assert(0<=(int)test_r && (int)test_r<=2);
-		b[0] = "NYS"[test_r];
-		write_r = (int)write(outcome_pipe[1], b, 1);
-		if (write_r != 1) {
-			perror("write outcome to pipe");
-			exit(1);
-		}
-		exit(0);
-		return FAIL; /* unreachable */
-	} else {
-		/* parent */
-		int status, r;
-		char b[1];
-		/* Close this now, so that if the other side closes it,
-		 * our read fails. */
-		close(outcome_pipe[1]);
-		r = (int)read(outcome_pipe[0], b, 1);
-		if (r == 0) {
-			printf("[Lost connection!] ");
-			return 0;
-		} else if (r != 1) {
-			perror("read outcome from pipe");
-		}
-		waitpid(pid, &status, 0);
-		close(outcome_pipe[0]);
-		return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
-	}
-#endif
-}
-
-int
-testcase_run_one(const struct testgroup_t *group,
-		 const struct testcase_t *testcase)
-{
-	enum outcome outcome;
-
-	if (testcase->flags & TT_SKIP) {
-		if (opt_verbosity>0)
-			printf("%s%s: SKIPPED\n",
-			    group->prefix, testcase->name);
-		++n_skipped;
-		return SKIP;
-	}
-
-	if (opt_verbosity>0 && !opt_forked) {
-		printf("%s%s: ", group->prefix, testcase->name);
-	} else {
-		if (opt_verbosity==0) printf(".");
-		cur_test_prefix = group->prefix;
-		cur_test_name = testcase->name;
-	}
-
-	if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
-		outcome = testcase_run_forked_(group, testcase);
-	} else {
-		outcome = testcase_run_bare_(testcase);
-	}
-
-	if (outcome == OK) {
-		++n_ok;
-		if (opt_verbosity>0 && !opt_forked)
-			puts(opt_verbosity==1?"OK":"");
-	} else if (outcome == SKIP) {
-		++n_skipped;
-		if (opt_verbosity>0 && !opt_forked)
-			puts("SKIPPED");
-	} else {
-		++n_bad;
-		if (!opt_forked)
-			printf("\n  [%s FAILED]\n", testcase->name);
-	}
-
-	if (opt_forked) {
-		exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
-		return 1; /* unreachable */
-	} else {
-		return (int)outcome;
-	}
-}
-
-int
-tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag)
-{
-	int i, j;
-	size_t length = LONGEST_TEST_NAME;
-	char fullname[LONGEST_TEST_NAME];
-	int found=0;
-	if (strstr(arg, ".."))
-		length = strstr(arg,"..")-arg;
-	for (i=0; groups[i].prefix; ++i) {
-		for (j=0; groups[i].cases[j].name; ++j) {
-			snprintf(fullname, sizeof(fullname), "%s%s",
-				 groups[i].prefix, groups[i].cases[j].name);
-			if (!flag) /* Hack! */
-				printf("    %s\n", fullname);
-			if (!strncmp(fullname, arg, length)) {
-				groups[i].cases[j].flags |= flag;
-				++found;
-			}
-		}
-	}
-	return found;
-}
-
-static void
-usage(struct testgroup_t *groups, int list_groups)
-{
-	puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
-	puts("  Specify tests by name, or using a prefix ending with '..'");
-	puts("  To skip a test, list give its name prefixed with a colon.");
-	puts("  Use --list-tests for a list of tests.");
-	if (list_groups) {
-		puts("Known tests are:");
-		tinytest_set_flag_(groups, "..", 0);
-	}
-	exit(0);
-}
-
-int
-tinytest_main(int c, const char **v, struct testgroup_t *groups)
-{
-	int i, j, n=0;
-
-#ifdef _WIN32
-	const char *sp = strrchr(v[0], '.');
-	const char *extension = "";
-	if (!sp || stricmp(sp, ".exe"))
-		extension = ".exe"; /* Add an exe so CreateProcess will work */
-	snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
-	commandname[MAX_PATH]='\0';
-#endif
-	for (i=1; i<c; ++i) {
-		if (v[i][0] == '-') {
-			if (!strcmp(v[i], "--RUNNING-FORKED")) {
-				opt_forked = 1;
-			} else if (!strcmp(v[i], "--no-fork")) {
-				opt_nofork = 1;
-			} else if (!strcmp(v[i], "--quiet")) {
-				opt_verbosity = -1;
-				verbosity_flag = "--quiet";
-			} else if (!strcmp(v[i], "--verbose")) {
-				opt_verbosity = 2;
-				verbosity_flag = "--verbose";
-			} else if (!strcmp(v[i], "--terse")) {
-				opt_verbosity = 0;
-				verbosity_flag = "--terse";
-			} else if (!strcmp(v[i], "--help")) {
-				usage(groups, 0);
-			} else if (!strcmp(v[i], "--list-tests")) {
-				usage(groups, 1);
-			} else {
-				printf("Unknown option %s.  Try --help\n",v[i]);
-				return -1;
-			}
-		} else {
-			const char *test = v[i];
-			int flag = TT_ENABLED_;
-			if (test[0] == ':') {
-				++test;
-				flag = TT_SKIP;
-			} else {
-				++n;
-			}
-			if (!tinytest_set_flag_(groups, test, flag)) {
-				printf("No such test as %s!\n", v[i]);
-				return -1;
-			}
-		}
-	}
-	if (!n)
-		tinytest_set_flag_(groups, "..", TT_ENABLED_);
-
-	setvbuf(stdout, NULL, _IONBF, 0);
-
-	++in_tinytest_main;
-	for (i=0; groups[i].prefix; ++i)
-		for (j=0; groups[i].cases[j].name; ++j)
-			if (groups[i].cases[j].flags & TT_ENABLED_)
-				testcase_run_one(&groups[i],
-						 &groups[i].cases[j]);
-
-	--in_tinytest_main;
-
-	if (opt_verbosity==0)
-		puts("");
-
-	if (n_bad)
-		printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
-		       n_bad+n_ok,n_skipped);
-	else if (opt_verbosity >= 1)
-		printf("%d tests ok.  (%d skipped)\n", n_ok, n_skipped);
-
-	return (n_bad == 0) ? 0 : 1;
-}
-
-int
-tinytest_get_verbosity_(void)
-{
-	return opt_verbosity;
-}
-
-void
-tinytest_set_test_failed_(void)
-{
-	if (opt_verbosity <= 0 && cur_test_name) {
-		if (opt_verbosity==0) puts("");
-		printf("%s%s: ", cur_test_prefix, cur_test_name);
-		cur_test_name = NULL;
-	}
-	cur_test_outcome = 0;
-}
-
-void
-tinytest_set_test_skipped_(void)
-{
-	if (cur_test_outcome==OK)
-		cur_test_outcome = SKIP;
-}
-
diff --git a/src/test/tinytest.h b/src/test/tinytest.h
deleted file mode 100644
index bcac9f0..0000000
--- a/src/test/tinytest.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TINYTEST_H_INCLUDED_
-#define TINYTEST_H_INCLUDED_
-
-/** Flag for a test that needs to run in a subprocess. */
-#define TT_FORK  (1<<0)
-/** Runtime flag for a test we've decided to skip. */
-#define TT_SKIP  (1<<1)
-/** Internal runtime flag for a test we've decided to run. */
-#define TT_ENABLED_  (1<<2)
-/** If you add your own flags, make them start at this point. */
-#define TT_FIRST_USER_FLAG (1<<3)
-
-typedef void (*testcase_fn)(void *);
-
-struct testcase_t;
-
-/** Functions to initialize/teardown a structure for a testcase. */
-struct testcase_setup_t {
-	/** Return a new structure for use by a given testcase. */
-	void *(*setup_fn)(const struct testcase_t *);
-	/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
-	int (*cleanup_fn)(const struct testcase_t *, void *);
-};
-
-/** A single test-case that you can run. */
-struct testcase_t {
-	const char *name; /**< An identifier for this case. */
-	testcase_fn fn; /**< The function to run to implement this case. */
-	unsigned long flags; /**< Bitfield of TT_* flags. */
-	const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
-	void *setup_data; /**< Extra data usable by setup function */
-};
-#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
-
-/** A group of tests that are selectable together. */
-struct testgroup_t {
-	const char *prefix; /**< Prefix to prepend to testnames. */
-	struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
-};
-#define END_OF_GROUPS { NULL, NULL}
-
-/** Implementation: called from a test to indicate failure, before logging. */
-void tinytest_set_test_failed_(void);
-/** Implementation: called from a test to indicate that we're skipping. */
-void tinytest_set_test_skipped_(void);
-/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
-int tinytest_get_verbosity_(void);
-/** Implementation: Set a flag on tests matching a name; returns number
- * of tests that matched. */
-int tinytest_set_flag_(struct testgroup_t *, const char *, unsigned long);
-
-/** Set all tests in 'groups' matching the name 'named' to be skipped. */
-#define tinytest_skip(groups, named) \
-	tinytest_set_flag_(groups, named, TT_SKIP)
-
-/** Run a single testcase in a single group. */
-int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
-/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
-    as selected from the command line. */
-int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
-
-#endif
diff --git a/src/test/tinytest_demo.c b/src/test/tinytest_demo.c
deleted file mode 100644
index be95ce4..0000000
--- a/src/test/tinytest_demo.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* Welcome to the example file for tinytest!  I'll show you how to set up
- * some simple and not-so-simple testcases. */
-
-/* Make sure you include these headers. */
-#include "tinytest.h"
-#include "tinytest_macros.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/* ============================================================ */
-
-/* First, let's see if strcmp is working.  (All your test cases should be
- * functions declared to take a single void * as an argument.) */
-void
-test_strcmp(void *data)
-{
-	(void)data; /* This testcase takes no data. */
-
-	/* Let's make sure the empty string is equal to itself */
-	if (strcmp("","")) {
-		/* This macro tells tinytest to stop the current test
-		 * and go straight to the "end" label. */
-		tt_abort_msg("The empty string was not equal to itself");
-	}
-
-	/* Pretty often, calling tt_abort_msg to indicate failure is more
-	   heavy-weight than you want.	Instead, just say: */
-	tt_assert(strcmp("testcase", "testcase") == 0);
-
-	/* Occasionally, you don't want to stop the current testcase just
-	   because a single assertion has failed.  In that case, use
-	   tt_want: */
-	tt_want(strcmp("tinytest", "testcase") > 0);
-
-	/* You can use the tt_*_op family of macros to compare values and to
-	   fail unless they have the relationship you want.  They produce
-	   more useful output than tt_assert, since they display the actual
-	   values of the failing things.
-
-	   Fail unless strcmp("abc, "abc") == 0 */
-	tt_int_op(strcmp("abc", "abc"), ==, 0);
-
-	/* Fail unless strcmp("abc, "abcd") is less than 0 */
-	tt_int_op(strcmp("abc", "abcd"), < , 0);
-
-	/* Incidentally, there's a test_str_op that uses strcmp internally. */
-	tt_str_op("abc", <, "abcd");
-
-
-	/* Every test-case function needs to finish with an "end:"
-	   label and (optionally) code to clean up local variables. */
- end:
-	;
-}
-
-/* ============================================================ */
-
-/* Now let's mess with setup and teardown functions!  These are handy if
-   you have a bunch of tests that all need a similar environment, and you
-   want to reconstruct that environment freshly for each one. */
-
-/* First you declare a type to hold the environment info, and functions to
-   set it up and tear it down. */
-struct data_buffer {
-	/* We're just going to have couple of character buffer.	 Using
-	   setup/teardown functions is probably overkill for this case.
-
-	   You could also do file descriptors, complicated handles, temporary
-	   files, etc. */
-	char buffer1[512];
-	char buffer2[512];
-};
-/* The setup function needs to take a const struct testcase_t and return
-   void* */
-void *
-setup_data_buffer(const struct testcase_t *testcase)
-{
-	struct data_buffer *db = malloc(sizeof(struct data_buffer));
-
-	/* If you had a complicated set of setup rules, you might behave
-	   differently here depending on testcase->flags or
-	   testcase->setup_data or even or testcase->name. */
-
-	/* Returning a NULL here would mean that we couldn't set up for this
-	   test, so we don't need to test db for null. */
-	return db;
-}
-/* The clean function deallocates storage carefully and returns true on
-   success. */
-int
-clean_data_buffer(const struct testcase_t *testcase, void *ptr)
-{
-	struct data_buffer *db = ptr;
-
-	if (db) {
-		free(db);
-		return 1;
-	}
-	return 0;
-}
-/* Finally, declare a testcase_setup_t with these functions. */
-struct testcase_setup_t data_buffer_setup = {
-	setup_data_buffer, clean_data_buffer
-};
-
-
-/* Now let's write our test. */
-void
-test_memcpy(void *ptr)
-{
-	/* This time, we use the argument. */
-	struct data_buffer *db = ptr;
-
-	/* We'll also introduce a local variable that might need cleaning up. */
-	char *mem = NULL;
-
-	/* Let's make sure that memcpy does what we'd like. */
-	strcpy(db->buffer1, "String 0");
-	memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
-	tt_str_op(db->buffer1, ==, db->buffer2);
-
-	/* Now we've allocated memory that's referenced by a local variable.
-	   The end block of the function will clean it up. */
-	mem = strdup("Hello world.");
-	tt_assert(mem);
-
-	/* Another rather trivial test. */
-	tt_str_op(db->buffer1, !=, mem);
-
- end:
-	/* This time our end block has something to do. */
-	if (mem)
-		free(mem);
-}
-
-/* ============================================================ */
-
-/* Now we need to make sure that our tests get invoked.	  First, you take
-   a bunch of related tests and put them into an array of struct testcase_t.
-*/
-
-struct testcase_t demo_tests[] = {
-	/* Here's a really simple test: it has a name you can refer to it
-	   with, and a function to invoke it. */
-	{ "strcmp", test_strcmp, },
-
-	/* The second test has a flag, "TT_FORK", to make it run in a
-	   subprocess, and a pointer to the testcase_setup_t that configures
-	   its environment. */
-	{ "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
-
-	/* The array has to end with END_OF_TESTCASES. */
-	END_OF_TESTCASES
-};
-
-/* Next, we make an array of testgroups.  This is mandatory.  Unlike more
-   heavy-duty testing frameworks, groups can't nest. */
-struct testgroup_t groups[] = {
-
-	/* Every group has a 'prefix', and an array of tests.  That's it. */
-	{ "demo/", demo_tests },
-
-	END_OF_GROUPS
-};
-
-
-int
-main(int c, const char **v)
-{
-	/* Finally, just call tinytest_main().	It lets you specify verbose
-	   or quiet output with --verbose and --quiet.	You can list
-	   specific tests:
-
-	       tinytest-demo demo/memcpy
-
-	   or use a ..-wildcard to select multiple tests with a common
-	   prefix:
-
-	       tinytest-demo demo/..
-
-	   If you list no tests, you get them all by default, so that
-	   "tinytest-demo" and "tinytest-demo .." mean the same thing.
-
-	*/
-	return tinytest_main(c, v, groups);
-}
diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h
deleted file mode 100644
index 9ff69b1..0000000
--- a/src/test/tinytest_macros.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TINYTEST_MACROS_H_INCLUDED_
-#define TINYTEST_MACROS_H_INCLUDED_
-
-/* Helpers for defining statement-like macros */
-#define TT_STMT_BEGIN do {
-#define TT_STMT_END } while (0)
-
-/* Redefine this if your test functions want to abort with something besides
- * "goto end;" */
-#ifndef TT_EXIT_TEST_FUNCTION
-#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
-#endif
-
-/* Redefine this if you want to note success/failure in some different way. */
-#ifndef TT_DECLARE
-#define TT_DECLARE(prefix, args)				\
-	TT_STMT_BEGIN						\
-	printf("\n  %s %s:%d: ",prefix,__FILE__,__LINE__);	\
-	printf args ;						\
-	TT_STMT_END
-#endif
-
-/* Announce a failure. Args are parenthesized printf args. */
-#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
-
-/* Announce a non-failure if we're verbose. */
-#define TT_BLATHER(args)						\
-	TT_STMT_BEGIN							\
-	if (tinytest_get_verbosity_()>1) TT_DECLARE("  OK", args);	\
-	TT_STMT_END
-
-#define TT_DIE(args)						\
-	TT_STMT_BEGIN						\
-	tinytest_set_test_failed_();				\
-	TT_GRIPE(args);						\
-	TT_EXIT_TEST_FUNCTION;					\
-	TT_STMT_END
-
-#define TT_FAIL(args)				\
-	TT_STMT_BEGIN						\
-	tinytest_set_test_failed_();				\
-	TT_GRIPE(args);						\
-	TT_STMT_END
-
-/* Fail and abort the current test for the reason in msg */
-#define tt_abort_printf(msg) TT_DIE(msg)
-#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
-#define tt_abort_msg(msg) TT_DIE(("%s", msg))
-#define tt_abort() TT_DIE(("%s", "(Failed.)"))
-
-/* Fail but do not abort the current test for the reason in msg. */
-#define tt_failprint_f(msg) TT_FAIL(msg)
-#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
-#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
-#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
-
-/* End the current test, and indicate we are skipping it. */
-#define tt_skip()						\
-	TT_STMT_BEGIN						\
-	tinytest_set_test_skipped_();				\
-	TT_EXIT_TEST_FUNCTION;					\
-	TT_STMT_END
-
-#define tt_want_(b, msg, fail)				\
-	TT_STMT_BEGIN					\
-	if (!(b)) {					\
-		tinytest_set_test_failed_();		\
-		TT_GRIPE(("%s",msg));			\
-		fail;					\
-	} else {					\
-		TT_BLATHER(("%s",msg));			\
-	}						\
-	TT_STMT_END
-
-/* Assert b, but do not stop the test if b fails.  Log msg on failure. */
-#define tt_want_msg(b, msg)			\
-	tt_want_(b, msg, );
-
-/* Assert b and stop the test if b fails.  Log msg on failure. */
-#define tt_assert_msg(b, msg)			\
-	tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
-
-/* Assert b, but do not stop the test if b fails. */
-#define tt_want(b)   tt_want_msg( (b), "want("#b")")
-/* Assert b, and stop the test if b fails. */
-#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
-
-#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
-    setup_block,cleanup_block,die_on_fail)				\
-	TT_STMT_BEGIN							\
-	type val1_ = (type)(a);						\
-	type val2_ = (type)(b);						\
-	int tt_status_ = (test);					\
-	if (!tt_status_ || tinytest_get_verbosity_()>1)	{		\
-		printf_type print_;					\
-		printf_type print1_;					\
-		printf_type print2_;					\
-		type value_ = val1_;					\
-		setup_block;						\
-		print1_ = print_;					\
-		value_ = val2_;						\
-		setup_block;						\
-		print2_ = print_;					\
-		TT_DECLARE(tt_status_?"	 OK":"FAIL",			\
-			   ("assert(%s): "printf_fmt" vs "printf_fmt,	\
-			    str_test, print1_, print2_));		\
-		print_ = print1_;					\
-		cleanup_block;						\
-		print_ = print2_;					\
-		cleanup_block;						\
-		if (!tt_status_) {					\
-			tinytest_set_test_failed_();			\
-			die_on_fail ;					\
-		}							\
-	}								\
-	TT_STMT_END
-
-#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail)	\
-	tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt,	\
-	    {print_=value_;},{},die_on_fail)
-
-/* Helper: assert that a op b, when cast to type.  Format the values with
- * printf format fmt on failure. */
-#define tt_assert_op_type(a,op,b,type,fmt)				\
-	tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
-	    TT_EXIT_TEST_FUNCTION)
-
-#define tt_int_op(a,op,b)			\
-	tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
-	    "%ld",TT_EXIT_TEST_FUNCTION)
-
-#define tt_uint_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long,		\
-	    (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
-
-#define tt_ptr_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,void*,			\
-	    (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
-
-#define tt_str_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,const char *,		\
-	    (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
-
-#define tt_want_int_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
-
-#define tt_want_uint_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long,		\
-	    (val1_ op val2_),"%lu",(void)0)
-
-#define tt_want_ptr_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,void*,			\
-	    (val1_ op val2_),"%p",(void)0)
-
-#define tt_want_str_op(a,op,b)						\
-	tt_assert_test_type(a,b,#a" "#op" "#b,const char *,		\
-	    (strcmp(val1_,val2_) op 0),"<%s>",(void)0)
-
-#endif





More information about the tor-commits mailing list