r2974 - in branches/ppcgui: . ex-libs ex-libs/udns-arm ex-libs/udns-arm/build ex-libs/udns-arm/win32 ex-libs/udns-arm/win32/_UpgradeReport_Files

athkar at minisip.org athkar at minisip.org
Wed Nov 29 00:01:42 CET 2006


Author: athkar
Date: 2006-11-29 00:01:41 +0100 (Wed, 29 Nov 2006)
New Revision: 2974

Added:
   branches/ppcgui/ex-libs/
   branches/ppcgui/ex-libs/udns-arm/
   branches/ppcgui/ex-libs/udns-arm/Makefile
   branches/ppcgui/ex-libs/udns-arm/TODO
   branches/ppcgui/ex-libs/udns-arm/build/
   branches/ppcgui/ex-libs/udns-arm/build/dnsget.exe
   branches/ppcgui/ex-libs/udns-arm/build/udns.dll
   branches/ppcgui/ex-libs/udns-arm/build/udns.lib
   branches/ppcgui/ex-libs/udns-arm/dnsget.c
   branches/ppcgui/ex-libs/udns-arm/rblcheck.c
   branches/ppcgui/ex-libs/udns-arm/readme1st.txt
   branches/ppcgui/ex-libs/udns-arm/udns.3
   branches/ppcgui/ex-libs/udns-arm/udns.h
   branches/ppcgui/ex-libs/udns-arm/udns_bl.c
   branches/ppcgui/ex-libs/udns-arm/udns_dn.c
   branches/ppcgui/ex-libs/udns-arm/udns_dntosp.c
   branches/ppcgui/ex-libs/udns-arm/udns_misc.c
   branches/ppcgui/ex-libs/udns-arm/udns_parse.c
   branches/ppcgui/ex-libs/udns-arm/udns_resolver.c
   branches/ppcgui/ex-libs/udns-arm/udns_rr_a.c
   branches/ppcgui/ex-libs/udns-arm/udns_rr_mx.c
   branches/ppcgui/ex-libs/udns-arm/udns_rr_ptr.c
   branches/ppcgui/ex-libs/udns-arm/udns_rr_txt.c
   branches/ppcgui/ex-libs/udns-arm/win32/
   branches/ppcgui/ex-libs/udns-arm/win32/UpgradeLog.XML
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/Thumbs.db
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/UpgradeReport.css
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/UpgradeReport.xslt
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/UpgradeReport_Minus.gif
   branches/ppcgui/ex-libs/udns-arm/win32/_UpgradeReport_Files/UpgradeReport_Plus.gif
   branches/ppcgui/ex-libs/udns-arm/win32/dnsget.rc
   branches/ppcgui/ex-libs/udns-arm/win32/dnsget.vcproj
   branches/ppcgui/ex-libs/udns-arm/win32/dnsget.vcproj.7.10.old
   branches/ppcgui/ex-libs/udns-arm/win32/dnsget.vcproj.XPS.thanasis.user
   branches/ppcgui/ex-libs/udns-arm/win32/resource.h
   branches/ppcgui/ex-libs/udns-arm/win32/udns.aps
   branches/ppcgui/ex-libs/udns-arm/win32/udns.rc
   branches/ppcgui/ex-libs/udns-arm/win32/udns.sln
   branches/ppcgui/ex-libs/udns-arm/win32/udns.sln.old
   branches/ppcgui/ex-libs/udns-arm/win32/udns.suo
   branches/ppcgui/ex-libs/udns-arm/win32/udns.vcproj
   branches/ppcgui/ex-libs/udns-arm/win32/udns.vcproj.7.10.old
   branches/ppcgui/ex-libs/udns-arm/win32/udns.vcproj.XPS.thanasis.user
   branches/ppcgui/ex-libs/udns-arm/win32/udns_codes.c
   branches/ppcgui/ex-libs/udns-arm/win32/win32.c
   branches/ppcgui/ex-libs/udns-arm/win32/win32.h
Log:
Upload of the udns pocket pc port (including the dnsget.exe example

Added: branches/ppcgui/ex-libs/udns-arm/Makefile
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/Makefile	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/Makefile	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,71 @@
+# $Id: Makefile,v 1.18 2004/07/11 11:17:40 mjt Exp $
+# libudns Makefile
+#
+UDNS_SRCS = udns_dn.c udns_dntosp.c udns_parse.c udns_resolver.c udns_misc.c \
+	udns_rr_a.c udns_rr_ptr.c udns_rr_mx.c udns_rr_txt.c udns_bl.c
+UDNS_HDRS = udns.h
+UDNS_GENS = udns_codes.c
+UDNS_UTIL = dnsget.c rblcheck.c
+UDNS_DIST = udns.h udns.3 $(UDNS_SRCS) Makefile TODO $(UDNS_UTIL)
+UDNS_OBJS = $(UDNS_SRCS:.c=.o) $(UDNS_GENS:.c=.o)
+UDNS_NAME = udns
+UDNS_LIBS = lib$(UDNS_NAME).a
+UDNS_VERS = 0.0.4
+
+CFLAGS = -Wall -W -Wmissing-prototypes -DHAVE_POLL
+AWK = awk
+
+all: lib$(UDNS_NAME).a $(UDNS_UTIL:.c=)
+
+lib$(UDNS_NAME).a: $(UDNS_OBJS)
+	-rm -f $@
+	$(AR) rv $@ $(UDNS_OBJS)
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+
+udns_codes.c:	udns.h Makefile
+	@echo Generating $@
+	@set -e; exec >$@.tmp; \
+	set T type C class R rcode; \
+	echo "/* Automatically generated. */"; \
+	echo "#include \"udns.h\""; \
+	echo "#include <stdio.h>"; \
+	while [ "$$1" ]; do \
+	 echo; \
+	 echo "const struct dns_nameval dns_$${2}tab[] = {"; \
+	 $(AWK) "/^  DNS_$${1}_[A-Z0-9_]+[ 	]*=/ \
+	  { printf \" {%s,\\\"%s\\\"},\\n\", \$$1, substr(\$$1,7) }" \
+	  $< ; \
+	 echo " {0,0}};"; \
+	 echo "const char *dns_$${2}name(enum dns_$${2} code) {"; \
+	 echo " static char nm[20];"; \
+	 echo " switch(code) {"; \
+	 $(AWK) "BEGIN{i=0} \
+	   /^  DNS_$${1}_[A-Z0-9_]+[ 	]*=/ \
+	   {printf \" case %s: return dns_$${2}tab[%d].name;\\n\",\$$1,i++}\
+	   " $< ; \
+	 echo " }"; \
+	 echo " sprintf(nm,\"$$2%d\", code);"; \
+	 echo " return nm;"; \
+	 echo "}"; \
+	 shift 2; \
+	done
+	@mv $@.tmp $@
+
+$(UDNS_NAME).3.html: $(UDNS_NAME).3
+	groff -man -Thtml $< > $@.tmp
+	mv $@.tmp $@
+
+$(UDNS_OBJS): $(UDNS_HDRS)
+dnsget: dnsget.c $(UDNS_HDRS) lib$(UDNS_NAME).a
+	$(CC) $(CFLAGS) -o $@ $< lib$(UDNS_NAME).a
+rblcheck: rblcheck.c $(UDNS_HDRS) lib$(UDNS_NAME).a
+	$(CC) $(CFLAGS) -o $@ $< lib$(UDNS_NAME).a
+
+dist: $(UDNS_NAME)-$(UDNS_VERS).tar.gz
+$(UDNS_NAME)-$(UDNS_VERS).tar.gz: $(UDNS_DIST)
+	tar cvfz $@ $(UDNS_DIST)
+clean:
+	rm -f $(UDNS_OBJS) $(UDNS_GENS)
+distclean: clean
+	rm -f $(UDNS_LIBS) $(UDNS_NAME).3.html

Added: branches/ppcgui/ex-libs/udns-arm/TODO
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/TODO	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/TODO	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,52 @@
+$Id: TODO,v 1.7 2004/07/11 11:18:36 mjt Exp $
+
+The following is mostly an internal, not user-visible stuff.
+
+* allow NULL callbacks?  Or provide separate resolver
+  context list of queries which are done but wich did not
+  have callback, and dns_pick() routine to retrieve results
+  from this query, i.e. allow non-callback usage?  The
+  non-callback usage may be handy sometimes (any *good*
+  example?), but it will be difficult to provide type-safe
+  non-callback interface due to various RR-specific types
+  in use.
+
+* in dns_set_serv() (set list of nameservers to use), we may
+  accept *names* in addition to IP addresses, and perform
+  internal resolving using current (defined) set of nameservers.
+  Is such a feature useful for anything but debugging tools
+  such as dig, host, etc?
+
+* DNS_OPT_FLAGS should be DNS_OPT_ADDFLAGS and DNS_OPT_SETFLAGS.
+  Currently one can't add a single flag bit but preserve
+  existing bits... at least not without retrieving all current
+  flags before, which isn't that bad anyway.
+
+* dns_set_opts() may process flags too (such as aaonly etc)
+
+* a way to disable $NSCACHEIP et al processing?
+
+* initialize/open the context automatically, and be more
+  liberal about initialization in general?
+
+* dns_init(do_open) - make the parameter opposite, aka
+  dns_init(skip_open) ?
+
+* check the error value returned by recvfrom() and
+  sendto() and determine which errors to ignore.
+
+* maybe merge dns_timeouts() and dns_ioevent(), to have
+  only one entry point for everything?  For traditional
+  select-loop-based eventloop it may be easier, but for
+  callback-driven event loops the two should be separate.
+  Provide an option, or a single dns_events() entry point
+  for select-loop approach, or just call dns_ioevent()
+  from within dns_timeouts() (probably after renaming
+  it to be dns_events()) ?
+
+* implement /etc/hosts lookup too, ala [c-]ares??
+
+* sortlist support?
+
+* windows port?  Oh no please!..  At least, I can't do it myself
+  because of the lack of platform.

Added: branches/ppcgui/ex-libs/udns-arm/build/dnsget.exe
===================================================================
(Binary files differ)


Property changes on: branches/ppcgui/ex-libs/udns-arm/build/dnsget.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/ppcgui/ex-libs/udns-arm/build/udns.dll
===================================================================
(Binary files differ)


Property changes on: branches/ppcgui/ex-libs/udns-arm/build/udns.dll
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/ppcgui/ex-libs/udns-arm/build/udns.lib
===================================================================
(Binary files differ)


Property changes on: branches/ppcgui/ex-libs/udns-arm/build/udns.lib
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/ppcgui/ex-libs/udns-arm/dnsget.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/dnsget.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/dnsget.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,353 @@
+/* $Id: dnsget.c,v 1.3 2004/07/11 10:34:40 mjt Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <time.h>
+#include "udns.h"
+
+static char *progname;
+static int verbose = 1;
+static int errors;
+static int notfound;
+
+static const struct qtype {
+  const char *name;
+  enum dns_type qtyp;
+  int flags;
+} qtypes[] = {
+  { "a",    DNS_T_A,    0 },
+  { "aaaa", DNS_T_AAAA, 0 },
+  { "ptr",  DNS_T_PTR,  1 },
+  { "mx",   DNS_T_MX,   0 },
+  { "txt",  DNS_T_TXT,  0 },
+  { 0, 0, 0 }
+};
+
+static const struct qtype *qt;
+static enum dns_class qcls = DNS_C_IN;
+
+static void
+dnserror(const char *name, int errnum) {
+  if (verbose >= 0)
+    fprintf(stderr, "%s: unable to lookup %s record for %s: %s\n",
+            progname, qt->name, name, dns_strerror(errnum));
+  if (errnum == DNS_E_NXDOMAIN || errnum == DNS_E_NODATA)
+    ++notfound;
+  else
+    ++errors;
+}
+
+static void xperr() {
+  printf("<parse error>\n");
+  ++errors;
+}
+
+static int
+printsection(const unsigned char *pkt,
+             const unsigned char **curp,
+             const unsigned char *end,
+	     enum dns_class qcls, enum dns_type qtyp,
+             int nrr, const char *name) {
+  unsigned char dn[DNS_MAXDN];
+  enum dns_class cls;
+  enum dns_type  typ;
+  unsigned ttl;
+  unsigned dsz;
+  const unsigned char *dptr, *dend, *c, *cur = *curp;
+  int n;
+  if (!nrr) return 0;
+  if (verbose > 1) printf("\n;; %s section (%d):\n", name, nrr);
+
+  while(nrr--) {
+    if (dns_getdn(pkt, &cur, end, dn, sizeof(dn)) <= 0)
+      return -1;
+    if (cur + 10 > end) return -1;
+    typ = dns_get16(cur); cur += 2;
+    cls = dns_get16(cur); cur += 2;
+    ttl = dns_get32(cur); cur += 4;
+    dsz = dns_get16(cur); cur += 2;
+    dptr = cur;
+    dend = cur = cur + dsz;
+    if (cur > end) return -1;
+    if (qcls && cls != qcls) continue;
+    if (qtyp &&
+        (typ != qtyp && (typ != DNS_T_CNAME || verbose <= 0)))
+      continue;
+    if (verbose > 0) {
+      if (verbose > 1) {
+        if (!nrr && !dn[0] && typ == DNS_T_OPT) {
+          printf(";EDNS0 OPT record (UDPsize: %d): %d bytes\n", cls, dsz);
+          continue;
+	}
+        n = printf("%s.", dns_dntosp(dn));
+        printf("%s%u\t%s\t%s\t",
+               n > 15 ? "\t" : n > 7 ? "\t\t" : "\t\t\t",
+               ttl, dns_classname(cls), dns_typename(typ));
+      }
+      else printf("%s. %s ", dns_dntosp(dn), dns_typename(typ));
+    }
+    switch(typ) {
+
+    case DNS_T_CNAME:
+    case DNS_T_PTR:
+    case DNS_T_NS:
+    case DNS_T_MB:
+    case DNS_T_MD:
+    case DNS_T_MF:
+    case DNS_T_MG:
+    case DNS_T_MR:
+      if (dns_getdn(pkt, &dptr, dend, dn, sizeof(dn)) <= 0) {
+        xperr(); continue;
+      }
+      printf("%s.\n", dns_dntosp(dn));
+      break;
+
+    case DNS_T_A:
+      if (dsz != 4) xperr();
+      else printf("%d.%d.%d.%d\n", dptr[0], dptr[1], dptr[2], dptr[3]);
+      break;
+
+    case DNS_T_AAAA:
+      if (dsz != 16) xperr();
+      else printf("%s\n", inet_ntop(AF_INET6, dptr, dn, 16));
+      break;
+
+    case DNS_T_MX:
+      c = dptr + 2;
+      if (dns_getdn(pkt, &c, dend, dn, sizeof(dn)) <= 0) xperr();
+      else printf("%d %s.\n", dns_get16(dptr), dns_dntosp(dn));
+      break;
+
+    case DNS_T_TXT:
+      /* first verify it */
+      for(c = dptr; c < dend; c += n) {
+        n = *c++;
+        if (c + n > dend) {
+          xperr();
+          c = 0;
+          break;
+	}
+      }
+      if (!c) continue;
+      c = dptr;
+      if (verbose > 0) {
+        const unsigned char *e;
+	int i = 0;
+        while(c < dend) {
+          n = *c++;
+	  e = c + n;
+	  printf("%s\"", i++?" ":"");
+	  while(c < e) {
+            if (*c < ' ' || *c >= 127) printf("\\%02x", *c);
+	    else if (*c == '\\' || *c == '"') printf("\\%c", *c);
+	    else putchar(*c);
+	    ++c;
+	  }
+	  putchar('"');
+	}
+      }
+      else {
+        while(c < dend) {
+          n = *c++;
+	  fwrite(c, n, 1, stdout);
+	  c += n;
+	}
+      }
+      putchar('\n');
+      break;
+
+    case DNS_T_SOA:
+      if (dns_getdn(pkt, &dptr, dend, dn, sizeof(dn)) <= 0) { xperr(); break; }
+      printf("%s. ", dns_dntosp(dn));
+      if (dns_getdn(pkt, &dptr, dend, dn, sizeof(dn)) <= 0) { xperr(); break; }
+      printf("%s. ", dns_dntosp(dn));
+      if (dptr + 4*5 != dend) { xperr(); break; }
+      printf("%u %u %u %u %u\n",
+             dns_get32(dptr), dns_get32(dptr+4), dns_get32(dptr+8),
+             dns_get32(dptr+12), dns_get32(dptr+16));
+      break;
+
+    case DNS_T_MINFO:
+      if (dns_getdn(pkt, &dptr, dend, dn, sizeof(dn)) <= 0) { xperr(); break; }
+      printf("%s. ", dns_dntosp(dn));
+      if (dns_getdn(pkt, &dptr, dend, dn, sizeof(dn)) <= 0) { xperr(); break; }
+      printf("%s.\n", dns_dntosp(dn));
+      break;
+
+    case DNS_T_HINFO:
+    case DNS_T_WKS:
+    case DNS_T_A6:
+    case DNS_T_NULL:
+
+    default:
+      printf("<unknown RR type (size %d)>\n", dsz);
+      break;
+    }
+  }
+  *curp = cur;
+  return 0;
+}
+
+static void dnscb(struct dns_ctx *ctx, void *result, void *data) {
+  int r = dns_status(ctx);
+  const char *name = data;
+  const unsigned char *pkt = result;
+  const unsigned char *end = pkt + r;
+  const unsigned char *cur, *qdn;
+  enum dns_class qcls;
+  enum dns_type  qtyp;
+  if (!result) {
+    dnserror(name, r);
+    return;
+  }
+  qdn = dns_payload(pkt);
+  cur = qdn + dns_dnlen(qdn);
+  if (verbose > 1) {
+    printf(";; ->>HEADER<<- opcode: QUERY, status: %s, id: %d, size: %d\n",
+           dns_rcodename(dns_rcode(pkt)), dns_qid(pkt), r);
+    printf(";; flags:");
+    if (dns_qr(pkt)) printf(" qr");
+    if (dns_rd(pkt)) printf(" rd");
+    if (dns_ra(pkt)) printf(" ra");
+    if (dns_aa(pkt)) printf(" aa");
+    if (dns_tc(pkt)) printf(" tc");
+    printf("; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d\n",
+           dns_numqd(pkt), dns_numan(pkt), dns_numns(pkt), dns_numar(pkt));
+    printf("\n;; QUERY SECTION (%d):\n", dns_numqd(pkt));
+    r = printf(";%s.", dns_dntosp(qdn));
+    printf("%s%s\t%s\n",
+           r > 23 ? "\t" : r > 15 ? "\t\t" : r > 7 ? "\t\t\t" : "\t\t\t\t",
+           dns_classname(dns_get16(cur+2)), dns_typename(dns_get16(cur)));
+    qcls = 0; qtyp = 0;
+  }
+  else {
+    qtyp = dns_get16(cur);   if (qtyp == DNS_T_ANY) qtyp = 0;
+    qcls = dns_get16(cur+2); if (qcls == DNS_C_ANY) qcls = 0;
+  }
+  cur += 4;
+  r = printsection(pkt, &cur, end, qcls, qtyp, dns_numan(pkt), "ANSWER");
+  if (r < 0 || verbose <= 1) { free(result); return; }
+  if (r == 0)
+    r = printsection(pkt, &cur, end, 0, 0, dns_numns(pkt), "AUTHORITY");
+  if (r == 0)
+    r = printsection(pkt, &cur, end, 0, 0, dns_numar(pkt), "ADDITIONAL");
+  putchar('\n');
+  free(result);
+}
+
+void print_usage(void)
+{
+	fprintf(stdout,
+		"Usage: %s [options] domain_name [domain_name ...]\n"
+		" Options\n"
+		"   -h               Print this help information\n"
+		"   -v               Be more verbose\n"
+		"   -q               Be more quiet\n"
+		"   -t <type>        DNS record type (e.g. \"A\" or \"AAAA\")\n"
+		"   -c <class>       DNS class (e.g. \"in\")\n"
+		"   -n <nameserver>  Add nameserver to server list\n",
+		progname);
+}
+
+int main(int argc, char **argv) {
+  int i;
+  int fd;
+  fd_set fds;
+  struct timeval tv;
+  time_t now;
+  struct qtype qtp;
+
+  if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
+  else argv[0] = ++progname;
+
+  fprintf(stdout, "UDNS dnsget tool\n");
+  dns_init(0);
+
+  while((i = getopt(argc, argv, "hvqn:t:c:")) != EOF) switch(i) {
+  case 'h':
+	  print_usage();
+	  return 0;
+	  break;
+	case 'v': ++verbose; break;
+  case 'q': --verbose; break;
+  case 'n':
+	  dns_add_serv(NULL, optarg);
+	  break;
+  case 't':
+#if 0
+    for (i = 0; qtypes[i].name; ++i)
+      if (strcmp(qtypes[i].name, optarg) == 0)
+        break;
+    if (!qtypes[i].name) {
+      fprintf(stderr, "%s: unrecognized query type %s\n", progname, optarg);
+      return 1;
+    }
+    qt = &qtypes[i];
+#else
+    i = dns_findtypename(optarg);
+    if (!i) {
+      fprintf(stderr, "%s: unrecognized query type %s\n", progname, optarg);
+      return 1;
+    }
+    qtp.qtyp = i;
+    qtp.name = optarg;
+    qt = &qtp;
+#endif
+    break;
+  case 'c':
+    if (strcmp(optarg, "in") == 0) qcls = DNS_C_IN;
+    else if (strcmp(optarg, "ch") == 0) qcls = DNS_C_CH;
+    else if (strcmp(optarg, "hs") == 0) qcls = DNS_C_HS;
+    else if (strcmp(optarg, "any") == 0) qcls = DNS_C_ANY;
+    else if (strcmp(optarg, "*") == 0) qcls = DNS_C_ANY;
+    else {
+      fprintf(stderr, "%s: unrecognized class type %s\n", progname, optarg);
+      return 1;
+    }
+    break;
+  default: return 1;
+  }
+
+  argc -= optind; argv += optind;
+  if(!argc)
+  {
+	  fprintf(stderr, "%s: argument (domain name) missing\n", progname);
+	  print_usage();
+	  return 1;
+  }
+
+  fd = dns_open(NULL);
+  if (fd < 0) {
+    fprintf(stderr, "%s: unable to initialize dns library: %m\n", progname);
+    return 1;
+  }
+  now = NULL;//time(NULL);
+  if (!qt) qt = qtypes;
+  for(i = 0; i < argc; ++i) {
+    if (!dns_submit_p(0, argv[i], qcls, qt->qtyp, 0, 0, dnscb, argv[i], now))
+      dnserror(argv[i], dns_status(0));
+	else
+		fprintf(stdout, "Started request for '%s'\n", argv[i]);
+  }
+
+  FD_ZERO(&fds);
+  while((i = dns_timeouts(0, -1, now)) > 0) {
+    FD_SET(fd, &fds);
+    tv.tv_sec = i;
+    tv.tv_usec = 0;
+    i = select(fd+1, &fds, 0, 0, &tv);
+    now = NULL;//time(NULL);
+    if (i > 0) dns_ioevent(0, now);
+  }
+
+  return errors ? 1 : notfound ? 100 : 0;
+}

Added: branches/ppcgui/ex-libs/udns-arm/rblcheck.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/rblcheck.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/rblcheck.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,282 @@
+/* $Id: rblcheck.c,v 1.4 2004/07/09 01:16:13 mjt Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include "udns.h"
+
+#ifdef WIN32
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+static const char *version = "udns-rblcheck 0.1";
+static char *progname;
+
+struct rblookup {
+  struct ipcheck *parent;
+  struct in_addr key;
+  const char *zone;
+  struct dns_rr_a4  *addr;
+  struct dns_rr_txt *txt;
+};
+
+struct ipcheck {
+  const char *name;
+  int naddr;
+  int listed;
+  struct rblookup *lookup;
+};
+
+#define notlisted ((void*)1)
+
+static int nzones, nzalloc;
+static const char **zones;
+
+static int do_txt;
+static int stopfirst;
+static int verbose = 1;
+/* verbosity level:
+ * <0 - only bare As/TXTs
+ * 0 - what RBL result
+ * 1(default) - what is listed by RBL: result
+ * 2          - what is[not ]listed by RBL: result, name lookups
+ */
+
+static int listed;
+static int failures;
+
+static time_t now;
+
+static void *ecalloc(int size, int cnt) {
+  void *t = calloc(size, cnt);
+  if (!t) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+  return t;
+}
+
+static void addzone(const char *zone) {
+  if (nzones >= nzalloc) {
+    const char **zs = (const char**)ecalloc(sizeof(char*), (nzalloc += 16));
+    if (zones) {
+      memcpy(zs, zones, nzones * sizeof(char*));
+      free(zones);
+    }
+    zones = zs;
+  }
+  zones[nzones++] = zone;
+}
+
+static void dnserror(struct rblookup *ipl, const char *what) {
+  fprintf(stderr, "%s: unable to %s for %s (%s): %s\n",
+          progname, what, inet_ntoa(ipl->key), ipl->zone,
+          dns_strerror(dns_status(0)));
+  ++failures;
+}
+
+static void display_result(struct ipcheck *ipc) {
+  int j;
+  struct rblookup *l, *le;
+  if (!ipc->naddr) return;
+  for (l = ipc->lookup, le = l + nzones * ipc->naddr; l < le; ++l) {
+    if (!l->addr) continue;
+    if (verbose < 2 && l->addr == notlisted) continue;
+    if (verbose >= 0) {
+      if (ipc->name) printf("%s[%s]", ipc->name, inet_ntoa(l->key));
+      else printf("%s", inet_ntoa(l->key));
+    }
+    if (l->addr == notlisted) {
+      printf(" is NOT listed by %s\n", l->zone);
+      continue;
+    }
+    else if (verbose >= 1)
+      printf(" is listed by %s: ", l->zone);
+    else if (verbose >= 0)
+      printf(" %s ", l->zone);
+    if (verbose >= 1 || !do_txt)
+      for (j = 0; j < l->addr->dnsa4_nrr; ++j)
+        printf("%s%s", j ? " " : "", inet_ntoa(l->addr->dnsa4_addr[j]));
+    if (!do_txt) ;
+    else if (l->txt) {
+      for(j = 0; j < l->txt->dnstxt_nrr; ++j) {
+        unsigned char *t = l->txt->dnstxt_txt[j].txt;
+        unsigned char *e = t + l->txt->dnstxt_txt[j].len;
+        printf("%s\"", verbose > 0 ? "\n\t" : j ? " " : "");
+        while(t < e) {
+          if (*t < ' ' || *t >= 127) printf("\\x%02x", *t);
+          else if (*t == '\\' || *t == '"') printf("\\%c", *t);
+          else putchar(*t);
+          ++t;
+        }
+        putchar('"');
+      }
+      free(l->txt);
+    }
+    else
+      printf("%s<no text available>", verbose > 0 ? "\n\t" : "");
+    free(l->addr);
+    putchar('\n');
+  }
+  free(ipc->lookup);
+}
+
+static void txtcb(struct dns_ctx *ctx, struct dns_rr_txt *r, void *data) {
+  struct rblookup *ipl = data;
+  if (r) {
+    ipl->txt = r;
+    ++ipl->parent->listed;
+  }
+  else if (dns_status(ctx) != DNS_E_NXDOMAIN)
+    dnserror(ipl, "lookup DNSBL TXT record");
+}
+
+static void a4cb(struct dns_ctx *ctx, struct dns_rr_a4 *r, void *data) {
+  struct rblookup *ipl = data;
+  if (r) {
+    ipl->addr = r;
+    ++listed;
+    if (do_txt) {
+      if (dns_submit_a4dnsbl_txt(0, &ipl->key, ipl->zone, txtcb, ipl, now))
+        return;
+      dnserror(ipl, "submit DNSBL TXT record");
+    }
+    ++ipl->parent->listed;
+  }
+  else if (dns_status(ctx) != DNS_E_NXDOMAIN)
+    dnserror(ipl, "lookup DNSBL A record");
+  else
+    ipl->addr = notlisted;
+}
+
+static int
+submit_a_queries(struct ipcheck *ipc,
+                 int naddr, const struct in_addr *addr) {
+  int z, a;
+  struct rblookup *rl = ecalloc(sizeof(*rl), nzones * naddr);
+  ipc->lookup = rl;
+  ipc->naddr = naddr;
+  for(a = 0; a < naddr; ++a) {
+    for(z = 0; z < nzones; ++z) {
+      rl->key = addr[a];
+      rl->zone = zones[z];
+      rl->parent = ipc;
+      if (!dns_submit_a4dnsbl(0, &rl->key, rl->zone, a4cb, rl, now))
+        dnserror(rl, "submit DNSBL A query");
+      ++rl;
+    }
+  }
+  return 0;
+}
+
+static void namecb(struct dns_ctx *ctx, struct dns_rr_a4 *rr, void *data) {
+  struct ipcheck *ipc = data;
+  if (rr) {
+    submit_a_queries(ipc, rr->dnsa4_nrr, rr->dnsa4_addr);
+    free(rr);
+  }
+  else
+    fprintf(stderr, "%s: unable to lookup %s: %s\n",
+            progname, ipc->name, dns_strerror(dns_status(ctx)));
+}
+
+static int submit(struct ipcheck *ipc) {
+  struct in_addr addr;
+  if (inet_aton(ipc->name, &addr)) {
+    submit_a_queries(ipc, 1, &addr);
+    ipc->name = NULL;
+  }
+  else if (!dns_submit_a4(0, ipc->name, 0, namecb, ipc, now))
+    fprintf(stderr, "%s: unable to submit name query for %s: %s\n",
+            progname, ipc->name, dns_strerror(dns_status(0)));
+  return 0;
+}
+
+static void waitdns(struct ipcheck *ipc) {
+  struct timeval tv;
+  fd_set fds;
+  int c;
+  int fd = dns_sock(NULL);
+  FD_ZERO(&fds);
+  while((c = dns_timeouts(NULL, -1, now)) > 0) {
+    FD_SET(fd, &fds);
+    tv.tv_sec = c;
+    tv.tv_usec = 0;
+    c = select(fd+1, &fds, NULL, NULL, &tv);
+    now = time(NULL);
+    if (c > 0)
+      dns_ioevent(NULL, now);
+    if (stopfirst && ipc->listed)
+      break;
+  }
+}
+
+int main(int argc, char **argv) {
+  int c;
+  struct ipcheck ipc;
+  char *nameserver = NULL;
+
+  if (!(progname = strrchr(argv[0], '/'))) progname = argv[0];
+  else argv[0] = ++progname;
+
+  while((c = getopt(argc, argv, "hqtvms:cn:")) != EOF) switch(c) {
+  case 's': addzone(optarg); break;
+  case 'c': nzones = 0; break;
+  case 'q': --verbose; break;
+  case 'v': ++verbose; break;
+  case 't': do_txt = 1; break;
+  case 'n': nameserver = optarg; break;
+  case 'm': ++stopfirst; break;
+  case 'h':
+    printf("%s: %s.\n", progname, version);
+    printf("Usage is: %s [options] address..\n", progname);
+    printf(
+"Where options are:\n"
+" -h - print this help and exit\n"
+" -s service - add the service (DNSBL zone) to the serice list\n"
+" -c - clear service list\n"
+" -v - increase verbosity level (more -vs => more verbose)\n"
+" -q - decrease verbosity level (opposite of -v)\n"
+" -t - obtain and print TXT records if any\n"
+" -m - stop checking after first address match in any list\n"
+    );
+    return 0;
+  default:
+    fprintf(stderr, "%s: use `%s -h' for help\n", progname, progname);
+    return 1;
+  }
+
+  if (!nzones) {
+    fprintf(stderr, "%s: no service (zone) list specified (-s option)\n",
+            progname);
+    return 1;
+  }
+
+  if (dns_init(1) < 0) {
+    fprintf(stderr, "%s: unable to initialize DNS library: %s\n",
+            progname, strerror(errno));
+    return 1;
+  }
+
+  argv += optind;
+  argc -= optind;
+
+  now = time(NULL);
+  for (c = 0; c < argc; ++c) {
+    if (c && (verbose > 1 || (verbose == 1 && do_txt))) putchar('\n');
+    ipc.name = argv[c];
+    submit(&ipc);
+    waitdns(&ipc);
+    display_result(&ipc);
+    if (stopfirst > 1 && listed) break;
+  }
+
+  return listed ? 100 : failures ? 2 : 0;
+}

Added: branches/ppcgui/ex-libs/udns-arm/readme1st.txt
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/readme1st.txt	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/readme1st.txt	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,11 @@
+Before building the dnsget executable, make sure to include the udns.lib file located in the /build folder:
+From Tools -> Options: 
+	Select Platform: Pocket PC (ARMV4)
+	Show Directories for: library files
+	Then add the complete path to the udns.lib file.
+You should now be able to compile (F6).
+
+
+---
+28-Nov-2006
+Athanasios Karapantelakis (athkar at kth.se)
\ No newline at end of file

Added: branches/ppcgui/ex-libs/udns-arm/udns.3
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns.3	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns.3	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,1147 @@
+.\" $Id: udns.3,v 1.14 2004/07/02 21:52:04 mjt Exp $
+.\" udns library manpage
+.\"
+.TH udns 3 "Jun 2004" "Library Functions"
+
+.SH NAME
+udns \- stub DNS resolver library
+
+.SH SYNOPSYS
+.nf
+#include <udns.h>
+struct \fBdns_ctx\fR;
+struct \fBdns_query\fR;
+extern struct dns_ctx \fBdns_defctx\fR;
+struct dns_ctx *\fIctx\fR;
+typedef void \fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR);
+typedef int
+\fBdns_parse_fn\fR(const unsigned char *\fIpkt\fR, const unsigned char \fIpkte\fR,
+       void **\fIresultp\fR);
+
+\fBcc\fR ... -l\fBudns\fR
+.fi
+
+.SH DESCRIPTION
+
+.PP
+The DNS library, \fBudns\fR, implements thread\-safe stub DNS resolver
+functionality, which may be used both traditional, syncronous way
+and asyncronously, with application\-supplied event loop.
+
+.PP
+While DNS works with both TCP and UDP, performing UDP query first and
+if the result does not fit in UDP buffer (512 bytes max for original
+DNS protocol), retrying the query over TCP, the library uses UDP only,
+but uses EDNS0 (RFCxxx) extensions which allows larger UDP buffers.
+
+.PP
+The library uses single UDP socket to perform all operations even when
+asking multiple nameservers.  This way, it is very simple to use the
+library in asyncronous event\-loop applications: an application should
+add only single socket to the set of filedescriptors it monitors for I/O.
+
+.PP
+The library uses two main objects, \fIresolver context\fR of type
+\fBstruct\ dns_ctx\fR, and \fIquery structure\fR of type
+\fBstruct\ dns_query\fR, both are opaque for an application.
+Resolver context holds global information about the resolver,
+such as list of nameservers to use, list of active requests and the like.
+Query objects holds information about a single DNS query in progress and
+are allocated/processed/freed by the library.   Pointer to query structure
+may be treated as an identifier of an in\-progress query and may be used
+to cancel the asyncronous query or to wait for it to complete.
+
+.PP
+Asyncronous interface works as follows.  An application initializes
+resolver context, submits any number of queries for it using one of
+supplied \fBdns_submit_\fIXXX\fR() routines (each return the query
+identifier as pointer to query structure), waits for input on the
+UDP socket used by the library, and gives some control to the library
+by calling \fBdns_ioevent\fR() and \fBdns_timeouts\fR() routines when
+appropriate.  The library performs all necessary processing and executes
+application supplied callback routine when a query completes (either
+successefully or not), giving it the result if any, pointer to the
+resolver context (from which completion status may be obtained), and
+the data pointer supplied by an application when the query has been
+submitted.  When submitting a query, an application requests how to
+handle the reply \-\- to either return raw DNS reply packet for its
+own low\-level processing, or it may provide an address of \fIparsing
+routine\fR of type \fBdns_parse_fn\fR to perform conversion of on\-wire
+format into easy to use data structure (the library provides parsing
+routines for several commonly used resource record types, as well as
+type\-safe higher\-level inteface that requests parsing automatically).
+The I/O monitoring and timeout handling may be either traditional
+select() or poll() based, or any callback\-driven technique may be
+used.
+
+.PP
+Additionally, the library provides traditional syncronous interface,
+which may be intermixed with asyncronous calls (during syncronous
+query processing, other asyncronous queries for the same resolver
+context continued to be processed as usual).  An application uses
+one of numerous \fBdns_resolve_\fIXXX\fR() routines provided by the
+library to perform a query.  As with asyncronous interface, an
+application may either request to return raw DNS packet or type\-specific
+data structure by providing the parsing routine to handle the reply.
+Every routine from \fBdns_resolve_\fIXXX\fR() series return pointer
+to result or NULL in case of any error.  Query completion status
+(or length of the raw DNS packet) is available from the resolver
+context using \fBdns_status\fR() routine, the same way as for the
+asyncronous interface.
+
+.PP
+Internally, library uses on\-wire format of domain names, referred
+to as \fIDN format\fR in this manual page.  This is a series of domain
+\fIlabels\fR whith preceeding length byte, terminated by zero\-length
+label wich is integral part of the DN format.  There are several routines
+provided to convert from traditional asciiz string to DN and back.
+Higher\-level type\-specific query interface hides the DN format from
+an application.
+
+.SH "COMMON DEFINITIONS"
+
+.PP
+Every DNS Resource Record (RR) has a \fItype\fR and a \fIclass\fR.
+The library defines several integer constants, \fBDNS_C_\fIXXX\fR and
+\fBDNS_T_\fIXXX\fR, to use as symbolic names for RR classes and types,
+such as \fBDNS_C_IN\fR for Internet class, \fBDNS_T_A\fR for IPv4
+address record type and so on.  See udns.h header file for complete list
+of all such constants.
+
+.PP
+The following constants are defined in dns.h header file:
+.IP "\fBDNS_MAXDN\fR (255 bytes)"
+Maximum length of the domain name in internal (on\-wire) DN format.
+.IP "\fBDNS_MAXLABEL\fR (63 bytes)"
+Maximum length of a single label in DN format.
+.IP "\fBDNS_MAXNAME\fR (1024 bytes)"
+Maximum length of asciiz format of a domain name.
+.IP "\fBDNS_HSIZE\fR (12 bytes)"
+Size of header in DNS packet.
+.IP "\fBDNS_PORT\fR (53)"
+Default port to use when contacting a DNS server.
+.IP "\fBDNS_MAXSERV\fR (6 servers)"
+Maximum number of DNS servers to use.
+.IP "\fBDNS_MAXSRCH\fR (5 search list entries)"
+Maximum number of domain search list
+.IP "\fBDNS_MAXPACKET\fR (512 bytes)"
+Maximum length of DNS UDP packet as specified by original DNS protocol
+.IP "\fBDNS_EDNS0PACKET\fR (4096 bytes)"
+Default length of DNS UDP packet (with EDNS0 extensions) the library uses.
+Note that recursive nameservers usually resides near the client asking them
+to resolve names, e.g. on the same LAN segment or even on the same host, so
+UDP packet fragmentation isn't a problem in most cases.  Note also that
+the size of actual packets will be as many bytes as actual reply size requires,
+which is smaller than this value in almost all cases.
+
+.PP
+Additionally, several constants are defined to simplify work with raw DNS
+packets, such as DNS response codes (\fBDNS_R_\fIXXX\fR), DNS header layout
+(\fBDNS_H_\fIXXX\fR) and others.  Again, see udns.h for complete list.
+Library error codes (\fBDNS_E_\fIXXX\fR) are described later in this
+manual page.
+
+.SH "RESOLVER CONTEXT"
+
+.PP
+Resolver context, of type \fBstruct\ dns_ctx\fR, is an object which is
+opaque to an application.  Several routines provided by the library
+to initialize, copy and free resolver contexts.  Most other high\-level
+routines in this library expects a pointer to resolver context, \fIctx\fR,
+as the first argument.  There is a default resolver context available,
+named \fBdns_defctx\fR.  When the context pointer \fIctx\fR passed to
+a routine is NULL, \fBdns_defctx\fR is used.  Several resolver contexts
+may be active at the same time, for example, when an application is
+multi\-threaded and each thread uses resolver.
+.PP
+When initializing resolver context, the library uses information from
+system file /etc/resolv.conf (see \fBresolv.conf\fR(5)), consults
+environment variables \fB$LOCALDOMAIN\fR, \fB$DNSCACHEIP\fR,
+\fB$NAMESERVERS\fR and \fB$RES_OPTIONS\fR, and local host name to obtain
+list of local nameservers, domain name search list and various resolver
+options.
+.PP
+The following routines to initialize resolver context are available:
+.PP
+.nf
+int \fBdns_init\fR(int \fIdo_open\fR)
+struct dns_ctx *\fBdns_new\fR(struct dns_ctx *\fIcopy\fR)
+void \fBdns_free\fR(\fIctx\fR)
+.fi
+.RS
+\fBdns_init\fR() initializes default resolver context, \fBdns_defctx\fR,
+and optionally opens it (if \fIdo_open\fR is true) using \fBdns_open\fR(),
+returning negative value on error.
+\fBdns_new\fR() makes a copy of a given resolver context \fIcopy\fR, or
+default context if \fIcopy\fR is NULL, and returns pointer to it.
+\fBdns_new\fR() may fail if there's no memory available to make a copy
+of \fIcopy\fR, in which case the routine will return NULL pointer.
+\fBdns_free\fR() is used to close assotiated socket and free resolver
+context resources and cancelling (abandoming) all active queries
+assotiated with it.  It's ok to free \fBdns_defctx\fR as well as
+dynamically allocated contexts returned by \fBdns_new\fR().
+.RE
+.PP
+.nf
+int \fBdns_set_serv\fR(\fIctx\fR, const char *\fIserv\fR[])
+int \fBdns_set_srch\fR(\fIctx\fR, const char *\fIsrch\fR[])
+.fi
+.RS
+Set the list of nameservers (\fBdns_set_serv\fR()) and search list
+(\fBdns_set_srch\fR()) for the given context \fIctx\fR.  Both
+\fIsrv\fR and \fIsrch\fR is an argv\-style list of strings, holding
+IP addresses of nameservers to use and domain names in search list.
+Current values in \fIctx\fR are replaced with the given ones.  It is
+an error to call either of this functions if there's at least one
+query is queued for \fIctx\fR.
+.RE
+.PP
+.nf
+int \fBdns_set_opts\fR(\fIctx\fR, const char *\fIopts\fR)
+.fi
+.RS
+set resolver context options from \fIopts\fR string, in the same way as
+processing \fBoptions\fR statement in resolv.conf and \fB$RES_OPTIONS\fR
+environment variable.
+.RE
+.PP
+.nf
+void \fBdns_set_opt\fR(\fIctx\fR, int \fIopt\fR, \fIval\fR)
+.fi
+.RS
+.B TODO
+The \fIflags\fR argument is a bitmask with the following bits defined:
+.IP \fBDNS_NOSRCH\fR
+do not perform domain name search in search list.
+.IP \fBDNS_NORD\fR
+do not request recursion when performing queries
+(i.e. don't set RD flag in querues).
+.IP \fBDNS_AAONLY\fR
+request authoritative answers only (i.e. set AA
+flag in queries).
+.RE
+
+.PP
+.nf
+int \fBdns_open\fR(\fIctx\fR)
+int \fBdns_sock\fR(const \fIctx\fR)
+void \fBdns_close\fR(\fIctx\fR)
+.fi
+.RS
+\fBdns_open\fR() opens the UDP socket used for queries if not already
+open, and return assotiated filedescriptor (or negative value in case
+of error).
+\fBdns_sock\fR() return the UDP socket if open, or -1 if not.
+\fBdns_close\fR() closes the UDP socket if it was open.
+.RE
+
+.PP
+.nf
+int \fBdns_active\fR(const \fIctx\fR)
+.fi
+.RS
+return true if there's at least one query queued for the given context
+\fIctx\fR.
+.RE
+
+.PP
+.nf
+int \fBdns_status\fR(const \fIctx\fR)
+.fi
+.RS
+return status code from last operation.  When using syncronous
+interface, this is the query completion status of the last query.
+With asyncronous interface, from within the callback routine,
+this is the query completion status of the query for which the
+callback is being called.  When query submission fails, this
+is the error code indicating failure reason.  All error codes
+are negative and are represented by \fBDNS_E_\fIXXX\fR constants
+described below.
+.RE
+
+.PP
+.nf
+void \fBdns_ioevent\fR(\fIctx\fR, time_t \fInow\fR)
+.fi
+.RS
+this routine may be called by an application to process I/O
+events on the UDP socket used by the library, as returned
+by \fBdns_sock\fR().  The routine tries to receive incoming
+UDP datagram from the socket and process it.  The socket is
+set up to be non\-blocking, so it is safe to call the routine
+even if there's no data to read.  The routine will process
+as many datagrams as are queued for the socket, so it is
+safe to use it with either level\-triggered or edge\-triggered
+I/O monitoring model.  The \fInow\fR argument is either a
+current time as returned by \fBtime\fR(), or 0, in which
+case the routine will obtain current time by it's own.
+.RE
+
+.PP
+.nf
+int \fBdns_timeouts\fR(\fIctx\fR, int \fImaxwait\fR, time_t \fInow\fR)
+.fi
+.RS
+process any pending timeouts and return number of secounds
+from current time (\fInow\fR if it is not 0) to the time when
+the library wants the application to pass it control to process
+more queued requests.  In case when there are no requests pending,
+this time is -1.  The routine will not request a time larger than
+\fImaxwait\fR secounds if it is greather or equal to zero.  If
+\fInow\fR is 0, the routine will obtain current time by it's own;
+when it is not 0, it should contain current time as returned by
+\fBtime\fR().
+.RE
+
+.PP
+.nf
+typedef int \fBdns_utm_fn\fR(void *\fIarg\fR, struct dns_query *\fIq\fR, int \fItimeout\fR)
+void \fBdns_set_cbck\fR(\fIctx\fR, dns_utm_fn *\fIutmfn\fR, void *\fIarg\fR)
+.fi
+.RS
+An application may use custom callback\-based I/O multiplexing mechanism.
+Usually such a mechanism have concept of a \fItimer\fR, and an ability
+to register a timer event in a form of a callback routine which will
+be executed after certain amount of time.  In order to use such an
+event mechanism, udns provides an ability to register and de\-register
+timer events necessary for internal processing using whatever event
+mechanism an application uses.  For this to work, it is possible to
+assotiate a pointer to a routine that will perform necessary work for
+(de)registering timer events with a given resolver context, and
+udns will call that routine at appropriate times.  Prototype of
+such a routine is shown by \fBdns_utm_fn\fR typedef above.  Libudns
+assotiates timers with queue structure only, and there may be only
+one active timer for any given queue structure.  To register timer
+event, udns will call the routine giving it the query structure
+in question and non\-zero \fItimeout\fR argument.  When a timer is
+not needed anymore, udns de\-registers it by calling the same
+routine with zero \fItimeout\fR.  When a timer expires, an application
+should de\-register timer event and call \fBdns_tmevent\fR() routine
+with the query structure as an argument.
+Other, non\-callback timer usage is provided too, see below.
+.RE
+
+.PP
+.nf
+void \fBdns_tmevent\fR(struct dns_query *\fIq\fR, time_t \fInow\fR);
+.fi
+.RS
+routine which should be called from event\-driven application
+event loop when a timer set using routine set up by
+\fBdns_set_cbck\fR() expires.
+.RE
+
+.PP
+.B XXXX TODO: some more resolver context routines, like dns_set_dbgfn() etc.
+
+.SH "QUERY INTERFACE"
+
+.PP
+There are two ways to perform DNS queries: traditional syncronous
+way, when udns performs all the necessary processing and return
+control to the application only when the query completes, and
+asyncronous way, when an application submits one or more queries
+to the library using given resolver context, and waits for completion
+by monitoring filedescriptor used by library and calling library
+routines to process input on that filedescriptor.  Asyncronous mode
+works with callback routines: an application supplies an address of
+a routine to execute when the query completes, and a data pointer,
+which is passed to the callback routine.
+
+.PP
+Queries are submitted to the library in a form of \fBstruct\ dns_query\fR.
+To perform asyncronous query, an application allocates memory for the
+\fIquery structure\fR and passes it to the library using \fBdns_submit\fR()
+routines, together with all the query parameters.  When the query completes,
+library will call application\-supplied callback routine, giving it the
+resolver context (wich holds query completion status), dynamically allocated
+result (which will be either raw DNS packet or, if applicatin requested parsing
+the result by specifying non-NULL parse routine, ready\-to\-use type\-specific
+structure), and a data pointer provided by an application when it submitted the
+query.  It is the application who's responsible for freeing the result memory.
+.PP
+Generic query callback routine looks like this:
+.nf
+typedef void
+\fBdns_query_fn\fR(\fIctx\fR, void *\fIresult\fR, void *\fIdata\fR)
+.fi
+Type\-specific query interface expects similar form of callback
+routine with the only difference in type of \fBresult\fR argument,
+which will be pointer to specific data structure (decoded reply)
+instead of this void pointer to raw DNS packet data.
+
+.PP
+Result parsing routine looks like this:
+.nf
+typedef int
+\fBdns_parse_fn\fR(const unsigned char *\fIpkt\fR, const unsigned char *\fIpkte\fR,
+      void **\fIresultp\fR);
+.fi
+Type\-specific query inteface supplies necessary parsing routines
+automatically.
+
+.PP
+In case of error, query completion status as returned by
+\fBdns_status\fR(\fIctx\fR), will contain one of the following values:
+.IP "positive value"
+length of raw DNS packet if parsing is not requested.
+.IP 0
+the query was successeful and the \fIreply\fR points to type\-specific
+data structure.
+.IP \fBDNS_E_TEMPFAIL\fR
+temporary error, the resolver nameserver was not able to
+process our query or timed out.
+.IP \fBDNS_E_PROTOCOL\fR
+protocol error, a nameserver returned malformed reply.
+.IP \fBDNS_E_NXDOMAIN\fR
+the domain name does not exist.
+.IP \fBDNS_E_NODATA\fR
+there is no data of requested type found.
+.IP \fBDNS_E_NOMEM\fR
+out of memory while processing request.
+.IP \fBDNS_E_BADQUERY\fR
+some aspect of the query (most common is the domain name in question)
+is invalid, and the library can't even start a query.
+
+.PP
+Library provides two series of routines which uses similar interface \-\-
+one for asyncronous queries and another for syncronous queries.  There
+are two general low\-level routines in each series to submit (asyncronous
+interface) and resolve (syncronous interface) queries, as well as several
+type\-specific routines with more easy\-to\-use interfaces.  To submit
+an asyncronous query, use one of \fBdns_submit_\fIXXX\fR() routine, each
+of which accepts query parameters, pointers to callback routine and to
+callback data, and optional current time hint.  Note type\-specific
+\fBdns_submit_\fIXXX\fR() routines expects specific type of the callback
+routine as well, which accepts reply as a pointer to corresponding
+structure, not a void pointer).  Every \fBdns_submit_\fIXXX\fR() routine
+return pointer to internal query structure of type struct\ dns_query,
+used as an identifier for the given query.
+
+.PP
+To resolve a query syncronously, use one of \fBdns_resolve_\fIXXX\fR()
+routines, which accepts the same query parameters (but not the
+callback pointers) as corresponding \fBdns_submit_\fIXXX\fR(), and
+return the query result, which is the same as passed to the callback
+routine in case of asyncronous interface.
+
+.PP
+In either case, the result memory (if the query completed successefully)
+is dynamically allocated and should be freed by an application.  If
+the query failed for any reason, the result will be NULL, and error
+status will be available from \fBdns_status\fR(\fIctx\fR) routine
+as shown above.
+
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_dn\fR(\fIctx\fR,
+     const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR,
+     \fIparse\fR, \fIcbck\fR, \fIdata\fR, \fInow\fR)
+struct dns_query *
+\fBdns_submit_p\fR(\fIctx\fR,
+     const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR,
+     \fIparse\fR, \fIcbck\fR, \fIdata\fR, \fInow\fR)
+   enum dns_class \fIqcls\fR;
+   enum dns_type \fIqtyp\fR;
+   int \fIflags\fR;
+   dns_parse_fn *\fIparse\fR;
+   dns_query_fn *\fIcbck\fR;
+   void *\fIdata\fR;
+   time_t \fInow\fR;
+.fi
+.RS
+submit a query for processing for the given resolver context \fIctx\fR.
+Two routines differs only in 3rd argument, which is domain name in
+DN format (\fIdn\fR) or asciiz string (\fIname\fR).  The query will be
+performed for the given domain name, with type \fIqtyp\fR in class \fIqcls\fR,
+using option bits in \fIflags\fR, using RR parsing routine pointed by
+\fIparse\fR if not-NULL, and upon completion, \fIcbck\fR function will
+be called with the \fIdata\fR argument.  The \fInow\fR argument specifies
+current time as returned by \fBtime\fR() routine, used to minimize number
+of system calls performed by an application; if \fInow\fR is 0, the routine
+will obtain current time by it's own.  In case of successeful query submission,
+the routine return pointer to internal query structure which may be treated
+as an identifier of the query as used by the library, and may be used as an
+argument for \fBdns_cancel\fR() routine.  In case of error, NULL will be
+returned, and context error status (available using \fIdns_status\fR() routine)
+will be set to corresponding error code, which in this case may be
+DNS_E_BADQUERY if the \fIname\fR of \fIdn\fR is invalid, DNS_E_NOMEM if
+there's no memory available to allocate query structure, or DNS_E_TEMPFAIL
+if an internal error occured.
+.RE
+
+.PP
+.nf
+void *\fBdns_resolve_dn\fR(\fIctx\fR,
+     const unsigned char *\fIdn\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR);
+void *\fBdns_resolve_p\fR(\fIctx\fR,
+     const char *\fIname\fR, \fIqcls\fR, \fIqtyp\fR, \fIflags\fR, \fIparse\fR)
+     \fIparse\fR, \fIcbck\fR, \fIdata\fR, \fInow\fR)
+   enum dns_class \fIqcls\fR;
+   enum dns_type \fIqtyp\fR;
+   int \fIflags\fR;
+   dns_parse_fn *\fIparse\fR;  
+.fi
+.RS
+syncronous interface.  The routines perform all the steps necessary to resolve
+the given query and return the result.  If there's no positive result for any
+reason, all the routines return NULL, and set context error status (available 
+using \fBdns_status\fR() routine) to indicate the error code.  If the query
+was successeful, context status code will contain either the length of the
+raw DNS reply packet if \fIparse\fR argument was NULL (in which case the return
+value is pointer to the reply DNS packet), or 0 (in which case the return value
+is the result of \fIparse\fR routine).  If the query successeful (return value
+is not NULL), the memory returned was dynamically allocated by the library
+and should be free()d by application after use.
+.RE
+
+.PP
+.nf
+void *\fBdns_resolve\fR(\fIctx\fR, struct dns_query *\fIq\fR)
+.fi
+.RS
+wait for the given query \fIq\fR, as returned by one of
+\fBdns_submit_\fIXXX\fR() routines, for completion, and
+return the result.  The callback routine will not be called
+for this query.  After completion, the query identifier \fIq\fI
+is not valid. Both \fBdns_resolve_dn\fR() and \fBdns_resolve_p\fR()
+are just wrappers around corresponding submit routines and this
+\fBdns_resolve\fR() routine.
+.RE
+
+.PP
+.nf
+void \fBdns_cancel\fR(\fIctx\fR, struct dns_query *\fIq\fR)
+.fi
+.RS
+cancel an active query \fIq\fR, without calling a callback routine.
+After completion, the query identifier \fIq\fR is not valid.
+.RE
+
+.SH "TYPE\-SPECIFIC QUERIES"
+
+.PP
+In addition to the generic low\-level query interface, the library provides
+a set of routines to perform specific queries in a type\-safe manner, as
+well as parsers for several well\-known resource record types.  The library
+implements high\-level interface for A, AAAA, PTR, MX and TXT records
+and DNSBL and RHSBL functionality.  These routines returns specific types
+as result of a query, instead of raw DNS packets.  The following types
+and routines are available.
+
+.PP
+.nf
+struct \fBdns_rr_null\fR {
+  char *\fBdnsn_qname\fR;     /* original query name */
+  char *\fBdnsn_cname\fR;     /* canonical name */
+  unsigned \fBdnsn_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnsn_nrr\fR;         /* number of records in the set */
+};
+.fi
+.PP
+NULL RR set, used as a base for all other RR type structures.
+Every RR structure as used by the library have four standard
+fields as in struct\ \fBdns_rr_null\fR.
+
+.SS "IN A Queries"
+.PP
+.nf
+struct \fBdns_rr_a4\fR {       /* IN A RRset */
+  char *\fBdnsa4_qname\fR;     /* original query name */
+  char *\fBdnsa4_cname\fR;     /* canonical name */
+  unsigned \fBdnsa4_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnsa4_nrr\fR;         /* number of addresses in the set */
+  struct in_addr \fBdnsa4_addr\fR[]; /* array of addresses */
+};
+typedef void
+  \fBdns_query_a4_fn\fR(\fIctx\fR, struct dns_rr_a4 *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_a4\fB;
+struct dns_query *
+\fBdns_submit_a4\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR,
+   dns_query_a4_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_a4 *
+\fBdns_resolve_a4\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBstruct\ dns_rr_a4\fR structure holds a result of an \fBIN A\fR query,
+which is an array of IPv4 addresses.  Callback routine for IN A queries
+expected to be of type \fBdns_query_a4_fn\fR, which expects pointer to
+struct\ \fBdns_rr_a4\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_a4\fR() is used to convert raw DNS reply packet into
+struct\ \fBdns_rr_a4\fR (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_a4\fR() and
+\fBdns_resolve_a4\fR() are used to perform A IN queries in a type\-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "IN AAAA Queries"
+.PP
+.nf
+struct \fBdns_rr_a6\fR {       /* IN AAAA RRset */
+  char *\fBdnsa6_qname\fR;     /* original query name */
+  char *\fBdnsa6_cname\fR;     /* canonical name */
+  unsigned \fBdnsa6_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnsa6_nrr\fR;         /* number of addresses in the set */
+  struct in6_addr \fBdnsa6_addr\fR[]; /* array of addresses */
+};
+typedef void
+  \fBdns_query_a6_fn\fR(\fIctx\fR, struct dns_rr_a6 *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_a6\fB;
+struct dns_query *
+\fBdns_submit_a6\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR,
+   dns_query_a6_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_a6 *
+\fBdns_resolve_a6\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBstruct\ dns_rr_a6\fR structure holds a result of an \fBIN AAAA\fR query,
+which is an array of IPv6 addresses.  Callback routine for IN AAAA queries
+expected to be of type \fBdns_query_a6_fn\fR, which expects pointer to
+struct\ \fBdns_rr_a6\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_a6\fR() is used to convert raw DNS reply packet into
+struct\ \fBdns_rr_a6\fR (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_a6\fR() and
+\fBdns_resolve_a6\fR() are used to perform AAAA IN queries in a type\-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "IN PTR Queries"
+.PP
+.nf
+struct \fBdns_rr_ptr\fR {       /* IN PTR RRset */
+  char *\fBdnsptr_qname\fR;     /* original query name */
+  char *\fBdnsptr_cname\fR;     /* canonical name */
+  unsigned \fBdnsptr_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnsptr_nrr\fR;         /* number of domain name pointers */
+  char *\fBdnsptr_ptr\fR[];     /* array of domain name pointers */
+};
+typedef void
+  \fBdns_query_ptr_fn\fR(\fIctx\fR, struct dns_rr_ptr *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_ptr\fB;
+struct dns_query *
+\fBdns_submit_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR,
+   dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_ptr *
+\fBdns_resolve_a4ptr\fB(\fIctx\fR, const struct in_addr *\fBaddr\fR);
+struct dns_query *
+\fBdns_submit_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR,
+   dns_query_ptr_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_ptr *
+\fBdns_resolve_a6ptr\fB(\fIctx\fR, const struct in6_addr *\fBaddr\fR);
+.fi
+.PP
+The \fBstruct\ dns_rr_ptr\fR structure holds a result of an IN PTR query, which
+is an array of domain name pointers for a given IPv4 or IPv6 address.
+Callback routine for IN PTR queries expected to be of type
+\fBdns_query_ptr_fn\fR, which expects pointer to struct\ \fBdns_rr_ptr\fR
+structure as query result instead of raw DNS packet.  The \fBdns_parse_ptr\fR()
+is used to convert raw DNS reply packet into struct\ \fBdns_rr_ptr\fR
+(it is used internally and may be used directly too with generic query
+interface).  Routines \fBdns_submit_a4ptr\fR() and \fBdns_resolve_a4ptr\fR()
+are used to perform IN PTR queries for IPv4 addresses in a type\-safe
+manner. Routines \fBdns_submit_a6ptr\fR() and \fBdns_resolve_a6ptr\fR()
+are used to perform IN PTR queries for IPv6 addresses.
+
+.SS "IN MX Queries"
+.PP
+.nf
+struct \fBdns_mx\fR {          /* single MX record */
+  int \fBpriority\fR;          /* priority value of this MX */
+  char *\fBname\fR;            /* domain name of this MX */
+};
+struct \fBdns_rr_mx\fR {       /* IN MX RRset */
+  char *\fBdnsmx_qname\fR;     /* original query name */
+  char *\fBdnsmx_cname\fR;     /* canonical name */
+  unsigned \fBdnsmx_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnsmx_nrr\fR;         /* number of mail exchangers in the set */
+  struct dns_mx \fBdnsmx_mx\fR[]; /* array of mail exchangers */
+};
+typedef void
+  \fBdns_query_mx_fn\fR(\fIctx\fR, struct dns_rr_mx *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_mx\fB;
+struct dns_query *
+\fBdns_submit_mx\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR,
+   dns_query_mx_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_mx *
+\fBdns_resolve_mx\fB(\fIctx\fR, const char \fIname\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBstruct\ dns_rr_mx\fR structure holds a result of an IN MX query, which
+is an array of mail exchangers for a given domain.  Callback routine for IN MX
+queries expected to be of type \fBdns_query_mx_fn\fR, which expects pointer to
+struct\ \fBdns_rr_mx\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_mx\fR() is used to convert raw DNS reply packet into
+struct\ \fBdns_rr_mx\fR (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_mx\fR() and
+\fBdns_resolve_mx\fR() are used to perform IN MX queries in a type\-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).
+
+.SS "TXT Queries"
+.PP
+.nf
+struct \fBdns_txt\fR {          /* single TXT record */
+  int \fBlen\fR;                /* length of the text */
+  unsigned char *\fBtxt\fR;     /* pointer to the text */
+};
+struct \fBdns_rr_txt\fR {       /* TXT RRset */
+  char *\fBdnstxt_qname\fR;     /* original query name */
+  char *\fBdnstxt_cname\fR;     /* canonical name */
+  unsigned \fBdnstxt_ttl\fR;    /* Time\-To\-Live (TTL) value */
+  int \fBdnstxt_nrr\fR;         /* number of text records in the set */
+  struct dns_txt \fBdnstxt_txt\fR[]; /* array of mail exchangers */
+};
+typedef void
+  \fBdns_query_txt_fn\fR(\fIctx\fR, struct dns_rr_txt *\fIresult\fR, \fIdata\fR)
+dns_parse_fn \fBdns_parse_txt\fB;
+struct dns_query *
+\fBdns_submit_txt\fB(\fIctx\fR, const char \fIname\fR, enum dns_class \fIqcls\fR,
+   int \fIflags\fR, dns_query_txt_fn *\fIcbck\fR, \fIdata\fR, \fInow\fR);
+struct dns_rr_txt *
+\fBdns_resolve_txt\fB(\fIctx\fR, const char \fIname\fR,
+             enum dns_class \fIqcls\fR, int \fIflags\fR);
+.fi
+.PP
+The \fBstruct\ dns_rr_txt\fR structure holds a result of an IN MX query, which
+is an array of mail exchangers for a given domain.  Callback routine for IN MX
+queries expected to be of type \fBdns_query_txt_fn\fR, which expects pointer to
+struct\ \fBdns_rr_txt\fR structure as query result instead of raw DNS packet.
+The \fBdns_parse_txt\fR() is used to convert raw DNS reply packet into
+struct\ \fBdns_rr_txt\fR (it is used internally and may be used directly too
+with generic query interface).  Routines \fBdns_submit_txt\fR() and
+\fBdns_resolve_txt\fR() are used to perform IN MX queries in a type\-safe
+manner.  The \fIname\fR parameter is the domain name in question, and
+\fIflags\fR is query flags bitmask, with one bit, DNS_NOSRCH, of practical
+interest (if the \fIname\fR is absolute, that is, it ends up with a dot,
+DNS_NOSRCH flag will be set automatically).  Note that each TXT string
+as represented by \fBstruct\ dns_txt\fR, while zero\-terminated (and the
+len field of the structure does not include the terminator), may contain
+embedded null characters \-\- content of TXT records is not interpreted
+by the library in any way.
+
+.SS "DNSBL Interface"
+.PP
+A DNS\-based blocklists, or a DNSBLs, are in wide use nowadays, especially
+to protect mailservers from spammers.  The library provides DNSBL interface,
+a set of routines to perform queries against DNSBLs.  Routines accepts an
+IP address (IPv4 and IPv6 are both supported) and a base DNSBL zone as
+query parameters, and returns either \fBdns_rr_a4\fR or \fBdns_rr_txt\fR
+structure.  Note that IPv6 interface return IPv4 RRset.
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_a4dnsbl\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_query *
+\fBdns_submit_a4dnsbl_txt\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_query *
+\fBdns_submit_a6dnsbl\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_query *
+\fBdns_submit_a6dnsbl_txt\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_rr_a4 *\fBdns_resolve_a4dnsbl\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_txt *\fBdns_resolve_a4dnsbl_txt\fR(\fIctx\fR,
+  const struct in_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_a4 *\fBdns_resolve_a6dnsbl\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+struct dns_rr_txt *\fBdns_resolve_a6dnsbl_txt\fR(\fIctx\fR,
+  const struct in6_addr *\fIaddr\fR, const char *\fIdnsbl\fR)
+.fi
+Perform (submit or resolve) a DNSBL query for the given \fIdnsbl\fR
+domain and an IP \fIaddr\fR in question, requesting either A or TXT
+records.
+
+.SS "RHSBL Interface"
+.PP
+RHSBL is similar to DNSBL, but instead of an IP address, the
+parameter is a domain name.
+.PP
+.nf
+struct dns_query *
+\fBdns_submit_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR,
+  dns_query_a4_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_query *
+\fBdns_submit_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR,
+  dns_query_txt_fn *\fIcbck\fR, void *\fIdata\fR, time_t \fInow\fR);
+struct dns_rr_a4 *
+\fBdns_resolve_rhsbl\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR);
+struct dns_rr_txt *
+\fBdns_resolve_rhsbl_txt\fR(\fIctx\fR, const char *\fIname\fR, const char *\fIrhsbl\fR);
+.fi
+Perform (submit or resolve) a RHSBL query for the given \fIrhsbl\fR
+domain and \fIname\fR in question, requesting either A or TXT records.
+
+
+.SH "LOW\-LEVEL INTERFACE"
+
+.SS "Domain Names (DNs)"
+
+.PP
+A DN is a series of domain name labels each starts with length byte,
+followed by empty label (label with zero length).  The following
+routines to work with DNs are provided.
+
+.PP
+.nf
+unsigned \fBdns_dnlen\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return length of the domain name \fIdn\fR, including the terminating label.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dnlabels\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return number of non\-zero labels in domain name \fIdn\fR.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dnequal\fR(\fIdn1\fR, \fIdn2\fR)
+  const unsigned char *\fIdn1\fR, *\fIdn2\fR;
+.fi
+.RS
+test whenever the two domain names, \fIdn1\fR and \fIdn2\fR, are
+equal (case\-insensitive).  Return domain name length if equal
+or 0 if not.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dntodn\fR(\fIsdn\fR, \fIddn\fR, \fIdnsiz\fR)
+  const unsigned char *\fIsdn\fR;
+  unsigned char *\fIddn\fR;
+  unsigned \fIdnsiz\fR;
+.fi
+.RS
+copies the source domain name \fIsdn\fR to destination buffer \fIddn\fR
+of size \fIdnsiz\fR.  Return domain name length or 0 if \fIddn\fR is
+too small.
+.RE
+
+.PP
+.nf
+int \fBdns_ptodn\fR(\fIname\fR, \fInamelen\fR, \fIdn\fR, \fIdnsiz\fR, \fIisabs\fR)
+int \fBdns_sptodn\fR(\fIname\fR, \fIdn\fR, \fIdnsiz\fR)
+  const char *\fIname\fR; unsigned \fInamelen\fR;
+  unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR;
+  int *\fIisabs\fR;
+.fi
+.RS
+convert asciiz name \fIname\fR of length \fInamelen\fR to DN format,
+placing result into buffer \fIdn\fR of size \fIdnsiz\fR.  Return
+length of the DN if successeful, 0 if the \fIdn\fR buffer supplied is
+too small, or negative value if \fIname\fR is invalid.  If \fIisabs\fR
+is non\-NULL and conversion was successeful, *\fIisabs\fR will be set to
+either 1 or 0 depending whenever \fIname\fR was absolute (i.e. ending with
+a dot) or not.  Name length, \fInamelength\fR, may be zero, in which case
+strlen(\fIname\fR) will be used.  Second form, \fBdns_sptodn\fR(), is a
+simplified form of \fBdns_ptodn\fR(), equivalent to
+.br
+.nf
+\fBdns_ptodn\fR(\fIname\fR, 0, \fIdn\fR, \fIdnlen\fR, 0).
+.fi
+.RE
+
+.PP
+.nf
+extern const unsigned char \fBdns_inaddr_arpa_dn\fR[]
+int \fBdns_a4todn\fR(const struct in_addr *\fIaddr\fR, const unsigned char *\fItdn\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+int \fBdns_a4ptodn\fR(const struct in_addr *\fIaddr\fR, const char *\fItname\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+extern const unsigned char \fBdns_ip6_arpa_dn\fR[]
+int \fBdns_a6todn\fR(const struct in6_addr *\fIaddr\fR, const unsigned char *\fItdn\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+int \fBdns_a6ptodn\fR(const struct in6_addr *\fIaddr\fR, const char *\fItname\fR,
+      unsigned char *\fIdn\fR, unsigned \fIdnsiz\fR)
+.fi
+.RS
+several variants of routines to convert IPv4 and IPv6 address \fIaddr\fR
+into reverseDNS\-like domain name in DN format, storing result in \fIdn\fR
+of size \fIdnsiz\fR.  \fItdn\fR (or \fItname\fR) is the base zone name,
+like in-addr.arpa for IPv4 or in6.arpa for IPv6.  If \fItdn\fR (or \fItname\fR)
+is NULL, \fBdns_inaddr_arpa_dn\fR (or \fBdns_ip6_arpa_dn\fR) will be used.
+The routines may be used to construct a DN for a DNSBL lookup for example.
+All routines return length of the resulting DN on success, -1 if resulting
+DN is invalid, or 0 if the \fIdn\fR buffer (\fIdnsiz\fR) is too small.
+To hold standard rDNS DN, a buffer of size \fBDNS_A4RSIZE\fR (30 bytes) for
+IPv4 address, or \fBDNS_A6RSIZE\fR (74 bytes) for IPv6 address, is sufficient.
+.RE
+
+.PP
+.nf
+int \fBdns_dntop\fR(\fIdn\fR, \fIname\fR, \fInamesiz\fR)
+   const unsigned char *\fIdn\fR;
+   const char *\fIname\fR; unsigned \fInamesiz\fR;
+.fi
+.RS
+convert domain name \fIdn\fR in DN format to asciiz string, placing result
+into \fIname\fR buffer of size \fInamesiz\fR.  Maximum length of asciiz
+representation of domain name is \fBDNS_MAXNAME\fR (1024) bytes.  Root
+domain is represented as empty string.  Return length of the resulting name
+(including terminating character, i.e. strlen(name)+1) on success, 0 if the
+\fIname\fR buffer is too small, or negative value if \fIdn\fR is invalid
+(last case should never happen since all routines in this library which
+produce domain names ensure the DNs generated are valid).
+.RE
+
+.PP
+.nf
+const char *\fBdns_dntosp\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+convert domain name \fIdn\fR in DN format to asciiz string using static
+buffer.  Return the resulting asciiz string on success or NULL on failure.
+Note since this routine uses static buffer, it is not thread\-safe.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_dntop_size\fR(const unsigned char *\fIdn\fR)
+.fi
+.RS
+return the buffer size needed to convert the \fIdn\fR domain name
+in DN format to asciiz string, for \fBdns_dntop\fR().  The routine
+return either the size of buffer required, including the trailing
+zero byte, or 0 if \fIdn\fR is invalid.
+.RE
+
+.SS "Working with DNS Packets"
+
+.PP
+The following routines are provided to encode and decode DNS on\-wire
+packets.  This is low\-level interface.
+
+.PP
+DNS response codes (returned by \fBdns_rcode\fR() routine) are
+defined as constants prefixed with \fBDNS_R_\fR.  See dns.h
+header file for the complete list.  In particular, constants
+\fBDNS_R_NOERROR\fR (0), \fBDNS_R_SERVFAIL\fR, \fBDNS_R_NXDOMAIN\fR
+may be of interest to an application.
+
+.PP
+.nf
+unsigned \fBdns_get16\fR(const unsigned char *\fIp\fR)
+unsigned \fBdns_get32\fR(const unsigned char *\fIp\fR)
+.fi
+.RS
+helper routines, convert 16\-bit or 32\-bit integer in on\-wire
+format pointed to by \fIp\fR to unsigned.
+.RE
+
+.PP
+.nf
+unsigned char *\fBdns_put16\fR(unsigned char *\fId\fR, unsigned \fIn\fR)
+unsigned char *\fBdns_put32\fR(unsigned char *\fId\fR, unsigned \fIn\fR)
+.fi
+.RS
+helper routine, convert unsigned 16\-bit or 32\-bit integer \fIn\fR to
+on\-wire format to buffer pointed to by \fId\fR, return \fId\fR+2 or
+\fId\fR+4.
+.RE
+
+.PP
+.nf
+\fBDNS_HSIZE\fR (12)
+.fi
+.RS
+defines size of DNS header.  Data section
+in the DNS packet immediately follows the header.  In the header,
+there are query identifier (id), various flags and codes,
+and number of resource records in various data sections.
+See dns.h header file for complete list of DNS header definitions.
+.RE
+
+.PP
+.nf
+unsigned \fBdns_qid\fB(const unsigned char *\fIpkt\fR)
+int \fBdns_rd\fB(const unsigned char *\fIpkt\fR)
+int \fBdns_tc\fB(const unsigned char *\fIpkt\fR)
+int \fBdns_aa\fB(const unsigned char *\fIpkt\fR)
+int \fBdns_qr\fB(const unsigned char *\fIpkt\fR)
+int \fBdns_ra\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_opcode\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_rcode\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numqd\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numan\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numns\fB(const unsigned char *\fIpkt\fR)
+unsigned \fBdns_numar\fB(const unsigned char *\fIpkt\fR)
+const unsigned char *\fBdns_payload\fR(const unsigned char *\fIpkt\fR)
+.fi
+.RS
+return various parts from the DNS packet header \fIpkt\fR:
+query identifier (qid),
+recursion desired (rd) flag,
+truncation occured (tc) flag,
+authoritative answer (aa) flag,
+query response (qr) flag,
+recursion available (ra) flag,
+operation code (opcode),
+result code (rcode),
+number of entries in question section (numqd),
+number of answers (numan),
+number of authority records (numns),
+number of additional records (numar),
+and the pointer to the packet data (payload).
+.RE
+
+.PP
+.nf
+int \fBdns_getdn\fR(\fIpkt\fR, \fIcurp\fR, \fIpkte\fR, \fIdn\fR, \fIdnsiz\fR)
+const unsigned char *\fBdns_skipdn\fR(\fIcur\fR, \fIpkte\fR)
+   const unsigned char *\fIpkt\fR, *\fIpkte\fR, **\fIcurp\fR, *\fIcur\fR;
+   unsigned char *\fIdn\fR; unsigned \fIdnsiz\fR;
+.fi
+.RS
+\fBdns_getdn\fR() extract DN from DNS packet \fIpkt\fR which ends before
+\fIpkte\fR starting at position *\fIcurp\fR into buffer pointed to by
+\fIdn\fR of size \fIdnsiz\fR.  Upon successeful completion, *\fIcurp\fR
+will point to the next byte in the packet after the extracted domain name.
+It return positive number (length of the DN if \fIdn\fR) upon successeful
+completion, negative value on error (when the packet contains invalid data),
+or zero if the \fIdnsiz\fR is too small (maximum length of a domain name is
+\fBDNS_MAXDN\fR).  \fBdns_skipdn\fR() return pointer to the next byte in
+DNS packet which ends up before \fIpkte\fR after a domain name which starts
+at the \fIcur\fP byte, or NULL if the packet is invalid.  \fBdns_skipdn\fR()
+is more or less equivalent to what \fBdns_getdn\fR() does, except it does not
+actually extract the domain name in question, and uses simpler interface.
+.RE
+
+.PP
+.nf
+struct \fBdns_rr\fR {
+  unsigned char \fBdnsrr_dn\fR[DNS_MAXDN]; /* the RR DN name */
+  enum dns_class \fBdnsrr_cls\fR;          /* class of the RR */
+  enum dns_type  \fBdnsrr_typ\fR;          /* type of the RR */
+  unsigned \fBdnsrr_ttl\fR;                /* TTL value */
+  unsigned \fBdnsrr_dsz\fR;                /* size of data in bytes */
+  const unsigned char *\fBdnsrr_dptr\fR;   /* pointer to the first data byte */
+  const unsigned char *\fBdnsrr_dend\fR;   /* next byte after RR */
+};
+.fi
+.RS
+The \fBstruct\ dns_rr\fR structure is used to hold information about
+single DNS Resource Record (RR) in an easy to use form.
+.RE
+
+.PP
+.nf
+struct \fBdns_parse\fR {
+  const unsigned char *\fBdnsp_pkt\fR; /* pointer to the packet being parsed */
+  const unsigned char *\fBdnsp_end\fR; /* end of the packet pointer */
+  const unsigned char *\fBdnsp_cur\fR; /* current packet positionn */
+  int \fBdnsp_rrl\fR;                  /* number of RRs left */
+  int \fBdnsp_nrr\fR;                  /* number of relevant RRs seen so far */
+  unsigned \fBdnsp_ttl\fR;             /* TTL value so far */
+  const unsigned char *\fBdnsp_qdn\fR; /* the domain of interest or NULL */
+  enum dns_class \fBdnsp_qcls\fR;      /* class of interest or 0 for any */
+  enum dns_type  \fBdnsp_qtyp\fR;      /* type of interest or 0 for any */
+  unsigned char \fBdnsp_dnbuf\fR[DNS_MAXDN]; /* domain name buffer */
+};
+.fi
+.RS
+The \fBstruct dns_parse\fR structure is used to parse DNS reply packet.
+It holds information about the packet being parsed (dnsp_pkt, dnsp_end and
+dnsp_cur fields), number of RRs in the current section left to do, and
+the information about specific RR which we're looking for (dnsp_qdn,
+dnsp_qcls and dnsp_qtyp fields).
+.RE
+
+.PP
+.nf
+int \fBdns_initparse\fR(struct dns_parse *\fIp\fR,
+  enum dns_class \fIqcls\fR, enum dns_type \fIqtyp\fR,
+  const unsigned char *\fIpkt\fR, const unsigned char *\fIend\fR)
+.fi
+.RS
+initializes the RR parsing structure \fIp\fR.  The \fIp\fR->\fBdnsp_qdn\fR
+field is initialized to the DN in question section, \fIp\fR->\fBdnsp_rrl\fR
+is set to number of RRs in answer section, \fIp\fR->\fBdnsp_cur\fR is
+set to point to the first RR in answer section, and \fIp\fR->\fBdnsp_ttl\fR
+will be set to max TTL value, 0xffffffff.
+.RE
+
+.PP
+.nf
+int \fBdns_nextrr\fR(struct dns_parse *\fIp\fR, struct dns_rr *\fIrr\fR);
+.fi
+.RS
+searches for next RR in the packet based on the criteria provided in
+the \fIp\fR structure, filling in the \fIrr\fR structure and
+advancing \fIp\fR->\fBdnsp_cur\fR to the next RR in the packet.
+RR selection is based on dnsp_qdn, dnsp_qcls and dnsp_qtyp fields in
+the dns_parse structure.  Any (or all) of the 3 fields may be 0,
+which means any actual value from the packet is acceptable.  In case
+the field isn't 0 (or NULL for dnsp_qdn), only RRs with corresponding
+characteristics are acceptable.  Additionally, when dnsp_qdn is non\-NULL,
+\fBdns_nextrr\fR() performs automatic CNAME expansion.
+Routine will return positive value on success, 0 in case it reached the end
+of current section in the packet (\fIp\fR->\fBdnsp_rrl\fR is zero), or
+negative value if next RR can not be decoded (packet format is invalid).
+The routine updates \fIp\fR->\fBdnsp_qdn\fR automatically when this
+field is non\-NULL and it encounters appropriate CNAME RRs (saving CNAME
+target in \fIp\fR->\fBdnsp_dnbuf\fR), so after end of the process,
+\fIp\fR->\fBdnsp_qdn\fR will point to canonical name of the domain
+in question.  The routine updates \fIp\fR->\fBdnsp_ttl\fR value to
+be the minimum TTL of all RRs found.
+.RE
+
+.PP
+.nf
+void \fBdns_rewind\fR(struct dns_parse *\fIp\fR)
+.fi
+.RS
+this routine "rewinds" the packet parse state structure to be at the
+same state as after a call to \fBdns_initparse\fR(), i.e. reposition
+the parse structure \fIp\fR to the start of answer section and
+initialize \fIp\fR->\fBdnsp_rrl\fR to the number of entries in
+answer section.
+.RE
+
+.PP
+.nf
+int \fBdns_stdrr_size\fR(const struct dns_parse *\fIp\fR);
+.fi
+.RS
+return size to hold standard RRset structure information, as shown
+in \fBstruct\ dns_rr_null\fR structure (for the query and canonical
+names).  Used to calculate amount of memory to allocate for common
+part of type\-specific RR structures in parsing routines.
+.RE
+
+.PP
+.nf
+void *\fBdns_stdrr_finish\fR(struct dns_rr_null *\fIret\fR, char *\fIcp\fR,
+  const struct dns_parse *\fIp\fR);
+.fi
+.RS
+initializes standard RRset fields in \fIret\fR structure using buffer
+pointed to by \fIcp\fR, which should have at least as many bytes
+as \fBdns_stdrr_size\fR(\fIp\fR) returned.  Used to finalize common
+part of type\-specific RR structures in parsing routines.
+.RE
+
+.PP
+See library source for usage examples of all the above low\-level routines,
+especially source of the parsing routines.
+
+.SH AUTHOR
+.PP
+The \fBudns\fR library has been written by Michael Tokarev, mjt at corpit.ru.

Added: branches/ppcgui/ex-libs/udns-arm/udns.h
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns.h	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns.h	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,689 @@
+/* $Id: udns.h,v 1.19 2004/07/09 01:18:00 mjt Exp $
+ * header file for the dns library.
+ */
+
+#ifndef UDNS_VERSION	/* include guard */
+
+#define UDNS_VERSION "0.0.1"
+
+#include <assert.h>
+#ifdef WIN32
+/* NOTE: do not include 'windows.h' before 'winsock2.h'.
+ * It is included by 'winsock2.h' anyway.
+ */
+#include <winsock2.h>
+#include <ws2tcpip.h>	// << Needed for 'struct in6_addr'
+#include <time.h>
+#include "win32/win32.h"
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#ifndef AF_INET6
+struct in6_addr {
+  unsigned char s6_addr[16];
+};
+#endif
+
+/**************************************************************************/
+/**************** Common definitions **************************************/
+#ifdef WIN32
+#define DNS_INLINE	__inline
+
+#if defined(DNS_DYNAMIC_LIBRARY)
+#if defined(DNS_LIBRARY_BUILD)
+// We're building the library
+#define DNS_API	__declspec(dllexport)
+#define DNS_DATA_API __declspec(dllexport)
+#else // !DNS_LIBRARY_BUILD
+// User including header
+#define DNS_API	__declspec(dllimport)
+#define DNS_DATA_API __declspec(dllimport)
+#endif // DNS_LIBRARY_BUILD
+#else // !DNS_DYNAMIC_LIBRARY
+/* By default, we assume that we are used as a static lib.
+ */
+#define DNS_API
+#define DNS_DATA_API extern
+#endif // DNS_DYNAMIC_LIBRARY
+
+int dns_win32_get_nameservers(struct dns_ctx *ctx);
+#define socket_close(sock) closesocket(sock)
+#define snprintf _snprintf
+typedef int socklen_t;
+
+#else // UNIX-like OSes
+
+#define DNS_INLINE	inline
+#define DNS_API
+#define DNS_DATA_API extern
+#define socket_close(sock) close(sock)
+#endif
+
+extern const char *dns_version(void);
+
+struct dns_ctx;
+struct dns_query;
+
+#define DNS_MAXDN	255	/* max DN length */
+#define DNS_MAXLABEL	63	/* max DN label length */
+#define DNS_MAXNAME	1024	/* max asciiz domain name length */
+#define DNS_HSIZE	12	/* DNS packet header size */
+#define DNS_PORT	53	/* default domain port */
+#define DNS_MAXSERV	6	/* max servers to consult */
+#define DNS_MAXSRCH	5	/* max searchlist entries */
+#define DNS_MAXPACKET	512	/* max traditional-DNS UDP packet size */
+#define DNS_EDNS0PACKET	4096	/* EDNS0 packet size to use */
+
+enum dns_class {	/* DNS RR Classes */
+  DNS_C_INVALID	= 0,	/* invalid class */
+  DNS_C_IN	= 1,	/* Internet */
+  DNS_C_CH	= 3,	/* CHAOS */
+  DNS_C_HS	= 4,	/* HESIOD */
+  DNS_C_ANY	= 255	/* wildcard */
+};
+
+enum dns_type {		/* DNS RR Types */
+  DNS_T_INVALID		= 0,	/* Cookie. */
+  DNS_T_A		= 1,	/* Host address. */
+  DNS_T_NS		= 2,	/* Authoritative server. */
+  DNS_T_MD		= 3,	/* Mail destination. */
+  DNS_T_MF		= 4,	/* Mail forwarder. */
+  DNS_T_CNAME		= 5,	/* Canonical name. */
+  DNS_T_SOA		= 6,	/* Start of authority zone. */
+  DNS_T_MB		= 7,	/* Mailbox domain name. */
+  DNS_T_MG		= 8,	/* Mail group member. */
+  DNS_T_MR		= 9,	/* Mail rename name. */
+  DNS_T_NULL		= 10,	/* Null resource record. */
+  DNS_T_WKS		= 11,	/* Well known service. */
+  DNS_T_PTR		= 12,	/* Domain name pointer. */
+  DNS_T_HINFO		= 13,	/* Host information. */
+  DNS_T_MINFO		= 14,	/* Mailbox information. */
+  DNS_T_MX		= 15,	/* Mail routing information. */
+  DNS_T_TXT		= 16,	/* Text strings. */
+  DNS_T_RP		= 17,	/* Responsible person. */
+  DNS_T_AFSDB		= 18,	/* AFS cell database. */
+  DNS_T_X25		= 19,	/* X_25 calling address. */
+  DNS_T_ISDN		= 20,	/* ISDN calling address. */
+  DNS_T_RT		= 21,	/* Router. */
+  DNS_T_NSAP		= 22,	/* NSAP address. */
+  DNS_T_NSAP_PTR	= 23,	/* Reverse NSAP lookup (deprecated). */
+  DNS_T_SIG		= 24,	/* Security signature. */
+  DNS_T_KEY		= 25,	/* Security key. */
+  DNS_T_PX		= 26,	/* X.400 mail mapping. */
+  DNS_T_GPOS		= 27,	/* Geographical position (withdrawn). */
+  DNS_T_AAAA		= 28,	/* Ip6 Address. */
+  DNS_T_LOC		= 29,	/* Location Information. */
+  DNS_T_NXT		= 30,	/* Next domain (security). */
+  DNS_T_EID		= 31,	/* Endpoint identifier. */
+  DNS_T_NIMLOC		= 32,	/* Nimrod Locator. */
+  DNS_T_SRV		= 33,	/* Server Selection. */
+  DNS_T_ATMA		= 34,	/* ATM Address */
+  DNS_T_NAPTR		= 35,	/* Naming Authority PoinTeR */
+  DNS_T_KX		= 36,	/* Key Exchange */
+  DNS_T_CERT		= 37,	/* Certification record */
+  DNS_T_A6		= 38,	/* IPv6 address (deprecates AAAA) */
+  DNS_T_DNAME		= 39,	/* Non-terminal DNAME (for IPv6) */
+  DNS_T_SINK		= 40,	/* Kitchen sink (experimentatl) */
+  DNS_T_OPT		= 41,	/* EDNS0 option (meta-RR) */
+  DNS_T_TSIG		= 250,	/* Transaction signature. */
+  DNS_T_IXFR		= 251,	/* Incremental zone transfer. */
+  DNS_T_AXFR		= 252,	/* Transfer zone of authority. */
+  DNS_T_MAILB		= 253,	/* Transfer mailbox records. */
+  DNS_T_MAILA		= 254,	/* Transfer mail agent records. */
+  DNS_T_ANY		= 255,	/* Wildcard match. */
+  DNS_T_ZXFR		= 256,	/* BIND-specific, nonstandard. */
+  DNS_T_MAX		= 65536
+};
+
+/**************************************************************************/
+/**************** Domain Names (DNs) **************************************/
+
+/* return length of the DN */
+DNS_API unsigned dns_dnlen(const unsigned char *dn);
+
+/* return #of labels in a DN */
+DNS_API unsigned dns_dnlabels(const unsigned char *dn);
+
+/* lower- and uppercase single DN char */
+#define DNS_DNLC(c) ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 'a' : (c))
+#define DNS_DNUC(c) ((c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 'A' : (c))
+
+/* compare the DNs, return dnlen of equal or 0 if not */
+DNS_API unsigned dns_dnequal(const unsigned char *dn1, const unsigned char *dn2);
+
+/* copy one DN to another, size checking */
+DNS_API unsigned
+dns_dntodn(const unsigned char *sdn, unsigned char *ddn, unsigned ddnsiz);
+
+/* convert asciiz string of length namelen (0 to use strlen) to DN */
+DNS_API int
+dns_ptodn(const char *name, unsigned namelen,
+          unsigned char *dn, unsigned dnsiz,
+          int *isabs);
+
+/* simpler form of dns_ptodn() */
+#define dns_sptodn(name,dn,dnsiz) dns_ptodn((name),0,(dn),(dnsiz),0)
+
+extern const unsigned char dns_inaddr_arpa_dn[14];
+#define DNS_A4RSIZE	30
+DNS_API int dns_a4todn(const struct in_addr *addr, const unsigned char *tdn,
+               unsigned char *dn, unsigned dnsiz);
+DNS_API int dns_a4ptodn(const struct in_addr *addr, const char *tname,
+                unsigned char *dn, unsigned dnsiz);
+DNS_API unsigned char *
+dns_a4todn_(const struct in_addr *addr, unsigned char *dn, unsigned char *dne);
+
+extern const unsigned char dns_ip6_arpa_dn[10];
+#define DNS_A6RSIZE	74
+DNS_API int dns_a6todn(const struct in6_addr *addr, const unsigned char *tdn,
+               unsigned char *dn, unsigned dnsiz);
+DNS_API int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
+               unsigned char *dn, unsigned dnsiz);
+DNS_API unsigned char *
+dns_a6todn_(const struct in6_addr *addr, unsigned char *dn, unsigned char *dne);
+
+/* convert DN into asciiz string */
+DNS_API int dns_dntop(const unsigned char *dn, char *name, unsigned namesiz);
+
+/* convert DN into asciiz string, using static buffer (NOT thread-safe!) */
+DNS_API const char *dns_dntosp(const unsigned char *dn);
+
+/* return buffer size (incl. null byte) required for asciiz form of a DN */
+DNS_API unsigned dns_dntop_size(const unsigned char *dn);
+
+/**************************************************************************/
+/**************** DNS raw packet layout ***********************************/
+
+enum dns_rcode {	/* reply codes */
+  DNS_R_NOERROR		= 0,	/* ok, no error */
+  DNS_R_FORMERR		= 1,	/* format error */
+  DNS_R_SERVFAIL	= 2,	/* server failed */
+  DNS_R_NXDOMAIN	= 3,	/* domain does not exists */
+  DNS_R_NOTIMPL		= 4,	/* not implemented */
+  DNS_R_REFUSED		= 5,	/* query refused */
+  /* these are for BIND_UPDATE */
+  DNS_R_YXDOMAIN	= 6,	/* Name exists */
+  DNS_R_YXRRSET		= 7,	/* RRset exists */
+  DNS_R_NXRRSET		= 8,	/* RRset does not exist */
+  DNS_R_NOTAUTH		= 9,	/* Not authoritative for zone */
+  DNS_R_NOTZONE		= 10,	/* Zone of record different from zone section */
+  /*ns_r_max = 11,*/
+  /* The following are TSIG extended errors */
+  DNS_R_BADSIG		= 16,
+  DNS_R_BADKEY		= 17,
+  DNS_R_BADTIME		= 18
+};
+
+static DNS_INLINE unsigned dns_get16(const unsigned char *s) {
+  return ((unsigned)s[0]<<8) | s[1];
+}
+static DNS_INLINE unsigned dns_get32(const unsigned char *s) {
+  return ((unsigned)s[0]<<24) | ((unsigned)s[1]<<16)
+        | ((unsigned)s[2]<<8) | s[3];
+}
+static DNS_INLINE unsigned char *dns_put16(unsigned char *d, unsigned n) {
+  *d++ = (n >> 8) & 255; *d++ = n & 255; return d;
+}
+static DNS_INLINE unsigned char *dns_put32(unsigned char *d, unsigned n) {
+  *d++ = (n >> 24) & 255; *d++ = (n >> 16) & 255;
+  *d++ = (n >>  8) & 255; *d++ = n & 255;
+  return d;
+}
+
+/* DNS Header layout */
+enum {
+ /* bytes 0:1 - query ID */
+  DNS_H_QID1	= 0,
+  DNS_H_QID2	= 1,
+  DNS_H_QID	= DNS_H_QID1,
+#define dns_qid(pkt)	dns_get16((pkt)+DNS_H_QID)
+ /* byte 2: flags1 */
+  DNS_H_F1	= 2,
+  DNS_HF1_QR	= 0x80,	/* query response flag */
+#define dns_qr(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_QR)
+  DNS_HF1_OPCODE = 0x78, /* opcode, 0 = query */
+#define dns_opcode(pkt)	(((pkt)[DNS_H_F1]&DNS_HF1_OPCODE)>>3)
+  DNS_HF1_AA	= 0x04,	/* auth answer */
+#define dns_aa(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_AA)
+  DNS_HF1_TC	= 0x02,	/* truncation flag */
+#define dns_tc(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_TC)
+  DNS_HF1_RD	= 0x01,	/* recursion desired (may be set in query) */
+#define dns_rd(pkt)	((pkt)[DNS_H_F1]&DNS_HF1_RD)
+ /* byte 3: flags2 */
+  DNS_H_F2	= 3,
+  DNS_HF2_RA	= 0x80,	/* recursion available */
+#define dns_ra(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RA)
+  DNS_HF2_Z	= 0x70,	/* reserved */
+  DNS_HF2_RCODE	= 0x0f,	/* response code, DNS_R_XXX above */
+#define dns_rcode(pkt)	((pkt)[DNS_H_F2]&DNS_HF2_RCODE)
+ /* bytes 4:5: qdcount, numqueries */
+  DNS_H_QDCNT1	= 4,
+  DNS_H_QDCNT2	= 5,
+  DNS_H_QDCNT	= DNS_H_QDCNT1,
+#define dns_numqd(pkt)	dns_get16((pkt)+4)
+ /* bytes 6:7: ancount, numanswers */
+  DNS_H_ANCNT1	= 6,
+  DNS_H_ANCNT2	= 7,
+  DNS_H_ANCNT	= DNS_H_ANCNT1,
+#define dns_numan(pkt)	dns_get16((pkt)+6)
+ /* bytes 8:9: nscount, numauthority */
+  DNS_H_NSCNT1	= 8,
+  DNS_H_NSCNT2	= 9,
+  DNS_H_NSCNT	= DNS_H_NSCNT1,
+#define dns_numns(pkt)	dns_get16((pkt)+8)
+ /* bytes 10:11: arcount, numadditional */
+  DNS_H_ARCNT1	= 10,
+  DNS_H_ARCNT2	= 11,
+  DNS_H_ARCNT	= DNS_H_ARCNT1,
+#define dns_numar(pkt)	dns_get16((pkt)+10)
+#define dns_payload(pkt) ((pkt)+DNS_HSIZE)
+};
+
+/* packet buffer: start at pkt, end before pkte, current pos *curp.
+ * extract a DN and set *curp to the next byte after DN in packet.
+ * return -1 on error, 0 if dnsiz is too small, or dnlen on ok.
+ */
+DNS_API int
+dns_getdn(const unsigned char *pkt,
+          const unsigned char **curp,
+          const unsigned char *pkte,
+          unsigned char *dn, unsigned dnsiz);
+
+/* skip the DN at position cur in packet ending before pkte,
+ * return pointer to the next byte after the DN or NULL on error */
+DNS_API const unsigned char *
+dns_skipdn(const unsigned char *pkte, const unsigned char *cur);
+
+struct dns_rr {		/* DNS Resource Record */
+  unsigned char dnsrr_dn[DNS_MAXDN];		/* the DN of the RR */
+  enum dns_class dnsrr_cls;			/* Class */
+  enum dns_type  dnsrr_typ;			/* Type */
+  unsigned dnsrr_ttl;				/* Time-To-Live (TTL) */
+  unsigned dnsrr_dsz;				/* data size */
+  const unsigned char *dnsrr_dptr;		/* pointer to start of data */
+  const unsigned char *dnsrr_dend;		/* past end of data */
+};
+
+struct dns_parse {	/* RR/packet parsing state */
+  const unsigned char *dnsp_pkt;	/* start of the packet */
+  const unsigned char *dnsp_end;	/* end of the packet */
+  const unsigned char *dnsp_cur;	/* current packet position */
+  int dnsp_rrl;				/* number of RRs left to go */
+  int dnsp_nrr;				/* RR count so far */
+  unsigned dnsp_ttl;			/* TTL value so far */
+  const unsigned char *dnsp_qdn;	/* the RR DN we're looking for */
+  enum dns_class dnsp_qcls;		/* RR class we're looking for or 0 */
+  enum dns_type  dnsp_qtyp;		/* RR type we're looking for or 0 */
+  unsigned char dnsp_dnbuf[DNS_MAXDN];
+};
+
+/* initialize the parse structure */
+int dns_initparse(struct dns_parse *p, int qcls, int qtyp,
+                  const unsigned char *pkt, const unsigned char *pkte);
+
+/* search next RR, <0=error, 0=no more RRs, >0 = found. */
+int dns_nextrr(struct dns_parse *p, struct dns_rr *rr);
+
+/* equivalent to dns_initparse() followed by dns_nextrr() */
+int dns_firstrr(struct dns_parse *p, struct dns_rr *rr, int qcls, int qtyp,
+                const unsigned char *pkt, const unsigned char *pkte);
+void dns_rewind(struct dns_parse *p);
+
+
+/**************************************************************************/
+/**************** Resolver Context ****************************************/
+
+/* default resolver context */
+extern struct dns_ctx dns_defctx;
+
+/* initialize default resolver context and open it if do_open is true.
+ * <0 on failure. */
+DNS_API int dns_init(int do_open);
+
+/* return new resolver context with the same settings as copy */
+DNS_API struct dns_ctx *dns_new(const struct dns_ctx *copy);
+
+/* free resolver context; all queries are dropped */
+DNS_API void dns_free(struct dns_ctx *ctx);
+
+DNS_API int dns_add_serv(struct dns_ctx *ctx, const char *ns);
+
+/* set nameserver list for a resolver context */
+DNS_API int dns_set_serv(struct dns_ctx *ctx, const char *serv[]);
+
+/* set search list for a resolver context */
+DNS_API int dns_set_srch(struct dns_ctx *ctx, const char *srch[]);
+
+/* set options for a resolver context */
+DNS_API int dns_set_opts(struct dns_ctx *ctx, const char *opts);
+
+enum dns_opt {		/* options */
+  DNS_OPT_FLAGS,	/* flags, DNS_F_XXX */
+  DNS_OPT_TIMEOUT,	/* timeout in secounds */
+  DNS_OPT_NTRIES,	/* number of retries */
+  DNS_OPT_NDOTS,	/* ndots */
+  DNS_OPT_UDPSIZE,	/* EDNS0 UDP size */
+  DNS_OPT_PORT,		/* port to use */
+};
+
+/* set or get (if val<0) an option */
+DNS_API int dns_set_opt(struct dns_ctx *ctx, enum dns_opt opt, int val);
+
+enum dns_flags {
+  DNS_NOSRCH	= 0x00010000,	/* do not perform search */
+  DNS_NORD	= 0x00020000,	/* request no recursion */
+  DNS_AAONLY	= 0x00040000,	/* set AA flag in queries */
+  DNS_PASSALL	= 0x00080000,	/* pass all replies to application */
+};
+
+/* set the debug function pointer */
+DNS_API void dns_set_dbgfn(struct dns_ctx *ctx, void (*fn)(const unsigned char*,int));
+
+/* open and return UDP socket */
+DNS_API int dns_open(struct dns_ctx *ctx);
+
+/* return UDP socket or -1 if not open */
+DNS_API int dns_sock(const struct dns_ctx *ctx);
+
+/* close the UDP socket */
+DNS_API void dns_close(struct dns_ctx *ctx);
+
+/* return true if any request queued */
+DNS_API int dns_active(const struct dns_ctx *ctx);
+
+/* return status of the last operation */
+DNS_API int dns_status(const struct dns_ctx *ctx);
+void dns_setstatus(struct dns_ctx *ctx, int status);
+
+/* handle I/O event on UDP socket */
+DNS_API void dns_ioevent(struct dns_ctx *ctx, time_t now);
+
+/* process any timeouts, return time in secounds to the
+ * next timeout (or -1 if none) but not greather than maxwait */
+DNS_API int dns_timeouts(struct dns_ctx *ctx, int maxwait, time_t now);
+
+/* define timer requesting routine to use */
+typedef int dns_utm_fn(void *arg, struct dns_query *q, int timeout);
+void dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *utmfn, void *arg);
+/* routine to call as timer callback */
+void dns_tmevent(struct dns_query *q, time_t now);
+
+/**************************************************************************/
+/**************** Making Queries ******************************************/
+
+/* query callback routine */
+typedef void dns_query_fn(struct dns_ctx *ctx, void *result, void *data);
+
+/* query parse routine: raw DNS => application structure */
+typedef int
+dns_parse_fn(const unsigned char *pkt, const unsigned char *pkte, void **res);
+
+enum dns_status {
+  DNS_E_NOERROR		= 0,	/* ok, not an error */
+  DNS_E_TEMPFAIL	= -1,	/* timeout, SERVFAIL or similar */
+  DNS_E_PROTOCOL	= -2,	/* got garbled reply */
+  DNS_E_NXDOMAIN	= -3,	/* domain does not exists */
+  DNS_E_NODATA		= -4,	/* domain exists but no data of reqd type */
+  DNS_E_NOMEM		= -5,	/* out of memory while processing */
+  DNS_E_BADQUERY	= -6	/* the query is malformed */
+};
+
+/* submit generic DN query */
+DNS_API struct dns_query *
+dns_submit_dn(struct dns_ctx *ctx,
+              const unsigned char *dn, int qcls, int qtyp, int flags,
+              dns_parse_fn *parse, dns_query_fn *cbck, void *data, time_t now);
+/* submit generic name query */
+DNS_API struct dns_query *
+dns_submit_p(struct dns_ctx *ctx,
+             const char *name, int qcls, int qtyp, int flags,
+             dns_parse_fn *parse, dns_query_fn *cbck, void *data, time_t now);
+
+/* cancel the given async query in progress */
+DNS_API int dns_cancel(struct dns_ctx *ctx, struct dns_query *q);
+
+/* immediately resolve a generic query, return the answer
+ * and place completion status into *statusp */
+DNS_API void *
+dns_resolve_dn(struct dns_ctx *ctx,
+               const unsigned char *qdn, int qcls, int qtyp, int flags,
+               dns_parse_fn *parse);
+DNS_API void *
+dns_resolve_p(struct dns_ctx *ctx,
+              const char *qname, int qcls, int qtyp, int flags,
+              dns_parse_fn *parse);
+DNS_API void *dns_resolve(struct dns_ctx *ctx, struct dns_query *q);
+
+
+/* Specific RR handlers */
+
+#define dns_rr_common(prefix)						\
+  char *prefix##_cname;		/* canonical name */			\
+  char *prefix##_qname;		/* original query name */		\
+  unsigned prefix##_ttl;	/* TTL value */				\
+  int prefix##_nrr		/* number of records */
+
+struct dns_rr_null {		/* NULL RRset, aka RRset template */
+  dns_rr_common(dnsn);
+};
+
+int dns_stdrr_size(const struct dns_parse *p);
+void *
+dns_stdrr_finish(struct dns_rr_null *ret, char *cp, const struct dns_parse *p);
+
+struct dns_rr_a4 {		/* the A RRset */
+  dns_rr_common(dnsa4);
+  struct in_addr *dnsa4_addr;	/* array of addresses, naddr elements */
+};
+
+dns_parse_fn dns_parse_a4;	/* A RR parsing routine */
+typedef void			/* A query callback routine */
+dns_query_a4_fn(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data);
+
+/* submit A IN query */
+DNS_API struct dns_query *
+dns_submit_a4(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a4_fn *cbck, void *data, time_t now);
+
+/* resolve A IN query */
+DNS_API struct dns_rr_a4 *
+dns_resolve_a4(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_rr_a6 {		/* the AAAA RRset */
+  dns_rr_common(dnsa6);
+  struct in6_addr *dnsa6_addr;	/* array of addresses, naddr elements */
+};
+
+dns_parse_fn dns_parse_a6;	/* A RR parsing routine */
+typedef void			/* A query callback routine */
+dns_query_a6_fn(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data);
+
+/* submit AAAA IN query */
+DNS_API struct dns_query *
+dns_submit_a6(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_a6_fn *cbck, void *data, time_t now);
+
+/* resolve AAAA IN query */
+DNS_API struct dns_rr_a6 *
+dns_resolve_a6(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_rr_ptr {		/* the PTR RRset */
+  dns_rr_common(dnsptr);
+  char **dnsptr_ptr;		/* array of PTRs */
+};
+
+dns_parse_fn dns_parse_ptr;	/* PTR RR parsing routine */
+typedef void			/* PTR query callback */
+dns_query_ptr_fn(struct dns_ctx *ctx, struct dns_rr_ptr *result, void *data);
+/* submit PTR IN in-addr.arpa query */
+DNS_API struct dns_query *
+dns_submit_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data, time_t now);
+/* resolve PTR IN in-addr.arpa query */
+DNS_API struct dns_rr_ptr *
+dns_resolve_a4ptr(struct dns_ctx *ctx, const struct in_addr *addr);
+
+/* the same as above, but for ip6.arpa */
+DNS_API struct dns_query *
+dns_submit_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr,
+                 dns_query_ptr_fn *cbck, void *data, time_t now);
+DNS_API struct dns_rr_ptr *
+dns_resolve_a6ptr(struct dns_ctx *ctx, const struct in6_addr *addr);
+
+
+struct dns_mx {		/* single MX RR */
+  int priority;		/* MX priority */
+  char *name;		/* MX name */
+};
+struct dns_rr_mx {		/* the MX RRset */
+  dns_rr_common(dnsmx);
+  struct dns_mx *dnsmx_mx;	/* array of MXes */
+};
+dns_parse_fn dns_parse_mx;	/* MX RR parsing routine */
+typedef void			/* MX RR callback */
+dns_query_mx_fn(struct dns_ctx *ctx, struct dns_rr_mx *result, void *data);
+/* submit MX IN query */
+DNS_API struct dns_query *
+dns_submit_mx(struct dns_ctx *ctx, const char *name, int flags,
+              dns_query_mx_fn *cbck, void *data, time_t now);
+/* resolve MX IN query */
+DNS_API struct dns_rr_mx *
+dns_resolve_mx(struct dns_ctx *ctx, const char *name, int flags);
+
+
+struct dns_txt {	/* single TXT record */
+  int len;		/* length of the text */
+  unsigned char *txt;	/* pointer to text buffer. May contain nulls. */
+};
+struct dns_rr_txt {		/* the TXT RRset */
+  dns_rr_common(dnstxt);
+  struct dns_txt *dnstxt_txt;	/* array of TXT records */
+};
+dns_parse_fn dns_parse_txt;	/* TXT RR parsing routine */
+typedef void			/* TXT RR callback */
+dns_query_txt_fn(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data);
+/* submit TXT query */
+DNS_API struct dns_query *
+dns_submit_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags,
+               dns_query_txt_fn *cbck, void *data, time_t now);
+/* resolve TXT query */
+DNS_API struct dns_rr_txt *
+dns_resolve_txt(struct dns_ctx *ctx, const char *name, int qcls, int flags);
+
+DNS_API struct dns_query *
+dns_submit_a4dnsbl(struct dns_ctx *ctx,
+                   const struct in_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data, time_t now);
+DNS_API struct dns_query *
+dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data, time_t now);
+DNS_API struct dns_rr_a4 *
+dns_resolve_a4dnsbl(struct dns_ctx *ctx,
+                    const struct in_addr *addr, const char *dnsbl);
+DNS_API struct dns_rr_txt *
+dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in_addr *addr, const char *dnsbl);
+
+DNS_API struct dns_query *
+dns_submit_a6dnsbl(struct dns_ctx *ctx,
+                   const struct in6_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data, time_t now);
+DNS_API struct dns_query *
+dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in6_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data, time_t now);
+DNS_API struct dns_rr_a4 *
+dns_resolve_a6dnsbl(struct dns_ctx *ctx,
+                    const struct in6_addr *addr, const char *dnsbl);
+DNS_API struct dns_rr_txt *
+dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in6_addr *addr, const char *dnsbl);
+
+DNS_API struct dns_query *
+dns_submit_rhsbl(struct dns_ctx *ctx,
+                 const char *name, const char *rhsbl,
+                 dns_query_a4_fn *cbck, void *data, time_t now);
+DNS_API struct dns_query *
+dns_submit_rhsbl_txt(struct dns_ctx *ctx,
+                     const char *name, const char *rhsbl,
+                     dns_query_txt_fn *cbck, void *data, time_t now);
+DNS_API struct dns_rr_a4 *
+dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl);
+DNS_API struct dns_rr_txt *
+dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl);
+
+/**************************************************************************/
+/**************** Names, Names ********************************************/
+
+struct dns_nameval {
+  int val;
+  const char *name;
+};
+
+DNS_DATA_API const struct dns_nameval dns_classtab[];
+DNS_DATA_API const struct dns_nameval dns_typetab[];
+DNS_DATA_API const struct dns_nameval dns_rcodetab[];
+
+DNS_API int dns_findname(const struct dns_nameval *nv, const char *name);
+#define dns_findclassname(class) dns_findname(dns_classtab, (class))
+#define dns_findtypename(type) dns_findname(dns_typetab, (type))
+#define dns_findrcodename(rcode) dns_findname(dns_rcodetab, (rcode))
+
+DNS_API const char *dns_classname(enum dns_class class);
+DNS_API const char *dns_typename(enum dns_type type);
+DNS_API const char *dns_rcodename(enum dns_rcode rcode);
+
+DNS_API const char *dns_strerror(int errnum);
+/**
+ * Log level for UDNS log messages.
+ */
+enum dns_log_level
+{
+	DNS_LOG_DEBUG = 0,
+	DNS_LOG_INFO = 2,
+	DNS_LOG_WARN = 4,
+	DNS_LOG_ERROR = 8
+};
+#define UDNS_LOG_LEVEL_MIN	DNS_LOG_WARN
+/**
+ * Function for logging messages.
+ */
+void dns_log(struct dns_ctx *ctx, enum dns_log_level level, const char *msg, ...);
+/**
+ * Converts a string representing a address into the corresponding network address structure.
+ * @addrstr The string to convert
+ * @sa Pointer to struct sockaddr_storage to which the resulting network address will be written.
+ * @return 0 on success
+ * @note Works for IPv4 and IPv6
+ */
+int dns_str2addr(const char *addrstr, struct sockaddr_storage *sa);
+/**
+ * Converts a string representing a address into the corresponding network address structure.
+ * @addrstr The string to convert
+ * @sa Pointer to struct sockaddr_storage to which the resulting network address will be written.
+ * @return 0 on success
+ * @note Works for IPv4 and IPv6
+ */
+int dns_addr2str(struct sockaddr *addr, char *buf, int len);
+/**
+ * Returns actual the length of the supplied sockaddr structure.
+ * @param sa Pointer to sockaddr structure
+ * @return length of supplied sockaddr structure in bytes.
+ * @note Works for IPv4 and IPv6
+ */
+socklen_t dns_sockaddr_get_len(struct sockaddr *sa);
+/**
+ * Sets the port member of a sockaddr structure.
+ * @param sa Pointer to sockaddr structure
+ * @param port The port number
+ * @return length of supplied sockaddr structure in bytes.
+ * @note Works for IPv4 and IPv6
+ */
+int dns_sockaddr_set_port(struct sockaddr *sa, int port);
+#endif	/* include guard */

Added: branches/ppcgui/ex-libs/udns-arm/udns_bl.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns_bl.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns_bl.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,138 @@
+/* $Id: udns_bl.c,v 1.6 2004/06/30 10:43:36 mjt Exp $
+ * DNSBL stuff
+ */
+
+#include "udns.h"
+
+struct dns_query *
+dns_submit_a4dnsbl(struct dns_ctx *ctx,
+                   const struct in_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data, now);
+}
+
+struct dns_query *
+dns_submit_a4dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (dns_a4ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data, now);
+}
+
+struct dns_rr_a4 *
+dns_resolve_a4dnsbl(struct dns_ctx *ctx,
+                    const struct in_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_a4 *)
+    dns_resolve(ctx, dns_submit_a4dnsbl(ctx, addr, dnsbl, 0, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_a4dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_txt *)
+    dns_resolve(ctx, dns_submit_a4dnsbl_txt(ctx, addr, dnsbl, 0, 0, 0));
+}
+
+
+struct dns_query *
+dns_submit_a6dnsbl(struct dns_ctx *ctx,
+                   const struct in6_addr *addr, const char *dnsbl,
+                   dns_query_a4_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data, now);
+}
+
+struct dns_query *
+dns_submit_a6dnsbl_txt(struct dns_ctx *ctx,
+                       const struct in6_addr *addr, const char *dnsbl,
+                       dns_query_txt_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (dns_a6ptodn(addr, dnsbl, dn, sizeof(dn)) <= 0) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data, now);
+}
+
+struct dns_rr_a4 *
+dns_resolve_a6dnsbl(struct dns_ctx *ctx,
+                    const struct in6_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_a4 *)
+    dns_resolve(ctx, dns_submit_a6dnsbl(ctx, addr, dnsbl, 0, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_a6dnsbl_txt(struct dns_ctx *ctx,
+                        const struct in6_addr *addr, const char *dnsbl) {
+  return (struct dns_rr_txt *)
+    dns_resolve(ctx, dns_submit_a6dnsbl_txt(ctx, addr, dnsbl, 0, 0, 0));
+}
+
+static int
+dns_rhsbltodn(const char *name, const char *rhsbl, unsigned char dn[DNS_MAXDN])
+{
+  int l = dns_sptodn(name, dn, DNS_MAXDN);
+  if (l <= 0) return 0;
+  l = dns_sptodn(rhsbl, dn+l-1, DNS_MAXDN-l+1);
+  if (l <= 0) return 0;
+  return 1;
+}
+
+struct dns_query *
+dns_submit_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl,
+                 dns_query_a4_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (!dns_rhsbltodn(name, rhsbl, dn)) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_A, DNS_NOSRCH,
+                  dns_parse_a4, (dns_query_fn*)cbck, data, now);
+}
+struct dns_query *
+dns_submit_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl,
+                     dns_query_txt_fn *cbck, void *data, time_t now) {
+  unsigned char dn[DNS_MAXDN];
+  if (!dns_rhsbltodn(name, rhsbl, dn)) {
+    dns_setstatus(ctx, DNS_E_BADQUERY);
+    return NULL;
+  }
+  return
+    dns_submit_dn(ctx, dn, DNS_C_IN, DNS_T_TXT, DNS_NOSRCH,
+                  dns_parse_txt, (dns_query_fn*)cbck, data, now);
+}
+
+struct dns_rr_a4 *
+dns_resolve_rhsbl(struct dns_ctx *ctx, const char *name, const char *rhsbl) {
+  return (struct dns_rr_a4*)
+    dns_resolve(ctx, dns_submit_rhsbl(ctx, name, rhsbl, 0, 0, 0));
+}
+
+struct dns_rr_txt *
+dns_resolve_rhsbl_txt(struct dns_ctx *ctx, const char *name, const char *rhsbl)
+{
+  return (struct dns_rr_txt*)
+    dns_resolve(ctx, dns_submit_rhsbl_txt(ctx, name, rhsbl, 0, 0, 0));
+}

Added: branches/ppcgui/ex-libs/udns-arm/udns_dn.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns_dn.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns_dn.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,366 @@
+/* $Id: udns_dn.c,v 1.3 2004/06/29 07:46:39 mjt Exp $
+ * domain names manipulation routines
+ */
+
+#include <string.h>
+#include "udns.h"
+
+unsigned dns_dnlen(const unsigned char *dn) {
+  register const unsigned char *d = dn;
+  while(*d)
+    d += 1 + *d;
+  return (unsigned)(d - dn) + 1;
+}
+
+unsigned dns_dnlabels(register const unsigned char *dn) {
+  register unsigned l = 0;
+  while(*dn)
+    ++l, dn += 1 + *dn;
+  return l;
+}
+
+unsigned dns_dnequal(register const unsigned char *dn1,
+                     register const unsigned char *dn2) {
+  register unsigned c;
+  const unsigned char *dn = dn1;
+  for(;;) {
+    if ((c = *dn1++) != *dn2++)
+      return 0;
+    if (!c)
+      return (unsigned)(dn1 - dn);
+    while(c--) {
+      if (DNS_DNLC(*dn1) != DNS_DNLC(*dn2))
+        return 0;
+      ++dn1; ++dn2;
+    }
+  }
+}
+
+unsigned
+dns_dntodn(const unsigned char *sdn, unsigned char *ddn, unsigned ddnsiz) {
+  unsigned sdnlen = dns_dnlen(sdn);
+  if (ddnsiz < sdnlen)
+    return 0;
+  memcpy(ddn, sdn, sdnlen);
+  return sdnlen;
+}
+
+int
+dns_ptodn(const char *name, unsigned namelen,
+          unsigned char *dn, unsigned dnsiz,
+          int *isabs)
+{
+  unsigned char *dp;		/* current position in dn (len byte first) */
+  unsigned char *const de	/* end of dn: last byte that can be filled up */
+      = dn + (dnsiz >= DNS_MAXDN ? DNS_MAXDN : dnsiz) - 1;
+  const unsigned char *np = (const unsigned char *)name;
+  const unsigned char *ne = np + (namelen ? namelen : strlen(np));
+  unsigned char *llab;	/* start of last label (llab[-1] will be length) */
+  unsigned c;		/* next input character, or length of last label */
+
+  if (!dnsiz)
+    return 0;
+  dp = llab = dn + 1;
+
+  while(np < ne) {
+
+    if (*np == '.') {	/* label delimiter */
+      c = dp - llab;		/* length of the label */
+      if (!c) {			/* empty label */
+        if (np == (const unsigned char *)name && np + 1 == ne) {
+          /* special case for root dn, aka `.' */
+          ++np;
+          break;
+        }
+        return -1;		/* zero label */
+      }
+      if (c > DNS_MAXLABEL)
+        return -1;		/* label too long */
+      llab[-1] = (unsigned char)c; /* update len of last label */
+      llab = ++dp; /* start new label, llab[-1] will be len of it */
+      ++np;
+      continue;
+    }
+
+    /* check whenever we may put out one more byte */
+    if (dp >= de) /* too long? */
+      return dnsiz >= DNS_MAXDN ? -1 : 0;
+    if (*np != '\\') { /* non-escape, simple case */
+      *dp++ = *np++;
+      continue;
+    }
+    /* handle \-style escape */
+    /* note that traditionally, domain names (gethostbyname etc)
+     * used decimal \dd notation, not octal \ooo (RFC1035), so
+     * we're following this tradition here.
+     */
+    if (++np == ne)
+      return -1;			/* bad escape */
+    else if (*np >= '0' && *np <= '9') { /* decimal number */
+      /* we allow not only exactly 3 digits as per RFC1035,
+       * but also 2 or 1, for better usability. */
+      c = *np++ - '0';
+      if (np < ne && *np >= '0' && *np <= '9') { /* 2digits */
+        c = c * 10 + *np++ - '0';
+        if (np < ne && *np >= '0' && *np <= '9') {
+          c = c * 10 + *np++ - '0';
+          if (c > 255)
+            return -1;			/* bad escape */
+        }
+      }
+    }
+    else
+      c = *np++;
+    *dp++ = (unsigned char)c; /* place next out byte */
+  }
+
+  if ((c = dp - llab) > DNS_MAXLABEL)
+    return -1;				/* label too long */
+  if ((llab[-1] = (unsigned char)c) != 0) {
+    *dp++ = 0;
+    if (isabs)
+      *isabs = 0;
+  }
+  else if (isabs)
+    *isabs = 1;
+
+  return dp - dn;
+}
+
+const unsigned char dns_inaddr_arpa_dn[14] = "\07in-addr\04arpa";
+
+unsigned char *
+dns_a4todn_(const struct in_addr *addr, unsigned char *dn, unsigned char *dne) {
+  unsigned char *p;
+  unsigned n;
+  const unsigned char *s = ((const unsigned char *)addr) + 4;
+  while(--s >= (const unsigned char *)addr) {
+    n = *s;
+    p = dn + 1;
+    if (n > 99) {
+      if (p + 2 > dne) return 0;
+      *p++ = n / 100 + '0';
+      *p++ = (n % 100 / 10) + '0';
+      *p = n % 10 + '0';
+    }
+    else if (n > 9) {
+      if (p + 1 > dne) return 0;
+      *p++ = n / 10 + '0';
+      *p = n % 10 + '0';
+    }
+    else {
+      if (p > dne) return 0;
+      *p = n + '0';
+    }
+    *dn = p - dn;
+    dn = p + 1;
+  }
+  return dn;
+}
+
+int dns_a4todn(const struct in_addr *addr, const unsigned char *tdn,
+               unsigned char *dn, unsigned dnsiz) {
+  unsigned char *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
+  unsigned char *p;
+  unsigned l;
+  p = dns_a4todn_(addr, dn, dne);
+  if (!p) return 0;
+  if (!tdn)
+    tdn = dns_inaddr_arpa_dn;
+  l = dns_dnlen(tdn);
+  if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
+  memcpy(p, tdn, l);
+  return (p + l) - dn;
+}
+
+int dns_a4ptodn(const struct in_addr *addr, const char *tname,
+                unsigned char *dn, unsigned dnsiz) {
+  unsigned char *p;
+  int r;
+  if (!tname)
+    return dns_a4todn(addr, NULL, dn, dnsiz);
+  p = dns_a4todn_(addr, dn, dn + dnsiz);
+  if (!p) return 0;
+  r = dns_sptodn(tname, p, dnsiz - (p - dn));
+  return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
+}
+
+const unsigned char dns_ip6_arpa_dn[10] = "\03ip6\04arpa";
+
+unsigned char *
+dns_a6todn_(const struct in6_addr *addr,
+            unsigned char *dn, unsigned char *dne) {
+  unsigned n;
+  const unsigned char *s = ((const unsigned char *)addr) + 16;
+  if (dn + 64 > dne) return 0;
+  while(--s >= (const unsigned char *)addr) {
+    *dn++ = 1;
+    n = *s & 0x0f;
+    *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
+    *dn++ = 1;
+    n = *s >> 4;
+    *dn++ = n > 9 ? n + 'a' - 10 : n + '0';
+  }
+  return dn;
+}
+
+int dns_a6todn(const struct in6_addr *addr, const unsigned char *tdn,
+               unsigned char *dn, unsigned dnsiz) {
+  unsigned char *dne = dn + (dnsiz > DNS_MAXDN ? DNS_MAXDN : dnsiz);
+  unsigned char *p;
+  unsigned l;
+  p = dns_a6todn_(addr, dn, dne);
+  if (!p) return 0;
+  if (!tdn)
+    tdn = dns_ip6_arpa_dn;
+  l = dns_dnlen(tdn);
+  if (p + l > dne) return dnsiz >= DNS_MAXDN ? -1 : 0;
+  memcpy(p, tdn, l);
+  return (p + l) - dn;
+}
+
+int dns_a6ptodn(const struct in6_addr *addr, const char *tname,
+                unsigned char *dn, unsigned dnsiz) {
+  unsigned char *p;
+  int r;
+  if (!tname)
+    return dns_a6todn(addr, NULL, dn, dnsiz);
+  p = dns_a6todn_(addr, dn, dn + dnsiz);
+  if (!p) return 0;
+  r = dns_sptodn(tname, p, dnsiz - (p - dn));
+  return r != 0 ? r : dnsiz >= DNS_MAXDN ? -1 : 0;
+}
+
+/* return size of buffer required to convert the dn into asciiz string.
+ * Keep in sync with dns_dntop() below.
+ */
+unsigned dns_dntop_size(const unsigned char *dn) {
+  unsigned size = 0;			/* the size reqd */
+  const unsigned char *le;		/* label end */
+
+  while(*dn) {
+    /* *dn is the length of the next label, non-zero */
+    if (size)
+      ++size;		/* for the dot */
+    le = dn + *dn + 1;
+    ++dn;
+    do {
+      switch(*dn) {
+      case '.':
+      case '\\':
+      /* Special modifiers in zone files. */
+      case '"':
+      case ';':
+      case '@':
+      case '$':
+        size += 2;
+        break;
+      default:
+        if (*dn <= 0x20 || *dn >= 0x7f)
+          /* \ddd decimal notation */
+          size += 4;
+        else
+          size += 1;
+      }
+    } while(++dn < le);
+  }
+  size += 1;	/* zero byte at the end - string terminator */
+  return size > DNS_MAXNAME ? 0 : size;
+}
+
+/* Convert the dn into asciiz string.
+ * Keep in sync with dns_dntop_size() above.
+ */
+int dns_dntop(const unsigned char *dn, char *name, unsigned namesiz) {
+  char *np = name;			/* current name ptr */
+  char *const ne = name + namesiz;	/* end of name */
+  const unsigned char *le;		/* label end */
+
+  while(*dn) {
+    /* *dn is the length of the next label, non-zero */
+    if (np != name) {
+      if (np >= ne) goto toolong;
+      *np++ = '.';
+    }
+    le = dn + *dn + 1;
+    ++dn;
+    do {
+      switch(*dn) {
+      case '.':
+      case '\\':
+      /* Special modifiers in zone files. */
+      case '"':
+      case ';':
+      case '@':
+      case '$':
+        if (np + 2 > ne) goto toolong;
+        *np++ = '\\';
+        *np++ = *dn;
+        break;
+      default:
+        if (*dn <= 0x20 || *dn >= 0x7f) {
+          /* \ddd decimal notation */
+          if (np + 4 >= ne) goto toolong;
+          *np++ = '\\';
+          *np++ = '0' + (*dn / 100);
+          *np++ = '0' + ((*dn % 100) / 10);
+          *np++ = '0' + (*dn % 10);
+        }
+        else {
+          if (np >= ne) goto toolong;
+          *np++ = *dn;
+        }
+      }
+    } while(++dn < le);
+  }
+  if (np >= ne) goto toolong;
+  *np++ = '\0';
+  return np - name;
+toolong:
+  return namesiz >= DNS_MAXNAME ? -1 : 0;
+}
+
+#ifdef TEST
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+  int i;
+  int sz;
+  unsigned char dn[DNS_MAXDN+10];
+  unsigned char *dl, *dp;
+  int isabs;
+
+  sz = (argc > 1) ? atoi(argv[1]) : 0;
+
+  for(i = 2; i < argc; ++i) {
+    int r = dns_ptodn(argv[i], 0, dn, sz, &isabs);
+    printf("%s: ", argv[i]);
+    if (r < 0) printf("error\n");
+    else if (!r) printf("buffer too small\n");
+    else {
+      printf("len=%d dnlen=%d size=%d name:",
+             r, dns_dnlen(dn), dns_dntop_size(dn));
+      dl = dn;
+      while(*dl) {
+        printf(" %d=", *dl);
+        dp = dl + 1;
+        dl = dp + *dl;
+        while(dp < dl) {
+          if (*dp <= ' ' || *dp >= 0x7f)
+            printf("\\%03d", *dp);
+          else if (*dp == '.' || *dp == '\\')
+            printf("\\%c", *dp);
+          else
+            putchar(*dp);
+          ++dp;
+        }
+      }
+      if (isabs) putchar('.');
+      putchar('\n');
+    }
+  }
+  return 0;
+}
+
+#endif /* TEST */

Added: branches/ppcgui/ex-libs/udns-arm/udns_dntosp.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns_dntosp.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns_dntosp.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,11 @@
+/* $Id: udns_dntosp.c,v 1.3 2004/06/29 07:46:39 mjt Exp $
+ * dns_dntosp() = convert DN to asciiz string using static buffer
+ */
+
+#include "udns.h"
+
+static char name[DNS_MAXNAME];
+
+const char *dns_dntosp(const unsigned char *dn) {
+  return dns_dntop(dn, name, sizeof(name)) > 0 ? name : 0;
+}

Added: branches/ppcgui/ex-libs/udns-arm/udns_misc.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns_misc.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns_misc.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,231 @@
+/* $Id: udns_misc.c,v 1.5 2004/07/02 00:14:48 mjt Exp $
+ */
+
+#include "udns.h"
+#include <stdio.h>
+#include <string.h>
+#ifndef WIN32
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#endif
+
+int dns_findname(const struct dns_nameval *nv, const char *name) {
+  register const char *a, *b;
+  for(; nv->name; ++nv)
+    for(a = name, b = nv->name; ; ++a, ++b)
+      if (DNS_DNUC(*a) != *b) break;
+      else if (!*a) return nv->val;
+  return -1;
+}
+
+const char *dns_strerror(int err) {
+  if (err >= 0) return "successeful completion";
+  switch(err) {
+  case DNS_E_TEMPFAIL:	return "temporary failure in name resolution";
+  case DNS_E_PROTOCOL:	return "protocol error";
+  case DNS_E_NXDOMAIN:	return "domain name does not exist";
+  case DNS_E_NODATA:	return "valid domain but no data of requested type";
+  case DNS_E_NOMEM:	return "out of memory";
+  case DNS_E_BADQUERY:	return "malformed query";
+  default:		return "unknown error";
+  }
+}
+
+/**
+ * @todo use dns_ctx debug function if availible, otherwise suppress output.
+ */
+void dns_log(struct dns_ctx *ctx, enum dns_log_level level, const char *msg, ...)
+{
+	va_list va;
+	const char *level_str;
+#define DNS_LOG_PREFIX_LEN 1024
+	char prefix[DNS_LOG_PREFIX_LEN];
+
+	if(level < UDNS_LOG_LEVEL_MIN)
+		return;
+
+	switch(level)
+	{
+		case DNS_LOG_DEBUG: level_str = "DEBUG"; break;
+		case DNS_LOG_INFO: level_str = "INFO"; break;
+		case DNS_LOG_WARN: level_str = "WARN"; break;
+		case DNS_LOG_ERROR: level_str = "ERROR"; break;
+		default: level_str = "DEBUG"; break;
+	}
+	snprintf(prefix, DNS_LOG_PREFIX_LEN, "UDNS-%s: ", level_str);
+	fprintf(stdout, prefix);
+	va_start(va, msg);
+	vfprintf(stdout, msg, va);
+	va_end(va);
+#undef DNS_LOG_PREFIX_LEN
+}
+
+int dns_str2addr(const char *addrstr, struct sockaddr_storage *sa)
+{
+	int af = 0;
+	#ifdef WIN32
+	int len = sizeof(struct sockaddr_storage);
+	#else
+	void *addrptr = NULL;
+	#endif
+
+	if(!addrstr)
+		return -1;
+
+	if(strchr(addrstr, ':'))
+		af = AF_INET6;
+	else if(strchr(addrstr, '.'))
+		af = AF_INET;
+	else
+		return -1;
+
+#ifdef WIN32
+	if(WSAStringToAddress(addrstr, af, NULL, sa, &len))
+		return -1;
+#else
+	memset(sa, 0x0, sizeof(struct sockaddr_storage));
+	switch(af)
+	{
+		case AF_INET:
+			addrptr = &(((struct sockaddr_in*) sa)->sin_addr);
+			((struct sockaddr_in*) sa)->sin_family = AF_INET;
+			break;
+		case AF_INET6:
+			addrptr = &(((struct sockaddr_in6*) sa)->sin6_addr);
+			((struct sockaddr_in6*) sa)->sin6_family = AF_INET6;
+			break;
+		default:
+			// !! Protocol family not supported !
+			return -2;
+	}
+	assert(addrptr != NULL);
+	if(inet_pton(af, addrstr, addrptr) <= 0)
+		return -1;
+#endif
+	return 0;
+}
+
+int dns_addr2str(struct sockaddr *addr, char *buf, int len)
+{
+	int err;
+	#ifdef WIN32
+	int chars_written;
+	int addrlen = dns_sockaddr_get_len(addr);
+	char *temp;
+	#else
+	char *result;
+	void *addrptr;
+	#endif
+	
+	assert(addr != NULL);
+	assert(buf != NULL);
+	assert(len > 0);
+	
+	*buf = '\0';
+
+	#ifdef WIN32
+	chars_written = len;
+	if(WSAAddressToString(addr, addrlen, NULL, buf, &chars_written) == SOCKET_ERROR)
+	{
+		// !! Error !
+		err = WSAGetLastError();
+		/* NOTE: if the buffer was to small, WSAAddressToString() fails with
+		 * WSAEFAULT and writes the number of bytes actually needed to complete
+		 * the operation in chars_written.
+		 */
+		if(err == WSAEFAULT && chars_written > len)
+		{
+			// !! Not enough space in user buffer !
+			err = -3;
+		}
+		else if(err == WSAEINVAL)
+		{
+			// !! Protocol family not supported !
+			err = -2;
+		}
+		else
+		{
+			// !! Generic error !
+			err = -1;
+		}
+		return err;
+	}
+	temp = strchr(buf,':');
+	if(temp)
+		*temp='\0';
+	#else
+	switch(addr->sa_family)
+	{
+		case PF_INET:
+			addrptr = &(((struct sockaddr_in*) addr)->sin_addr);
+			break;
+		case PF_INET6:
+			addrptr = &(((struct sockaddr_in6*) addr)->sin6_addr);
+			break;
+		default:
+			// !! Protocol family not supported !
+			return -2;
+	}
+
+	result = (char*) inet_ntop(addr->sa_family, addrptr, buf, len);
+	if(result == NULL)
+	{
+		// !! Error !
+		
+		if(errno == EAFNOSUPPORT)
+		{
+			// !! Protocol family not supported !
+			err = -2;
+		}
+		else if(errno == ENOSPC)
+		{
+			// !! Not enough space in user buffer !
+			err = -3;
+		}
+		else
+		{
+			// !! Generic error !
+			err = -1;
+		}
+		return err;
+	}
+	
+	#endif
+	
+	// No error
+	return 0;
+}
+
+socklen_t dns_sockaddr_get_len(struct sockaddr *sa)
+{
+	switch(sa->sa_family)
+	{
+		case AF_INET:
+			return sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			return sizeof(struct sockaddr_in6);
+			break;
+		default:
+			return 0;	// don't return -1, this would be very dangerous
+	}
+}
+
+int dns_sockaddr_set_port(struct sockaddr *sa, int port)
+{
+	switch(sa->sa_family)
+	{
+		case AF_INET:
+			((struct sockaddr_in*) sa)->sin_port = htons(port);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6*) sa)->sin6_port = htons(port);
+			break;
+		default:
+			return -1;
+	}
+	return 0;
+}

Added: branches/ppcgui/ex-libs/udns-arm/udns_parse.c
===================================================================
--- branches/ppcgui/ex-libs/udns-arm/udns_parse.c	2006-11-28 22:30:15 UTC (rev 2973)
+++ branches/ppcgui/ex-libs/udns-arm/udns_parse.c	2006-11-28 23:01:41 UTC (rev 2974)
@@ -0,0 +1,163 @@
+/* $Id: udns_parse.c,v 1.10 2004/07/02 21:52:04 mjt Exp $
+ * raw DNS packet parsing routines
+ */
+
+#include <string.h>
+#include <assert.h>
+#include "udns.h"
+
+const unsigned char *
+dns_skipdn(const unsigned char *cur, const unsigned char *pkte) {
+  unsigned c;
+  for(;;) {
+    if (cur >= pkte)
+      return NULL;
+    c = *cur++;
+    if (!c)
+      return cur;
+    if (c & 192) {		/* jump */
+      return cur + 1 >= pkte ? NULL : cur + 1;
+    }
+    cur += c;
+  }
+}
+
+int
+dns_getdn(const unsigned char *pkt,
+          const unsigned char **curp,
+          const unsigned char *pkte,
+          register unsigned char *dn, unsigned dnsiz) {
+  unsigned c;
+  const unsigned char *cp = *curp;	/* max jump position (jump only back) */
+  const un