This began as a cleanup of a few startling bugs in resolver.c, but I encountered so many other endemic issues (IMO) along the way that I just started from the top and groomed everything on my way through. Apologies if the style doesn't quite match the rest of the codebase, but I hope it's at least a little easier to follow. The resolver is still architected the same as the original (id est, a group of threads, all feeding from a common input stream in turn, resolving their data and responding independently before repeating), but it strives to do the things it does a little more correctly. I've probably screwed up portability somewhere, and it may now require a non-vintage compiler. Major fixes: * locking. original had none around its core data structures (!) * functions no longer harbor static buffers (!) * non-blocking IO is more resilient Other changes: * uses modern socket framework * can cache successful lookups as well as failures * cache lookups are now less than linear * uses native stdio locking Possible future improvements to consider: * track more internal data, dump stats on a signal * make the threadpool dynamically sized * use a different work-queue model entirely